shipit-cli 0.1.3__py3-none-any.whl → 0.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- shipit/cli.py +192 -80
- shipit/generator.py +22 -6
- shipit/providers/base.py +11 -2
- shipit/providers/gatsby.py +7 -3
- shipit/providers/laravel.py +7 -2
- shipit/providers/mkdocs.py +7 -4
- shipit/providers/node_static.py +6 -2
- shipit/providers/php.py +8 -3
- shipit/providers/python.py +20 -11
- shipit/providers/staticfile.py +9 -3
- shipit/version.py +2 -2
- {shipit_cli-0.1.3.dist-info → shipit_cli-0.2.1.dist-info}/METADATA +1 -1
- shipit_cli-0.2.1.dist-info/RECORD +19 -0
- shipit_cli-0.1.3.dist-info/RECORD +0 -19
- {shipit_cli-0.1.3.dist-info → shipit_cli-0.2.1.dist-info}/WHEEL +0 -0
- {shipit_cli-0.1.3.dist-info → shipit_cli-0.2.1.dist-info}/entry_points.txt +0 -0
shipit/cli.py
CHANGED
|
@@ -40,6 +40,12 @@ app = typer.Typer(invoke_without_command=True)
|
|
|
40
40
|
DIR_PATH = Path(__file__).resolve().parent
|
|
41
41
|
ASSETS_PATH = DIR_PATH / "assets"
|
|
42
42
|
|
|
43
|
+
@dataclass
|
|
44
|
+
class Mount:
|
|
45
|
+
name: str
|
|
46
|
+
build_path: Path
|
|
47
|
+
serve_path: Path
|
|
48
|
+
|
|
43
49
|
|
|
44
50
|
@dataclass
|
|
45
51
|
class Serve:
|
|
@@ -51,7 +57,8 @@ class Serve:
|
|
|
51
57
|
assets: Optional[Dict[str, str]] = None
|
|
52
58
|
prepare: Optional[List["PrepareStep"]] = None
|
|
53
59
|
workers: Optional[List[str]] = None
|
|
54
|
-
mounts: Optional[
|
|
60
|
+
mounts: Optional[List[Mount]] = None
|
|
61
|
+
env: Optional[Dict[str, str]] = None
|
|
55
62
|
|
|
56
63
|
|
|
57
64
|
@dataclass
|
|
@@ -71,6 +78,11 @@ class RunStep:
|
|
|
71
78
|
group: Optional[str] = None
|
|
72
79
|
|
|
73
80
|
|
|
81
|
+
@dataclass
|
|
82
|
+
class WorkdirStep:
|
|
83
|
+
path: Path
|
|
84
|
+
|
|
85
|
+
|
|
74
86
|
@dataclass
|
|
75
87
|
class CopyStep:
|
|
76
88
|
source: str
|
|
@@ -96,7 +108,7 @@ class PathStep:
|
|
|
96
108
|
path: str
|
|
97
109
|
|
|
98
110
|
|
|
99
|
-
Step = Union[RunStep, CopyStep, EnvStep, PathStep, UseStep]
|
|
111
|
+
Step = Union[RunStep, CopyStep, EnvStep, PathStep, UseStep, WorkdirStep]
|
|
100
112
|
PrepareStep = Union[RunStep]
|
|
101
113
|
|
|
102
114
|
|
|
@@ -122,7 +134,7 @@ class MapperItem(TypedDict):
|
|
|
122
134
|
|
|
123
135
|
|
|
124
136
|
class Builder(Protocol):
|
|
125
|
-
def build(self, env: Dict[str, str], steps: List[Step]) -> None: ...
|
|
137
|
+
def build(self, env: Dict[str, str], mounts: List[Mount], steps: List[Step]) -> None: ...
|
|
126
138
|
def build_assets(self, assets: Dict[str, str]) -> None: ...
|
|
127
139
|
def build_prepare(self, serve: Serve) -> None: ...
|
|
128
140
|
def build_serve(self, serve: Serve) -> None: ...
|
|
@@ -135,6 +147,8 @@ class Builder(Protocol):
|
|
|
135
147
|
) -> Any: ...
|
|
136
148
|
def serve_mount(self, name: str) -> str: ...
|
|
137
149
|
def get_asset(self, name: str) -> str: ...
|
|
150
|
+
def get_build_mount_path(self, name: str) -> Path: ...
|
|
151
|
+
def get_serve_mount_path(self, name: str) -> Path: ...
|
|
138
152
|
|
|
139
153
|
|
|
140
154
|
class DockerBuilder:
|
|
@@ -142,6 +156,7 @@ class DockerBuilder:
|
|
|
142
156
|
self.src_dir = src_dir
|
|
143
157
|
self.docker_file_contents = ""
|
|
144
158
|
self.docker_path = self.src_dir / ".shipit" / "docker"
|
|
159
|
+
self.docker_out_path = self.docker_path / "out"
|
|
145
160
|
self.depot_metadata = self.docker_path / "depot-build.json"
|
|
146
161
|
self.docker_file_path = self.docker_path / "Dockerfile"
|
|
147
162
|
self.docker_name_path = self.docker_path / "name"
|
|
@@ -151,7 +166,20 @@ class DockerBuilder:
|
|
|
151
166
|
self.env = {
|
|
152
167
|
"HOME": "/root",
|
|
153
168
|
}
|
|
154
|
-
|
|
169
|
+
|
|
170
|
+
def get_mount_path(self, name: str) -> Path:
|
|
171
|
+
if name == "app":
|
|
172
|
+
return Path("app")
|
|
173
|
+
else:
|
|
174
|
+
return Path("opt") / name
|
|
175
|
+
|
|
176
|
+
def get_build_mount_path(self, name: str) -> Path:
|
|
177
|
+
path = Path("/") / self.get_mount_path(name)
|
|
178
|
+
return path
|
|
179
|
+
|
|
180
|
+
def get_serve_mount_path(self, name: str) -> Path:
|
|
181
|
+
return self.docker_out_path / self.get_mount_path(name)
|
|
182
|
+
|
|
155
183
|
@property
|
|
156
184
|
def is_depot(self) -> bool:
|
|
157
185
|
return self.docker_client == "depot"
|
|
@@ -169,10 +197,10 @@ class DockerBuilder:
|
|
|
169
197
|
self.docker_name_path.write_text(image_name)
|
|
170
198
|
self.print_dockerfile()
|
|
171
199
|
extra_args = []
|
|
172
|
-
if self.is_depot:
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
200
|
+
# if self.is_depot:
|
|
201
|
+
# # We load the docker image back into the local docker daemon
|
|
202
|
+
# # extra_args += ["--load"]
|
|
203
|
+
# extra_args += ["--save", f"--metadata-file={self.depot_metadata.absolute()}"]
|
|
176
204
|
sh.Command(self.docker_client)(
|
|
177
205
|
"build",
|
|
178
206
|
"-f",
|
|
@@ -181,6 +209,8 @@ class DockerBuilder:
|
|
|
181
209
|
image_name,
|
|
182
210
|
"--platform",
|
|
183
211
|
"linux/amd64",
|
|
212
|
+
"--output",
|
|
213
|
+
self.docker_out_path.absolute(),
|
|
184
214
|
".",
|
|
185
215
|
*extra_args,
|
|
186
216
|
_cwd=self.src_dir.absolute(),
|
|
@@ -188,25 +218,25 @@ class DockerBuilder:
|
|
|
188
218
|
_out=write_stdout,
|
|
189
219
|
_err=write_stderr,
|
|
190
220
|
)
|
|
191
|
-
if self.is_depot:
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
221
|
+
# if self.is_depot:
|
|
222
|
+
# json_text = self.depot_metadata.read_text()
|
|
223
|
+
# json_data = json.loads(json_text)
|
|
224
|
+
# build_data = json_data["depot.build"]
|
|
225
|
+
# image_id = build_data["buildID"]
|
|
226
|
+
# project = build_data["projectID"]
|
|
227
|
+
# sh.Command("depot")(
|
|
228
|
+
# "pull",
|
|
229
|
+
# "--platform",
|
|
230
|
+
# "linux/amd64",
|
|
231
|
+
# "--project",
|
|
232
|
+
# project,
|
|
233
|
+
# image_id,
|
|
234
|
+
# _cwd=self.src_dir.absolute(),
|
|
235
|
+
# _env=os.environ, # Pass the current environment variables to the Docker client
|
|
236
|
+
# _out=write_stdout,
|
|
237
|
+
# _err=write_stderr,
|
|
238
|
+
# )
|
|
239
|
+
# # console.print(f"[bold]Image ID:[/bold] {image_id}")
|
|
210
240
|
|
|
211
241
|
def finalize_build(self, serve: Serve) -> None:
|
|
212
242
|
console.print(f"\n[bold]Building Docker file[/bold]")
|
|
@@ -280,11 +310,11 @@ RUN chmod {oct(mode)[2:]} {path.absolute()}
|
|
|
280
310
|
else:
|
|
281
311
|
self.docker_file_contents += f"RUN pkgm install {dependency.name}\n"
|
|
282
312
|
|
|
283
|
-
def build(self, env: Dict[str, str], steps: List[Step]) -> None:
|
|
313
|
+
def build(self, env: Dict[str, str], mounts: List[Mount], steps: List[Step]) -> None:
|
|
284
314
|
base_path = self.docker_path
|
|
285
315
|
shutil.rmtree(base_path, ignore_errors=True)
|
|
286
316
|
base_path.mkdir(parents=True, exist_ok=True)
|
|
287
|
-
self.docker_file_contents = "FROM debian:bookworm-slim\n"
|
|
317
|
+
self.docker_file_contents = "FROM debian:bookworm-slim AS build\n"
|
|
288
318
|
self.docker_file_contents += """
|
|
289
319
|
RUN apt-get update \\
|
|
290
320
|
&& apt-get -y --no-install-recommends install sudo curl ca-certificates locate git zip unzip \\
|
|
@@ -295,13 +325,17 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
|
|
295
325
|
RUN curl https://pkgx.sh | sh
|
|
296
326
|
"""
|
|
297
327
|
# docker_file_contents += "RUN curl https://mise.run | sh\n"
|
|
298
|
-
|
|
299
|
-
RUN curl https://get.wasmer.io -sSfL | sh -s "v6.1.0-rc.3"
|
|
300
|
-
ENV PATH="/root/.wasmer/bin:${PATH}"
|
|
301
|
-
"""
|
|
302
|
-
|
|
328
|
+
# self.docker_file_contents += """
|
|
329
|
+
# RUN curl https://get.wasmer.io -sSfL | sh -s "v6.1.0-rc.3"
|
|
330
|
+
# ENV PATH="/root/.wasmer/bin:${PATH}"
|
|
331
|
+
# """
|
|
332
|
+
for mount in mounts:
|
|
333
|
+
self.docker_file_contents += f"RUN mkdir -p {mount.build_path.absolute()}\n"
|
|
334
|
+
|
|
303
335
|
for step in steps:
|
|
304
|
-
if isinstance(step,
|
|
336
|
+
if isinstance(step, WorkdirStep):
|
|
337
|
+
self.docker_file_contents += f"WORKDIR {step.path.absolute()}\n"
|
|
338
|
+
elif isinstance(step, RunStep):
|
|
305
339
|
if step.inputs:
|
|
306
340
|
pre = "\\\n " + "".join(
|
|
307
341
|
[
|
|
@@ -325,6 +359,12 @@ ENV PATH="/root/.wasmer/bin:${PATH}"
|
|
|
325
359
|
for dependency in step.dependencies:
|
|
326
360
|
self.add_dependency(dependency)
|
|
327
361
|
|
|
362
|
+
self.docker_file_contents += """
|
|
363
|
+
FROM scratch
|
|
364
|
+
"""
|
|
365
|
+
for mount in mounts:
|
|
366
|
+
self.docker_file_contents += f"COPY --from=build {mount.build_path} {mount.build_path}\n"
|
|
367
|
+
|
|
328
368
|
self.docker_ignore_path.write_text("""
|
|
329
369
|
.shipit
|
|
330
370
|
Shipit
|
|
@@ -384,14 +424,33 @@ class LocalBuilder:
|
|
|
384
424
|
self.src_dir = src_dir
|
|
385
425
|
self.local_path = self.src_dir / ".shipit" / "local"
|
|
386
426
|
self.prepare_bash_script = self.local_path / "prepare" / "prepare.sh"
|
|
427
|
+
self.build_path = self.local_path / "build"
|
|
428
|
+
self.workdir = self.build_path
|
|
429
|
+
|
|
430
|
+
def get_mount_path(self, name: str) -> Path:
|
|
431
|
+
if name == "app":
|
|
432
|
+
return self.build_path / "app"
|
|
433
|
+
else:
|
|
434
|
+
return self.build_path / "opt" / name
|
|
435
|
+
|
|
436
|
+
def get_build_mount_path(self, name: str) -> Path:
|
|
437
|
+
return self.get_mount_path(name)
|
|
387
438
|
|
|
388
|
-
def
|
|
439
|
+
def get_serve_mount_path(self, name: str) -> Path:
|
|
440
|
+
return self.get_mount_path(name)
|
|
441
|
+
|
|
442
|
+
def execute_step(self, step: Step, env: Dict[str, str]) -> None:
|
|
443
|
+
build_path = self.workdir
|
|
389
444
|
if isinstance(step, UseStep):
|
|
390
445
|
console.print(f"[bold]Using dependencies:[/bold] {step.dependencies}")
|
|
446
|
+
elif isinstance(step, WorkdirStep):
|
|
447
|
+
console.print(f"[bold]Working in {step.path}[/bold]")
|
|
448
|
+
self.workdir = step.path
|
|
391
449
|
elif isinstance(step, RunStep):
|
|
392
450
|
extra = ""
|
|
393
451
|
if step.inputs:
|
|
394
452
|
for input in step.inputs:
|
|
453
|
+
print(f"Copying {input} to {build_path / input}")
|
|
395
454
|
copy((self.src_dir / input), (build_path / input))
|
|
396
455
|
all_inputs = ", ".join(step.inputs)
|
|
397
456
|
extra = f" [bright_black]# using {all_inputs}[/bright_black]"
|
|
@@ -448,17 +507,17 @@ class LocalBuilder:
|
|
|
448
507
|
else:
|
|
449
508
|
raise Exception(f"Unknown step type: {type(step)}")
|
|
450
509
|
|
|
451
|
-
def build(self, env: Dict[str, str], steps: List[Step]) -> None:
|
|
510
|
+
def build(self, env: Dict[str, str], mounts: List[Mount], steps: List[Step]) -> None:
|
|
452
511
|
console.print(f"\n[bold]Building package[/bold]")
|
|
453
512
|
base_path = self.local_path
|
|
454
513
|
shutil.rmtree(base_path, ignore_errors=True)
|
|
455
514
|
base_path.mkdir(parents=True, exist_ok=True)
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
515
|
+
self.build_path.mkdir(exist_ok=True)
|
|
516
|
+
for mount in mounts:
|
|
517
|
+
mount.build_path.mkdir(parents=True, exist_ok=True)
|
|
459
518
|
for step in steps:
|
|
460
519
|
console.print(Rule(characters="-", style="bright_black"))
|
|
461
|
-
self.execute_step(step, env
|
|
520
|
+
self.execute_step(step, env)
|
|
462
521
|
|
|
463
522
|
if "PATH" in env:
|
|
464
523
|
path = base_path / ".path"
|
|
@@ -565,6 +624,15 @@ class LocalBuilder:
|
|
|
565
624
|
|
|
566
625
|
|
|
567
626
|
class WasmerBuilder:
|
|
627
|
+
def get_build_mount_path(self, name: str) -> Path:
|
|
628
|
+
return self.inner_builder.get_build_mount_path(name)
|
|
629
|
+
|
|
630
|
+
def get_serve_mount_path(self, name: str) -> Path:
|
|
631
|
+
if name == "app":
|
|
632
|
+
return Path("/app")
|
|
633
|
+
else:
|
|
634
|
+
return Path("/opt") / name
|
|
635
|
+
|
|
568
636
|
mapper: Dict[str, MapperItem] = {
|
|
569
637
|
"python": {
|
|
570
638
|
"dependencies": {
|
|
@@ -576,8 +644,6 @@ class WasmerBuilder:
|
|
|
576
644
|
"env": {
|
|
577
645
|
"PYTHONEXECUTABLE": "/bin/python",
|
|
578
646
|
"PYTHONHOME": "/cpython",
|
|
579
|
-
"PYTHONPATH": "/.venv/lib/python3.13/site-packages",
|
|
580
|
-
"HOME": "/app",
|
|
581
647
|
},
|
|
582
648
|
},
|
|
583
649
|
"php": {
|
|
@@ -616,24 +682,26 @@ class WasmerBuilder:
|
|
|
616
682
|
src_dir: Path,
|
|
617
683
|
registry: Optional[str] = None,
|
|
618
684
|
token: Optional[str] = None,
|
|
685
|
+
bin: Optional[Path] = None,
|
|
619
686
|
) -> None:
|
|
620
687
|
self.src_dir = src_dir
|
|
621
688
|
self.inner_builder = inner_builder
|
|
622
689
|
# The path where we store the directory of the wasmer app in the inner builder
|
|
623
|
-
self.wasmer_dir_path = Path(self.src_dir / ".shipit" / "
|
|
690
|
+
self.wasmer_dir_path = Path(self.src_dir / ".shipit" / "wasmer")
|
|
624
691
|
self.wasmer_registry = registry
|
|
625
692
|
self.wasmer_token = token
|
|
693
|
+
self.bin = bin.absolute() if bin else "wasmer"
|
|
626
694
|
self.default_env = {
|
|
627
695
|
"SHIPIT_PYTHON_EXTRA_INDEX_URL": "https://pythonindex.wasix.org/simple",
|
|
628
696
|
"SHIPIT_PYTHON_CROSS_PLATFORM": "wasix_wasm32",
|
|
629
|
-
|
|
697
|
+
"SHIPIT_PYTHON_PRECOMPILE": "true",
|
|
630
698
|
}
|
|
631
699
|
|
|
632
700
|
def getenv(self, name: str) -> Optional[str]:
|
|
633
701
|
return self.inner_builder.getenv(name) or self.default_env.get(name)
|
|
634
702
|
|
|
635
|
-
def build(self, env: Dict[str, str], build: List[Step]) -> None:
|
|
636
|
-
return self.inner_builder.build(env, build)
|
|
703
|
+
def build(self, env: Dict[str, str], mounts: List[Mount], build: List[Step]) -> None:
|
|
704
|
+
return self.inner_builder.build(env, mounts, build)
|
|
637
705
|
|
|
638
706
|
def build_assets(self, assets: Dict[str, str]) -> None:
|
|
639
707
|
return self.inner_builder.build_assets(assets)
|
|
@@ -643,9 +711,9 @@ class WasmerBuilder:
|
|
|
643
711
|
|
|
644
712
|
def build_prepare(self, serve: Serve) -> None:
|
|
645
713
|
print("Building prepare")
|
|
646
|
-
|
|
647
|
-
prepare_dir
|
|
648
|
-
env = {}
|
|
714
|
+
prepare_dir = (self.wasmer_dir_path / "prepare")
|
|
715
|
+
prepare_dir.mkdir(parents=True, exist_ok=True)
|
|
716
|
+
env = serve.env or {}
|
|
649
717
|
for dep in serve.deps:
|
|
650
718
|
if dep.name in self.mapper:
|
|
651
719
|
dep_env = self.mapper[dep.name].get("env")
|
|
@@ -663,19 +731,17 @@ class WasmerBuilder:
|
|
|
663
731
|
if isinstance(step, RunStep):
|
|
664
732
|
commands.append(step.command)
|
|
665
733
|
body = "\n".join(filter(None, [env_lines, *commands]))
|
|
666
|
-
|
|
667
|
-
Path(prepare_dir) / "prepare.sh",
|
|
734
|
+
(prepare_dir / "prepare.sh").write_text(
|
|
668
735
|
f"#!/bin/bash\ncd /app\n{body}",
|
|
669
|
-
mode=0o755,
|
|
670
736
|
)
|
|
737
|
+
(prepare_dir / "prepare.sh").chmod(0o755)
|
|
671
738
|
|
|
672
739
|
def finalize_build(self, serve: Serve) -> None:
|
|
673
740
|
inner = cast(Any, self.inner_builder)
|
|
674
741
|
inner.finalize_build(serve)
|
|
675
742
|
|
|
676
743
|
def prepare(self, env: Dict[str, str], prepare: List[PrepareStep]) -> None:
|
|
677
|
-
|
|
678
|
-
prepare_dir = inner.mkdir(Path("wasmer") / "prepare")
|
|
744
|
+
prepare_dir = (self.wasmer_dir_path / "prepare")
|
|
679
745
|
self.run_serve_command(
|
|
680
746
|
"bash",
|
|
681
747
|
extra_args=[
|
|
@@ -739,10 +805,10 @@ class WasmerBuilder:
|
|
|
739
805
|
inner = cast(Any, self.inner_builder)
|
|
740
806
|
if serve.assets:
|
|
741
807
|
fs.add("/assets", str((inner.get_path() / "assets").absolute()))
|
|
742
|
-
fs.add("/app", str(inner.get_build_path().absolute()))
|
|
808
|
+
# fs.add("/app", str(inner.get_build_path().absolute()))
|
|
743
809
|
if serve.mounts:
|
|
744
810
|
for mount in serve.mounts:
|
|
745
|
-
fs.add(mount,
|
|
811
|
+
fs.add(str(mount.serve_path.absolute()), str(self.inner_builder.get_serve_mount_path(mount.name).absolute()))
|
|
746
812
|
|
|
747
813
|
doc.add(nl())
|
|
748
814
|
if serve.commands:
|
|
@@ -760,8 +826,10 @@ class WasmerBuilder:
|
|
|
760
826
|
wasi_args = table()
|
|
761
827
|
wasi_args.add("cwd", "/app")
|
|
762
828
|
wasi_args.add("main-args", parts[1:])
|
|
763
|
-
env = program_binary.get("env")
|
|
764
|
-
if env
|
|
829
|
+
env = program_binary.get("env") or {}
|
|
830
|
+
if serve.env:
|
|
831
|
+
env.update(serve.env)
|
|
832
|
+
if env:
|
|
765
833
|
wasi_args.add(
|
|
766
834
|
"env",
|
|
767
835
|
[f"{k}={v}" for k, v in env.items()],
|
|
@@ -770,9 +838,7 @@ class WasmerBuilder:
|
|
|
770
838
|
command.add(title, wasi_args)
|
|
771
839
|
|
|
772
840
|
inner = cast(Any, self.inner_builder)
|
|
773
|
-
|
|
774
|
-
# Dump the wasmer_dir path to a file
|
|
775
|
-
self.wasmer_dir_path.write_text(str(wasmer_dir))
|
|
841
|
+
self.wasmer_dir_path.mkdir(parents=True, exist_ok=True)
|
|
776
842
|
|
|
777
843
|
manifest = doc.as_string().replace(
|
|
778
844
|
'[command."annotations.wasi"]', "[command.annotations.wasi]"
|
|
@@ -791,7 +857,7 @@ class WasmerBuilder:
|
|
|
791
857
|
expand=False,
|
|
792
858
|
)
|
|
793
859
|
console.print(manifest_panel, markup=False, highlight=True)
|
|
794
|
-
|
|
860
|
+
(self.wasmer_dir_path / "wasmer.toml").write_text(manifest)
|
|
795
861
|
|
|
796
862
|
# Crete app.yaml
|
|
797
863
|
yaml_config = {
|
|
@@ -811,7 +877,7 @@ class WasmerBuilder:
|
|
|
811
877
|
}
|
|
812
878
|
|
|
813
879
|
app_yaml = yaml.dump(yaml_config)
|
|
814
|
-
|
|
880
|
+
(self.wasmer_dir_path / "app.yaml").write_text(app_yaml)
|
|
815
881
|
|
|
816
882
|
# self.inner_builder.build_serve(serve)
|
|
817
883
|
|
|
@@ -823,14 +889,13 @@ class WasmerBuilder:
|
|
|
823
889
|
self, command: str, extra_args: Optional[List[str]] = None
|
|
824
890
|
) -> None:
|
|
825
891
|
console.print(f"\n[bold]Serving site[/bold]: running {command} command")
|
|
826
|
-
wasmer_path = self.wasmer_dir_path.read_text()
|
|
827
892
|
extra_args = extra_args or []
|
|
828
893
|
|
|
829
894
|
if self.wasmer_registry:
|
|
830
895
|
extra_args = [f"--registry={self.wasmer_registry}"] + extra_args
|
|
831
|
-
self.
|
|
832
|
-
|
|
833
|
-
["run", str(
|
|
896
|
+
self.run_command(
|
|
897
|
+
self.bin,
|
|
898
|
+
["run", str(self.wasmer_dir_path.absolute()), "--net", f"--command={command}", *extra_args],
|
|
834
899
|
)
|
|
835
900
|
|
|
836
901
|
def serve_mount(self, name: str) -> str:
|
|
@@ -842,7 +907,7 @@ class WasmerBuilder:
|
|
|
842
907
|
def run_command(
|
|
843
908
|
self, command: str, extra_args: Optional[List[str]] | None = None
|
|
844
909
|
) -> Any:
|
|
845
|
-
|
|
910
|
+
sh.Command(command)(*(extra_args or []), _out=write_stdout, _err=write_stderr, _env=os.environ)
|
|
846
911
|
|
|
847
912
|
def deploy(
|
|
848
913
|
self, app_owner: Optional[str] = None, app_name: Optional[str] = None
|
|
@@ -854,8 +919,8 @@ class WasmerBuilder:
|
|
|
854
919
|
extra_args += ["--registry", self.wasmer_registry]
|
|
855
920
|
if self.wasmer_token:
|
|
856
921
|
extra_args += ["--token", self.wasmer_token]
|
|
857
|
-
self.
|
|
858
|
-
|
|
922
|
+
self.run_command(
|
|
923
|
+
self.bin,
|
|
859
924
|
[
|
|
860
925
|
"package",
|
|
861
926
|
"push",
|
|
@@ -866,8 +931,8 @@ class WasmerBuilder:
|
|
|
866
931
|
*extra_args,
|
|
867
932
|
],
|
|
868
933
|
)
|
|
869
|
-
return self.
|
|
870
|
-
|
|
934
|
+
return self.run_command(
|
|
935
|
+
self.bin,
|
|
871
936
|
[
|
|
872
937
|
"deploy",
|
|
873
938
|
"--publish-package",
|
|
@@ -890,6 +955,7 @@ class Ctx:
|
|
|
890
955
|
self.builds: List[Build] = []
|
|
891
956
|
self.steps: List[Step] = []
|
|
892
957
|
self.serves: Dict[str, Serve] = {}
|
|
958
|
+
self.mounts: List[Mount] = []
|
|
893
959
|
|
|
894
960
|
def add_package(self, package: Package) -> str:
|
|
895
961
|
index = f"{package.name}@{package.version}" if package.version else package.name
|
|
@@ -905,6 +971,8 @@ class Ctx:
|
|
|
905
971
|
return self.serves[index[len("ref:serve:") :]]
|
|
906
972
|
elif index.startswith("ref:step:"):
|
|
907
973
|
return self.steps[int(index[len("ref:step:") :])]
|
|
974
|
+
elif index.startswith("ref:mount:"):
|
|
975
|
+
return self.mounts[int(index[len("ref:mount:") :])]
|
|
908
976
|
else:
|
|
909
977
|
raise Exception(f"Invalid reference: {index}")
|
|
910
978
|
|
|
@@ -945,7 +1013,8 @@ class Ctx:
|
|
|
945
1013
|
assets: Optional[Dict[str, str]] = None,
|
|
946
1014
|
prepare: Optional[List[str]] = None,
|
|
947
1015
|
workers: Optional[List[str]] = None,
|
|
948
|
-
mounts: Optional[
|
|
1016
|
+
mounts: Optional[List[Mount]] = None,
|
|
1017
|
+
env: Optional[Dict[str, str]] = None,
|
|
949
1018
|
) -> str:
|
|
950
1019
|
build_refs = [cast(Step, r) for r in self.get_refs(build)]
|
|
951
1020
|
prepare_steps: Optional[List[PrepareStep]] = None
|
|
@@ -965,7 +1034,8 @@ class Ctx:
|
|
|
965
1034
|
commands=commands,
|
|
966
1035
|
prepare=prepare_steps,
|
|
967
1036
|
workers=workers,
|
|
968
|
-
mounts=mounts,
|
|
1037
|
+
mounts=self.get_refs([mount["ref"] for mount in mounts]) if mounts else None,
|
|
1038
|
+
env=env,
|
|
969
1039
|
)
|
|
970
1040
|
return self.add_serve(serve)
|
|
971
1041
|
|
|
@@ -982,6 +1052,10 @@ class Ctx:
|
|
|
982
1052
|
step = RunStep(*args, **kwargs)
|
|
983
1053
|
return self.add_step(step)
|
|
984
1054
|
|
|
1055
|
+
def workdir(self, path: str) -> Optional[str]:
|
|
1056
|
+
step = WorkdirStep(Path(path))
|
|
1057
|
+
return self.add_step(step)
|
|
1058
|
+
|
|
985
1059
|
def copy(
|
|
986
1060
|
self, source: str, target: str, ignore: Optional[List[str]] = None
|
|
987
1061
|
) -> Optional[str]:
|
|
@@ -995,6 +1069,21 @@ class Ctx:
|
|
|
995
1069
|
step = EnvStep(env_vars)
|
|
996
1070
|
return self.add_step(step)
|
|
997
1071
|
|
|
1072
|
+
def add_mount(self, mount: Mount) -> Optional[str]:
|
|
1073
|
+
self.mounts.append(mount)
|
|
1074
|
+
return f"ref:mount:{len(self.mounts) - 1}"
|
|
1075
|
+
|
|
1076
|
+
def mount(self, name: str) -> Optional[str]:
|
|
1077
|
+
build_path = self.builder.get_build_mount_path(name)
|
|
1078
|
+
serve_path = self.builder.get_serve_mount_path(name)
|
|
1079
|
+
mount = Mount(name, build_path, serve_path)
|
|
1080
|
+
ref = self.add_mount(mount)
|
|
1081
|
+
return {
|
|
1082
|
+
"ref": ref,
|
|
1083
|
+
"build": str(build_path.absolute()),
|
|
1084
|
+
"serve": str(serve_path.absolute()),
|
|
1085
|
+
}
|
|
1086
|
+
|
|
998
1087
|
def serve_mount(self, name: str) -> Optional[str]:
|
|
999
1088
|
return self.builder.serve_mount(name)
|
|
1000
1089
|
|
|
@@ -1020,6 +1109,10 @@ def auto(
|
|
|
1020
1109
|
False,
|
|
1021
1110
|
help="Use Wasmer to build and serve the project.",
|
|
1022
1111
|
),
|
|
1112
|
+
wasmer_bin: Optional[Path] = typer.Option(
|
|
1113
|
+
None,
|
|
1114
|
+
help="The path to the Wasmer binary.",
|
|
1115
|
+
),
|
|
1023
1116
|
docker: bool = typer.Option(
|
|
1024
1117
|
False,
|
|
1025
1118
|
help="Use Docker to build the project.",
|
|
@@ -1064,11 +1157,12 @@ def auto(
|
|
|
1064
1157
|
if not (path / "Shipit").exists() or regenerate or regenerate_path is not None:
|
|
1065
1158
|
generate(path, out=regenerate_path)
|
|
1066
1159
|
|
|
1067
|
-
build(path, wasmer=(wasmer or wasmer_deploy), docker=docker, docker_client=docker_client,)
|
|
1160
|
+
build(path, wasmer=(wasmer or wasmer_deploy), docker=docker, docker_client=docker_client, wasmer_registry=wasmer_registry, wasmer_token=wasmer_token, wasmer_bin=wasmer_bin)
|
|
1068
1161
|
if start or wasmer_deploy:
|
|
1069
1162
|
serve(
|
|
1070
1163
|
path,
|
|
1071
1164
|
wasmer=wasmer,
|
|
1165
|
+
wasmer_bin=wasmer_bin,
|
|
1072
1166
|
docker=docker,
|
|
1073
1167
|
docker_client=docker_client,
|
|
1074
1168
|
start=start,
|
|
@@ -1130,6 +1224,10 @@ def serve(
|
|
|
1130
1224
|
False,
|
|
1131
1225
|
help="Use Wasmer to build and serve the project.",
|
|
1132
1226
|
),
|
|
1227
|
+
wasmer_bin: Optional[Path] = typer.Option(
|
|
1228
|
+
None,
|
|
1229
|
+
help="The path to the Wasmer binary.",
|
|
1230
|
+
),
|
|
1133
1231
|
docker: bool = typer.Option(
|
|
1134
1232
|
False,
|
|
1135
1233
|
help="Use Docker to build the project.",
|
|
@@ -1170,7 +1268,7 @@ def serve(
|
|
|
1170
1268
|
builder = LocalBuilder(path)
|
|
1171
1269
|
if wasmer or wasmer_deploy:
|
|
1172
1270
|
builder = WasmerBuilder(
|
|
1173
|
-
builder, path, registry=wasmer_registry, token=wasmer_token
|
|
1271
|
+
builder, path, registry=wasmer_registry, token=wasmer_token, bin=wasmer_bin
|
|
1174
1272
|
)
|
|
1175
1273
|
if start:
|
|
1176
1274
|
builder.run_serve_command("start")
|
|
@@ -1193,6 +1291,18 @@ def build(
|
|
|
1193
1291
|
False,
|
|
1194
1292
|
help="Use Wasmer to build and serve the project.",
|
|
1195
1293
|
),
|
|
1294
|
+
wasmer_bin: Optional[Path] = typer.Option(
|
|
1295
|
+
None,
|
|
1296
|
+
help="The path to the Wasmer binary.",
|
|
1297
|
+
),
|
|
1298
|
+
wasmer_registry: Optional[str] = typer.Option(
|
|
1299
|
+
None,
|
|
1300
|
+
help="Wasmer registry.",
|
|
1301
|
+
),
|
|
1302
|
+
wasmer_token: Optional[str] = typer.Option(
|
|
1303
|
+
None,
|
|
1304
|
+
help="Wasmer token.",
|
|
1305
|
+
),
|
|
1196
1306
|
docker: bool = typer.Option(
|
|
1197
1307
|
False,
|
|
1198
1308
|
help="Use Docker to build the project.",
|
|
@@ -1214,7 +1324,7 @@ def build(
|
|
|
1214
1324
|
else:
|
|
1215
1325
|
builder = LocalBuilder(path)
|
|
1216
1326
|
if wasmer:
|
|
1217
|
-
builder = WasmerBuilder(builder, path)
|
|
1327
|
+
builder = WasmerBuilder(builder, path, registry=wasmer_registry, token=wasmer_token, bin=wasmer_bin)
|
|
1218
1328
|
|
|
1219
1329
|
ctx = Ctx(builder)
|
|
1220
1330
|
glb = sl.Globals.standard()
|
|
@@ -1224,13 +1334,15 @@ def build(
|
|
|
1224
1334
|
mod.add_callable("dep", ctx.dep)
|
|
1225
1335
|
mod.add_callable("serve", ctx.serve)
|
|
1226
1336
|
mod.add_callable("run", ctx.run)
|
|
1227
|
-
mod.add_callable("
|
|
1337
|
+
mod.add_callable("mount", ctx.mount)
|
|
1338
|
+
mod.add_callable("workdir", ctx.workdir)
|
|
1228
1339
|
mod.add_callable("copy", ctx.copy)
|
|
1229
1340
|
mod.add_callable("path", ctx.path)
|
|
1230
1341
|
mod.add_callable("buildpath", ctx.buildpath)
|
|
1231
1342
|
mod.add_callable("get_asset", ctx.get_asset)
|
|
1232
1343
|
mod.add_callable("env", ctx.env)
|
|
1233
1344
|
mod.add_callable("use", ctx.use)
|
|
1345
|
+
# REMOVE ME
|
|
1234
1346
|
mod.add_callable("serve_mount", ctx.serve_mount)
|
|
1235
1347
|
|
|
1236
1348
|
dialect = sl.Dialect.extended()
|
|
@@ -1252,7 +1364,7 @@ def build(
|
|
|
1252
1364
|
serve = next(iter(ctx.serves.values()))
|
|
1253
1365
|
|
|
1254
1366
|
# Build and serve
|
|
1255
|
-
builder.build(env, serve.build)
|
|
1367
|
+
builder.build(env, serve.mounts, serve.build)
|
|
1256
1368
|
if serve.prepare:
|
|
1257
1369
|
builder.build_prepare(serve)
|
|
1258
1370
|
if serve.assets:
|
shipit/generator.py
CHANGED
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Dict, List, Optional
|
|
5
5
|
|
|
6
|
-
from shipit.providers.base import DependencySpec, Provider, ProviderPlan, DetectResult
|
|
6
|
+
from shipit.providers.base import DependencySpec, Provider, ProviderPlan, DetectResult, MountSpec
|
|
7
7
|
from shipit.providers.registry import providers as registry_providers
|
|
8
8
|
|
|
9
9
|
|
|
@@ -87,13 +87,13 @@ def generate_shipit(path: Path) -> str:
|
|
|
87
87
|
plan = ProviderPlan(
|
|
88
88
|
serve_name=provider.serve_name(path),
|
|
89
89
|
provider=provider.provider_kind(path),
|
|
90
|
+
mounts=provider.mounts(path),
|
|
90
91
|
declarations=provider.declarations(path),
|
|
91
92
|
dependencies=provider.dependencies(path),
|
|
92
93
|
build_steps=provider.build_steps(path),
|
|
93
94
|
prepare=provider.prepare_steps(path),
|
|
94
95
|
commands=provider.commands(path),
|
|
95
|
-
|
|
96
|
-
mounts=provider.mounts(path),
|
|
96
|
+
env=provider.env(path),
|
|
97
97
|
)
|
|
98
98
|
|
|
99
99
|
# Declare dependency variables (combined) and collect serve deps
|
|
@@ -110,15 +110,24 @@ def generate_shipit(path: Path) -> str:
|
|
|
110
110
|
build_steps_block = ",\n".join([f" {s}" for s in build_steps])
|
|
111
111
|
deps_array = ", ".join(serve_dep_vars)
|
|
112
112
|
commands_lines = ",\n".join([f' "{k}": {v}' for k, v in plan.commands.items()])
|
|
113
|
+
env_lines = None
|
|
114
|
+
if plan.env is not None:
|
|
115
|
+
if len(plan.env) == 0:
|
|
116
|
+
env_lines = "{}"
|
|
117
|
+
else:
|
|
118
|
+
env_lines = ",\n".join([f' "{k}": {v}' for k, v in plan.env.items()])
|
|
113
119
|
assets_block = _render_assets(plan.assets)
|
|
114
120
|
mounts_block = None
|
|
115
121
|
if plan.mounts:
|
|
116
|
-
|
|
122
|
+
mounts = filter(lambda m: m.attach_to_serve, plan.mounts)
|
|
123
|
+
mounts_block = ",\n".join([f" {m.name}" for m in mounts])
|
|
117
124
|
|
|
118
125
|
out: List[str] = []
|
|
119
126
|
if dep_block:
|
|
120
127
|
out.append(dep_block)
|
|
121
128
|
out.append("")
|
|
129
|
+
for m in plan.mounts:
|
|
130
|
+
out.append(f"{m.name} = mount(\"{m.name}\")")
|
|
122
131
|
if plan.declarations:
|
|
123
132
|
out.append(plan.declarations)
|
|
124
133
|
out.append("")
|
|
@@ -136,13 +145,20 @@ def generate_shipit(path: Path) -> str:
|
|
|
136
145
|
out.append(" prepare=[")
|
|
137
146
|
out.append(prepare_steps_block)
|
|
138
147
|
out.append(" ],")
|
|
148
|
+
if env_lines is not None:
|
|
149
|
+
if env_lines == "{}":
|
|
150
|
+
out.append(" env = {},")
|
|
151
|
+
else:
|
|
152
|
+
out.append(" env = {")
|
|
153
|
+
out.append(env_lines)
|
|
154
|
+
out.append(" },")
|
|
139
155
|
out.append(" commands = {")
|
|
140
156
|
out.append(commands_lines)
|
|
141
157
|
out.append(" },")
|
|
142
158
|
if mounts_block:
|
|
143
|
-
out.append(" mounts=
|
|
159
|
+
out.append(" mounts=[")
|
|
144
160
|
out.append(mounts_block)
|
|
145
|
-
out.append("
|
|
161
|
+
out.append(" ],")
|
|
146
162
|
out.append(")")
|
|
147
163
|
out.append("")
|
|
148
164
|
return "\n".join(out)
|
shipit/providers/base.py
CHANGED
|
@@ -25,7 +25,8 @@ class Provider(Protocol):
|
|
|
25
25
|
def prepare_steps(self, path: Path) -> Optional[List[str]]: ...
|
|
26
26
|
def commands(self, path: Path) -> Dict[str, str]: ...
|
|
27
27
|
def assets(self, path: Path) -> Optional[Dict[str, str]]: ...
|
|
28
|
-
def mounts(self, path: Path) ->
|
|
28
|
+
def mounts(self, path: Path) -> List["MountSpec"]: ...
|
|
29
|
+
def env(self, path: Path) -> Optional[Dict[str, str]]: ...
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
@dataclass
|
|
@@ -38,17 +39,25 @@ class DependencySpec:
|
|
|
38
39
|
use_in_serve: bool = False
|
|
39
40
|
|
|
40
41
|
|
|
42
|
+
@dataclass
|
|
43
|
+
class MountSpec:
|
|
44
|
+
name: str
|
|
45
|
+
attach_to_build: bool = True
|
|
46
|
+
attach_to_serve: bool = True
|
|
47
|
+
|
|
48
|
+
|
|
41
49
|
@dataclass
|
|
42
50
|
class ProviderPlan:
|
|
43
51
|
serve_name: str
|
|
44
52
|
provider: str
|
|
53
|
+
mounts: List[MountSpec]
|
|
45
54
|
declarations: Optional[str] = None
|
|
46
55
|
dependencies: List[DependencySpec] = field(default_factory=list)
|
|
47
56
|
build_steps: List[str] = field(default_factory=list)
|
|
48
57
|
prepare: Optional[List[str]] = None
|
|
49
58
|
commands: Dict[str, str] = field(default_factory=dict)
|
|
50
59
|
assets: Optional[Dict[str, str]] = None
|
|
51
|
-
|
|
60
|
+
env: Optional[Dict[str, str]] = None
|
|
52
61
|
|
|
53
62
|
|
|
54
63
|
def _exists(path: Path, *candidates: str) -> bool:
|
shipit/providers/gatsby.py
CHANGED
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Dict, Optional
|
|
5
5
|
|
|
6
|
-
from .base import DetectResult, DependencySpec, Provider, _exists, _has_dependency
|
|
6
|
+
from .base import DetectResult, DependencySpec, Provider, _exists, _has_dependency, MountSpec
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class GatsbyProvider:
|
|
@@ -49,16 +49,20 @@ class GatsbyProvider:
|
|
|
49
49
|
"run(\"npm install\", inputs=[\"package.json\", \"package-lock.json\"], group=\"install\")",
|
|
50
50
|
"copy(\".\", \".\", ignore=[\"node_modules\", \".git\"])",
|
|
51
51
|
"run(\"npm run build\", outputs=[\"public\"], group=\"build\")",
|
|
52
|
+
"run(\"cp -R public/* {}/\".format(app[\"build\"]))",
|
|
52
53
|
]
|
|
53
54
|
|
|
54
55
|
def prepare_steps(self, path: Path) -> Optional[list[str]]:
|
|
55
56
|
return None
|
|
56
57
|
|
|
57
58
|
def commands(self, path: Path) -> Dict[str, str]:
|
|
58
|
-
return {"start": '"static-web-server --root /app
|
|
59
|
+
return {"start": '"static-web-server --root /app"'}
|
|
59
60
|
|
|
60
61
|
def assets(self, path: Path) -> Optional[Dict[str, str]]:
|
|
61
62
|
return None
|
|
62
63
|
|
|
63
|
-
def mounts(self, path: Path) ->
|
|
64
|
+
def mounts(self, path: Path) -> list[MountSpec]:
|
|
65
|
+
return [MountSpec("app")]
|
|
66
|
+
|
|
67
|
+
def env(self, path: Path) -> Optional[Dict[str, str]]:
|
|
64
68
|
return None
|
shipit/providers/laravel.py
CHANGED
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Dict, Optional
|
|
5
5
|
|
|
6
|
-
from .base import DetectResult, DependencySpec, Provider, _exists
|
|
6
|
+
from .base import DetectResult, DependencySpec, Provider, _exists, MountSpec
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class LaravelProvider:
|
|
@@ -45,6 +45,7 @@ class LaravelProvider:
|
|
|
45
45
|
def build_steps(self, path: Path) -> list[str]:
|
|
46
46
|
return [
|
|
47
47
|
"env(HOME=HOME, COMPOSER_FUND=\"0\")",
|
|
48
|
+
"workdir(app[\"build\"])",
|
|
48
49
|
"run(\"pie install php/pdo_pgsql\")",
|
|
49
50
|
"run(\"composer install --optimize-autoloader --no-scripts --no-interaction\", inputs=[\"composer.json\", \"composer.lock\", \"artisan\"], outputs=[\".\"], group=\"install\")",
|
|
50
51
|
"run(\"pnpm install\", inputs=[\"package.json\", \"package-lock.json\"], outputs=[\".\"], group=\"install\")",
|
|
@@ -54,6 +55,7 @@ class LaravelProvider:
|
|
|
54
55
|
|
|
55
56
|
def prepare_steps(self, path: Path) -> Optional[list[str]]:
|
|
56
57
|
return [
|
|
58
|
+
'workdir(app["serve"])',
|
|
57
59
|
'run("mkdir -p storage/framework/{sessions,views,cache,testing} storage/logs bootstrap/cache")',
|
|
58
60
|
'run("php artisan config:cache")',
|
|
59
61
|
'run("php artisan event:cache")',
|
|
@@ -70,5 +72,8 @@ class LaravelProvider:
|
|
|
70
72
|
def assets(self, path: Path) -> Optional[Dict[str, str]]:
|
|
71
73
|
return None
|
|
72
74
|
|
|
73
|
-
def mounts(self, path: Path) ->
|
|
75
|
+
def mounts(self, path: Path) -> list[MountSpec]:
|
|
76
|
+
return [MountSpec("app")]
|
|
77
|
+
|
|
78
|
+
def env(self, path: Path) -> Optional[Dict[str, str]]:
|
|
74
79
|
return None
|
shipit/providers/mkdocs.py
CHANGED
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Dict, Optional
|
|
5
5
|
|
|
6
|
-
from .base import DetectResult, DependencySpec, Provider, _exists
|
|
6
|
+
from .base import DetectResult, DependencySpec, Provider, _exists, MountSpec
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class MkdocsProvider:
|
|
@@ -65,17 +65,20 @@ class MkdocsProvider:
|
|
|
65
65
|
return [
|
|
66
66
|
*install_lines,
|
|
67
67
|
"copy(\".\", \".\", ignore=[\".venv\", \".git\", \"__pycache__\"])",
|
|
68
|
-
"run(\"uv run mkdocs build\", outputs=[\".\"], group=\"build\")",
|
|
68
|
+
"run(\"uv run mkdocs build --site-dir={}\".format(app[\"build\"]), outputs=[\".\"], group=\"build\")",
|
|
69
69
|
]
|
|
70
70
|
|
|
71
71
|
def prepare_steps(self, path: Path) -> Optional[list[str]]:
|
|
72
72
|
return None
|
|
73
73
|
|
|
74
74
|
def commands(self, path: Path) -> Dict[str, str]:
|
|
75
|
-
return {"start": '"static-web-server --root
|
|
75
|
+
return {"start": '"static-web-server --root /app"'}
|
|
76
76
|
|
|
77
77
|
def assets(self, path: Path) -> Optional[Dict[str, str]]:
|
|
78
78
|
return None
|
|
79
79
|
|
|
80
|
-
def mounts(self, path: Path) ->
|
|
80
|
+
def mounts(self, path: Path) -> list[MountSpec]:
|
|
81
|
+
return [MountSpec("app")]
|
|
82
|
+
|
|
83
|
+
def env(self, path: Path) -> Optional[Dict[str, str]]:
|
|
81
84
|
return None
|
shipit/providers/node_static.py
CHANGED
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Dict, Optional
|
|
5
5
|
|
|
6
|
-
from .base import DetectResult, DependencySpec, Provider, _exists, _has_dependency
|
|
6
|
+
from .base import DetectResult, DependencySpec, Provider, _exists, _has_dependency, MountSpec
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class NodeStaticProvider:
|
|
@@ -49,6 +49,7 @@ class NodeStaticProvider:
|
|
|
49
49
|
"run(\"npm install\", inputs=[\"package.json\", \"package-lock.json\"], group=\"install\")",
|
|
50
50
|
"copy(\".\", \".\", ignore=[\"node_modules\", \".git\"])",
|
|
51
51
|
f"run(\"npm run build\", outputs=[\"{output_dir}\"], group=\"build\")",
|
|
52
|
+
f"run(\"cp -R {output_dir}/* {{}}/\".format(app[\"build\"]))",
|
|
52
53
|
]
|
|
53
54
|
|
|
54
55
|
def prepare_steps(self, path: Path) -> Optional[list[str]]:
|
|
@@ -61,5 +62,8 @@ class NodeStaticProvider:
|
|
|
61
62
|
def assets(self, path: Path) -> Optional[Dict[str, str]]:
|
|
62
63
|
return None
|
|
63
64
|
|
|
64
|
-
def mounts(self, path: Path) ->
|
|
65
|
+
def mounts(self, path: Path) -> list[MountSpec]:
|
|
66
|
+
return [MountSpec("app")]
|
|
67
|
+
|
|
68
|
+
def env(self, path: Path) -> Optional[Dict[str, str]]:
|
|
65
69
|
return None
|
shipit/providers/php.py
CHANGED
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Dict, Optional
|
|
5
5
|
|
|
6
|
-
from .base import DetectResult, DependencySpec, Provider, _exists
|
|
6
|
+
from .base import DetectResult, DependencySpec, Provider, _exists, MountSpec
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class PhpProvider:
|
|
@@ -48,7 +48,9 @@ class PhpProvider:
|
|
|
48
48
|
return "HOME = getenv(\"HOME\")"
|
|
49
49
|
|
|
50
50
|
def build_steps(self, path: Path) -> list[str]:
|
|
51
|
-
steps = [
|
|
51
|
+
steps = [
|
|
52
|
+
"workdir(app[\"build\"])",
|
|
53
|
+
]
|
|
52
54
|
|
|
53
55
|
if self.has_composer(path):
|
|
54
56
|
steps.append("env(HOME=HOME, COMPOSER_FUND=\"0\")")
|
|
@@ -69,5 +71,8 @@ class PhpProvider:
|
|
|
69
71
|
def assets(self, path: Path) -> Optional[Dict[str, str]]:
|
|
70
72
|
return {"php.ini": "get_asset(\"php/php.ini\")"}
|
|
71
73
|
|
|
72
|
-
def mounts(self, path: Path) ->
|
|
74
|
+
def mounts(self, path: Path) -> list[MountSpec]:
|
|
75
|
+
return [MountSpec("app")]
|
|
76
|
+
|
|
77
|
+
def env(self, path: Path) -> Optional[Dict[str, str]]:
|
|
73
78
|
return None
|
shipit/providers/python.py
CHANGED
|
@@ -8,6 +8,7 @@ from .base import (
|
|
|
8
8
|
DependencySpec,
|
|
9
9
|
Provider,
|
|
10
10
|
_exists,
|
|
11
|
+
MountSpec,
|
|
11
12
|
)
|
|
12
13
|
|
|
13
14
|
|
|
@@ -57,29 +58,26 @@ class PythonProvider:
|
|
|
57
58
|
return (
|
|
58
59
|
"cross_platform = getenv(\"SHIPIT_PYTHON_CROSS_PLATFORM\")\n"
|
|
59
60
|
"python_extra_index_url = getenv(\"SHIPIT_PYTHON_EXTRA_INDEX_URL\")\n"
|
|
60
|
-
"python_cross_packages_serve_path = None\n"
|
|
61
|
-
"python_cross_packages_path = None\n"
|
|
62
|
-
"if cross_platform:\n"
|
|
63
|
-
" python_cross_packages_path = serve_mount(\"python-cross-packages\")\n"
|
|
64
|
-
" python_cross_packages_serve_path = f\"/.venv/lib/python{python_version}/site-packages\"\n"
|
|
65
61
|
"precompile_python = getenv(\"SHIPIT_PYTHON_PRECOMPILE\") in [\"true\", \"True\", \"TRUE\", \"1\", \"on\", \"yes\", \"y\", \"Y\", \"YES\", \"On\", \"ON\"]\n"
|
|
62
|
+
"python_cross_packages_path = venv[\"build\"] + f\"/lib/python{python_version}/site-packages\""
|
|
66
63
|
)
|
|
67
64
|
|
|
68
65
|
def build_steps(self, path: Path) -> list[str]:
|
|
69
66
|
return [
|
|
67
|
+
"workdir(app[\"build\"])",
|
|
68
|
+
"env(UV_PROJECT_ENVIRONMENT=local_venv[\"build\"] if cross_platform else venv[\"build\"])",
|
|
70
69
|
"run(f\"uv sync --compile --python python{python_version} --locked --no-managed-python\", inputs=[\"pyproject.toml\", \"uv.lock\"], outputs=[\".\"], group=\"install\")",
|
|
71
70
|
"run(f\"uv pip compile pyproject.toml --python-version={python_version} --universal --extra-index-url {python_extra_index_url} --index-url=https://pypi.org/simple --emit-index-url --only-binary :all: -o cross-requirements.txt\", inputs=[\"pyproject.toml\"], outputs=[\"cross-requirements.txt\"]) if cross_platform else None",
|
|
72
71
|
"run(f\"uvx pip install -r cross-requirements.txt --target {python_cross_packages_path} --platform {cross_platform} --only-binary=:all: --python-version={python_version} --compile\", outputs=[\".\"]) if cross_platform else None",
|
|
73
72
|
"run(\"rm cross-requirements.txt\") if cross_platform else None",
|
|
74
|
-
"path(\"
|
|
73
|
+
"path((local_venv[\"build\"] if cross_platform else venv[\"build\"]) + \"/bin\")",
|
|
75
74
|
"copy(\".\", \".\", ignore=[\".venv\", \".git\", \"__pycache__\"])",
|
|
76
|
-
"run(\"rm -rf .venv\") if cross_platform else None",
|
|
77
75
|
]
|
|
78
76
|
|
|
79
77
|
def prepare_steps(self, path: Path) -> Optional[list[str]]:
|
|
80
78
|
return [
|
|
81
|
-
'run("echo \\\"Precompiling Python code...\\\"") if precompile_python
|
|
82
|
-
'run(
|
|
79
|
+
'run("echo \\\"Precompiling Python code...\\\"") if precompile_python else None',
|
|
80
|
+
'run("python -m compileall -o 2 $PYTHONPATH") if precompile_python else None',
|
|
83
81
|
'run("echo \\\"Precompiling package code...\\\"") if precompile_python else None',
|
|
84
82
|
'run("python -m compileall -o 2 .") if precompile_python else None',
|
|
85
83
|
]
|
|
@@ -100,5 +98,16 @@ class PythonProvider:
|
|
|
100
98
|
def assets(self, path: Path) -> Optional[Dict[str, str]]:
|
|
101
99
|
return None
|
|
102
100
|
|
|
103
|
-
def mounts(self, path: Path) ->
|
|
104
|
-
return
|
|
101
|
+
def mounts(self, path: Path) -> list[MountSpec]:
|
|
102
|
+
return [
|
|
103
|
+
MountSpec("app"),
|
|
104
|
+
MountSpec("venv"),
|
|
105
|
+
MountSpec("local_venv", attach_to_serve=False),
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
def env(self, path: Path) -> Optional[Dict[str, str]]:
|
|
109
|
+
# For Django projects, generate an empty env dict to surface the field
|
|
110
|
+
# in the Shipit file. Other Python projects omit it by default.
|
|
111
|
+
return {
|
|
112
|
+
"PYTHONPATH": "\"{}/lib/python{}/site-packages\".format(venv[\"serve\"], python_version)"
|
|
113
|
+
}
|
shipit/providers/staticfile.py
CHANGED
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Dict, Optional
|
|
5
5
|
|
|
6
|
-
from .base import DetectResult, DependencySpec, Provider, _exists
|
|
6
|
+
from .base import DetectResult, DependencySpec, Provider, _exists, MountSpec
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class StaticFileProvider:
|
|
@@ -41,7 +41,10 @@ class StaticFileProvider:
|
|
|
41
41
|
]
|
|
42
42
|
|
|
43
43
|
def build_steps(self, path: Path) -> list[str]:
|
|
44
|
-
return [
|
|
44
|
+
return [
|
|
45
|
+
'workdir(app["build"])',
|
|
46
|
+
'copy(".", ".", ignore=[".git"])'
|
|
47
|
+
]
|
|
45
48
|
|
|
46
49
|
def prepare_steps(self, path: Path) -> Optional[list[str]]:
|
|
47
50
|
return None
|
|
@@ -57,5 +60,8 @@ class StaticFileProvider:
|
|
|
57
60
|
def assets(self, path: Path) -> Optional[Dict[str, str]]:
|
|
58
61
|
return None
|
|
59
62
|
|
|
60
|
-
def mounts(self, path: Path) ->
|
|
63
|
+
def mounts(self, path: Path) -> list[MountSpec]:
|
|
64
|
+
return [MountSpec("app")]
|
|
65
|
+
|
|
66
|
+
def env(self, path: Path) -> Optional[Dict[str, str]]:
|
|
61
67
|
return None
|
shipit/version.py
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
shipit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
shipit/cli.py,sha256=jeL3NOkpInk0t5o7mkKMqwyE1X3Q-7rRnArJz8HWK4E,47263
|
|
3
|
+
shipit/generator.py,sha256=iBkVcs44dd_xYKitM_zNVLnpiZ3KrV__xVswPMCZ97Y,5570
|
|
4
|
+
shipit/version.py,sha256=iiC3XVOrqOpEsnDmqt5bwypq0_Awz7jUa80HHEAUGH8,95
|
|
5
|
+
shipit/assets/php/php.ini,sha256=f4irndAjB4GuuouEImRkNV22Q-yw1KqR-43jAMDw730,2531
|
|
6
|
+
shipit/providers/base.py,sha256=bqh1k7TSPJo7hOnxgdI6PIJmrqzQkZhgUoV0bbYIWrw,2403
|
|
7
|
+
shipit/providers/gatsby.py,sha256=VUGhE7xtQJHsYzEzdkXi3n5mbpgg868wbUVOU4MWN5s,2173
|
|
8
|
+
shipit/providers/hugo.py,sha256=UDIM2KvPcgJsiLn0mZ5Dejtuf09X3cnEQYkn-2KpZKI,1465
|
|
9
|
+
shipit/providers/laravel.py,sha256=4wSa0ByLrq87WhrAf04mOGVKz_xn8xtCaSYHpx0l7-0,2812
|
|
10
|
+
shipit/providers/mkdocs.py,sha256=YIbSAaL2jDQtr8YteZmKjIbRMDWdoQgy6G2D6dfH1ws,2842
|
|
11
|
+
shipit/providers/node_static.py,sha256=Zpq4fRCMBzGkObdsfPVAoYUAnZSqE9C1D0aaJyI30Fc,2334
|
|
12
|
+
shipit/providers/php.py,sha256=HxxgfXmA0U6PeTLyFMbyXWm05G_IQqdFz4Liq1d_VBM,2635
|
|
13
|
+
shipit/providers/python.py,sha256=ep8qflY_9J-F_zei4Lt0zeDWFEHUf-lOr4F-LBgYPiE,4870
|
|
14
|
+
shipit/providers/registry.py,sha256=V6CAOK5gEX0RhWhr-lcAkvlwRuMom7YY2ZeAyRy1Eck,672
|
|
15
|
+
shipit/providers/staticfile.py,sha256=9Ksi9WO_52Dnj_hqNn_cYVjTniJ3tBjVr5kBvgCPF-0,1908
|
|
16
|
+
shipit_cli-0.2.1.dist-info/METADATA,sha256=-JXEKtPvJ0b6A3vXOGh1PUNKQek4nSzn4lDGqRoFl8A,462
|
|
17
|
+
shipit_cli-0.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
18
|
+
shipit_cli-0.2.1.dist-info/entry_points.txt,sha256=7AE1NjSrHaSDfbfsRRO50KKnHFTbB0Imsccd1WynzAQ,72
|
|
19
|
+
shipit_cli-0.2.1.dist-info/RECORD,,
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
shipit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
shipit/cli.py,sha256=r0T-_IlEfB7goG_wzVO29mopdKsH3cy0QYgfS-3qHWQ,43205
|
|
3
|
-
shipit/generator.py,sha256=dEBH7T2OE6F96XM4oo0aaJfmAP2nTCt9gwD-ndP7it0,5013
|
|
4
|
-
shipit/version.py,sha256=Qz4YGriaQOa2gMqqNG4xaz98-TIaAUfaKx-N6AbcJeQ,95
|
|
5
|
-
shipit/assets/php/php.ini,sha256=f4irndAjB4GuuouEImRkNV22Q-yw1KqR-43jAMDw730,2531
|
|
6
|
-
shipit/providers/base.py,sha256=52_PAAShw9XKmxo3D6yyEq40c2NE5ctz9QnvTJQ4lFU,2212
|
|
7
|
-
shipit/providers/gatsby.py,sha256=pkdlIa4kAUwrDMFGryS1f7Gg8-0zDQzoaDxkBNgSlDg,2018
|
|
8
|
-
shipit/providers/hugo.py,sha256=UDIM2KvPcgJsiLn0mZ5Dejtuf09X3cnEQYkn-2KpZKI,1465
|
|
9
|
-
shipit/providers/laravel.py,sha256=nYvx1b4mqLNLPDFoWJIH6PXRNzLl2NSnSPna_eVnC_U,2640
|
|
10
|
-
shipit/providers/mkdocs.py,sha256=RHpQ75CiTr2GcPQNpIrPKePFR13NR5u6ZzAnCPIYAH4,2733
|
|
11
|
-
shipit/providers/node_static.py,sha256=JRyD5bBST8J3xFSO4Wvc5vZn2KitCxh9nKyFGMg0jAE,2163
|
|
12
|
-
shipit/providers/php.py,sha256=OAK9Sxdb_Fi6N04mEN_c1EtQlXYuJIuMks6x6MCOEKA,2491
|
|
13
|
-
shipit/providers/python.py,sha256=1C-ZI6rh3eTzL-hMEaJIf2Q-TynMywQdyDqIPadYSZM,4643
|
|
14
|
-
shipit/providers/registry.py,sha256=V6CAOK5gEX0RhWhr-lcAkvlwRuMom7YY2ZeAyRy1Eck,672
|
|
15
|
-
shipit/providers/staticfile.py,sha256=R4nOl_W6xbEXZ-uHZlZ5CQ2bdiIssiPslX0_O3PUrPU,1753
|
|
16
|
-
shipit_cli-0.1.3.dist-info/METADATA,sha256=2SWaDb0hi0rdicpUJl_6OVKorUcazSclbXY3QIiNCPE,462
|
|
17
|
-
shipit_cli-0.1.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
18
|
-
shipit_cli-0.1.3.dist-info/entry_points.txt,sha256=7AE1NjSrHaSDfbfsRRO50KKnHFTbB0Imsccd1WynzAQ,72
|
|
19
|
-
shipit_cli-0.1.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|