aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/console
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe/src/console')
-rw-r--r--crates/shirabe/src/console/application.rs112
-rw-r--r--crates/shirabe/src/console/html_output_formatter.rs6
-rw-r--r--crates/shirabe/src/console/input/input_argument.rs54
-rw-r--r--crates/shirabe/src/console/input/input_option.rs81
4 files changed, 63 insertions, 190 deletions
diff --git a/crates/shirabe/src/console/application.rs b/crates/shirabe/src/console/application.rs
index 07996bb..13489fd 100644
--- a/crates/shirabe/src/console/application.rs
+++ b/crates/shirabe/src/console/application.rs
@@ -177,8 +177,8 @@ impl Application {
input: &mut dyn InputInterface,
output: &dyn OutputInterface,
) -> anyhow::Result<i64> {
- self.disable_plugins_by_default = input.has_parameter_option("--no-plugins", false);
- self.disable_scripts_by_default = input.has_parameter_option("--no-scripts", false);
+ self.disable_plugins_by_default = input.has_parameter_option(&["--no-plugins"], false);
+ self.disable_scripts_by_default = input.has_parameter_option(&["--no-scripts"], false);
// PHP: static $stdin = null;
// We use an Option here to mimic the lazy initialization.
@@ -210,8 +210,8 @@ impl Application {
// Register error handler again to pass it the IO instance
ErrorHandler::register(Some(io));
- if input.has_parameter_option("--no-cache", false) {
- io.write_error("Disabling cache usage", true, io_interface::DEBUG);
+ if input.has_parameter_option(&["--no-cache"], false) {
+ io.write_error3("Disabling cache usage", true, io_interface::DEBUG);
Platform::put_env(
"COMPOSER_CACHE_DIR",
if Platform::is_windows() {
@@ -230,7 +230,7 @@ impl Application {
chdir(nwd);
self.initial_working_directory = getcwd();
let cwd = Platform::get_cwd_real(true);
- io.write_error(
+ io.write_error3(
&format!(
"Changed CWD to {}",
if !cwd.is_empty() {
@@ -283,10 +283,10 @@ impl Application {
&& !file_exists(&Factory::get_composer_file())
&& use_parent_dir_if_no_json_available.as_bool() != Some(false)
&& (command_name.as_deref() != Some("config")
- || (input.has_parameter_option("--file", true) == false
- && input.has_parameter_option("-f", true) == false))
- && input.has_parameter_option("--help", true) == false
- && input.has_parameter_option("-h", true) == false
+ || (input.has_parameter_option(&["--file"], true) == false
+ && input.has_parameter_option(&["-f"], true) == false))
+ && input.has_parameter_option(&["--help"], true) == false
+ && input.has_parameter_option(&["-h"], true) == false
{
let mut dir = dirname(&Platform::get_cwd_real(true));
let home_value = Platform::get_env("HOME")
@@ -426,7 +426,7 @@ impl Application {
}
let mut ghe = GithubActionError::new(self.io.clone_box());
- ghe.emit(&pe.get_message(), file.as_deref(), line);
+ ghe.emit(&pe.message, file.as_deref(), line);
return Err(e);
} else {
@@ -458,7 +458,7 @@ impl Application {
}
if !is_proxy_command {
- io.write_error(
+ io.write_error3(
&sprintf(
"Running %s (%s) with %s on %s",
&[
@@ -675,7 +675,7 @@ impl Application {
let mut start_time: Option<f64> = None;
let result_outcome: anyhow::Result<i64> = (|| -> anyhow::Result<i64> {
- if input.has_parameter_option("--profile", false) {
+ if input.has_parameter_option(&["--profile"], false) {
start_time = Some(microtime(true));
self.io.enable_debugging(start_time.unwrap());
}
@@ -712,7 +712,7 @@ impl Application {
io.write_error(&format!(
"<info>Memory usage: {}MiB (peak: {}MiB), time: {}s</info>",
round((memory_get_usage() as f64) / 1024.0 / 1024.0, 2),
- round((memory_get_peak_usage() as f64) / 1024.0 / 1024.0, 2),
+ round((memory_get_peak_usage(true) as f64) / 1024.0 / 1024.0, 2),
round(microtime(true) - st, 2)
));
}
@@ -725,8 +725,8 @@ impl Application {
&& self.is_running_as_root()
&& !self.io.is_interactive()
{
- io.write_error("<error>Plugins have been disabled automatically as you are running as root, this may be the cause of the script failure.</error>", true, io_interface::QUIET);
- io.write_error(
+ io.write_error3("<error>Plugins have been disabled automatically as you are running as root, this may be the cause of the script failure.</error>", true, io_interface::QUIET);
+ io.write_error3(
"<error>See also https://getcomposer.org/root</error>",
true,
io_interface::QUIET,
@@ -809,7 +809,7 @@ impl Application {
output.set_verbosity(OutputInterface::VERBOSITY_VERBOSE);
}
- Silencer::suppress();
+ Silencer::suppress(None);
let _ = (|| -> anyhow::Result<()> {
let composer = self.get_composer(false, Some(true), None)?;
if composer.is_some() && function_exists("disk_free_space") {
@@ -835,7 +835,7 @@ impl Application {
hit = df.map(|d| d < min_space_free).unwrap_or(false);
}
if hit {
- io.write_error(&format!("<error>The disk hosting {} has less than 100MiB of free space, this may be the cause of the following exception</error>", dir), true, io_interface::QUIET);
+ io.write_error3(&format!("<error>The disk hosting {} has less than 100MiB of free space, this may be the cause of the following exception</error>", dir), true, io_interface::QUIET);
}
}
Ok(())
@@ -846,12 +846,12 @@ impl Application {
if exception.downcast_ref::<TransportException>().is_some()
&& str_contains(&message, "Unable to use a proxy")
{
- io.write_error(
+ io.write_error3(
"<error>The following exception indicates your proxy is misconfigured</error>",
true,
io_interface::QUIET,
);
- io.write_error("<error>Check https://getcomposer.org/doc/faqs/how-to-use-composer-behind-a-proxy.md for details</error>", true, io_interface::QUIET);
+ io.write_error3("<error>Check https://getcomposer.org/doc/faqs/how-to-use-composer-behind-a-proxy.md for details</error>", true, io_interface::QUIET);
}
if Platform::is_windows()
@@ -866,15 +866,15 @@ impl Application {
.collect(),
)) && count(&avast_detect) != 0
{
- io.write_error("<error>The following exception indicates a possible issue with the Avast Firewall</error>", true, io_interface::QUIET);
- io.write_error(
+ io.write_error3("<error>The following exception indicates a possible issue with the Avast Firewall</error>", true, io_interface::QUIET);
+ io.write_error3(
"<error>Check https://getcomposer.org/local-issuer for details</error>",
true,
io_interface::QUIET,
);
} else {
- io.write_error("<error>The following exception indicates a possible issue with a Firewall/Antivirus</error>", true, io_interface::QUIET);
- io.write_error(
+ io.write_error3("<error>The following exception indicates a possible issue with a Firewall/Antivirus</error>", true, io_interface::QUIET);
+ io.write_error3(
"<error>Check https://getcomposer.org/local-issuer for details</error>",
true,
io_interface::QUIET,
@@ -885,13 +885,13 @@ impl Application {
if Platform::is_windows()
&& strpos(&message, "The system cannot find the path specified").is_some()
{
- io.write_error("<error>The following exception may be caused by a stale entry in your cmd.exe AutoRun</error>", true, io_interface::QUIET);
- io.write_error("<error>Check https://getcomposer.org/doc/articles/troubleshooting.md#-the-system-cannot-find-the-path-specified-windows- for details</error>", true, io_interface::QUIET);
+ io.write_error3("<error>The following exception may be caused by a stale entry in your cmd.exe AutoRun</error>", true, io_interface::QUIET);
+ io.write_error3("<error>Check https://getcomposer.org/doc/articles/troubleshooting.md#-the-system-cannot-find-the-path-specified-windows- for details</error>", true, io_interface::QUIET);
}
if strpos(&message, "fork failed - Cannot allocate memory").is_some() {
- io.write_error("<error>The following exception is caused by a lack of memory or swap, or not having swap configured</error>", true, io_interface::QUIET);
- io.write_error("<error>Check https://getcomposer.org/doc/articles/troubleshooting.md#proc-open-fork-failed-errors for details</error>", true, io_interface::QUIET);
+ io.write_error3("<error>The following exception is caused by a lack of memory or swap, or not having swap configured</error>", true, io_interface::QUIET);
+ io.write_error3("<error>Check https://getcomposer.org/doc/articles/troubleshooting.md#proc-open-fork-failed-errors for details</error>", true, io_interface::QUIET);
}
if exception
@@ -903,26 +903,26 @@ impl Application {
true,
io_interface::QUIET,
);
- io.write_error("<error>Check https://getcomposer.org/doc/06-config.md#process-timeout for details</error>", true, io_interface::QUIET);
+ io.write_error3("<error>Check https://getcomposer.org/doc/06-config.md#process-timeout for details</error>", true, io_interface::QUIET);
}
if self.get_disable_plugins_by_default()
&& self.is_running_as_root()
&& !self.io.is_interactive()
{
- io.write_error("<error>Plugins have been disabled automatically as you are running as root, this may be the cause of the following exception. See also https://getcomposer.org/root</error>", true, io_interface::QUIET);
+ io.write_error3("<error>Plugins have been disabled automatically as you are running as root, this may be the cause of the following exception. See also https://getcomposer.org/root</error>", true, io_interface::QUIET);
} else if exception
.downcast_ref::<CommandNotFoundException>()
.is_some()
&& self.get_disable_plugins_by_default()
{
- io.write_error("<error>Plugins have been disabled, which may be why some commands are missing, unless you made a typo</error>", true, io_interface::QUIET);
+ io.write_error3("<error>Plugins have been disabled, which may be why some commands are missing, unless you made a typo</error>", true, io_interface::QUIET);
}
let hints = HttpDownloader::get_exception_hints_from_error(exception);
if !hints.is_empty() && count(&hints) > 0 {
for hint in &hints {
- io.write_error(hint, true, io_interface::QUIET);
+ io.write_error3(hint, true, io_interface::QUIET);
}
}
}
@@ -985,43 +985,10 @@ impl Application {
/// Initializes all the composer commands.
pub(crate) fn get_default_commands(&self) -> Vec<Box<dyn Command>> {
- let mut cmds = self.inner.get_default_commands();
- let extras: Vec<Box<dyn Command>> = vec![
- Box::new(AboutCommand::new()),
- Box::new(ConfigCommand::new()),
- Box::new(DependsCommand::new()),
- Box::new(ProhibitsCommand::new()),
- Box::new(InitCommand::new()),
- Box::new(InstallCommand::new()),
- Box::new(CreateProjectCommand::new()),
- Box::new(UpdateCommand::new()),
- Box::new(SearchCommand::new()),
- Box::new(ValidateCommand::new()),
- Box::new(AuditCommand::new()),
- Box::new(ShowCommand::new()),
- Box::new(SuggestsCommand::new()),
- Box::new(RequireCommand::new()),
- Box::new(DumpAutoloadCommand::new()),
- Box::new(StatusCommand::new()),
- Box::new(ArchiveCommand::new()),
- Box::new(DiagnoseCommand::new()),
- Box::new(RunScriptCommand::new()),
- Box::new(LicensesCommand::new()),
- Box::new(GlobalCommand::new()),
- Box::new(ClearCacheCommand::new()),
- Box::new(RemoveCommand::new()),
- Box::new(HomeCommand::new()),
- Box::new(ExecCommand::new()),
- Box::new(OutdatedCommand::new()),
- Box::new(CheckPlatformReqsCommand::new()),
- Box::new(FundCommand::new()),
- Box::new(ReinstallCommand::new()),
- Box::new(BumpCommand::new()),
- Box::new(RepositoryCommand::new()),
- Box::new(SelfUpdateCommand::new()),
- ];
- cmds.extend(extras);
- cmds
+ // TODO(phase-b): each shirabe command struct needs its own `impl Command` (the orphan
+ // rule disallowed a blanket `impl<C: HasBaseCommandData> Command for C`). Until those
+ // are written, expose only the inner symfony defaults.
+ self.inner.get_default_commands()
}
/// This ensures we can find the correct command name even if a global input option is present before it
@@ -1120,16 +1087,19 @@ impl Application {
let mut ctor_args: IndexMap<String, PhpMixed> = IndexMap::new();
ctor_args.insert(
"composer".to_string(),
- PhpMixed::Object(shirabe_php_shim::ArrayObject::new()),
+ PhpMixed::Object(shirabe_php_shim::ArrayObject::new(None)),
);
ctor_args.insert(
"io".to_string(),
- PhpMixed::Object(shirabe_php_shim::ArrayObject::new()),
+ PhpMixed::Object(shirabe_php_shim::ArrayObject::new(None)),
);
for capability in pm
.get_plugin_capabilities("Composer\\Plugin\\Capability\\CommandProvider", ctor_args)
{
- let new_commands = capability.get_commands();
+ // TODO(phase-b): downcast to CommandProvider via Any/trait-object instead of todo!()
+ let new_commands: Vec<Box<dyn crate::command::base_command::BaseCommand>> =
+ todo!("downcast capability to CommandProvider and call get_commands()");
+ let _ = capability;
for command in &new_commands {
if command.as_any().downcast_ref::<BaseCommand>().is_none() {
return Err(UnexpectedValueException {
diff --git a/crates/shirabe/src/console/html_output_formatter.rs b/crates/shirabe/src/console/html_output_formatter.rs
index a69b4c6..c7be6ee 100644
--- a/crates/shirabe/src/console/html_output_formatter.rs
+++ b/crates/shirabe/src/console/html_output_formatter.rs
@@ -42,13 +42,15 @@ impl HtmlOutputFormatter {
];
pub fn new(styles: IndexMap<String, OutputFormatterStyle>) -> Self {
+ // TODO(phase-b): styles dropped until base OutputFormatter::new accepts a style map
+ let _ = styles;
Self {
- inner: OutputFormatter::new(true, styles),
+ inner: OutputFormatter::new(true),
}
}
pub fn format(&self, message: Option<&str>) -> Option<String> {
- let formatted = self.inner.format(message)?;
+ let formatted = self.inner.format(message.unwrap_or(""));
let clear_escape_codes = "(?:39|49|0|22|24|25|27|28)";
let pattern = format!(
diff --git a/crates/shirabe/src/console/input/input_argument.rs b/crates/shirabe/src/console/input/input_argument.rs
index fdd05d9..c2c2799 100644
--- a/crates/shirabe/src/console/input/input_argument.rs
+++ b/crates/shirabe/src/console/input/input_argument.rs
@@ -1,67 +1,27 @@
//! ref: composer/src/Composer/Console/Input/InputArgument.php
use anyhow::Result;
-use shirabe_external_packages::symfony::console::completion::completion_input::CompletionInput;
-use shirabe_external_packages::symfony::console::completion::completion_suggestions::CompletionSuggestions;
-use shirabe_external_packages::symfony::console::completion::suggestion::Suggestion;
use shirabe_external_packages::symfony::console::input::input_argument::InputArgument as BaseInputArgument;
use shirabe_php_shim::PhpMixed;
-pub enum SuggestedValues {
- List(Vec<String>),
- Closure(Box<dyn Fn(&CompletionInput, &mut CompletionSuggestions) -> Vec<StringOrSuggestion>>),
-}
-
-impl std::fmt::Debug for SuggestedValues {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- SuggestedValues::List(list) => write!(f, "SuggestedValues::List({:?})", list),
- SuggestedValues::Closure(_) => write!(f, "SuggestedValues::Closure(<closure>)"),
- }
- }
-}
-
-pub enum StringOrSuggestion {
- Str(String),
- Suggestion(Suggestion),
-}
-
#[derive(Debug)]
pub struct InputArgument {
inner: BaseInputArgument,
- suggested_values: SuggestedValues,
}
impl InputArgument {
+ pub const REQUIRED: i64 = 1;
+ pub const OPTIONAL: i64 = 2;
+ pub const IS_ARRAY: i64 = 4;
+
pub fn new(
name: &str,
mode: Option<i64>,
description: &str,
default: Option<PhpMixed>,
- suggested_values: SuggestedValues,
+ // TODO(cli-completion): suggested_values closure / list dropped along with completion support
) -> Result<Self> {
- let inner = BaseInputArgument::new(name, mode, description, default)?;
- Ok(Self {
- inner,
- suggested_values,
- })
- }
-
- pub fn complete(
- &self,
- input: &CompletionInput,
- suggestions: &mut CompletionSuggestions,
- ) -> Result<()> {
- let values: Vec<StringOrSuggestion> = match &self.suggested_values {
- SuggestedValues::List(list) => list
- .iter()
- .map(|s| StringOrSuggestion::Str(s.clone()))
- .collect(),
- SuggestedValues::Closure(closure) => closure(input, suggestions),
- };
- if !values.is_empty() {
- suggestions.suggest_values(values);
- }
- Ok(())
+ let inner = BaseInputArgument::new(name, mode, description, default);
+ Ok(Self { inner })
}
}
diff --git a/crates/shirabe/src/console/input/input_option.rs b/crates/shirabe/src/console/input/input_option.rs
index 6e93a62..0c0745e 100644
--- a/crates/shirabe/src/console/input/input_option.rs
+++ b/crates/shirabe/src/console/input/input_option.rs
@@ -1,91 +1,32 @@
//! ref: composer/src/Composer/Console/Input/InputOption.php
use anyhow::Result;
-use shirabe_external_packages::symfony::console::completion::completion_input::CompletionInput;
-use shirabe_external_packages::symfony::console::completion::completion_suggestions::CompletionSuggestions;
-use shirabe_external_packages::symfony::console::completion::suggestion::Suggestion;
use shirabe_external_packages::symfony::console::input::input_option::InputOption as BaseInputOption;
-use shirabe_php_shim::LogicException;
use shirabe_php_shim::PhpMixed;
-pub enum SuggestedValues {
- List(Vec<String>),
- Closure(Box<dyn Fn(&CompletionInput, &mut CompletionSuggestions) -> Vec<StringOrSuggestion>>),
-}
-
-impl std::fmt::Debug for SuggestedValues {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- SuggestedValues::List(list) => write!(f, "SuggestedValues::List({:?})", list),
- SuggestedValues::Closure(_) => write!(f, "SuggestedValues::Closure(<closure>)"),
- }
- }
-}
-
-pub enum StringOrSuggestion {
- Str(String),
- Suggestion(Suggestion),
-}
-
#[derive(Debug)]
pub struct InputOption {
inner: BaseInputOption,
- suggested_values: SuggestedValues,
}
impl InputOption {
+ pub const VALUE_NONE: i64 = 1;
+ pub const VALUE_REQUIRED: i64 = 2;
+ pub const VALUE_OPTIONAL: i64 = 4;
+ pub const VALUE_IS_ARRAY: i64 = 8;
+ pub const VALUE_NEGATABLE: i64 = 16;
+
pub fn new(
name: &str,
shortcut: Option<PhpMixed>,
mode: Option<i64>,
description: &str,
default: Option<PhpMixed>,
- suggested_values: SuggestedValues,
+ // TODO(cli-completion): suggested_values closure / list dropped along with completion support
) -> Result<Self> {
- let inner = BaseInputOption::new(name, shortcut, mode, description, default)?;
- let this = Self {
- inner,
- suggested_values,
- };
-
- if let SuggestedValues::List(ref list) = this.suggested_values {
- if !list.is_empty() && !this.inner.accept_value() {
- return Err(LogicException {
- message: "Cannot set suggested values if the option does not accept a value."
- .to_string(),
- code: 0,
- }
- .into());
- }
- } else if let SuggestedValues::Closure(_) = this.suggested_values {
- if !this.inner.accept_value() {
- return Err(LogicException {
- message: "Cannot set suggested values if the option does not accept a value."
- .to_string(),
- code: 0,
- }
- .into());
- }
- }
-
- Ok(this)
- }
-
- pub fn complete(
- &self,
- input: &CompletionInput,
- suggestions: &mut CompletionSuggestions,
- ) -> Result<()> {
- let values: Vec<StringOrSuggestion> = match &self.suggested_values {
- SuggestedValues::List(list) => list
- .iter()
- .map(|s| StringOrSuggestion::Str(s.clone()))
- .collect(),
- SuggestedValues::Closure(closure) => closure(input, suggestions),
- };
- if !values.is_empty() {
- suggestions.suggest_values(values);
- }
- Ok(())
+ let shortcut_str = shortcut.as_ref().and_then(|s| s.as_string());
+ let default_mixed = default.unwrap_or(PhpMixed::Null);
+ let inner = BaseInputOption::new(name, shortcut_str, mode, description, default_mixed);
+ Ok(Self { inner })
}
}