diff --git a/rust/Cargo.lock b/rust/Cargo.lock --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -489,6 +489,9 @@ [[package]] name = "rhg" version = "0.1.0" +dependencies = [ + "hg-core 0.1.0", +] [[package]] name = "rustc_version" diff --git a/rust/rhg/Cargo.toml b/rust/rhg/Cargo.toml --- a/rust/rhg/Cargo.toml +++ b/rust/rhg/Cargo.toml @@ -5,4 +5,5 @@ edition = "2018" [dependencies] +hg-core = { path = "../hg-core"} diff --git a/rust/rhg/src/commands/mod.rs b/rust/rhg/src/commands/mod.rs --- a/rust/rhg/src/commands/mod.rs +++ b/rust/rhg/src/commands/mod.rs @@ -1,3 +1,4 @@ +pub mod root; use crate::error::CommandError; /// The common trait for rhg commands diff --git a/rust/rhg/src/commands/root.rs b/rust/rhg/src/commands/root.rs new file mode 100644 --- /dev/null +++ b/rust/rhg/src/commands/root.rs @@ -0,0 +1,79 @@ +use crate::commands::Command; +use crate::error::{CommandError, CommandErrorKind}; +use hg::operations::{FindRoot, FindRootError, FindRootErrorKind, Operation}; +use hg::utils::files::get_bytes_from_path; +use std::io::Write; +use std::path::PathBuf; + +pub const HELP_TEXT: &str = " +Print the root directory of the current repository. + +Returns 0 on success. +"; + +pub struct RootCommand; + +impl RootCommand { + fn display_found_path(path_buf: PathBuf) -> Result<(), CommandError> { + // TODO use formating macro + let mut stdout = std::io::stdout(); + let bytes = get_bytes_from_path(path_buf); + + stdout + .write_all(&[bytes.as_slice(), b"\n"].concat()) + .expect("Should be able to write to stdout"); + + Err(CommandErrorKind::Ok.into()) + } + + fn display_error(error: FindRootError) -> Result<(), CommandError> { + match error.kind { + FindRootErrorKind::RootNotFound => { + let current_dir = match error.current_dir { + Some(path) => path, + None => panic!("This should not happen"), + }; + + // TODO use formating macro + let mut stderr = std::io::stderr(); + let bytes = get_bytes_from_path(current_dir); + + stderr + .write_all( + &[ + b"abandon : no repository found in ", + bytes.as_slice(), + b" (.hg not found) !\n", + ] + .concat(), + ) + .expect("Should be able to write to stderr"); + } + FindRootErrorKind::GetCurrentDirError => { + // TODO use formating macro + let mut stderr = std::io::stderr(); + + stderr + .write_all( + &concat!( + "Current directory does not exists", + "or permissions are insufficient to get access to it" + ) + .as_bytes(), + ) + .expect("Should be able to write to stderr"); + } + } + Err(CommandErrorKind::RootNotFound.into()) + } +} + +impl Command for RootCommand { + fn run() -> Result<(), CommandError> { + let operation = FindRoot::new(); + match operation.run() { + Ok(path_buf) => RootCommand::display_found_path(path_buf), + Err(e) => RootCommand::display_error(e), + } + } +} diff --git a/rust/rhg/src/error.rs b/rust/rhg/src/error.rs --- a/rust/rhg/src/error.rs +++ b/rust/rhg/src/error.rs @@ -1,4 +1,32 @@ +use crate::exitcode; +use std::convert::From; + +/// The kind of command error +#[derive(Debug, PartialEq)] +pub enum CommandErrorKind { + /// The command finished without error + Ok, + /// The root of the repository cannot be found + RootNotFound, +} + +impl CommandErrorKind { + pub fn get_exit_code(&self) -> exitcode::ExitCode { + match self { + CommandErrorKind::Ok => exitcode::OK, + CommandErrorKind::RootNotFound => exitcode::ABORT, + } + } +} /// The error type for the Command trait #[derive(Debug, PartialEq)] -pub struct CommandError {} +pub struct CommandError { + pub kind: CommandErrorKind, +} + +impl From for CommandError { + fn from(kind: CommandErrorKind) -> Self { + CommandError { kind } + } +} diff --git a/rust/rhg/src/exitcode.rs b/rust/rhg/src/exitcode.rs --- a/rust/rhg/src/exitcode.rs +++ b/rust/rhg/src/exitcode.rs @@ -1,4 +1,10 @@ pub type ExitCode = i32; +/// Successful exit +pub const OK: ExitCode = 0; + +/// Generic abort +pub const ABORT: ExitCode = 255; + /// Command not implemented by rhg pub const UNIMPLEMENTED_COMMAND: ExitCode = 252;