1
+ import util from 'node:util' ;
2
+ import process from 'node:process' ;
3
+ import fs from 'node:fs/promises' ;
4
+ import child_process from 'node:child_process' ;
5
+ import events from 'node:events' ;
6
+ import path from 'node:path' ;
7
+
8
+ async function parseArguments ( ) {
9
+ const jsonImport = { [ process . version . split ( '.' ) . at ( 0 ) === 'v16' ? 'assert' : 'with' ] : { type : 'json' } } ;
10
+ const pkg = ( await import ( './package.json' , jsonImport ) ) . default ;
11
+ const libmongocryptVersion = pkg [ 'mongodb:libmongocrypt' ] ;
12
+
13
+ const options = {
14
+ url : { short : 'u' , type : 'string' , default : 'https://github.com/mongodb/libmongocrypt.git' } ,
15
+ libversion : { short : 'l' , type : 'string' , default : libmongocryptVersion } ,
16
+ clean : { short : 'c' , type : 'boolean' } ,
17
+ help : { short : 'h' , type : 'boolean' }
18
+ } ;
19
+
20
+ const args = util . parseArgs ( { args : process . argv . slice ( 2 ) , options, allowPositionals : false } ) ;
21
+
22
+ if ( args . values . help ) {
23
+ console . log (
24
+ `${ process . argv [ 1 ] } ${ [ ...Object . keys ( options ) ]
25
+ . filter ( k => k !== 'help' )
26
+ . map ( k => `[--${ k } =${ options [ k ] . type } ]` )
27
+ . join ( ' ' ) } `
28
+ ) ;
29
+ process . exit ( 0 ) ;
30
+ }
31
+
32
+ return {
33
+ libmongocrypt : { url : args . values . url , ref : args . values . libversion } ,
34
+ clean : args . values . clean
35
+ } ;
36
+ }
37
+
38
+ /** `xtrace` style command runner, uses spawn so that stdio is inherited */
39
+ async function run ( command , args = [ ] , options = { } ) {
40
+ console . error ( `+ ${ command } ${ args . join ( ' ' ) } ` , options . cwd ? `(in: ${ options . cwd } )` : '' ) ;
41
+ await events . once ( child_process . spawn ( command , args , { stdio : 'inherit' , ...options } ) , 'exit' ) ;
42
+ }
43
+
44
+ /** CLI flag maker: `toFlags({a: 1, b: 2})` yields `['-a=1', '-b=2']` */
45
+ function toFlags ( object ) {
46
+ return Array . from ( Object . entries ( object ) ) . map ( ( [ k , v ] ) => `-${ k } =${ v } ` ) ;
47
+ }
48
+
49
+ const args = await parseArguments ( ) ;
50
+ const libmongocryptRoot = path . resolve ( '_libmongocrypt' ) ;
51
+
52
+ const currentLibMongoCryptBranch = await fs . readFile ( path . join ( libmongocryptRoot , '.git' , 'HEAD' ) , 'utf8' ) . catch ( ( ) => '' )
53
+ const libmongocryptAlreadyClonedAndCheckedOut = currentLibMongoCryptBranch . trim ( ) . endsWith ( `r-${ args . libmongocrypt . ref } ` ) ;
54
+
55
+ if ( ! args . clean && ! libmongocryptAlreadyClonedAndCheckedOut ) {
56
+ console . error ( 'fetching libmongocrypt...' , args . libmongocrypt ) ;
57
+ await fs . rm ( libmongocryptRoot , { recursive : true , force : true } ) ;
58
+ await run ( 'git' , [ 'clone' , args . libmongocrypt . url , libmongocryptRoot ] ) ;
59
+ await run ( 'git' , [ 'fetch' , '--tags' ] , { cwd : libmongocryptRoot } ) ;
60
+ await run ( 'git' , [ 'checkout' , args . libmongocrypt . ref , '-b' , `r-${ args . libmongocrypt . ref } ` ] , { cwd : libmongocryptRoot } ) ;
61
+ } else {
62
+ console . error ( 'libmongocrypt already up to date...' , args . libmongocrypt ) ;
63
+ }
64
+
65
+ const libmongocryptBuiltVersion = await fs . readFile ( path . join ( libmongocryptRoot , 'VERSION_CURRENT' ) , 'utf8' ) . catch ( ( ) => '' ) ;
66
+ const libmongocryptAlreadyBuilt = libmongocryptBuiltVersion . trim ( ) === args . libmongocrypt . ref ;
67
+
68
+ if ( ! args . clean && ! libmongocryptAlreadyBuilt ) {
69
+ console . error ( 'building libmongocrypt...\n' , args ) ;
70
+
71
+ const nodeDepsRoot = path . resolve ( 'deps' ) ;
72
+ const nodeBuildRoot = path . resolve ( nodeDepsRoot , 'tmp' , 'libmongocrypt-build' ) ;
73
+
74
+ await fs . rm ( nodeBuildRoot , { recursive : true , force : true } ) ;
75
+ await fs . mkdir ( nodeBuildRoot , { recursive : true } ) ;
76
+
77
+ const CMAKE_FLAGS = toFlags ( {
78
+ /**
79
+ * We provide crypto hooks from Node.js binding to openssl (so disable system crypto)
80
+ * TODO: NODE-5455
81
+ *
82
+ * One thing that is not obvious from the build instructions for libmongocrypt
83
+ * and the Node.js bindings is that the Node.js driver uses libmongocrypt in
84
+ * DISABLE_NATIVE_CRYPTO aka nocrypto mode, that is, instead of using native
85
+ * system libraries for crypto operations, it provides callbacks to libmongocrypt
86
+ * which, in the Node.js addon case, call JS functions that in turn call built-in
87
+ * Node.js crypto methods.
88
+ *
89
+ * That’s way more convoluted than it needs to be, considering that we always
90
+ * have a copy of OpenSSL available directly, but for now it seems to make sense
91
+ * to stick with what the Node.js addon does here.
92
+ */
93
+ DDISABLE_NATIVE_CRYPTO : '1' ,
94
+ /** A consistent name for the output "library" directory */
95
+ DCMAKE_INSTALL_LIBDIR : 'lib' ,
96
+ /** No warnings allowed */
97
+ DENABLE_MORE_WARNINGS_AS_ERRORS : 'ON' ,
98
+ /** Where to build libmongocrypt */
99
+ DCMAKE_PREFIX_PATH : nodeDepsRoot ,
100
+ /**
101
+ * Where to install libmongocrypt
102
+ * Note that `binding.gyp` will set `./deps/include`
103
+ * as an include path if BUILD_TYPE=static
104
+ */
105
+ DCMAKE_INSTALL_PREFIX : nodeDepsRoot
106
+ } ) ;
107
+
108
+ const WINDOWS_CMAKE_FLAGS =
109
+ process . platform === 'win32' // Windows is still called "win32" when it is 64-bit
110
+ ? toFlags ( { Thost : 'x64' , A : 'x64' , DENABLE_WINDOWS_STATIC_RUNTIME : 'ON' } )
111
+ : [ ] ;
112
+
113
+ const MACOS_CMAKE_FLAGS =
114
+ process . platform === 'darwin' // The minimum macos target version we want for
115
+ ? toFlags ( { DCMAKE_OSX_DEPLOYMENT_TARGET : '10.12' } )
116
+ : [ ] ;
117
+
118
+ await run ( 'cmake' , [ ...CMAKE_FLAGS , ...WINDOWS_CMAKE_FLAGS , ...MACOS_CMAKE_FLAGS , libmongocryptRoot ] , { cwd : nodeBuildRoot } ) ;
119
+ await run ( 'cmake' , [ '--build' , '.' , '--target' , 'install' , '--config' , 'RelWithDebInfo' ] , { cwd : nodeBuildRoot } ) ;
120
+ } else {
121
+ console . error ( 'libmongocrypt already built...' ) ;
122
+ }
123
+
124
+ await run ( 'npm' , [ 'install' , '--ignore-scripts' ] ) ;
125
+ await run ( 'npm' , [ 'run' , 'rebuild' ] , { env : { ...process . env , BUILD_TYPE : 'static' } } ) ;
0 commit comments