shipit-cli 0.3.2__tar.gz → 0.3.4__tar.gz

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.
Files changed (23) hide show
  1. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/PKG-INFO +1 -1
  2. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/pyproject.toml +1 -1
  3. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/src/shipit/cli.py +5 -1
  4. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/src/shipit/generator.py +18 -21
  5. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/src/shipit/providers/base.py +17 -14
  6. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/src/shipit/providers/gatsby.py +19 -15
  7. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/src/shipit/providers/hugo.py +12 -10
  8. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/src/shipit/providers/laravel.py +19 -15
  9. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/src/shipit/providers/mkdocs.py +20 -16
  10. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/src/shipit/providers/node_static.py +21 -17
  11. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/src/shipit/providers/php.py +26 -22
  12. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/src/shipit/providers/python.py +32 -25
  13. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/src/shipit/providers/registry.py +9 -10
  14. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/src/shipit/providers/staticfile.py +22 -17
  15. shipit_cli-0.3.4/src/shipit/version.py +5 -0
  16. shipit_cli-0.3.2/src/shipit/version.py +0 -5
  17. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/.gitignore +0 -0
  18. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/README.md +0 -0
  19. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/src/shipit/__init__.py +0 -0
  20. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/src/shipit/assets/php/php.ini +0 -0
  21. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/tests/test_examples_build.py +0 -0
  22. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/tests/test_generate_shipit_examples.py +0 -0
  23. {shipit_cli-0.3.2 → shipit_cli-0.3.4}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shipit-cli
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: Add your description here
5
5
  Project-URL: homepage, https://wasmer.io
6
6
  Project-URL: repository, https://github.com/wasmerio/shipit
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "shipit-cli"
3
- version = "0.3.2"
3
+ version = "0.3.4"
4
4
  description = "Add your description here"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -584,6 +584,8 @@ class LocalBuilder:
584
584
  for step in serve.prepare:
585
585
  if isinstance(step, RunStep):
586
586
  commands.append(step.command)
587
+ elif isinstance(step, WorkdirStep):
588
+ commands.append(f"cd {step.path}")
587
589
  content = "#!/bin/bash\ncd {app_dir}\n{body}".format(
588
590
  app_dir=app_dir, body="\n".join(commands)
589
591
  )
@@ -741,9 +743,11 @@ class WasmerBuilder:
741
743
  for step in serve.prepare:
742
744
  if isinstance(step, RunStep):
743
745
  commands.append(step.command)
746
+ elif isinstance(step, WorkdirStep):
747
+ commands.append(f"cd {step.path}")
744
748
  body = "\n".join(filter(None, [env_lines, *commands]))
745
749
  (prepare_dir / "prepare.sh").write_text(
746
- f"#!/bin/bash\ncd /app\n{body}",
750
+ f"#!/bin/bash\n\n{body}",
747
751
  )
748
752
  (prepare_dir / "prepare.sh").chmod(0o755)
749
753
 
@@ -7,22 +7,19 @@ from shipit.providers.base import DependencySpec, Provider, ProviderPlan, Detect
7
7
  from shipit.providers.registry import providers as registry_providers
8
8
 
9
9
 
10
- def _providers() -> list[Provider]:
11
- # Load providers from modular registry
10
+ def _providers() -> list[type[Provider]]:
11
+ # Load provider classes from modular registry
12
12
  return registry_providers()
13
13
 
14
14
 
15
15
  def detect_provider(path: Path) -> Provider:
16
- matches: list[tuple[Provider, DetectResult]] = []
17
- for p in _providers():
18
- res = p.detect(path)
16
+ matches: list[tuple[type[Provider], DetectResult]] = []
17
+ for provider_cls in _providers():
18
+ res = provider_cls.detect(path)
19
19
  if res:
20
- matches.append((p, res))
20
+ matches.append((provider_cls, res))
21
21
  if not matches:
22
- # Default to static site as the safest fallback
23
- from shipit.providers.staticfile import StaticFileProvider
24
-
25
- return StaticFileProvider()
22
+ raise Exception("Shipit could not detect a provider for this project")
26
23
  # Highest score wins; tie-breaker by order
27
24
  matches.sort(key=lambda x: x[1].score, reverse=True)
28
25
  return matches[0][0]
@@ -80,20 +77,20 @@ def _render_assets(assets: Optional[Dict[str, str]]) -> Optional[str]:
80
77
 
81
78
 
82
79
  def generate_shipit(path: Path) -> str:
83
- provider = detect_provider(path)
84
- provider.initialize(path)
80
+ provider_cls = detect_provider(path)
81
+ provider = provider_cls(path)
85
82
 
86
83
  # Collect parts
87
84
  plan = ProviderPlan(
88
- serve_name=provider.serve_name(path),
89
- provider=provider.provider_kind(path),
90
- mounts=provider.mounts(path),
91
- declarations=provider.declarations(path),
92
- dependencies=provider.dependencies(path),
93
- build_steps=provider.build_steps(path),
94
- prepare=provider.prepare_steps(path),
95
- commands=provider.commands(path),
96
- env=provider.env(path),
85
+ serve_name=provider.serve_name(),
86
+ provider=provider.provider_kind(),
87
+ mounts=provider.mounts(),
88
+ declarations=provider.declarations(),
89
+ dependencies=provider.dependencies(),
90
+ build_steps=provider.build_steps(),
91
+ prepare=provider.prepare_steps(),
92
+ commands=provider.commands(),
93
+ env=provider.env(),
97
94
  )
98
95
 
99
96
  # Declare dependency variables (combined) and collect serve deps
@@ -12,21 +12,24 @@ class DetectResult:
12
12
 
13
13
 
14
14
  class Provider(Protocol):
15
- def name(self) -> str: ...
16
- def detect(self, path: Path) -> Optional[DetectResult]: ...
17
- def initialize(self, path: Path) -> None: ...
18
- # Structured plan steps
19
- def serve_name(self, path: Path) -> str: ...
20
- def provider_kind(self, path: Path) -> str: ...
21
- def dependencies(self, path: Path) -> list["DependencySpec"]: ...
22
- def declarations(self, path: Path) -> Optional[str]: ...
23
- def build_steps(self, path: Path) -> list[str]: ...
15
+ def __init__(self, path: Path): ...
16
+ @classmethod
17
+ def name(cls) -> str: ...
18
+ @classmethod
19
+ def detect(cls, path: Path) -> Optional[DetectResult]: ...
20
+ def initialize(self) -> None: ...
21
+ # Structured plan steps (no path args; use self.path)
22
+ def serve_name(self) -> str: ...
23
+ def provider_kind(self) -> str: ...
24
+ def dependencies(self) -> list["DependencySpec"]: ...
25
+ def declarations(self) -> Optional[str]: ...
26
+ def build_steps(self) -> list[str]: ...
24
27
  # Prepare: list of Starlark step calls (currently only run(...))
25
- def prepare_steps(self, path: Path) -> Optional[List[str]]: ...
26
- def commands(self, path: Path) -> Dict[str, str]: ...
27
- def assets(self, path: Path) -> Optional[Dict[str, str]]: ...
28
- def mounts(self, path: Path) -> List["MountSpec"]: ...
29
- def env(self, path: Path) -> Optional[Dict[str, str]]: ...
28
+ def prepare_steps(self) -> Optional[List[str]]: ...
29
+ def commands(self) -> Dict[str, str]: ...
30
+ def assets(self) -> Optional[Dict[str, str]]: ...
31
+ def mounts(self) -> List["MountSpec"]: ...
32
+ def env(self) -> Optional[Dict[str, str]]: ...
30
33
 
31
34
 
32
35
  @dataclass
@@ -7,32 +7,36 @@ from .base import DetectResult, DependencySpec, Provider, _exists, _has_dependen
7
7
 
8
8
 
9
9
  class GatsbyProvider:
10
- def name(self) -> str:
10
+ def __init__(self, path: Path):
11
+ self.path = path
12
+ @classmethod
13
+ def name(cls) -> str:
11
14
  return "gatsby"
12
15
 
13
- def detect(self, path: Path) -> Optional[DetectResult]:
16
+ @classmethod
17
+ def detect(cls, path: Path) -> Optional[DetectResult]:
14
18
  pkg = path / "package.json"
15
19
  if not pkg.exists():
16
20
  return None
17
21
  if _exists(path, "gatsby-config.js", "gatsby-config.ts") or _has_dependency(
18
22
  pkg, "gatsby"
19
23
  ):
20
- return DetectResult(self.name(), 90)
24
+ return DetectResult(cls.name(), 90)
21
25
  return None
22
26
 
23
- def initialize(self, path: Path) -> None:
27
+ def initialize(self) -> None:
24
28
  pass
25
29
 
26
- def serve_name(self, path: Path) -> str:
27
- return path.name
30
+ def serve_name(self) -> str:
31
+ return self.path.name
28
32
 
29
- def provider_kind(self, path: Path) -> str:
33
+ def provider_kind(self) -> str:
30
34
  return "staticsite"
31
35
 
32
- def declarations(self, path: Path) -> Optional[str]:
36
+ def declarations(self) -> Optional[str]:
33
37
  return None
34
38
 
35
- def dependencies(self, path: Path) -> list[DependencySpec]:
39
+ def dependencies(self) -> list[DependencySpec]:
36
40
  return [
37
41
  DependencySpec(
38
42
  "node",
@@ -44,7 +48,7 @@ class GatsbyProvider:
44
48
  DependencySpec("static-web-server", env_var="SHIPIT_SWS_VERSION", use_in_serve=True),
45
49
  ]
46
50
 
47
- def build_steps(self, path: Path) -> list[str]:
51
+ def build_steps(self) -> list[str]:
48
52
  return [
49
53
  "run(\"npm install\", inputs=[\"package.json\", \"package-lock.json\"], group=\"install\")",
50
54
  "copy(\".\", \".\", ignore=[\"node_modules\", \".git\"])",
@@ -52,17 +56,17 @@ class GatsbyProvider:
52
56
  "run(\"cp -R public/* {}/\".format(app[\"build\"]))",
53
57
  ]
54
58
 
55
- def prepare_steps(self, path: Path) -> Optional[list[str]]:
59
+ def prepare_steps(self) -> Optional[list[str]]:
56
60
  return None
57
61
 
58
- def commands(self, path: Path) -> Dict[str, str]:
62
+ def commands(self) -> Dict[str, str]:
59
63
  return {"start": '"static-web-server --root /app"'}
60
64
 
61
- def assets(self, path: Path) -> Optional[Dict[str, str]]:
65
+ def assets(self) -> Optional[Dict[str, str]]:
62
66
  return None
63
67
 
64
- def mounts(self, path: Path) -> list[MountSpec]:
68
+ def mounts(self) -> list[MountSpec]:
65
69
  return [MountSpec("app")]
66
70
 
67
- def env(self, path: Path) -> Optional[Dict[str, str]]:
71
+ def env(self) -> Optional[Dict[str, str]]:
68
72
  return None
@@ -7,27 +7,29 @@ from .base import DetectResult, DependencySpec, Provider, _exists
7
7
  from .staticfile import StaticFileProvider
8
8
 
9
9
  class HugoProvider(StaticFileProvider):
10
- def name(self) -> str:
10
+ @classmethod
11
+ def name(cls) -> str:
11
12
  return "hugo"
12
13
 
13
- def detect(self, path: Path) -> Optional[DetectResult]:
14
+ @classmethod
15
+ def detect(cls, path: Path) -> Optional[DetectResult]:
14
16
  if _exists(path, "hugo.toml", "hugo.json", "hugo.yaml", "hugo.yml"):
15
- return DetectResult(self.name(), 80)
17
+ return DetectResult(cls.name(), 80)
16
18
  if (
17
19
  _exists(path, "config.toml", "config.json", "config.yaml", "config.yml")
18
20
  and _exists(path, "content")
19
21
  and (_exists(path, "static") or _exists(path, "themes"))
20
22
  ):
21
- return DetectResult(self.name(), 40)
23
+ return DetectResult(cls.name(), 40)
22
24
  return None
23
25
 
24
- def serve_name(self, path: Path) -> str:
25
- return path.name
26
+ def serve_name(self) -> str:
27
+ return self.path.name
26
28
 
27
- def provider_kind(self, path: Path) -> str:
29
+ def provider_kind(self) -> str:
28
30
  return "staticsite"
29
31
 
30
- def dependencies(self, path: Path) -> list[DependencySpec]:
32
+ def dependencies(self) -> list[DependencySpec]:
31
33
  return [
32
34
  DependencySpec(
33
35
  "hugo",
@@ -35,10 +37,10 @@ class HugoProvider(StaticFileProvider):
35
37
  default_version="0.149.0",
36
38
  use_in_build=True,
37
39
  ),
38
- *super().dependencies(path),
40
+ *super().dependencies(),
39
41
  ]
40
42
 
41
- def build_steps(self, path: Path) -> list[str]:
43
+ def build_steps(self) -> list[str]:
42
44
  return [
43
45
  'copy(".", ".", ignore=[".git"])',
44
46
  'run("hugo build --destination={}".format(app["build"]), group="build")',
@@ -7,24 +7,28 @@ from .base import DetectResult, DependencySpec, Provider, _exists, MountSpec
7
7
 
8
8
 
9
9
  class LaravelProvider:
10
- def name(self) -> str:
10
+ def __init__(self, path: Path):
11
+ self.path = path
12
+ @classmethod
13
+ def name(cls) -> str:
11
14
  return "laravel"
12
15
 
13
- def detect(self, path: Path) -> Optional[DetectResult]:
16
+ @classmethod
17
+ def detect(cls, path: Path) -> Optional[DetectResult]:
14
18
  if _exists(path, "artisan") and _exists(path, "composer.json"):
15
- return DetectResult(self.name(), 95)
19
+ return DetectResult(cls.name(), 95)
16
20
  return None
17
21
 
18
- def initialize(self, path: Path) -> None:
22
+ def initialize(self) -> None:
19
23
  pass
20
24
 
21
- def serve_name(self, path: Path) -> str:
22
- return path.name
25
+ def serve_name(self) -> str:
26
+ return self.path.name
23
27
 
24
- def provider_kind(self, path: Path) -> str:
28
+ def provider_kind(self) -> str:
25
29
  return "php"
26
30
 
27
- def dependencies(self, path: Path) -> list[DependencySpec]:
31
+ def dependencies(self) -> list[DependencySpec]:
28
32
  return [
29
33
  DependencySpec(
30
34
  "php",
@@ -39,10 +43,10 @@ class LaravelProvider:
39
43
  DependencySpec("bash", use_in_serve=True),
40
44
  ]
41
45
 
42
- def declarations(self, path: Path) -> Optional[str]:
46
+ def declarations(self) -> Optional[str]:
43
47
  return "HOME = getenv(\"HOME\")"
44
48
 
45
- def build_steps(self, path: Path) -> list[str]:
49
+ def build_steps(self) -> list[str]:
46
50
  return [
47
51
  "env(HOME=HOME, COMPOSER_FUND=\"0\")",
48
52
  "workdir(app[\"build\"])",
@@ -53,7 +57,7 @@ class LaravelProvider:
53
57
  "run(\"pnpm run build\", outputs=[\".\"], group=\"build\")",
54
58
  ]
55
59
 
56
- def prepare_steps(self, path: Path) -> Optional[list[str]]:
60
+ def prepare_steps(self) -> Optional[list[str]]:
57
61
  return [
58
62
  'workdir(app["serve"])',
59
63
  'run("mkdir -p storage/framework/{sessions,views,cache,testing} storage/logs bootstrap/cache")',
@@ -63,17 +67,17 @@ class LaravelProvider:
63
67
  'run("php artisan view:cache")',
64
68
  ]
65
69
 
66
- def commands(self, path: Path) -> Dict[str, str]:
70
+ def commands(self) -> Dict[str, str]:
67
71
  return {
68
72
  "start": '"php -S localhost:8080 -t public"',
69
73
  "after_deploy": '"php artisan migrate"',
70
74
  }
71
75
 
72
- def assets(self, path: Path) -> Optional[Dict[str, str]]:
76
+ def assets(self) -> Optional[Dict[str, str]]:
73
77
  return None
74
78
 
75
- def mounts(self, path: Path) -> list[MountSpec]:
79
+ def mounts(self) -> list[MountSpec]:
76
80
  return [MountSpec("app")]
77
81
 
78
- def env(self, path: Path) -> Optional[Dict[str, str]]:
82
+ def env(self) -> Optional[Dict[str, str]]:
79
83
  return None
@@ -7,24 +7,28 @@ from .base import DetectResult, DependencySpec, Provider, _exists, MountSpec
7
7
 
8
8
 
9
9
  class MkdocsProvider:
10
- def name(self) -> str:
10
+ def __init__(self, path: Path):
11
+ self.path = path
12
+ @classmethod
13
+ def name(cls) -> str:
11
14
  return "mkdocs"
12
15
 
13
- def detect(self, path: Path) -> Optional[DetectResult]:
16
+ @classmethod
17
+ def detect(cls, path: Path) -> Optional[DetectResult]:
14
18
  if _exists(path, "mkdocs.yml", "mkdocs.yaml"):
15
- return DetectResult(self.name(), 85)
19
+ return DetectResult(cls.name(), 85)
16
20
  return None
17
21
 
18
- def initialize(self, path: Path) -> None:
22
+ def initialize(self) -> None:
19
23
  pass
20
24
 
21
- def serve_name(self, path: Path) -> str:
22
- return path.name
25
+ def serve_name(self) -> str:
26
+ return self.path.name
23
27
 
24
- def provider_kind(self, path: Path) -> str:
28
+ def provider_kind(self) -> str:
25
29
  return "mkdocs-site"
26
30
 
27
- def dependencies(self, path: Path) -> list[DependencySpec]:
31
+ def dependencies(self) -> list[DependencySpec]:
28
32
  return [
29
33
  DependencySpec(
30
34
  "python",
@@ -46,11 +50,11 @@ class MkdocsProvider:
46
50
  ),
47
51
  ]
48
52
 
49
- def declarations(self, path: Path) -> Optional[str]:
53
+ def declarations(self) -> Optional[str]:
50
54
  return None
51
55
 
52
- def build_steps(self, path: Path) -> list[str]:
53
- has_requirements = _exists(path, "requirements.txt")
56
+ def build_steps(self) -> list[str]:
57
+ has_requirements = _exists(self.path, "requirements.txt")
54
58
  if has_requirements:
55
59
  install_lines = [
56
60
  "run(\"uv init --no-managed-python\", inputs=[], outputs=[\".\"], group=\"install\")",
@@ -68,17 +72,17 @@ class MkdocsProvider:
68
72
  "run(\"uv run mkdocs build --site-dir={}\".format(app[\"build\"]), outputs=[\".\"], group=\"build\")",
69
73
  ]
70
74
 
71
- def prepare_steps(self, path: Path) -> Optional[list[str]]:
75
+ def prepare_steps(self) -> Optional[list[str]]:
72
76
  return None
73
77
 
74
- def commands(self, path: Path) -> Dict[str, str]:
78
+ def commands(self) -> Dict[str, str]:
75
79
  return {"start": '"static-web-server --root /app"'}
76
80
 
77
- def assets(self, path: Path) -> Optional[Dict[str, str]]:
81
+ def assets(self) -> Optional[Dict[str, str]]:
78
82
  return None
79
83
 
80
- def mounts(self, path: Path) -> list[MountSpec]:
84
+ def mounts(self) -> list[MountSpec]:
81
85
  return [MountSpec("app")]
82
86
 
83
- def env(self, path: Path) -> Optional[Dict[str, str]]:
87
+ def env(self) -> Optional[Dict[str, str]]:
84
88
  return None
@@ -7,28 +7,32 @@ from .base import DetectResult, DependencySpec, Provider, _exists, _has_dependen
7
7
 
8
8
 
9
9
  class NodeStaticProvider:
10
- def name(self) -> str:
10
+ def __init__(self, path: Path):
11
+ self.path = path
12
+ @classmethod
13
+ def name(cls) -> str:
11
14
  return "node-static"
12
15
 
13
- def detect(self, path: Path) -> Optional[DetectResult]:
16
+ @classmethod
17
+ def detect(cls, path: Path) -> Optional[DetectResult]:
14
18
  pkg = path / "package.json"
15
19
  if not pkg.exists():
16
20
  return None
17
21
  static_generators = ["astro", "vite", "next", "nuxt"]
18
22
  if any(_has_dependency(pkg, dep) for dep in static_generators):
19
- return DetectResult(self.name(), 40)
23
+ return DetectResult(cls.name(), 40)
20
24
  return None
21
25
 
22
- def initialize(self, path: Path) -> None:
26
+ def initialize(self) -> None:
23
27
  pass
24
28
 
25
- def serve_name(self, path: Path) -> str:
26
- return path.name
29
+ def serve_name(self) -> str:
30
+ return self.path.name
27
31
 
28
- def provider_kind(self, path: Path) -> str:
32
+ def provider_kind(self) -> str:
29
33
  return "staticsite"
30
34
 
31
- def dependencies(self, path: Path) -> list[DependencySpec]:
35
+ def dependencies(self) -> list[DependencySpec]:
32
36
  return [
33
37
  DependencySpec(
34
38
  "node",
@@ -40,11 +44,11 @@ class NodeStaticProvider:
40
44
  DependencySpec("static-web-server", use_in_serve=True),
41
45
  ]
42
46
 
43
- def declarations(self, path: Path) -> Optional[str]:
47
+ def declarations(self) -> Optional[str]:
44
48
  return None
45
49
 
46
- def build_steps(self, path: Path) -> list[str]:
47
- output_dir = "dist" if (path / "dist").exists() else "public"
50
+ def build_steps(self) -> list[str]:
51
+ output_dir = "dist" if (self.path / "dist").exists() else "public"
48
52
  return [
49
53
  "run(\"npm install\", inputs=[\"package.json\", \"package-lock.json\"], group=\"install\")",
50
54
  "copy(\".\", \".\", ignore=[\"node_modules\", \".git\"])",
@@ -52,18 +56,18 @@ class NodeStaticProvider:
52
56
  f"run(\"cp -R {output_dir}/* {{}}/\".format(app[\"build\"]))",
53
57
  ]
54
58
 
55
- def prepare_steps(self, path: Path) -> Optional[list[str]]:
59
+ def prepare_steps(self) -> Optional[list[str]]:
56
60
  return None
57
61
 
58
- def commands(self, path: Path) -> Dict[str, str]:
59
- output_dir = "dist" if (path / "dist").exists() else "public"
62
+ def commands(self) -> Dict[str, str]:
63
+ output_dir = "dist" if (self.path / "dist").exists() else "public"
60
64
  return {"start": f'"static-web-server --root /app/{output_dir}"'}
61
65
 
62
- def assets(self, path: Path) -> Optional[Dict[str, str]]:
66
+ def assets(self) -> Optional[Dict[str, str]]:
63
67
  return None
64
68
 
65
- def mounts(self, path: Path) -> list[MountSpec]:
69
+ def mounts(self) -> list[MountSpec]:
66
70
  return [MountSpec("app")]
67
71
 
68
- def env(self, path: Path) -> Optional[Dict[str, str]]:
72
+ def env(self) -> Optional[Dict[str, str]]:
69
73
  return None
@@ -7,29 +7,33 @@ from .base import DetectResult, DependencySpec, Provider, _exists, MountSpec
7
7
 
8
8
 
9
9
  class PhpProvider:
10
- def name(self) -> str:
10
+ def __init__(self, path: Path):
11
+ self.path = path
12
+ @classmethod
13
+ def name(cls) -> str:
11
14
  return "php"
12
15
 
13
- def detect(self, path: Path) -> Optional[DetectResult]:
16
+ @classmethod
17
+ def detect(cls, path: Path) -> Optional[DetectResult]:
14
18
  if _exists(path, "composer.json") and _exists(path, "public/index.php"):
15
- return DetectResult(self.name(), 60)
19
+ return DetectResult(cls.name(), 60)
16
20
  if _exists(path, "index.php") and not _exists(path, "composer.json"):
17
- return DetectResult(self.name(), 10)
21
+ return DetectResult(cls.name(), 10)
18
22
  return None
19
23
 
20
- def initialize(self, path: Path) -> None:
24
+ def initialize(self) -> None:
21
25
  pass
22
26
 
23
- def serve_name(self, path: Path) -> str:
24
- return path.name
27
+ def serve_name(self) -> str:
28
+ return self.path.name
25
29
 
26
- def provider_kind(self, path: Path) -> str:
30
+ def provider_kind(self) -> str:
27
31
  return "php"
28
32
 
29
- def has_composer(self, path: Path) -> bool:
30
- return _exists(path, "composer.json", "composer.lock")
33
+ def has_composer(self) -> bool:
34
+ return _exists(self.path, "composer.json", "composer.lock")
31
35
 
32
- def dependencies(self, path: Path) -> list[DependencySpec]:
36
+ def dependencies(self) -> list[DependencySpec]:
33
37
  deps = [
34
38
  DependencySpec(
35
39
  "php",
@@ -39,40 +43,40 @@ class PhpProvider:
39
43
  use_in_serve=True,
40
44
  ),
41
45
  ]
42
- if self.has_composer(path):
46
+ if self.has_composer():
43
47
  deps.append(DependencySpec("composer", use_in_build=True))
44
48
  deps.append(DependencySpec("bash", use_in_serve=True))
45
49
  return deps
46
50
 
47
- def declarations(self, path: Path) -> Optional[str]:
51
+ def declarations(self) -> Optional[str]:
48
52
  return "HOME = getenv(\"HOME\")"
49
53
 
50
- def build_steps(self, path: Path) -> list[str]:
54
+ def build_steps(self) -> list[str]:
51
55
  steps = [
52
56
  "workdir(app[\"build\"])",
53
57
  ]
54
58
 
55
- if self.has_composer(path):
59
+ if self.has_composer():
56
60
  steps.append("env(HOME=HOME, COMPOSER_FUND=\"0\")")
57
61
  steps.append("run(\"composer install --optimize-autoloader --no-scripts --no-interaction\", inputs=[\"composer.json\", \"composer.lock\"], outputs=[\".\"], group=\"install\")")
58
62
 
59
63
  steps.append("copy(\".\", \".\", ignore=[\".git\"])")
60
64
  return steps
61
65
 
62
- def prepare_steps(self, path: Path) -> Optional[list[str]]:
66
+ def prepare_steps(self) -> Optional[list[str]]:
63
67
  return None
64
68
 
65
- def commands(self, path: Path) -> Dict[str, str]:
66
- if _exists(path, "public/index.php"):
69
+ def commands(self) -> Dict[str, str]:
70
+ if _exists(self.path, "public/index.php"):
67
71
  return {"start": '"php -S localhost:8080 -t public"'}
68
- elif _exists(path, "index.php"):
72
+ elif _exists(self.path, "index.php"):
69
73
  return {"start": '"php -S localhost:8080" -t .'}
70
74
 
71
- def assets(self, path: Path) -> Optional[Dict[str, str]]:
75
+ def assets(self) -> Optional[Dict[str, str]]:
72
76
  return {"php.ini": "get_asset(\"php/php.ini\")"}
73
77
 
74
- def mounts(self, path: Path) -> list[MountSpec]:
78
+ def mounts(self) -> list[MountSpec]:
75
79
  return [MountSpec("app")]
76
80
 
77
- def env(self, path: Path) -> Optional[Dict[str, str]]:
81
+ def env(self) -> Optional[Dict[str, str]]:
78
82
  return None
@@ -13,28 +13,32 @@ from .base import (
13
13
 
14
14
 
15
15
  class PythonProvider:
16
- def name(self) -> str:
16
+ def __init__(self, path: Path):
17
+ self.path = path
18
+ @classmethod
19
+ def name(cls) -> str:
17
20
  return "python"
18
21
 
19
- def detect(self, path: Path) -> Optional[DetectResult]:
22
+ @classmethod
23
+ def detect(cls, path: Path) -> Optional[DetectResult]:
20
24
  if _exists(path, "pyproject.toml", "requirements.txt"):
21
25
  if _exists(path, "manage.py"):
22
- return DetectResult(self.name(), 70)
23
- return DetectResult(self.name(), 50)
26
+ return DetectResult(cls.name(), 70)
27
+ return DetectResult(cls.name(), 50)
24
28
  return None
25
29
 
26
- def initialize(self, path: Path) -> None:
30
+ def initialize(self) -> None:
27
31
  pass
28
32
 
29
- def serve_name(self, path: Path) -> str:
30
- return path.name
33
+ def serve_name(self) -> str:
34
+ return self.path.name
31
35
 
32
- def provider_kind(self, path: Path) -> str:
36
+ def provider_kind(self) -> str:
33
37
  return "python"
34
38
 
35
- def dependencies(self, path: Path) -> list[DependencySpec]:
36
- if _exists(path, ".python-version"):
37
- python_version = (path / ".python-version").read_text().strip()
39
+ def dependencies(self) -> list[DependencySpec]:
40
+ if _exists(self.path, ".python-version"):
41
+ python_version = (self.path / ".python-version").read_text().strip()
38
42
  else:
39
43
  python_version = "3.13"
40
44
 
@@ -54,7 +58,7 @@ class PythonProvider:
54
58
  ),
55
59
  ]
56
60
 
57
- def declarations(self, path: Path) -> Optional[str]:
61
+ def declarations(self) -> Optional[str]:
58
62
  return (
59
63
  "cross_platform = getenv(\"SHIPIT_PYTHON_CROSS_PLATFORM\")\n"
60
64
  "python_extra_index_url = getenv(\"SHIPIT_PYTHON_EXTRA_INDEX_URL\")\n"
@@ -62,24 +66,26 @@ class PythonProvider:
62
66
  "python_cross_packages_path = venv[\"build\"] + f\"/lib/python{python_version}/site-packages\""
63
67
  )
64
68
 
65
- def build_steps(self, path: Path) -> list[str]:
69
+ def build_steps(self) -> list[str]:
66
70
  steps = [
67
71
  "workdir(app[\"build\"])"
68
72
  ]
69
73
 
70
- if _exists(path, "pyproject.toml"):
74
+ if _exists(self.path, "pyproject.toml"):
71
75
  input_files = ["pyproject.toml"]
72
- if _exists(path, "uv.lock"):
76
+ extra_args = ""
77
+ if _exists(self.path, "uv.lock"):
73
78
  input_files.append("uv.lock")
79
+ extra_args = " --locked"
74
80
  inputs = ", ".join([f"\"{input}\"" for input in input_files])
75
81
  steps += [
76
82
  "env(UV_PROJECT_ENVIRONMENT=local_venv[\"build\"] if cross_platform else venv[\"build\"])",
77
- "run(f\"uv sync --compile --python python{python_version} --locked --no-managed-python\", inputs=[" + inputs + "], group=\"install\")",
83
+ "run(f\"uv sync --compile --python python{python_version} --no-managed-python" + extra_args + "\", inputs=[" + inputs + "], group=\"install\")",
78
84
  "run(f\"uv pip compile pyproject.toml --python-version={python_version} --universal --extra-index-url {python_extra_index_url} --index-url=https://pypi.org/simple --emit-index-url --only-binary :all: -o cross-requirements.txt\", inputs=[\"pyproject.toml\"], outputs=[\"cross-requirements.txt\"]) if cross_platform else None",
79
85
  "run(f\"uvx pip install -r cross-requirements.txt --target {python_cross_packages_path} --platform {cross_platform} --only-binary=:all: --python-version={python_version} --compile\") if cross_platform else None",
80
86
  "run(\"rm cross-requirements.txt\") if cross_platform else None",
81
87
  ]
82
- if _exists(path, "requirements.txt"):
88
+ if _exists(self.path, "requirements.txt"):
83
89
  steps += [
84
90
  "env(UV_PROJECT_ENVIRONMENT=local_venv[\"build\"] if cross_platform else venv[\"build\"])",
85
91
  "run(f\"uv init --no-managed-python --python python{python_version}\", inputs=[], outputs=[\"uv.lock\"], group=\"install\")",
@@ -95,38 +101,39 @@ class PythonProvider:
95
101
  ]
96
102
  return steps
97
103
 
98
- def prepare_steps(self, path: Path) -> Optional[list[str]]:
104
+ def prepare_steps(self) -> Optional[list[str]]:
99
105
  return [
106
+ 'workdir(app["serve"])',
100
107
  'run("echo \\\"Precompiling Python code...\\\"") if precompile_python else None',
101
108
  'run("python -m compileall -o 2 $PYTHONPATH") if precompile_python else None',
102
109
  'run("echo \\\"Precompiling package code...\\\"") if precompile_python else None',
103
110
  'run("python -m compileall -o 2 .") if precompile_python else None',
104
111
  ]
105
112
 
106
- def commands(self, path: Path) -> Dict[str, str]:
107
- if _exists(path, "manage.py"):
113
+ def commands(self) -> Dict[str, str]:
114
+ if _exists(self.path, "manage.py"):
108
115
  start_cmd = '"python manage.py runserver 0.0.0.0:8000"'
109
116
  migrate_cmd = '"python manage.py migrate"'
110
117
  return {"start": start_cmd, "after_deploy": migrate_cmd}
111
- elif _exists(path, "main.py"):
118
+ elif _exists(self.path, "main.py"):
112
119
  start_cmd = '"python main.py"'
113
- elif _exists(path, "src/main.py"):
120
+ elif _exists(self.path, "src/main.py"):
114
121
  start_cmd = '"python src/main.py"'
115
122
  else:
116
123
  start_cmd = '"python -c \'print(\\\"Hello, World!\\\")\'"'
117
124
  return {"start": start_cmd}
118
125
 
119
- def assets(self, path: Path) -> Optional[Dict[str, str]]:
126
+ def assets(self) -> Optional[Dict[str, str]]:
120
127
  return None
121
128
 
122
- def mounts(self, path: Path) -> list[MountSpec]:
129
+ def mounts(self) -> list[MountSpec]:
123
130
  return [
124
131
  MountSpec("app"),
125
132
  MountSpec("venv"),
126
133
  MountSpec("local_venv", attach_to_serve=False),
127
134
  ]
128
135
 
129
- def env(self, path: Path) -> Optional[Dict[str, str]]:
136
+ def env(self) -> Optional[Dict[str, str]]:
130
137
  # For Django projects, generate an empty env dict to surface the field
131
138
  # in the Shipit file. Other Python projects omit it by default.
132
139
  return {
@@ -11,16 +11,15 @@ from .python import PythonProvider
11
11
  from .staticfile import StaticFileProvider
12
12
 
13
13
 
14
- def providers() -> list[Provider]:
14
+ def providers() -> list[type[Provider]]:
15
15
  # Order matters: more specific providers first
16
16
  return [
17
- LaravelProvider(),
18
- GatsbyProvider(),
19
- HugoProvider(),
20
- MkdocsProvider(),
21
- PythonProvider(),
22
- PhpProvider(),
23
- NodeStaticProvider(),
24
- StaticFileProvider(),
17
+ LaravelProvider,
18
+ GatsbyProvider,
19
+ HugoProvider,
20
+ MkdocsProvider,
21
+ PythonProvider,
22
+ PhpProvider,
23
+ NodeStaticProvider,
24
+ StaticFileProvider,
25
25
  ]
26
-
@@ -7,28 +7,33 @@ from .base import DetectResult, DependencySpec, Provider, _exists, MountSpec
7
7
 
8
8
 
9
9
  class StaticFileProvider:
10
- def name(self) -> str:
10
+ def __init__(self, path: Path):
11
+ self.path = path
12
+
13
+ @classmethod
14
+ def name(cls) -> str:
11
15
  return "staticfile"
12
16
 
13
- def detect(self, path: Path) -> Optional[DetectResult]:
17
+ @classmethod
18
+ def detect(cls, path: Path) -> Optional[DetectResult]:
14
19
  if _exists(path, "Staticfile"):
15
- return DetectResult(self.name(), 50)
20
+ return DetectResult(cls.name(), 50)
16
21
  if _exists(path, "index.html") and not _exists(
17
22
  path, "package.json", "pyproject.toml", "composer.json"
18
23
  ):
19
- return DetectResult(self.name(), 10)
24
+ return DetectResult(cls.name(), 10)
20
25
  return None
21
26
 
22
- def initialize(self, path: Path) -> None:
27
+ def initialize(self) -> None:
23
28
  pass
24
29
 
25
- def serve_name(self, path: Path) -> str:
26
- return path.name
30
+ def serve_name(self) -> str:
31
+ return self.path.name
27
32
 
28
- def provider_kind(self, path: Path) -> str:
33
+ def provider_kind(self) -> str:
29
34
  return "staticfile"
30
35
 
31
- def dependencies(self, path: Path) -> list[DependencySpec]:
36
+ def dependencies(self) -> list[DependencySpec]:
32
37
  return [
33
38
  DependencySpec(
34
39
  "static-web-server",
@@ -38,28 +43,28 @@ class StaticFileProvider:
38
43
  )
39
44
  ]
40
45
 
41
- def build_steps(self, path: Path) -> list[str]:
46
+ def build_steps(self) -> list[str]:
42
47
  return [
43
48
  'workdir(app["build"])',
44
49
  'copy(".", ".", ignore=[".git"])'
45
50
  ]
46
51
 
47
- def prepare_steps(self, path: Path) -> Optional[list[str]]:
52
+ def prepare_steps(self) -> Optional[list[str]]:
48
53
  return None
49
54
 
50
- def declarations(self, path: Path) -> Optional[str]:
55
+ def declarations(self) -> Optional[str]:
51
56
  return None
52
57
 
53
- def commands(self, path: Path) -> Dict[str, str]:
58
+ def commands(self) -> Dict[str, str]:
54
59
  return {
55
- "start": '"static-web-server --root=/app --log-level=info"'
60
+ "start": '"static-web-server --root={} --log-level=info".format(app["serve"])'
56
61
  }
57
62
 
58
- def assets(self, path: Path) -> Optional[Dict[str, str]]:
63
+ def assets(self) -> Optional[Dict[str, str]]:
59
64
  return None
60
65
 
61
- def mounts(self, path: Path) -> list[MountSpec]:
66
+ def mounts(self) -> list[MountSpec]:
62
67
  return [MountSpec("app")]
63
68
 
64
- def env(self, path: Path) -> Optional[Dict[str, str]]:
69
+ def env(self) -> Optional[Dict[str, str]]:
65
70
  return None
@@ -0,0 +1,5 @@
1
+ __all__ = ["version", "version_info"]
2
+
3
+
4
+ version = "0.3.4"
5
+ version_info = (0, 3, 4, "final", 0)
@@ -1,5 +0,0 @@
1
- __all__ = ["version", "version_info"]
2
-
3
-
4
- version = "0.3.2"
5
- version_info = (0, 3, 2, "final", 0)
File without changes
File without changes