test local replay of edits, needed for local cache

This commit is contained in:
2015-01-23 20:30:19 +11:00
parent 27a0f7471b
commit 98f67c5d7f
5 changed files with 152 additions and 10 deletions

View File

@@ -350,12 +350,21 @@ class BlendFileBlock:
assert(type(dna_type_id) is bytes)
self.refine_type_from_index(self.file.sdna_index_from_id[dna_type_id])
def get(self, path,
def get_file_offset(self, path,
default=...,
sdna_index_refine=None,
use_nil=True, use_str=True,
base_index=0,
):
"""
Return (offset, length)
"""
assert(type(path) is bytes)
ofs = self.file_offset
if base_index != 0:
assert(base_index < self.count)
ofs += (self.size // self.count) * base_index
self.file.handle.seek(ofs, os.SEEK_SET)
if sdna_index_refine is None:
sdna_index_refine = self.sdna_index
@@ -363,13 +372,30 @@ class BlendFileBlock:
self.file.ensure_subtype_smaller(self.sdna_index, sdna_index_refine)
dna_struct = self.file.structs[sdna_index_refine]
ofs = self.file_offset
field = dna_struct.field_from_path(
self.file.header, self.file.handle, path)
return (self.file.handle.tell(), field.dna_name.array_size)
def get(self, path,
default=...,
sdna_index_refine=None,
use_nil=True, use_str=True,
base_index=0,
):
ofs = self.file_offset
if base_index != 0:
assert(base_index < self.count)
ofs += (self.size // self.count) * base_index
self.file.handle.seek(ofs, os.SEEK_SET)
if sdna_index_refine is None:
sdna_index_refine = self.sdna_index
else:
self.file.ensure_subtype_smaller(self.sdna_index, sdna_index_refine)
dna_struct = self.file.structs[sdna_index_refine]
return dna_struct.field_get(
self.file.header, self.file.handle, path,
default=default,

View File

@@ -122,6 +122,13 @@ def pack(
# Read variations from json files.
use_variations=True,
# do _everything_ except to write the paths.
# useful if we want to calculate deps to remap but postpone applying them.
readonly=False,
# dict of binary_edits:
# {file: [(ofs, bytes), ...], ...}
binary_edits=None,
):
"""
:param deps_remap: Store path deps_remap info as follows.
@@ -135,7 +142,7 @@ def pack(
# so we can modify in-place.
# - temp files are only created once, (if we never touched them before),
# this way, for linked libraries - a single blend file may be used
# multiple times, each access will apply new edits ontop of the old ones.
# multiple times, each access will apply new edits on top of the old ones.
# - we track which libs we have touched (using 'lib_visit' arg),
# this means that the same libs wont be touched many times to modify the same data
# also prevents cyclic loops from crashing.
@@ -275,7 +282,7 @@ def pack(
for fp, (rootdir, fp_blend_basename) in blendfile_path_walker.FilePath.visit_from_blend(
blendfile_src,
readonly=False,
readonly=readonly,
temp_remap_cb=temp_remap_cb,
recursive=True,
recursive_all=all_deps,
@@ -293,6 +300,14 @@ def pack(
yield report(" %s: %s\n" % (colorize("blend", color='blue'), fp_blend))
fp_blend_basename_last = fp_blend_basename
if binary_edits is not None:
# TODO, temp_remap_cb makes paths, this isn't ideal,
# in this case we only want to remap!
tmp = temp_remap_cb(fp_blend, base_dir_src)
tmp = os.path.relpath(tmp[:-1], base_dir_dst_temp)
binary_edits_curr = binary_edits.setdefault(tmp, [])
del tmp
# assume the path might be relative
path_src_orig = fp.filepath
path_rel = blendfile_path_walker.utils.compatpath(path_src_orig)
@@ -323,7 +338,13 @@ def pack(
path_dst = os.path.join(base_dir_dst, path_dst)
path_dst_final = b'//' + path_dst_final
fp.filepath = path_dst_final
# Assign direct or add to edit-list (to apply later)
if not readonly:
fp.filepath = path_dst_final
if binary_edits is not None:
fp.filepath_assign_edits(path_dst_final, binary_edits_curr)
# add to copy-list
# never copy libs (handled separately)
if not isinstance(fp, blendfile_path_walker.FPElem_block_path) or fp.userdata[0].code != b'LI':

View File

@@ -106,6 +106,24 @@ class FPElem:
else:
return utils.compatpath(filepath)
def filepath_assign_edits(self, filepath, binary_edits):
self._set_cb_edits(filepath, binary_edits)
@staticmethod
def _filepath_assign_edits(block, path, filepath, binary_edits):
"""
Record the write to a separate entry (binary file-like object),
this lets us replay the edits later.
(so we can replay them onto the clients local cache without a file transfer).
"""
import struct
assert(type(filepath) is bytes)
assert(type(path) is bytes)
ofs, size = block.get_file_offset(path)
# ensure we dont write past the field size & allow for \0
filepath = filepath[:size - 1]
binary_edits.append((ofs, filepath + b'\0'))
@property
def filepath(self):
return self._get_cb()
@@ -134,11 +152,15 @@ class FPElem_block_path(FPElem):
block, path = self.userdata
block[path] = filepath
def _set_cb_edits(self, filepath, binary_edits):
block, path = self.userdata
self._filepath_assign_edits(block, path, filepath, binary_edits)
class FPElem_sequence_single(FPElem):
"""
Movie sequence
userdata = (block, path)
userdata = (block, path, sub_block, sub_path)
"""
__slots__ = ()
@@ -148,16 +170,23 @@ class FPElem_sequence_single(FPElem):
def _set_cb(self, filepath):
block, path, sub_block, sub_path = self.userdata
head, sep, tail = utils.splitpath(filepath)
block[path] = head + sep
sub_block[sub_path] = tail
def _set_cb_edits(self, filepath, binary_edits):
block, path, sub_block, sub_path = self.userdata
head, sep, tail = utils.splitpath(filepath)
self._filepath_assign_edits(block, path, head + sep, binary_edits)
self._filepath_assign_edits(sub_block, sub_path, tail, binary_edits)
class FPElem_sequence_image_seq(FPElem_sequence_single):
"""
Image sequence
userdata = (block, path)
userdata = (block, path, sub_block, sub_path)
"""
__slots__ = ()