##// END OF EJS Templates
rhg: Add a `rhg.on-unsupported` configuration key...
Simon Sapin -
r47424:33f2d56a default
parent child Browse files
Show More
@@ -1,65 +1,67 b''
1 1 use crate::error::CommandError;
2 2 use clap::Arg;
3 3 use hg::operations::cat;
4 4 use hg::utils::hg_path::HgPathBuf;
5 5 use micro_timer::timed;
6 6 use std::convert::TryFrom;
7 7
8 8 pub const HELP_TEXT: &str = "
9 9 Output the current or given revision of files
10 10 ";
11 11
12 12 pub fn args() -> clap::App<'static, 'static> {
13 13 clap::SubCommand::with_name("cat")
14 14 .arg(
15 15 Arg::with_name("rev")
16 16 .help("search the repository as it is in REV")
17 17 .short("-r")
18 18 .long("--revision")
19 19 .value_name("REV")
20 20 .takes_value(true),
21 21 )
22 22 .arg(
23 23 clap::Arg::with_name("files")
24 24 .required(true)
25 25 .multiple(true)
26 26 .empty_values(false)
27 27 .value_name("FILE")
28 28 .help("Activity to start: activity@category"),
29 29 )
30 30 .about(HELP_TEXT)
31 31 }
32 32
33 33 #[timed]
34 34 pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> {
35 35 let rev = invocation.subcommand_args.value_of("rev");
36 36 let file_args = match invocation.subcommand_args.values_of("files") {
37 37 Some(files) => files.collect(),
38 38 None => vec![],
39 39 };
40 40
41 41 let repo = invocation.repo?;
42 42 let cwd = hg::utils::current_dir()?;
43 43
44 44 let mut files = vec![];
45 45 for file in file_args.iter() {
46 46 // TODO: actually normalize `..` path segments etc?
47 47 let normalized = cwd.join(&file);
48 48 let stripped = normalized
49 49 .strip_prefix(&repo.working_directory_path())
50 50 // TODO: error message for path arguments outside of the repo
51 51 .map_err(|_| CommandError::abort(""))?;
52 52 let hg_file = HgPathBuf::try_from(stripped.to_path_buf())
53 53 .map_err(|e| CommandError::abort(e.to_string()))?;
54 54 files.push(hg_file);
55 55 }
56 56
57 57 match rev {
58 58 Some(rev) => {
59 59 let data = cat(&repo, rev, &files).map_err(|e| (e, rev))?;
60 60 invocation.ui.write_stdout(&data)?;
61 61 Ok(())
62 62 }
63 None => Err(CommandError::Unimplemented.into()),
63 None => Err(CommandError::unsupported(
64 "`rhg cat` without `--rev` / `-r`",
65 )),
64 66 }
65 67 }
@@ -1,136 +1,143 b''
1 1 use crate::ui::utf8_to_local;
2 2 use crate::ui::UiError;
3 3 use crate::NoRepoInCwdError;
4 4 use format_bytes::format_bytes;
5 5 use hg::config::{ConfigError, ConfigParseError};
6 6 use hg::errors::HgError;
7 7 use hg::repo::RepoError;
8 8 use hg::revlog::revlog::RevlogError;
9 9 use hg::utils::files::get_bytes_from_path;
10 10 use std::convert::From;
11 11
12 12 /// The kind of command error
13 13 #[derive(Debug)]
14 14 pub enum CommandError {
15 15 /// Exit with an error message and "standard" failure exit code.
16 16 Abort { message: Vec<u8> },
17 17
18 /// A mercurial capability as not been implemented.
19 ///
20 /// There is no error message printed in this case.
21 /// Instead, we exit with a specic status code and a wrapper script may
22 /// fallback to Python-based Mercurial.
23 Unimplemented,
18 /// Encountered something (such as a CLI argument, repository layout, …)
19 /// not supported by this version of `rhg`. Depending on configuration
20 /// `rhg` may attempt to silently fall back to Python-based `hg`, which
21 /// may or may not support this feature.
22 UnsupportedFeature { message: Vec<u8> },
24 23 }
25 24
26 25 impl CommandError {
27 26 pub fn abort(message: impl AsRef<str>) -> Self {
28 27 CommandError::Abort {
29 28 // TODO: bytes-based (instead of Unicode-based) formatting
30 29 // of error messages to handle non-UTF-8 filenames etc:
31 30 // https://www.mercurial-scm.org/wiki/EncodingStrategy#Mixing_output
32 31 message: utf8_to_local(message.as_ref()).into(),
33 32 }
34 33 }
34
35 pub fn unsupported(message: impl AsRef<str>) -> Self {
36 CommandError::UnsupportedFeature {
37 message: utf8_to_local(message.as_ref()).into(),
38 }
39 }
35 40 }
36 41
37 42 /// For now we don’t differenciate between invalid CLI args and valid for `hg`
38 43 /// but not supported yet by `rhg`.
39 44 impl From<clap::Error> for CommandError {
40 fn from(_: clap::Error) -> Self {
41 CommandError::Unimplemented
45 fn from(error: clap::Error) -> Self {
46 CommandError::unsupported(error.to_string())
42 47 }
43 48 }
44 49
45 50 impl From<HgError> for CommandError {
46 51 fn from(error: HgError) -> Self {
47 52 match error {
48 HgError::UnsupportedFeature(_) => CommandError::Unimplemented,
53 HgError::UnsupportedFeature(message) => {
54 CommandError::unsupported(message)
55 }
49 56 _ => CommandError::abort(error.to_string()),
50 57 }
51 58 }
52 59 }
53 60
54 61 impl From<UiError> for CommandError {
55 62 fn from(_error: UiError) -> Self {
56 63 // If we already failed writing to stdout or stderr,
57 64 // writing an error message to stderr about it would be likely to fail
58 65 // too.
59 66 CommandError::abort("")
60 67 }
61 68 }
62 69
63 70 impl From<RepoError> for CommandError {
64 71 fn from(error: RepoError) -> Self {
65 72 match error {
66 73 RepoError::NotFound { at } => CommandError::Abort {
67 74 message: format_bytes!(
68 75 b"repository {} not found",
69 76 get_bytes_from_path(at)
70 77 ),
71 78 },
72 79 RepoError::ConfigParseError(error) => error.into(),
73 80 RepoError::Other(error) => error.into(),
74 81 }
75 82 }
76 83 }
77 84
78 85 impl<'a> From<&'a NoRepoInCwdError> for CommandError {
79 86 fn from(error: &'a NoRepoInCwdError) -> Self {
80 87 let NoRepoInCwdError { cwd } = error;
81 88 CommandError::Abort {
82 89 message: format_bytes!(
83 90 b"no repository found in '{}' (.hg not found)!",
84 91 get_bytes_from_path(cwd)
85 92 ),
86 93 }
87 94 }
88 95 }
89 96
90 97 impl From<ConfigError> for CommandError {
91 98 fn from(error: ConfigError) -> Self {
92 99 match error {
93 100 ConfigError::Parse(error) => error.into(),
94 101 ConfigError::Other(error) => error.into(),
95 102 }
96 103 }
97 104 }
98 105
99 106 impl From<ConfigParseError> for CommandError {
100 107 fn from(error: ConfigParseError) -> Self {
101 108 let ConfigParseError {
102 109 origin,
103 110 line,
104 111 bytes,
105 112 } = error;
106 113 let line_message = if let Some(line_number) = line {
107 114 format_bytes!(b" at line {}", line_number.to_string().into_bytes())
108 115 } else {
109 116 Vec::new()
110 117 };
111 118 CommandError::Abort {
112 119 message: format_bytes!(
113 120 b"config parse error in {}{}: '{}'",
114 121 origin,
115 122 line_message,
116 123 bytes
117 124 ),
118 125 }
119 126 }
120 127 }
121 128
122 129 impl From<(RevlogError, &str)> for CommandError {
123 130 fn from((err, rev): (RevlogError, &str)) -> CommandError {
124 131 match err {
125 132 RevlogError::InvalidRevision => CommandError::abort(format!(
126 133 "invalid revision identifier {}",
127 134 rev
128 135 )),
129 136 RevlogError::AmbiguousPrefix => CommandError::abort(format!(
130 137 "ambiguous revision identifier {}",
131 138 rev
132 139 )),
133 140 RevlogError::Other(error) => error.into(),
134 141 }
135 142 }
136 143 }
@@ -1,228 +1,286 b''
1 1 extern crate log;
2 2 use crate::ui::Ui;
3 3 use clap::App;
4 4 use clap::AppSettings;
5 5 use clap::Arg;
6 6 use clap::ArgMatches;
7 7 use format_bytes::format_bytes;
8 8 use hg::config::Config;
9 9 use hg::repo::{Repo, RepoError};
10 10 use hg::utils::files::{get_bytes_from_os_str, get_path_from_bytes};
11 11 use hg::utils::SliceExt;
12 12 use std::ffi::OsString;
13 13 use std::path::PathBuf;
14 14
15 15 mod blackbox;
16 16 mod error;
17 17 mod exitcode;
18 18 mod ui;
19 19 use error::CommandError;
20 20
21 21 fn main_with_result(
22 22 process_start_time: &blackbox::ProcessStartTime,
23 23 ui: &ui::Ui,
24 24 repo: Result<&Repo, &NoRepoInCwdError>,
25 25 config: &Config,
26 26 ) -> Result<(), CommandError> {
27 27 let app = App::new("rhg")
28 28 .global_setting(AppSettings::AllowInvalidUtf8)
29 29 .setting(AppSettings::SubcommandRequired)
30 30 .setting(AppSettings::VersionlessSubcommands)
31 31 .arg(
32 32 Arg::with_name("repository")
33 33 .help("repository root directory")
34 34 .short("-R")
35 35 .long("--repository")
36 36 .value_name("REPO")
37 37 .takes_value(true)
38 38 // Both ok: `hg -R ./foo log` or `hg log -R ./foo`
39 39 .global(true),
40 40 )
41 41 .arg(
42 42 Arg::with_name("config")
43 43 .help("set/override config option (use 'section.name=value')")
44 44 .long("--config")
45 45 .value_name("CONFIG")
46 46 .takes_value(true)
47 47 .global(true)
48 48 // Ok: `--config section.key1=val --config section.key2=val2`
49 49 .multiple(true)
50 50 // Not ok: `--config section.key1=val section.key2=val2`
51 51 .number_of_values(1),
52 52 )
53 53 .version("0.0.1");
54 54 let app = add_subcommand_args(app);
55 55
56 56 let matches = app.clone().get_matches_safe()?;
57 57
58 58 let (subcommand_name, subcommand_matches) = matches.subcommand();
59 59 let run = subcommand_run_fn(subcommand_name)
60 60 .expect("unknown subcommand name from clap despite AppSettings::SubcommandRequired");
61 61 let subcommand_args = subcommand_matches
62 62 .expect("no subcommand arguments from clap despite AppSettings::SubcommandRequired");
63 63
64 64 let invocation = CliInvocation {
65 65 ui,
66 66 subcommand_args,
67 67 config,
68 68 repo,
69 69 };
70 70 let blackbox = blackbox::Blackbox::new(&invocation, process_start_time)?;
71 71 blackbox.log_command_start();
72 72 let result = run(&invocation);
73 73 blackbox.log_command_end(exit_code(&result));
74 74 result
75 75 }
76 76
77 77 fn main() {
78 78 // Run this first, before we find out if the blackbox extension is even
79 79 // enabled, in order to include everything in-between in the duration
80 80 // measurements. Reading config files can be slow if they’re on NFS.
81 81 let process_start_time = blackbox::ProcessStartTime::now();
82 82
83 83 env_logger::init();
84 84 let ui = ui::Ui::new();
85 85
86 86 let early_args = EarlyArgs::parse(std::env::args_os());
87 let non_repo_config = Config::load(early_args.config)
88 .unwrap_or_else(|error| exit(&ui, Err(error.into())));
87 let non_repo_config =
88 Config::load(early_args.config).unwrap_or_else(|error| {
89 // Normally this is decided based on config, but we don’t have that
90 // available. As of this writing config loading never returns an
91 // "unsupported" error but that is not enforced by the type system.
92 let on_unsupported = OnUnsupported::Abort;
93
94 exit(&ui, on_unsupported, Err(error.into()))
95 });
89 96
90 97 let repo_path = early_args.repo.as_deref().map(get_path_from_bytes);
91 98 let repo_result = match Repo::find(&non_repo_config, repo_path) {
92 99 Ok(repo) => Ok(repo),
93 100 Err(RepoError::NotFound { at }) if repo_path.is_none() => {
94 101 // Not finding a repo is not fatal yet, if `-R` was not given
95 102 Err(NoRepoInCwdError { cwd: at })
96 103 }
97 Err(error) => exit(&ui, Err(error.into())),
104 Err(error) => exit(
105 &ui,
106 OnUnsupported::from_config(&non_repo_config),
107 Err(error.into()),
108 ),
98 109 };
99 110
100 111 let config = if let Ok(repo) = &repo_result {
101 112 repo.config()
102 113 } else {
103 114 &non_repo_config
104 115 };
105 116
106 117 let result = main_with_result(
107 118 &process_start_time,
108 119 &ui,
109 120 repo_result.as_ref(),
110 121 config,
111 122 );
112 exit(&ui, result)
123 exit(&ui, OnUnsupported::from_config(config), result)
113 124 }
114 125
115 126 fn exit_code(result: &Result<(), CommandError>) -> i32 {
116 127 match result {
117 128 Ok(()) => exitcode::OK,
118 129 Err(CommandError::Abort { .. }) => exitcode::ABORT,
119 130
120 131 // Exit with a specific code and no error message to let a potential
121 132 // wrapper script fallback to Python-based Mercurial.
122 Err(CommandError::Unimplemented) => exitcode::UNIMPLEMENTED,
133 Err(CommandError::UnsupportedFeature { .. }) => {
134 exitcode::UNIMPLEMENTED
135 }
123 136 }
124 137 }
125 138
126 fn exit(ui: &Ui, result: Result<(), CommandError>) -> ! {
127 if let Err(CommandError::Abort { message }) = &result {
128 if !message.is_empty() {
129 // Ignore errors when writing to stderr, we’re already exiting
130 // with failure code so there’s not much more we can do.
131 let _ = ui.write_stderr(&format_bytes!(b"abort: {}\n", message));
139 fn exit(
140 ui: &Ui,
141 on_unsupported: OnUnsupported,
142 result: Result<(), CommandError>,
143 ) -> ! {
144 match &result {
145 Ok(_) => {}
146 Err(CommandError::Abort { message }) => {
147 if !message.is_empty() {
148 // Ignore errors when writing to stderr, we’re already exiting
149 // with failure code so there’s not much more we can do.
150 let _ =
151 ui.write_stderr(&format_bytes!(b"abort: {}\n", message));
152 }
153 }
154 Err(CommandError::UnsupportedFeature { message }) => {
155 match on_unsupported {
156 OnUnsupported::Abort => {
157 let _ = ui.write_stderr(&format_bytes!(
158 b"unsupported feature: {}\n",
159 message
160 ));
161 }
162 OnUnsupported::AbortSilent => {}
163 }
132 164 }
133 165 }
134 166 std::process::exit(exit_code(&result))
135 167 }
136 168
137 169 macro_rules! subcommands {
138 170 ($( $command: ident )+) => {
139 171 mod commands {
140 172 $(
141 173 pub mod $command;
142 174 )+
143 175 }
144 176
145 177 fn add_subcommand_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
146 178 app
147 179 $(
148 180 .subcommand(commands::$command::args())
149 181 )+
150 182 }
151 183
152 184 pub type RunFn = fn(&CliInvocation) -> Result<(), CommandError>;
153 185
154 186 fn subcommand_run_fn(name: &str) -> Option<RunFn> {
155 187 match name {
156 188 $(
157 189 stringify!($command) => Some(commands::$command::run),
158 190 )+
159 191 _ => None,
160 192 }
161 193 }
162 194 };
163 195 }
164 196
165 197 subcommands! {
166 198 cat
167 199 debugdata
168 200 debugrequirements
169 201 files
170 202 root
171 203 config
172 204 }
173 205 pub struct CliInvocation<'a> {
174 206 ui: &'a Ui,
175 207 subcommand_args: &'a ArgMatches<'a>,
176 208 config: &'a Config,
177 209 /// References inside `Result` is a bit peculiar but allow
178 210 /// `invocation.repo?` to work out with `&CliInvocation` since this
179 211 /// `Result` type is `Copy`.
180 212 repo: Result<&'a Repo, &'a NoRepoInCwdError>,
181 213 }
182 214
183 215 struct NoRepoInCwdError {
184 216 cwd: PathBuf,
185 217 }
186 218
187 219 /// CLI arguments to be parsed "early" in order to be able to read
188 220 /// configuration before using Clap. Ideally we would also use Clap for this,
189 221 /// see <https://github.com/clap-rs/clap/discussions/2366>.
190 222 ///
191 223 /// These arguments are still declared when we do use Clap later, so that Clap
192 224 /// does not return an error for their presence.
193 225 struct EarlyArgs {
194 226 /// Values of all `--config` arguments. (Possibly none)
195 227 config: Vec<Vec<u8>>,
196 228 /// Value of the `-R` or `--repository` argument, if any.
197 229 repo: Option<Vec<u8>>,
198 230 }
199 231
200 232 impl EarlyArgs {
201 233 fn parse(args: impl IntoIterator<Item = OsString>) -> Self {
202 234 let mut args = args.into_iter().map(get_bytes_from_os_str);
203 235 let mut config = Vec::new();
204 236 let mut repo = None;
205 237 // Use `while let` instead of `for` so that we can also call
206 238 // `args.next()` inside the loop.
207 239 while let Some(arg) = args.next() {
208 240 if arg == b"--config" {
209 241 if let Some(value) = args.next() {
210 242 config.push(value)
211 243 }
212 244 } else if let Some(value) = arg.drop_prefix(b"--config=") {
213 245 config.push(value.to_owned())
214 246 }
215 247
216 248 if arg == b"--repository" || arg == b"-R" {
217 249 if let Some(value) = args.next() {
218 250 repo = Some(value)
219 251 }
220 252 } else if let Some(value) = arg.drop_prefix(b"--repository=") {
221 253 repo = Some(value.to_owned())
222 254 } else if let Some(value) = arg.drop_prefix(b"-R") {
223 255 repo = Some(value.to_owned())
224 256 }
225 257 }
226 258 Self { config, repo }
227 259 }
228 260 }
261
262 /// What to do when encountering some unsupported feature.
263 ///
264 /// See `HgError::UnsupportedFeature` and `CommandError::UnsupportedFeature`.
265 enum OnUnsupported {
266 /// Print an error message describing what feature is not supported,
267 /// and exit with code 252.
268 Abort,
269 /// Silently exit with code 252.
270 AbortSilent,
271 }
272
273 impl OnUnsupported {
274 fn from_config(config: &Config) -> Self {
275 let default = OnUnsupported::Abort;
276 match config.get(b"rhg", b"on-unsupported") {
277 Some(b"abort") => OnUnsupported::Abort,
278 Some(b"abort-silent") => OnUnsupported::AbortSilent,
279 None => default,
280 Some(_) => {
281 // TODO: warn about unknown config value
282 default
283 }
284 }
285 }
286 }
@@ -1,275 +1,287 b''
1 1 #require rust
2 2
3 3 Define an rhg function that will only run if rhg exists
4 4 $ rhg() {
5 5 > if [ -f "$RUNTESTDIR/../rust/target/release/rhg" ]; then
6 6 > "$RUNTESTDIR/../rust/target/release/rhg" "$@"
7 7 > else
8 8 > echo "skipped: Cannot find rhg. Try to run cargo build in rust/rhg."
9 9 > exit 80
10 10 > fi
11 11 > }
12 12
13 13 Unimplemented command
14 14 $ rhg unimplemented-command
15 unsupported feature: error: Found argument 'unimplemented-command' which wasn't expected, or isn't valid in this context
16
17 USAGE:
18 rhg [OPTIONS] <SUBCOMMAND>
19
20 For more information try --help
21
22 [252]
23 $ rhg unimplemented-command --config rhg.on-unsupported=abort-silent
15 24 [252]
16 25
17 26 Finding root
18 27 $ rhg root
19 28 abort: no repository found in '$TESTTMP' (.hg not found)!
20 29 [255]
21 30
22 31 $ hg init repository
23 32 $ cd repository
24 33 $ rhg root
25 34 $TESTTMP/repository
26 35
27 36 Reading and setting configuration
28 37 $ echo "[ui]" >> $HGRCPATH
29 38 $ echo "username = user1" >> $HGRCPATH
30 39 $ rhg config ui.username
31 40 user1
32 41 $ echo "[ui]" >> .hg/hgrc
33 42 $ echo "username = user2" >> .hg/hgrc
34 43 $ rhg config ui.username
35 44 user2
36 45 $ rhg --config ui.username=user3 config ui.username
37 46 user3
38 47
39 48 Unwritable file descriptor
40 49 $ rhg root > /dev/full
41 50 abort: No space left on device (os error 28)
42 51 [255]
43 52
44 53 Deleted repository
45 54 $ rm -rf `pwd`
46 55 $ rhg root
47 56 abort: $ENOENT$: current directory
48 57 [255]
49 58
50 59 Listing tracked files
51 60 $ cd $TESTTMP
52 61 $ hg init repository
53 62 $ cd repository
54 63 $ for i in 1 2 3; do
55 64 > echo $i >> file$i
56 65 > hg add file$i
57 66 > done
58 67 > hg commit -m "commit $i" -q
59 68
60 69 Listing tracked files from root
61 70 $ rhg files
62 71 file1
63 72 file2
64 73 file3
65 74
66 75 Listing tracked files from subdirectory
67 76 $ mkdir -p path/to/directory
68 77 $ cd path/to/directory
69 78 $ rhg files
70 79 ../../../file1
71 80 ../../../file2
72 81 ../../../file3
73 82
74 83 Listing tracked files through broken pipe
75 84 $ rhg files | head -n 1
76 85 ../../../file1
77 86
78 87 Debuging data in inline index
79 88 $ cd $TESTTMP
80 89 $ rm -rf repository
81 90 $ hg init repository
82 91 $ cd repository
83 92 $ for i in 1 2 3 4 5 6; do
84 93 > echo $i >> file-$i
85 94 > hg add file-$i
86 95 > hg commit -m "Commit $i" -q
87 96 > done
88 97 $ rhg debugdata -c 2
89 98 8d0267cb034247ebfa5ee58ce59e22e57a492297
90 99 test
91 100 0 0
92 101 file-3
93 102
94 103 Commit 3 (no-eol)
95 104 $ rhg debugdata -m 2
96 105 file-1\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
97 106 file-2\x005d9299349fc01ddd25d0070d149b124d8f10411e (esc)
98 107 file-3\x002661d26c649684b482d10f91960cc3db683c38b4 (esc)
99 108
100 109 Debuging with full node id
101 110 $ rhg debugdata -c `hg log -r 0 -T '{node}'`
102 111 d1d1c679d3053e8926061b6f45ca52009f011e3f
103 112 test
104 113 0 0
105 114 file-1
106 115
107 116 Commit 1 (no-eol)
108 117
109 118 Specifying revisions by changeset ID
110 119 $ hg log -T '{node}\n'
111 120 c6ad58c44207b6ff8a4fbbca7045a5edaa7e908b
112 121 d654274993d0149eecc3cc03214f598320211900
113 122 f646af7e96481d3a5470b695cf30ad8e3ab6c575
114 123 cf8b83f14ead62b374b6e91a0e9303b85dfd9ed7
115 124 91c6f6e73e39318534dc415ea4e8a09c99cd74d6
116 125 6ae9681c6d30389694d8701faf24b583cf3ccafe
117 126 $ rhg files -r cf8b83
118 127 file-1
119 128 file-2
120 129 file-3
121 130 $ rhg cat -r cf8b83 file-2
122 131 2
123 132 $ rhg cat -r c file-2
124 133 abort: ambiguous revision identifier c
125 134 [255]
126 135 $ rhg cat -r d file-2
127 136 2
128 137
129 138 Cat files
130 139 $ cd $TESTTMP
131 140 $ rm -rf repository
132 141 $ hg init repository
133 142 $ cd repository
134 143 $ echo "original content" > original
135 144 $ hg add original
136 145 $ hg commit -m "add original" original
137 146 $ rhg cat -r 0 original
138 147 original content
139 148 Cat copied file should not display copy metadata
140 149 $ hg copy original copy_of_original
141 150 $ hg commit -m "add copy of original"
142 151 $ rhg cat -r 1 copy_of_original
143 152 original content
144 153
145 154 Requirements
146 155 $ rhg debugrequirements
147 156 dotencode
148 157 fncache
149 158 generaldelta
150 159 revlogv1
151 160 sparserevlog
152 161 store
153 162
154 163 $ echo indoor-pool >> .hg/requires
155 164 $ rhg files
165 unsupported feature: repository requires feature unknown to this Mercurial: indoor-pool
156 166 [252]
157 167
158 168 $ rhg cat -r 1 copy_of_original
169 unsupported feature: repository requires feature unknown to this Mercurial: indoor-pool
159 170 [252]
160 171
161 172 $ rhg debugrequirements
173 unsupported feature: repository requires feature unknown to this Mercurial: indoor-pool
162 174 [252]
163 175
164 176 $ echo -e '\xFF' >> .hg/requires
165 177 $ rhg debugrequirements
166 178 abort: corrupted repository: parse error in 'requires' file
167 179 [255]
168 180
169 181 Persistent nodemap
170 182 $ cd $TESTTMP
171 183 $ rm -rf repository
172 184 $ hg init repository
173 185 $ cd repository
174 186 $ rhg debugrequirements | grep nodemap
175 187 [1]
176 188 $ hg debugbuilddag .+5000 --overwritten-file --config "storage.revlog.nodemap.mode=warn"
177 189 $ hg id -r tip
178 190 c3ae8dec9fad tip
179 191 $ ls .hg/store/00changelog*
180 192 .hg/store/00changelog.d
181 193 .hg/store/00changelog.i
182 194 $ rhg files -r c3ae8dec9fad
183 195 of
184 196
185 197 $ cd $TESTTMP
186 198 $ rm -rf repository
187 199 $ hg --config format.use-persistent-nodemap=True init repository
188 200 $ cd repository
189 201 $ rhg debugrequirements | grep nodemap
190 202 persistent-nodemap
191 203 $ hg debugbuilddag .+5000 --overwritten-file --config "storage.revlog.nodemap.mode=warn"
192 204 $ hg id -r tip
193 205 c3ae8dec9fad tip
194 206 $ ls .hg/store/00changelog*
195 207 .hg/store/00changelog-*.nd (glob)
196 208 .hg/store/00changelog.d
197 209 .hg/store/00changelog.i
198 210 .hg/store/00changelog.n
199 211
200 212 Specifying revisions by changeset ID
201 213 $ rhg files -r c3ae8dec9fad
202 214 of
203 215 $ rhg cat -r c3ae8dec9fad of
204 216 r5000
205 217
206 218 Crate a shared repository
207 219
208 220 $ echo "[extensions]" >> $HGRCPATH
209 221 $ echo "share = " >> $HGRCPATH
210 222
211 223 $ cd $TESTTMP
212 224 $ hg init repo1
213 225 $ echo a > repo1/a
214 226 $ hg -R repo1 commit -A -m'init'
215 227 adding a
216 228
217 229 $ hg share repo1 repo2
218 230 updating working directory
219 231 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
220 232
221 233 And check that basic rhg commands work with sharing
222 234
223 235 $ rhg files -R repo2
224 236 repo2/a
225 237 $ rhg -R repo2 cat -r 0 repo2/a
226 238 a
227 239
228 240 Same with relative sharing
229 241
230 242 $ hg share repo2 repo3 --relative
231 243 updating working directory
232 244 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
233 245
234 246 $ rhg files -R repo3
235 247 repo3/a
236 248 $ rhg -R repo3 cat -r 0 repo3/a
237 249 a
238 250
239 251 Same with share-safe
240 252
241 253 $ echo "[format]" >> $HGRCPATH
242 254 $ echo "use-share-safe = True" >> $HGRCPATH
243 255
244 256 $ cd $TESTTMP
245 257 $ hg init repo4
246 258 $ cd repo4
247 259 $ echo a > a
248 260 $ hg commit -A -m'init'
249 261 adding a
250 262
251 263 $ cd ..
252 264 $ hg share repo4 repo5
253 265 updating working directory
254 266 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
255 267
256 268 And check that basic rhg commands work with sharing
257 269
258 270 $ cd repo5
259 271 $ rhg files
260 272 a
261 273 $ rhg cat -r 0 a
262 274 a
263 275
264 276 The blackbox extension is supported
265 277
266 278 $ echo "[extensions]" >> $HGRCPATH
267 279 $ echo "blackbox =" >> $HGRCPATH
268 280 $ echo "[blackbox]" >> $HGRCPATH
269 281 $ echo "maxsize = 1" >> $HGRCPATH
270 282 $ rhg files > /dev/null
271 283 $ cat .hg/blackbox.log
272 284 ????/??/?? ??:??:??.??? * @d3873e73d99ef67873dac33fbcc66268d5d2b6f4 (*)> (rust) files exited 0 after 0.??? seconds (glob)
273 285 $ cat .hg/blackbox.log.1
274 286 ????/??/?? ??:??:??.??? * @d3873e73d99ef67873dac33fbcc66268d5d2b6f4 (*)> (rust) files (glob)
275 287
General Comments 0
You need to be logged in to leave comments. Login now