Skip to content

Instantly share code, notes, and snippets.

@thediveo
Last active September 27, 2024 01:04
Show Gist options
  • Save thediveo/0d8b6ae7f88918c2571890e508468b23 to your computer and use it in GitHub Desktop.
Save thediveo/0d8b6ae7f88918c2571890e508468b23 to your computer and use it in GitHub Desktop.
Dynamic Go workspace Docker build contexts

(gist title)

This gist assumes the following directory structure:

  • foobar-ws/
    • bar/
      • bar.go
      • go.mod
    • foo/
      • foo.go
      • go.mod
    • foobar/
      • deployments/foobar/
        • Dockerfile
      • go.mod
      • go.sum
      • main.go
      • Makefile
FROM scratch as empty
FROM golang:1.20-alpine AS builder
ARG WSDISKPATHS
ARG MOD1=./
ARG MOD2=./
ARG MOD3=./
ARG MOD4=./
ARG MOD5=./
ARG MOD6=./
ARG MOD7=./
ARG MOD8=./
ARG MOD9=./
WORKDIR /ws
# Copy the additionally used modules into the soon-to-be workspace.
COPY --from=bctx1 . ${MOD1}
COPY --from=bctx2 . ${MOD2}
COPY --from=bctx3 . ${MOD3}
COPY --from=bctx4 . ${MOD4}
COPY --from=bctx5 . ${MOD5}
COPY --from=bctx6 . ${MOD6}
COPY --from=bctx7 . ${MOD7}
COPY --from=bctx8 . ${MOD8}
COPY --from=bctx9 . ${MOD9}
# Finally copy in the main module containing a main package to be build.
WORKDIR /ws/foobar
COPY go.mod go.sum ./
RUN go mod download
COPY *.go ./
# Establish the Go workspace
WORKDIR /ws
RUN go work init ${WSDISKPATHS}
RUN go build -v -o /foobar ./foobar
MAINUSE:=./foobar
EMPTYCONTEXT:=.emptyctx
NUMCONTEXTS:=9
SHELL:=/bin/bash
build:
@# find out if we are in workspace mode -- and it we are, then the list of
@# modules actually used.
@mkdir -p $(EMPTYCONTEXT); \
trap 'rm -rf -- "$(EMPTYCONTEXT)"' EXIT; \
contexts=(); \
workspace_details=$$(go work edit --json); \
if [[ $${workspace_details} ]]; then \
goworkdir=$$(dirname $$(go env GOWORK)); \
echo "found workspace" $${goworkdir}; \
diskpaths=$$(echo $${workspace_details} | jq --raw-output '.Use | .[]? | .DiskPath'); \
echo "modules used in workspace:" $${diskpaths}; \
while IFS= read -r module; do \
if [[ "$${module}" == "$(MAINUSE)" ]]; then \
echo " 🏠" $${module}; \
else \
relcontext=$$(realpath --relative-to="." $${goworkdir}/$${module}); \
contexts+=( $${relcontext} ); \
echo " 🧩" $${module} "» 📁" $${relcontext}; \
fi \
done <<< $${diskpaths}; \
else \
diskpaths="$(MAINUSE)"; \
fi; \
buildctxargs=(); \
buildargs=(); \
ctxno=1; \
for ctx in "$${contexts[@]}"; do \
buildctxargs+=( "--build-context=bctx$${ctxno}=$${ctx}" ); \
buildargs+=( "--build-arg=MOD$${ctxno}=./$$(basename ./$${ctx})/" ); \
((ctxno=ctxno+1)); \
done; \
for ((;ctxno<=$(NUMCONTEXTS);ctxno++)); do \
buildctxargs+=( "--build-context=bctx$${ctxno}=$(EMPTYCONTEXT)" ); \
done; \
echo "args:" $${buildctxargs[*]} $${buildargs[*]}; \
echo "build inside:" $${CWD}; \
docker build \
-f ./deployments/foobar/Dockerfile \
$${buildargs[@]} \
$${buildctxargs[@]} \
--build-arg=WSDISKPATHS="$$(echo $${diskpaths})" \
.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment