@@ -65,6 +65,7 @@ type Compiled struct {
65
65
DockerfilePath string
66
66
DockerfileContent string
67
67
BuildContext string
68
+ FeatureContexts map [string ]string
68
69
BuildArgs []string
69
70
70
71
User string
@@ -130,7 +131,7 @@ func (s Spec) HasDockerfile() bool {
130
131
// devcontainerDir is the path to the directory where the devcontainer.json file
131
132
// is located. scratchDir is the path to the directory where the Dockerfile will
132
133
// be written to if one doesn't exist.
133
- func (s * Spec ) Compile (fs billy.Filesystem , devcontainerDir , scratchDir , fallbackDockerfile , workspaceFolder string ) (* Compiled , error ) {
134
+ func (s * Spec ) Compile (fs billy.Filesystem , devcontainerDir , scratchDir string , fallbackDockerfile , workspaceFolder string , useBuildContexts bool ) (* Compiled , error ) {
134
135
params := & Compiled {
135
136
User : s .ContainerUser ,
136
137
ContainerEnv : s .ContainerEnv ,
@@ -213,25 +214,26 @@ func (s *Spec) Compile(fs billy.Filesystem, devcontainerDir, scratchDir, fallbac
213
214
if remoteUser == "" {
214
215
remoteUser = params .User
215
216
}
216
- params .DockerfileContent , err = s .compileFeatures (fs , devcontainerDir , scratchDir , params .User , remoteUser , params .DockerfileContent )
217
+ params .DockerfileContent , params . FeatureContexts , err = s .compileFeatures (fs , devcontainerDir , scratchDir , params .User , remoteUser , params .DockerfileContent , useBuildContexts )
217
218
if err != nil {
218
219
return nil , err
219
220
}
220
221
return params , nil
221
222
}
222
223
223
- func (s * Spec ) compileFeatures (fs billy.Filesystem , devcontainerDir , scratchDir , containerUser , remoteUser , dockerfileContent string ) (string , error ) {
224
+ func (s * Spec ) compileFeatures (fs billy.Filesystem , devcontainerDir , scratchDir string , containerUser , remoteUser , dockerfileContent string , useBuildContexts bool ) (string , map [ string ] string , error ) {
224
225
// If there are no features, we don't need to do anything!
225
226
if len (s .Features ) == 0 {
226
- return dockerfileContent , nil
227
+ return dockerfileContent , nil , nil
227
228
}
228
229
229
230
featuresDir := filepath .Join (scratchDir , "features" )
230
231
err := fs .MkdirAll (featuresDir , 0644 )
231
232
if err != nil {
232
- return "" , fmt .Errorf ("create features directory: %w" , err )
233
+ return "" , nil , fmt .Errorf ("create features directory: %w" , err )
233
234
}
234
235
featureDirectives := []string {}
236
+ featureContexts := make (map [string ]string )
235
237
236
238
// TODO: Respect the installation order outlined by the spec:
237
239
// https://containers.dev/implementors/features/#installation-order
@@ -251,7 +253,7 @@ func (s *Spec) compileFeatures(fs billy.Filesystem, devcontainerDir, scratchDir,
251
253
if _ , featureRef , ok = strings .Cut (featureRefRaw , "./" ); ! ok {
252
254
featureRefParsed , err := name .NewTag (featureRefRaw )
253
255
if err != nil {
254
- return "" , fmt .Errorf ("parse feature ref %s: %w" , featureRefRaw , err )
256
+ return "" , nil , fmt .Errorf ("parse feature ref %s: %w" , featureRefRaw , err )
255
257
}
256
258
featureRef = featureRefParsed .Repository .Name ()
257
259
}
@@ -275,19 +277,21 @@ func (s *Spec) compileFeatures(fs billy.Filesystem, devcontainerDir, scratchDir,
275
277
featureSha := md5 .Sum ([]byte (featureRefRaw ))
276
278
featureName := filepath .Base (featureRef )
277
279
featureDir := filepath .Join (featuresDir , fmt .Sprintf ("%s-%x" , featureName , featureSha [:4 ]))
278
- err = fs .MkdirAll (featureDir , 0644 )
279
- if err != nil {
280
- return "" , err
280
+ if err := fs .MkdirAll (featureDir , 0644 ); err != nil {
281
+ return "" , nil , err
281
282
}
282
283
spec , err := features .Extract (fs , devcontainerDir , featureDir , featureRefRaw )
283
284
if err != nil {
284
- return "" , fmt .Errorf ("extract feature %s: %w" , featureRefRaw , err )
285
+ return "" , nil , fmt .Errorf ("extract feature %s: %w" , featureRefRaw , err )
285
286
}
286
- directive , err := spec .Compile (containerUser , remoteUser , featureOpts )
287
+ directive , err := spec .Compile (featureName , containerUser , remoteUser , useBuildContexts , featureOpts )
287
288
if err != nil {
288
- return "" , fmt .Errorf ("compile feature %s: %w" , featureRefRaw , err )
289
+ return "" , nil , fmt .Errorf ("compile feature %s: %w" , featureRefRaw , err )
289
290
}
290
291
featureDirectives = append (featureDirectives , directive )
292
+ if useBuildContexts {
293
+ featureContexts [featureName ] = featureDir
294
+ }
291
295
}
292
296
293
297
lines := []string {"\n USER root" }
@@ -297,7 +301,7 @@ func (s *Spec) compileFeatures(fs billy.Filesystem, devcontainerDir, scratchDir,
297
301
// we're going to run as root.
298
302
lines = append (lines , fmt .Sprintf ("USER %s" , remoteUser ))
299
303
}
300
- return strings .Join (append ([]string {dockerfileContent }, lines ... ), "\n " ), err
304
+ return strings .Join (append ([]string {dockerfileContent }, lines ... ), "\n " ), featureContexts , err
301
305
}
302
306
303
307
// UserFromDockerfile inspects the contents of a provided Dockerfile
0 commit comments