shipit-cli 0.7.1__py3-none-any.whl → 0.9.0__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/assets/wordpress/install.sh +4 -9
- shipit/cli.py +43 -33
- shipit/generator.py +14 -2
- shipit/providers/hugo.py +6 -2
- shipit/providers/laravel.py +1 -1
- shipit/providers/mkdocs.py +2 -0
- shipit/providers/node_static.py +238 -22
- shipit/providers/php.py +2 -2
- shipit/providers/python.py +16 -15
- shipit/providers/registry.py +1 -1
- shipit/providers/staticfile.py +14 -2
- shipit/providers/wordpress.py +1 -1
- shipit/version.py +2 -2
- {shipit_cli-0.7.1.dist-info → shipit_cli-0.9.0.dist-info}/METADATA +3 -2
- shipit_cli-0.9.0.dist-info/RECORD +23 -0
- shipit_cli-0.7.1.dist-info/RECORD +0 -23
- {shipit_cli-0.7.1.dist-info → shipit_cli-0.9.0.dist-info}/WHEEL +0 -0
- {shipit_cli-0.7.1.dist-info → shipit_cli-0.9.0.dist-info}/entry_points.txt +0 -0
|
@@ -12,7 +12,7 @@ echo "" > wp-content/upgrade/.keep
|
|
|
12
12
|
|
|
13
13
|
echo "Installing WordPress core..."
|
|
14
14
|
|
|
15
|
-
wp
|
|
15
|
+
wp core install \
|
|
16
16
|
--url="$WASMER_APP_URL" \
|
|
17
17
|
--title="$WP_SITE_TITLE" \
|
|
18
18
|
--admin_user="$WP_ADMIN_USERNAME" \
|
|
@@ -21,13 +21,8 @@ wp-cli core install \
|
|
|
21
21
|
--locale="$WP_LOCALE"
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
if [ -z "$
|
|
25
|
-
wp
|
|
26
|
-
fi
|
|
27
|
-
|
|
28
|
-
echo "Installing theme..."
|
|
29
|
-
wp-cli wasmer-aio-install install \
|
|
30
|
-
--locale="$WP_LOCALE" \
|
|
31
|
-
--theme=twentytwentyfive || true
|
|
24
|
+
if [ -z "$WP_UPDATE_DB" ]; then
|
|
25
|
+
wp core update-db
|
|
26
|
+
fi
|
|
32
27
|
|
|
33
28
|
echo "Installation complete"
|
shipit/cli.py
CHANGED
|
@@ -148,10 +148,12 @@ class Build:
|
|
|
148
148
|
|
|
149
149
|
def write_stdout(line: str) -> None:
|
|
150
150
|
sys.stdout.write(line) # print to console
|
|
151
|
+
sys.stdout.flush()
|
|
151
152
|
|
|
152
153
|
|
|
153
154
|
def write_stderr(line: str) -> None:
|
|
154
155
|
sys.stderr.write(line) # print to console
|
|
156
|
+
sys.stderr.flush()
|
|
155
157
|
|
|
156
158
|
|
|
157
159
|
class MapperItem(TypedDict):
|
|
@@ -179,6 +181,16 @@ class Builder(Protocol):
|
|
|
179
181
|
|
|
180
182
|
|
|
181
183
|
class DockerBuilder:
|
|
184
|
+
mise_mapper = {
|
|
185
|
+
"php": {
|
|
186
|
+
"source": "ubi:adwinying/php",
|
|
187
|
+
},
|
|
188
|
+
"composer": {
|
|
189
|
+
"source": "ubi:composer/composer",
|
|
190
|
+
"postinstall": """composer_dir=$(mise where ubi:composer/composer); ln -s "$composer_dir/composer.phar" /usr/local/bin/composer""",
|
|
191
|
+
},
|
|
192
|
+
}
|
|
193
|
+
|
|
182
194
|
def __init__(self, src_dir: Path, docker_client: Optional[str] = None) -> None:
|
|
183
195
|
self.src_dir = src_dir
|
|
184
196
|
self.docker_file_contents = ""
|
|
@@ -293,7 +305,7 @@ class DockerBuilder:
|
|
|
293
305
|
image_name,
|
|
294
306
|
command,
|
|
295
307
|
*(extra_args or []),
|
|
296
|
-
_env=os.environ, # Pass the current environment variables to the Docker client
|
|
308
|
+
_env={"DOCKER_BUILDKIT": "1", **os.environ}, # Pass the current environment variables to the Docker client
|
|
297
309
|
_out=write_stdout,
|
|
298
310
|
_err=write_stderr,
|
|
299
311
|
)
|
|
@@ -340,12 +352,17 @@ RUN chmod {oct(mode)[2:]} {path.absolute()}
|
|
|
340
352
|
)
|
|
341
353
|
self.docker_file_contents += f"RUN curl --proto '=https' --tlsv1.2 -sSfL https://get.static-web-server.net | sh\n"
|
|
342
354
|
return
|
|
355
|
+
|
|
356
|
+
mapped_dependency = self.mise_mapper.get(dependency.name, {})
|
|
357
|
+
package_name = mapped_dependency.get("source", dependency.name)
|
|
343
358
|
if dependency.version:
|
|
344
359
|
self.docker_file_contents += (
|
|
345
|
-
f"RUN mise use --global {
|
|
360
|
+
f"RUN mise use --global {package_name}@{dependency.version}\n"
|
|
346
361
|
)
|
|
347
362
|
else:
|
|
348
|
-
self.docker_file_contents += f"RUN mise use --global {
|
|
363
|
+
self.docker_file_contents += f"RUN mise use --global {package_name}\n"
|
|
364
|
+
if mapped_dependency.get("postinstall"):
|
|
365
|
+
self.docker_file_contents += f"RUN {mapped_dependency.get('postinstall')}\n"
|
|
349
366
|
|
|
350
367
|
def build(
|
|
351
368
|
self, env: Dict[str, str], mounts: List[Mount], steps: List[Step]
|
|
@@ -353,14 +370,17 @@ RUN chmod {oct(mode)[2:]} {path.absolute()}
|
|
|
353
370
|
base_path = self.docker_path
|
|
354
371
|
shutil.rmtree(base_path, ignore_errors=True)
|
|
355
372
|
base_path.mkdir(parents=True, exist_ok=True)
|
|
356
|
-
self.docker_file_contents = "
|
|
373
|
+
self.docker_file_contents = "# syntax=docker/dockerfile:1.7-labs\n"
|
|
374
|
+
self.docker_file_contents += "FROM debian:trixie-slim AS build\n"
|
|
357
375
|
|
|
358
376
|
self.docker_file_contents += """
|
|
359
377
|
RUN apt-get update \\
|
|
360
378
|
&& apt-get -y --no-install-recommends install \\
|
|
361
|
-
build-essential gcc make \\
|
|
362
|
-
dpkg-dev pkg-config \\
|
|
379
|
+
build-essential gcc make autoconf libtool bison \\
|
|
380
|
+
dpkg-dev pkg-config re2c locate \\
|
|
363
381
|
libmariadb-dev libmariadb-dev-compat libpq-dev \\
|
|
382
|
+
libvips-dev default-libmysqlclient-dev libmagickwand-dev \\
|
|
383
|
+
libicu-dev libxml2-dev libxslt-dev \\
|
|
364
384
|
sudo curl ca-certificates \\
|
|
365
385
|
&& rm -rf /var/lib/apt/lists/*
|
|
366
386
|
|
|
@@ -407,7 +427,7 @@ RUN curl https://mise.run | sh
|
|
|
407
427
|
# Read the file content and write it to the target file
|
|
408
428
|
content_base64 = base64.b64encode(
|
|
409
429
|
(ASSETS_PATH / step.source).read_bytes()
|
|
410
|
-
)
|
|
430
|
+
).decode("utf-8")
|
|
411
431
|
self.docker_file_contents += (
|
|
412
432
|
f"RUN echo '{content_base64}' | base64 -d > {step.target}\n"
|
|
413
433
|
)
|
|
@@ -418,7 +438,11 @@ RUN curl https://mise.run | sh
|
|
|
418
438
|
else:
|
|
419
439
|
raise Exception(f"Asset {step.source} does not exist")
|
|
420
440
|
else:
|
|
421
|
-
|
|
441
|
+
if step.ignore:
|
|
442
|
+
exclude = " \\\n" +" \\\n".join([f" --exclude={ignore}" for ignore in step.ignore]) + " \\\n "
|
|
443
|
+
else:
|
|
444
|
+
exclude = ""
|
|
445
|
+
self.docker_file_contents += f"COPY{exclude} {step.source} {step.target}\n"
|
|
422
446
|
elif isinstance(step, EnvStep):
|
|
423
447
|
env_vars = " ".join(
|
|
424
448
|
[f"{key}={value}" for key, value in step.variables.items()]
|
|
@@ -446,12 +470,6 @@ Shipit
|
|
|
446
470
|
def get_path(self) -> Path:
|
|
447
471
|
return Path("/")
|
|
448
472
|
|
|
449
|
-
def get_build_path(self) -> Path:
|
|
450
|
-
return self.get_path() / "app"
|
|
451
|
-
|
|
452
|
-
def get_serve_path(self) -> Path:
|
|
453
|
-
return self.get_path() / "serve"
|
|
454
|
-
|
|
455
473
|
def prepare(self, env: Dict[str, str], prepare: List[PrepareStep]) -> None:
|
|
456
474
|
raise NotImplementedError
|
|
457
475
|
|
|
@@ -461,13 +479,12 @@ Shipit
|
|
|
461
479
|
for dep in serve.deps:
|
|
462
480
|
self.add_dependency(dep)
|
|
463
481
|
|
|
464
|
-
build_path = self.get_build_path()
|
|
465
482
|
for command in serve.commands:
|
|
466
483
|
console.print(f"* {command}")
|
|
467
484
|
command_path = serve_command_path / command
|
|
468
485
|
self.create_file(
|
|
469
486
|
command_path,
|
|
470
|
-
f"#!/bin/bash\ncd {
|
|
487
|
+
f"#!/bin/bash\ncd {serve.cwd}\n{serve.commands[command]}",
|
|
471
488
|
mode=0o755,
|
|
472
489
|
)
|
|
473
490
|
|
|
@@ -480,6 +497,7 @@ class LocalBuilder:
|
|
|
480
497
|
def __init__(self, src_dir: Path) -> None:
|
|
481
498
|
self.src_dir = src_dir
|
|
482
499
|
self.local_path = self.src_dir / ".shipit" / "local"
|
|
500
|
+
self.serve_bin_path = self.local_path / "serve" / "bin"
|
|
483
501
|
self.prepare_bash_script = self.local_path / "prepare" / "prepare.sh"
|
|
484
502
|
self.build_path = self.local_path / "build"
|
|
485
503
|
self.workdir = self.build_path
|
|
@@ -503,6 +521,8 @@ class LocalBuilder:
|
|
|
503
521
|
elif isinstance(step, WorkdirStep):
|
|
504
522
|
console.print(f"[bold]Working in {step.path}[/bold]")
|
|
505
523
|
self.workdir = step.path
|
|
524
|
+
# We make sure the dir exists
|
|
525
|
+
step.path.mkdir(parents=True, exist_ok=True)
|
|
506
526
|
elif isinstance(step, RunStep):
|
|
507
527
|
extra = ""
|
|
508
528
|
if step.inputs:
|
|
@@ -525,9 +545,10 @@ class LocalBuilder:
|
|
|
525
545
|
exe = shutil.which(program, path=PATH)
|
|
526
546
|
if not exe:
|
|
527
547
|
raise Exception(f"Program is not installed: {program}")
|
|
528
|
-
cmd = sh.Command(
|
|
548
|
+
cmd = sh.Command("bash") # "grep"
|
|
529
549
|
result = cmd(
|
|
530
|
-
|
|
550
|
+
"-c",
|
|
551
|
+
command_line,
|
|
531
552
|
_env={**env, "PATH": PATH},
|
|
532
553
|
_cwd=build_path,
|
|
533
554
|
_out=write_stdout,
|
|
@@ -628,12 +649,6 @@ class LocalBuilder:
|
|
|
628
649
|
def get_path(self) -> Path:
|
|
629
650
|
return self.local_path
|
|
630
651
|
|
|
631
|
-
def get_build_path(self) -> Path:
|
|
632
|
-
return self.get_path() / "build"
|
|
633
|
-
|
|
634
|
-
def get_serve_path(self) -> Path:
|
|
635
|
-
return self.get_path() / "serve"
|
|
636
|
-
|
|
637
652
|
def build_prepare(self, serve: Serve) -> None:
|
|
638
653
|
self.prepare_bash_script.parent.mkdir(parents=True, exist_ok=True)
|
|
639
654
|
commands: List[str] = []
|
|
@@ -676,14 +691,13 @@ class LocalBuilder:
|
|
|
676
691
|
def build_serve(self, serve: Serve) -> None:
|
|
677
692
|
# Remember serve configuration for run-time
|
|
678
693
|
console.print("\n[bold]Building serve[/bold]")
|
|
679
|
-
|
|
680
|
-
serve_command_path.mkdir(parents=True, exist_ok=False)
|
|
694
|
+
self.serve_bin_path.mkdir(parents=True, exist_ok=False)
|
|
681
695
|
path = self.get_path() / ".path"
|
|
682
696
|
path_text = path.read_text()
|
|
683
697
|
console.print(f"[bold]Serve Commands:[/bold]")
|
|
684
698
|
for command in serve.commands:
|
|
685
699
|
console.print(f"* {command}")
|
|
686
|
-
command_path =
|
|
700
|
+
command_path = self.serve_bin_path / command
|
|
687
701
|
env_vars = ""
|
|
688
702
|
if serve.env:
|
|
689
703
|
env_vars = " ".join([f"{k}={v}" for k, v in serve.env.items()])
|
|
@@ -707,8 +721,7 @@ class LocalBuilder:
|
|
|
707
721
|
|
|
708
722
|
def run_serve_command(self, command: str) -> None:
|
|
709
723
|
console.print(f"\n[bold]Running {command} command[/bold]")
|
|
710
|
-
|
|
711
|
-
command_path = base_path / command
|
|
724
|
+
command_path = self.serve_bin_path / command
|
|
712
725
|
sh.Command(str(command_path))(_out=write_stdout, _err=write_stderr)
|
|
713
726
|
|
|
714
727
|
|
|
@@ -808,9 +821,6 @@ class WasmerBuilder:
|
|
|
808
821
|
) -> None:
|
|
809
822
|
return self.inner_builder.build(env, mounts, build)
|
|
810
823
|
|
|
811
|
-
def get_build_path(self) -> Path:
|
|
812
|
-
return Path("/app")
|
|
813
|
-
|
|
814
824
|
def build_prepare(self, serve: Serve) -> None:
|
|
815
825
|
print("Building prepare")
|
|
816
826
|
prepare_dir = self.wasmer_dir_path / "prepare"
|
|
@@ -1704,7 +1714,7 @@ def main() -> None:
|
|
|
1704
1714
|
app()
|
|
1705
1715
|
except Exception as e:
|
|
1706
1716
|
console.print(f"[bold red]{type(e).__name__}[/bold red]: {e}")
|
|
1707
|
-
raise e
|
|
1717
|
+
# raise e
|
|
1708
1718
|
|
|
1709
1719
|
|
|
1710
1720
|
if __name__ == "__main__":
|
shipit/generator.py
CHANGED
|
@@ -109,7 +109,7 @@ def generate_shipit(path: Path, custom_commands: CustomCommands) -> str:
|
|
|
109
109
|
|
|
110
110
|
build_steps_block = ",\n".join([f" {s}" for s in build_steps])
|
|
111
111
|
deps_array = ", ".join(serve_dep_vars)
|
|
112
|
-
commands_lines = ",\n".join([f' "{k}": {v}' for k, v in plan.commands.items()])
|
|
112
|
+
commands_lines = ",\n".join([f' "{k}": {v}.replace("$PORT", PORT)' for k, v in plan.commands.items()])
|
|
113
113
|
env_lines = None
|
|
114
114
|
if plan.env is not None:
|
|
115
115
|
if len(plan.env) == 0:
|
|
@@ -119,31 +119,43 @@ def generate_shipit(path: Path, custom_commands: CustomCommands) -> str:
|
|
|
119
119
|
mounts_block = None
|
|
120
120
|
volumes_block = None
|
|
121
121
|
attach_serve_names: list[str] = []
|
|
122
|
+
|
|
122
123
|
if plan.mounts:
|
|
123
124
|
mounts = list(filter(lambda m: m.attach_to_serve, plan.mounts))
|
|
124
125
|
attach_serve_names = [m.name for m in mounts]
|
|
125
126
|
mounts_block = ",\n".join([f" {m.name}" for m in mounts])
|
|
127
|
+
|
|
126
128
|
if plan.volumes:
|
|
127
129
|
volumes_block = ",\n".join(
|
|
128
130
|
[f" {v.var_name or v.name}" for v in plan.volumes]
|
|
129
131
|
)
|
|
130
132
|
|
|
131
133
|
out: List[str] = []
|
|
134
|
+
|
|
132
135
|
if dep_block:
|
|
133
136
|
out.append(dep_block)
|
|
134
137
|
out.append("")
|
|
138
|
+
|
|
135
139
|
for m in plan.mounts:
|
|
136
140
|
out.append(f"{m.name} = mount(\"{m.name}\")")
|
|
141
|
+
out.append("")
|
|
142
|
+
|
|
137
143
|
if plan.volumes:
|
|
138
144
|
for v in plan.volumes:
|
|
139
145
|
out.append(f"{v.var_name or v.name} = volume(\"{v.name}\", {v.serve_path})")
|
|
146
|
+
out.append("")
|
|
147
|
+
|
|
140
148
|
if plan.services:
|
|
141
149
|
for s in plan.services:
|
|
142
150
|
out.append(f"{s.name} = service(\n name=\"{s.name}\",\n provider=\"{s.provider}\"\n)")
|
|
151
|
+
out.append("")
|
|
152
|
+
|
|
153
|
+
out.append("PORT = getenv(\"PORT\") or\"8080\"")
|
|
143
154
|
|
|
144
155
|
if plan.declarations:
|
|
145
156
|
out.append(plan.declarations)
|
|
146
|
-
|
|
157
|
+
|
|
158
|
+
out.append("")
|
|
147
159
|
out.append("serve(")
|
|
148
160
|
out.append(f' name="{plan.serve_name}",')
|
|
149
161
|
out.append(f' provider="{plan.provider}",')
|
shipit/providers/hugo.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, ServiceSpec, VolumeSpec, CustomCommands
|
|
6
|
+
from .base import DetectResult, DependencySpec, Provider, _exists, ServiceSpec, VolumeSpec, CustomCommands, MountSpec
|
|
7
7
|
from .staticfile import StaticFileProvider
|
|
8
8
|
|
|
9
9
|
class HugoProvider(StaticFileProvider):
|
|
@@ -43,10 +43,14 @@ class HugoProvider(StaticFileProvider):
|
|
|
43
43
|
|
|
44
44
|
def build_steps(self) -> list[str]:
|
|
45
45
|
return [
|
|
46
|
+
'workdir(temp["build"])',
|
|
46
47
|
'copy(".", ".", ignore=[".git"])',
|
|
47
48
|
'run("hugo build --destination={}".format(app["build"]), group="build")',
|
|
48
49
|
]
|
|
49
|
-
|
|
50
|
+
|
|
51
|
+
def mounts(self) -> list[MountSpec]:
|
|
52
|
+
return [MountSpec("temp", attach_to_serve=False), *super().mounts()]
|
|
53
|
+
|
|
50
54
|
def services(self) -> list[ServiceSpec]:
|
|
51
55
|
return []
|
|
52
56
|
|
shipit/providers/laravel.py
CHANGED
shipit/providers/mkdocs.py
CHANGED
|
@@ -30,6 +30,8 @@ class MkdocsProvider(StaticFileProvider):
|
|
|
30
30
|
def detect(cls, path: Path, custom_commands: CustomCommands) -> Optional[DetectResult]:
|
|
31
31
|
if _exists(path, "mkdocs.yml", "mkdocs.yaml"):
|
|
32
32
|
return DetectResult(cls.name(), 85)
|
|
33
|
+
if custom_commands.build and custom_commands.build.startswith("mkdocs "):
|
|
34
|
+
return DetectResult(cls.name(), 85)
|
|
33
35
|
return None
|
|
34
36
|
|
|
35
37
|
def initialize(self) -> None:
|
shipit/providers/node_static.py
CHANGED
|
@@ -1,37 +1,206 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import json
|
|
4
|
+
import yaml
|
|
3
5
|
from pathlib import Path
|
|
4
|
-
from typing import Dict, Optional
|
|
6
|
+
from typing import Dict, Optional, Any, Set
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from semantic_version import Version, NpmSpec
|
|
9
|
+
|
|
5
10
|
|
|
6
11
|
from .base import (
|
|
7
12
|
DetectResult,
|
|
8
13
|
DependencySpec,
|
|
9
14
|
Provider,
|
|
10
15
|
_exists,
|
|
11
|
-
_has_dependency,
|
|
12
16
|
MountSpec,
|
|
13
17
|
ServiceSpec,
|
|
14
18
|
VolumeSpec,
|
|
15
19
|
CustomCommands,
|
|
16
20
|
)
|
|
21
|
+
from .staticfile import StaticFileProvider
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class PackageManager(Enum):
|
|
25
|
+
NPM = "npm"
|
|
26
|
+
PNPM = "pnpm"
|
|
27
|
+
YARN = "yarn"
|
|
28
|
+
BUN = "bun"
|
|
29
|
+
|
|
30
|
+
def as_dependency(self, path) -> DependencySpec:
|
|
31
|
+
dep_name = {
|
|
32
|
+
PackageManager.NPM: "npm",
|
|
33
|
+
PackageManager.PNPM: "pnpm",
|
|
34
|
+
PackageManager.YARN: "yarn",
|
|
35
|
+
PackageManager.BUN: "bun",
|
|
36
|
+
}[self]
|
|
37
|
+
|
|
38
|
+
default_version = None
|
|
39
|
+
if self == PackageManager.PNPM:
|
|
40
|
+
lockfile = path / self.lockfile()
|
|
41
|
+
lockfile_version = self.pnpm_lockfile_version(lockfile)
|
|
42
|
+
if lockfile_version:
|
|
43
|
+
if lockfile_version.startswith("5."):
|
|
44
|
+
default_version = "7"
|
|
45
|
+
elif lockfile_version.startswith("6."):
|
|
46
|
+
default_version = "8"
|
|
47
|
+
|
|
48
|
+
return DependencySpec(
|
|
49
|
+
dep_name,
|
|
50
|
+
env_var=f"SHIPIT_{dep_name.upper()}_VERSION",
|
|
51
|
+
default_version=default_version,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def lockfile(self) -> (str):
|
|
55
|
+
return {
|
|
56
|
+
PackageManager.NPM: "package-lock.json",
|
|
57
|
+
PackageManager.PNPM: "pnpm-lock.yaml",
|
|
58
|
+
PackageManager.YARN: "yarn.lock",
|
|
59
|
+
PackageManager.BUN: "bun.lockb",
|
|
60
|
+
}[self]
|
|
61
|
+
|
|
62
|
+
@classmethod
|
|
63
|
+
def pnpm_lockfile_version(cls, lockfile: Path) -> Optional[str]:
|
|
64
|
+
# Read line by line and return the lockfileVersion
|
|
65
|
+
with open(lockfile, "r") as f:
|
|
66
|
+
for line in f:
|
|
67
|
+
if "lockfileVersion" in line:
|
|
68
|
+
try:
|
|
69
|
+
config = yaml.safe_load(line)
|
|
70
|
+
version = config.get("lockfileVersion")
|
|
71
|
+
assert isinstance(version, (str, bytes))
|
|
72
|
+
return version
|
|
73
|
+
except:
|
|
74
|
+
pass
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
def install_command(self, has_lockfile: bool = False) -> str:
|
|
78
|
+
return {
|
|
79
|
+
PackageManager.NPM: f"npm {'ci' if has_lockfile else 'install'}",
|
|
80
|
+
PackageManager.PNPM: f"pnpm install{' --frozen-lockfile' if has_lockfile else ''}",
|
|
81
|
+
PackageManager.YARN: f"yarn install{' --frozen-lockfile' if has_lockfile else ''}",
|
|
82
|
+
PackageManager.BUN: f"bun install{' --no-save' if has_lockfile else ''}",
|
|
83
|
+
}[self]
|
|
84
|
+
|
|
85
|
+
def run_command(self, command: str) -> str:
|
|
86
|
+
return {
|
|
87
|
+
PackageManager.NPM: f"npm run {command}",
|
|
88
|
+
PackageManager.PNPM: f"pnpm run {command}",
|
|
89
|
+
PackageManager.YARN: f"yarn run {command}",
|
|
90
|
+
PackageManager.BUN: f"bun run {command}",
|
|
91
|
+
}[self]
|
|
92
|
+
|
|
93
|
+
def run_execute_command(self, command: str) -> str:
|
|
94
|
+
return {
|
|
95
|
+
PackageManager.NPM: f"npx {command}",
|
|
96
|
+
PackageManager.PNPM: f"pnpx {command}",
|
|
97
|
+
PackageManager.YARN: f"ypx {command}",
|
|
98
|
+
PackageManager.BUN: f"bunx {command}",
|
|
99
|
+
}[self]
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class StaticGenerator(Enum):
|
|
103
|
+
ASTRO = "astro"
|
|
104
|
+
VITE = "vite"
|
|
105
|
+
NEXT = "next"
|
|
106
|
+
GATSBY = "gatsby"
|
|
107
|
+
DOCUSAURUS = "docusaurus"
|
|
108
|
+
SVELTE = "svelte"
|
|
109
|
+
REMIX = "remix"
|
|
110
|
+
NUXT_OLD = "nuxt"
|
|
111
|
+
NUXT_V3 = "nuxt3"
|
|
17
112
|
|
|
18
113
|
|
|
19
|
-
class NodeStaticProvider:
|
|
114
|
+
class NodeStaticProvider(StaticFileProvider):
|
|
115
|
+
package_manager: PackageManager
|
|
116
|
+
package_json: Optional[Dict[str, Any]]
|
|
117
|
+
extra_dependencies: Set[str]
|
|
118
|
+
|
|
20
119
|
def __init__(self, path: Path, custom_commands: CustomCommands):
|
|
21
|
-
|
|
22
|
-
|
|
120
|
+
super().__init__(path, custom_commands)
|
|
121
|
+
if (path / "package-lock.json").exists():
|
|
122
|
+
self.package_manager = PackageManager.NPM
|
|
123
|
+
elif (path / "pnpm-lock.yaml").exists():
|
|
124
|
+
self.package_manager = PackageManager.PNPM
|
|
125
|
+
elif (path / "yarn.lock").exists():
|
|
126
|
+
self.package_manager = PackageManager.YARN
|
|
127
|
+
elif (path / "bun.lockb").exists():
|
|
128
|
+
self.package_manager = PackageManager.BUN
|
|
129
|
+
else:
|
|
130
|
+
self.package_manager = PackageManager.PNPM
|
|
131
|
+
|
|
132
|
+
self.package_json = self.parse_package_json(path)
|
|
133
|
+
|
|
134
|
+
if self.has_dependency(self.package_json, "gatsby"):
|
|
135
|
+
self.static_generator = StaticGenerator.GATSBY
|
|
136
|
+
elif self.has_dependency(self.package_json, "astro"):
|
|
137
|
+
self.static_generator = StaticGenerator.ASTRO
|
|
138
|
+
elif self.has_dependency(self.package_json, "@docusaurus/core"):
|
|
139
|
+
self.static_generator = StaticGenerator.DOCUSAURUS
|
|
140
|
+
elif self.has_dependency(self.package_json, "svelte"):
|
|
141
|
+
self.static_generator = StaticGenerator.SVELTE
|
|
142
|
+
elif self.has_dependency(self.package_json, "@remix-run/dev"):
|
|
143
|
+
self.static_generator = StaticGenerator.REMIX
|
|
144
|
+
elif self.has_dependency(self.package_json, "vite"):
|
|
145
|
+
self.static_generator = StaticGenerator.VITE
|
|
146
|
+
elif self.has_dependency(self.package_json, "next"):
|
|
147
|
+
self.static_generator = StaticGenerator.NEXT
|
|
148
|
+
elif self.has_dependency(self.package_json, "nuxt", "2") or self.has_dependency(
|
|
149
|
+
self.package_json, "nuxt", "1"
|
|
150
|
+
):
|
|
151
|
+
self.static_generator = StaticGenerator.NUXT_OLD
|
|
152
|
+
elif self.has_dependency(self.package_json, "nuxt"):
|
|
153
|
+
self.static_generator = StaticGenerator.NUXT_V3
|
|
154
|
+
|
|
155
|
+
# if self.has_dependency(self.package_json, "sharp"):
|
|
156
|
+
# self.extra_dependencies.add("libvips")
|
|
157
|
+
|
|
158
|
+
@classmethod
|
|
159
|
+
def parse_package_json(cls, path: Path) -> Optional[Dict[str, Any]]:
|
|
160
|
+
package_json_path = path / "package.json"
|
|
161
|
+
if not package_json_path.exists():
|
|
162
|
+
return None
|
|
163
|
+
try:
|
|
164
|
+
package_json = json.loads(package_json_path.read_text())
|
|
165
|
+
assert isinstance(package_json, dict), (
|
|
166
|
+
"package.json must be a valid JSON object"
|
|
167
|
+
)
|
|
168
|
+
return package_json
|
|
169
|
+
except Exception:
|
|
170
|
+
return None
|
|
171
|
+
|
|
172
|
+
@classmethod
|
|
173
|
+
def has_dependency(
|
|
174
|
+
cls, package_json: Optional[Dict[str, Any]], dep: str, version: Optional[str] = None
|
|
175
|
+
) -> bool:
|
|
176
|
+
if not package_json:
|
|
177
|
+
return False
|
|
178
|
+
for section in ("dependencies", "devDependencies", "peerDependencies"):
|
|
179
|
+
dep_section = package_json.get(section, {})
|
|
180
|
+
if dep in dep_section:
|
|
181
|
+
if version:
|
|
182
|
+
try:
|
|
183
|
+
constraint = NpmSpec(dep_section[dep])
|
|
184
|
+
return Version(version) in constraint
|
|
185
|
+
except Exception:
|
|
186
|
+
pass
|
|
187
|
+
else:
|
|
188
|
+
return True
|
|
189
|
+
return False
|
|
23
190
|
|
|
24
191
|
@classmethod
|
|
25
192
|
def name(cls) -> str:
|
|
26
193
|
return "node-static"
|
|
27
194
|
|
|
28
195
|
@classmethod
|
|
29
|
-
def detect(
|
|
30
|
-
|
|
31
|
-
|
|
196
|
+
def detect(
|
|
197
|
+
cls, path: Path, custom_commands: CustomCommands
|
|
198
|
+
) -> Optional[DetectResult]:
|
|
199
|
+
package_json = cls.parse_package_json(path)
|
|
200
|
+
if not package_json:
|
|
32
201
|
return None
|
|
33
|
-
static_generators = ["astro", "vite", "next", "nuxt"]
|
|
34
|
-
if any(
|
|
202
|
+
static_generators = ["astro", "vite", "next", "nuxt", "gatsby", "svelte", "@docusaurus/core", "@remix-run/dev"]
|
|
203
|
+
if any(cls.has_dependency(package_json, dep) for dep in static_generators):
|
|
35
204
|
return DetectResult(cls.name(), 40)
|
|
36
205
|
return None
|
|
37
206
|
|
|
@@ -45,6 +214,8 @@ class NodeStaticProvider:
|
|
|
45
214
|
return "staticsite"
|
|
46
215
|
|
|
47
216
|
def dependencies(self) -> list[DependencySpec]:
|
|
217
|
+
package_manager_dep = self.package_manager.as_dependency(self.path)
|
|
218
|
+
package_manager_dep.use_in_build = True
|
|
48
219
|
return [
|
|
49
220
|
DependencySpec(
|
|
50
221
|
"node",
|
|
@@ -52,37 +223,82 @@ class NodeStaticProvider:
|
|
|
52
223
|
default_version="22",
|
|
53
224
|
use_in_build=True,
|
|
54
225
|
),
|
|
55
|
-
|
|
226
|
+
package_manager_dep,
|
|
56
227
|
DependencySpec("static-web-server", use_in_serve=True),
|
|
57
228
|
]
|
|
58
229
|
|
|
59
230
|
def declarations(self) -> Optional[str]:
|
|
60
231
|
return None
|
|
61
232
|
|
|
233
|
+
def get_output_dir(self) -> str:
|
|
234
|
+
if self.static_generator == StaticGenerator.NEXT:
|
|
235
|
+
return "out"
|
|
236
|
+
elif self.static_generator in [StaticGenerator.ASTRO, StaticGenerator.VITE, StaticGenerator.NUXT_OLD, StaticGenerator.NUXT_V3]:
|
|
237
|
+
return "dist"
|
|
238
|
+
elif self.static_generator in [StaticGenerator.GATSBY, StaticGenerator.REMIX]:
|
|
239
|
+
return "public"
|
|
240
|
+
elif self.static_generator in [StaticGenerator.DOCUSAURUS, StaticGenerator.SVELTE]:
|
|
241
|
+
return "build"
|
|
242
|
+
else:
|
|
243
|
+
return "dist"
|
|
244
|
+
|
|
245
|
+
def get_build_command(self) -> bool:
|
|
246
|
+
if not self.package_json:
|
|
247
|
+
return False
|
|
248
|
+
build_command = self.package_json.get("scripts", {}).get("build")
|
|
249
|
+
if build_command:
|
|
250
|
+
return self.package_manager.run_command("build")
|
|
251
|
+
if self.static_generator == StaticGenerator.GATSBY:
|
|
252
|
+
return self.package_manager.run_execute_command("gatsby build")
|
|
253
|
+
if self.static_generator == StaticGenerator.ASTRO:
|
|
254
|
+
return self.package_manager.run_execute_command("astro build")
|
|
255
|
+
elif self.static_generator == StaticGenerator.REMIX:
|
|
256
|
+
return self.package_manager.run_execute_command("remix-ssg build")
|
|
257
|
+
elif self.static_generator == StaticGenerator.DOCUSAURUS:
|
|
258
|
+
return self.package_manager.run_execute_command("docusaurus build")
|
|
259
|
+
elif self.static_generator == StaticGenerator.SVELTE:
|
|
260
|
+
return self.package_manager.run_execute_command("svelte-kit build")
|
|
261
|
+
elif self.static_generator == StaticGenerator.VITE:
|
|
262
|
+
return self.package_manager.run_execute_command("vite build")
|
|
263
|
+
elif self.static_generator == StaticGenerator.NEXT:
|
|
264
|
+
return self.package_manager.run_execute_command("next export")
|
|
265
|
+
elif self.static_generator == StaticGenerator.NUXT_V3:
|
|
266
|
+
return self.package_manager.run_execute_command("nuxi generate")
|
|
267
|
+
elif self.static_generator == StaticGenerator.NUXT_OLD:
|
|
268
|
+
return self.package_manager.run_execute_command("nuxt generate")
|
|
269
|
+
return False
|
|
270
|
+
|
|
62
271
|
def build_steps(self) -> list[str]:
|
|
63
|
-
output_dir =
|
|
272
|
+
output_dir = self.get_output_dir()
|
|
273
|
+
get_build_command = self.get_build_command()
|
|
274
|
+
lockfile = self.package_manager.lockfile()
|
|
275
|
+
has_lockfile = (self.path / lockfile).exists()
|
|
276
|
+
install_command = self.package_manager.install_command(has_lockfile=has_lockfile)
|
|
277
|
+
input_files = ["package.json"]
|
|
278
|
+
if has_lockfile:
|
|
279
|
+
input_files.append(lockfile)
|
|
280
|
+
inputs_install_files = ", ".join([f'"{file}"' for file in input_files])
|
|
281
|
+
|
|
64
282
|
return [
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
f
|
|
68
|
-
|
|
283
|
+
'workdir(temp["build"])',
|
|
284
|
+
# 'run("npx corepack enable", inputs=["package.json"], group="install")',
|
|
285
|
+
f'run("{install_command}", inputs=[{inputs_install_files}], group="install")',
|
|
286
|
+
'copy(".", ".", ignore=["node_modules", ".git"])',
|
|
287
|
+
f'run("{get_build_command}", outputs=["{output_dir}"], group="build")',
|
|
288
|
+
f'run("cp -R {output_dir}/* {{}}/".format(app["build"]))',
|
|
69
289
|
]
|
|
70
290
|
|
|
71
291
|
def prepare_steps(self) -> Optional[list[str]]:
|
|
72
292
|
return None
|
|
73
293
|
|
|
74
|
-
def commands(self) -> Dict[str, str]:
|
|
75
|
-
output_dir = "dist" if (self.path / "dist").exists() else "public"
|
|
76
|
-
return {"start": f'"static-web-server --root /app/{output_dir}"'}
|
|
77
|
-
|
|
78
294
|
def mounts(self) -> list[MountSpec]:
|
|
79
|
-
return [MountSpec("
|
|
295
|
+
return [MountSpec("temp"), *super().mounts()]
|
|
80
296
|
|
|
81
297
|
def volumes(self) -> list[VolumeSpec]:
|
|
82
298
|
return []
|
|
83
299
|
|
|
84
300
|
def env(self) -> Optional[Dict[str, str]]:
|
|
85
301
|
return None
|
|
86
|
-
|
|
302
|
+
|
|
87
303
|
def services(self) -> list[ServiceSpec]:
|
|
88
304
|
return []
|
shipit/providers/php.py
CHANGED
|
@@ -92,9 +92,9 @@ class PhpProvider:
|
|
|
92
92
|
|
|
93
93
|
def base_commands(self) -> Dict[str, str]:
|
|
94
94
|
if _exists(self.path, "public/index.php"):
|
|
95
|
-
return {"start": '"php -S localhost:
|
|
95
|
+
return {"start": 'f"php -S localhost:{PORT} -t public"'}
|
|
96
96
|
elif _exists(self.path, "index.php"):
|
|
97
|
-
return {"start": '"php -S localhost:
|
|
97
|
+
return {"start": 'f"php -S localhost:{PORT} -t ."'}
|
|
98
98
|
|
|
99
99
|
def mounts(self) -> list[MountSpec]:
|
|
100
100
|
return [
|
shipit/providers/python.py
CHANGED
|
@@ -284,7 +284,7 @@ class PythonProvider:
|
|
|
284
284
|
if not self.only_build:
|
|
285
285
|
steps = ['workdir(app["build"])']
|
|
286
286
|
else:
|
|
287
|
-
steps = []
|
|
287
|
+
steps = ['workdir(temp["build"])']
|
|
288
288
|
|
|
289
289
|
extra_deps = ", ".join([f"{dep}" for dep in self.extra_dependencies])
|
|
290
290
|
has_requirements = _exists(self.path, "requirements.txt")
|
|
@@ -317,7 +317,7 @@ class PythonProvider:
|
|
|
317
317
|
]
|
|
318
318
|
if not self.only_build:
|
|
319
319
|
steps += [
|
|
320
|
-
'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 -o cross-requirements.txt", outputs=["cross-requirements.txt"]) if cross_platform else None',
|
|
320
|
+
'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 --no-deps -o cross-requirements.txt", outputs=["cross-requirements.txt"]) if cross_platform else None',
|
|
321
321
|
f'run(f"uvx pip install -r cross-requirements.txt {extra_deps} --target {{python_cross_packages_path}} --platform {{cross_platform}} --only-binary=:all: --python-version={{python_version}} --compile") if cross_platform else None',
|
|
322
322
|
'run("rm cross-requirements.txt") if cross_platform else None',
|
|
323
323
|
]
|
|
@@ -337,7 +337,7 @@ class PythonProvider:
|
|
|
337
337
|
]
|
|
338
338
|
if not self.only_build:
|
|
339
339
|
steps += [
|
|
340
|
-
'run(f"uv pip compile requirements.txt --python-version={python_version} --universal --extra-index-url {python_extra_index_url} --index-url=https://pypi.org/simple --emit-index-url -o cross-requirements.txt", inputs=["requirements.txt"], outputs=["cross-requirements.txt"]) if cross_platform else None',
|
|
340
|
+
'run(f"uv pip compile requirements.txt --python-version={python_version} --universal --extra-index-url {python_extra_index_url} --index-url=https://pypi.org/simple --emit-index-url --no-deps -o cross-requirements.txt", inputs=["requirements.txt"], outputs=["cross-requirements.txt"]) if cross_platform else None',
|
|
341
341
|
f'run(f"uvx pip install -r cross-requirements.txt {extra_deps} --target {{python_cross_packages_path}} --platform {{cross_platform}} --only-binary=:all: --python-version={{python_version}} --compile") if cross_platform else None',
|
|
342
342
|
'run("rm cross-requirements.txt") if cross_platform else None',
|
|
343
343
|
]
|
|
@@ -396,20 +396,20 @@ class PythonProvider:
|
|
|
396
396
|
if self.server == PythonServer.Daphne and self.asgi_application:
|
|
397
397
|
asgi_application = format_app_import(self.asgi_application)
|
|
398
398
|
start_cmd = (
|
|
399
|
-
f'"python -m daphne {asgi_application} --bind 0.0.0.0 --port
|
|
399
|
+
f'f"python -m daphne {asgi_application} --bind 0.0.0.0 --port {{PORT}}"'
|
|
400
400
|
)
|
|
401
401
|
elif self.server == PythonServer.Uvicorn:
|
|
402
402
|
if self.asgi_application:
|
|
403
403
|
asgi_application = format_app_import(self.asgi_application)
|
|
404
|
-
start_cmd = f'"python -m uvicorn {asgi_application} --host 0.0.0.0 --port
|
|
404
|
+
start_cmd = f'f"python -m uvicorn {asgi_application} --host 0.0.0.0 --port {{PORT}}"'
|
|
405
405
|
elif self.wsgi_application:
|
|
406
406
|
wsgi_application = format_app_import(self.wsgi_application)
|
|
407
|
-
start_cmd = f'"python -m uvicorn {wsgi_application} --interface=wsgi --host 0.0.0.0 --port
|
|
407
|
+
start_cmd = f'f"python -m uvicorn {wsgi_application} --interface=wsgi --host 0.0.0.0 --port {{PORT}}"'
|
|
408
408
|
# elif self.server == PythonServer.Gunicorn:
|
|
409
|
-
# start_cmd = f'"
|
|
409
|
+
# start_cmd = f'"fpython -m gunicorn {self.wsgi_application} --bind 0.0.0.0 --port {{PORT}}"'
|
|
410
410
|
if not start_cmd:
|
|
411
411
|
# We run the default runserver command if no server is specified
|
|
412
|
-
start_cmd = '"python manage.py runserver 0.0.0.0:
|
|
412
|
+
start_cmd = 'f"python manage.py runserver 0.0.0.0:{PORT}"'
|
|
413
413
|
migrate_cmd = '"python manage.py migrate"'
|
|
414
414
|
return {"start": start_cmd, "after_deploy": migrate_cmd}
|
|
415
415
|
|
|
@@ -423,21 +423,21 @@ class PythonProvider:
|
|
|
423
423
|
python_path = file_to_python_path(main_file)
|
|
424
424
|
path = f"{python_path}:app"
|
|
425
425
|
if self.server == PythonServer.Uvicorn:
|
|
426
|
-
start_cmd = f'"python -m uvicorn {path} --host 0.0.0.0 --port
|
|
426
|
+
start_cmd = f'f"python -m uvicorn {path} --host 0.0.0.0 --port {{PORT}}"'
|
|
427
427
|
elif self.server == PythonServer.Hypercorn:
|
|
428
|
-
start_cmd = f'"python -m hypercorn {path} --bind 0.0.0.0:
|
|
428
|
+
start_cmd = f'f"python -m hypercorn {path} --bind 0.0.0.0:{{PORT}}"'
|
|
429
429
|
else:
|
|
430
430
|
start_cmd = '"python -c \'print(\\"No start command detected, please provide a start command manually\\")\'"'
|
|
431
431
|
return {"start": start_cmd}
|
|
432
432
|
|
|
433
433
|
elif self.framework == PythonFramework.Streamlit:
|
|
434
|
-
start_cmd = f'"python -m streamlit run {main_file} --server.port
|
|
434
|
+
start_cmd = f'f"python -m streamlit run {main_file} --server.port {{PORT}} --server.address 0.0.0.0 --server.headless true"'
|
|
435
435
|
|
|
436
436
|
elif self.framework == PythonFramework.Flask:
|
|
437
437
|
python_path = file_to_python_path(main_file)
|
|
438
438
|
path = f"{python_path}:app"
|
|
439
|
-
# start_cmd = f'"python -m flask --app {path} run --debug --host 0.0.0.0 --port
|
|
440
|
-
start_cmd = f'"python -m uvicorn {path} --interface=wsgi --host 0.0.0.0 --port
|
|
439
|
+
# start_cmd = f'f"python -m flask --app {path} run --debug --host 0.0.0.0 --port {{PORT}}"'
|
|
440
|
+
start_cmd = f'f"python -m uvicorn {path} --interface=wsgi --host 0.0.0.0 --port {{PORT}}"'
|
|
441
441
|
|
|
442
442
|
elif self.framework == PythonFramework.MCP:
|
|
443
443
|
contents = (self.path / main_file).read_text()
|
|
@@ -449,7 +449,7 @@ class PythonProvider:
|
|
|
449
449
|
elif self.framework == PythonFramework.FastHTML:
|
|
450
450
|
python_path = file_to_python_path(main_file)
|
|
451
451
|
path = f"{python_path}:app"
|
|
452
|
-
start_cmd = f'"python -m uvicorn {path} --host 0.0.0.0 --port
|
|
452
|
+
start_cmd = f'f"python -m uvicorn {path} --host 0.0.0.0 --port {{PORT}}"'
|
|
453
453
|
|
|
454
454
|
else:
|
|
455
455
|
start_cmd = f'"python {main_file}"'
|
|
@@ -459,6 +459,7 @@ class PythonProvider:
|
|
|
459
459
|
def mounts(self) -> list[MountSpec]:
|
|
460
460
|
if self.only_build:
|
|
461
461
|
return [
|
|
462
|
+
MountSpec("temp", attach_to_serve=False),
|
|
462
463
|
MountSpec("local_venv", attach_to_serve=False),
|
|
463
464
|
]
|
|
464
465
|
return [
|
|
@@ -486,7 +487,7 @@ class PythonProvider:
|
|
|
486
487
|
env_vars["STREAMLIT_SERVER_HEADLESS"] = '"true"'
|
|
487
488
|
elif self.framework == PythonFramework.MCP:
|
|
488
489
|
env_vars["FASTMCP_HOST"] = '"0.0.0.0"'
|
|
489
|
-
env_vars["FASTMCP_PORT"] = '
|
|
490
|
+
env_vars["FASTMCP_PORT"] = 'PORT'
|
|
490
491
|
return env_vars
|
|
491
492
|
|
|
492
493
|
def services(self) -> list[ServiceSpec]:
|
shipit/providers/registry.py
CHANGED
shipit/providers/staticfile.py
CHANGED
|
@@ -2,6 +2,8 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Dict, Optional
|
|
5
|
+
import json
|
|
6
|
+
import yaml
|
|
5
7
|
|
|
6
8
|
from .base import (
|
|
7
9
|
DetectResult,
|
|
@@ -16,9 +18,19 @@ from .base import (
|
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
class StaticFileProvider:
|
|
21
|
+
config: Optional[dict] = None
|
|
22
|
+
path: Path
|
|
23
|
+
custom_commands: CustomCommands
|
|
24
|
+
|
|
19
25
|
def __init__(self, path: Path, custom_commands: CustomCommands):
|
|
20
26
|
self.path = path
|
|
21
27
|
self.custom_commands = custom_commands
|
|
28
|
+
if (self.path / "Staticfile").exists():
|
|
29
|
+
try:
|
|
30
|
+
self.config = yaml.safe_load((self.path / "Staticfile").read_text())
|
|
31
|
+
except yaml.YAMLError as e:
|
|
32
|
+
print(f"Error loading Staticfile: {e}")
|
|
33
|
+
pass
|
|
22
34
|
|
|
23
35
|
@classmethod
|
|
24
36
|
def name(cls) -> str:
|
|
@@ -58,7 +70,7 @@ class StaticFileProvider:
|
|
|
58
70
|
def build_steps(self) -> list[str]:
|
|
59
71
|
return [
|
|
60
72
|
'workdir(app["build"])',
|
|
61
|
-
'copy(
|
|
73
|
+
'copy({}, ".", ignore=[".git"])'.format(json.dumps(self.config and self.config.get("root") or "."))
|
|
62
74
|
]
|
|
63
75
|
|
|
64
76
|
def prepare_steps(self) -> Optional[list[str]]:
|
|
@@ -69,7 +81,7 @@ class StaticFileProvider:
|
|
|
69
81
|
|
|
70
82
|
def commands(self) -> Dict[str, str]:
|
|
71
83
|
return {
|
|
72
|
-
"start": '"static-web-server --root={} --log-level=info".format(app["serve"])'
|
|
84
|
+
"start": '"static-web-server --root={} --log-level=info --port={}".format(app["serve"], PORT)'
|
|
73
85
|
}
|
|
74
86
|
|
|
75
87
|
def mounts(self) -> list[MountSpec]:
|
shipit/providers/wordpress.py
CHANGED
|
@@ -70,7 +70,7 @@ class WordPressProvider(PhpProvider):
|
|
|
70
70
|
|
|
71
71
|
def commands(self) -> Dict[str, str]:
|
|
72
72
|
return {
|
|
73
|
-
"start": '"php -S localhost:
|
|
73
|
+
"start": 'f"php -S localhost:{PORT} -t ."',
|
|
74
74
|
"wp": '"php {}/wp-cli.phar --allow-root --path={}".format(assets[\"serve\"], app[\"serve\"])',
|
|
75
75
|
"after_deploy": '"bash {}/wordpress-install.sh".format(assets["serve"])',
|
|
76
76
|
}
|
shipit/version.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shipit-cli
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.9.0
|
|
4
|
+
Summary: Shipit CLI is the best way to build, serve and deploy your projects anywhere.
|
|
5
5
|
Project-URL: homepage, https://wasmer.io
|
|
6
6
|
Project-URL: repository, https://github.com/wasmerio/shipit
|
|
7
7
|
Project-URL: Changelog, https://github.com/wasmerio/shipit/changelog
|
|
@@ -10,6 +10,7 @@ Requires-Dist: dotenv>=0.9.9
|
|
|
10
10
|
Requires-Dist: pyyaml>=6.0.2
|
|
11
11
|
Requires-Dist: requests>=2.32.5
|
|
12
12
|
Requires-Dist: rich>=14.1.0
|
|
13
|
+
Requires-Dist: semantic-version>=2.10.0
|
|
13
14
|
Requires-Dist: sh>=2.2.2
|
|
14
15
|
Requires-Dist: starlark-pyo3>=2025.1
|
|
15
16
|
Requires-Dist: tomlkit>=0.13.3
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
shipit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
shipit/cli.py,sha256=NMZ6xSLq8MlV9yT3FLi9XZ5IBw2IMppoPna_vl9LK1Y,59170
|
|
3
|
+
shipit/generator.py,sha256=W4MynSFwId4PRWWrF0R3NsANye_Zv8TwXCUXai94pW0,6553
|
|
4
|
+
shipit/procfile.py,sha256=GlfdwzFUr0GWGKaaiXlLKNFInWaRNMy_wN14UEyU_5Q,2974
|
|
5
|
+
shipit/version.py,sha256=0hkQAsOavRu0fhDHnq4yN300QZjC88Y_Nr7gIReJ_9Y,95
|
|
6
|
+
shipit/assets/php/php.ini,sha256=f4irndAjB4GuuouEImRkNV22Q-yw1KqR-43jAMDw730,2531
|
|
7
|
+
shipit/assets/wordpress/install.sh,sha256=fJkVeGAw_dj-ywmQipAWRjaz57sayD6F0OFvZKMIKug,669
|
|
8
|
+
shipit/assets/wordpress/wp-config.php,sha256=IdGQoeg8E89JiqwxO2i8WnGMzmhNWgRz80X6lbU5GXc,4134
|
|
9
|
+
shipit/providers/base.py,sha256=-lraLhnXtc2SfYNIUiyry7xD2NL4q0n6voNjr6qfRis,2994
|
|
10
|
+
shipit/providers/gatsby.py,sha256=kzfS-z040GaJ0a9u2_6S6K-ykGSX2yPG17VpjUWBOBA,2393
|
|
11
|
+
shipit/providers/hugo.py,sha256=l3IZ14LGYc3wQ7Uk0iQMDNN9Syd1G4HPzm0ePCGFyzE,1808
|
|
12
|
+
shipit/providers/laravel.py,sha256=2rCuOi2kC5OYQfAG7C0NMhG7KEgzfudwUT_CvVFz4hM,3031
|
|
13
|
+
shipit/providers/mkdocs.py,sha256=mDJpT3rzYAr5Vw-yt5fCpV0QgBZyksn9MrkPd4nzROU,2200
|
|
14
|
+
shipit/providers/node_static.py,sha256=j5VKT_RblonIHTtpiUNai4e_izZUhbyLtPTsGeALpcY,11508
|
|
15
|
+
shipit/providers/php.py,sha256=BSOqS3UhABoe_ued8aXtyn0KdqWbOCq6VV2ehtoBlmk,3547
|
|
16
|
+
shipit/providers/python.py,sha256=kQpaaQi8ajHM_SFk2xI5lRIeOc6PXSKumb-Tv_5n6m0,20954
|
|
17
|
+
shipit/providers/registry.py,sha256=JCuQaYTvJcWK1nS-om9TIQgGW6pT5BuNLIRzChLLFWE,731
|
|
18
|
+
shipit/providers/staticfile.py,sha256=F4thEuihDW-h5DO-lotrjSdHYWzoXofQPpsAgWonvpY,2677
|
|
19
|
+
shipit/providers/wordpress.py,sha256=Wjc1fgFburewlf4hQ2ZmxTQko_SHQW-8jrDukzKx0Gs,3019
|
|
20
|
+
shipit_cli-0.9.0.dist-info/METADATA,sha256=ULUMj5u3OzMZA00AoJJOxA0iAsHIw5R-d8IODyR0hJ8,615
|
|
21
|
+
shipit_cli-0.9.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
22
|
+
shipit_cli-0.9.0.dist-info/entry_points.txt,sha256=7AE1NjSrHaSDfbfsRRO50KKnHFTbB0Imsccd1WynzAQ,72
|
|
23
|
+
shipit_cli-0.9.0.dist-info/RECORD,,
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
shipit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
shipit/cli.py,sha256=1U65pviCsaH-fZO3hGYWoyO1WqXCfOxnGwPIomwc5Fg,58363
|
|
3
|
-
shipit/generator.py,sha256=GFsuqZG83gn7yxphE4GHwZjEB3sToJn24yNDE-zrTtM,6400
|
|
4
|
-
shipit/procfile.py,sha256=GlfdwzFUr0GWGKaaiXlLKNFInWaRNMy_wN14UEyU_5Q,2974
|
|
5
|
-
shipit/version.py,sha256=-1rPwQ4VEhKG8LAXODaAwzxwpFY9hDgohd2s_aRySc4,95
|
|
6
|
-
shipit/assets/php/php.ini,sha256=f4irndAjB4GuuouEImRkNV22Q-yw1KqR-43jAMDw730,2531
|
|
7
|
-
shipit/assets/wordpress/install.sh,sha256=GOIwJX3qPp7VuZXjkKVFFY6Mo9k7VFWfobS6aZYitPg,817
|
|
8
|
-
shipit/assets/wordpress/wp-config.php,sha256=IdGQoeg8E89JiqwxO2i8WnGMzmhNWgRz80X6lbU5GXc,4134
|
|
9
|
-
shipit/providers/base.py,sha256=-lraLhnXtc2SfYNIUiyry7xD2NL4q0n6voNjr6qfRis,2994
|
|
10
|
-
shipit/providers/gatsby.py,sha256=kzfS-z040GaJ0a9u2_6S6K-ykGSX2yPG17VpjUWBOBA,2393
|
|
11
|
-
shipit/providers/hugo.py,sha256=BvSYTDTVxHz6FW2mA4sqIsNayFRo5BK6Z4tWFRRimmY,1644
|
|
12
|
-
shipit/providers/laravel.py,sha256=yhOnaaXZ2US8EO5ZD5pBTerSOBi9IWBBIqeQrbW7YoM,3028
|
|
13
|
-
shipit/providers/mkdocs.py,sha256=pWTeIUEnSyB653s7Cw_OSllgiSGcDymRTEHgV5ChDLM,2070
|
|
14
|
-
shipit/providers/node_static.py,sha256=QVUTTZbvUGtj2yT9WTbGmuM30rJzejnp76crIqSGA7o,2564
|
|
15
|
-
shipit/providers/php.py,sha256=JIWl5CdVEdf9DAr9O9rR8NucucYCj_M5PbJRw_SnmYU,3541
|
|
16
|
-
shipit/providers/python.py,sha256=n0748miZ5RpQyQUCmkq3_G2Nnub8SaogZoJTNNFalZc,20801
|
|
17
|
-
shipit/providers/registry.py,sha256=lHUViVuPJf1OIZD8I_NTX4LP7E3Uo5-MmLfarmAA_cM,729
|
|
18
|
-
shipit/providers/staticfile.py,sha256=O1D0cXa_cFZH4OXRFLjBG3e-LbjMDo7ZBC2D3CvrPo4,2218
|
|
19
|
-
shipit/providers/wordpress.py,sha256=wMIcBpICqcEpbOgJCufrnM-r76AVI7_xC-NUlh9XMmE,3016
|
|
20
|
-
shipit_cli-0.7.1.dist-info/METADATA,sha256=uW1Lt7b6mOl7H5k3CPpaPPWNNr-0DHY6p5dxE4Z9B6g,523
|
|
21
|
-
shipit_cli-0.7.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
22
|
-
shipit_cli-0.7.1.dist-info/entry_points.txt,sha256=7AE1NjSrHaSDfbfsRRO50KKnHFTbB0Imsccd1WynzAQ,72
|
|
23
|
-
shipit_cli-0.7.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|