Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ on:
push:
branches:
- main
pull_request:
branches:
- main


jobs:
Expand Down
15 changes: 12 additions & 3 deletions pkg/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package ast
import (
"fmt"
"math/rand"
"slices"
"strings"
)

Expand Down Expand Up @@ -105,12 +106,20 @@ func (ai *AddInstructionNode) Instruction() string { return "ADD" }

// ARG
type ArgInstructionNode struct {
Name string
Value string // optional default
Pairs map[string]string
}

func (ai *ArgInstructionNode) ToString() string {
return fmt.Sprintf("%sARG%s %s %s %s", colorPurple, colorCyan, ai.Name, ai.Value, colorNone)
mapStrings := []string{}
keys := make([]string, 0, len(ai.Pairs))
for k := range ai.Pairs {
keys = append(keys, k)
}
slices.Sort(keys)
for _, k := range keys {
mapStrings = append(mapStrings, fmt.Sprintf("%s=%s", k, ai.Pairs[k]))
}
return fmt.Sprintf("%sARG%s %s %s", colorPurple, colorCyan, strings.Join(mapStrings, ","), colorNone)
}

func (ai *ArgInstructionNode) Instruction() string { return "ARG" }
Expand Down
96 changes: 61 additions & 35 deletions pkg/ast/reconstruct.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ func escapeSlice[T any](slice []T) string {
func (sn *StageNode) Reconstruct() []string {
reconstructed := []string{}
if sn.Image != "" {
fromInstruction := fmt.Sprintf("FROM %s", sn.Image)
var fromInstruction strings.Builder
fromInstruction.WriteString(fmt.Sprintf("FROM %s", sn.Image))
if sn.Name != "" {
fromInstruction += fmt.Sprintf(" AS %s", sn.Name)
fromInstruction.WriteString(fmt.Sprintf(" AS %s", sn.Name))
}
reconstructed = append(reconstructed, fromInstruction)
reconstructed = append(reconstructed, fromInstruction.String())
}
for _, instructionNode := range sn.Instructions {
reconstructed = append(reconstructed, instructionNode.Reconstruct()...)
Expand All @@ -55,7 +56,17 @@ func (ai *AddInstructionNode) Reconstruct() []string {
}

func (ai *ArgInstructionNode) Reconstruct() []string {
reconstructed := fmt.Sprintf("%s %s=%s", ai.Instruction(), ai.Name, ai.Value)
reconstructed := fmt.Sprintf("%s", ai.Instruction())
keys := make([]string, len(ai.Pairs))
index := 0
for k := range ai.Pairs {
keys[index] = k
index++
}
slices.Sort(keys)
for _, k := range keys {
reconstructed += fmt.Sprintf(" %s=%s", k, ai.Pairs[k])
}
return []string{reconstructed}
}

Expand All @@ -64,22 +75,24 @@ func (ci *CmdInstructionNode) Reconstruct() []string {
return []string{reconstructed}
}
func (ci *CopyInstructionNode) Reconstruct() []string {
reconstructed := fmt.Sprintf("%s ", ci.Instruction())
var reconstructed strings.Builder
reconstructed.WriteString(fmt.Sprintf("%s ", ci.Instruction()))

reconstructed += formatIfValue("--keep-git-dir=%s ", strconv.FormatBool(ci.KeepGitDir))
reconstructed += formatIfValue("--chown=%s ", ci.Chown)
reconstructed += formatIfValue("--link=%s ", strconv.FormatBool(ci.Link))
reconstructed += formatIfValue("--from=%s ", ci.From)
reconstructed += fmt.Sprintf("%s ", strings.Join(ci.Source, " "))
reconstructed += fmt.Sprintf("%s", ci.Destination)
return []string{reconstructed}
reconstructed.WriteString(formatIfValue("--keep-git-dir=%s ", strconv.FormatBool(ci.KeepGitDir)))
reconstructed.WriteString(formatIfValue("--chown=%s ", ci.Chown))
reconstructed.WriteString(formatIfValue("--link=%s ", strconv.FormatBool(ci.Link)))
reconstructed.WriteString(formatIfValue("--from=%s ", ci.From))
reconstructed.WriteString(fmt.Sprintf("%s ", strings.Join(ci.Source, " ")))
reconstructed.WriteString(fmt.Sprintf("%s", ci.Destination))
return []string{reconstructed.String()}
}
func (ei *EntrypointInstructionNode) Reconstruct() []string {
reconstructed := fmt.Sprintf("%s %s", ei.Instruction(), escapeSlice(ei.Exec))
return []string{reconstructed}
}
func (ei *EnvInstructionNode) Reconstruct() []string {
reconstructed := fmt.Sprintf("%s", ei.Instruction())
var reconstructed strings.Builder
reconstructed.WriteString(fmt.Sprintf("%s", ei.Instruction()))
keys := make([]string, len(ei.Pairs))
index := 0
for k := range ei.Pairs {
Expand All @@ -88,41 +101,52 @@ func (ei *EnvInstructionNode) Reconstruct() []string {
}
slices.Sort(keys)
for _, k := range keys {
reconstructed += fmt.Sprintf(" %s=%s", k, ei.Pairs[k])
reconstructed.WriteString(fmt.Sprintf(" %s=%s", k, ei.Pairs[k]))
}
return []string{reconstructed}
return []string{reconstructed.String()}
}

func (ei *ExposeInstructionNode) Reconstruct() []string {
reconstructed := fmt.Sprintf("%s", ei.Instruction())
var reconstructed strings.Builder
reconstructed.WriteString(fmt.Sprintf("%s", ei.Instruction()))
for _, port := range ei.Ports {
protocol := "tcp"
if !port.IsTCP {
protocol = "udp"
}
reconstructed += fmt.Sprintf(" %s/%s", port.Port, protocol)
reconstructed.WriteString(fmt.Sprintf(" %s/%s", port.Port, protocol))
}
return []string{reconstructed}
return []string{reconstructed.String()}
}
func (hi *HealthcheckInstructionNode) Reconstruct() []string {
reconstructed := fmt.Sprintf("%s ", hi.Instruction())
var reconstructed strings.Builder
reconstructed.WriteString(fmt.Sprintf("%s ", hi.Instruction()))
if hi.CancelStatement {
return []string{reconstructed + "NONE"}
reconstructed.WriteString("NONE")
return []string{reconstructed.String()}
}
reconstructed += formatIfValue("--interval=%s ", hi.Interval)
reconstructed += formatIfValue("--timeout=%s ", hi.Timeout)
reconstructed += formatIfValue("--start-period=%s ", hi.StartPeriod)
reconstructed += formatIfValue("--start-interval=%s ", hi.StartInterval)
reconstructed += formatIfValue("--retries=%s ", strconv.Itoa(hi.Retries))
reconstructed += escapeSlice(hi.Cmd)
return []string{reconstructed}
reconstructed.WriteString(formatIfValue("--interval=%s ", hi.Interval))
reconstructed.WriteString(formatIfValue("--timeout=%s ", hi.Timeout))
reconstructed.WriteString(formatIfValue("--start-period=%s ", hi.StartPeriod))
reconstructed.WriteString(formatIfValue("--start-interval=%s ", hi.StartInterval))
reconstructed.WriteString(formatIfValue("--retries=%s ", strconv.Itoa(hi.Retries)))
reconstructed.WriteString(escapeSlice(hi.Cmd))
return []string{reconstructed.String()}
}
func (li *LabelInstructionNode) Reconstruct() []string {
reconstructed := fmt.Sprintf("%s", li.Instruction())
for k, v := range li.Pairs {
reconstructed += fmt.Sprintf(" %s=%s", k, v)
var reconstructed strings.Builder
reconstructed.WriteString(fmt.Sprintf("%s", li.Instruction()))
keys := make([]string, len(li.Pairs))
index := 0
for k := range li.Pairs {
keys[index] = k
index++
}
return []string{reconstructed}
slices.Sort(keys)
for _, k := range keys {
reconstructed.WriteString(fmt.Sprintf(" %s=%s", k, li.Pairs[k]))
}
return []string{reconstructed.String()}
}
func (mi *MaintainerInstructionNode) Reconstruct() []string {
reconstructed := fmt.Sprintf("%s %s", mi.Instruction(), mi.Name)
Expand All @@ -135,14 +159,16 @@ func (oi *OnbuildInstructionNode) Reconstruct() []string {
return nested
}
func (ri *RunInstructionNode) Reconstruct() []string {
reconstructed := fmt.Sprintf("%s ", ri.Instruction())
var reconstructed strings.Builder
reconstructed.WriteString(fmt.Sprintf("%s ", ri.Instruction()))
if !ri.ShellForm && !ri.IsHeredoc {
return []string{reconstructed + escapeSlice(ri.Cmd)}
reconstructed.WriteString(escapeSlice(ri.Cmd))
return []string{reconstructed.String()}
}
if ri.IsHeredoc {
reconstructed += "<< "
reconstructed.WriteString("<< ")
}
ri.Cmd[0] = reconstructed + ri.Cmd[0]
ri.Cmd[0] = reconstructed.String() + ri.Cmd[0]
return ri.Cmd
}
func (si *ShellInstructionNode) Reconstruct() []string {
Expand Down
19 changes: 17 additions & 2 deletions pkg/ast/reconstruct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,28 @@ func TestReconstructInstruction(t *testing.T) {
Input: ast.StageNode{
Instructions: []ast.InstructionNode{
&ast.ArgInstructionNode{
Name: "abc",
Value: "def",
Pairs: map[string]string{
"abc": "def",
},
},
},
},
Expected: []string{"ARG abc=def"},
},
{
Input: ast.StageNode{
Instructions: []ast.InstructionNode{
&ast.ArgInstructionNode{
Pairs: map[string]string{
"abc": "def",
"xy": "z",
},
},
},
},
Expected: []string{"ARG abc=def xy=z"},
},

{
Input: ast.StageNode{
Instructions: []ast.InstructionNode{
Expand Down
9 changes: 4 additions & 5 deletions pkg/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,12 @@ func (p Parser) parseAdd(t token.Token) ast.InstructionNode {
}

func (p Parser) parseArg(t token.Token) ast.InstructionNode {
key, value := util.ParseAssign(t.Content)
if len(key)+len(value) == 0 {
key = t.Content
pairs := util.ParseAssigns(t.Content)
if len(pairs) == 0 {
pairs[t.Content] = ""
}
return &ast.ArgInstructionNode{
Name: key,
Value: value,
Pairs: pairs,
}
}

Expand Down
8 changes: 3 additions & 5 deletions pkg/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func compareInstructionNode(expected, actual ast.InstructionNode) string {
case *ast.AddInstructionNode:
return compareAddInstructionNode(expected.(*ast.AddInstructionNode), ac)
case *ast.ArgInstructionNode:
if *expected.(*ast.ArgInstructionNode) != *ac {
if !reflect.DeepEqual(expected.(*ast.ArgInstructionNode).Pairs, ac.Pairs) {
return fmt.Sprintf("ARG instruction mismatch: Expected %v Got %v", expected, ac)
}
case *ast.CmdInstructionNode:
Expand Down Expand Up @@ -314,8 +314,7 @@ func TestInstructionParsing(t *testing.T) {
},
},
Expected: []ast.InstructionNode{&ast.ArgInstructionNode{
Name: "test",
Value: "value",
Pairs: map[string]string{"test": "value"},
}},
},
{
Expand All @@ -326,8 +325,7 @@ func TestInstructionParsing(t *testing.T) {
},
},
Expected: []ast.InstructionNode{&ast.ArgInstructionNode{
Name: "test",
Value: "",
Pairs: map[string]string{"test": ""},
}},
},
{
Expand Down
Loading