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:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user