22
33namespace Laravel \Installer \Console ;
44
5+ use Illuminate \Filesystem \Filesystem ;
6+ use Illuminate \Support \Composer ;
7+ use Illuminate \Support \ProcessUtils ;
58use RuntimeException ;
69use Symfony \Component \Console \Command \Command ;
710use Symfony \Component \Console \Input \InputArgument ;
811use Symfony \Component \Console \Input \InputInterface ;
912use Symfony \Component \Console \Input \InputOption ;
1013use Symfony \Component \Console \Output \OutputInterface ;
14+ use Symfony \Component \Process \PhpExecutableFinder ;
1115use Symfony \Component \Process \Process ;
1216
1317use function Laravel \Prompts \confirm ;
@@ -19,6 +23,13 @@ class NewCommand extends Command
1923{
2024 use Concerns \ConfiguresPrompts;
2125
26+ /**
27+ * The Composer instance.
28+ *
29+ * @var \Illuminate\Support\Composer
30+ */
31+ protected $ composer ;
32+
2233 /**
2334 * Configure the command options.
2435 *
@@ -130,6 +141,8 @@ protected function execute(InputInterface $input, OutputInterface $output)
130141
131142 $ directory = $ name !== '. ' ? getcwd ().'/ ' .$ name : '. ' ;
132143
144+ $ this ->composer = new Composer (new Filesystem (), $ directory );
145+
133146 $ version = $ this ->getVersion ($ input );
134147
135148 if (! $ input ->getOption ('force ' )) {
@@ -295,12 +308,10 @@ protected function configureDefaultDatabaseConnection(string $directory, string
295308 */
296309 protected function installBreeze (string $ directory , InputInterface $ input , OutputInterface $ output )
297310 {
298- chdir ($ directory );
299-
300311 $ commands = array_filter ([
301312 $ this ->findComposer ().' require laravel/breeze ' ,
302313 trim (sprintf (
303- ' " ' . PHP_BINARY . ' " artisan breeze:install %s %s %s %s %s ' ,
314+ $ this -> phpBinary (). ' artisan breeze:install %s %s %s %s %s ' ,
304315 $ input ->getOption ('stack ' ),
305316 $ input ->getOption ('typescript ' ) ? '--typescript ' : '' ,
306317 $ input ->getOption ('pest ' ) ? '--pest ' : '' ,
@@ -309,7 +320,7 @@ protected function installBreeze(string $directory, InputInterface $input, Outpu
309320 )),
310321 ]);
311322
312- $ this ->runCommands ($ commands , $ input , $ output );
323+ $ this ->runCommands ($ commands , $ input , $ output, workingPath: $ directory );
313324
314325 $ this ->commitChanges ('Install Breeze ' , $ directory , $ input , $ output );
315326 }
@@ -324,12 +335,10 @@ protected function installBreeze(string $directory, InputInterface $input, Outpu
324335 */
325336 protected function installJetstream (string $ directory , InputInterface $ input , OutputInterface $ output )
326337 {
327- chdir ($ directory );
328-
329338 $ commands = array_filter ([
330339 $ this ->findComposer ().' require laravel/jetstream ' ,
331340 trim (sprintf (
332- ' " ' . PHP_BINARY . ' " artisan jetstream:install %s %s %s %s %s %s ' ,
341+ $ this -> phpBinary (). ' artisan jetstream:install %s %s %s %s %s %s ' ,
333342 $ input ->getOption ('stack ' ),
334343 $ input ->getOption ('api ' ) ? '--api ' : '' ,
335344 $ input ->getOption ('dark ' ) ? '--dark ' : '' ,
@@ -339,7 +348,7 @@ protected function installJetstream(string $directory, InputInterface $input, Ou
339348 )),
340349 ]);
341350
342- $ this ->runCommands ($ commands , $ input , $ output );
351+ $ this ->runCommands ($ commands , $ input , $ output, workingPath: $ directory );
343352
344353 $ this ->commitChanges ('Install Jetstream ' , $ directory , $ input , $ output );
345354 }
@@ -479,29 +488,28 @@ protected function validateStackOption(InputInterface $input)
479488 */
480489 protected function installPest (string $ directory , InputInterface $ input , OutputInterface $ output )
481490 {
482- chdir ($ directory );
483-
484- $ commands = array_filter ([
485- $ this ->findComposer ().' remove phpunit/phpunit --dev ' ,
486- $ this ->findComposer ().' require pestphp/pest:^2.0 pestphp/pest-plugin-laravel:^2.0 --dev ' ,
487- '" ' .PHP_BINARY .'" ./vendor/bin/pest --init ' ,
488- ]);
489-
490- $ this ->runCommands ($ commands , $ input , $ output , [
491- 'PEST_NO_SUPPORT ' => 'true ' ,
492- ]);
493-
494- $ this ->replaceFile (
495- 'pest/Feature.php ' ,
496- $ directory .'/tests/Feature/ExampleTest.php ' ,
497- );
491+ if ($ this ->removeComposerPackages (['phpunit/phpunit ' ], $ output , true )
492+ && $ this ->requireComposerPackages (['pestphp/pest:^2.0 ' , 'pestphp/pest-plugin-laravel:^2.0 ' ], $ output , true )) {
493+ $ commands = array_filter ([
494+ $ this ->phpBinary ().' ./vendor/bin/pest --init ' ,
495+ ]);
496+
497+ $ this ->runCommands ($ commands , $ input , $ output , workingPath: $ directory , env: [
498+ 'PEST_NO_SUPPORT ' => 'true ' ,
499+ ]);
500+
501+ $ this ->replaceFile (
502+ 'pest/Feature.php ' ,
503+ $ directory .'/tests/Feature/ExampleTest.php ' ,
504+ );
498505
499- $ this ->replaceFile (
500- 'pest/Unit.php ' ,
501- $ directory .'/tests/Unit/ExampleTest.php ' ,
502- );
506+ $ this ->replaceFile (
507+ 'pest/Unit.php ' ,
508+ $ directory .'/tests/Unit/ExampleTest.php ' ,
509+ );
503510
504- $ this ->commitChanges ('Install Pest ' , $ directory , $ input , $ output );
511+ $ this ->commitChanges ('Install Pest ' , $ directory , $ input , $ output );
512+ }
505513 }
506514
507515 /**
@@ -514,8 +522,6 @@ protected function installPest(string $directory, InputInterface $input, OutputI
514522 */
515523 protected function createRepository (string $ directory , InputInterface $ input , OutputInterface $ output )
516524 {
517- chdir ($ directory );
518-
519525 $ branch = $ input ->getOption ('branch ' ) ?: $ this ->defaultBranch ();
520526
521527 $ commands = [
@@ -525,7 +531,7 @@ protected function createRepository(string $directory, InputInterface $input, Ou
525531 "git branch -M {$ branch }" ,
526532 ];
527533
528- $ this ->runCommands ($ commands , $ input , $ output );
534+ $ this ->runCommands ($ commands , $ input , $ output, workingPath: $ directory );
529535 }
530536
531537 /**
@@ -543,14 +549,12 @@ protected function commitChanges(string $message, string $directory, InputInterf
543549 return ;
544550 }
545551
546- chdir ($ directory );
547-
548552 $ commands = [
549553 'git add . ' ,
550554 "git commit -q -m \"$ message \"" ,
551555 ];
552556
553- $ this ->runCommands ($ commands , $ input , $ output );
557+ $ this ->runCommands ($ commands , $ input , $ output, workingPath: $ directory );
554558 }
555559
556560 /**
@@ -573,16 +577,14 @@ protected function pushToGitHub(string $name, string $directory, InputInterface
573577 return ;
574578 }
575579
576- chdir ($ directory );
577-
578580 $ name = $ input ->getOption ('organization ' ) ? $ input ->getOption ('organization ' )."/ $ name " : $ name ;
579581 $ flags = $ input ->getOption ('github ' ) ?: '--private ' ;
580582
581583 $ commands = [
582584 "gh repo create {$ name } --source=. --push {$ flags }" ,
583585 ];
584586
585- $ this ->runCommands ($ commands , $ input , $ output , ['GIT_TERMINAL_PROMPT ' => 0 ]);
587+ $ this ->runCommands ($ commands , $ input , $ output , workingPath: $ directory , env: ['GIT_TERMINAL_PROMPT ' => 0 ]);
586588 }
587589
588590 /**
@@ -644,13 +646,41 @@ protected function getVersion(InputInterface $input)
644646 */
645647 protected function findComposer ()
646648 {
647- $ composerPath = getcwd ().'/composer.phar ' ;
649+ return implode (' ' , $ this ->composer ->findComposer ());
650+ }
648651
649- if (file_exists ($ composerPath )) {
650- return '" ' .PHP_BINARY .'" ' .$ composerPath ;
651- }
652+ /**
653+ * Get the path to the appropriate PHP binary.
654+ *
655+ * @return string
656+ */
657+ protected function phpBinary ()
658+ {
659+ $ phpBinary = (new PhpExecutableFinder )->find (false );
660+
661+ return $ phpBinary !== false
662+ ? ProcessUtils::escapeArgument ($ phpBinary )
663+ : 'php ' ;
664+ }
652665
653- return 'composer ' ;
666+ /**
667+ * Install the given Composer Packages into the application.
668+ *
669+ * @return bool
670+ */
671+ protected function requireComposerPackages (array $ packages , OutputInterface $ output , bool $ asDev = false )
672+ {
673+ return $ this ->composer ->requirePackages ($ packages , $ asDev , $ output );
674+ }
675+
676+ /**
677+ * Remove the given Composer Packages from the application.
678+ *
679+ * @return bool
680+ */
681+ protected function removeComposerPackages (array $ packages , OutputInterface $ output , bool $ asDev = false )
682+ {
683+ return $ this ->composer ->removePackages ($ packages , $ asDev , $ output );
654684 }
655685
656686 /**
@@ -659,10 +689,11 @@ protected function findComposer()
659689 * @param array $commands
660690 * @param \Symfony\Component\Console\Input\InputInterface $input
661691 * @param \Symfony\Component\Console\Output\OutputInterface $output
692+ * @param string|null $workingPath
662693 * @param array $env
663694 * @return \Symfony\Component\Process\Process
664695 */
665- protected function runCommands ($ commands , InputInterface $ input , OutputInterface $ output , array $ env = [])
696+ protected function runCommands ($ commands , InputInterface $ input , OutputInterface $ output , string $ workingPath = null , array $ env = [])
666697 {
667698 if (! $ output ->isDecorated ()) {
668699 $ commands = array_map (function ($ value ) {
@@ -692,7 +723,7 @@ protected function runCommands($commands, InputInterface $input, OutputInterface
692723 }, $ commands );
693724 }
694725
695- $ process = Process::fromShellCommandline (implode (' && ' , $ commands ), null , $ env , null , null );
726+ $ process = Process::fromShellCommandline (implode (' && ' , $ commands ), $ workingPath , $ env , null , null );
696727
697728 if ('\\' !== DIRECTORY_SEPARATOR && file_exists ('/dev/tty ' ) && is_readable ('/dev/tty ' )) {
698729 try {
0 commit comments