##// END OF EJS Templates
rust-narrow: enable narrow support for plain `rhg files`...
Raphaël Gomès -
r50879:df9eabc9 default
parent child Browse files
Show More
@@ -1,112 +1,119 b''
1 use crate::error::CommandError;
1 use crate::error::CommandError;
2 use crate::ui::Ui;
2 use crate::ui::{print_narrow_sparse_warnings, Ui};
3 use crate::utils::path_utils::RelativizePaths;
3 use crate::utils::path_utils::RelativizePaths;
4 use clap::Arg;
4 use clap::Arg;
5 use hg::narrow;
5 use hg::operations::list_rev_tracked_files;
6 use hg::operations::list_rev_tracked_files;
6 use hg::repo::Repo;
7 use hg::repo::Repo;
7 use hg::utils::filter_map_results;
8 use hg::utils::filter_map_results;
8 use hg::utils::hg_path::HgPath;
9 use hg::utils::hg_path::HgPath;
9 use rayon::prelude::*;
10 use rayon::prelude::*;
10
11
11 pub const HELP_TEXT: &str = "
12 pub const HELP_TEXT: &str = "
12 List tracked files.
13 List tracked files.
13
14
14 Returns 0 on success.
15 Returns 0 on success.
15 ";
16 ";
16
17
17 pub fn args() -> clap::Command {
18 pub fn args() -> clap::Command {
18 clap::command!("files")
19 clap::command!("files")
19 .arg(
20 .arg(
20 Arg::new("rev")
21 Arg::new("rev")
21 .help("search the repository as it is in REV")
22 .help("search the repository as it is in REV")
22 .short('r')
23 .short('r')
23 .long("revision")
24 .long("revision")
24 .value_name("REV"),
25 .value_name("REV"),
25 )
26 )
26 .about(HELP_TEXT)
27 .about(HELP_TEXT)
27 }
28 }
28
29
29 pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> {
30 pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> {
30 let relative = invocation.config.get(b"ui", b"relative-paths");
31 let relative = invocation.config.get(b"ui", b"relative-paths");
31 if relative.is_some() {
32 if relative.is_some() {
32 return Err(CommandError::unsupported(
33 return Err(CommandError::unsupported(
33 "non-default ui.relative-paths",
34 "non-default ui.relative-paths",
34 ));
35 ));
35 }
36 }
36
37
37 let rev = invocation.subcommand_args.get_one::<String>("rev");
38 let rev = invocation.subcommand_args.get_one::<String>("rev");
38
39
39 let repo = invocation.repo?;
40 let repo = invocation.repo?;
40
41
41 // It seems better if this check is removed: this would correspond to
42 // It seems better if this check is removed: this would correspond to
42 // automatically enabling the extension if the repo requires it.
43 // automatically enabling the extension if the repo requires it.
43 // However we need this check to be in sync with vanilla hg so hg tests
44 // However we need this check to be in sync with vanilla hg so hg tests
44 // pass.
45 // pass.
45 if repo.has_sparse()
46 if repo.has_sparse()
46 && invocation.config.get(b"extensions", b"sparse").is_none()
47 && invocation.config.get(b"extensions", b"sparse").is_none()
47 {
48 {
48 return Err(CommandError::unsupported(
49 return Err(CommandError::unsupported(
49 "repo is using sparse, but sparse extension is not enabled",
50 "repo is using sparse, but sparse extension is not enabled",
50 ));
51 ));
51 }
52 }
52
53
53 if let Some(rev) = rev {
54 if let Some(rev) = rev {
54 if repo.has_narrow() {
55 if repo.has_narrow() {
55 return Err(CommandError::unsupported(
56 return Err(CommandError::unsupported(
56 "rhg files -r <rev> is not supported in narrow clones",
57 "rhg files -r <rev> is not supported in narrow clones",
57 ));
58 ));
58 }
59 }
59 let files = list_rev_tracked_files(repo, rev)
60 let files = list_rev_tracked_files(repo, rev)
60 .map_err(|e| (e, rev.as_ref()))?;
61 .map_err(|e| (e, rev.as_ref()))?;
61 display_files(invocation.ui, repo, files.iter())
62 display_files(invocation.ui, repo, files.iter())
62 } else {
63 } else {
63 // The dirstate always reflects the sparse narrowspec, so if
64 // The dirstate always reflects the sparse narrowspec.
64 // we only have sparse without narrow all is fine.
65 let (narrow_matcher, narrow_warnings) = narrow::matcher(repo)?;
65 // If we have narrow, then [hg files] needs to check if
66 print_narrow_sparse_warnings(
66 // the store narrowspec is in sync with the one of the dirstate,
67 &narrow_warnings,
67 // so we can't support that without explicit code.
68 &[],
68 if repo.has_narrow() {
69 invocation.ui,
69 return Err(CommandError::unsupported(
70 repo,
70 "rhg files is not supported in narrow clones",
71 )?;
71 ));
72 }
73 let dirstate = repo.dirstate_map()?;
72 let dirstate = repo.dirstate_map()?;
74 let files_res: Result<Vec<_>, _> =
73 let files_res: Result<Vec<_>, _> =
75 filter_map_results(dirstate.iter(), |(path, entry)| {
74 filter_map_results(dirstate.iter(), |(path, entry)| {
76 Ok(if entry.tracked() { Some(path) } else { None })
75 Ok(if entry.tracked() && narrow_matcher.matches(path) {
76 Some(path)
77 } else {
78 None
79 })
77 })
80 })
78 .collect();
81 .collect();
79
82
80 let mut files = files_res?;
83 let mut files = files_res?;
81 files.par_sort_unstable();
84 files.par_sort_unstable();
82
85
83 display_files(invocation.ui, repo, files.into_iter().map(Ok))
86 display_files(
87 invocation.ui,
88 repo,
89 files.into_iter().map::<Result<_, CommandError>, _>(Ok),
90 )
84 }
91 }
85 }
92 }
86
93
87 fn display_files<'a, E>(
94 fn display_files<'a, E>(
88 ui: &Ui,
95 ui: &Ui,
89 repo: &Repo,
96 repo: &Repo,
90 files: impl IntoIterator<Item = Result<&'a HgPath, E>>,
97 files: impl IntoIterator<Item = Result<&'a HgPath, E>>,
91 ) -> Result<(), CommandError>
98 ) -> Result<(), CommandError>
92 where
99 where
93 CommandError: From<E>,
100 CommandError: From<E>,
94 {
101 {
95 let mut stdout = ui.stdout_buffer();
102 let mut stdout = ui.stdout_buffer();
96 let mut any = false;
103 let mut any = false;
97
104
98 let relativize = RelativizePaths::new(repo)?;
105 let relativize = RelativizePaths::new(repo)?;
99 for result in files {
106 for result in files {
100 let path = result?;
107 let path = result?;
101 stdout.write_all(&relativize.relativize(path))?;
108 stdout.write_all(&relativize.relativize(path))?;
102 stdout.write_all(b"\n")?;
109 stdout.write_all(b"\n")?;
103 any = true;
110 any = true;
104 }
111 }
105
112
106 stdout.flush()?;
113 stdout.flush()?;
107 if any {
114 if any {
108 Ok(())
115 Ok(())
109 } else {
116 } else {
110 Err(CommandError::Unsuccessful)
117 Err(CommandError::Unsuccessful)
111 }
118 }
112 }
119 }
@@ -1,112 +1,121 b''
1 #require rhg
1 #require rhg
2
2
3 $ NO_FALLBACK="env RHG_ON_UNSUPPORTED=abort"
3 $ NO_FALLBACK="env RHG_ON_UNSUPPORTED=abort"
4
4
5 Rhg works well when sparse working copy is enabled.
5 Rhg works well when sparse working copy is enabled.
6
6
7 $ cd "$TESTTMP"
7 $ cd "$TESTTMP"
8 $ hg init repo-sparse
8 $ hg init repo-sparse
9 $ cd repo-sparse
9 $ cd repo-sparse
10 $ cat > .hg/hgrc <<EOF
10 $ cat > .hg/hgrc <<EOF
11 > [extensions]
11 > [extensions]
12 > sparse=
12 > sparse=
13 > EOF
13 > EOF
14
14
15 $ echo a > show
15 $ echo a > show
16 $ echo x > hide
16 $ echo x > hide
17 $ mkdir dir1 dir2
17 $ mkdir dir1 dir2
18 $ echo x > dir1/x
18 $ echo x > dir1/x
19 $ echo y > dir1/y
19 $ echo y > dir1/y
20 $ echo z > dir2/z
20 $ echo z > dir2/z
21
21
22 $ hg ci -Aqm 'initial'
22 $ hg ci -Aqm 'initial'
23 $ hg debugsparse --include 'show'
23 $ hg debugsparse --include 'show'
24 $ ls -A
24 $ ls -A
25 .hg
25 .hg
26 show
26 show
27
27
28 $ tip=$(hg log -r . --template '{node}')
28 $ tip=$(hg log -r . --template '{node}')
29 $ $NO_FALLBACK rhg files -r "$tip"
29 $ $NO_FALLBACK rhg files -r "$tip"
30 dir1/x
30 dir1/x
31 dir1/y
31 dir1/y
32 dir2/z
32 dir2/z
33 hide
33 hide
34 show
34 show
35 $ $NO_FALLBACK rhg files
35 $ $NO_FALLBACK rhg files
36 show
36 show
37
37
38 $ $NO_FALLBACK rhg cat -r "$tip" hide
38 $ $NO_FALLBACK rhg cat -r "$tip" hide
39 x
39 x
40
40
41 $ cd ..
41 $ cd ..
42
42
43 We support most things when narrow is enabled, too, with a couple of caveats.
43 We support most things when narrow is enabled, too, with a couple of caveats.
44
44
45 $ . "$TESTDIR/narrow-library.sh"
45 $ . "$TESTDIR/narrow-library.sh"
46 $ real_hg=$RHG_FALLBACK_EXECUTABLE
46 $ real_hg=$RHG_FALLBACK_EXECUTABLE
47
47
48 $ cat >> $HGRCPATH <<EOF
48 $ cat >> $HGRCPATH <<EOF
49 > [extensions]
49 > [extensions]
50 > narrow=
50 > narrow=
51 > EOF
51 > EOF
52
52
53 $ hg clone --narrow ./repo-sparse repo-narrow --include dir1
53 $ hg clone --narrow ./repo-sparse repo-narrow --include dir1
54 requesting all changes
54 requesting all changes
55 adding changesets
55 adding changesets
56 adding manifests
56 adding manifests
57 adding file changes
57 adding file changes
58 added 1 changesets with 2 changes to 2 files
58 added 1 changesets with 2 changes to 2 files
59 new changesets 6d714a4a2998
59 new changesets 6d714a4a2998
60 updating to branch default
60 updating to branch default
61 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
61 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
62
62
63 $ cd repo-narrow
63 $ cd repo-narrow
64
64
65 $ $NO_FALLBACK rhg cat -r "$tip" dir1/x
65 $ $NO_FALLBACK rhg cat -r "$tip" dir1/x
66 x
66 x
67 $ "$real_hg" cat -r "$tip" dir1/x
67 $ "$real_hg" cat -r "$tip" dir1/x
68 x
68 x
69
69
70 TODO: bad error message
70 TODO: bad error message
71
71
72 $ $NO_FALLBACK rhg cat -r "$tip" hide
72 $ $NO_FALLBACK rhg cat -r "$tip" hide
73 abort: invalid revision identifier: 6d714a4a2998cbfd0620db44da58b749f6565d63
73 abort: invalid revision identifier: 6d714a4a2998cbfd0620db44da58b749f6565d63
74 [255]
74 [255]
75 $ "$real_hg" cat -r "$tip" hide
75 $ "$real_hg" cat -r "$tip" hide
76 [1]
76 [1]
77
77
78 A naive implementation of [rhg files] leaks the paths that are supposed to be
78 A naive implementation of [rhg files] leaks the paths that are supposed to be
79 hidden by narrow, so we just fall back to hg.
79 hidden by narrow, so we just fall back to hg when accessing a revision.
80
80
81 $ $NO_FALLBACK rhg files -r "$tip"
81 $ $NO_FALLBACK rhg files -r "$tip"
82 unsupported feature: rhg files -r <rev> is not supported in narrow clones
82 unsupported feature: rhg files -r <rev> is not supported in narrow clones
83 [252]
83 [252]
84 $ "$real_hg" files -r "$tip"
84 $ "$real_hg" files -r "$tip"
85 dir1/x
85 dir1/x
86 dir1/y
86 dir1/y
87
87
88 The working copy version works with narrow correctly
89
90 $ $NO_FALLBACK rhg files
91 dir1/x
92 dir1/y
93 $ "$real_hg" files
94 dir1/x
95 dir1/y
96
88 Hg status needs to do some filtering based on narrow spec
97 Hg status needs to do some filtering based on narrow spec
89
98
90 $ mkdir dir2
99 $ mkdir dir2
91 $ touch dir2/q
100 $ touch dir2/q
92 $ "$real_hg" status
101 $ "$real_hg" status
93 $ $NO_FALLBACK rhg --config rhg.status=true status
102 $ $NO_FALLBACK rhg --config rhg.status=true status
94
103
95 Adding "orphaned" index files:
104 Adding "orphaned" index files:
96
105
97 $ (cd ..; cp repo-sparse/.hg/store/data/hide.i repo-narrow/.hg/store/data/hide.i)
106 $ (cd ..; cp repo-sparse/.hg/store/data/hide.i repo-narrow/.hg/store/data/hide.i)
98 $ (cd ..; mkdir repo-narrow/.hg/store/data/dir2; cp repo-sparse/.hg/store/data/dir2/z.i repo-narrow/.hg/store/data/dir2/z.i)
107 $ (cd ..; mkdir repo-narrow/.hg/store/data/dir2; cp repo-sparse/.hg/store/data/dir2/z.i repo-narrow/.hg/store/data/dir2/z.i)
99 $ "$real_hg" verify -q
108 $ "$real_hg" verify -q
100
109
101 $ "$real_hg" files -r "$tip"
110 $ "$real_hg" files -r "$tip"
102 dir1/x
111 dir1/x
103 dir1/y
112 dir1/y
104
113
105 # TODO: even though [hg files] hides the orphaned dir2/z, [hg cat] still shows it.
114 # TODO: even though [hg files] hides the orphaned dir2/z, [hg cat] still shows it.
106 # rhg has the same issue, but at least it's not specific to rhg.
115 # rhg has the same issue, but at least it's not specific to rhg.
107 # This is despite [hg verify] succeeding above.
116 # This is despite [hg verify] succeeding above.
108
117
109 $ $NO_FALLBACK rhg cat -r "$tip" dir2/z
118 $ $NO_FALLBACK rhg cat -r "$tip" dir2/z
110 z
119 z
111 $ "$real_hg" cat -r "$tip" dir2/z
120 $ "$real_hg" cat -r "$tip" dir2/z
112 z
121 z
General Comments 0
You need to be logged in to leave comments. Login now