[Updated] D8612: rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
acezar (Antoine Cezar)
phabricator at mercurial-scm.org
Wed Jun 24 13:05:42 UTC 2020
acezar edited the summary of this revision.
acezar updated this revision to Diff 21697.
REPOSITORY
rHG Mercurial
CHANGES SINCE LAST UPDATE
https://phab.mercurial-scm.org/D8612?vs=21657&id=21697
BRANCH
default
CHANGES SINCE LAST ACTION
https://phab.mercurial-scm.org/D8612/new/
REVISION DETAIL
https://phab.mercurial-scm.org/D8612
AFFECTED FILES
rust/Cargo.lock
rust/rhg/Cargo.toml
rust/rhg/src/commands.rs
rust/rhg/src/commands/root.rs
rust/rhg/src/error.rs
rust/rhg/src/exitcode.rs
rust/rhg/src/main.rs
rust/rhg/src/ui.rs
CHANGE DETAILS
diff --git a/rust/rhg/src/ui.rs b/rust/rhg/src/ui.rs
new file mode 100644
--- /dev/null
+++ b/rust/rhg/src/ui.rs
@@ -0,0 +1,54 @@
+use std::io;
+use std::io::Write;
+
+pub struct Ui {}
+
+/// The kind of user interface error
+pub enum UiError {
+ /// The standard output stream cannot be written to
+ StdoutError(io::Error),
+ /// The standard error stream cannot be written to
+ StderrError(io::Error),
+}
+
+/// The commandline user interface
+impl Ui {
+ pub fn new() -> Self {
+ Ui {}
+ }
+
+ /// Write bytes to stdout
+ pub fn write_stdout(&self, bytes: &[u8]) -> Result<(), UiError> {
+ let mut stdout = io::stdout();
+
+ self.write_stream(&mut stdout, bytes)
+ .or_else(|e| self.into_stdout_error(e))?;
+
+ stdout.flush().or_else(|e| self.into_stdout_error(e))
+ }
+
+ fn into_stdout_error(&self, error: io::Error) -> Result<(), UiError> {
+ self.write_stderr(
+ &[b"abort: ", error.to_string().as_bytes(), b"\n"].concat(),
+ )?;
+ Err(UiError::StdoutError(error))
+ }
+
+ /// Write bytes to stderr
+ pub fn write_stderr(&self, bytes: &[u8]) -> Result<(), UiError> {
+ let mut stderr = io::stderr();
+
+ self.write_stream(&mut stderr, bytes)
+ .or_else(|e| Err(UiError::StderrError(e)))?;
+
+ stderr.flush().or_else(|e| Err(UiError::StderrError(e)))
+ }
+
+ fn write_stream(
+ &self,
+ stream: &mut impl Write,
+ bytes: &[u8],
+ ) -> Result<(), io::Error> {
+ stream.write_all(bytes)
+ }
+}
diff --git a/rust/rhg/src/main.rs b/rust/rhg/src/main.rs
--- a/rust/rhg/src/main.rs
+++ b/rust/rhg/src/main.rs
@@ -1,6 +1,7 @@
mod commands;
mod error;
mod exitcode;
+mod ui;
fn main() {
std::process::exit(exitcode::UNIMPLEMENTED_COMMAND)
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;
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,3 +1,60 @@
+use crate::exitcode;
+use crate::ui::UiError;
+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,
+ /// The current directory cannot be found
+ CurrentDirNotFound,
+ /// The standard output stream cannot be written to
+ StdoutError,
+ /// The standard error stream cannot be written to
+ StderrError,
+}
+
+impl CommandErrorKind {
+ pub fn get_exit_code(&self) -> exitcode::ExitCode {
+ match self {
+ CommandErrorKind::Ok => exitcode::OK,
+ CommandErrorKind::RootNotFound => exitcode::ABORT,
+ CommandErrorKind::CurrentDirNotFound => exitcode::ABORT,
+ CommandErrorKind::StdoutError => exitcode::ABORT,
+ CommandErrorKind::StderrError => exitcode::ABORT,
+ }
+ }
+}
+
/// The error type for the Command trait
#[derive(Debug, PartialEq)]
-pub struct CommandError {}
+pub struct CommandError {
+ pub kind: CommandErrorKind,
+}
+
+impl CommandError {
+ /// Exist the process with the corresponding exit code.
+ pub fn exit(&self) -> () {
+ std::process::exit(self.kind.get_exit_code())
+ }
+}
+
+impl From<CommandErrorKind> for CommandError {
+ fn from(kind: CommandErrorKind) -> Self {
+ CommandError { kind }
+ }
+}
+
+impl From<UiError> for CommandError {
+ fn from(error: UiError) -> Self {
+ CommandError {
+ kind: match error {
+ UiError::StdoutError(_) => CommandErrorKind::StdoutError,
+ UiError::StderrError(_) => CommandErrorKind::StderrError,
+ },
+ }
+ }
+}
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,76 @@
+use crate::commands::Command;
+use crate::error::{CommandError, CommandErrorKind};
+use crate::ui::Ui;
+use hg::operations::{FindRoot, FindRootError, FindRootErrorKind, Operation};
+use hg::utils::files::get_bytes_from_path;
+use std::path::PathBuf;
+
+pub const HELP_TEXT: &str = "
+Print the root directory of the current repository.
+
+Returns 0 on success.
+";
+
+pub struct RootCommand {
+ ui: Ui,
+}
+
+impl RootCommand {
+ pub fn new() -> Self {
+ RootCommand { ui: Ui::new() }
+ }
+
+ fn display_found_path(
+ &self,
+ path_buf: PathBuf,
+ ) -> Result<(), CommandError> {
+ let bytes = get_bytes_from_path(path_buf);
+
+ // TODO use formating macro
+ self.ui.write_stdout(&[bytes.as_slice(), b"\n"].concat())?;
+
+ Err(CommandErrorKind::Ok.into())
+ }
+
+ fn display_error(&self, error: FindRootError) -> Result<(), CommandError> {
+ match error.kind {
+ FindRootErrorKind::RootNotFound(path) => {
+ let bytes = get_bytes_from_path(path);
+
+ // TODO use formating macro
+ self.ui.write_stderr(
+ &[
+ b"abort: no repository found in '",
+ bytes.as_slice(),
+ b"' (.hg not found)!\n",
+ ]
+ .concat(),
+ )?;
+
+ Err(CommandErrorKind::RootNotFound.into())
+ }
+ FindRootErrorKind::GetCurrentDirError(e) => {
+ // TODO use formating macro
+ self.ui.write_stderr(
+ &[
+ b"abort: error getting current working directory: ",
+ e.to_string().as_bytes(),
+ b"\n",
+ ]
+ .concat(),
+ )?;
+
+ Err(CommandErrorKind::CurrentDirNotFound.into())
+ }
+ }
+ }
+}
+
+impl Command for RootCommand {
+ fn run(&self) -> Result<(), CommandError> {
+ match FindRoot::new().run() {
+ Ok(path_buf) => self.display_found_path(path_buf),
+ Err(e) => self.display_error(e),
+ }
+ }
+}
diff --git a/rust/rhg/src/commands.rs b/rust/rhg/src/commands.rs
--- a/rust/rhg/src/commands.rs
+++ b/rust/rhg/src/commands.rs
@@ -1,3 +1,4 @@
+pub mod root;
use crate::error::CommandError;
/// The common trait for rhg commands
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/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"
To: acezar, #hg-reviewers, marmoute, Alphare
Cc: Alphare, marmoute, mercurial-patches
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mercurial-scm.org/pipermail/mercurial-patches/attachments/20200624/4c164b80/attachment-0002.html>
More information about the Mercurial-patches
mailing list