args[0])) {
$project = $this->args[0];
} else {
$appContents = array_diff(scandir(APP), ['.', '..']);
if (empty($appContents)) {
$suggestedPath = rtrim(APP, DS);
} else {
$suggestedPath = APP . 'MyApp';
}
}
while (!$project) {
$prompt = 'What is the path to the project you want to bake?';
$project = $this->in($prompt, null, $suggestedPath);
}
$namespace = basename($project);
if (!preg_match('/^\w[\w\d_]+$/', $namespace)) {
$this->err('Project Name/Namespace needs to start with a letter and can only contain letters, digits and underscore');
$this->args = [];
return $this->main();
}
if ($project && !Folder::isAbsolute($project) && isset($_SERVER['PWD'])) {
$project = $_SERVER['PWD'] . DS . $project;
}
$response = false;
while (!$response && is_dir($project) === true && file_exists($project . 'Config' . 'boostrap.php')) {
$prompt = sprintf('A project already exists in this location: %s Overwrite?', $project);
$response = $this->in($prompt, ['y', 'n'], 'n');
if (strtolower($response) === 'n') {
$response = $project = false;
}
}
if ($project === false) {
$this->out('Aborting project creation.');
return;
}
if ($this->bake($project)) {
$this->out('Project baked successfully!');
return $project;
}
}
/**
* Uses either the CLI option or looks in $PATH and cwd for composer.
*
* @return string|false Either the path to composer or false if it cannot be found.
*/
public function findComposer() {
if (!empty($this->params['composer'])) {
$path = $this->params['composer'];
if (file_exists($path)) {
return $path;
}
}
$composer = false;
$path = env('PATH');
if (!empty($path)) {
$paths = explode(PATH_SEPARATOR, $path);
$composer = $this->_searchPath($paths);
}
return $composer;
}
/**
* Search the $PATH for composer.
*
* @param array $path The paths to search.
* @return string|bool
*/
protected function _searchPath($path) {
$composer = ['composer.phar', 'composer'];
foreach ($path as $dir) {
foreach ($composer as $cmd) {
if (is_file($dir . DS . $cmd)) {
$this->_io->verbose('Found composer executable in ' . $dir);
return $dir . DS . $cmd;
}
}
}
return false;
}
/**
* Uses composer to generate a new package using the cakephp/app project.
*
* @param string $path Project path
* @return mixed
*/
public function bake($path) {
$composer = $this->findComposer();
if (!$composer) {
$this->error('Cannot bake project. Could not find composer. Add composer to your PATH, or use the -composer option.');
return false;
}
$this->out('Downloading a new cakephp app from packagist.org');
$command = 'php ' . escapeshellarg($composer) . ' create-project -s dev cakephp/app ' . escapeshellarg($path);
try {
$this->callProcess($command);
} catch (\RuntimeException $e) {
$error = $e->getMessage();
$this->error('Installation from packagist.org failed with: %s', $error);
return false;
}
return true;
}
/**
* get the option parser.
*
* @return \Cake\Console\ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
'Generate a new CakePHP project skeleton.'
)->addArgument('name', [
'help' => 'Application directory to make, if it starts with "/" the path is absolute.'
])->addOption('empty', [
'boolean' => true,
'help' => 'Create empty files in each of the directories. Good if you are using git'
])->addOption('theme', [
'short' => 't',
'help' => 'Theme to use when baking code.'
])->addOption('composer', [
'default' => ROOT . '/composer.phar',
'help' => 'The path to the composer executable.'
])->removeOption('plugin');
}
}