dockerimg: use a default image from a public registry
If the LLM chooses our default alpine Go image, we save some
work by instead starting from a sketch docker image pushed
to ghcr.io.
diff --git a/dockerimg/createdockerfile.go b/dockerimg/createdockerfile.go
index 7178b94..a9e8738 100644
--- a/dockerimg/createdockerfile.go
+++ b/dockerimg/createdockerfile.go
@@ -22,13 +22,29 @@
for _, path := range slices.Sorted(maps.Keys(initFiles)) {
fmt.Fprintf(h, "%s\n%s\n\n", path, initFiles[path])
}
- fmt.Fprintf(h, "docker template\n%s\n", dockerfileBase)
+ fmt.Fprintf(h, "docker template 1\n%s\n", dockerfileCustomTmpl)
+ fmt.Fprintf(h, "docker template 2\n%s\n", dockerfileDefaultTmpl)
return hex.EncodeToString(h.Sum(nil))
}
+// DefaultImage is intended to ONLY be used by the pushdockerimg.go script.
+func DefaultImage() (name, dockerfile, hash string) {
+ buf := new(bytes.Buffer)
+ err := template.Must(template.New("dockerfile").Parse(dockerfileBaseTmpl)).Execute(buf, map[string]string{
+ "From": defaultBaseImg,
+ })
+ if err != nil {
+ panic(err)
+ }
+ return dockerfileDefaultImg, buf.String(), hashInitFiles(nil)
+}
+
+const dockerfileDefaultImg = "ghcr.io/boldsoftware/sketch:v1"
+const defaultBaseImg = "golang:1.24.2-alpine3.21"
+
// TODO: add semgrep, prettier -- they require node/npm/etc which is more complicated than apk
// If/when we do this, add them into the list of available tools in bash.go.
-const dockerfileBase = `FROM {{.From}}
+const dockerfileBaseTmpl = `FROM {{.From}}
RUN apk add bash git make jq sqlite gcc musl-dev linux-headers npm nodejs go github-cli ripgrep fzf python3 curl vim
@@ -41,9 +57,9 @@
RUN go install mvdan.cc/gofumpt@latest
RUN mkdir -p /root/.cache/sketch/webui
+`
-{{.ExtraCmds}}
-
+const dockerfileFragment = `
ARG GIT_USER_EMAIL
ARG GIT_USER_NAME
@@ -56,7 +72,18 @@
WORKDIR /app{{.SubDir}}
RUN if [ -f go.mod ]; then go mod download; fi
-CMD ["/bin/sketch"]`
+{{.ExtraCmds}}
+
+CMD ["/bin/sketch"]
+`
+
+// dockerfileCustomTmpl is the dockerfile template used when the LLM
+// chooses a custom base image.
+const dockerfileCustomTmpl = dockerfileBaseTmpl + dockerfileFragment
+
+// dockerfileDefaultTmpl is the dockerfile used when the LLM went with
+// the defaultBaseImg. In this case, we use a pre-canned image.
+const dockerfileDefaultTmpl = "FROM " + dockerfileDefaultImg + "\n" + dockerfileFragment
// createDockerfile creates a Dockerfile for a git repo.
// It expects the relevant initFiles to have been provided.
@@ -136,10 +163,10 @@
The parameters to dockerfile fill out the From and ExtraCmds
template variables in the following Go template:
-` + "```\n" + dockerfileBase + "\n```" + `
+` + "```\n" + dockerfileCustomTmpl + "\n```" + `
In particular:
-- Assume it is primarily a Go project. For a minimal env, prefer 1.24.2-alpine3.21 as a base image.
+- Assume it is primarily a Go project. For a minimal env, prefer ` + defaultBaseImg + ` as a base image.
- If any python is needed at all, switch to using a python alpine image as a the base and apk add go.
Favor using uv, and use one of these base images, depending on the preferred python version:
ghcr.io/astral-sh/uv:python3.13-alpine
@@ -149,7 +176,8 @@
- Python env setup is challenging and often no required, so any RUN commands involving python tooling should be written to let docker build continue if there is a failure.
- Include any tools particular to this repository that can be inferred from the given context.
- Append || true to any apk add commands in case the package does not exist.
-- Do not expose any ports.
+- Do NOT expose any ports.
+- Do NOT generate any CMD or ENTRYPOINT extra commands.
`,
}},
}
@@ -181,8 +209,16 @@
return "", fmt.Errorf("no dockerfile returned")
}
+ tmpl := dockerfileCustomTmpl
+ if dockerfileFROM == defaultBaseImg {
+ // Because the LLM has chosen the image we recommended, we
+ // can use a pre-canned image of our entire template, which
+ // saves a lot of build time.
+ tmpl = dockerfileDefaultTmpl
+ }
+
buf := new(bytes.Buffer)
- err = template.Must(template.New("dockerfile").Parse(dockerfileBase)).Execute(buf, map[string]string{
+ err = template.Must(template.New("dockerfile").Parse(tmpl)).Execute(buf, map[string]string{
"From": dockerfileFROM,
"ExtraCmds": dockerfileExtraCmds,
"InitFilesHash": hashInitFiles(initFiles),