##// END OF EJS Templates
rhg: add a `Files` `Command` to prepare the `rhg files` subcommand...
Antoine Cezar -
r45923:5fe25f8e default
parent child Browse files
Show More
@@ -0,0 +1,50 b''
1 use crate::commands::Command;
2 use crate::error::{CommandError, CommandErrorKind};
3 use crate::ui::Ui;
4 use hg::operations::{ListTrackedFiles, ListTrackedFilesErrorKind};
5
6 pub const HELP_TEXT: &str = "
7 List tracked files.
8
9 Returns 0 on success.
10 ";
11
12 pub struct FilesCommand<'a> {
13 ui: &'a Ui,
14 }
15
16 impl<'a> FilesCommand<'a> {
17 pub fn new(ui: &'a Ui) -> Self {
18 FilesCommand { ui }
19 }
20 }
21
22 impl<'a> Command<'a> for FilesCommand<'a> {
23 fn run(&self) -> Result<(), CommandError> {
24 let operation_builder = ListTrackedFiles::new()?;
25 let operation = operation_builder.load().map_err(|err| {
26 CommandErrorKind::Abort(Some(
27 [b"abort: ", err.to_string().as_bytes(), b"\n"]
28 .concat()
29 .to_vec(),
30 ))
31 })?;
32 let files = operation.run().map_err(|err| match err.kind {
33 ListTrackedFilesErrorKind::ParseError(_) => {
34 CommandErrorKind::Abort(Some(
35 // TODO find a better error message
36 b"abort: parse error\n".to_vec(),
37 ))
38 }
39 })?;
40
41 let mut stdout = self.ui.stdout_buffer();
42 for file in files {
43 stdout.write_all(file.as_bytes())?;
44 stdout.write_all(b"\n")?;
45 }
46 stdout.flush()?;
47
48 Ok(())
49 }
50 }
@@ -1,191 +1,192 b''
1 // Copyright 2018-2020 Georges Racinet <georges.racinet@octobus.net>
1 // Copyright 2018-2020 Georges Racinet <georges.racinet@octobus.net>
2 // and Mercurial contributors
2 // and Mercurial contributors
3 //
3 //
4 // This software may be used and distributed according to the terms of the
4 // This software may be used and distributed according to the terms of the
5 // GNU General Public License version 2 or any later version.
5 // GNU General Public License version 2 or any later version.
6 mod ancestors;
6 mod ancestors;
7 pub mod dagops;
7 pub mod dagops;
8 pub use ancestors::{AncestorsIterator, LazyAncestors, MissingAncestors};
8 pub use ancestors::{AncestorsIterator, LazyAncestors, MissingAncestors};
9 mod dirstate;
9 mod dirstate;
10 pub mod discovery;
10 pub mod discovery;
11 pub mod testing; // unconditionally built, for use from integration tests
11 pub mod testing; // unconditionally built, for use from integration tests
12 pub use dirstate::{
12 pub use dirstate::{
13 dirs_multiset::{DirsMultiset, DirsMultisetIter},
13 dirs_multiset::{DirsMultiset, DirsMultisetIter},
14 dirstate_map::DirstateMap,
14 dirstate_map::DirstateMap,
15 parsers::{pack_dirstate, parse_dirstate, PARENT_SIZE},
15 parsers::{pack_dirstate, parse_dirstate, PARENT_SIZE},
16 status::{
16 status::{
17 status, BadMatch, BadType, DirstateStatus, StatusError, StatusOptions,
17 status, BadMatch, BadType, DirstateStatus, StatusError, StatusOptions,
18 },
18 },
19 CopyMap, CopyMapIter, DirstateEntry, DirstateParents, EntryState,
19 CopyMap, CopyMapIter, DirstateEntry, DirstateParents, EntryState,
20 StateMap, StateMapIter,
20 StateMap, StateMapIter,
21 };
21 };
22 mod filepatterns;
22 mod filepatterns;
23 pub mod matchers;
23 pub mod matchers;
24 pub mod revlog;
24 pub mod revlog;
25 pub use revlog::*;
25 pub use revlog::*;
26 pub mod operations;
26 pub mod operations;
27 pub mod utils;
27 pub mod utils;
28
28
29 // Remove this to see (potential) non-artificial compile failures. MacOS
29 // Remove this to see (potential) non-artificial compile failures. MacOS
30 // *should* compile, but fail to compile tests for example as of 2020-03-06
30 // *should* compile, but fail to compile tests for example as of 2020-03-06
31 #[cfg(not(target_os = "linux"))]
31 #[cfg(not(target_os = "linux"))]
32 compile_error!(
32 compile_error!(
33 "`hg-core` has only been tested on Linux and will most \
33 "`hg-core` has only been tested on Linux and will most \
34 likely not behave correctly on other platforms."
34 likely not behave correctly on other platforms."
35 );
35 );
36
36
37 use crate::utils::hg_path::{HgPathBuf, HgPathError};
37 use crate::utils::hg_path::{HgPathBuf, HgPathError};
38 pub use filepatterns::{
38 pub use filepatterns::{
39 parse_pattern_syntax, read_pattern_file, IgnorePattern,
39 parse_pattern_syntax, read_pattern_file, IgnorePattern,
40 PatternFileWarning, PatternSyntax,
40 PatternFileWarning, PatternSyntax,
41 };
41 };
42 use std::collections::HashMap;
42 use std::collections::HashMap;
43 use twox_hash::RandomXxHashBuilder64;
43 use twox_hash::RandomXxHashBuilder64;
44
44
45 /// This is a contract between the `micro-timer` crate and us, to expose
45 /// This is a contract between the `micro-timer` crate and us, to expose
46 /// the `log` crate as `crate::log`.
46 /// the `log` crate as `crate::log`.
47 use log;
47 use log;
48
48
49 pub type LineNumber = usize;
49 pub type LineNumber = usize;
50
50
51 /// Rust's default hasher is too slow because it tries to prevent collision
51 /// Rust's default hasher is too slow because it tries to prevent collision
52 /// attacks. We are not concerned about those: if an ill-minded person has
52 /// attacks. We are not concerned about those: if an ill-minded person has
53 /// write access to your repository, you have other issues.
53 /// write access to your repository, you have other issues.
54 pub type FastHashMap<K, V> = HashMap<K, V, RandomXxHashBuilder64>;
54 pub type FastHashMap<K, V> = HashMap<K, V, RandomXxHashBuilder64>;
55
55
56 #[derive(Clone, Debug, PartialEq)]
56 #[derive(Clone, Debug, PartialEq)]
57 pub enum DirstateParseError {
57 pub enum DirstateParseError {
58 TooLittleData,
58 TooLittleData,
59 Overflow,
59 Overflow,
60 // TODO refactor to use bytes instead of String
60 CorruptedEntry(String),
61 CorruptedEntry(String),
61 Damaged,
62 Damaged,
62 }
63 }
63
64
64 impl From<std::io::Error> for DirstateParseError {
65 impl From<std::io::Error> for DirstateParseError {
65 fn from(e: std::io::Error) -> Self {
66 fn from(e: std::io::Error) -> Self {
66 DirstateParseError::CorruptedEntry(e.to_string())
67 DirstateParseError::CorruptedEntry(e.to_string())
67 }
68 }
68 }
69 }
69
70
70 impl ToString for DirstateParseError {
71 impl ToString for DirstateParseError {
71 fn to_string(&self) -> String {
72 fn to_string(&self) -> String {
72 use crate::DirstateParseError::*;
73 use crate::DirstateParseError::*;
73 match self {
74 match self {
74 TooLittleData => "Too little data for dirstate.".to_string(),
75 TooLittleData => "Too little data for dirstate.".to_string(),
75 Overflow => "Overflow in dirstate.".to_string(),
76 Overflow => "Overflow in dirstate.".to_string(),
76 CorruptedEntry(e) => format!("Corrupted entry: {:?}.", e),
77 CorruptedEntry(e) => format!("Corrupted entry: {:?}.", e),
77 Damaged => "Dirstate appears to be damaged.".to_string(),
78 Damaged => "Dirstate appears to be damaged.".to_string(),
78 }
79 }
79 }
80 }
80 }
81 }
81
82
82 #[derive(Debug, PartialEq)]
83 #[derive(Debug, PartialEq)]
83 pub enum DirstatePackError {
84 pub enum DirstatePackError {
84 CorruptedEntry(String),
85 CorruptedEntry(String),
85 CorruptedParent,
86 CorruptedParent,
86 BadSize(usize, usize),
87 BadSize(usize, usize),
87 }
88 }
88
89
89 impl From<std::io::Error> for DirstatePackError {
90 impl From<std::io::Error> for DirstatePackError {
90 fn from(e: std::io::Error) -> Self {
91 fn from(e: std::io::Error) -> Self {
91 DirstatePackError::CorruptedEntry(e.to_string())
92 DirstatePackError::CorruptedEntry(e.to_string())
92 }
93 }
93 }
94 }
94 #[derive(Debug, PartialEq)]
95 #[derive(Debug, PartialEq)]
95 pub enum DirstateMapError {
96 pub enum DirstateMapError {
96 PathNotFound(HgPathBuf),
97 PathNotFound(HgPathBuf),
97 EmptyPath,
98 EmptyPath,
98 InvalidPath(HgPathError),
99 InvalidPath(HgPathError),
99 }
100 }
100
101
101 impl ToString for DirstateMapError {
102 impl ToString for DirstateMapError {
102 fn to_string(&self) -> String {
103 fn to_string(&self) -> String {
103 match self {
104 match self {
104 DirstateMapError::PathNotFound(_) => {
105 DirstateMapError::PathNotFound(_) => {
105 "expected a value, found none".to_string()
106 "expected a value, found none".to_string()
106 }
107 }
107 DirstateMapError::EmptyPath => "Overflow in dirstate.".to_string(),
108 DirstateMapError::EmptyPath => "Overflow in dirstate.".to_string(),
108 DirstateMapError::InvalidPath(e) => e.to_string(),
109 DirstateMapError::InvalidPath(e) => e.to_string(),
109 }
110 }
110 }
111 }
111 }
112 }
112
113
113 #[derive(Debug)]
114 #[derive(Debug)]
114 pub enum DirstateError {
115 pub enum DirstateError {
115 Parse(DirstateParseError),
116 Parse(DirstateParseError),
116 Pack(DirstatePackError),
117 Pack(DirstatePackError),
117 Map(DirstateMapError),
118 Map(DirstateMapError),
118 IO(std::io::Error),
119 IO(std::io::Error),
119 }
120 }
120
121
121 impl From<DirstateParseError> for DirstateError {
122 impl From<DirstateParseError> for DirstateError {
122 fn from(e: DirstateParseError) -> Self {
123 fn from(e: DirstateParseError) -> Self {
123 DirstateError::Parse(e)
124 DirstateError::Parse(e)
124 }
125 }
125 }
126 }
126
127
127 impl From<DirstatePackError> for DirstateError {
128 impl From<DirstatePackError> for DirstateError {
128 fn from(e: DirstatePackError) -> Self {
129 fn from(e: DirstatePackError) -> Self {
129 DirstateError::Pack(e)
130 DirstateError::Pack(e)
130 }
131 }
131 }
132 }
132
133
133 #[derive(Debug)]
134 #[derive(Debug)]
134 pub enum PatternError {
135 pub enum PatternError {
135 Path(HgPathError),
136 Path(HgPathError),
136 UnsupportedSyntax(String),
137 UnsupportedSyntax(String),
137 UnsupportedSyntaxInFile(String, String, usize),
138 UnsupportedSyntaxInFile(String, String, usize),
138 TooLong(usize),
139 TooLong(usize),
139 IO(std::io::Error),
140 IO(std::io::Error),
140 /// Needed a pattern that can be turned into a regex but got one that
141 /// Needed a pattern that can be turned into a regex but got one that
141 /// can't. This should only happen through programmer error.
142 /// can't. This should only happen through programmer error.
142 NonRegexPattern(IgnorePattern),
143 NonRegexPattern(IgnorePattern),
143 }
144 }
144
145
145 impl ToString for PatternError {
146 impl ToString for PatternError {
146 fn to_string(&self) -> String {
147 fn to_string(&self) -> String {
147 match self {
148 match self {
148 PatternError::UnsupportedSyntax(syntax) => {
149 PatternError::UnsupportedSyntax(syntax) => {
149 format!("Unsupported syntax {}", syntax)
150 format!("Unsupported syntax {}", syntax)
150 }
151 }
151 PatternError::UnsupportedSyntaxInFile(syntax, file_path, line) => {
152 PatternError::UnsupportedSyntaxInFile(syntax, file_path, line) => {
152 format!(
153 format!(
153 "{}:{}: unsupported syntax {}",
154 "{}:{}: unsupported syntax {}",
154 file_path, line, syntax
155 file_path, line, syntax
155 )
156 )
156 }
157 }
157 PatternError::TooLong(size) => {
158 PatternError::TooLong(size) => {
158 format!("matcher pattern is too long ({} bytes)", size)
159 format!("matcher pattern is too long ({} bytes)", size)
159 }
160 }
160 PatternError::IO(e) => e.to_string(),
161 PatternError::IO(e) => e.to_string(),
161 PatternError::Path(e) => e.to_string(),
162 PatternError::Path(e) => e.to_string(),
162 PatternError::NonRegexPattern(pattern) => {
163 PatternError::NonRegexPattern(pattern) => {
163 format!("'{:?}' cannot be turned into a regex", pattern)
164 format!("'{:?}' cannot be turned into a regex", pattern)
164 }
165 }
165 }
166 }
166 }
167 }
167 }
168 }
168
169
169 impl From<DirstateMapError> for DirstateError {
170 impl From<DirstateMapError> for DirstateError {
170 fn from(e: DirstateMapError) -> Self {
171 fn from(e: DirstateMapError) -> Self {
171 DirstateError::Map(e)
172 DirstateError::Map(e)
172 }
173 }
173 }
174 }
174
175
175 impl From<std::io::Error> for DirstateError {
176 impl From<std::io::Error> for DirstateError {
176 fn from(e: std::io::Error) -> Self {
177 fn from(e: std::io::Error) -> Self {
177 DirstateError::IO(e)
178 DirstateError::IO(e)
178 }
179 }
179 }
180 }
180
181
181 impl From<std::io::Error> for PatternError {
182 impl From<std::io::Error> for PatternError {
182 fn from(e: std::io::Error) -> Self {
183 fn from(e: std::io::Error) -> Self {
183 PatternError::IO(e)
184 PatternError::IO(e)
184 }
185 }
185 }
186 }
186
187
187 impl From<HgPathError> for PatternError {
188 impl From<HgPathError> for PatternError {
188 fn from(e: HgPathError) -> Self {
189 fn from(e: HgPathError) -> Self {
189 PatternError::Path(e)
190 PatternError::Path(e)
190 }
191 }
191 }
192 }
@@ -1,9 +1,10 b''
1 pub mod files;
1 pub mod root;
2 pub mod root;
2 use crate::error::CommandError;
3 use crate::error::CommandError;
3
4
4 /// The common trait for rhg commands
5 /// The common trait for rhg commands
5 ///
6 ///
6 /// Normalize the interface of the commands provided by rhg
7 /// Normalize the interface of the commands provided by rhg
7 pub trait Command<'a> {
8 pub trait Command<'a> {
8 fn run(&self) -> Result<(), CommandError>;
9 fn run(&self) -> Result<(), CommandError>;
9 }
10 }
@@ -1,106 +1,110 b''
1 use crate::exitcode;
1 use crate::exitcode;
2 use crate::ui::UiError;
2 use crate::ui::UiError;
3 use hg::operations::{FindRootError, FindRootErrorKind};
3 use hg::operations::{FindRootError, FindRootErrorKind};
4 use hg::utils::files::get_bytes_from_path;
4 use hg::utils::files::get_bytes_from_path;
5 use std::convert::From;
5 use std::convert::From;
6 use std::path::PathBuf;
6 use std::path::PathBuf;
7
7
8 /// The kind of command error
8 /// The kind of command error
9 #[derive(Debug)]
9 #[derive(Debug)]
10 pub enum CommandErrorKind {
10 pub enum CommandErrorKind {
11 /// The root of the repository cannot be found
11 /// The root of the repository cannot be found
12 RootNotFound(PathBuf),
12 RootNotFound(PathBuf),
13 /// The current directory cannot be found
13 /// The current directory cannot be found
14 CurrentDirNotFound(std::io::Error),
14 CurrentDirNotFound(std::io::Error),
15 /// The standard output stream cannot be written to
15 /// The standard output stream cannot be written to
16 StdoutError,
16 StdoutError,
17 /// The standard error stream cannot be written to
17 /// The standard error stream cannot be written to
18 StderrError,
18 StderrError,
19 /// The command aborted
20 Abort(Option<Vec<u8>>),
19 }
21 }
20
22
21 impl CommandErrorKind {
23 impl CommandErrorKind {
22 pub fn get_exit_code(&self) -> exitcode::ExitCode {
24 pub fn get_exit_code(&self) -> exitcode::ExitCode {
23 match self {
25 match self {
24 CommandErrorKind::RootNotFound(_) => exitcode::ABORT,
26 CommandErrorKind::RootNotFound(_) => exitcode::ABORT,
25 CommandErrorKind::CurrentDirNotFound(_) => exitcode::ABORT,
27 CommandErrorKind::CurrentDirNotFound(_) => exitcode::ABORT,
26 CommandErrorKind::StdoutError => exitcode::ABORT,
28 CommandErrorKind::StdoutError => exitcode::ABORT,
27 CommandErrorKind::StderrError => exitcode::ABORT,
29 CommandErrorKind::StderrError => exitcode::ABORT,
30 CommandErrorKind::Abort(_) => exitcode::ABORT,
28 }
31 }
29 }
32 }
30
33
31 /// Return the message corresponding to the error kind if any
34 /// Return the message corresponding to the error kind if any
32 pub fn get_error_message_bytes(&self) -> Option<Vec<u8>> {
35 pub fn get_error_message_bytes(&self) -> Option<Vec<u8>> {
33 match self {
36 match self {
34 // TODO use formating macro
37 // TODO use formating macro
35 CommandErrorKind::RootNotFound(path) => {
38 CommandErrorKind::RootNotFound(path) => {
36 let bytes = get_bytes_from_path(path);
39 let bytes = get_bytes_from_path(path);
37 Some(
40 Some(
38 [
41 [
39 b"abort: no repository found in '",
42 b"abort: no repository found in '",
40 bytes.as_slice(),
43 bytes.as_slice(),
41 b"' (.hg not found)!\n",
44 b"' (.hg not found)!\n",
42 ]
45 ]
43 .concat(),
46 .concat(),
44 )
47 )
45 }
48 }
46 // TODO use formating macro
49 // TODO use formating macro
47 CommandErrorKind::CurrentDirNotFound(e) => Some(
50 CommandErrorKind::CurrentDirNotFound(e) => Some(
48 [
51 [
49 b"abort: error getting current working directory: ",
52 b"abort: error getting current working directory: ",
50 e.to_string().as_bytes(),
53 e.to_string().as_bytes(),
51 b"\n",
54 b"\n",
52 ]
55 ]
53 .concat(),
56 .concat(),
54 ),
57 ),
58 CommandErrorKind::Abort(message) => message.to_owned(),
55 _ => None,
59 _ => None,
56 }
60 }
57 }
61 }
58 }
62 }
59
63
60 /// The error type for the Command trait
64 /// The error type for the Command trait
61 #[derive(Debug)]
65 #[derive(Debug)]
62 pub struct CommandError {
66 pub struct CommandError {
63 pub kind: CommandErrorKind,
67 pub kind: CommandErrorKind,
64 }
68 }
65
69
66 impl CommandError {
70 impl CommandError {
67 /// Exist the process with the corresponding exit code.
71 /// Exist the process with the corresponding exit code.
68 pub fn exit(&self) -> () {
72 pub fn exit(&self) -> () {
69 std::process::exit(self.kind.get_exit_code())
73 std::process::exit(self.kind.get_exit_code())
70 }
74 }
71
75
72 /// Return the message corresponding to the command error if any
76 /// Return the message corresponding to the command error if any
73 pub fn get_error_message_bytes(&self) -> Option<Vec<u8>> {
77 pub fn get_error_message_bytes(&self) -> Option<Vec<u8>> {
74 self.kind.get_error_message_bytes()
78 self.kind.get_error_message_bytes()
75 }
79 }
76 }
80 }
77
81
78 impl From<CommandErrorKind> for CommandError {
82 impl From<CommandErrorKind> for CommandError {
79 fn from(kind: CommandErrorKind) -> Self {
83 fn from(kind: CommandErrorKind) -> Self {
80 CommandError { kind }
84 CommandError { kind }
81 }
85 }
82 }
86 }
83
87
84 impl From<UiError> for CommandError {
88 impl From<UiError> for CommandError {
85 fn from(error: UiError) -> Self {
89 fn from(error: UiError) -> Self {
86 CommandError {
90 CommandError {
87 kind: match error {
91 kind: match error {
88 UiError::StdoutError(_) => CommandErrorKind::StdoutError,
92 UiError::StdoutError(_) => CommandErrorKind::StdoutError,
89 UiError::StderrError(_) => CommandErrorKind::StderrError,
93 UiError::StderrError(_) => CommandErrorKind::StderrError,
90 },
94 },
91 }
95 }
92 }
96 }
93 }
97 }
94
98
95 impl From<FindRootError> for CommandError {
99 impl From<FindRootError> for CommandError {
96 fn from(err: FindRootError) -> Self {
100 fn from(err: FindRootError) -> Self {
97 match err.kind {
101 match err.kind {
98 FindRootErrorKind::RootNotFound(path) => CommandError {
102 FindRootErrorKind::RootNotFound(path) => CommandError {
99 kind: CommandErrorKind::RootNotFound(path),
103 kind: CommandErrorKind::RootNotFound(path),
100 },
104 },
101 FindRootErrorKind::GetCurrentDirError(e) => CommandError {
105 FindRootErrorKind::GetCurrentDirError(e) => CommandError {
102 kind: CommandErrorKind::CurrentDirNotFound(e),
106 kind: CommandErrorKind::CurrentDirNotFound(e),
103 },
107 },
104 }
108 }
105 }
109 }
106 }
110 }
General Comments 0
You need to be logged in to leave comments. Login now