1+ #!/usr/bin/env node
2+
3+
4+ "use strict" ;
5+
6+ var _typeof = typeof Symbol === "function" && typeof Symbol . iterator === "symbol" ? function ( obj ) { return typeof obj ; } : function ( obj ) { return obj && typeof Symbol === "function" && obj . constructor === Symbol && obj !== Symbol . prototype ? "symbol" : typeof obj ; } ;
7+
8+ var request = require ( "request" ) ,
9+ path = require ( "path" ) ,
10+ unzipper = require ( "unzipper" ) ,
11+ mkdirp = require ( "mkdirp" ) ,
12+ fs = require ( "fs" ) ,
13+ exec = require ( "child_process" ) . exec ;
14+
15+ // Mapping from Node's `process.arch` to Golang's `$GOARCH`
16+ var ARCH_MAPPING = {
17+ ia32 : "386" ,
18+ x64 : "amd64" ,
19+ arm : "arm"
20+ } ;
21+
22+ // Mapping between Node's `process.platform` to Golang's
23+ var PLATFORM_MAPPING = {
24+ darwin : "darwin" ,
25+ linux : "linux" ,
26+ win32 : "windows" ,
27+ freebsd : "freebsd"
28+ } ;
29+
30+ function getInstallationPath ( callback ) {
31+ // `$npm_execpath bin` will output the path where binary files should be installed
32+ // using whichever package manager is current
33+ var execPath = process . env . npm_execpath ;
34+ var packageManager = execPath && execPath . includes ( "yarn" ) ? "yarn global" : "npm" ;
35+ exec ( packageManager + " bin" , function ( err , stdout , stderr ) {
36+ var dir = null ;
37+ if ( err || stderr && ! stderr . includes ( "No license field" ) || ! stdout || stdout . length === 0 ) {
38+ // We couldn't infer path from `npm bin`. Let's try to get it from
39+ // Environment variables set by NPM when it runs.
40+ // npm_config_prefix points to NPM's installation directory where `bin` folder is available
41+ // Ex: /Users/foo/.nvm/versions/node/v4.3.0
42+ var env = process . env ;
43+ if ( env && env . npm_config_prefix ) {
44+ dir = path . join ( env . npm_config_prefix , "bin" ) ;
45+ }
46+ } else {
47+ dir = stdout . trim ( ) ;
48+ }
49+
50+ mkdirp . sync ( dir ) ;
51+
52+ callback ( null , dir ) ;
53+ } ) ;
54+ }
55+
56+ function verifyAndPlaceBinary ( binName , binPath , callback ) {
57+ if ( ! fs . existsSync ( path . join ( binPath , binName ) ) ) return callback ( "Downloaded binary does not contain the binary specified in configuration - " + binName ) ;
58+
59+ getInstallationPath ( function ( err , installationPath ) {
60+ if ( err ) return callback ( "Error getting binary installation path from `npm bin`" ) ;
61+
62+ // Move the binary file
63+ fs . renameSync ( path . join ( binPath , binName ) , path . join ( installationPath , binName ) ) ;
64+
65+ callback ( null ) ;
66+ } ) ;
67+ }
68+
69+ function validateConfiguration ( packageJson ) {
70+ if ( ! packageJson . version ) {
71+ return "'version' property must be specified" ;
72+ }
73+
74+ if ( ! packageJson . goBinary || _typeof ( packageJson . goBinary ) !== "object" ) {
75+ return "'goBinary' property must be defined and be an object" ;
76+ }
77+
78+ if ( ! packageJson . goBinary . name ) {
79+ return "'name' property is necessary" ;
80+ }
81+
82+ if ( ! packageJson . goBinary . path ) {
83+ return "'path' property is necessary" ;
84+ }
85+
86+ if ( ! packageJson . goBinary . url ) {
87+ return "'url' property is required" ;
88+ }
89+
90+ // if (!packageJson.bin || typeof(packageJson.bin) !== "object") {
91+ // return "'bin' property of package.json must be defined and be an object";
92+ // }
93+ }
94+
95+ function parsePackageJson ( ) {
96+ if ( ! ( process . arch in ARCH_MAPPING ) ) {
97+ console . error ( "Installation is not supported for this architecture: " + process . arch ) ;
98+ return ;
99+ }
100+
101+ if ( ! ( process . platform in PLATFORM_MAPPING ) ) {
102+ console . error ( "Installation is not supported for this platform: " + process . platform ) ;
103+ return ;
104+ }
105+
106+ var packageJsonPath = path . join ( "." , "package.json" ) ;
107+ if ( ! fs . existsSync ( packageJsonPath ) ) {
108+ console . error ( "Unable to find package.json. " + "Please run this script at root of the package you want to be installed" ) ;
109+ return ;
110+ }
111+
112+ var packageJson = JSON . parse ( fs . readFileSync ( packageJsonPath ) ) ;
113+ var error = validateConfiguration ( packageJson ) ;
114+ if ( error && error . length > 0 ) {
115+ console . error ( "Invalid package.json: " + error ) ;
116+ return ;
117+ }
118+
119+ // We have validated the config. It exists in all its glory
120+ var binName = packageJson . goBinary . name ;
121+ var binPath = packageJson . goBinary . path ;
122+ var url = packageJson . goBinary . url ;
123+ var version = packageJson . version ;
124+ if ( version [ 0 ] === "v" ) version = version . substr ( 1 ) ; // strip the 'v' if necessary v0.0.1 => 0.0.1
125+
126+ // Binary name on Windows has .exe suffix
127+ if ( process . platform === "win32" ) {
128+ binName += ".exe" ;
129+ }
130+
131+ // Interpolate variables in URL, if necessary
132+ url = url . replace ( / { { arch} } / g, ARCH_MAPPING [ process . arch ] ) ;
133+ url = url . replace ( / { { platform} } / g, PLATFORM_MAPPING [ process . platform ] ) ;
134+ url = url . replace ( / { { version} } / g, version ) ;
135+ url = url . replace ( / { { bin_ n a m e } } / g, binName ) ;
136+
137+ return {
138+ binName : binName ,
139+ binPath : binPath ,
140+ url : url ,
141+ version : version
142+ } ;
143+ }
144+
145+ /**
146+ * Reads the configuration from application's package.json,
147+ * validates properties, downloads the binary, untars, and stores at
148+ * ./bin in the package's root. NPM already has support to install binary files
149+ * specific locations when invoked with "npm install -g"
150+ *
151+ * See: https://docs.npmjs.com/files/package.json#bin
152+ */
153+ function install ( callback ) {
154+ var opts = parsePackageJson ( ) ;
155+ if ( ! opts ) {
156+ return callback ( "Invalid inputs" ) ;
157+ }
158+ mkdirp . sync ( opts . binPath ) ;
159+ console . log ( "Downloading from URL: " + opts . url ) ;
160+ var req = request ( { uri : opts . url } ) ;
161+ req . on ( "error" , callback . bind ( null , "Error downloading from URL: " + opts . url ) ) ;
162+ req . on ( "response" , function ( res ) {
163+ if ( res . statusCode !== 200 ) {
164+ return callback ( "Error downloading binary. HTTP Status Code: " + res . statusCode ) ;
165+ }
166+ req . pipe ( unzipper . Extract ( { path : opts . binPath } ) ) . on ( "error" , callback )
167+ // First we will Un-GZip, then we will untar. So once untar is completed,
168+ // binary is downloaded into `binPath`. Verify the binary and call it good
169+ . on ( "close" , verifyAndPlaceBinary . bind ( null , opts . binName , opts . binPath , callback ) ) ;
170+ } ) ;
171+ }
172+
173+ function uninstall ( callback ) {
174+ var opts = parsePackageJson ( ) ;
175+ getInstallationPath ( function ( err , installationPath ) {
176+ if ( err ) callback ( "Error finding Kamanda installation directory" ) ;
177+
178+ try {
179+ fs . unlinkSync ( path . join ( installationPath , opts . binName ) ) ;
180+ } catch ( ex ) {
181+ // Ignore errors when deleting the file.
182+ }
183+
184+ return callback ( null ) ;
185+ } ) ;
186+ }
187+
188+ // Parse command line arguments and call the right method
189+ var actions = {
190+ install : install ,
191+ uninstall : uninstall
192+ } ;
193+
194+ var argv = process . argv ;
195+ if ( argv && argv . length > 2 ) {
196+ var cmd = process . argv [ 2 ] ;
197+ if ( ! actions [ cmd ] ) {
198+ console . log ( "Invalid command to go-npm. `install` and `uninstall` are the only supported commands" ) ;
199+ process . exit ( 1 ) ;
200+ }
201+
202+ actions [ cmd ] ( function ( err ) {
203+ if ( err ) {
204+ console . error ( err ) ;
205+ process . exit ( 1 ) ;
206+ } else {
207+ process . exit ( 0 ) ;
208+ }
209+ } ) ;
210+ }
211+
212+ // this code is thanks to:
213+ // https://github.com/jumoel/go-npm/blob/feat/yarn-support/src/index.js and
214+ // https://github.com/sanathkr/go-npm
0 commit comments