diff --git a/rust/hg-core/src/repo.rs b/rust/hg-core/src/repo.rs --- a/rust/hg-core/src/repo.rs +++ b/rust/hg-core/src/repo.rs @@ -248,6 +248,14 @@ .contains(requirements::DIRSTATE_V2_REQUIREMENT) } + pub fn has_sparse(&self) -> bool { + self.requirements.contains(requirements::SPARSE_REQUIREMENT) + } + + pub fn has_narrow(&self) -> bool { + self.requirements.contains(requirements::NARROW_REQUIREMENT) + } + fn dirstate_file_contents(&self) -> Result, HgError> { Ok(self .hg_vfs() 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 @@ -88,6 +88,10 @@ // When it starts writing to the repository, it’ll need to either keep the // persistent nodemap up to date or remove this entry: NODEMAP_REQUIREMENT, + // Not all commands support `sparse` and `narrow`. The commands that do + // not should opt out by checking `has_sparse` and `has_narrow`. + SPARSE_REQUIREMENT, + NARROW_REQUIREMENT, ]; // Copied from mercurial/requirements.py: 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 @@ -39,10 +39,38 @@ let rev = invocation.subcommand_args.value_of("rev"); let repo = invocation.repo?; + + // It seems better if this check is removed: this would correspond to + // automatically enabling the extension if the repo requires it. + // However we need this check to be in sync with vanilla hg so hg tests + // pass. + if repo.has_sparse() + && invocation.config.get(b"extensions", b"sparse").is_none() + { + return Err(CommandError::unsupported( + "repo is using sparse, but sparse extension is not enabled", + )); + } + if let Some(rev) = rev { + if repo.has_narrow() { + return Err(CommandError::unsupported( + "rhg files -r is not supported in narrow clones", + )); + } let files = list_rev_tracked_files(repo, rev).map_err(|e| (e, rev))?; display_files(invocation.ui, repo, files.iter()) } else { + // The dirstate always reflects the sparse narrowspec, so if + // we only have sparse without narrow all is fine. + // If we have narrow, then [hg files] needs to check if + // the store narrowspec is in sync with the one of the dirstate, + // so we can't support that without explicit code. + if repo.has_narrow() { + return Err(CommandError::unsupported( + "rhg files is not supported in narrow clones", + )); + } let distate = Dirstate::new(repo)?; let files = distate.tracked_files()?; display_files(invocation.ui, repo, files) diff --git a/rust/rhg/src/commands/status.rs b/rust/rhg/src/commands/status.rs --- a/rust/rhg/src/commands/status.rs +++ b/rust/rhg/src/commands/status.rs @@ -174,6 +174,13 @@ }; let repo = invocation.repo?; + + if repo.has_sparse() || repo.has_narrow() { + return Err(CommandError::unsupported( + "rhg status is not supported for sparse checkouts or narrow clones yet" + )); + } + let mut dmap = repo.dirstate_map_mut()?; let options = StatusOptions { 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 @@ -588,7 +588,8 @@ } } -const SUPPORTED_EXTENSIONS: &[&[u8]] = &[b"blackbox", b"share"]; +const SUPPORTED_EXTENSIONS: &[&[u8]] = + &[b"blackbox", b"share", b"sparse", b"narrow"]; fn check_extensions(config: &Config) -> Result<(), CommandError> { let enabled = config.get_section_keys(b"extensions"); diff --git a/tests/test-rhg-sparse-narrow.t b/tests/test-rhg-sparse-narrow.t new file mode 100644 --- /dev/null +++ b/tests/test-rhg-sparse-narrow.t @@ -0,0 +1,120 @@ +#require rhg + + $ NO_FALLBACK="env RHG_ON_UNSUPPORTED=abort" + +Rhg works well when sparse working copy is enabled. + + $ cd "$TESTTMP" + $ hg init repo-sparse + $ cd repo-sparse + $ cat > .hg/hgrc < [extensions] + > sparse= + > EOF + + $ echo a > show + $ echo x > hide + $ mkdir dir1 dir2 + $ echo x > dir1/x + $ echo y > dir1/y + $ echo z > dir2/z + + $ hg ci -Aqm 'initial' + $ hg debugsparse --include 'show' + $ ls -A + .hg + show + + $ tip=$(hg log -r . --template '{node}') + $ $NO_FALLBACK rhg files -r "$tip" + dir1/x + dir1/y + dir2/z + hide + show + $ $NO_FALLBACK rhg files + show + + $ $NO_FALLBACK rhg cat -r "$tip" hide + x + + $ cd .. + +We support most things when narrow is enabled, too, with a couple of caveats. + + $ . "$TESTDIR/narrow-library.sh" + $ real_hg=$RHG_FALLBACK_EXECUTABLE + + $ cat >> $HGRCPATH < [extensions] + > narrow= + > EOF + + $ hg clone --narrow ./repo-sparse repo-narrow --include dir1 + requesting all changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 2 changes to 2 files + new changesets 6d714a4a2998 + updating to branch default + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + + $ cd repo-narrow + + $ $NO_FALLBACK rhg cat -r "$tip" dir1/x + x + $ "$real_hg" cat -r "$tip" dir1/x + x + +TODO: bad error message + + $ $NO_FALLBACK rhg cat -r "$tip" hide + abort: invalid revision identifier: 6d714a4a2998cbfd0620db44da58b749f6565d63 + [255] + $ "$real_hg" cat -r "$tip" hide + [1] + +A naive implementation of [rhg files] leaks the paths that are supposed to be +hidden by narrow, so we just fall back to hg. + + $ $NO_FALLBACK rhg files -r "$tip" + unsupported feature: rhg files -r is not supported in narrow clones + [252] + $ "$real_hg" files -r "$tip" + dir1/x + dir1/y + +Hg status needs to do some filtering based on narrow spec, so we don't +support it in rhg for narrow clones yet. + + $ mkdir dir2 + $ touch dir2/q + $ "$real_hg" status + $ $NO_FALLBACK rhg --config rhg.status=true status + unsupported feature: rhg status is not supported for sparse checkouts or narrow clones yet + [252] + +Adding "orphaned" index files: + + $ (cd ..; cp {repo-sparse,repo-narrow}/.hg/store/data/hide.i) + $ (cd ..; mkdir repo-narrow/.hg/store/data/dir2; cp {repo-sparse,repo-narrow}/.hg/store/data/dir2/z.i) + $ "$real_hg" verify + checking changesets + checking manifests + crosschecking files in changesets and manifests + checking files + checked 1 changesets with 2 changes to 2 files + + $ "$real_hg" files -r "$tip" + dir1/x + dir1/y + +# TODO: even though [hg files] hides the orphaned dir2/z, [hg cat] still shows it. +# rhg has the same issue, but at least it's not specific to rhg. +# This is despite [hg verify] succeeding above. + + $ $NO_FALLBACK rhg cat -r "$tip" dir2/z + z + $ "$real_hg" cat -r "$tip" dir2/z + z