Skip to content

Commit 45e6850

Browse files
Add entrypoint script
1 parent 2aa880c commit 45e6850

File tree

9 files changed

+88
-24
lines changed

9 files changed

+88
-24
lines changed

src/deploy/__main__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def build(force: bool, extra_scripts: str) -> None:
114114
def links() -> None:
115115
configpath = Path.cwd()
116116
config = load_config(configpath)
117-
make_links(config, prefix=Args.prefix)
117+
make_links(config.links, prefix=Args.prefix)
118118

119119

120120
@cli.command(help="Run tests in ./deploy_tests using pytest")
@@ -135,10 +135,10 @@ def test(args: tuple[str, ...]) -> None:
135135
for pkg in plist.packages.values():
136136
os.environ[f"{pkg.config.name}_version"] = pkg.config.version
137137

138-
for name, dest in plist.envs:
138+
for name, dest, _ in plist.envs:
139139
os.environ[f"{name}_env"] = f"{Args.prefix / dest}"
140140

141-
for name, dest in plist.envs:
141+
for name, dest, _ in plist.envs:
142142
pkg = plist.packages[name]
143143
for path in (plist.prefix / dest).glob("*/manifest"):
144144
if path.read_text() == pkg.manifest:

src/deploy/build.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from deploy.package import Package
1717
from deploy.package_list import PackageList
1818
from deploy.utils import redirect_output
19+
from deploy.links import make_links
1920

2021

2122
def _checkout(pkg: Package) -> None:
@@ -151,12 +152,14 @@ def _build_packages(self) -> None:
151152
_build(pkg, tmp)
152153

153154
def _build_envs(self) -> None:
154-
for name, dest in self.package_list.envs:
155+
for name, dest, entrypoint in self.package_list.envs:
155156
pkg = self.packages[name]
156157
path = self._get_build_path(self.package_list.prefix / dest, pkg)
157158
if path is None:
158159
continue
159160
self._build_env_for_package(path, pkg)
161+
self._create_default_symlinks(self.package_list.prefix / dest, path)
162+
self._create_wrapper_script(dest, pkg, entrypoint)
160163

161164
def _build_env_for_package(self, base: Path, finalpkg: Package) -> None:
162165
for pkg in chain([finalpkg], finalpkg.depends):
@@ -188,3 +191,39 @@ def _get_build_path(self, base: Path, finalpkg: Package) -> Path | None:
188191
sys.exit(
189192
f"Out of range while trying to find a build number for {finalpkg.config.version}"
190193
)
194+
195+
def _create_wrapper_script(
196+
self, dest: str, pkg: Package, entrypoint: str | None
197+
) -> None:
198+
if entrypoint is None:
199+
return
200+
201+
bin_dir = self.package_list.prefix / "bin"
202+
bin_dir.mkdir(parents=True, exist_ok=True)
203+
204+
wrapper_script = bin_dir / "run"
205+
206+
script_content = f"""#!/usr/bin/env bash
207+
# Auto-generated wrapper script for {pkg.config.name}
208+
209+
VERSION="${{1:-stable}}"
210+
BASE_DIR="$(dirname "$(dirname "$(readlink -f "${{BASH_SOURCE[0]}}")")")"
211+
VERSIONS_DIR="$BASE_DIR/{dest}"
212+
213+
ENTRY_POINT="$VERSIONS_DIR/$VERSION/{entrypoint}"
214+
215+
if [ ! -f "$ENTRY_POINT" ]; then
216+
echo "Error: Entry point not found: $ENTRY_POINT" >&2
217+
exit 1
218+
fi
219+
220+
exec "$ENTRY_POINT" "${{@:2}}"
221+
"""
222+
223+
wrapper_script.write_text(script_content)
224+
wrapper_script.chmod(0o755)
225+
226+
def _create_default_symlinks(self, base: Path, target: Path) -> None:
227+
rel_base = base.relative_to(self.package_list.prefix)
228+
default_links = {str(rel_base): {"latest": "^", "stable": "latest"}}
229+
make_links(default_links, prefix=self.package_list.prefix, force=False)

src/deploy/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class BuildConfig(BaseModel):
2828
class EnvConfig(BaseModel):
2929
name: str
3030
dest: str
31+
entrypoint: str | None = None
3132

3233

3334
class PathConfig(BaseModel):

src/deploy/links.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import os
44
import sys
55

6-
from deploy.config import Config
76
from pathlib import Path
87
from semver import Version
98

@@ -45,12 +44,21 @@ def validate(base: Path) -> None:
4544
print(f"'{name}' links to '{target}' which doesn't exist!", file=sys.stderr)
4645

4746

48-
def make_links(config: Config, *, prefix: Path) -> None:
49-
for subdir, links in config.links.items():
50-
for source, target in links.items():
47+
def make_links(
48+
links: dict[str, dict[str, str]],
49+
prefix: Path,
50+
force: bool = True,
51+
) -> None:
52+
for subdir, link_specs in links.items():
53+
for source, target in link_specs.items():
5154
path = prefix / subdir / source
55+
56+
if not force and path.exists():
57+
continue
58+
5259
if target == "^":
5360
target = get_latest(prefix / subdir)
61+
5462
path.unlink(missing_ok=True)
5563
path.symlink_to(target)
5664
print(f"Created symlink: {path} -> {target}")

src/deploy/package_list.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ def __init__(
4646
[self.packages[x] for x in build.depends],
4747
)
4848

49-
self.envs: list[tuple[str, str]] = [(e.name, e.dest) for e in config.envs]
49+
self.envs: list[tuple[str, str, str | None]] = [
50+
(e.name, e.dest, e.entrypoint) for e in config.envs
51+
]
5052

5153
if check_scripts:
5254
self._check_scripts_exist()

src/deploy/sync.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ def __init__(
4949
if not (path.parent).is_symlink()
5050
if plist.packages[name].manifest == path.read_text()
5151
]
52-
for name, dest in plist.envs
52+
for name, dest, _ in plist.envs
5353
}
5454

5555
# Create symlinking script
5656
self._post_script = io.StringIO()
5757
self._post_script.write("set -euxo pipefail\n")
58-
for _, dest in plist.envs:
58+
for _, dest, _ in plist.envs:
5959
self._post_script.write(f"mkdir -p {self._dest_prefix / dest}\n")
6060
self._post_script.writelines(
6161
f"ln -sfn {os.readlink(path)} {change_prefix(path, plist.prefix, self._dest_prefix)} \n"

tests/test_build.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,24 @@ def test_clean_package_cache_on_rebuild(
223223
call_args[0][0][1] for call_args in mocked_subprocess.run.call_args_list
224224
]
225225
assert "clean" in git_commands
226+
227+
228+
def test_default_symlinks_created_on_build(tmp_path, base_config):
229+
(tmp_path / "build_test.sh").write_text("#!/bin/bash\nmkdir -p $out/bin\n")
230+
(tmp_path / "build_test.sh").chmod(0o755)
231+
232+
base_config["builds"].append({"name": "test", "version": "1.0.0"})
233+
base_config["envs"].append({"name": "test", "dest": "versions"})
234+
235+
config = Config.model_validate(base_config)
236+
builder = Build(tmp_path, config, extra_scripts=tmp_path, prefix=tmp_path)
237+
builder.build()
238+
239+
stable_link = tmp_path / "versions" / "stable"
240+
latest_link = tmp_path / "versions" / "latest"
241+
242+
assert stable_link.is_symlink()
243+
assert latest_link.is_symlink()
244+
assert str(stable_link.readlink()) == "latest"
245+
assert str(latest_link.readlink()) == "1.0.0-1"
246+
assert stable_link.resolve() == latest_link.resolve()

tests/test_links.py

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from pathlib import Path
44

55
from deploy.links import make_links
6-
from deploy.config import Config
76

87

98
@pytest.fixture
@@ -25,47 +24,41 @@ def _setup_env(tmp_path, base_config):
2524

2625
def test_make_links(tmp_path, base_config):
2726
_setup_env(tmp_path, base_config)
28-
config = Config.model_validate(base_config)
29-
make_links(config, prefix=tmp_path)
27+
make_links(base_config["links"], prefix=tmp_path)
3028
assert (tmp_path / "location/symlink").exists()
3129

3230

3331
def test_make_links_fail_missing_target(tmp_path, base_config):
34-
# Note the lack of setting up environment, hence no target file exists
35-
config = Config.model_validate(base_config)
3632
with pytest.raises(FileNotFoundError, match="No such file or directory: 'target'"):
37-
make_links(config, prefix=tmp_path)
33+
make_links(base_config["links"], prefix=tmp_path)
3834

3935

4036
def test_make_links_on_new_package_resolves_latest(tmp_path, base_config):
4137
base_config["links"] = {"location": {"cool": "^"}}
42-
config = Config.model_validate(base_config)
4338

4439
(tmp_path / "location" / "1.0.0").mkdir(parents=True)
4540
(tmp_path / "location" / "1.0.1").mkdir(parents=True)
4641

47-
make_links(config, prefix=tmp_path)
42+
make_links(base_config["links"], prefix=tmp_path)
4843
assert os.path.islink(tmp_path / "location/cool")
4944
assert os.path.realpath(tmp_path / "location/cool") == str(
5045
(tmp_path / "location" / "1.0.1")
5146
)
5247

53-
# Lets create a new version
5448
(tmp_path / "location" / "1.0.2").mkdir(parents=True)
55-
make_links(config, prefix=tmp_path)
49+
make_links(base_config["links"], prefix=tmp_path)
5650
assert os.path.realpath(tmp_path / "location/cool") == str(
5751
(tmp_path / "location" / "1.0.2")
5852
)
5953

6054

6155
def test_some(tmp_path, base_config):
6256
base_config["links"] = {"location": {"1.0": "1.0.1"}}
63-
config = Config.model_validate(base_config)
6457

6558
(tmp_path / "location" / "1.0.0").mkdir(parents=True)
6659
(tmp_path / "location" / "1.0.1").mkdir(parents=True)
6760

68-
make_links(config, prefix=tmp_path)
61+
make_links(base_config["links"], prefix=tmp_path)
6962
assert os.path.islink(tmp_path / "location/1.0")
7063
assert os.path.realpath(tmp_path / "location/1.0") == str(
7164
(tmp_path / "location" / "1.0.1")

tests/test_sync.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def test_successful_sync(tmp_path, base_config):
9999

100100
builder = _deploy_config(base_config, tmp_path)
101101

102-
make_links(base_config, prefix=tmp_path)
102+
make_links(base_config.links, prefix=tmp_path)
103103
pkg = builder.packages["A"]
104104
installed_file_path = pkg.out / "bin/a_file"
105105
assert installed_file_path.exists()

0 commit comments

Comments
 (0)