Show More
@@ -0,0 +1,99 b'' | |||||
|
1 | use crate::commands::Command; | |||
|
2 | use crate::error::{CommandError, CommandErrorKind}; | |||
|
3 | use crate::ui::utf8_to_local; | |||
|
4 | use crate::ui::Ui; | |||
|
5 | use hg::operations::FindRoot; | |||
|
6 | use hg::operations::{CatRev, CatRevError, CatRevErrorKind}; | |||
|
7 | use hg::utils::hg_path::HgPathBuf; | |||
|
8 | use micro_timer::timed; | |||
|
9 | use std::convert::TryFrom; | |||
|
10 | ||||
|
11 | pub const HELP_TEXT: &str = " | |||
|
12 | Output the current or given revision of files | |||
|
13 | "; | |||
|
14 | ||||
|
15 | pub struct CatCommand<'a> { | |||
|
16 | rev: Option<&'a str>, | |||
|
17 | files: Vec<&'a str>, | |||
|
18 | } | |||
|
19 | ||||
|
20 | impl<'a> CatCommand<'a> { | |||
|
21 | pub fn new(rev: Option<&'a str>, files: Vec<&'a str>) -> Self { | |||
|
22 | Self { rev, files } | |||
|
23 | } | |||
|
24 | ||||
|
25 | fn display(&self, ui: &Ui, data: &[u8]) -> Result<(), CommandError> { | |||
|
26 | ui.write_stdout(data)?; | |||
|
27 | Ok(()) | |||
|
28 | } | |||
|
29 | } | |||
|
30 | ||||
|
31 | impl<'a> Command for CatCommand<'a> { | |||
|
32 | #[timed] | |||
|
33 | fn run(&self, ui: &Ui) -> Result<(), CommandError> { | |||
|
34 | let root = FindRoot::new().run()?; | |||
|
35 | let cwd = std::env::current_dir() | |||
|
36 | .or_else(|e| Err(CommandErrorKind::CurrentDirNotFound(e)))?; | |||
|
37 | ||||
|
38 | let mut files = vec![]; | |||
|
39 | for file in self.files.iter() { | |||
|
40 | let normalized = cwd.join(&file); | |||
|
41 | let stripped = normalized | |||
|
42 | .strip_prefix(&root) | |||
|
43 | .map_err(|_| CommandErrorKind::Abort(None))?; | |||
|
44 | let hg_file = HgPathBuf::try_from(stripped.to_path_buf()) | |||
|
45 | .map_err(|_| CommandErrorKind::Abort(None))?; | |||
|
46 | files.push(hg_file); | |||
|
47 | } | |||
|
48 | ||||
|
49 | match self.rev { | |||
|
50 | Some(rev) => { | |||
|
51 | let mut operation = CatRev::new(&root, rev, &files) | |||
|
52 | .map_err(|e| map_rev_error(rev, e))?; | |||
|
53 | let data = | |||
|
54 | operation.run().map_err(|e| map_rev_error(rev, e))?; | |||
|
55 | self.display(ui, &data) | |||
|
56 | } | |||
|
57 | None => Err(CommandErrorKind::Unimplemented.into()), | |||
|
58 | } | |||
|
59 | } | |||
|
60 | } | |||
|
61 | ||||
|
62 | /// Convert `CatRevErrorKind` to `CommandError` | |||
|
63 | fn map_rev_error(rev: &str, err: CatRevError) -> CommandError { | |||
|
64 | CommandError { | |||
|
65 | kind: match err.kind { | |||
|
66 | CatRevErrorKind::IoError(err) => CommandErrorKind::Abort(Some( | |||
|
67 | utf8_to_local(&format!("abort: {}\n", err)).into(), | |||
|
68 | )), | |||
|
69 | CatRevErrorKind::InvalidRevision => CommandErrorKind::Abort(Some( | |||
|
70 | utf8_to_local(&format!( | |||
|
71 | "abort: invalid revision identifier{}\n", | |||
|
72 | rev | |||
|
73 | )) | |||
|
74 | .into(), | |||
|
75 | )), | |||
|
76 | CatRevErrorKind::UnsuportedRevlogVersion(version) => { | |||
|
77 | CommandErrorKind::Abort(Some( | |||
|
78 | utf8_to_local(&format!( | |||
|
79 | "abort: unsupported revlog version {}\n", | |||
|
80 | version | |||
|
81 | )) | |||
|
82 | .into(), | |||
|
83 | )) | |||
|
84 | } | |||
|
85 | CatRevErrorKind::CorruptedRevlog => CommandErrorKind::Abort(Some( | |||
|
86 | "abort: corrupted revlog\n".into(), | |||
|
87 | )), | |||
|
88 | CatRevErrorKind::UnknowRevlogDataFormat(format) => { | |||
|
89 | CommandErrorKind::Abort(Some( | |||
|
90 | utf8_to_local(&format!( | |||
|
91 | "abort: unknow revlog dataformat {:?}\n", | |||
|
92 | format | |||
|
93 | )) | |||
|
94 | .into(), | |||
|
95 | )) | |||
|
96 | } | |||
|
97 | }, | |||
|
98 | } | |||
|
99 | } |
@@ -1,3 +1,4 b'' | |||||
|
1 | pub mod cat; | |||
1 | pub mod debugdata; |
|
2 | pub mod debugdata; | |
2 | pub mod files; |
|
3 | pub mod files; | |
3 | pub mod root; |
|
4 | pub mod root; |
@@ -18,6 +18,8 b' pub enum CommandErrorKind {' | |||||
18 | StderrError, |
|
18 | StderrError, | |
19 | /// The command aborted |
|
19 | /// The command aborted | |
20 | Abort(Option<Vec<u8>>), |
|
20 | Abort(Option<Vec<u8>>), | |
|
21 | /// A mercurial capability as not been implemented. | |||
|
22 | Unimplemented, | |||
21 | } |
|
23 | } | |
22 |
|
24 | |||
23 | impl CommandErrorKind { |
|
25 | impl CommandErrorKind { | |
@@ -28,6 +30,7 b' impl CommandErrorKind {' | |||||
28 | CommandErrorKind::StdoutError => exitcode::ABORT, |
|
30 | CommandErrorKind::StdoutError => exitcode::ABORT, | |
29 | CommandErrorKind::StderrError => exitcode::ABORT, |
|
31 | CommandErrorKind::StderrError => exitcode::ABORT, | |
30 | CommandErrorKind::Abort(_) => exitcode::ABORT, |
|
32 | CommandErrorKind::Abort(_) => exitcode::ABORT, | |
|
33 | CommandErrorKind::Unimplemented => exitcode::UNIMPLEMENTED_COMMAND, | |||
31 | } |
|
34 | } | |
32 | } |
|
35 | } | |
33 |
|
36 |
@@ -38,6 +38,26 b' fn main() {' | |||||
38 | .about(commands::files::HELP_TEXT), |
|
38 | .about(commands::files::HELP_TEXT), | |
39 | ) |
|
39 | ) | |
40 | .subcommand( |
|
40 | .subcommand( | |
|
41 | SubCommand::with_name("cat") | |||
|
42 | .arg( | |||
|
43 | Arg::with_name("rev") | |||
|
44 | .help("search the repository as it is in REV") | |||
|
45 | .short("-r") | |||
|
46 | .long("--revision") | |||
|
47 | .value_name("REV") | |||
|
48 | .takes_value(true), | |||
|
49 | ) | |||
|
50 | .arg( | |||
|
51 | clap::Arg::with_name("files") | |||
|
52 | .required(true) | |||
|
53 | .multiple(true) | |||
|
54 | .empty_values(false) | |||
|
55 | .value_name("FILE") | |||
|
56 | .help("Activity to start: activity@category"), | |||
|
57 | ) | |||
|
58 | .about(commands::cat::HELP_TEXT), | |||
|
59 | ) | |||
|
60 | .subcommand( | |||
41 | SubCommand::with_name("debugdata") |
|
61 | SubCommand::with_name("debugdata") | |
42 | .about(commands::debugdata::HELP_TEXT) |
|
62 | .about(commands::debugdata::HELP_TEXT) | |
43 | .arg( |
|
63 | .arg( | |
@@ -98,6 +118,9 b' fn match_subcommand(' | |||||
98 | ("files", Some(matches)) => { |
|
118 | ("files", Some(matches)) => { | |
99 | commands::files::FilesCommand::try_from(matches)?.run(&ui) |
|
119 | commands::files::FilesCommand::try_from(matches)?.run(&ui) | |
100 | } |
|
120 | } | |
|
121 | ("cat", Some(matches)) => { | |||
|
122 | commands::cat::CatCommand::try_from(matches)?.run(&ui) | |||
|
123 | } | |||
101 | ("debugdata", Some(matches)) => { |
|
124 | ("debugdata", Some(matches)) => { | |
102 | commands::debugdata::DebugDataCommand::try_from(matches)?.run(&ui) |
|
125 | commands::debugdata::DebugDataCommand::try_from(matches)?.run(&ui) | |
103 | } |
|
126 | } | |
@@ -114,6 +137,19 b" impl<'a> TryFrom<&'a ArgMatches<'_>> for" | |||||
114 | } |
|
137 | } | |
115 | } |
|
138 | } | |
116 |
|
139 | |||
|
140 | impl<'a> TryFrom<&'a ArgMatches<'_>> for commands::cat::CatCommand<'a> { | |||
|
141 | type Error = CommandError; | |||
|
142 | ||||
|
143 | fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> { | |||
|
144 | let rev = args.value_of("rev"); | |||
|
145 | let files = match args.values_of("files") { | |||
|
146 | Some(files) => files.collect(), | |||
|
147 | None => vec![], | |||
|
148 | }; | |||
|
149 | Ok(commands::cat::CatCommand::new(rev, files)) | |||
|
150 | } | |||
|
151 | } | |||
|
152 | ||||
117 | impl<'a> TryFrom<&'a ArgMatches<'_>> |
|
153 | impl<'a> TryFrom<&'a ArgMatches<'_>> | |
118 | for commands::debugdata::DebugDataCommand<'a> |
|
154 | for commands::debugdata::DebugDataCommand<'a> | |
119 | { |
|
155 | { |
General Comments 0
You need to be logged in to leave comments.
Login now