dockermind 0.1.2__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.
@@ -0,0 +1,119 @@
1
+ Metadata-Version: 2.4
2
+ Name: dockermind
3
+ Version: 0.1.2
4
+ Summary: Smart Dockerfile generation CLI for Node.js and Python projects
5
+ License: MIT
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: typer>=0.9.0
9
+ Provides-Extra: dev
10
+ Requires-Dist: pytest>=7.0; extra == "dev"
11
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
12
+ Requires-Dist: ruff>=0.1; extra == "dev"
13
+ Requires-Dist: mypy>=1.0; extra == "dev"
14
+
15
+ # Dockermind
16
+
17
+ > Smart Dockerfile generation CLI for Node.js and Python projects.
18
+
19
+ ## Overview
20
+
21
+ Dockermind analyses a project (Node.js or Python), infers the runtime and framework, and generates production-optimised Dockerfile and .dockerignore (optionally a docker-compose.yml). It also provides a small CLI to build and run the resulting image and a doctor command to validate the local Docker environment.
22
+
23
+ This repository contains a Next.js frontend (in the `app/` and `components/` folders) and the `dockermind` Python package that implements analysis and generation logic.
24
+
25
+ ## Requirements
26
+
27
+ - Python 3.10 or newer (the package declares `requires-python = ">=3.10"`)
28
+ - Docker (for `dockermind build`, `dockermind run` and to validate with `dockermind doctor`)
29
+ - Node.js (for the Next.js frontend; development and build use the `next` CLI)
30
+
31
+ When running commands below, ensure you are in the repository root.
32
+
33
+ ## Node / Frontend commands (npm scripts)
34
+
35
+ The repository defines the following npm scripts in `package.json`. These are the standard Next.js scripts and an ESLint target.
36
+
37
+ - `npm run dev` (alias: `pnpm dev` / `yarn dev`) — Runs `next dev`.
38
+ - What it does: starts the Next.js development server. The server serves the app in development mode, enables fast refresh, and rebuilds pages on change. Default listening port is 3000 unless overridden by environment variables.
39
+
40
+ - `npm run build` — Runs `next build`.
41
+ - What it does: produces a production build for Next.js, compiling pages and assets into the `.next` directory. Run this before `npm run start` for production usage.
42
+
43
+ - `npm run start` — Runs `next start`.
44
+ - What it does: launches the Next.js production server that serves the contents of the `.next` build directory. Requires a successful `npm run build` beforehand.
45
+
46
+ - `npm run lint` — Runs `eslint .`.
47
+ - What it does: runs ESLint across the repository (the configuration and rules are determined by the repo). Use this to detect and fix lint issues.
48
+
49
+ Notes:
50
+
51
+ - Use your preferred package manager. The repository contains a `pnpm-lock.yaml` file; if you use pnpm prefer `pnpm install`. Otherwise `npm ci` or `npm install` will work for npm users.
52
+
53
+ ## Python / Dockermind CLI
54
+
55
+ The Python package is configured in `pyproject.toml`. It exposes a console entry point named `dockermind` (see `[project.scripts]`). After installing the package, the `dockermind` command will be available.
56
+
57
+ Installation (editable/development install):
58
+
59
+ ```bash
60
+ python -m pip install -e .
61
+ ```
62
+
63
+ What that does: installs the package in editable mode and registers the `dockermind` CLI entry point. You can then run the CLI from the repository root.
64
+
65
+ Available CLI commands (usage: `dockermind <command> [options]`):
66
+
67
+ - `dockermind init [path] [--compose] [--dry-run] [--force]`
68
+ - What it does: Analyses the project at `path` (defaults to `.`) to detect whether the project is Node.js or Python, determines framework, ports, and build/start steps, then generates a Dockerfile and `.dockerignore`. If `--compose` is specified it also generates a `docker-compose.yml`. `--dry-run` prints generated files to the console without writing them. Without `--force`, the command will prompt before overwriting an existing Dockerfile.
69
+
70
+ - `dockermind build [path] [--tag <tag>]`
71
+ - What it does: Runs `docker build` using the `Dockerfile` in `path` (defaults to `.`). The `--tag` (`-t`) option sets the image name (default `dockermind-app`). The command streams `docker build` output to the terminal and returns a non-zero exit code on failure.
72
+
73
+ - `dockermind run [--tag <tag>] [--port <port>] [--detach]`
74
+ - What it does: Runs a Docker container from an image built by `dockermind build`. The command maps host port to container port as `port:port` and runs the container in foreground by default. Use `--detach` (`-d`) to run in background. The command checks if the selected port appears in use and warns if so.
75
+
76
+ - `dockermind doctor`
77
+ - What it does: Verifies that Docker is installed and that the Docker daemon is running. Also checks for Docker Compose and prints helpful messages and next steps. Returns a non-zero exit code if checks fail.
78
+
79
+ - `dockermind version`
80
+ - What it does: Prints the installed dockermind package version.
81
+
82
+ You can also invoke the CLI directly (without installing) with:
83
+
84
+ ```bash
85
+ python -m dockermind.cli init --dry-run
86
+ ```
87
+
88
+ This runs the `init` command using the local source tree without installing the package.
89
+
90
+ ## Test and helper scripts
91
+
92
+ - `scripts/run_tests.py` — Self-contained smoke tests.
93
+ - What it does: creates a temporary copy of the `dockermind` package inside `/tmp`, imports it and runs a suite of smoke tests that exercise analysis, Dockerfile generation and compose generation for representative Node.js and Python fixtures. The script prints pass/fail results and exits with non-zero status if any tests fail. It is intended as an on-host smoke test and may assume a POSIX environment (it uses `/tmp`).
94
+
95
+ - `scripts/run_tests.sh` — Simple shell wrapper for tests.
96
+ - What it does: installs minimal Python dependencies if needed and then runs the repo test harness under a specific path used by some CI environments.
97
+
98
+ Notes about tests: the tests in `scripts/run_tests.py` are not a replacement for a full test suite. They are smoke tests that exercise the core behaviour of the analysis and generation modules.
99
+
100
+ ## Docker usage notes
101
+
102
+ - Generated Dockerfiles attempt to create small, production-ready images. For Node.js projects the generator may use multi-stage builds when a build step is present. For Python projects it will attempt to use `uvicorn` for FastAPI projects or `flask` for Flask projects and will add minimal system packages when native dependencies are detected.
103
+ - The `dockermind run` and `dockermind build` commands rely on the local Docker CLI and daemon.
104
+
105
+ ## Contributing & Development
106
+
107
+ - Install Python development dependencies from `pyproject.toml` for tests and linters (e.g. `pytest`, `ruff`, `mypy`).
108
+ - Follow the linting and type checks present in the repo. Use `npm run lint` for JavaScript/TypeScript code quality checks.
109
+
110
+ ## Developer Contact
111
+
112
+ - GitHub: https://github.com/Aakashsingh0388
113
+ - LinkedIn: https://www.linkedin.com/in/aakash-singh-7b8416318/
114
+
115
+ If you need further details about the project or help building images, please open an issue on GitHub or contact the developer directly via LinkedIn.
116
+
117
+ ## License
118
+
119
+ This project is provided under the MIT License (see `dockermind.egg-info` for packaged metadata).
@@ -0,0 +1,105 @@
1
+ # Dockermind
2
+
3
+ > Smart Dockerfile generation CLI for Node.js and Python projects.
4
+
5
+ ## Overview
6
+
7
+ Dockermind analyses a project (Node.js or Python), infers the runtime and framework, and generates production-optimised Dockerfile and .dockerignore (optionally a docker-compose.yml). It also provides a small CLI to build and run the resulting image and a doctor command to validate the local Docker environment.
8
+
9
+ This repository contains a Next.js frontend (in the `app/` and `components/` folders) and the `dockermind` Python package that implements analysis and generation logic.
10
+
11
+ ## Requirements
12
+
13
+ - Python 3.10 or newer (the package declares `requires-python = ">=3.10"`)
14
+ - Docker (for `dockermind build`, `dockermind run` and to validate with `dockermind doctor`)
15
+ - Node.js (for the Next.js frontend; development and build use the `next` CLI)
16
+
17
+ When running commands below, ensure you are in the repository root.
18
+
19
+ ## Node / Frontend commands (npm scripts)
20
+
21
+ The repository defines the following npm scripts in `package.json`. These are the standard Next.js scripts and an ESLint target.
22
+
23
+ - `npm run dev` (alias: `pnpm dev` / `yarn dev`) — Runs `next dev`.
24
+ - What it does: starts the Next.js development server. The server serves the app in development mode, enables fast refresh, and rebuilds pages on change. Default listening port is 3000 unless overridden by environment variables.
25
+
26
+ - `npm run build` — Runs `next build`.
27
+ - What it does: produces a production build for Next.js, compiling pages and assets into the `.next` directory. Run this before `npm run start` for production usage.
28
+
29
+ - `npm run start` — Runs `next start`.
30
+ - What it does: launches the Next.js production server that serves the contents of the `.next` build directory. Requires a successful `npm run build` beforehand.
31
+
32
+ - `npm run lint` — Runs `eslint .`.
33
+ - What it does: runs ESLint across the repository (the configuration and rules are determined by the repo). Use this to detect and fix lint issues.
34
+
35
+ Notes:
36
+
37
+ - Use your preferred package manager. The repository contains a `pnpm-lock.yaml` file; if you use pnpm prefer `pnpm install`. Otherwise `npm ci` or `npm install` will work for npm users.
38
+
39
+ ## Python / Dockermind CLI
40
+
41
+ The Python package is configured in `pyproject.toml`. It exposes a console entry point named `dockermind` (see `[project.scripts]`). After installing the package, the `dockermind` command will be available.
42
+
43
+ Installation (editable/development install):
44
+
45
+ ```bash
46
+ python -m pip install -e .
47
+ ```
48
+
49
+ What that does: installs the package in editable mode and registers the `dockermind` CLI entry point. You can then run the CLI from the repository root.
50
+
51
+ Available CLI commands (usage: `dockermind <command> [options]`):
52
+
53
+ - `dockermind init [path] [--compose] [--dry-run] [--force]`
54
+ - What it does: Analyses the project at `path` (defaults to `.`) to detect whether the project is Node.js or Python, determines framework, ports, and build/start steps, then generates a Dockerfile and `.dockerignore`. If `--compose` is specified it also generates a `docker-compose.yml`. `--dry-run` prints generated files to the console without writing them. Without `--force`, the command will prompt before overwriting an existing Dockerfile.
55
+
56
+ - `dockermind build [path] [--tag <tag>]`
57
+ - What it does: Runs `docker build` using the `Dockerfile` in `path` (defaults to `.`). The `--tag` (`-t`) option sets the image name (default `dockermind-app`). The command streams `docker build` output to the terminal and returns a non-zero exit code on failure.
58
+
59
+ - `dockermind run [--tag <tag>] [--port <port>] [--detach]`
60
+ - What it does: Runs a Docker container from an image built by `dockermind build`. The command maps host port to container port as `port:port` and runs the container in foreground by default. Use `--detach` (`-d`) to run in background. The command checks if the selected port appears in use and warns if so.
61
+
62
+ - `dockermind doctor`
63
+ - What it does: Verifies that Docker is installed and that the Docker daemon is running. Also checks for Docker Compose and prints helpful messages and next steps. Returns a non-zero exit code if checks fail.
64
+
65
+ - `dockermind version`
66
+ - What it does: Prints the installed dockermind package version.
67
+
68
+ You can also invoke the CLI directly (without installing) with:
69
+
70
+ ```bash
71
+ python -m dockermind.cli init --dry-run
72
+ ```
73
+
74
+ This runs the `init` command using the local source tree without installing the package.
75
+
76
+ ## Test and helper scripts
77
+
78
+ - `scripts/run_tests.py` — Self-contained smoke tests.
79
+ - What it does: creates a temporary copy of the `dockermind` package inside `/tmp`, imports it and runs a suite of smoke tests that exercise analysis, Dockerfile generation and compose generation for representative Node.js and Python fixtures. The script prints pass/fail results and exits with non-zero status if any tests fail. It is intended as an on-host smoke test and may assume a POSIX environment (it uses `/tmp`).
80
+
81
+ - `scripts/run_tests.sh` — Simple shell wrapper for tests.
82
+ - What it does: installs minimal Python dependencies if needed and then runs the repo test harness under a specific path used by some CI environments.
83
+
84
+ Notes about tests: the tests in `scripts/run_tests.py` are not a replacement for a full test suite. They are smoke tests that exercise the core behaviour of the analysis and generation modules.
85
+
86
+ ## Docker usage notes
87
+
88
+ - Generated Dockerfiles attempt to create small, production-ready images. For Node.js projects the generator may use multi-stage builds when a build step is present. For Python projects it will attempt to use `uvicorn` for FastAPI projects or `flask` for Flask projects and will add minimal system packages when native dependencies are detected.
89
+ - The `dockermind run` and `dockermind build` commands rely on the local Docker CLI and daemon.
90
+
91
+ ## Contributing & Development
92
+
93
+ - Install Python development dependencies from `pyproject.toml` for tests and linters (e.g. `pytest`, `ruff`, `mypy`).
94
+ - Follow the linting and type checks present in the repo. Use `npm run lint` for JavaScript/TypeScript code quality checks.
95
+
96
+ ## Developer Contact
97
+
98
+ - GitHub: https://github.com/Aakashsingh0388
99
+ - LinkedIn: https://www.linkedin.com/in/aakash-singh-7b8416318/
100
+
101
+ If you need further details about the project or help building images, please open an issue on GitHub or contact the developer directly via LinkedIn.
102
+
103
+ ## License
104
+
105
+ This project is provided under the MIT License (see `dockermind.egg-info` for packaged metadata).
@@ -0,0 +1,5 @@
1
+ """
2
+ Dockermind -- Smart Dockerfile generation CLI for Node.js and Python projects.
3
+ """
4
+
5
+ __version__ = "0.1.1"
@@ -0,0 +1,285 @@
1
+ """
2
+ Project analyzer -- detects project type, framework, version, port, and scripts.
3
+
4
+ Only Node.js and Python are supported in v1.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import os
11
+ import re
12
+ from dataclasses import dataclass, field
13
+
14
+ from dockermind.utils import file_exists, read_file, extract_port_from_source, yellow
15
+
16
+
17
+ # ---------------------------------------------------------------------------
18
+ # Analysis result dataclass
19
+ # ---------------------------------------------------------------------------
20
+
21
+
22
+ @dataclass
23
+ class AnalysisResult:
24
+ """Everything dockermind needs to know about the target project."""
25
+
26
+ # Core detection
27
+ language: str | None = None # "node" | "python" | None
28
+ framework: str | None = None # "express" | "fastapi" | "flask" | None
29
+
30
+ # Runtime version
31
+ node_version: str = "18" # Default Node version
32
+ python_version: str = "3.11" # Default Python version
33
+
34
+ # Scripts (Node)
35
+ has_build_script: bool = False
36
+ build_script: str | None = None
37
+ start_script: str | None = None
38
+
39
+ # Entry point (Python)
40
+ python_entry_module: str | None = None # e.g. "main:app"
41
+ uses_uvicorn: bool = False
42
+
43
+ # Port
44
+ port: int | None = None
45
+ port_is_default: bool = False # True if we fell back to a default
46
+
47
+ # Package manager
48
+ has_package_lock: bool = False
49
+ has_yarn_lock: bool = False
50
+ has_pnpm_lock: bool = False
51
+
52
+ # Raw Python dependency names (lowercase) for native-package inference
53
+ python_deps: set[str] = field(default_factory=set)
54
+
55
+ # Warnings generated during analysis
56
+ warnings: list[str] = field(default_factory=list)
57
+
58
+ @property
59
+ def runtime_version(self) -> str:
60
+ """Return the resolved runtime version string."""
61
+ if self.language == "node":
62
+ return self.node_version
63
+ return self.python_version
64
+
65
+
66
+ # ---------------------------------------------------------------------------
67
+ # Analyzer
68
+ # ---------------------------------------------------------------------------
69
+
70
+
71
+ class Analyzer:
72
+ """Analyse a project directory and return an AnalysisResult."""
73
+
74
+ def __init__(self, project_path: str) -> None:
75
+ if not os.path.isdir(project_path):
76
+ raise FileNotFoundError(f"Project path does not exist: {project_path}")
77
+ self.path = project_path
78
+
79
+ def run(self) -> AnalysisResult:
80
+ """Run full analysis pipeline and return the result."""
81
+ result = AnalysisResult()
82
+
83
+ has_node = file_exists(self.path, "package.json")
84
+ has_python = (
85
+ file_exists(self.path, "requirements.txt")
86
+ or file_exists(self.path, "pyproject.toml")
87
+ )
88
+
89
+ # Language detection -- only one allowed
90
+ if has_node and has_python:
91
+ # Hard stop: ambiguous multi-runtime projects are not supported.
92
+ raise SystemExit(
93
+ "Error: Multiple backend runtimes detected (Node.js and Python).\n"
94
+ "Please run dockermind inside the specific service directory."
95
+ )
96
+
97
+ if has_node:
98
+ result.language = "node"
99
+ self._analyse_node(result)
100
+ elif has_python:
101
+ result.language = "python"
102
+ self._analyse_python(result)
103
+ else:
104
+ # Unsupported or empty project
105
+ result.language = None
106
+
107
+ return result
108
+
109
+ # ------------------------------------------------------------------
110
+ # Node.js analysis
111
+ # ------------------------------------------------------------------
112
+
113
+ def _analyse_node(self, result: AnalysisResult) -> None:
114
+ """Populate *result* with Node.js-specific details."""
115
+ raw = read_file(self.path, "package.json")
116
+ if not raw:
117
+ result.warnings.append("package.json exists but could not be read.")
118
+ return
119
+
120
+ try:
121
+ pkg = json.loads(raw)
122
+ except json.JSONDecodeError:
123
+ result.warnings.append("package.json is not valid JSON.")
124
+ return
125
+
126
+ # -- Node version from engines field --
127
+ engines = pkg.get("engines", {})
128
+ requested_version = engines.get("node", "")
129
+ if requested_version:
130
+ result.node_version = self._parse_node_version(requested_version)
131
+ # else: stays at default "18"
132
+
133
+ # -- Scripts --
134
+ scripts = pkg.get("scripts", {})
135
+ if "build" in scripts:
136
+ result.has_build_script = True
137
+ result.build_script = scripts["build"]
138
+ result.start_script = scripts.get("start")
139
+
140
+ # -- Framework detection --
141
+ all_deps = {
142
+ **pkg.get("dependencies", {}),
143
+ **pkg.get("devDependencies", {}),
144
+ }
145
+ if "express" in all_deps:
146
+ result.framework = "express"
147
+ elif "fastify" in all_deps:
148
+ result.framework = "fastify"
149
+ elif "koa" in all_deps:
150
+ result.framework = "koa"
151
+ # For v1 we just note whatever framework; Dockerfile is the same.
152
+
153
+ # -- Lock file detection --
154
+ result.has_package_lock = file_exists(self.path, "package-lock.json")
155
+ result.has_yarn_lock = file_exists(self.path, "yarn.lock")
156
+ result.has_pnpm_lock = file_exists(self.path, "pnpm-lock.yaml")
157
+
158
+ # -- Port detection --
159
+ result.port = self._detect_node_port(pkg)
160
+ if result.port is None:
161
+ result.port = 3000
162
+ result.port_is_default = True
163
+ result.warnings.append(
164
+ "Could not detect port from source. Defaulting to 3000."
165
+ )
166
+
167
+ def _parse_node_version(self, version_spec: str) -> str:
168
+ """Extract a major version number from an engines.node specifier.
169
+
170
+ Examples:
171
+ ">=18" -> "18"
172
+ "^20.0.0" -> "20"
173
+ "18.x" -> "18"
174
+ ">=18 <22" -> "18"
175
+ """
176
+ match = re.search(r"(\d{1,3})", version_spec)
177
+ if match:
178
+ return match.group(1)
179
+ return "18" # safe fallback
180
+
181
+ def _detect_node_port(self, pkg: dict) -> int | None:
182
+ """Try to detect port from source files or scripts."""
183
+ # Check common entry points for .listen(PORT)
184
+ candidates = ["server.js", "index.js", "app.js", "src/index.js", "src/server.js",
185
+ "src/app.js", "dist/index.js", "server.ts", "index.ts", "src/index.ts"]
186
+
187
+ for filename in candidates:
188
+ source = read_file(self.path, filename)
189
+ if source:
190
+ port = extract_port_from_source(source)
191
+ if port:
192
+ return port
193
+
194
+ return None
195
+
196
+ # ------------------------------------------------------------------
197
+ # Python analysis
198
+ # ------------------------------------------------------------------
199
+
200
+ def _analyse_python(self, result: AnalysisResult) -> None:
201
+ """Populate *result* with Python-specific details."""
202
+
203
+ # Gather all dependency names
204
+ deps_lower: set[str] = set()
205
+
206
+ # From requirements.txt
207
+ reqs = read_file(self.path, "requirements.txt")
208
+ if reqs:
209
+ for line in reqs.splitlines():
210
+ line = line.strip()
211
+ if not line or line.startswith("#"):
212
+ continue
213
+ # "fastapi==0.100.0" -> "fastapi"
214
+ dep_name = re.split(r"[>=<!~\[]", line)[0].strip().lower()
215
+ if dep_name:
216
+ deps_lower.add(dep_name)
217
+
218
+ # From pyproject.toml (simple parse -- no toml library needed for v1)
219
+ pyproject = read_file(self.path, "pyproject.toml")
220
+ if pyproject:
221
+ # Quick regex extraction for dependencies list
222
+ for match in re.finditer(r'"([a-zA-Z0-9_-]+)', pyproject):
223
+ deps_lower.add(match.group(1).lower())
224
+
225
+ # Expose raw deps for native-package inference in dockerfile_generator
226
+ result.python_deps = deps_lower
227
+
228
+ # -- Framework detection --
229
+ if "fastapi" in deps_lower:
230
+ result.framework = "fastapi"
231
+ result.port = 8000
232
+ elif "flask" in deps_lower:
233
+ result.framework = "flask"
234
+ result.port = 5000
235
+ else:
236
+ # Unknown Python framework -- set a sensible default
237
+ result.framework = None
238
+ result.port = 8000
239
+ result.warnings.append(
240
+ "No recognised framework (FastAPI/Flask). Defaulting to port 8000."
241
+ )
242
+
243
+ # -- Uvicorn detection --
244
+ if "uvicorn" in deps_lower:
245
+ result.uses_uvicorn = True
246
+
247
+ # -- Detect entry module --
248
+ result.python_entry_module = self._detect_python_entry(result)
249
+
250
+ # -- Python version from pyproject.toml requires-python --
251
+ if pyproject:
252
+ match = re.search(r'requires-python\s*=\s*["\']([^"\']+)["\']', pyproject)
253
+ if match:
254
+ ver_match = re.search(r"(\d+\.\d+)", match.group(1))
255
+ if ver_match:
256
+ result.python_version = ver_match.group(1)
257
+
258
+ def _detect_python_entry(self, result: AnalysisResult) -> str | None:
259
+ """Detect the Python entry module (e.g. 'main:app')."""
260
+
261
+ # Look for common entry files
262
+ candidates = ["main.py", "app.py", "application.py", "server.py",
263
+ "src/main.py", "src/app.py"]
264
+
265
+ for filename in candidates:
266
+ source = read_file(self.path, filename)
267
+ if source is None:
268
+ continue
269
+
270
+ # Look for FastAPI() or Flask() app instantiation
271
+ app_match = re.search(
272
+ r"(\w+)\s*=\s*(?:FastAPI|Flask)\s*\(", source
273
+ )
274
+ if app_match:
275
+ app_var = app_match.group(1)
276
+ module_name = filename.replace("/", ".").replace(".py", "")
277
+ return f"{module_name}:{app_var}"
278
+
279
+ # Fallback: if main.py exists, assume main:app
280
+ if file_exists(self.path, "main.py"):
281
+ return "main:app"
282
+ if file_exists(self.path, "app.py"):
283
+ return "app:app"
284
+
285
+ return None