Skip to content

Commit

Permalink
Auto-skip: handle if-else statements (#3367)
Browse files Browse the repository at this point in the history
Adds auto-skip support for if statements. 

earthly/earthly#3040
  • Loading branch information
mikejholly authored Oct 12, 2023
1 parent 8821533 commit 5a4f720
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 18 deletions.
71 changes: 53 additions & 18 deletions inputgraph/inputgraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,20 +187,28 @@ func (l *loader) handleWithDocker(ctx context.Context, cmd spec.Command) error {
}

func (l *loader) handleIf(ctx context.Context, ifStmt spec.IfStatement) error {
return errors.Wrap(ErrUnableToDetermineHash, "if not supported")
l.hashIfStatement(ifStmt)
if err := l.loadBlock(ctx, ifStmt.IfBody); err != nil {
return err
}
if ifStmt.ElseBody != nil {
if err := l.loadBlock(ctx, *ifStmt.ElseBody); err != nil {
return err
}
}
for _, elseIf := range ifStmt.ElseIf {
l.hashElseIf(elseIf)
if err := l.loadBlock(ctx, elseIf.Body); err != nil {
return err
}
}
return nil
}

func (l *loader) handleFor(ctx context.Context, forStmt spec.ForStatement) error {
return errors.Wrap(ErrUnableToDetermineHash, "for not supported")
}

func (l *loader) hashWaitStatement(w spec.WaitStatement) {
w.SourceLocation = nil
l.hasher.HashString("WAIT")
l.hasher.HashInt(len(w.Body))
l.hasher.HashJSONMarshalled(w.Args)
}

func (l *loader) handleWait(ctx context.Context, waitStmt spec.WaitStatement) error {
l.hashWaitStatement(waitStmt)
for _, stmt := range waitStmt.Body {
Expand Down Expand Up @@ -247,6 +255,43 @@ func (l *loader) loadBlock(ctx context.Context, b spec.Block) error {
return nil
}

func (l *loader) hashIfStatement(s spec.IfStatement) {
s.SourceLocation = nil
l.hasher.HashString("IF")
l.hasher.HashJSONMarshalled(s.Expression)
l.hasher.HashBool(s.ExecMode)
l.hasher.HashInt(len(s.IfBody))
l.hasher.HashInt(len(s.ElseIf))
if s.ElseBody != nil {
l.hasher.HashInt(len(*s.ElseBody))
}
}

func (l *loader) hashElseIf(e spec.ElseIf) {
e.SourceLocation = nil
l.hasher.HashString("ELSE IF")
l.hasher.HashJSONMarshalled(e.Expression)
l.hasher.HashBool(e.ExecMode)
l.hasher.HashInt(len(e.Body))
}

func (l *loader) hashWaitStatement(w spec.WaitStatement) {
w.SourceLocation = nil
l.hasher.HashString("WAIT")
l.hasher.HashInt(len(w.Body))
l.hasher.HashJSONMarshalled(w.Args)
}

func (l *loader) hashVersion(v spec.Version) {
v.SourceLocation = nil
l.hasher.HashJSONMarshalled(v)
}

func (l *loader) hashCommand(cmd spec.Command) {
cmd.SourceLocation = nil
l.hasher.HashJSONMarshalled(cmd)
}

func copyVisited(m map[string]struct{}) map[string]struct{} {
m2 := map[string]struct{}{}
for k := range m {
Expand Down Expand Up @@ -284,16 +329,6 @@ func (l *loader) loadTargetFromString(ctx context.Context, targetName string) er
return loaderInst.load(ctx)
}

func (l *loader) hashVersion(v spec.Version) {
v.SourceLocation = nil
l.hasher.HashJSONMarshalled(v)
}

func (l *loader) hashCommand(cmd spec.Command) {
cmd.SourceLocation = nil
l.hasher.HashJSONMarshalled(cmd)
}

func (l *loader) findProject(ctx context.Context) (org, project string, err error) {
if l.target.IsRemote() {
return "", "", ErrRemoteNotSupported
Expand Down
5 changes: 5 additions & 0 deletions tests/autoskip/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ test-all:
BUILD +test-auto-skip-with-subdir
BUILD +test-auto-skip-requires-project
BUILD +test-auto-skip-wait
BUILD +test-auto-skip-if-else

test-auto-skip:
RUN echo hello > my-file
Expand Down Expand Up @@ -46,6 +47,10 @@ test-auto-skip-wait:
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=wait.earth --target=+test --output_contains="not skipped"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=wait.earth --target=+test --output_contains="ec3d61867365de2deda79ce06f7afa849b765bb1"

test-auto-skip-if-else:
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=if-else.earth --target=+test --output_contains="condition ok"
DO --pass-args +RUN_EARTHLY_ARGS --earthfile=if-else.earth --target=+test --output_contains="d7ba3699b3342c386fd40b3368c167898ae58f2a"

RUN_EARTHLY_ARGS:
COMMAND
ARG earthfile
Expand Down
14 changes: 14 additions & 0 deletions tests/autoskip/if-else.earth
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
VERSION 0.7

PROJECT earthly-technologies/core

FROM alpine

test:
IF [ true ]
RUN echo "condition ok"
ELSE IF [ false ]
RUN echo "never"
ELSE
RUN echo "nope"
END
4 changes: 4 additions & 0 deletions util/buildkitskipper/hasher/hasher.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ func (h *Hasher) HashJSONMarshalled(v any) {
h.HashBytes(dt)
}

func (h *Hasher) HashBool(v bool) {
h.HashBytes([]byte(fmt.Sprintf("bool:%t", v)))
}

func (h *Hasher) HashString(s string) {
h.HashBytes([]byte(fmt.Sprintf("str:%s", s)))
}
Expand Down

0 comments on commit 5a4f720

Please sign in to comment.