##// END OF EJS Templates
rhg: add a limited `rhg cat -r` subcommand...
Antoine Cezar -
r46113:33ded2d3 default
parent child Browse files
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