@kntic/kntic 0.4.0 → 0.4.2
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/package.json +1 -1
- package/src/cli.js +9 -1
- package/src/commands/index.js +2 -1
- package/src/commands/start.js +12 -2
- package/src/commands/start.test.js +42 -26
- package/src/commands/stop.js +11 -0
- package/src/commands/stop.test.js +17 -0
- package/src/commands/usage.js +2 -0
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -16,7 +16,15 @@ if (!subcommand || subcommand === "usage") {
|
|
|
16
16
|
});
|
|
17
17
|
} else if (subcommand === "start") {
|
|
18
18
|
try {
|
|
19
|
-
|
|
19
|
+
const startOpts = { screen: args.includes("--screen") };
|
|
20
|
+
commands.start(startOpts);
|
|
21
|
+
} catch (err) {
|
|
22
|
+
console.error(`Error: ${err.message}`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
} else if (subcommand === "stop") {
|
|
26
|
+
try {
|
|
27
|
+
commands.stop();
|
|
20
28
|
} catch (err) {
|
|
21
29
|
console.error(`Error: ${err.message}`);
|
|
22
30
|
process.exit(1);
|
package/src/commands/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const usage = require("./usage");
|
|
4
4
|
const init = require("./init");
|
|
5
5
|
const start = require("./start");
|
|
6
|
+
const stop = require("./stop");
|
|
6
7
|
const update = require("./update");
|
|
7
8
|
|
|
8
|
-
module.exports = { usage, init, start, update };
|
|
9
|
+
module.exports = { usage, init, start, stop, update };
|
package/src/commands/start.js
CHANGED
|
@@ -13,6 +13,10 @@ function isScreenAvailable() {
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
function isInsideScreen() {
|
|
17
|
+
return !!process.env.STY;
|
|
18
|
+
}
|
|
19
|
+
|
|
16
20
|
function getScreenName() {
|
|
17
21
|
try {
|
|
18
22
|
const content = readFileSync(".kntic.env", "utf8");
|
|
@@ -26,14 +30,20 @@ function getScreenName() {
|
|
|
26
30
|
return basename(process.cwd());
|
|
27
31
|
}
|
|
28
32
|
|
|
29
|
-
function start() {
|
|
33
|
+
function start(options = {}) {
|
|
30
34
|
const composeCmd = "docker compose -f kntic.yml --env-file .kntic.env up --build";
|
|
35
|
+
const useScreen = !!options.screen;
|
|
31
36
|
|
|
32
|
-
if (isScreenAvailable()) {
|
|
37
|
+
if (useScreen && isScreenAvailable() && !isInsideScreen()) {
|
|
33
38
|
const screenName = getScreenName();
|
|
34
39
|
console.log(`Starting KNTIC services in screen session "${screenName}"…`);
|
|
35
40
|
execSync(`screen -S ${screenName} ${composeCmd}`, { stdio: "inherit" });
|
|
36
41
|
} else {
|
|
42
|
+
if (useScreen && isInsideScreen()) {
|
|
43
|
+
console.log("Already inside a screen session, skipping screen wrapper.");
|
|
44
|
+
} else if (useScreen && !isScreenAvailable()) {
|
|
45
|
+
console.log("screen is not available, starting without screen wrapper.");
|
|
46
|
+
}
|
|
37
47
|
console.log("Starting KNTIC services…");
|
|
38
48
|
execSync(composeCmd, { stdio: "inherit" });
|
|
39
49
|
}
|
|
@@ -6,9 +6,14 @@ const fs = require("fs");
|
|
|
6
6
|
const path = require("path");
|
|
7
7
|
const os = require("os");
|
|
8
8
|
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
// Helper: extract a named function from start.js source by evaluating it in isolation.
|
|
10
|
+
function extractFn(fnName) {
|
|
11
|
+
const src = fs.readFileSync(require.resolve("./start"), "utf8");
|
|
12
|
+
return new Function("require", "process",
|
|
13
|
+
src.replace(/^"use strict";\s*/, "")
|
|
14
|
+
.replace(/module\.exports\s*=\s*start;/, `return ${fnName};`)
|
|
15
|
+
)(require, process);
|
|
16
|
+
}
|
|
12
17
|
|
|
13
18
|
describe("start — getScreenName resolution", () => {
|
|
14
19
|
let tmpDir, origCwd;
|
|
@@ -26,47 +31,58 @@ describe("start — getScreenName resolution", () => {
|
|
|
26
31
|
|
|
27
32
|
it("uses KNTIC_PRJ_PREFIX from .kntic.env when present", () => {
|
|
28
33
|
fs.writeFileSync(path.join(tmpDir, ".kntic.env"), "UID=1000\nKNTIC_PRJ_PREFIX=myproject\nGID=1000\n");
|
|
29
|
-
// Re-require to get fresh module (clear cache)
|
|
30
34
|
delete require.cache[require.resolve("./start")];
|
|
31
|
-
|
|
32
|
-
// by reading the source and evaluating the helper in isolation.
|
|
33
|
-
const src = fs.readFileSync(require.resolve("./start"), "utf8");
|
|
34
|
-
const getScreenName = new Function("require", "process",
|
|
35
|
-
src.replace(/^"use strict";\s*/, "")
|
|
36
|
-
.replace(/module\.exports\s*=\s*start;/, "return getScreenName;")
|
|
37
|
-
)(require, process);
|
|
35
|
+
const getScreenName = extractFn("getScreenName");
|
|
38
36
|
assert.equal(getScreenName(), "myproject");
|
|
39
37
|
});
|
|
40
38
|
|
|
41
39
|
it("falls back to current directory name when KNTIC_PRJ_PREFIX is missing", () => {
|
|
42
40
|
fs.writeFileSync(path.join(tmpDir, ".kntic.env"), "UID=1000\nGID=1000\n");
|
|
43
41
|
delete require.cache[require.resolve("./start")];
|
|
44
|
-
const
|
|
45
|
-
const getScreenName = new Function("require", "process",
|
|
46
|
-
src.replace(/^"use strict";\s*/, "")
|
|
47
|
-
.replace(/module\.exports\s*=\s*start;/, "return getScreenName;")
|
|
48
|
-
)(require, process);
|
|
42
|
+
const getScreenName = extractFn("getScreenName");
|
|
49
43
|
assert.equal(getScreenName(), path.basename(tmpDir));
|
|
50
44
|
});
|
|
51
45
|
|
|
52
46
|
it("falls back to current directory name when .kntic.env does not exist", () => {
|
|
53
47
|
delete require.cache[require.resolve("./start")];
|
|
54
|
-
const
|
|
55
|
-
const getScreenName = new Function("require", "process",
|
|
56
|
-
src.replace(/^"use strict";\s*/, "")
|
|
57
|
-
.replace(/module\.exports\s*=\s*start;/, "return getScreenName;")
|
|
58
|
-
)(require, process);
|
|
48
|
+
const getScreenName = extractFn("getScreenName");
|
|
59
49
|
assert.equal(getScreenName(), path.basename(tmpDir));
|
|
60
50
|
});
|
|
61
51
|
|
|
62
52
|
it("ignores empty KNTIC_PRJ_PREFIX value", () => {
|
|
63
53
|
fs.writeFileSync(path.join(tmpDir, ".kntic.env"), "KNTIC_PRJ_PREFIX=\nUID=1000\n");
|
|
64
54
|
delete require.cache[require.resolve("./start")];
|
|
65
|
-
const
|
|
66
|
-
const getScreenName = new Function("require", "process",
|
|
67
|
-
src.replace(/^"use strict";\s*/, "")
|
|
68
|
-
.replace(/module\.exports\s*=\s*start;/, "return getScreenName;")
|
|
69
|
-
)(require, process);
|
|
55
|
+
const getScreenName = extractFn("getScreenName");
|
|
70
56
|
assert.equal(getScreenName(), path.basename(tmpDir));
|
|
71
57
|
});
|
|
72
58
|
});
|
|
59
|
+
|
|
60
|
+
describe("start — isInsideScreen detection", () => {
|
|
61
|
+
let origSTY;
|
|
62
|
+
|
|
63
|
+
beforeEach(() => {
|
|
64
|
+
origSTY = process.env.STY;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
afterEach(() => {
|
|
68
|
+
if (origSTY === undefined) {
|
|
69
|
+
delete process.env.STY;
|
|
70
|
+
} else {
|
|
71
|
+
process.env.STY = origSTY;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("returns true when STY environment variable is set", () => {
|
|
76
|
+
process.env.STY = "12345.myscreen";
|
|
77
|
+
delete require.cache[require.resolve("./start")];
|
|
78
|
+
const isInsideScreen = extractFn("isInsideScreen");
|
|
79
|
+
assert.equal(isInsideScreen(), true);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("returns false when STY environment variable is not set", () => {
|
|
83
|
+
delete process.env.STY;
|
|
84
|
+
delete require.cache[require.resolve("./start")];
|
|
85
|
+
const isInsideScreen = extractFn("isInsideScreen");
|
|
86
|
+
assert.equal(isInsideScreen(), false);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { execSync } = require("child_process");
|
|
4
|
+
|
|
5
|
+
function stop() {
|
|
6
|
+
const composeCmd = "docker compose -f kntic.yml --env-file .kntic.env stop";
|
|
7
|
+
console.log("Stopping KNTIC services…");
|
|
8
|
+
execSync(composeCmd, { stdio: "inherit" });
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
module.exports = stop;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { describe, it } = require("node:test");
|
|
4
|
+
const assert = require("node:assert/strict");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
|
|
7
|
+
describe("stop — module structure", () => {
|
|
8
|
+
it("exports a function", () => {
|
|
9
|
+
const stop = require("./stop");
|
|
10
|
+
assert.equal(typeof stop, "function");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("source contains the correct docker compose stop command", () => {
|
|
14
|
+
const src = fs.readFileSync(require.resolve("./stop"), "utf8");
|
|
15
|
+
assert.ok(src.includes("docker compose -f kntic.yml --env-file .kntic.env stop"));
|
|
16
|
+
});
|
|
17
|
+
});
|
package/src/commands/usage.js
CHANGED
|
@@ -7,6 +7,8 @@ function usage() {
|
|
|
7
7
|
console.log(" usage List all available sub-commands");
|
|
8
8
|
console.log(" init Download and extract the KNTIC bootstrap template into the current directory");
|
|
9
9
|
console.log(" start Build and start KNTIC services via docker compose (uses kntic.yml + .kntic.env)");
|
|
10
|
+
console.log(" --screen Run inside a GNU screen session");
|
|
11
|
+
console.log(" stop Stop KNTIC services via docker compose");
|
|
10
12
|
console.log(" update Download the latest KNTIC bootstrap and update .kntic/lib only");
|
|
11
13
|
console.log("");
|
|
12
14
|
}
|