Skip to content

Commit b62881e

Browse files
committed
fix: docker backend
1 parent 6c362df commit b62881e

3 files changed

Lines changed: 90 additions & 65 deletions

File tree

ddiff.py

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,29 @@ def _request_manifest(tag):
7878
with urllib.request.urlopen(req) as response:
7979
manifest = response.read().decode()
8080
content_type = (response.getheader("Content-Type") or "").split(";")[0]
81+
82+
if content_type in [DOCKER_MANIFEST_LIST_V2, OCI_INDEX_V1]:
83+
data = json.loads(manifest)
84+
manifests = data.get("manifests", [])
85+
target_digest = None
86+
87+
# Try to find amd64/linux architecture
88+
for m in manifests:
89+
plat = m.get("platform", {})
90+
if plat.get("architecture") == "amd64" and plat.get("os") == "linux":
91+
target_digest = m.get("digest")
92+
break
93+
94+
# Fallback to first available manifest if amd64/linux is missing
95+
if not target_digest and manifests:
96+
target_digest = manifests[0].get("digest")
97+
98+
if target_digest:
99+
print_debug(f"Resolved manifest list to digest: {target_digest}")
100+
return _request_manifest(f"{repo}@{target_digest}")
101+
else:
102+
print_error("Failed to find valid manifest in the manifest list/index.")
103+
81104
return manifest, content_type
82105
except urllib.error.HTTPError as e:
83106
print_error(f"HTTP error: {e.code} - {e.reason} ({manifest_url})")
@@ -86,8 +109,6 @@ def _request_manifest(tag):
86109

87110
def _validate_manifest_media_type(manifest):
88111
media_type = manifest.get("mediaType", "")
89-
if media_type in [DOCKER_MANIFEST_LIST_V2, OCI_INDEX_V1]:
90-
print_error("Manifest list/index is not supported yet. Please provide a single image manifest tag.")
91112
if media_type and media_type not in SUPPORTED_MANIFEST_TYPES:
92113
print_error(f"Unsupported manifest mediaType: {media_type}")
93114
return media_type
@@ -315,22 +336,30 @@ def load_image(base_tag, image_tarball):
315336
def build_image(build_args):
316337
target_tag = None
317338
dockerfile_str = "Dockerfile"
339+
do_diff = False
318340
for i, arg in enumerate(build_args):
319341
if arg == "-t" and i + 1 < len(build_args):
320342
target_tag = build_args[i + 1]
321343
if arg == "-f" and i + 1 < len(build_args):
322344
dockerfile_str = build_args[i + 1]
323-
dockerfile_path = f"{build_args[-1]}/{dockerfile_str}"
324-
325-
with open(dockerfile_path) as f:
326-
base_tag = f.read().split("\n")[0].strip().replace("FROM ", "")
327-
345+
if arg == "--diff":
346+
do_diff = True
347+
build_args[i] = ""
348+
if container_runtime == "docker":
349+
build_args.append("--provenance=false")
328350
assert not target_tag is None
329351

330-
print_debug(f"Building image with tag: {target_tag}\nwe will diff image blobs of {target_tag} from {base_tag}")
352+
# Fall back to docker build
353+
print_debug(f"Building image with tag: {target_tag}")
331354
run_command(f"{container_runtime} build " + " ".join(build_args))
332-
print_debug(f"Diff image blobs of {target_tag} from {base_tag}")
333-
diff_image(base_tag, target_tag)
355+
356+
# ddiff diff
357+
if do_diff:
358+
dockerfile_path = f"{build_args[-1]}/{dockerfile_str}"
359+
with open(dockerfile_path) as f:
360+
base_tag = f.read().split("\n")[0].strip().replace("FROM ", "")
361+
print_debug(f"Diff image blobs of {target_tag} from {base_tag}")
362+
diff_image(base_tag, target_tag)
334363

335364
def list_blobs(tag):
336365
push_images([tag])

test/dockerfiles/Dockerfile.delta

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
FROM ddiff-test/base
2-
RUN apt-get update && apt-get install -y --no-install-recommends tmux && rm -rf /var/lib/apt/lists/*
2+
RUN echo "Hello DockerDiff!" > hello_ddiff.txt

test/test_ddiff_backends.sh

Lines changed: 50 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ log() {
3636
run_step() {
3737
local logfile="$1"
3838
shift
39-
39+
4040
mkdir -p "$(dirname "$logfile")"
4141
{
4242
echo "+ $*"
@@ -52,7 +52,7 @@ run_step() {
5252
wait_for_registry() {
5353
local port="$1"
5454
for _ in $(seq 1 30); do
55-
if curl -fsS "http://127.0.0.1:${port}/v2/" >/dev/null 2>&1; then
55+
if curl -fsS "http://localhost:${port}/v2/" >/dev/null 2>&1; then
5656
return 0
5757
fi
5858
sleep 1
@@ -81,10 +81,10 @@ cleanup_case() {
8181
local work_dir="$4"
8282

8383
set +e
84-
"$runtime" rm -f "$diff_container" >/dev/null 2>&1
85-
"$runtime" rm -f "$load_container" >/dev/null 2>&1
86-
"$runtime" rmi "$DELTA_TAG" >/dev/null 2>&1
87-
"$runtime" rmi "$BASE_TAG" >/dev/null 2>&1
84+
"$runtime" rm -f "$diff_container" >/dev/null
85+
"$runtime" rm -f "$load_container" >/dev/null
86+
"$runtime" rmi "$DELTA_TAG" >/dev/null
87+
"$runtime" rmi "$BASE_TAG" >/dev/null
8888
rm -f "$ARCHIVE_PATH"
8989
rm -rf "$work_dir"
9090
set -e
@@ -114,53 +114,47 @@ run_case() {
114114
local logs_dir="$work_dir/logs"
115115
local diff_registry_dir="$work_dir/registry_diff"
116116
local load_registry_dir="$work_dir/registry_load"
117-
local diff_container="ddiff-${name}-diff"
118-
local load_container="ddiff-${name}-load"
117+
local diff_container="ddiff-diff"
118+
local load_container="ddiff-load"
119+
120+
# Set environment variables
121+
if [[ -n "$force_key" ]]; then
122+
export "$force_key=$force_value"
123+
fi
119124

125+
# Clear the environment
120126
rm -rf "$work_dir"
121127
mkdir -p "$logs_dir" "$diff_registry_dir" "$load_registry_dir"
122128

123129
log "[$name] prerequisites"
124-
if ! have_all_commands "${required[@]}"; then
125-
SKIPPED=$((SKIPPED + 1))
126-
echo "SKIP: $name"
127-
cleanup_case "$runtime" "$diff_container" "$load_container" "$work_dir"
128-
return 0
129-
fi
130+
cleanup_case "$runtime" "$diff_container" "$load_container" "$work_dir"
130131

131132
local status=0
132133

133134
log "[$name] build base image"
134135
run_step "$logs_dir/build-base.log" \
135-
"$runtime" build -t "$BASE_TAG" -f "$DOCKERFILES_DIR/Dockerfile.base" "$TEST_DIR" || status=$?
136+
ddiff build -t "$BASE_TAG" -f "$DOCKERFILES_DIR/Dockerfile.base" "$TEST_DIR" || status=$?
136137

137138
if [[ "$status" -eq 0 ]]; then
138139
log "[$name] build delta image"
139140
run_step "$logs_dir/build-delta.log" \
140-
"$runtime" build -t "$DELTA_TAG" -f "$DOCKERFILES_DIR/Dockerfile.delta" "$TEST_DIR" || status=$?
141+
ddiff build -t "$DELTA_TAG" -f "$DOCKERFILES_DIR/Dockerfile.delta" "$TEST_DIR" || status=$?
141142
fi
142-
143143
if [[ "$status" -eq 0 ]]; then
144144
log "[$name] start diff registry"
145+
export DDIFF_URL="http://localhost:${diff_port}"
145146
run_step "$logs_dir/registry-diff-start.log" \
146-
"$runtime" run -d --name "$diff_container" -p "${diff_port}:5000" -v "$diff_registry_dir:/var/lib/registry" "$REGISTRY_IMAGE" || status=$?
147+
"$runtime" run -d --name "$diff_container" -p "${diff_port}:5000" "$REGISTRY_IMAGE" || status=$?
147148
fi
148-
149+
149150
if [[ "$status" -eq 0 ]]; then
150151
wait_for_registry "$diff_port" || { echo "registry not ready on ${diff_port}" | tee "$logs_dir/registry-diff-ready.log"; status=1; }
151152
fi
152-
153+
153154
if [[ "$status" -eq 0 ]]; then
154155
log "[$name] ddiff diff"
155-
if [[ -n "$force_key" ]]; then
156-
run_step "$logs_dir/ddiff-diff.log" \
157-
env DDIFF_URL="http://127.0.0.1:${diff_port}" "$force_key=$force_value" \
158-
python3 "$DDIFF_PY" diff "$BASE_TAG" "$DELTA_TAG" || status=$?
159-
else
160-
run_step "$logs_dir/ddiff-diff.log" \
161-
env DDIFF_URL="http://127.0.0.1:${diff_port}" \
162-
python3 "$DDIFF_PY" diff "$BASE_TAG" "$DELTA_TAG" || status=$?
163-
fi
156+
run_step "$logs_dir/ddiff-diff.log" \
157+
ddiff diff "$BASE_TAG" "$DELTA_TAG" || status=$?
164158
fi
165159

166160
if [[ "$status" -eq 0 && ! -f "$ARCHIVE_PATH" ]]; then
@@ -175,37 +169,25 @@ run_case() {
175169
mkdir -p "$diff_registry_dir"
176170

177171
log "[$name] start fresh load registry"
172+
export DDIFF_URL="http://localhost:${load_port}"
178173
run_step "$logs_dir/registry-load-start.log" \
179-
"$runtime" run -d --name "$load_container" -p "${load_port}:5000" -v "$load_registry_dir:/var/lib/registry" "$REGISTRY_IMAGE" || status=$?
174+
"$runtime" run -d --name "$load_container" -p "${load_port}:5000" "$REGISTRY_IMAGE" || status=$?
180175
fi
181-
176+
182177
if [[ "$status" -eq 0 ]]; then
183178
wait_for_registry "$load_port" || { echo "registry not ready on ${load_port}" | tee "$logs_dir/registry-load-ready.log"; status=1; }
184179
fi
185180

186181
if [[ "$status" -eq 0 ]]; then
187182
log "[$name] ddiff load"
188-
if [[ -n "$force_key" ]]; then
189-
run_step "$logs_dir/ddiff-load.log" \
190-
env DDIFF_URL="http://127.0.0.1:${load_port}" "$force_key=$force_value" \
191-
python3 "$DDIFF_PY" load "$ARCHIVE_PATH" || status=$?
192-
else
193-
run_step "$logs_dir/ddiff-load.log" \
194-
env DDIFF_URL="http://127.0.0.1:${load_port}" \
195-
python3 "$DDIFF_PY" load "$ARCHIVE_PATH" || status=$?
196-
fi
197-
fi
198-
199-
if [[ "$status" -eq 0 && -n "$expect_marker" ]]; then
200-
if ! grep -q "$expect_marker" "$logs_dir/ddiff-diff.log"; then
201-
echo "missing mode marker: $expect_marker" | tee "$logs_dir/mode-check.log"
202-
status=1
203-
fi
183+
run_step "$logs_dir/ddiff-load.log" \
184+
python3 "$DDIFF_PY" load "$ARCHIVE_PATH" || status=$?
204185
fi
205186

187+
# exit 0
206188
if [[ "$status" -eq 0 ]]; then
207189
log "[$name] verify loaded image"
208-
run_step "$logs_dir/verify.log" "$runtime" run --rm "$DELTA_TAG" tmux -V || status=$?
190+
run_step "$logs_dir/verify.log" "$runtime" run --rm "$DELTA_TAG" cat hello_ddiff.txt || status=$?
209191
fi
210192

211193
cleanup_case "$runtime" "$diff_container" "$load_container" "$work_dir"
@@ -265,19 +247,33 @@ run_selected_cases() {
265247
;;
266248
esac
267249

268-
[[ "$target" == "all" || "$target" == "docker" ]] && run_docker_mode
269-
[[ "$target" == "all" || "$target" == "docker-skopeo" ]] && run_docker_skopeo_mode
270-
[[ "$target" == "all" || "$target" == "podman" ]] && run_podman_mode
250+
if [[ "$target" == "all" || "$target" == "docker" ]]; then
251+
run_docker_mode
252+
fi
253+
if [[ "$target" == "all" || "$target" == "docker-skopeo" ]]; then
254+
run_docker_skopeo_mode
255+
fi
256+
if [[ "$target" == "all" || "$target" == "podman" ]]; then
257+
run_podman_mode
258+
fi
271259
}
272260

273261
main() {
274262
mkdir -p "$TMP_ROOT"
275263
run_selected_cases "${1:-all}"
276264

277265
echo ""
278-
echo "Total: $TOTAL, Passed: $PASSED, Failed: $FAILED, Skipped: $SKIPPED"
279-
280-
[[ "$FAILED" -eq 0 ]]
266+
echo "==================== TEST RESULTS ===================="
267+
echo "Total cases run: $TOTAL"
268+
echo "Passed: $PASSED"
269+
echo "Failed: $FAILED"
270+
echo "Skipped: $SKIPPED"
271+
echo "======================================================"
272+
273+
if [[ "$FAILED" -ne 0 ]]; then
274+
exit 1
275+
fi
276+
exit 0
281277
}
282278

283279
main "$@"

0 commit comments

Comments
 (0)