aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/command/init_command.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-18 07:18:07 +0900
committernsfisis <nsfisis@gmail.com>2026-08-18 07:18:07 +0900
commit6a7e64d04a8b0ad932169df43e2d93efe8ceedf8 (patch)
treef74bca82b226fde11c820ba3988e094a49073940 /crates/shirabe/src/command/init_command.rs
parentbed0cd33ca32b95aed9d65891f97649a6f9d0069 (diff)
downloadphp-shirabe-6a7e64d04a8b0ad932169df43e2d93efe8ceedf8.tar.gz
php-shirabe-6a7e64d04a8b0ad932169df43e2d93efe8ceedf8.tar.zst
php-shirabe-6a7e64d04a8b0ad932169df43e2d93efe8ceedf8.zip
fix: propagate ported exceptions instead of flattening them
`ProcessExecutor::execute_args` existed only to turn `execute`'s `anyhow::Result` into an exit code of 1, so every one of its ~87 call sites silently took the "command failed" branch on an error PHP would have thrown. It is gone; callers use `execute` and propagate with `?`. Where the enclosing function had no `Result` to propagate into, its signature grew one, up to and including `Git::get_version`, `Svn::binary_version`, `GitHub`/`GitLab`/`Bitbucket::authorize_oauth`, `InitCommand::get_git_config` and `DiagnoseCommand::check_git`. The VCS drivers had the same problem in the other direction: their `get_contents` returned `Result<Response, Box<TransportException>>`, a type too narrow for the PHP method, which lets any Throwable out of the `catch (TransportException $e)` block. Every non-transport error was therefore rewritten into a `TransportException` with code 0, which the callers switch on. They now return `anyhow::Result<Result<Response, Box<TransportException>>>`: the outer `Result` carries what PHP does not catch, the inner one the exception the drivers handle. That signature also restores `GitLabDriver::getContents`: the 400/401 `TransportException`s it raises to force authentication are thrown inside its own `try` block and handled by its own `catch`, but the port returned them straight to the caller, so the authentication flow behind them never ran. `impl_php_exception!` gains `From<Box<$ty>> for anyhow::Error` so a caught exception can be re-propagated with `?`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/command/init_command.rs')
-rw-r--r--crates/shirabe/src/command/init_command.rs50
1 files changed, 28 insertions, 22 deletions
diff --git a/crates/shirabe/src/command/init_command.rs b/crates/shirabe/src/command/init_command.rs
index add7c237..2205b852 100644
--- a/crates/shirabe/src/command/init_command.rs
+++ b/crates/shirabe/src/command/init_command.rs
@@ -152,19 +152,19 @@ impl InitCommand {
Some(implode("\\", &namespace))
}
- fn get_git_config(&self) -> IndexMap<String, String> {
+ fn get_git_config(&self) -> anyhow::Result<IndexMap<String, String>> {
if self.git_config.borrow().is_some() {
- return self.git_config.borrow().clone().unwrap_or_default();
+ return Ok(self.git_config.borrow().clone().unwrap_or_default());
}
let mut process = ProcessExecutor::new(Some(self.get_io().clone()));
let mut output = String::new();
- if process.execute_args(
+ if process.execute(
&["git".to_string(), "config".to_string(), "-l".to_string()],
&mut output,
None,
- ) == 0
+ )? == 0
{
*self.git_config.borrow_mut() = Some(IndexMap::new());
for m in preg_match_all(php_regex!(r"{^([^=]+)=(.*)$}m"), &output) {
@@ -178,11 +178,11 @@ impl InitCommand {
);
}
- return self.git_config.borrow().clone().unwrap_or_default();
+ return Ok(self.git_config.borrow().clone().unwrap_or_default());
}
*self.git_config.borrow_mut() = Some(IndexMap::new());
- IndexMap::new()
+ Ok(IndexMap::new())
}
/// Checks the local .gitignore file for the Composer vendor directory.
@@ -241,7 +241,7 @@ impl InitCommand {
}
/// For testing only: invoke the crate-private `get_git_config`.
- pub fn __get_git_config(&self) -> IndexMap<String, String> {
+ pub fn __get_git_config(&self) -> anyhow::Result<IndexMap<String, String>> {
self.get_git_config()
}
@@ -333,8 +333,8 @@ impl InitCommand {
preg_replace(php_regex!(r"{([_.-]){2,}}u"), "$1", &name)
}
- fn get_default_package_name(&self) -> String {
- let git = self.get_git_config();
+ fn get_default_package_name(&self) -> anyhow::Result<String> {
+ let git = self.get_git_config()?;
let cwd = realpath(".").unwrap_or_default();
let name = basename(&cwd);
let name = self.sanitize_package_name_component(&name);
@@ -384,11 +384,11 @@ impl InitCommand {
let vendor = self.sanitize_package_name_component(&vendor);
- format!("{}/{}", vendor, name)
+ Ok(format!("{}/{}", vendor, name))
}
- fn get_default_author(&self) -> Option<String> {
- let git = self.get_git_config();
+ fn get_default_author(&self) -> anyhow::Result<Option<String>> {
+ let git = self.get_git_config()?;
let mut author_name: Option<String> = None;
let composer_default_author = PHP_SERVER
@@ -425,10 +425,10 @@ impl InitCommand {
}
if let (Some(name), Some(email)) = (author_name, author_email) {
- return Some(format!("{} <{}>", name, email));
+ return Ok(Some(format!("{} <{}>", name, email)));
}
- None
+ Ok(None)
}
}
@@ -753,7 +753,7 @@ impl Command for InitCommand {
if !input.borrow().is_interactive() {
if input.borrow().get_option("name")?.is_null() {
- let name = self.get_default_package_name();
+ let name = self.get_default_package_name()?;
input
.borrow_mut()
.set_option("name", PhpMixed::from(name))
@@ -761,7 +761,7 @@ impl Command for InitCommand {
}
if input.borrow().get_option("author")?.is_null() {
- let author = self.get_default_author();
+ let author = self.get_default_author()?;
input
.borrow_mut()
.set_option("author", PhpMixed::from(author))
@@ -881,12 +881,15 @@ impl Command for InitCommand {
io_interface::NORMAL,
);
- let mut name = input
+ let name_option = input
.borrow()
.get_option("name")?
.as_string()
- .map(|s| s.to_string())
- .unwrap_or_else(|| self.get_default_package_name());
+ .map(|s| s.to_string());
+ let mut name = match name_option {
+ Some(name) => name,
+ None => self.get_default_package_name()?,
+ };
let name_default = name.clone();
let name_for_validate = name.clone();
@@ -943,12 +946,15 @@ impl Command for InitCommand {
)?;
input.borrow_mut().set_option("description", description);
- let author = input
+ let author_option = input
.borrow()
.get_option("author")?
.as_string()
- .map(|s| s.to_string())
- .unwrap_or_else(|| self.get_default_author().unwrap_or_default());
+ .map(|s| s.to_string());
+ let author = match author_option {
+ Some(author) => author,
+ None => self.get_default_author()?.unwrap_or_default(),
+ };
let author_for_validate = author.clone();
let author_default = author.clone();