Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions cli/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ pub mod ls_files;
pub mod ls_tree;
pub mod meva_command;
pub mod plugins;
pub mod pull;
pub mod push;
pub mod remote;
pub mod restore;
pub mod show;
Expand All @@ -30,6 +32,8 @@ pub use log::LogCommand;
pub use ls_files::LsFilesCommand;
pub use ls_tree::LsTreeCommand;
pub use plugins::PluginsCommand;
pub use pull::PullCommand;
pub use push::PushCommand;
pub use remote::RemoteCommand;
pub use restore::RestoreCommand;
pub use show::ShowCommand;
Expand All @@ -41,6 +45,7 @@ use miette::{Context, Result};
use engine::engine_container::MevaContainer;
pub use meva_command::MevaCommand;

/// Executes the appropriate subcommand based on the provided matches.
pub async fn execute_multiple(
matches: &ArgMatches,
container: &MevaContainer,
Expand All @@ -57,3 +62,31 @@ pub async fn execute_multiple(

Ok(())
}

/// Collection type for Meva commands.
pub type CommandsCollection = Vec<Box<dyn MevaCommand<Container = MevaContainer>>>;

/// Collects all available Meva commands into a single collection.
pub fn collect_commands() -> CommandsCollection {
vec![
Box::new(InitCommand),
Box::new(ConfigCommand),
Box::new(IgnoreCommand),
Box::new(PluginsCommand),
Box::new(AddCommand),
Box::new(LsFilesCommand),
Box::new(ShowCommand),
Box::new(StatusCommand),
Box::new(CommitCommand),
Box::new(DiffCommand),
Box::new(LsTreeCommand),
Box::new(LogCommand),
Box::new(RestoreCommand),
Box::new(CloneCommand),
Box::new(RemoteCommand),
Box::new(FetchCommand),
Box::new(BranchCommand),
Box::new(PushCommand),
Box::new(PullCommand),
]
}
17 changes: 4 additions & 13 deletions cli/src/commands/clone.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::commands::MevaCommand;
use crate::{commands::MevaCommand, extensions::WithVerbose};
use async_trait::async_trait;
use clap::{Arg, ArgAction, ArgMatches, Command, ValueHint};
use clap::{Arg, ArgMatches, Command, ValueHint};
use engine::{EngineContainer, engine_container::MevaContainer, handlers::clone::Request};
use miette::{IntoDiagnostic, Result};
use std::path::PathBuf;
Expand All @@ -26,9 +26,6 @@ impl CloneCommand {

/// Argument name for specifying the server public key.
const ARG_SERVER_KEY: &'static str = "server-key";

/// Argument name for the quiet flag.
const ARG_QUIET: &'static str = "quiet";
}

#[async_trait]
Expand All @@ -50,6 +47,7 @@ impl MevaCommand for CloneCommand {
/// Builds the CLI argument parser for the `clone` command using `clap`.
fn build_command(&self) -> Command {
self.build_base_command()
.with_verbose_arg("Enable verbose output")
.arg(
Arg::new(Self::ARG_REPOSITORY)
.value_name("REPOSITORY")
Expand Down Expand Up @@ -82,13 +80,6 @@ impl MevaCommand for CloneCommand {
.value_parser(clap::value_parser!(PathBuf))
.help("Path to server's public key"),
)
.arg(
Arg::new(Self::ARG_QUIET)
.long(Self::ARG_QUIET)
.short('q')
.action(ArgAction::SetTrue)
.help("Suppress non-error output"),
)
}

/// Executes the `clone` command.
Expand All @@ -107,7 +98,7 @@ impl MevaCommand for CloneCommand {
.get_one::<PathBuf>(Self::ARG_SERVER_KEY)
.unwrap()
.clone(),
quiet: matches.get_flag(Self::ARG_QUIET),
quiet: !matches.get_flag(Command::ARG_VERBOSE),
};

let handler = container.clone_handler().into_diagnostic()?;
Expand Down
2 changes: 1 addition & 1 deletion cli/src/commands/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ impl MevaCommand for FetchCommand {
};

let handler = container.fetch_handler().into_diagnostic()?;
let _response = handler.handle_fetch(request).await.into_diagnostic()?;
let _ = handler.handle_fetch(request).await.into_diagnostic()?;

Ok(())
}
Expand Down
85 changes: 85 additions & 0 deletions cli/src/commands/pull.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
use async_trait::async_trait;
use clap::{Arg, ArgMatches, Command};
use miette::Result;

use engine::engine_container::MevaContainer;

use crate::{commands::MevaCommand, extensions::WithVerbose};

/// Implements the `pull` command for Meva DVCS.
#[derive(Default)]
pub struct PullCommand;

impl PullCommand {
const ARG_ORIGIN: &'static str = "origin";

const ARG_BRANCH: &'static str = "branch";
}

#[async_trait]
impl MevaCommand for PullCommand {
type Container = MevaContainer;

fn name(&self) -> &'static str {
"pull"
}

fn about(&self) -> &'static str {
"Fetch and integrate the latest changes from the remote repository into your local branch"
}

fn version(&self) -> &'static str {
"1.0.0"
}

/// Builds the CLI argument parser for the `pull` command.
fn build_command(&self) -> Command {
self.build_base_command()
.with_verbose_arg("Enable verbose output when pulling from remote server")
.arg(
Arg::new(Self::ARG_ORIGIN)
.value_name("ORIGIN")
.index(1)
.required(false)
.default_value("origin")
Comment thread
adamgracikowski marked this conversation as resolved.
.help("Name of the remote repository to pull from"),
)
.arg(
Arg::new(Self::ARG_BRANCH)
.value_name("BRANCH")
.index(2)
.required(false)
.help("Name of the branch to pull from"),
)
}

/// Executes the `pull` command.
///
/// # Arguments
/// * `matches`: Parsed command-line arguments.
/// * `container`: Dependency injection container.
///
/// # Returns
/// * `Result<()>`: Success or error during execution.
async fn execute(&self, _matches: &ArgMatches, _container: &Self::Container) -> Result<()> {
Ok(())
Comment thread
adamgracikowski marked this conversation as resolved.
}
}

#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use rstest::rstest;

#[rstest]
fn test_command_name_about_version() {
let cmd = PullCommand;
assert_eq!(cmd.name(), "pull");
assert_eq!(
cmd.about(),
"Fetch and integrate the latest changes from the remote repository into your local branch"
);
assert_eq!(cmd.version(), "1.0.0");
}
}
120 changes: 120 additions & 0 deletions cli/src/commands/push.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use async_trait::async_trait;
use clap::{Arg, ArgAction, ArgMatches, Command};
use miette::{IntoDiagnostic, Result};

use engine::{EngineContainer, engine_container::MevaContainer, handlers::push::Request};

use crate::{commands::MevaCommand, extensions::WithVerbose};

/// Implements the `push` command for Meva DVCS.
///
/// This command pushes local commits to a remote repository.
/// It supports pushing specific branches or all local branches
/// Deletion of remote branches is also supported.
#[derive(Default)]
pub struct PushCommand;

impl PushCommand {
const ARG_ORIGIN: &'static str = "origin";

const ARG_BRANCH: &'static str = "branch";

const ARG_ALL: &'static str = "all";

const ARG_DELETE: &'static str = "delete";
}

#[async_trait]
impl MevaCommand for PushCommand {
type Container = MevaContainer;

fn name(&self) -> &'static str {
"push"
}

fn about(&self) -> &'static str {
"Push local commits to a remote repository"
}

fn version(&self) -> &'static str {
"1.0.0"
}

/// Builds the CLI argument parser for the `push` command.
fn build_command(&self) -> Command {
self.build_base_command()
.with_verbose_arg("Enable verbose output when pushing to remote server")
.arg(
Arg::new(Self::ARG_ORIGIN)
.value_name("ORIGIN")
.index(1)
.required(false)
.default_value("origin")
Comment thread
adamgracikowski marked this conversation as resolved.
.help("Name of the remote repository to push to"),
)
.arg(
Arg::new(Self::ARG_BRANCH)
.value_name("BRANCH")
.index(2)
.required(false)
.help("Name of the branch to push to"),
)
.arg(
Arg::new(Self::ARG_ALL)
.long(Self::ARG_ALL)
.short('a')
.help("Push all local branches to the specified remote")
.action(ArgAction::SetTrue)
.conflicts_with_all([Self::ARG_BRANCH, Self::ARG_DELETE]),
)
.arg(
Arg::new(Self::ARG_DELETE)
.long(Self::ARG_DELETE)
.short('d')
.help("Delete the given remote branch.")
.action(ArgAction::SetTrue)
.requires(Self::ARG_BRANCH),
)
}

/// Executes the `push` command.
///
/// # Arguments
/// * `matches`: Parsed command-line arguments.
/// * `container`: Dependency injection container.
///
/// # Returns
/// * `Result<()>`: Success or error during execution.
async fn execute(&self, matches: &ArgMatches, container: &Self::Container) -> Result<()> {
let request = Request {
origin: matches.get_one::<String>(Self::ARG_ORIGIN).unwrap().clone(),
branch: matches.get_one::<String>(Self::ARG_BRANCH).cloned(),
all: matches.get_flag(Self::ARG_ALL),
delete: matches.get_flag(Self::ARG_DELETE),
verbose: matches.get_flag(Command::ARG_VERBOSE),
};

let handler = container.push_handler().into_diagnostic()?;

let response = handler.handle_push(request).await.into_diagnostic()?;

println!();
println!("{response}");
Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use rstest::rstest;

#[rstest]
fn test_command_name_about_version() {
let cmd = PushCommand;
assert_eq!(cmd.name(), "push");
assert_eq!(cmd.about(), "Push local commits to a remote repository");
assert_eq!(cmd.version(), "1.0.0");
}
}
26 changes: 9 additions & 17 deletions cli/src/commands/remote/subcommands/add.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::path::PathBuf;

use async_trait::async_trait;
use clap::{Arg, ArgAction, ArgMatches, Command, ValueHint};
use clap::{Arg, ArgMatches, Command, ValueHint};
use engine::{
EngineContainer,
engine_container::MevaContainer,
Expand All @@ -20,9 +20,6 @@ use crate::{commands::MevaCommand, extensions::WithName};
pub struct RemoteAddCommand;

impl RemoteAddCommand {
/// Argument name for the fetch flag.
const ARG_FETCH: &'static str = "fetch";

/// Argument name for the remote URL.
const ARG_URL: &'static str = "url";

Expand Down Expand Up @@ -67,13 +64,6 @@ impl MevaCommand for RemoteAddCommand {
.value_parser(clap::value_parser!(PathBuf))
.help("Path to server's public key"),
)
.arg(
Arg::new(Self::ARG_FETCH)
.short('f')
.long(Self::ARG_FETCH)
.action(ArgAction::SetTrue)
.help("Fetch remote refs immediately after adding"),
)
}

/// Executes the `remote add` command.
Expand All @@ -85,23 +75,25 @@ impl MevaCommand for RemoteAddCommand {
matches: &ArgMatches,
container: &Self::Container,
) -> miette::Result<()> {
let name = matches
.get_one::<String>(Command::ARG_NAME)
.unwrap()
.to_string();

let request = AddRequest {
name: matches
.get_one::<String>(Command::ARG_NAME)
.unwrap()
.to_string(),
name: name.clone(),
url: matches.get_one::<Url>(Self::ARG_URL).unwrap().clone(),
pub_key: matches
.get_one::<PathBuf>(Self::ARG_SERVER_KEY)
.unwrap()
.clone(),
fetch: matches.get_flag(Self::ARG_FETCH),
};

let handler = container.remote_handler().into_diagnostic()?;

let _response = handler.add(request).into_diagnostic()?;
let response = handler.add(request).into_diagnostic()?;

println!("{}", response.remote.display_verbose(&name));
Ok(())
}
}
Expand Down
Loading