Skip to content

Commit 6412400

Browse files
committed
Improve CDS extractor logging
Cleans up DEBUG logging and improves existing CDS extractor logging in order to provide more useful indications of the CDS compiler version used to compile a given `*.cds.json` file.
1 parent f9e41aa commit 6412400

File tree

8 files changed

+88
-34
lines changed

8 files changed

+88
-34
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,5 @@ tmp/
7171
**.testproj
7272
dbs
7373
*.cds.json
74+
.cds-extractor-cache
75+

extractors/cds/tools/cds-extractor.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,6 @@ process.chdir(sourceRoot);
5959
console.log(
6060
`INFO: CodeQL CDS extractor using run mode '${runMode}' for scan of project source root directory '${sourceRoot}'.`,
6161
);
62-
console.log(`DEBUG: CodeQL executable path: ${codeqlExePath}`);
63-
console.log(`DEBUG: Current working directory: ${process.cwd()}`);
6462

6563
// Only process response file for INDEX_FILES mode
6664
let cdsFilePathsToProcess: string[] = [];
@@ -98,13 +96,8 @@ if (typedProjectMap.__debugParserSuccess) {
9896

9997
// Install dependencies using the new caching approach
10098
console.log('Installing required CDS compiler versions using cached approach...');
101-
console.log(`DEBUG: Before installDependencies - CodeQL path: ${codeqlExePath}`);
102-
console.log(`DEBUG: Current working directory: ${process.cwd()}`);
10399
const projectCacheDirMap = installDependencies(projectMap, sourceRoot, codeqlExePath);
104100

105-
// Determine the CDS command to use.
106-
const cdsCommand = determineCdsCommand();
107-
108101
console.log('Processing CDS files to JSON ...');
109102

110103
// Compile each `.cds` file to create a `.cds.json` file.
@@ -113,9 +106,9 @@ for (const rawCdsFilePath of cdsFilePathsToProcess) {
113106
// Find which project this CDS file belongs to, to use the correct cache directory
114107
const projectDir = findProjectForCdsFile(rawCdsFilePath, sourceRoot, projectMap);
115108
const cacheDir = projectDir ? projectCacheDirMap.get(projectDir) : undefined;
116-
if (cacheDir) {
117-
console.log(`Using cache directory for ${rawCdsFilePath}: ${cacheDir}`);
118-
}
109+
110+
// Determine the CDS command to use based on the cache directory for this specific file
111+
const cdsCommand = determineCdsCommand(cacheDir);
119112

120113
// Use resolved path directly instead of passing through getArg
121114
const compilationResult = compileCdsToJson(rawCdsFilePath, sourceRoot, cdsCommand, cacheDir);
@@ -137,7 +130,6 @@ for (const rawCdsFilePath of cdsFilePathsToProcess) {
137130
// Configure the "LGTM" index filters for proper extraction.
138131
configureLgtmIndexFilters();
139132

140-
console.log(`DEBUG: CODEQL_DIST before runJavaScriptExtractor: ${process.env.CODEQL_DIST}`);
141133
// Run CodeQL's JavaScript extractor to process the compiled JSON files.
142134
const extractorResult = runJavaScriptExtractor(sourceRoot, autobuildScriptPath, codeqlExePath);
143135
if (!extractorResult.success && extractorResult.error) {

extractors/cds/tools/src/cds/compiler/functions.ts

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,28 @@ import { CdsCompilationResult } from './types';
55
import { fileExists, dirExists, recursivelyRenameJsonFiles } from '../../filesystem';
66

77
/**
8-
* Determine the `cds` command to use based on the environment.
8+
* Determine the `cds` command to use based on the environment and cache directory.
9+
* @param cacheDir Optional path to a directory containing installed dependencies
910
* @returns A string representing the CLI command to run to invoke the
1011
* CDS compiler.
1112
*/
12-
export function determineCdsCommand(): string {
13+
export function determineCdsCommand(cacheDir?: string): string {
14+
// If we have a cache directory, use the cds binary from there
15+
if (cacheDir) {
16+
const localCdsBin = join(cacheDir, 'node_modules', '.bin', 'cds');
17+
18+
// Check if the local cds binary exists in the cache directory
19+
if (fileExists(localCdsBin)) {
20+
// We need to use node to execute the local bin directly to ensure correct resolution
21+
return `node "${localCdsBin}"`;
22+
}
23+
24+
// If there's a cache directory but no local binary, use npx with NODE_PATH
25+
return `npx --no-install cds`;
26+
}
27+
28+
// Default behavior when no cache directory is provided
1329
let cdsCommand = 'cds';
14-
// TODO : create a mapping of project sub-directories to the correct
15-
// cds command to use, which will also determine the version of the cds
16-
// compiler that will be used for compiling `.cds` files to `.cds.json`
17-
// files for that sub-directory / project.
1830
try {
1931
execFileSync('cds', ['--version'], { stdio: 'ignore' });
2032
} catch {
@@ -24,6 +36,51 @@ export function determineCdsCommand(): string {
2436
return cdsCommand;
2537
}
2638

39+
/**
40+
* Get the CDS compiler version from a specific command or cache directory
41+
* @param cdsCommand The CDS command to use
42+
* @param cacheDir Optional path to a directory containing installed dependencies
43+
* @returns The CDS compiler version string, or undefined if it couldn't be determined
44+
*/
45+
export function getCdsVersion(cdsCommand: string, cacheDir?: string): string | undefined {
46+
try {
47+
// Set up environment vars if using a cache directory
48+
const spawnOptions: SpawnSyncOptions = {
49+
shell: true,
50+
stdio: 'pipe',
51+
env: { ...process.env },
52+
};
53+
54+
// If a cache directory is provided, set NODE_PATH to use that cache
55+
if (cacheDir) {
56+
const nodePath = join(cacheDir, 'node_modules');
57+
58+
// Set up environment to use the cached dependencies
59+
spawnOptions.env = {
60+
...process.env,
61+
NODE_PATH: `${nodePath}${delimiter}${process.env.NODE_PATH ?? ''}`,
62+
PATH: `${join(nodePath, '.bin')}${delimiter}${process.env.PATH}`,
63+
npm_config_prefix: cacheDir,
64+
};
65+
}
66+
67+
// Execute the CDS command with the --version flag
68+
const result = spawnSync(cdsCommand, ['--version'], spawnOptions);
69+
if (result.status === 0 && result.stdout) {
70+
const versionOutput = result.stdout.toString().trim();
71+
// Extract version number, which is typically in formats like "@sap/cds: 6.1.3" or similar
72+
const match = versionOutput.match(/@sap\/cds[^0-9]*([0-9]+\.[0-9]+\.[0-9]+)/);
73+
if (match?.[1]) {
74+
return match[1]; // Return just the version number
75+
}
76+
return versionOutput; // Return full output if we couldn't parse it
77+
}
78+
return undefined;
79+
} catch {
80+
return undefined;
81+
}
82+
}
83+
2784
/**
2885
* Compile a CDS file to JSON
2986
* @param cdsFilePath Path to the CDS file
@@ -45,23 +102,33 @@ export function compileCdsToJson(
45102
}
46103

47104
const cdsJsonOutPath = `${resolvedCdsFilePath}.json`;
48-
console.log(`Processing CDS file ${resolvedCdsFilePath} to ${cdsJsonOutPath} ...`);
105+
106+
// Get and log the CDS version
107+
const cdsVersion = getCdsVersion(cdsCommand, cacheDir);
108+
const versionInfo = cdsVersion ? `with CDS v${cdsVersion}` : '';
109+
console.log(`Processing CDS file ${resolvedCdsFilePath} ${versionInfo}...`);
49110

50111
// Prepare spawn options
51112
const spawnOptions: SpawnSyncOptions = {
52113
cwd: sourceRoot,
53114
shell: true,
54115
stdio: 'pipe',
116+
env: { ...process.env },
55117
};
56118

57119
// If a cache directory is provided, set NODE_PATH to use that cache
58120
if (cacheDir) {
59121
const nodePath = join(cacheDir, 'node_modules');
122+
123+
// Set up environment to use the cached dependencies
60124
spawnOptions.env = {
61125
...process.env,
62126
NODE_PATH: `${nodePath}${delimiter}${process.env.NODE_PATH ?? ''}`,
63127
PATH: `${join(nodePath, '.bin')}${delimiter}${process.env.PATH}`,
128+
// Add NPM configuration to ensure dependencies are resolved from the cache directory
129+
npm_config_prefix: cacheDir,
64130
};
131+
65132
console.log(`Using cached dependencies from: ${cacheDir}`);
66133
}
67134

extractors/cds/tools/src/codeql.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export function runJavaScriptExtractor(
4141
});
4242

4343
if (result.error) {
44-
const errorMessage = `Error executing JavaScript extractor: ${result.error.message}`;
44+
const errorMessage = `Error running JavaScript extractor: ${result.error.message}`;
4545
if (codeqlExePath) {
4646
addJavaScriptExtractorDiagnostic(sourceRoot, errorMessage, codeqlExePath);
4747
}
@@ -52,7 +52,7 @@ export function runJavaScriptExtractor(
5252
}
5353

5454
if (result.status !== 0) {
55-
const errorMessage = `JavaScript extractor failed with exit code: ${String(result.status)}`;
55+
const errorMessage = `JavaScript extractor failed with exit code ${String(result.status)}`;
5656
if (codeqlExePath) {
5757
addJavaScriptExtractorDiagnostic(sourceRoot, errorMessage, codeqlExePath);
5858
}

extractors/cds/tools/src/environment.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,6 @@ export function getJavaScriptExtractorRoot(codeqlExePath: string): string {
149149
return '';
150150
}
151151

152-
console.log(
153-
`DEBUG: Attempting to resolve JavaScript extractor root with codeqlExePath: ${codeqlExePath}`,
154-
);
155-
console.log(`DEBUG: Current working directory: ${process.cwd()}`);
156152
try {
157153
jsExtractorRoot = execFileSync(
158154
codeqlExePath,

extractors/cds/tools/src/filesystem.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,10 @@ export function readResponseFile(responseFile: string): string[] {
101101
export function recursivelyRenameJsonFiles(dirPath: string): void {
102102
// Make sure the directory exists
103103
if (!dirExists(dirPath)) {
104-
console.log(`Directory not found or not a directory: ${dirPath}`);
104+
console.log(`Directory not found: ${dirPath}`);
105105
return;
106106
}
107-
108-
console.log(`Processing JSON files in output directory: ${dirPath}`);
107+
console.log(`Processing JSON files in directory: ${dirPath}`);
109108

110109
// Get all entries in the directory
111110
const entries = readdirSync(dirPath, { withFileTypes: true });

extractors/cds/tools/test/src/codeql.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ describe('codeql', () => {
157157

158158
expect(result).toEqual({
159159
success: false,
160-
error: 'Error executing JavaScript extractor: Failed to execute',
160+
error: 'Error running JavaScript extractor: Failed to execute',
161161
});
162162
});
163163

@@ -175,7 +175,7 @@ describe('codeql', () => {
175175

176176
expect(result).toEqual({
177177
success: false,
178-
error: 'JavaScript extractor failed with exit code: 1',
178+
error: 'JavaScript extractor failed with exit code 1',
179179
});
180180
});
181181

@@ -190,12 +190,12 @@ describe('codeql', () => {
190190

191191
expect(result).toEqual({
192192
success: false,
193-
error: 'Error executing JavaScript extractor: Failed to execute',
193+
error: 'Error running JavaScript extractor: Failed to execute',
194194
});
195195

196196
expect(addJavaScriptExtractorDiagnostic).toHaveBeenCalledWith(
197197
'/path/to/source',
198-
'Error executing JavaScript extractor: Failed to execute',
198+
'Error running JavaScript extractor: Failed to execute',
199199
codeqlPath,
200200
);
201201
});

extractors/cds/tools/test/src/filesystem.test.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,7 @@ describe('filesystem', () => {
128128

129129
recursivelyRenameJsonFiles('/non-existent/dir');
130130

131-
expect(mockConsoleLog).toHaveBeenCalledWith(
132-
'Directory not found or not a directory: /non-existent/dir',
133-
);
131+
expect(mockConsoleLog).toHaveBeenCalledWith('Directory not found: /non-existent/dir');
134132
expect(fs.readdirSync).not.toHaveBeenCalled();
135133
});
136134

0 commit comments

Comments
 (0)