Initial Variation support

See: T42930

Also added tests
This commit is contained in:
2014-12-17 11:38:55 +01:00
parent 3ddc2551c7
commit b16801dd6c
8 changed files with 167 additions and 52 deletions

View File

@@ -119,6 +119,9 @@ def pack(
# converting: '../../bar' --> '__/__/bar'
# so all paths are nested and not moved outside the session path.
blendfile_src_dir_fakeroot=None,
# Read variations from json files.
use_variations=True,
):
"""
:param deps_remap: Store path deps_remap info as follows.
@@ -181,6 +184,12 @@ def pack(
"""
filepath = blendfile_path_walker.utils.compatpath(filepath)
if use_variations:
if blendfile_levels_dict_curr:
filepath = blendfile_levels_dict_curr.get(filepath, filepath)
# ...
# first remap this blend file to the location it will end up (so we can get images relative to _that_)
# TODO(cam) cache the results
fp_basedir_conv = _relpath_remap(os.path.join(rootdir, b'dummy'), base_dir_src, base_dir_src, blendfile_src_dir_fakeroot)[0]
@@ -197,6 +206,70 @@ def pack(
path_temp_files.add(filepath_tmp)
return filepath_tmp
# -----------------
# Variation Support
#
# Use a json file to allow recursive-remapping of variations.
#
# file_a.blend
# file_a.json '{"variations": ["tree.blue.blend", ...]}'
# file_a.blend -> file_b.blend
# file_b.blend --> tree.blend
#
# the variation of `file_a.blend` causes `file_b.blend`
# to link in `tree.blue.blend`
if use_variations:
blendfile_levels = []
blendfile_levels_dict = []
blendfile_levels_dict_curr = {}
def blendfile_levels_rebuild():
# after changing blend file configurations,
# re-create current variation lookup table
blendfile_levels_dict_curr.clear()
for d in blendfile_levels_dict:
if d is not None:
blendfile_levels_dict_curr.update(d)
# use variations!
def blendfile_level_cb_enter(filepath):
import json
filepath_json = os.path.splitext(filepath)[0] + b".json"
if os.path.exists(filepath_json):
with open(filepath_json, encoding='utf-8') as f_handle:
variations = [f.encode("utf-8") for f in json.load(f_handle).get("variations")]
# convert to absolute paths
basepath = os.path.dirname(filepath)
variations = {
# Reverse lookup, from non-variation to variation we specify in this file.
# {"/abs/path/foo.png": "/abs/path/foo.variation.png", ...}
# .. where the input _is_ the variation,
# we just make it absolute and use the non-variation as
# the key to the variation value.
b".".join(f.rsplit(b".", 2)[0::2]): f for f_ in variations
for f in (os.path.normpath(os.path.join(basepath, f_)),)
}
else:
variations = None
blendfile_levels.append(filepath)
blendfile_levels_dict.append(variations)
if variations:
blendfile_levels_rebuild()
def blendfile_level_cb_exit(filepath):
blendfile_levels.pop()
blendfile_levels_dict.pop()
if blendfile_levels_dict_curr:
blendfile_levels_rebuild()
else:
blendfile_level_cb_enter = blendfile_level_cb_exit = None
blendfile_levels_dict_curr = None
lib_visit = {}
fp_blend_basename_last = b''
@@ -207,6 +280,10 @@ def pack(
recursive=True,
recursive_all=all_deps,
lib_visit=lib_visit,
blendfile_level_cb=(
blendfile_level_cb_enter,
blendfile_level_cb_exit,
)
):
# we could pass this in!
@@ -222,6 +299,15 @@ def pack(
path_src = blendfile_path_walker.utils.abspath(path_rel, fp.basedir)
path_src = os.path.normpath(path_src)
# apply variation (if available)
if use_variations:
if blendfile_levels_dict_curr:
path_src_variation = blendfile_levels_dict_curr.get(path_src)
if path_src_variation is not None:
path_src = path_src_variation
path_rel = os.path.join(os.path.dirname(path_rel), os.path.basename(path_src))
del path_src_variation
# destination path realtive to the root
# assert(b'..' not in path_src)
assert(b'..' not in base_dir_src)
@@ -238,7 +324,6 @@ def pack(
path_dst_final = b'//' + path_dst_final
fp.filepath = path_dst_final
# 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

@@ -19,7 +19,8 @@
# ***** END GPL LICENCE BLOCK *****
import os
VERBOSE = os.environ.get('BAM_VERBOSE', False)
# gives problems with scripts that use stdout, for testing 'bam deps' for eg.
# VERBOSE = os.environ.get('BAM_VERBOSE', False)
TIMEIT = False
@@ -199,10 +200,17 @@ class FilePath:
# prevents cyclic references too!
# {lib_path: set([block id's ...])}
lib_visit=None,
# optional blendfile callbacks
# These callbacks run on enter-exit blend files
# so you can keep track of what file and level you're at.
blendfile_level_cb=(None, None),
):
# print(level, block_codes)
import os
filepath = os.path.abspath(filepath)
if VERBOSE:
indent_str = " " * level
# print(indent_str + "Opening:", filepath)
@@ -212,7 +220,12 @@ class FilePath:
log_deps.info("%s%s" % (indent_str, filepath.decode('utf-8')))
log_deps.info("%s%s" % (indent_str, set_as_str(block_codes)))
basedir = os.path.dirname(os.path.abspath(filepath))
blendfile_level_cb_enter, blendfile_level_cb_exit = blendfile_level_cb
if blendfile_level_cb_enter is not None:
blendfile_level_cb_enter(filepath)
basedir = os.path.dirname(filepath)
if rootdir is None:
rootdir = basedir
@@ -416,8 +429,13 @@ class FilePath:
rootdir=rootdir,
level=level + 1,
lib_visit=lib_visit,
blendfile_level_cb=blendfile_level_cb,
)
if blendfile_level_cb_exit is not None:
blendfile_level_cb_exit(filepath)
# ------------------------------------------------------------------------
# Direct filepaths from Blocks
#

View File

@@ -818,7 +818,7 @@ class bam_commands:
print("]")
else:
for f_src, f_dst, f_dst_abs, f_status in status_walker():
print(" %r -> (%r = %r) %s" % (f_src, f_dst, f_dst_abs, f_status))ia
print(" %r -> (%r = %r) %s" % (f_src, f_dst, f_dst_abs, f_status))
@staticmethod
def pack(

View File

@@ -860,6 +860,66 @@ class BamCheckoutTest(BamSessionTestCase):
# checkout inside of the existing session, should raise exception
self.assertRaises(RuntimeError, bam_run, ["checkout", file_name, "--output", session_path], session_path)
def test_checkout_variation(self):
session_name = "mysession"
proj_path, session_path = self.init_session(session_name)
variation_path = os.path.join(session_path, "variations")
if 1:
import shutil
# path cant already exist, ugh
shutil.copytree(
os.path.join(CURRENT_DIR, "blends", "variations"),
variation_path,
)
stdout, stderr = bam_run(["commit", "-m", "test message"], session_path)
self.assertEqual("", stderr)
listing = bam_run_as_json(["ls", "variations", "--json"], session_path)
listing_expect = [
["cone.blend", "file"],
["cone.blue.blend", "file"],
["lib_endpoint.blend", "file"],
["lib_user.blend", "file"],
]
self.assertEqual(listing, listing_expect)
f_variation = os.path.join(variation_path, "lib_user.json")
# now create variation file & commit it
file_quick_write(
f_variation,
data='{"variations": ["cone.blue.blend"]}',
)
stdout, stderr = bam_run(["commit", "-m", "add variation"], session_path)
self.assertEqual("", stderr)
listing = bam_run_as_json(["ls", "variations", "--json"], session_path)
listing_expect.append(["lib_user.json", "file"])
listing_expect.sort()
self.assertEqual(listing, listing_expect)
# now clear the repo and do a fresh checkout, and see that the variation is applied.
# remove the path
shutil.rmtree(session_path)
# checkout the file again
file_name = "variations/lib_endpoint.blend"
session_path = session_path + "_a"
stdout, stderr = bam_run(["checkout", file_name, "--output", session_path], proj_path)
self.assertEqual("", stderr)
ret = bam_run_as_json(["deps", "lib_endpoint.blend", "--json", "--recursive"], session_path)
ret.sort()
self.assertEqual(ret[0][1], "//lib_user.blend")
self.assertEqual(ret[0][3], "OK")
self.assertEqual(ret[1][1], "//cone.blue.blend")
self.assertEqual(ret[1][3], "OK")
class BamUpdateTest(BamSessionTestCase):
"""Test for the `bam update` command.
@@ -1356,54 +1416,6 @@ class BamRelativeAbsoluteTest(BamSessionTestCase):
# self.assertEqual(ret[0], ["house_rel.blend", "file"])
class BamVariation(BamSessionTestCase):
"""
"""
def __init__(self, *args):
self.init_defaults()
super().__init__(*args)
def test_variation(self):
"""
"""
session_name = "mysession"
proj_path, session_path = self.init_session(session_name)
variation_path = os.path.join(session_path, "variations")
if 1:
import shutil
# path cant already exist, ugh
shutil.copytree(
os.path.join(CURRENT_DIR, "blends", "variations"),
variation_path,
)
stdout, stderr = bam_run(["commit", "-m", "test message"], session_path)
self.assertEqual("", stderr)
listing = bam_run_as_json(["ls", "variations", "--json"], session_path)
self.assertEqual(
listing,
[["cone.blue.blend", "file"],
["cone.red.blend", "file"],
["lib_endpoint.blend", "file"]],
["lib_user.blend", "file"]],
)
f_variation = os.path.join(variation_path, "lib_user.json")
# now create variation file & commit it
file_quick_write(
session_path,
f,
"",
append=True)
# import time; time.sleep(10000000)
class BamIgnoreTest(BamSessionTestCase):
"""Checks out a project, creates a .bamignore file with a few rules
and tries to commit files that violate them.