RoXuS
RoXuS14mo ago

Usage of Deno.Command?

Hey guys we use Deno.run to launch shell cmd and pipe the result to log. But Deno.run will be deprecated and I am not able to write a good equivalent with Deno.Command, do you have a suggestion? Here is my simple Deno.run:
import * as log from "https://deno.land/std@0.204.0/log/mod.ts";

export default async (
cmd: string,
args: Array<string>,
cwd?: string,
dry = false,
) => {
const logger = log.getLogger();
if (dry) {
logger.debug([`dry ${cwd} ${cmd}`, ...args].join(" "));
return Promise.resolve("");
}
logger.debug([cwd, cmd, ...args].join(" "));
const p = Deno.run({
cmd: [cmd, ...args],
cwd,
stdout: "piped",
stderr: "piped",
});

const [stderr, stdout, status] = await Promise.all([
p.stderrOutput(),
p.output(),
p.status(),
]);

p.close();

if (status.code === 0) {
return new TextDecoder().decode(stdout);
} else {
const errorString = new TextDecoder().decode(stderr);
throw new Error(
`\n${Deno.cwd()} ${cwd} ${cmd} ${args} ${errorString}`,
);
}
};
import * as log from "https://deno.land/std@0.204.0/log/mod.ts";

export default async (
cmd: string,
args: Array<string>,
cwd?: string,
dry = false,
) => {
const logger = log.getLogger();
if (dry) {
logger.debug([`dry ${cwd} ${cmd}`, ...args].join(" "));
return Promise.resolve("");
}
logger.debug([cwd, cmd, ...args].join(" "));
const p = Deno.run({
cmd: [cmd, ...args],
cwd,
stdout: "piped",
stderr: "piped",
});

const [stderr, stdout, status] = await Promise.all([
p.stderrOutput(),
p.output(),
p.status(),
]);

p.close();

if (status.code === 0) {
return new TextDecoder().decode(stdout);
} else {
const errorString = new TextDecoder().decode(stderr);
throw new Error(
`\n${Deno.cwd()} ${cwd} ${cmd} ${args} ${errorString}`,
);
}
};
5 Replies
RoXuS
RoXuSOP14mo ago
if I use the example of Deno.Command, something like
const command = new Deno.Command(Deno.execPath(), {
args: [
"eval",
"console.log('hello'); console.error('world')",
],
});
const { code, stdout, stderr } = await command.output();
const command = new Deno.Command(Deno.execPath(), {
args: [
"eval",
"console.log('hello'); console.error('world')",
],
});
const { code, stdout, stderr } = await command.output();
It works but I have the log after total execution, I would like the log as execution progresses
Deno AI Helper
Deno AI Helper14mo ago
Sure, I can help you with that. The Deno.Command class is used to create a child process. It has methods like output(), outputSync(), and spawn() to execute the command and collect its output. Here's how you can rewrite your function using Deno.Command:
import * as log from "https://deno.land/std@0.204.0/log/mod.ts";

export default async (
cmd: string,
args: Array<string>,
cwd?: string,
dry = false,
) => {
const logger = log.getLogger();
if (dry) {
logger.debug([`dry ${cwd} ${cmd}`, ...args].join(" "));
return Promise.resolve("");
}
logger.debug([cwd, cmd, ...args].join(" "));

const command = new Deno.Command(cmd, {
args,
cwd,
stdin: "piped",
stdout: "piped",
stderr: "piped",
});

const { code, stdout, stderr } = await command.output();

if (code === 0) {
return new TextDecoder().decode(stdout);
} else {
const errorString = new TextDecoder().decode(stderr);
throw new Error(
`\n${Deno.cwd()} ${cwd} ${cmd} ${args} ${errorString}`,
);
}
};
import * as log from "https://deno.land/std@0.204.0/log/mod.ts";

export default async (
cmd: string,
args: Array<string>,
cwd?: string,
dry = false,
) => {
const logger = log.getLogger();
if (dry) {
logger.debug([`dry ${cwd} ${cmd}`, ...args].join(" "));
return Promise.resolve("");
}
logger.debug([cwd, cmd, ...args].join(" "));

const command = new Deno.Command(cmd, {
args,
cwd,
stdin: "piped",
stdout: "piped",
stderr: "piped",
});

const { code, stdout, stderr } = await command.output();

if (code === 0) {
return new TextDecoder().decode(stdout);
} else {
const errorString = new TextDecoder().decode(stderr);
throw new Error(
`\n${Deno.cwd()} ${cwd} ${cmd} ${args} ${errorString}`,
);
}
};
Please note that the Deno.Command API is still unstable, so you need to run your script with the --unstable flag. Also, the Deno.Command class does not have a cwd option, so you might need to adjust your command and arguments to account for the working directory.
RoXuS
RoXuSOP14mo ago
No u can't use command.output with stdin to piped
ry
ry14mo ago
@RoXuS You would use command.spawn()
RoXuS
RoXuSOP14mo ago
yes finally I have try :
import { log } from "../deps.ts";

export default async (
cmd: string,
args: Array<string>,
cwd?: string,
dry = false,
) => {
const logger = log.getLogger();
if (dry) {
logger.debug([`dry ${cwd} ${cmd}`, ...args].join(" "));
return Promise.resolve("");
}
logger.debug([cwd, cmd, ...args].join(" "));
const p = new Deno.Command(cmd, {
args,
cwd,
stdin: "piped",
stdout: "piped",
});

const child = p.spawn();

const status = await child.status;

if (status.code === 0) {
return Promise.resolve();
} else {
throw new Error(
`\n${Deno.cwd()} ${cwd} ${cmd} ${args}`,
);
}
};
import { log } from "../deps.ts";

export default async (
cmd: string,
args: Array<string>,
cwd?: string,
dry = false,
) => {
const logger = log.getLogger();
if (dry) {
logger.debug([`dry ${cwd} ${cmd}`, ...args].join(" "));
return Promise.resolve("");
}
logger.debug([cwd, cmd, ...args].join(" "));
const p = new Deno.Command(cmd, {
args,
cwd,
stdin: "piped",
stdout: "piped",
});

const child = p.spawn();

const status = await child.status;

if (status.code === 0) {
return Promise.resolve();
} else {
throw new Error(
`\n${Deno.cwd()} ${cwd} ${cmd} ${args}`,
);
}
};
And it is ok, I don't understand why the result are piped to the log but it works haha thx for your response!