krickstart 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
devspeed/__init__.py ADDED
@@ -0,0 +1,15 @@
1
+ """Legacy compatibility package alias for Slipway."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import warnings
6
+
7
+ from slipway import PLUGIN_API_VERSION, StackPlugin, __version__
8
+
9
+ warnings.warn(
10
+ "'devspeed' has been renamed to 'slipway'. Please update imports to 'slipway'.",
11
+ DeprecationWarning,
12
+ stacklevel=2,
13
+ )
14
+
15
+ __all__ = ["PLUGIN_API_VERSION", "StackPlugin", "__version__"]
devspeed/cli.py ADDED
@@ -0,0 +1,21 @@
1
+ """Backward-compatibility aliases for devspeed.cli."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from slipway.cli import (
6
+ GENERATED_COMPOSE,
7
+ GENERATED_ENV,
8
+ GENERATED_ENV_EXAMPLE,
9
+ build_parser,
10
+ deprecated_alias_main,
11
+ )
12
+ from slipway.cli import deprecated_alias_main as main
13
+
14
+ __all__ = [
15
+ "GENERATED_COMPOSE",
16
+ "GENERATED_ENV",
17
+ "GENERATED_ENV_EXAMPLE",
18
+ "build_parser",
19
+ "deprecated_alias_main",
20
+ "main",
21
+ ]
devspeed/config.py ADDED
@@ -0,0 +1,29 @@
1
+ """Backward-compatibility aliases for devspeed.config."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from slipway.config import (
6
+ CONFIG_FILENAME,
7
+ LEGACY_CONFIG_FILENAME,
8
+ DevspeedConfig,
9
+ LifecycleConfig,
10
+ ServiceConfig,
11
+ SlipwayConfig,
12
+ config_path,
13
+ load_config,
14
+ save_config,
15
+ validate_config,
16
+ )
17
+
18
+ __all__ = [
19
+ "CONFIG_FILENAME",
20
+ "LEGACY_CONFIG_FILENAME",
21
+ "DevspeedConfig",
22
+ "LifecycleConfig",
23
+ "ServiceConfig",
24
+ "SlipwayConfig",
25
+ "config_path",
26
+ "load_config",
27
+ "save_config",
28
+ "validate_config",
29
+ ]
@@ -0,0 +1,29 @@
1
+ """Core generation services for DevSpeed (legacy alias)."""
2
+
3
+ from slipway.core.compose_generator import (
4
+ DEFAULT_COMPOSE_FILENAME,
5
+ DEFAULT_ENV_FILENAME,
6
+ ComposeGenerationError,
7
+ ComposeGenerator,
8
+ ConfigValidationError,
9
+ GeneratedArtifacts,
10
+ GeneratorSettings,
11
+ OutputFileExistsError,
12
+ PluginResolutionError,
13
+ PortConflictError,
14
+ WriteResult,
15
+ )
16
+
17
+ __all__ = [
18
+ "DEFAULT_COMPOSE_FILENAME",
19
+ "DEFAULT_ENV_FILENAME",
20
+ "ComposeGenerationError",
21
+ "ComposeGenerator",
22
+ "ConfigValidationError",
23
+ "GeneratedArtifacts",
24
+ "GeneratorSettings",
25
+ "OutputFileExistsError",
26
+ "PluginResolutionError",
27
+ "PortConflictError",
28
+ "WriteResult",
29
+ ]
@@ -0,0 +1,3 @@
1
+ """Backward-compatibility aliases for devspeed.core.compose_generator."""
2
+
3
+ from slipway.core.compose_generator import * # noqa: F403
devspeed/errors.py ADDED
@@ -0,0 +1,29 @@
1
+ """Backward-compatibility aliases for devspeed.errors."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from slipway.errors import (
6
+ CommandFailedError,
7
+ ComposeNotFoundError,
8
+ ConfigNotFoundError,
9
+ ConfigValidationError,
10
+ DevspeedError,
11
+ DockerNotFoundError,
12
+ DockerNotRunningError,
13
+ PortConflictError,
14
+ SlipwayError,
15
+ UnknownStackError,
16
+ )
17
+
18
+ __all__ = [
19
+ "CommandFailedError",
20
+ "ComposeNotFoundError",
21
+ "ConfigNotFoundError",
22
+ "ConfigValidationError",
23
+ "DevspeedError",
24
+ "DockerNotFoundError",
25
+ "DockerNotRunningError",
26
+ "PortConflictError",
27
+ "SlipwayError",
28
+ "UnknownStackError",
29
+ ]
devspeed/plugin.py ADDED
@@ -0,0 +1,25 @@
1
+ """Backward-compatibility aliases for devspeed.plugin."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from slipway.plugin import (
6
+ ENTRY_POINT_GROUP,
7
+ PLUGIN_API_VERSION,
8
+ PluginError,
9
+ PluginRegistry,
10
+ StackPlugin,
11
+ builtin_registry,
12
+ discover_pypi_stack_packages,
13
+ pypi_package_metadata,
14
+ )
15
+
16
+ __all__ = [
17
+ "ENTRY_POINT_GROUP",
18
+ "PLUGIN_API_VERSION",
19
+ "PluginError",
20
+ "PluginRegistry",
21
+ "StackPlugin",
22
+ "builtin_registry",
23
+ "discover_pypi_stack_packages",
24
+ "pypi_package_metadata",
25
+ ]
@@ -0,0 +1,21 @@
1
+ """Public plugin API for DevSpeed."""
2
+
3
+ from devspeed.plugins.base import PLUGIN_API_VERSION, PluginError, StackPlugin
4
+ from devspeed.plugins.registry import (
5
+ ENTRY_POINT_GROUP,
6
+ PluginRegistry,
7
+ builtin_registry,
8
+ discover_pypi_stack_packages,
9
+ pypi_package_metadata,
10
+ )
11
+
12
+ __all__ = [
13
+ "ENTRY_POINT_GROUP",
14
+ "PLUGIN_API_VERSION",
15
+ "PluginError",
16
+ "PluginRegistry",
17
+ "StackPlugin",
18
+ "builtin_registry",
19
+ "discover_pypi_stack_packages",
20
+ "pypi_package_metadata",
21
+ ]
@@ -0,0 +1,7 @@
1
+ """Backward-compatibility aliases for devspeed.plugins.base."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from slipway.plugins.base import PLUGIN_API_VERSION, PluginError, StackPlugin
6
+
7
+ __all__ = ["PLUGIN_API_VERSION", "PluginError", "StackPlugin"]
@@ -0,0 +1,29 @@
1
+ """Backward-compatibility aliases for devspeed.plugins.registry."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from slipway.plugins.registry import (
6
+ ENTRY_POINT_GROUP,
7
+ LEGACY_ENTRY_POINT_GROUP,
8
+ PLUGIN_API_VERSION,
9
+ PluginError,
10
+ PluginFactory,
11
+ PluginRegistry,
12
+ StackPlugin,
13
+ builtin_registry,
14
+ discover_pypi_stack_packages,
15
+ pypi_package_metadata,
16
+ )
17
+
18
+ __all__ = [
19
+ "ENTRY_POINT_GROUP",
20
+ "LEGACY_ENTRY_POINT_GROUP",
21
+ "PLUGIN_API_VERSION",
22
+ "PluginError",
23
+ "PluginFactory",
24
+ "PluginRegistry",
25
+ "StackPlugin",
26
+ "builtin_registry",
27
+ "discover_pypi_stack_packages",
28
+ "pypi_package_metadata",
29
+ ]
@@ -0,0 +1,21 @@
1
+ """Backward-compatibility aliases for devspeed.stacks."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from slipway.stacks import (
6
+ STACKS,
7
+ PluginRegistry,
8
+ StackPlugin,
9
+ get_registry,
10
+ get_stack,
11
+ list_stacks,
12
+ )
13
+
14
+ __all__ = [
15
+ "STACKS",
16
+ "PluginRegistry",
17
+ "StackPlugin",
18
+ "get_registry",
19
+ "get_stack",
20
+ "list_stacks",
21
+ ]
@@ -0,0 +1,66 @@
1
+ """Shared rendering helpers for stack templates."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from collections.abc import Mapping
7
+ from typing import Any
8
+
9
+
10
+ def postgres_service_yaml(
11
+ postgres: Mapping[str, Any],
12
+ project: str,
13
+ *,
14
+ database_url: bool = False,
15
+ ) -> str:
16
+ """Render the common Postgres service and named volume block."""
17
+ database_line = ""
18
+ if database_url:
19
+ database_line = (
20
+ f" - DATABASE_URL=postgres://{postgres['user']}:{postgres['password']}"
21
+ f"@postgres:5432/{postgres['db']}\n"
22
+ )
23
+ return f"""\
24
+ postgres:
25
+ image: postgres:16-alpine
26
+ ports:
27
+ - \"127.0.0.1:{postgres["port"]}:5432\"
28
+
29
+ environment:
30
+ - POSTGRES_DB={postgres["db"]}
31
+ - POSTGRES_USER={postgres["user"]}
32
+ - POSTGRES_PASSWORD={postgres["password"]}
33
+ {database_line} volumes:
34
+ - {project}_pgdata:/var/lib/postgresql/data
35
+ healthcheck:
36
+ test: [\"CMD-SHELL\", \"pg_isready -U {postgres["user"]}\"]
37
+ interval: 3s
38
+ timeout: 3s
39
+ retries: 10
40
+
41
+
42
+ volumes:
43
+ {project}_pgdata:
44
+ """
45
+
46
+
47
+ def env_example(env_text: str) -> str:
48
+ """Mask common local credentials while preserving useful connection examples."""
49
+ masked = re.sub(r"(://[^:]+:)[^@]+@", r"\1<password>@", env_text)
50
+ return re.sub(r"(?m)^(POSTGRES_PASSWORD=).*$", r"\1<password>", masked)
51
+
52
+
53
+ def lifecycle_command(
54
+ config: Mapping[str, Any],
55
+ default_install: str,
56
+ default_dev: str,
57
+ ) -> str:
58
+ """Build the app command, allowing config to override lifecycle steps."""
59
+ lifecycle = config.get("lifecycle", {})
60
+ if not isinstance(lifecycle, Mapping):
61
+ lifecycle = {}
62
+ install = lifecycle.get("install", default_install)
63
+ dev = lifecycle.get("dev", default_dev)
64
+ if not isinstance(install, str) or not isinstance(dev, str):
65
+ raise TypeError("lifecycle.install and lifecycle.dev must be strings")
66
+ return f'sh -c "{install} && {dev}"'
@@ -0,0 +1,168 @@
1
+ """Django and Postgres stack plugin."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Mapping
6
+ from typing import Any
7
+
8
+ from devspeed.plugins.base import StackPlugin
9
+
10
+ from .common import lifecycle_command, postgres_service_yaml
11
+
12
+
13
+ class DjangoPostgresPlugin(StackPlugin):
14
+ """Provide a hot-reloading Django application with Postgres."""
15
+
16
+ @property
17
+ def name(self) -> str:
18
+ """Return the stable configuration identifier."""
19
+ return "django-postgres"
20
+
21
+ @property
22
+ def description(self) -> str:
23
+ """Return the stack description shown by the CLI."""
24
+ return "Django web app + Postgres"
25
+
26
+ def default_config(self, project_name: str) -> dict[str, Any]:
27
+ """Return defaults for a Django project."""
28
+ return {
29
+ "project": project_name,
30
+ "stack": self.name,
31
+ "lifecycle": {
32
+ "install": "pip install --no-cache-dir -r requirements.txt",
33
+ "dev": "python manage.py migrate --noinput && python manage.py runserver 0.0.0.0:8000",
34
+ },
35
+ "services": {
36
+ "app": {"port": 8000, "python_version": "3.12"},
37
+ "postgres": {
38
+ "port": 5432,
39
+ "db": project_name.replace("-", "_"),
40
+ "user": "devspeed",
41
+ "password": "devspeed",
42
+ },
43
+ },
44
+ }
45
+
46
+ def starter_files(self, config: Mapping[str, Any]) -> dict[str, str]:
47
+ """Return a minimal Django project for a new project."""
48
+ return {
49
+ "requirements.txt": "Django>=5.1,<6\npsycopg[binary]>=3.2,<4\n",
50
+ "manage.py": """import os
51
+ import sys
52
+
53
+
54
+ if __name__ == "__main__":
55
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
56
+ from django.core.management import execute_from_command_line
57
+ execute_from_command_line(sys.argv)
58
+ """,
59
+ "config/__init__.py": "",
60
+ "config/settings.py": """import os
61
+
62
+ SECRET_KEY = "devspeed-local-only"
63
+ DEBUG = True
64
+ ROOT_URLCONF = "config.urls"
65
+ ALLOWED_HOSTS = ["*"]
66
+ INSTALLED_APPS = ["django.contrib.contenttypes"]
67
+ MIDDLEWARE = []
68
+ DATABASES = {"default": {
69
+ "ENGINE": "django.db.backends.postgresql",
70
+ "NAME": os.getenv("POSTGRES_DB", "devspeed"),
71
+ "USER": os.getenv("POSTGRES_USER", "devspeed"),
72
+ "PASSWORD": os.getenv("POSTGRES_PASSWORD", "devspeed"),
73
+ "HOST": os.getenv("POSTGRES_HOST", "postgres"),
74
+ "PORT": "5432",
75
+ }}
76
+ """,
77
+ "config/urls.py": """from django.http import JsonResponse
78
+ from django.urls import path
79
+
80
+
81
+ urlpatterns = [path("", lambda request: JsonResponse({"message": "Your DevSpeed app is running"}))]
82
+ """,
83
+ }
84
+
85
+ def compose_yaml(self, config: Mapping[str, Any]) -> str:
86
+ """Render the Django and Postgres Compose services."""
87
+ services = config["services"]
88
+ app = services["app"]
89
+ postgres = services["postgres"]
90
+ project = config["project"]
91
+ app_command = lifecycle_command(
92
+ config,
93
+ "pip install --no-cache-dir -r requirements.txt",
94
+ f"python manage.py migrate --noinput && python manage.py runserver 0.0.0.0:{app['port']}",
95
+ )
96
+ postgres_yaml = postgres_service_yaml(postgres, project, database_url=False)
97
+
98
+ return f"""\
99
+ name: {project}
100
+
101
+ services:
102
+ app:
103
+ image: python:{app["python_version"]}-slim
104
+ working_dir: /app
105
+ volumes:
106
+ - ./:/app
107
+ command: {app_command}
108
+ ports:
109
+ - "{app["port"]}:{app["port"]}"
110
+ environment:
111
+ - DATABASE_URL=postgres://{postgres["user"]}:{postgres["password"]}@postgres:5432/{postgres["db"]}
112
+ - POSTGRES_DB={postgres["db"]}
113
+ - POSTGRES_USER={postgres["user"]}
114
+ - POSTGRES_PASSWORD={postgres["password"]}
115
+ - POSTGRES_HOST=postgres
116
+ depends_on:
117
+ postgres:
118
+ condition: service_healthy
119
+
120
+ {postgres_yaml}
121
+ """
122
+
123
+ def env_file(self, config: Mapping[str, Any]) -> str:
124
+ """Render the host Postgres connection variable."""
125
+ postgres = config["services"]["postgres"]
126
+ return (
127
+ f"DATABASE_URL=postgres://{postgres['user']}:{postgres['password']}"
128
+ f"@localhost:{postgres['port']}/{postgres['db']}\n"
129
+ )
130
+
131
+ def post_up_hints(self, config: Mapping[str, Any]) -> list[str]:
132
+ """Return startup notes for the generated Django environment."""
133
+ app_port = config["services"]["app"]["port"]
134
+ return [
135
+ "App container installs requirements.txt and runs Django's development server.",
136
+ f"Django should be reachable at http://localhost:{app_port} once dependencies finish installing.",
137
+ "Make sure manage.py and requirements.txt are present at the project root.",
138
+ ]
139
+
140
+
141
+ plugin = DjangoPostgresPlugin()
142
+ NAME = plugin.name
143
+ DESCRIPTION = plugin.description
144
+
145
+
146
+ def default_config(project_name: str) -> dict[str, Any]:
147
+ """Backward-compatible wrapper for the plugin method."""
148
+ return plugin.default_config(project_name)
149
+
150
+
151
+ def starter_files(config: Mapping[str, Any]) -> dict[str, str]:
152
+ """Backward-compatible wrapper for the plugin method."""
153
+ return plugin.starter_files(config)
154
+
155
+
156
+ def compose_yaml(config: Mapping[str, Any]) -> str:
157
+ """Backward-compatible wrapper for the plugin method."""
158
+ return plugin.compose_yaml(config)
159
+
160
+
161
+ def env_file(config: Mapping[str, Any]) -> str:
162
+ """Backward-compatible wrapper for the plugin method."""
163
+ return plugin.env_file(config)
164
+
165
+
166
+ def post_up_hints(config: Mapping[str, Any]) -> list[str]:
167
+ """Backward-compatible wrapper for the plugin method."""
168
+ return plugin.post_up_hints(config)
@@ -0,0 +1,128 @@
1
+ """Express and MongoDB stack plugin."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Mapping
6
+ from typing import Any
7
+
8
+ from devspeed.plugins.base import StackPlugin
9
+
10
+ from .common import lifecycle_command
11
+
12
+
13
+ class ExpressMongodbPlugin(StackPlugin):
14
+ """Provide a Node.js Express application with MongoDB."""
15
+
16
+ @property
17
+ def name(self) -> str:
18
+ return "express-mongodb"
19
+
20
+ @property
21
+ def description(self) -> str:
22
+ return "Node.js Express API + MongoDB"
23
+
24
+ def default_config(self, project_name: str) -> dict[str, Any]:
25
+ return {
26
+ "project": project_name,
27
+ "stack": self.name,
28
+ "lifecycle": {
29
+ "install": "npm install",
30
+ "dev": "npm run dev",
31
+ },
32
+ "services": {
33
+ "app": {"port": 3000, "node_version": "20"},
34
+ "mongodb": {
35
+ "port": 27017,
36
+ "user": "devspeed",
37
+ "password": "devspeed",
38
+ },
39
+ },
40
+ }
41
+
42
+ def starter_files(self, config: Mapping[str, Any]) -> dict[str, str]:
43
+ return {
44
+ "package.json": '{\n "name": "devspeed-express",\n "version": "1.0.0",\n "scripts": { "dev": "node app.js" },\n "dependencies": { "express": "^4.19.0", "mongoose": "^8.0.0" }\n}',
45
+ "app.js": 'const express = require("express");\nconst mongoose = require("mongoose");\n\nconst app = express();\nconst port = 3000;\n\nmongoose.connect(process.env.MONGODB_URI).then(() => console.log("Connected to MongoDB"));\n\napp.get("/", (req, res) => res.json({ message: "Your DevSpeed app is running" }));\n\napp.listen(port, () => console.log(`App listening on port ${port}`));',
46
+ }
47
+
48
+ def compose_yaml(self, config: Mapping[str, Any]) -> str:
49
+ services = config["services"]
50
+ app = services["app"]
51
+ mongo = services["mongodb"]
52
+ project = config["project"]
53
+ command = lifecycle_command(
54
+ config,
55
+ "npm install",
56
+ "npm run dev",
57
+ )
58
+ return f"""\
59
+ name: {project}
60
+
61
+ services:
62
+ app:
63
+ image: node:{app["node_version"]}-slim
64
+ working_dir: /app
65
+ volumes:
66
+ - ./:/app
67
+ command: {command}
68
+ ports:
69
+ - "{app["port"]}:{app["port"]}"
70
+ environment:
71
+ - MONGODB_URI=mongodb://{mongo["user"]}:{mongo["password"]}@mongodb:27017/devspeed_db?authSource=admin
72
+ depends_on:
73
+ mongodb:
74
+ condition: service_healthy
75
+
76
+ mongodb:
77
+ image: mongo:6-alpine
78
+ ports:
79
+ - "{mongo["port"]}:27017"
80
+ environment:
81
+ - MONGO_INITDB_ROOT_USERNAME={mongo["user"]}
82
+ - MONGO_INITDB_ROOT_PASSWORD={mongo["password"]}
83
+ healthcheck:
84
+ test: ["CMD", "mongo", "--eval", "db.adminCommand('ping')"]
85
+ interval: 3s
86
+ timeout: 3s
87
+ retries: 10
88
+
89
+ volumes:
90
+ {project}_mongodata:
91
+ """
92
+
93
+ def env_file(self, config: Mapping[str, Any]) -> str:
94
+ mongo = config["services"]["mongodb"]
95
+ return f"MONGODB_URI=mongodb://{mongo['user']}:{mongo['password']}@localhost:{mongo['port']}/devspeed_db?authSource=admin\n"
96
+
97
+ def post_up_hints(self, config: Mapping[str, Any]) -> list[str]:
98
+ port = config["services"]["app"]["port"]
99
+ return [
100
+ "App container runs npm install and npm run dev.",
101
+ f"API should be reachable at http://localhost:{port} once dependencies finish installing.",
102
+ "Make sure app.js is configured to use MONGODB_URI.",
103
+ ]
104
+
105
+
106
+ plugin = ExpressMongodbPlugin()
107
+ NAME = plugin.name
108
+ DESCRIPTION = plugin.description
109
+
110
+
111
+ def default_config(project_name: str) -> dict[str, Any]:
112
+ return plugin.default_config(project_name)
113
+
114
+
115
+ def starter_files(config: Mapping[str, Any]) -> dict[str, str]:
116
+ return plugin.starter_files(config)
117
+
118
+
119
+ def compose_yaml(config: Mapping[str, Any]) -> str:
120
+ return plugin.compose_yaml(config)
121
+
122
+
123
+ def env_file(config: Mapping[str, Any]) -> str:
124
+ return plugin.env_file(config)
125
+
126
+
127
+ def post_up_hints(config: Mapping[str, Any]) -> list[str]:
128
+ return plugin.post_up_hints(config)