|
3 | 3 | import * as fs from 'fs'; |
4 | 4 | import * as path from 'path'; |
5 | 5 | import { Uri, window } from 'vscode'; |
6 | | -import { getRpath, getCurrentWorkspaceFolder, executeRCommand, createTempDir } from './util'; |
7 | | -import { execSync } from 'child_process'; |
| 6 | +import { |
| 7 | + getRpath, |
| 8 | + getCurrentWorkspaceFolder, |
| 9 | + executeRCommand, |
| 10 | + createTempDir, |
| 11 | + spawnAsync, |
| 12 | + ToRStringLiteral, |
| 13 | +} from './util'; |
8 | 14 | import { extensionContext } from './extension'; |
9 | 15 |
|
10 | 16 | export async function generateCppProperties(): Promise<void> { |
@@ -52,25 +58,33 @@ async function generateCppPropertiesProc(workspaceFolder: string) { |
52 | 58 | }); |
53 | 59 | } |
54 | 60 |
|
55 | | - const compileOutputCpp = collectCompilerOutput(rPath, workspaceFolder, 'cpp'); |
56 | | - const compileOutputC = collectCompilerOutput(rPath, workspaceFolder, 'c'); |
57 | | - |
58 | | - if (fs.existsSync(path.join(workspaceFolder, cleanupFile))) { |
59 | | - await executeRCommand(`system("sh ./${cleanupFile}")`, workspaceFolder, (e: Error) => { |
60 | | - void window.showErrorMessage(e.message); |
61 | | - return ''; |
62 | | - }); |
| 61 | + let compileOutputCpp: string; |
| 62 | + let compileOutputC: string; |
| 63 | + try { |
| 64 | + compileOutputCpp = await collectCompilerOutput(rPath, workspaceFolder, 'cpp'); |
| 65 | + compileOutputC = await collectCompilerOutput(rPath, workspaceFolder, 'c'); |
| 66 | + } finally { |
| 67 | + if (fs.existsSync(path.join(workspaceFolder, cleanupFile))) { |
| 68 | + await executeRCommand(`system("sh ./${cleanupFile}")`, workspaceFolder, (e: Error) => { |
| 69 | + void window.showErrorMessage(e.message); |
| 70 | + return ''; |
| 71 | + }); |
| 72 | + } |
63 | 73 | } |
64 | 74 |
|
65 | 75 | const compileInfo = extractCompilerInfo(compileOutputCpp); |
66 | 76 | const compileStdCpp = extractCompilerStd(compileOutputCpp); |
67 | 77 | const compileStdC = extractCompilerStd(compileOutputC); |
68 | 78 | const compileCall = extractCompilerCall(compileOutputCpp); |
69 | 79 | const compilerPath = compileCall |
70 | | - ? await executeRCommand(`cat(Sys.which("${compileCall}"))`, workspaceFolder, (e: Error) => { |
71 | | - void window.showErrorMessage(e.message); |
72 | | - return ''; |
73 | | - }) |
| 80 | + ? await executeRCommand( |
| 81 | + `cat(Sys.which(${ToRStringLiteral(compileCall, '"')}))`, |
| 82 | + workspaceFolder, |
| 83 | + (e: Error) => { |
| 84 | + void window.showErrorMessage(e.message); |
| 85 | + return ''; |
| 86 | + }, |
| 87 | + ) |
74 | 88 | : ''; |
75 | 89 |
|
76 | 90 | const intelliSensePlatform = platformChoose('windows', 'macos', 'linux'); |
@@ -134,10 +148,14 @@ async function collectRLinkingTo(workspaceFolder: string): Promise<string[]> { |
134 | 148 | .asAbsolutePath('R/cppProperties/extractLinkingTo.R') |
135 | 149 | .replace(/\\/g, '/'); |
136 | 150 | const linkingToIncludesStr = ( |
137 | | - await executeRCommand(`source('${rScript}')`, workspaceFolder, (e: Error) => { |
138 | | - void window.showErrorMessage(e.message); |
139 | | - return ''; |
140 | | - }) |
| 151 | + await executeRCommand( |
| 152 | + `source(${ToRStringLiteral(rScript, '"')})`, |
| 153 | + workspaceFolder, |
| 154 | + (e: Error) => { |
| 155 | + void window.showErrorMessage(e.message); |
| 156 | + return ''; |
| 157 | + }, |
| 158 | + ) |
141 | 159 | )?.trim(); |
142 | 160 | if (!linkingToIncludesStr || linkingToIncludesStr === '') { |
143 | 161 | return []; |
@@ -190,37 +208,44 @@ function extractCompilerCall(compileOutput: string): string | undefined { |
190 | 208 | } |
191 | 209 |
|
192 | 210 | const m = ccalls[1].match(rxComp); |
193 | | - return m?.[1]; |
| 211 | + return m ? ensureUnquoted(m[1]) : undefined; |
194 | 212 | } |
195 | 213 |
|
196 | | -function collectCompilerOutput(rPath: string, workspaceFolder: string, testExtension: 'cpp' | 'c') { |
| 214 | +async function collectCompilerOutput( |
| 215 | + rPath: string, |
| 216 | + workspaceFolder: string, |
| 217 | + testExtension: 'cpp' | 'c', |
| 218 | +): Promise<string> { |
197 | 219 | const makevarsFiles = ['Makevars', 'Makevars.win', 'Makevars.ucrt']; |
198 | 220 |
|
199 | 221 | const srcFolder = path.join(workspaceFolder, 'src'); |
200 | 222 | const tempFolder = createTempDir(workspaceFolder); |
201 | 223 |
|
202 | | - // Copy makevars |
203 | | - if (fs.existsSync(srcFolder)) { |
204 | | - const projectMakevarsFiles = fs |
205 | | - .readdirSync(srcFolder) |
206 | | - .filter((fn) => makevarsFiles.includes(fn)); |
207 | | - for (const f of projectMakevarsFiles) { |
208 | | - fs.copyFileSync(path.join(srcFolder, f), path.join(tempFolder, f)); |
| 224 | + try { |
| 225 | + // Copy makevars |
| 226 | + if (fs.existsSync(srcFolder)) { |
| 227 | + const projectMakevarsFiles = fs |
| 228 | + .readdirSync(srcFolder) |
| 229 | + .filter((fn) => makevarsFiles.includes(fn)); |
| 230 | + for (const f of projectMakevarsFiles) { |
| 231 | + fs.copyFileSync(path.join(srcFolder, f), path.join(tempFolder, f)); |
| 232 | + } |
209 | 233 | } |
210 | | - } |
211 | | - |
212 | | - // Create dummy source file |
213 | | - const testFile = `comp_test.${testExtension}`; |
214 | | - fs.writeFileSync(path.join(tempFolder, testFile), ''); |
215 | | - |
216 | | - // Compile dummy |
217 | | - const command = `"${rPath}" CMD SHLIB ${testFile}`; |
218 | | - const compileOutput = execSync(command, { |
219 | | - cwd: tempFolder, |
220 | | - }).toString(); |
221 | 234 |
|
222 | | - // Cleanup |
223 | | - fs.rmSync(tempFolder, { recursive: true, force: true }); |
224 | | - |
225 | | - return compileOutput; |
| 235 | + // Create dummy source file |
| 236 | + const testFile = `comp_test.${testExtension}`; |
| 237 | + fs.writeFileSync(path.join(tempFolder, testFile), ''); |
| 238 | + |
| 239 | + // Compile dummy |
| 240 | + const result = await spawnAsync(rPath, ['CMD', 'SHLIB', testFile], { cwd: tempFolder }); |
| 241 | + if (result.status !== 0) { |
| 242 | + throw ( |
| 243 | + result.error ?? |
| 244 | + new Error(result.stderr || 'Could not determine R compiler settings.') |
| 245 | + ); |
| 246 | + } |
| 247 | + return result.stdout; |
| 248 | + } finally { |
| 249 | + fs.rmSync(tempFolder, { recursive: true, force: true }); |
| 250 | + } |
226 | 251 | } |
0 commit comments