@@ -44,7 +44,7 @@ func FormatNode(ast *ExtendedNode, c *Config) (string, bool) {
4444 command .Arg : formatBasic ,
4545 command .Cmd : formatCmd ,
4646 command .Copy : formatSpaceSeparated ,
47- command .Entrypoint : formatCmd ,
47+ command .Entrypoint : formatEntrypoint ,
4848 command .Env : formatEnv ,
4949 command .Expose : formatSpaceSeparated ,
5050 command .From : formatSpaceSeparated ,
@@ -341,10 +341,7 @@ func formatRun(n *ExtendedNode, c *Config) string {
341341 flags := n .Node .Flags
342342
343343 var content string
344- if len (n .Node .Heredocs ) > 1 {
345- // Not implemented yet
346- panic ("Multiple Heredocs not implemented yet" )
347- } else if len (n .Node .Heredocs ) == 1 {
344+ if len (n .Node .Heredocs ) >= 1 {
348345 content = n .Node .Heredocs [0 ].Content
349346 hereDoc = true
350347 // TODO: check if doc.FileDescriptor == 0?
@@ -373,7 +370,8 @@ func formatRun(n *ExtendedNode, c *Config) string {
373370 } else {
374371 content = formatShell (content , hereDoc , c )
375372 if hereDoc {
376- content = "<<" + n .Node .Heredocs [0 ].Name + "\n " + content + n .Node .Heredocs [0 ].Name + "\n "
373+ n .Node .Heredocs [0 ].Content = content
374+ content , _ = GetHeredoc (n )
377375 }
378376 }
379377
@@ -384,12 +382,33 @@ func formatRun(n *ExtendedNode, c *Config) string {
384382 return strings .ToUpper (n .Value ) + " " + content
385383}
386384
385+ func GetHeredoc (n * ExtendedNode ) (string , bool ) {
386+ if len (n .Node .Heredocs ) == 0 {
387+ return "" , false
388+ }
389+
390+ printAST (n , 0 )
391+ args := []string {}
392+ cur := n .Next
393+ for cur != nil {
394+ if cur .Node .Value != "" {
395+ args = append (args , cur .Node .Value )
396+ }
397+ cur = cur .Next
398+ }
399+
400+ content := strings .Join (args , " " ) + "\n " + n .Node .Heredocs [0 ].Content + n .Node .Heredocs [0 ].Name + "\n "
401+ return content , true
402+ }
387403func formatBasic (n * ExtendedNode , c * Config ) string {
388404 // Uppercases the command, and indent the following lines
389405 originalTrimmed := strings .TrimLeft (n .OriginalMultiline , " \t " )
390406
391- parts := regexp .MustCompile (" " ).Split (originalTrimmed , 2 )
392- return IndentFollowingLines (strings .ToUpper (n .Value )+ " " + parts [1 ], c .IndentSize )
407+ value , success := GetHeredoc (n )
408+ if ! success {
409+ value = regexp .MustCompile (" " ).Split (originalTrimmed , 2 )[1 ]
410+ }
411+ return IndentFollowingLines (strings .ToUpper (n .Value )+ " " + value , c .IndentSize )
393412}
394413
395414// Marshal is a UTF-8 friendly marshaler. Go's json.Marshal is not UTF-8
@@ -407,47 +426,99 @@ func Marshal(i interface{}) ([]byte, error) {
407426 return bytes .TrimRight (buffer .Bytes (), "\n " ), err
408427}
409428
410- func getCmd (n * ExtendedNode ) []string {
429+ func getCmd (n * ExtendedNode , shouldSplitNode bool ) []string {
411430 cmd := []string {}
412431 for node := n ; node != nil ; node = node .Next {
413432 // Split value by whitespace
414- rawValue := strings .Trim (node .Value , " \t " )
415- if len (node .Flags ) > 0 {
416- rawValue += " " + strings . Join ( node .Flags , " " )
433+ rawValue := strings .Trim (node .Node . Value , " \t " )
434+ if len (node .Node . Flags ) > 0 {
435+ cmd = append ( cmd , node .Node . Flags ... )
417436 }
418- parts , err := shlex .Split (rawValue )
419- if err != nil {
420- log .Fatalf ("Error splitting: %s\n " , node .Value )
437+ // log.Printf("ShouldSplitNode: %v\n", shouldSplitNode)
438+ if shouldSplitNode {
439+ parts , err := shlex .Split (rawValue )
440+ if err != nil {
441+ log .Fatalf ("Error splitting: %s\n " , node .Node .Value )
442+ }
443+ cmd = append (cmd , parts ... )
444+ } else {
445+ cmd = append (cmd , rawValue )
421446 }
422- cmd = append (cmd , parts ... )
423447 }
424448 // log.Printf("getCmd: %v\n", cmd)
425449 return cmd
426450}
427451
452+ func formatEntrypoint (n * ExtendedNode , c * Config ) string {
453+ // this can technically change behavior. https://docs.docker.com/reference/dockerfile/#understand-how-cmd-and-entrypoint-interact
454+ isJSON , ok := n .Node .Attributes ["json" ]
455+ if ! ok {
456+ isJSON = false
457+ }
458+ if ! isJSON {
459+ // https://docs.docker.com/reference/dockerfile/#entrypoint
460+ node := n .Next .Node .Value
461+ parts , err := shlex .Split (node )
462+ if err != nil {
463+ log .Fatalf ("Error splitting: %s\n " , node )
464+ }
465+
466+ doNotSplit := false
467+ // This is a simplistic check to determine if we need to run in a full shell.
468+ for _ , part := range parts {
469+ if part == "&&" || part == ";" || part == "||" {
470+ doNotSplit = true
471+ break
472+ }
473+ }
474+
475+ if doNotSplit {
476+ n .Next .Node .Flags = append (n .Next .Node .Flags , []string {"/bin/sh" , "-c" }... )
477+ // Hacky workaround to tell getCmd to not split the command
478+ if n .Node .Attributes == nil {
479+ n .Node .Attributes = make (map [string ]bool )
480+ }
481+ n .Node .Attributes ["json" ] = true
482+ }
483+ }
484+ // printAST(n, 0)
485+ return formatCmd (n , c )
486+ }
428487func formatCmd (n * ExtendedNode , c * Config ) string {
429- cmd := getCmd (n .Next )
488+ // printAST(n, 0)
489+ isJSON , ok := n .Node .Attributes ["json" ]
490+ if ! ok {
491+ isJSON = false
492+ }
493+ cmd := getCmd (n .Next , ! isJSON )
430494 b , err := Marshal (cmd )
431495 if err != nil {
432496 return ""
433497 }
434498 bWithSpace := strings .ReplaceAll (string (b ), "\" ,\" " , "\" , \" " )
435- return strings .ToUpper (n .Value ) + " " + string (bWithSpace ) + "\n "
499+ return strings .ToUpper (n .Node . Value ) + " " + string (bWithSpace ) + "\n "
436500}
437501
438502func formatSpaceSeparated (n * ExtendedNode , c * Config ) string {
439- cmd := strings .Join (getCmd (n .Next ), " " )
440- if len (n .Node .Flags ) > 0 {
441- cmd = strings .Join (n .Node .Flags , " " ) + " " + cmd
503+ isJSON , ok := n .Node .Attributes ["json" ]
504+ if ! ok {
505+ isJSON = false
506+ }
507+ cmd , success := GetHeredoc (n )
508+ if ! success {
509+ cmd = strings .Join (getCmd (n .Next , isJSON ), " " )
510+ if len (n .Node .Flags ) > 0 {
511+ cmd = strings .Join (n .Node .Flags , " " ) + " " + cmd
512+ }
442513 }
443514
444- return strings .ToUpper (n .Value ) + " " + cmd + "\n "
515+ return strings .ToUpper (n .Node . Value ) + " " + cmd + "\n "
445516}
446517
447518func formatMaintainer (n * ExtendedNode , c * Config ) string {
448519
449520 // Get text between quotes
450- maintainer := strings .Trim (n .Next .Value , "\" " )
521+ maintainer := strings .Trim (n .Next .Node . Value , "\" " )
451522 return "LABEL org.opencontainers.image.authors=\" " + maintainer + "\" \n "
452523}
453524
0 commit comments