diff --git a/src/ria_toolkit_oss/agent/cli.py b/src/ria_toolkit_oss/agent/cli.py index 83a7769..eb5d818 100644 --- a/src/ria_toolkit_oss/agent/cli.py +++ b/src/ria_toolkit_oss/agent/cli.py @@ -25,6 +25,9 @@ from .hardware import available_devices from .legacy_executor import main as _legacy_main from .namegen import generate_agent_name +# Switch to "https://riahub.ai" when targeting production. +DEFAULT_HUB_URL = "http://localhost:3000" + _LEGACY_ALIASES = {"--hub", "--key", "--name", "--device", "--insecure", "--log-level", "--config"} @@ -140,7 +143,7 @@ def main() -> None: sub.add_parser("detect", help="List available SDR drivers") p_reg = sub.add_parser("register", help="Register agent with RIA Hub and save credentials") - p_reg.add_argument("--hub", required=True, help="RIA Hub URL (e.g. http://whitehorse:3005)") + p_reg.add_argument("--hub", default=DEFAULT_HUB_URL, help=f"RIA Hub URL (default: {DEFAULT_HUB_URL})") p_reg.add_argument("--api-key", dest="api_key", required=True, help="Hub API key") p_reg.add_argument("--name", default=None, help="Human-friendly agent name") p_reg.add_argument("--insecure", action="store_true", help="Skip TLS verification") diff --git a/src/ria_toolkit_oss_cli/cli.py b/src/ria_toolkit_oss_cli/cli.py index bf97dfa..088c908 100644 --- a/src/ria_toolkit_oss_cli/cli.py +++ b/src/ria_toolkit_oss_cli/cli.py @@ -2,15 +2,40 @@ This module contains the main group for the ria toolkit oss CLI. """ +import subprocess +import sys + import click from ria_toolkit_oss_cli.ria_toolkit_oss import commands +def _git_lfs_installed() -> bool: + """Return True if git-lfs is available on PATH.""" + try: + return subprocess.run( + ["git", "lfs", "version"], + capture_output=True, + ).returncode == 0 + except FileNotFoundError: + return False + + @click.group() @click.option("-v", "--verbose", is_flag=True, type=bool, help="Increase verbosity, especially useful for debugging.") def cli(verbose): - pass + if not _git_lfs_installed(): + click.echo( + "Warning: git-lfs is not installed. RIA Hub projects require git-lfs to\n" + "track large binary files (models, recordings, datasets).\n" + "\n" + " Linux: sudo apt-get install git-lfs\n" + " macOS: brew install git-lfs\n" + " Other platforms: https://git-lfs.com\n" + "\n" + "After installing, run: git lfs install", + err=True, + ) # Loop through project commands, binding them all to the CLI. diff --git a/src/ria_toolkit_oss_cli/ria_toolkit_oss/commands.py b/src/ria_toolkit_oss_cli/ria_toolkit_oss/commands.py index 174a5f4..4a003f2 100644 --- a/src/ria_toolkit_oss_cli/ria_toolkit_oss/commands.py +++ b/src/ria_toolkit_oss_cli/ria_toolkit_oss/commands.py @@ -20,6 +20,7 @@ from .split import split from .transform import transform from .transmit import transmit from .view import view +from .setup_repo import setup_repo # Aliases synth = generate diff --git a/src/ria_toolkit_oss_cli/ria_toolkit_oss/setup_repo.py b/src/ria_toolkit_oss_cli/ria_toolkit_oss/setup_repo.py new file mode 100644 index 0000000..6cbb2d8 --- /dev/null +++ b/src/ria_toolkit_oss_cli/ria_toolkit_oss/setup_repo.py @@ -0,0 +1,129 @@ +"""ria setup-repo — configure a local git repo as a RIA Hub Project.""" + +import os +import re +import subprocess +import sys + +import click + +RIA_LFS_RULES = [ + ("*.pt", "filter=lfs diff=lfs merge=lfs -text"), + ("*.pth", "filter=lfs diff=lfs merge=lfs -text"), + ("*.onnx", "filter=lfs diff=lfs merge=lfs -text"), + ("*.sigmf", "filter=lfs diff=lfs merge=lfs -text"), + ("*.sigmf-data", "filter=lfs diff=lfs merge=lfs -text"), + ("*.sigmf-meta", "filter=lfs diff=lfs merge=lfs -text"), + ("*.npy", "filter=lfs diff=lfs merge=lfs -text"), + ("*.npz", "filter=lfs diff=lfs merge=lfs -text"), + ("*.h5", "filter=lfs diff=lfs merge=lfs -text"), + ("*.hdf5", "filter=lfs diff=lfs merge=lfs -text"), + ("*.bin", "filter=lfs diff=lfs merge=lfs -text"), + ("*.pkl", "filter=lfs diff=lfs merge=lfs -text"), +] + + +def _tracked_patterns(ga_path: str) -> set: + """Return the set of glob patterns already in .gitattributes.""" + if not os.path.exists(ga_path): + return set() + patterns = set() + with open(ga_path, encoding="utf-8") as f: + for line in f: + line = line.strip() + if not line or line.startswith("#"): + continue + m = re.match(r"^(\S+)\s+", line) + if m: + patterns.add(m.group(1)) + return patterns + + +@click.command("setup_repo") +@click.option( + "--path", + default=".", + show_default=True, + help="Path to the git repository (default: current directory).", +) +@click.option( + "--remote", + default=None, + metavar="URL", + help="RIA Hub remote URL to add as 'origin'.", +) +def setup_repo(path: str, remote: str | None) -> None: + """Configure a local directory as a RIA Hub Project repo. + + Installs git-lfs locally and writes .gitattributes with the RIA Hub + LFS tracking rules. Run this once after cloning or initialising a repo. + """ + repo_path = os.path.abspath(path) + + # 1. Verify this is a git repository. + if not os.path.isdir(os.path.join(repo_path, ".git")): + click.echo( + f"Error: '{repo_path}' is not a git repository.\n" + "Run 'git init' first, or use --path to point at an existing repo.", + err=True, + ) + sys.exit(1) + + # 2. Verify git-lfs is installed. + if subprocess.run(["git", "lfs", "version"], capture_output=True).returncode != 0: + click.echo( + "Error: git-lfs is not installed.\n" + "Get it at: https://git-lfs.com", + err=True, + ) + sys.exit(1) + + # 3. Install git-lfs hooks for this repo. + subprocess.run( + ["git", "-C", repo_path, "lfs", "install", "--local"], + check=True, + capture_output=True, + ) + click.echo("git lfs install --local: done") + + # 4. Write .gitattributes (append only new rules). + ga_path = os.path.join(repo_path, ".gitattributes") + existing = _tracked_patterns(ga_path) + new_rules = [(p, a) for p, a in RIA_LFS_RULES if p not in existing] + + if new_rules: + with open(ga_path, "a", encoding="utf-8") as f: + # Ensure we start on a fresh line. + if os.path.exists(ga_path) and os.path.getsize(ga_path) > 0: + with open(ga_path, encoding="utf-8") as rf: + content = rf.read() + if content and not content.endswith("\n"): + f.write("\n") + for pattern, attrs in new_rules: + f.write(f"{pattern} {attrs}\n") + click.echo(f".gitattributes: {len(new_rules)} rule(s) added") + else: + click.echo(".gitattributes: all RIA Hub rules are already present, nothing added") + + # 5. Optionally set the remote origin. + if remote: + result = subprocess.run( + ["git", "-C", repo_path, "remote", "add", "origin", remote], + capture_output=True, + text=True, + ) + if result.returncode != 0: + if "already exists" in result.stderr: + click.echo(f"remote 'origin' already exists, skipping (use git remote set-url to change it)") + else: + click.echo(f"Warning: could not add remote: {result.stderr.strip()}", err=True) + else: + click.echo(f"remote origin: {remote}") + + # 6. Print next steps. + click.echo( + "\nRepo is ready. Commit the updated .gitattributes and push:\n" + " git add .gitattributes\n" + " git commit -m 'chore: add RIA Hub LFS rules'\n" + " git push -u origin main" + )