aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/command/create_project_command.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-07 07:26:48 +0900
committernsfisis <nsfisis@gmail.com>2026-08-07 07:26:48 +0900
commitf749a47804cd296a3059cd3f8079c62dbaa5fdc0 (patch)
treea84d5d40f6f9eea2a83355a273d0fb57214a864a /crates/shirabe/src/command/create_project_command.rs
parente7f83b74e8f8c12b4a1b0f9f613387b03858dbdd (diff)
downloadphp-shirabe-f749a47804cd296a3059cd3f8079c62dbaa5fdc0.tar.gz
php-shirabe-f749a47804cd296a3059cd3f8079c62dbaa5fdc0.tar.zst
php-shirabe-f749a47804cd296a3059cd3f8079c62dbaa5fdc0.zip
refactor: merge split inherent impl blocks into one per type
Enable clippy::multiple_inherent_impl and fix the 21 sites it reports. Types whose inherent methods were spread across two or three impl blocks now keep them in a single block; only the impl headers move, no method bodies change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/command/create_project_command.rs')
-rw-r--r--crates/shirabe/src/command/create_project_command.rs410
1 files changed, 204 insertions, 206 deletions
diff --git a/crates/shirabe/src/command/create_project_command.rs b/crates/shirabe/src/command/create_project_command.rs
index 260685c7..dcf0e0f8 100644
--- a/crates/shirabe/src/command/create_project_command.rs
+++ b/crates/shirabe/src/command/create_project_command.rs
@@ -81,213 +81,7 @@ impl CreateProjectCommand {
.expect("CreateProjectCommand::configure uses static, valid metadata");
command
}
-}
-
-impl Command for CreateProjectCommand {
- fn configure(&self) -> anyhow::Result<()> {
- self.set_name("create-project")?;
- self.set_description("Creates new project from a package into given directory");
- self.set_definition(&[
- InputArgument::new5("package", Some(InputArgument::OPTIONAL), "Package name to be installed", None, self.suggest_available_package(99)).unwrap().into(),
- InputArgument::new("directory", Some(InputArgument::OPTIONAL), "Directory where the files should be created", None).unwrap().into(),
- InputArgument::new("version", Some(InputArgument::OPTIONAL), "Version, will default to latest", None).unwrap().into(),
- InputOption::new("stability", Some(PhpMixed::String("s".to_string())), Some(InputOption::VALUE_REQUIRED), "Minimum-stability allowed (unless a version is specified).", None).unwrap().into(),
- InputOption::new("prefer-source", None, Some(InputOption::VALUE_NONE), "Forces installation from package sources when possible, including VCS information.", None).unwrap().into(),
- InputOption::new("prefer-dist", None, Some(InputOption::VALUE_NONE), "Forces installation from package dist (default behavior).", None).unwrap().into(),
- InputOption::new6("prefer-install", None, Some(InputOption::VALUE_REQUIRED), "Forces installation from package dist|source|auto (auto chooses source for dev versions, dist for the rest).", None, self.suggest_prefer_install()).unwrap().into(),
- InputOption::new("repository", None, Some(InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY), "Add custom repositories to look the package up, either by URL or using JSON arrays", None).unwrap().into(),
- InputOption::new("repository-url", None, Some(InputOption::VALUE_REQUIRED), "DEPRECATED: Use --repository instead.", None).unwrap().into(),
- InputOption::new("add-repository", None, Some(InputOption::VALUE_NONE), "Add the custom repository in the composer.json. If a lock file is present it will be deleted and an update will be run instead of install.", None).unwrap().into(),
- InputOption::new("dev", None, Some(InputOption::VALUE_NONE), "Enables installation of require-dev packages (enabled by default, only present for BC).", None).unwrap().into(),
- InputOption::new("no-dev", None, Some(InputOption::VALUE_NONE), "Disables installation of require-dev packages.", None).unwrap().into(),
- InputOption::new("no-custom-installers", None, Some(InputOption::VALUE_NONE), "DEPRECATED: Use no-plugins instead.", None).unwrap().into(),
- InputOption::new("no-scripts", None, Some(InputOption::VALUE_NONE), "Whether to prevent execution of all defined scripts in the root package.", None).unwrap().into(),
- InputOption::new("no-progress", None, Some(InputOption::VALUE_NONE), "Do not output download progress.", None).unwrap().into(),
- InputOption::new("no-secure-http", None, Some(InputOption::VALUE_NONE), "Disable the secure-http config option temporarily while installing the root package. Use at your own risk. Using this flag is a bad idea.", None).unwrap().into(),
- InputOption::new("keep-vcs", None, Some(InputOption::VALUE_NONE), "Whether to prevent deleting the vcs folder.", None).unwrap().into(),
- InputOption::new("remove-vcs", None, Some(InputOption::VALUE_NONE), "Whether to force deletion of the vcs folder without prompting.", None).unwrap().into(),
- InputOption::new("no-install", None, Some(InputOption::VALUE_NONE), "Whether to skip installation of the package dependencies.", None).unwrap().into(),
- InputOption::new("no-audit", None, Some(InputOption::VALUE_NONE), "Whether to skip auditing of the installed package dependencies (can also be set via the COMPOSER_NO_AUDIT=1 env var).", None).unwrap().into(),
- InputOption::new6("audit-format", None, Some(InputOption::VALUE_REQUIRED), "Audit output format. Must be \"table\", \"plain\", \"json\" or \"summary\".", Some(PhpMixed::String(Auditor::FORMAT_SUMMARY.to_string())), SuggestedValues::List(Auditor::FORMATS.iter().map(|s| s.to_string()).collect())).unwrap().into(),
- InputOption::new("no-security-blocking", None, Some(InputOption::VALUE_NONE), "Allows installing packages with security advisories or that are abandoned (can also be set via the COMPOSER_NO_SECURITY_BLOCKING=1 env var).", None).unwrap().into(),
- InputOption::new("ignore-platform-req", None, Some(InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY), "Ignore a specific platform requirement (php & ext- packages).", None).unwrap().into(),
- InputOption::new("ignore-platform-reqs", None, Some(InputOption::VALUE_NONE), "Ignore all platform requirements (php & ext- packages).", None).unwrap().into(),
- InputOption::new("ask", None, Some(InputOption::VALUE_NONE), "Whether to ask for project directory.", None).unwrap().into(),
- ]);
- self.set_help(
- "The <info>create-project</info> command creates a new project from a given\n\
- package into a new directory. If executed without params and in a directory\n\
- with a composer.json file it installs the packages for the current project.\n\n\
- You can use this command to bootstrap new projects or setup a clean\n\
- version-controlled installation for developers of your project.\n\n\
- <info>shirabe create-project vendor/project target-directory [version]</info>\n\n\
- You can also specify the version with the package name using = or : as separator.\n\n\
- <info>shirabe create-project vendor/project:version target-directory</info>\n\n\
- To install unstable packages, either specify the version you want, or use the\n\
- --stability=dev (where dev can be one of RC, beta, alpha or dev).\n\n\
- To setup a developer workable version you should create the project using the source\n\
- controlled code by appending the <info>'--prefer-source'</info> flag.\n\n\
- To install a package from another repository than the default one you\n\
- can pass the <info>'--repository=https://myrepository.org'</info> flag.\n\n\
- Read more at https://getcomposer.org/doc/03-cli.md#create-project"
- );
- Ok(())
- }
-
- fn execute(
- &self,
- input: std::rc::Rc<std::cell::RefCell<dyn InputInterface>>,
- _output: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>,
- ) -> anyhow::Result<i64> {
- let config = std::rc::Rc::new(std::cell::RefCell::new(Factory::create_config(None, None)?));
- let io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>> = self.get_io();
-
- let (prefer_source, prefer_dist) =
- self.get_preferred_install_options(&config.borrow(), input.clone(), true)?;
-
- if input.borrow().get_option("dev")?.as_bool().unwrap_or(false) {
- io.write_error("<warning>You are using the deprecated option \"dev\". Dev packages are installed by default now.</warning>");
- }
- if input
- .borrow()
- .get_option("no-custom-installers")?
- .as_bool()
- .unwrap_or(false)
- {
- io.write_error("<warning>You are using the deprecated option \"no-custom-installers\". Use \"no-plugins\" instead.</warning>");
- input
- .borrow_mut()
- .set_option("no-plugins", PhpMixed::Bool(true));
- }
-
- if input.borrow().is_interactive()
- && input.borrow().get_option("ask")?.as_bool().unwrap_or(false)
- {
- let package = input.borrow().get_argument("package")?;
- if package.is_null() {
- return Err(RuntimeException {
- message: "Not enough arguments (missing: \"package\").".to_string(),
- code: 0,
- }
- .into());
- }
- let mut parts =
- explode_with_limit("/", &strtolower(package.as_string().unwrap_or("")), 2);
- let prompt = format!(
- "New project directory [<comment>{}</comment>]: ",
- array_pop(&mut parts).unwrap_or_default()
- );
- input
- .borrow_mut()
- .set_argument("directory", io.ask(prompt, PhpMixed::Null)?);
- }
-
- let repository_opt = input.borrow().get_option("repository")?;
- let repository_url_opt = input.borrow().get_option("repository-url")?;
- let repositories = if repository_opt
- .as_list()
- .map(|l| !l.is_empty())
- .unwrap_or(false)
- {
- Some(repository_opt)
- } else {
- Some(repository_url_opt)
- };
-
- self.install_project(
- io,
- config,
- input.clone(),
- input
- .borrow()
- .get_argument("package")?
- .as_string()
- .map(|s| s.to_string()),
- input
- .borrow()
- .get_argument("directory")?
- .as_string()
- .map(|s| s.to_string()),
- input
- .borrow()
- .get_argument("version")?
- .as_string()
- .map(|s| s.to_string()),
- input
- .borrow()
- .get_option("stability")?
- .as_string()
- .map(|s| s.to_string()),
- prefer_source,
- prefer_dist,
- !input
- .borrow()
- .get_option("no-dev")?
- .as_bool()
- .unwrap_or(false),
- repositories,
- input
- .borrow()
- .get_option("no-plugins")?
- .as_bool()
- .unwrap_or(false),
- input
- .borrow()
- .get_option("no-scripts")?
- .as_bool()
- .unwrap_or(false),
- input
- .borrow()
- .get_option("no-progress")?
- .as_bool()
- .unwrap_or(false),
- input
- .borrow()
- .get_option("no-install")?
- .as_bool()
- .unwrap_or(false),
- Some(self.get_platform_requirement_filter(input.clone())?),
- !input
- .borrow()
- .get_option("no-secure-http")?
- .as_bool()
- .unwrap_or(false),
- input
- .borrow()
- .get_option("add-repository")?
- .as_bool()
- .unwrap_or(false),
- )
- }
-
- fn initialize(
- &self,
- input: std::rc::Rc<std::cell::RefCell<dyn InputInterface>>,
- output: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>,
- ) -> anyhow::Result<()> {
- base_command_initialize(self, input, output)
- }
-
- fn complete(
- &self,
- input: &shirabe_external_packages::symfony::console::completion::completion_input::CompletionInput,
- suggestions: &mut shirabe_external_packages::symfony::console::completion::completion_suggestions::CompletionSuggestions,
- ) -> anyhow::Result<()> {
- crate::command::base_command::base_command_complete(self, input, suggestions)
- }
-
- shirabe_external_packages::delegate_command_trait_impls_to_inner!(base_command_data);
-}
-
-impl BaseCommand for CreateProjectCommand {
- fn base_command_data(&self) -> &crate::command::BaseCommandData {
- &self.base_command_data
- }
-
- crate::delegate_base_command_trait_impls_to_inner!(base_command_data);
-}
-impl CreateProjectCommand {
/// @throws \Exception
#[allow(clippy::too_many_arguments)]
pub fn install_project(
@@ -1057,3 +851,207 @@ impl CreateProjectCommand {
Ok(installed_from_vcs)
}
}
+
+impl Command for CreateProjectCommand {
+ fn configure(&self) -> anyhow::Result<()> {
+ self.set_name("create-project")?;
+ self.set_description("Creates new project from a package into given directory");
+ self.set_definition(&[
+ InputArgument::new5("package", Some(InputArgument::OPTIONAL), "Package name to be installed", None, self.suggest_available_package(99)).unwrap().into(),
+ InputArgument::new("directory", Some(InputArgument::OPTIONAL), "Directory where the files should be created", None).unwrap().into(),
+ InputArgument::new("version", Some(InputArgument::OPTIONAL), "Version, will default to latest", None).unwrap().into(),
+ InputOption::new("stability", Some(PhpMixed::String("s".to_string())), Some(InputOption::VALUE_REQUIRED), "Minimum-stability allowed (unless a version is specified).", None).unwrap().into(),
+ InputOption::new("prefer-source", None, Some(InputOption::VALUE_NONE), "Forces installation from package sources when possible, including VCS information.", None).unwrap().into(),
+ InputOption::new("prefer-dist", None, Some(InputOption::VALUE_NONE), "Forces installation from package dist (default behavior).", None).unwrap().into(),
+ InputOption::new6("prefer-install", None, Some(InputOption::VALUE_REQUIRED), "Forces installation from package dist|source|auto (auto chooses source for dev versions, dist for the rest).", None, self.suggest_prefer_install()).unwrap().into(),
+ InputOption::new("repository", None, Some(InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY), "Add custom repositories to look the package up, either by URL or using JSON arrays", None).unwrap().into(),
+ InputOption::new("repository-url", None, Some(InputOption::VALUE_REQUIRED), "DEPRECATED: Use --repository instead.", None).unwrap().into(),
+ InputOption::new("add-repository", None, Some(InputOption::VALUE_NONE), "Add the custom repository in the composer.json. If a lock file is present it will be deleted and an update will be run instead of install.", None).unwrap().into(),
+ InputOption::new("dev", None, Some(InputOption::VALUE_NONE), "Enables installation of require-dev packages (enabled by default, only present for BC).", None).unwrap().into(),
+ InputOption::new("no-dev", None, Some(InputOption::VALUE_NONE), "Disables installation of require-dev packages.", None).unwrap().into(),
+ InputOption::new("no-custom-installers", None, Some(InputOption::VALUE_NONE), "DEPRECATED: Use no-plugins instead.", None).unwrap().into(),
+ InputOption::new("no-scripts", None, Some(InputOption::VALUE_NONE), "Whether to prevent execution of all defined scripts in the root package.", None).unwrap().into(),
+ InputOption::new("no-progress", None, Some(InputOption::VALUE_NONE), "Do not output download progress.", None).unwrap().into(),
+ InputOption::new("no-secure-http", None, Some(InputOption::VALUE_NONE), "Disable the secure-http config option temporarily while installing the root package. Use at your own risk. Using this flag is a bad idea.", None).unwrap().into(),
+ InputOption::new("keep-vcs", None, Some(InputOption::VALUE_NONE), "Whether to prevent deleting the vcs folder.", None).unwrap().into(),
+ InputOption::new("remove-vcs", None, Some(InputOption::VALUE_NONE), "Whether to force deletion of the vcs folder without prompting.", None).unwrap().into(),
+ InputOption::new("no-install", None, Some(InputOption::VALUE_NONE), "Whether to skip installation of the package dependencies.", None).unwrap().into(),
+ InputOption::new("no-audit", None, Some(InputOption::VALUE_NONE), "Whether to skip auditing of the installed package dependencies (can also be set via the COMPOSER_NO_AUDIT=1 env var).", None).unwrap().into(),
+ InputOption::new6("audit-format", None, Some(InputOption::VALUE_REQUIRED), "Audit output format. Must be \"table\", \"plain\", \"json\" or \"summary\".", Some(PhpMixed::String(Auditor::FORMAT_SUMMARY.to_string())), SuggestedValues::List(Auditor::FORMATS.iter().map(|s| s.to_string()).collect())).unwrap().into(),
+ InputOption::new("no-security-blocking", None, Some(InputOption::VALUE_NONE), "Allows installing packages with security advisories or that are abandoned (can also be set via the COMPOSER_NO_SECURITY_BLOCKING=1 env var).", None).unwrap().into(),
+ InputOption::new("ignore-platform-req", None, Some(InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY), "Ignore a specific platform requirement (php & ext- packages).", None).unwrap().into(),
+ InputOption::new("ignore-platform-reqs", None, Some(InputOption::VALUE_NONE), "Ignore all platform requirements (php & ext- packages).", None).unwrap().into(),
+ InputOption::new("ask", None, Some(InputOption::VALUE_NONE), "Whether to ask for project directory.", None).unwrap().into(),
+ ]);
+ self.set_help(
+ "The <info>create-project</info> command creates a new project from a given\n\
+ package into a new directory. If executed without params and in a directory\n\
+ with a composer.json file it installs the packages for the current project.\n\n\
+ You can use this command to bootstrap new projects or setup a clean\n\
+ version-controlled installation for developers of your project.\n\n\
+ <info>shirabe create-project vendor/project target-directory [version]</info>\n\n\
+ You can also specify the version with the package name using = or : as separator.\n\n\
+ <info>shirabe create-project vendor/project:version target-directory</info>\n\n\
+ To install unstable packages, either specify the version you want, or use the\n\
+ --stability=dev (where dev can be one of RC, beta, alpha or dev).\n\n\
+ To setup a developer workable version you should create the project using the source\n\
+ controlled code by appending the <info>'--prefer-source'</info> flag.\n\n\
+ To install a package from another repository than the default one you\n\
+ can pass the <info>'--repository=https://myrepository.org'</info> flag.\n\n\
+ Read more at https://getcomposer.org/doc/03-cli.md#create-project"
+ );
+ Ok(())
+ }
+
+ fn execute(
+ &self,
+ input: std::rc::Rc<std::cell::RefCell<dyn InputInterface>>,
+ _output: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>,
+ ) -> anyhow::Result<i64> {
+ let config = std::rc::Rc::new(std::cell::RefCell::new(Factory::create_config(None, None)?));
+ let io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>> = self.get_io();
+
+ let (prefer_source, prefer_dist) =
+ self.get_preferred_install_options(&config.borrow(), input.clone(), true)?;
+
+ if input.borrow().get_option("dev")?.as_bool().unwrap_or(false) {
+ io.write_error("<warning>You are using the deprecated option \"dev\". Dev packages are installed by default now.</warning>");
+ }
+ if input
+ .borrow()
+ .get_option("no-custom-installers")?
+ .as_bool()
+ .unwrap_or(false)
+ {
+ io.write_error("<warning>You are using the deprecated option \"no-custom-installers\". Use \"no-plugins\" instead.</warning>");
+ input
+ .borrow_mut()
+ .set_option("no-plugins", PhpMixed::Bool(true));
+ }
+
+ if input.borrow().is_interactive()
+ && input.borrow().get_option("ask")?.as_bool().unwrap_or(false)
+ {
+ let package = input.borrow().get_argument("package")?;
+ if package.is_null() {
+ return Err(RuntimeException {
+ message: "Not enough arguments (missing: \"package\").".to_string(),
+ code: 0,
+ }
+ .into());
+ }
+ let mut parts =
+ explode_with_limit("/", &strtolower(package.as_string().unwrap_or("")), 2);
+ let prompt = format!(
+ "New project directory [<comment>{}</comment>]: ",
+ array_pop(&mut parts).unwrap_or_default()
+ );
+ input
+ .borrow_mut()
+ .set_argument("directory", io.ask(prompt, PhpMixed::Null)?);
+ }
+
+ let repository_opt = input.borrow().get_option("repository")?;
+ let repository_url_opt = input.borrow().get_option("repository-url")?;
+ let repositories = if repository_opt
+ .as_list()
+ .map(|l| !l.is_empty())
+ .unwrap_or(false)
+ {
+ Some(repository_opt)
+ } else {
+ Some(repository_url_opt)
+ };
+
+ self.install_project(
+ io,
+ config,
+ input.clone(),
+ input
+ .borrow()
+ .get_argument("package")?
+ .as_string()
+ .map(|s| s.to_string()),
+ input
+ .borrow()
+ .get_argument("directory")?
+ .as_string()
+ .map(|s| s.to_string()),
+ input
+ .borrow()
+ .get_argument("version")?
+ .as_string()
+ .map(|s| s.to_string()),
+ input
+ .borrow()
+ .get_option("stability")?
+ .as_string()
+ .map(|s| s.to_string()),
+ prefer_source,
+ prefer_dist,
+ !input
+ .borrow()
+ .get_option("no-dev")?
+ .as_bool()
+ .unwrap_or(false),
+ repositories,
+ input
+ .borrow()
+ .get_option("no-plugins")?
+ .as_bool()
+ .unwrap_or(false),
+ input
+ .borrow()
+ .get_option("no-scripts")?
+ .as_bool()
+ .unwrap_or(false),
+ input
+ .borrow()
+ .get_option("no-progress")?
+ .as_bool()
+ .unwrap_or(false),
+ input
+ .borrow()
+ .get_option("no-install")?
+ .as_bool()
+ .unwrap_or(false),
+ Some(self.get_platform_requirement_filter(input.clone())?),
+ !input
+ .borrow()
+ .get_option("no-secure-http")?
+ .as_bool()
+ .unwrap_or(false),
+ input
+ .borrow()
+ .get_option("add-repository")?
+ .as_bool()
+ .unwrap_or(false),
+ )
+ }
+
+ fn initialize(
+ &self,
+ input: std::rc::Rc<std::cell::RefCell<dyn InputInterface>>,
+ output: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>,
+ ) -> anyhow::Result<()> {
+ base_command_initialize(self, input, output)
+ }
+
+ fn complete(
+ &self,
+ input: &shirabe_external_packages::symfony::console::completion::completion_input::CompletionInput,
+ suggestions: &mut shirabe_external_packages::symfony::console::completion::completion_suggestions::CompletionSuggestions,
+ ) -> anyhow::Result<()> {
+ crate::command::base_command::base_command_complete(self, input, suggestions)
+ }
+
+ shirabe_external_packages::delegate_command_trait_impls_to_inner!(base_command_data);
+}
+
+impl BaseCommand for CreateProjectCommand {
+ fn base_command_data(&self) -> &crate::command::BaseCommandData {
+ &self.base_command_data
+ }
+
+ crate::delegate_base_command_trait_impls_to_inner!(base_command_data);
+}