@@ -10,9 +10,10 @@ import (
1010 "path/filepath"
1111
1212 "github.com/microsoft/azure-linux-dev-tools/internal/app/azldev"
13+ "github.com/microsoft/azure-linux-dev-tools/internal/app/azldev/core/components"
14+ "github.com/microsoft/azure-linux-dev-tools/internal/providers/sourceproviders"
1315 "github.com/microsoft/azure-linux-dev-tools/internal/providers/sourceproviders/fedorasource"
1416 "github.com/microsoft/azure-linux-dev-tools/internal/utils/downloader"
15- "github.com/microsoft/azure-linux-dev-tools/internal/utils/fileutils"
1617 "github.com/microsoft/azure-linux-dev-tools/internal/utils/retry"
1718 "github.com/spf13/cobra"
1819)
@@ -22,7 +23,7 @@ type DownloadSourcesOptions struct {
2223 Directory string
2324 OutputDir string
2425 LookasideBaseURIs []string
25- PackageName string
26+ ComponentName string
2627 LookasideDownloader fedorasource.FedoraSourceDownloader
2728}
2829
@@ -45,28 +46,29 @@ The command reads the 'sources' file, resolves the lookaside cache URI from
4546the distro configuration, and downloads each listed file into the directory.
4647Files that already exist in the directory are skipped.
4748
48- The package name is derived from the directory name and can be overridden
49- with --package-name. The directory must contain a 'sources' file.
49+ Either --component or --lookaside-uri must be provided:
5050
51- This command can run without project configuration by providing
52- --lookaside-uri explicitly.` ,
53- Example : ` # Download sources in the current directory (package name derived from dir name)
54- azldev advanced download-sources
51+ --component (-p) Uses the component's distro configuration to resolve
52+ the lookaside URI and package name.
53+ --lookaside-uri Provides the URI explicitly (no project config needed).
54+ Package name is derived from the directory name.` ,
55+ Example : ` # Download sources for a component (uses component's distro config)
56+ azldev advanced download-sources -p curl
5557
56- # Download sources from a specific directory
57- azldev advanced download-sources -d ./path/to/curl/
58+ # Download sources using explicit lookaside URI (no config needed)
59+ azldev advanced download-sources \
60+ --lookaside-uri 'https://example.com/$pkg/$filename/$hashtype/$hash/$filename'
5861
59- # Download sources to a different output directory
60- azldev advanced download-sources -o /tmp/output
62+ # Specify a different source directory
63+ azldev advanced download-sources -p curl -d ./path/to/sources/
6164
62- # Download sources using explicit lookaside URIs
63- azldev advanced download-sources \\
64- --lookaside-uri https://example.com/cache1 \\
65- --lookaside-uri https://example.com/cache2
65+ # Download to a different output directory
66+ azldev advanced download-sources -p curl -o /tmp/output
6667
67- # Download sources without project configuration
68- azldev advanced download-sources \\
69- --lookaside-uri https://example.com/cache -d ./curl` ,
68+ # Try multiple lookaside URIs in order
69+ azldev advanced download-sources \
70+ --lookaside-uri 'https://cache1.example.com/$pkg/$filename/$hashtype/$hash/$filename' \
71+ --lookaside-uri 'https://cache2.example.com/$pkg/$filename/$hashtype/$hash/$filename'` ,
7072 RunE : azldev .RunFuncWithoutRequiredConfig (func (env * azldev.Env ) (interface {}, error ) {
7173 if options .Directory == "" {
7274 options .Directory = "."
@@ -84,11 +86,15 @@ This command can run without project configuration by providing
8486 "output directory for downloaded files (defaults to source directory)" )
8587 _ = cmd .MarkFlagDirname ("output-dir" )
8688
89+ cmd .Flags ().StringVarP (& options .ComponentName , "component" , "p" , "" ,
90+ "component name to resolve distro and package name from" )
91+
8792 cmd .Flags ().StringArrayVar (& options .LookasideBaseURIs , "lookaside-uri" , nil ,
88- "explicit lookaside base URI(s) to use instead of the distro configuration (can be specified multiple times)" )
93+ "explicit lookaside base URI(s) to try in order, first success wins " +
94+ "(can be specified multiple times)" )
8995
90- cmd .Flags (). StringVar ( & options . PackageName , "package-name " , "" ,
91- "explicit package name to use instead of deriving from the directory name " )
96+ cmd .MarkFlagsOneRequired ( "component " , "lookaside-uri" )
97+ cmd . MarkFlagsMutuallyExclusive ( "component" , "lookaside-uri " )
9298
9399 return cmd
94100}
@@ -117,45 +123,40 @@ func DownloadSources(env *azldev.Env, options *DownloadSourcesOptions) error {
117123 extractOpts = append (extractOpts , fedorasource .WithOutputDir (options .OutputDir ))
118124 }
119125
120- // Verify the 'sources' file exists before attempting downloads.
121- sourcesPath := filepath .Join (options .Directory , "sources" )
122-
123- sourcesExists , err := fileutils .Exists (env .FS (), sourcesPath )
124- if err != nil {
125- return fmt .Errorf ("failed to check for sources file at %#q:\n %w" , sourcesPath , err )
126- }
127-
128- if ! sourcesExists {
129- return fmt .Errorf ("no 'sources' file found in %#q" , options .Directory )
130- }
131-
132126 // Try each lookaside base URI until one succeeds.
133127 var downloadErr error
134128
135129 for _ , uri := range lookasideBaseURIs {
136130 slog .Info ("Trying lookaside base URI" , "uri" , uri )
137131
138- downloadErr = lookasideDownloader .ExtractSourcesFromRepo (
132+ uriErr : = lookasideDownloader .ExtractSourcesFromRepo (
139133 env , options .Directory , packageName , uri , nil , extractOpts ... ,
140134 )
141- if downloadErr == nil {
135+ if uriErr == nil {
142136 break
143137 }
144138
145139 slog .Warn ("Failed to download sources from lookaside URI" ,
146- "uri" , uri , "error" , downloadErr )
140+ "uri" , uri , "error" , uriErr )
141+
142+ downloadErr = errors .Join (downloadErr , uriErr )
147143 }
148144
149145 if downloadErr != nil {
150- return fmt .Errorf ("failed to download sources from any lookaside URI:\n %w" , downloadErr )
146+ return fmt .Errorf ("failed to download sources from any lookaside URI:\n %w" ,
147+ downloadErr )
151148 }
152149
153150 outputDir := options .Directory
154151 if options .OutputDir != "" {
155152 outputDir = options .OutputDir
156153 }
157154
158- absOutputDir , _ := filepath .Abs (outputDir )
155+ absOutputDir , absErr := filepath .Abs (outputDir )
156+ if absErr != nil {
157+ absOutputDir = outputDir
158+ }
159+
159160 slog .Info ("Sources downloaded successfully" , "outputDir" , absOutputDir )
160161
161162 return nil
@@ -185,72 +186,96 @@ func createLookasideDownloader(env *azldev.Env) (fedorasource.FedoraSourceDownlo
185186}
186187
187188// resolveDownloadParams determines the package name and lookaside URIs.
189+ // In component mode, both are resolved from the component's config.
190+ // In standalone mode, lookaside URIs come from the flag and the package name
191+ // is derived from the directory basename.
188192func resolveDownloadParams (
189193 env * azldev.Env , options * DownloadSourcesOptions ,
190194) (packageName string , lookasideBaseURIs []string , err error ) {
191- packageName , err = resolvePackageName ( options )
192- if err != nil {
193- return "" , nil , err
195+ if len ( options . LookasideBaseURIs ) == 0 && options . ComponentName == "" {
196+ return "" , nil , errors . New (
197+ "either --component or --lookaside-uri must be provided" )
194198 }
195199
200+ // Standalone mode: --lookaside-uri provided.
196201 if len (options .LookasideBaseURIs ) > 0 {
197- return packageName , options .LookasideBaseURIs , nil
198- }
202+ packageName , err = resolvePackageNameFromDir (options )
203+ if err != nil {
204+ return "" , nil , err
205+ }
199206
200- lookasideBaseURI , err := resolveLookasideURI (env )
201- if err != nil {
202- return "" , nil , err
207+ return packageName , options .LookasideBaseURIs , nil
203208 }
204209
205- return packageName , []string {lookasideBaseURI }, nil
210+ // Component mode: --component provided.
211+ return resolveFromComponent (env , options )
206212}
207213
208- // resolvePackageName determines the package name from the --package-name flag or directory name.
209- func resolvePackageName (options * DownloadSourcesOptions ) (string , error ) {
210- if options .PackageName != "" {
211- return options .PackageName , nil
212- }
213-
214+ // resolvePackageNameFromDir derives the package name from the directory basename.
215+ func resolvePackageNameFromDir (options * DownloadSourcesOptions ) (string , error ) {
214216 absDir , err := filepath .Abs (options .Directory )
215217 if err != nil {
216- return "" , fmt .Errorf ("failed to resolve absolute path for %#q:\n %w" , options .Directory , err )
218+ return "" , fmt .Errorf (
219+ "failed to resolve absolute path for %#q:\n %w" ,
220+ options .Directory , err )
217221 }
218222
219223 packageName := filepath .Base (absDir )
220224
221- slog .Debug ("Derived package name from directory name" , "name" , packageName , "dir" , options .Directory )
225+ slog .Debug ("Derived package name from directory name" ,
226+ "name" , packageName , "dir" , options .Directory )
222227
223228 return packageName , nil
224229}
225230
226- // resolveLookasideURI finds the lookaside base URI by checking the default distro first,
227- // then following the upstream distro reference if needed.
228- func resolveLookasideURI (env * azldev.Env ) (string , error ) {
229- distroDef , distroVersionDef , err := env .Distro ()
231+ // resolveFromComponent resolves both the package name and lookaside URI
232+ // from a component's configuration.
233+ func resolveFromComponent (
234+ env * azldev.Env , options * DownloadSourcesOptions ,
235+ ) (packageName string , lookasideBaseURIs []string , err error ) {
236+ resolver := components .NewResolver (env )
237+
238+ filter := & components.ComponentFilter {
239+ ComponentNamePatterns : []string {options .ComponentName },
240+ }
241+
242+ comps , err := resolver .FindComponents (filter )
230243 if err != nil {
231- return "" , fmt .Errorf ("failed to resolve default distro:\n %w" , err )
244+ return "" , nil , fmt .Errorf ("failed to resolve component %#q:\n %w" ,
245+ options .ComponentName , err )
232246 }
233247
234- // If the default distro itself has a lookaside URI, use it directly.
235- if distroDef . LookasideBaseURI != "" {
236- return distroDef . LookasideBaseURI , nil
248+ if comps . Len () == 0 {
249+ return "" , nil , fmt . Errorf ( "component %#q not found" ,
250+ options . ComponentName )
237251 }
238252
239- // Otherwise, follow the upstream distro reference from the default component config.
240- upstreamRef := distroVersionDef .DefaultComponentConfig .Spec .UpstreamDistro
241- if upstreamRef .Name == "" {
242- return "" , errors .New ("no lookaside base URI configured for the default distro, " +
243- "and no upstream distro reference found; use --lookaside-uri to specify one" )
253+ if comps .Len () != 1 {
254+ return "" , nil , fmt .Errorf (
255+ "expected exactly one component for %#q, got %d" ,
256+ options .ComponentName , comps .Len ())
257+ }
258+
259+ component := comps .Components ()[0 ]
260+
261+ // Derive package name from the component's upstream-name or component name.
262+ packageName = component .GetName ()
263+ if upstreamName := component .GetConfig ().Spec .UpstreamName ; upstreamName != "" {
264+ packageName = upstreamName
244265 }
245266
246- upstreamDef , _ , err := env . ResolveDistroRef ( upstreamRef )
267+ distro , err := sourceproviders . ResolveDistro ( env , component )
247268 if err != nil {
248- return "" , fmt .Errorf ("failed to resolve upstream distro %#q:\n %w" , upstreamRef .Name , err )
269+ return "" , nil , fmt .Errorf (
270+ "failed to resolve distro for component %#q:\n %w" ,
271+ options .ComponentName , err )
249272 }
250273
251- if upstreamDef .LookasideBaseURI == "" {
252- return "" , fmt .Errorf ("no lookaside base URI configured for upstream distro %#q" , upstreamRef .Name )
274+ if distro .Definition .LookasideBaseURI == "" {
275+ return "" , nil , fmt .Errorf (
276+ "no lookaside base URI configured for distro %#q" ,
277+ distro .Ref .Name )
253278 }
254279
255- return upstreamDef . LookasideBaseURI , nil
280+ return packageName , [] string { distro . Definition . LookasideBaseURI } , nil
256281}
0 commit comments