Skip to content

Commit c9bd079

Browse files
authored
Merge pull request #2796 from opossum-tool/feat/merge-into-current
Merging of input files (Backend logic)
2 parents 1132cb8 + 0ba8858 commit c9bd079

11 files changed

+370
-162
lines changed

src/ElectronBackend/main/listeners.ts

+5-70
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { BrowserWindow, shell, WebContents } from 'electron';
77
import fs from 'fs';
88
import path from 'path';
99
import upath from 'upath';
10-
import zlib from 'zlib';
1110

11+
import { legacyOutputFileEnding } from '../../Frontend/shared-constants';
1212
import { AllowedFrontendChannels } from '../../shared/ipc-channels';
1313
import {
1414
ExportArgsType,
@@ -33,10 +33,7 @@ import {
3333
} from '../errorHandling/errorHandling';
3434
import { loadInputAndOutputFromFilePath } from '../input/importFromFile';
3535
import { serializeAttributions } from '../input/parseInputData';
36-
import {
37-
convertOwaspToOpossum,
38-
convertScancodeToOpossum,
39-
} from '../opossum-file/convertToOpossum';
36+
import { convertToOpossum } from '../opossum-file/opossum-file';
4037
import { writeCsvToFile } from '../output/writeCsvToFile';
4138
import { writeSpdxFile } from '../output/writeSpdxFile';
4239
import { GlobalBackendState, OpossumOutputFile } from '../types/types';
@@ -54,10 +51,6 @@ import {
5451
} from './globalBackendState';
5552
import logger from './logger';
5653

57-
const outputFileEnding = '_attributions.json';
58-
const jsonGzipFileExtension = '.json.gz';
59-
const jsonFileExtension = '.json';
60-
6154
export function getSaveFileListener(
6255
mainWindow: BrowserWindow,
6356
): (_: unknown, args: SaveFileArgs) => Promise<void> {
@@ -213,27 +206,8 @@ export function getImportFileConvertAndLoadListener(
213206
throw new Error('Output directory does not exist');
214207
}
215208

216-
logger.info('Converting .json to .opossum format');
217-
218-
if (resourceFilePath.endsWith(outputFileEnding)) {
219-
resourceFilePath = tryToGetInputFileFromOutputFile(resourceFilePath);
220-
}
221-
222-
switch (fileType) {
223-
case FileType.LEGACY_OPOSSUM:
224-
await writeOpossumFile({
225-
path: opossumFilePath,
226-
input: getInputJson(resourceFilePath),
227-
output: getOutputJson(resourceFilePath),
228-
});
229-
break;
230-
case FileType.SCANCODE_JSON:
231-
await convertScancodeToOpossum(resourceFilePath, opossumFilePath);
232-
break;
233-
case FileType.OWASP_JSON:
234-
await convertOwaspToOpossum(resourceFilePath, opossumFilePath);
235-
break;
236-
}
209+
logger.info('Converting input file to .opossum format');
210+
await convertToOpossum(resourceFilePath, opossumFilePath, fileType);
237211

238212
logger.info('Updating global backend state');
239213
initializeGlobalBackendState(opossumFilePath, true);
@@ -255,7 +229,7 @@ function initializeGlobalBackendState(
255229
resourceFilePath: isOpossumFormat ? undefined : filePath,
256230
attributionFilePath: isOpossumFormat
257231
? undefined
258-
: getFilePathWithAppendix(filePath, outputFileEnding),
232+
: getFilePathWithAppendix(filePath, legacyOutputFileEnding),
259233
opossumFilePath: isOpossumFormat ? filePath : undefined,
260234
followUpFilePath: getFilePathWithAppendix(filePath, '_follow_up.csv'),
261235
compactBomFilePath: getFilePathWithAppendix(
@@ -316,17 +290,6 @@ function formatBaseURL(baseURL: string): string {
316290
return `file://${baseURL}/{path}`;
317291
}
318292

319-
function tryToGetInputFileFromOutputFile(filePath: string): string {
320-
const outputFilePattern = `(${outputFileEnding})$`;
321-
const outputFileRegex = new RegExp(outputFilePattern);
322-
323-
return fs.existsSync(filePath.replace(outputFileRegex, jsonFileExtension))
324-
? filePath.replace(outputFileRegex, jsonFileExtension)
325-
: fs.existsSync(filePath.replace(outputFileRegex, jsonGzipFileExtension))
326-
? filePath.replace(outputFileRegex, jsonGzipFileExtension)
327-
: filePath;
328-
}
329-
330293
export async function openFile(
331294
mainWindow: BrowserWindow,
332295
filePath: string,
@@ -545,31 +508,3 @@ export function setLoadingState(
545508
isLoading,
546509
});
547510
}
548-
549-
function getInputJson(resourceFilePath: string): string {
550-
let inputJson: string;
551-
if (resourceFilePath.endsWith(jsonGzipFileExtension)) {
552-
const file = fs.readFileSync(resourceFilePath);
553-
inputJson = zlib.gunzipSync(file).toString();
554-
} else {
555-
inputJson = fs.readFileSync(resourceFilePath, {
556-
encoding: 'utf-8',
557-
});
558-
}
559-
560-
return inputJson;
561-
}
562-
563-
function getOutputJson(resourceFilePath: string): string | undefined {
564-
const expectedAssociatedAttributionFilePath = getFilePathWithAppendix(
565-
resourceFilePath,
566-
outputFileEnding,
567-
);
568-
if (fs.existsSync(expectedAssociatedAttributionFilePath)) {
569-
return fs.readFileSync(expectedAssociatedAttributionFilePath, {
570-
encoding: 'utf-8',
571-
});
572-
}
573-
574-
return undefined;
575-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates
2+
// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
3+
//
4+
// SPDX-License-Identifier: Apache-2.0
5+
import { FileConverter } from './FileConverter';
6+
7+
export abstract class ExternalFileConverter extends FileConverter {
8+
protected override preConvertFile(_: string): Promise<string | null> {
9+
return new Promise((resolve) => resolve(null));
10+
}
11+
12+
override async convertToOpossum(
13+
toBeConvertedFilePath: string,
14+
opossumSaveLocation: string,
15+
): Promise<void> {
16+
try {
17+
await this.execFile(this.OPOSSUM_FILE_EXECUTABLE, [
18+
'generate',
19+
'-o',
20+
opossumSaveLocation,
21+
this.fileTypeSwitch,
22+
toBeConvertedFilePath,
23+
]);
24+
} catch (error) {
25+
throw new Error(
26+
`Conversion of ${this.fileTypeName} file to .opossum file failed`,
27+
);
28+
}
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates
2+
// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
3+
//
4+
// SPDX-License-Identifier: Apache-2.0
5+
import { execFile as execFileCallback } from 'child_process';
6+
import { app } from 'electron';
7+
import fs from 'fs';
8+
import { join } from 'path';
9+
import { promisify } from 'util';
10+
11+
export abstract class FileConverter {
12+
protected abstract readonly fileTypeSwitch: string;
13+
protected abstract readonly fileTypeName: string;
14+
15+
protected readonly execFile = promisify(execFileCallback);
16+
17+
protected readonly OPOSSUM_FILE_EXECUTABLE = join(
18+
app?.getAppPath?.() ?? './',
19+
process.env.NODE_ENV === 'e2e' ? '../..' : '',
20+
'bin/opossum-file',
21+
);
22+
23+
protected abstract preConvertFile(
24+
toBeConvertedFilePath: string,
25+
): Promise<string | null>;
26+
27+
abstract convertToOpossum(
28+
toBeConvertedFilePath: string,
29+
opossumSaveLocation: string,
30+
): Promise<void>;
31+
32+
async mergeFileIntoOpossum(
33+
toBeConvertedFilePath: string,
34+
opossumFilePath: string,
35+
): Promise<void> {
36+
const preConvertedFilePath = await this.preConvertFile(
37+
toBeConvertedFilePath,
38+
);
39+
40+
try {
41+
await this.execFile(this.OPOSSUM_FILE_EXECUTABLE, [
42+
'generate',
43+
'-o',
44+
opossumFilePath,
45+
this.fileTypeSwitch,
46+
preConvertedFilePath || toBeConvertedFilePath,
47+
'--opossum',
48+
opossumFilePath,
49+
]);
50+
51+
if (preConvertedFilePath) {
52+
fs.rmSync(preConvertedFilePath);
53+
}
54+
} catch (error) {
55+
throw new Error(
56+
`Merging ${this.fileTypeName} file into current file failed`,
57+
);
58+
}
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates
2+
// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
3+
//
4+
// SPDX-License-Identifier: Apache-2.0
5+
import { app } from 'electron';
6+
import fs from 'fs';
7+
import path from 'path';
8+
import zlib from 'zlib';
9+
10+
import { legacyOutputFileEnding } from '../../Frontend/shared-constants';
11+
import { writeOpossumFile } from '../../shared/write-file';
12+
import { getFilePathWithAppendix } from '../utils/getFilePathWithAppendix';
13+
import { FileConverter } from './FileConverter';
14+
15+
export class LegacyFileConverter extends FileConverter {
16+
readonly fileTypeName: string = 'Legacy Opossum';
17+
readonly fileTypeSwitch: string = '--opossum';
18+
19+
private tryToGetLegacyInputJsonFromLegacyOutputJson(
20+
filePath: string,
21+
): string {
22+
const outputFilePattern = `(${legacyOutputFileEnding})$`;
23+
const outputFileRegex = new RegExp(outputFilePattern);
24+
25+
const jsonInputFilePath = filePath.replace(outputFileRegex, '.json');
26+
if (fs.existsSync(jsonInputFilePath)) {
27+
return jsonInputFilePath;
28+
}
29+
30+
const jsonGzipInputFilePath = filePath.replace(outputFileRegex, '.json.gz');
31+
if (fs.existsSync(jsonGzipInputFilePath)) {
32+
return jsonGzipInputFilePath;
33+
}
34+
35+
return filePath;
36+
}
37+
38+
private readInputJson(filePath: string): string {
39+
let inputJson: string;
40+
if (filePath.endsWith('.json.gz')) {
41+
const file = fs.readFileSync(filePath);
42+
inputJson = zlib.gunzipSync(file).toString();
43+
} else {
44+
inputJson = fs.readFileSync(filePath, {
45+
encoding: 'utf-8',
46+
});
47+
}
48+
49+
return inputJson;
50+
}
51+
52+
private readOutputJson(filePath: string): string | undefined {
53+
const expectedAssociatedAttributionFilePath = getFilePathWithAppendix(
54+
filePath,
55+
legacyOutputFileEnding,
56+
);
57+
if (fs.existsSync(expectedAssociatedAttributionFilePath)) {
58+
return fs.readFileSync(expectedAssociatedAttributionFilePath, {
59+
encoding: 'utf-8',
60+
});
61+
}
62+
63+
return undefined;
64+
}
65+
66+
override async convertToOpossum(
67+
toBeConvertedFilePath: string,
68+
opossumSaveLocation: string,
69+
): Promise<void> {
70+
try {
71+
let pathToInputJson = toBeConvertedFilePath;
72+
73+
if (toBeConvertedFilePath.endsWith(legacyOutputFileEnding)) {
74+
pathToInputJson = this.tryToGetLegacyInputJsonFromLegacyOutputJson(
75+
toBeConvertedFilePath,
76+
);
77+
}
78+
79+
await writeOpossumFile({
80+
path: opossumSaveLocation,
81+
input: this.readInputJson(pathToInputJson),
82+
output: this.readOutputJson(pathToInputJson),
83+
});
84+
} catch (error) {
85+
throw new Error(
86+
'Conversion of Legacy Opossum file to .opossum file failed',
87+
);
88+
}
89+
}
90+
91+
protected override async preConvertFile(
92+
toBeConvertedFilePath: string,
93+
): Promise<string | null> {
94+
let tempFilePath;
95+
try {
96+
tempFilePath = path.join(app.getPath('temp'), 'temp.opossum');
97+
} catch (error) {
98+
// When executing as part of unit tests, app.getPath('temp') throws an error
99+
tempFilePath = path.join(__dirname, 'temp.opossum');
100+
}
101+
102+
await this.convertToOpossum(toBeConvertedFilePath, tempFilePath);
103+
104+
return tempFilePath;
105+
}
106+
}

src/ElectronBackend/opossum-file/__tests__/convertToOpossum.test.ts

-40
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"metadata": {
3+
"projectId": "2a58a469-738e-4508-98d3-a27bce6e71f7",
4+
"projectTitle": "Test Title",
5+
"fileCreationDate": "2020-07-23 11:47:13.764544"
6+
},
7+
"resources": {
8+
"index.html": 1
9+
},
10+
"externalAttributions": {},
11+
"resourcesToAttributions": {},
12+
"frequentLicenses": [],
13+
"attributionBreakpoints": [],
14+
"filesWithChildren": [],
15+
"baseUrlsForSources": {},
16+
"externalAttributionSources": {}
17+
}
Binary file not shown.

0 commit comments

Comments
 (0)