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