@flisk-sh/flisk-import 0.9.0 → 0.10.0
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.
- package/README.md +1 -0
- package/dist/detectors/compose.js +26 -2
- package/dist/write.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ flisk import . --yes # write service.json files and project setup
|
|
|
12
12
|
|
|
13
13
|
- **Reads one file:** the root `docker-compose.yml`, or `compose.yaml`, `compose.yml` or `docker-compose.yaml` when that is absent. Not override files, nested Compose files, Dockerfiles on their own, `package.json`, or Procfiles.
|
|
14
14
|
- **Writes:** one bring-your-own `service.json` per Compose service, plus `.flisk/project.json` if the repo is not a Flisk project yet. It never edits the Compose file or overwrites a `service.json` without `--force`.
|
|
15
|
+
- **Keeps the install's data:** each named volume gets `name`, the Docker volume `docker compose up` created (`<project>_<volume>`, its own `name:`, or an `external` volume), so `flisk up` mounts the same data with no copy (needs the Flisk release with flisk#2964).
|
|
15
16
|
- **Keeps:** the service names (`db` stays `db`, so it stays the hostname), the build context and Dockerfile (or the image), the container port as written (3000, 80, 5432), `depends_on`, and an HTTP health path. Databases and brokers are private, with no proxy route.
|
|
16
17
|
- **Runtime keys:** named volumes and bind mounts inside the project (`volumes`), `cap_add`, `cap_drop`, `init`, `read_only`, `user`, `security_opt` and `shm_size` (`container`), extra published ports (`extraPorts`, on 127.0.0.1 only), `network_mode: service:<name>` (`sidecarOf`) and `restart`.
|
|
17
18
|
- **Environment:** values that cannot be secrets go into the committed `service.json` `env`: numbers, `true`/`false`, another imported service's address without a user, password or query (`http://invidious:3000`, `redis:6379`), and pure `${VAR}` references. Every other name, and any name that looks like a credential (`PASSWORD`, `TOKEN`, `KEY`, ...), goes into `secrets.required`, with its literal value copied to the project `.env`, which is added to `.gitignore`. Values in `.env` already are kept.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
|
-
import { dirname, isAbsolute, join, normalize } from "node:path/posix";
|
|
2
|
+
import { basename, dirname, isAbsolute, join, normalize } from "node:path/posix";
|
|
3
3
|
import { isAlias, isMap, parseDocument, visit } from "yaml";
|
|
4
4
|
import { HEALTH_CHECK_PATH_PATTERN } from "../flisk.js";
|
|
5
5
|
import { registerDetector } from "../registry.js";
|
|
@@ -189,6 +189,26 @@ function volumeOf(entry, composeDir) {
|
|
|
189
189
|
return undefined;
|
|
190
190
|
return { source: resolved, target, ...(readOnly ? { readOnly } : {}), bind };
|
|
191
191
|
}
|
|
192
|
+
/** Compose's project name: top-level `name`, else the directory name, lowercased with other characters dropped. */
|
|
193
|
+
function projectNameOf(root, absPath) {
|
|
194
|
+
const raw = isObj(root) && typeof root.name === "string" && !root.name.includes("$")
|
|
195
|
+
? root.name
|
|
196
|
+
: basename(dirname(absPath));
|
|
197
|
+
const name = raw.toLowerCase().replace(/[^a-z0-9_-]/g, "");
|
|
198
|
+
return /^[a-z0-9]/.test(name) ? name : undefined;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* The Docker name of a named volume, as `docker compose up` created it: its own `name:`, the key itself when it is
|
|
202
|
+
* `external`, else `<project>_<key>`. Undefined when the name uses Compose variables.
|
|
203
|
+
*/
|
|
204
|
+
function dockerVolumeName(key, volumes, project) {
|
|
205
|
+
const def = isObj(volumes) ? volumes[key] : undefined;
|
|
206
|
+
if (isObj(def) && typeof def.name === "string")
|
|
207
|
+
return /^[A-Za-z0-9][A-Za-z0-9_.-]*$/.test(def.name) ? def.name : undefined;
|
|
208
|
+
if (isObj(def) && (def.external === true || isObj(def.external)))
|
|
209
|
+
return key;
|
|
210
|
+
return project ? `${project}_${key}` : undefined;
|
|
211
|
+
}
|
|
192
212
|
function envNames(environment) {
|
|
193
213
|
if (Array.isArray(environment)) {
|
|
194
214
|
return environment
|
|
@@ -358,6 +378,7 @@ registerDetector({
|
|
|
358
378
|
if (!services || !isMap(doc.get("services", true))) {
|
|
359
379
|
return { candidates, skips: [...skips, { ...base, reason: "no `services:` map" }] };
|
|
360
380
|
}
|
|
381
|
+
const project = projectNameOf(root, absPath);
|
|
361
382
|
for (const [name, raw] of Object.entries(services)) {
|
|
362
383
|
if (!isObj(raw)) {
|
|
363
384
|
skips.push({ ...base, reason: `service "${name}" is not a map` });
|
|
@@ -477,8 +498,11 @@ registerDetector({
|
|
|
477
498
|
const volumes = [];
|
|
478
499
|
for (const entry of Array.isArray(raw.volumes) ? raw.volumes : []) {
|
|
479
500
|
const volume = volumeOf(entry, composeDir);
|
|
501
|
+
const dockerName = volume && !volume.bind
|
|
502
|
+
? dockerVolumeName(volume.source, isObj(root) ? root.volumes : undefined, project)
|
|
503
|
+
: undefined;
|
|
480
504
|
if (volume)
|
|
481
|
-
volumes.push(volume);
|
|
505
|
+
volumes.push(dockerName ? { ...volume, name: dockerName } : volume);
|
|
482
506
|
else
|
|
483
507
|
skips.push({
|
|
484
508
|
...base,
|
package/dist/write.js
CHANGED
|
@@ -276,10 +276,12 @@ export function planWrites(plan, force) {
|
|
|
276
276
|
...(sidecarOf ? { sidecarOf } : {}),
|
|
277
277
|
...(volumes.length
|
|
278
278
|
? {
|
|
279
|
-
|
|
279
|
+
// `name` keeps the Docker volume the Compose install already has, so its data is used with no copy.
|
|
280
|
+
volumes: volumes.map(({ source, target, readOnly, name }) => ({
|
|
280
281
|
source,
|
|
281
282
|
target,
|
|
282
283
|
...(readOnly ? { readOnly } : {}),
|
|
284
|
+
...(name ? { name } : {}),
|
|
283
285
|
})),
|
|
284
286
|
}
|
|
285
287
|
: {}),
|
package/package.json
CHANGED