//! ref: composer/src/Composer/Command/SuggestsCommand.php
use crate::command::base_command::base_command_initialize;
use crate::command::{BaseCommand, BaseCommandData};
use crate::console::input::InputArgument;
use crate::console::input::InputOption;
use crate::installer::SuggestedPackagesReporter;
use crate::repository::InstalledRepository;
use crate::repository::PlatformRepository;
use crate::repository::RepositoryInterface;
use crate::repository::RepositoryInterfaceHandle;
use crate::repository::RootPackageRepository;
use indexmap::IndexMap;
use shirabe_external_packages::symfony::console::command::command::Command;
use shirabe_external_packages::symfony::console::input::InputInterface;
use shirabe_external_packages::symfony::console::output::OutputInterface;
use shirabe_php_shim::{PhpMixed, empty, in_array};
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
pub struct SuggestsCommand {
base_command_data: BaseCommandData,
}
impl Default for SuggestsCommand {
fn default() -> Self {
Self::new()
}
}
impl SuggestsCommand {
pub fn new() -> Self {
let command = SuggestsCommand {
base_command_data: BaseCommandData::new(None),
};
command
.configure()
.expect("SuggestsCommand::configure uses static, valid metadata");
command
}
}
impl Command for SuggestsCommand {
fn configure(&self) -> anyhow::Result<()> {
// TODO(cli-completion): suggest_installed_package() for `packages` argument
self.set_name("suggests")?;
self.set_description("Shows package suggestions");
self.set_definition(&[
InputOption::new(
"by-package",
None,
Some(InputOption::VALUE_NONE),
"Groups output by suggesting package (default)",
None,
)
.unwrap()
.into(),
InputOption::new(
"by-suggestion",
None,
Some(InputOption::VALUE_NONE),
"Groups output by suggested package",
None,
)
.unwrap()
.into(),
InputOption::new(
"all",
Some(PhpMixed::String("a".to_string())),
Some(InputOption::VALUE_NONE),
"Show suggestions from all dependencies, including transitive ones",
None,
)
.unwrap()
.into(),
InputOption::new(
"list",
None,
Some(InputOption::VALUE_NONE),
"Show only list of suggested package names",
None,
)
.unwrap()
.into(),
InputOption::new(
"no-dev",
None,
Some(InputOption::VALUE_NONE),
"Exclude suggestions from require-dev packages",
None,
)
.unwrap()
.into(),
InputArgument::new(
"packages",
Some(InputArgument::IS_ARRAY | InputArgument::OPTIONAL),
"Packages that you want to list suggestions from.",
None,
)
.unwrap()
.into(),
]);
self.set_help(
"\nThe %command.name% command shows a sorted list of suggested packages.\n\nRead more at https://getcomposer.org/doc/03-cli.md#suggests",
);
Ok(())
}
fn execute(
&self,
input: Rc>,
_output: Rc>,
) -> anyhow::Result {
let composer = self.require_composer(None, None)?;
let composer = crate::composer::composer_full(&composer);
let mut installed_repos: Vec =
vec![RepositoryInterfaceHandle::new(RootPackageRepository::new(
crate::package::RootPackageInterfaceHandle::dup(composer.get_package()),
))];
if composer.get_locker().borrow_mut().is_locked() {
let platform_overrides = composer
.get_locker()
.borrow_mut()
.get_platform_overrides()?;
let platform_overrides: IndexMap = platform_overrides
.into_iter()
.map(|(k, v)| (k, PhpMixed::String(v)))
.collect();
installed_repos.push(RepositoryInterfaceHandle::new(PlatformRepository::new(
vec![],
platform_overrides,
)?));
let locked_repo = composer.get_locker().borrow_mut().get_locked_repository(
!input
.borrow()
.get_option("no-dev")?
.as_bool()
.unwrap_or(false),
)?;
installed_repos.push(locked_repo.into());
} else {
let platform_cfg = composer.get_config().borrow().get("platform");
let platform_overrides: IndexMap = platform_cfg
.as_array()
.map(|m| m.iter().map(|(k, v)| (k.clone(), v.clone())).collect())
.unwrap_or_default();
installed_repos.push(RepositoryInterfaceHandle::new(PlatformRepository::new(
vec![],
platform_overrides,
)?));
installed_repos.push(
composer
.get_repository_manager()
.borrow()
.get_local_repository(),
);
}
let mut installed_repo = InstalledRepository::new(installed_repos);
let mut reporter = SuggestedPackagesReporter::new(self.get_io().clone());
let filter = input.borrow().get_argument("packages")?;
let mut packages = RepositoryInterface::get_packages(&mut installed_repo)?;
let root_pkg_as_base: crate::package::BasePackageHandle =
composer.get_package().clone().into();
packages.push(root_pkg_as_base);
for package in &packages {
if !empty(&filter) && !in_array(PhpMixed::String(package.get_name()), &filter, false) {
continue;
}
reporter.add_suggestions_from_package(package.clone());
}
let mut mode = SuggestedPackagesReporter::MODE_BY_PACKAGE;
if input
.borrow()
.get_option("by-suggestion")?
.as_bool()
.unwrap_or(false)
{
mode = SuggestedPackagesReporter::MODE_BY_SUGGESTION;
}
if input
.borrow()
.get_option("by-package")?
.as_bool()
.unwrap_or(false)
{
mode |= SuggestedPackagesReporter::MODE_BY_PACKAGE;
}
if input
.borrow()
.get_option("list")?
.as_bool()
.unwrap_or(false)
{
mode = SuggestedPackagesReporter::MODE_LIST;
}
let only_dependents_of: Option =
if empty(&filter) && !input.borrow().get_option("all")?.as_bool().unwrap_or(false) {
Some(composer.get_package().clone().into())
} else {
None
};
reporter.output(mode, Some(&mut installed_repo), only_dependents_of)?;
Ok(0)
}
fn initialize(
&self,
input: Rc>,
output: Rc>,
) -> anyhow::Result<()> {
base_command_initialize(self, input, output)
}
shirabe_external_packages::delegate_command_trait_impls_to_inner!(base_command_data);
}
impl BaseCommand for SuggestsCommand {
fn command_data(
&self,
) -> &shirabe_external_packages::symfony::console::command::command::CommandData {
self.base_command_data.command_data()
}
crate::delegate_base_command_trait_impls_to_inner!(base_command_data);
}