Skip to content

Commit 51a2fcc

Browse files
authored
Merge pull request #86 from entangled/develop
merge from develop
2 parents 4949b24 + 011ff65 commit 51a2fcc

30 files changed

Lines changed: 241 additions & 174 deletions

entangled/commands/brei.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import textwrap
66

77
from ..config import Config, read_config
8+
from ..io import FileCache
89
from brei import resolve_tasks, Phony
910
from ..logging import logger
1011
from .main import main
@@ -18,7 +19,7 @@ async def brei_main(target_strs: list[str], force_run: bool, throttle: int | Non
1819
if not Path(".entangled").exists():
1920
Path(".entangled").mkdir()
2021

21-
cfg = Config() | read_config()
22+
cfg = Config() | read_config(FileCache())
2223
db = await resolve_tasks(cfg.brei, Path(".entangled/brei_history"))
2324
if throttle:
2425
db.throttle = asyncio.Semaphore(throttle)

entangled/commands/main.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,4 @@ def main(version: bool = False, debug: bool = False):
2020
sys.exit(0)
2121

2222
configure(debug)
23-
logger().debug(f"Welcome to Entangled v{__version__}!")
24-
23+
logger().info(f"Welcome to Entangled v{__version__}!")

entangled/commands/reset.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,10 @@ def reset():
2020
Resets the file database. This performs a tangle without actually
2121
writing output to the files, but updating the database as if we were.
2222
"""
23-
24-
try:
25-
doc = Document()
26-
mode = TransactionMode.RESETDB
23+
doc = Document()
24+
mode = TransactionMode.RESETDB
2725

28-
with transaction(mode) as t:
29-
doc.load(t)
30-
doc.tangle(t)
31-
t.clear_orphans()
32-
33-
except UserError as e:
34-
logging.error(str(e))
26+
with transaction(mode) as t:
27+
doc.load(t)
28+
doc.tangle(t)
29+
t.clear_orphans()

entangled/commands/status.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from collections.abc import Iterable
33
from ..status import list_dependent_files
44
from ..config import Config, read_config, get_input_files
5+
from ..io import FileCache
56
from pathlib import Path
67

78
from rich.console import Console, Group
@@ -30,7 +31,8 @@ def files_panel(file_list: Iterable[Path], title: str) -> Panel:
3031

3132

3233
def rich_status():
33-
cfg = Config() | read_config()
34+
fs = FileCache()
35+
cfg = Config() | read_config(fs)
3436
config_table = Table()
3537
config_table.add_column("name")
3638
config_table.add_column("value")
@@ -47,7 +49,7 @@ def rich_status():
4749
Panel(config_table, title="config", border_style="dark_cyan"),
4850
Columns(
4951
[
50-
files_panel(get_input_files(cfg), "input files"),
52+
files_panel(get_input_files(fs, cfg), "input files"),
5153
files_panel(list_dependent_files(), "dependent files"),
5254
]
5355
),

entangled/commands/stitch.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,9 @@ def stitch(*, force: bool = False, show: bool = False):
1919
else:
2020
mode = TransactionMode.FAIL
2121

22-
try:
23-
doc = Document()
22+
doc = Document()
2423

25-
with transaction(mode) as t:
26-
doc.load(t)
27-
doc.load_all_code(t)
28-
doc.stitch(t)
29-
30-
except UserError as e:
31-
e.handle()
24+
with transaction(mode) as t:
25+
doc.load(t)
26+
doc.load_all_code(t)
27+
doc.stitch(t)

entangled/commands/sync.py

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ class Action(Enum):
1616

1717

1818
def sync_action(doc: Document) -> Action:
19-
input_file_list = doc.input_files()
2019
fs = FileCache()
20+
input_file_list = doc.input_files(fs)
2121

2222
with filedb(readonly=True) as db:
2323
changed = set(db.changed_files(fs))
@@ -59,29 +59,24 @@ def stitch(doc: Document):
5959
doc.tangle(t)
6060
for h in doc.context.all_hooks:
6161
h.post_tangle(doc.reference_map)
62-
6362

64-
def run_sync():
65-
try:
66-
doc = Document()
67-
match sync_action(doc):
68-
case Action.TANGLE:
69-
logging.info("Tangling.")
70-
tangle(doc)
7163

72-
case Action.STITCH:
73-
logging.info("Stitching.")
74-
stitch(doc)
64+
def run_sync():
65+
doc = Document()
66+
match sync_action(doc):
67+
case Action.TANGLE:
68+
logging.info("Tangling.")
69+
tangle(doc)
7570

76-
case Action.NOTHING:
77-
pass
71+
case Action.STITCH:
72+
logging.info("Stitching.")
73+
stitch(doc)
7874

79-
except UserError as e:
80-
e.handle()
75+
case Action.NOTHING:
76+
pass
8177

8278

8379
@main.command()
8480
def sync():
8581
"""Be smart wether to tangle or stich"""
8682
run_sync()
87-

entangled/commands/tangle.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,12 @@ def tangle(*, annotate: AnnotationMethod | None = None, force: bool = False, sho
2222
else:
2323
mode = TransactionMode.FAIL
2424

25-
try:
26-
doc = Document()
25+
doc = Document()
2726

28-
with transaction(mode) as t:
29-
doc.load(t)
30-
doc.tangle(t, annotate)
31-
t.clear_orphans()
27+
with transaction(mode) as t:
28+
doc.load(t)
29+
doc.tangle(t, annotate)
30+
t.clear_orphans()
3231

33-
for h in doc.context.all_hooks:
34-
h.post_tangle(doc.reference_map)
35-
36-
except UserError as e:
37-
e.handle()
32+
for h in doc.context.all_hooks:
33+
h.post_tangle(doc.reference_map)

entangled/commands/watch.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,17 @@ def _watch(_stop_event: Event | None = None, _start_event: Event | None = None):
2727
def stop() -> bool:
2828
return _stop_event is not None and _stop_event.is_set()
2929

30+
log.debug("Running daemon")
3031
run_sync()
3132

32-
if _start_event:
33+
if _start_event is not None:
34+
log.debug("Setting start event")
3335
_start_event.set()
3436

3537
dirs = "." # find_watch_dirs()
36-
38+
3739
for changes in watchfiles.watch(dirs, stop_event=_stop_event, watch_filter=watch_filter):
38-
log.debug(changes)
40+
log.debug(changes)
3941
run_sync()
4042

4143

entangled/config/__init__.py

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@
2020
from ..logging import logger
2121
from ..version import __version__
2222
from ..errors.user import HelpfulUserError
23-
23+
from ..io import AbstractFileCache
2424

2525
log = logger()
2626

2727

2828
def read_config_from_toml(
29-
path: Path, section: str | None = None
29+
fs: AbstractFileCache, path: Path, section: str | None = None
3030
) -> ConfigUpdate | None:
3131
"""Read a config from given `path` in given `section`. The path should refer to
3232
a TOML file that should decode to a `Config` object. If `section` is given, only
@@ -39,17 +39,17 @@ def read_config_from_toml(
3939
read_config_from_toml(Path("./pyproject.toml"), "tool.entangled")
4040
```
4141
"""
42-
if not path.exists():
42+
if path not in fs:
4343
return None
4444
try:
45-
with open(path, "rb") as f:
46-
json: Any = tomllib.load(f) # pyright: ignore[reportExplicitAny]
47-
if section is not None:
48-
for s in section.split("."):
49-
json = json[s] # pyright: ignore[reportAny]
50-
update = msgspec.convert(json, type=ConfigUpdate)
51-
log.debug("Read config from `%s`", path)
52-
return update
45+
content = fs[path].content
46+
json: Any = tomllib.loads(content)
47+
if section is not None:
48+
for s in section.split("."):
49+
json = json[s] # pyright: ignore[reportAny]
50+
update = msgspec.convert(json, type=ConfigUpdate)
51+
log.debug("Read config from `%s`", path)
52+
return update
5353

5454
except (msgspec.ValidationError, tomllib.TOMLDecodeError) as e:
5555
raise HelpfulUserError(f"Could not read config: {e}")
@@ -59,23 +59,33 @@ def read_config_from_toml(
5959
return None
6060

6161

62-
def read_config() -> ConfigUpdate | None:
63-
if Path("./entangled.toml").exists():
64-
return read_config_from_toml(Path("./entangled.toml"))
65-
if Path("./pyproject.toml").exists():
62+
def read_config(fs: AbstractFileCache) -> ConfigUpdate | None:
63+
"""
64+
Read configuration from any of the possible hard-coded locations:
65+
66+
- `./entangled.toml`
67+
- `./pyproject.toml` section `[tool.entangled]`.
68+
69+
Returns a `ConfigUpdate` or `None`. To get the full `Config` object,
70+
run `Config() | read_config(fs)`.
71+
"""
72+
if Path("./entangled.toml") in fs:
73+
return read_config_from_toml(fs, Path("./entangled.toml"))
74+
if Path("./pyproject.toml") in fs:
6675
return (
67-
read_config_from_toml(Path("./pyproject.toml"), "tool.entangled")
76+
read_config_from_toml(fs, Path("./pyproject.toml"), "tool.entangled")
6877
)
6978
return None
7079

7180

72-
def get_input_files(cfg: Config) -> list[Path]:
81+
def get_input_files(fs: AbstractFileCache, cfg: Config) -> list[Path]:
82+
"""
83+
Get a sorted list of all input files for this project.
84+
"""
7385
log.debug("watch list: %s; ignoring: %s", cfg.watch_list, cfg.ignore_list)
74-
include_file_list = chain.from_iterable(map(Path(".").glob, cfg.watch_list))
75-
input_file_list = [
76-
path for path in include_file_list
77-
if not any(path.match(pat) for pat in cfg.ignore_list) and path.is_file()
78-
]
86+
input_file_list = filter(
87+
lambda p: not any(p.match(pat) for pat in cfg.ignore_list),
88+
chain.from_iterable(map(fs.glob, cfg.watch_list)))
7989
log.debug("input file list %s", input_file_list)
8090
return sorted(input_file_list)
8191

entangled/hooks/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,15 @@
2525
} | external_hooks
2626

2727

28-
def create_hook(cfg: Config, h: str) -> HookBase | None:
28+
def create_hook(cfg: Config, h: str, state: HookBase.State) -> HookBase | None:
2929
if h not in hooks:
3030
logging.error("hook `%s` not found", h)
3131
return None
3232

3333
try:
34-
hook_cfg = msgspec.convert(cfg.hook.get(h, {}), type=hooks[h].Config)
35-
hook_instance = hooks[h](hook_cfg)
34+
hook_cls = hooks[h]
35+
hook_cfg = msgspec.convert(cfg.hook.get(h, {}), type=hook_cls.Config)
36+
hook_instance = hook_cls(hook_cfg, state)
3637
hook_instance.check_prerequisites()
3738
return hook_instance
3839
except PrerequisitesFailed as e:

0 commit comments

Comments
 (0)