@@ -60,6 +60,8 @@ var execSync = require('child_process').execSync;
60
60
var spawn = require ( 'cross-spawn' ) ;
61
61
var semver = require ( 'semver' ) ;
62
62
var dns = require ( 'dns' ) ;
63
+ var tmp = require ( 'tmp' ) ;
64
+ var unpack = require ( 'tar-pack' ) . unpack ;
63
65
64
66
var projectName ;
65
67
@@ -201,20 +203,25 @@ function install(useYarn, dependencies, verbose, isOnline) {
201
203
202
204
function run ( root , appName , version , verbose , originalDirectory , template ) {
203
205
var packageToInstall = getInstallPackage ( version ) ;
204
- var packageName = getPackageName ( packageToInstall ) ;
206
+ var packageName = packageToInstall ;
205
207
206
208
var allDependencies = [ 'react' , 'react-dom' , packageToInstall ] ;
207
209
208
210
console . log ( 'Installing packages. This might take a couple minutes.' ) ;
209
- console . log (
210
- 'Installing ' + chalk . cyan ( 'react' ) + ', ' + chalk . cyan ( 'react-dom' ) +
211
- ', and ' + chalk . cyan ( packageName ) + '...'
212
- ) ;
213
- console . log ( ) ;
214
-
211
+
215
212
var useYarn = shouldUseYarn ( ) ;
216
- checkIfOnline ( useYarn )
213
+ getPackageName ( packageToInstall )
214
+ . then ( function ( _packageName ) {
215
+ packageName = _packageName ;
216
+ return checkIfOnline ( useYarn ) ;
217
+ } )
217
218
. then ( function ( isOnline ) {
219
+ console . log (
220
+ 'Installing ' + chalk . cyan ( 'react' ) + ', ' + chalk . cyan ( 'react-dom' ) +
221
+ ', and ' + chalk . cyan ( packageName ) + '...'
222
+ ) ;
223
+ console . log ( ) ;
224
+
218
225
return install ( useYarn , allDependencies , verbose , isOnline ) ;
219
226
} )
220
227
. then ( function ( ) {
@@ -288,19 +295,48 @@ function getInstallPackage(version) {
288
295
// Extract package name from tarball url or path.
289
296
function getPackageName ( installPackage ) {
290
297
if ( installPackage . indexOf ( '.tgz' ) > - 1 ) {
291
- // The package name could be with or without semver version, e.g. react-scripts-0.2.0-alpha.1.tgz
292
- // However, this function returns package name only without semver version.
293
- return installPackage . match ( / ^ .+ \/ ( .+ ?) (?: - \d + .+ ) ? \. t g z $ / ) [ 1 ] ;
298
+ return new Promise ( function ( resolve , reject ) {
299
+ tmp . dir ( { unsafeCleanup : true } , function ( err , tmpdir , callback ) {
300
+ if ( err ) {
301
+ reject ( err ) ;
302
+ } else {
303
+ resolve ( {
304
+ tmpdir : tmpdir ,
305
+ callback : callback
306
+ } ) ;
307
+ }
308
+ } ) ;
309
+ } ) . then ( function ( obj ) {
310
+ return new Promise ( function ( resolve , reject ) {
311
+ fs . createReadStream ( installPackage ) . pipe ( unpack ( obj . tmpdir , function ( err ) {
312
+ if ( err ) {
313
+ reject ( err ) ;
314
+ } else {
315
+ var packageName = require ( path . join ( obj . tmpdir , 'package.json' ) ) . name ;
316
+ try {
317
+ obj . callback ( ) ;
318
+ } catch ( ignored ) { }
319
+ resolve ( packageName ) ;
320
+ }
321
+ } ) ) ;
322
+ } ) ;
323
+ } ) . catch ( function ( err ) {
324
+ // The package name could be with or without semver version, e.g. react-scripts-0.2.0-alpha.1.tgz
325
+ // However, this function returns package name only without semver version.
326
+ console . log ( 'Failed to extract package: ' + err . message ) ;
327
+ console . log ( 'Falling back to naive behavior ...' )
328
+ return Promise . resolve ( installPackage . match ( / ^ .+ \/ ( .+ ?) (?: - \d + .+ ) ? \. t g z $ / ) [ 1 ] ) ;
329
+ } ) ;
294
330
} else if ( installPackage . indexOf ( 'git+' ) === 0 ) {
295
331
// Pull package name out of git urls e.g:
296
332
// git+https://github.com/mycompany/react-scripts.git
297
333
// git+ssh://github.com/mycompany/react-scripts.git#v1.2.3
298
- return installPackage . match ( / ( [ ^ \/ ] + ) \. g i t ( # .* ) ? $ / ) [ 1 ] ;
334
+ return Promise . resolve ( installPackage . match ( / ( [ ^ \/ ] + ) \. g i t ( # .* ) ? $ / ) [ 1 ] ) ;
299
335
} else if ( installPackage . indexOf ( '@' ) > 0 ) {
300
336
// Do not match @scope / when stripping off @version or @tag
301
- return installPackage . charAt ( 0 ) + installPackage . substr ( 1 ) . split ( '@' ) [ 0 ] ;
337
+ return Promise . resolve ( installPackage . charAt ( 0 ) + installPackage . substr ( 1 ) . split ( '@' ) [ 0 ] ) ;
302
338
}
303
- return installPackage ;
339
+ return Promise . resolve ( installPackage ) ;
304
340
}
305
341
306
342
function checkNpmVersion ( ) {
@@ -356,7 +392,7 @@ function checkAppName(appName) {
356
392
printValidationResults ( validationResult . warnings ) ;
357
393
process . exit ( 1 ) ;
358
394
}
359
-
395
+
360
396
// TODO: there should be a single place that holds the dependencies
361
397
var dependencies = [ 'react' , 'react-dom' ] ;
362
398
var devDependencies = [ 'react-scripts' ] ;
@@ -449,7 +485,7 @@ function checkIfOnline(useYarn) {
449
485
// We'll just assume the best case.
450
486
return Promise . resolve ( true ) ;
451
487
}
452
-
488
+
453
489
return new Promise ( function ( resolve ) {
454
490
dns . resolve ( 'registry.yarnpkg.com' , function ( err ) {
455
491
resolve ( err === null ) ;
0 commit comments