shipit-cli 0.3.3__py3-none-any.whl → 0.3.4__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/generator.py CHANGED
@@ -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
shipit/providers/base.py CHANGED
@@ -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
shipit/providers/hugo.py CHANGED
@@ -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
shipit/providers/php.py CHANGED
@@ -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,7 +101,7 @@ 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 [
100
106
  'workdir(app["serve"])',
101
107
  'run("echo \\\"Precompiling Python code...\\\"") if precompile_python else None',
@@ -104,30 +110,30 @@ class PythonProvider:
104
110
  'run("python -m compileall -o 2 .") if precompile_python else None',
105
111
  ]
106
112
 
107
- def commands(self, path: Path) -> Dict[str, str]:
108
- if _exists(path, "manage.py"):
113
+ def commands(self) -> Dict[str, str]:
114
+ if _exists(self.path, "manage.py"):
109
115
  start_cmd = '"python manage.py runserver 0.0.0.0:8000"'
110
116
  migrate_cmd = '"python manage.py migrate"'
111
117
  return {"start": start_cmd, "after_deploy": migrate_cmd}
112
- elif _exists(path, "main.py"):
118
+ elif _exists(self.path, "main.py"):
113
119
  start_cmd = '"python main.py"'
114
- elif _exists(path, "src/main.py"):
120
+ elif _exists(self.path, "src/main.py"):
115
121
  start_cmd = '"python src/main.py"'
116
122
  else:
117
123
  start_cmd = '"python -c \'print(\\\"Hello, World!\\\")\'"'
118
124
  return {"start": start_cmd}
119
125
 
120
- def assets(self, path: Path) -> Optional[Dict[str, str]]:
126
+ def assets(self) -> Optional[Dict[str, str]]:
121
127
  return None
122
128
 
123
- def mounts(self, path: Path) -> list[MountSpec]:
129
+ def mounts(self) -> list[MountSpec]:
124
130
  return [
125
131
  MountSpec("app"),
126
132
  MountSpec("venv"),
127
133
  MountSpec("local_venv", attach_to_serve=False),
128
134
  ]
129
135
 
130
- def env(self, path: Path) -> Optional[Dict[str, str]]:
136
+ def env(self) -> Optional[Dict[str, str]]:
131
137
  # For Django projects, generate an empty env dict to surface the field
132
138
  # in the Shipit file. Other Python projects omit it by default.
133
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
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
shipit/version.py CHANGED
@@ -1,5 +1,5 @@
1
1
  __all__ = ["version", "version_info"]
2
2
 
3
3
 
4
- version = "0.3.3"
5
- version_info = (0, 3, 3, "final", 0)
4
+ version = "0.3.4"
5
+ version_info = (0, 3, 4, "final", 0)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shipit-cli
3
- Version: 0.3.3
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
@@ -0,0 +1,19 @@
1
+ shipit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ shipit/cli.py,sha256=extuf-zJzjddNXbQR5m-e_SfpdtJmL7WaFHSsBtZZqM,48402
3
+ shipit/generator.py,sha256=qU619Qa17nqERTC2kf0-TDUFUz4x5BQw9Wf6_wuJ0ow,5513
4
+ shipit/version.py,sha256=YaMLXH-p3IyMxUWoEEPfD6W-m8ydr8DTML_Nv8fy5HM,95
5
+ shipit/assets/php/php.ini,sha256=f4irndAjB4GuuouEImRkNV22Q-yw1KqR-43jAMDw730,2531
6
+ shipit/providers/base.py,sha256=a_5VA1tV4_QbH83yjPCTHsNR23EJT2CiKUpWA_pu_lo,2373
7
+ shipit/providers/gatsby.py,sha256=uwNjIJloS9JwKXqkbhihgdTTpJL4iL4bLCZ5kuzqqNs,2138
8
+ shipit/providers/hugo.py,sha256=tbn_1t_1AwXHk3-J6mGA2C0D7-3Wpzr-fKpDNhqHy2Q,1439
9
+ shipit/providers/laravel.py,sha256=rDpfx7RyF4sK0xxDAWefX0IiguU2xdgEXP2jJp1Jdzo,2777
10
+ shipit/providers/mkdocs.py,sha256=QJFNt7QWMvYbWeo7WjOgFVKGVcdUnUmUNfFbe4c8ThM,2812
11
+ shipit/providers/node_static.py,sha256=K55BXkNz4QXSXR2wdg5diP6HLpmksC70ph16zox7v6Y,2309
12
+ shipit/providers/php.py,sha256=Hmtv47K5qtYbQ3v9SSk-_KTNlhXedStg2MxhTTOK9ac,2594
13
+ shipit/providers/python.py,sha256=h6QZ9gDwQu2e-FaIVLrogHXpr6FwofhQZNFdZK0aw8A,6393
14
+ shipit/providers/registry.py,sha256=UisII1dr24ZxmDD8GnpTsyNwPN9W8MnAHQ1Px1iJ-OQ,661
15
+ shipit/providers/staticfile.py,sha256=Y4oqw6dNDU2crzcWQ5SEgnXHoDy0CXRntABwlgdf1mo,1827
16
+ shipit_cli-0.3.4.dist-info/METADATA,sha256=6EE4IOFyNKDiXZW6aN1Gww_ZUT_fz-heyN8GFMBdca4,462
17
+ shipit_cli-0.3.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
18
+ shipit_cli-0.3.4.dist-info/entry_points.txt,sha256=7AE1NjSrHaSDfbfsRRO50KKnHFTbB0Imsccd1WynzAQ,72
19
+ shipit_cli-0.3.4.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- shipit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- shipit/cli.py,sha256=extuf-zJzjddNXbQR5m-e_SfpdtJmL7WaFHSsBtZZqM,48402
3
- shipit/generator.py,sha256=iBkVcs44dd_xYKitM_zNVLnpiZ3KrV__xVswPMCZ97Y,5570
4
- shipit/version.py,sha256=m-Vgs5jnC0nfsmDfrP6scrIRgwcnv_Lkot6BIgxrNmw,95
5
- shipit/assets/php/php.ini,sha256=f4irndAjB4GuuouEImRkNV22Q-yw1KqR-43jAMDw730,2531
6
- shipit/providers/base.py,sha256=bqh1k7TSPJo7hOnxgdI6PIJmrqzQkZhgUoV0bbYIWrw,2403
7
- shipit/providers/gatsby.py,sha256=VUGhE7xtQJHsYzEzdkXi3n5mbpgg868wbUVOU4MWN5s,2173
8
- shipit/providers/hugo.py,sha256=CpkDw9LQWcUfWb1K64eEB1fTtj7OESoA1o3MqFhux7E,1456
9
- shipit/providers/laravel.py,sha256=4wSa0ByLrq87WhrAf04mOGVKz_xn8xtCaSYHpx0l7-0,2812
10
- shipit/providers/mkdocs.py,sha256=YIbSAaL2jDQtr8YteZmKjIbRMDWdoQgy6G2D6dfH1ws,2842
11
- shipit/providers/node_static.py,sha256=Zpq4fRCMBzGkObdsfPVAoYUAnZSqE9C1D0aaJyI30Fc,2334
12
- shipit/providers/php.py,sha256=HxxgfXmA0U6PeTLyFMbyXWm05G_IQqdFz4Liq1d_VBM,2635
13
- shipit/providers/python.py,sha256=p4hIE0vXmNiqR2gbneUhYjtQVJ2HqKuirwudSuEQm9A,6311
14
- shipit/providers/registry.py,sha256=V6CAOK5gEX0RhWhr-lcAkvlwRuMom7YY2ZeAyRy1Eck,672
15
- shipit/providers/staticfile.py,sha256=DDA4dMHQesYu0AfZEWBHqfk4Ib8GFrkpmvcsnwJkqH4,1862
16
- shipit_cli-0.3.3.dist-info/METADATA,sha256=zILxyeA1OSaxuXMFfFoNieT_khB1YYi8xfd8MwmDB9c,462
17
- shipit_cli-0.3.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
18
- shipit_cli-0.3.3.dist-info/entry_points.txt,sha256=7AE1NjSrHaSDfbfsRRO50KKnHFTbB0Imsccd1WynzAQ,72
19
- shipit_cli-0.3.3.dist-info/RECORD,,