docker-diff 0.0.8__py3-none-any.whl → 0.0.9__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.8.dist-info → docker_diff-0.0.9.dist-info}/METADATA +1 -1
- docker_diff-0.0.9.dist-info/RECORD +10 -0
- docker_diff_pkg/_version.py +2 -2
- docker_diff_pkg/cli.py +97 -19
- docker_diff-0.0.8.dist-info/RECORD +0 -10
- {docker_diff-0.0.8.dist-info → docker_diff-0.0.9.dist-info}/WHEEL +0 -0
- {docker_diff-0.0.8.dist-info → docker_diff-0.0.9.dist-info}/entry_points.txt +0 -0
- {docker_diff-0.0.8.dist-info → docker_diff-0.0.9.dist-info}/licenses/LICENSE +0 -0
- {docker_diff-0.0.8.dist-info → docker_diff-0.0.9.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,10 @@
|
|
1
|
+
docker_diff-0.0.9.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=X2FLFwBoUmgJPsOV-1l-SxIXNSTX1TQ036Kf2j9Mc68,704
|
4
|
+
docker_diff_pkg/cli.py,sha256=zrUzf36Ld1HWW1jVneO6COnes7EOszw6ibUAUjIleyg,24989
|
5
|
+
docker_diff_pkg/schema.sql,sha256=xI3kOohbUEzwFhmIGQs2_abN_tJn1BBdAya7tVbw6n8,5477
|
6
|
+
docker_diff-0.0.9.dist-info/METADATA,sha256=xZxoN25AcmUNEq1YZ9R5w5DWAnvc6qo0H0PfSTX9iu0,4549
|
7
|
+
docker_diff-0.0.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
8
|
+
docker_diff-0.0.9.dist-info/entry_points.txt,sha256=nEDTWZsgB5fRJgeXHJbXJyaHKMmKyN9Qypf3X78tosw,57
|
9
|
+
docker_diff-0.0.9.dist-info/top_level.txt,sha256=GB5Qrc3AH1pk0543cQz9SRNr5Fatrj-c0Cdp3rCvTM8,16
|
10
|
+
docker_diff-0.0.9.dist-info/RECORD,,
|
docker_diff_pkg/_version.py
CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
28
28
|
commit_id: COMMIT_ID
|
29
29
|
__commit_id__: COMMIT_ID
|
30
30
|
|
31
|
-
__version__ = version = '0.0.
|
32
|
-
__version_tuple__ = version_tuple = (0, 0,
|
31
|
+
__version__ = version = '0.0.9'
|
32
|
+
__version_tuple__ = version_tuple = (0, 0, 9)
|
33
33
|
|
34
34
|
__commit_id__ = commit_id = None
|
docker_diff_pkg/cli.py
CHANGED
@@ -222,25 +222,103 @@ class DockerImageDB:
|
|
222
222
|
|
223
223
|
# Get file listing using docker run
|
224
224
|
try:
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
225
|
+
# Stream file listing using Docker SDK if available; fallback to streaming subprocess
|
226
|
+
# Clear existing files first (we'll insert incrementally)
|
227
|
+
self._exec("DELETE FROM files WHERE image_id = ?", (image_id,))
|
228
|
+
|
229
|
+
insert_sql = """
|
230
|
+
INSERT INTO files
|
231
|
+
(image_id, file_path, file_size, file_mode, modified_time, file_type, checksum)
|
232
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
233
|
+
"""
|
234
|
+
|
235
|
+
batch: List[Tuple[Any, ...]] = []
|
236
|
+
batch_size = 500
|
237
|
+
inserted = 0
|
238
|
+
|
239
|
+
def flush_batch():
|
240
|
+
nonlocal batch, inserted
|
241
|
+
if batch:
|
242
|
+
self._executemany(insert_sql, batch)
|
243
|
+
inserted += len(batch)
|
244
|
+
batch = []
|
245
|
+
if inserted % 1000 == 0:
|
246
|
+
print(f" Discovered {inserted} files...", flush=True)
|
247
|
+
|
248
|
+
def parse_line(line: str):
|
249
|
+
parts = line.strip().split("|")
|
250
|
+
if len(parts) >= 3:
|
251
|
+
path = parts[0]
|
252
|
+
size = int(parts[1]) if parts[1].isdigit() else 0
|
253
|
+
mtime = int(parts[2]) if parts[2].isdigit() else None
|
254
|
+
batch.append((image_id, path, size, None, mtime, "file", None))
|
255
|
+
if len(batch) >= batch_size:
|
256
|
+
flush_batch()
|
257
|
+
|
258
|
+
cmd = ['find', '/', '-type', 'f', '-exec', 'stat', '-c', '%n|%s|%Y', '{}', ';']
|
259
|
+
|
260
|
+
try:
|
261
|
+
try:
|
262
|
+
import docker # type: ignore
|
263
|
+
client = docker.from_env()
|
264
|
+
# Ensure image is available; pull only if not present
|
265
|
+
try:
|
266
|
+
client.images.get(image_name)
|
267
|
+
except Exception:
|
268
|
+
client.images.pull(image_name)
|
269
|
+
|
270
|
+
container = client.containers.create(image=image_name, command=cmd, detach=True)
|
271
|
+
try:
|
272
|
+
container.start()
|
273
|
+
remainder = ""
|
274
|
+
for chunk in container.logs(stream=True, stdout=True, stderr=False, follow=True):
|
275
|
+
if not chunk:
|
276
|
+
continue
|
277
|
+
text = chunk.decode("utf-8", errors="ignore")
|
278
|
+
remainder += text
|
279
|
+
while True:
|
280
|
+
nl = remainder.find("\n")
|
281
|
+
if nl == -1:
|
282
|
+
break
|
283
|
+
line = remainder[:nl]
|
284
|
+
remainder = remainder[nl + 1 :]
|
285
|
+
if line:
|
286
|
+
parse_line(line)
|
287
|
+
if remainder.strip():
|
288
|
+
parse_line(remainder.strip())
|
289
|
+
flush_batch()
|
290
|
+
finally:
|
291
|
+
try:
|
292
|
+
container.remove(force=True)
|
293
|
+
except Exception:
|
294
|
+
pass
|
295
|
+
|
296
|
+
print(f" Stored {inserted} files for {image_name}")
|
297
|
+
return image_id
|
298
|
+
|
299
|
+
except Exception as docker_err:
|
300
|
+
# Fallback to streaming via subprocess
|
301
|
+
proc = subprocess.Popen(
|
302
|
+
['docker', 'run', '--rm', image_name, *cmd],
|
303
|
+
stdout=subprocess.PIPE,
|
304
|
+
stderr=subprocess.PIPE,
|
305
|
+
text=True,
|
306
|
+
bufsize=1,
|
307
|
+
)
|
308
|
+
assert proc.stdout is not None
|
309
|
+
for line in proc.stdout:
|
310
|
+
if line:
|
311
|
+
parse_line(line)
|
312
|
+
proc.wait()
|
313
|
+
if proc.returncode != 0:
|
314
|
+
err = (proc.stderr.read() if proc.stderr else "").strip()
|
315
|
+
raise subprocess.SubprocessError(err or f"docker run exited with {proc.returncode}")
|
316
|
+
flush_batch()
|
317
|
+
print(f" Stored {inserted} files for {image_name}")
|
318
|
+
return image_id
|
319
|
+
|
320
|
+
except Exception as e:
|
321
|
+
raise subprocess.SubprocessError(str(e))
|
244
322
|
|
245
323
|
except subprocess.SubprocessError as e:
|
246
324
|
print(f"Error scanning {image_name}: {e}")
|
@@ -1,10 +0,0 @@
|
|
1
|
-
docker_diff-0.0.8.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=j-ar4gJGiWIawqKXhvv9hGJWLfwu0tISl-0GV97B7a0,704
|
4
|
-
docker_diff_pkg/cli.py,sha256=C6LYpgFGmiZsBZ8MO4TJKmtKMvg1EqB6qYlpilbq6pI,21549
|
5
|
-
docker_diff_pkg/schema.sql,sha256=xI3kOohbUEzwFhmIGQs2_abN_tJn1BBdAya7tVbw6n8,5477
|
6
|
-
docker_diff-0.0.8.dist-info/METADATA,sha256=7B6M1QDA_F4YtmzjQduM7KTbmP4_6_P0ii-4QklOqNs,4549
|
7
|
-
docker_diff-0.0.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
8
|
-
docker_diff-0.0.8.dist-info/entry_points.txt,sha256=nEDTWZsgB5fRJgeXHJbXJyaHKMmKyN9Qypf3X78tosw,57
|
9
|
-
docker_diff-0.0.8.dist-info/top_level.txt,sha256=GB5Qrc3AH1pk0543cQz9SRNr5Fatrj-c0Cdp3rCvTM8,16
|
10
|
-
docker_diff-0.0.8.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|