Skip to content

Deno.env review/cleanup: no set() past startup #12621

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/command/render/render-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ export async function renderExecute(
previewServer: context.options.previewServer,
handledLanguages: languages(),
project: context.project,
env: {},
};
// execute computations
setExecuteEnvironment(executeOptions);
Expand Down
12 changes: 6 additions & 6 deletions src/execute/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ export const setExecuteEnvironment: (options: ExecuteOptions) => void = (
options,
) => {
if (options.projectDir) {
Deno.env.set("QUARTO_PROJECT_ROOT", options.projectDir);
Deno.env.set("QUARTO_DOCUMENT_PATH", dirname(options.target.source));
Deno.env.set("QUARTO_DOCUMENT_FILE", basename(options.target.source));
options.env["QUARTO_PROJECT_ROOT"] = options.projectDir;
options.env["QUARTO_DOCUMENT_PATH"] = dirname(options.target.source);
options.env["QUARTO_DOCUMENT_FILE"] = basename(options.target.source);
} else {
// FIXME: This should not be passthrough anymore as singleFileProjectContext always set `options.projectDir`
// https://github.com/quarto-dev/quarto-cli/pull/8771
Expand All @@ -23,8 +23,8 @@ export const setExecuteEnvironment: (options: ExecuteOptions) => void = (
"No project directory or current working directory",
);
}
Deno.env.set("QUARTO_PROJECT_ROOT", options.cwd);
Deno.env.set("QUARTO_DOCUMENT_PATH", options.cwd);
Deno.env.set("QUARTO_DOCUMENT_FILE", basename(options.target.source));
options.env["QUARTO_PROJECT_ROOT"] = options.cwd;
options.env["QUARTO_DOCUMENT_PATH"] = options.cwd;
options.env["QUARTO_DOCUMENT_FILE"] = basename(options.target.source);
}
};
4 changes: 4 additions & 0 deletions src/execute/jupyter/jupyter-kernel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export async function executeKernelOneshot(
"execute",
{ ...options, debug },
options.kernelspec,
options.env,
);

if (!result.success) {
Expand Down Expand Up @@ -186,6 +187,7 @@ async function execJupyter(
command: string,
options: Record<string, unknown>,
kernelspec: JupyterKernelspec,
env: Record<string, string> = {},
): Promise<ProcessResult> {
try {
const cmd = await pythonExec(kernelspec);
Expand All @@ -196,6 +198,7 @@ async function execJupyter(
...cmd.slice(1),
resourcePath("jupyter/jupyter.py"),
],
// FIXME IS THIS NOT SET WITH THE DAEMON?
env: {
// Force default matplotlib backend. something simillar is done here:
// https://github.com/ipython/ipykernel/blob/d7339c2c70115bbe6042880d29eeb273b5a2e350/ipykernel/kernelapp.py#L549-L554
Expand All @@ -206,6 +209,7 @@ async function execJupyter(
// function within the notebook
"MPLBACKEND": "module://matplotlib_inline.backend_inline",
"PYDEVD_DISABLE_FILE_VALIDATION": "1",
...env,
},
stdout: "piped",
},
Expand Down
4 changes: 4 additions & 0 deletions src/execute/rmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ export const knitrEngine: ExecutionEngine = {

return output;
},
true,
options.env,
);
const includes = result.includes as unknown;
// knitr appears to return [] instead of {} as the value for includes.
Expand Down Expand Up @@ -256,6 +258,7 @@ async function callR<T>(
quiet?: boolean,
outputFilter?: (output: string) => string,
reportError = true,
env?: Record<string, string>,
): Promise<T> {
// establish cwd for our R scripts (the current dir if there is an renv
// otherwise the project dir if specified)
Expand Down Expand Up @@ -288,6 +291,7 @@ async function callR<T>(
...rscriptArgsArray,
resourcePath("rmd/rmd.R"),
],
env,
cwd,
stderr: quiet ? "piped" : "inherit",
},
Expand Down
1 change: 1 addition & 0 deletions src/execute/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export interface ExecutionTarget {

// execute options
export interface ExecuteOptions {
env: Record<string, string>;
target: ExecutionTarget;
format: Format;
resourceDir: string;
Expand Down
33 changes: 5 additions & 28 deletions src/quarto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,11 @@ const checkReconfiguration = async () => {
}
};

const passThroughPandoc = async (
args: string[],
env?: Record<string, string>,
) => {
const passThroughPandoc = async (args: string[]) => {
const result = await execProcess(
{
cmd: pandocBinaryPath(),
args: args.slice(1),
env,
},
undefined,
undefined,
Expand All @@ -95,10 +91,7 @@ const passThroughPandoc = async (
Deno.exit(result.code);
};

const passThroughTypst = async (
args: string[],
env?: Record<string, string>,
) => {
const passThroughTypst = async (args: string[]) => {
if (args[1] === "update") {
error(
"The 'typst update' command is not supported.\n" +
Expand All @@ -109,28 +102,26 @@ const passThroughTypst = async (
const result = await execProcess({
cmd: typstBinaryPath(),
args: args.slice(1),
env,
});
Deno.exit(result.code);
};

export async function quarto(
args: string[],
cmdHandler?: (command: Command) => Command,
env?: Record<string, string>,
) {
await checkReconfiguration();
checkVersionRequirement();
if (args[0] === "pandoc" && args[1] !== "help") {
await passThroughPandoc(args, env);
await passThroughPandoc(args);
}
if (args[0] === "typst") {
await passThroughTypst(args, env);
await passThroughTypst(args);
}

// passthrough to run handlers
if (args[0] === "run" && args[1] !== "help" && args[1] !== "--help") {
const result = await runScript(args.slice(1), env);
const result = await runScript(args.slice(1));
Deno.exit(result.code);
}

Expand All @@ -155,13 +146,6 @@ export async function quarto(

debug("Quarto version: " + quartoConfig.version());

const oldEnv: Record<string, string | undefined> = {};
for (const [key, value] of Object.entries(env || {})) {
const oldV = Deno.env.get(key);
oldEnv[key] = oldV;
Deno.env.set(key, value);
}

const quartoCommand = new Command()
.name("quarto")
.help({ colors: false })
Expand Down Expand Up @@ -191,13 +175,6 @@ export async function quarto(

try {
await promise;
for (const [key, value] of Object.entries(oldEnv)) {
if (value === undefined) {
Deno.env.delete(key);
} else {
Deno.env.set(key, value);
}
}
if (commandFailed()) {
exitWithCleanup(1);
}
Expand Down
1 change: 1 addition & 0 deletions tests/smoke/env/install.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ testQuartoCmd(
[
noErrorsOrWarnings,
printsMessage({level: "INFO", regex: /tinytex\s+/}),
// FIXME WE SHOULD BE ABLE TO TURN THIS BACK ON
// printsMessage({level: "INFO", regex: /chromium\s+/}),
// temporarily disabled until we get puppeteer back
],
Expand Down
4 changes: 4 additions & 0 deletions tests/smoke/extensions/extension-render-journals.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ for (const journalRepo of journalRepos) {
// Sets up the test
setup: async () => {
console.log(`using quarto-journals/${journalRepo.repo}`);

// FIXME THIS DOESN'T WORK
// WE CANNOT GUARANTEE THAT CHDIR WILL BE CONSTANT
// THROUGHOUT THE ASYNC CALL
const wd = Deno.cwd();
Deno.chdir(workingDir);
await quarto([
Expand Down
38 changes: 19 additions & 19 deletions tests/smoke/project/project-prepost.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { docs } from "../../utils.ts";

import { join } from "../../../src/deno_ral/path.ts";
import { existsSync } from "../../../src/deno_ral/fs.ts";
import { testQuartoCmd } from "../../test.ts";
import { testQuartoCmd, testQuartoCmdWithEnv } from "../../test.ts";
import { fileExists, noErrors, printsMessage, verifyNoPath, verifyPath } from "../../verify.ts";
import { normalizePath, safeRemoveIfExists } from "../../../src/core/path.ts";

Expand Down Expand Up @@ -78,22 +78,22 @@ testQuartoCmd(
}
});

testQuartoCmd(
"render",
[docs("project/prepost/issue-10828")],
[],
{
env: {
"QUARTO_USE_FILE_FOR_PROJECT_INPUT_FILES": normalizePath(docs("project/prepost/issue-10828/input-files.txt")),
"QUARTO_USE_FILE_FOR_PROJECT_OUTPUT_FILES": normalizePath(docs("project/prepost/issue-10828/output-files.txt"))
},
teardown: async () => {
const inputPath = normalizePath(docs("project/prepost/issue-10828/input-files.txt"));
const outputPath = normalizePath(docs("project/prepost/issue-10828/output-files.txt"));
verifyPath(inputPath);
safeRemoveIfExists(inputPath);
verifyPath(outputPath);
safeRemoveIfExists(outputPath);
}
testQuartoCmdWithEnv(
"render",
[docs("project/prepost/issue-10828")],
[],
{
"QUARTO_USE_FILE_FOR_PROJECT_INPUT_FILES": normalizePath(docs("project/prepost/issue-10828/input-files.txt")),
"QUARTO_USE_FILE_FOR_PROJECT_OUTPUT_FILES": normalizePath(docs("project/prepost/issue-10828/output-files.txt"))
},
{
teardown: async () => {
const inputPath = normalizePath(docs("project/prepost/issue-10828/input-files.txt"));
const outputPath = normalizePath(docs("project/prepost/issue-10828/output-files.txt"));
verifyPath(inputPath);
safeRemoveIfExists(inputPath);
verifyPath(outputPath);
safeRemoveIfExists(outputPath);
}
)
}
)
43 changes: 37 additions & 6 deletions tests/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { runningInCI } from "../src/core/ci-info.ts";
import { relative, fromFileUrl } from "../src/deno_ral/path.ts";
import { quartoConfig } from "../src/core/quarto.ts";
import { isWindows } from "../src/deno_ral/platform.ts";
import { execProcess } from "../src/core/process.ts";

export interface TestDescriptor {
// The name of the test
Expand Down Expand Up @@ -55,9 +56,6 @@ export interface TestContext {

// control if test is ran or skipped
ignore?: boolean;

// environment to pass to downstream processes
env?: Record<string, string>;
}

// Allow to merge test contexts in Tests helpers
Expand Down Expand Up @@ -95,11 +93,44 @@ export function mergeTestContexts(baseContext: TestContext, additionalContext?:
},
// override ignore if provided
ignore: additionalContext.ignore ?? baseContext.ignore,
// merge env with additional context taking precedence
env: { ...baseContext.env, ...additionalContext.env },
};
}

// for Quarto tests that new to change the environment,
// we use a subprocess call to run the command, or else we risk
// race conditions with environment variables overwriting
// each other
export function testQuartoCmdWithEnv(
cmd: string,
args: string[],
verify: Verify[],
env: Record<string, string>,
context?: TestContext,
name?: string
) {
if (name === undefined) {
name = `quarto ${cmd} ${args.join(" ")}`;
}
test({
name,
execute: async () => {
const timeout = new Promise((_resolve, reject) => {
setTimeout(reject, 600000, "timed out after 10 minutes");
});
await Promise.race([
execProcess({
cmd: [quartoConfig.binPath(), cmd, ...args],
env
}),
timeout,
]);
},
verify,
context: context || {},
type: "smoke",
});
}

export function testQuartoCmd(
cmd: string,
args: string[],
Expand All @@ -117,7 +148,7 @@ export function testQuartoCmd(
setTimeout(reject, 600000, "timed out after 10 minutes");
});
await Promise.race([
quarto([cmd, ...args], undefined, context?.env),
quarto([cmd, ...args]),
timeout,
]);
},
Expand Down
Loading