@@ -6,17 +6,30 @@ import events from 'node:events';
6
6
import path from 'node:path' ;
7
7
import https from 'node:https' ;
8
8
import stream from 'node:stream/promises' ;
9
+ import url from 'node:url' ;
10
+
11
+ const __dirname = path . dirname ( url . fileURLToPath ( import . meta. url ) ) ;
12
+
13
+ /** Resolves to the root of this repository */
14
+ function resolveRoot ( ...paths ) {
15
+ return path . resolve ( __dirname , '..' , '..' , ...paths ) ;
16
+ }
17
+
18
+ async function exists ( fsPath ) {
19
+ try {
20
+ await fs . access ( fsPath ) ;
21
+ return true ;
22
+ } catch {
23
+ return false ;
24
+ }
25
+ }
9
26
10
27
async function parseArguments ( ) {
11
- const jsonImport = {
12
- [ process . version . split ( '.' ) . at ( 0 ) === 'v16' ? 'assert' : 'with' ] : { type : 'json' }
13
- } ;
14
- const pkg = ( await import ( '../../package.json' , jsonImport ) ) . default ;
15
- const libmongocryptVersion = pkg [ 'mongodb:libmongocrypt' ] ;
28
+ const pkg = JSON . parse ( await fs . readFile ( resolveRoot ( 'package.json' ) , 'utf8' ) ) ;
16
29
17
30
const options = {
18
31
gitURL : { short : 'u' , type : 'string' , default : 'https://github.com/mongodb/libmongocrypt.git' } ,
19
- libVersion : { short : 'l' , type : 'string' , default : libmongocryptVersion } ,
32
+ libVersion : { short : 'l' , type : 'string' , default : pkg [ 'mongodb:libmongocrypt' ] } ,
20
33
clean : { short : 'c' , type : 'boolean' , default : false } ,
21
34
build : { short : 'b' , type : 'boolean' , default : false } ,
22
35
help : { short : 'h' , type : 'boolean' , default : false }
@@ -44,44 +57,32 @@ async function parseArguments() {
44
57
/** `xtrace` style command runner, uses spawn so that stdio is inherited */
45
58
async function run ( command , args = [ ] , options = { } ) {
46
59
console . error ( `+ ${ command } ${ args . join ( ' ' ) } ` , options . cwd ? `(in: ${ options . cwd } )` : '' ) ;
47
- await events . once ( child_process . spawn ( command , args , { stdio : 'inherit' , ...options } ) , 'exit' ) ;
60
+ await events . once (
61
+ child_process . spawn ( command , args , { stdio : 'inherit' , cwd : resolveRoot ( '.' ) , ...options } ) ,
62
+ 'exit'
63
+ ) ;
48
64
}
49
65
50
66
/** CLI flag maker: `toFlags({a: 1, b: 2})` yields `['-a=1', '-b=2']` */
51
67
function toFlags ( object ) {
52
68
return Array . from ( Object . entries ( object ) ) . map ( ( [ k , v ] ) => `-${ k } =${ v } ` ) ;
53
69
}
54
70
55
- const args = await parseArguments ( ) ;
56
- const libmongocryptRoot = path . resolve ( '_libmongocrypt' ) ;
57
-
58
- const currentLibMongoCryptBranch = await fs
59
- . readFile ( path . join ( libmongocryptRoot , '.git' , 'HEAD' ) , 'utf8' )
60
- . catch ( ( ) => '' ) ;
61
- const libmongocryptAlreadyClonedAndCheckedOut = currentLibMongoCryptBranch
62
- . trim ( )
63
- . endsWith ( `r-${ args . libmongocrypt . ref } ` ) ;
64
-
65
- if ( args . build && ( args . clean || ! libmongocryptAlreadyClonedAndCheckedOut ) ) {
66
- console . error ( 'fetching libmongocrypt...' , args . libmongocrypt ) ;
71
+ export async function cloneLibMongoCrypt ( libmongocryptRoot , { url, ref } ) {
72
+ console . error ( 'fetching libmongocrypt...' , { url, ref } ) ;
67
73
await fs . rm ( libmongocryptRoot , { recursive : true , force : true } ) ;
68
- await run ( 'git' , [ 'clone' , args . libmongocrypt . url , libmongocryptRoot ] ) ;
69
- await run ( 'git' , [ 'fetch' , '--tags' ] , { cwd : libmongocryptRoot } ) ;
70
- await run ( 'git' , [ 'checkout' , args . libmongocrypt . ref , '-b' , `r-${ args . libmongocrypt . ref } ` ] , {
71
- cwd : libmongocryptRoot
72
- } ) ;
74
+ await run ( 'git' , [ 'clone' , url , libmongocryptRoot ] ) ;
75
+ if ( ref !== 'latest' ) {
76
+ // Support "latest" as leaving the clone as-is so whatever the default branch name is works
77
+ await run ( 'git' , [ 'fetch' , '--tags' ] , { cwd : libmongocryptRoot } ) ;
78
+ await run ( 'git' , [ 'checkout' , ref , '-b' , `r-${ ref } ` ] , { cwd : libmongocryptRoot } ) ;
79
+ }
73
80
}
74
81
75
- const libmongocryptBuiltVersion = await fs
76
- . readFile ( path . join ( libmongocryptRoot , 'VERSION_CURRENT' ) , 'utf8' )
77
- . catch ( ( ) => '' ) ;
78
- const libmongocryptAlreadyBuilt = libmongocryptBuiltVersion . trim ( ) === args . libmongocrypt . ref ;
79
-
80
- if ( args . build && ( args . clean || ! libmongocryptAlreadyBuilt ) ) {
81
- console . error ( 'building libmongocrypt...\n' , args . libmongocrypt ) ;
82
+ export async function buildLibMongoCrypt ( libmongocryptRoot , nodeDepsRoot ) {
83
+ console . error ( 'building libmongocrypt...' ) ;
82
84
83
- const nodeDepsRoot = path . resolve ( 'deps' ) ;
84
- const nodeBuildRoot = path . resolve ( nodeDepsRoot , 'tmp' , 'libmongocrypt-build' ) ;
85
+ const nodeBuildRoot = resolveRoot ( nodeDepsRoot , 'tmp' , 'libmongocrypt-build' ) ;
85
86
86
87
await fs . rm ( nodeBuildRoot , { recursive : true , force : true } ) ;
87
88
await fs . mkdir ( nodeBuildRoot , { recursive : true } ) ;
@@ -137,14 +138,14 @@ if (args.build && (args.clean || !libmongocryptAlreadyBuilt)) {
137
138
} ) ;
138
139
}
139
140
140
- if ( ! args . build ) {
141
+ export async function downloadLibMongoCrypt ( nodeDepsRoot , { ref } ) {
141
142
const downloadURL =
142
- args . libmongocrypt . ref === 'latest'
143
+ ref === 'latest'
143
144
? 'https://mciuploads.s3.amazonaws.com/libmongocrypt/all/master/latest/libmongocrypt-all.tar.gz'
144
- : `https://mciuploads.s3.amazonaws.com/libmongocrypt/all/${ args . libmongocrypt . ref } /libmongocrypt-all.tar.gz` ;
145
+ : `https://mciuploads.s3.amazonaws.com/libmongocrypt/all/${ ref } /libmongocrypt-all.tar.gz` ;
145
146
146
147
console . error ( 'downloading libmongocrypt...' , downloadURL ) ;
147
- const destination = `_libmongocrypt-${ args . libmongocrypt . ref } ` ;
148
+ const destination = resolveRoot ( `_libmongocrypt-${ ref } ` ) ;
148
149
149
150
await fs . rm ( destination , { recursive : true , force : true } ) ;
150
151
await fs . mkdir ( destination ) ;
@@ -159,12 +160,15 @@ if (!args.build) {
159
160
[ 'win32-x64' ] : 'windows-test'
160
161
} ;
161
162
162
- const platform = platformMatrix [ `${ process . platform } -${ process . arch } ` ] ;
163
- if ( platform == null ) throw new Error ( `${ process . platform } -${ process . arch } ` ) ;
163
+ const detectedPlatform = `${ process . platform } -${ process . arch } ` ;
164
+ const prebuild = platformMatrix [ detectedPlatform ] ;
165
+ if ( prebuild == null ) throw new Error ( `Unsupported: ${ detectedPlatform } ` ) ;
164
166
165
- const unzip = child_process . spawn ( 'tar' , [ '-xz' , '-C' , destination , `${ platform } /nocrypto` ] , {
166
- stdio : [ 'pipe' ]
167
- } ) ;
167
+ console . error ( `Platform: ${ detectedPlatform } Prebuild: ${ prebuild } ` ) ;
168
+
169
+ const unzipArgs = [ '-xzv' , '-C' , destination , `${ prebuild } /nocrypto` ] ;
170
+ console . error ( `+ tar ${ unzipArgs . join ( ' ' ) } ` ) ;
171
+ const unzip = child_process . spawn ( 'tar' , unzipArgs , { stdio : [ 'pipe' , 'inherit' ] } ) ;
168
172
169
173
const [ response ] = await events . once ( https . get ( downloadURL ) , 'response' ) ;
170
174
@@ -174,12 +178,53 @@ if (!args.build) {
174
178
175
179
console . error ( `downloaded libmongocrypt in ${ ( end - start ) / 1000 } secs...` ) ;
176
180
177
- await fs . rm ( 'deps' , { recursive : true , force : true } ) ;
178
- await fs . cp ( path . join ( destination , platform , 'nocrypto' ) , 'deps' , { recursive : true } ) ;
179
- if ( await fs . access ( path . join ( 'deps' , 'lib64' ) ) . then ( ( ) => true , ( ) => false ) ) {
180
- await fs . rename ( path . join ( 'deps' , 'lib64' ) , path . join ( 'deps' , 'lib' ) ) ;
181
+ await fs . rm ( nodeDepsRoot , { recursive : true , force : true } ) ;
182
+ await fs . cp ( resolveRoot ( destination , prebuild , 'nocrypto' ) , nodeDepsRoot , { recursive : true } ) ;
183
+ if ( await exists ( path . join ( nodeDepsRoot , 'lib64' ) ) ) {
184
+ await fs . rename ( path . join ( nodeDepsRoot , 'lib64' ) , path . join ( nodeDepsRoot , 'lib' ) ) ;
181
185
}
182
186
}
183
187
184
- await run ( 'npm' , [ 'install' , '--ignore-scripts' ] ) ;
185
- await run ( 'npm' , [ 'run' , 'rebuild' ] , { env : { ...process . env , BUILD_TYPE : 'static' } } ) ;
188
+ async function main ( ) {
189
+ const { libmongocrypt, build, clean } = await parseArguments ( ) ;
190
+
191
+ const nodeDepsDir = resolveRoot ( 'deps' ) ;
192
+
193
+ if ( build ) {
194
+ const libmongocryptCloneDir = resolveRoot ( '_libmongocrypt' ) ;
195
+
196
+ const currentLibMongoCryptBranch = await fs
197
+ . readFile ( path . join ( libmongocryptCloneDir , '.git' , 'HEAD' ) , 'utf8' )
198
+ . catch ( ( ) => '' ) ;
199
+ const isClonedAndCheckedOut = currentLibMongoCryptBranch
200
+ . trim ( )
201
+ . endsWith ( `r-${ libmongocrypt . ref } ` ) ;
202
+
203
+ if ( clean || ! isClonedAndCheckedOut ) {
204
+ await cloneLibMongoCrypt ( libmongocryptCloneDir , libmongocrypt ) ;
205
+ }
206
+
207
+ const libmongocryptBuiltVersion = await fs
208
+ . readFile ( path . join ( libmongocryptCloneDir , 'VERSION_CURRENT' ) , 'utf8' )
209
+ . catch ( ( ) => '' ) ;
210
+ const isBuilt = libmongocryptBuiltVersion . trim ( ) === libmongocrypt . ref ;
211
+
212
+ if ( clean || ! isBuilt ) {
213
+ await buildLibMongoCrypt ( libmongocryptCloneDir , nodeDepsDir ) ;
214
+ }
215
+ } else {
216
+ // Download
217
+ await downloadLibMongoCrypt ( nodeDepsDir , libmongocrypt ) ;
218
+ }
219
+
220
+ await fs . rm ( resolveRoot ( 'build' ) , { force : true , recursive : true } ) ;
221
+ await fs . rm ( resolveRoot ( 'prebuilds' ) , { force : true , recursive : true } ) ;
222
+
223
+ // install with "ignore-scripts" so that we don't attempt to download a prebuild
224
+ await run ( 'npm' , [ 'install' , '--ignore-scripts' ] ) ;
225
+ // The prebuild command will make both a .node file in `./build` (local and CI testing will run on current code)
226
+ // it will also produce `./prebuild/xx.tgz`. prebuild has GH upload functionality.
227
+ await run ( 'npm' , [ 'run' , 'prebuild' ] ) ;
228
+ }
229
+
230
+ await main ( ) ;
0 commit comments