shipit-cli 0.6.1__py3-none-any.whl → 0.7.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/assets/wordpress/install.sh +33 -0
- shipit/assets/wordpress/wp-config.php +133 -0
- shipit/cli.py +243 -116
- shipit/generator.py +27 -16
- shipit/procfile.py +106 -0
- shipit/providers/base.py +19 -3
- shipit/providers/gatsby.py +18 -6
- shipit/providers/hugo.py +6 -2
- shipit/providers/laravel.py +17 -6
- shipit/providers/mkdocs.py +16 -7
- shipit/providers/node_static.py +18 -6
- shipit/providers/php.py +39 -10
- shipit/providers/python.py +54 -14
- shipit/providers/registry.py +2 -0
- shipit/providers/staticfile.py +18 -6
- shipit/providers/wordpress.py +88 -0
- shipit/version.py +2 -2
- {shipit_cli-0.6.1.dist-info → shipit_cli-0.7.1.dist-info}/METADATA +3 -1
- shipit_cli-0.7.1.dist-info/RECORD +23 -0
- shipit_cli-0.6.1.dist-info/RECORD +0 -19
- {shipit_cli-0.6.1.dist-info → shipit_cli-0.7.1.dist-info}/WHEEL +0 -0
- {shipit_cli-0.6.1.dist-info → shipit_cli-0.7.1.dist-info}/entry_points.txt +0 -0
shipit/generator.py
CHANGED
|
@@ -3,7 +3,15 @@ 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
|
|
6
|
+
from shipit.providers.base import (
|
|
7
|
+
DependencySpec,
|
|
8
|
+
Provider,
|
|
9
|
+
ProviderPlan,
|
|
10
|
+
DetectResult,
|
|
11
|
+
MountSpec,
|
|
12
|
+
VolumeSpec,
|
|
13
|
+
CustomCommands,
|
|
14
|
+
)
|
|
7
15
|
from shipit.providers.registry import providers as registry_providers
|
|
8
16
|
|
|
9
17
|
|
|
@@ -12,10 +20,10 @@ def _providers() -> list[type[Provider]]:
|
|
|
12
20
|
return registry_providers()
|
|
13
21
|
|
|
14
22
|
|
|
15
|
-
def detect_provider(path: Path) -> Provider:
|
|
23
|
+
def detect_provider(path: Path, custom_commands: CustomCommands) -> Provider:
|
|
16
24
|
matches: list[tuple[type[Provider], DetectResult]] = []
|
|
17
25
|
for provider_cls in _providers():
|
|
18
|
-
res = provider_cls.detect(path)
|
|
26
|
+
res = provider_cls.detect(path, custom_commands)
|
|
19
27
|
if res:
|
|
20
28
|
matches.append((provider_cls, res))
|
|
21
29
|
if not matches:
|
|
@@ -69,22 +77,16 @@ def _emit_dependencies_declarations(
|
|
|
69
77
|
return "\n".join(lines), serve_vars, build_vars
|
|
70
78
|
|
|
71
79
|
|
|
72
|
-
def
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
inner = ",\n".join([f' "{k}": {v}' for k, v in assets.items()])
|
|
76
|
-
return f"{{\n{inner}\n }}"
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def generate_shipit(path: Path) -> str:
|
|
80
|
-
provider_cls = detect_provider(path)
|
|
81
|
-
provider = provider_cls(path)
|
|
80
|
+
def generate_shipit(path: Path, custom_commands: CustomCommands) -> str:
|
|
81
|
+
provider_cls = detect_provider(path, custom_commands)
|
|
82
|
+
provider = provider_cls(path, custom_commands)
|
|
82
83
|
|
|
83
84
|
# Collect parts
|
|
84
85
|
plan = ProviderPlan(
|
|
85
86
|
serve_name=provider.serve_name(),
|
|
86
87
|
provider=provider.provider_kind(),
|
|
87
88
|
mounts=provider.mounts(),
|
|
89
|
+
volumes=provider.volumes(),
|
|
88
90
|
declarations=provider.declarations(),
|
|
89
91
|
dependencies=provider.dependencies(),
|
|
90
92
|
build_steps=provider.build_steps(),
|
|
@@ -114,13 +116,17 @@ def generate_shipit(path: Path) -> str:
|
|
|
114
116
|
env_lines = "{}"
|
|
115
117
|
else:
|
|
116
118
|
env_lines = ",\n".join([f' "{k}": {v}' for k, v in plan.env.items()])
|
|
117
|
-
assets_block = _render_assets(plan.assets)
|
|
118
119
|
mounts_block = None
|
|
120
|
+
volumes_block = None
|
|
119
121
|
attach_serve_names: list[str] = []
|
|
120
122
|
if plan.mounts:
|
|
121
123
|
mounts = list(filter(lambda m: m.attach_to_serve, plan.mounts))
|
|
122
124
|
attach_serve_names = [m.name for m in mounts]
|
|
123
125
|
mounts_block = ",\n".join([f" {m.name}" for m in mounts])
|
|
126
|
+
if plan.volumes:
|
|
127
|
+
volumes_block = ",\n".join(
|
|
128
|
+
[f" {v.var_name or v.name}" for v in plan.volumes]
|
|
129
|
+
)
|
|
124
130
|
|
|
125
131
|
out: List[str] = []
|
|
126
132
|
if dep_block:
|
|
@@ -128,6 +134,9 @@ def generate_shipit(path: Path) -> str:
|
|
|
128
134
|
out.append("")
|
|
129
135
|
for m in plan.mounts:
|
|
130
136
|
out.append(f"{m.name} = mount(\"{m.name}\")")
|
|
137
|
+
if plan.volumes:
|
|
138
|
+
for v in plan.volumes:
|
|
139
|
+
out.append(f"{v.var_name or v.name} = volume(\"{v.name}\", {v.serve_path})")
|
|
131
140
|
if plan.services:
|
|
132
141
|
for s in plan.services:
|
|
133
142
|
out.append(f"{s.name} = service(\n name=\"{s.name}\",\n provider=\"{s.provider}\"\n)")
|
|
@@ -144,8 +153,6 @@ def generate_shipit(path: Path) -> str:
|
|
|
144
153
|
out.append(" build=[")
|
|
145
154
|
out.append(build_steps_block)
|
|
146
155
|
out.append(" ],")
|
|
147
|
-
if assets_block:
|
|
148
|
-
out.append(" assets=" + assets_block + ",")
|
|
149
156
|
out.append(f" deps=[{deps_array}],")
|
|
150
157
|
if plan.prepare:
|
|
151
158
|
prepare_steps_block = ",\n".join([f" {s}" for s in plan.prepare])
|
|
@@ -171,6 +178,10 @@ def generate_shipit(path: Path) -> str:
|
|
|
171
178
|
out.append(" mounts=[")
|
|
172
179
|
out.append(mounts_block)
|
|
173
180
|
out.append(" ],")
|
|
181
|
+
if volumes_block:
|
|
182
|
+
out.append(" volumes=[")
|
|
183
|
+
out.append(volumes_block)
|
|
184
|
+
out.append(" ],")
|
|
174
185
|
out.append(")")
|
|
175
186
|
out.append("")
|
|
176
187
|
return "\n".join(out)
|
shipit/procfile.py
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# File forked from https://github.com/nickstenning/honcho/blob/main/honcho/environ.py
|
|
2
|
+
# MIT License
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
from collections import defaultdict, namedtuple
|
|
6
|
+
|
|
7
|
+
PROCFILE_LINE = re.compile(r'^([A-Za-z0-9_-]+):\s*(.+)$')
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Env(object):
|
|
11
|
+
|
|
12
|
+
def __init__(self, config):
|
|
13
|
+
self._c = config
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def port(self):
|
|
17
|
+
try:
|
|
18
|
+
return int(self._c['port'])
|
|
19
|
+
except ValueError:
|
|
20
|
+
raise ValueError(f"invalid value for port: '{self._c['port']}'")
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def procfile(self):
|
|
24
|
+
return os.path.join(self._c['app_root'], self._c['procfile'])
|
|
25
|
+
|
|
26
|
+
def load_procfile(self):
|
|
27
|
+
with open(self.procfile) as f:
|
|
28
|
+
content = f.read()
|
|
29
|
+
|
|
30
|
+
return parse_procfile(content)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Procfile(object):
|
|
34
|
+
"""A data structure representing a Procfile"""
|
|
35
|
+
|
|
36
|
+
def __init__(self):
|
|
37
|
+
self.processes = {}
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def loads(cls, contents):
|
|
41
|
+
p = cls()
|
|
42
|
+
for line in contents.splitlines():
|
|
43
|
+
m = PROCFILE_LINE.match(line)
|
|
44
|
+
if m:
|
|
45
|
+
p.add_process(m.group(1), m.group(2))
|
|
46
|
+
return p
|
|
47
|
+
|
|
48
|
+
def add_process(self, name, command):
|
|
49
|
+
assert name not in self.processes, \
|
|
50
|
+
"process names must be unique within a Procfile"
|
|
51
|
+
self.processes[name] = command
|
|
52
|
+
|
|
53
|
+
def get_start_command(self):
|
|
54
|
+
if "web" in self.processes:
|
|
55
|
+
return self.processes["web"]
|
|
56
|
+
elif "default" in self.processes:
|
|
57
|
+
return self.processes["default"]
|
|
58
|
+
elif "start" in self.processes:
|
|
59
|
+
return self.processes["start"]
|
|
60
|
+
elif len(self.processes) == 1:
|
|
61
|
+
return list(self.processes.values())[0]
|
|
62
|
+
return None
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
ProcessParams = namedtuple("ProcessParams", "name cmd quiet env")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def expand_processes(processes, concurrency=None, env=None, quiet=None, port=None):
|
|
69
|
+
"""
|
|
70
|
+
Get a list of the processes that need to be started given the specified
|
|
71
|
+
list of process types, concurrency, environment, quietness, and base port
|
|
72
|
+
number.
|
|
73
|
+
|
|
74
|
+
Returns a list of ProcessParams objects, which have `name`, `cmd`, `env`,
|
|
75
|
+
and `quiet` attributes, corresponding to the parameters to the constructor
|
|
76
|
+
of `honcho.process.Process`.
|
|
77
|
+
"""
|
|
78
|
+
if env is not None and env.get("PORT") is not None:
|
|
79
|
+
port = int(env.get("PORT"))
|
|
80
|
+
|
|
81
|
+
if quiet is None:
|
|
82
|
+
quiet = []
|
|
83
|
+
|
|
84
|
+
con = defaultdict(lambda: 1)
|
|
85
|
+
if concurrency is not None:
|
|
86
|
+
con.update(concurrency)
|
|
87
|
+
|
|
88
|
+
out = []
|
|
89
|
+
|
|
90
|
+
for name, cmd in processes.items():
|
|
91
|
+
for i in range(con[name]):
|
|
92
|
+
n = "{0}.{1}".format(name, i + 1)
|
|
93
|
+
c = cmd
|
|
94
|
+
q = name in quiet
|
|
95
|
+
e = {'SHIPIT_PROCESS_NAME': n}
|
|
96
|
+
if env is not None:
|
|
97
|
+
e.update(env)
|
|
98
|
+
if port is not None:
|
|
99
|
+
e['PORT'] = str(port + i)
|
|
100
|
+
|
|
101
|
+
params = ProcessParams(n, c, q, e)
|
|
102
|
+
out.append(params)
|
|
103
|
+
if port is not None:
|
|
104
|
+
port += 100
|
|
105
|
+
|
|
106
|
+
return out
|
shipit/providers/base.py
CHANGED
|
@@ -11,12 +11,20 @@ class DetectResult:
|
|
|
11
11
|
score: int # Higher score wins when multiple providers match
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
@dataclass
|
|
15
|
+
class CustomCommands:
|
|
16
|
+
install: Optional[str] = None
|
|
17
|
+
build: Optional[str] = None
|
|
18
|
+
start: Optional[str] = None
|
|
19
|
+
after_deploy: Optional[str] = None
|
|
20
|
+
|
|
21
|
+
|
|
14
22
|
class Provider(Protocol):
|
|
15
23
|
def __init__(self, path: Path): ...
|
|
16
24
|
@classmethod
|
|
17
25
|
def name(cls) -> str: ...
|
|
18
26
|
@classmethod
|
|
19
|
-
def detect(cls, path: Path) -> Optional[DetectResult]: ...
|
|
27
|
+
def detect(cls, path: Path, custom_commands: CustomCommands) -> Optional[DetectResult]: ...
|
|
20
28
|
def initialize(self) -> None: ...
|
|
21
29
|
# Structured plan steps (no path args; use self.path)
|
|
22
30
|
def serve_name(self) -> str: ...
|
|
@@ -27,9 +35,9 @@ class Provider(Protocol):
|
|
|
27
35
|
# Prepare: list of Starlark step calls (currently only run(...))
|
|
28
36
|
def prepare_steps(self) -> Optional[List[str]]: ...
|
|
29
37
|
def commands(self) -> Dict[str, str]: ...
|
|
30
|
-
def assets(self) -> Optional[Dict[str, str]]: ...
|
|
31
38
|
def services(self) -> List["ServiceSpec"]: ...
|
|
32
39
|
def mounts(self) -> List["MountSpec"]: ...
|
|
40
|
+
def volumes(self) -> List["VolumeSpec"]: ...
|
|
33
41
|
def env(self) -> Optional[Dict[str, str]]: ...
|
|
34
42
|
|
|
35
43
|
|
|
@@ -50,6 +58,14 @@ class MountSpec:
|
|
|
50
58
|
attach_to_serve: bool = True
|
|
51
59
|
|
|
52
60
|
|
|
61
|
+
@dataclass
|
|
62
|
+
class VolumeSpec:
|
|
63
|
+
name: str
|
|
64
|
+
# Absolute path inside the serve/runtime environment where the volume is mounted
|
|
65
|
+
serve_path: str
|
|
66
|
+
var_name: Optional[str] = None
|
|
67
|
+
|
|
68
|
+
|
|
53
69
|
@dataclass
|
|
54
70
|
class ServiceSpec:
|
|
55
71
|
name: str
|
|
@@ -61,13 +77,13 @@ class ProviderPlan:
|
|
|
61
77
|
serve_name: str
|
|
62
78
|
provider: str
|
|
63
79
|
mounts: List[MountSpec]
|
|
80
|
+
volumes: List[VolumeSpec] = field(default_factory=list)
|
|
64
81
|
declarations: Optional[str] = None
|
|
65
82
|
dependencies: List[DependencySpec] = field(default_factory=list)
|
|
66
83
|
build_steps: List[str] = field(default_factory=list)
|
|
67
84
|
prepare: Optional[List[str]] = None
|
|
68
85
|
services: List[ServiceSpec] = field(default_factory=list)
|
|
69
86
|
commands: Dict[str, str] = field(default_factory=dict)
|
|
70
|
-
assets: Optional[Dict[str, str]] = None
|
|
71
87
|
env: Optional[Dict[str, str]] = None
|
|
72
88
|
|
|
73
89
|
|
shipit/providers/gatsby.py
CHANGED
|
@@ -3,18 +3,30 @@ from __future__ import annotations
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Dict, Optional
|
|
5
5
|
|
|
6
|
-
from .base import
|
|
6
|
+
from .base import (
|
|
7
|
+
DetectResult,
|
|
8
|
+
DependencySpec,
|
|
9
|
+
Provider,
|
|
10
|
+
_exists,
|
|
11
|
+
_has_dependency,
|
|
12
|
+
MountSpec,
|
|
13
|
+
ServiceSpec,
|
|
14
|
+
VolumeSpec,
|
|
15
|
+
CustomCommands,
|
|
16
|
+
)
|
|
7
17
|
|
|
8
18
|
|
|
9
19
|
class GatsbyProvider:
|
|
10
|
-
def __init__(self, path: Path):
|
|
20
|
+
def __init__(self, path: Path, custom_commands: CustomCommands):
|
|
11
21
|
self.path = path
|
|
22
|
+
self.custom_commands = custom_commands
|
|
23
|
+
|
|
12
24
|
@classmethod
|
|
13
25
|
def name(cls) -> str:
|
|
14
26
|
return "gatsby"
|
|
15
27
|
|
|
16
28
|
@classmethod
|
|
17
|
-
def detect(cls, path: Path) -> Optional[DetectResult]:
|
|
29
|
+
def detect(cls, path: Path, custom_commands: CustomCommands) -> Optional[DetectResult]:
|
|
18
30
|
pkg = path / "package.json"
|
|
19
31
|
if not pkg.exists():
|
|
20
32
|
return None
|
|
@@ -62,12 +74,12 @@ class GatsbyProvider:
|
|
|
62
74
|
def commands(self) -> Dict[str, str]:
|
|
63
75
|
return {"start": '"static-web-server --root /app"'}
|
|
64
76
|
|
|
65
|
-
def assets(self) -> Optional[Dict[str, str]]:
|
|
66
|
-
return None
|
|
67
|
-
|
|
68
77
|
def mounts(self) -> list[MountSpec]:
|
|
69
78
|
return [MountSpec("app")]
|
|
70
79
|
|
|
80
|
+
def volumes(self) -> list[VolumeSpec]:
|
|
81
|
+
return []
|
|
82
|
+
|
|
71
83
|
def env(self) -> Optional[Dict[str, str]]:
|
|
72
84
|
return None
|
|
73
85
|
|
shipit/providers/hugo.py
CHANGED
|
@@ -3,16 +3,17 @@ 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
|
|
6
|
+
from .base import DetectResult, DependencySpec, Provider, _exists, ServiceSpec, VolumeSpec, CustomCommands
|
|
7
7
|
from .staticfile import StaticFileProvider
|
|
8
8
|
|
|
9
9
|
class HugoProvider(StaticFileProvider):
|
|
10
|
+
|
|
10
11
|
@classmethod
|
|
11
12
|
def name(cls) -> str:
|
|
12
13
|
return "hugo"
|
|
13
14
|
|
|
14
15
|
@classmethod
|
|
15
|
-
def detect(cls, path: Path) -> Optional[DetectResult]:
|
|
16
|
+
def detect(cls, path: Path, custom_commands: CustomCommands) -> Optional[DetectResult]:
|
|
16
17
|
if _exists(path, "hugo.toml", "hugo.json", "hugo.yaml", "hugo.yml"):
|
|
17
18
|
return DetectResult(cls.name(), 80)
|
|
18
19
|
if (
|
|
@@ -48,3 +49,6 @@ class HugoProvider(StaticFileProvider):
|
|
|
48
49
|
|
|
49
50
|
def services(self) -> list[ServiceSpec]:
|
|
50
51
|
return []
|
|
52
|
+
|
|
53
|
+
def volumes(self) -> list[VolumeSpec]:
|
|
54
|
+
return []
|
shipit/providers/laravel.py
CHANGED
|
@@ -3,18 +3,29 @@ from __future__ import annotations
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Dict, Optional
|
|
5
5
|
|
|
6
|
-
from .base import
|
|
6
|
+
from .base import (
|
|
7
|
+
DetectResult,
|
|
8
|
+
DependencySpec,
|
|
9
|
+
Provider,
|
|
10
|
+
_exists,
|
|
11
|
+
MountSpec,
|
|
12
|
+
ServiceSpec,
|
|
13
|
+
VolumeSpec,
|
|
14
|
+
CustomCommands,
|
|
15
|
+
)
|
|
7
16
|
|
|
8
17
|
|
|
9
18
|
class LaravelProvider:
|
|
10
|
-
def __init__(self, path: Path):
|
|
19
|
+
def __init__(self, path: Path, custom_commands: CustomCommands):
|
|
11
20
|
self.path = path
|
|
21
|
+
self.custom_commands = custom_commands
|
|
22
|
+
|
|
12
23
|
@classmethod
|
|
13
24
|
def name(cls) -> str:
|
|
14
25
|
return "laravel"
|
|
15
26
|
|
|
16
27
|
@classmethod
|
|
17
|
-
def detect(cls, path: Path) -> Optional[DetectResult]:
|
|
28
|
+
def detect(cls, path: Path, custom_commands: CustomCommands) -> Optional[DetectResult]:
|
|
18
29
|
if _exists(path, "artisan") and _exists(path, "composer.json"):
|
|
19
30
|
return DetectResult(cls.name(), 95)
|
|
20
31
|
return None
|
|
@@ -73,12 +84,12 @@ class LaravelProvider:
|
|
|
73
84
|
"after_deploy": '"php artisan migrate"',
|
|
74
85
|
}
|
|
75
86
|
|
|
76
|
-
def assets(self) -> Optional[Dict[str, str]]:
|
|
77
|
-
return None
|
|
78
|
-
|
|
79
87
|
def mounts(self) -> list[MountSpec]:
|
|
80
88
|
return [MountSpec("app")]
|
|
81
89
|
|
|
90
|
+
def volumes(self) -> list[VolumeSpec]:
|
|
91
|
+
return []
|
|
92
|
+
|
|
82
93
|
def env(self) -> Optional[Dict[str, str]]:
|
|
83
94
|
return None
|
|
84
95
|
|
shipit/providers/mkdocs.py
CHANGED
|
@@ -3,22 +3,31 @@ from __future__ import annotations
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Dict, Optional
|
|
5
5
|
|
|
6
|
-
from .base import
|
|
6
|
+
from .base import (
|
|
7
|
+
DetectResult,
|
|
8
|
+
DependencySpec,
|
|
9
|
+
Provider,
|
|
10
|
+
_exists,
|
|
11
|
+
MountSpec,
|
|
12
|
+
ServiceSpec,
|
|
13
|
+
VolumeSpec,
|
|
14
|
+
CustomCommands,
|
|
15
|
+
)
|
|
7
16
|
from .staticfile import StaticFileProvider
|
|
8
17
|
from .python import PythonProvider
|
|
9
18
|
|
|
10
19
|
|
|
11
20
|
class MkdocsProvider(StaticFileProvider):
|
|
12
|
-
def __init__(self, path: Path):
|
|
21
|
+
def __init__(self, path: Path, custom_commands: CustomCommands):
|
|
13
22
|
self.path = path
|
|
14
|
-
self.python_provider = PythonProvider(path, only_build=True, extra_dependencies={"mkdocs"})
|
|
23
|
+
self.python_provider = PythonProvider(path, custom_commands, only_build=True, extra_dependencies={"mkdocs"})
|
|
15
24
|
|
|
16
25
|
@classmethod
|
|
17
26
|
def name(cls) -> str:
|
|
18
27
|
return "mkdocs"
|
|
19
28
|
|
|
20
29
|
@classmethod
|
|
21
|
-
def detect(cls, path: Path) -> Optional[DetectResult]:
|
|
30
|
+
def detect(cls, path: Path, custom_commands: CustomCommands) -> Optional[DetectResult]:
|
|
22
31
|
if _exists(path, "mkdocs.yml", "mkdocs.yaml"):
|
|
23
32
|
return DetectResult(cls.name(), 85)
|
|
24
33
|
return None
|
|
@@ -50,12 +59,12 @@ class MkdocsProvider(StaticFileProvider):
|
|
|
50
59
|
def prepare_steps(self) -> Optional[list[str]]:
|
|
51
60
|
return self.python_provider.prepare_steps()
|
|
52
61
|
|
|
53
|
-
def assets(self) -> Optional[Dict[str, str]]:
|
|
54
|
-
return None
|
|
55
|
-
|
|
56
62
|
def mounts(self) -> list[MountSpec]:
|
|
57
63
|
return [MountSpec("app"), *self.python_provider.mounts()]
|
|
58
64
|
|
|
65
|
+
def volumes(self) -> list[VolumeSpec]:
|
|
66
|
+
return []
|
|
67
|
+
|
|
59
68
|
def env(self) -> Optional[Dict[str, str]]:
|
|
60
69
|
return self.python_provider.env()
|
|
61
70
|
|
shipit/providers/node_static.py
CHANGED
|
@@ -3,18 +3,30 @@ from __future__ import annotations
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Dict, Optional
|
|
5
5
|
|
|
6
|
-
from .base import
|
|
6
|
+
from .base import (
|
|
7
|
+
DetectResult,
|
|
8
|
+
DependencySpec,
|
|
9
|
+
Provider,
|
|
10
|
+
_exists,
|
|
11
|
+
_has_dependency,
|
|
12
|
+
MountSpec,
|
|
13
|
+
ServiceSpec,
|
|
14
|
+
VolumeSpec,
|
|
15
|
+
CustomCommands,
|
|
16
|
+
)
|
|
7
17
|
|
|
8
18
|
|
|
9
19
|
class NodeStaticProvider:
|
|
10
|
-
def __init__(self, path: Path):
|
|
20
|
+
def __init__(self, path: Path, custom_commands: CustomCommands):
|
|
11
21
|
self.path = path
|
|
22
|
+
self.custom_commands = custom_commands
|
|
23
|
+
|
|
12
24
|
@classmethod
|
|
13
25
|
def name(cls) -> str:
|
|
14
26
|
return "node-static"
|
|
15
27
|
|
|
16
28
|
@classmethod
|
|
17
|
-
def detect(cls, path: Path) -> Optional[DetectResult]:
|
|
29
|
+
def detect(cls, path: Path, custom_commands: CustomCommands) -> Optional[DetectResult]:
|
|
18
30
|
pkg = path / "package.json"
|
|
19
31
|
if not pkg.exists():
|
|
20
32
|
return None
|
|
@@ -63,12 +75,12 @@ class NodeStaticProvider:
|
|
|
63
75
|
output_dir = "dist" if (self.path / "dist").exists() else "public"
|
|
64
76
|
return {"start": f'"static-web-server --root /app/{output_dir}"'}
|
|
65
77
|
|
|
66
|
-
def assets(self) -> Optional[Dict[str, str]]:
|
|
67
|
-
return None
|
|
68
|
-
|
|
69
78
|
def mounts(self) -> list[MountSpec]:
|
|
70
79
|
return [MountSpec("app")]
|
|
71
80
|
|
|
81
|
+
def volumes(self) -> list[VolumeSpec]:
|
|
82
|
+
return []
|
|
83
|
+
|
|
72
84
|
def env(self) -> Optional[Dict[str, str]]:
|
|
73
85
|
return None
|
|
74
86
|
|
shipit/providers/php.py
CHANGED
|
@@ -1,24 +1,38 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import json
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
from typing import Dict, Optional
|
|
5
6
|
|
|
6
|
-
from .base import
|
|
7
|
+
from .base import (
|
|
8
|
+
DetectResult,
|
|
9
|
+
DependencySpec,
|
|
10
|
+
Provider,
|
|
11
|
+
_exists,
|
|
12
|
+
MountSpec,
|
|
13
|
+
ServiceSpec,
|
|
14
|
+
VolumeSpec,
|
|
15
|
+
CustomCommands,
|
|
16
|
+
)
|
|
7
17
|
|
|
8
18
|
|
|
9
19
|
class PhpProvider:
|
|
10
|
-
def __init__(self, path: Path):
|
|
20
|
+
def __init__(self, path: Path, custom_commands: CustomCommands):
|
|
11
21
|
self.path = path
|
|
22
|
+
self.custom_commands = custom_commands
|
|
23
|
+
|
|
12
24
|
@classmethod
|
|
13
25
|
def name(cls) -> str:
|
|
14
26
|
return "php"
|
|
15
27
|
|
|
16
28
|
@classmethod
|
|
17
|
-
def detect(cls, path: Path) -> Optional[DetectResult]:
|
|
29
|
+
def detect(cls, path: Path, custom_commands: CustomCommands) -> Optional[DetectResult]:
|
|
18
30
|
if _exists(path, "composer.json") and _exists(path, "public/index.php"):
|
|
19
31
|
return DetectResult(cls.name(), 60)
|
|
20
32
|
if _exists(path, "index.php") and not _exists(path, "composer.json"):
|
|
21
33
|
return DetectResult(cls.name(), 10)
|
|
34
|
+
if custom_commands.start and custom_commands.start.startswith("php "):
|
|
35
|
+
return DetectResult(cls.name(), 70)
|
|
22
36
|
return None
|
|
23
37
|
|
|
24
38
|
def initialize(self) -> None:
|
|
@@ -49,12 +63,16 @@ class PhpProvider:
|
|
|
49
63
|
return deps
|
|
50
64
|
|
|
51
65
|
def declarations(self) -> Optional[str]:
|
|
52
|
-
return "HOME = getenv(\"HOME\")"
|
|
66
|
+
return "HOME = getenv(\"HOME\")\n"
|
|
53
67
|
|
|
54
68
|
def build_steps(self) -> list[str]:
|
|
55
69
|
steps = [
|
|
56
70
|
"workdir(app[\"build\"])",
|
|
57
71
|
]
|
|
72
|
+
if _exists(self.path, "php.ini"):
|
|
73
|
+
steps.append('copy("php.ini", "{}/php.ini".format(assets["build"]))')
|
|
74
|
+
else:
|
|
75
|
+
steps.append('copy("php/php.ini", "{}/php.ini".format(assets["build"]), base="assets")')
|
|
58
76
|
|
|
59
77
|
if self.has_composer():
|
|
60
78
|
steps.append("env(HOME=HOME, COMPOSER_FUND=\"0\")")
|
|
@@ -67,19 +85,30 @@ class PhpProvider:
|
|
|
67
85
|
return None
|
|
68
86
|
|
|
69
87
|
def commands(self) -> Dict[str, str]:
|
|
88
|
+
commands = self.base_commands()
|
|
89
|
+
if self.custom_commands.start:
|
|
90
|
+
commands["start"] = json.dumps(self.custom_commands.start)
|
|
91
|
+
return commands
|
|
92
|
+
|
|
93
|
+
def base_commands(self) -> Dict[str, str]:
|
|
70
94
|
if _exists(self.path, "public/index.php"):
|
|
71
95
|
return {"start": '"php -S localhost:8080 -t public"'}
|
|
72
96
|
elif _exists(self.path, "index.php"):
|
|
73
|
-
return {"start": '"php -S localhost:8080
|
|
74
|
-
|
|
75
|
-
def assets(self) -> Optional[Dict[str, str]]:
|
|
76
|
-
return {"php.ini": "get_asset(\"php/php.ini\")"}
|
|
97
|
+
return {"start": '"php -S localhost:8080 -t ."'}
|
|
77
98
|
|
|
78
99
|
def mounts(self) -> list[MountSpec]:
|
|
79
|
-
return [
|
|
100
|
+
return [
|
|
101
|
+
MountSpec("app"),
|
|
102
|
+
MountSpec("assets"),
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
def volumes(self) -> list[VolumeSpec]:
|
|
106
|
+
return []
|
|
80
107
|
|
|
81
108
|
def env(self) -> Optional[Dict[str, str]]:
|
|
82
|
-
return
|
|
109
|
+
return {
|
|
110
|
+
"PHP_INI_SCAN_DIR": '"{}".format(assets["serve"])',
|
|
111
|
+
}
|
|
83
112
|
|
|
84
113
|
def services(self) -> list[ServiceSpec]:
|
|
85
114
|
return []
|