Both the dependency Tracer class and the Packer class now support a callback object, where the latter is a subclass of the former. For file transfers running in a separate thread, there is a thread-safe wrapper for progress callbacks. This wrapper can be called from any thread, and calls the wrapped callback object from the main thread. This way the callback implementation itself doesn't have to worry about threading issues.
56 lines
1.7 KiB
Python
56 lines
1.7 KiB
Python
import logging
|
|
import pathlib
|
|
import typing
|
|
|
|
from blender_asset_tracer import blendfile
|
|
from . import result, blocks2assets, file2blocks, progress
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
codes_to_skip = {
|
|
# These blocks never have external assets:
|
|
b'ID', b'WM', b'SN',
|
|
|
|
# These blocks are skipped for now, until we have proof they point to
|
|
# assets otherwise missed:
|
|
b'GR', b'WO', b'BR', b'LS',
|
|
}
|
|
|
|
|
|
def deps(bfilepath: pathlib.Path, progress_cb: typing.Optional[progress.Callback] = None) \
|
|
-> typing.Iterator[result.BlockUsage]:
|
|
"""Open the blend file and report its dependencies.
|
|
|
|
:param bfilepath: File to open.
|
|
:param progress_cb: Progress callback object.
|
|
"""
|
|
|
|
log.info('opening: %s', bfilepath)
|
|
bfile = blendfile.open_cached(bfilepath)
|
|
|
|
bi = file2blocks.BlockIterator()
|
|
if progress_cb:
|
|
bi.progress_cb = progress_cb
|
|
|
|
ahb = asset_holding_blocks(bi.iter_blocks(bfile))
|
|
# Sort the asset-holding blocks so that we can iterate over them
|
|
# in disk order, which is slightly faster than random order.
|
|
for block in sorted(ahb):
|
|
yield from blocks2assets.iter_assets(block)
|
|
|
|
|
|
def asset_holding_blocks(blocks: typing.Iterable[blendfile.BlendFileBlock]) \
|
|
-> typing.Iterator[blendfile.BlendFileBlock]:
|
|
"""Generator, yield data blocks that could reference external assets."""
|
|
for block in blocks:
|
|
assert isinstance(block, blendfile.BlendFileBlock)
|
|
code = block.code
|
|
|
|
# The longer codes are either arbitrary data or data blocks that
|
|
# don't refer to external assets. The former data blocks will be
|
|
# visited when we hit the two-letter datablocks that use them.
|
|
if len(code) > 2 or code in codes_to_skip:
|
|
continue
|
|
|
|
yield block
|