efficient build

- postpone building until really needed
- rebuild only if artifacts change
- no build on source update
- prune takes current resolver state instead of global var
This commit is contained in:
relikd
2022-04-13 15:41:57 +02:00
parent 8ae5376d41
commit 1d9629566c
8 changed files with 302 additions and 270 deletions

View File

@@ -1,16 +1,15 @@
from lektor.build_programs import BuildProgram # subclass
from lektor.builder import Artifact # typing
from lektor.context import get_ctx
from lektor.db import Record # typing
from lektor.environment import Expression
from lektor.sourceobj import VirtualSourceObject # subclass
from lektor.utils import build_url
from typing import Dict, List, Any, Optional, Iterator
from weakref import WeakSet
from .config import Config
from .pruner import track_not_prune
from typing import TYPE_CHECKING, Dict, List, Any, Optional, Iterator
from .backref import VGroups
from .util import report_config_error
if TYPE_CHECKING:
from lektor.builder import Artifact
from lektor.db import Record
from .config import Config
VPATH = '@groupby' # potentially unsafe. All matching entries are pruned.
@@ -28,15 +27,16 @@ class GroupBySource(VirtualSourceObject):
def __init__(
self,
record: Record,
record: 'Record',
group: str,
config: Config,
children: Optional[Dict[Record, List[Any]]] = None,
config: 'Config',
children: Optional[Dict['Record', List[Any]]] = None,
) -> None:
super().__init__(record)
self.key = config.slugify(group)
self.group = group
self.config = config
self._children = children or {} # type: Dict[Record, List[Any]]
# evaluate slug Expression
if config.slug and '{key}' in config.slug:
self.slug = config.slug.replace('{key}', self.key)
@@ -45,16 +45,12 @@ class GroupBySource(VirtualSourceObject):
assert self.slug != Ellipsis, 'invalid config: ' + config.slug
if self.slug and self.slug.endswith('/index.html'):
self.slug = self.slug[:-10]
# make sure children are on the same pad
self._children = {} # type: Dict[Record, List[Any]]
for child, extras in (children or {}).items():
if child.pad != record.pad:
child = record.pad.get(child.path)
self._children[child] = extras
VGroups.of(child).add(self)
# extra fields
for attr, expr in config.fields.items():
setattr(self, attr, self._eval(expr, field='fields.' + attr))
# back-ref
for child in self._children:
VGroups.of(child).add(self)
def _eval(self, value: Any, *, field: str) -> Any:
''' Internal only: evaluates Lektor config file field expression. '''
@@ -94,12 +90,12 @@ class GroupBySource(VirtualSourceObject):
# -----------------------
@property
def children(self) -> Dict[Record, List[Any]]:
def children(self) -> Dict['Record', List[Any]]:
''' Returns dict with page record key and (optional) extra value. '''
return self._children
@property
def first_child(self) -> Optional[Record]:
def first_child(self) -> Optional['Record']:
''' Returns first referencing page record. '''
if self._children:
return iter(self._children).__next__()
@@ -139,44 +135,6 @@ class GroupBySource(VirtualSourceObject):
self.path, len(self._children))
# -----------------------------------
# Reverse Reference
# -----------------------------------
class VGroups:
@staticmethod
def of(record: Record) -> WeakSet:
try:
wset = record.__vgroups # type: ignore[attr-defined]
except AttributeError:
wset = WeakSet()
record.__vgroups = wset # type: ignore[attr-defined]
return wset # type: ignore[no-any-return]
@staticmethod
def iter(
record: Record,
*keys: str,
recursive: bool = False
) -> Iterator[GroupBySource]:
''' Extract all referencing groupby virtual objects from a page. '''
ctx = get_ctx()
# manage dependencies
if ctx:
for dep in ctx.env.plugins['groupby'].config_dependencies:
ctx.record_dependency(dep)
# find groups
proc_list = [record]
while proc_list:
page = proc_list.pop(0)
if recursive and hasattr(page, 'children'):
proc_list.extend(page.children) # type: ignore[attr-defined]
for vobj in VGroups.of(page):
vobj.config.dependencies
if not keys or vobj.config.key in keys:
yield vobj
# -----------------------------------
# BuildProgram
# -----------------------------------
@@ -190,9 +148,8 @@ class GroupByBuildProgram(BuildProgram):
url += 'index.html'
self.declare_artifact(url, sources=list(
self.source.iter_source_filenames()))
track_not_prune(url)
def build_artifact(self, artifact: Artifact) -> None:
def build_artifact(self, artifact: 'Artifact') -> None:
get_ctx().record_virtual_dependency(self.source)
artifact.render_template_into(
self.source.config.template, this=self.source)