@@ -61,36 +61,64 @@ async function main() {
6161
6262 // prompt which files to download from assets
6363 // TODO: reorder by matching arch/os/platform
64- const selectedAsset = await prompts . select < string > ( {
64+ const selectedAssetMeta = await prompts . select < {
65+ name : string ;
66+ browser_download_url : string ;
67+ } > ( {
6568 message : "Select an asset to download" ,
6669 options : assets . map ( ( asset : any ) => ( {
6770 label : asset . name ,
68- value : asset . browser_download_url ,
71+ value : asset ,
6972 } ) ) ,
7073 } ) ;
71- if ( prompts . isCancel ( selectedAsset ) ) {
74+ if ( prompts . isCancel ( selectedAssetMeta ) ) {
7275 return ;
7376 }
7477
7578 // download a selected asset
79+ const selectedAsset = selectedAssetMeta . name ;
80+ const selectedAssetUrl = selectedAssetMeta . browser_download_url ;
7681 const downloadSpinner = prompts . spinner ( ) ;
7782 downloadSpinner . start ( `Downloading ${ selectedAsset } ` ) ;
7883 let tmpAssetPath = path . join (
7984 os . tmpdir ( ) ,
8085 `gh-bin-asset-${ owner } -${ repo } ${ path . extname ( selectedAsset ) } `
8186 ) ;
8287 try {
83- const res = await fetch ( selectedAsset ) ;
88+ const res = await fetch ( selectedAssetUrl ) ;
8489 if ( ! res . ok || ! res . body ) {
85- console . error ( `[ERROR] Failed to download '${ selectedAsset } '\n` ) ;
90+ console . error ( `[ERROR] Failed to download '${ selectedAssetUrl } '\n` ) ;
8691 process . exit ( 1 ) ;
8792 }
88- await fs . promises . writeFile (
89- tmpAssetPath ,
90- Readable . fromWeb ( res . body as any )
93+ const contentLength = res . headers . get ( "content-length" ) ;
94+ const total = contentLength ? Number ( contentLength ) : null ;
95+ let current = 0 ;
96+ const stream = res . body . pipeThrough (
97+ new TransformStream ( {
98+ transform ( chunk , controller ) {
99+ controller . enqueue ( chunk ) ;
100+ current += chunk . byteLength ;
101+ if ( total ) {
102+ downloadSpinner . message (
103+ `Downloading ${ selectedAsset } (${ prettyBytes ( total ) } - ${ ( ( 100 * current ) / total ! ) . toFixed ( 2 ) } %)`
104+ ) ;
105+ } else {
106+ downloadSpinner . message (
107+ `Downloading ${ selectedAsset } (${ prettyBytes ( current ) } )`
108+ ) ;
109+ }
110+ } ,
111+ flush ( ) {
112+ downloadSpinner . stop (
113+ `Download success ${ selectedAsset } (${ prettyBytes ( current ) } )`
114+ ) ;
115+ } ,
116+ } )
91117 ) ;
92- } finally {
93- downloadSpinner . stop ( `Downloaded ${ selectedAsset } ` ) ;
118+ await fs . promises . writeFile ( tmpAssetPath , Readable . fromWeb ( stream as any ) ) ;
119+ } catch ( e ) {
120+ downloadSpinner . stop ( `Failed to download '${ selectedAssetUrl } '` ) ;
121+ throw e ;
94122 }
95123
96124 let defaultBinName = repo ;
@@ -166,6 +194,12 @@ async function main() {
166194 console . log ( `Executable is installed in ${ destPath } ` ) ;
167195}
168196
197+ function prettyBytes ( bytes : number ) : string {
198+ return bytes > 1024
199+ ? `${ ( bytes / ( 1024 * 1024 ) ) . toFixed ( 2 ) } MB`
200+ : `${ ( bytes / 1024 ) . toFixed ( 2 ) } KB` ;
201+ }
202+
169203async function fetchGhApi ( url : string ) {
170204 const res = await fetch ( url , {
171205 headers : {
0 commit comments