docker-devtools 0.0.1__tar.gz → 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- docker_devtools-0.1.0/PKG-INFO +414 -0
- docker_devtools-0.1.0/README.md +386 -0
- docker_devtools-0.1.0/cmd/docker-devtools/context.go +145 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/cmd/docker-devtools/image.go +12 -1
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/cmd/docker-devtools/main.go +14 -3
- docker_devtools-0.1.0/cmd/docker-devtools/registry.go +111 -0
- docker_devtools-0.1.0/cmd/docker-devtools/registry_test.go +26 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/hatch_build.py +1 -1
- docker_devtools-0.1.0/internal/imgref/dockerfile.go +220 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/internal/imgref/imgref.go +4 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/internal/imgref/imgref_test.go +18 -5
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/internal/imgref/scan.go +17 -2
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/internal/imgupdate/tagpolicy.go +38 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/internal/imgupdate/tagpolicy_test.go +43 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/internal/imgupdate/update_test.go +40 -5
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/internal/plugin/plugin.go +1 -1
- docker_devtools-0.1.0/internal/registry/netrc.go +124 -0
- docker_devtools-0.1.0/internal/registry/netrc_test.go +47 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/internal/registry/registry.go +12 -2
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/scripts/completions.sh +3 -3
- docker_devtools-0.1.0/scripts/conformance.sh +86 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/scripts/test-fresh-clone.sh +1 -1
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/src/docker_devtools/__init__.py +2 -2
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/src/docker_devtools/_version.py +2 -2
- docker_devtools-0.1.0/testdata/dctx/copysubset/all.golden +17 -0
- docker_devtools-0.1.0/testdata/dctx/copysubset/context/.dockerignore +1 -0
- docker_devtools-0.1.0/testdata/dctx/copysubset/context/Dockerfile +6 -0
- docker_devtools-0.1.0/testdata/dctx/copysubset/context/excluded.txt +1 -0
- docker_devtools-0.1.0/testdata/dctx/copysubset/context/heavy/blob.bin +1 -0
- docker_devtools-0.1.0/testdata/dctx/copysubset/context/keep.txt +1 -0
- docker_devtools-0.1.0/testdata/dctx/copysubset/context/sub/inside.txt +1 -0
- docker_devtools-0.1.0/testdata/dctx/copysubset/context/sub/nested/deep.txt +1 -0
- docker_devtools-0.1.0/testdata/dctx/copysubset/context/unreferenced.txt +1 -0
- docker_devtools-0.1.0/testdata/dctx/copysubset/ignored.golden +7 -0
- docker_devtools-0.1.0/testdata/dctx/copysubset/included.golden +11 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/lowercase/all.golden +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/lowercase/ignored.golden +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/lowercase/included.golden +1 -0
- docker_devtools-0.1.0/testdata/dctx/nesteddockerfile/all.golden +13 -0
- docker_devtools-0.1.0/testdata/dctx/nesteddockerfile/case.json +1 -0
- docker_devtools-0.1.0/testdata/dctx/nesteddockerfile/context/docker/Dockerfile.dev.dockerignore +1 -0
- docker_devtools-0.1.0/testdata/dctx/nesteddockerfile/ignored.golden +7 -0
- docker_devtools-0.1.0/testdata/dctx/nesteddockerfile/included.golden +12 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/none/all.golden +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/none/ignored.golden +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/none/included.golden +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/order/all.golden +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/order/ignored.golden +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/order/included.golden +1 -0
- docker_devtools-0.1.0/testdata/dctx/outofcontext/all.golden +12 -0
- docker_devtools-0.1.0/testdata/dctx/outofcontext/build.Dockerfile.dockerignore +1 -0
- docker_devtools-0.1.0/testdata/dctx/outofcontext/case.json +1 -0
- docker_devtools-0.1.0/testdata/dctx/outofcontext/context/.dockerignore +1 -0
- docker_devtools-0.1.0/testdata/dctx/outofcontext/context/beside-only +1 -0
- docker_devtools-0.1.0/testdata/dctx/outofcontext/context/build.Dockerfile.dockerignore +1 -0
- docker_devtools-0.1.0/testdata/dctx/outofcontext/context/decoy-only +1 -0
- docker_devtools-0.1.0/testdata/dctx/outofcontext/context/keep +1 -0
- docker_devtools-0.1.0/testdata/dctx/outofcontext/context/root-only +1 -0
- docker_devtools-0.1.0/testdata/dctx/outofcontext/ignored.golden +7 -0
- docker_devtools-0.1.0/testdata/dctx/outofcontext/included.golden +11 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/percent/all.golden +1 -0
- docker_devtools-0.1.0/testdata/dctx/percent/case.json +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/percent/ignored.golden +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/percent/included.golden +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/perdockerfile/all.golden +1 -0
- docker_devtools-0.1.0/testdata/dctx/perdockerfile/case.json +1 -0
- docker_devtools-0.1.0/testdata/dctx/perdockerfile/context/.dockerignore +1 -0
- docker_devtools-0.1.0/testdata/dctx/perdockerfile/context/only-default +1 -0
- docker_devtools-0.1.0/testdata/dctx/perdockerfile/context/only-prj1 +1 -0
- docker_devtools-0.1.0/testdata/dctx/perdockerfile/context/other +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/perdockerfile/ignored.golden +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/perdockerfile/included.golden +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/pycache/all.golden +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/pycache/ignored.golden +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/pycache/included.golden +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/reinclude/all.golden +1 -0
- docker_devtools-0.1.0/testdata/dctx/reinclude/context/Dockerfile +2 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/reinclude/ignored.golden +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/reinclude/included.golden +1 -0
- docker_devtools-0.1.0/testdata/dctx/targetstage/all.golden +12 -0
- docker_devtools-0.1.0/testdata/dctx/targetstage/case.json +1 -0
- docker_devtools-0.1.0/testdata/dctx/targetstage/context/Dockerfile +7 -0
- docker_devtools-0.1.0/testdata/dctx/targetstage/context/app/main.go +1 -0
- docker_devtools-0.1.0/testdata/dctx/targetstage/context/vendor/big.a +1 -0
- docker_devtools-0.1.0/testdata/dctx/targetstage/context/vendor/big.b +1 -0
- docker_devtools-0.1.0/testdata/dctx/targetstage/ignored.golden +6 -0
- docker_devtools-0.1.0/testdata/dctx/targetstage/included.golden +9 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/trailing/all.golden +1 -0
- docker_devtools-0.1.0/testdata/dctx/trailing/context/Dockerfile +2 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/trailing/ignored.golden +1 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/trailing/included.golden +1 -0
- docker_devtools-0.1.0/testdata/dctx/unreachedstage/all.golden +12 -0
- docker_devtools-0.1.0/testdata/dctx/unreachedstage/context/Dockerfile +7 -0
- docker_devtools-0.1.0/testdata/dctx/unreachedstage/context/app/main.go +1 -0
- docker_devtools-0.1.0/testdata/dctx/unreachedstage/context/vendor/big.a +1 -0
- docker_devtools-0.1.0/testdata/dctx/unreachedstage/context/vendor/big.b +1 -0
- docker_devtools-0.1.0/testdata/dctx/unreachedstage/ignored.golden +6 -0
- docker_devtools-0.1.0/testdata/dctx/unreachedstage/included.golden +8 -0
- docker_devtools-0.1.0/testdata/imageref/argbase/Dockerfile +25 -0
- docker_devtools-0.1.0/testdata/imageref/argbase/expected.txt +5 -0
- docker_devtools-0.0.1/PKG-INFO +0 -227
- docker_devtools-0.0.1/README.md +0 -199
- docker_devtools-0.0.1/cmd/docker-devtools/context.go +0 -166
- docker_devtools-0.0.1/internal/imgref/dockerfile.go +0 -119
- docker_devtools-0.0.1/scripts/conformance.sh +0 -66
- docker_devtools-0.0.1/testdata/dctx/percent/case.json +0 -1
- docker_devtools-0.0.1/testdata/dctx/perdockerfile/case.json +0 -1
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/.gitignore +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/LICENSE +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/go.mod +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/go.sum +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/internal/imgref/compose.go +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/internal/imgupdate/update.go +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/internal/plugin/plugin_test.go +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/internal/rewrite/rewrite.go +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/internal/rewrite/rewrite_test.go +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/pyproject.toml +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/scripts/build-wheels.sh +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/scripts/commit-msg-lint.sh +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/scripts/prose-lint.sh +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/src/docker_devtools/__main__.py +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/src/docker_devtools/_find.py +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/src/docker_devtools/py.typed +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/lowercase/context/dockerfile +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/lowercase/context/dockerfile.dockerignore +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/lowercase/context/keep +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/lowercase/context/secret +0 -0
- {docker_devtools-0.0.1/testdata/dctx/perdockerfile → docker_devtools-0.1.0/testdata/dctx/nesteddockerfile}/context/.dockerignore +0 -0
- /docker_devtools-0.0.1/testdata/dctx/none/context/Dockerfile → /docker_devtools-0.1.0/testdata/dctx/nesteddockerfile/context/docker/Dockerfile.dev +0 -0
- /docker_devtools-0.0.1/testdata/dctx/none/context/a.txt → /docker_devtools-0.1.0/testdata/dctx/nesteddockerfile/context/only-default +0 -0
- /docker_devtools-0.0.1/testdata/dctx/none/context/b.txt → /docker_devtools-0.1.0/testdata/dctx/nesteddockerfile/context/only-nested +0 -0
- {docker_devtools-0.0.1/testdata/dctx/perdockerfile → docker_devtools-0.1.0/testdata/dctx/nesteddockerfile}/context/other +0 -0
- {docker_devtools-0.0.1/testdata/dctx/order → docker_devtools-0.1.0/testdata/dctx/none}/context/Dockerfile +0 -0
- /docker_devtools-0.0.1/testdata/dctx/perdockerfile/context/only-prj1 → /docker_devtools-0.1.0/testdata/dctx/none/context/a.txt +0 -0
- /docker_devtools-0.0.1/testdata/dctx/perdockerfile/context/only-default → /docker_devtools-0.1.0/testdata/dctx/none/context/b.txt +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/order/context/.dockerignore +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/order/context/CHANGELOG.md +0 -0
- {docker_devtools-0.0.1/testdata/dctx/pycache → docker_devtools-0.1.0/testdata/dctx/order}/context/Dockerfile +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/order/context/README.md +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/order/context/docs/guide.md +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/order/context/main.go +0 -0
- /docker_devtools-0.0.1/testdata/dctx/percent/context/we%ird → /docker_devtools-0.1.0/testdata/dctx/outofcontext/build.Dockerfile +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/percent/context/nope +0 -0
- /docker_devtools-0.0.1/testdata/dctx/perdockerfile/context/Prj1 → /docker_devtools-0.1.0/testdata/dctx/percent/context/we%ird +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/percent/context/we%ird.dockerignore +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/percent/context/yes +0 -0
- /docker_devtools-0.0.1/testdata/dctx/reinclude/context/Dockerfile → /docker_devtools-0.1.0/testdata/dctx/perdockerfile/context/Prj1 +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/perdockerfile/context/Prj1.dockerignore +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/pycache/context/.dockerignore +0 -0
- {docker_devtools-0.0.1/testdata/dctx/trailing → docker_devtools-0.1.0/testdata/dctx/pycache}/context/Dockerfile +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/pycache/context/a/b/keep.py +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/pycache/context/main.py +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/pycache/context/pkg/mod.py +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/reinclude/context/.dockerignore +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/reinclude/context/app.js +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/reinclude/context/node_modules/drop/index.js +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/reinclude/context/node_modules/keep/index.js +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/trailing/context/.dockerignore +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/trailing/context/build/out.bin +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/trailing/context/build/sub/deep.bin +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/dctx/trailing/context/src.go +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/imageref/compose/compose.yaml +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/imageref/compose/expected.txt +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/imageref/edge/Dockerfile +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/imageref/edge/Dockerfile.pinned +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/imageref/edge/expected.txt +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/imageref/multistage/Dockerfile +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/testdata/imageref/multistage/expected.txt +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/tests/__init__.py +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/tests/api_test.py +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/tests/binary_test.py +0 -0
- {docker_devtools-0.0.1 → docker_devtools-0.1.0}/tests/conftest.py +0 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: docker-devtools
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Work on the Dockerfiles, Compose files and build context in a repository.
|
|
5
|
+
Project-URL: Documentation, https://github.com/FlavioAmurrioCS/docker-devtools#readme
|
|
6
|
+
Project-URL: Issues, https://github.com/FlavioAmurrioCS/docker-devtools/issues
|
|
7
|
+
Project-URL: Source, https://github.com/FlavioAmurrioCS/docker-devtools
|
|
8
|
+
Author-email: Flavio Amurrio <25621374+FlavioAmurrioCS@users.noreply.github.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: build-context,buildkit,docker,docker-compose,dockerfile,dockerignore,pre-commit
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Go
|
|
16
|
+
Classifier: Programming Language :: Python
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
23
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
24
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
25
|
+
Classifier: Topic :: Utilities
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# docker-devtools
|
|
30
|
+
|
|
31
|
+
Work on the Docker files in a repository: the build context a Dockerfile would
|
|
32
|
+
send, and the image references it and your Compose files point at.
|
|
33
|
+
|
|
34
|
+
```console
|
|
35
|
+
$ docker-devtools image-refs ls
|
|
36
|
+
Dockerfile:1 python:3.11-slim
|
|
37
|
+
compose.yaml:3 nginx:1.25-alpine
|
|
38
|
+
|
|
39
|
+
$ docker-devtools image-refs update --tag-policy same-pattern --dry-run
|
|
40
|
+
Dockerfile:1 python:3.11-slim -> python:3.14-slim (tag 3.11-slim -> 3.14-slim)
|
|
41
|
+
compose.yaml:3 nginx:1.25-alpine -> nginx:1.31-alpine (tag 1.25-alpine -> 1.31-alpine)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Why another one
|
|
45
|
+
|
|
46
|
+
Renovate and Dependabot already update image references, and they do it well.
|
|
47
|
+
They run as bots against a repository and open pull requests. This one runs on
|
|
48
|
+
your machine and edits the files in place. It is fast enough for a pre-commit
|
|
49
|
+
hook, so a stale base image gets caught before it is ever committed.
|
|
50
|
+
|
|
51
|
+
Where the semantics are Docker's, this defers to Docker's own code:
|
|
52
|
+
|
|
53
|
+
| Step | Package |
|
|
54
|
+
| --- | --- |
|
|
55
|
+
| Parse Dockerfiles | `moby/buildkit/frontend/dockerfile/parser` and `instructions` |
|
|
56
|
+
| Parse image references | `google/go-containerregistry/pkg/name` |
|
|
57
|
+
| Talk to registries | `google/go-containerregistry/pkg/v1/remote` |
|
|
58
|
+
| Match .dockerignore rules | `moby/patternmatcher` |
|
|
59
|
+
| Walk a build context | `tonistiigi/fsutil`, the package BuildKit sends contexts with |
|
|
60
|
+
|
|
61
|
+
None of the `.dockerignore` semantics are reimplemented here, and CI checks
|
|
62
|
+
that rather than asserting it: for every fixture, `scripts/conformance.sh`
|
|
63
|
+
builds `FROM scratch` with `COPY . /`, exports the image as a tarball, and
|
|
64
|
+
diffs the tar members against what `build-context ls` reports.
|
|
65
|
+
|
|
66
|
+
## Install
|
|
67
|
+
|
|
68
|
+
```console
|
|
69
|
+
$ uvx docker-devtools image-refs ls # no install
|
|
70
|
+
$ pipx run docker-devtools image-refs ls # no install
|
|
71
|
+
$ uv tool install docker-devtools
|
|
72
|
+
$ pip install docker-devtools
|
|
73
|
+
$ mise use ubi:FlavioAmurrioCS/docker-devtools
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Prebuilt binaries are attached to each
|
|
77
|
+
[release](https://github.com/FlavioAmurrioCS/docker-devtools/releases). With a
|
|
78
|
+
Go toolchain:
|
|
79
|
+
|
|
80
|
+
```console
|
|
81
|
+
$ go install github.com/FlavioAmurrioCS/docker-devtools/cmd/docker-devtools@latest
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Reading and updating files doesn't require a Docker installation or a running
|
|
85
|
+
daemon.
|
|
86
|
+
Registry lookups authenticate with the same `~/.docker/config.json` the docker
|
|
87
|
+
CLI uses.
|
|
88
|
+
|
|
89
|
+
The build context is what BuildKit would send, because `docker build` forwards to
|
|
90
|
+
buildx by default. The legacy builder never learned `<dockerfile>.dockerignore`
|
|
91
|
+
at all. Its `ReadDockerignore` opens only `<context>/.dockerignore`, so a
|
|
92
|
+
`DOCKER_BUILDKIT=0` build legitimately disagrees with this listing whenever a
|
|
93
|
+
per-Dockerfile ignore file is in play.
|
|
94
|
+
|
|
95
|
+
## As a pre-commit hook
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
repos:
|
|
99
|
+
- repo: https://github.com/FlavioAmurrioCS/docker-devtools
|
|
100
|
+
rev: v0.0.1
|
|
101
|
+
hooks:
|
|
102
|
+
- id: docker-image-check
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The hooks are scoped to `Dockerfile*`, `Containerfile*` and
|
|
106
|
+
`(docker-)?compose*.ya?ml` already:
|
|
107
|
+
|
|
108
|
+
| Hook | What it does |
|
|
109
|
+
| --- | --- |
|
|
110
|
+
| `docker-image-check` | Fails when a tag could move. Writes nothing. |
|
|
111
|
+
| `docker-image-update` | Moves tags in place, under `same-pattern`. |
|
|
112
|
+
| `docker-image-pin` | Appends or refreshes the `@sha256` digest. |
|
|
113
|
+
|
|
114
|
+
Each one reaches the registry, so a hook is only as fast as the tag listing it
|
|
115
|
+
asks for. `docker-image-check` is the one to reach for first: it reports without
|
|
116
|
+
touching the tree.
|
|
117
|
+
|
|
118
|
+
pre-commit installs a `repo:` from source, and building this one compiles the Go
|
|
119
|
+
binary, so the machine running the hook needs a Go toolchain. Somewhere that
|
|
120
|
+
cannot have one, install the published wheel instead and point a `local` hook at
|
|
121
|
+
the `docker-devtools` it puts on PATH.
|
|
122
|
+
|
|
123
|
+
## Usage
|
|
124
|
+
|
|
125
|
+
```text
|
|
126
|
+
docker-devtools build-context ls [PATH] list the files Docker would send
|
|
127
|
+
docker-devtools image-refs ls [PATH...] list every image reference, with file and line
|
|
128
|
+
docker-devtools image-refs update [PATH...] rewrite references in place
|
|
129
|
+
docker-devtools registry tags REF list a repository's tags, newest last
|
|
130
|
+
docker-devtools install-docker-plugin register as "docker devtools"
|
|
131
|
+
docker-devtools version print the version (also --version)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Each group's `ls` is also the default, so `image-refs Dockerfile` and
|
|
135
|
+
`build-context .` work without it. The cost is that a mistyped verb reads as a
|
|
136
|
+
path: `image-refs updte` reports `stat updte: no such file or directory`.
|
|
137
|
+
|
|
138
|
+
`ls` is also spelled `list`. The groups are named away from `context` and
|
|
139
|
+
`image` on purpose: `docker context ls` lists CLI endpoints and `docker image ls`
|
|
140
|
+
lists local images, and neither is anything like what these do.
|
|
141
|
+
|
|
142
|
+
`PATH` is the build context directory for `build-context ls`, and files or
|
|
143
|
+
directories to scan for `image-refs`. Every command takes `--json`, which is the
|
|
144
|
+
same document the Python API parses.
|
|
145
|
+
|
|
146
|
+
`build-context ls` lists directories in their own right, the way `docker build`
|
|
147
|
+
sends them, so a listing piped through `-0` into `xargs` gets both. It also
|
|
148
|
+
takes:
|
|
149
|
+
|
|
150
|
+
```text
|
|
151
|
+
-f, --file PATH Dockerfile to derive <path>.dockerignore from
|
|
152
|
+
--ignored list what the ignore file excluded instead
|
|
153
|
+
--all list everything, prefixed + for sent and - for excluded
|
|
154
|
+
--size prefix each path with its size in bytes
|
|
155
|
+
--why append the ignore-file rule that decided each path
|
|
156
|
+
--target STAGE build as if --target were given, changing what is reached
|
|
157
|
+
--whole-context list everything the ignore rules permit
|
|
158
|
+
--summary print totals to stderr after the listing
|
|
159
|
+
-0, --zero separate paths with NUL
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### What actually gets sent
|
|
163
|
+
|
|
164
|
+
BuildKit transfers only the paths the Dockerfile names. Every `COPY` and `ADD`
|
|
165
|
+
source becomes a follow path on the build context, so a Dockerfile that copies
|
|
166
|
+
one file transfers one file, however large the directory around it:
|
|
167
|
+
|
|
168
|
+
```console
|
|
169
|
+
$ docker-devtools build-context ls --summary
|
|
170
|
+
taplo.toml
|
|
171
|
+
transferred: 1 file, 1.7 KiB
|
|
172
|
+
permitted: 24626 files, 458.5 MiB
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The gap between those two lines is the point. `permitted` is what the ignore
|
|
176
|
+
rules allow through, which is also what gets sent when something copies the
|
|
177
|
+
context whole: `COPY . /` switches the filter off. `--whole-context` lists that
|
|
178
|
+
set, and `--target` picks the stage, since a stage the build never reaches never
|
|
179
|
+
reads its sources.
|
|
180
|
+
|
|
181
|
+
### Which Dockerfile, and which .dockerignore
|
|
182
|
+
|
|
183
|
+
A context needs a Dockerfile. With no `-f`, `Dockerfile` is looked for and then
|
|
184
|
+
the lowercase `dockerfile`, which is the whole candidate set BuildKit uses;
|
|
185
|
+
there is no `Containerfile` fallback. When neither is there the command fails,
|
|
186
|
+
because `docker build` would too, and a listing of a build that cannot run
|
|
187
|
+
describes nothing.
|
|
188
|
+
|
|
189
|
+
A context with no `.dockerignore` at all says so, since that is the reason
|
|
190
|
+
`.git` and a virtualenv turn up in the listing:
|
|
191
|
+
|
|
192
|
+
```console
|
|
193
|
+
$ docker-devtools build-context ls
|
|
194
|
+
warning: no .dockerignore in .; every file is sent
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
`-f` takes a path, resolved from your working directory rather than from the
|
|
198
|
+
context. That is the rule `docker build -f` follows, and the Dockerfile may sit
|
|
199
|
+
outside the context entirely. The ignore file is the one **beside the
|
|
200
|
+
Dockerfile**, `<path>.dockerignore`, falling back to `<context>/.dockerignore`.
|
|
201
|
+
The first wins outright. They never merge.
|
|
202
|
+
|
|
203
|
+
```console
|
|
204
|
+
$ docker-devtools build-context ls -f docker/build.Dockerfile ./app
|
|
205
|
+
# reads docker/build.Dockerfile.dockerignore, else app/.dockerignore
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
`--why` says which rule decided each path, which is usually the question:
|
|
209
|
+
|
|
210
|
+
```console
|
|
211
|
+
$ docker-devtools build-context ls --all --why
|
|
212
|
+
+ app.js
|
|
213
|
+
- node_modules/drop/index.js <- .dockerignore:1 node_modules
|
|
214
|
+
+ node_modules/keep/index.js <- .dockerignore:2 !node_modules/keep
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Updating image references
|
|
218
|
+
|
|
219
|
+
What changes is split by how much judgement it needs.
|
|
220
|
+
|
|
221
|
+
`--pin-digest` resolves the current tag to a digest and appends it, turning
|
|
222
|
+
`nginx:1.29` into `nginx:1.29@sha256:…`. It doesn't decide anything about versions, so it is
|
|
223
|
+
reversible and safe to run anywhere.
|
|
224
|
+
|
|
225
|
+
`--tag-policy` moves the tag. The default, `same-pattern`, moves only the last
|
|
226
|
+
component and keeps the suffix, so how specific your tag is decides how far it
|
|
227
|
+
may move:
|
|
228
|
+
|
|
229
|
+
| Current tag | same-pattern | minor | patch | latest |
|
|
230
|
+
| --- | --- | --- | --- | --- |
|
|
231
|
+
| `3.12-slim` | `3.13-slim` | `3.13-slim` | `3.12.7-slim` | `4.0-slim` |
|
|
232
|
+
| `3.12.1-slim` | `3.12.7-slim` | `3.13.0-slim` | `3.12.7-slim` | `4.0-slim` |
|
|
233
|
+
| `latest` | no change | no change | no change | no change |
|
|
234
|
+
|
|
235
|
+
Only `same-pattern` keeps the shape of a tag. The other three compare version
|
|
236
|
+
components, and a component the current tag omits counts as zero, so `patch` can
|
|
237
|
+
turn `3.12-slim` into `3.12.7-slim`: a tag that pinned a minor line now pins a
|
|
238
|
+
patch.
|
|
239
|
+
|
|
240
|
+
No policy ever changes the suffix: `-alpine` and `-slim` are different images,
|
|
241
|
+
and swapping them would change your base distribution without saying so. Tags
|
|
242
|
+
with no version, such as `latest` or `bookworm`, are never moved, because there
|
|
243
|
+
is no ordering to move along.
|
|
244
|
+
|
|
245
|
+
Add `--dry-run` to see the plan without writing, and `--fail-on-diff` to exit
|
|
246
|
+
non-zero when anything would change, which is what makes it useful in CI.
|
|
247
|
+
|
|
248
|
+
`--fail-on-diff` reports on the plan, not on the writing, so on its own it
|
|
249
|
+
still rewrites the files and then exits non-zero. Pair it with `--dry-run` for a
|
|
250
|
+
check that leaves the tree alone, which is what the `docker-image-check` hook
|
|
251
|
+
does.
|
|
252
|
+
|
|
253
|
+
### Base images behind an ARG
|
|
254
|
+
|
|
255
|
+
A Dockerfile that opens `ARG BASE_IMAGE=debian:13-slim` and then
|
|
256
|
+
`FROM "${BASE_IMAGE}"` still has a real base image, and it is updatable. The
|
|
257
|
+
`FROM` is expanded through the ARG defaults with BuildKit's own lexer, the same
|
|
258
|
+
way `docker build` does it, and the reference is reported on the **ARG** line,
|
|
259
|
+
because that is the only text an update can rewrite:
|
|
260
|
+
|
|
261
|
+
```console
|
|
262
|
+
$ docker-devtools image-refs ls --unresolved
|
|
263
|
+
Dockerfile:1 debian:13-slim
|
|
264
|
+
Dockerfile:5 "${BASE_IMAGE}" (resolved from ARG BASE_IMAGE on line 1)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
This holds only when the ARG default is the whole reference, spelled out on its
|
|
268
|
+
own line. `ARG VERSION=12` with `FROM debian:${VERSION}-slim` stays unresolved:
|
|
269
|
+
the image is `debian:12-slim`, which is written nowhere, and rewriting would
|
|
270
|
+
mean splicing a bare tag into the middle of a line.
|
|
271
|
+
|
|
272
|
+
### What it will not touch
|
|
273
|
+
|
|
274
|
+
Some references cannot be resolved to an image, and those are reported rather
|
|
275
|
+
than guessed at. Pass `--unresolved` to `image-refs ls` to see them:
|
|
276
|
+
|
|
277
|
+
- `FROM builder`, where `builder` is an earlier stage
|
|
278
|
+
- `COPY --from=0`, which indexes a stage
|
|
279
|
+
- `FROM $BASE` where the ARG has no default, or supplies only part of the
|
|
280
|
+
reference
|
|
281
|
+
- `FROM scratch`, which is the empty base rather than a registry image
|
|
282
|
+
- Compose values built from variables, such as `${REGISTRY}/app:latest`
|
|
283
|
+
|
|
284
|
+
A listing says how many it withheld, so a file whose every reference is one of
|
|
285
|
+
these does not simply vanish from the output.
|
|
286
|
+
|
|
287
|
+
### Editing in place
|
|
288
|
+
|
|
289
|
+
An update splices the new reference into the exact byte range the parser
|
|
290
|
+
reported. It never re-encodes the file, so comments, quoting style, anchors and
|
|
291
|
+
whitespace all survive:
|
|
292
|
+
|
|
293
|
+
```yaml
|
|
294
|
+
image: "nginx:1.29-alpine" # keep this comment and the quotes
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
becomes
|
|
298
|
+
|
|
299
|
+
```yaml
|
|
300
|
+
image: "nginx:1.31-alpine" # keep this comment and the quotes
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
If a byte range no longer holds the text the parse said it held, the update
|
|
304
|
+
fails instead of writing. A rewrite that has drifted from the parse is a bug,
|
|
305
|
+
and corrupting the file would hide it.
|
|
306
|
+
|
|
307
|
+
## Listing tags
|
|
308
|
+
|
|
309
|
+
```console
|
|
310
|
+
$ docker-devtools registry tags python:3.12-slim
|
|
311
|
+
3.11-slim
|
|
312
|
+
* 3.12-slim
|
|
313
|
+
3.13-slim
|
|
314
|
+
3.14-slim
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Given a tag, the listing keeps only tags sharing its suffix and marks the one
|
|
318
|
+
you named, so it answers what that reference could move to. `-alpine` and
|
|
319
|
+
`-slim` stay apart for the same reason no policy crosses between them. Pass
|
|
320
|
+
`--all` for everything, and `--json` to script against.
|
|
321
|
+
|
|
322
|
+
The ordering is computed here, not taken from the registry. The OCI
|
|
323
|
+
distribution spec requires the tags endpoint to return
|
|
324
|
+
"lexical (i.e. case-insensitive alphanumeric order)" and carries no timestamps,
|
|
325
|
+
which is the order that puts `3.10` before `3.9`. There is no portable way to
|
|
326
|
+
sort by publication date: reading one costs three requests per tag and is
|
|
327
|
+
meaningless for reproducible builds, which set it to the epoch. `--sort lexical`
|
|
328
|
+
hands the registry's own order back.
|
|
329
|
+
|
|
330
|
+
Credentials come from `~/.docker/config.json`, including the `credsStore` and
|
|
331
|
+
`credHelpers` entries that shell out to `docker-credential-*`, and from
|
|
332
|
+
`$DOCKER_CONFIG`, `$REGISTRY_AUTH_FILE` and Podman's `containers/auth.json`.
|
|
333
|
+
Behind all of those, `~/.netrc` is consulted, or `$NETRC` when it is set.
|
|
334
|
+
|
|
335
|
+
## Shell completion
|
|
336
|
+
|
|
337
|
+
The binary emits a [usage](https://usage.jdx.dev) spec describing its own
|
|
338
|
+
command tree, and the `usage` CLI turns that into completions for bash, zsh,
|
|
339
|
+
fish, powershell and nushell:
|
|
340
|
+
|
|
341
|
+
```console
|
|
342
|
+
$ mise use usage
|
|
343
|
+
$ usage g completion zsh docker-devtools --usage-cmd 'docker-devtools --usage-spec' --install
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
The generated scripts call back to `usage` at completion time, so it has to stay
|
|
347
|
+
on your PATH. `mise run completions` regenerates all five, plus a markdown
|
|
348
|
+
reference, into `build/`.
|
|
349
|
+
|
|
350
|
+
## As a Docker CLI plugin
|
|
351
|
+
|
|
352
|
+
```console
|
|
353
|
+
$ docker-devtools install-docker-plugin
|
|
354
|
+
$ docker devtools image-refs ls
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
This symlinks the binary into `~/.docker/cli-plugins/`, so upgrading the binary
|
|
358
|
+
upgrades the plugin. Windows gets a copy instead, having no dependable
|
|
359
|
+
unprivileged symlink. `DOCKER_CONFIG` moves the directory, and `--system`
|
|
360
|
+
installs for every user.
|
|
361
|
+
|
|
362
|
+
The subcommand is `devtools` because Docker validates plugin names against
|
|
363
|
+
`^[a-z][a-z0-9]*$` and refuses to load anything else. Python wheels cannot do
|
|
364
|
+
this step at install time: they have no post-install hook, and
|
|
365
|
+
`~/.docker/cli-plugins/` sits outside every Python install path.
|
|
366
|
+
|
|
367
|
+
## Python API
|
|
368
|
+
|
|
369
|
+
The wheel bundles the binary and a typed wrapper.
|
|
370
|
+
|
|
371
|
+
```python
|
|
372
|
+
from docker_devtools import image_ls
|
|
373
|
+
from docker_devtools import image_update
|
|
374
|
+
|
|
375
|
+
for ref in image_ls(".").resolved():
|
|
376
|
+
print(f"{ref.path}:{ref.line}", ref.repository, ref.tag)
|
|
377
|
+
|
|
378
|
+
report = image_update(".", pin_digest=True, dry_run=True)
|
|
379
|
+
for change in report.changes:
|
|
380
|
+
print(change.old, "->", change.new, f"({change.reason})")
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
`image_update` defaults to `dry_run=True`, so calling it by accident cannot
|
|
384
|
+
rewrite a repository. The CLI defaults the other way, as a CLI should: `image
|
|
385
|
+
update` writes unless you pass `--dry-run`.
|
|
386
|
+
|
|
387
|
+
The wrapper shells out to the bundled binary, which the wheel installs onto
|
|
388
|
+
PATH. Where that directory isn't on PATH, `python -m docker_devtools` runs it
|
|
389
|
+
anyway, and `DOCKER_DEVTOOLS_BINARY` points at a specific build.
|
|
390
|
+
|
|
391
|
+
## Development
|
|
392
|
+
|
|
393
|
+
`mise.toml` defines the tools and the tasks.
|
|
394
|
+
|
|
395
|
+
```console
|
|
396
|
+
$ mise run build # compile into ./build
|
|
397
|
+
$ mise run test # go test + pytest
|
|
398
|
+
$ mise run lint # pre-commit across the repo
|
|
399
|
+
$ mise run prose # vale-ai-tells across all markdown
|
|
400
|
+
$ mise run conformance # diff context listing against real docker build
|
|
401
|
+
$ mise run completions # regenerate completions and docs
|
|
402
|
+
$ mise run wheels # every platform wheel into ./dist
|
|
403
|
+
$ mise run test-clone # verify a fresh clone in a container
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
Registry behaviour is tested against `go-containerregistry`'s in-process
|
|
407
|
+
registry, so the suite doesn't touch the network or carry recorded fixtures.
|
|
408
|
+
|
|
409
|
+
## License
|
|
410
|
+
|
|
411
|
+
MIT. See [LICENSE](LICENSE).
|
|
412
|
+
|
|
413
|
+
`src/docker_devtools/_find.py` adapts the binary-discovery search order from
|
|
414
|
+
[uv](https://github.com/astral-sh/uv), which is MIT OR Apache-2.0.
|