@@ -7,121 +7,65 @@ const srcDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
77const wasmDir = path . join ( srcDir , "node_modules" , "tree-sitter-wasms" , "out" )
88const distDir = path . join ( srcDir , "dist" )
99const wasmPattern = / ^ t r e e - s i t t e r - .* \. w a s m $ /
10- const temporaryPattern = / ^ t r e e - s i t t e r - .* \. w a s m \. \d + \. t m p $ /
11-
12- export function cleanPublishedTreeSitterWasms ( destinationDir , filesystem = fs ) {
13- if ( ! filesystem . existsSync ( destinationDir ) ) return
14- for ( const filename of filesystem . readdirSync ( destinationDir ) ) {
15- if ( wasmPattern . test ( filename ) || temporaryPattern . test ( filename ) ) {
16- filesystem . rmSync ( path . join ( destinationDir , filename ) , { force : true } )
17- }
18- }
19- }
2010
2111export async function publishTreeSitterWasms (
2212 sourceDir ,
2313 destinationDir ,
2414 { filesystem = fs . promises , onStep = async ( ) => { } , signalState = { requested : undefined } } = { } ,
2515) {
26- const transactionDir = `${ destinationDir } .tree-sitter-wasms-transaction`
27- const stagedDir = path . join ( transactionDir , "staged" )
28- const backupDir = path . join ( transactionDir , "backup" )
29- const quarantineDir = path . join ( transactionDir , "quarantine" )
16+ const stagingDir = `${ destinationDir } .tree-sitter-wasms-staging`
3017 const sourceFiles = ( await filesystem . readdir ( sourceDir ) ) . filter ( ( filename ) => wasmPattern . test ( filename ) ) . sort ( )
3118 if ( sourceFiles . length === 0 ) throw new Error ( "WASM source set is empty" )
32- const step = async ( name , filename ) => {
19+ const checkpoint = async ( name , filename ) => {
3320 await onStep ( name , filename )
34- if ( signalState . requested ) throw Object . assign ( new Error ( "WASM publication cancelled" ) , { code : "CANCELLED" } )
21+ if ( signalState . requested ) throw new Error ( "WASM publication cancelled" )
3522 }
3623
37- let commitStarted = false
38- let committed = false
39- let ownsTransaction = false
40- const publishedFiles = [ ]
24+ await filesystem . rm ( stagingDir , { recursive : true , force : true } )
25+ await filesystem . mkdir ( stagingDir , { recursive : true } )
26+ await filesystem . mkdir ( destinationDir , { recursive : true } )
4127 try {
42- await filesystem . mkdir ( destinationDir , { recursive : true } )
43- await step ( "initialized" , destinationDir )
44- await filesystem . mkdir ( transactionDir )
45- ownsTransaction = true
46- await step ( "initialized" , transactionDir )
47- await filesystem . mkdir ( stagedDir )
48- await step ( "initialized" , stagedDir )
49- await filesystem . mkdir ( backupDir )
50- await step ( "initialized" , backupDir )
51- await filesystem . mkdir ( quarantineDir )
52- await step ( "initialized" , quarantineDir )
53-
5428 for ( const filename of sourceFiles ) {
55- await filesystem . copyFile ( path . join ( sourceDir , filename ) , path . join ( stagedDir , filename ) )
56- await step ( "staged" , filename )
29+ await filesystem . copyFile ( path . join ( sourceDir , filename ) , path . join ( stagingDir , filename ) )
30+ await checkpoint ( "staged" , filename )
5731 }
58-
59- const previousFiles = ( await filesystem . readdir ( destinationDir ) ) . filter ( ( filename ) =>
60- wasmPattern . test ( filename ) ,
61- )
62- commitStarted = true
63- for ( const filename of previousFiles ) {
64- await filesystem . rename ( path . join ( destinationDir , filename ) , path . join ( backupDir , filename ) )
65- await step ( "backed-up" , filename )
66- }
67- for ( const filename of sourceFiles ) {
68- await filesystem . rename ( path . join ( stagedDir , filename ) , path . join ( destinationDir , filename ) )
69- publishedFiles . push ( filename )
70- await step ( "published" , filename )
32+ for ( const filename of await filesystem . readdir ( stagingDir ) ) {
33+ if ( ! wasmPattern . test ( filename ) ) throw new Error ( `Unexpected staged WASM: ${ filename } ` )
7134 }
72- const destinationFiles = await filesystem . readdir ( destinationDir )
73- await step ( "inspected-temporaries" , destinationDir )
74- for ( const filename of destinationFiles ) {
75- if ( temporaryPattern . test ( filename ) ) {
35+ await checkpoint ( "validated" , stagingDir )
36+
37+ for ( const filename of await filesystem . readdir ( destinationDir ) ) {
38+ if ( wasmPattern . test ( filename ) || ( filename . includes ( "tree-sitter-" ) && filename . endsWith ( ".tmp" ) ) ) {
7639 await filesystem . rm ( path . join ( destinationDir , filename ) , { force : true } )
77- await step ( "removed-temporary" , filename )
7840 }
7941 }
80-
81- committed = true
82- await filesystem . rm ( transactionDir , { recursive : true , force : true } )
83- return { sourceFiles, cleanup : ( ) => cleanPublishedTreeSitterWasms ( destinationDir ) }
84- } catch ( error ) {
85- if ( committed ) throw error
86- if ( ! commitStarted && ownsTransaction ) {
87- await filesystem . rm ( transactionDir , { recursive : true , force : true } )
88- }
89- if ( ! commitStarted ) throw error
90-
91- const failures = [ ]
92- for ( const filename of publishedFiles ) {
93- try {
94- await filesystem . rename ( path . join ( destinationDir , filename ) , path . join ( quarantineDir , filename ) )
95- } catch ( rollbackError ) {
96- if ( rollbackError . code !== "ENOENT" ) failures . push ( rollbackError )
97- }
42+ for ( const filename of sourceFiles ) {
43+ await filesystem . rename ( path . join ( stagingDir , filename ) , path . join ( destinationDir , filename ) )
44+ await checkpoint ( "published" , filename )
9845 }
99- for ( const filename of await filesystem . readdir ( backupDir ) ) {
100- try {
101- await filesystem . rename ( path . join ( backupDir , filename ) , path . join ( destinationDir , filename ) )
102- await onStep ( "restored" , filename )
103- } catch ( rollbackError ) {
104- failures . push ( rollbackError )
46+ await checkpoint ( "completed" , destinationDir )
47+ } catch ( error ) {
48+ try {
49+ for ( const filename of await filesystem . readdir ( destinationDir ) ) {
50+ if ( wasmPattern . test ( filename ) )
51+ await filesystem . rm ( path . join ( destinationDir , filename ) , { force : true } )
10552 }
106- }
107- if ( failures . length > 0 ) {
53+ } catch ( cleanupError ) {
10854 throw new AggregateError (
109- [ error , ... failures ] ,
110- `WASM rollback incomplete; recovery retained at ${ transactionDir } ` ,
55+ [ error , cleanupError ] ,
56+ `WASM publication and cleanup failed; remove ${ stagingDir } and rerun to rebuild ` ,
11157 )
11258 }
113- await filesystem . rm ( transactionDir , { recursive : true , force : true } )
11459 throw error
60+ } finally {
61+ await filesystem . rm ( stagingDir , { recursive : true , force : true } )
11562 }
63+ return { sourceFiles }
11664}
11765
11866if ( process . argv [ 1 ] === fileURLToPath ( import . meta. url ) ) {
11967 const signalState = { requested : undefined }
120- for ( const signal of [ "SIGINT" , "SIGTERM" ] ) {
121- process . on ( signal , ( ) => {
122- signalState . requested ??= signal
123- } )
124- }
68+ for ( const signal of [ "SIGINT" , "SIGTERM" ] ) process . on ( signal , ( ) => ( signalState . requested ??= signal ) )
12569 try {
12670 await publishTreeSitterWasms ( wasmDir , distDir , { signalState } )
12771 if ( signalState . requested ) process . exitCode = signalState . requested === "SIGINT" ? 130 : 143
0 commit comments