fix: flatten nested single-child directories after extraction

Archives like Debian_13_VMG.7z contain nested single-child dirs:
  Debian_13_VMG_LinuxVMImages.COM/Debian_13_VMG_LinuxVMImages.COM/

_flatten_nested() collapses these chains until files sit directly
in the parent, eliminating the double-nesting issue.
This commit is contained in:
Claus Lohmar 2026-07-23 10:09:25 +00:00
parent a28e2af674
commit 9dcde5d022

View file

@ -110,18 +110,38 @@ def extract_if_needed(filename: str) -> Path:
# If the archive had a single top-level directory matching the stem, use it
expected_dir = STAGING_IN / stem
if expected_dir in new_items and expected_dir.is_dir():
return expected_dir
result = expected_dir
else:
# Collect scattered files into a subdirectory
out_dir = STAGING_IN / stem
out_dir.mkdir(parents=True, exist_ok=True)
for item in new_items:
shutil.move(str(item), str(out_dir / item.name))
result = out_dir
# Otherwise, collect scattered files into a subdirectory
out_dir = STAGING_IN / stem
out_dir.mkdir(parents=True, exist_ok=True)
for item in new_items:
dest = out_dir / item.name
if item.is_dir():
shutil.move(str(item), str(dest))
else:
shutil.move(str(item), str(dest))
return out_dir
# Flatten nested single-child directories (archive quirk)
result = _flatten_nested(result)
return result
def _flatten_nested(base: Path) -> Path:
"""If a directory has exactly one child that is also a directory,
move the child's contents up and remove the child. Repeat until stable.
Returns the (possibly changed) base path."""
changed = True
while changed:
changed = False
if not base.is_dir():
break
entries = [e for e in base.iterdir() if e.name not in ('.', '..')]
if len(entries) == 1 and entries[0].is_dir():
inner = entries[0]
# Move everything from inner into base
for item in list(inner.iterdir()):
shutil.move(str(item), str(base / item.name))
inner.rmdir()
changed = True
return base
def _detect_archive_ext(name: str) -> Optional[str]: