##// END OF EJS Templates
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`...
Antoine Cezar -
r45592:513b3ef2 default
parent child Browse files
Show More
@@ -0,0 +1,76
1 use crate::commands::Command;
2 use crate::error::{CommandError, CommandErrorKind};
3 use crate::ui::Ui;
4 use hg::operations::{FindRoot, FindRootError, FindRootErrorKind, Operation};
5 use hg::utils::files::get_bytes_from_path;
6 use std::path::PathBuf;
7
8 pub const HELP_TEXT: &str = "
9 Print the root directory of the current repository.
10
11 Returns 0 on success.
12 ";
13
14 pub struct RootCommand {
15 ui: Ui,
16 }
17
18 impl RootCommand {
19 pub fn new() -> Self {
20 RootCommand { ui: Ui::new() }
21 }
22
23 fn display_found_path(
24 &self,
25 path_buf: PathBuf,
26 ) -> Result<(), CommandError> {
27 let bytes = get_bytes_from_path(path_buf);
28
29 // TODO use formating macro
30 self.ui.write_stdout(&[bytes.as_slice(), b"\n"].concat())?;
31
32 Err(CommandErrorKind::Ok.into())
33 }
34
35 fn display_error(&self, error: FindRootError) -> Result<(), CommandError> {
36 match error.kind {
37 FindRootErrorKind::RootNotFound(path) => {
38 let bytes = get_bytes_from_path(path);
39
40 // TODO use formating macro
41 self.ui.write_stderr(
42 &[
43 b"abort: no repository found in '",
44 bytes.as_slice(),
45 b"' (.hg not found)!\n",
46 ]
47 .concat(),
48 )?;
49
50 Err(CommandErrorKind::RootNotFound.into())
51 }
52 FindRootErrorKind::GetCurrentDirError(e) => {
53 // TODO use formating macro
54 self.ui.write_stderr(
55 &[
56 b"abort: error getting current working directory: ",
57 e.to_string().as_bytes(),
58 b"\n",
59 ]
60 .concat(),
61 )?;
62
63 Err(CommandErrorKind::CurrentDirNotFound.into())
64 }
65 }
66 }
67 }
68
69 impl Command for RootCommand {
70 fn run(&self) -> Result<(), CommandError> {
71 match FindRoot::new().run() {
72 Ok(path_buf) => self.display_found_path(path_buf),
73 Err(e) => self.display_error(e),
74 }
75 }
76 }
@@ -0,0 +1,54
1 use std::io;
2 use std::io::Write;
3
4 pub struct Ui {}
5
6 /// The kind of user interface error
7 pub enum UiError {
8 /// The standard output stream cannot be written to
9 StdoutError(io::Error),
10 /// The standard error stream cannot be written to
11 StderrError(io::Error),
12 }
13
14 /// The commandline user interface
15 impl Ui {
16 pub fn new() -> Self {
17 Ui {}
18 }
19
20 /// Write bytes to stdout
21 pub fn write_stdout(&self, bytes: &[u8]) -> Result<(), UiError> {
22 let mut stdout = io::stdout();
23
24 self.write_stream(&mut stdout, bytes)
25 .or_else(|e| self.into_stdout_error(e))?;
26
27 stdout.flush().or_else(|e| self.into_stdout_error(e))
28 }
29
30 fn into_stdout_error(&self, error: io::Error) -> Result<(), UiError> {
31 self.write_stderr(
32 &[b"abort: ", error.to_string().as_bytes(), b"\n"].concat(),
33 )?;
34 Err(UiError::StdoutError(error))
35 }
36
37 /// Write bytes to stderr
38 pub fn write_stderr(&self, bytes: &[u8]) -> Result<(), UiError> {
39 let mut stderr = io::stderr();
40
41 self.write_stream(&mut stderr, bytes)
42 .or_else(|e| Err(UiError::StderrError(e)))?;
43
44 stderr.flush().or_else(|e| Err(UiError::StderrError(e)))
45 }
46
47 fn write_stream(
48 &self,
49 stream: &mut impl Write,
50 bytes: &[u8],
51 ) -> Result<(), io::Error> {
52 stream.write_all(bytes)
53 }
54 }
@@ -489,6 +489,9 dependencies = [
489 489 [[package]]
490 490 name = "rhg"
491 491 version = "0.1.0"
492 dependencies = [
493 "hg-core 0.1.0",
494 ]
492 495
493 496 [[package]]
494 497 name = "rustc_version"
@@ -5,4 +5,5 authors = ["Antoine Cezar <antoine.cezar
5 5 edition = "2018"
6 6
7 7 [dependencies]
8 hg-core = { path = "../hg-core"}
8 9
@@ -1,3 +1,4
1 pub mod root;
1 2 use crate::error::CommandError;
2 3
3 4 /// The common trait for rhg commands
@@ -1,3 +1,60
1 use crate::exitcode;
2 use crate::ui::UiError;
3 use std::convert::From;
4
5 /// The kind of command error
6 #[derive(Debug, PartialEq)]
7 pub enum CommandErrorKind {
8 /// The command finished without error
9 Ok,
10 /// The root of the repository cannot be found
11 RootNotFound,
12 /// The current directory cannot be found
13 CurrentDirNotFound,
14 /// The standard output stream cannot be written to
15 StdoutError,
16 /// The standard error stream cannot be written to
17 StderrError,
18 }
19
20 impl CommandErrorKind {
21 pub fn get_exit_code(&self) -> exitcode::ExitCode {
22 match self {
23 CommandErrorKind::Ok => exitcode::OK,
24 CommandErrorKind::RootNotFound => exitcode::ABORT,
25 CommandErrorKind::CurrentDirNotFound => exitcode::ABORT,
26 CommandErrorKind::StdoutError => exitcode::ABORT,
27 CommandErrorKind::StderrError => exitcode::ABORT,
28 }
29 }
30 }
31
1 32 /// The error type for the Command trait
2 33 #[derive(Debug, PartialEq)]
3 pub struct CommandError {}
34 pub struct CommandError {
35 pub kind: CommandErrorKind,
36 }
37
38 impl CommandError {
39 /// Exist the process with the corresponding exit code.
40 pub fn exit(&self) -> () {
41 std::process::exit(self.kind.get_exit_code())
42 }
43 }
44
45 impl From<CommandErrorKind> for CommandError {
46 fn from(kind: CommandErrorKind) -> Self {
47 CommandError { kind }
48 }
49 }
50
51 impl From<UiError> for CommandError {
52 fn from(error: UiError) -> Self {
53 CommandError {
54 kind: match error {
55 UiError::StdoutError(_) => CommandErrorKind::StdoutError,
56 UiError::StderrError(_) => CommandErrorKind::StderrError,
57 },
58 }
59 }
60 }
@@ -1,4 +1,10
1 1 pub type ExitCode = i32;
2 2
3 /// Successful exit
4 pub const OK: ExitCode = 0;
5
6 /// Generic abort
7 pub const ABORT: ExitCode = 255;
8
3 9 /// Command not implemented by rhg
4 10 pub const UNIMPLEMENTED_COMMAND: ExitCode = 252;
@@ -1,6 +1,7
1 1 mod commands;
2 2 mod error;
3 3 mod exitcode;
4 mod ui;
4 5
5 6 fn main() {
6 7 std::process::exit(exitcode::UNIMPLEMENTED_COMMAND)
General Comments 0
You need to be logged in to leave comments. Login now