Skip to content

Commit baba8f2

Browse files
committed
R --version & reduced process creation
- Use R --version for details - Only create executables when calling refreshPaths()
1 parent 05b11ee commit baba8f2

File tree

5 files changed

+81
-62
lines changed

5 files changed

+81
-62
lines changed

src/executables/executable.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { getVersionFromPath, getArchitectureFromPath } from './locator';
1+
import { getRDetailsFromPath } from './locator';
22

33
export class RExecutableFactory {
44
static createExecutable(executablePath: string): RExecutable {
@@ -20,9 +20,10 @@ export class RExecutable {
2020
private _arch: string;
2121

2222
constructor(bin_path: string) {
23+
const details = getRDetailsFromPath(bin_path);
2324
this._rBin = bin_path;
24-
this._rVersion = getVersionFromPath(bin_path);
25-
this._arch = getArchitectureFromPath(bin_path);
25+
this._rVersion = details.version;
26+
this._arch = details.arch;
2627
}
2728

2829
public get rBin(): string {

src/executables/locator/shared.ts

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,26 @@
1-
import path = require('path');
2-
import * as fs from 'fs-extra';
1+
import { execSync } from 'child_process';
2+
import { RExecutable } from '../executable';
33

4-
export function getVersionFromPath(rPath: string): string {
5-
if (process.platform === 'win32') {
6-
// not sure how to do this
7-
return '';
8-
} else {
9-
try {
10-
const scriptPath = path.normalize(`${rPath}/../Rcmd`);
11-
const rCmdFile = fs.readFileSync(scriptPath, 'utf-8');
12-
const regex = /(?<=R_VERSION=)[0-9.]*/g;
13-
const version = regex.exec(rCmdFile)?.[0];
14-
return version ?? '';
15-
} catch (error) {
16-
return '';
17-
}
18-
}
19-
}
20-
21-
export function getArchitectureFromPath(path: string): string {
22-
if (process.platform === 'win32') {
23-
// \\bin\\i386 = 32bit
24-
// \\bin\\x64 = 64bit
25-
return '';
26-
} else {
27-
return '64-bit';
4+
export function getRDetailsFromPath(rPath: string): {version: string, arch: string} {
5+
try {
6+
const child = execSync(`${rPath} --version`).toString();
7+
const versionRegex = /(?<=R version\s)[0-9.]*/g;
8+
const archRegex = /[0-9]*-bit/g;
9+
const out = {
10+
version: child.match(versionRegex)?.[0] ?? '',
11+
arch: child.match(archRegex)?.[0] ?? ''
12+
};
13+
return out;
14+
} catch (error) {
15+
return { version: '', arch: '' };
2816
}
2917
}
3018

3119
export abstract class AbstractLocatorService {
32-
protected binary_paths: string[];
33-
public abstract get hasBinaries(): boolean;
34-
public abstract get binaries(): string[];
20+
protected _binaryPaths: string[];
21+
protected _executables: RExecutable[];
22+
public abstract get hasExecutables(): boolean;
23+
public abstract get executables(): RExecutable[];
24+
public abstract get binaryPaths(): string[];
3525
public abstract refreshPaths(): void;
3626
}

src/executables/locator/unix.ts

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,53 @@
11
import * as fs from 'fs-extra';
22
import * as os from 'os';
33
import path = require('path');
4+
import { RExecutable, RExecutableFactory } from '../executable';
45

56
import { AbstractLocatorService } from './shared';
67

78
export class UnixExecLocator extends AbstractLocatorService {
8-
public get hasBinaries(): boolean {
9-
return this.binary_paths.length > 0;
9+
constructor() {
10+
super();
11+
this._binaryPaths = [];
12+
this._executables = [];
1013
}
11-
public get binaries(): string[] {
12-
return this.binary_paths;
14+
public get hasExecutables(): boolean {
15+
return this._executables.length > 0;
16+
}
17+
public get executables(): RExecutable[] {
18+
return this._executables;
19+
}
20+
public get binaryPaths(): string[] {
21+
return this._binaryPaths;
1322
}
1423
public refreshPaths(): void {
15-
this.binary_paths = Array.from(
24+
const paths = Array.from(
1625
new Set([
1726
...this.getHomeFromDirs(),
1827
...this.getHomeFromEnv(),
1928
... this.getHomeFromConda()
2029
])
2130
);
31+
for (const path of paths) {
32+
if (!this._binaryPaths?.includes(path)) {
33+
this._binaryPaths.push(path);
34+
this._executables.push(RExecutableFactory.createExecutable(path));
35+
}
36+
}
2237
}
2338

24-
private potential_bin_paths: string[] = [
25-
'/usr/lib64/R/bin/R',
26-
'/usr/lib/R/bin/R',
27-
'/usr/local/lib64/R/bin/R',
28-
'/usr/local/lib/R/bin/R',
29-
'/opt/local/lib64/R/bin/R',
30-
'/opt/local/lib/R/bin/R'
31-
];
32-
3339
private getHomeFromDirs(): string[] {
3440
const dirBins: string[] = [];
35-
for (const bin of this.potential_bin_paths) {
41+
const potentialPaths: string[] = [
42+
'/usr/lib64/R/bin/R',
43+
'/usr/lib/R/bin/R',
44+
'/usr/local/lib64/R/bin/R',
45+
'/usr/local/lib/R/bin/R',
46+
'/opt/local/lib64/R/bin/R',
47+
'/opt/local/lib/R/bin/R'
48+
];
49+
50+
for (const bin of potentialPaths) {
3651
if (fs.existsSync(bin)) {
3752
dirBins.push(bin);
3853
}

src/executables/locator/windows.ts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,42 @@
11
import * as fs from 'fs-extra';
2-
import * as os from 'os';
32
import path = require('path');
43
import winreg = require('winreg');
4+
import { RExecutable, RExecutableFactory } from '../executable';
55

66
import { AbstractLocatorService } from './shared';
77

88
export class WindowsExecLocator extends AbstractLocatorService {
9-
public get hasBinaries(): boolean {
10-
return this.binary_paths.length > 0;
9+
constructor() {
10+
super();
11+
this._binaryPaths = [];
12+
this._executables = [];
1113
}
12-
public get binaries(): string[] {
13-
return this.binary_paths;
14+
public get hasExecutables(): boolean {
15+
return this._executables.length > 0;
16+
}
17+
public get executables(): RExecutable[] {
18+
return this._executables;
19+
}
20+
public get binaryPaths(): string[] {
21+
return this._binaryPaths;
1422
}
1523
public refreshPaths(): void {
16-
this.binary_paths = Array.from(
24+
const paths = Array.from(
1725
new Set([
1826
...this.getHomeFromDirs(),
1927
...this.getHomeFromEnv(),
2028
...this.getHomeFromRegistry(),
2129
// ... this.getHomeFromConda()
2230
])
2331
);
32+
for (const path of paths) {
33+
if (!this._binaryPaths?.includes(path)) {
34+
this._binaryPaths.push(path);
35+
this._executables.push(RExecutableFactory.createExecutable(path));
36+
}
37+
}
2438
}
2539

26-
private potential_bin_paths: string[] = [
27-
'%ProgramFiles%\\R\\',
28-
'%ProgramFiles(x86)%\\R\\'
29-
];
30-
3140
private getHomeFromRegistry(): string[] {
3241
const registryBins: string[] = [];
3342
const potentialBins = [
@@ -68,7 +77,11 @@ export class WindowsExecLocator extends AbstractLocatorService {
6877

6978
private getHomeFromDirs(): string[] {
7079
const dirBins: string[] = [];
71-
for (const bin of this.potential_bin_paths) {
80+
const potential_bin_paths: string[] = [
81+
'%ProgramFiles%\\R\\',
82+
'%ProgramFiles(x86)%\\R\\'
83+
];
84+
for (const bin of potential_bin_paths) {
7285
const resolvedBin = path.resolve(bin);
7386
if (fs.existsSync(resolvedBin)) {
7487
const i386 = `${resolvedBin}\\i386\\`;

src/executables/ui/quickpick.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,9 @@ export class ExecutableQuickPick implements vscode.Disposable {
8484
}
8585
);
8686

87-
this.retriever.binaries.forEach(home => {
87+
this.retriever.binaryPaths.forEach(home => {
8888
if (validateRFolder(home)) {
89-
const inst = RExecutableFactory.createExecutable(home);
90-
executables.push(inst);
89+
executables.push(this.retriever.executables.filter(exec => exec.rBin === home)?.[0]);
9190
}
9291
});
9392
sortBins(executables).forEach((bin: RExecutable) => {
@@ -119,6 +118,7 @@ export class ExecutableQuickPick implements vscode.Disposable {
119118
function setupQuickpickListeners(self: ExecutableQuickPick, resolver: () => void): void {
120119
self.qp.onDidTriggerButton((item: vscode.QuickInputButton) => {
121120
if (item.tooltip === 'Refresh paths') {
121+
self.retriever.refreshPaths();
122122
self.setItems();
123123
self.qp.show();
124124
} else {

0 commit comments

Comments
 (0)