mirror of https://github.com/chipsenkbeil/distant
Refactor a lot of commands -- need to update tests
parent
abac61a707
commit
6c72f4a577
@ -1,106 +0,0 @@
|
||||
use crate::{data::Cmd, DistantMsg, DistantRequestData};
|
||||
use clap::{
|
||||
error::{Error, ErrorKind},
|
||||
Arg, ArgAction, ArgMatches, Args, Command, FromArgMatches, Subcommand,
|
||||
};
|
||||
|
||||
impl FromArgMatches for Cmd {
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> {
|
||||
let mut matches = matches.clone();
|
||||
Self::from_arg_matches_mut(&mut matches)
|
||||
}
|
||||
fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> {
|
||||
let cmd = matches.get_one::<String>("cmd").ok_or_else(|| {
|
||||
Error::raw(
|
||||
ErrorKind::MissingRequiredArgument,
|
||||
"program must be specified",
|
||||
)
|
||||
})?;
|
||||
let args: Vec<String> = matches
|
||||
.get_many::<String>("arg")
|
||||
.unwrap_or_default()
|
||||
.map(ToString::to_string)
|
||||
.collect();
|
||||
Ok(Self::new(format!("{cmd} {}", args.join(" "))))
|
||||
}
|
||||
fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
|
||||
let mut matches = matches.clone();
|
||||
self.update_from_arg_matches_mut(&mut matches)
|
||||
}
|
||||
fn update_from_arg_matches_mut(&mut self, _matches: &mut ArgMatches) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Args for Cmd {
|
||||
fn augment_args(cmd: Command) -> Command {
|
||||
cmd.arg(
|
||||
Arg::new("cmd")
|
||||
.required(true)
|
||||
.value_name("CMD")
|
||||
.action(ArgAction::Set),
|
||||
)
|
||||
.trailing_var_arg(true)
|
||||
.arg(
|
||||
Arg::new("arg")
|
||||
.value_name("ARGS")
|
||||
.num_args(1..)
|
||||
.action(ArgAction::Append),
|
||||
)
|
||||
}
|
||||
fn augment_args_for_update(cmd: Command) -> Command {
|
||||
cmd
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArgMatches for DistantMsg<DistantRequestData> {
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> {
|
||||
match matches.subcommand() {
|
||||
Some(("single", args)) => Ok(Self::Single(DistantRequestData::from_arg_matches(args)?)),
|
||||
Some((_, _)) => Err(Error::raw(
|
||||
ErrorKind::InvalidSubcommand,
|
||||
"Valid subcommand is `single`",
|
||||
)),
|
||||
None => Err(Error::raw(
|
||||
ErrorKind::MissingSubcommand,
|
||||
"Valid subcommand is `single`",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
|
||||
match matches.subcommand() {
|
||||
Some(("single", args)) => {
|
||||
*self = Self::Single(DistantRequestData::from_arg_matches(args)?)
|
||||
}
|
||||
Some((_, _)) => {
|
||||
return Err(Error::raw(
|
||||
ErrorKind::InvalidSubcommand,
|
||||
"Valid subcommand is `single`",
|
||||
))
|
||||
}
|
||||
None => (),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Subcommand for DistantMsg<DistantRequestData> {
|
||||
fn augment_subcommands(cmd: Command) -> Command {
|
||||
cmd.subcommand(DistantRequestData::augment_subcommands(Command::new(
|
||||
"single",
|
||||
)))
|
||||
.subcommand_required(true)
|
||||
}
|
||||
|
||||
fn augment_subcommands_for_update(cmd: Command) -> Command {
|
||||
cmd.subcommand(DistantRequestData::augment_subcommands(Command::new(
|
||||
"single",
|
||||
)))
|
||||
.subcommand_required(true)
|
||||
}
|
||||
|
||||
fn has_subcommand(name: &str) -> bool {
|
||||
matches!(name, "single")
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,13 @@
|
||||
mod address;
|
||||
mod cmd;
|
||||
mod logging;
|
||||
mod network;
|
||||
mod search;
|
||||
mod value;
|
||||
|
||||
pub use address::*;
|
||||
pub use cmd::*;
|
||||
pub use logging::*;
|
||||
pub use network::*;
|
||||
pub use search::*;
|
||||
pub use value::*;
|
||||
|
@ -0,0 +1,101 @@
|
||||
use clap::error::{Error, ErrorKind};
|
||||
use clap::{Arg, ArgAction, ArgMatches, Args, Command, FromArgMatches};
|
||||
use derive_more::{Display, From, Into};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
/// Represents some command with arguments to execute
|
||||
#[derive(Clone, Debug, Display, From, Into, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Cmd(String);
|
||||
|
||||
impl Cmd {
|
||||
/// Creates a new command from the given `cmd`
|
||||
pub fn new(cmd: impl Into<String>) -> Self {
|
||||
Self(cmd.into())
|
||||
}
|
||||
|
||||
/// Returns reference to the program portion of the command
|
||||
pub fn program(&self) -> &str {
|
||||
match self.0.split_once(' ') {
|
||||
Some((program, _)) => program.trim(),
|
||||
None => self.0.trim(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns reference to the arguments portion of the command
|
||||
pub fn arguments(&self) -> &str {
|
||||
match self.0.split_once(' ') {
|
||||
Some((_, arguments)) => arguments.trim(),
|
||||
None => "",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Cmd {
|
||||
type Target = String;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Cmd {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Cmd {
|
||||
fn from(s: &'a str) -> Self {
|
||||
Self(s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArgMatches for Cmd {
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> {
|
||||
let mut matches = matches.clone();
|
||||
Self::from_arg_matches_mut(&mut matches)
|
||||
}
|
||||
fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> {
|
||||
let cmd = matches.get_one::<String>("cmd").ok_or_else(|| {
|
||||
Error::raw(
|
||||
ErrorKind::MissingRequiredArgument,
|
||||
"program must be specified",
|
||||
)
|
||||
})?;
|
||||
let args: Vec<String> = matches
|
||||
.get_many::<String>("arg")
|
||||
.unwrap_or_default()
|
||||
.map(ToString::to_string)
|
||||
.collect();
|
||||
Ok(Self::new(format!("{cmd} {}", args.join(" "))))
|
||||
}
|
||||
fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
|
||||
let mut matches = matches.clone();
|
||||
self.update_from_arg_matches_mut(&mut matches)
|
||||
}
|
||||
fn update_from_arg_matches_mut(&mut self, _matches: &mut ArgMatches) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Args for Cmd {
|
||||
fn augment_args(cmd: Command) -> Command {
|
||||
cmd.arg(
|
||||
Arg::new("cmd")
|
||||
.required(true)
|
||||
.value_name("CMD")
|
||||
.action(ArgAction::Set),
|
||||
)
|
||||
.trailing_var_arg(true)
|
||||
.arg(
|
||||
Arg::new("arg")
|
||||
.value_name("ARGS")
|
||||
.num_args(1..)
|
||||
.action(ArgAction::Append),
|
||||
)
|
||||
}
|
||||
fn augment_args_for_update(cmd: Command) -> Command {
|
||||
cmd
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
use clap::{Args, ValueEnum};
|
||||
use distant_core::data::FileType;
|
||||
use distant_core::data::{SearchQueryOptions, SearchQueryTarget};
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub use distant_core::data::SearchQueryCondition as CliSearchQueryCondition;
|
||||
|
||||
/// Options to customize the search results.
|
||||
#[derive(Args, Clone, Debug, Default, PartialEq, Eq)]
|
||||
pub struct CliSearchQueryOptions {
|
||||
/// Restrict search to only these file types (otherwise all are allowed)
|
||||
#[clap(skip)]
|
||||
pub allowed_file_types: HashSet<FileType>,
|
||||
|
||||
/// Regex to use to filter paths being searched to only those that match the include condition
|
||||
#[clap(long)]
|
||||
pub include: Option<CliSearchQueryCondition>,
|
||||
|
||||
/// Regex to use to filter paths being searched to only those that do not match the exclude
|
||||
/// condition
|
||||
#[clap(long)]
|
||||
pub exclude: Option<CliSearchQueryCondition>,
|
||||
|
||||
/// Search should follow symbolic links
|
||||
#[clap(long)]
|
||||
pub follow_symbolic_links: bool,
|
||||
|
||||
/// Maximum results to return before stopping the query
|
||||
#[clap(long)]
|
||||
pub limit: Option<u64>,
|
||||
|
||||
/// Maximum depth (directories) to search
|
||||
///
|
||||
/// The smallest depth is 0 and always corresponds to the path given to the new function on
|
||||
/// this type. Its direct descendents have depth 1, and their descendents have depth 2, and so
|
||||
/// on.
|
||||
///
|
||||
/// Note that this will not simply filter the entries of the iterator, but it will actually
|
||||
/// avoid descending into directories when the depth is exceeded.
|
||||
#[clap(long)]
|
||||
pub max_depth: Option<u64>,
|
||||
|
||||
/// Amount of results to batch before sending back excluding final submission that will always
|
||||
/// include the remaining results even if less than pagination request
|
||||
#[clap(long)]
|
||||
pub pagination: Option<u64>,
|
||||
}
|
||||
|
||||
impl From<CliSearchQueryOptions> for SearchQueryOptions {
|
||||
fn from(x: CliSearchQueryOptions) -> Self {
|
||||
Self {
|
||||
allowed_file_types: x.allowed_file_types,
|
||||
include: x.include,
|
||||
exclude: x.exclude,
|
||||
follow_symbolic_links: x.follow_symbolic_links,
|
||||
limit: x.limit,
|
||||
max_depth: x.max_depth,
|
||||
pagination: x.pagination,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Kind of data to examine using conditions
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
|
||||
#[clap(rename_all = "snake_case")]
|
||||
pub enum CliSearchQueryTarget {
|
||||
/// Checks path of file, directory, or symlink
|
||||
Path,
|
||||
|
||||
/// Checks contents of files
|
||||
Contents,
|
||||
}
|
||||
|
||||
impl From<CliSearchQueryTarget> for SearchQueryTarget {
|
||||
fn from(x: CliSearchQueryTarget) -> Self {
|
||||
match x {
|
||||
CliSearchQueryTarget::Contents => Self::Contents,
|
||||
CliSearchQueryTarget::Path => Self::Path,
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ClientActionConfig {
|
||||
pub timeout: Option<f32>,
|
||||
}
|
Loading…
Reference in New Issue