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)