diff --git a/distroless/private/flatten.sh b/distroless/private/flatten.sh index 3fdcbd9..25b6762 100755 --- a/distroless/private/flatten.sh +++ b/distroless/private/flatten.sh @@ -35,16 +35,25 @@ if [[ "$deduplicate" == "True" ]]; then # number of occurrences of each path, and the second pass determines whether each entry is the final (or only) # occurrence of that path. - $bsdtar --confirmation "$@" 2< <("${awk}" '{ - count[$1]++; + $bsdtar --confirmation "$@" 2< <("${awk}" ' + function normalize(p) { + # Strip leading "./" and trailing "/" so that "./etc/" and "etc/" are treated as the same path. + sub(/^\.\//, "", p) + sub(/\/$/, "", p) + return p + } + { + key = normalize($1) + count[key]++ files[NR] = $1 + keys[NR] = key } END { ORS="" for (i=1; i<=NR; i++) { - seen[files[i]]++ + seen[keys[i]]++ keep="n" - if (count[files[i]] == seen[files[i]]) { + if (count[keys[i]] == seen[keys[i]]) { keep="y" } for (j=0; j<31; j++) print keep diff --git a/examples/flatten/BUILD.bazel b/examples/flatten/BUILD.bazel index 67d7dd5..a4dbfca 100644 --- a/examples/flatten/BUILD.bazel +++ b/examples/flatten/BUILD.bazel @@ -120,3 +120,42 @@ examples/flatten/dir/sub/ examples/flatten/dir/sub/content.txt """, ) + +# Flatten with deduplication across mixed path formats ("./etc/" vs "etc/"). +# Tars produced by different tools use inconsistent path prefixes; deduplication +# must normalize them so the merged layer contains each path only once. +tar( + name = "dotslash_tar", + compress = "gzip", + mtree = [ + "./etc/ type=dir uid=0 gid=0 mode=0755 time=0.0", + "./etc/sub/ type=dir uid=0 gid=0 mode=0755 time=0.0", + ], +) + +tar( + name = "nodotslash_tar", + compress = "gzip", + mtree = [ + "etc/ type=dir uid=0 gid=0 mode=0755 time=0.0", + "etc/sub/ type=dir uid=0 gid=0 mode=0755 time=0.0", + ], +) + +flatten( + name = "flatten_dedup_normalize", + deduplicate = True, + tars = [ + ":dotslash_tar", + ":nodotslash_tar", + ], +) + +assert_tar_listing( + name = "test_flatten_dedup_normalize", + actual = "flatten_dedup_normalize", + expected = """\ +etc/ +etc/sub/ +""", +)