@@ -21,9 +21,11 @@ import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } fr
2121import path from 'path' ;
2222import { downloadFile } from './file-download' ;
2323import yargs from 'yargs' ;
24- import extractZip from 'extract-zip' ;
2524import { execSync } from 'child_process' ;
2625import { hideBin } from 'yargs/helpers' ;
26+ import console from 'console' ;
27+ import fastExtract from 'fast-extract' ;
28+ import extractZip from 'extract-zip' ;
2729
2830// OS/architecture pairs from vsce --publish
2931type VsceTarget = 'win32-x64' | 'win32-arm64' | 'linux-x64' | 'linux-arm64' | 'darwin-x64' | 'darwin-arm64' ;
@@ -41,6 +43,7 @@ type ToolOptions = {
4143
4244const TOOLS = {
4345 'pyocd' : downloadPyOCD ,
46+ 'gdb' : downloadGDB ,
4447} ;
4548
4649const PACKAGE_JSON = path . resolve ( __dirname , '../package.json' ) ;
@@ -104,8 +107,7 @@ async function retrieveSha256(url?: string, token?: string) {
104107 }
105108 return undefined ;
106109}
107-
108- async function download ( url : string , options ?: ToolOptions & { cache_key ?: string } ) {
110+ async function downloadAsset ( url : string , options ?: ToolOptions & { cache_key ?: string } ) {
109111 const cachePath = ( options ?. cache && options ?. cache_key ) ? path . join ( options . cache , options . cache_key ) : undefined ;
110112 if ( cachePath && existsSync ( cachePath ) ) {
111113 console . debug ( `Found asset in cache ${ cachePath } ...` ) ;
@@ -121,7 +123,7 @@ async function download(url: string, options?: ToolOptions & { cache_key?: strin
121123
122124 const extractPath = cachePath ?? downloadFilePath . replace ( '.zip' , '' ) ;
123125 console . debug ( `Extracting to ${ extractPath } ...` ) ;
124- await extractZip ( downloadFilePath , { dir : extractPath } ) . catch ( error => {
126+ await fastExtract ( downloadFilePath , extractPath ) . catch ( error => {
125127 throw new Error ( `Failed to extract ${ url } ` , { cause : error } ) ;
126128 } ) ;
127129
@@ -180,7 +182,7 @@ async function downloadPyOCD(target: VsceTarget, dest: string, options?: ToolOpt
180182 cache : options ?. cache ,
181183 cache_key : sha256sum ? `cmsis-pyocd-${ version } -${ sha256sum } ` : undefined
182184 } ;
183- const { mode, path : extractPath } = await download ( asset . url , dloptions ) ;
185+ const { mode, path : extractPath } = await downloadAsset ( asset . url , dloptions ) ;
184186
185187 if ( existsSync ( destPath ) ) {
186188 console . debug ( `Removing existing ${ destPath } ...` ) ;
@@ -202,6 +204,93 @@ async function downloadPyOCD(target: VsceTarget, dest: string, options?: ToolOpt
202204 }
203205}
204206
207+ async function downloadGDB ( target : VsceTarget , dest : string , options ?: ToolOptions ) {
208+
209+ const jsonVersion = getVersionFromPackageJson ( PACKAGE_JSON , 'gdb' ) ;
210+
211+ if ( ! jsonVersion ) {
212+ throw new Error ( 'GDB version not found in package.json' ) ;
213+ }
214+
215+ const destPath = path . join ( dest , 'gdb' ) ;
216+ const versionFilePath = path . join ( destPath , 'version.txt' ) ;
217+ const targetFilePath = path . join ( destPath , 'target.txt' ) ;
218+
219+ if ( ! options ?. force && existsSync ( versionFilePath ) && existsSync ( targetFilePath ) ) {
220+ const hasVersion = readFileSync ( versionFilePath , { encoding : 'utf8' } ) ;
221+ const hasTarget = readFileSync ( targetFilePath , { encoding : 'utf8' } ) ;
222+
223+ if ( jsonVersion === hasVersion && target === hasTarget ) {
224+ console . log ( `GDB version ${ jsonVersion } (${ target } ) already available.` ) ;
225+ return ;
226+ }
227+ }
228+
229+ console . log ( `Downloading GDB version ${ jsonVersion } (${ target } ) ...` ) ;
230+
231+ const { build, ext } = {
232+ 'win32-x64' : { build : 'mingw-w64-x86_64' , ext : 'zip' } ,
233+ 'win32-arm64' : { build : 'mingw-w64-x86_64' , ext : 'zip' } ,
234+ 'linux-x64' : { build : 'x86_64' , ext : 'tar.xz' } ,
235+ 'linux-arm64' : { build : 'aarch64' , ext : 'tar.xz' } ,
236+ 'darwin-x64' : { build : 'darwin-arm64' , ext : 'tar.xz' } ,
237+ 'darwin-arm64' : { build : 'darwin-arm64' , ext : 'tar.xz' } ,
238+ } [ target ] ;
239+
240+ const asset_name = `arm-gnu-toolchain-${ build } -arm-none-eabi-gdb.${ ext } ` ;
241+ const url = `https://artifacts.tools.arm.com/arm-none-eabi-gdb/${ jsonVersion } /${ asset_name } ` ;
242+
243+ const tempfile = await import ( 'tempfile' ) ;
244+
245+ const { mode, downloadPath } = ( options ?. cache )
246+ ? { mode : 'cache' , downloadPath : options . cache }
247+ : { mode : 'temp' , downloadPath : tempfile . default ( ) } ;
248+ const downloadFilePath = path . join ( downloadPath , asset_name ) ;
249+
250+ if ( options ?. force === false && mode === 'cache' && existsSync ( downloadFilePath ) ) {
251+ console . debug ( `Found GDB asset in cache ${ downloadFilePath } ...` ) ;
252+ } else {
253+ console . debug ( `Downloading ${ url } ...` ) ;
254+ mkdirSync ( downloadPath , { recursive : true } ) ;
255+ await downloadFile ( url , downloadFilePath )
256+ }
257+
258+ if ( existsSync ( destPath ) ) {
259+ console . debug ( `Removing existing ${ destPath } ...` ) ;
260+ rmSync ( destPath , { recursive : true , force : true } ) ;
261+ }
262+
263+ console . debug ( `Extracting ${ downloadFilePath } to ${ destPath } ...` ) ;
264+ mkdirSync ( dest , { recursive : true } ) ;
265+
266+ const { fileTypeFromFile} = await import ( 'file-type' ) ;
267+
268+ const fileType = await fileTypeFromFile ( downloadFilePath ) ;
269+
270+ if ( nodeOs . platform ( ) === 'win32' ) {
271+ await extractZip ( downloadFilePath , { dir : destPath } ) . catch ( error => {
272+ throw new Error ( `Failed to extract ${ url } ` , { cause : error } ) ;
273+ } ) ;
274+ } else {
275+ await fastExtract ( downloadFilePath , destPath , { strip : 1 , type : fileType ?. ext } ) . catch ( error => {
276+ throw new Error ( `Failed to extract ${ downloadFilePath } ` , { cause : error } ) ;
277+ } ) ;
278+ }
279+
280+
281+ // Remove doc directory as it contains duplicate files (names differ only in case)
282+ // which are not supported by ZIP (VSIX) archives
283+ rmSync ( path . join ( destPath , 'share' , 'doc' ) , { recursive : true , force : true } ) ;
284+
285+ if ( mode === 'temp' ) {
286+ console . debug ( `Removing temporary ${ downloadPath } ...` ) ;
287+ rmSync ( downloadPath , { recursive : true , force : true } ) ;
288+ }
289+
290+ writeFileSync ( versionFilePath , jsonVersion , { encoding : 'utf8' } ) ;
291+ writeFileSync ( targetFilePath , target , { encoding : 'utf8' } ) ;
292+ }
293+
205294async function main ( ) {
206295 // Get Yarn cache directory
207296 const yarnCacheDir = execSync ( 'yarn cache dir' ) . toString ( ) . trim ( ) ;
@@ -256,11 +345,11 @@ async function main() {
256345 }
257346
258347 for ( const tool of new Set ( tools ) ) {
259- TOOLS [ tool ] ( target , dest , { cache : cacheFolder ( cache ) , force } ) ;
348+ await TOOLS [ tool ] ( target , dest , { cache : cacheFolder ( cache ) , force } ) ;
260349 }
261350}
262351
263352main ( ) . catch ( error => {
264353 console . error ( error ) ;
265- process . exit ( 1 ) ;
354+ process . exitCode = 1 ;
266355} ) ;
0 commit comments