docker-diff 0.0.2__py3-none-any.whl → 0.0.4__py3-none-any.whl
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_diff-0.0.2.dist-info → docker_diff-0.0.4.dist-info}/METADATA +1 -1
- docker_diff-0.0.4.dist-info/RECORD +10 -0
- docker_diff-0.0.4.dist-info/entry_points.txt +2 -0
- docker_diff-0.0.4.dist-info/top_level.txt +1 -0
- docker_diff_pkg/__init__.py +10 -0
- docker_diff_pkg/_version.py +34 -0
- docker_diff.py → docker_diff_pkg/cli.py +12 -4
- docker_diff_pkg/schema.sql +138 -0
- docker_diff-0.0.2.dist-info/RECORD +0 -7
- docker_diff-0.0.2.dist-info/entry_points.txt +0 -2
- docker_diff-0.0.2.dist-info/top_level.txt +0 -1
- {docker_diff-0.0.2.dist-info → docker_diff-0.0.4.dist-info}/WHEEL +0 -0
- {docker_diff-0.0.2.dist-info → docker_diff-0.0.4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,10 @@
|
|
1
|
+
docker_diff-0.0.4.dist-info/licenses/LICENSE,sha256=awOCsWJ58m_2kBQwBUGWejVqZm6wuRtCL2hi9rfa0X4,1211
|
2
|
+
docker_diff_pkg/__init__.py,sha256=aG5WUO74Z5ax04A5iwh6thCpHcFXBsdH5v-ph-uUJuI,321
|
3
|
+
docker_diff_pkg/_version.py,sha256=QlXZ5JTjE_pgpDaeHk0GTExkc75xUZFmd0hA7kGYCJ0,704
|
4
|
+
docker_diff_pkg/cli.py,sha256=iXC5GR1jCzhmJpFCSJHSujL3vdAkXQOpeOtBJYGQy_A,15983
|
5
|
+
docker_diff_pkg/schema.sql,sha256=xI3kOohbUEzwFhmIGQs2_abN_tJn1BBdAya7tVbw6n8,5477
|
6
|
+
docker_diff-0.0.4.dist-info/METADATA,sha256=OlE5flK3eKlHJEwHEv6JnuTUSLd-rOL8qevNyUnGfkM,1654
|
7
|
+
docker_diff-0.0.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
8
|
+
docker_diff-0.0.4.dist-info/entry_points.txt,sha256=nEDTWZsgB5fRJgeXHJbXJyaHKMmKyN9Qypf3X78tosw,57
|
9
|
+
docker_diff-0.0.4.dist-info/top_level.txt,sha256=GB5Qrc3AH1pk0543cQz9SRNr5Fatrj-c0Cdp3rCvTM8,16
|
10
|
+
docker_diff-0.0.4.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
docker_diff_pkg
|
@@ -0,0 +1,10 @@
|
|
1
|
+
"""
|
2
|
+
Docker Image Comparison Database Manager
|
3
|
+
Provides functions to store and query Docker image file comparison results in SQLite
|
4
|
+
"""
|
5
|
+
|
6
|
+
from .cli import DockerImageDB, main
|
7
|
+
try:
|
8
|
+
from ._version import version as __version__
|
9
|
+
except Exception: # pragma: no cover - fallback for editable/no-scm
|
10
|
+
__version__ = "0.0.0"
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# file generated by setuptools-scm
|
2
|
+
# don't change, don't track in version control
|
3
|
+
|
4
|
+
__all__ = [
|
5
|
+
"__version__",
|
6
|
+
"__version_tuple__",
|
7
|
+
"version",
|
8
|
+
"version_tuple",
|
9
|
+
"__commit_id__",
|
10
|
+
"commit_id",
|
11
|
+
]
|
12
|
+
|
13
|
+
TYPE_CHECKING = False
|
14
|
+
if TYPE_CHECKING:
|
15
|
+
from typing import Tuple
|
16
|
+
from typing import Union
|
17
|
+
|
18
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
19
|
+
COMMIT_ID = Union[str, None]
|
20
|
+
else:
|
21
|
+
VERSION_TUPLE = object
|
22
|
+
COMMIT_ID = object
|
23
|
+
|
24
|
+
version: str
|
25
|
+
__version__: str
|
26
|
+
__version_tuple__: VERSION_TUPLE
|
27
|
+
version_tuple: VERSION_TUPLE
|
28
|
+
commit_id: COMMIT_ID
|
29
|
+
__commit_id__: COMMIT_ID
|
30
|
+
|
31
|
+
__version__ = version = '0.0.4'
|
32
|
+
__version_tuple__ = version_tuple = (0, 0, 4)
|
33
|
+
|
34
|
+
__commit_id__ = commit_id = None
|
@@ -20,10 +20,18 @@ class DockerImageDB:
|
|
20
20
|
def init_database(self):
|
21
21
|
"""Initialize the database with schema"""
|
22
22
|
with sqlite3.connect(self.db_path) as conn:
|
23
|
-
# Read
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
# Read schema using importlib.resources for proper packaging
|
24
|
+
try:
|
25
|
+
import importlib.resources as pkg_resources
|
26
|
+
with pkg_resources.files('docker_diff_pkg').joinpath('schema.sql').open('r') as f:
|
27
|
+
schema_content = f.read()
|
28
|
+
except (ImportError, AttributeError):
|
29
|
+
# Fallback for Python < 3.9
|
30
|
+
import importlib_resources as pkg_resources
|
31
|
+
with pkg_resources.files('docker_diff_pkg').joinpath('schema.sql').open('r') as f:
|
32
|
+
schema_content = f.read()
|
33
|
+
|
34
|
+
conn.executescript(schema_content)
|
27
35
|
|
28
36
|
def add_image(self, name: str, digest: str = None, size_bytes: int = None) -> int:
|
29
37
|
"""Add an image to the database, return image_id"""
|
@@ -0,0 +1,138 @@
|
|
1
|
+
-- SQLite schema for Docker image file comparison results
|
2
|
+
-- This database stores file listings and comparison results across multiple images
|
3
|
+
|
4
|
+
-- Table to store unique images being analyzed
|
5
|
+
CREATE TABLE IF NOT EXISTS images (
|
6
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
7
|
+
name TEXT NOT NULL UNIQUE, -- e.g., 'ubuntu:20.04'
|
8
|
+
digest TEXT, -- SHA256 digest if available
|
9
|
+
size_bytes INTEGER, -- Total image size
|
10
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
11
|
+
scanned_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
12
|
+
);
|
13
|
+
|
14
|
+
-- Table to store files found in each image
|
15
|
+
CREATE TABLE IF NOT EXISTS files (
|
16
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
17
|
+
image_id INTEGER NOT NULL,
|
18
|
+
file_path TEXT NOT NULL, -- Full path: /usr/bin/curl
|
19
|
+
file_size INTEGER, -- Size in bytes
|
20
|
+
file_mode TEXT, -- File permissions (optional)
|
21
|
+
modified_time INTEGER, -- Unix timestamp
|
22
|
+
file_type TEXT DEFAULT 'file', -- 'file', 'directory', 'symlink'
|
23
|
+
checksum TEXT, -- MD5/SHA256 if calculated
|
24
|
+
FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE,
|
25
|
+
UNIQUE(image_id, file_path)
|
26
|
+
);
|
27
|
+
|
28
|
+
-- Table to store comparison sessions
|
29
|
+
CREATE TABLE IF NOT EXISTS comparisons (
|
30
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
31
|
+
name TEXT, -- Optional comparison name
|
32
|
+
description TEXT, -- Optional description
|
33
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
34
|
+
);
|
35
|
+
|
36
|
+
-- Junction table linking images to comparisons
|
37
|
+
CREATE TABLE IF NOT EXISTS comparison_images (
|
38
|
+
comparison_id INTEGER NOT NULL,
|
39
|
+
image_id INTEGER NOT NULL,
|
40
|
+
FOREIGN KEY (comparison_id) REFERENCES comparisons(id) ON DELETE CASCADE,
|
41
|
+
FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE,
|
42
|
+
PRIMARY KEY (comparison_id, image_id)
|
43
|
+
);
|
44
|
+
|
45
|
+
-- Table to store file differences between images
|
46
|
+
CREATE TABLE IF NOT EXISTS file_differences (
|
47
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
48
|
+
comparison_id INTEGER NOT NULL,
|
49
|
+
file_path TEXT NOT NULL,
|
50
|
+
difference_type TEXT NOT NULL, -- 'added', 'removed', 'modified', 'common'
|
51
|
+
source_image_id INTEGER, -- Image where file exists/existed
|
52
|
+
target_image_id INTEGER, -- Image being compared to
|
53
|
+
old_size INTEGER, -- Previous size (for modified files)
|
54
|
+
new_size INTEGER, -- New size (for modified files)
|
55
|
+
size_change INTEGER, -- Calculated: new_size - old_size
|
56
|
+
FOREIGN KEY (comparison_id) REFERENCES comparisons(id) ON DELETE CASCADE,
|
57
|
+
FOREIGN KEY (source_image_id) REFERENCES images(id),
|
58
|
+
FOREIGN KEY (target_image_id) REFERENCES images(id)
|
59
|
+
);
|
60
|
+
|
61
|
+
-- Table for summary statistics per comparison
|
62
|
+
CREATE TABLE IF NOT EXISTS comparison_stats (
|
63
|
+
comparison_id INTEGER PRIMARY KEY,
|
64
|
+
total_files_compared INTEGER,
|
65
|
+
files_added INTEGER,
|
66
|
+
files_removed INTEGER,
|
67
|
+
files_modified INTEGER,
|
68
|
+
files_common INTEGER,
|
69
|
+
total_size_change INTEGER, -- Net size change in bytes
|
70
|
+
largest_file_added TEXT, -- Path to largest added file
|
71
|
+
largest_file_removed TEXT, -- Path to largest removed file
|
72
|
+
FOREIGN KEY (comparison_id) REFERENCES comparisons(id) ON DELETE CASCADE
|
73
|
+
);
|
74
|
+
|
75
|
+
-- Indexes for better query performance
|
76
|
+
CREATE INDEX IF NOT EXISTS idx_files_image_id ON files(image_id);
|
77
|
+
CREATE INDEX IF NOT EXISTS idx_files_path ON files(file_path);
|
78
|
+
CREATE INDEX IF NOT EXISTS idx_files_size ON files(file_size);
|
79
|
+
CREATE INDEX IF NOT EXISTS idx_differences_comparison ON file_differences(comparison_id);
|
80
|
+
CREATE INDEX IF NOT EXISTS idx_differences_type ON file_differences(difference_type);
|
81
|
+
CREATE INDEX IF NOT EXISTS idx_differences_path ON file_differences(file_path);
|
82
|
+
|
83
|
+
-- Views for common queries
|
84
|
+
|
85
|
+
-- View: Files unique to each image in a comparison
|
86
|
+
CREATE VIEW IF NOT EXISTS unique_files AS
|
87
|
+
SELECT
|
88
|
+
c.name as comparison_name,
|
89
|
+
i.name as image_name,
|
90
|
+
f.file_path,
|
91
|
+
f.file_size,
|
92
|
+
'unique' as status
|
93
|
+
FROM files f
|
94
|
+
JOIN images i ON f.image_id = i.id
|
95
|
+
JOIN comparison_images ci ON i.id = ci.image_id
|
96
|
+
JOIN comparisons c ON ci.comparison_id = c.id
|
97
|
+
WHERE f.file_path NOT IN (
|
98
|
+
SELECT DISTINCT f2.file_path
|
99
|
+
FROM files f2
|
100
|
+
JOIN comparison_images ci2 ON f2.image_id = ci2.image_id
|
101
|
+
WHERE ci2.comparison_id = ci.comparison_id
|
102
|
+
AND f2.image_id != f.image_id
|
103
|
+
);
|
104
|
+
|
105
|
+
-- View: Files common across all images in a comparison
|
106
|
+
CREATE VIEW IF NOT EXISTS common_files AS
|
107
|
+
SELECT
|
108
|
+
c.name as comparison_name,
|
109
|
+
f.file_path,
|
110
|
+
COUNT(DISTINCT f.image_id) as image_count,
|
111
|
+
MIN(f.file_size) as min_size,
|
112
|
+
MAX(f.file_size) as max_size,
|
113
|
+
AVG(f.file_size) as avg_size
|
114
|
+
FROM files f
|
115
|
+
JOIN images i ON f.image_id = i.id
|
116
|
+
JOIN comparison_images ci ON i.id = ci.image_id
|
117
|
+
JOIN comparisons c ON ci.comparison_id = c.id
|
118
|
+
GROUP BY c.id, f.file_path
|
119
|
+
HAVING COUNT(DISTINCT f.image_id) = (
|
120
|
+
SELECT COUNT(*)
|
121
|
+
FROM comparison_images ci2
|
122
|
+
WHERE ci2.comparison_id = c.id
|
123
|
+
);
|
124
|
+
|
125
|
+
-- View: Size comparison between images
|
126
|
+
CREATE VIEW IF NOT EXISTS image_sizes AS
|
127
|
+
SELECT
|
128
|
+
c.name as comparison_name,
|
129
|
+
i.name as image_name,
|
130
|
+
COUNT(f.id) as file_count,
|
131
|
+
SUM(f.file_size) as total_file_size,
|
132
|
+
AVG(f.file_size) as avg_file_size,
|
133
|
+
MAX(f.file_size) as largest_file_size
|
134
|
+
FROM images i
|
135
|
+
JOIN files f ON i.id = f.image_id
|
136
|
+
JOIN comparison_images ci ON i.id = ci.image_id
|
137
|
+
JOIN comparisons c ON ci.comparison_id = c.id
|
138
|
+
GROUP BY c.id, i.id;
|
@@ -1,7 +0,0 @@
|
|
1
|
-
docker_diff.py,sha256=_Jt20fhQqZQGac-PacGyV9IU10FXNoCrc6lqlZe4Gps,15516
|
2
|
-
docker_diff-0.0.2.dist-info/licenses/LICENSE,sha256=awOCsWJ58m_2kBQwBUGWejVqZm6wuRtCL2hi9rfa0X4,1211
|
3
|
-
docker_diff-0.0.2.dist-info/METADATA,sha256=BLooTmbTBpdHy8SGPYURksA-bIBvA6uxfQ-CildqBkY,1654
|
4
|
-
docker_diff-0.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
5
|
-
docker_diff-0.0.2.dist-info/entry_points.txt,sha256=Hknxh2UZBgBH5Lwe55BK5Gh813R1qHZSPIYQ9dzKQXk,49
|
6
|
-
docker_diff-0.0.2.dist-info/top_level.txt,sha256=HSDBG4y8znoDTP5jcUCH2gZZ-qiZW0_6AsIeXry71Ew,12
|
7
|
-
docker_diff-0.0.2.dist-info/RECORD,,
|
@@ -1 +0,0 @@
|
|
1
|
-
docker_diff
|
File without changes
|
File without changes
|