docker-image-cleanup 0.1.2__tar.gz → 0.1.3__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_image_cleanup-0.1.2 → docker_image_cleanup-0.1.3}/PKG-INFO +11 -1
- {docker_image_cleanup-0.1.2 → docker_image_cleanup-0.1.3}/README.md +10 -0
- {docker_image_cleanup-0.1.2 → docker_image_cleanup-0.1.3}/docker_image_cleanup/__init__.py +26 -4
- docker_image_cleanup-0.1.3/docker_image_cleanup/version.py +34 -0
- {docker_image_cleanup-0.1.2 → docker_image_cleanup-0.1.3}/pyproject.toml +21 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: docker-image-cleanup
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Clean up old Docker images from local storage with retention controls
|
|
5
5
|
Keywords: docker,cleanup,images,disk-space
|
|
6
6
|
Author: Michael Bianco
|
|
@@ -14,6 +14,11 @@ Requires-Python: >=3.11
|
|
|
14
14
|
Project-URL: Repository, https://github.com/iloveitaly/docker-image-cleanup
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
|
|
17
|
+
[](https://github.com/iloveitaly/docker-image-cleanup/releases)
|
|
18
|
+
[](https://pepy.tech/project/docker-image-cleanup)
|
|
19
|
+

|
|
20
|
+
[](https://opensource.org/licenses/MIT)
|
|
21
|
+
|
|
17
22
|
# Clean Up Images from Self-Hosted Docker Registries
|
|
18
23
|
|
|
19
24
|
If you're running a self-hosted Docker registry (using tools like [unregistry](https://github.com/psviderski/unregistry)), you'll want to clean up old images to reclaim disk space. This tool connects to your local Docker daemon and removes old images from specified repositories while keeping the ones you actually need.
|
|
@@ -123,3 +128,8 @@ The cleanup process is straightforward:
|
|
|
123
128
|
Images with multiple tags are handled intelligently. If all tags on an image would be removed, the entire image is deleted. If only some tags would be removed, those tags are untagged but the image remains.
|
|
124
129
|
|
|
125
130
|
# [MIT License](LICENSE.md)
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
*This project was created from [iloveitaly/python-package-template](https://github.com/iloveitaly/python-package-template)*
|
|
135
|
+
> theirs
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
[](https://github.com/iloveitaly/docker-image-cleanup/releases)
|
|
2
|
+
[](https://pepy.tech/project/docker-image-cleanup)
|
|
3
|
+

|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
1
6
|
# Clean Up Images from Self-Hosted Docker Registries
|
|
2
7
|
|
|
3
8
|
If you're running a self-hosted Docker registry (using tools like [unregistry](https://github.com/psviderski/unregistry)), you'll want to clean up old images to reclaim disk space. This tool connects to your local Docker daemon and removes old images from specified repositories while keeping the ones you actually need.
|
|
@@ -107,3 +112,8 @@ The cleanup process is straightforward:
|
|
|
107
112
|
Images with multiple tags are handled intelligently. If all tags on an image would be removed, the entire image is deleted. If only some tags would be removed, those tags are untagged but the image remains.
|
|
108
113
|
|
|
109
114
|
# [MIT License](LICENSE.md)
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
*This project was created from [iloveitaly/python-package-template](https://github.com/iloveitaly/python-package-template)*
|
|
119
|
+
> theirs
|
|
@@ -12,6 +12,8 @@ from pydantic import BaseModel, Field
|
|
|
12
12
|
from structlog_config import configure_logger
|
|
13
13
|
from whenever import Instant
|
|
14
14
|
|
|
15
|
+
from .version import __version__ as __version__
|
|
16
|
+
|
|
15
17
|
log = configure_logger()
|
|
16
18
|
|
|
17
19
|
|
|
@@ -48,9 +50,25 @@ def parse_docker_image(
|
|
|
48
50
|
used_image_ids: set[
|
|
49
51
|
str
|
|
50
52
|
], # Use Any due to pyright resolution issues with docker library types
|
|
51
|
-
) -> ImageInfo:
|
|
52
|
-
"""Parses docker.models.images.Image into our ImageInfo model.
|
|
53
|
-
|
|
53
|
+
) -> ImageInfo | None:
|
|
54
|
+
"""Parses docker.models.images.Image into our ImageInfo model.
|
|
55
|
+
|
|
56
|
+
Returns None if the creation date cannot be determined.
|
|
57
|
+
"""
|
|
58
|
+
created_str = image_data.attrs.get("Created")
|
|
59
|
+
if not created_str:
|
|
60
|
+
metadata = image_data.attrs.get("Metadata") or {}
|
|
61
|
+
created_str = metadata.get("LastTagTime")
|
|
62
|
+
|
|
63
|
+
if not created_str or created_str == "0001-01-01T00:00:00Z":
|
|
64
|
+
log.warning(
|
|
65
|
+
"could not determine image age, skipping",
|
|
66
|
+
image_id=image_data.id,
|
|
67
|
+
tags=image_data.tags,
|
|
68
|
+
)
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
created_instant = Instant.parse_iso(created_str)
|
|
54
72
|
image_id = image_data.id
|
|
55
73
|
|
|
56
74
|
return ImageInfo(
|
|
@@ -71,7 +89,11 @@ def get_images_to_process(
|
|
|
71
89
|
log.info("no images found for repository", repo=repo_name)
|
|
72
90
|
return []
|
|
73
91
|
|
|
74
|
-
parsed_images = [
|
|
92
|
+
parsed_images = [
|
|
93
|
+
parsed
|
|
94
|
+
for img in images
|
|
95
|
+
if (parsed := parse_docker_image(img, used_image_ids)) is not None
|
|
96
|
+
]
|
|
75
97
|
return sorted(parsed_images, key=lambda img: img.created, reverse=True)
|
|
76
98
|
|
|
77
99
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Version handling for docker-image-cleanup."""
|
|
2
|
+
|
|
3
|
+
import importlib.metadata
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def is_local_source_checkout() -> bool:
|
|
8
|
+
"""Check if the code is running from a local source checkout."""
|
|
9
|
+
package_dir = Path(__file__).resolve().parent
|
|
10
|
+
# Since this is a flat layout (module-root = ""), repo root is the parent of the package dir
|
|
11
|
+
repo_root = package_dir.parent
|
|
12
|
+
|
|
13
|
+
return (repo_root / ".git").exists() and (repo_root / "pyproject.toml").exists()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_version() -> str:
|
|
17
|
+
"""Get the version string, appending .dev if running from source."""
|
|
18
|
+
try:
|
|
19
|
+
# Try to get the version of the installed package
|
|
20
|
+
version = importlib.metadata.version("docker-image-cleanup")
|
|
21
|
+
except importlib.metadata.PackageNotFoundError:
|
|
22
|
+
# Fallback for local development if not installed
|
|
23
|
+
version = "0.1.0"
|
|
24
|
+
|
|
25
|
+
if not is_local_source_checkout():
|
|
26
|
+
return version
|
|
27
|
+
|
|
28
|
+
if version.endswith(".dev"):
|
|
29
|
+
return version
|
|
30
|
+
|
|
31
|
+
return f"{version}.dev"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
__version__ = get_version()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "docker-image-cleanup"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.3"
|
|
4
4
|
description = "Clean up old Docker images from local storage with retention controls"
|
|
5
5
|
keywords = ["docker", "cleanup", "images", "disk-space"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -15,12 +15,14 @@ dependencies = [
|
|
|
15
15
|
authors = [{ name = "Michael Bianco", email = "mike@mikebian.co" }]
|
|
16
16
|
urls = { "Repository" = "https://github.com/iloveitaly/docker-image-cleanup" }
|
|
17
17
|
|
|
18
|
+
|
|
18
19
|
# additional packaging information: https://packaging.python.org/en/latest/specifications/core-metadata/#license
|
|
19
20
|
[project.scripts]
|
|
20
21
|
docker-image-cleanup = "docker_image_cleanup:main"
|
|
21
22
|
|
|
23
|
+
|
|
22
24
|
[build-system]
|
|
23
|
-
requires = ["uv_build>=0.
|
|
25
|
+
requires = ["uv_build>=0.11.0,<0.12"]
|
|
24
26
|
build-backend = "uv_build"
|
|
25
27
|
|
|
26
28
|
[tool.uv.build-backend]
|
|
@@ -28,10 +30,24 @@ build-backend = "uv_build"
|
|
|
28
30
|
module-root = ""
|
|
29
31
|
|
|
30
32
|
[dependency-groups]
|
|
31
|
-
dev = [
|
|
33
|
+
dev = [
|
|
34
|
+
"pytest>=8.3.4",
|
|
35
|
+
"pyright[nodejs]>=1.1.408",
|
|
36
|
+
"ruff>=0.8.0",
|
|
37
|
+
"coverage>=7.13.4",
|
|
38
|
+
"pytest-cov>=7.0.0",
|
|
39
|
+
"covdefaults>=2.3.0",
|
|
40
|
+
]
|
|
32
41
|
|
|
33
42
|
[tool.pyright]
|
|
34
43
|
exclude = ["examples/", "playground/", "tmp/", ".venv/", "tests/"]
|
|
35
44
|
|
|
36
|
-
[tool.
|
|
37
|
-
|
|
45
|
+
[tool.pytest.ini_options]
|
|
46
|
+
addopts = "--cov --cov-report=term-missing --cov-report=html:tmp/htmlcov"
|
|
47
|
+
|
|
48
|
+
[tool.coverage.run]
|
|
49
|
+
plugins = ["covdefaults"]
|
|
50
|
+
source = ["docker_image_cleanup"]
|
|
51
|
+
|
|
52
|
+
[tool.coverage.report]
|
|
53
|
+
fail_under = 50
|