@@ -15,44 +15,55 @@ import { fileURLToPath } from "node:url";
1515
1616const HOST = "https://copy.sh/v86/" ;
1717
18- const files = [
18+ const remote = [
1919 {
2020 url : HOST + "bios/seabios.bin" ,
2121 out : "public/v86/bios/seabios.bin" ,
22+ size : 131072 ,
2223 sha256 : "73e3f359102e3a9982c35fce98eb7cd08f18303ac7f1ba6ebfbe6cdc1c244d98" ,
2324 } ,
2425 {
2526 url : HOST + "bios/vgabios.bin" ,
2627 out : "public/v86/bios/vgabios.bin" ,
28+ size : 36352 ,
2729 sha256 : "a4bc0d80cc3ca028c73dafa8fee396b8d054ce87ebd8abfbd31b06b437607880" ,
2830 } ,
2931 {
3032 url : HOST + "images/linux4.iso" ,
3133 out : "public/v86/images/linux.iso" ,
34+ size : 7712768 ,
3235 sha256 : "cb403835be0d857191cdeb86efc8d559b94a787d6fcb57e0a04667296405c223" ,
3336 } ,
3437] ;
3538
39+ const bundled = [
40+ { src : "node_modules/v86/build/v86.wasm" , out : "public/v86/build/v86.wasm" } ,
41+ { src : "node_modules/v86/build/v86-fallback.wasm" , out : "public/v86/build/v86-fallback.wasm" } ,
42+ ] ;
43+
3644const root = dirname ( dirname ( fileURLToPath ( import . meta. url ) ) ) ;
45+ const verify = process . argv . includes ( "--verify" ) || process . env . CI === "true" ;
3746
3847const sha256 = async ( path ) => {
3948 const hash = createHash ( "sha256" ) ;
4049 await pipeline ( createReadStream ( path ) , hash ) ;
4150 return hash . digest ( "hex" ) ;
4251} ;
4352
44- const download = async ( url , outRel , expectedHash ) => {
45- const out = join ( root , outRel ) ;
46- if ( existsSync ( out ) && statSync ( out ) . size > 0 ) {
47- const actual = await sha256 ( out ) ;
48- if ( actual === expectedHash ) {
49- console . log ( `✓ cached ${ outRel } ` ) ;
50- return ;
51- }
52- console . warn ( `! hash mismatch for cached ${ outRel } ; re-downloading` ) ;
53- unlinkSync ( out ) ;
53+ const isCached = async ( path , size , hash ) => {
54+ if ( ! existsSync ( path ) || statSync ( path ) . size !== size ) return false ;
55+ if ( ! verify ) return true ;
56+ return ( await sha256 ( path ) ) === hash ;
57+ } ;
58+
59+ const fetchOne = async ( { url, out, size, sha256 : expected } ) => {
60+ const abs = join ( root , out ) ;
61+ if ( await isCached ( abs , size , expected ) ) {
62+ console . log ( `✓ cached ${ out } ` ) ;
63+ return ;
5464 }
55- mkdirSync ( dirname ( out ) , { recursive : true } ) ;
65+ if ( existsSync ( abs ) ) unlinkSync ( abs ) ;
66+ mkdirSync ( dirname ( abs ) , { recursive : true } ) ;
5667 console . log ( `↓ ${ url } ` ) ;
5768 const res = await fetch ( url ) ;
5869 if ( ! res . ok || ! res . body ) {
@@ -61,37 +72,45 @@ const download = async (url, outRel, expectedHash) => {
6172 `${ url } → ${ res . status } ${ res . statusText } ${ snippet . slice ( 0 , 120 ) . replace ( / \s + / g, " " ) } ` . trim ( ) ,
6273 ) ;
6374 }
64- const tmp = out + ".part" ;
75+ const tmp = abs + ".part" ;
6576 try {
6677 await pipeline ( res . body , createWriteStream ( tmp ) ) ;
6778 const actual = await sha256 ( tmp ) ;
68- if ( actual !== expectedHash ) {
69- throw new Error ( `sha256 mismatch for ${ outRel } : got ${ actual } , expected ${ expectedHash } ` ) ;
79+ if ( actual !== expected ) {
80+ throw new Error ( `sha256 mismatch for ${ out } : got ${ actual } , expected ${ expected } ` ) ;
7081 }
71- renameSync ( tmp , out ) ;
82+ renameSync ( tmp , abs ) ;
7283 } catch ( e ) {
7384 try {
7485 unlinkSync ( tmp ) ;
7586 } catch { }
7687 throw e ;
7788 }
78- console . log ( ` saved ${ outRel } (${ statSync ( out ) . size } bytes)` ) ;
89+ console . log ( ` saved ${ out } (${ statSync ( abs ) . size } bytes)` ) ;
7990} ;
8091
81- for ( const f of files ) {
92+ const copyOne = ( { src, out } ) => {
93+ const absSrc = join ( root , src ) ;
94+ const absOut = join ( root , out ) ;
95+ const srcSize = statSync ( absSrc ) . size ;
96+ if ( existsSync ( absOut ) && statSync ( absOut ) . size === srcSize ) {
97+ console . log ( `✓ cached ${ out } ` ) ;
98+ return ;
99+ }
100+ mkdirSync ( dirname ( absOut ) , { recursive : true } ) ;
101+ copyFileSync ( absSrc , absOut ) ;
102+ console . log ( ` copied ${ out } ` ) ;
103+ } ;
104+
105+ let failed = false ;
106+ for ( const f of remote ) {
82107 try {
83- await download ( f . url , f . out , f . sha256 ) ;
108+ await fetchOne ( f ) ;
84109 } catch ( e ) {
85110 console . error ( `failed ${ f . url } :` , e . message ) ;
86- process . exitCode = 1 ;
111+ failed = true ;
87112 }
88113}
114+ for ( const f of bundled ) copyOne ( f ) ;
89115
90- const wasms = [ "v86.wasm" , "v86-fallback.wasm" ] ;
91- for ( const name of wasms ) {
92- const src = join ( root , "node_modules/v86/build" , name ) ;
93- const out = join ( root , "public/v86/build" , name ) ;
94- mkdirSync ( dirname ( out ) , { recursive : true } ) ;
95- copyFileSync ( src , out ) ;
96- console . log ( `✓ copied ${ name } ` ) ;
97- }
116+ if ( failed ) process . exitCode = 1 ;
0 commit comments