Apply audit fixes for pack-sequence (14 findings, 28 new tests)
Cross-validation audit by Codex + Opus identified 14 issues: CRITICAL: - Fix _find_subdir_ci() prefix match accepting wrong folders (e.g. Publish_old). Now uses exact case-insensitive match. HIGH: - Add pack-sequence CLI subcommand with unambiguous arg parsing. Deprecate --sequence on pack (nargs='+' consumed the target). - Fix Windows UNC/drive path normalization in bpathlib.make_absolute() - Fix ZIP failure losing traceback + progress bar stuck on error - Fix os.path.commonpath crash on cross-drive paths (new derive_common_project helper) - Fix progress bar saturating at 40% during trace (log scale) MEDIUM: - Add per-shot error isolation in sequence scan (collect all errors) - Add memory warning for >50 files in sequence pack - Improve pack-info.txt with dedup stats - Wrap single Path in list for old operators (type consistency) LOW/INFO: - Document VERSION_RE pattern - Add TASK_CHOICE_ITEMS empty guard 28 new tests in tests/test_sequence_pack.py, 0 regressions. Co-Authored-By: Mario Hawat <mario@autourdeminuit.com> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -79,6 +79,7 @@ def cli_main():
|
||||
|
||||
blocks.add_parser(subparsers)
|
||||
pack.add_parser(subparsers)
|
||||
pack.add_sequence_parser(subparsers)
|
||||
list_deps.add_parser(subparsers)
|
||||
version.add_parser(subparsers)
|
||||
|
||||
|
||||
@@ -104,12 +104,122 @@ def add_parser(subparsers):
|
||||
nargs="+",
|
||||
type=pathlib.Path,
|
||||
metavar="BLENDFILE",
|
||||
help="Pack multiple blend files together, deduplicating shared dependencies. "
|
||||
"All listed blend files and their dependencies are packed into the target.",
|
||||
help="(Deprecated: use 'pack-sequence' subcommand instead.) "
|
||||
"Pack multiple blend files together, deduplicating shared dependencies.",
|
||||
)
|
||||
|
||||
|
||||
def add_sequence_parser(subparsers):
|
||||
"""Add argparser for the pack-sequence subcommand."""
|
||||
|
||||
parser = subparsers.add_parser(
|
||||
"pack-sequence",
|
||||
help="Pack multiple blend files together, deduplicating shared dependencies.",
|
||||
)
|
||||
parser.set_defaults(func=cli_pack_sequence)
|
||||
parser.add_argument(
|
||||
"blendfiles",
|
||||
nargs="+",
|
||||
type=pathlib.Path,
|
||||
help="Blend files to pack.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--target",
|
||||
type=str,
|
||||
required=True,
|
||||
help="Target directory or ZIP file.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--project",
|
||||
type=pathlib.Path,
|
||||
help="Root directory of your project.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-n",
|
||||
"--noop",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Don't copy files, just show what would be done.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-e",
|
||||
"--exclude",
|
||||
nargs="*",
|
||||
default="",
|
||||
help="Space-separated list of glob patterns to exclude.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--compress",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Compress blend files while copying.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-r",
|
||||
"--relative-only",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Only pack assets referred to with a relative path.",
|
||||
)
|
||||
|
||||
|
||||
def derive_common_project(bpaths: typing.List[pathlib.Path]) -> pathlib.Path:
|
||||
"""Derive common project directory from multiple blend file paths.
|
||||
|
||||
Raises ValueError if paths span multiple drives or if common root
|
||||
is the filesystem root.
|
||||
"""
|
||||
if len(bpaths) == 1:
|
||||
return bpaths[0].parent
|
||||
|
||||
try:
|
||||
ppath = pathlib.Path(os.path.commonpath([p.parent for p in bpaths]))
|
||||
except ValueError:
|
||||
raise ValueError(
|
||||
"Blend files span multiple drives or have no common path. "
|
||||
"Specify the project directory explicitly with -p/--project."
|
||||
)
|
||||
|
||||
if ppath == pathlib.Path(ppath.anchor):
|
||||
raise ValueError(
|
||||
"Computed project path is the filesystem root (%s). "
|
||||
"Specify the project directory explicitly." % ppath
|
||||
)
|
||||
|
||||
return ppath
|
||||
|
||||
|
||||
def cli_pack_sequence(args):
|
||||
"""CLI entry point for pack-sequence subcommand."""
|
||||
# Synthesize args to reuse paths_from_cli and create_packer
|
||||
args.blendfile = None
|
||||
args.sequence = args.blendfiles
|
||||
args.keep_hierarchy = True # always for sequence packing
|
||||
if not hasattr(args, 'target') or args.target is None:
|
||||
log.critical("No target specified. Use -t/--target.")
|
||||
sys.exit(3)
|
||||
|
||||
bpaths, ppath, tpath = paths_from_cli(args)
|
||||
|
||||
with create_packer(args, bpaths, ppath, tpath) as packer:
|
||||
packer.strategise()
|
||||
try:
|
||||
packer.execute()
|
||||
except blender_asset_tracer.pack.transfer.FileTransferError as ex:
|
||||
log.error(
|
||||
"%d files couldn't be copied, starting with %s",
|
||||
len(ex.files_remaining),
|
||||
ex.files_remaining[0],
|
||||
)
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
def cli_pack(args):
|
||||
if args.sequence:
|
||||
log.warning("--sequence on 'pack' is deprecated. Use 'bat pack-sequence -t TARGET FILE...' instead.")
|
||||
bpaths, ppath, tpath = paths_from_cli(args)
|
||||
|
||||
with create_packer(args, bpaths, ppath, tpath) as packer:
|
||||
@@ -270,10 +380,11 @@ def paths_from_cli(args) -> typing.Tuple[typing.List[pathlib.Path], pathlib.Path
|
||||
tpath = args.target
|
||||
|
||||
if args.project is None:
|
||||
if len(bpaths) == 1:
|
||||
ppath = bpaths[0].parent
|
||||
else:
|
||||
ppath = pathlib.Path(os.path.commonpath([p.parent for p in bpaths]))
|
||||
try:
|
||||
ppath = derive_common_project(bpaths)
|
||||
except ValueError as ex:
|
||||
log.critical("%s", ex)
|
||||
sys.exit(5)
|
||||
log.warning("No project path given, using %s", ppath)
|
||||
else:
|
||||
ppath = bpathlib.make_absolute(args.project)
|
||||
|
||||
Reference in New Issue
Block a user