D9370: hgignore: add VS Code config
SimonSapin created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D9370 AFFECTED FILES .hgignore CHANGE DETAILS diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -49,6 +49,7 @@ .DS_Store tags cscope.* +.vscode/* .idea/* .asv/* .pytype/* To: SimonSapin, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D9373: bisect: add `-G` to an `hg log` command in a test
SimonSapin created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REVISION SUMMARY This helps readers see what shape of DAG to expect REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D9373 AFFECTED FILES tests/test-bisect.t CHANGE DETAILS diff --git a/tests/test-bisect.t b/tests/test-bisect.t --- a/tests/test-bisect.t +++ b/tests/test-bisect.t @@ -14,167 +14,167 @@ adding a - $ hg log - changeset: 31:58c80a7c8a40 - tag: tip - user:test - date:Thu Jan 01 00:00:31 1970 + - summary: msg 31 - - changeset: 30:ed2d2f24b11c - user:test - date:Thu Jan 01 00:00:30 1970 + - summary: msg 30 - - changeset: 29:b5bd63375ab9 - user:test - date:Thu Jan 01 00:00:29 1970 + - summary: msg 29 - - changeset: 28:8e0c2264c8af - user:test - date:Thu Jan 01 00:00:28 1970 + - summary: msg 28 - - changeset: 27:288867a866e9 - user:test - date:Thu Jan 01 00:00:27 1970 + - summary: msg 27 - - changeset: 26:3efc6fd51aeb - user:test - date:Thu Jan 01 00:00:26 1970 + - summary: msg 26 - - changeset: 25:02a84173a97a - user:test - date:Thu Jan 01 00:00:25 1970 + - summary: msg 25 - - changeset: 24:10e0acd3809e - user:test - date:Thu Jan 01 00:00:24 1970 + - summary: msg 24 - - changeset: 23:5ec79163bff4 - user:test - date:Thu Jan 01 00:00:23 1970 + - summary: msg 23 - - changeset: 22:06c7993750ce - user:test - date:Thu Jan 01 00:00:22 1970 + - summary: msg 22 - - changeset: 21:e5db6aa3fe2a - user:test - date:Thu Jan 01 00:00:21 1970 + - summary: msg 21 - - changeset: 20:7128fb4fdbc9 - user:test - date:Thu Jan 01 00:00:20 1970 + - summary: msg 20 - - changeset: 19:52798545b482 - user:test - date:Thu Jan 01 00:00:19 1970 + - summary: msg 19 - - changeset: 18:86977a90077e - user:test - date:Thu Jan 01 00:00:18 1970 + - summary: msg 18 - - changeset: 17:03515f4a9080 - user:test - date:Thu Jan 01 00:00:17 1970 + - summary: msg 17 - - changeset: 16:a2e6ea4973e9 - user:test - date:Thu Jan 01 00:00:16 1970 + - summary: msg 16 - - changeset: 15:e7fa0811edb0 - user:test - date:Thu Jan 01 00:00:15 1970 + - summary: msg 15 - - changeset: 14:ce8f0998e922 - user:test - date:Thu Jan 01 00:00:14 1970 + - summary: msg 14 - - changeset: 13:9d7d07bc967c - user:test - date:Thu Jan 01 00:00:13 1970 + - summary: msg 13 - - changeset: 12:1941b52820a5 - user:test - date:Thu Jan 01 00:00:12 1970 + - summary: msg 12 - - changeset: 11:7b4cd9578619 - user:test - date:Thu Jan 01 00:00:11 1970 + - summary: msg 11 - - changeset: 10:7c5eff49a6b6 - user:test - date:Thu Jan 01 00:00:10 1970 + - summary: msg 10 - - changeset: 9:eb44510ef29a - user:test - date:Thu Jan 01 00:00:09 1970 + - summary: msg 9 - - changeset: 8:453eb4dba229 - user:test - date:Thu Jan 01 00:00:08 1970 + - summary: msg 8 - - changeset: 7:03750880c6b5 - user:test - date:Thu Jan 01 00:00:07 1970 + - summary: msg 7 - - changeset: 6:a3d5c6fdf0d3 - user:test - date:Thu Jan 01 00:00:06 1970 + - summary: msg 6 - - changeset: 5:7874a09ea728 - user:test - date:Thu Jan 01 00:00:05 1970 + - summary: msg 5 - - changeset: 4:9b2ba8336a65 - user:test - date:Thu Jan 01 00:00:04 1970 + - summary: msg 4 - - changeset: 3:b53bea5e2fcb - user:test - date:Thu Jan 01 00:00:03 1970 + - summary: msg 3 - - changeset: 2:db07c04beaca - user:test - date:Thu Jan 01 00:00:02 1970 + - summary: msg 2 - - changeset: 1:5cd978ea5149 - user:test - date:Thu Jan 01 00:00:01 1970 + - summary: msg 1 - - changeset: 0:b99c7b9c8e11 - user:test - date:Thu Jan 01 00:00:00 1970 + - summary: msg 0 + $ hg log -G + @ changeset: 31:58c80a7c8a40 + | tag: tip + | user:test + | date:Thu Jan 01 00:00:31 1970 + + | summary: msg 31 + | + o changeset: 30:ed2d2f24b11c + | user:test + | date:Thu Jan 01 00:00:30 1970 + + | summary: msg 30 + | + o changeset: 29:b5bd63375ab9 + | user:test + | date:Thu Jan 01 00:00:29 1970 + + | su
D9371: bisect: use tuple literal instead of split on string literal
SimonSapin created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D9371 AFFECTED FILES mercurial/commands.py CHANGE DETAILS diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -999,7 +999,7 @@ Returns 0 on success. """ # backward compatibility -if rev in b"good bad reset init".split(): +if rev in (b"good", b"bad", b"reset", b"init"): ui.warn(_(b"(use of 'hg bisect ' is deprecated)\n")) cmd, rev, extra = rev, extra, None if cmd == b"good": To: SimonSapin, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D9372: bisect: refactor to work on a list of revspecs
SimonSapin created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REVISION SUMMARY This will allow adding a `--rev` flag that can be passed more than once. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D9372 AFFECTED FILES mercurial/commands.py CHANGE DETAILS diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -907,8 +907,8 @@ def bisect( ui, repo, -rev=None, -extra=None, +positional_1=None, +positional_2=None, command=None, reset=None, good=None, @@ -998,18 +998,22 @@ Returns 0 on success. """ +rev = [] # backward compatibility -if rev in (b"good", b"bad", b"reset", b"init"): +if positional_1 in (b"good", b"bad", b"reset", b"init"): ui.warn(_(b"(use of 'hg bisect ' is deprecated)\n")) -cmd, rev, extra = rev, extra, None +cmd = positional_1 +rev.append(positional_2) if cmd == b"good": good = True elif cmd == b"bad": bad = True else: reset = True -elif extra: +elif positional_2: raise error.InputError(_(b'incompatible arguments')) +elif positional_1 is not None: +rev.append(positional_1) incompatibles = { b'--bad': bad, @@ -1033,12 +1037,13 @@ state = hbisect.load_state(repo) +if rev: +nodes = [repo[i].node() for i in scmutil.revrange(repo, rev)] +else: +nodes = [repo.lookup(b'.')] + # update state if good or bad or skip: -if rev: -nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])] -else: -nodes = [repo.lookup(b'.')] if good: state[b'good'] += nodes elif bad: @@ -1076,7 +1081,9 @@ if p2 != nullid: raise error.StateError(_(b'current bisect revision is a merge')) if rev: -node = repo[scmutil.revsingle(repo, rev, node)].node() +if not nodes: +raise error.Abort(_(b'empty revision set')) +node = repo[nodes.last()].node() with hbisect.restore_state(repo, state, node): while changesets: # update state To: SimonSapin, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D9374: bisect: add a `--rev` flag
SimonSapin created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REVISION SUMMARY This is the same as the positional argument, and can be passed more than once. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D9374 AFFECTED FILES mercurial/commands.py tests/test-bisect.t tests/test-completion.t CHANGE DETAILS diff --git a/tests/test-completion.t b/tests/test-completion.t --- a/tests/test-completion.t +++ b/tests/test-completion.t @@ -251,7 +251,7 @@ annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, skip, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, include, exclude, template archive: no-decode, prefix, rev, type, subrepos, include, exclude backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user - bisect: reset, good, bad, skip, extend, command, noupdate + bisect: reset, good, bad, skip, rev, extend, command, noupdate bookmarks: force, rev, delete, rename, inactive, list, template branch: force, clean, rev branches: active, closed, rev, template diff --git a/tests/test-bisect.t b/tests/test-bisect.t --- a/tests/test-bisect.t +++ b/tests/test-bisect.t @@ -232,8 +232,8 @@ $ hg bisect -r $ hg bisect -b "0::3" - $ hg bisect -s "13::16" - $ hg bisect -g "26::tip" + $ hg bisect -s --rev "13::16" + $ hg bisect -g --rev "26::28" --rev "29" "30::tip" Testing changeset 12:1941b52820a5 (23 changesets remaining, ~4 tests) 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ cat .hg/bisect.state diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -891,6 +891,7 @@ (b'g', b'good', False, _(b'mark changeset good')), (b'b', b'bad', False, _(b'mark changeset bad')), (b's', b'skip', False, _(b'skip testing changeset')), +(b'', b'rev', [], _(b'select the changesets to mark')), (b'e', b'extend', False, _(b'extend the bisect range')), ( b'c', @@ -909,6 +910,7 @@ repo, positional_1=None, positional_2=None, +rev=None, command=None, reset=None, good=None, @@ -998,7 +1000,6 @@ Returns 0 on success. """ -rev = [] # backward compatibility if positional_1 in (b"good", b"bad", b"reset", b"init"): ui.warn(_(b"(use of 'hg bisect ' is deprecated)\n")) To: SimonSapin, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D9397: rhg: add a `debugrequirements` subcommand
SimonSapin created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REVISION SUMMARY For now it only prints the contents of `.hg/requires` as-is, without parsing. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D9397 AFFECTED FILES rust/rhg/src/commands.rs rust/rhg/src/commands/debugrequirements.rs rust/rhg/src/error.rs rust/rhg/src/main.rs tests/test-rhg.t CHANGE DETAILS diff --git a/tests/test-rhg.t b/tests/test-rhg.t --- a/tests/test-rhg.t +++ b/tests/test-rhg.t @@ -115,3 +115,12 @@ $ hg commit -m "add copy of original" $ rhg cat -r 1 copy_of_original original content + +Requirements + $ rhg debugrequirements + dotencode + fncache + generaldelta + revlogv1 + sparserevlog + store diff --git a/rust/rhg/src/main.rs b/rust/rhg/src/main.rs --- a/rust/rhg/src/main.rs +++ b/rust/rhg/src/main.rs @@ -83,6 +83,10 @@ .required(true) .value_name("REV"), ), +) +.subcommand( +SubCommand::with_name("debugrequirements") +.about(commands::debugrequirements::HELP_TEXT), ); let matches = app.clone().get_matches_safe().unwrap_or_else(|err| { @@ -124,6 +128,10 @@ ("debugdata", Some(matches)) => { commands::debugdata::DebugDataCommand::try_from(matches)?.run(&ui) } +("debugrequirements", _) => { +commands::debugrequirements::DebugRequirementsCommand::new() +.run(&ui) +} _ => unreachable!(), // Because of AppSettings::SubcommandRequired, } } diff --git a/rust/rhg/src/error.rs b/rust/rhg/src/error.rs --- a/rust/rhg/src/error.rs +++ b/rust/rhg/src/error.rs @@ -12,6 +12,9 @@ RootNotFound(PathBuf), /// The current directory cannot be found CurrentDirNotFound(std::io::Error), +/// Error while reading or writing a file +// TODO: add the file name/path? +FileError(std::io::Error), /// The standard output stream cannot be written to StdoutError, /// The standard error stream cannot be written to @@ -27,6 +30,7 @@ match self { CommandErrorKind::RootNotFound(_) => exitcode::ABORT, CommandErrorKind::CurrentDirNotFound(_) => exitcode::ABORT, +CommandErrorKind::FileError(_) => exitcode::ABORT, CommandErrorKind::StdoutError => exitcode::ABORT, CommandErrorKind::StderrError => exitcode::ABORT, CommandErrorKind::Abort(_) => exitcode::ABORT, diff --git a/rust/rhg/src/commands/debugrequirements.rs b/rust/rhg/src/commands/debugrequirements.rs new file mode 100644 --- /dev/null +++ b/rust/rhg/src/commands/debugrequirements.rs @@ -0,0 +1,40 @@ +use crate::commands::Command; +use crate::error::{CommandError, CommandErrorKind}; +use crate::ui::Ui; +use hg::operations::FindRoot; + +pub const HELP_TEXT: &str = " +Print the current repo requirements. +"; + +pub struct DebugRequirementsCommand {} + +impl DebugRequirementsCommand { +pub fn new() -> Self { +DebugRequirementsCommand {} +} +} + +impl Command for DebugRequirementsCommand { +fn run(&self, ui: &Ui) -> Result<(), CommandError> { +let root = FindRoot::new().run()?; +let requires = root.join(".hg").join("requires"); +let requirements = match std::fs::read(requires) { +Ok(bytes) => bytes, + +// Treat a missing file the same as an empty file. +// From `mercurial/localrepo.py`: +// > requires file contains a newline-delimited list of +// > features/capabilities the opener (us) must have in order to use +// > the repository. This file was introduced in Mercurial 0.9.2, +// > which means very old repositories may not have one. We assume +// > a missing file translates to no requirements. +Err(error) if error.kind() == std::io::ErrorKind::NotFound => Vec::new(), + +Err(error) => Err(CommandErrorKind::FileError(error))?, +}; + +ui.write_stdout(&requirements)?; +Ok(()) +} +} diff --git a/rust/rhg/src/commands.rs b/rust/rhg/src/commands.rs --- a/rust/rhg/src/commands.rs +++ b/rust/rhg/src/commands.rs @@ -1,5 +1,6 @@ pub mod cat; pub mod debugdata; +pub mod debugrequirements; pub mod files; pub mod root; use crate::error::CommandError; To: SimonSapin, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D9400: rhg: check that .hg/requires is ASCII
SimonSapin created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D9400 AFFECTED FILES rust/hg-core/src/requirements.rs tests/test-rhg.t CHANGE DETAILS diff --git a/tests/test-rhg.t b/tests/test-rhg.t --- a/tests/test-rhg.t +++ b/tests/test-rhg.t @@ -140,3 +140,8 @@ sparserevlog store indoor-pool + + $ echo -e '\xFF' >> .hg/requires + $ rhg debugrequirements + abort: .hg/requires is corrupted + [255] diff --git a/rust/hg-core/src/requirements.rs b/rust/hg-core/src/requirements.rs --- a/rust/hg-core/src/requirements.rs +++ b/rust/hg-core/src/requirements.rs @@ -24,7 +24,7 @@ .map(|line| { // Python uses Unicode `str.isalnum` but feature names are all // ASCII -if line[0].is_ascii_alphanumeric() { +if line[0].is_ascii_alphanumeric() && line.is_ascii() { Ok(String::from_utf8(line.into()).unwrap()) } else { Err(()) To: SimonSapin, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D9399: rhg: exit with relevant code for unsupported requirements
SimonSapin created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D9399 AFFECTED FILES rust/hg-core/src/requirements.rs rust/rhg/src/commands/cat.rs rust/rhg/src/commands/files.rs rust/rhg/src/error.rs tests/test-rhg.t CHANGE DETAILS diff --git a/tests/test-rhg.t b/tests/test-rhg.t --- a/tests/test-rhg.t +++ b/tests/test-rhg.t @@ -124,3 +124,19 @@ revlogv1 sparserevlog store + + $ echo indoor-pool >> .hg/requires + $ rhg files + [252] + + $ rhg cat -r 1 copy_of_original + [252] + + $ rhg debugrequirements + dotencode + fncache + generaldelta + revlogv1 + sparserevlog + store + indoor-pool diff --git a/rust/rhg/src/error.rs b/rust/rhg/src/error.rs --- a/rust/rhg/src/error.rs +++ b/rust/rhg/src/error.rs @@ -30,6 +30,9 @@ match self { CommandErrorKind::RootNotFound(_) => exitcode::ABORT, CommandErrorKind::CurrentDirNotFound(_) => exitcode::ABORT, +CommandErrorKind::RequirementsError( +RequirementsError::Unsupported { .. }, +) => exitcode::UNIMPLEMENTED_COMMAND, CommandErrorKind::RequirementsError(_) => exitcode::ABORT, CommandErrorKind::StdoutError => exitcode::ABORT, CommandErrorKind::StderrError => exitcode::ABORT, diff --git a/rust/rhg/src/commands/files.rs b/rust/rhg/src/commands/files.rs --- a/rust/rhg/src/commands/files.rs +++ b/rust/rhg/src/commands/files.rs @@ -11,6 +11,7 @@ ListRevTrackedFiles, ListRevTrackedFilesError, ListRevTrackedFilesErrorKind, }; +use hg::requirements; use hg::utils::files::{get_bytes_from_path, relativize_path}; use hg::utils::hg_path::{HgPath, HgPathBuf}; use std::path::PathBuf; @@ -57,6 +58,7 @@ impl<'a> Command for FilesCommand<'a> { fn run(&self, ui: &Ui) -> Result<(), CommandError> { let root = FindRoot::new().run()?; +requirements::check(&root)?; if let Some(rev) = self.rev { let mut operation = ListRevTrackedFiles::new(&root, rev) .map_err(|e| map_rev_error(rev, e))?; diff --git a/rust/rhg/src/commands/cat.rs b/rust/rhg/src/commands/cat.rs --- a/rust/rhg/src/commands/cat.rs +++ b/rust/rhg/src/commands/cat.rs @@ -4,6 +4,7 @@ use crate::ui::Ui; use hg::operations::FindRoot; use hg::operations::{CatRev, CatRevError, CatRevErrorKind}; +use hg::requirements; use hg::utils::hg_path::HgPathBuf; use micro_timer::timed; use std::convert::TryFrom; @@ -32,6 +33,7 @@ #[timed] fn run(&self, ui: &Ui) -> Result<(), CommandError> { let root = FindRoot::new().run()?; +requirements::check(&root)?; let cwd = std::env::current_dir() .or_else(|e| Err(CommandErrorKind::CurrentDirNotFound(e)))?; diff --git a/rust/hg-core/src/requirements.rs b/rust/hg-core/src/requirements.rs --- a/rust/hg-core/src/requirements.rs +++ b/rust/hg-core/src/requirements.rs @@ -51,3 +51,22 @@ Err(error) => Err(RequirementsError::Io(error))?, } } + +pub fn check(repo_root: &Path) -> Result<(), RequirementsError> { +for feature in load(repo_root)? { +if !SUPPORTED.contains(&&*feature) { +return Err(RequirementsError::Unsupported { feature }) +} +} +Ok(()) +} + +// TODO: set this to actually-supported features +const SUPPORTED: &[&str] = &[ +"dotencode", +"fncache", +"generaldelta", +"revlogv1", +"sparserevlog", +"store", +]; To: SimonSapin, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D9398: requirements: move loading to hg-core and add parsing
SimonSapin created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REVISION SUMMARY No functional change, checking comes later. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D9398 AFFECTED FILES rust/hg-core/src/lib.rs rust/hg-core/src/requirements.rs rust/rhg/src/commands/debugrequirements.rs rust/rhg/src/error.rs CHANGE DETAILS diff --git a/rust/rhg/src/error.rs b/rust/rhg/src/error.rs --- a/rust/rhg/src/error.rs +++ b/rust/rhg/src/error.rs @@ -1,6 +1,7 @@ use crate::exitcode; use crate::ui::UiError; use hg::operations::{FindRootError, FindRootErrorKind}; +use hg::requirements::RequirementsError; use hg::utils::files::get_bytes_from_path; use std::convert::From; use std::path::PathBuf; @@ -12,9 +13,8 @@ RootNotFound(PathBuf), /// The current directory cannot be found CurrentDirNotFound(std::io::Error), -/// Error while reading or writing a file -// TODO: add the file name/path? -FileError(std::io::Error), +/// `.hg/requires` +RequirementsError(RequirementsError), /// The standard output stream cannot be written to StdoutError, /// The standard error stream cannot be written to @@ -30,7 +30,7 @@ match self { CommandErrorKind::RootNotFound(_) => exitcode::ABORT, CommandErrorKind::CurrentDirNotFound(_) => exitcode::ABORT, -CommandErrorKind::FileError(_) => exitcode::ABORT, +CommandErrorKind::RequirementsError(_) => exitcode::ABORT, CommandErrorKind::StdoutError => exitcode::ABORT, CommandErrorKind::StderrError => exitcode::ABORT, CommandErrorKind::Abort(_) => exitcode::ABORT, @@ -62,6 +62,11 @@ ] .concat(), ), +CommandErrorKind::RequirementsError( +RequirementsError::Corrupted, +) => Some( +"abort: .hg/requires is corrupted\n".as_bytes().to_owned(), +), CommandErrorKind::Abort(message) => message.to_owned(), _ => None, } @@ -115,3 +120,11 @@ } } } + +impl From for CommandError { +fn from(err: RequirementsError) -> Self { +CommandError { +kind: CommandErrorKind::RequirementsError(err), +} +} +} diff --git a/rust/rhg/src/commands/debugrequirements.rs b/rust/rhg/src/commands/debugrequirements.rs --- a/rust/rhg/src/commands/debugrequirements.rs +++ b/rust/rhg/src/commands/debugrequirements.rs @@ -1,7 +1,8 @@ use crate::commands::Command; -use crate::error::{CommandError, CommandErrorKind}; +use crate::error::CommandError; use crate::ui::Ui; use hg::operations::FindRoot; +use hg::requirements; pub const HELP_TEXT: &str = " Print the current repo requirements. @@ -18,23 +19,12 @@ impl Command for DebugRequirementsCommand { fn run(&self, ui: &Ui) -> Result<(), CommandError> { let root = FindRoot::new().run()?; -let requires = root.join(".hg").join("requires"); -let requirements = match std::fs::read(requires) { -Ok(bytes) => bytes, - -// Treat a missing file the same as an empty file. -// From `mercurial/localrepo.py`: -// > requires file contains a newline-delimited list of -// > features/capabilities the opener (us) must have in order to use -// > the repository. This file was introduced in Mercurial 0.9.2, -// > which means very old repositories may not have one. We assume -// > a missing file translates to no requirements. -Err(error) if error.kind() == std::io::ErrorKind::NotFound => Vec::new(), - -Err(error) => Err(CommandErrorKind::FileError(error))?, -}; - -ui.write_stdout(&requirements)?; +let mut output = String::new(); +for req in requirements::load(&root)? { +output.push_str(&req); +output.push('\n'); +} +ui.write_stdout(output.as_bytes())?; Ok(()) } } diff --git a/rust/hg-core/src/requirements.rs b/rust/hg-core/src/requirements.rs new file mode 100644 --- /dev/null +++ b/rust/hg-core/src/requirements.rs @@ -0,0 +1,53 @@ +use std::io; +use std::path::Path; + +#[derive(Debug)] +pub enum RequirementsError { +// TODO: include a path? +Io(io::Error), +/// The `requires` file is corrupted +Corrupted, +/// The repository requires a feature that we don’t support +Unsupported { +feature: String, +}, +} + +fn parse(bytes: &[u8]) -> Result, ()> { +// The Python code reading this file uses `str.splitlines` +// which looks for a number of line separators (even including a couple of +// non-ASCII ones), but Python code writing it always uses `\n`. +let lines = bytes.split(|&byte| byte == b'\n'); + +lines +.filter(|line| !line.is_empty()) +