Skip to content

Commit 41369cc

Browse files
authored
Merge pull request #11114 from quarto-dev/bugfix/issue-10566
Fix `quarto run` stream redirection
2 parents 39ba722 + badd430 commit 41369cc

File tree

5 files changed

+111
-33
lines changed

5 files changed

+111
-33
lines changed

news/changelog-1.6.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ All changes included in 1.6:
7171
## Projects
7272

7373
- ([#10268](https://github.com/quarto-dev/quarto-cli/issues/10268)): `quarto create` supports opening project in Positron, in addition to VS Code and RStudio IDE.
74+
- ([#10566](https://github.com/quarto-dev/quarto-cli/issues/10566)): Ensure that `quarto run` outputs `stdout` and `stderr` to the correct streams.
7475

7576
### Websites
7677

src/core/run/lua.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,16 @@ export const luaRunHandler: RunHandler = {
4242
);
4343
cmd.push(...args);
4444

45-
return await execProcess({
46-
cmd,
47-
...options,
48-
}, "");
45+
return await execProcess(
46+
{
47+
cmd,
48+
...options,
49+
},
50+
"",
51+
undefined,
52+
undefined,
53+
true,
54+
);
4955
},
5056
};
5157

src/core/run/python.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
/*
2-
* python.ts
3-
*
4-
* Copyright (C) 2020-2022 Posit Software, PBC
5-
*
6-
*/
2+
* python.ts
3+
*
4+
* Copyright (C) 2020-2022 Posit Software, PBC
5+
*/
76

87
import { extname } from "../../deno_ral/path.ts";
98
import { pythonExec } from "../jupyter/exec.ts";
@@ -21,13 +20,19 @@ export const pythonRunHandler: RunHandler = {
2120
stdin?: string,
2221
options?: RunHandlerOptions,
2322
) => {
24-
return await execProcess({
25-
cmd: [
26-
...(await pythonExec()),
27-
script,
28-
...args,
29-
],
30-
...options,
31-
}, stdin);
23+
return await execProcess(
24+
{
25+
cmd: [
26+
...(await pythonExec()),
27+
script,
28+
...args,
29+
],
30+
...options,
31+
},
32+
stdin,
33+
undefined,
34+
undefined,
35+
true,
36+
);
3237
},
3338
};

src/core/run/r.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
/*
2-
* r.ts
3-
*
4-
* Copyright (C) 2020-2022 Posit Software, PBC
5-
*
6-
*/
2+
* r.ts
3+
*
4+
* Copyright (C) 2020-2022 Posit Software, PBC
5+
*/
76

87
import { extname } from "../../deno_ral/path.ts";
98

@@ -21,13 +20,19 @@ export const rRunHandler: RunHandler = {
2120
stdin?: string,
2221
options?: RunHandlerOptions,
2322
) => {
24-
return await execProcess({
25-
cmd: [
26-
await rBinaryPath("Rscript"),
27-
script,
28-
...args,
29-
],
30-
...options,
31-
}, stdin);
23+
return await execProcess(
24+
{
25+
cmd: [
26+
await rBinaryPath("Rscript"),
27+
script,
28+
...args,
29+
],
30+
...options,
31+
},
32+
stdin,
33+
undefined,
34+
undefined,
35+
true,
36+
);
3237
},
3338
};

tests/smoke/run/run-script.test.ts

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,61 @@
11
import { basename, join } from "../../../src/deno_ral/path.ts";
22
import { ensureDirSync } from "../../../src/deno_ral/fs.ts";
3-
import { assert } from "testing/asserts";
3+
import { assert, assertEquals } from "testing/asserts";
44
import { execProcess } from "../../../src/core/process.ts";
55
import { quartoDevCmd } from "../../utils.ts";
66
import { unitTest } from "../../test.ts";
7+
import { EOL } from "fs/eol";
8+
import { lines } from "../../../src/core/text.ts";
79

810
const workingDir = Deno.makeTempDirSync();
911

1012
ensureDirSync(workingDir);
1113

14+
const ensureStreams = (name: string, script: string, stdout: string, stderr: string) => {
15+
unitTest(name, async () => {
16+
const result = await execProcess({
17+
cmd: [
18+
quartoDevCmd(),
19+
"run",
20+
basename(script),
21+
],
22+
// disable logging here to allow for checking the output
23+
env: {
24+
"QUARTO_LOG_LEVEL": "CRITICAL",
25+
}
26+
},
27+
undefined,
28+
undefined,
29+
undefined,
30+
true
31+
);
32+
assert(result.success);
33+
assertEquals((result.stdout ?? "").replaceAll("\r", ""), stdout);
34+
assertEquals((result.stderr ?? "").replaceAll("\r", ""), stderr);
35+
},
36+
{
37+
teardown: () => {
38+
try {
39+
Deno.removeSync(basename(script));
40+
} catch (_e) {
41+
// ignore
42+
}
43+
return Promise.resolve();
44+
},
45+
cwd: () => {
46+
return workingDir;
47+
}
48+
})
49+
}
50+
1251
const testRunCmd = (name: string, script: string) => {
1352
unitTest(name, async () => {
1453
const result = await execProcess({
1554
cmd: [
1655
quartoDevCmd(),
1756
"run",
1857
basename(script),
19-
],
58+
]
2059
});
2160
assert(result.success);
2261
},
@@ -53,4 +92,26 @@ testRunCmd("run-py-script", pyScript);
5392
// Run R script
5493
const rScript = join(workingDir, "test.R");
5594
Deno.writeTextFileSync(rScript, "print('Hello, world!')");
56-
testRunCmd("run-r-script", rScript);
95+
testRunCmd("run-r-script", rScript);
96+
97+
// check stream outputs
98+
99+
// in R
100+
const rScript2 = join(workingDir, "test2.R");
101+
Deno.writeTextFileSync(rScript2, "cat('write stdout\\n', file = stdout()); cat('write stderr\\n', file = stderr())");
102+
ensureStreams("run-r-script-stdout-stderr", rScript2, "write stdout\n", "write stderr\n");
103+
104+
// in Python
105+
const pyScript2 = join(workingDir, "test2.py");
106+
Deno.writeTextFileSync(pyScript2, "import sys; print('write stdout'); print('write stderr', file = sys.stderr)");
107+
ensureStreams("run-py-script-stdout-stderr", pyScript2, "write stdout\n", "write stderr\n");
108+
109+
// in Deno TS
110+
const tsScript2 = join(workingDir, "test2.ts");
111+
Deno.writeTextFileSync(tsScript2, "console.log('write stdout'); console.error('write stderr')");
112+
ensureStreams("run-ts-script-stdout-stderr", tsScript2, "write stdout\n", "write stderr\n");
113+
114+
// in Lua
115+
const luaScript2 = join(workingDir, "test2.lua");
116+
Deno.writeTextFileSync(luaScript2, "print('write stdout'); io.stderr:write('write stderr\\n')");
117+
ensureStreams("run-lua-script-stdout-stderr", luaScript2, "write stdout\n\n", "write stderr\n"); // don't know why there is an extra newline

0 commit comments

Comments
 (0)