Compare commits

..

No commits in common. "0562772dc877bc9dc707af7cf62cc47320c567e9" and "73c9e684238de549a94b97ccede4929d029c1adf" have entirely different histories.

4 changed files with 43 additions and 62 deletions

View file

@ -1,4 +1,4 @@
__version__ = "0.2.5-5"
__version__ = "0.2.5"
__author__ = "Reid D. 'arrdem' McKenzie <me@arrdem.com>"
__copyright__ = "Copyright 2020"
__license__ = "https://anticapitalist.software/"

View file

@ -3,6 +3,8 @@
import logging
import os
import pickle
import platform
import re
from collections import defaultdict
from pathlib import Path
from pprint import pformat
@ -16,7 +18,6 @@ from vfs import Vfs
from . import __author__, __copyright__, __license__, __version__
from .v0 import PackageV0, ProfileV0
from .v1 import LightPackageV1, PackageV1, ProfileV1
from .common import expandvars
log = logging.getLogger(__name__)
@ -59,6 +60,29 @@ def upsearch(name: Union[str, Path], limit=10) -> Optional[Path]:
limit -= 1
def expandvars(s: str) -> str:
def _repl(m: re.Match) -> str:
var = m.group(0).lower()
match var:
case "${hostname}":
return os.uname()[1].split(".")[0]
case "${fqdn}":
return os.uname()[1]
case "${home}":
return os.path.expanduser("~")
case "${uname}" | "${sysname}":
return platform.system().lower()
case "${arch}":
return platform.machine()
case "${release}":
return platform.release()
case _:
return os.path.expandvars(m.group(0))
s = re.sub(r"\${?([^\s}]+)}?", "${\\1}", s)
return re.sub(r"\$\{.*?\}", _repl, s)
def handle_vars(_ctx, _param, s):
return expandvars(s)
@ -194,10 +218,6 @@ def load_state(statefile: Path) -> Vfs:
return oldfs
def remove_all(l, it):
return [i for i in l if i != it]
def simplify(old_fs: Vfs, new_fs: Vfs, /, exec_idempotent=True) -> Vfs:
"""Try to reduce a new VFS using diff from the original VFS."""
@ -206,12 +226,15 @@ def simplify(old_fs: Vfs, new_fs: Vfs, /, exec_idempotent=True) -> Vfs:
initial_new_steps = len(new_fs._log)
# Scrub anything in the new log that's in the old log
for txn in old_fs._log:
for txn in list(old_fs._log):
# Except for execs which are stateful
if txn[0] == "exec" and not exec_idempotent:
continue
new_fs._log = remove_all(new_fs._log, txn)
try:
new_fs._log.remove(txn)
except ValueError:
pass
# Dedupe the new log while preserving order.
keys = set()
@ -221,7 +244,6 @@ def simplify(old_fs: Vfs, new_fs: Vfs, /, exec_idempotent=True) -> Vfs:
if key not in keys:
keys.add(key)
deduped.append(op)
new_fs._log = deduped
log.info(f"Optimized out {initial_new_steps - len(new_fs._log)} steps")
@ -256,8 +278,6 @@ def configure(ctx, param, filename: Optional[Path]):
log.debug(f"Loading config from {filename}")
ctx.obj = cfg = toml.load(filename)
assert cfg["cram"]["version"] >= 1
cfg["cram"]["config"] = str(filename.absolute())
cfg["cram"]["root"] = str(filename.absolute().parent)
task_cfg = cfg.get("cram", {}).get("task", {})
defaults = task_cfg.get("default", {})
@ -579,7 +599,6 @@ version = 1
confdir = "${PWD}"
destdir = "${HOME}"
state_file = "${PWD}/.cram.log"
cache_dir = "${HOME}/.cache/cram"
optimize = true
exec_idempotent = true
# Where to load requirements from, and the requirement type

View file

@ -5,8 +5,6 @@ import sys
from pathlib import Path
from shlex import quote as sh_quote
from typing import List, Optional
import re
import platform
from vfs import Vfs
@ -49,8 +47,8 @@ def stow(fs: Vfs, src_dir: Path, dest_dir: Path, skip=[]):
dest = dest_root / src.relative_to(src_root)
if src.is_symlink():
fs.link(src.readlink().resolve(), dest)
fs.link(src.readlink().resolve(), dest)
elif src.is_dir():
fs.mkdir(dest)
fs.chmod(dest, src.stat().st_mode)
@ -88,26 +86,3 @@ class Package(object):
def post_install(self, fs: Vfs, dest: Path):
pass
def expandvars(s: str) -> str:
def _repl(m: re.Match) -> str:
var = m.group(0).lower()
match var:
case "${hostname}":
return os.uname()[1].split(".")[0]
case "${fqdn}":
return os.uname()[1]
case "${home}":
return os.path.expanduser("~")
case "${uname}" | "${sysname}":
return platform.system().lower()
case "${arch}":
return platform.machine()
case "${release}":
return platform.release()
case _:
return os.path.expandvars(m.group(0))
s = re.sub(r"\${?([^\s}]+)}?", "${\\1}", s)
return re.sub(r"\$\{.*?\}", _repl, s)

View file

@ -12,17 +12,13 @@ from typing import List, Optional, Union
import toml
from vfs import Vfs
from .common import Package, sh, stow, expandvars
from .common import Package, sh, stow
def tempf(global_config, name):
root = Path(global_config["cram"]["root"])
assert root.exists() and root.is_dir()
cache_dir = global_config.get("cram", {}).get("task", {}).get("default", {}).get("cache_dir")
cache_root = cache_dir and Path(expandvars(cache_dir)) or root / ".cache"
return cache_root / name[0:2] / name
def tempf(name):
root = Path("/tmp/stow")
root.mkdir(exist_ok=True, parents=True)
return root / name
class PackageV1(Package):
@ -75,24 +71,15 @@ class PackageV1(Package):
sum = sum.hexdigest()
installf = self.root / content
def _installf_exists():
try:
return installf.exists()
except OSError as e:
return False
if content.startswith("#!") or "\n" in content or not _installf_exists():
f = tempf(self.global_config, f"{sum}.sh")
f.parent.mkdir(exist_ok=True, parents=True)
with open(f, "w") as fp:
fp.write(content)
fs.exec(cwd, sh(self.global_config, [str(f)]))
else:
if installf.exists():
with open(installf, "r") as fp:
self.do_sh_or_script(fp.read(), fs, dest)
elif content:
f = tempf(f"{sum}.sh")
with open(f, "w") as fp:
fp.write(content)
fs.exec(cwd, sh(self.global_config, [f]))
def do_build(self, fs: Vfs, dest: Path):
self.do_sh_or_script(self.config().get("package", {}).get("build"), fs, dest)