1
- import * as fs from 'fs/promises' ;
2
- import * as fs1 from 'fs' ;
1
+ import * as fsPromises from 'fs/promises' ;
2
+ import * as fs from 'fs' ;
3
3
import * as path from 'path' ;
4
4
import * as tar from 'tar' ;
5
5
import axios from 'axios' ;
6
6
import * as unzipper from 'unzipper' ;
7
- import { Semaphore } from 'async-mutex' ;
7
+ import { Semaphore } from 'async-mutex' ;
8
8
import * as os from "os" ;
9
9
import { logger } from "../wrapper/loggerConfig" ;
10
+ import { finished } from 'stream/promises' ;
10
11
12
+ type SupportedPlatforms = 'win32' | 'darwin' | 'linux' ;
11
13
export class CxInstaller {
12
14
private readonly platform : string ;
13
15
private cliVersion : string ;
14
16
private readonly resourceDirPath : string ;
17
+ private readonly cliDefaultVersion = '2.2.5' ; // This will be used if the version file is not found. Should be updated with the latest version.
15
18
private static installSemaphore = new Semaphore ( 1 ) ; // Semaphore with 1 slot
16
19
17
20
constructor ( platform : string ) {
18
21
this . platform = platform ;
19
22
this . resourceDirPath = path . join ( __dirname , `../wrapper/resources` ) ;
20
23
}
21
24
22
- // Method to get the download URL based on OS and architecture
23
25
async getDownloadURL ( ) : Promise < string > {
24
26
const cliVersion = await this . readASTCLIVersion ( ) ;
25
- let platformString : string ;
26
- let archiveExtension : string ;
27
-
28
- switch ( this . platform ) {
29
- case 'win32' :
30
- platformString = 'windows' ;
31
- archiveExtension = 'zip' ;
32
- break ;
33
- case 'darwin' :
34
- archiveExtension = 'tar.gz' ;
35
- platformString = 'darwin' ;
36
- break ;
37
- case 'linux' :
38
- archiveExtension = 'tar.gz' ;
39
- platformString = 'linux' ;
40
- break ;
41
- default :
42
- throw new Error ( 'Unsupported platform or architecture' ) ;
27
+
28
+ const platforms : Record < SupportedPlatforms , { platform : string ; extension : string } > = {
29
+ win32 : { platform : 'windows' , extension : 'zip' } ,
30
+ darwin : { platform : 'darwin' , extension : 'tar.gz' } ,
31
+ linux : { platform : 'linux' , extension : 'tar.gz' }
32
+ } ;
33
+
34
+ const platformKey = this . platform as SupportedPlatforms ;
35
+
36
+ const platformData = platforms [ platformKey ] ;
37
+ if ( ! platformData ) {
38
+ throw new Error ( 'Unsupported platform or architecture' ) ;
43
39
}
44
40
45
- return `https://download.checkmarx.com/CxOne/CLI/${ cliVersion } /ast-cli_${ cliVersion } _${ platformString } _x64.${ archiveExtension } ` ;
41
+ return `https://download.checkmarx.com/CxOne/CLI/${ cliVersion } /ast-cli_${ cliVersion } _${ platformData . platform } _x64.${ platformData . extension } ` ;
46
42
}
47
43
48
44
getExecutablePath ( ) : string {
@@ -55,7 +51,7 @@ export class CxInstaller {
55
51
return executablePath ;
56
52
}
57
53
58
- async downloadIfNotInstalledCLI ( ) {
54
+ async downloadIfNotInstalledCLI ( ) : Promise < void > {
59
55
const [ _ , release ] = await CxInstaller . installSemaphore . acquire ( ) ;
60
56
try {
61
57
if ( this . checkExecutableExists ( ) ) {
@@ -70,40 +66,38 @@ export class CxInstaller {
70
66
logger . info ( 'Downloaded CLI to:' , zipPath ) ;
71
67
72
68
await this . extractArchive ( zipPath , this . resourceDirPath ) ;
73
- fs1 . chmodSync ( this . getExecutablePath ( ) , 0o777 ) ;
69
+ fs . chmodSync ( this . getExecutablePath ( ) , 0o755 ) ;
74
70
logger . info ( 'Extracted CLI to:' , this . resourceDirPath ) ;
75
71
} catch ( error ) {
76
72
logger . error ( 'Error during installation:' , error ) ;
77
73
} finally {
78
- release ( ) ;
74
+ release ( ) ;
79
75
}
80
76
}
81
77
82
78
async extractArchive ( zipPath : string , extractPath : string ) : Promise < void > {
83
79
if ( zipPath . endsWith ( '.zip' ) ) {
84
80
await unzipper . Open . file ( zipPath )
85
- . then ( d => d . extract ( { path : extractPath } ) ) ;
81
+ . then ( d => d . extract ( { path : extractPath } ) ) ;
86
82
} else if ( zipPath . endsWith ( '.tar.gz' ) ) {
87
- await tar . extract ( { file : zipPath , cwd : extractPath } ) ;
83
+ await tar . extract ( { file : zipPath , cwd : extractPath } ) ;
88
84
} else {
89
85
logger . error ( 'Unsupported file type. Only .zip and .tar.gz are supported.' ) ;
90
86
}
91
87
}
92
88
93
89
async downloadFile ( url : string , outputPath : string ) {
94
90
logger . info ( 'Downloading file from:' , url ) ;
95
- const writer = fs1 . createWriteStream ( outputPath ) ;
96
- const response = await axios ( { url, responseType : 'stream' } ) ;
91
+ const writer = fs . createWriteStream ( outputPath ) ;
92
+ const response = await axios ( { url, responseType : 'stream' } ) ;
97
93
response . data . pipe ( writer ) ;
98
94
99
- return new Promise ( ( resolve , reject ) => {
100
- writer . on ( 'finish' , resolve ) ;
101
- writer . on ( 'error' , reject ) ;
102
- } ) ;
95
+ await finished ( writer ) ; // Use stream promises to await the writer
96
+ logger . info ( 'Download finished' ) ;
103
97
}
104
98
105
99
checkExecutableExists ( ) : boolean {
106
- return fs1 . existsSync ( this . getExecutablePath ( ) ) ;
100
+ return fs . existsSync ( this . getExecutablePath ( ) ) ;
107
101
}
108
102
109
103
async readASTCLIVersion ( ) : Promise < string > {
@@ -112,10 +106,11 @@ export class CxInstaller {
112
106
}
113
107
try {
114
108
const versionFilePath = path . join ( process . cwd ( ) , 'checkmarx-ast-cli.version' ) ;
115
- const versionContent = await fs . readFile ( versionFilePath , 'utf-8' ) ;
109
+ const versionContent = await fsPromises . readFile ( versionFilePath , 'utf-8' ) ;
116
110
return versionContent . trim ( ) ;
117
111
} catch ( error ) {
118
112
logger . error ( 'Error reading AST CLI version: ' + error . message ) ;
113
+ return this . cliDefaultVersion ;
119
114
}
120
115
}
121
116
}
0 commit comments