Seeking help migrating from Deno.run to Deno.Command with spawn

I have this code
function wait<T>(
time: number,
msg?: T,
reject = false,
id?: any,
): [Promise<T>, () => void] {
function makeResolver(action: (arg: any) => void) {
//prettier-ignore
id = setTimeout(() => action(msg), time);
}
return [
new Promise((resolver, rejecter) =>
makeResolver(reject ? rejecter : resolver)
),
() => clearTimeout(id),
];
}

/**
* withTimeout returns a new promise that resolves when the promise resolves or the timeout occurs.
*
* NOTE: Deno has issues with inferring generics see https://github.com/denoland/deno/issues/3997.
* For now, just pass explicit generic parameters
* @param ms specify timeout in milliseconds
* @param promise a function that returns a promise. Be sure to call bind if it is a method.
* @param timoutMsg Specify an object to return if the timeout occurs
*/
export async function withTimeout<V, TO>(
ms: number,
promise: () => Promise<V>,
timoutMsg?: TO,
rejectOnTimeout = false,
): Promise<V | TO> {
const [waiting, cancel] = wait(ms, timoutMsg, rejectOnTimeout);
const result = await Promise.race([promise(), waiting]);
cancel();
return result as V | TO;
}

const timeoutMsg: Deno.ProcessStatus = {
success: false,
code: 0,
signal: 255,
};
function isTimeoutMessage(x: any) {
return x.success === false && x.signal === 255;
}

//////////// BEGIN MAIN CODE //////////

const p = new Deno.Command("deno", {
args: cmdArgs,
stderr: spec.quiet ? "piped" : "inherit",
stdout: "piped",
}).spawn();

const out = await withTimeout(15e3, p.output.bind(p), timeoutMsg);
if (isTimeoutMessage(out)) {
p.kill();
throw new Error("Config program timed out.");
}
const s = await p.status;
if (!s.success) {
if (spec.quiet) console.error(p.stderr);
throw new Error("Config program threw an Error");
}
const _yamlText = new TextDecoder().decode(p.stdout);
function wait<T>(
time: number,
msg?: T,
reject = false,
id?: any,
): [Promise<T>, () => void] {
function makeResolver(action: (arg: any) => void) {
//prettier-ignore
id = setTimeout(() => action(msg), time);
}
return [
new Promise((resolver, rejecter) =>
makeResolver(reject ? rejecter : resolver)
),
() => clearTimeout(id),
];
}

/**
* withTimeout returns a new promise that resolves when the promise resolves or the timeout occurs.
*
* NOTE: Deno has issues with inferring generics see https://github.com/denoland/deno/issues/3997.
* For now, just pass explicit generic parameters
* @param ms specify timeout in milliseconds
* @param promise a function that returns a promise. Be sure to call bind if it is a method.
* @param timoutMsg Specify an object to return if the timeout occurs
*/
export async function withTimeout<V, TO>(
ms: number,
promise: () => Promise<V>,
timoutMsg?: TO,
rejectOnTimeout = false,
): Promise<V | TO> {
const [waiting, cancel] = wait(ms, timoutMsg, rejectOnTimeout);
const result = await Promise.race([promise(), waiting]);
cancel();
return result as V | TO;
}

const timeoutMsg: Deno.ProcessStatus = {
success: false,
code: 0,
signal: 255,
};
function isTimeoutMessage(x: any) {
return x.success === false && x.signal === 255;
}

//////////// BEGIN MAIN CODE //////////

const p = new Deno.Command("deno", {
args: cmdArgs,
stderr: spec.quiet ? "piped" : "inherit",
stdout: "piped",
}).spawn();

const out = await withTimeout(15e3, p.output.bind(p), timeoutMsg);
if (isTimeoutMessage(out)) {
p.kill();
throw new Error("Config program timed out.");
}
const s = await p.status;
if (!s.success) {
if (spec.quiet) console.error(p.stderr);
throw new Error("Config program threw an Error");
}
const _yamlText = new TextDecoder().decode(p.stdout);
3 Replies
Brandon Kalinowski
Brandon KalinowskiOP6mo ago
The issue I am having is that I cannot decode p.stdout
Deno AI Helper
Deno AI Helper6mo ago
I wasn't able to find the answer to your question in the official Deno documentation. However, based on the code snippet you've provided, I noticed a potential issue that you might want to address. In the main code section, you are using p.output.bind(p) as a promise for the withTimeout function. However, p.output is not a function but a property that returns a Deno.Reader. You should be using p.output() to get the output as a promise. Since p.output is not a function, calling bind on it will not work as expected. Here's the corrected line:
const out = await withTimeout(15e3, () => p.output(), timeoutMsg);
const out = await withTimeout(15e3, () => p.output(), timeoutMsg);
Please note that this advice is not based on the Deno documentation, and I advise you to double-check the accuracy of the advice given. If you continue to experience issues, you may want to consider reaching out to the Deno community or reviewing the Deno documentation for further guidance.
crowlKats
crowlKats6mo ago
p.stdout is a ReadableStream. your options are either using p.output() instead of p.status, or use streaming capabilities, but since you seem to want to collect the output to a single string, probably the first solution is the best for you