11/**
22 * Copyright (c) 2015-present, Facebook, Inc.
3- * All rights reserved.
43 *
5- * This source code is licensed under the BSD-style license found in the
6- * LICENSE file in the root directory of this source tree. An additional grant
7- * of patent rights can be found in the PATENTS file in the same directory.
4+ * This source code is licensed under the MIT license found in the
5+ * LICENSE file in the root directory of this source tree.
86 */
97
108// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -75,14 +73,10 @@ const program = new commander.Command(packageJson.name)
7573 ) ;
7674 console . log ( ` - a specific npm version: ${ chalk . green ( '0.8.2' ) } ` ) ;
7775 console . log (
78- ` - a custom fork published on npm: ${ chalk . green (
79- 'my-react-scripts'
80- ) } `
76+ ` - a custom fork published on npm: ${ chalk . green ( 'my-react-scripts' ) } `
8177 ) ;
8278 console . log (
83- ` - a .tgz archive: ${ chalk . green (
84- 'https://mysite.com/my-react-scripts-0.8.2.tgz'
85- ) } `
79+ ` - a .tgz archive: ${ chalk . green ( 'https://mysite.com/my-react-scripts-0.8.2.tgz' ) } `
8680 ) ;
8781 console . log (
8882 ` It is not needed unless you specifically want to use a fork.`
@@ -92,9 +86,7 @@ const program = new commander.Command(packageJson.name)
9286 ` If you have any problems, do not hesitate to file an issue:`
9387 ) ;
9488 console . log (
95- ` ${ chalk . cyan (
96- 'https://github.com/facebookincubator/create-react-app/issues/new'
97- ) } `
89+ ` ${ chalk . cyan ( 'https://github.com/facebookincubator/create-react-app/issues/new' ) } `
9890 ) ;
9991 console . log ( ) ;
10092 } )
@@ -160,8 +152,13 @@ function createApp(name, verbose, version, template) {
160152 path . join ( root , 'package.json' ) ,
161153 JSON . stringify ( packageJson , null , 2 )
162154 ) ;
155+
156+ const useYarn = shouldUseYarn ( ) ;
163157 const originalDirectory = process . cwd ( ) ;
164158 process . chdir ( root ) ;
159+ if ( ! useYarn && ! checkThatNpmCanReadCwd ( ) ) {
160+ process . exit ( 1 ) ;
161+ }
165162
166163 if ( ! semver . satisfies ( process . version , '>=6.0.0' ) ) {
167164 console . log (
@@ -174,7 +171,6 @@ function createApp(name, verbose, version, template) {
174171 version = 'react-scripts@0.9.x' ;
175172 }
176173
177- const useYarn = shouldUseYarn ( ) ;
178174 if ( ! useYarn ) {
179175 const npmInfo = checkNpmVersion ( ) ;
180176 if ( ! npmInfo . hasMinNpm ) {
@@ -202,7 +198,7 @@ function shouldUseYarn() {
202198 }
203199}
204200
205- function install ( useYarn , dependencies , verbose , isOnline ) {
201+ function install ( root , useYarn , dependencies , verbose , isOnline ) {
206202 return new Promise ( ( resolve , reject ) => {
207203 let command ;
208204 let args ;
@@ -214,6 +210,14 @@ function install(useYarn, dependencies, verbose, isOnline) {
214210 }
215211 [ ] . push . apply ( args , dependencies ) ;
216212
213+ // Explicitly set cwd() to work around issues like
214+ // https://github.com/facebookincubator/create-react-app/issues/3326.
215+ // Unfortunately we can only do this for Yarn because npm support for
216+ // equivalent --prefix flag doesn't help with this issue.
217+ // This is why for npm, we run checkThatNpmCanReadCwd() early instead.
218+ args . push ( '--cwd' ) ;
219+ args . push ( root ) ;
220+
217221 if ( ! isOnline ) {
218222 console . log ( chalk . yellow ( 'You appear to be offline.' ) ) ;
219223 console . log ( chalk . yellow ( 'Falling back to the local Yarn cache.' ) ) ;
@@ -261,23 +265,19 @@ function run(
261265
262266 console . log ( 'Installing packages. This might take a couple of minutes.' ) ;
263267 getPackageName ( packageToInstall )
264- . then ( packageName =>
265- checkIfOnline ( useYarn ) . then ( isOnline => ( {
266- isOnline : isOnline ,
267- packageName : packageName ,
268- } ) )
269- )
268+ . then ( packageName => checkIfOnline ( useYarn ) . then ( isOnline => ( {
269+ isOnline : isOnline ,
270+ packageName : packageName ,
271+ } ) ) )
270272 . then ( info => {
271273 const isOnline = info . isOnline ;
272274 const packageName = info . packageName ;
273275 console . log (
274- `Installing ${ chalk . cyan ( 'react' ) } , ${ chalk . cyan (
275- 'react-dom'
276- ) } , and ${ chalk . cyan ( packageName ) } ...`
276+ `Installing ${ chalk . cyan ( 'react' ) } , ${ chalk . cyan ( 'react-dom' ) } , and ${ chalk . cyan ( packageName ) } ...`
277277 ) ;
278278 console . log ( ) ;
279279
280- return install ( useYarn , allDependencies , verbose , isOnline ) . then (
280+ return install ( root , useYarn , allDependencies , verbose , isOnline ) . then (
281281 ( ) => packageName
282282 ) ;
283283 } )
@@ -341,9 +341,7 @@ function run(
341341 if ( ! remainingFiles . length ) {
342342 // Delete target folder if empty
343343 console . log (
344- `Deleting ${ chalk . cyan ( `${ appName } /` ) } from ${ chalk . cyan (
345- path . resolve ( root , '..' )
346- ) } `
344+ `Deleting ${ chalk . cyan ( `${ appName } /` ) } from ${ chalk . cyan ( path . resolve ( root , '..' ) ) } `
347345 ) ;
348346 process . chdir ( path . resolve ( root , '..' ) ) ;
349347 fs . removeSync ( path . join ( root ) ) ;
@@ -431,9 +429,7 @@ function getPackageName(installPackage) {
431429 / ^ .+ \/ ( .+ ?) (?: - \d + .+ ) ? \. t g z $ /
432430 ) [ 1 ] ;
433431 console . log (
434- `Based on the filename, assuming it is "${ chalk . cyan (
435- assumedProjectName
436- ) } "`
432+ `Based on the filename, assuming it is "${ chalk . cyan ( assumedProjectName ) } "`
437433 ) ;
438434 return Promise . resolve ( assumedProjectName ) ;
439435 } ) ;
@@ -496,9 +492,7 @@ function checkAppName(appName) {
496492 const validationResult = validateProjectName ( appName ) ;
497493 if ( ! validationResult . validForNewPackages ) {
498494 console . error (
499- `Could not create a project called ${ chalk . red (
500- `"${ appName } "`
501- ) } because of npm naming restrictions:`
495+ `Could not create a project called ${ chalk . red ( `"${ appName } "` ) } because of npm naming restrictions:`
502496 ) ;
503497 printValidationResults ( validationResult . errors ) ;
504498 printValidationResults ( validationResult . warnings ) ;
@@ -510,9 +504,7 @@ function checkAppName(appName) {
510504 if ( dependencies . indexOf ( appName ) >= 0 ) {
511505 console . error (
512506 chalk . red (
513- `We cannot create a project called ${ chalk . green (
514- appName
515- ) } because a dependency with the same name exists.\n` +
507+ `We cannot create a project called ${ chalk . green ( appName ) } because a dependency with the same name exists.\n` +
516508 `Due to the way npm works, the following names are not allowed:\n\n`
517509 ) +
518510 chalk . cyan ( dependencies . map ( depName => ` ${ depName } ` ) . join ( '\n' ) ) +
@@ -534,9 +526,7 @@ function makeCaretRange(dependencies, name) {
534526
535527 if ( ! semver . validRange ( patchedVersion ) ) {
536528 console . error (
537- `Unable to patch ${ name } dependency version because version ${ chalk . red (
538- version
539- ) } will become invalid ${ chalk . red ( patchedVersion ) } `
529+ `Unable to patch ${ name } dependency version because version ${ chalk . red ( version ) } will become invalid ${ chalk . red ( patchedVersion ) } `
540530 ) ;
541531 patchedVersion = version ;
542532 }
@@ -606,6 +596,61 @@ function isSafeToCreateProjectIn(root, name) {
606596 return false ;
607597}
608598
599+ function checkThatNpmCanReadCwd ( ) {
600+ const cwd = process . cwd ( ) ;
601+ let childOutput = null ;
602+ try {
603+ // Note: intentionally using spawn over exec since
604+ // the problem doesn't reproduce otherwise.
605+ // `npm config list` is the only reliable way I could find
606+ // to reproduce the wrong path. Just printing process.cwd()
607+ // in a Node process was not enough.
608+ childOutput = spawn . sync ( 'npm' , [ 'config' , 'list' ] ) . output . join ( '' ) ;
609+ } catch ( err ) {
610+ // Something went wrong spawning node.
611+ // Not great, but it means we can't do this check.
612+ // We might fail later on, but let's continue.
613+ return true ;
614+ }
615+ if ( typeof childOutput !== 'string' ) {
616+ return true ;
617+ }
618+ const lines = childOutput . split ( '\n' ) ;
619+ // `npm config list` output includes the following line:
620+ // "; cwd = C:\path\to\current\dir" (unquoted)
621+ // I couldn't find an easier way to get it.
622+ const prefix = '; cwd = ' ;
623+ const line = lines . find ( line => line . indexOf ( prefix ) === 0 ) ;
624+ if ( typeof line !== 'string' ) {
625+ // Fail gracefully. They could remove it.
626+ return true ;
627+ }
628+ const npmCWD = line . substring ( prefix . length ) ;
629+ if ( npmCWD === cwd ) {
630+ return true ;
631+ }
632+ console . error (
633+ chalk . red (
634+ `Could not start an npm process in the right directory.\n\n` +
635+ `The current directory is: ${ chalk . bold ( cwd ) } \n` +
636+ `However, a newly started npm process runs in: ${ chalk . bold ( npmCWD ) } \n\n` +
637+ `This is probably caused by a misconfigured system terminal shell.`
638+ )
639+ ) ;
640+ if ( process . platform === 'win32' ) {
641+ console . error (
642+ chalk . red ( `On Windows, this can usually be fixed by running:\n\n` ) +
643+ ` ${ chalk . cyan ( 'reg' ) } delete "HKCU\\Software\\Microsoft\\Command Processor" /v AutoRun /f\n` +
644+ ` ${ chalk . cyan ( 'reg' ) } delete "HKLM\\Software\\Microsoft\\Command Processor" /v AutoRun /f\n\n` +
645+ chalk . red ( `Try to run the above two lines in the terminal.\n` ) +
646+ chalk . red (
647+ `To learn more about this problem, read: https://blogs.msdn.microsoft.com/oldnewthing/20071121-00/?p=24433/`
648+ )
649+ ) ;
650+ }
651+ return false ;
652+ }
653+
609654function checkIfOnline ( useYarn ) {
610655 if ( ! useYarn ) {
611656 // Don't ping the Yarn registry.
0 commit comments