forked from microsoft/azure-linux-dev-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcomponent.go
More file actions
216 lines (171 loc) · 10.7 KB
/
component.go
File metadata and controls
216 lines (171 loc) · 10.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package projectconfig
import (
"fmt"
"dario.cat/mergo"
"github.com/brunoga/deep"
"github.com/microsoft/azure-linux-dev-tools/internal/rpm"
"github.com/microsoft/azure-linux-dev-tools/internal/utils/fileutils"
)
const (
// HashTypeSHA256 represents the SHA-256 hash algorithm.
HashTypeSHA256 = fileutils.HashTypeSHA256
// HashTypeSHA512 represents the SHA-512 hash algorithm.
HashTypeSHA512 = fileutils.HashTypeSHA512
)
// ComponentReference encapsulates a reference to a source component.
type ComponentReference struct {
// Name of the component.
Name string
// Version of the component (optional).
Version *rpm.Version
}
// OriginType indicates the type of origin for a source file.
type OriginType string
const (
// OriginTypeURI indicates that the source file is fetched from a URI.
OriginTypeURI OriginType = "download"
)
// Origin describes where a source file comes from and how to retrieve it.
// When omitted from a source file reference, the file will be resolved via the lookaside cache.
type Origin struct {
// Type indicates how the source file should be acquired.
Type OriginType `toml:"type" json:"type" jsonschema:"required,enum=download,title=Origin type,description=Type of origin for this source file"`
// Uri to download the source file from if origin type is 'download'. Ignored for other origin types.
Uri string `toml:"uri,omitempty" json:"uri,omitempty" jsonschema:"title=URI,description=URI to download the source file from if origin type is 'download',example=https://example.com/source.tar.gz"`
}
// SourceFileReference encapsulates a reference to a specific source file artifact.
type SourceFileReference struct {
// Reference to the component to which the source file belongs.
Component ComponentReference `toml:"-" json:"-" fingerprint:"-"`
// Name of the source file; must be non-empty.
Filename string `toml:"filename" json:"filename"`
// Hash of the source file, expressed as a hex string.
Hash string `toml:"hash,omitempty" json:"hash,omitempty"`
// Type of hash used by Hash (e.g., "SHA256", "SHA512").
HashType fileutils.HashType `toml:"hash-type,omitempty" json:"hashType,omitempty" jsonschema:"enum=SHA256,enum=SHA512,title=Hash type,description=Hash algorithm used for the hash value"`
// Origin for this source file. When omitted, the file is resolved via the lookaside cache.
Origin Origin `toml:"origin,omitempty" json:"origin,omitempty" fingerprint:"-"`
}
// Defines a component group. Component groups are logical groupings of components (see [ComponentConfig]).
// A component group is useful because it allows for succinctly naming/identifying a curated set of components,
// say in a command line interface. Note that a component group does not uniquely "own" its components; a
// component may belong to multiple groups, and components need not belong to any group.
type ComponentGroupConfig struct {
// A human-friendly description of this component group.
Description string `toml:"description,omitempty" json:"description,omitempty" jsonschema:"title=Description,description=Description of this component group"`
// List of explicitly included components, identified by name.
Components []string `toml:"components,omitempty" json:"components,omitempty" jsonschema:"title=Components,description=List of component names that are members of this group"`
// List of glob patterns specifying raw spec files that define components.
SpecPathPatterns []string `toml:"specs,omitempty" json:"specs,omitempty" validate:"dive,required" jsonschema:"title=Spec path patterns,description=List of glob patterns identifying local specs for components in this group,example=SPECS/**/.spec"`
// List of glob patterns specifying files to specifically ignore from spec selection.
ExcludedPathPatterns []string `toml:"excluded-paths,omitempty" json:"excludedPaths,omitempty" jsonschema:"title=Excluded path patterns,description=List of glob patterns identifying local paths to exclude from spec selection,example=build/**"`
// Default configuration to apply to component members of this group.
DefaultComponentConfig ComponentConfig `toml:"default-component-config,omitempty" json:"defaultComponentConfig,omitempty" jsonschema:"title=Default component configuration,description=Default component config inherited by all members of this component group"`
}
// Returns a copy of the component group config with relative file paths converted to absolute
// file paths (relative to referenceDir, not the current working directory).
func (g ComponentGroupConfig) WithAbsolutePaths(referenceDir string) ComponentGroupConfig {
// First deep-copy ourselves.
//
// NOTE: We use the panicking MustCopy() because copying should only fail if the input *type*
// is invalid. Since we're always using the same type, we never expect to see a runtime error
// here.
result := deep.MustCopy(g)
// Fix up paths.
for i := range result.SpecPathPatterns {
result.SpecPathPatterns[i] = makeAbsolute(referenceDir, result.SpecPathPatterns[i])
}
for i := range result.ExcludedPathPatterns {
result.ExcludedPathPatterns[i] = makeAbsolute(referenceDir, result.ExcludedPathPatterns[i])
}
result.DefaultComponentConfig = *(result.DefaultComponentConfig.WithAbsolutePaths(referenceDir))
return result
}
// ReleaseCalculation controls how the Release tag is managed during rendering.
type ReleaseCalculation string
const (
// ReleaseCalculationAuto is the default. azldev auto-bumps the Release tag based on
// synthetic commit history. Static integer releases are incremented; %autorelease
// is handled by rpmautospec.
ReleaseCalculationAuto ReleaseCalculation = "auto"
// ReleaseCalculationManual skips all automatic Release tag manipulation. Use this for
// components that manage their own release numbering (e.g. kernel).
ReleaseCalculationManual ReleaseCalculation = "manual"
)
// Defines a component.
type ComponentConfig struct {
// The component's name; not actually present in serialized files.
Name string `toml:"-" json:"name" table:",sortkey" fingerprint:"-"`
// Reference to the source config file that this definition came from; not present
// in serialized files.
SourceConfigFile *ConfigFile `toml:"-" json:"-" table:"-" fingerprint:"-"`
// RenderedSpecDir is the output directory for this component's rendered spec files.
// Derived at resolve time from the project's rendered-specs-dir setting; not present
// in serialized files. Empty when rendered-specs-dir is not configured.
RenderedSpecDir string `toml:"-" json:"renderedSpecDir,omitempty" table:"-"`
// Where to get its spec and adjacent files from.
Spec SpecSource `toml:"spec,omitempty" json:"spec,omitempty" jsonschema:"title=Spec,description=Identifies where to find the spec for this component"`
// ReleaseCalculation controls how the Release tag is managed during rendering.
// Defaults to auto (empty). Set to "manual" for components that manage their own
// release numbering (e.g. kernel).
ReleaseCalculation ReleaseCalculation `toml:"release-calculation,omitempty" json:"releaseCalculation,omitempty" validate:"omitempty,oneof=auto manual" jsonschema:"enum=auto,enum=manual,title=Release calculation,description=Controls how the Release tag is managed during rendering. Empty or omitted means auto."`
// Overlays to apply to sources after they've been acquired. May mutate the spec as well as sources.
Overlays []ComponentOverlay `toml:"overlays,omitempty" json:"overlays,omitempty" table:"-" jsonschema:"title=Overlays,description=Overlays to apply to this component's spec and/or sources"`
// Configuration for building the component.
Build ComponentBuildConfig `toml:"build,omitempty" json:"build,omitempty" table:"-" jsonschema:"title=Build configuration,description=Configuration for building the component"`
// Source file references for this component.
SourceFiles []SourceFileReference `toml:"source-files,omitempty" json:"sourceFiles,omitempty" table:"-" jsonschema:"title=Source files,description=Source files to download for this component"`
// Default configuration applied to all binary packages produced by this component.
// Takes precedence over package-group defaults; overridden by explicit Packages entries.
DefaultPackageConfig PackageConfig `toml:"default-package-config,omitempty" json:"defaultPackageConfig,omitempty" table:"-" jsonschema:"title=Default package config,description=Default configuration applied to all binary packages produced by this component"`
// Per-package configuration overrides, keyed by exact binary package name.
// Takes precedence over DefaultPackageConfig and package-group defaults.
Packages map[string]PackageConfig `toml:"packages,omitempty" json:"packages,omitempty" table:"-" validate:"dive" jsonschema:"title=Package overrides,description=Per-package configuration overrides keyed by exact binary package name"`
}
// AllowedSourceFilesHashTypes defines the set of hash types that are supported
// for use in [SourceFileReference] entries in component configs.
// MD5 is excluded by design.
//
//nolint:gochecknoglobals // This is effectively a constant, but Go doesn't have const maps.
var AllowedSourceFilesHashTypes = map[fileutils.HashType]bool{
fileutils.HashTypeSHA256: true,
fileutils.HashTypeSHA512: true,
}
// Mutates the component config, updating it with overrides present in other.
func (c *ComponentConfig) MergeUpdatesFrom(other *ComponentConfig) error {
err := mergo.Merge(c, other, mergo.WithOverride, mergo.WithAppendSlice)
if err != nil {
return fmt.Errorf("failed to merge project info:\n%w", err)
}
return nil
}
// Returns a copy of the component config with relative file paths converted to absolute
// file paths (relative to referenceDir, not the current working directory).
func (c *ComponentConfig) WithAbsolutePaths(referenceDir string) *ComponentConfig {
// Deep copy the input to avoid unexpected sharing. Make sure *not* to deep-copy
// the SourceConfigFile, as we *do* want to alias that pointer, sharing it across
// all configs that came from that source config file.
result := &ComponentConfig{
Name: c.Name,
SourceConfigFile: c.SourceConfigFile,
RenderedSpecDir: c.RenderedSpecDir,
ReleaseCalculation: c.ReleaseCalculation,
Spec: deep.MustCopy(c.Spec),
Build: deep.MustCopy(c.Build),
SourceFiles: deep.MustCopy(c.SourceFiles),
DefaultPackageConfig: deep.MustCopy(c.DefaultPackageConfig),
Packages: deep.MustCopy(c.Packages),
}
// Fix up paths.
result.Spec.Path = makeAbsolute(referenceDir, result.Spec.Path)
// Copy and fix up overlays.
if c.Overlays != nil {
result.Overlays = make([]ComponentOverlay, len(c.Overlays))
for i := range result.Overlays {
result.Overlays[i] = *c.Overlays[i].WithAbsolutePaths(referenceDir)
}
}
return result
}