diff --git a/bin/bastion.py b/bin/bastion.py index 04e01b2..3fdec2d 100755 --- a/bin/bastion.py +++ b/bin/bastion.py @@ -22,7 +22,7 @@ sys.path.insert(0, str(LIB_PATH)) -from Bastion.Common import Boggle, asPath +from Bastion.Common import Boggle, asPath, toJDN from Bastion.Chronology import Quantim from Bastion.Site import Site from Bastion.Condo import Condex @@ -246,25 +246,25 @@ def run(self): else: sys.exit(1) - def remember(self, answer): + def remember(self, result): """ Given an answer structure and opts (as a dict), I serialize the answer to YAML and save the answer as a file in the logs. I need answer to include "log.scope" in the context block. If no "log.scope" is declared, I silently ignore the request to record. """ - if 'log.scope' in answer.request.context: + if 'log.scope' in result.request.context: #-- only write a log file if we have an explicit log.scope in the answer's context block. - session = answer.request.ID + session = result.request.ID scope = self.logroot - if answer.request.context['log.scope'] != '*': - scope = scope / answer.request.context['log.scope'] + if result.request.context['log.scope'] != '*': + scope = scope / result.request.context['log.scope'] halo = scope / "{}.yaml".format(session) halo.parent.mkdir(parents = True, exist_ok = True) with open(halo, 'wt') as fout: - self.emit_YAML(answer.toJDN(), fout) + self.emit_YAML(toJDN(result), fout) def emit(self, answer, ostream = None): ostream = ostream if (ostream is not None) else sys.stdout @@ -280,10 +280,10 @@ def emit(self, answer, ostream = None): def emit_YAML(self, result, ostream): yaml = YAML() yaml.default_flow_style = False - yaml.dump(result.toJDN(), ostream) + yaml.dump(toJDN(result), ostream) def emit_JSON(self, result, ostream): - json.dump(result.toJDN(), ostream, sort_keys = True, indent = 3) + json.dump(toJDN(result), ostream, sort_keys = True, indent = 3) def emit_PROSE(self, result, ostream): request = result.request @@ -345,7 +345,7 @@ def do_bank_asset(self, request): request['log.scope'] = "site/{}".format(ark.site) result = vault.push(asset, client = self.hostname) - if result.indicates_success: + if result.succeeded: return request.succeeded(result, report = "pushed full backup of {} to {}".format(str(ark), str(result.blonde))) else: return request.failed(result, report = "while pushing full backup of {}, something went wrong!".format(str(ark))) @@ -657,9 +657,10 @@ def do_export_site_catalog(self, request): for asset_name in catalog[zone_name]: manifest = vault.manifest(ARK(site_name, zone_name, asset_name)) anchor = manifest.head.anchor - origin = anchor.when.datetime.isoformat() - recent = manifest.head.tail.when.datetime.isoformat() - doclins.append("* {} {} ({} → {})".format(asset_name, str(anchor), origin, recent)) + origin = manifest.head.earliest.isoformat() + recent = manifest.head.latest.isoformat() + #doclins.append("* {} {} ({} → {})".format(asset_name, str(anchor), origin, recent)) + doclins.append(" * {}".format(repr(manifest.head))) doc = '\n'.join(doclins) return request.succeeded(catalog, report = doc) diff --git a/lib/Bastion/CARP.py b/lib/Bastion/CARP.py index 480e4e1..c3b1280 100644 --- a/lib/Bastion/CARP.py +++ b/lib/Bastion/CARP.py @@ -400,5 +400,5 @@ def __iter__(self): def toJDN(self, **kwargs): jdn = { } jdn['results'] = [result.toJDN(**kwargs) for result in self] - jdn['tags'] = self.tags.copy() + jdn['tags'] = sorted( self.tags.copy() ) return jdn diff --git a/lib/Bastion/Clerks/BFD.py b/lib/Bastion/Clerks/BFD.py index fbc5c2e..cbedb17 100644 --- a/lib/Bastion/Clerks/BFD.py +++ b/lib/Bastion/Clerks/BFD.py @@ -51,8 +51,8 @@ def assets(self, site, zone): #-- assets will be subdirectories (subfolders) of a given site, zone. assets = [ ] zroot = self.root / site / zone - if zroot.exists( ): - for entry in zroot.is_dir(): + if zroot.exists( ) and zroot.is_dir(): + for entry in zroot.iterdir(): assets.append(entry.name) return tuple(sorted(assets)) diff --git a/lib/Bastion/Curator.py b/lib/Bastion/Curator.py index bd26d8f..99d3323 100644 --- a/lib/Bastion/Curator.py +++ b/lib/Bastion/Curator.py @@ -41,9 +41,9 @@ def revise(self, whence = None): raise Exception("Can only create revisions of anchor backups") if whence is not None: - return BLONDE.forDiffBackup(self) - else: return BLONDE.forDiffBackup(self, when = whence) + else: + return BLONDE.forDiffBackup(self) def age(self, whence = None): whence = whence if (whence is not None) else datetime.datetime.now() @@ -182,7 +182,7 @@ def head(self): """ I am the most recent snap. """ - return self._snaps[-1] + return self.snaps[-1] def thread(self, ankle): """ @@ -248,6 +248,19 @@ def __repr__(self): } return "({badge}/{genus} @ {latest} - {earliest} ({elapsed}))".format(**opts) + @property + def earliest(self): + return self.anchor.when.latest + + @property + def latest(self): + return self.head.when.earliest + + @property + def delta(self): + #-- Alias for the "head" (i.e. the most recent or differential backup BLONDE) + return self.head + @property def genus(self): return self.anchor.genus @@ -263,7 +276,7 @@ def age(self, whence = None): @property def drift(self): #-- elapsed time between head and its anchor. - return (self.head.when.datetime - self.anchor.when.datetime) + return (self.latest - self.earliest) @property def isAnchor(self): diff --git a/lib/Bastion/Vaults/Common.py b/lib/Bastion/Vaults/Common.py index 77d0aae..07dac8e 100644 --- a/lib/Bastion/Vaults/Common.py +++ b/lib/Bastion/Vaults/Common.py @@ -3,6 +3,7 @@ """ import logging +from Bastion.Common import tag import Bastion.Model from Bastion.Vaults.CARP import PushRequest, PushReceipt import Bastion.Packers.TARs @@ -52,9 +53,9 @@ def push(self, asset, basis = None, **kwargs): packing.record.tarp.unlink() if movement.failed: - return request.failed( PushReceipt(tag(packing, 'packed'), tag(movement, 'moved')) ) + return request.failed( receipt ) else: - return request.succeeded( PushReceipt(tag(packing, 'packed'), tag(movement, 'moved')) ) + return request.succeeded( receipt ) def pull(self, ark, **kwargs): raise NotImplementedError