##// END OF EJS Templates
rhg: Remove error message on unsupported CLI arguments...
Simon Sapin -
r47333:21d3b40b default
parent child Browse files
Show More
@@ -1,115 +1,123
1 use crate::ui::utf8_to_local;
1 use crate::ui::utf8_to_local;
2 use crate::ui::UiError;
2 use crate::ui::UiError;
3 use format_bytes::format_bytes;
3 use format_bytes::format_bytes;
4 use hg::config::{ConfigError, ConfigParseError};
4 use hg::config::{ConfigError, ConfigParseError};
5 use hg::errors::HgError;
5 use hg::errors::HgError;
6 use hg::repo::RepoError;
6 use hg::repo::RepoError;
7 use hg::revlog::revlog::RevlogError;
7 use hg::revlog::revlog::RevlogError;
8 use hg::utils::files::get_bytes_from_path;
8 use hg::utils::files::get_bytes_from_path;
9 use std::convert::From;
9 use std::convert::From;
10
10
11 /// The kind of command error
11 /// The kind of command error
12 #[derive(Debug)]
12 #[derive(Debug)]
13 pub enum CommandError {
13 pub enum CommandError {
14 /// Exit with an error message and "standard" failure exit code.
14 /// Exit with an error message and "standard" failure exit code.
15 Abort { message: Vec<u8> },
15 Abort { message: Vec<u8> },
16
16
17 /// A mercurial capability as not been implemented.
17 /// A mercurial capability as not been implemented.
18 ///
18 ///
19 /// There is no error message printed in this case.
19 /// There is no error message printed in this case.
20 /// Instead, we exit with a specic status code and a wrapper script may
20 /// Instead, we exit with a specic status code and a wrapper script may
21 /// fallback to Python-based Mercurial.
21 /// fallback to Python-based Mercurial.
22 Unimplemented,
22 Unimplemented,
23 }
23 }
24
24
25 impl CommandError {
25 impl CommandError {
26 pub fn abort(message: impl AsRef<str>) -> Self {
26 pub fn abort(message: impl AsRef<str>) -> Self {
27 CommandError::Abort {
27 CommandError::Abort {
28 // TODO: bytes-based (instead of Unicode-based) formatting
28 // TODO: bytes-based (instead of Unicode-based) formatting
29 // of error messages to handle non-UTF-8 filenames etc:
29 // of error messages to handle non-UTF-8 filenames etc:
30 // https://www.mercurial-scm.org/wiki/EncodingStrategy#Mixing_output
30 // https://www.mercurial-scm.org/wiki/EncodingStrategy#Mixing_output
31 message: utf8_to_local(message.as_ref()).into(),
31 message: utf8_to_local(message.as_ref()).into(),
32 }
32 }
33 }
33 }
34 }
34 }
35
35
36 /// For now we don’t differenciate between invalid CLI args and valid for `hg`
37 /// but not supported yet by `rhg`.
38 impl From<clap::Error> for CommandError {
39 fn from(_: clap::Error) -> Self {
40 CommandError::Unimplemented
41 }
42 }
43
36 impl From<HgError> for CommandError {
44 impl From<HgError> for CommandError {
37 fn from(error: HgError) -> Self {
45 fn from(error: HgError) -> Self {
38 match error {
46 match error {
39 HgError::UnsupportedFeature(_) => CommandError::Unimplemented,
47 HgError::UnsupportedFeature(_) => CommandError::Unimplemented,
40 _ => CommandError::abort(error.to_string()),
48 _ => CommandError::abort(error.to_string()),
41 }
49 }
42 }
50 }
43 }
51 }
44
52
45 impl From<UiError> for CommandError {
53 impl From<UiError> for CommandError {
46 fn from(_error: UiError) -> Self {
54 fn from(_error: UiError) -> Self {
47 // If we already failed writing to stdout or stderr,
55 // If we already failed writing to stdout or stderr,
48 // writing an error message to stderr about it would be likely to fail
56 // writing an error message to stderr about it would be likely to fail
49 // too.
57 // too.
50 CommandError::abort("")
58 CommandError::abort("")
51 }
59 }
52 }
60 }
53
61
54 impl From<RepoError> for CommandError {
62 impl From<RepoError> for CommandError {
55 fn from(error: RepoError) -> Self {
63 fn from(error: RepoError) -> Self {
56 match error {
64 match error {
57 RepoError::NotFound { at } => CommandError::Abort {
65 RepoError::NotFound { at } => CommandError::Abort {
58 message: format_bytes!(
66 message: format_bytes!(
59 b"no repository found in '{}' (.hg not found)!",
67 b"no repository found in '{}' (.hg not found)!",
60 get_bytes_from_path(at)
68 get_bytes_from_path(at)
61 ),
69 ),
62 },
70 },
63 RepoError::ConfigParseError(error) => error.into(),
71 RepoError::ConfigParseError(error) => error.into(),
64 RepoError::Other(error) => error.into(),
72 RepoError::Other(error) => error.into(),
65 }
73 }
66 }
74 }
67 }
75 }
68
76
69 impl From<ConfigError> for CommandError {
77 impl From<ConfigError> for CommandError {
70 fn from(error: ConfigError) -> Self {
78 fn from(error: ConfigError) -> Self {
71 match error {
79 match error {
72 ConfigError::Parse(error) => error.into(),
80 ConfigError::Parse(error) => error.into(),
73 ConfigError::Other(error) => error.into(),
81 ConfigError::Other(error) => error.into(),
74 }
82 }
75 }
83 }
76 }
84 }
77
85
78 impl From<ConfigParseError> for CommandError {
86 impl From<ConfigParseError> for CommandError {
79 fn from(error: ConfigParseError) -> Self {
87 fn from(error: ConfigParseError) -> Self {
80 let ConfigParseError {
88 let ConfigParseError {
81 origin,
89 origin,
82 line,
90 line,
83 bytes,
91 bytes,
84 } = error;
92 } = error;
85 let line_message = if let Some(line_number) = line {
93 let line_message = if let Some(line_number) = line {
86 format_bytes!(b" at line {}", line_number.to_string().into_bytes())
94 format_bytes!(b" at line {}", line_number.to_string().into_bytes())
87 } else {
95 } else {
88 Vec::new()
96 Vec::new()
89 };
97 };
90 CommandError::Abort {
98 CommandError::Abort {
91 message: format_bytes!(
99 message: format_bytes!(
92 b"config parse error in {}{}: '{}'",
100 b"config parse error in {}{}: '{}'",
93 origin,
101 origin,
94 line_message,
102 line_message,
95 bytes
103 bytes
96 ),
104 ),
97 }
105 }
98 }
106 }
99 }
107 }
100
108
101 impl From<(RevlogError, &str)> for CommandError {
109 impl From<(RevlogError, &str)> for CommandError {
102 fn from((err, rev): (RevlogError, &str)) -> CommandError {
110 fn from((err, rev): (RevlogError, &str)) -> CommandError {
103 match err {
111 match err {
104 RevlogError::InvalidRevision => CommandError::abort(format!(
112 RevlogError::InvalidRevision => CommandError::abort(format!(
105 "invalid revision identifier {}",
113 "invalid revision identifier {}",
106 rev
114 rev
107 )),
115 )),
108 RevlogError::AmbiguousPrefix => CommandError::abort(format!(
116 RevlogError::AmbiguousPrefix => CommandError::abort(format!(
109 "ambiguous revision identifier {}",
117 "ambiguous revision identifier {}",
110 rev
118 rev
111 )),
119 )),
112 RevlogError::Other(error) => error.into(),
120 RevlogError::Other(error) => error.into(),
113 }
121 }
114 }
122 }
115 }
123 }
@@ -1,138 +1,135
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::ArgMatches;
5 use clap::ArgMatches;
6 use format_bytes::format_bytes;
6 use format_bytes::format_bytes;
7 use std::path::Path;
7 use std::path::Path;
8
8
9 mod error;
9 mod error;
10 mod exitcode;
10 mod exitcode;
11 mod ui;
11 mod ui;
12 use error::CommandError;
12 use error::CommandError;
13
13
14 fn add_global_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
14 fn add_global_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
15 app.arg(
15 app.arg(
16 Arg::with_name("repository")
16 Arg::with_name("repository")
17 .help("repository root directory")
17 .help("repository root directory")
18 .short("-R")
18 .short("-R")
19 .long("--repository")
19 .long("--repository")
20 .value_name("REPO")
20 .value_name("REPO")
21 .takes_value(true),
21 .takes_value(true),
22 )
22 )
23 .arg(
23 .arg(
24 Arg::with_name("config")
24 Arg::with_name("config")
25 .help("set/override config option (use 'section.name=value')")
25 .help("set/override config option (use 'section.name=value')")
26 .long("--config")
26 .long("--config")
27 .value_name("CONFIG")
27 .value_name("CONFIG")
28 .takes_value(true)
28 .takes_value(true)
29 // Ok: `--config section.key1=val --config section.key2=val2`
29 // Ok: `--config section.key1=val --config section.key2=val2`
30 .multiple(true)
30 .multiple(true)
31 // Not ok: `--config section.key1=val section.key2=val2`
31 // Not ok: `--config section.key1=val section.key2=val2`
32 .number_of_values(1),
32 .number_of_values(1),
33 )
33 )
34 }
34 }
35
35
36 fn main() {
36 fn main_with_result(ui: &ui::Ui) -> Result<(), CommandError> {
37 env_logger::init();
37 env_logger::init();
38 let app = App::new("rhg")
38 let app = App::new("rhg")
39 .setting(AppSettings::AllowInvalidUtf8)
39 .setting(AppSettings::AllowInvalidUtf8)
40 .setting(AppSettings::SubcommandRequired)
40 .setting(AppSettings::SubcommandRequired)
41 .setting(AppSettings::VersionlessSubcommands)
41 .setting(AppSettings::VersionlessSubcommands)
42 .version("0.0.1");
42 .version("0.0.1");
43 let app = add_global_args(app);
43 let app = add_global_args(app);
44 let app = add_subcommand_args(app);
44 let app = add_subcommand_args(app);
45
45
46 let ui = ui::Ui::new();
46 let matches = app.clone().get_matches_safe()?;
47
48 let matches = app.clone().get_matches_safe().unwrap_or_else(|err| {
49 let _ = ui.writeln_stderr_str(&err.message);
50 std::process::exit(exitcode::UNIMPLEMENTED)
51 });
52
47
53 let (subcommand_name, subcommand_matches) = matches.subcommand();
48 let (subcommand_name, subcommand_matches) = matches.subcommand();
54 let run = subcommand_run_fn(subcommand_name)
49 let run = subcommand_run_fn(subcommand_name)
55 .expect("unknown subcommand name from clap despite AppSettings::SubcommandRequired");
50 .expect("unknown subcommand name from clap despite AppSettings::SubcommandRequired");
56 let args = subcommand_matches
51 let args = subcommand_matches
57 .expect("no subcommand arguments from clap despite AppSettings::SubcommandRequired");
52 .expect("no subcommand arguments from clap despite AppSettings::SubcommandRequired");
58
53
59 // Global arguments can be in either based on e.g. `hg -R ./foo log` v.s.
54 // Global arguments can be in either based on e.g. `hg -R ./foo log` v.s.
60 // `hg log -R ./foo`
55 // `hg log -R ./foo`
61 let value_of_global_arg =
56 let value_of_global_arg =
62 |name| args.value_of_os(name).or_else(|| matches.value_of_os(name));
57 |name| args.value_of_os(name).or_else(|| matches.value_of_os(name));
63 // For arguments where multiple occurences are allowed, return a
58 // For arguments where multiple occurences are allowed, return a
64 // possibly-iterator of all values.
59 // possibly-iterator of all values.
65 let values_of_global_arg = |name: &str| {
60 let values_of_global_arg = |name: &str| {
66 let a = matches.values_of_os(name).into_iter().flatten();
61 let a = matches.values_of_os(name).into_iter().flatten();
67 let b = args.values_of_os(name).into_iter().flatten();
62 let b = args.values_of_os(name).into_iter().flatten();
68 a.chain(b)
63 a.chain(b)
69 };
64 };
70
65
71 let repo_path = value_of_global_arg("repository").map(Path::new);
66 let repo_path = value_of_global_arg("repository").map(Path::new);
72 let result = (|| -> Result<(), CommandError> {
73 let config_args = values_of_global_arg("config")
67 let config_args = values_of_global_arg("config")
74 // `get_bytes_from_path` works for OsStr the same as for Path
68 // `get_bytes_from_path` works for OsStr the same as for Path
75 .map(hg::utils::files::get_bytes_from_path);
69 .map(hg::utils::files::get_bytes_from_path);
76 let config = hg::config::Config::load(config_args)?;
70 let config = hg::config::Config::load(config_args)?;
77 run(&ui, &config, repo_path, args)
71 run(&ui, &config, repo_path, args)
78 })();
72 }
79
73
80 let exit_code = match result {
74 fn main() {
81 Ok(_) => exitcode::OK,
75 let ui = ui::Ui::new();
76
77 let exit_code = match main_with_result(&ui) {
78 Ok(()) => exitcode::OK,
82
79
83 // Exit with a specific code and no error message to let a potential
80 // Exit with a specific code and no error message to let a potential
84 // wrapper script fallback to Python-based Mercurial.
81 // wrapper script fallback to Python-based Mercurial.
85 Err(CommandError::Unimplemented) => exitcode::UNIMPLEMENTED,
82 Err(CommandError::Unimplemented) => exitcode::UNIMPLEMENTED,
86
83
87 Err(CommandError::Abort { message }) => {
84 Err(CommandError::Abort { message }) => {
88 if !message.is_empty() {
85 if !message.is_empty() {
89 // Ignore errors when writing to stderr, we’re already exiting
86 // Ignore errors when writing to stderr, we’re already exiting
90 // with failure code so there’s not much more we can do.
87 // with failure code so there’s not much more we can do.
91 let _ =
88 let _ =
92 ui.write_stderr(&format_bytes!(b"abort: {}\n", message));
89 ui.write_stderr(&format_bytes!(b"abort: {}\n", message));
93 }
90 }
94 exitcode::ABORT
91 exitcode::ABORT
95 }
92 }
96 };
93 };
97 std::process::exit(exit_code)
94 std::process::exit(exit_code)
98 }
95 }
99
96
100 macro_rules! subcommands {
97 macro_rules! subcommands {
101 ($( $command: ident )+) => {
98 ($( $command: ident )+) => {
102 mod commands {
99 mod commands {
103 $(
100 $(
104 pub mod $command;
101 pub mod $command;
105 )+
102 )+
106 }
103 }
107
104
108 fn add_subcommand_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
105 fn add_subcommand_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
109 app
106 app
110 $(
107 $(
111 .subcommand(add_global_args(commands::$command::args()))
108 .subcommand(add_global_args(commands::$command::args()))
112 )+
109 )+
113 }
110 }
114
111
115 fn subcommand_run_fn(name: &str) -> Option<fn(
112 fn subcommand_run_fn(name: &str) -> Option<fn(
116 &ui::Ui,
113 &ui::Ui,
117 &hg::config::Config,
114 &hg::config::Config,
118 Option<&Path>,
115 Option<&Path>,
119 &ArgMatches,
116 &ArgMatches,
120 ) -> Result<(), CommandError>> {
117 ) -> Result<(), CommandError>> {
121 match name {
118 match name {
122 $(
119 $(
123 stringify!($command) => Some(commands::$command::run),
120 stringify!($command) => Some(commands::$command::run),
124 )+
121 )+
125 _ => None,
122 _ => None,
126 }
123 }
127 }
124 }
128 };
125 };
129 }
126 }
130
127
131 subcommands! {
128 subcommands! {
132 cat
129 cat
133 debugdata
130 debugdata
134 debugrequirements
131 debugrequirements
135 files
132 files
136 root
133 root
137 config
134 config
138 }
135 }
@@ -1,117 +1,112
1 use format_bytes::format_bytes;
1 use format_bytes::format_bytes;
2 use std::borrow::Cow;
2 use std::borrow::Cow;
3 use std::io;
3 use std::io;
4 use std::io::{ErrorKind, Write};
4 use std::io::{ErrorKind, Write};
5
5
6 #[derive(Debug)]
6 #[derive(Debug)]
7 pub struct Ui {
7 pub struct Ui {
8 stdout: std::io::Stdout,
8 stdout: std::io::Stdout,
9 stderr: std::io::Stderr,
9 stderr: std::io::Stderr,
10 }
10 }
11
11
12 /// The kind of user interface error
12 /// The kind of user interface error
13 pub enum UiError {
13 pub enum UiError {
14 /// The standard output stream cannot be written to
14 /// The standard output stream cannot be written to
15 StdoutError(io::Error),
15 StdoutError(io::Error),
16 /// The standard error stream cannot be written to
16 /// The standard error stream cannot be written to
17 StderrError(io::Error),
17 StderrError(io::Error),
18 }
18 }
19
19
20 /// The commandline user interface
20 /// The commandline user interface
21 impl Ui {
21 impl Ui {
22 pub fn new() -> Self {
22 pub fn new() -> Self {
23 Ui {
23 Ui {
24 stdout: std::io::stdout(),
24 stdout: std::io::stdout(),
25 stderr: std::io::stderr(),
25 stderr: std::io::stderr(),
26 }
26 }
27 }
27 }
28
28
29 /// Returns a buffered handle on stdout for faster batch printing
29 /// Returns a buffered handle on stdout for faster batch printing
30 /// operations.
30 /// operations.
31 pub fn stdout_buffer(&self) -> StdoutBuffer<std::io::StdoutLock> {
31 pub fn stdout_buffer(&self) -> StdoutBuffer<std::io::StdoutLock> {
32 StdoutBuffer::new(self.stdout.lock())
32 StdoutBuffer::new(self.stdout.lock())
33 }
33 }
34
34
35 /// Write bytes to stdout
35 /// Write bytes to stdout
36 pub fn write_stdout(&self, bytes: &[u8]) -> Result<(), UiError> {
36 pub fn write_stdout(&self, bytes: &[u8]) -> Result<(), UiError> {
37 let mut stdout = self.stdout.lock();
37 let mut stdout = self.stdout.lock();
38
38
39 stdout.write_all(bytes).or_else(handle_stdout_error)?;
39 stdout.write_all(bytes).or_else(handle_stdout_error)?;
40
40
41 stdout.flush().or_else(handle_stdout_error)
41 stdout.flush().or_else(handle_stdout_error)
42 }
42 }
43
43
44 /// Write bytes to stderr
44 /// Write bytes to stderr
45 pub fn write_stderr(&self, bytes: &[u8]) -> Result<(), UiError> {
45 pub fn write_stderr(&self, bytes: &[u8]) -> Result<(), UiError> {
46 let mut stderr = self.stderr.lock();
46 let mut stderr = self.stderr.lock();
47
47
48 stderr.write_all(bytes).or_else(handle_stderr_error)?;
48 stderr.write_all(bytes).or_else(handle_stderr_error)?;
49
49
50 stderr.flush().or_else(handle_stderr_error)
50 stderr.flush().or_else(handle_stderr_error)
51 }
51 }
52
53 /// Write string line to stderr
54 pub fn writeln_stderr_str(&self, s: &str) -> Result<(), UiError> {
55 self.write_stderr(&format!("{}\n", s).as_bytes())
56 }
57 }
52 }
58
53
59 /// A buffered stdout writer for faster batch printing operations.
54 /// A buffered stdout writer for faster batch printing operations.
60 pub struct StdoutBuffer<W: Write> {
55 pub struct StdoutBuffer<W: Write> {
61 buf: io::BufWriter<W>,
56 buf: io::BufWriter<W>,
62 }
57 }
63
58
64 impl<W: Write> StdoutBuffer<W> {
59 impl<W: Write> StdoutBuffer<W> {
65 pub fn new(writer: W) -> Self {
60 pub fn new(writer: W) -> Self {
66 let buf = io::BufWriter::new(writer);
61 let buf = io::BufWriter::new(writer);
67 Self { buf }
62 Self { buf }
68 }
63 }
69
64
70 /// Write bytes to stdout buffer
65 /// Write bytes to stdout buffer
71 pub fn write_all(&mut self, bytes: &[u8]) -> Result<(), UiError> {
66 pub fn write_all(&mut self, bytes: &[u8]) -> Result<(), UiError> {
72 self.buf.write_all(bytes).or_else(handle_stdout_error)
67 self.buf.write_all(bytes).or_else(handle_stdout_error)
73 }
68 }
74
69
75 /// Flush bytes to stdout
70 /// Flush bytes to stdout
76 pub fn flush(&mut self) -> Result<(), UiError> {
71 pub fn flush(&mut self) -> Result<(), UiError> {
77 self.buf.flush().or_else(handle_stdout_error)
72 self.buf.flush().or_else(handle_stdout_error)
78 }
73 }
79 }
74 }
80
75
81 /// Sometimes writing to stdout is not possible, try writing to stderr to
76 /// Sometimes writing to stdout is not possible, try writing to stderr to
82 /// signal that failure, otherwise just bail.
77 /// signal that failure, otherwise just bail.
83 fn handle_stdout_error(error: io::Error) -> Result<(), UiError> {
78 fn handle_stdout_error(error: io::Error) -> Result<(), UiError> {
84 if let ErrorKind::BrokenPipe = error.kind() {
79 if let ErrorKind::BrokenPipe = error.kind() {
85 // This makes `| head` work for example
80 // This makes `| head` work for example
86 return Ok(());
81 return Ok(());
87 }
82 }
88 let mut stderr = io::stderr();
83 let mut stderr = io::stderr();
89
84
90 stderr
85 stderr
91 .write_all(&format_bytes!(
86 .write_all(&format_bytes!(
92 b"abort: {}\n",
87 b"abort: {}\n",
93 error.to_string().as_bytes()
88 error.to_string().as_bytes()
94 ))
89 ))
95 .map_err(UiError::StderrError)?;
90 .map_err(UiError::StderrError)?;
96
91
97 stderr.flush().map_err(UiError::StderrError)?;
92 stderr.flush().map_err(UiError::StderrError)?;
98
93
99 Err(UiError::StdoutError(error))
94 Err(UiError::StdoutError(error))
100 }
95 }
101
96
102 /// Sometimes writing to stderr is not possible.
97 /// Sometimes writing to stderr is not possible.
103 fn handle_stderr_error(error: io::Error) -> Result<(), UiError> {
98 fn handle_stderr_error(error: io::Error) -> Result<(), UiError> {
104 // A broken pipe should not result in a error
99 // A broken pipe should not result in a error
105 // like with `| head` for example
100 // like with `| head` for example
106 if let ErrorKind::BrokenPipe = error.kind() {
101 if let ErrorKind::BrokenPipe = error.kind() {
107 return Ok(());
102 return Ok(());
108 }
103 }
109 Err(UiError::StdoutError(error))
104 Err(UiError::StdoutError(error))
110 }
105 }
111
106
112 /// Encode rust strings according to the user system.
107 /// Encode rust strings according to the user system.
113 pub fn utf8_to_local(s: &str) -> Cow<[u8]> {
108 pub fn utf8_to_local(s: &str) -> Cow<[u8]> {
114 // TODO encode for the user's system //
109 // TODO encode for the user's system //
115 let bytes = s.as_bytes();
110 let bytes = s.as_bytes();
116 Cow::Borrowed(bytes)
111 Cow::Borrowed(bytes)
117 }
112 }
@@ -1,269 +1,263
1 #require rust
1 #require rust
2
2
3 Define an rhg function that will only run if rhg exists
3 Define an rhg function that will only run if rhg exists
4 $ rhg() {
4 $ rhg() {
5 > if [ -f "$RUNTESTDIR/../rust/target/release/rhg" ]; then
5 > if [ -f "$RUNTESTDIR/../rust/target/release/rhg" ]; then
6 > "$RUNTESTDIR/../rust/target/release/rhg" "$@"
6 > "$RUNTESTDIR/../rust/target/release/rhg" "$@"
7 > else
7 > else
8 > echo "skipped: Cannot find rhg. Try to run cargo build in rust/rhg."
8 > echo "skipped: Cannot find rhg. Try to run cargo build in rust/rhg."
9 > exit 80
9 > exit 80
10 > fi
10 > fi
11 > }
11 > }
12
12
13 Unimplemented command
13 Unimplemented command
14 $ rhg unimplemented-command
14 $ rhg unimplemented-command
15 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 [252]
15 [252]
22
16
23 Finding root
17 Finding root
24 $ rhg root
18 $ rhg root
25 abort: no repository found in '$TESTTMP' (.hg not found)!
19 abort: no repository found in '$TESTTMP' (.hg not found)!
26 [255]
20 [255]
27
21
28 $ hg init repository
22 $ hg init repository
29 $ cd repository
23 $ cd repository
30 $ rhg root
24 $ rhg root
31 $TESTTMP/repository
25 $TESTTMP/repository
32
26
33 Reading and setting configuration
27 Reading and setting configuration
34 $ echo "[ui]" >> $HGRCPATH
28 $ echo "[ui]" >> $HGRCPATH
35 $ echo "username = user1" >> $HGRCPATH
29 $ echo "username = user1" >> $HGRCPATH
36 $ rhg config ui.username
30 $ rhg config ui.username
37 user1
31 user1
38 $ echo "[ui]" >> .hg/hgrc
32 $ echo "[ui]" >> .hg/hgrc
39 $ echo "username = user2" >> .hg/hgrc
33 $ echo "username = user2" >> .hg/hgrc
40 $ rhg config ui.username
34 $ rhg config ui.username
41 user2
35 user2
42 $ rhg --config ui.username=user3 config ui.username
36 $ rhg --config ui.username=user3 config ui.username
43 user3
37 user3
44
38
45 Unwritable file descriptor
39 Unwritable file descriptor
46 $ rhg root > /dev/full
40 $ rhg root > /dev/full
47 abort: No space left on device (os error 28)
41 abort: No space left on device (os error 28)
48 [255]
42 [255]
49
43
50 Deleted repository
44 Deleted repository
51 $ rm -rf `pwd`
45 $ rm -rf `pwd`
52 $ rhg root
46 $ rhg root
53 abort: $ENOENT$: current directory
47 abort: $ENOENT$: current directory
54 [255]
48 [255]
55
49
56 Listing tracked files
50 Listing tracked files
57 $ cd $TESTTMP
51 $ cd $TESTTMP
58 $ hg init repository
52 $ hg init repository
59 $ cd repository
53 $ cd repository
60 $ for i in 1 2 3; do
54 $ for i in 1 2 3; do
61 > echo $i >> file$i
55 > echo $i >> file$i
62 > hg add file$i
56 > hg add file$i
63 > done
57 > done
64 > hg commit -m "commit $i" -q
58 > hg commit -m "commit $i" -q
65
59
66 Listing tracked files from root
60 Listing tracked files from root
67 $ rhg files
61 $ rhg files
68 file1
62 file1
69 file2
63 file2
70 file3
64 file3
71
65
72 Listing tracked files from subdirectory
66 Listing tracked files from subdirectory
73 $ mkdir -p path/to/directory
67 $ mkdir -p path/to/directory
74 $ cd path/to/directory
68 $ cd path/to/directory
75 $ rhg files
69 $ rhg files
76 ../../../file1
70 ../../../file1
77 ../../../file2
71 ../../../file2
78 ../../../file3
72 ../../../file3
79
73
80 Listing tracked files through broken pipe
74 Listing tracked files through broken pipe
81 $ rhg files | head -n 1
75 $ rhg files | head -n 1
82 ../../../file1
76 ../../../file1
83
77
84 Debuging data in inline index
78 Debuging data in inline index
85 $ cd $TESTTMP
79 $ cd $TESTTMP
86 $ rm -rf repository
80 $ rm -rf repository
87 $ hg init repository
81 $ hg init repository
88 $ cd repository
82 $ cd repository
89 $ for i in 1 2 3 4 5 6; do
83 $ for i in 1 2 3 4 5 6; do
90 > echo $i >> file-$i
84 > echo $i >> file-$i
91 > hg add file-$i
85 > hg add file-$i
92 > hg commit -m "Commit $i" -q
86 > hg commit -m "Commit $i" -q
93 > done
87 > done
94 $ rhg debugdata -c 2
88 $ rhg debugdata -c 2
95 8d0267cb034247ebfa5ee58ce59e22e57a492297
89 8d0267cb034247ebfa5ee58ce59e22e57a492297
96 test
90 test
97 0 0
91 0 0
98 file-3
92 file-3
99
93
100 Commit 3 (no-eol)
94 Commit 3 (no-eol)
101 $ rhg debugdata -m 2
95 $ rhg debugdata -m 2
102 file-1\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
96 file-1\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
103 file-2\x005d9299349fc01ddd25d0070d149b124d8f10411e (esc)
97 file-2\x005d9299349fc01ddd25d0070d149b124d8f10411e (esc)
104 file-3\x002661d26c649684b482d10f91960cc3db683c38b4 (esc)
98 file-3\x002661d26c649684b482d10f91960cc3db683c38b4 (esc)
105
99
106 Debuging with full node id
100 Debuging with full node id
107 $ rhg debugdata -c `hg log -r 0 -T '{node}'`
101 $ rhg debugdata -c `hg log -r 0 -T '{node}'`
108 d1d1c679d3053e8926061b6f45ca52009f011e3f
102 d1d1c679d3053e8926061b6f45ca52009f011e3f
109 test
103 test
110 0 0
104 0 0
111 file-1
105 file-1
112
106
113 Commit 1 (no-eol)
107 Commit 1 (no-eol)
114
108
115 Specifying revisions by changeset ID
109 Specifying revisions by changeset ID
116 $ hg log -T '{node}\n'
110 $ hg log -T '{node}\n'
117 c6ad58c44207b6ff8a4fbbca7045a5edaa7e908b
111 c6ad58c44207b6ff8a4fbbca7045a5edaa7e908b
118 d654274993d0149eecc3cc03214f598320211900
112 d654274993d0149eecc3cc03214f598320211900
119 f646af7e96481d3a5470b695cf30ad8e3ab6c575
113 f646af7e96481d3a5470b695cf30ad8e3ab6c575
120 cf8b83f14ead62b374b6e91a0e9303b85dfd9ed7
114 cf8b83f14ead62b374b6e91a0e9303b85dfd9ed7
121 91c6f6e73e39318534dc415ea4e8a09c99cd74d6
115 91c6f6e73e39318534dc415ea4e8a09c99cd74d6
122 6ae9681c6d30389694d8701faf24b583cf3ccafe
116 6ae9681c6d30389694d8701faf24b583cf3ccafe
123 $ rhg files -r cf8b83
117 $ rhg files -r cf8b83
124 file-1
118 file-1
125 file-2
119 file-2
126 file-3
120 file-3
127 $ rhg cat -r cf8b83 file-2
121 $ rhg cat -r cf8b83 file-2
128 2
122 2
129 $ rhg cat -r c file-2
123 $ rhg cat -r c file-2
130 abort: ambiguous revision identifier c
124 abort: ambiguous revision identifier c
131 [255]
125 [255]
132 $ rhg cat -r d file-2
126 $ rhg cat -r d file-2
133 2
127 2
134
128
135 Cat files
129 Cat files
136 $ cd $TESTTMP
130 $ cd $TESTTMP
137 $ rm -rf repository
131 $ rm -rf repository
138 $ hg init repository
132 $ hg init repository
139 $ cd repository
133 $ cd repository
140 $ echo "original content" > original
134 $ echo "original content" > original
141 $ hg add original
135 $ hg add original
142 $ hg commit -m "add original" original
136 $ hg commit -m "add original" original
143 $ rhg cat -r 0 original
137 $ rhg cat -r 0 original
144 original content
138 original content
145 Cat copied file should not display copy metadata
139 Cat copied file should not display copy metadata
146 $ hg copy original copy_of_original
140 $ hg copy original copy_of_original
147 $ hg commit -m "add copy of original"
141 $ hg commit -m "add copy of original"
148 $ rhg cat -r 1 copy_of_original
142 $ rhg cat -r 1 copy_of_original
149 original content
143 original content
150
144
151 Requirements
145 Requirements
152 $ rhg debugrequirements
146 $ rhg debugrequirements
153 dotencode
147 dotencode
154 fncache
148 fncache
155 generaldelta
149 generaldelta
156 revlogv1
150 revlogv1
157 sparserevlog
151 sparserevlog
158 store
152 store
159
153
160 $ echo indoor-pool >> .hg/requires
154 $ echo indoor-pool >> .hg/requires
161 $ rhg files
155 $ rhg files
162 [252]
156 [252]
163
157
164 $ rhg cat -r 1 copy_of_original
158 $ rhg cat -r 1 copy_of_original
165 [252]
159 [252]
166
160
167 $ rhg debugrequirements
161 $ rhg debugrequirements
168 [252]
162 [252]
169
163
170 $ echo -e '\xFF' >> .hg/requires
164 $ echo -e '\xFF' >> .hg/requires
171 $ rhg debugrequirements
165 $ rhg debugrequirements
172 abort: corrupted repository: parse error in 'requires' file
166 abort: corrupted repository: parse error in 'requires' file
173 [255]
167 [255]
174
168
175 Persistent nodemap
169 Persistent nodemap
176 $ cd $TESTTMP
170 $ cd $TESTTMP
177 $ rm -rf repository
171 $ rm -rf repository
178 $ hg init repository
172 $ hg init repository
179 $ cd repository
173 $ cd repository
180 $ rhg debugrequirements | grep nodemap
174 $ rhg debugrequirements | grep nodemap
181 [1]
175 [1]
182 $ hg debugbuilddag .+5000 --overwritten-file --config "storage.revlog.nodemap.mode=warn"
176 $ hg debugbuilddag .+5000 --overwritten-file --config "storage.revlog.nodemap.mode=warn"
183 $ hg id -r tip
177 $ hg id -r tip
184 c3ae8dec9fad tip
178 c3ae8dec9fad tip
185 $ ls .hg/store/00changelog*
179 $ ls .hg/store/00changelog*
186 .hg/store/00changelog.d
180 .hg/store/00changelog.d
187 .hg/store/00changelog.i
181 .hg/store/00changelog.i
188 $ rhg files -r c3ae8dec9fad
182 $ rhg files -r c3ae8dec9fad
189 of
183 of
190
184
191 $ cd $TESTTMP
185 $ cd $TESTTMP
192 $ rm -rf repository
186 $ rm -rf repository
193 $ hg --config format.use-persistent-nodemap=True init repository
187 $ hg --config format.use-persistent-nodemap=True init repository
194 $ cd repository
188 $ cd repository
195 $ rhg debugrequirements | grep nodemap
189 $ rhg debugrequirements | grep nodemap
196 persistent-nodemap
190 persistent-nodemap
197 $ hg debugbuilddag .+5000 --overwritten-file --config "storage.revlog.nodemap.mode=warn"
191 $ hg debugbuilddag .+5000 --overwritten-file --config "storage.revlog.nodemap.mode=warn"
198 $ hg id -r tip
192 $ hg id -r tip
199 c3ae8dec9fad tip
193 c3ae8dec9fad tip
200 $ ls .hg/store/00changelog*
194 $ ls .hg/store/00changelog*
201 .hg/store/00changelog-*.nd (glob)
195 .hg/store/00changelog-*.nd (glob)
202 .hg/store/00changelog.d
196 .hg/store/00changelog.d
203 .hg/store/00changelog.i
197 .hg/store/00changelog.i
204 .hg/store/00changelog.n
198 .hg/store/00changelog.n
205
199
206 Specifying revisions by changeset ID
200 Specifying revisions by changeset ID
207 $ rhg files -r c3ae8dec9fad
201 $ rhg files -r c3ae8dec9fad
208 of
202 of
209 $ rhg cat -r c3ae8dec9fad of
203 $ rhg cat -r c3ae8dec9fad of
210 r5000
204 r5000
211
205
212 Crate a shared repository
206 Crate a shared repository
213
207
214 $ echo "[extensions]" >> $HGRCPATH
208 $ echo "[extensions]" >> $HGRCPATH
215 $ echo "share = " >> $HGRCPATH
209 $ echo "share = " >> $HGRCPATH
216
210
217 $ cd $TESTTMP
211 $ cd $TESTTMP
218 $ hg init repo1
212 $ hg init repo1
219 $ echo a > repo1/a
213 $ echo a > repo1/a
220 $ hg -R repo1 commit -A -m'init'
214 $ hg -R repo1 commit -A -m'init'
221 adding a
215 adding a
222
216
223 $ hg share repo1 repo2
217 $ hg share repo1 repo2
224 updating working directory
218 updating working directory
225 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
219 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
226
220
227 And check that basic rhg commands work with sharing
221 And check that basic rhg commands work with sharing
228
222
229 $ rhg files -R repo2
223 $ rhg files -R repo2
230 repo2/a
224 repo2/a
231 $ rhg -R repo2 cat -r 0 repo2/a
225 $ rhg -R repo2 cat -r 0 repo2/a
232 a
226 a
233
227
234 Same with relative sharing
228 Same with relative sharing
235
229
236 $ hg share repo2 repo3 --relative
230 $ hg share repo2 repo3 --relative
237 updating working directory
231 updating working directory
238 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
232 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
239
233
240 $ rhg files -R repo3
234 $ rhg files -R repo3
241 repo3/a
235 repo3/a
242 $ rhg -R repo3 cat -r 0 repo3/a
236 $ rhg -R repo3 cat -r 0 repo3/a
243 a
237 a
244
238
245 Same with share-safe
239 Same with share-safe
246
240
247 $ echo "[format]" >> $HGRCPATH
241 $ echo "[format]" >> $HGRCPATH
248 $ echo "use-share-safe = True" >> $HGRCPATH
242 $ echo "use-share-safe = True" >> $HGRCPATH
249
243
250 $ cd $TESTTMP
244 $ cd $TESTTMP
251 $ hg init repo4
245 $ hg init repo4
252 $ cd repo4
246 $ cd repo4
253 $ echo a > a
247 $ echo a > a
254 $ hg commit -A -m'init'
248 $ hg commit -A -m'init'
255 adding a
249 adding a
256
250
257 $ cd ..
251 $ cd ..
258 $ hg share repo4 repo5
252 $ hg share repo4 repo5
259 updating working directory
253 updating working directory
260 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
254 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
261
255
262 And check that basic rhg commands work with sharing
256 And check that basic rhg commands work with sharing
263
257
264 $ cd repo5
258 $ cd repo5
265 $ rhg files
259 $ rhg files
266 a
260 a
267 $ rhg cat -r 0 a
261 $ rhg cat -r 0 a
268 a
262 a
269
263
General Comments 0
You need to be logged in to leave comments. Login now