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:
parent
985b99513b
commit
1f2fd93117
23 changed files with 60 additions and 60 deletions
|
|
@ -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.
|
||||
|
|
@ -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,
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
module github.com/imjasonh/terraform-playground/py-image-builder
|
||||
module github.com/imjasonh/terraform-playground/pymage
|
||||
|
||||
go 1.22.2
|
||||
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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,
|
||||
|
|
@ -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
|
||||
|
|
@ -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:
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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) {
|
||||
|
|
@ -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__":
|
||||
|
|
@ -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"}
|
||||
|
|
@ -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
|
||||
|
|
@ -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) {
|
||||
|
|
@ -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() {
|
||||
Loading…
Add table
Add a link
Reference in a new issue