Skip to content

Commit

Permalink
Make sure that list of plugins is sorted and unique (#5395)
Browse files Browse the repository at this point in the history
## Description

Fixes #5396, #5402

The sorting is performed by the file_name instead of the full text to be
printed or full path

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [x] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [x] I have added tests that prove my fix is effective or that my
feature works.
- [x] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.
  • Loading branch information
crodas authored Jan 3, 2024
1 parent 910e33b commit caa1822
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 11 deletions.
55 changes: 46 additions & 9 deletions forc/src/cli/commands/plugins.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use crate::cli::PluginsCommand;
use anyhow::anyhow;
use clap::Parser;
use forc_tracing::println_warning;
use forc_util::ForcResult;
use std::path::{Path, PathBuf};
use std::{
collections::HashMap,
path::{Path, PathBuf},
};
use tracing::info;

/// Find all forc plugins available via `PATH`.
Expand All @@ -18,15 +22,52 @@ pub struct Command {
describe: bool,
}

fn get_file_name(path: &Path) -> String {
if let Some(path_str) = path.file_name().and_then(|path_str| path_str.to_str()) {
path_str.to_owned()
} else {
path.display().to_string()
}
}

pub(crate) fn exec(command: PluginsCommand) -> ForcResult<()> {
let PluginsCommand {
print_full_path,
describe,
} = command;

let mut plugins = crate::cli::plugin::find_all()
.map(|path| {
get_plugin_info(path.clone(), print_full_path, describe).map(|info| (path, info))
})
.collect::<Result<Vec<(_, _)>, _>>()?
.into_iter()
.fold(HashMap::new(), |mut acc, (path, content)| {
let bin_name = get_file_name(&path);
acc.entry(bin_name.clone())
.or_insert_with(|| (bin_name, vec![], content.clone()))
.1
.push(path);
acc
})
.into_values()
.map(|(bin_name, mut paths, content)| {
paths.sort();
paths.dedup();
(bin_name, paths, content)
})
.collect::<Vec<_>>();
plugins.sort_by(|a, b| a.0.cmp(&b.0));

info!("Installed Plugins:");
for path in crate::cli::plugin::find_all() {
info!("{}", print_plugin(path, print_full_path, describe)?);
for plugin in plugins {
info!("{}", plugin.2);
if plugin.1.len() > 1 {
println_warning(&format!("Multiple paths found for {}", plugin.0));
for path in plugin.1 {
println_warning(&format!(" {}", path.display()));
}
}
}
Ok(())
}
Expand Down Expand Up @@ -72,11 +113,7 @@ fn format_print_description(
let display = if print_full_path {
path.display().to_string()
} else {
path.file_name()
.expect("Failed to read file name")
.to_str()
.expect("Failed to print file name")
.to_string()
get_file_name(&path)
};

let description = parse_description_for_plugin(&path);
Expand All @@ -94,7 +131,7 @@ fn format_print_description(
/// paths yielded from plugin::find_all(), as well as that the file names are in valid
/// unicode format since file names should be prefixed with `forc-`. Should one of these 2
/// assumptions fail, this function panics.
fn print_plugin(path: PathBuf, print_full_path: bool, describe: bool) -> ForcResult<String> {
fn get_plugin_info(path: PathBuf, print_full_path: bool, describe: bool) -> ForcResult<String> {
format_print_description(path, print_full_path, describe)
.map_err(|e| anyhow!("Could not get plugin info: {}", e.as_ref()).into())
}
2 changes: 1 addition & 1 deletion forc/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ pub async fn run_cli() -> ForcResult<()> {
Forc::ContractId(command) => contract_id::exec(command),
Forc::PredicateRoot(command) => predicate_root::exec(command),
Forc::Plugin(args) => {
let output = plugin::execute_external_subcommand(args)?;
let output = plugin::execute_external_subcommand(args, opt.silent)?;
let code = output
.status
.code()
Expand Down
18 changes: 17 additions & 1 deletion forc/src/cli/plugin.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Items related to plugin support for `forc`.
use anyhow::{bail, Result};
use forc_tracing::println_warning;
use std::{
env, fs,
path::{Path, PathBuf},
Expand All @@ -14,14 +15,29 @@ use std::{
///
/// E.g. given `foo bar baz` where `foo` is an unrecognized subcommand to `forc`, tries to execute
/// `forc-foo bar baz`.
pub(crate) fn execute_external_subcommand(args: Vec<String>) -> Result<process::Output> {
pub(crate) fn execute_external_subcommand(
args: Vec<String>,
silent: bool,
) -> Result<process::Output> {
let cmd = args.get(0).expect("`args` must not be empty");
let args = &args[1..];
let path = find_external_subcommand(cmd);
let command = match path {
Some(command) => command,
None => bail!("no such subcommand: `{}`", cmd),
};

if let Ok(forc_path) = std::env::current_exe() {
if !silent && command.parent() != forc_path.parent() {
println_warning(&format!(
"The {} ({}) plugin is in a different directory than forc ({})\n",
cmd,
command.display(),
forc_path.display(),
));
}
}

let output = process::Command::new(command)
.stdin(process::Stdio::inherit())
.stdout(process::Stdio::inherit())
Expand Down

0 comments on commit caa1822

Please sign in to comment.