@cyclonedx/cdxgen 10.9.2 → 10.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/cdxgen.js CHANGED
@@ -13,6 +13,7 @@ import jws from "jws";
13
13
  import {
14
14
  printCallStack,
15
15
  printDependencyTree,
16
+ printFormulation,
16
17
  printOccurrences,
17
18
  printReachables,
18
19
  printServices,
@@ -22,6 +23,7 @@ import {
22
23
  } from "../display.js";
23
24
  import { createBom, submitBom } from "../index.js";
24
25
  import { postProcess } from "../postgen.js";
26
+ import { prepareEnv } from "../pregen.js";
25
27
  import { ATOM_DB } from "../utils.js";
26
28
  import { validateBom } from "../validator.js";
27
29
 
@@ -502,6 +504,7 @@ const checkPermissions = (filePath) => {
502
504
  if (!options.usagesSlicesFile) {
503
505
  options.usagesSlicesFile = `${options.projectName}-usages.json`;
504
506
  }
507
+ prepareEnv(filePath, options);
505
508
  let bomNSData = (await createBom(filePath, options)) || {};
506
509
  // Add extra metadata and annotations with post processing
507
510
  bomNSData = postProcess(bomNSData, options);
@@ -721,6 +724,9 @@ const checkPermissions = (filePath) => {
721
724
  }
722
725
  if (options.print && bomNSData.bomJson && bomNSData.bomJson.components) {
723
726
  printSummary(bomNSData.bomJson);
727
+ if (options.includeFormulation) {
728
+ printFormulation(bomNSData.bomJson);
729
+ }
724
730
  printDependencyTree(bomNSData.bomJson);
725
731
  printTable(bomNSData.bomJson);
726
732
  // CBOM related print
package/bin/repl.js CHANGED
@@ -10,6 +10,7 @@ import jsonata from "jsonata";
10
10
  import {
11
11
  printCallStack,
12
12
  printDependencyTree,
13
+ printFormulation,
13
14
  printOSTable,
14
15
  printOccurrences,
15
16
  printServices,
@@ -500,6 +501,32 @@ cdxgenRepl.defineCommand("vulnerabilities", {
500
501
  this.displayPrompt();
501
502
  },
502
503
  });
504
+ cdxgenRepl.defineCommand("formulation", {
505
+ help: "view formulation",
506
+ async action() {
507
+ if (sbom) {
508
+ try {
509
+ const expression = jsonata("formulation");
510
+ let formulation = await expression.evaluate(sbom);
511
+ if (!formulation) {
512
+ console.log(
513
+ "No formulation found. Pass the argument --include-formulation to generate SBOM with formulation details.",
514
+ );
515
+ } else {
516
+ if (!Array.isArray(formulation)) {
517
+ formulation = [formulation];
518
+ }
519
+ printFormulation({ formulation });
520
+ }
521
+ } catch (e) {
522
+ console.log(e);
523
+ }
524
+ } else {
525
+ console.log("⚠ No SBOM is loaded. Use .import command to import an SBOM");
526
+ }
527
+ this.displayPrompt();
528
+ },
529
+ });
503
530
  cdxgenRepl.defineCommand("osinfocategories", {
504
531
  help: "view the category names for the OS info from the obom",
505
532
  async action() {
package/display.js CHANGED
@@ -18,11 +18,11 @@ const highlightStr = (s, highlight) => {
18
18
  }
19
19
  return s;
20
20
  };
21
- export const printTable = (
21
+ export function printTable(
22
22
  bomJson,
23
23
  filterTypes = undefined,
24
24
  highlight = undefined,
25
- ) => {
25
+ ) {
26
26
  if (!bomJson || !bomJson.components) {
27
27
  return;
28
28
  }
@@ -85,7 +85,7 @@ export const printTable = (
85
85
  } else {
86
86
  console.log(`Components filtered based on type: ${filterTypes.join(", ")}`);
87
87
  }
88
- };
88
+ }
89
89
  const formatProps = (props) => {
90
90
  const retList = [];
91
91
  for (const p of props) {
@@ -93,7 +93,7 @@ const formatProps = (props) => {
93
93
  }
94
94
  return retList.join("\n");
95
95
  };
96
- export const printOSTable = (bomJson) => {
96
+ export function printOSTable(bomJson) {
97
97
  const config = {
98
98
  columnDefault: {
99
99
  width: 50,
@@ -111,8 +111,8 @@ export const printOSTable = (bomJson) => {
111
111
  ]);
112
112
  }
113
113
  console.log();
114
- };
115
- export const printServices = (bomJson) => {
114
+ }
115
+ export function printServices(bomJson) {
116
116
  const data = [["Name", "Endpoints", "Authenticated", "X Trust Boundary"]];
117
117
  if (!bomJson || !bomJson.services) {
118
118
  return;
@@ -134,7 +134,30 @@ export const printServices = (bomJson) => {
134
134
  if (data.length > 1) {
135
135
  console.log(table(data, config));
136
136
  }
137
- };
137
+ }
138
+
139
+ export function printFormulation(bomJson) {
140
+ const data = [["Tyoe", "Name", "Version"]];
141
+ if (!bomJson || !bomJson.formulation) {
142
+ return;
143
+ }
144
+ for (const aform of bomJson.formulation) {
145
+ if (aform.components) {
146
+ for (const acomp of aform.components) {
147
+ data.push([acomp.type || "", acomp.name || "", acomp.version || ""]);
148
+ }
149
+ }
150
+ }
151
+ const config = {
152
+ header: {
153
+ alignment: "center",
154
+ content: "Formulation\nGenerated with \u2665 by cdxgen",
155
+ },
156
+ };
157
+ if (data.length > 1) {
158
+ console.log(table(data, config));
159
+ }
160
+ }
138
161
 
139
162
  const locationComparator = (a, b) => {
140
163
  if (a && b && a.includes("#") && b.includes("#")) {
@@ -149,7 +172,7 @@ const locationComparator = (a, b) => {
149
172
  return a.localeCompare(b);
150
173
  };
151
174
 
152
- export const printOccurrences = (bomJson) => {
175
+ export function printOccurrences(bomJson) {
153
176
  const data = [["Group", "Name", "Version", "Occurrences"]];
154
177
  if (!bomJson || !bomJson.components) {
155
178
  return;
@@ -177,8 +200,8 @@ export const printOccurrences = (bomJson) => {
177
200
  if (data.length > 1) {
178
201
  console.log(table(data, config));
179
202
  }
180
- };
181
- export const printCallStack = (bomJson) => {
203
+ }
204
+ export function printCallStack(bomJson) {
182
205
  const data = [["Group", "Name", "Version", "Call Stack"]];
183
206
  if (!bomJson || !bomJson.components) {
184
207
  return;
@@ -224,12 +247,12 @@ export const printCallStack = (bomJson) => {
224
247
  if (data.length > 1) {
225
248
  console.log(table(data, config));
226
249
  }
227
- };
228
- export const printDependencyTree = (
250
+ }
251
+ export function printDependencyTree(
229
252
  bomJson,
230
253
  mode = "dependsOn",
231
254
  highlight = undefined,
232
- ) => {
255
+ ) {
233
256
  const dependencies = bomJson.dependencies || [];
234
257
  if (!dependencies.length) {
235
258
  return;
@@ -264,7 +287,7 @@ export const printDependencyTree = (
264
287
  } else {
265
288
  console.log(highlightStr(treeGraphics.join("\n"), highlight));
266
289
  }
267
- };
290
+ }
268
291
 
269
292
  const levelPrefix = (level, isLast) => {
270
293
  if (level === 0) {
@@ -324,7 +347,7 @@ const recursePrint = (depMap, subtree, level, shownList, treeGraphics) => {
324
347
  }
325
348
  };
326
349
 
327
- export const printReachables = (sliceArtefacts) => {
350
+ export function printReachables(sliceArtefacts) {
328
351
  const reachablesSlicesFile = sliceArtefacts.reachablesSlicesFile;
329
352
  if (!existsSync(reachablesSlicesFile)) {
330
353
  return;
@@ -355,7 +378,7 @@ export const printReachables = (sliceArtefacts) => {
355
378
  if (data.length > 1) {
356
379
  console.log(table(data, config));
357
380
  }
358
- };
381
+ }
359
382
 
360
383
  export function printVulnerabilities(vulnerabilities) {
361
384
  if (!vulnerabilities) {
@@ -407,7 +430,7 @@ export function printSponsorBanner(options) {
407
430
  }
408
431
  }
409
432
 
410
- export const printSummary = (bomJson) => {
433
+ export function printSummary(bomJson) {
411
434
  const config = {
412
435
  header: {
413
436
  alignment: "center",
@@ -418,8 +441,18 @@ export const printSummary = (bomJson) => {
418
441
  if (!metadataProperties) {
419
442
  return;
420
443
  }
444
+ const tools = bomJson?.metadata?.tools?.components;
445
+ let message = "";
421
446
  let bomPkgTypes = [];
422
447
  let bomPkgNamespaces = [];
448
+ if (tools) {
449
+ message = "** Generator Tools **";
450
+ for (const atool of tools) {
451
+ if (atool.name && atool.version) {
452
+ message = `${message}\n${atool.name} (${atool.version})`;
453
+ }
454
+ }
455
+ }
423
456
  for (const aprop of metadataProperties) {
424
457
  if (aprop.name === "cdx:bom:componentTypes") {
425
458
  bomPkgTypes = aprop?.value.split("\\n");
@@ -431,10 +464,10 @@ export const printSummary = (bomJson) => {
431
464
  if (!bomPkgTypes.length && !bomPkgNamespaces.length) {
432
465
  return;
433
466
  }
434
- let message = `** Package Types (${bomPkgTypes.length}) **\n${bomPkgTypes.join("\n")}`;
467
+ message = `${message}\n\n** Package Types (${bomPkgTypes.length}) **\n${bomPkgTypes.join("\n")}`;
435
468
  if (bomPkgNamespaces.length) {
436
469
  message = `${message}\n\n** Namespaces (${bomPkgNamespaces.length}) **\n${bomPkgNamespaces.join("\n")}`;
437
470
  }
438
471
  const data = [[message]];
439
472
  console.log(table(data, config));
440
- };
473
+ }
package/envcontext.js CHANGED
@@ -1,20 +1,33 @@
1
1
  import { Buffer } from "node:buffer";
2
2
  import { spawnSync } from "node:child_process";
3
+ import { existsSync } from "node:fs";
4
+ import { homedir } from "node:os";
5
+ import { delimiter, join } from "node:path";
3
6
  import process from "node:process";
4
7
  import {
5
8
  CARGO_CMD,
9
+ DEBUG_MODE,
6
10
  DOTNET_CMD,
7
11
  GCC_CMD,
8
12
  GO_CMD,
9
- JAVA_CMD,
10
13
  NODE_CMD,
11
14
  NPM_CMD,
12
- PYTHON_CMD,
13
15
  RUSTC_CMD,
16
+ getJavaCommand,
17
+ getPythonCommand,
14
18
  isWin,
15
19
  } from "./utils.js";
16
20
 
17
- const GIT_COMMAND = process.env.GIT_CMD || "git";
21
+ export const GIT_COMMAND = process.env.GIT_CMD || "git";
22
+
23
+ // sdkman tool aliases
24
+ export const SDKMAN_TOOL_ALIASES = {
25
+ java8: "8.0.422-tem",
26
+ java11: "11.0.24-tem",
27
+ java17: "17.0.12-tem",
28
+ java21: "21.0.4-tem",
29
+ java22: "22.0.2-tem",
30
+ };
18
31
 
19
32
  /**
20
33
  * Retrieves a git config item
@@ -23,9 +36,9 @@ const GIT_COMMAND = process.env.GIT_CMD || "git";
23
36
  *
24
37
  * @returns Output from git config or undefined
25
38
  */
26
- export const getGitConfig = (configKey, dir) => {
39
+ export function getGitConfig(configKey, dir) {
27
40
  return execGitCommand(dir, ["config", "--get", configKey]);
28
- };
41
+ }
29
42
 
30
43
  /**
31
44
  * Retrieves the git origin url
@@ -33,9 +46,9 @@ export const getGitConfig = (configKey, dir) => {
33
46
  *
34
47
  * @returns Output from git config or undefined
35
48
  */
36
- export const getOriginUrl = (dir) => {
49
+ export function getOriginUrl(dir) {
37
50
  return getGitConfig("remote.origin.url", dir);
38
- };
51
+ }
39
52
 
40
53
  /**
41
54
  * Retrieves the git branch name
@@ -44,9 +57,9 @@ export const getOriginUrl = (dir) => {
44
57
  *
45
58
  * @returns Output from git config or undefined
46
59
  */
47
- export const getBranch = (configKey, dir) => {
60
+ export function getBranch(configKey, dir) {
48
61
  return execGitCommand(dir, ["rev-parse", "--abbrev-ref", "HEAD"]);
49
- };
62
+ }
50
63
 
51
64
  /**
52
65
  * Retrieves the tree and parent hash for a git repo
@@ -54,7 +67,7 @@ export const getBranch = (configKey, dir) => {
54
67
  *
55
68
  * @returns Output from git cat-file or undefined
56
69
  */
57
- export const gitTreeHashes = (dir) => {
70
+ export function gitTreeHashes(dir) {
58
71
  const treeHashes = {};
59
72
  const output = execGitCommand(dir, ["cat-file", "commit", "HEAD"]);
60
73
  if (output) {
@@ -72,7 +85,7 @@ export const gitTreeHashes = (dir) => {
72
85
  });
73
86
  }
74
87
  return treeHashes;
75
- };
88
+ }
76
89
 
77
90
  /**
78
91
  * Retrieves the files list from git
@@ -80,7 +93,7 @@ export const gitTreeHashes = (dir) => {
80
93
  *
81
94
  * @returns Output from git config or undefined
82
95
  */
83
- export const listFiles = (dir) => {
96
+ export function listFiles(dir) {
84
97
  const filesList = [];
85
98
  const output = execGitCommand(dir, [
86
99
  "ls-tree",
@@ -108,7 +121,7 @@ export const listFiles = (dir) => {
108
121
  });
109
122
  }
110
123
  return filesList;
111
- };
124
+ }
112
125
 
113
126
  /**
114
127
  * Execute a git command
@@ -118,9 +131,9 @@ export const listFiles = (dir) => {
118
131
  *
119
132
  * @returns Output from the git command
120
133
  */
121
- export const execGitCommand = (dir, args) => {
134
+ export function execGitCommand(dir, args) {
122
135
  return getCommandOutput(GIT_COMMAND, dir, args);
123
- };
136
+ }
124
137
 
125
138
  /**
126
139
  * Collect Java version and installed modules
@@ -128,9 +141,10 @@ export const execGitCommand = (dir, args) => {
128
141
  * @param {string} dir Working directory
129
142
  * @returns Object containing the java details
130
143
  */
131
- export const collectJavaInfo = (dir) => {
132
- const versionDesc = getCommandOutput(JAVA_CMD, dir, ["--version"]);
133
- const moduleDesc = getCommandOutput(JAVA_CMD, dir, ["--list-modules"]) || "";
144
+ export function collectJavaInfo(dir) {
145
+ const versionDesc = getCommandOutput(getJavaCommand(), dir, ["--version"]);
146
+ const moduleDesc =
147
+ getCommandOutput(getJavaCommand(), dir, ["--list-modules"]) || "";
134
148
  if (versionDesc) {
135
149
  return {
136
150
  type: "platform",
@@ -146,7 +160,7 @@ export const collectJavaInfo = (dir) => {
146
160
  };
147
161
  }
148
162
  return undefined;
149
- };
163
+ }
150
164
 
151
165
  /**
152
166
  * Collect dotnet version
@@ -154,7 +168,7 @@ export const collectJavaInfo = (dir) => {
154
168
  * @param {string} dir Working directory
155
169
  * @returns Object containing dotnet details
156
170
  */
157
- export const collectDotnetInfo = (dir) => {
171
+ export function collectDotnetInfo(dir) {
158
172
  const versionDesc = getCommandOutput(DOTNET_CMD, dir, ["--version"]);
159
173
  const moduleDesc =
160
174
  getCommandOutput(DOTNET_CMD, dir, ["--list-runtimes"]) || "";
@@ -167,7 +181,7 @@ export const collectDotnetInfo = (dir) => {
167
181
  };
168
182
  }
169
183
  return undefined;
170
- };
184
+ }
171
185
 
172
186
  /**
173
187
  * Collect python version
@@ -175,10 +189,10 @@ export const collectDotnetInfo = (dir) => {
175
189
  * @param {string} dir Working directory
176
190
  * @returns Object containing python details
177
191
  */
178
- export const collectPythonInfo = (dir) => {
179
- const versionDesc = getCommandOutput(PYTHON_CMD, dir, ["--version"]);
192
+ export function collectPythonInfo(dir) {
193
+ const versionDesc = getCommandOutput(getPythonCommand(), dir, ["--version"]);
180
194
  const moduleDesc =
181
- getCommandOutput(PYTHON_CMD, dir, ["-m", "pip", "--version"]) || "";
195
+ getCommandOutput(getPythonCommand(), dir, ["-m", "pip", "--version"]) || "";
182
196
  if (versionDesc) {
183
197
  return {
184
198
  type: "platform",
@@ -188,7 +202,7 @@ export const collectPythonInfo = (dir) => {
188
202
  };
189
203
  }
190
204
  return undefined;
191
- };
205
+ }
192
206
 
193
207
  /**
194
208
  * Collect node version
@@ -196,7 +210,7 @@ export const collectPythonInfo = (dir) => {
196
210
  * @param {string} dir Working directory
197
211
  * @returns Object containing node details
198
212
  */
199
- export const collectNodeInfo = (dir) => {
213
+ export function collectNodeInfo(dir) {
200
214
  const versionDesc = getCommandOutput(NODE_CMD, dir, ["--version"]);
201
215
  let moduleDesc = getCommandOutput(NPM_CMD, dir, ["--version"]);
202
216
  if (moduleDesc) {
@@ -211,7 +225,7 @@ export const collectNodeInfo = (dir) => {
211
225
  };
212
226
  }
213
227
  return undefined;
214
- };
228
+ }
215
229
 
216
230
  /**
217
231
  * Collect gcc version
@@ -219,7 +233,7 @@ export const collectNodeInfo = (dir) => {
219
233
  * @param {string} dir Working directory
220
234
  * @returns Object containing gcc details
221
235
  */
222
- export const collectGccInfo = (dir) => {
236
+ export function collectGccInfo(dir) {
223
237
  const versionDesc = getCommandOutput(GCC_CMD, dir, ["--version"]);
224
238
  const moduleDesc = getCommandOutput(GCC_CMD, dir, ["-print-search-dirs"]);
225
239
  if (versionDesc) {
@@ -231,7 +245,7 @@ export const collectGccInfo = (dir) => {
231
245
  };
232
246
  }
233
247
  return undefined;
234
- };
248
+ }
235
249
 
236
250
  /**
237
251
  * Collect rust version
@@ -239,7 +253,7 @@ export const collectGccInfo = (dir) => {
239
253
  * @param {string} dir Working directory
240
254
  * @returns Object containing rust details
241
255
  */
242
- export const collectRustInfo = (dir) => {
256
+ export function collectRustInfo(dir) {
243
257
  const versionDesc = getCommandOutput(RUSTC_CMD, dir, ["--version"]);
244
258
  const moduleDesc = getCommandOutput(CARGO_CMD, dir, ["--version"]);
245
259
  if (versionDesc) {
@@ -251,7 +265,7 @@ export const collectRustInfo = (dir) => {
251
265
  };
252
266
  }
253
267
  return undefined;
254
- };
268
+ }
255
269
 
256
270
  /**
257
271
  * Collect go version
@@ -259,7 +273,7 @@ export const collectRustInfo = (dir) => {
259
273
  * @param {string} dir Working directory
260
274
  * @returns Object containing go details
261
275
  */
262
- export const collectGoInfo = (dir) => {
276
+ export function collectGoInfo(dir) {
263
277
  const versionDesc = getCommandOutput(GO_CMD, dir, ["version"]);
264
278
  if (versionDesc) {
265
279
  return {
@@ -269,9 +283,9 @@ export const collectGoInfo = (dir) => {
269
283
  };
270
284
  }
271
285
  return undefined;
272
- };
286
+ }
273
287
 
274
- export const collectEnvInfo = (dir) => {
288
+ export function collectEnvInfo(dir) {
275
289
  const infoComponents = [];
276
290
  let cmp = collectJavaInfo(dir);
277
291
  if (cmp) {
@@ -302,7 +316,7 @@ export const collectEnvInfo = (dir) => {
302
316
  infoComponents.push(cmp);
303
317
  }
304
318
  return infoComponents;
305
- };
319
+ }
306
320
 
307
321
  /**
308
322
  * Execute any command to retrieve the output
@@ -324,6 +338,162 @@ const getCommandOutput = (cmd, dir, args) => {
324
338
  const stdout = result.stdout;
325
339
  if (stdout) {
326
340
  const cmdOutput = Buffer.from(stdout).toString();
327
- return cmdOutput.trim();
341
+ return cmdOutput.trim().replaceAll("\r", "");
328
342
  }
329
343
  };
344
+
345
+ /**
346
+ * Method to check if sdkman is available.
347
+ */
348
+ export function isSdkmanAvailable() {
349
+ let isSdkmanSetup =
350
+ ["SDKMAN_DIR", "SDKMAN_CANDIDATES_DIR"].filter(
351
+ (v) => process.env[v] && existsSync(process.env[v]),
352
+ ).length >= 1;
353
+ if (!isSdkmanSetup && existsSync(join(homedir(), ".sdkman", "bin"))) {
354
+ process.env.SDKMAN_DIR = join(homedir(), ".sdkman");
355
+ process.env.SDKMAN_CANDIDATES_DIR = join(
356
+ homedir(),
357
+ ".sdkman",
358
+ "candidates",
359
+ );
360
+ isSdkmanSetup = true;
361
+ }
362
+ return isSdkmanSetup;
363
+ }
364
+
365
+ /**
366
+ * Method to check if a given sdkman tool is installed and available.
367
+ *
368
+ * @param {String} toolType Tool type such as java, gradle, maven etc.
369
+ * @param {String} toolName Tool name with version. Eg: 22.0.2-tem
370
+ *
371
+ * @returns {Boolean} true if the tool is available. false otherwise.
372
+ */
373
+ export function isSdkmanToolAvailable(toolType, toolName) {
374
+ toolName = getSdkmanToolFullname(toolName);
375
+ let isToolAvailable =
376
+ process.env.SDKMAN_CANDIDATES_DIR &&
377
+ existsSync(
378
+ join(process.env.SDKMAN_CANDIDATES_DIR, toolType, toolName, "bin"),
379
+ );
380
+ if (
381
+ !isToolAvailable &&
382
+ existsSync(
383
+ join(homedir(), ".sdkman", "candidates", toolType, toolName, "bin"),
384
+ )
385
+ ) {
386
+ process.env.SDKMAN_CANDIDATES_DIR = join(
387
+ homedir(),
388
+ ".sdkman",
389
+ "candidates",
390
+ );
391
+ isToolAvailable = true;
392
+ }
393
+ return isToolAvailable;
394
+ }
395
+
396
+ /**
397
+ * Method to install and use a given sdkman tool.
398
+ *
399
+ * @param {String} toolType Tool type such as java, gradle, maven etc.
400
+ * @param {String} toolName Tool name with version. Eg: 22.0.2-tem
401
+ *
402
+ * @returns {Boolean} true if the tool is available. false otherwise.
403
+ */
404
+ export function installSdkmanTool(toolType, toolName) {
405
+ if (isWin) {
406
+ return false;
407
+ }
408
+ toolName = getSdkmanToolFullname(toolName);
409
+ let result = undefined;
410
+ if (!isSdkmanToolAvailable(toolType, toolName)) {
411
+ console.log("About to install", toolType, toolName);
412
+ result = spawnSync(
413
+ process.env.SHELL || "bash",
414
+ ["-i", "-c", `"echo -e "no" | sdk install ${toolType} ${toolName}"`],
415
+ {
416
+ encoding: "utf-8",
417
+ shell: process.env.SHELL || true,
418
+ },
419
+ );
420
+ if (DEBUG_MODE) {
421
+ if (console.stdout) {
422
+ console.log(result.stdout);
423
+ }
424
+ if (console.stderr) {
425
+ console.log(result.stderr);
426
+ }
427
+ }
428
+ if (result.status === 1 || result.error) {
429
+ console.log(
430
+ "Unable to install",
431
+ toolType,
432
+ toolName,
433
+ "due to below errors.",
434
+ );
435
+ return false;
436
+ }
437
+ }
438
+ const toolUpper = toolType.toUpperCase();
439
+ // Set process env variables
440
+ if (
441
+ process.env[`${toolUpper}_HOME`] &&
442
+ process.env[`${toolUpper}_HOME`].includes("current")
443
+ ) {
444
+ process.env[`${toolUpper}_HOME`] = process.env[`${toolUpper}_HOME`].replace(
445
+ "current",
446
+ toolName,
447
+ );
448
+ console.log(
449
+ `${toolUpper}_HOME`,
450
+ "set to",
451
+ process.env[`${toolUpper}_HOME`],
452
+ );
453
+ } else if (
454
+ process.env.SDKMAN_CANDIDATES_DIR &&
455
+ existsSync(join(process.env.SDKMAN_CANDIDATES_DIR, toolType, toolName))
456
+ ) {
457
+ process.env[`${toolUpper}_HOME`] = join(
458
+ process.env.SDKMAN_CANDIDATES_DIR,
459
+ toolType,
460
+ toolName,
461
+ );
462
+ console.log(
463
+ `${toolUpper}_HOME`,
464
+ "set to",
465
+ process.env[`${toolUpper}_HOME`],
466
+ );
467
+ } else {
468
+ console.log(
469
+ "Directory",
470
+ join(process.env.SDKMAN_CANDIDATES_DIR, toolType, toolName),
471
+ "is not found",
472
+ );
473
+ }
474
+ const toolCurrentBin = join(toolType, "current", "bin");
475
+ if (process.env?.PATH.includes(toolCurrentBin)) {
476
+ process.env.PATH = process.env.PATH.replace(
477
+ toolCurrentBin,
478
+ join(toolType, toolName, "bin"),
479
+ );
480
+ } else if (process.env.SDKMAN_CANDIDATES_DIR) {
481
+ const fullToolBinDir = join(
482
+ process.env.SDKMAN_CANDIDATES_DIR,
483
+ toolType,
484
+ toolName,
485
+ "bin",
486
+ );
487
+ if (!process.env?.PATH?.includes(fullToolBinDir)) {
488
+ process.env.PATH = `${fullToolBinDir}${delimiter}${process.env.PATH}`;
489
+ }
490
+ }
491
+ return true;
492
+ }
493
+
494
+ /**
495
+ * Retrieve sdkman tool full name
496
+ */
497
+ function getSdkmanToolFullname(toolName) {
498
+ return SDKMAN_TOOL_ALIASES[toolName] || toolName;
499
+ }
@@ -1,3 +1,4 @@
1
+ import process from "node:process";
1
2
  import { expect, test } from "@jest/globals";
2
3
 
3
4
  import {
@@ -10,6 +11,8 @@ import {
10
11
  collectRustInfo,
11
12
  getBranch,
12
13
  getOriginUrl,
14
+ isSdkmanAvailable,
15
+ isSdkmanToolAvailable,
13
16
  listFiles,
14
17
  } from "./envcontext.js";
15
18
 
@@ -29,3 +32,10 @@ test("tools tests", () => {
29
32
  expect(collectRustInfo()).toBeDefined();
30
33
  expect(collectGoInfo()).toBeDefined();
31
34
  });
35
+
36
+ test("sdkman tests", () => {
37
+ if (process.env?.SDKMAN_VERSION) {
38
+ expect(isSdkmanAvailable()).toBeTruthy();
39
+ expect(isSdkmanToolAvailable("java", "22.0.1-tem")).toBeTruthy();
40
+ }
41
+ });
package/evinser.js CHANGED
@@ -658,7 +658,7 @@ export const parseSliceUsages = async (
658
658
  if (purlImportsMap && Object.keys(purlImportsMap).length) {
659
659
  for (const apurl of Object.keys(purlImportsMap)) {
660
660
  const apurlImports = purlImportsMap[apurl];
661
- if (language === "php") {
661
+ if (["php", "python"].includes(language)) {
662
662
  for (const aimp of apurlImports) {
663
663
  if (atype.startsWith(aimp)) {
664
664
  if (!purlLocationMap[apurl]) {