Mercurial > piecrust2
view piecrust/baking/records.py @ 412:a1567766c83c
internal: Allow re-registering performance timers.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sat, 20 Jun 2015 19:15:57 -0700 |
parents | e7b865f8f335 |
children | 0e9a94b7fdfa |
line wrap: on
line source
import copy import os.path import hashlib import logging from piecrust.records import Record, TransitionalRecord logger = logging.getLogger(__name__) def _get_transition_key(path, taxonomy_info=None): key = path if taxonomy_info: key += '+%s:%s=' % (taxonomy_info.source_name, taxonomy_info.taxonomy_name) if isinstance(taxonomy_info.term, tuple): key += '/'.join(taxonomy_info.term) else: key += taxonomy_info.term return hashlib.md5(key.encode('utf8')).hexdigest() class BakeRecord(Record): RECORD_VERSION = 14 def __init__(self): super(BakeRecord, self).__init__() self.out_dir = None self.bake_time = None self.timers = None self.success = True class BakePassInfo(object): def __init__(self): self.used_source_names = set() self.used_taxonomy_terms = set() class SubPageBakeInfo(object): FLAG_NONE = 0 FLAG_BAKED = 2**0 FLAG_FORCED_BY_SOURCE = 2**1 FLAG_FORCED_BY_NO_PREVIOUS = 2**2 FLAG_FORCED_BY_PREVIOUS_ERRORS = 2**3 FLAG_FORMATTING_INVALIDATED = 2**4 def __init__(self, out_uri, out_path): self.out_uri = out_uri self.out_path = out_path self.flags = self.FLAG_NONE self.errors = [] self.render_passes = {} @property def was_clean(self): return (self.flags & self.FLAG_BAKED) == 0 and len(self.errors) == 0 @property def was_baked(self): return (self.flags & self.FLAG_BAKED) != 0 @property def was_baked_successfully(self): return self.was_baked and len(self.errors) == 0 def collapseRenderPasses(self, other): for p, pinfo in self.render_passes.items(): if p not in other.render_passes: other.render_passes[p] = copy.deepcopy(pinfo) class PageBakeInfo(object): def __init__(self): self.subs = [] self.assets = [] class FirstRenderInfo(object): def __init__(self): self.assets = [] self.used_pagination = False self.pagination_has_more = False class TaxonomyInfo(object): def __init__(self, taxonomy_name, source_name, term): self.taxonomy_name = taxonomy_name self.source_name = source_name self.term = term class BakeRecordEntry(object): """ An entry in the bake record. The `taxonomy_info` attribute should be a tuple of the form: (taxonomy name, term, source name) """ FLAG_NONE = 0 FLAG_NEW = 2**0 FLAG_SOURCE_MODIFIED = 2**1 FLAG_OVERRIDEN = 2**2 def __init__(self, source_name, path, taxonomy_info=None): self.source_name = source_name self.path = path self.taxonomy_info = taxonomy_info self.flags = self.FLAG_NONE self.config = None self.errors = [] self.bake_info = None self.first_render_info = None @property def path_mtime(self): return os.path.getmtime(self.path) @property def was_overriden(self): return (self.flags & self.FLAG_OVERRIDEN) != 0 @property def num_subs(self): if self.bake_info is None: return 0 return len(self.bake_info.subs) @property def was_any_sub_baked(self): if self.bake_info is not None: for o in self.bake_info.subs: if o.was_baked: return True return False @property def subs(self): if self.bake_info is not None: return self.bake_info.subs return [] @property def has_any_error(self): if len(self.errors) > 0: return True if self.bake_info is not None: for o in self.bake_info.subs: if len(o.errors) > 0: return True return False def getSub(self, sub_index): if self.bake_info is None: raise Exception("No bake info available on this entry.") return self.bake_info.subs[sub_index - 1] def getAllErrors(self): yield from self.errors if self.bake_info is not None: for o in self.bake_info.subs: yield from o.errors def getAllUsedSourceNames(self): res = set() if self.bake_info is not None: for o in self.bake_info.subs: for p, pinfo in o.render_passes.items(): res |= pinfo.used_source_names return res def getAllUsedTaxonomyTerms(self): res = set() if self.bake_info is not None: for o in self.bake_info.subs: for p, pinfo in o.render_passes.items(): res |= pinfo.used_taxonomy_terms return res class TransitionalBakeRecord(TransitionalRecord): def __init__(self, previous_path=None): super(TransitionalBakeRecord, self).__init__(BakeRecord, previous_path) self.dirty_source_names = set() def addEntry(self, entry): if (self.previous.bake_time and entry.path_mtime >= self.previous.bake_time): entry.flags |= BakeRecordEntry.FLAG_SOURCE_MODIFIED self.dirty_source_names.add(entry.source_name) super(TransitionalBakeRecord, self).addEntry(entry) def getTransitionKey(self, entry): return _get_transition_key(entry.path, entry.taxonomy_info) def getPreviousAndCurrentEntries(self, path, taxonomy_info=None): key = _get_transition_key(path, taxonomy_info) pair = self.transitions.get(key) return pair def getOverrideEntry(self, path, uri): for pair in self.transitions.values(): cur = pair[1] if cur and cur.path != path: for o in cur.subs: if o.out_uri == uri: return cur return None def getPreviousEntry(self, path, taxonomy_info=None): pair = self.getPreviousAndCurrentEntries(path, taxonomy_info) if pair is not None: return pair[0] return None def getCurrentEntry(self, path, taxonomy_info=None): pair = self.getPreviousAndCurrentEntries(path, taxonomy_info) if pair is not None: return pair[1] return None def collapseEntry(self, prev_entry): cur_entry = copy.deepcopy(prev_entry) cur_entry.flags = BakeRecordEntry.FLAG_NONE for o in cur_entry.subs: o.flags = SubPageBakeInfo.FLAG_NONE self.addEntry(cur_entry) def getDeletions(self): for prev, cur in self.transitions.values(): if prev and not cur: for sub in prev.subs: yield (sub.out_path, 'previous source file was removed') elif prev and cur: prev_out_paths = [o.out_path for o in prev.subs] cur_out_paths = [o.out_path for o in cur.subs] diff = set(prev_out_paths) - set(cur_out_paths) for p in diff: yield (p, 'source file changed outputs') def _onNewEntryAdded(self, entry): entry.flags |= BakeRecordEntry.FLAG_NEW