[Bf-blender-cvs] [0661b80] asset-engine: Continue fleshing out Amber.
Bastien Montagne
noreply at git.blender.org
Mon Mar 16 20:19:48 CET 2015
Commit: 0661b80aa0f178efa426218f5ebfac264cd77016
Author: Bastien Montagne
Date: Mon Mar 16 20:18:42 2015 +0100
Branches: asset-engine
https://developer.blender.org/rB0661b80aa0f178efa426218f5ebfac264cd77016
Continue fleshing out Amber.
Start to add real asset engine behavior. Still completely uncomplete and not even half working.
===================================================================
M release/scripts/startup/bl_operators/amber.py
===================================================================
diff --git a/release/scripts/startup/bl_operators/amber.py b/release/scripts/startup/bl_operators/amber.py
index 3848e1b..7a0216e 100644
--- a/release/scripts/startup/bl_operators/amber.py
+++ b/release/scripts/startup/bl_operators/amber.py
@@ -32,11 +32,68 @@ from bpy.props import (
CollectionProperty,
)
+import binascii
import concurrent.futures as futures
+import hashlib
+import json
import os
import stat
import time
+AMBER_DB_NAME = "__amber_db.json"
+AMBER_DBK_VERSION = "version"
+
+
+##########
+# Helpers.
+
+# Notes about UUIDs:
+# * UUID of an asset/variant/revision is computed once at its creation! Later changes to data do not affect it.
+# * Collision, for unlikely it is, may happen across different repositories...
+# Doubt this will be practical issue though.
+# * We keep eight first bytes of 'clear' identifier, to (try to) keep some readable uuid.
+
+def _uuid_gen_single(used_uuids, uuid_root, h, str_arg):
+ h.update(str_arg.encode())
+ uuid = uuid_root + h.digest()
+ uuid = uuid[:23].replace(b'\0', b'\1') # No null chars, RNA 'bytes' use them as in regular strings... :/
+ if uuid not in used_uuids: # *Very* likely, but...
+ used_uuids.add(uuid)
+ return uuid
+ return None
+
+
+def _uuid_gen(used_uuids, uuid_root, bytes_seed, *str_args):
+ h = hashlib.md5(bytes_seed)
+ for arg in str_args:
+ uuid = _uuid_gen_single(used_uuids, uuid_root, h, arg)
+ if uuid is not None:
+ return uuid
+ # This is a fallback in case we'd get a collision... Should never be needed in real life!
+ for i in range(100000):
+ uuid = _uuid_gen_single(used_uuids, uuid_root, h, i.to_bytes(4, 'little'))
+ if uuid is not None:
+ return uuid
+ return None # If this happens...
+
+
+def uuid_asset_gen(used_uuids, path_db, name, tags):
+ uuid_root = name.encode()[:8] + b'|'
+ return _uuid_gen_single(used_uuids, uuid_root, path_db.encode(), name, *tags)
+
+
+def uuid_variant_gen(used_uuids, asset_uuid, name):
+ uuid_root = name.encode()[:8] + b'|'
+ return _uuid_gen_single(used_uuids, uuid_root, asset_uuid, name)
+
+
+def uuid_revision_gen(used_uuids, variant_uuid, number, size, time):
+ uuid_root = str(number).encode() + b'|'
+ return _uuid_gen_single(used_uuids, uuid_root, variant_uuid, str(number), str(size), str(timestamp))
+
+
+#############
+# Amber Jobs.
class AmberJob:
def __init__(self, executor, job_id):
self.executor = executor
@@ -47,10 +104,34 @@ class AmberJob:
class AmberJobList(AmberJob):
@staticmethod
+ def ls_repo(db_path):
+ repo = None
+ with open(db_path, 'r') as db_f:
+ repo = json.load(db_f)
+ if isinstance(repo, dict):
+ repo_ver = repo.get(AMBER_DBK_VERSION, "")
+ if repo_ver != "1.0.0":
+ # Unsupported...
+ printf("WARNING: unsupported Amber repository version '%s'." % repo_ver)
+ repo = None
+ else:
+ repo = None
+ return repo
+
+ @staticmethod
def ls(path):
- ret = [".."] + os.listdir(path)
+ print(path)
+ repo = None
+ ret = [".."]
+ tmp = os.listdir(path)
+ print(tmp)
+ if AMBER_DB_NAME in tmp:
+ # That dir is an Amber repo, we only list content define by our amber 'db'.
+ repo = AmberJobList.ls_repo(os.path.join(path, AMBER_DB_NAME))
+ if repo is None:
+ ret += tmp
#~ time.sleep(0.1) # 100% Artificial Lag (c)
- return ret
+ return ret, repo
@staticmethod
def stat(root, path):
@@ -65,37 +146,75 @@ class AmberJobList(AmberJob):
self.status = {'VALID', 'RUNNING'}
def update(self, entries, uuids):
+ self.status = {'VALID', 'RUNNING'}
if self.ls_task is not None:
if not self.ls_task.done():
+ print("ls not done")
return
- paths = self.ls_task.result()
+ paths, repo = self.ls_task.result()
self.ls_task = None
self.tot = len(paths)
+ if repo is not None:
+ self.repo = repo
for p in paths:
self.stat_tasks.add(self.executor.submit(self.stat, self.root, p))
- else:
- done = set()
- for tsk in self.stat_tasks:
- if tsk.done():
- path, (is_dir, size, timestamp) = tsk.result()
- self.nbr += 1
-
- if is_dir:
- # We only list dirs from real file system.
- entry = entries.entries.add()
- entry.type = {'DIR'}
- entry.relpath = path
- entry.uuid = entry.relpath.encode()[:8] + b"|" + bytes(self.nbr)
- uuids[entry.uuid] = self.root + path
- variant = entry.variants.add()
+
+ done = set()
+ for tsk in self.stat_tasks:
+ print("some stat tasks...")
+ if tsk.done():
+ path, (is_dir, size, timestamp) = tsk.result()
+ self.nbr += 1
+ if is_dir:
+ # We only list dirs from real file system.
+ entry = entries.entries.add()
+ entry.type = {'DIR'}
+ entry.relpath = path
+ entry.uuid = entry.relpath.encode()[:8] + b"|" + bytes(self.nbr)
+ uuids[entry.uuid] = self.root + path
+ variant = entry.variants.add()
+ entry.variants.active = variant
+ rev = variant.revisions.add()
+ rev.size = size
+ rev.timestamp = timestamp
+ variant.revisions.active = rev
+ done.add(tsk)
+ self.stat_tasks -= done
+
+ if self.repo is not None:
+ print("has repo...")
+ for euuid, e in self.repo["entries"].items():
+ entry = entries.entries.add()
+ entry.uuid = binascii.unhexlify(euuid)
+ entry.name = e["name"]
+ entry.description = e["description"]
+ entry.type = {e["file_type"]}
+ entry.blender_type = e["blen_type"]
+ vuuids = {}
+ uuids[entry.uuid] = (self.root, entry.type, entry.blender_type, vuuids)
+ act_rev = None
+ for vuuid, v in e["variants"].items():
+ variant = entry.variants.add()
+ variant.uuid = binascii.unhexlify(vuuid)
+ variant.name = v["name"]
+ variant.description = v["description"]
+ ruuids = vuuids[variant.uuid] = {}
+ if vuuid == e["variant_default"]:
entry.variants.active = variant
- rev = variant.revisions.add()
- rev.size = size
- rev.timestamp = timestamp
- variant.revisions.active = rev
+ for ruuid, r in v["revisions"].items():
+ revision = variant.revisions.add()
+ revision.uuid = binascii.unhexlify(ruuid)
+ #~ revision.comment = r["comment"]
+ revision.size = r["size"]
+ revision.timestamp = r["timestamp"]
+ ruuids[revision.uuid] = (r["path_archive"], r["path"])
+ if ruuid == v["revision_default"]:
+ variant.revisions.active = revision
+ if vuuid == e["variant_default"]:
+ act_rev = r
+ if act_rev:
+ entry.relpath = act_rev["path"]
- done.add(tsk)
- self.stat_tasks -= done
self.progress = self.nbr / self.tot
if not self.stat_tasks and self.ls_task is None:
self.status = {'VALID'}
@@ -103,7 +222,8 @@ class AmberJobList(AmberJob):
def __init__(self, executor, job_id, root):
super().__init__(executor, job_id)
self.root = root
- self.entries = {}
+ self.repo = None
+
self.ls_task = None
self.stat_tasks = set()
@@ -117,6 +237,8 @@ class AmberJobList(AmberJob):
tsk.cancel()
+###########################
+# Mains Asset Engine class.
class AssetEngineAmber(AssetEngine):
bl_label = "Amber"
@@ -129,7 +251,8 @@ class AssetEngineAmber(AssetEngine):
def __del__(self):
pass
- # XXX This errors, saying self has no executor attribute... :/
+ # XXX This errors, saying self has no executor attribute... Suspect some py/RNA funky game. :/
+ # Even though it does not seem to be an issue, this is not nice and shall be fixed somehow.
#~ self.executor.shutdown(wait=False)
def status(self, job_id):
@@ -154,12 +277,11 @@ class AssetEngineAmber(AssetEngine):
if job_id:
self.jobs.pop(job_id, None)
return
- for job in self.jobs.values():
- job.kill()
+ self.jobs.clear()
def list_dir(self, job_id, entries):
job = self.jobs.get(job_id, None)
- #~ print(entries.root_path, job_id, job)
+ print(entries.root_path, job_id, job)
if job is not None and isinstance(job, AmberJobList):
if job.root != entries.root_path:
self.jobs[job_id] = AmberJobList(self.executor, job_id, entries.root_path)
@@ -173,11 +295,21 @@ class AssetEngineAmber(AssetEngine):
def load_pre(self, uuids, entries):
# Not quite sure this engine will need it in the end, but for sake of testing...
- entries.root_path = "/"
- for uuid in uuids.uuids[:1]:
+ root_path = None
+ for uuid in uuids.uuids:
+ root, file_type, blen_type, vuuids = self.uuids[uuid.uuid_asset]
+ ruuids = vuuids[uuid.uuid_variant]
+ path_archive, path = ruuids[uuid.uuid_revision]
+
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list