shipit-cli 0.14.0__py3-none-any.whl → 0.15.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/builders/__init__.py +9 -0
- shipit/builders/base.py +14 -0
- shipit/builders/docker.py +250 -0
- shipit/builders/local.py +161 -0
- shipit/cli.py +318 -1325
- shipit/generator.py +54 -36
- shipit/procfile.py +4 -72
- shipit/providers/base.py +49 -10
- shipit/providers/hugo.py +62 -12
- shipit/providers/jekyll.py +48 -21
- shipit/providers/laravel.py +38 -29
- shipit/providers/mkdocs.py +33 -18
- shipit/providers/node_static.py +205 -139
- shipit/providers/php.py +41 -37
- shipit/providers/python.py +282 -226
- shipit/providers/registry.py +0 -2
- shipit/providers/staticfile.py +44 -25
- shipit/providers/wordpress.py +25 -26
- shipit/runners/__init__.py +9 -0
- shipit/runners/base.py +17 -0
- shipit/runners/local.py +105 -0
- shipit/runners/wasmer.py +470 -0
- shipit/shipit_types.py +103 -0
- shipit/ui.py +14 -0
- shipit/utils.py +10 -0
- shipit/version.py +2 -2
- {shipit_cli-0.14.0.dist-info → shipit_cli-0.15.1.dist-info}/METADATA +6 -3
- shipit_cli-0.15.1.dist-info/RECORD +34 -0
- {shipit_cli-0.14.0.dist-info → shipit_cli-0.15.1.dist-info}/WHEEL +1 -1
- shipit_cli-0.14.0.dist-info/RECORD +0 -23
- {shipit_cli-0.14.0.dist-info → shipit_cli-0.15.1.dist-info}/entry_points.txt +0 -0
shipit/providers/laravel.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
1
|
from pathlib import Path
|
|
4
2
|
from typing import Dict, Optional
|
|
5
3
|
|
|
@@ -12,65 +10,76 @@ from .base import (
|
|
|
12
10
|
ServiceSpec,
|
|
13
11
|
VolumeSpec,
|
|
14
12
|
CustomCommands,
|
|
13
|
+
Config,
|
|
15
14
|
)
|
|
15
|
+
from .php import PhpConfig, PhpProvider
|
|
16
|
+
from .node_static import NodeStaticConfig, NodeStaticProvider
|
|
17
|
+
from pydantic_settings import SettingsConfigDict
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class LaravelConfig(PhpConfig, NodeStaticConfig):
|
|
21
|
+
model_config = SettingsConfigDict(extra="ignore", env_prefix="SHIPIT_")
|
|
16
22
|
|
|
17
23
|
|
|
18
|
-
class LaravelProvider:
|
|
19
|
-
def __init__(self, path: Path,
|
|
24
|
+
class LaravelProvider(PhpProvider):
|
|
25
|
+
def __init__(self, path: Path, config: LaravelConfig):
|
|
20
26
|
self.path = path
|
|
21
|
-
self.
|
|
27
|
+
self.node_provider = NodeStaticProvider(path, config, only_build=True)
|
|
28
|
+
self.config = config
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def load_config(cls, path: Path, base_config: Config) -> LaravelConfig:
|
|
32
|
+
config = super().load_config(path, base_config)
|
|
33
|
+
node_config = NodeStaticProvider.load_config(path, base_config)
|
|
34
|
+
node_config.static_dir = None
|
|
35
|
+
node_config.static_generator = None
|
|
36
|
+
return LaravelConfig(
|
|
37
|
+
**(
|
|
38
|
+
config.model_dump()
|
|
39
|
+
| node_config.model_dump()
|
|
40
|
+
| base_config.model_dump()
|
|
41
|
+
)
|
|
42
|
+
)
|
|
22
43
|
|
|
23
44
|
@classmethod
|
|
24
45
|
def name(cls) -> str:
|
|
25
46
|
return "laravel"
|
|
26
47
|
|
|
27
48
|
@classmethod
|
|
28
|
-
def detect(cls, path: Path,
|
|
49
|
+
def detect(cls, path: Path, config: Config) -> Optional[DetectResult]:
|
|
29
50
|
if _exists(path, "artisan") and _exists(path, "composer.json"):
|
|
30
51
|
return DetectResult(cls.name(), 95)
|
|
31
52
|
return None
|
|
32
53
|
|
|
33
|
-
def initialize(self) -> None:
|
|
34
|
-
pass
|
|
35
|
-
|
|
36
54
|
def serve_name(self) -> Optional[str]:
|
|
37
55
|
return None
|
|
38
56
|
|
|
39
|
-
def platform(self) -> Optional[str]:
|
|
40
|
-
return "laravel"
|
|
41
|
-
|
|
42
57
|
def dependencies(self) -> list[DependencySpec]:
|
|
43
58
|
return [
|
|
44
59
|
DependencySpec(
|
|
45
60
|
"php",
|
|
46
|
-
|
|
47
|
-
default_version="8.3",
|
|
61
|
+
var_name="config.php_version",
|
|
48
62
|
use_in_build=True,
|
|
49
63
|
use_in_serve=True,
|
|
50
64
|
),
|
|
51
65
|
DependencySpec("composer", use_in_build=True),
|
|
52
|
-
DependencySpec("pie", use_in_build=True),
|
|
53
|
-
|
|
66
|
+
# DependencySpec("pie", use_in_build=True),
|
|
67
|
+
*self.node_provider.dependencies(),
|
|
54
68
|
DependencySpec("bash", use_in_serve=True),
|
|
55
69
|
]
|
|
56
70
|
|
|
57
|
-
def declarations(self) -> Optional[str]:
|
|
58
|
-
return "HOME = getenv(\"HOME\")"
|
|
59
|
-
|
|
60
71
|
def build_steps(self) -> list[str]:
|
|
61
72
|
return [
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"run(\"pie install php/pdo_pgsql\")",
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
"copy(\".\", \".\", ignore=[\".git\"])",
|
|
68
|
-
"run(\"pnpm run build\", outputs=[\".\"], group=\"build\")",
|
|
73
|
+
'env(COMPOSER_HOME="/tmp", COMPOSER_FUND="0")',
|
|
74
|
+
'workdir(app.path)',
|
|
75
|
+
# "run(\"pie install php/pdo_pgsql\")",
|
|
76
|
+
'run("composer install --optimize-autoloader --no-scripts --no-interaction", inputs=["composer.json", "composer.lock", "artisan"], outputs=["."], group="install")',
|
|
77
|
+
*self.node_provider.build_steps(),
|
|
69
78
|
]
|
|
70
79
|
|
|
71
80
|
def prepare_steps(self) -> Optional[list[str]]:
|
|
72
81
|
return [
|
|
73
|
-
'workdir(app
|
|
82
|
+
'workdir(app.serve_path)',
|
|
74
83
|
'run("mkdir -p storage/framework/{sessions,views,cache,testing} storage/logs bootstrap/cache")',
|
|
75
84
|
'run("php artisan config:cache")',
|
|
76
85
|
'run("php artisan event:cache")',
|
|
@@ -85,13 +94,13 @@ class LaravelProvider:
|
|
|
85
94
|
}
|
|
86
95
|
|
|
87
96
|
def mounts(self) -> list[MountSpec]:
|
|
88
|
-
return [MountSpec("app")]
|
|
97
|
+
return [MountSpec("app"), *self.node_provider.mounts()]
|
|
89
98
|
|
|
90
99
|
def volumes(self) -> list[VolumeSpec]:
|
|
91
100
|
return []
|
|
92
101
|
|
|
93
102
|
def env(self) -> Optional[Dict[str, str]]:
|
|
94
103
|
return None
|
|
95
|
-
|
|
104
|
+
|
|
96
105
|
def services(self) -> list[ServiceSpec]:
|
|
97
106
|
return []
|
shipit/providers/mkdocs.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
1
|
from pathlib import Path
|
|
4
2
|
from typing import Dict, Optional
|
|
5
3
|
|
|
@@ -12,37 +10,54 @@ from .base import (
|
|
|
12
10
|
ServiceSpec,
|
|
13
11
|
VolumeSpec,
|
|
14
12
|
CustomCommands,
|
|
13
|
+
Config,
|
|
15
14
|
)
|
|
16
|
-
from .staticfile import StaticFileProvider
|
|
17
|
-
from .python import PythonProvider
|
|
15
|
+
from .staticfile import StaticFileProvider, StaticFileConfig
|
|
16
|
+
from .python import PythonProvider, PythonConfig
|
|
17
|
+
from pydantic_settings import SettingsConfigDict
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class MkdocsConfig(PythonConfig, StaticFileConfig):
|
|
21
|
+
model_config = SettingsConfigDict(extra="ignore", env_prefix="SHIPIT_")
|
|
22
|
+
|
|
23
|
+
mkdocs_version: Optional[str] = None
|
|
18
24
|
|
|
19
25
|
|
|
20
26
|
class MkdocsProvider(StaticFileProvider):
|
|
21
|
-
def __init__(self, path: Path,
|
|
27
|
+
def __init__(self, path: Path, config: MkdocsConfig):
|
|
22
28
|
self.path = path
|
|
23
|
-
self.python_provider = PythonProvider(path,
|
|
29
|
+
self.python_provider = PythonProvider(path, config, only_build=True)
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def load_config(cls, path: Path, base_config: Config) -> MkdocsConfig:
|
|
33
|
+
python_config = PythonProvider.load_config(
|
|
34
|
+
path, base_config, must_have_deps={"mkdocs"}
|
|
35
|
+
)
|
|
36
|
+
staticfile_config = StaticFileProvider.load_config(path, base_config)
|
|
37
|
+
|
|
38
|
+
return MkdocsConfig(
|
|
39
|
+
**(
|
|
40
|
+
python_config.model_dump()
|
|
41
|
+
| staticfile_config.model_dump()
|
|
42
|
+
| base_config.model_dump()
|
|
43
|
+
)
|
|
44
|
+
)
|
|
24
45
|
|
|
25
46
|
@classmethod
|
|
26
47
|
def name(cls) -> str:
|
|
27
48
|
return "mkdocs"
|
|
28
49
|
|
|
29
50
|
@classmethod
|
|
30
|
-
def detect(cls, path: Path,
|
|
51
|
+
def detect(cls, path: Path, config: Config) -> Optional[DetectResult]:
|
|
31
52
|
if _exists(path, "mkdocs.yml", "mkdocs.yaml"):
|
|
32
53
|
return DetectResult(cls.name(), 85)
|
|
33
|
-
if
|
|
54
|
+
if config.commands.build and config.commands.build.startswith("mkdocs "):
|
|
34
55
|
return DetectResult(cls.name(), 85)
|
|
35
56
|
return None
|
|
36
57
|
|
|
37
|
-
def initialize(self) -> None:
|
|
38
|
-
pass
|
|
39
|
-
|
|
40
58
|
def serve_name(self) -> Optional[str]:
|
|
41
59
|
return None
|
|
42
60
|
|
|
43
|
-
def platform(self) -> Optional[str]:
|
|
44
|
-
return None
|
|
45
|
-
|
|
46
61
|
def dependencies(self) -> list[DependencySpec]:
|
|
47
62
|
return [
|
|
48
63
|
*self.python_provider.dependencies(),
|
|
@@ -50,25 +65,25 @@ class MkdocsProvider(StaticFileProvider):
|
|
|
50
65
|
]
|
|
51
66
|
|
|
52
67
|
def declarations(self) -> Optional[str]:
|
|
53
|
-
return
|
|
68
|
+
return self.python_provider.declarations() or ""
|
|
54
69
|
|
|
55
70
|
def build_steps(self) -> list[str]:
|
|
56
71
|
return [
|
|
57
72
|
*self.python_provider.build_steps(),
|
|
58
|
-
|
|
73
|
+
'run("uv run mkdocs build --site-dir={}".format(static_app.path), outputs=["."], group="build")',
|
|
59
74
|
]
|
|
60
75
|
|
|
61
76
|
def prepare_steps(self) -> Optional[list[str]]:
|
|
62
77
|
return self.python_provider.prepare_steps()
|
|
63
78
|
|
|
64
79
|
def mounts(self) -> list[MountSpec]:
|
|
65
|
-
return [
|
|
80
|
+
return [*self.python_provider.mounts(), *super().mounts()]
|
|
66
81
|
|
|
67
82
|
def volumes(self) -> list[VolumeSpec]:
|
|
68
83
|
return []
|
|
69
84
|
|
|
70
85
|
def env(self) -> Optional[Dict[str, str]]:
|
|
71
86
|
return self.python_provider.env()
|
|
72
|
-
|
|
87
|
+
|
|
73
88
|
def services(self) -> list[ServiceSpec]:
|
|
74
89
|
return []
|
shipit/providers/node_static.py
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
1
|
import json
|
|
4
2
|
import yaml
|
|
5
3
|
from pathlib import Path
|
|
6
|
-
from typing import Dict, Optional, Any, Set
|
|
4
|
+
from typing import Dict, Optional, Any, Set, List
|
|
7
5
|
from enum import Enum
|
|
8
6
|
from semantic_version import Version, NpmSpec
|
|
7
|
+
from pydantic import Field
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
from .base import (
|
|
@@ -15,9 +14,10 @@ from .base import (
|
|
|
15
14
|
MountSpec,
|
|
16
15
|
ServiceSpec,
|
|
17
16
|
VolumeSpec,
|
|
18
|
-
|
|
17
|
+
Config,
|
|
19
18
|
)
|
|
20
|
-
from .staticfile import StaticFileProvider
|
|
19
|
+
from .staticfile import StaticFileProvider, StaticFileConfig
|
|
20
|
+
from pydantic_settings import SettingsConfigDict
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class PackageManager(Enum):
|
|
@@ -46,7 +46,7 @@ class PackageManager(Enum):
|
|
|
46
46
|
|
|
47
47
|
return DependencySpec(
|
|
48
48
|
dep_name,
|
|
49
|
-
|
|
49
|
+
var_name=f"config.{dep_name.lower()}_version",
|
|
50
50
|
default_version=default_version,
|
|
51
51
|
)
|
|
52
52
|
|
|
@@ -114,60 +114,146 @@ class StaticGenerator(Enum):
|
|
|
114
114
|
REMIX_OLD = "remix-old"
|
|
115
115
|
REMIX_V2 = "remix-v2"
|
|
116
116
|
|
|
117
|
+
def get_output_dir(self) -> str:
|
|
118
|
+
if self == StaticGenerator.NEXT:
|
|
119
|
+
return "out"
|
|
120
|
+
elif self == StaticGenerator.NUXT_V3:
|
|
121
|
+
return ".output/public"
|
|
122
|
+
elif self in [
|
|
123
|
+
StaticGenerator.ASTRO,
|
|
124
|
+
StaticGenerator.VITE,
|
|
125
|
+
StaticGenerator.NUXT_OLD,
|
|
126
|
+
StaticGenerator.REMIX_V2,
|
|
127
|
+
]:
|
|
128
|
+
return "dist"
|
|
129
|
+
elif self == StaticGenerator.GATSBY:
|
|
130
|
+
return "public"
|
|
131
|
+
elif self == StaticGenerator.REMIX_OLD:
|
|
132
|
+
return "build/client"
|
|
133
|
+
elif self in [
|
|
134
|
+
StaticGenerator.DOCUSAURUS,
|
|
135
|
+
StaticGenerator.DOCUSAURUS_OLD,
|
|
136
|
+
StaticGenerator.SVELTE,
|
|
137
|
+
]:
|
|
138
|
+
return "build"
|
|
139
|
+
else:
|
|
140
|
+
return "dist"
|
|
141
|
+
|
|
142
|
+
@classmethod
|
|
143
|
+
def detect_generators_from_command(cls, build_command) -> List["StaticGenerator"]:
|
|
144
|
+
commands = {
|
|
145
|
+
"gatsby": [StaticGenerator.GATSBY],
|
|
146
|
+
"astro": [StaticGenerator.ASTRO],
|
|
147
|
+
"remix-ssg": [StaticGenerator.REMIX_OLD],
|
|
148
|
+
"vite": [StaticGenerator.VITE, StaticGenerator.REMIX_V2],
|
|
149
|
+
"docusaurus": [StaticGenerator.DOCUSAURUS, StaticGenerator.DOCUSAURUS_OLD],
|
|
150
|
+
"next": [StaticGenerator.NEXT],
|
|
151
|
+
"nuxi": [StaticGenerator.NUXT_V3],
|
|
152
|
+
"nuxt": [StaticGenerator.NUXT_OLD],
|
|
153
|
+
"svelte-kit": [StaticGenerator.SVELTE],
|
|
154
|
+
}
|
|
155
|
+
build_command = build_command.split(" ")[0]
|
|
156
|
+
if build_command in commands:
|
|
157
|
+
return commands[build_command]
|
|
158
|
+
else:
|
|
159
|
+
return []
|
|
160
|
+
|
|
161
|
+
def build_command(self) -> str:
|
|
162
|
+
return {
|
|
163
|
+
StaticGenerator.GATSBY: "gatsby build",
|
|
164
|
+
StaticGenerator.ASTRO: "astro build",
|
|
165
|
+
StaticGenerator.REMIX_OLD: "remix-ssg build",
|
|
166
|
+
StaticGenerator.REMIX_V2: "vite build",
|
|
167
|
+
StaticGenerator.DOCUSAURUS: "docusaurus build",
|
|
168
|
+
StaticGenerator.DOCUSAURUS_OLD: "docusaurus build",
|
|
169
|
+
StaticGenerator.SVELTE: "svelte-kit build",
|
|
170
|
+
StaticGenerator.VITE: "vite build",
|
|
171
|
+
StaticGenerator.NEXT: "next export",
|
|
172
|
+
StaticGenerator.NUXT_V3: "nuxi generate",
|
|
173
|
+
StaticGenerator.NUXT_OLD: "nuxt generate",
|
|
174
|
+
StaticGenerator.REMIX: "remix-ssg build",
|
|
175
|
+
}[self]
|
|
117
176
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
177
|
+
|
|
178
|
+
class NodeStaticConfig(StaticFileConfig):
|
|
179
|
+
model_config = SettingsConfigDict(extra="ignore", env_prefix="SHIPIT_")
|
|
180
|
+
|
|
181
|
+
package_manager: Optional[PackageManager] = None
|
|
182
|
+
extra_dependencies: Set[str] = Field(default_factory=set)
|
|
122
183
|
static_generator: Optional[StaticGenerator] = None
|
|
123
184
|
build_command: Optional[str] = None
|
|
185
|
+
node_version: Optional[str] = "22"
|
|
186
|
+
npm_version: Optional[str] = None
|
|
187
|
+
pnpm_version: Optional[str] = None
|
|
188
|
+
yarn_version: Optional[str] = None
|
|
189
|
+
bun_version: Optional[str] = None
|
|
124
190
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
191
|
+
|
|
192
|
+
class NodeStaticProvider(StaticFileProvider):
|
|
193
|
+
only_build: bool = False
|
|
194
|
+
|
|
195
|
+
def __init__(
|
|
196
|
+
self, path: Path, config: NodeStaticConfig, only_build: bool = False
|
|
197
|
+
):
|
|
198
|
+
super().__init__(path, config)
|
|
199
|
+
self.only_build = only_build
|
|
200
|
+
|
|
201
|
+
@classmethod
|
|
202
|
+
def load_config(
|
|
203
|
+
cls, path: Path, base_config: Config
|
|
204
|
+
) -> NodeStaticConfig:
|
|
205
|
+
config = NodeStaticConfig(**base_config.model_dump())
|
|
206
|
+
if not config.package_manager:
|
|
207
|
+
if (path / "package-lock.json").exists():
|
|
208
|
+
config.package_manager = PackageManager.NPM
|
|
209
|
+
elif (path / "pnpm-lock.yaml").exists():
|
|
210
|
+
config.package_manager = PackageManager.PNPM
|
|
211
|
+
elif (path / "yarn.lock").exists():
|
|
212
|
+
config.package_manager = PackageManager.YARN
|
|
213
|
+
elif (path / "bun.lockb").exists():
|
|
214
|
+
config.package_manager = PackageManager.BUN
|
|
215
|
+
else:
|
|
216
|
+
config.package_manager = PackageManager.PNPM
|
|
217
|
+
|
|
218
|
+
package_json = cls.parse_package_json(path)
|
|
219
|
+
|
|
220
|
+
if not config.static_generator:
|
|
221
|
+
if cls.has_dependency(package_json, "gatsby"):
|
|
222
|
+
config.static_generator = StaticGenerator.GATSBY
|
|
223
|
+
elif cls.has_dependency(package_json, "astro"):
|
|
224
|
+
config.static_generator = StaticGenerator.ASTRO
|
|
225
|
+
elif cls.has_dependency(package_json, "docusaurus"):
|
|
226
|
+
config.static_generator = StaticGenerator.DOCUSAURUS_OLD
|
|
227
|
+
elif cls.has_dependency(package_json, "@docusaurus/core"):
|
|
228
|
+
config.static_generator = StaticGenerator.DOCUSAURUS
|
|
229
|
+
elif cls.has_dependency(package_json, "svelte"):
|
|
230
|
+
config.static_generator = StaticGenerator.SVELTE
|
|
231
|
+
elif cls.has_dependency(
|
|
232
|
+
package_json, "@remix-run/dev", "1"
|
|
233
|
+
) or cls.has_dependency(package_json, "@remix-run/dev", "0"):
|
|
234
|
+
config.static_generator = StaticGenerator.REMIX_OLD
|
|
235
|
+
elif cls.has_dependency(package_json, "@remix-run/dev"):
|
|
236
|
+
config.static_generator = StaticGenerator.REMIX_V2
|
|
237
|
+
elif cls.has_dependency(package_json, "vite"):
|
|
238
|
+
config.static_generator = StaticGenerator.VITE
|
|
239
|
+
elif cls.has_dependency(package_json, "next"):
|
|
240
|
+
config.static_generator = StaticGenerator.NEXT
|
|
241
|
+
elif cls.has_dependency(package_json, "nuxt", "2") or cls.has_dependency(
|
|
242
|
+
package_json, "nuxt", "1"
|
|
243
|
+
):
|
|
244
|
+
config.static_generator = StaticGenerator.NUXT_OLD
|
|
245
|
+
elif cls.has_dependency(package_json, "nuxt"):
|
|
246
|
+
config.static_generator = StaticGenerator.NUXT_V3
|
|
247
|
+
|
|
248
|
+
if not config.build_command:
|
|
249
|
+
config.build_command = cls.get_build_command(
|
|
250
|
+
package_json, config.package_manager, config.static_generator
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
if not config.static_dir:
|
|
254
|
+
config.static_dir = config.static_generator.get_output_dir()
|
|
255
|
+
|
|
256
|
+
return config
|
|
171
257
|
|
|
172
258
|
@classmethod
|
|
173
259
|
def parse_package_json(cls, path: Path) -> Optional[Dict[str, Any]]:
|
|
@@ -211,8 +297,27 @@ class NodeStaticProvider(StaticFileProvider):
|
|
|
211
297
|
|
|
212
298
|
@classmethod
|
|
213
299
|
def detect(
|
|
214
|
-
cls, path: Path,
|
|
300
|
+
cls, path: Path, config: Config
|
|
215
301
|
) -> Optional[DetectResult]:
|
|
302
|
+
if config.commands.install:
|
|
303
|
+
# Detect this provider from the install command
|
|
304
|
+
if config.commands.install in ["npm install", "npm ci", "npm i", "pnpm install", "pnpm ci", "pnpm i", "yarn install", "yarn ci", "yarn i", "bun install", "bun ci", "bun i"]:
|
|
305
|
+
return DetectResult(cls.name(), 40)
|
|
306
|
+
|
|
307
|
+
if config.commands.build:
|
|
308
|
+
if config.commands.build.startswith("npm run "):
|
|
309
|
+
return DetectResult(cls.name(), 40)
|
|
310
|
+
elif config.commands.build.startswith("pnpm run "):
|
|
311
|
+
return DetectResult(cls.name(), 40)
|
|
312
|
+
elif config.commands.build.startswith("yarn run "):
|
|
313
|
+
return DetectResult(cls.name(), 40)
|
|
314
|
+
elif config.commands.build.startswith("bun run "):
|
|
315
|
+
return DetectResult(cls.name(), 40)
|
|
316
|
+
|
|
317
|
+
static_generators = StaticGenerator.detect_generators_from_command(config.commands.build)
|
|
318
|
+
if static_generators:
|
|
319
|
+
return DetectResult(cls.name(), 40)
|
|
320
|
+
|
|
216
321
|
package_json = cls.parse_package_json(path)
|
|
217
322
|
if not package_json:
|
|
218
323
|
return None
|
|
@@ -231,119 +336,80 @@ class NodeStaticProvider(StaticFileProvider):
|
|
|
231
336
|
return DetectResult(cls.name(), 40)
|
|
232
337
|
return None
|
|
233
338
|
|
|
234
|
-
def initialize(self) -> None:
|
|
235
|
-
pass
|
|
236
|
-
|
|
237
339
|
def serve_name(self) -> Optional[str]:
|
|
238
340
|
return None
|
|
239
341
|
|
|
240
|
-
def platform(self) -> Optional[str]:
|
|
241
|
-
return self.static_generator.value if self.static_generator else None
|
|
242
|
-
|
|
243
342
|
def dependencies(self) -> list[DependencySpec]:
|
|
244
|
-
package_manager_dep = self.package_manager.as_dependency(self.path)
|
|
343
|
+
package_manager_dep = self.config.package_manager.as_dependency(self.path)
|
|
245
344
|
package_manager_dep.use_in_build = True
|
|
246
345
|
return [
|
|
247
346
|
DependencySpec(
|
|
248
347
|
"node",
|
|
249
|
-
|
|
250
|
-
default_version="22",
|
|
348
|
+
var_name="config.node_version",
|
|
251
349
|
use_in_build=True,
|
|
252
350
|
),
|
|
253
351
|
package_manager_dep,
|
|
254
|
-
|
|
352
|
+
*super().dependencies(),
|
|
255
353
|
]
|
|
256
354
|
|
|
257
|
-
def declarations(self) -> Optional[str]:
|
|
258
|
-
output_dir = self.get_output_dir()
|
|
259
|
-
return (
|
|
260
|
-
f'shipit_static_dir = getenv("SHIPIT_STATIC_DIR") or "{output_dir}"\n'
|
|
261
|
-
)
|
|
262
|
-
|
|
263
|
-
def get_output_dir(self) -> str:
|
|
264
|
-
if self.static_generator == StaticGenerator.NEXT:
|
|
265
|
-
return "out"
|
|
266
|
-
elif self.static_generator in [
|
|
267
|
-
StaticGenerator.ASTRO,
|
|
268
|
-
StaticGenerator.VITE,
|
|
269
|
-
StaticGenerator.NUXT_OLD,
|
|
270
|
-
StaticGenerator.NUXT_V3,
|
|
271
|
-
StaticGenerator.REMIX_V2,
|
|
272
|
-
]:
|
|
273
|
-
return "dist"
|
|
274
|
-
elif self.static_generator == StaticGenerator.GATSBY:
|
|
275
|
-
return "public"
|
|
276
|
-
elif self.static_generator == StaticGenerator.REMIX_OLD:
|
|
277
|
-
return "build/client"
|
|
278
|
-
elif self.static_generator in [
|
|
279
|
-
StaticGenerator.DOCUSAURUS,
|
|
280
|
-
StaticGenerator.DOCUSAURUS_OLD,
|
|
281
|
-
StaticGenerator.SVELTE,
|
|
282
|
-
]:
|
|
283
|
-
return "build"
|
|
284
|
-
else:
|
|
285
|
-
return "dist"
|
|
286
|
-
|
|
287
355
|
@classmethod
|
|
288
|
-
def get_build_command(
|
|
356
|
+
def get_build_command(
|
|
357
|
+
cls,
|
|
358
|
+
package_json: Optional[Dict[str, Any]],
|
|
359
|
+
package_manager: PackageManager,
|
|
360
|
+
static_generator: StaticGenerator,
|
|
361
|
+
) -> Optional[str]:
|
|
289
362
|
if package_json:
|
|
290
|
-
|
|
363
|
+
scripts = package_json.get("scripts", {})
|
|
364
|
+
generate_command = scripts.get("generate")
|
|
365
|
+
if generate_command:
|
|
366
|
+
return package_manager.run_command("generate")
|
|
367
|
+
build_command = scripts.get("build")
|
|
291
368
|
if build_command:
|
|
292
369
|
return package_manager.run_command("build")
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
elif static_generator == StaticGenerator.ASTRO:
|
|
296
|
-
return package_manager.run_execute_command("astro build")
|
|
297
|
-
elif static_generator == StaticGenerator.REMIX_OLD:
|
|
298
|
-
return package_manager.run_execute_command("remix-ssg build")
|
|
299
|
-
elif static_generator == StaticGenerator.REMIX_V2:
|
|
300
|
-
return package_manager.run_execute_command("vite build")
|
|
301
|
-
elif static_generator == StaticGenerator.DOCUSAURUS:
|
|
302
|
-
return package_manager.run_execute_command("docusaurus build")
|
|
303
|
-
elif static_generator == StaticGenerator.DOCUSAURUS_OLD:
|
|
304
|
-
return package_manager.run_execute_command("docusaurus build")
|
|
305
|
-
elif static_generator == StaticGenerator.SVELTE:
|
|
306
|
-
return package_manager.run_execute_command("svelte-kit build")
|
|
307
|
-
elif static_generator == StaticGenerator.VITE:
|
|
308
|
-
return package_manager.run_execute_command("vite build")
|
|
309
|
-
elif static_generator == StaticGenerator.NEXT:
|
|
310
|
-
return package_manager.run_execute_command("next export")
|
|
311
|
-
elif static_generator == StaticGenerator.NUXT_V3:
|
|
312
|
-
return package_manager.run_execute_command("nuxi generate")
|
|
313
|
-
elif static_generator == StaticGenerator.NUXT_OLD:
|
|
314
|
-
return package_manager.run_execute_command("nuxt generate")
|
|
315
|
-
return None
|
|
370
|
+
command = static_generator.build_command()
|
|
371
|
+
return package_manager.run_execute_command(command)
|
|
316
372
|
|
|
317
373
|
def build_steps(self) -> list[str]:
|
|
318
|
-
lockfile = self.package_manager.lockfile()
|
|
374
|
+
lockfile = self.config.package_manager.lockfile()
|
|
319
375
|
has_lockfile = (self.path / lockfile).exists()
|
|
320
|
-
install_command = self.package_manager.install_command(
|
|
376
|
+
install_command = self.config.package_manager.install_command(
|
|
321
377
|
has_lockfile=has_lockfile
|
|
322
378
|
)
|
|
323
|
-
input_files = ["package.json"]
|
|
324
|
-
# if has_lockfile:
|
|
325
|
-
# input_files.append(lockfile)
|
|
326
|
-
inputs_install_files = ", ".join([f'"{file}"' for file in input_files])
|
|
327
|
-
|
|
328
379
|
ignored_files = ["node_modules", ".git"]
|
|
329
380
|
if has_lockfile:
|
|
330
381
|
ignored_files.append(lockfile)
|
|
331
382
|
all_ignored_files = ", ".join([f'"{file}"' for file in ignored_files])
|
|
332
|
-
|
|
333
|
-
return
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
383
|
+
|
|
384
|
+
return filter(
|
|
385
|
+
None,
|
|
386
|
+
[
|
|
387
|
+
'workdir(temp.path)' if not self.only_build else None,
|
|
388
|
+
f'copy("{lockfile}")' if has_lockfile else None,
|
|
389
|
+
'env(CI="true", NODE_ENV="production", NPM_CONFIG_FUND="false")'
|
|
390
|
+
if self.config.package_manager == PackageManager.NPM
|
|
391
|
+
else None,
|
|
392
|
+
# 'run("npx corepack enable", inputs=["package.json"], group="install")',
|
|
393
|
+
f'run("{install_command}", inputs=["package.json"], group="install")',
|
|
394
|
+
f'copy(".", ignore=[{all_ignored_files}])',
|
|
395
|
+
f'run("{self.config.build_command}", outputs=[config.static_dir], group="build")'
|
|
396
|
+
if not self.only_build
|
|
397
|
+
else None,
|
|
398
|
+
f'run("{self.config.build_command}", group="build")'
|
|
399
|
+
if self.only_build
|
|
400
|
+
else None,
|
|
401
|
+
'run("cp -R {}/* {}/".format(config.static_dir, static_app.path))'
|
|
402
|
+
if not self.only_build
|
|
403
|
+
else None,
|
|
404
|
+
],
|
|
405
|
+
)
|
|
342
406
|
|
|
343
407
|
def prepare_steps(self) -> Optional[list[str]]:
|
|
344
408
|
return None
|
|
345
409
|
|
|
346
410
|
def mounts(self) -> list[MountSpec]:
|
|
411
|
+
if self.only_build:
|
|
412
|
+
return []
|
|
347
413
|
return [MountSpec("temp", attach_to_serve=False), *super().mounts()]
|
|
348
414
|
|
|
349
415
|
def volumes(self) -> list[VolumeSpec]:
|