@tsplc/build 0.1.0 → 0.2.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/dist/cli.js +57 -13
- package/dist/cli.js.map +8 -8
- package/dist/index.js +146 -15
- package/dist/index.js.map +7 -7
- package/docker/Dockerfile.dockerignore +1 -0
- package/docker/edge-gateway/Dockerfile +17 -0
- package/docker/runner.ts +31 -6
- package/package.json +3 -3
- package/python/build.py +6 -1
- package/python/codesys_login.py +100 -0
- package/python/codesys_online.py +47 -20
- package/python/test_codesys_login.py +120 -0
- package/python/test_codesys_online.py +14 -0
- package/python/worker.py +13 -0
- package/src/controller-online.ts +170 -16
- package/src/controller-session.ts +72 -3
- package/src/diagnostics.ts +2 -0
- package/src/docker-build.ts +15 -0
- package/src/docker-run.ts +3 -4
- package/src/host/codesys-worker.ts +9 -6
- package/src/index.ts +19 -2
package/dist/index.js
CHANGED
|
@@ -124,6 +124,7 @@ class CodesysCompilerError extends Error {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
var buildFailureFile = ".codesys/docker/failure.json";
|
|
127
|
+
var controllerFailureFile = ".codesys/controller/failure.txt";
|
|
127
128
|
var buildFailureSchema = z2.strictObject({
|
|
128
129
|
operationId: z2.uuid(),
|
|
129
130
|
message: z2.string(),
|
|
@@ -190,8 +191,6 @@ var prepareContainerRun = async (config, requestDirectory, options) => {
|
|
|
190
191
|
runtime: undefined
|
|
191
192
|
}));
|
|
192
193
|
return [
|
|
193
|
-
"run",
|
|
194
|
-
"--rm",
|
|
195
194
|
"--init",
|
|
196
195
|
...config.docker?.cpuSet ? ["--cpuset-cpus", config.docker.cpuSet] : [],
|
|
197
196
|
"--network",
|
|
@@ -269,6 +268,13 @@ var configureRuntime = async () => {
|
|
|
269
268
|
await runDocker(["build", "--platform", "linux/amd64", "--progress", "plain", "-t", runtimeImage, context], (status) => `Runtime image build failed (${status}). Review the image-build output`);
|
|
270
269
|
return runtimeImage;
|
|
271
270
|
};
|
|
271
|
+
var gatewayImage = "tsplc-edge-gateway:4.22.0.0";
|
|
272
|
+
var configureGateway = async () => {
|
|
273
|
+
const context = resolve5(packageDirectory, "docker/edge-gateway");
|
|
274
|
+
console.log(`Preparing the CODESYS gateway (${gatewayImage}).`);
|
|
275
|
+
await runDocker(["build", "--platform", "linux/amd64", "--progress", "plain", "-t", gatewayImage, context], (status) => `Gateway image build failed (${status}). Review the image-build output`);
|
|
276
|
+
return gatewayImage;
|
|
277
|
+
};
|
|
272
278
|
var buildInDocker = async (config, image) => {
|
|
273
279
|
const requestDirectory = await mkdtemp2(resolve5(tmpdir2(), "codesys-docker-"));
|
|
274
280
|
try {
|
|
@@ -277,6 +283,8 @@ var buildInDocker = async (config, image) => {
|
|
|
277
283
|
const failurePath = resolve5(config.outDir, buildFailureFile);
|
|
278
284
|
await rm3(failurePath, { force: true });
|
|
279
285
|
const args = [
|
|
286
|
+
"run",
|
|
287
|
+
"--rm",
|
|
280
288
|
...await prepareContainerRun(config, requestDirectory, { network: "none", sources: true }),
|
|
281
289
|
image,
|
|
282
290
|
"--request",
|
|
@@ -1222,10 +1230,12 @@ var buildProject = async (config) => {
|
|
|
1222
1230
|
};
|
|
1223
1231
|
// packages/build/src/controller-online.ts
|
|
1224
1232
|
import { execFile as execFile4 } from "node:child_process";
|
|
1233
|
+
import { existsSync } from "node:fs";
|
|
1225
1234
|
import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
|
|
1226
1235
|
import { mkdir as mkdir5, mkdtemp as mkdtemp3, readFile as readFile6, rm as rm5 } from "node:fs/promises";
|
|
1227
1236
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
1228
1237
|
import { resolve as resolve8 } from "node:path";
|
|
1238
|
+
import { setTimeout as delay2 } from "node:timers/promises";
|
|
1229
1239
|
import { promisify as promisify4 } from "node:util";
|
|
1230
1240
|
import { z as z5 } from "zod";
|
|
1231
1241
|
var execute4 = promisify4(execFile4);
|
|
@@ -1256,7 +1266,7 @@ var controllerResultSchema = z5.strictObject({
|
|
|
1256
1266
|
state: z5.string().nonempty(),
|
|
1257
1267
|
values: z5.record(z5.string(), z5.string())
|
|
1258
1268
|
});
|
|
1259
|
-
var
|
|
1269
|
+
var controllerConnection = async (config) => {
|
|
1260
1270
|
if (!config.docker || !config.online) {
|
|
1261
1271
|
throw new Error("Docker image and online gateway/device configuration are required for controller operations");
|
|
1262
1272
|
}
|
|
@@ -1269,20 +1279,30 @@ var controllerOperation = async (config, operation, options) => {
|
|
|
1269
1279
|
const { stdout } = await execute4("docker", ["image", "inspect", "--format", "{{.Id}}", dockerImage], { timeout: config.timeouts.hostCommand }).catch((cause) => {
|
|
1270
1280
|
throw new Error(`Cannot inspect Docker builder image ${dockerImage}. Install and start Docker, then run tsplc-build configure if the image is missing`, { cause });
|
|
1271
1281
|
});
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1282
|
+
return {
|
|
1283
|
+
environmentNames,
|
|
1284
|
+
imageId: imageIdSchema.parse(stdout.trim()),
|
|
1285
|
+
templateHash: createHash2("sha256").update(await readFile6(config.template)).digest("hex"),
|
|
1286
|
+
target: {
|
|
1287
|
+
network: config.online.network,
|
|
1288
|
+
gateway: config.online.gateway,
|
|
1289
|
+
device: config.online.device,
|
|
1290
|
+
controller: config.controller
|
|
1291
|
+
}
|
|
1280
1292
|
};
|
|
1293
|
+
};
|
|
1294
|
+
var controllerOperation = async (config, operation, options) => {
|
|
1295
|
+
const { environmentNames, imageId, templateHash, target } = await controllerConnection(config);
|
|
1296
|
+
const operationId = randomUUID2();
|
|
1281
1297
|
const requestDirectory = await mkdtemp3(resolve8(tmpdir3(), "codesys-controller-"));
|
|
1282
1298
|
const diagnostics = resolve8(config.outDir, ".codesys/controller");
|
|
1299
|
+
const failure = resolve8(config.outDir, controllerFailureFile);
|
|
1283
1300
|
try {
|
|
1284
1301
|
await mkdir5(config.outDir, { recursive: true });
|
|
1302
|
+
await rm5(failure, { force: true });
|
|
1285
1303
|
await runDocker([
|
|
1304
|
+
"run",
|
|
1305
|
+
"--rm",
|
|
1286
1306
|
...await prepareContainerRun(config, requestDirectory, {
|
|
1287
1307
|
network: target.network,
|
|
1288
1308
|
environment: environmentNames,
|
|
@@ -1298,7 +1318,13 @@ var controllerOperation = async (config, operation, options) => {
|
|
|
1298
1318
|
imageId,
|
|
1299
1319
|
...options.initializeUser ? ["--initialize-user"] : [],
|
|
1300
1320
|
...options.read ? ["--read", JSON.stringify(options.read)] : []
|
|
1301
|
-
], (status) => `Docker controller operation failed (${status}). Inspect ${diagnostics} for diagnostics`)
|
|
1321
|
+
], (status) => `Docker controller operation failed (${status}). Inspect ${diagnostics} for diagnostics`).catch(async (cause) => {
|
|
1322
|
+
if (!existsSync(failure))
|
|
1323
|
+
throw cause;
|
|
1324
|
+
const reason = (await readFile6(failure, "utf8")).trim().split(`
|
|
1325
|
+
`).at(-1);
|
|
1326
|
+
throw new Error(`${reason}. Inspect ${diagnostics} for diagnostics`, { cause });
|
|
1327
|
+
});
|
|
1302
1328
|
const result = await readFile6(resolve8(diagnostics, "result.json"), "utf8").then((content) => controllerResultSchema.parse(JSON.parse(content))).catch((cause) => {
|
|
1303
1329
|
throw new Error(`Docker did not produce a valid controller receipt. Inspect ${diagnostics} for diagnostics`, { cause });
|
|
1304
1330
|
});
|
|
@@ -1312,12 +1338,110 @@ var controllerOperation = async (config, operation, options) => {
|
|
|
1312
1338
|
};
|
|
1313
1339
|
var updateController = (config, operation, options = {}) => controllerOperation(config, operation, options);
|
|
1314
1340
|
var inspectController = (config, read) => controllerOperation(config, "inspect", { read });
|
|
1341
|
+
var explicitDownload = "use an explicit download";
|
|
1342
|
+
var loginCommandSchema = z5.discriminatedUnion("command", [
|
|
1343
|
+
z5.strictObject({ command: z5.literal("state") }),
|
|
1344
|
+
z5.strictObject({
|
|
1345
|
+
command: z5.literal("read"),
|
|
1346
|
+
expressions: z5.array(z5.string().nonempty()).nonempty()
|
|
1347
|
+
}),
|
|
1348
|
+
z5.strictObject({
|
|
1349
|
+
command: z5.enum(["write", "force"]),
|
|
1350
|
+
values: z5.record(z5.string().nonempty(), z5.string().nonempty())
|
|
1351
|
+
}),
|
|
1352
|
+
z5.strictObject({
|
|
1353
|
+
command: z5.literal("unforce"),
|
|
1354
|
+
expressions: z5.array(z5.string().nonempty()),
|
|
1355
|
+
restore: z5.boolean()
|
|
1356
|
+
}),
|
|
1357
|
+
z5.strictObject({ command: z5.enum(["start", "stop"]) }),
|
|
1358
|
+
z5.strictObject({ command: z5.literal("reset"), kind: z5.enum(["Warm", "Cold"]) })
|
|
1359
|
+
]);
|
|
1360
|
+
var loginResultSchema = z5.union([
|
|
1361
|
+
z5.strictObject({ values: z5.record(z5.string(), z5.string()) }),
|
|
1362
|
+
z5.strictObject({ state: z5.string(), forced: z5.array(z5.string()) })
|
|
1363
|
+
]);
|
|
1364
|
+
var loginReplySchema = z5.discriminatedUnion("ok", [
|
|
1365
|
+
z5.strictObject({ ok: z5.literal(true), result: z5.unknown() }),
|
|
1366
|
+
z5.strictObject({ ok: z5.literal(false), error: z5.string() })
|
|
1367
|
+
]);
|
|
1368
|
+
var loginPort = 4851;
|
|
1369
|
+
var docker = (args, timeout) => execute4("docker", args, { timeout }).then(({ stdout }) => stdout.trim());
|
|
1370
|
+
var isRunning = async (name, timeout) => await docker(["container", "ls", "--quiet", "--filter", `name=^${name}$`], timeout) !== "";
|
|
1371
|
+
var attachLogin = async (name, timeout) => {
|
|
1372
|
+
const published = await docker(["port", name, String(loginPort)], timeout);
|
|
1373
|
+
const url = `http://${published.split(`
|
|
1374
|
+
`)[0]}`;
|
|
1375
|
+
const call = async (init) => {
|
|
1376
|
+
const reply = loginReplySchema.parse(await (await fetch(url, init)).json());
|
|
1377
|
+
if (!reply.ok)
|
|
1378
|
+
throw new Error(reply.error);
|
|
1379
|
+
return reply.result;
|
|
1380
|
+
};
|
|
1381
|
+
return {
|
|
1382
|
+
name,
|
|
1383
|
+
ready: () => fetch(url).then((response) => response.ok).catch(() => false),
|
|
1384
|
+
send: async (command) => loginResultSchema.parse(await call({
|
|
1385
|
+
method: "POST",
|
|
1386
|
+
headers: { "Content-Type": "application/json" },
|
|
1387
|
+
body: JSON.stringify(command)
|
|
1388
|
+
})),
|
|
1389
|
+
close: async () => {
|
|
1390
|
+
await call({ method: "DELETE" });
|
|
1391
|
+
await docker(["wait", name], timeout);
|
|
1392
|
+
await docker(["rm", name], timeout);
|
|
1393
|
+
}
|
|
1394
|
+
};
|
|
1395
|
+
};
|
|
1396
|
+
var findControllerLogin = async (name) => await isRunning(name, 15000) ? attachLogin(name, 15000) : undefined;
|
|
1397
|
+
var openControllerLogin = async (config, name) => {
|
|
1398
|
+
const { environmentNames, imageId, target } = await controllerConnection(config);
|
|
1399
|
+
const timeout = config.timeouts.hostCommand;
|
|
1400
|
+
await docker(["rm", "--force", name], timeout);
|
|
1401
|
+
const requestDirectory = resolve8(config.outDir, ".codesys/login-request");
|
|
1402
|
+
await mkdir5(requestDirectory, { recursive: true });
|
|
1403
|
+
await docker([
|
|
1404
|
+
"run",
|
|
1405
|
+
"--detach",
|
|
1406
|
+
"--name",
|
|
1407
|
+
name,
|
|
1408
|
+
"--publish",
|
|
1409
|
+
`127.0.0.1::${loginPort}`,
|
|
1410
|
+
...await prepareContainerRun(config, requestDirectory, {
|
|
1411
|
+
network: target.network,
|
|
1412
|
+
environment: environmentNames,
|
|
1413
|
+
sources: false
|
|
1414
|
+
}),
|
|
1415
|
+
imageId,
|
|
1416
|
+
"login",
|
|
1417
|
+
"--request",
|
|
1418
|
+
"/input/config.json",
|
|
1419
|
+
"--image-id",
|
|
1420
|
+
imageId,
|
|
1421
|
+
"--port",
|
|
1422
|
+
String(loginPort)
|
|
1423
|
+
], timeout);
|
|
1424
|
+
const deadline = Date.now() + config.timeouts.startup + config.timeouts.build;
|
|
1425
|
+
while (Date.now() < deadline) {
|
|
1426
|
+
if (!await isRunning(name, timeout)) {
|
|
1427
|
+
const logs = await execute4("docker", ["logs", "--tail", "40", name], { timeout });
|
|
1428
|
+
throw new Error(`The controller login failed:
|
|
1429
|
+
${logs.stdout}${logs.stderr}`);
|
|
1430
|
+
}
|
|
1431
|
+
const login = await attachLogin(name, timeout);
|
|
1432
|
+
if (await login.ready())
|
|
1433
|
+
return login;
|
|
1434
|
+
await delay2(2000);
|
|
1435
|
+
}
|
|
1436
|
+
await docker(["rm", "--force", name], timeout);
|
|
1437
|
+
throw new Error("The controller login did not open in time");
|
|
1438
|
+
};
|
|
1315
1439
|
// packages/build/src/run.ts
|
|
1316
1440
|
import { execFile as execFile5 } from "node:child_process";
|
|
1317
1441
|
import { mkdtemp as mkdtemp4, readFile as readFile7, rm as rm6, writeFile as writeFile5 } from "node:fs/promises";
|
|
1318
1442
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
1319
1443
|
import { basename as basename4, dirname as dirname2, join } from "node:path";
|
|
1320
|
-
import { setTimeout as
|
|
1444
|
+
import { setTimeout as delay3 } from "node:timers/promises";
|
|
1321
1445
|
import { promisify as promisify5 } from "node:util";
|
|
1322
1446
|
import { z as z6 } from "zod";
|
|
1323
1447
|
|
|
@@ -1402,7 +1526,7 @@ ${log.split(`
|
|
|
1402
1526
|
`).slice(-25).join(`
|
|
1403
1527
|
`)}`);
|
|
1404
1528
|
}
|
|
1405
|
-
await
|
|
1529
|
+
await delay3(250);
|
|
1406
1530
|
}
|
|
1407
1531
|
} finally {
|
|
1408
1532
|
await rm6(definitionDirectory, { force: true, recursive: true });
|
|
@@ -1533,13 +1657,20 @@ export {
|
|
|
1533
1657
|
buildProject,
|
|
1534
1658
|
configSchema,
|
|
1535
1659
|
configureDocker,
|
|
1660
|
+
configureGateway,
|
|
1536
1661
|
configureRuntime,
|
|
1537
1662
|
defineBuildConfig as defineConfig,
|
|
1663
|
+
explicitDownload,
|
|
1664
|
+
findControllerLogin,
|
|
1665
|
+
gatewayImage,
|
|
1538
1666
|
inspectController,
|
|
1539
1667
|
installLibraries,
|
|
1540
1668
|
libraryIndex,
|
|
1541
1669
|
loadConfig,
|
|
1542
1670
|
loadSources,
|
|
1671
|
+
loginCommandSchema,
|
|
1672
|
+
loginResultSchema,
|
|
1673
|
+
openControllerLogin,
|
|
1543
1674
|
parseSource,
|
|
1544
1675
|
readBuild,
|
|
1545
1676
|
resolveConfig,
|
|
@@ -1548,5 +1679,5 @@ export {
|
|
|
1548
1679
|
validateLibrary
|
|
1549
1680
|
};
|
|
1550
1681
|
|
|
1551
|
-
//# debugId=
|
|
1682
|
+
//# debugId=B75F268E384DC61264756E2164756E21
|
|
1552
1683
|
//# sourceMappingURL=index.js.map
|