Skip to content

Commit f11ab86

Browse files
committed
feat(cli): changes to run to work better with detached stdin (no shell)
1 parent 37f7452 commit f11ab86

3 files changed

Lines changed: 92 additions & 56 deletions

File tree

.changeset/tame-cobras-kick.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@cartesi/cli": patch
3+
---
4+
5+
changes to run to work better with detached stdin (no shell)

apps/cli/src/commands/run.ts

Lines changed: 69 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { DEFAULT_SDK_VERSION, PREFERRED_PORT } from "../config.js";
2020
import {
2121
AVAILABLE_SERVICES,
2222
deployApplication,
23+
host,
2324
removeApplication,
2425
type RollupsDeployment,
2526
startEnvironment,
@@ -38,32 +39,17 @@ const commaSeparatedList = (value: string) => value.split(",");
3839

3940
const shell = async (options: {
4041
build?: CommandUnknownOpts;
42+
deployment?: RollupsDeployment;
4143
epochLength: number;
4244
log?: CommandUnknownOpts;
4345
projectName: string;
4446
prt?: boolean;
47+
salt: number;
4548
}) => {
4649
const { build, epochLength, log, projectName, prt } = options;
4750

48-
// keep track of last deployment
49-
let lastDeployment: RollupsDeployment | undefined;
50-
let salt = 0;
51-
52-
// deploy for the first time
53-
const hash = getMachineHash();
54-
if (hash) {
55-
lastDeployment = await deploy({
56-
epochLength,
57-
hash,
58-
projectName,
59-
prt,
60-
salt: numberToHex(salt++, { size: 32 }),
61-
});
62-
} else {
63-
console.warn(
64-
chalk.yellow("machine snapshot not found, waiting for build"),
65-
);
66-
}
51+
let lastDeployment = options.deployment;
52+
let salt = options.salt;
6753

6854
while (true) {
6955
try {
@@ -313,11 +299,15 @@ export const createRunCommand = () => {
313299
// configure optional anvil fork
314300
const forkConfig = await configureFork(options);
315301

302+
// if TTY is not attached, run on foreground (not detached)
303+
const detach = process.stdin.isTTY;
304+
316305
// run compose environment (detached)
317-
const { address, config } = await startEnvironment({
306+
const { cmd, config } = await startEnvironment({
318307
blockTime,
319308
cpus,
320309
defaultBlock,
310+
detach,
321311
dryRun,
322312
forkConfig,
323313
memory,
@@ -328,6 +318,9 @@ export const createRunCommand = () => {
328318
verbose,
329319
});
330320

321+
// host address
322+
const address = `${host}:${port}`;
323+
331324
if (dryRun && config) {
332325
// just show the docker compose configuration and quit
333326
process.stdout.write(config);
@@ -346,6 +339,27 @@ export const createRunCommand = () => {
346339
services,
347340
});
348341

342+
// deploy the application
343+
let deployment: RollupsDeployment | undefined;
344+
let salt = 0;
345+
const prt = !authority;
346+
const hash = getMachineHash();
347+
if (hash) {
348+
deployment = await deploy({
349+
epochLength,
350+
hash,
351+
projectName,
352+
prt,
353+
salt: numberToHex(salt++, { size: 32 }),
354+
});
355+
} else {
356+
console.warn(
357+
chalk.yellow(
358+
"machine snapshot not found, waiting for build",
359+
),
360+
);
361+
}
362+
349363
const shutdown = async () => {
350364
progress.start(`${chalk.cyan(projectName)} stopping...`);
351365
try {
@@ -359,23 +373,41 @@ export const createRunCommand = () => {
359373
process.exit(0);
360374
};
361375

362-
// inhibit SIGINT and SIGTERM, will be handled gracefully by the shell
363-
process.on("SIGINT", () => {});
364-
process.on("SIGTERM", () => {});
376+
if (detach) {
377+
// inhibit SIGINT and SIGTERM, will be handled gracefully by the shell
378+
process.on("SIGINT", () => {});
379+
process.on("SIGTERM", () => {});
365380

366-
const log = program.parent?.commands.find(
367-
(c) => c.name() === "logs",
368-
);
369-
const build = program.parent?.commands.find(
370-
(c) => c.name() === "build",
371-
);
372-
await shell({
373-
build,
374-
epochLength,
375-
log,
376-
projectName,
377-
prt: !authority,
378-
});
379-
await shutdown();
381+
const log = program.parent?.commands.find(
382+
(c) => c.name() === "logs",
383+
);
384+
const build = program.parent?.commands.find(
385+
(c) => c.name() === "build",
386+
);
387+
await shell({
388+
build,
389+
deployment,
390+
epochLength,
391+
log,
392+
projectName,
393+
prt,
394+
salt,
395+
});
396+
await shutdown();
397+
} else {
398+
process.on("SIGINT", shutdown);
399+
process.on("SIGTERM", shutdown);
400+
try {
401+
await cmd;
402+
} catch (error: unknown) {
403+
if (error instanceof ExecaError) {
404+
// just continue gracefully
405+
if (error.exitCode === 130) {
406+
return;
407+
}
408+
throw error;
409+
}
410+
}
411+
}
380412
});
381413
};

apps/cli/src/exec/rollups.ts

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ type Service = {
135135
errorTitle?: string; // title of the service when it is not healthy
136136
};
137137

138-
const host = "http://127.0.0.1";
138+
export const host = "http://127.0.0.1";
139139

140140
// services configuration
141141
const baseServices: Service[] = [
@@ -242,6 +242,7 @@ export const startEnvironment = async (options: {
242242
blockTime: number;
243243
cpus?: number;
244244
defaultBlock: "latest" | "safe" | "pending" | "finalized";
245+
detach: boolean;
245246
dryRun: boolean;
246247
forkConfig?: ForkConfig;
247248
memory?: number;
@@ -255,6 +256,7 @@ export const startEnvironment = async (options: {
255256
blockTime,
256257
cpus,
257258
defaultBlock,
259+
detach,
258260
dryRun,
259261
forkConfig,
260262
memory,
@@ -265,25 +267,26 @@ export const startEnvironment = async (options: {
265267
verbose,
266268
} = options;
267269

268-
const address = `${host}:${port}`;
269-
270270
// setup the environment variable used in docker compose
271271
const env: NodeJS.ProcessEnv = {
272272
CARTESI_BLOCKCHAIN_DEFAULT_BLOCK: defaultBlock,
273273
CARTESI_LISTEN_PORT: port.toString(),
274274
CARTESI_LOG_LEVEL: verbose ? "debug" : "info",
275275
};
276276

277+
// local dev environment, we don't need security
278+
const databasePassword = "password";
279+
277280
const files = [
278281
anvil({
279282
blockTime,
280283
forkConfig,
281284
imageTag: runtimeVersion,
282285
}),
283-
database({ imageTag: runtimeVersion, password: "password" }),
286+
database({ imageTag: runtimeVersion, password: databasePassword }),
284287
node({
285288
cpus,
286-
databasePassword: "password",
289+
databasePassword,
287290
defaultBlock,
288291
forkChainId: forkConfig?.chainId,
289292
imageTag: runtimeVersion,
@@ -298,7 +301,7 @@ export const startEnvironment = async (options: {
298301
explorer({
299302
imageTag: "1.4.0",
300303
apiTag: "1.1.0",
301-
databasePassword: "password",
304+
databasePassword,
302305
port,
303306
}),
304307
);
@@ -316,7 +319,7 @@ export const startEnvironment = async (options: {
316319
const composeArgs = ["compose", "-f", "-", "--project-directory", "."];
317320

318321
// run in detached mode (background)
319-
const upArgs = ["--detach"];
322+
const upArgs = detach ? ["--detach"] : [];
320323

321324
// merge files, following Docker Compose merge rules
322325
const composeFile = concat([{ name: projectName }, ...files]);
@@ -330,25 +333,21 @@ export const startEnvironment = async (options: {
330333
{ env, input: stringify(composeFile, { lineWidth: 0, indent: 2 }) },
331334
);
332335

333-
return { address, config };
336+
return { config };
334337
}
335338

336-
// pull images first
337-
// const pullArgs = ["--policy", "missing"];
338-
// await execa("docker", [...composeArgs, "pull", ...pullArgs], {
339-
// env,
340-
////FIXME: stdio and input won't work together
341-
// stdio: "inherit",
342-
// input: composeFile.build()
343-
// });
344-
345339
// run compose
346-
await execa("docker", [...composeArgs, "up", ...upArgs], {
340+
const cmd = execa("docker", [...composeArgs, "up", ...upArgs], {
347341
env,
348342
input: stringify(composeFile, { lineWidth: 0, indent: 2 }),
349343
});
350344

351-
return { address };
345+
// if detached, wait to finish
346+
if (detach) {
347+
await cmd;
348+
}
349+
350+
return { cmd };
352351
};
353352

354353
/**

0 commit comments

Comments
 (0)