Skip to content

Commit 7ea3aae

Browse files
committed
windows: when necessary, discover R using registry curent version
Note that R_HOME and any version of R on the PATH are preferred to what is in the registry. Note also that R front ends like RStudio and R GUI will automatially set R_HOME, so when Quarto is run from within these environments it will use the same version of R as the host session.
1 parent c0ca049 commit 7ea3aae

File tree

4 files changed

+89
-7
lines changed

4 files changed

+89
-7
lines changed

src/core/knitr.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export async function knitrCapabilities() {
2424
try {
2525
const result = await execProcess({
2626
cmd: [
27-
rBinaryPath("Rscript"),
27+
await rBinaryPath("Rscript"),
2828
resourcePath("capabilities/knitr.R"),
2929
],
3030
stdout: "piped",

src/core/registry.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* registry.ts
3+
*
4+
* Copyright (C) 2020 by RStudio, PBC
5+
*
6+
*/
7+
8+
import { execProcess } from "./process.ts";
9+
10+
export const kHKeyCurrentUser = "HKCU";
11+
export const kHKeyLocalMachine = "HKLM";
12+
13+
export async function registryReadString(
14+
root: string | string[],
15+
key: string,
16+
value: string,
17+
): Promise<string | undefined> {
18+
// if an array is passed then call each one in turn
19+
if (Array.isArray(root)) {
20+
for (const r of root) {
21+
const val = registryReadString(r, key, value);
22+
if (val !== undefined) {
23+
return val;
24+
}
25+
}
26+
return undefined;
27+
}
28+
29+
// run reg query
30+
const kTypeString = "REG_SZ";
31+
const cmd = [
32+
"reg",
33+
"query",
34+
`${root}\\${key}`,
35+
"/v",
36+
value,
37+
];
38+
const result = await execProcess({
39+
cmd,
40+
stdout: "piped",
41+
});
42+
if (result.success && result.stdout) {
43+
const typePos = result.stdout?.indexOf(kTypeString);
44+
if (typePos !== -1) {
45+
return result.stdout.substring(typePos + kTypeString.length).trim();
46+
}
47+
}
48+
return undefined;
49+
}

src/core/resources.ts

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@
77

88
import { existsSync, walkSync } from "fs/mod.ts";
99
import { join } from "path/mod.ts";
10+
import { which } from "./path.ts";
1011
import { quartoConfig } from "./quarto.ts";
12+
import {
13+
kHKeyCurrentUser,
14+
kHKeyLocalMachine,
15+
registryReadString,
16+
} from "./registry.ts";
1117

1218
export function resourcePath(resource?: string): string {
1319
const sharePath = quartoConfig.sharePath();
@@ -26,13 +32,40 @@ export function binaryPath(binary: string): string {
2632
return join(quartoConfig.binPath(), binary);
2733
}
2834

29-
export function rBinaryPath(binary: string): string {
35+
export async function rBinaryPath(binary: string): Promise<string> {
36+
// if there is an R_HOME then respect that
3037
const rHome = Deno.env.get("R_HOME");
3138
if (rHome) {
32-
// If there is an R_HOME, respect that.
3339
return join(rHome, "bin", binary);
34-
} else if (Deno.build.os === "windows") {
35-
// On windows, try to find R in program files
40+
}
41+
42+
// then check the path
43+
const path = await which(binary);
44+
if (path) {
45+
return path;
46+
}
47+
48+
// on windows check the registry for a current version
49+
if (Deno.build.os === "windows") {
50+
// determine current version
51+
const version = await registryReadString(
52+
[kHKeyLocalMachine, kHKeyCurrentUser],
53+
"Software\\R-core\\R",
54+
"Current Version",
55+
);
56+
// determine path to version
57+
if (version) {
58+
const installPath = await registryReadString(
59+
[kHKeyLocalMachine, kHKeyCurrentUser],
60+
`Software\\R-core\\R\\${version}`,
61+
"InstallPath",
62+
);
63+
if (installPath) {
64+
return join(installPath, "bin", binary);
65+
}
66+
}
67+
68+
// last ditch, try to find R in program files
3669
const progFiles = Deno.env.get("programfiles");
3770
if (progFiles) {
3871
// Search program files for the binary
@@ -49,7 +82,7 @@ export function rBinaryPath(binary: string): string {
4982
}
5083
}
5184

52-
// We couldn't find R, just pass the binary itself and hope its on the path!
85+
// We couldn't find R, just pass the binary itself and hope it works out!
5386
return binary;
5487
}
5588

src/execute/rmd.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ async function callR<T>(
145145
const result = await execProcess(
146146
{
147147
cmd: [
148-
rBinaryPath("Rscript"),
148+
await rBinaryPath("Rscript"),
149149
resourcePath("rmd/rmd.R"),
150150
],
151151
stderr: quiet ? "piped" : "inherit",

0 commit comments

Comments
 (0)