shipit-cli 0.10.1__py3-none-any.whl → 0.11.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/cli.py +182 -41
- shipit/generator.py +21 -9
- shipit/providers/base.py +3 -0
- shipit/providers/gatsby.py +3 -0
- shipit/providers/hugo.py +3 -0
- shipit/providers/laravel.py +3 -0
- shipit/providers/mkdocs.py +3 -0
- shipit/providers/node_static.py +4 -0
- shipit/providers/php.py +34 -16
- shipit/providers/python.py +11 -4
- shipit/providers/staticfile.py +3 -0
- shipit/providers/wordpress.py +7 -5
- shipit/version.py +2 -2
- {shipit_cli-0.10.1.dist-info → shipit_cli-0.11.0.dist-info}/METADATA +1 -1
- shipit_cli-0.11.0.dist-info/RECORD +23 -0
- shipit_cli-0.10.1.dist-info/RECORD +0 -23
- {shipit_cli-0.10.1.dist-info → shipit_cli-0.11.0.dist-info}/WHEEL +0 -0
- {shipit_cli-0.10.1.dist-info → shipit_cli-0.11.0.dist-info}/entry_points.txt +0 -0
shipit/cli.py
CHANGED
|
@@ -16,6 +16,7 @@ from typing import (
|
|
|
16
16
|
Optional,
|
|
17
17
|
Protocol,
|
|
18
18
|
Set,
|
|
19
|
+
Tuple,
|
|
19
20
|
TypedDict,
|
|
20
21
|
Union,
|
|
21
22
|
Literal,
|
|
@@ -33,7 +34,7 @@ from rich.rule import Rule
|
|
|
33
34
|
from rich.syntax import Syntax
|
|
34
35
|
|
|
35
36
|
from shipit.version import version as shipit_version
|
|
36
|
-
from shipit.generator import generate_shipit
|
|
37
|
+
from shipit.generator import generate_shipit, detect_provider
|
|
37
38
|
from shipit.providers.base import CustomCommands
|
|
38
39
|
from shipit.procfile import Procfile
|
|
39
40
|
from dotenv import dotenv_values
|
|
@@ -88,11 +89,13 @@ class Serve:
|
|
|
88
89
|
class Package:
|
|
89
90
|
name: str
|
|
90
91
|
version: Optional[str] = None
|
|
92
|
+
architecture: Optional[Literal["64-bit", "32-bit"]] = None
|
|
91
93
|
|
|
92
94
|
def __str__(self) -> str: # pragma: no cover - simple representation
|
|
95
|
+
name = f"{self.name}({self.architecture})" if self.architecture else self.name
|
|
93
96
|
if self.version is None:
|
|
94
|
-
return
|
|
95
|
-
return f"{
|
|
97
|
+
return name
|
|
98
|
+
return f"{name}@{self.version}"
|
|
96
99
|
|
|
97
100
|
|
|
98
101
|
@dataclass
|
|
@@ -780,6 +783,25 @@ class WasmerBuilder:
|
|
|
780
783
|
"dependencies": {
|
|
781
784
|
"latest": "php/php-32@=8.3.2102",
|
|
782
785
|
"8.3": "php/php-32@=8.3.2102",
|
|
786
|
+
"8.2": "php/php-32@=8.2.2801",
|
|
787
|
+
"8.1": "php/php-32@=8.1.3201",
|
|
788
|
+
"7.4": "php/php-32@=7.4.3301",
|
|
789
|
+
},
|
|
790
|
+
"architecture_dependencies": {
|
|
791
|
+
"64-bit": {
|
|
792
|
+
"latest": "php/php-64@=8.3.2102",
|
|
793
|
+
"8.3": "php/php-64@=8.3.2102",
|
|
794
|
+
"8.2": "php/php-64@=8.2.2801",
|
|
795
|
+
"8.1": "php/php-64@=8.1.3201",
|
|
796
|
+
"7.4": "php/php-64@=7.4.3301",
|
|
797
|
+
},
|
|
798
|
+
"32-bit": {
|
|
799
|
+
"latest": "php/php-32@=8.3.2102",
|
|
800
|
+
"8.3": "php/php-32@=8.3.2102",
|
|
801
|
+
"8.2": "php/php-32@=8.2.2801",
|
|
802
|
+
"8.1": "php/php-32@=8.1.3201",
|
|
803
|
+
"7.4": "php/php-32@=7.4.3301",
|
|
804
|
+
},
|
|
783
805
|
},
|
|
784
806
|
"scripts": {"php"},
|
|
785
807
|
"aliases": {},
|
|
@@ -925,13 +947,20 @@ class WasmerBuilder:
|
|
|
925
947
|
for dep in deps:
|
|
926
948
|
if dep.name in self.mapper:
|
|
927
949
|
version = dep.version or "latest"
|
|
928
|
-
|
|
950
|
+
mapped_dependencies = self.mapper[dep.name]["dependencies"]
|
|
951
|
+
if dep.architecture:
|
|
952
|
+
architecture_dependencies = (
|
|
953
|
+
self.mapper[dep.name]
|
|
954
|
+
.get("architecture_dependencies", {})
|
|
955
|
+
.get(dep.architecture, {})
|
|
956
|
+
)
|
|
957
|
+
if architecture_dependencies:
|
|
958
|
+
mapped_dependencies = architecture_dependencies
|
|
959
|
+
if version in mapped_dependencies:
|
|
929
960
|
console.print(
|
|
930
961
|
f"* {dep.name}@{version} mapped to {self.mapper[dep.name]['dependencies'][version]}"
|
|
931
962
|
)
|
|
932
|
-
package_name, version =
|
|
933
|
-
version
|
|
934
|
-
].split("@")
|
|
963
|
+
package_name, version = mapped_dependencies[version].split("@")
|
|
935
964
|
dependencies.add(package_name, version)
|
|
936
965
|
scripts = self.mapper[dep.name].get("scripts") or []
|
|
937
966
|
for script in scripts:
|
|
@@ -1156,6 +1185,7 @@ class Ctx:
|
|
|
1156
1185
|
self.mounts: List[Mount] = []
|
|
1157
1186
|
self.volumes: List[Volume] = []
|
|
1158
1187
|
self.services: Dict[str, Service] = {}
|
|
1188
|
+
self.getenv_variables: Set[str] = set()
|
|
1159
1189
|
|
|
1160
1190
|
def add_package(self, package: Package) -> str:
|
|
1161
1191
|
index = f"{package.name}@{package.version}" if package.version else package.name
|
|
@@ -1202,10 +1232,16 @@ class Ctx:
|
|
|
1202
1232
|
return f"ref:step:{len(self.steps) - 1}"
|
|
1203
1233
|
|
|
1204
1234
|
def getenv(self, name: str) -> Optional[str]:
|
|
1235
|
+
self.getenv_variables.add(name)
|
|
1205
1236
|
return self.builder.getenv(name)
|
|
1206
1237
|
|
|
1207
|
-
def dep(
|
|
1208
|
-
|
|
1238
|
+
def dep(
|
|
1239
|
+
self,
|
|
1240
|
+
name: str,
|
|
1241
|
+
version: Optional[str] = None,
|
|
1242
|
+
architecture: Optional[Literal["64-bit", "32-bit"]] = None,
|
|
1243
|
+
) -> str:
|
|
1244
|
+
package = Package(name, version, architecture)
|
|
1209
1245
|
return self.add_package(package)
|
|
1210
1246
|
|
|
1211
1247
|
def service(
|
|
@@ -1318,6 +1354,43 @@ class Ctx:
|
|
|
1318
1354
|
}
|
|
1319
1355
|
|
|
1320
1356
|
|
|
1357
|
+
def evaluate_shipit(path: Path, builder: Builder) -> Tuple[Ctx, Serve]:
|
|
1358
|
+
shipit_file = path / "Shipit"
|
|
1359
|
+
if not shipit_file.exists():
|
|
1360
|
+
raise FileNotFoundError(
|
|
1361
|
+
f"Shipit file not found at {shipit_file}. Run `shipit generate {path}` to create it."
|
|
1362
|
+
)
|
|
1363
|
+
source = shipit_file.read_text()
|
|
1364
|
+
ctx = Ctx(builder)
|
|
1365
|
+
glb = sl.Globals.standard()
|
|
1366
|
+
mod = sl.Module()
|
|
1367
|
+
|
|
1368
|
+
mod.add_callable("service", ctx.service)
|
|
1369
|
+
mod.add_callable("getenv", ctx.getenv)
|
|
1370
|
+
mod.add_callable("dep", ctx.dep)
|
|
1371
|
+
mod.add_callable("serve", ctx.serve)
|
|
1372
|
+
mod.add_callable("run", ctx.run)
|
|
1373
|
+
mod.add_callable("mount", ctx.mount)
|
|
1374
|
+
mod.add_callable("volume", ctx.volume)
|
|
1375
|
+
mod.add_callable("workdir", ctx.workdir)
|
|
1376
|
+
mod.add_callable("copy", ctx.copy)
|
|
1377
|
+
mod.add_callable("path", ctx.path)
|
|
1378
|
+
mod.add_callable("env", ctx.env)
|
|
1379
|
+
mod.add_callable("use", ctx.use)
|
|
1380
|
+
|
|
1381
|
+
dialect = sl.Dialect.extended()
|
|
1382
|
+
dialect.enable_f_strings = True
|
|
1383
|
+
|
|
1384
|
+
ast = sl.parse("shipit", source, dialect=dialect)
|
|
1385
|
+
|
|
1386
|
+
sl.eval(mod, ast, glb)
|
|
1387
|
+
if not ctx.serves:
|
|
1388
|
+
raise ValueError(f"No serve definition found in {shipit_file}")
|
|
1389
|
+
assert len(ctx.serves) <= 1, "Only one serve is allowed for now"
|
|
1390
|
+
serve = next(iter(ctx.serves.values()))
|
|
1391
|
+
return ctx, serve
|
|
1392
|
+
|
|
1393
|
+
|
|
1321
1394
|
def print_help() -> None:
|
|
1322
1395
|
panel = Panel(
|
|
1323
1396
|
f"Shipit {shipit_version}",
|
|
@@ -1528,7 +1601,8 @@ def generate(
|
|
|
1528
1601
|
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
|
|
1529
1602
|
)
|
|
1530
1603
|
def _default(ctx: typer.Context) -> None:
|
|
1531
|
-
|
|
1604
|
+
if ctx.invoked_subcommand is None:
|
|
1605
|
+
print_help()
|
|
1532
1606
|
|
|
1533
1607
|
|
|
1534
1608
|
@app.command(name="deploy")
|
|
@@ -1612,6 +1686,103 @@ def serve(
|
|
|
1612
1686
|
raise Exception("Wasmer deploy is only supported for Wasmer builders")
|
|
1613
1687
|
|
|
1614
1688
|
|
|
1689
|
+
@app.command(name="plan")
|
|
1690
|
+
def plan(
|
|
1691
|
+
path: Path = typer.Argument(
|
|
1692
|
+
Path("."),
|
|
1693
|
+
help="Project path (defaults to current directory).",
|
|
1694
|
+
show_default=False,
|
|
1695
|
+
),
|
|
1696
|
+
wasmer: bool = typer.Option(
|
|
1697
|
+
False,
|
|
1698
|
+
help="Use Wasmer to evaluate the project.",
|
|
1699
|
+
),
|
|
1700
|
+
wasmer_bin: Optional[Path] = typer.Option(
|
|
1701
|
+
None,
|
|
1702
|
+
help="The path to the Wasmer binary.",
|
|
1703
|
+
),
|
|
1704
|
+
wasmer_registry: Optional[str] = typer.Option(
|
|
1705
|
+
None,
|
|
1706
|
+
help="Wasmer registry.",
|
|
1707
|
+
),
|
|
1708
|
+
wasmer_token: Optional[str] = typer.Option(
|
|
1709
|
+
None,
|
|
1710
|
+
help="Wasmer token.",
|
|
1711
|
+
),
|
|
1712
|
+
docker: bool = typer.Option(
|
|
1713
|
+
False,
|
|
1714
|
+
help="Use Docker to evaluate the project.",
|
|
1715
|
+
),
|
|
1716
|
+
docker_client: Optional[str] = typer.Option(
|
|
1717
|
+
None,
|
|
1718
|
+
help="Use a specific Docker client (such as depot, podman, etc.)",
|
|
1719
|
+
),
|
|
1720
|
+
) -> None:
|
|
1721
|
+
if not path.exists():
|
|
1722
|
+
raise Exception(f"The path {path} does not exist")
|
|
1723
|
+
|
|
1724
|
+
custom_commands = CustomCommands()
|
|
1725
|
+
procfile_path = path / "Procfile"
|
|
1726
|
+
if procfile_path.exists():
|
|
1727
|
+
try:
|
|
1728
|
+
procfile = Procfile.loads(procfile_path.read_text())
|
|
1729
|
+
custom_commands.start = procfile.get_start_command()
|
|
1730
|
+
except Exception:
|
|
1731
|
+
pass
|
|
1732
|
+
|
|
1733
|
+
builder: Builder
|
|
1734
|
+
if docker or docker_client:
|
|
1735
|
+
builder = DockerBuilder(path, docker_client)
|
|
1736
|
+
else:
|
|
1737
|
+
builder = LocalBuilder(path)
|
|
1738
|
+
if wasmer:
|
|
1739
|
+
builder = WasmerBuilder(
|
|
1740
|
+
builder, path, registry=wasmer_registry, token=wasmer_token, bin=wasmer_bin
|
|
1741
|
+
)
|
|
1742
|
+
|
|
1743
|
+
ctx, serve = evaluate_shipit(path, builder)
|
|
1744
|
+
metadata_commands: Dict[str, Optional[str]] = {
|
|
1745
|
+
"start": serve.commands.get("start"),
|
|
1746
|
+
"after_deploy": serve.commands.get("after_deploy"),
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
def _collect_group_commands(group: str) -> Optional[str]:
|
|
1750
|
+
commands = [
|
|
1751
|
+
step.command
|
|
1752
|
+
for step in serve.build
|
|
1753
|
+
if isinstance(step, RunStep) and step.group == group
|
|
1754
|
+
]
|
|
1755
|
+
if not commands:
|
|
1756
|
+
return None
|
|
1757
|
+
return " && ".join(commands)
|
|
1758
|
+
|
|
1759
|
+
metadata_install = _collect_group_commands("install")
|
|
1760
|
+
metadata_build = _collect_group_commands("build")
|
|
1761
|
+
metadata_commands["install"] = metadata_install
|
|
1762
|
+
metadata_commands["build"] = metadata_build
|
|
1763
|
+
platform: Optional[str]
|
|
1764
|
+
try:
|
|
1765
|
+
provider_cls = detect_provider(path, custom_commands)
|
|
1766
|
+
provider_instance = provider_cls(path, custom_commands)
|
|
1767
|
+
provider_instance.initialize()
|
|
1768
|
+
platform = provider_instance.platform()
|
|
1769
|
+
except Exception:
|
|
1770
|
+
platform = None
|
|
1771
|
+
plan_output = {
|
|
1772
|
+
"provider": serve.provider,
|
|
1773
|
+
"metadata": {
|
|
1774
|
+
"platform": platform,
|
|
1775
|
+
"commands": metadata_commands,
|
|
1776
|
+
},
|
|
1777
|
+
"config": sorted(ctx.getenv_variables),
|
|
1778
|
+
"services": [
|
|
1779
|
+
{"name": svc.name, "provider": svc.provider}
|
|
1780
|
+
for svc in (serve.services or [])
|
|
1781
|
+
],
|
|
1782
|
+
}
|
|
1783
|
+
print(json.dumps(plan_output, indent=4))
|
|
1784
|
+
|
|
1785
|
+
|
|
1615
1786
|
@app.command(name="build")
|
|
1616
1787
|
def build(
|
|
1617
1788
|
path: Path = typer.Argument(
|
|
@@ -1659,12 +1830,6 @@ def build(
|
|
|
1659
1830
|
if not path.exists():
|
|
1660
1831
|
raise Exception(f"The path {path} does not exist")
|
|
1661
1832
|
|
|
1662
|
-
ab_file = path / "Shipit"
|
|
1663
|
-
if not ab_file.exists():
|
|
1664
|
-
raise FileNotFoundError(
|
|
1665
|
-
f"Shipit file not found at {ab_file}. Run `shipit generate {path}` to create it."
|
|
1666
|
-
)
|
|
1667
|
-
source = open(ab_file).read()
|
|
1668
1833
|
builder: Builder
|
|
1669
1834
|
if docker or docker_client:
|
|
1670
1835
|
builder = DockerBuilder(path, docker_client)
|
|
@@ -1675,30 +1840,7 @@ def build(
|
|
|
1675
1840
|
builder, path, registry=wasmer_registry, token=wasmer_token, bin=wasmer_bin
|
|
1676
1841
|
)
|
|
1677
1842
|
|
|
1678
|
-
ctx =
|
|
1679
|
-
glb = sl.Globals.standard()
|
|
1680
|
-
mod = sl.Module()
|
|
1681
|
-
|
|
1682
|
-
mod.add_callable("service", ctx.service)
|
|
1683
|
-
mod.add_callable("getenv", ctx.getenv)
|
|
1684
|
-
mod.add_callable("dep", ctx.dep)
|
|
1685
|
-
mod.add_callable("serve", ctx.serve)
|
|
1686
|
-
mod.add_callable("run", ctx.run)
|
|
1687
|
-
mod.add_callable("mount", ctx.mount)
|
|
1688
|
-
mod.add_callable("volume", ctx.volume)
|
|
1689
|
-
mod.add_callable("workdir", ctx.workdir)
|
|
1690
|
-
mod.add_callable("copy", ctx.copy)
|
|
1691
|
-
mod.add_callable("path", ctx.path)
|
|
1692
|
-
mod.add_callable("env", ctx.env)
|
|
1693
|
-
mod.add_callable("use", ctx.use)
|
|
1694
|
-
|
|
1695
|
-
dialect = sl.Dialect.extended()
|
|
1696
|
-
dialect.enable_f_strings = True
|
|
1697
|
-
|
|
1698
|
-
ast = sl.parse("shipit", source, dialect=dialect)
|
|
1699
|
-
|
|
1700
|
-
sl.eval(mod, ast, glb)
|
|
1701
|
-
assert len(ctx.serves) <= 1, "Only one serve is allowed for now"
|
|
1843
|
+
ctx, serve = evaluate_shipit(path, builder)
|
|
1702
1844
|
env = {
|
|
1703
1845
|
"PATH": "",
|
|
1704
1846
|
"COLORTERM": os.environ.get("COLORTERM", ""),
|
|
@@ -1706,7 +1848,6 @@ def build(
|
|
|
1706
1848
|
"LS_COLORS": os.environ.get("LS_COLORS", "0"),
|
|
1707
1849
|
"CLICOLOR": os.environ.get("CLICOLOR", "0"),
|
|
1708
1850
|
}
|
|
1709
|
-
serve = next(iter(ctx.serves.values()))
|
|
1710
1851
|
|
|
1711
1852
|
if skip_docker_if_safe_build and serve.build and len(serve.build) > 0:
|
|
1712
1853
|
# If it doesn't have a run step, then it's safe to skip Docker and run all the
|
shipit/generator.py
CHANGED
|
@@ -64,15 +64,22 @@ def _emit_dependencies_declarations(
|
|
|
64
64
|
declared.add(alias)
|
|
65
65
|
|
|
66
66
|
version_var = None
|
|
67
|
+
architecture_var = None
|
|
67
68
|
if dep.env_var:
|
|
68
69
|
default = f' or "{dep.default_version}"' if dep.default_version else ""
|
|
69
70
|
version_key = alias + "_version"
|
|
70
71
|
lines.append(f'{version_key} = getenv("{dep.env_var}"){default}')
|
|
71
72
|
version_var = version_key
|
|
73
|
+
if dep.architecture_var:
|
|
74
|
+
architecture_key = alias + "_architecture"
|
|
75
|
+
lines.append(f'{architecture_key} = getenv("{dep.architecture_var}")')
|
|
76
|
+
architecture_var = architecture_key
|
|
77
|
+
vars = [f'"{dep.name}"']
|
|
72
78
|
if version_var:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
79
|
+
vars.append(version_var)
|
|
80
|
+
if architecture_var:
|
|
81
|
+
vars.append(f"architecture={architecture_var}")
|
|
82
|
+
lines.append(f"{alias} = dep({', '.join(vars)})")
|
|
76
83
|
|
|
77
84
|
return "\n".join(lines), serve_vars, build_vars
|
|
78
85
|
|
|
@@ -85,6 +92,7 @@ def generate_shipit(path: Path, custom_commands: CustomCommands) -> str:
|
|
|
85
92
|
plan = ProviderPlan(
|
|
86
93
|
serve_name=provider.serve_name(),
|
|
87
94
|
provider=provider.provider_kind(),
|
|
95
|
+
platform=provider.platform(),
|
|
88
96
|
mounts=provider.mounts(),
|
|
89
97
|
volumes=provider.volumes(),
|
|
90
98
|
declarations=provider.declarations(),
|
|
@@ -109,7 +117,9 @@ def generate_shipit(path: Path, custom_commands: CustomCommands) -> str:
|
|
|
109
117
|
|
|
110
118
|
build_steps_block = ",\n".join([f" {s}" for s in build_steps])
|
|
111
119
|
deps_array = ", ".join(serve_dep_vars)
|
|
112
|
-
commands_lines = ",\n".join(
|
|
120
|
+
commands_lines = ",\n".join(
|
|
121
|
+
[f' "{k}": {v}.replace("$PORT", PORT)' for k, v in plan.commands.items()]
|
|
122
|
+
)
|
|
113
123
|
env_lines = None
|
|
114
124
|
if plan.env is not None:
|
|
115
125
|
if len(plan.env) == 0:
|
|
@@ -137,24 +147,26 @@ def generate_shipit(path: Path, custom_commands: CustomCommands) -> str:
|
|
|
137
147
|
out.append("")
|
|
138
148
|
|
|
139
149
|
for m in plan.mounts:
|
|
140
|
-
out.append(f
|
|
150
|
+
out.append(f'{m.name} = mount("{m.name}")')
|
|
141
151
|
out.append("")
|
|
142
152
|
|
|
143
153
|
if plan.volumes:
|
|
144
154
|
for v in plan.volumes:
|
|
145
|
-
out.append(f
|
|
155
|
+
out.append(f'{v.var_name or v.name} = volume("{v.name}", {v.serve_path})')
|
|
146
156
|
out.append("")
|
|
147
157
|
|
|
148
158
|
if plan.services:
|
|
149
159
|
for s in plan.services:
|
|
150
|
-
out.append(
|
|
160
|
+
out.append(
|
|
161
|
+
f'{s.name} = service(\n name="{s.name}",\n provider="{s.provider}"\n)'
|
|
162
|
+
)
|
|
151
163
|
out.append("")
|
|
152
164
|
|
|
153
|
-
out.append(
|
|
165
|
+
out.append('PORT = getenv("PORT") or "8080"')
|
|
154
166
|
|
|
155
167
|
if plan.declarations:
|
|
156
168
|
out.append(plan.declarations)
|
|
157
|
-
|
|
169
|
+
|
|
158
170
|
out.append("")
|
|
159
171
|
out.append("serve(")
|
|
160
172
|
out.append(f' name="{plan.serve_name}",')
|
shipit/providers/base.py
CHANGED
|
@@ -29,6 +29,7 @@ class Provider(Protocol):
|
|
|
29
29
|
# Structured plan steps (no path args; use self.path)
|
|
30
30
|
def serve_name(self) -> str: ...
|
|
31
31
|
def provider_kind(self) -> str: ...
|
|
32
|
+
def platform(self) -> Optional[str]: ...
|
|
32
33
|
def dependencies(self) -> list["DependencySpec"]: ...
|
|
33
34
|
def declarations(self) -> Optional[str]: ...
|
|
34
35
|
def build_steps(self) -> list[str]: ...
|
|
@@ -46,6 +47,7 @@ class DependencySpec:
|
|
|
46
47
|
name: str
|
|
47
48
|
env_var: Optional[str] = None
|
|
48
49
|
default_version: Optional[str] = None
|
|
50
|
+
architecture_var: Optional[str] = None
|
|
49
51
|
alias: Optional[str] = None # Variable name in Shipit plan
|
|
50
52
|
use_in_build: bool = False
|
|
51
53
|
use_in_serve: bool = False
|
|
@@ -77,6 +79,7 @@ class ProviderPlan:
|
|
|
77
79
|
serve_name: str
|
|
78
80
|
provider: str
|
|
79
81
|
mounts: List[MountSpec]
|
|
82
|
+
platform: Optional[str] = None
|
|
80
83
|
volumes: List[VolumeSpec] = field(default_factory=list)
|
|
81
84
|
declarations: Optional[str] = None
|
|
82
85
|
dependencies: List[DependencySpec] = field(default_factory=list)
|
shipit/providers/gatsby.py
CHANGED
shipit/providers/hugo.py
CHANGED
shipit/providers/laravel.py
CHANGED
shipit/providers/mkdocs.py
CHANGED
|
@@ -43,6 +43,9 @@ class MkdocsProvider(StaticFileProvider):
|
|
|
43
43
|
def provider_kind(self) -> str:
|
|
44
44
|
return "mkdocs-site"
|
|
45
45
|
|
|
46
|
+
def platform(self) -> Optional[str]:
|
|
47
|
+
return "mkdocs"
|
|
48
|
+
|
|
46
49
|
def dependencies(self) -> list[DependencySpec]:
|
|
47
50
|
return [
|
|
48
51
|
*self.python_provider.dependencies(),
|
shipit/providers/node_static.py
CHANGED
|
@@ -122,6 +122,7 @@ class NodeStaticProvider(StaticFileProvider):
|
|
|
122
122
|
|
|
123
123
|
def __init__(self, path: Path, custom_commands: CustomCommands):
|
|
124
124
|
super().__init__(path, custom_commands)
|
|
125
|
+
self.static_generator: Optional[StaticGenerator] = None
|
|
125
126
|
if (path / "package-lock.json").exists():
|
|
126
127
|
self.package_manager = PackageManager.NPM
|
|
127
128
|
elif (path / "pnpm-lock.yaml").exists():
|
|
@@ -233,6 +234,9 @@ class NodeStaticProvider(StaticFileProvider):
|
|
|
233
234
|
def provider_kind(self) -> str:
|
|
234
235
|
return "staticsite"
|
|
235
236
|
|
|
237
|
+
def platform(self) -> Optional[str]:
|
|
238
|
+
return self.static_generator.value if self.static_generator else None
|
|
239
|
+
|
|
236
240
|
def dependencies(self) -> list[DependencySpec]:
|
|
237
241
|
package_manager_dep = self.package_manager.as_dependency(self.path)
|
|
238
242
|
package_manager_dep.use_in_build = True
|
shipit/providers/php.py
CHANGED
|
@@ -20,16 +20,23 @@ class PhpProvider:
|
|
|
20
20
|
def __init__(self, path: Path, custom_commands: CustomCommands):
|
|
21
21
|
self.path = path
|
|
22
22
|
self.custom_commands = custom_commands
|
|
23
|
-
|
|
23
|
+
self.has_composer = _exists(self.path, "composer.json", "composer.lock")
|
|
24
|
+
|
|
24
25
|
@classmethod
|
|
25
26
|
def name(cls) -> str:
|
|
26
27
|
return "php"
|
|
27
28
|
|
|
28
29
|
@classmethod
|
|
29
|
-
def detect(
|
|
30
|
+
def detect(
|
|
31
|
+
cls, path: Path, custom_commands: CustomCommands
|
|
32
|
+
) -> Optional[DetectResult]:
|
|
30
33
|
if _exists(path, "composer.json") and _exists(path, "public/index.php"):
|
|
31
34
|
return DetectResult(cls.name(), 60)
|
|
32
|
-
if
|
|
35
|
+
if (
|
|
36
|
+
_exists(path, "index.php")
|
|
37
|
+
or _exists(path, "public/index.php")
|
|
38
|
+
or _exists(path, "app/index.php")
|
|
39
|
+
):
|
|
33
40
|
return DetectResult(cls.name(), 10)
|
|
34
41
|
if custom_commands.start and custom_commands.start.startswith("php "):
|
|
35
42
|
return DetectResult(cls.name(), 70)
|
|
@@ -44,8 +51,8 @@ class PhpProvider:
|
|
|
44
51
|
def provider_kind(self) -> str:
|
|
45
52
|
return "php"
|
|
46
53
|
|
|
47
|
-
def
|
|
48
|
-
return
|
|
54
|
+
def platform(self) -> Optional[str]:
|
|
55
|
+
return None
|
|
49
56
|
|
|
50
57
|
def dependencies(self) -> list[DependencySpec]:
|
|
51
58
|
deps = [
|
|
@@ -53,32 +60,39 @@ class PhpProvider:
|
|
|
53
60
|
"php",
|
|
54
61
|
env_var="SHIPIT_PHP_VERSION",
|
|
55
62
|
default_version="8.3",
|
|
63
|
+
architecture_var="SHIPIT_PHP_ARCHITECTURE",
|
|
56
64
|
use_in_build=True,
|
|
57
65
|
use_in_serve=True,
|
|
58
66
|
),
|
|
59
67
|
]
|
|
60
|
-
if self.has_composer
|
|
68
|
+
if self.has_composer:
|
|
61
69
|
deps.append(DependencySpec("composer", use_in_build=True))
|
|
62
70
|
deps.append(DependencySpec("bash", use_in_serve=True))
|
|
63
71
|
return deps
|
|
64
72
|
|
|
65
73
|
def declarations(self) -> Optional[str]:
|
|
66
|
-
|
|
74
|
+
if self.has_composer:
|
|
75
|
+
return 'HOME = getenv("HOME")\n'
|
|
76
|
+
return None
|
|
67
77
|
|
|
68
78
|
def build_steps(self) -> list[str]:
|
|
69
79
|
steps = [
|
|
70
|
-
|
|
80
|
+
'workdir(app["build"])',
|
|
71
81
|
]
|
|
72
82
|
if _exists(self.path, "php.ini"):
|
|
73
83
|
steps.append('copy("php.ini", "{}/php.ini".format(assets["build"]))')
|
|
74
84
|
else:
|
|
75
|
-
steps.append(
|
|
85
|
+
steps.append(
|
|
86
|
+
'copy("php/php.ini", "{}/php.ini".format(assets["build"]), base="assets")'
|
|
87
|
+
)
|
|
76
88
|
|
|
77
|
-
if self.has_composer
|
|
78
|
-
steps.append(
|
|
79
|
-
steps.append(
|
|
89
|
+
if self.has_composer:
|
|
90
|
+
steps.append('env(HOME=HOME, COMPOSER_FUND="0")')
|
|
91
|
+
steps.append(
|
|
92
|
+
'run("composer install --optimize-autoloader --no-scripts --no-interaction", inputs=["composer.json", "composer.lock"], outputs=["."], group="install")'
|
|
93
|
+
)
|
|
80
94
|
|
|
81
|
-
steps.append(
|
|
95
|
+
steps.append('copy(".", ".", ignore=[".git"])')
|
|
82
96
|
return steps
|
|
83
97
|
|
|
84
98
|
def prepare_steps(self) -> Optional[list[str]]:
|
|
@@ -92,9 +106,13 @@ class PhpProvider:
|
|
|
92
106
|
|
|
93
107
|
def base_commands(self) -> Dict[str, str]:
|
|
94
108
|
if _exists(self.path, "public/index.php"):
|
|
95
|
-
return {
|
|
109
|
+
return {
|
|
110
|
+
"start": '"php -S localhost:{} -t {}/public".format(PORT, app["serve"])'
|
|
111
|
+
}
|
|
96
112
|
elif _exists(self.path, "app/index.php"):
|
|
97
|
-
return {
|
|
113
|
+
return {
|
|
114
|
+
"start": '"php -S localhost:{} -t {}/app".format(PORT, app["serve"])'
|
|
115
|
+
}
|
|
98
116
|
elif _exists(self.path, "index.php"):
|
|
99
117
|
return {"start": '"php -S localhost:{} -t {}".format(PORT, app["serve"])'}
|
|
100
118
|
return {}
|
|
@@ -112,6 +130,6 @@ class PhpProvider:
|
|
|
112
130
|
return {
|
|
113
131
|
"PHP_INI_SCAN_DIR": '"{}".format(assets["serve"])',
|
|
114
132
|
}
|
|
115
|
-
|
|
133
|
+
|
|
116
134
|
def services(self) -> list[ServiceSpec]:
|
|
117
135
|
return []
|
shipit/providers/python.py
CHANGED
|
@@ -229,6 +229,9 @@ class PythonProvider:
|
|
|
229
229
|
def provider_kind(self) -> str:
|
|
230
230
|
return "python"
|
|
231
231
|
|
|
232
|
+
def platform(self) -> Optional[str]:
|
|
233
|
+
return self.framework.value if self.framework else None
|
|
234
|
+
|
|
232
235
|
def dependencies(self) -> list[DependencySpec]:
|
|
233
236
|
deps = [
|
|
234
237
|
DependencySpec(
|
|
@@ -307,9 +310,9 @@ class PythonProvider:
|
|
|
307
310
|
# Join inputs
|
|
308
311
|
inputs = ", ".join([f'"{input}"' for input in input_files])
|
|
309
312
|
steps += [
|
|
310
|
-
'env(UV_PROJECT_ENVIRONMENT=local_venv["build"] if cross_platform else venv["build"])',
|
|
313
|
+
'env(UV_PROJECT_ENVIRONMENT=local_venv["build"] if cross_platform else venv["build"], UV_PYTHON_PREFERENCE="only-system", UV_PYTHON=f"python{python_version}")',
|
|
311
314
|
'copy(".", ".")' if self.install_requires_all_files else None,
|
|
312
|
-
f'run(f"uv sync
|
|
315
|
+
f'run(f"uv sync{extra_args}", inputs=[{inputs}], group="install")',
|
|
313
316
|
'copy("pyproject.toml", "pyproject.toml")'
|
|
314
317
|
if not self.install_requires_all_files
|
|
315
318
|
else None,
|
|
@@ -317,14 +320,14 @@ class PythonProvider:
|
|
|
317
320
|
]
|
|
318
321
|
if not self.only_build:
|
|
319
322
|
steps += [
|
|
320
|
-
'run(f"uv pip compile pyproject.toml --
|
|
323
|
+
'run(f"uv pip compile pyproject.toml --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
324
|
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
325
|
'run("rm cross-requirements.txt") if cross_platform else None',
|
|
323
326
|
]
|
|
324
327
|
elif has_requirements or extra_deps:
|
|
325
328
|
steps += [
|
|
326
329
|
'env(UV_PROJECT_ENVIRONMENT=local_venv["build"] if cross_platform else venv["build"])',
|
|
327
|
-
'run(f"uv init --no-workspace
|
|
330
|
+
'run(f"uv init --no-workspace", inputs=[], outputs=["uv.lock"], group="install")',
|
|
328
331
|
'copy(".", ".")' if self.install_requires_all_files else None,
|
|
329
332
|
]
|
|
330
333
|
if has_requirements:
|
|
@@ -351,6 +354,10 @@ class PythonProvider:
|
|
|
351
354
|
'run("mkdir -p {}/bin".format(venv["build"])) if cross_platform else None',
|
|
352
355
|
'run("cp {}/bin/mcp {}/bin/mcp".format(local_venv["build"], venv["build"])) if cross_platform else None',
|
|
353
356
|
]
|
|
357
|
+
if self.framework == PythonFramework.Django:
|
|
358
|
+
steps += [
|
|
359
|
+
'run("python manage.py collectstatic --noinput", group="build")',
|
|
360
|
+
]
|
|
354
361
|
return list(filter(None, steps))
|
|
355
362
|
|
|
356
363
|
def prepare_steps(self) -> Optional[list[str]]:
|
shipit/providers/staticfile.py
CHANGED
shipit/providers/wordpress.py
CHANGED
|
@@ -19,8 +19,7 @@ from .php import PhpProvider
|
|
|
19
19
|
|
|
20
20
|
class WordPressProvider(PhpProvider):
|
|
21
21
|
def __init__(self, path: Path, custom_commands: CustomCommands):
|
|
22
|
-
|
|
23
|
-
self.custom_commands = custom_commands
|
|
22
|
+
super().__init__(path, custom_commands)
|
|
24
23
|
|
|
25
24
|
@classmethod
|
|
26
25
|
def name(cls) -> str:
|
|
@@ -47,6 +46,9 @@ class WordPressProvider(PhpProvider):
|
|
|
47
46
|
def provider_kind(self) -> str:
|
|
48
47
|
return "php"
|
|
49
48
|
|
|
49
|
+
def platform(self) -> Optional[str]:
|
|
50
|
+
return "wordpress"
|
|
51
|
+
|
|
50
52
|
def dependencies(self) -> list[DependencySpec]:
|
|
51
53
|
return [
|
|
52
54
|
*super().dependencies(),
|
|
@@ -54,7 +56,7 @@ class WordPressProvider(PhpProvider):
|
|
|
54
56
|
]
|
|
55
57
|
|
|
56
58
|
def declarations(self) -> Optional[str]:
|
|
57
|
-
return super().declarations() + (
|
|
59
|
+
return (super().declarations() or "") + (
|
|
58
60
|
'wp_cli_version = getenv("SHIPIT_WPCLI_VERSION")\n'
|
|
59
61
|
"if wp_cli_version:\n"
|
|
60
62
|
' wp_cli_download_url = f"https://github.com/wp-cli/wp-cli/releases/download/v{wp_cli_version}/wp-cli-{wp_cli_version}.phar"\n'
|
|
@@ -65,7 +67,7 @@ class WordPressProvider(PhpProvider):
|
|
|
65
67
|
def build_steps(self) -> list[str]:
|
|
66
68
|
steps = [
|
|
67
69
|
'copy(wp_cli_download_url, "{}/wp-cli.phar".format(assets["build"]))',
|
|
68
|
-
'copy("wordpress/install.sh", "{}/
|
|
70
|
+
'copy("wordpress/install.sh", "{}/setup-wp.sh".format(assets["build"]), base="assets")',
|
|
69
71
|
]
|
|
70
72
|
if not _exists(self.path, "wp-config.php"):
|
|
71
73
|
steps.append(
|
|
@@ -80,7 +82,7 @@ class WordPressProvider(PhpProvider):
|
|
|
80
82
|
commands = super().commands()
|
|
81
83
|
return {
|
|
82
84
|
"wp": '"php {}/wp-cli.phar --allow-root --path={}".format(assets["serve"], app["serve"])',
|
|
83
|
-
"after_deploy": '"bash {}/
|
|
85
|
+
"after_deploy": '"bash {}/setup-wp.sh".format(assets["serve"])',
|
|
84
86
|
**commands,
|
|
85
87
|
}
|
|
86
88
|
|
shipit/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shipit-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0
|
|
4
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
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
shipit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
shipit/cli.py,sha256=3M-wn_X_z-MTep_Yoz5P8s404uJLr5GpTd--my2-DuA,65664
|
|
3
|
+
shipit/generator.py,sha256=37Y40KKrmVpQ6XMA3VqhdvMJFDsIqCuQy_aVUVJqA20,6945
|
|
4
|
+
shipit/procfile.py,sha256=GlfdwzFUr0GWGKaaiXlLKNFInWaRNMy_wN14UEyU_5Q,2974
|
|
5
|
+
shipit/version.py,sha256=guCYg8LK1bf7KxJBZzbM2RwQBLcGyAlvj5rF5tNz6TI,97
|
|
6
|
+
shipit/assets/php/php.ini,sha256=SaR3wvssSROtxTY_CQ5-BspM_47_I971V5X2dsqe8sU,2579
|
|
7
|
+
shipit/assets/wordpress/install.sh,sha256=h_Pbuj1nUqC0dE91yAYxeBiWf2oFbBWn0oCUkkosUsE,2498
|
|
8
|
+
shipit/assets/wordpress/wp-config.php,sha256=8M4C6xLI5ziX1udM7B-Ef3jd9xuMGVRve6cCuOgDT4o,4786
|
|
9
|
+
shipit/providers/base.py,sha256=bA1CgOpQ3dUQkXx_LPJvFj_CbZ77xNh5l2GI8Qh3Owo,3117
|
|
10
|
+
shipit/providers/gatsby.py,sha256=Yxzq-xYwgLGGxTA5X9AE6g6w4v8ruXFcg3U6QlJwqkE,2459
|
|
11
|
+
shipit/providers/hugo.py,sha256=ZMG54hbtdrTem-YUg9gp75Qu-pd1XzhaoNYOihU7HOg,1872
|
|
12
|
+
shipit/providers/laravel.py,sha256=v7xDNipE72CDCZtzkpmpHktBp5n2kmgduSYTmmKjo2Y,3098
|
|
13
|
+
shipit/providers/mkdocs.py,sha256=SRbTkRtzUbFiqP3KrPckD_IQF7nE1-FUkQk7FswaEBs,2266
|
|
14
|
+
shipit/providers/node_static.py,sha256=7vrz1lh_L-Op62r6HLcxy2RQypfQjFbJh7e9b46xNLM,12542
|
|
15
|
+
shipit/providers/php.py,sha256=_kXQ7ja9skvC9mOxW9pKqQzdcXaixXBGTdAAEbT4tsY,4086
|
|
16
|
+
shipit/providers/python.py,sha256=ZLzqv3P0R93u7_i_PBQ_VhVZEt9iTp1bvyjLlMJE-_0,21155
|
|
17
|
+
shipit/providers/registry.py,sha256=JCuQaYTvJcWK1nS-om9TIQgGW6pT5BuNLIRzChLLFWE,731
|
|
18
|
+
shipit/providers/staticfile.py,sha256=Zpt7s-R17Fow-f4ObXfCRDiLEM8gHp8dC7hyi2DUV6o,2802
|
|
19
|
+
shipit/providers/wordpress.py,sha256=IHRWcb1K3taD30eOruJMn5Cp_t8_PAQhdcY7KB4qBIw,3293
|
|
20
|
+
shipit_cli-0.11.0.dist-info/METADATA,sha256=NSATh2qlUnYhDArV5QbYqESLAIipD2SEYfZ3SWTYZhI,616
|
|
21
|
+
shipit_cli-0.11.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
22
|
+
shipit_cli-0.11.0.dist-info/entry_points.txt,sha256=7AE1NjSrHaSDfbfsRRO50KKnHFTbB0Imsccd1WynzAQ,72
|
|
23
|
+
shipit_cli-0.11.0.dist-info/RECORD,,
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
shipit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
shipit/cli.py,sha256=k60mGxpBoyxYgdsFfosc3HuSm5m7Nus5I9RnAaP8X0E,60820
|
|
3
|
-
shipit/generator.py,sha256=W4MynSFwId4PRWWrF0R3NsANye_Zv8TwXCUXai94pW0,6553
|
|
4
|
-
shipit/procfile.py,sha256=GlfdwzFUr0GWGKaaiXlLKNFInWaRNMy_wN14UEyU_5Q,2974
|
|
5
|
-
shipit/version.py,sha256=SEO-RlxHRJwzrNq9nnUQaHiEEN2nAfsVlW1Q9R0SXPU,97
|
|
6
|
-
shipit/assets/php/php.ini,sha256=SaR3wvssSROtxTY_CQ5-BspM_47_I971V5X2dsqe8sU,2579
|
|
7
|
-
shipit/assets/wordpress/install.sh,sha256=h_Pbuj1nUqC0dE91yAYxeBiWf2oFbBWn0oCUkkosUsE,2498
|
|
8
|
-
shipit/assets/wordpress/wp-config.php,sha256=8M4C6xLI5ziX1udM7B-Ef3jd9xuMGVRve6cCuOgDT4o,4786
|
|
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=tkttFRB2KEfhZYK_qzcdf7ulEepZEJq9EqkAUo2KYWs,12358
|
|
15
|
-
shipit/providers/php.py,sha256=B5CEvYX51IXWrleNNa6eq-d8xGI8xP4k0Pl8Rpi5cLo,3786
|
|
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=hs8ER8rATTho8pBJ6b6ibaOqAfbNZKmlRqbalSdeYY0,2740
|
|
19
|
-
shipit/providers/wordpress.py,sha256=6wd0wPBlE9DvNQgmcEKnH0TArGDkHfRvT9XhqnfOWTU,3258
|
|
20
|
-
shipit_cli-0.10.1.dist-info/METADATA,sha256=7fCKb7M90W9ffVYj-XZEP0ig4Bv2KEJk5FjcvLR4HtE,616
|
|
21
|
-
shipit_cli-0.10.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
22
|
-
shipit_cli-0.10.1.dist-info/entry_points.txt,sha256=7AE1NjSrHaSDfbfsRRO50KKnHFTbB0Imsccd1WynzAQ,72
|
|
23
|
-
shipit_cli-0.10.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|