Fix T55539: BAT doesn't pack particle caches

This commit is contained in:
Sybren A. Stüvel 2018-07-03 14:41:12 +02:00
parent aa8e2a8cdd
commit 0b96635953
29 changed files with 86 additions and 15 deletions

View File

@ -27,7 +27,7 @@ import threading
import typing import typing
from blender_asset_tracer import trace, bpathlib, blendfile from blender_asset_tracer import trace, bpathlib, blendfile
from blender_asset_tracer.trace import result from blender_asset_tracer.trace import file_sequence, result
from . import filesystem, transfer, progress from . import filesystem, transfer, progress
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -187,7 +187,13 @@ class Packer:
raise Aborted() raise Aborted()
def exclude(self, *globs: str): def exclude(self, *globs: str):
"""Register glob-compatible patterns of files that should be ignored.""" """Register glob-compatible patterns of files that should be ignored.
Must be called before calling strategise().
"""
if self._actions:
raise RuntimeError('%s.exclude() must be called before strategise()' %
self.__class__.__qualname__)
self._exclude_globs.update(globs) self._exclude_globs.update(globs)
def strategise(self) -> None: def strategise(self) -> None:
@ -196,6 +202,10 @@ class Packer:
Places an asset into one of these categories: Places an asset into one of these categories:
- Can be copied as-is, nothing smart required. - Can be copied as-is, nothing smart required.
- Blend files referring to this asset need to be rewritten. - Blend files referring to this asset need to be rewritten.
This function does *not* expand globs. Globs are seen as single
assets, and are only evaluated when performing the actual transfer
in the execute() function.
""" """
# The blendfile that we pack is generally not its own dependency, so # The blendfile that we pack is generally not its own dependency, so
@ -219,30 +229,55 @@ class Packer:
log.info('Excluding file: %s', asset_path) log.info('Excluding file: %s', asset_path)
continue continue
if not asset_path.exists(): if usage.is_sequence:
log.warning('Missing file: %s', asset_path) self._visit_sequence(asset_path, usage)
self.missing_files.add(asset_path) else:
self._progress_cb.missing_file(asset_path) self._visit_asset(asset_path, usage)
continue
self._visit_asset(asset_path, usage)
self._find_new_paths() self._find_new_paths()
self._group_rewrites() self._group_rewrites()
def _visit_sequence(self, asset_path: pathlib.Path, usage: result.BlockUsage):
assert usage.is_sequence
for first_path in file_sequence.expand_sequence(asset_path):
if first_path.exists():
break
else:
# At least the first file of a sequence must exist.
log.warning('Missing file: %s', asset_path)
self.missing_files.add(asset_path)
self._progress_cb.missing_file(asset_path)
return
# Handle this sequence as an asset.
self._visit_asset(asset_path, usage)
def _visit_asset(self, asset_path: pathlib.Path, usage: result.BlockUsage): def _visit_asset(self, asset_path: pathlib.Path, usage: result.BlockUsage):
"""Determine what to do with this asset. """Determine what to do with this asset.
Determines where this asset will be packed, whether it needs rewriting, Determines where this asset will be packed, whether it needs rewriting,
and records the blend file data block referring to it. and records the blend file data block referring to it.
""" """
# Sequences are allowed to not exist at this point.
if not usage.is_sequence and not asset_path.exists():
log.warning('Missing file: %s', asset_path)
self.missing_files.add(asset_path)
self._progress_cb.missing_file(asset_path)
return
bfile_path = usage.block.bfile.filepath.absolute() bfile_path = usage.block.bfile.filepath.absolute()
self._progress_cb.trace_asset(asset_path) self._progress_cb.trace_asset(asset_path)
# Needing rewriting is not a per-asset thing, but a per-asset-per- # Needing rewriting is not a per-asset thing, but a per-asset-per-
# blendfile thing, since different blendfiles can refer to it in # blendfile thing, since different blendfiles can refer to it in
# different ways (for example with relative and absolute paths). # different ways (for example with relative and absolute paths).
path_in_project = self._path_in_project(asset_path) if usage.is_sequence:
first_path = next(file_sequence.expand_sequence(asset_path))
else:
first_path = asset_path
path_in_project = self._path_in_project(first_path)
use_as_is = usage.asset_path.is_blendfile_relative() and path_in_project use_as_is = usage.asset_path.is_blendfile_relative() and path_in_project
needs_rewriting = not use_as_is needs_rewriting = not use_as_is
@ -428,11 +463,13 @@ class Packer:
bfile.close() bfile.close()
def _copy_asset_and_deps(self, asset_path: pathlib.Path, action: AssetAction): def _copy_asset_and_deps(self, asset_path: pathlib.Path, action: AssetAction):
# Copy the asset itself. # Copy the asset itself, but only if it's not a sequence (sequences are
packed_path = action.new_path # handled below in the for-loop).
read_path = action.read_from or asset_path if '*' not in str(asset_path):
self._send_to_target(read_path, packed_path, packed_path = action.new_path
may_move=action.read_from is not None) read_path = action.read_from or asset_path
self._send_to_target(read_path, packed_path,
may_move=action.read_from is not None)
# Copy its sequence dependencies. # Copy its sequence dependencies.
for usage in action.usages: for usage in action.usages:

View File

@ -371,6 +371,40 @@ class ProgressTest(AbstractPackTest):
cb.missing_file.assert_has_calls(expected_calls, any_order=True) cb.missing_file.assert_has_calls(expected_calls, any_order=True)
self.assertEqual(len(expected_calls), cb.missing_file.call_count) self.assertEqual(len(expected_calls), cb.missing_file.call_count)
def test_particle_cache(self):
# The particle cache uses a glob to indicate which files to pack.
cb = mock.Mock(progress.Callback)
infile = self.blendfiles / 'T55539-particles/particle.blend'
with pack.Packer(infile, self.blendfiles, self.tpath) as packer:
packer.progress_cb = cb
packer.strategise()
packer.execute()
# We should have all the *.bphys files now.
count = len(list((self.tpath / 'T55539-particles/blendcache_particle').glob('*.bphys')))
self.assertEqual(27, count)
# Physics files + particle.blend + pack_info.txt
self.assertGreaterEqual(cb.transfer_progress.call_count, 29,
'transfer_progress() should be called at least once per asset')
def test_particle_cache_with_ignore_glob(self):
cb = mock.Mock(progress.Callback)
infile = self.blendfiles / 'T55539-particles/particle.blend'
with pack.Packer(infile, self.blendfiles, self.tpath) as packer:
packer.progress_cb = cb
packer.exclude('*.bphys')
packer.strategise()
packer.execute()
# We should have none of the *.bphys files now.
count = len(list((self.tpath / 'T55539-particles/blendcache_particle').glob('*.bphys')))
self.assertEqual(0, count)
# Just particle.blend + pack_info.txt
self.assertGreaterEqual(cb.transfer_progress.call_count, 2,
'transfer_progress() should be called at least once per asset')
class AbortTest(AbstractPackTest): class AbortTest(AbstractPackTest):
def test_abort_strategise(self): def test_abort_strategise(self):