MCPcopy Create free account
hub / github.com/coder/envbuilder / UserFromDockerfile

Function UserFromDockerfile

devcontainer/devcontainer.go:322–425  ·  view source on GitHub ↗

UserFromDockerfile inspects the contents of a provided Dockerfile and returns the user that will be used to run the container.

(dockerfileContent string, buildArgs map[string]string)

Source from the content-addressed store, hash-verified

320// UserFromDockerfile inspects the contents of a provided Dockerfile
321// and returns the user that will be used to run the container.
322func UserFromDockerfile(dockerfileContent string, buildArgs map[string]string) (user string, err error) {
323 res, err := parser.Parse(strings.NewReader(dockerfileContent))
324 if err != nil {
325 return "", fmt.Errorf("parse dockerfile: %w", err)
326 }
327
328 // Collect ARG values (defaults + overrides from buildArgs) for
329 // substitution into FROM image refs.
330 lexer := shell.NewLex('\\')
331 var argEnvs []string
332 for _, child := range res.AST.Children {
333 if !strings.EqualFold(child.Value, "arg") || child.Next == nil {
334 continue
335 }
336 if key, val, ok := strings.Cut(child.Next.Value, "="); ok {
337 if override, has := buildArgs[key]; has {
338 val = override
339 }
340 argEnvs = append(argEnvs, key+"="+val)
341 } else {
342 arg := child.Next.Value
343 if val, has := buildArgs[arg]; has {
344 argEnvs = append(argEnvs, arg+"="+val)
345 }
346 }
347 }
348
349 // Parse stages and user commands to determine the relevant user
350 // from the final stage.
351 var (
352 stages []*instructions.Stage
353 stageNames = make(map[string]*instructions.Stage)
354 stageUser = make(map[*instructions.Stage]*instructions.UserCommand)
355 currentStage *instructions.Stage
356 )
357 for _, child := range res.AST.Children {
358 inst, err := instructions.ParseInstruction(child)
359 if err != nil {
360 return "", fmt.Errorf("parse instruction: %w", err)
361 }
362
363 switch i := inst.(type) {
364 case *instructions.Stage:
365 // Substitute ARG values in the base image name.
366 baseName, _, err := lexer.ProcessWord(i.BaseName, shell.EnvsFromSlice(argEnvs))
367 if err != nil {
368 return "", fmt.Errorf("processing ARG substitution in FROM %q: %w", i.BaseName, err)
369 }
370 i.BaseName = baseName
371 stages = append(stages, i)
372 if i.Name != "" {
373 stageNames[i.Name] = i
374 }
375 currentStage = i
376 case *instructions.UserCommand:
377 if currentStage == nil {
378 continue
379 }

Callers 3

TestUserFromFunction · 0.92
CompileMethod · 0.85

Calls 2

UserFromImageFunction · 0.85
NameMethod · 0.45

Tested by 2

TestUserFromFunction · 0.74