dockerbrain 1.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.
- core/__init__.py +1 -0
- core/__main__.py +4 -0
- core/ai_advisor.py +345 -0
- core/cli.py +369 -0
- core/dockerizer.py +310 -0
- core/fixer/__init__.py +21 -0
- core/fixer/container.py +171 -0
- core/fixer/dockerfile.py +225 -0
- core/llm.py +212 -0
- core/monitor/__init__.py +33 -0
- core/monitor/collector.py +197 -0
- core/monitor/display.py +279 -0
- core/monitor/snapshot.py +57 -0
- core/optimizer/__init__.py +23 -0
- core/optimizer/engine.py +84 -0
- core/optimizer/rules.py +221 -0
- core/storage.py +161 -0
- core/templates.py +559 -0
- core/utils.py +38 -0
- dockerbrain-1.0.dist-info/METADATA +156 -0
- dockerbrain-1.0.dist-info/RECORD +25 -0
- dockerbrain-1.0.dist-info/WHEEL +5 -0
- dockerbrain-1.0.dist-info/entry_points.txt +2 -0
- dockerbrain-1.0.dist-info/licenses/LICENSE +201 -0
- dockerbrain-1.0.dist-info/top_level.txt +1 -0
core/templates.py
ADDED
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
TEMPLATES: dict[str, dict[str, str]] = {
|
|
4
|
+
|
|
5
|
+
# Python
|
|
6
|
+
"fastapi": {
|
|
7
|
+
"name": "FastAPI",
|
|
8
|
+
"description": "Python FastAPI with uvicorn",
|
|
9
|
+
"dockerfile": """\
|
|
10
|
+
FROM python:3.12-slim
|
|
11
|
+
|
|
12
|
+
WORKDIR /app
|
|
13
|
+
|
|
14
|
+
COPY requirements.txt .
|
|
15
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
16
|
+
|
|
17
|
+
COPY . .
|
|
18
|
+
|
|
19
|
+
EXPOSE 8000
|
|
20
|
+
|
|
21
|
+
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
|
22
|
+
""",
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
"flask": {
|
|
26
|
+
"name": "Flask",
|
|
27
|
+
"description": "Python Flask with gunicorn",
|
|
28
|
+
"dockerfile": """\
|
|
29
|
+
FROM python:3.12-slim
|
|
30
|
+
|
|
31
|
+
WORKDIR /app
|
|
32
|
+
|
|
33
|
+
COPY requirements.txt .
|
|
34
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
35
|
+
|
|
36
|
+
COPY . .
|
|
37
|
+
|
|
38
|
+
EXPOSE 5000
|
|
39
|
+
|
|
40
|
+
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
|
|
41
|
+
""",
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
"django": {
|
|
45
|
+
"name": "Django",
|
|
46
|
+
"description": "Python Django with gunicorn",
|
|
47
|
+
"dockerfile": """\
|
|
48
|
+
FROM python:3.12-slim
|
|
49
|
+
|
|
50
|
+
WORKDIR /app
|
|
51
|
+
|
|
52
|
+
COPY requirements.txt .
|
|
53
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
54
|
+
|
|
55
|
+
COPY . .
|
|
56
|
+
|
|
57
|
+
RUN python manage.py collectstatic --noinput
|
|
58
|
+
|
|
59
|
+
EXPOSE 8000
|
|
60
|
+
|
|
61
|
+
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "config.wsgi:application"]
|
|
62
|
+
""",
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
# JavaScript / Node.js
|
|
66
|
+
"node": {
|
|
67
|
+
"name": "Node.js",
|
|
68
|
+
"description": "Node.js (Express / generic)",
|
|
69
|
+
"dockerfile": """\
|
|
70
|
+
FROM node:22-alpine
|
|
71
|
+
|
|
72
|
+
WORKDIR /app
|
|
73
|
+
|
|
74
|
+
COPY package*.json ./
|
|
75
|
+
RUN npm ci --omit=dev
|
|
76
|
+
|
|
77
|
+
COPY . .
|
|
78
|
+
|
|
79
|
+
EXPOSE 3000
|
|
80
|
+
|
|
81
|
+
CMD ["node", "index.js"]
|
|
82
|
+
""",
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
"nextjs": {
|
|
86
|
+
"name": "Next.js",
|
|
87
|
+
"description": "Next.js with standalone output",
|
|
88
|
+
"dockerfile": """\
|
|
89
|
+
FROM node:22-alpine AS deps
|
|
90
|
+
WORKDIR /app
|
|
91
|
+
COPY package*.json ./
|
|
92
|
+
RUN npm ci
|
|
93
|
+
|
|
94
|
+
FROM node:22-alpine AS builder
|
|
95
|
+
WORKDIR /app
|
|
96
|
+
COPY --from=deps /app/node_modules ./node_modules
|
|
97
|
+
COPY . .
|
|
98
|
+
RUN npm run build
|
|
99
|
+
|
|
100
|
+
FROM node:22-alpine AS runner
|
|
101
|
+
WORKDIR /app
|
|
102
|
+
ENV NODE_ENV=production
|
|
103
|
+
|
|
104
|
+
COPY --from=builder /app/public ./public
|
|
105
|
+
COPY --from=builder /app/.next/standalone ./
|
|
106
|
+
COPY --from=builder /app/.next/static ./.next/static
|
|
107
|
+
|
|
108
|
+
EXPOSE 3000
|
|
109
|
+
|
|
110
|
+
CMD ["node", "server.js"]
|
|
111
|
+
""",
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
"react": {
|
|
115
|
+
"name": "React",
|
|
116
|
+
"description": "React (Vite/CRA) with nginx",
|
|
117
|
+
"dockerfile": """\
|
|
118
|
+
FROM node:22-alpine AS build
|
|
119
|
+
WORKDIR /app
|
|
120
|
+
COPY package*.json ./
|
|
121
|
+
RUN npm ci
|
|
122
|
+
COPY . .
|
|
123
|
+
RUN npm run build
|
|
124
|
+
|
|
125
|
+
FROM nginx:alpine
|
|
126
|
+
COPY --from=build /app/dist /usr/share/nginx/html
|
|
127
|
+
EXPOSE 80
|
|
128
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
129
|
+
""",
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
"vue": {
|
|
133
|
+
"name": "Vue.js",
|
|
134
|
+
"description": "Vue.js with nginx",
|
|
135
|
+
"dockerfile": """\
|
|
136
|
+
FROM node:22-alpine AS build
|
|
137
|
+
WORKDIR /app
|
|
138
|
+
COPY package*.json ./
|
|
139
|
+
RUN npm ci
|
|
140
|
+
COPY . .
|
|
141
|
+
RUN npm run build
|
|
142
|
+
|
|
143
|
+
FROM nginx:alpine
|
|
144
|
+
COPY --from=build /app/dist /usr/share/nginx/html
|
|
145
|
+
EXPOSE 80
|
|
146
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
147
|
+
""",
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
"angular": {
|
|
151
|
+
"name": "Angular",
|
|
152
|
+
"description": "Angular with nginx",
|
|
153
|
+
"dockerfile": """\
|
|
154
|
+
FROM node:22-alpine AS build
|
|
155
|
+
WORKDIR /app
|
|
156
|
+
COPY package*.json ./
|
|
157
|
+
RUN npm ci
|
|
158
|
+
COPY . .
|
|
159
|
+
RUN npm run build --configuration=production
|
|
160
|
+
|
|
161
|
+
FROM nginx:alpine
|
|
162
|
+
COPY --from=build /app/dist/*/browser /usr/share/nginx/html
|
|
163
|
+
EXPOSE 80
|
|
164
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
165
|
+
""",
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
# TypeScript runtimes
|
|
169
|
+
"bun": {
|
|
170
|
+
"name": "Bun",
|
|
171
|
+
"description": "Bun runtime",
|
|
172
|
+
"dockerfile": """\
|
|
173
|
+
FROM oven/bun:1-alpine
|
|
174
|
+
|
|
175
|
+
WORKDIR /app
|
|
176
|
+
|
|
177
|
+
COPY package.json bun.lockb ./
|
|
178
|
+
RUN bun install --frozen-lockfile --production
|
|
179
|
+
|
|
180
|
+
COPY . .
|
|
181
|
+
|
|
182
|
+
EXPOSE 3000
|
|
183
|
+
|
|
184
|
+
CMD ["bun", "run", "index.ts"]
|
|
185
|
+
""",
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
"deno": {
|
|
189
|
+
"name": "Deno",
|
|
190
|
+
"description": "Deno runtime",
|
|
191
|
+
"dockerfile": """\
|
|
192
|
+
FROM denoland/deno:latest
|
|
193
|
+
|
|
194
|
+
WORKDIR /app
|
|
195
|
+
|
|
196
|
+
COPY . .
|
|
197
|
+
|
|
198
|
+
RUN deno cache main.ts
|
|
199
|
+
|
|
200
|
+
EXPOSE 8000
|
|
201
|
+
|
|
202
|
+
CMD ["deno", "run", "--allow-net", "--allow-read", "--allow-env", "main.ts"]
|
|
203
|
+
""",
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
# Go
|
|
207
|
+
"go": {
|
|
208
|
+
"name": "Go",
|
|
209
|
+
"description": "Go with multi-stage build",
|
|
210
|
+
"dockerfile": """\
|
|
211
|
+
FROM golang:1.23-alpine AS builder
|
|
212
|
+
WORKDIR /app
|
|
213
|
+
COPY go.mod go.sum ./
|
|
214
|
+
RUN go mod download
|
|
215
|
+
COPY . .
|
|
216
|
+
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /server .
|
|
217
|
+
|
|
218
|
+
FROM alpine:3.20
|
|
219
|
+
RUN apk --no-cache add ca-certificates
|
|
220
|
+
COPY --from=builder /server /server
|
|
221
|
+
|
|
222
|
+
EXPOSE 8080
|
|
223
|
+
|
|
224
|
+
CMD ["/server"]
|
|
225
|
+
""",
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
# Rust
|
|
229
|
+
"rust": {
|
|
230
|
+
"name": "Rust",
|
|
231
|
+
"description": "Rust with multi-stage build",
|
|
232
|
+
"dockerfile": """\
|
|
233
|
+
FROM rust:1.80-slim AS builder
|
|
234
|
+
WORKDIR /app
|
|
235
|
+
COPY Cargo.toml Cargo.lock ./
|
|
236
|
+
RUN mkdir src && echo "fn main() {}" > src/main.rs && cargo build --release && rm -rf src
|
|
237
|
+
COPY . .
|
|
238
|
+
RUN cargo build --release
|
|
239
|
+
|
|
240
|
+
FROM debian:bookworm-slim
|
|
241
|
+
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates && rm -rf /var/lib/apt/lists/*
|
|
242
|
+
COPY --from=builder /app/target/release/app /usr/local/bin/app
|
|
243
|
+
|
|
244
|
+
EXPOSE 8080
|
|
245
|
+
|
|
246
|
+
CMD ["app"]
|
|
247
|
+
""",
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
# Java
|
|
251
|
+
"spring": {
|
|
252
|
+
"name": "Spring Boot",
|
|
253
|
+
"description": "Spring Boot (Maven)",
|
|
254
|
+
"dockerfile": """\
|
|
255
|
+
FROM eclipse-temurin:21-jdk-alpine AS builder
|
|
256
|
+
WORKDIR /app
|
|
257
|
+
COPY pom.xml mvnw ./
|
|
258
|
+
COPY .mvn .mvn
|
|
259
|
+
RUN ./mvnw dependency:resolve
|
|
260
|
+
COPY src src
|
|
261
|
+
RUN ./mvnw package -DskipTests
|
|
262
|
+
|
|
263
|
+
FROM eclipse-temurin:21-jre-alpine
|
|
264
|
+
WORKDIR /app
|
|
265
|
+
COPY --from=builder /app/target/*.jar app.jar
|
|
266
|
+
|
|
267
|
+
EXPOSE 8080
|
|
268
|
+
|
|
269
|
+
CMD ["java", "-jar", "app.jar"]
|
|
270
|
+
""",
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
"gradle": {
|
|
274
|
+
"name": "Java (Gradle)",
|
|
275
|
+
"description": "Java app with Gradle",
|
|
276
|
+
"dockerfile": """\
|
|
277
|
+
FROM eclipse-temurin:21-jdk-alpine AS builder
|
|
278
|
+
WORKDIR /app
|
|
279
|
+
COPY build.gradle settings.gradle gradlew ./
|
|
280
|
+
COPY gradle gradle
|
|
281
|
+
RUN ./gradlew dependencies
|
|
282
|
+
COPY src src
|
|
283
|
+
RUN ./gradlew bootJar
|
|
284
|
+
|
|
285
|
+
FROM eclipse-temurin:21-jre-alpine
|
|
286
|
+
WORKDIR /app
|
|
287
|
+
COPY --from=builder /app/build/libs/*.jar app.jar
|
|
288
|
+
|
|
289
|
+
EXPOSE 8080
|
|
290
|
+
|
|
291
|
+
CMD ["java", "-jar", "app.jar"]
|
|
292
|
+
""",
|
|
293
|
+
},
|
|
294
|
+
|
|
295
|
+
# Ruby
|
|
296
|
+
"rails": {
|
|
297
|
+
"name": "Ruby on Rails",
|
|
298
|
+
"description": "Rails with Puma",
|
|
299
|
+
"dockerfile": """\
|
|
300
|
+
FROM ruby:3.3-slim
|
|
301
|
+
|
|
302
|
+
RUN apt-get update -qq && \\
|
|
303
|
+
apt-get install -y --no-install-recommends build-essential libpq-dev nodejs && \\
|
|
304
|
+
rm -rf /var/lib/apt/lists/*
|
|
305
|
+
|
|
306
|
+
WORKDIR /app
|
|
307
|
+
|
|
308
|
+
COPY Gemfile Gemfile.lock ./
|
|
309
|
+
RUN bundle install --without development test
|
|
310
|
+
|
|
311
|
+
COPY . .
|
|
312
|
+
|
|
313
|
+
RUN bundle exec rake assets:precompile
|
|
314
|
+
|
|
315
|
+
EXPOSE 3000
|
|
316
|
+
|
|
317
|
+
CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]
|
|
318
|
+
""",
|
|
319
|
+
},
|
|
320
|
+
|
|
321
|
+
# PHP
|
|
322
|
+
"laravel": {
|
|
323
|
+
"name": "Laravel",
|
|
324
|
+
"description": "PHP Laravel with Apache",
|
|
325
|
+
"dockerfile": """\
|
|
326
|
+
FROM php:8.3-apache
|
|
327
|
+
|
|
328
|
+
RUN a2enmod rewrite && \\
|
|
329
|
+
apt-get update && apt-get install -y --no-install-recommends \\
|
|
330
|
+
libpng-dev libzip-dev unzip && \\
|
|
331
|
+
docker-php-ext-install pdo_mysql gd zip && \\
|
|
332
|
+
rm -rf /var/lib/apt/lists/*
|
|
333
|
+
|
|
334
|
+
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
|
|
335
|
+
|
|
336
|
+
WORKDIR /var/www/html
|
|
337
|
+
|
|
338
|
+
COPY . .
|
|
339
|
+
RUN composer install --no-dev --optimize-autoloader
|
|
340
|
+
|
|
341
|
+
RUN chown -R www-data:www-data storage bootstrap/cache
|
|
342
|
+
|
|
343
|
+
ENV APACHE_DOCUMENT_ROOT=/var/www/html/public
|
|
344
|
+
RUN sed -ri 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/000-default.conf
|
|
345
|
+
|
|
346
|
+
EXPOSE 80
|
|
347
|
+
|
|
348
|
+
CMD ["apache2-foreground"]
|
|
349
|
+
""",
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
# .NET
|
|
353
|
+
"dotnet": {
|
|
354
|
+
"name": ".NET",
|
|
355
|
+
"description": "ASP.NET Core",
|
|
356
|
+
"dockerfile": """\
|
|
357
|
+
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
|
358
|
+
WORKDIR /src
|
|
359
|
+
COPY *.csproj ./
|
|
360
|
+
RUN dotnet restore
|
|
361
|
+
COPY . .
|
|
362
|
+
RUN dotnet publish -c Release -o /app/publish
|
|
363
|
+
|
|
364
|
+
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
|
365
|
+
WORKDIR /app
|
|
366
|
+
COPY --from=build /app/publish .
|
|
367
|
+
|
|
368
|
+
EXPOSE 8080
|
|
369
|
+
|
|
370
|
+
CMD ["dotnet", "App.dll"]
|
|
371
|
+
""",
|
|
372
|
+
},
|
|
373
|
+
|
|
374
|
+
# Elixir
|
|
375
|
+
"phoenix": {
|
|
376
|
+
"name": "Elixir Phoenix",
|
|
377
|
+
"description": "Phoenix Framework",
|
|
378
|
+
"dockerfile": """\
|
|
379
|
+
FROM elixir:1.16-alpine AS builder
|
|
380
|
+
RUN apk add --no-cache build-base git
|
|
381
|
+
WORKDIR /app
|
|
382
|
+
|
|
383
|
+
ENV MIX_ENV=prod
|
|
384
|
+
RUN mix local.hex --force && mix local.rebar --force
|
|
385
|
+
|
|
386
|
+
COPY mix.exs mix.lock ./
|
|
387
|
+
RUN mix deps.get --only prod && mix deps.compile
|
|
388
|
+
|
|
389
|
+
COPY . .
|
|
390
|
+
RUN mix assets.deploy && mix release
|
|
391
|
+
|
|
392
|
+
FROM alpine:3.20
|
|
393
|
+
RUN apk add --no-cache libstdc++ openssl ncurses-libs
|
|
394
|
+
WORKDIR /app
|
|
395
|
+
COPY --from=builder /app/_build/prod/rel/app ./
|
|
396
|
+
|
|
397
|
+
EXPOSE 4000
|
|
398
|
+
|
|
399
|
+
CMD ["bin/app", "start"]
|
|
400
|
+
""",
|
|
401
|
+
},
|
|
402
|
+
|
|
403
|
+
# Static / Nginx
|
|
404
|
+
"static": {
|
|
405
|
+
"name": "Static Site",
|
|
406
|
+
"description": "Static HTML/CSS/JS with nginx",
|
|
407
|
+
"dockerfile": """\
|
|
408
|
+
FROM nginx:alpine
|
|
409
|
+
|
|
410
|
+
COPY . /usr/share/nginx/html
|
|
411
|
+
|
|
412
|
+
EXPOSE 80
|
|
413
|
+
|
|
414
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
415
|
+
""",
|
|
416
|
+
},
|
|
417
|
+
|
|
418
|
+
# Python ML
|
|
419
|
+
"python-ml": {
|
|
420
|
+
"name": "Python ML",
|
|
421
|
+
"description": "Python ML/Data Science with Jupyter",
|
|
422
|
+
"dockerfile": """\
|
|
423
|
+
FROM python:3.12-slim
|
|
424
|
+
|
|
425
|
+
WORKDIR /app
|
|
426
|
+
|
|
427
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \\
|
|
428
|
+
build-essential && rm -rf /var/lib/apt/lists/*
|
|
429
|
+
|
|
430
|
+
COPY requirements.txt .
|
|
431
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
432
|
+
|
|
433
|
+
COPY . .
|
|
434
|
+
|
|
435
|
+
EXPOSE 8888
|
|
436
|
+
|
|
437
|
+
CMD ["jupyter", "notebook", "--ip=0.0.0.0", "--port=8888", "--no-browser", "--allow-root"]
|
|
438
|
+
""",
|
|
439
|
+
},
|
|
440
|
+
|
|
441
|
+
# SvelteKit
|
|
442
|
+
"sveltekit": {
|
|
443
|
+
"name": "SvelteKit",
|
|
444
|
+
"description": "SvelteKit with Node adapter",
|
|
445
|
+
"dockerfile": """\
|
|
446
|
+
FROM node:22-alpine AS builder
|
|
447
|
+
WORKDIR /app
|
|
448
|
+
COPY package*.json ./
|
|
449
|
+
RUN npm ci
|
|
450
|
+
COPY . .
|
|
451
|
+
RUN npm run build
|
|
452
|
+
|
|
453
|
+
FROM node:22-alpine
|
|
454
|
+
WORKDIR /app
|
|
455
|
+
COPY --from=builder /app/build ./build
|
|
456
|
+
COPY --from=builder /app/package*.json ./
|
|
457
|
+
RUN npm ci --omit=dev
|
|
458
|
+
|
|
459
|
+
EXPOSE 3000
|
|
460
|
+
|
|
461
|
+
CMD ["node", "build"]
|
|
462
|
+
""",
|
|
463
|
+
},
|
|
464
|
+
|
|
465
|
+
# Nuxt.js
|
|
466
|
+
"nuxtjs": {
|
|
467
|
+
"name": "Nuxt.js",
|
|
468
|
+
"description": "Nuxt.js with SSR output",
|
|
469
|
+
"dockerfile": """\
|
|
470
|
+
FROM node:22-alpine AS builder
|
|
471
|
+
WORKDIR /app
|
|
472
|
+
COPY package*.json ./
|
|
473
|
+
RUN npm ci
|
|
474
|
+
COPY . .
|
|
475
|
+
RUN npm run build
|
|
476
|
+
|
|
477
|
+
FROM node:22-alpine
|
|
478
|
+
WORKDIR /app
|
|
479
|
+
COPY --from=builder /app/.output ./
|
|
480
|
+
|
|
481
|
+
EXPOSE 3000
|
|
482
|
+
|
|
483
|
+
CMD ["node", "server/index.mjs"]
|
|
484
|
+
""",
|
|
485
|
+
},
|
|
486
|
+
|
|
487
|
+
# Astro
|
|
488
|
+
"astro": {
|
|
489
|
+
"name": "Astro",
|
|
490
|
+
"description": "Astro static site with nginx",
|
|
491
|
+
"dockerfile": """\
|
|
492
|
+
FROM node:22-alpine AS builder
|
|
493
|
+
WORKDIR /app
|
|
494
|
+
COPY package*.json ./
|
|
495
|
+
RUN npm ci
|
|
496
|
+
COPY . .
|
|
497
|
+
RUN npm run build
|
|
498
|
+
|
|
499
|
+
FROM nginx:alpine
|
|
500
|
+
COPY --from=builder /app/dist /usr/share/nginx/html
|
|
501
|
+
EXPOSE 80
|
|
502
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
503
|
+
""",
|
|
504
|
+
},
|
|
505
|
+
|
|
506
|
+
# Streamlit
|
|
507
|
+
"streamlit": {
|
|
508
|
+
"name": "Streamlit",
|
|
509
|
+
"description": "Python Streamlit data app",
|
|
510
|
+
"dockerfile": """\
|
|
511
|
+
FROM python:3.12-slim
|
|
512
|
+
|
|
513
|
+
WORKDIR /app
|
|
514
|
+
|
|
515
|
+
COPY requirements.txt .
|
|
516
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
517
|
+
|
|
518
|
+
COPY . .
|
|
519
|
+
|
|
520
|
+
EXPOSE 8501
|
|
521
|
+
|
|
522
|
+
CMD ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]
|
|
523
|
+
""",
|
|
524
|
+
},
|
|
525
|
+
|
|
526
|
+
# NestJS
|
|
527
|
+
"nestjs": {
|
|
528
|
+
"name": "NestJS",
|
|
529
|
+
"description": "NestJS backend with multi-stage build",
|
|
530
|
+
"dockerfile": """\
|
|
531
|
+
FROM node:22-alpine AS builder
|
|
532
|
+
WORKDIR /app
|
|
533
|
+
COPY package*.json ./
|
|
534
|
+
RUN npm ci
|
|
535
|
+
COPY . .
|
|
536
|
+
RUN npm run build
|
|
537
|
+
|
|
538
|
+
FROM node:22-alpine
|
|
539
|
+
WORKDIR /app
|
|
540
|
+
COPY --from=builder /app/dist ./dist
|
|
541
|
+
COPY --from=builder /app/package*.json ./
|
|
542
|
+
RUN npm ci --omit=dev
|
|
543
|
+
|
|
544
|
+
EXPOSE 3000
|
|
545
|
+
|
|
546
|
+
CMD ["node", "dist/main"]
|
|
547
|
+
""",
|
|
548
|
+
},
|
|
549
|
+
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
def get_template_names() -> list[str]:
|
|
553
|
+
"""Return sorted list of template keys."""
|
|
554
|
+
return sorted(TEMPLATES.keys())
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
def get_template(name: str) -> dict[str, str] | None:
|
|
558
|
+
"""Return template dict by key, or None."""
|
|
559
|
+
return TEMPLATES.get(name.lower())
|
core/utils.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
def format_bytes(b: int | float) -> str:
|
|
5
|
+
"""Human-readable byte string (e.g. 1.23 GiB)."""
|
|
6
|
+
for unit in ("B", "KiB", "MiB", "GiB", "TiB"):
|
|
7
|
+
if abs(b) < 1024:
|
|
8
|
+
return f"{b:.2f} {unit}"
|
|
9
|
+
b /= 1024
|
|
10
|
+
return f"{b:.2f} PiB"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def calc_cpu_percent(stats: dict) -> float:
|
|
14
|
+
"""Calculate CPU usage percentage from Docker stats JSON.
|
|
15
|
+
|
|
16
|
+
Uses the same formula as ``docker stats``:
|
|
17
|
+
delta_container / delta_system * num_cpus * 100
|
|
18
|
+
"""
|
|
19
|
+
cpu = stats.get("cpu_stats", {})
|
|
20
|
+
precpu = stats.get("precpu_stats", {})
|
|
21
|
+
|
|
22
|
+
container_delta = cpu.get("cpu_usage", {}).get("total_usage", 0) - precpu.get("cpu_usage", {}).get("total_usage", 0)
|
|
23
|
+
system_delta = cpu.get("system_cpu_usage", 0) - precpu.get("system_cpu_usage", 0)
|
|
24
|
+
num_cpus = cpu.get("online_cpus") or len(cpu.get("cpu_usage", {}).get("percpu_usage", []) or [1])
|
|
25
|
+
|
|
26
|
+
if system_delta > 0 and container_delta > 0:
|
|
27
|
+
return (container_delta / system_delta) * num_cpus * 100.0
|
|
28
|
+
return 0.0
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_docker_offline_hint() -> str:
|
|
32
|
+
"""Return an OS-specific hint for starting Docker."""
|
|
33
|
+
if sys.platform == "win32":
|
|
34
|
+
return "Make sure Docker Desktop is running, then try again."
|
|
35
|
+
elif sys.platform == "darwin":
|
|
36
|
+
return "Make sure Docker Desktop (or OrbStack/Colima) is running, then try again."
|
|
37
|
+
else:
|
|
38
|
+
return "Make sure the Docker daemon is running (e.g. `sudo systemctl start docker`), then try again."
|