Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions autotest/test_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from types import SimpleNamespace

import pytest

from modflow_devtools import cli


class _Registry:
def __init__(self, release_id, cache_path, error=None):
self.release_id = release_id
self.cache_path = cache_path
self._error = error

def sync(self):
if self._error:
raise self._error


class _ModelConfig:
def __init__(self, failed):
self._failed = failed

def sync(self):
return {"src": SimpleNamespace(failed=self._failed)}


@pytest.fixture
def fake_registries(monkeypatch, tmp_path):
def _fake(dfn_error=None, model_failed=()):
from modflow_devtools.dfns.registry import RemoteDfnRegistry
from modflow_devtools.models import ModelSourceConfig

registry = _Registry("owner/repo@1.0", tmp_path, dfn_error)
monkeypatch.setattr(RemoteDfnRegistry, "load_default", lambda: {"r": registry})
monkeypatch.setattr(ModelSourceConfig, "load", lambda: _ModelConfig(list(model_failed)))

return _fake


def test_sync_all_succeeds(fake_registries, capsys):
fake_registries()
assert cli._sync_all() == 0
assert "All registries synced!" in capsys.readouterr().out


def test_sync_all_fails_on_dfn_error(fake_registries, capsys):
fake_registries(dfn_error=OSError("no network"))
assert cli._sync_all() == 1
assert "Failed to sync owner/repo@1.0: no network" in capsys.readouterr().out


def test_sync_all_fails_on_model_error(fake_registries, capsys):
fake_registries(model_failed=[("current", "models.toml not found")])
assert cli._sync_all() == 1
assert "Models synced successfully" not in capsys.readouterr().out
38 changes: 27 additions & 11 deletions modflow_devtools/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,32 @@
import sys


def _sync_all():
def _sync_all() -> int:
"""Sync all registries (dfns, models). The Programs API has no registry to sync -
it installs directly from GitHub releases and tracks installs in a local ledger."""
it installs directly from GitHub releases and tracks installs in a local ledger.
Returns 0 if everything synced, 1 if anything failed."""
print("Syncing all registries...")
print()
failed = False

# Sync DFNs
print("=== DFNs ===")
try:
from modflow_devtools.dfns.registry import sync_dfns

registries = sync_dfns()
for registry in registries:
meta = registry.registry_meta
print(f" {registry.ref}: {len(meta.files)} files")
from modflow_devtools.dfns.registry import RemoteDfnRegistry

registries = RemoteDfnRegistry.load_default()
for registry in registries.values():
try:
registry.sync()
n_files = len(list(registry.cache_path.glob("*.*")))
print(f" {registry.release_id}: {n_files} files")
except Exception as e:
print(f" [-] Failed to sync {registry.release_id}: {e}")
failed = True
print(f"Synced {len(registries)} DFN registry(ies)")
except Exception as e:
print(f"Error syncing DFNs: {e}")
failed = True
print()

# Sync Models
Expand All @@ -47,13 +55,21 @@ def _sync_all():
from modflow_devtools.models import ModelSourceConfig

config = ModelSourceConfig.load()
config.sync()
print("Models synced successfully")
results = config.sync()
if any(result.failed for result in results.values()):
failed = True
else:
print("Models synced successfully")
except Exception as e:
print(f"Error syncing models: {e}")
failed = True
print()

if failed:
print("Some registries failed to sync.")
return 1
print("All registries synced!")
return 0


def main():
Expand Down Expand Up @@ -85,7 +101,7 @@ def main():

# Dispatch to the appropriate module CLI with remaining args
if args.subcommand == "sync":
_sync_all()
sys.exit(_sync_all())
elif args.subcommand == "dfns":
from modflow_devtools.dfns.__main__ import main as dfns_main

Expand Down
Loading