-- -- --- --- --- --- --- --- ------- ------- ------- |
"""
-- -- --- --- --- --- --- --- ------- ------- ------- |
For managing the state of the wily process.
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
Contains a lazy revision, index and process state model.
-- -- --- --- --- --- --- --- ------- ------- ------- |
"""
-- -- --- --- --- --- --- --- ------- ------- ------- |
from collections import OrderedDict
-- -- --- --- --- --- --- --- ------- ------- ------- |
from dataclasses import asdict, dataclass
-- -- --- --- --- --- --- --- ------- ------- ------- |
from pathlib import Path
-- -- --- --- --- --- --- --- ------- ------- ------- |
from typing import Any, Dict, List, Optional, Union
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
from wily import cache, logger
-- -- --- --- --- --- --- --- ------- ------- ------- |
from wily.archivers import Archiver, BaseArchiver, Revision, resolve_archiver
-- -- --- --- --- --- --- --- ------- ------- ------- |
from wily.config.types import WilyConfig
-- -- --- --- --- --- --- --- ------- ------- ------- |
from wily.operators import Operator, get_metric
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
@dataclass
03 -- --- --- --- --- --- --- ------- ------- ------- |
class IndexedRevision:
03 -- --- --- --- --- --- --- ------- ------- ------- |
"""Union of revision and the operators executed."""
03 -- --- --- --- --- --- --- ------- ------- ------- |
03 -- --- --- --- --- --- --- ------- ------- ------- |
revision: Revision
03 -- --- --- --- --- --- --- ------- ------- ------- |
operators: List
03 -- --- --- --- --- --- --- ------- ------- ------- |
_data = None
03 -- --- --- --- --- --- --- ------- ------- ------- |
03 -- --- --- --- --- --- --- ------- ------- ------- |
@staticmethod
03 06 001 006 005 010 007 015 0042.11 0035.09 0000.83 |
def fromdict(d: Dict[str, Any]) -> "IndexedRevision":
03 06 001 006 005 010 007 015 0042.11 0035.09 0000.83 |
"""Instantiate from a dictionary."""
03 06 001 006 005 010 007 015 0042.11 0035.09 0000.83 |
rev = Revision(
03 06 001 006 005 010 007 015 0042.11 0035.09 0000.83 |
key=d["key"],
03 06 001 006 005 010 007 015 0042.11 0035.09 0000.83 |
author_name=d["author_name"],
03 06 001 006 005 010 007 015 0042.11 0035.09 0000.83 |
author_email=d["author_email"],
03 06 001 006 005 010 007 015 0042.11 0035.09 0000.83 |
date=d["date"],
03 06 001 006 005 010 007 015 0042.11 0035.09 0000.83 |
message=d["message"],
03 06 001 006 005 010 007 015 0042.11 0035.09 0000.83 |
tracked_files=d["tracked_files"] if "tracked_files" in d else [],
03 06 001 006 005 010 007 015 0042.11 0035.09 0000.83 |
tracked_dirs=d["tracked_dirs"] if "tracked_dirs" in d else [],
03 06 001 006 005 010 007 015 0042.11 0035.09 0000.83 |
added_files=d["added_files"] if "added_files" in d else [],
03 06 001 006 005 010 007 015 0042.11 0035.09 0000.83 |
modified_files=d["modified_files"] if "modified_files" in d else [],
03 06 001 006 005 010 007 015 0042.11 0035.09 0000.83 |
deleted_files=d["deleted_files"] if "deleted_files" in d else [],
03 06 001 006 005 010 007 015 0042.11 0035.09 0000.83 |
)
03 06 001 006 005 010 007 015 0042.11 0035.09 0000.83 |
operators = d["operators"]
03 06 001 006 005 010 007 015 0042.11 0035.09 0000.83 |
return IndexedRevision(revision=rev, operators=operators)
03 -- --- --- --- --- --- --- ------- ------- ------- |
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def asdict(self) -> Dict[str, Any]:
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""Convert to dictionary."""
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
d = asdict(self.revision)
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
d["operators"] = self.operators
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
return d
03 -- --- --- --- --- --- --- ------- ------- ------- |
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
def get(
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
self, config: WilyConfig, archiver: str, operator: str, path: str, key: str
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
) -> Any:
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
"""
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
Get the metric data for this indexed revision.
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:param config: The wily config.
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:param archiver: The archiver.
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:param operator: The operator to find
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:param path: The path to find
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:param key: The metric key
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
"""
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
if not self._data:
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
self._data = cache.get(
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
config=config, archiver=archiver, revision=self.revision.key
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
)["operator_data"]
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
logger.debug(f"Fetching metric {path} - {key} for operator {operator}")
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
return get_metric(self._data, operator, path, key)
03 -- --- --- --- --- --- --- ------- ------- ------- |
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
def get_paths(self, config: WilyConfig, archiver: str, operator: str) -> List[str]:
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
"""
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
Get the indexed paths for this indexed revision.
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:param config: The wily config.
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:param archiver: The archiver.
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:param operator: The operator to find
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:return: A list of paths
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
"""
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
if not self._data:
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
self._data = cache.get(
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
config=config, archiver=archiver, revision=self.revision.key
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
)["operator_data"]
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
logger.debug("Fetching keys")
03 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
return list(self._data[operator].keys())
03 -- --- --- --- --- --- --- ------- ------- ------- |
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def store(
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self, config: WilyConfig, archiver: Union[Archiver, str], stats: Dict[str, Any]
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
) -> Path:
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
Store the stats for this indexed revision.
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param config: The wily config.
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param archiver: The archiver.
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param stats: The data
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self._data = stats
03 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
return cache.store(config, archiver, self.revision, stats)
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- |
class Index:
02 -- --- --- --- --- --- --- ------- ------- ------- |
"""The index of the wily cache."""
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- |
archiver: Archiver
02 -- --- --- --- --- --- --- ------- ------- ------- |
config: WilyConfig
02 -- --- --- --- --- --- --- ------- ------- ------- |
operators = None
02 -- --- --- --- --- --- --- ------- ------- ------- |
data: List[Any]
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def __init__(self, config: WilyConfig, archiver: Archiver):
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
Instantiate a new index.
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param config: The wily config.
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param archiver: The archiver.
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.config = config
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.archiver = archiver
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.data = (
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
cache.get_archiver_index(config, archiver.name)
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
if cache.has_archiver_index(config, archiver.name)
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
else []
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
)
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self._revisions = OrderedDict(
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
{d["key"]: IndexedRevision.fromdict(d) for d in self.data}
02 -- 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
)
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def __len__(self):
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""Use length of revisions as len."""
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
return len(self._revisions)
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- |
@property
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def last_revision(self) -> IndexedRevision:
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""Return the most recent revision."""
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
return next(iter(self._revisions.values()))
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- |
@property
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def revisions(self) -> List[IndexedRevision]:
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""List of all the revisions."""
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
return list(self._revisions.values())
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- |
@property
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def revision_keys(self) -> List[str]:
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""List of all the revision indexes."""
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
return list(self._revisions.keys())
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
def __contains__(self, item: Union[str, Revision]) -> bool:
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
"""Check if index contains `item`."""
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
if isinstance(item, Revision):
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
return item.key in self._revisions
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
elif isinstance(item, str):
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
return item in self._revisions
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
else:
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
raise TypeError("Invalid type for __contains__ in Index.")
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def __getitem__(self, index) -> IndexedRevision:
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""Get the revision for a specific index."""
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
return self._revisions[index]
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def add(self, revision: Revision, operators: List[Operator]) -> IndexedRevision:
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
Add a revision to the index.
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param revision: The revision.
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param operators: Operators for the revision.
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
ir = IndexedRevision(
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
revision=revision, operators=[operator.name for operator in operators]
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
)
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self._revisions[revision.key] = ir
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
return ir
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def save(self):
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""Save the index data back to the wily cache."""
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
data = [i.asdict() for i in self._revisions.values()]
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
logger.debug("Saving data")
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
cache.store_archiver_index(self.config, self.archiver, data)
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
04 -- --- --- --- --- --- --- ------- ------- ------- |
class State:
04 -- --- --- --- --- --- --- ------- ------- ------- |
"""
04 -- --- --- --- --- --- --- ------- ------- ------- |
The wily process state.
04 -- --- --- --- --- --- --- ------- ------- ------- |
04 -- --- --- --- --- --- --- ------- ------- ------- |
Includes indexes for each archiver.
04 -- --- --- --- --- --- --- ------- ------- ------- |
"""
04 -- --- --- --- --- --- --- ------- ------- ------- |
04 -- --- --- --- --- --- --- ------- ------- ------- |
archivers: List[str]
04 -- --- --- --- --- --- --- ------- ------- ------- |
config: WilyConfig
04 -- --- --- --- --- --- --- ------- ------- ------- |
index: Dict[str, Index]
04 -- --- --- --- --- --- --- ------- ------- ------- |
default_archiver: str
04 -- --- --- --- --- --- --- ------- ------- ------- |
operators: Optional[List[Operator]] = None
04 -- --- --- --- --- --- --- ------- ------- ------- |
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def __init__(
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self,
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
config: WilyConfig,
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
archiver: Optional[Union[Archiver, BaseArchiver]] = None,
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
):
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
Instantiate a new process state.
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param config: The wily configuration.
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param archiver: The archiver (optional).
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
if archiver:
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.archivers = [archiver.name]
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
else:
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.archivers = cache.list_archivers(config)
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
logger.debug(f"Initialised state indexes for archivers {self.archivers}")
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.config = config
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.index = {}
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
for _archiver in self.archivers:
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.index[_archiver] = Index(self.config, resolve_archiver(_archiver))
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.default_archiver = self.archivers[0]
04 -- --- --- --- --- --- --- ------- ------- ------- |
04 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
def ensure_exists(self):
04 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
"""Ensure that cache directory exists."""
04 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
if not cache.exists(self.config):
04 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
logger.debug("Wily cache not found, creating.")
04 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
cache.create(self.config)
04 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
logger.debug("Created wily cache")
04 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
else:
04 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
logger.debug(f"Cache {self.config.cache_path} exists")