@rainbow-robotics/muscat-plugin-kit 0.1.2-dev.34 → 0.1.2-dev.35
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/cli/bin/muscat-pk.mjs +1 -1
- package/cli/src/build.mjs +62 -74
- package/cli/src/cpp.mjs +12 -10
- package/cli/src/python.mjs +2 -2
- package/cli/src/ros2.mjs +38 -10
- package/package.json +2 -2
package/cli/bin/muscat-pk.mjs
CHANGED
|
@@ -21,7 +21,7 @@ Usage: muscat-pk <command> [options]
|
|
|
21
21
|
Commands:
|
|
22
22
|
new [dir] Scaffold a new plugin project (prompts: author, email, description, type, front-package-manager)
|
|
23
23
|
type change Switch backend type (python | cpp | ros2-python | ros2-cpp)
|
|
24
|
-
build Build + lock deps + vendor wheels + zip (--no-zip: skip zip, --no-lock: skip python lock/vendor)
|
|
24
|
+
build Build + lock deps + vendor wheels + zip (--no-zip: skip zip, --no-lock: skip python lock/vendor, --arch x86_64|aarch64|both)
|
|
25
25
|
dev Run Socket.IO bridge, dev:ui, and dev:back together
|
|
26
26
|
dev:ui Preview the plugin in a mini-Muscat (preview-host)
|
|
27
27
|
dev:back Run the plugin back end (python: watchfiles reload / ros2: Docker)
|
package/cli/src/build.mjs
CHANGED
|
@@ -68,37 +68,53 @@ function manifestRuntime(root) {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
// For ros2 plugins, compile the colcon workspace inside the Jazzy + Python 3.12
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
export async function exportRos2Build(root) {
|
|
71
|
+
// For ros2 plugins, compile the colcon workspace inside the Jazzy + Python 3.12 container.
|
|
72
|
+
// rclpy: arch-agnostic (pure Python) → dist/ros2_ws/install/ (built once)
|
|
73
|
+
// rclcpp: arch-specific C++ binaries → dist/ros2_ws/install-{arch}/ per arch
|
|
74
|
+
export async function exportRos2Build(root, archs = ["amd64", "arm64"]) {
|
|
75
75
|
if (manifestRuntime(root) !== "ros2") return;
|
|
76
|
-
const { assertDockerReady, ensureImage, colconBuild } = await import("./ros2.mjs");
|
|
76
|
+
const { assertDockerReady, ensureImage, colconBuild, ROS2_DEV_IMAGE, ARCH_DOCKER_PLATFORM } = await import("./ros2.mjs");
|
|
77
77
|
try {
|
|
78
78
|
assertDockerReady();
|
|
79
79
|
} catch (e) {
|
|
80
80
|
log.warn(`ros2 build skipped: ${e.message}`);
|
|
81
81
|
return;
|
|
82
82
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
|
|
84
|
+
const manifest = JSON.parse(readFileSync(resolve(root, "manifest.json"), "utf8"));
|
|
85
|
+
const rosClient = manifest.runtime?.rosClient;
|
|
86
|
+
|
|
87
|
+
if (rosClient === "rclcpp") {
|
|
88
|
+
// C++ ROS2: compile per arch so each robot picks the right install-{arch}/
|
|
89
|
+
for (const arch of archs) {
|
|
90
|
+
const dockerPlatform = ARCH_DOCKER_PLATFORM[arch];
|
|
91
|
+
if (!dockerPlatform) { log.warn(`unknown arch '${arch}' — skipped`); continue; }
|
|
92
|
+
const archImage = `${ROS2_DEV_IMAGE}-${arch}`;
|
|
93
|
+
ensureImage(archImage, { platform: dockerPlatform });
|
|
94
|
+
colconBuild(root, { symlink: false, arch });
|
|
95
|
+
log.ok(`dist/ros2_ws/install-${arch}/ ready`);
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
// rclpy / pure Python: arch-agnostic, build once
|
|
99
|
+
ensureImage();
|
|
100
|
+
colconBuild(root, { symlink: false });
|
|
101
|
+
log.ok("dist/ros2_ws/install/ ready");
|
|
102
|
+
}
|
|
86
103
|
}
|
|
87
104
|
|
|
88
105
|
// For cpp plugins, compile cpp/ inside the Ubuntu container (Release) per arch
|
|
89
106
|
// and copy each binary into dist/{arch}/{entry} so the ZIP carries relocatable
|
|
90
107
|
// robot-compatible executables. rb-runtime prefers dist/{arch}/ and falls back
|
|
91
108
|
// to dist/{entry} (legacy). Skipped (with a warning) if Docker is unavailable.
|
|
92
|
-
export async function exportCppBuild(root, distDir, archs = ["
|
|
109
|
+
export async function exportCppBuild(root, distDir, archs = ["amd64", "arm64"]) {
|
|
93
110
|
if (manifestRuntime(root) !== "cpp") return;
|
|
94
|
-
const { assertDockerReady, ensureImage, cmakeBuild } = await import("./cpp.mjs");
|
|
111
|
+
const { assertDockerReady, ensureImage, cmakeBuild, CPP_DEV_IMAGE, ARCH_DOCKER_PLATFORM } = await import("./cpp.mjs");
|
|
95
112
|
try {
|
|
96
113
|
assertDockerReady();
|
|
97
114
|
} catch (e) {
|
|
98
115
|
log.warn(`cpp build skipped: ${e.message}`);
|
|
99
116
|
return;
|
|
100
117
|
}
|
|
101
|
-
ensureImage();
|
|
102
118
|
|
|
103
119
|
const entry = JSON.parse(readFileSync(resolve(root, "manifest.json"), "utf8")).runtime?.entry;
|
|
104
120
|
if (!entry) {
|
|
@@ -107,6 +123,11 @@ export async function exportCppBuild(root, distDir, archs = ["x86_64", "aarch64"
|
|
|
107
123
|
}
|
|
108
124
|
|
|
109
125
|
for (const arch of archs) {
|
|
126
|
+
// python과 동일하게 arch별 이미지를 빌드해야 --platform 불일치를 피할 수 있다.
|
|
127
|
+
const dockerPlatform = ARCH_DOCKER_PLATFORM[arch];
|
|
128
|
+
if (!dockerPlatform) { log.warn(`unknown arch '${arch}' — skipped`); continue; }
|
|
129
|
+
const archImage = `${CPP_DEV_IMAGE}-${arch}`;
|
|
130
|
+
ensureImage(archImage, { platform: dockerPlatform });
|
|
110
131
|
cmakeBuild(root, { buildType: "Release", arch });
|
|
111
132
|
const buildDir = `cpp/build-${arch}`;
|
|
112
133
|
const built = resolve(root, buildDir, entry);
|
|
@@ -284,57 +305,15 @@ function dirSizeExcluding(dir, skip = []) {
|
|
|
284
305
|
|
|
285
306
|
// Read the uncompressed byte total of a .whl (zip) file by parsing its central
|
|
286
307
|
// directory — no external library needed, no actual extraction.
|
|
287
|
-
function unpackedWheelSize(whlPath) {
|
|
288
|
-
const buf = readFileSync(whlPath);
|
|
289
|
-
// Find EOCD signature (0x06054b50) scanning from end
|
|
290
|
-
let eocd = -1;
|
|
291
|
-
for (let i = buf.length - 22; i >= Math.max(0, buf.length - 65558); i--) {
|
|
292
|
-
if (buf.readUInt32LE(i) === 0x06054b50) { eocd = i; break; }
|
|
293
|
-
}
|
|
294
|
-
if (eocd === -1) return 0;
|
|
295
|
-
const cdOffset = buf.readUInt32LE(eocd + 16);
|
|
296
|
-
const cdSize = buf.readUInt32LE(eocd + 12);
|
|
297
|
-
let pos = cdOffset;
|
|
298
|
-
let total = 0;
|
|
299
|
-
while (pos < cdOffset + cdSize) {
|
|
300
|
-
if (buf.readUInt32LE(pos) !== 0x02014b50) break; // central dir signature
|
|
301
|
-
total += buf.readUInt32LE(pos + 24); // uncompressed size
|
|
302
|
-
const fnLen = buf.readUInt16LE(pos + 28);
|
|
303
|
-
const extraLen = buf.readUInt16LE(pos + 30);
|
|
304
|
-
const commentLen = buf.readUInt16LE(pos + 32);
|
|
305
|
-
pos += 46 + fnLen + extraLen + commentLen;
|
|
306
|
-
}
|
|
307
|
-
return total;
|
|
308
|
-
}
|
|
309
308
|
|
|
310
|
-
//
|
|
311
|
-
//
|
|
312
|
-
//
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
const
|
|
316
|
-
const ros2Install = resolve(pluginRoot, "ros2_ws/install");
|
|
317
|
-
|
|
318
|
-
const baseSize = dirSizeExcluding(distDir, ["wheels"]);
|
|
319
|
-
const ros2Size = existsSync(ros2Install) ? dirSize(ros2Install) : 0;
|
|
320
|
-
|
|
321
|
-
// Collect all wheel files once
|
|
322
|
-
const wheels = existsSync(wheelsDir)
|
|
323
|
-
? readdirSync(wheelsDir).filter((f) => f.endsWith(".whl")).map((f) => resolve(wheelsDir, f))
|
|
324
|
-
: [];
|
|
325
|
-
|
|
326
|
-
const perArchSize = archs.map((arch) => {
|
|
327
|
-
const archWheels = wheels.filter((w) => {
|
|
328
|
-
const name = w.split("/").pop();
|
|
329
|
-
// none-any wheels count for every arch
|
|
330
|
-
if (name.endsWith("none-any.whl")) return true;
|
|
331
|
-
return name.includes(arch);
|
|
332
|
-
});
|
|
333
|
-
const wheelSize = archWheels.reduce((sum, w) => sum + unpackedWheelSize(w), 0);
|
|
334
|
-
return baseSize + ros2Size + wheelSize;
|
|
335
|
-
});
|
|
309
|
+
// installedSize = "이 플러그인 하나를 지우면 되찾는 용량"
|
|
310
|
+
// = dist/(wheels/ 제외)
|
|
311
|
+
// ros2_ws/install* 은 이제 dist/ 안에 있으므로 별도 합산 불필요.
|
|
312
|
+
// 휠은 로봇 공유 스토어(store/py/)에 언팩되므로 포함하지 않는다.
|
|
313
|
+
function calcInstalledSize(pluginRoot) {
|
|
314
|
+
const distDir = resolve(pluginRoot, "dist");
|
|
336
315
|
|
|
337
|
-
const installedSize =
|
|
316
|
+
const installedSize = dirSizeExcluding(distDir, ["wheels"]);
|
|
338
317
|
|
|
339
318
|
// Write to root manifest.json
|
|
340
319
|
const rootManifestPath = resolve(pluginRoot, "manifest.json");
|
|
@@ -352,10 +331,11 @@ function calcInstalledSize(pluginRoot, archs) {
|
|
|
352
331
|
writeFileSync(distManifestPath, JSON.stringify(m, null, 2) + "\n");
|
|
353
332
|
}
|
|
354
333
|
|
|
355
|
-
log.ok(`installedSize → ${humanSize(installedSize)}
|
|
334
|
+
log.ok(`installedSize → ${humanSize(installedSize)}`);
|
|
356
335
|
}
|
|
357
336
|
|
|
358
|
-
// Zip dist/
|
|
337
|
+
// Zip dist/ into a distributable ZIP with a size report.
|
|
338
|
+
// ros2_ws/install* is now inside dist/, so only "dist" is needed.
|
|
359
339
|
function packZip(pluginRoot) {
|
|
360
340
|
const manifest = JSON.parse(readFileSync(resolve(pluginRoot, "manifest.json"), "utf8"));
|
|
361
341
|
const zipName = `${basename(pluginRoot)}-${manifest.version || "0.0.0"}.zip`;
|
|
@@ -363,7 +343,6 @@ function packZip(pluginRoot) {
|
|
|
363
343
|
rmSync(zipPath, { force: true });
|
|
364
344
|
|
|
365
345
|
const entries = ["dist"];
|
|
366
|
-
if (existsSync(resolve(pluginRoot, "ros2_ws/install"))) entries.push("ros2_ws/install");
|
|
367
346
|
|
|
368
347
|
log.step(`packing ${entries.join(", ")} → ${zipName}`);
|
|
369
348
|
try {
|
|
@@ -387,27 +366,36 @@ function packZip(pluginRoot) {
|
|
|
387
366
|
/**
|
|
388
367
|
* Ask which target arch(es) to build for.
|
|
389
368
|
* Non-TTY (CI): auto-selects current machine arch.
|
|
390
|
-
* @returns {Promise<string[]>} e.g. ['
|
|
369
|
+
* @returns {Promise<string[]>} e.g. ['amd64'] | ['arm64'] | ['amd64','arm64']
|
|
391
370
|
*/
|
|
392
|
-
async function promptArch() {
|
|
371
|
+
async function promptArch(args = []) {
|
|
372
|
+
// --arch x86_64 | --arch aarch64 | --arch both
|
|
373
|
+
const archFlag = args.find((a) => a.startsWith("--arch="))?.slice(7)
|
|
374
|
+
?? (args.includes("--arch") ? args[args.indexOf("--arch") + 1] : null);
|
|
375
|
+
if (archFlag) {
|
|
376
|
+
if (archFlag === "both") return ["amd64", "arm64"];
|
|
377
|
+
if (archFlag === "amd64" || archFlag === "x86_64") return ["amd64"];
|
|
378
|
+
if (archFlag === "arm64" || archFlag === "aarch64") return ["arm64"];
|
|
379
|
+
throw new Error(`unknown --arch value '${archFlag}' (valid: amd64, arm64, both)`);
|
|
380
|
+
}
|
|
393
381
|
if (!process.stdin.isTTY) {
|
|
394
382
|
const { arch } = await import("node:os");
|
|
395
|
-
const machine = arch() === "arm64" ? "
|
|
383
|
+
const machine = arch() === "arm64" ? "arm64" : "amd64";
|
|
396
384
|
log.info(`arch auto-selected (non-TTY): ${machine}`);
|
|
397
385
|
return [machine];
|
|
398
386
|
}
|
|
399
387
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
400
388
|
process.stdout.write(
|
|
401
389
|
"\n Target arch:\n" +
|
|
402
|
-
" 1) amd64
|
|
403
|
-
" 2) arm64
|
|
390
|
+
" 1) amd64\n" +
|
|
391
|
+
" 2) arm64\n" +
|
|
404
392
|
" 3) Both (fat ZIP)\n",
|
|
405
393
|
);
|
|
406
394
|
const answer = (await rl.question(" Select [1/2/3, default: 3]: ")).trim() || "3";
|
|
407
395
|
rl.close();
|
|
408
|
-
if (answer === "1") return ["
|
|
409
|
-
if (answer === "2") return ["
|
|
410
|
-
return ["
|
|
396
|
+
if (answer === "1") return ["amd64"];
|
|
397
|
+
if (answer === "2") return ["arm64"];
|
|
398
|
+
return ["amd64", "arm64"];
|
|
411
399
|
}
|
|
412
400
|
|
|
413
401
|
async function promptVersion(root) {
|
|
@@ -437,7 +425,7 @@ export async function runBuild(args) {
|
|
|
437
425
|
if (rt !== "none") ensureDocker();
|
|
438
426
|
|
|
439
427
|
await promptVersion(root);
|
|
440
|
-
const archs = await promptArch();
|
|
428
|
+
const archs = await promptArch(args);
|
|
441
429
|
|
|
442
430
|
const { pluginRoot, distDir } = await buildPlugin({ root, minify: true });
|
|
443
431
|
|
|
@@ -457,8 +445,8 @@ export async function runBuild(args) {
|
|
|
457
445
|
}
|
|
458
446
|
}
|
|
459
447
|
|
|
460
|
-
await exportRos2Build(root);
|
|
448
|
+
await exportRos2Build(root, archs);
|
|
461
449
|
await exportCppBuild(root, distDir, archs);
|
|
462
|
-
calcInstalledSize(pluginRoot
|
|
450
|
+
calcInstalledSize(pluginRoot);
|
|
463
451
|
if (!noZip) packZip(pluginRoot);
|
|
464
452
|
}
|
package/cli/src/cpp.mjs
CHANGED
|
@@ -21,11 +21,12 @@ export function assertDockerReady() {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/** Build the dev image from the kit's bundled Dockerfile (Docker layer-caches). */
|
|
24
|
-
export function ensureImage(image = CPP_DEV_IMAGE) {
|
|
25
|
-
log.step(`docker build -t ${image} (first run is slow, then cached)…`);
|
|
24
|
+
export function ensureImage(image = CPP_DEV_IMAGE, { platform = null } = {}) {
|
|
25
|
+
log.step(`docker build -t ${image}${platform ? ` (${platform})` : ""} (first run is slow, then cached)…`);
|
|
26
|
+
const platformFlags = platform ? ["--platform", platform] : [];
|
|
26
27
|
const r = spawnSync(
|
|
27
28
|
"docker",
|
|
28
|
-
["build", "-t", image, "-f", DOCKERFILE, dirname(DOCKERFILE)],
|
|
29
|
+
["build", ...platformFlags, "-t", image, "-f", DOCKERFILE, dirname(DOCKERFILE)],
|
|
29
30
|
{ stdio: "inherit" },
|
|
30
31
|
);
|
|
31
32
|
if (r.status !== 0) throw new Error("docker build failed.");
|
|
@@ -33,9 +34,9 @@ export function ensureImage(image = CPP_DEV_IMAGE) {
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
// Docker platform token for each target arch
|
|
36
|
-
const ARCH_DOCKER_PLATFORM = {
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
export const ARCH_DOCKER_PLATFORM = {
|
|
38
|
+
amd64: "linux/amd64",
|
|
39
|
+
arm64: "linux/arm64",
|
|
39
40
|
};
|
|
40
41
|
|
|
41
42
|
/**
|
|
@@ -47,9 +48,10 @@ const ARCH_DOCKER_PLATFORM = {
|
|
|
47
48
|
*/
|
|
48
49
|
export function cmakeBuild(root, { image = CPP_DEV_IMAGE, buildType = "Debug", arch = null } = {}) {
|
|
49
50
|
const buildDir = arch ? `cpp/build-${arch}` : "cpp/build";
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
const dockerPlatform = arch ? ARCH_DOCKER_PLATFORM[arch] : null;
|
|
52
|
+
const platformFlags = dockerPlatform ? ["--platform", dockerPlatform] : [];
|
|
53
|
+
// arch 빌드 시 arch별 이미지 사용 (로컬 이미지와 platform 불일치 방지)
|
|
54
|
+
const actualImage = arch ? `${CPP_DEV_IMAGE}-${arch}` : image;
|
|
53
55
|
const script = [
|
|
54
56
|
`cmake -S cpp -B ${buildDir} -DCMAKE_BUILD_TYPE=${buildType}`,
|
|
55
57
|
`cmake --build ${buildDir} -j`,
|
|
@@ -58,7 +60,7 @@ export function cmakeBuild(root, { image = CPP_DEV_IMAGE, buildType = "Debug", a
|
|
|
58
60
|
log.step(label);
|
|
59
61
|
const r = spawnSync(
|
|
60
62
|
"docker",
|
|
61
|
-
["run", "--rm", ...platformFlags, "-v", `${root}:/plugin`, "-w", "/plugin",
|
|
63
|
+
["run", "--rm", ...platformFlags, "-v", `${root}:/plugin`, "-w", "/plugin", actualImage, "bash", "-lc", script],
|
|
62
64
|
{ cwd: root, stdio: "inherit" },
|
|
63
65
|
);
|
|
64
66
|
if (r.status !== 0) throw new Error(`cmake build failed${arch ? ` (${arch})` : ""}.`);
|
package/cli/src/python.mjs
CHANGED
|
@@ -35,8 +35,8 @@ export function ensureImage(image = PYTHON_DEV_IMAGE, { platform = null } = {})
|
|
|
35
35
|
// Docker --platform 플래그: 컨테이너를 target arch로 띄우면
|
|
36
36
|
// pip이 glibc + arch를 자동 감지해 올바른 휠을 받는다.
|
|
37
37
|
const ARCH_DOCKER_PLATFORM = {
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
amd64: "linux/amd64",
|
|
39
|
+
arm64: "linux/arm64",
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
/**
|
package/cli/src/ros2.mjs
CHANGED
|
@@ -30,12 +30,18 @@ export function assertDockerReady() {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
export const ARCH_DOCKER_PLATFORM = {
|
|
34
|
+
amd64: "linux/amd64",
|
|
35
|
+
arm64: "linux/arm64",
|
|
36
|
+
};
|
|
37
|
+
|
|
33
38
|
/** Build the dev image from the kit's bundled Dockerfile (Docker layer-caches). */
|
|
34
|
-
export function ensureImage(image = ROS2_DEV_IMAGE) {
|
|
35
|
-
log.step(`docker build -t ${image} (first run is slow, then cached)…`);
|
|
39
|
+
export function ensureImage(image = ROS2_DEV_IMAGE, { platform = null } = {}) {
|
|
40
|
+
log.step(`docker build -t ${image}${platform ? ` (${platform})` : ""} (first run is slow, then cached)…`);
|
|
41
|
+
const platformFlags = platform ? ["--platform", platform] : [];
|
|
36
42
|
const r = spawnSync(
|
|
37
43
|
"docker",
|
|
38
|
-
["build", "-t", image, "-f", DOCKERFILE, dirname(DOCKERFILE)],
|
|
44
|
+
["build", ...platformFlags, "-t", image, "-f", DOCKERFILE, dirname(DOCKERFILE)],
|
|
39
45
|
{ stdio: "inherit" },
|
|
40
46
|
);
|
|
41
47
|
if (r.status !== 0) throw new Error("docker build failed.");
|
|
@@ -47,20 +53,42 @@ export function ensureImage(image = ROS2_DEV_IMAGE) {
|
|
|
47
53
|
* (the workspace is mounted). symlink=true for dev (fast, edit-in-place);
|
|
48
54
|
* symlink=false for export builds that ship in the ZIP (real copies, relocatable).
|
|
49
55
|
*/
|
|
50
|
-
|
|
56
|
+
/**
|
|
57
|
+
* arch=null → dev mode, builds to ros2_ws/install/ (native)
|
|
58
|
+
* arch="amd64"|"arm64" → export mode, builds to ros2_ws/install-{arch}/ using arch-specific image
|
|
59
|
+
*/
|
|
60
|
+
/**
|
|
61
|
+
* symlink=true (dev): ros2_ws/install/ — local dev workspace, not for ZIP
|
|
62
|
+
* symlink=false, arch=null (rclpy export): dist/ros2_ws/install/
|
|
63
|
+
* symlink=false, arch="amd64"|"arm64" (rclcpp export): dist/ros2_ws/install-{arch}/
|
|
64
|
+
*/
|
|
65
|
+
export function colconBuild(root, { image = ROS2_DEV_IMAGE, symlink = false, arch = null } = {}) {
|
|
66
|
+
// paths are relative to ros2_ws/ inside the container
|
|
67
|
+
let installBase;
|
|
68
|
+
if (symlink) {
|
|
69
|
+
installBase = "install";
|
|
70
|
+
} else if (arch) {
|
|
71
|
+
installBase = `../dist/ros2_ws/install-${arch}`;
|
|
72
|
+
} else {
|
|
73
|
+
installBase = "../dist/ros2_ws/install";
|
|
74
|
+
}
|
|
51
75
|
const flag = symlink ? "--symlink-install" : "";
|
|
52
76
|
const script = [
|
|
53
|
-
// --ignore-installed: don't try to uninstall debian-managed packages
|
|
54
|
-
// (e.g. psutil), which fails with "RECORD file not found".
|
|
55
77
|
"pip install -r requirements.txt --break-system-packages --ignore-installed -q || true",
|
|
56
78
|
"cd ros2_ws",
|
|
57
|
-
`colcon build ${flag}`.trim(),
|
|
79
|
+
`colcon build ${flag} --install-base ${installBase}`.trim(),
|
|
58
80
|
].join(" && ");
|
|
59
|
-
|
|
81
|
+
const label = arch
|
|
82
|
+
? `colcon build (${arch}) → dist/ros2_ws/install-${arch}/…`
|
|
83
|
+
: `colcon build${symlink ? " --symlink-install" : ""} (in container)…`;
|
|
84
|
+
log.step(label);
|
|
85
|
+
const actualImage = arch ? `${ROS2_DEV_IMAGE}-${arch}` : image;
|
|
86
|
+
const dockerPlatform = arch ? ARCH_DOCKER_PLATFORM[arch] : null;
|
|
87
|
+
const platformFlags = dockerPlatform ? ["--platform", dockerPlatform] : [];
|
|
60
88
|
const r = spawnSync(
|
|
61
89
|
"docker",
|
|
62
|
-
["run", "--rm", "-v", `${root}:/plugin`, "-w", "/plugin",
|
|
90
|
+
["run", "--rm", ...platformFlags, "-v", `${root}:/plugin`, "-w", "/plugin", actualImage, "bash", "-lc", script],
|
|
63
91
|
{ cwd: root, stdio: "inherit" },
|
|
64
92
|
);
|
|
65
|
-
if (r.status !== 0) throw new Error(
|
|
93
|
+
if (r.status !== 0) throw new Error(`colcon build failed${arch ? ` (${arch})` : ""}.`);
|
|
66
94
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rainbow-robotics/muscat-plugin-kit",
|
|
3
|
-
"version": "0.1.2-dev.
|
|
3
|
+
"version": "0.1.2-dev.35",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20"
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@types/react-dom": "^19.0.4"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@rainbow-robotics/preview-host": "0.1.2-dev.
|
|
34
|
+
"@rainbow-robotics/preview-host": "0.1.2-dev.35",
|
|
35
35
|
"socket.io": "^4.8.1"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|