1
0
Fork 0
mirror of https://github.com/imjasonh/terraform-playground synced 2026-07-07 23:35:16 +00:00

Rename py-image-builder to pymage (module, imports, CLI, workflow, docs)

Co-authored-by: Jason Hall <imjasonh@users.noreply.github.com>
This commit is contained in:
Cursor Agent 2026-06-10 13:30:05 +00:00
parent 985b99513b
commit 1f2fd93117
No known key found for this signature in database
23 changed files with 60 additions and 60 deletions

View file

@ -1,10 +1,10 @@
name: py-image-builder
name: pymage
on:
pull_request:
paths:
- "py-image-builder/**"
- ".github/workflows/py-image-builder.yaml"
- "pymage/**"
- ".github/workflows/pymage.yaml"
jobs:
ci:
@ -26,29 +26,29 @@ jobs:
- uses: actions/setup-go@v6.2.0
with:
go-version-file: py-image-builder/go.mod
cache-dependency-path: py-image-builder/go.sum
go-version-file: pymage/go.mod
cache-dependency-path: pymage/go.sum
- uses: actions/setup-python@v6.2.0
with:
python-version: "3.12"
- name: Run tests
working-directory: py-image-builder
working-directory: pymage
run: go test -race ./...
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v9.2.0
with:
working-directory: py-image-builder
working-directory: pymage
version: latest
- name: Build the CLI
working-directory: py-image-builder
run: go build -o pib .
working-directory: pymage
run: go build -o pymage .
- name: Prepare a demo app, wheelhouse, and hashed lock
working-directory: py-image-builder
working-directory: pymage
run: |
set -euo pipefail
mkdir -p demo/wheelhouse demo/src
@ -57,7 +57,7 @@ jobs:
import click
import six
print("py-image-builder demo OK | six=%s click=%s" % (six.__version__, click.__version__))
print("pymage demo OK | six=%s click=%s" % (six.__version__, click.__version__))
PY
python -m pip install --upgrade pip
@ -75,10 +75,10 @@ jobs:
cat demo/requirements.txt
- name: Build and push the image (no Docker daemon involved)
working-directory: py-image-builder
working-directory: pymage
run: |
set -euo pipefail
./pib build \
./pymage build \
--base "$BASE" \
--lock demo/requirements.txt \
--find-links demo/wheelhouse \
@ -92,14 +92,14 @@ jobs:
cat demo/sbom.json
- name: Verify the build is reproducible (same digest twice)
working-directory: py-image-builder
working-directory: pymage
run: |
set -euo pipefail
common=(--base "$BASE" --lock demo/requirements.txt --find-links demo/wheelhouse \
--source demo/src --python "$PYTHON" \
--entrypoint python --entrypoint /app/app.py --insecure --push=false)
d1=$(./pib build "${common[@]}" --print-digest)
d2=$(./pib build "${common[@]}" --print-digest)
d1=$(./pymage build "${common[@]}" --print-digest)
d2=$(./pymage build "${common[@]}" --print-digest)
echo "digest #1: $d1"
echo "digest #2: $d2"
if [ "$d1" != "$d2" ]; then
@ -114,13 +114,13 @@ jobs:
docker pull "$REGISTRY/demo:v1"
out=$(docker run --rm "$REGISTRY/demo:v1")
echo "container output: $out"
echo "$out" | grep -q "py-image-builder demo OK"
echo "$out" | grep -q "pymage demo OK"
- name: Install crane (for manifest inspection)
run: go install github.com/google/go-containerregistry/cmd/crane@v0.19.2
- name: Adding a dependency reuses existing layers (only one new layer)
working-directory: py-image-builder
working-directory: pymage
run: |
set -euo pipefail
# Resolve one more pure-python wheel and append it to the lock.
@ -129,7 +129,7 @@ jobs:
echo "idna==3.7 --hash=sha256:$(sha256sum "$idna_whl" | awk '{print $1}')" >> demo/requirements.txt
# Build the new image (now with the extra dependency) and push it.
./pib build \
./pymage build \
--base "$BASE" \
--lock demo/requirements.txt \
--find-links demo/wheelhouse \
@ -143,7 +143,7 @@ jobs:
docker pull "$REGISTRY/demo:v2"
out=$(docker run --rm "$REGISTRY/demo:v2")
echo "container output: $out"
echo "$out" | grep -q "py-image-builder demo OK"
echo "$out" | grep -q "pymage demo OK"
# Compare layer sets: every layer from v1 must still be present in v2
# (unchanged digests), and v2 must have exactly one more layer.

View file

@ -1,4 +1,4 @@
# `py-image-builder` — a docker-less, layer-aware Python image builder
# `pymage` — a docker-less, layer-aware Python image builder
> Status: **Design / plan** (no code yet). This document proposes the architecture
> and an incremental implementation plan. Comments and pushback welcome.
@ -226,7 +226,7 @@ pure-python layers), and publish an **image index** referencing each arch manife
- **A single CLI**, like `ko` — no daemon, no server, no infra. It builds and
pushes (or saves) an image in one command:
```
py-image-builder build \
pymage build \
--base cgr.dev/chainguard/python@sha256:... \
--lock requirements.txt \
--source ./ \
@ -238,7 +238,7 @@ pure-python layers), and publish an **image index** referencing each arch manife
`--push=false` (build to local OCI layout / `--tarball`), `--print-digest`
(compute the would-be digest offline, no push), and standard ggcr keychain
auth (Docker config / cloud helpers) so it works in CI without extra setup.
- New self-contained module dir `py-image-builder/` with its own `go.mod` and
- New self-contained module dir `pymage/` with its own `go.mod` and
`README.md`, mirroring repo conventions. **No `main.tf` / Cloud Run** — this is
a standalone CLI, not a hosted service.
@ -246,7 +246,7 @@ pure-python layers), and publish an **image index** referencing each arch manife
Each phase is independently useful and reviewable.
1. **Skeleton + deterministic tar.** New `py-image-builder/` Go module; a function
1. **Skeleton + deterministic tar.** New `pymage/` Go module; a function
that writes a normalized, reproducible tar and a round-trip determinism test
(same input ⇒ same bytes ⇒ same digest).
2. **Wheel → layer.** Parse a wheel zip, lay out files into the fixed prefix,

View file

@ -1,4 +1,4 @@
# `py-image-builder`
# `pymage`
A **docker-less**, layer-aware container image builder for Python applications,
in the spirit of [`ko`](https://github.com/ko-build/ko). It builds and pushes
@ -23,7 +23,7 @@ See [`DESIGN.md`](./DESIGN.md) for the full rationale.
## Usage
```
py-image-builder build \
pymage build \
--base cgr.dev/chainguard/python:latest \
--lock requirements.txt \ # pinned + hashed (pip-compile / uv pip compile --generate-hashes)
--find-links ./wheelhouse \ # directory of resolved .whl files

View file

@ -1,4 +1,4 @@
// Package e2e exercises py-image-builder end to end against a real local OCI
// Package e2e exercises pymage end to end against a real local OCI
// registry (go-containerregistry's in-process registry served over HTTP — a
// genuine registry daemon, just in the test process). No Docker is required.
//
@ -30,10 +30,10 @@ import (
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/build"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/testwheel"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/wheel"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/wheelhouse"
"github.com/imjasonh/terraform-playground/pymage/internal/build"
"github.com/imjasonh/terraform-playground/pymage/internal/testwheel"
"github.com/imjasonh/terraform-playground/pymage/internal/wheel"
"github.com/imjasonh/terraform-playground/pymage/internal/wheelhouse"
)
// uploadCounter records the set of blob digests that were actually uploaded

View file

@ -1,4 +1,4 @@
module github.com/imjasonh/terraform-playground/py-image-builder
module github.com/imjasonh/terraform-playground/pymage
go 1.22.2

View file

@ -20,9 +20,9 @@ import (
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/ptar"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/wheel"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/wheelhouse"
"github.com/imjasonh/terraform-playground/pymage/internal/ptar"
"github.com/imjasonh/terraform-playground/pymage/internal/wheel"
"github.com/imjasonh/terraform-playground/pymage/internal/wheelhouse"
)
// LayerStrategy controls how dependency layers are partitioned.
@ -362,7 +362,7 @@ func mergeEnv(base []string, layout wheel.Layout, extra []string) []string {
func history(createdBy string) v1.History {
return v1.History{
Created: v1.Time{Time: epoch()},
CreatedBy: "py-image-builder: " + createdBy,
CreatedBy: "pymage: " + createdBy,
}
}

View file

@ -11,9 +11,9 @@ import (
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/testwheel"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/wheel"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/wheelhouse"
"github.com/imjasonh/terraform-playground/pymage/internal/testwheel"
"github.com/imjasonh/terraform-playground/pymage/internal/wheel"
"github.com/imjasonh/terraform-playground/pymage/internal/wheelhouse"
)
func layerPaths(t *testing.T, l v1.Layer) map[string]bool {

View file

@ -1,4 +1,4 @@
// Package cli implements the py-image-builder command line.
// Package cli implements the pymage command line.
package cli
import (
@ -15,17 +15,17 @@ import (
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/spf13/cobra"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/build"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/lock"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/sbom"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/wheel"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/wheelhouse"
"github.com/imjasonh/terraform-playground/pymage/internal/build"
"github.com/imjasonh/terraform-playground/pymage/internal/lock"
"github.com/imjasonh/terraform-playground/pymage/internal/sbom"
"github.com/imjasonh/terraform-playground/pymage/internal/wheel"
"github.com/imjasonh/terraform-playground/pymage/internal/wheelhouse"
)
// Root returns the root cobra command.
func Root() *cobra.Command {
root := &cobra.Command{
Use: "py-image-builder",
Use: "pymage",
Short: "Docker-less, layer-aware Python container image builder",
SilenceUsage: true,
SilenceErrors: true,

View file

@ -14,7 +14,7 @@ import (
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/testwheel"
"github.com/imjasonh/terraform-playground/pymage/internal/testwheel"
)
// TestBuildCommandEndToEnd drives the cobra `build` command exactly as a user

View file

@ -1,7 +1,7 @@
// Package ptar builds deterministic (reproducible) tar archives and turns them
// into OCI layers.
//
// Reproducibility is the load-bearing property of py-image-builder: identical
// Reproducibility is the load-bearing property of pymage: identical
// inputs must yield byte-identical layers so that their content-addressed
// digests match and registries can dedupe/skip/mount them. To guarantee that,
// every tar we emit:

View file

@ -8,7 +8,7 @@ import (
"encoding/json"
"sort"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/wheelhouse"
"github.com/imjasonh/terraform-playground/pymage/internal/wheelhouse"
)
type doc struct {

View file

@ -5,7 +5,7 @@ import (
"strings"
"testing"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/wheelhouse"
"github.com/imjasonh/terraform-playground/pymage/internal/wheelhouse"
)
func TestGenerateDeterministicAndSorted(t *testing.T) {

View file

@ -21,7 +21,7 @@ import (
"sort"
"strings"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/ptar"
"github.com/imjasonh/terraform-playground/pymage/internal/ptar"
)
// Layout describes where files are installed inside the image filesystem.
@ -181,7 +181,7 @@ func (w *Wheel) consoleScripts(bin string) ([]ptar.File, error) {
for _, n := range names {
module, attr := eps[n].module, eps[n].attr
script := fmt.Sprintf(`#!/usr/bin/env python
# Generated by py-image-builder.
# Generated by pymage.
import sys
from %s import %s
if __name__ == "__main__":

View file

@ -4,8 +4,8 @@ import (
"strings"
"testing"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/ptar"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/testwheel"
"github.com/imjasonh/terraform-playground/pymage/internal/ptar"
"github.com/imjasonh/terraform-playground/pymage/internal/testwheel"
)
var layout = Layout{Prefix: "/app/.venv", PythonTag: "python3.12"}

View file

@ -17,8 +17,8 @@ import (
"sort"
"strings"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/lock"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/wheel"
"github.com/imjasonh/terraform-playground/pymage/internal/lock"
"github.com/imjasonh/terraform-playground/pymage/internal/wheel"
)
// ResolvedWheel pairs a pinned requirement with the wheel file that satisfies

View file

@ -3,8 +3,8 @@ package wheelhouse
import (
"testing"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/lock"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/testwheel"
"github.com/imjasonh/terraform-playground/pymage/internal/lock"
"github.com/imjasonh/terraform-playground/pymage/internal/testwheel"
)
func TestResolveSortedAndVerified(t *testing.T) {

View file

@ -1,4 +1,4 @@
// Command py-image-builder builds and pushes OCI images for Python applications
// Command pymage builds and pushes OCI images for Python applications
// without a Docker daemon, in the spirit of ko.
//
// It installs each resolved wheel into its own deterministic, content-addressed
@ -10,7 +10,7 @@ import (
"fmt"
"os"
"github.com/imjasonh/terraform-playground/py-image-builder/internal/cli"
"github.com/imjasonh/terraform-playground/pymage/internal/cli"
)
func main() {