diff --git a/README.md b/README.md index e2345db..2387920 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,10 @@ cpx gives you multiple ways to run PHP code quickly, perfect for running scratch - `cpx exec -r ` will execute the given PHP code. - `cpx tinker` will open an interactive REPL in the terminal for your project. +### cpx new + +`cpx new / ` or `cpx new /: ` will create a new project from the specified package. This is useful for quickly creating a new project without needing to install the package globally. + When using these commands, you get the following benefits: - **Automatic Autoloaders** - When running a PHP file, it will automatically detect and use Composer's autoloader if it exists in the current or a parent directory diff --git a/cpx b/cpx index 3a767d2..a25fcb8 100755 --- a/cpx +++ b/cpx @@ -15,6 +15,7 @@ use Cpx\Commands\FormatCommand; use Cpx\Commands\TinkerCommand; use Cpx\Commands\UpdateCommand; use Cpx\Commands\AliasesCommand; +use Cpx\Commands\NewCommand; use Cpx\Commands\UpgradeCommand; use Cpx\Commands\VersionCommand; @@ -55,6 +56,7 @@ $command = match (true) { $console->command === 'test' => TestCommand::class, $console->command === 'tinker' => TinkerCommand::class, $console->command === 'version' => VersionCommand::class, + $console->command === 'new' => NewCommand::class, file_exists(realpath($console->command)) && !is_dir(realpath($console->command)) => (new ExecCommand(Console::parse("exec {$console->command} {$console->getCommandInput()}")))(), array_key_exists($console->command, PackageAliases::$packages) => Package::parse(PackageAliases::$packages[$console->command]['package'])->runCommand($console), str_contains($console->command, '/') => Package::parse($console->command)->runCommand($console), diff --git a/src/Commands/HelpCommand.php b/src/Commands/HelpCommand.php index 09b2bd3..b949281 100644 --- a/src/Commands/HelpCommand.php +++ b/src/Commands/HelpCommand.php @@ -12,19 +12,20 @@ public function __invoke(bool $unknownCommand = false) $this->success('cpx - A Composer package runner with on-demand execution and package management.'); $this->line('Usage:'); - $this->line(' ' . Command::COLOR_GREEN . 'cpx [args] ' . Command::COLOR_RESET . 'Run a Composer package\'s bin command'); - $this->line(' ' . Command::COLOR_GREEN . 'cpx check ' . Command::COLOR_RESET . 'Run a static analysis tool over a project'); - $this->line(' ' . Command::COLOR_GREEN . 'cpx test ' . Command::COLOR_RESET . 'Run a testing framework over a project'); - $this->line(' ' . Command::COLOR_GREEN . 'cpx format ' . Command::COLOR_RESET . 'Run a code formatter over a project'); - $this->line(' ' . Command::COLOR_GREEN . 'cpx update ' . Command::COLOR_RESET . 'Update all packages'); - $this->line(' ' . Command::COLOR_GREEN . 'cpx update ' . Command::COLOR_RESET . 'Update all versions of a package'); - $this->line(' ' . Command::COLOR_GREEN . 'cpx clean ' . Command::COLOR_RESET . 'Clean unused packages (older than 30 days)'); - $this->line(' ' . Command::COLOR_GREEN . 'cpx clean --all ' . Command::COLOR_RESET . 'Clean all packages'); - $this->line(' ' . Command::COLOR_GREEN . 'cpx exec ' . Command::COLOR_RESET . 'Invoke a PHP file'); - $this->line(' ' . Command::COLOR_GREEN . 'cpx exec -r ' . Command::COLOR_RESET . 'Run PHP code without tags'); - $this->line(' ' . Command::COLOR_GREEN . 'cpx tinker ' . Command::COLOR_RESET . 'Open an interactive REPL'); - $this->line(' ' . Command::COLOR_GREEN . 'cpx list ' . Command::COLOR_RESET . 'List all installed packages'); - $this->line(' ' . Command::COLOR_GREEN . 'cpx aliases ' . Command::COLOR_RESET . 'Show aliased package names to run via `cpx `'); - $this->line(' ' . Command::COLOR_GREEN . 'cpx help ' . Command::COLOR_RESET . 'Show this help message'); + $this->line(' ' . Command::COLOR_GREEN . 'cpx [args] ' . Command::COLOR_RESET . 'Run a Composer package\'s bin command'); + $this->line(' ' . Command::COLOR_GREEN . 'cpx new [args] ' . Command::COLOR_RESET . 'Create a new project from a Composer package'); + $this->line(' ' . Command::COLOR_GREEN . 'cpx check ' . Command::COLOR_RESET . 'Run a static analysis tool over a project'); + $this->line(' ' . Command::COLOR_GREEN . 'cpx test ' . Command::COLOR_RESET . 'Run a testing framework over a project'); + $this->line(' ' . Command::COLOR_GREEN . 'cpx format ' . Command::COLOR_RESET . 'Run a code formatter over a project'); + $this->line(' ' . Command::COLOR_GREEN . 'cpx update ' . Command::COLOR_RESET . 'Update all packages'); + $this->line(' ' . Command::COLOR_GREEN . 'cpx update ' . Command::COLOR_RESET . 'Update all versions of a package'); + $this->line(' ' . Command::COLOR_GREEN . 'cpx clean ' . Command::COLOR_RESET . 'Clean unused packages (older than 30 days)'); + $this->line(' ' . Command::COLOR_GREEN . 'cpx clean --all ' . Command::COLOR_RESET . 'Clean all packages'); + $this->line(' ' . Command::COLOR_GREEN . 'cpx exec ' . Command::COLOR_RESET . 'Invoke a PHP file'); + $this->line(' ' . Command::COLOR_GREEN . 'cpx exec -r ' . Command::COLOR_RESET . 'Run PHP code without tags'); + $this->line(' ' . Command::COLOR_GREEN . 'cpx tinker ' . Command::COLOR_RESET . 'Open an interactive REPL'); + $this->line(' ' . Command::COLOR_GREEN . 'cpx list ' . Command::COLOR_RESET . 'List all installed packages'); + $this->line(' ' . Command::COLOR_GREEN . 'cpx aliases ' . Command::COLOR_RESET . 'Show aliased package names to run via `cpx `'); + $this->line(' ' . Command::COLOR_GREEN . 'cpx help ' . Command::COLOR_RESET . 'Show this help message'); } } diff --git a/src/Commands/NewCommand.php b/src/Commands/NewCommand.php new file mode 100644 index 0000000..a9bfa51 --- /dev/null +++ b/src/Commands/NewCommand.php @@ -0,0 +1,53 @@ +console; + + if (count($console->arguments) < 1) { + throw new \Exception("No package name provided."); + } + if (count($console->arguments) < 2) { + throw new \Exception("No directory provided."); + } + + $str = $console->arguments[0]; + if (!str_contains($str, '/')) { + throw new \Exception("Invalid package name: {$str}"); + } + + $package = Package::parse($str); + + $installDir = $package->installOrUpdatePackage(); + + $config = [ + "type" => "path", + "url" => "{$installDir}/vendor/{$package->vendor}/{$package->name}", + "options" => [ + "symlink" => false + ] + ]; + + $projectDir = getcwd() . '/' . $console->arguments[1]; + + $command = "composer create-project $package->vendor/$package->name --stability=dev --repository='" . json_encode($config) . "' $projectDir"; + foreach ($console->options as $key => $value) { + if ($key === 'repo') { + continue; + } + $command .= " --$key=$value"; + } + + $descriptorspec = [STDIN, STDOUT, STDOUT]; + $proc = proc_open($command, $descriptorspec, $pipes); + proc_close($proc); + } +}