Cache open blend files

This simplifies blend file handling, ensuring that blend files are only
opened once. Otherwise it would be harder to handle things like dependency
diamonds (libraries that are referenced via multiple paths through multiple
other libraries).
This commit is contained in:
Sybren A. Stüvel 2018-03-07 17:13:47 +01:00
parent c5a02423cb
commit 09a0866c14
3 changed files with 31 additions and 6 deletions

View File

@ -20,6 +20,7 @@
# (c) 2014, Blender Foundation - Campbell Barton
# (c) 2018, Blender Foundation - Sybren A. Stüvel
import atexit
import collections
import gzip
import logging
@ -27,6 +28,8 @@ import os
import struct
import pathlib
import tempfile
import functools
import typing
from . import exceptions, dna_io, dna, header
@ -39,6 +42,29 @@ FILE_BUFFER_SIZE = 1024 * 1024
BLENDFILE_MAGIC = b'BLENDER'
GZIP_MAGIC = b'\x1f\x8b'
_cached_bfiles = {}
def open_cached(path: pathlib.Path, mode='rb') -> 'BlendFile':
"""Open a blend file, ensuring it is only opened once."""
bfile_path = path.absolute().resolve()
try:
return _cached_bfiles[bfile_path]
except KeyError:
pass
bfile = BlendFile(path, mode=mode)
_cached_bfiles[bfile_path] = bfile
return bfile
@atexit.register
def close_all_cached():
log.info('Closing all blend files')
for bfile in _cached_bfiles.values():
bfile.close()
_cached_bfiles.clear()
class BlendFile:
"""Representation of a blend file.

View File

@ -23,7 +23,7 @@ def deps(bfilepath: pathlib.Path) -> typing.Iterator[result.BlockUsage]:
:param bfilepath: File to open.
"""
with blendfile.BlendFile(bfilepath) as bfile:
bfile = blendfile.open_cached(bfilepath)
for block in asset_holding_blocks(file2blocks.iter_blocks(bfile)):
yield from blocks2assets.iter_assets(block)

View File

@ -86,8 +86,7 @@ class _BlockIterator:
continue
log.debug('Expanding %d blocks in %s', len(idblocks), lib_path)
with blendfile.BlendFile(lib_path) as libfile:
libfile = blendfile.open_cached(lib_path)
yield from self.iter_blocks(libfile, idblocks)
def _queue_all_blocks(self, bfile: blendfile.BlendFile):