Skip to content

Commit cbb69d0

Browse files
committed
Fix2 for issues identified in peer review
Improves error handling during initial environment setup for the CDS extractor. Ensures that error codes are used when exiting due to an error in the configuration of the CDS extractor. Minor refactoring of index-files.ts script in order to migrate environment setup tasks to dedicated functions with associated unit tests. Migrates response-file checking and related logic to a dedicated 'getCdsFilePathsToProcess` function, which also helps to prepare for dropping the "index-files" approach in favor of an "autobuild" based approach.
1 parent 686feb6 commit cbb69d0

File tree

5 files changed

+350
-77
lines changed

5 files changed

+350
-77
lines changed

extractors/cds/tools/index-files.ts

Lines changed: 30 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,14 @@
11
import { addCompilationDiagnostic, compileCdsToJson, determineCdsCommand } from './src/cdsCompiler';
2-
import { runJavaScriptExtractor, validateRequirements } from './src/codeql';
3-
import {
4-
configureLgtmIndexFilters,
5-
getAutobuildScriptPath,
6-
getCodeQLExePath,
7-
getJavaScriptExtractorRoot,
8-
getPlatformInfo,
9-
setupJavaScriptExtractorEnv,
10-
} from './src/environment';
11-
import { dirExists, readResponseFile } from './src/filesystem';
2+
import { runJavaScriptExtractor } from './src/codeql';
3+
import { configureLgtmIndexFilters, setupAndValidateEnvironment } from './src/environment';
4+
import { getCdsFilePathsToProcess } from './src/filesystem';
125
import { findPackageJsonDirs, installDependencies } from './src/packageManager';
136
import { validateArguments } from './src/utils';
147

158
// Validate arguments to this script.
169
if (!validateArguments(process.argv, 4)) {
17-
process.exit(0);
10+
// Exit with an error code on invalid use of this script.
11+
process.exit(1);
1812
}
1913

2014
// Get command-line (CLI) arguments and store them in named variables for clarity.
@@ -26,73 +20,37 @@ const sourceRoot: string = process.argv[3];
2620
process.chdir(sourceRoot);
2721

2822
console.log(`Indexing CDS files in project source directory: ${sourceRoot}`);
29-
const { platform: osPlatform, arch: osPlatformArch } = getPlatformInfo();
30-
console.log(`Detected OS platform=${osPlatform} : arch=${osPlatformArch}`);
3123

32-
// Get the `codeql` (CLI) executable path as this is needed to lookup information
33-
// about the JavaScript extractor (root directory), and to run CodeQL's JavaScript
34-
// extractor via its autobuild script.
35-
const codeqlExePath = getCodeQLExePath();
36-
37-
// Validate that source (code) root directory exists.
38-
if (!dirExists(sourceRoot)) {
39-
const codeqlExe = osPlatform === 'win32' ? 'codeql.exe' : 'codeql';
40-
console.warn(
41-
`'${codeqlExe} database index-files --language cds' terminated early due to internal error: could not find project root directory '${sourceRoot}'.`,
42-
);
43-
process.exit(0);
44-
}
45-
46-
// Setup JavaScript extractor environment.
47-
const jsExtractorRoot = getJavaScriptExtractorRoot(codeqlExePath);
48-
if (!jsExtractorRoot) {
49-
const codeqlExe = osPlatform === 'win32' ? 'codeql.exe' : 'codeql';
24+
// Setup the environment and validate all requirements.
25+
const {
26+
success: envSetupSuccess,
27+
errorMessages,
28+
codeqlExePath,
29+
autobuildScriptPath,
30+
platformInfo,
31+
} = setupAndValidateEnvironment(sourceRoot);
32+
33+
if (!envSetupSuccess) {
34+
const codeqlExe = platformInfo.isWindows ? 'codeql.exe' : 'codeql';
5035
console.warn(
51-
`'${codeqlExe} database index-files --language cds' terminated early as CODEQL_EXTRACTOR_JAVASCRIPT_ROOT environment variable is not set.`,
36+
`'${codeqlExe} database index-files --language cds' terminated early due to: ${errorMessages.join(
37+
', ',
38+
)}.`,
5239
);
53-
process.exit(0);
40+
// Exit with an error code when environment setup fails.
41+
process.exit(1);
5442
}
5543

56-
// Set environment variables for JavaScript extractor.
57-
process.env.CODEQL_EXTRACTOR_JAVASCRIPT_ROOT = jsExtractorRoot;
58-
setupJavaScriptExtractorEnv();
59-
60-
// Get autobuild script path.
61-
const autobuildScriptPath = getAutobuildScriptPath(jsExtractorRoot);
62-
63-
// Validate all required components.
64-
if (
65-
!validateRequirements(
66-
sourceRoot,
67-
codeqlExePath,
68-
responseFile,
69-
autobuildScriptPath,
70-
jsExtractorRoot,
71-
)
72-
) {
73-
process.exit(0);
44+
// Validate response file and get the fully paths of CDS files to process.
45+
const filePathsResult = getCdsFilePathsToProcess(responseFile, platformInfo);
46+
if (!filePathsResult.success) {
47+
console.warn(filePathsResult.errorMessage);
48+
// Exit with an error if unable to get a list of `.cds` file paths to process.
49+
process.exit(1);
7450
}
7551

76-
// Read and validate response files.
77-
let cdsFilePathsToProcess: string[] = [];
78-
try {
79-
cdsFilePathsToProcess = readResponseFile(responseFile);
80-
if (!cdsFilePathsToProcess.length) {
81-
const codeqlExe = osPlatform === 'win32' ? 'codeql.exe' : 'codeql';
82-
console.warn(
83-
`'${codeqlExe} database index-files --language cds' terminated early as response file '${responseFile}' is empty. This is because no CDS files were selected or found.`,
84-
);
85-
process.exit(0);
86-
}
87-
} catch (err) {
88-
const codeqlExe = osPlatform === 'win32' ? 'codeql.exe' : 'codeql';
89-
console.warn(
90-
`'${codeqlExe} database index-files --language cds' terminated early as response file '${responseFile}' could not be read due to an error: ${String(
91-
err,
92-
)}`,
93-
);
94-
process.exit(0);
95-
}
52+
// Get the validated list of CDS files to process
53+
const cdsFilePathsToProcess = filePathsResult.cdsFilePaths;
9654

9755
// Find all package.json directories that have a `@sap/cds` node dependency.
9856
const packageJsonDirs = findPackageJsonDirs(cdsFilePathsToProcess);
@@ -106,7 +64,7 @@ const cdsCommand = determineCdsCommand();
10664

10765
console.log('Processing CDS files to JSON ...');
10866

109-
// Compile each CDS file to JSON
67+
// Compile each `.cds` file to create a `.cds.json` file.
11068
for (const rawCdsFilePath of cdsFilePathsToProcess) {
11169
try {
11270
// Use resolved path directly instead of passing through getArg

extractors/cds/tools/src/environment.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { execFileSync } from 'child_process';
22
import { arch, platform } from 'os';
33
import { join, resolve } from 'path';
44

5+
import { dirExists } from './filesystem';
6+
57
/**
68
* Interface for platform information
79
*/
@@ -12,6 +14,18 @@ export interface PlatformInfo {
1214
exeExtension: string;
1315
}
1416

17+
/**
18+
* Interface for environment validation results
19+
*/
20+
export interface EnvironmentSetupResult {
21+
success: boolean;
22+
errorMessages: string[];
23+
codeqlExePath: string;
24+
jsExtractorRoot: string;
25+
autobuildScriptPath: string;
26+
platformInfo: PlatformInfo;
27+
}
28+
1529
/**
1630
* Get platform information
1731
* @returns Platform information including OS platform, architecture, and whether it's Windows
@@ -130,3 +144,45 @@ export function configureLgtmIndexFilters(): void {
130144
// Configure to copy over the .cds files as well, by pretending they are JSON.
131145
process.env.LGTM_INDEX_FILETYPES = '.cds:JSON';
132146
}
147+
148+
/**
149+
* Sets up the environment and validates key components for CDS extractor
150+
* @param sourceRoot The source root directory
151+
* @returns The environment setup result
152+
*/
153+
export function setupAndValidateEnvironment(sourceRoot: string): EnvironmentSetupResult {
154+
const errorMessages: string[] = [];
155+
const platformInfo = getPlatformInfo();
156+
157+
// Get the CodeQL executable path
158+
const codeqlExePath = getCodeQLExePath();
159+
160+
// Validate that the required source root directory exists
161+
if (!dirExists(sourceRoot)) {
162+
errorMessages.push(`project root directory '${sourceRoot}' does not exist`);
163+
}
164+
165+
// Setup JavaScript extractor environment
166+
const jsExtractorRoot = getJavaScriptExtractorRoot(codeqlExePath);
167+
if (!jsExtractorRoot) {
168+
errorMessages.push(`CODEQL_EXTRACTOR_JAVASCRIPT_ROOT environment variable is not set`);
169+
}
170+
171+
// Set environment variables for JavaScript extractor
172+
if (jsExtractorRoot) {
173+
process.env.CODEQL_EXTRACTOR_JAVASCRIPT_ROOT = jsExtractorRoot;
174+
setupJavaScriptExtractorEnv();
175+
}
176+
177+
// Get autobuild script path
178+
const autobuildScriptPath = jsExtractorRoot ? getAutobuildScriptPath(jsExtractorRoot) : '';
179+
180+
return {
181+
success: errorMessages.length === 0,
182+
errorMessages,
183+
codeqlExePath,
184+
jsExtractorRoot,
185+
autobuildScriptPath,
186+
platformInfo,
187+
};
188+
}

extractors/cds/tools/src/filesystem.ts

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
import { existsSync, readdirSync, readFileSync, renameSync, statSync } from 'fs';
22
import { format, join, parse } from 'path';
33

4+
/**
5+
* Check if a directory exists
6+
* @param dirPath Path to the directory to check
7+
* @returns True if the directory exists, false otherwise
8+
*/
9+
export function dirExists(dirPath: string): boolean {
10+
return existsSync(dirPath) && statSync(dirPath).isDirectory();
11+
}
12+
413
/**
514
* Check if a file exists and can be read
615
* @param filePath Path to the file to check
@@ -11,12 +20,59 @@ export function fileExists(filePath: string): boolean {
1120
}
1221

1322
/**
14-
* Check if a directory exists
15-
* @param dirPath Path to the directory to check
16-
* @returns True if the directory exists, false otherwise
23+
* Read and validate a response file to get the list of CDS files to process
24+
* @param responseFile Path to the response file
25+
* @param platformInfo Platform information object with isWindows property
26+
* @returns Object containing success status, CDS file paths to process, and error message if any
1727
*/
18-
export function dirExists(dirPath: string): boolean {
19-
return existsSync(dirPath) && statSync(dirPath).isDirectory();
28+
export function getCdsFilePathsToProcess(
29+
responseFile: string,
30+
platformInfo: { isWindows: boolean },
31+
): {
32+
success: boolean;
33+
cdsFilePaths: string[];
34+
errorMessage?: string;
35+
} {
36+
// First validate the response file exists
37+
const responseFileValidation = validateResponseFile(responseFile);
38+
if (!responseFileValidation.success) {
39+
return {
40+
success: false,
41+
cdsFilePaths: [],
42+
errorMessage: `'${
43+
platformInfo.isWindows ? 'codeql.exe' : 'codeql'
44+
} database index-files --language cds' terminated early as ${responseFileValidation.errorMessage}`,
45+
};
46+
}
47+
48+
// Now read the file paths from the response file
49+
try {
50+
const cdsFilePathsToProcess = readResponseFile(responseFile);
51+
52+
// Check if there are any file paths to process
53+
if (!cdsFilePathsToProcess.length) {
54+
return {
55+
success: false,
56+
cdsFilePaths: [],
57+
errorMessage: `'${
58+
platformInfo.isWindows ? 'codeql.exe' : 'codeql'
59+
} database index-files --language cds' terminated early as response file '${responseFile}' is empty. This is because no CDS files were selected or found.`,
60+
};
61+
}
62+
63+
return {
64+
success: true,
65+
cdsFilePaths: cdsFilePathsToProcess,
66+
};
67+
} catch (err) {
68+
return {
69+
success: false,
70+
cdsFilePaths: [],
71+
errorMessage: `'${
72+
platformInfo.isWindows ? 'codeql.exe' : 'codeql'
73+
} database index-files --language cds' terminated early as response file '${responseFile}' could not be read due to an error: ${String(err)}`,
74+
};
75+
}
2076
}
2177

2278
/**
@@ -72,3 +128,21 @@ export function recursivelyRenameJsonFiles(dirPath: string): void {
72128
}
73129
}
74130
}
131+
132+
/**
133+
* Validate a response file exists and can be read
134+
* @param responseFile Path to the response file
135+
* @returns Object containing success status and error message if any
136+
*/
137+
export function validateResponseFile(responseFile: string): {
138+
success: boolean;
139+
errorMessage?: string;
140+
} {
141+
if (!fileExists(responseFile)) {
142+
return {
143+
success: false,
144+
errorMessage: `response file '${responseFile}' does not exist. This is because no CDS files were selected or found`,
145+
};
146+
}
147+
return { success: true };
148+
}

0 commit comments

Comments
 (0)