##// END OF EJS Templates
rhg: add `--revision` argument to `rhg files`...
Antoine Cezar -
r46108:2f8227a1 default
parent child Browse files
Show More
@@ -1,69 +1,136 b''
1 use crate::commands::Command;
1 use crate::commands::Command;
2 use crate::error::{CommandError, CommandErrorKind};
2 use crate::error::{CommandError, CommandErrorKind};
3 use crate::ui::utf8_to_local;
3 use crate::ui::utf8_to_local;
4 use crate::ui::Ui;
4 use crate::ui::Ui;
5 use hg::operations::FindRoot;
5 use hg::operations::FindRoot;
6 use hg::operations::{
6 use hg::operations::{
7 ListDirstateTrackedFiles, ListDirstateTrackedFilesError,
7 ListDirstateTrackedFiles, ListDirstateTrackedFilesError,
8 ListDirstateTrackedFilesErrorKind,
8 ListDirstateTrackedFilesErrorKind,
9 };
9 };
10 use hg::operations::{
11 ListRevTrackedFiles, ListRevTrackedFilesError,
12 ListRevTrackedFilesErrorKind,
13 };
10 use hg::utils::files::{get_bytes_from_path, relativize_path};
14 use hg::utils::files::{get_bytes_from_path, relativize_path};
11 use hg::utils::hg_path::HgPathBuf;
15 use hg::utils::hg_path::{HgPath, HgPathBuf};
16 use std::path::PathBuf;
12
17
13 pub const HELP_TEXT: &str = "
18 pub const HELP_TEXT: &str = "
14 List tracked files.
19 List tracked files.
15
20
16 Returns 0 on success.
21 Returns 0 on success.
17 ";
22 ";
18
23
19 pub struct FilesCommand {}
24 pub struct FilesCommand<'a> {
20
25 rev: Option<&'a str>,
21 impl FilesCommand {
22 pub fn new() -> Self {
23 FilesCommand {}
24 }
25 }
26 }
26
27
27 impl Command for FilesCommand {
28 impl<'a> FilesCommand<'a> {
28 fn run(&self, ui: &Ui) -> Result<(), CommandError> {
29 pub fn new(rev: Option<&'a str>) -> Self {
29 let root = FindRoot::new().run()?;
30 FilesCommand { rev }
30 let mut operation = ListDirstateTrackedFiles::new(&root)
31 }
31 .map_err(map_dirstate_error)?;
32 let files = operation.run().map_err(map_dirstate_error)?;
33
32
33 fn display_files(
34 &self,
35 ui: &Ui,
36 root: &PathBuf,
37 files: impl IntoIterator<Item = &'a HgPath>,
38 ) -> Result<(), CommandError> {
34 let cwd = std::env::current_dir()
39 let cwd = std::env::current_dir()
35 .or_else(|e| Err(CommandErrorKind::CurrentDirNotFound(e)))?;
40 .or_else(|e| Err(CommandErrorKind::CurrentDirNotFound(e)))?;
36 let rooted_cwd = cwd
41 let rooted_cwd = cwd
37 .strip_prefix(&root)
42 .strip_prefix(&root)
38 .expect("cwd was already checked within the repository");
43 .expect("cwd was already checked within the repository");
39 let rooted_cwd = HgPathBuf::from(get_bytes_from_path(rooted_cwd));
44 let rooted_cwd = HgPathBuf::from(get_bytes_from_path(rooted_cwd));
40
45
41 let mut stdout = ui.stdout_buffer();
46 let mut stdout = ui.stdout_buffer();
42
47
43 for file in files {
48 for file in files {
44 stdout.write_all(relativize_path(file, &rooted_cwd).as_ref())?;
49 stdout.write_all(relativize_path(file, &rooted_cwd).as_ref())?;
45 stdout.write_all(b"\n")?;
50 stdout.write_all(b"\n")?;
46 }
51 }
47 stdout.flush()?;
52 stdout.flush()?;
48 Ok(())
53 Ok(())
49 }
54 }
50 }
55 }
51
56
52 /// Convert operation errors to command errors
57 impl<'a> Command for FilesCommand<'a> {
58 fn run(&self, ui: &Ui) -> Result<(), CommandError> {
59 let root = FindRoot::new().run()?;
60 if let Some(rev) = self.rev {
61 let mut operation = ListRevTrackedFiles::new(&root, rev)
62 .map_err(|e| map_rev_error(rev, e))?;
63 let files = operation.run().map_err(|e| map_rev_error(rev, e))?;
64 self.display_files(ui, &root, files)
65 } else {
66 let mut operation = ListDirstateTrackedFiles::new(&root)
67 .map_err(map_dirstate_error)?;
68 let files = operation.run().map_err(map_dirstate_error)?;
69 self.display_files(ui, &root, files)
70 }
71 }
72 }
73
74 /// Convert `ListRevTrackedFilesErrorKind` to `CommandError`
75 fn map_rev_error(rev: &str, err: ListRevTrackedFilesError) -> CommandError {
76 CommandError {
77 kind: match err.kind {
78 ListRevTrackedFilesErrorKind::IoError(err) => {
79 CommandErrorKind::Abort(Some(
80 utf8_to_local(&format!("abort: {}\n", err)).into(),
81 ))
82 }
83 ListRevTrackedFilesErrorKind::InvalidRevision => {
84 CommandErrorKind::Abort(Some(
85 utf8_to_local(&format!(
86 "abort: invalid revision identifier{}\n",
87 rev
88 ))
89 .into(),
90 ))
91 }
92 ListRevTrackedFilesErrorKind::UnsuportedRevlogVersion(version) => {
93 CommandErrorKind::Abort(Some(
94 utf8_to_local(&format!(
95 "abort: unsupported revlog version {}\n",
96 version
97 ))
98 .into(),
99 ))
100 }
101 ListRevTrackedFilesErrorKind::CorruptedRevlog => {
102 CommandErrorKind::Abort(Some(
103 "abort: corrupted revlog\n".into(),
104 ))
105 }
106 ListRevTrackedFilesErrorKind::UnknowRevlogDataFormat(format) => {
107 CommandErrorKind::Abort(Some(
108 utf8_to_local(&format!(
109 "abort: unknow revlog dataformat {:?}\n",
110 format
111 ))
112 .into(),
113 ))
114 }
115 },
116 }
117 }
118
119 /// Convert `ListDirstateTrackedFilesError` to `CommandError`
53 fn map_dirstate_error(err: ListDirstateTrackedFilesError) -> CommandError {
120 fn map_dirstate_error(err: ListDirstateTrackedFilesError) -> CommandError {
54 CommandError {
121 CommandError {
55 kind: match err.kind {
122 kind: match err.kind {
56 ListDirstateTrackedFilesErrorKind::IoError(err) => {
123 ListDirstateTrackedFilesErrorKind::IoError(err) => {
57 CommandErrorKind::Abort(Some(
124 CommandErrorKind::Abort(Some(
58 utf8_to_local(&format!("abort: {}\n", err)).into(),
125 utf8_to_local(&format!("abort: {}\n", err)).into(),
59 ))
126 ))
60 }
127 }
61 ListDirstateTrackedFilesErrorKind::ParseError(_) => {
128 ListDirstateTrackedFilesErrorKind::ParseError(_) => {
62 CommandErrorKind::Abort(Some(
129 CommandErrorKind::Abort(Some(
63 // TODO find a better error message
130 // TODO find a better error message
64 b"abort: parse error\n".to_vec(),
131 b"abort: parse error\n".to_vec(),
65 ))
132 ))
66 }
133 }
67 },
134 },
68 }
135 }
69 }
136 }
@@ -1,121 +1,141 b''
1 extern crate log;
1 extern crate log;
2 use clap::App;
2 use clap::App;
3 use clap::AppSettings;
3 use clap::AppSettings;
4 use clap::Arg;
4 use clap::Arg;
5 use clap::ArgGroup;
5 use clap::ArgGroup;
6 use clap::ArgMatches;
6 use clap::ArgMatches;
7 use clap::SubCommand;
7 use clap::SubCommand;
8 use hg::operations::DebugDataKind;
8 use hg::operations::DebugDataKind;
9 use std::convert::TryFrom;
9 use std::convert::TryFrom;
10
10
11 mod commands;
11 mod commands;
12 mod error;
12 mod error;
13 mod exitcode;
13 mod exitcode;
14 mod ui;
14 mod ui;
15 use commands::Command;
15 use commands::Command;
16 use error::CommandError;
16 use error::CommandError;
17
17
18 fn main() {
18 fn main() {
19 env_logger::init();
19 env_logger::init();
20 let app = App::new("rhg")
20 let app = App::new("rhg")
21 .setting(AppSettings::AllowInvalidUtf8)
21 .setting(AppSettings::AllowInvalidUtf8)
22 .setting(AppSettings::SubcommandRequired)
22 .setting(AppSettings::SubcommandRequired)
23 .setting(AppSettings::VersionlessSubcommands)
23 .setting(AppSettings::VersionlessSubcommands)
24 .version("0.0.1")
24 .version("0.0.1")
25 .subcommand(
25 .subcommand(
26 SubCommand::with_name("root").about(commands::root::HELP_TEXT),
26 SubCommand::with_name("root").about(commands::root::HELP_TEXT),
27 )
27 )
28 .subcommand(
28 .subcommand(
29 SubCommand::with_name("files").about(commands::files::HELP_TEXT),
29 SubCommand::with_name("files")
30 .arg(
31 Arg::with_name("rev")
32 .help("search the repository as it is in REV")
33 .short("-r")
34 .long("--revision")
35 .value_name("REV")
36 .takes_value(true),
37 )
38 .about(commands::files::HELP_TEXT),
30 )
39 )
31 .subcommand(
40 .subcommand(
32 SubCommand::with_name("debugdata")
41 SubCommand::with_name("debugdata")
33 .about(commands::debugdata::HELP_TEXT)
42 .about(commands::debugdata::HELP_TEXT)
34 .arg(
43 .arg(
35 Arg::with_name("changelog")
44 Arg::with_name("changelog")
36 .help("open changelog")
45 .help("open changelog")
37 .short("-c")
46 .short("-c")
38 .long("--changelog"),
47 .long("--changelog"),
39 )
48 )
40 .arg(
49 .arg(
41 Arg::with_name("manifest")
50 Arg::with_name("manifest")
42 .help("open manifest")
51 .help("open manifest")
43 .short("-m")
52 .short("-m")
44 .long("--manifest"),
53 .long("--manifest"),
45 )
54 )
46 .group(
55 .group(
47 ArgGroup::with_name("")
56 ArgGroup::with_name("")
48 .args(&["changelog", "manifest"])
57 .args(&["changelog", "manifest"])
49 .required(true),
58 .required(true),
50 )
59 )
51 .arg(
60 .arg(
52 Arg::with_name("rev")
61 Arg::with_name("rev")
53 .help("revision")
62 .help("revision")
54 .required(true)
63 .required(true)
55 .value_name("REV"),
64 .value_name("REV"),
56 ),
65 ),
57 );
66 );
58
67
59 let matches = app.clone().get_matches_safe().unwrap_or_else(|err| {
68 let matches = app.clone().get_matches_safe().unwrap_or_else(|err| {
60 let _ = ui::Ui::new().writeln_stderr_str(&err.message);
69 let _ = ui::Ui::new().writeln_stderr_str(&err.message);
61 std::process::exit(exitcode::UNIMPLEMENTED_COMMAND)
70 std::process::exit(exitcode::UNIMPLEMENTED_COMMAND)
62 });
71 });
63
72
64 let ui = ui::Ui::new();
73 let ui = ui::Ui::new();
65
74
66 let command_result = match_subcommand(matches, &ui);
75 let command_result = match_subcommand(matches, &ui);
67
76
68 match command_result {
77 match command_result {
69 Ok(_) => std::process::exit(exitcode::OK),
78 Ok(_) => std::process::exit(exitcode::OK),
70 Err(e) => {
79 Err(e) => {
71 let message = e.get_error_message_bytes();
80 let message = e.get_error_message_bytes();
72 if let Some(msg) = message {
81 if let Some(msg) = message {
73 match ui.write_stderr(&msg) {
82 match ui.write_stderr(&msg) {
74 Ok(_) => (),
83 Ok(_) => (),
75 Err(_) => std::process::exit(exitcode::ABORT),
84 Err(_) => std::process::exit(exitcode::ABORT),
76 };
85 };
77 };
86 };
78 e.exit()
87 e.exit()
79 }
88 }
80 }
89 }
81 }
90 }
82
91
83 fn match_subcommand(
92 fn match_subcommand(
84 matches: ArgMatches,
93 matches: ArgMatches,
85 ui: &ui::Ui,
94 ui: &ui::Ui,
86 ) -> Result<(), CommandError> {
95 ) -> Result<(), CommandError> {
87 match matches.subcommand() {
96 match matches.subcommand() {
88 ("root", _) => commands::root::RootCommand::new().run(&ui),
97 ("root", _) => commands::root::RootCommand::new().run(&ui),
89 ("files", _) => commands::files::FilesCommand::new().run(&ui),
98 ("files", Some(matches)) => {
99 commands::files::FilesCommand::try_from(matches)?.run(&ui)
100 }
90 ("debugdata", Some(matches)) => {
101 ("debugdata", Some(matches)) => {
91 commands::debugdata::DebugDataCommand::try_from(matches)?.run(&ui)
102 commands::debugdata::DebugDataCommand::try_from(matches)?.run(&ui)
92 }
103 }
93 _ => unreachable!(), // Because of AppSettings::SubcommandRequired,
104 _ => unreachable!(), // Because of AppSettings::SubcommandRequired,
94 }
105 }
95 }
106 }
96
107
108 impl<'a> TryFrom<&'a ArgMatches<'_>> for commands::files::FilesCommand<'a> {
109 type Error = CommandError;
110
111 fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> {
112 let rev = args.value_of("rev");
113 Ok(commands::files::FilesCommand::new(rev))
114 }
115 }
116
97 impl<'a> TryFrom<&'a ArgMatches<'_>>
117 impl<'a> TryFrom<&'a ArgMatches<'_>>
98 for commands::debugdata::DebugDataCommand<'a>
118 for commands::debugdata::DebugDataCommand<'a>
99 {
119 {
100 type Error = CommandError;
120 type Error = CommandError;
101
121
102 fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> {
122 fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> {
103 let rev = args
123 let rev = args
104 .value_of("rev")
124 .value_of("rev")
105 .expect("rev should be a required argument");
125 .expect("rev should be a required argument");
106 let kind = match (
126 let kind = match (
107 args.is_present("changelog"),
127 args.is_present("changelog"),
108 args.is_present("manifest"),
128 args.is_present("manifest"),
109 ) {
129 ) {
110 (true, false) => DebugDataKind::Changelog,
130 (true, false) => DebugDataKind::Changelog,
111 (false, true) => DebugDataKind::Manifest,
131 (false, true) => DebugDataKind::Manifest,
112 (true, true) => {
132 (true, true) => {
113 unreachable!("Should not happen since options are exclusive")
133 unreachable!("Should not happen since options are exclusive")
114 }
134 }
115 (false, false) => {
135 (false, false) => {
116 unreachable!("Should not happen since options are required")
136 unreachable!("Should not happen since options are required")
117 }
137 }
118 };
138 };
119 Ok(commands::debugdata::DebugDataCommand::new(rev, kind))
139 Ok(commands::debugdata::DebugDataCommand::new(rev, kind))
120 }
140 }
121 }
141 }
General Comments 0
You need to be logged in to leave comments. Login now