1from pathlib import Path
2
3import click
4
5from plain.assets.finders import APP_ASSETS_DIR
6from plain.cli import register_cli
7
8from .deps import Dependency, get_deps
9from .exceptions import DependencyError
10
11VENDOR_DIR = APP_ASSETS_DIR / "vendor"
12
13
14@register_cli("vendor")
15@click.group()
16def cli():
17 """Vendor CSS/JS from a CDN"""
18 pass
19
20
21@cli.command()
22def sync():
23 """Clear vendored assets and re-download"""
24 click.secho("Clearing existing vendored dependencies...", bold=True)
25 if VENDOR_DIR.exists():
26 for path in VENDOR_DIR.iterdir():
27 path.unlink()
28
29 deps = get_deps()
30 if not deps:
31 click.echo(
32 "No vendored dependencies found in pyproject.toml. Use [tool.plain.vendor.dependencies]"
33 )
34 return
35
36 errors = []
37
38 for dep in deps:
39 click.secho(f"Installing {dep.name}...", bold=True, nl=False)
40 try:
41 vendored_path = dep.install()
42 except DependencyError as e:
43 click.secho(f" {e}", fg="red")
44 errors.append(e)
45
46 vendored_path = vendored_path.relative_to(Path.cwd())
47
48 click.secho(f" {dep.installed}", fg="green", nl=False)
49 click.secho(f" -> {vendored_path}")
50
51 if errors:
52 click.secho("Failed to install some dependencies.", fg="red")
53 exit(1)
54
55
56@cli.command()
57@click.argument("name", nargs=-1, default=None)
58def update(name):
59 """Update vendored dependencies in pyproject.toml"""
60 deps = get_deps()
61 if not deps:
62 click.echo(
63 "No vendored dependencies found in pyproject.toml. Use [tool.plain.vendor.dependencies]"
64 )
65 return
66
67 errors = []
68
69 if name:
70 deps = [dep for dep in deps if dep.name in name]
71 if len(deps) != len(name):
72 not_found = set(name) - {dep.name for dep in deps}
73 click.secho(
74 f"Some dependencies not found: {', '.join(not_found)}", fg="red"
75 )
76 exit(1)
77
78 for dep in deps:
79 click.secho(f"Updating {dep.name} {dep.installed}...", bold=True, nl=False)
80 try:
81 vendored_path = dep.update()
82 vendored_path = vendored_path.relative_to(Path.cwd())
83
84 click.secho(f" {dep.installed}", fg="green", nl=False)
85 click.secho(f" -> {vendored_path}")
86 except DependencyError as e:
87 click.secho(f" {e}", fg="red")
88 errors.append(e)
89
90 if errors:
91 click.secho("Failed to install some dependencies.", fg="red")
92 exit(1)
93
94
95@cli.command()
96@click.argument("url")
97@click.option("--name", help="Name of the dependency")
98@click.option("--sourcemap/--no-sourcemap", default=True, help="Download sourcemap")
99def add(url, name, sourcemap):
100 """Add a new vendored dependency to pyproject.toml"""
101 if not name:
102 name = url.split("/")[-1]
103
104 dep = Dependency(name, url=url, sourcemap=sourcemap)
105
106 click.secho(f"Installing {dep.name}", bold=True, nl=False)
107
108 try:
109 vendored_path = dep.update()
110 except DependencyError as e:
111 click.secho(f" {e}", fg="red")
112 exit(1)
113
114 vendored_path = vendored_path.relative_to(Path.cwd())
115
116 click.secho(f" {dep.installed}", fg="green", nl=False)
117 click.secho(f" -> {vendored_path}")
118
119 if not dep.installed:
120 click.secho(
121 "No version was parsed from the url. You can configure it manually if you need to.",
122 fg="yellow",
123 )