feature: pack folder
This commit is contained in:
@@ -80,6 +80,7 @@ def cli_main():
|
||||
blocks.add_parser(subparsers)
|
||||
pack.add_parser(subparsers)
|
||||
pack.add_sequence_parser(subparsers)
|
||||
pack.add_folder_parser(subparsers)
|
||||
list_deps.add_parser(subparsers)
|
||||
version.add_parser(subparsers)
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import typing
|
||||
|
||||
import blender_asset_tracer.pack.transfer
|
||||
from blender_asset_tracer import pack, bpathlib
|
||||
from blender_asset_tracer.pack import folder as folder_scan
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -166,6 +167,102 @@ def add_sequence_parser(subparsers):
|
||||
)
|
||||
|
||||
|
||||
def add_folder_parser(subparsers):
|
||||
"""Add argparser for the pack-folder subcommand."""
|
||||
|
||||
parser = subparsers.add_parser(
|
||||
"pack-folder",
|
||||
help="Pack every blend file in a directory tree, together with their "
|
||||
"dependencies, deduplicating shared assets.",
|
||||
)
|
||||
parser.set_defaults(func=cli_pack_folder)
|
||||
parser.add_argument(
|
||||
"folder",
|
||||
type=pathlib.Path,
|
||||
help="Directory to scan recursively for blend files.",
|
||||
)
|
||||
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. Defaults to the scanned folder, "
|
||||
"so that the pack mirrors the folder's own structure and assets from "
|
||||
"outside it end up in '_outside_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.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--keep-hierarchy",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Preserve the full filesystem directory hierarchy in the pack, "
|
||||
"instead of packing relative to the scanned folder.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--latest-only",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Of every 'name_vNNN.blend' version series in a directory, only "
|
||||
"pack the highest version. Variants like 'name_vNNN_light.blend' form "
|
||||
"their own series; files without a version are always packed.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--follow-symlinks",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Descend into symlinked directories while scanning.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--ignore-dir",
|
||||
nargs="*",
|
||||
default=list(folder_scan.DEFAULT_IGNORE_DIRS),
|
||||
metavar="GLOB",
|
||||
help="Globs of directory names to skip while scanning (default: %s)."
|
||||
% " ".join(folder_scan.DEFAULT_IGNORE_DIRS),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-validate",
|
||||
dest="validate",
|
||||
default=True,
|
||||
action="store_false",
|
||||
help="Don't check that each '.blend' file really is a blend file. "
|
||||
"Faster, but a non-blend file will abort the pack.",
|
||||
)
|
||||
|
||||
|
||||
def derive_common_project(bpaths: typing.List[pathlib.Path]) -> pathlib.Path:
|
||||
"""Derive common project directory from multiple blend file paths.
|
||||
|
||||
@@ -202,25 +299,58 @@ def cli_pack_sequence(args):
|
||||
log.critical("No target specified. Use -t/--target.")
|
||||
sys.exit(3)
|
||||
|
||||
bpaths, ppath, tpath = paths_from_cli(args)
|
||||
run_packer(args, *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_folder(args):
|
||||
"""CLI entry point for pack-folder subcommand."""
|
||||
fpath = args.folder
|
||||
if not fpath.exists():
|
||||
log.critical("Folder %s does not exist", fpath)
|
||||
sys.exit(3)
|
||||
if not fpath.is_dir():
|
||||
log.critical("%s is not a directory", fpath)
|
||||
sys.exit(3)
|
||||
fpath = bpathlib.make_absolute(fpath)
|
||||
|
||||
log.info("Scanning %s for blend files", fpath)
|
||||
scan = folder_scan.find_blend_files(
|
||||
fpath,
|
||||
follow_symlinks=args.follow_symlinks,
|
||||
ignore_dirs=args.ignore_dir,
|
||||
latest_only=args.latest_only,
|
||||
validate=args.validate,
|
||||
)
|
||||
|
||||
for dirpath, reason in scan.unreadable_dirs:
|
||||
log.error("Could not scan %s: %s", dirpath, reason)
|
||||
if scan.skipped:
|
||||
log.warning("Skipped %d file(s) while scanning", len(scan.skipped))
|
||||
if not scan.blendfiles:
|
||||
log.critical("No blend files found in %s", fpath)
|
||||
sys.exit(3)
|
||||
log.warning("Found %d blend files in %s", len(scan.blendfiles), fpath)
|
||||
|
||||
# Synthesize args to reuse paths_from_cli and create_packer.
|
||||
args.blendfile = None
|
||||
args.sequence = scan.blendfiles
|
||||
if args.project is None:
|
||||
args.project = fpath
|
||||
|
||||
run_packer(args, *paths_from_cli(args))
|
||||
|
||||
|
||||
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)
|
||||
|
||||
run_packer(args, *paths_from_cli(args))
|
||||
|
||||
|
||||
def run_packer(
|
||||
args, bpaths: typing.List[pathlib.Path], ppath: pathlib.Path, tpath: str
|
||||
) -> None:
|
||||
"""Create the packer for these paths, and run it."""
|
||||
|
||||
with create_packer(args, bpaths, ppath, tpath) as packer:
|
||||
packer.strategise()
|
||||
|
||||
Reference in New Issue
Block a user