Plain is headed towards 1.0! Subscribe for development updates →

  1import subprocess
  2import sys
  3from pathlib import Path
  4
  5import click
  6
  7from plain.cli import register_cli
  8
  9
 10@register_cli("contrib")
 11@click.command("contribute", hidden=True)
 12@click.option("--repo", default="../plain", help="Path to the plain repo")
 13@click.option(
 14    "--reset", is_flag=True, help="Undo any changes to pyproject.toml and uv.lock"
 15)
 16@click.option(
 17    "--all", "all_packages", is_flag=True, help="Link all installed plain packages"
 18)
 19@click.argument("packages", nargs=-1)
 20def cli(packages, repo, reset, all_packages):
 21    """Contribute to plain by linking packages locally."""
 22
 23    if reset:
 24        click.secho("Undoing any changes to pyproject.toml and uv.lock", bold=True)
 25        result = subprocess.run(["git", "checkout", "pyproject.toml", "uv.lock"])
 26        if result.returncode:
 27            click.secho("Failed to checkout pyproject.toml and uv.lock", fg="red")
 28            sys.exit(result.returncode)
 29
 30        click.secho("Running uv sync", bold=True)
 31        result = subprocess.run(["uv", "sync", "--reinstall"])
 32        if result.returncode:
 33            click.secho("Failed to sync", fg="red")
 34            sys.exit(result.returncode)
 35
 36        return
 37
 38    packages = list(packages)
 39
 40    repo = Path(repo)
 41    if not repo.exists():
 42        click.secho(f"Repo not found at {repo}", fg="red")
 43        return
 44
 45    repo_branch = (
 46        subprocess.check_output(
 47            [
 48                "git",
 49                "rev-parse",
 50                "--abbrev-ref",
 51                "HEAD",
 52            ],
 53            cwd=repo,
 54        )
 55        .decode()
 56        .strip()
 57    )
 58    click.secho(f"Using repo at {repo} ({repo_branch} branch)", bold=True)
 59
 60    plain_packages = []
 61    plainx_packages = []
 62    skipped_plainx_packages = []
 63
 64    if all_packages:
 65        # get all installed plain packages
 66        output = subprocess.check_output(["uv", "pip", "freeze"])
 67
 68        installed_packages = output.decode()
 69        if not installed_packages:
 70            click.secho("No installed packages found", fg="red")
 71            sys.exit(1)
 72
 73        packages = []
 74        for line in installed_packages.splitlines():
 75            if not line.startswith("plain"):
 76                continue
 77            package = line.split("==")[0]
 78            if package.startswith("plainx-"):
 79                skipped_plainx_packages.append(package)
 80            else:
 81                packages.append(package)
 82
 83        if skipped_plainx_packages:
 84            click.secho(
 85                "Skipping plainx packages: "
 86                + ", ".join(sorted(skipped_plainx_packages))
 87                + " (unknown repo)",
 88                fg="yellow",
 89            )
 90
 91    for package in packages:
 92        package = package.replace(".", "-")
 93        click.secho(f"Linking {package} to {repo}", bold=True)
 94        if package == "plain" or package.startswith("plain-"):
 95            plain_packages.append(str(repo / package))
 96        elif package.startswith("plainx-"):
 97            plainx_packages.append(str(repo))
 98        else:
 99            click.secho(f"Unknown package {package}", fg="red")
100            sys.exit(2)
101
102    if plain_packages:
103        result = subprocess.run(["uv", "add", "--editable", "--dev"] + plain_packages)
104        if result.returncode:
105            click.secho("Failed to link plain packages", fg="red")
106            sys.exit(result.returncode)
107
108    if plainx_packages:
109        result = subprocess.run(["uv", "add", "--editable", "--dev"] + plainx_packages)
110        if result.returncode:
111            click.secho("Failed to link plainx packages", fg="red")
112            sys.exit(result.returncode)