##// END OF EJS Templates
rhg: support rhg status --rev --rev
Arseniy Alekseyev -
r52048:ac3859a8 default
parent child Browse files
Show More
@@ -0,0 +1,89 b''
1 use crate::errors::HgError;
2 use crate::matchers::Matcher;
3 use crate::repo::Repo;
4 use crate::revlog::manifest::Manifest;
5 use crate::utils::filter_map_results;
6 use crate::utils::hg_path::HgPath;
7 use crate::utils::merge_join_results_by;
8
9 use crate::Revision;
10
11 use itertools::EitherOrBoth;
12
13 #[derive(Debug, Copy, Clone)]
14 pub enum DiffStatus {
15 Removed,
16 Added,
17 Matching,
18 Modified,
19 }
20
21 pub struct StatusRevRev {
22 manifest1: Manifest,
23 manifest2: Manifest,
24 narrow_matcher: Box<dyn Matcher>,
25 }
26
27 fn manifest_for_rev(repo: &Repo, rev: Revision) -> Result<Manifest, HgError> {
28 repo.manifest_for_rev(rev.into()).map_err(|e| {
29 HgError::corrupted(format!(
30 "manifest lookup failed for revision {}: {}",
31 rev, e
32 ))
33 })
34 }
35
36 pub fn status_rev_rev_no_copies(
37 repo: &Repo,
38 rev1: Revision,
39 rev2: Revision,
40 narrow_matcher: Box<dyn Matcher>,
41 ) -> Result<StatusRevRev, HgError> {
42 let manifest1 = manifest_for_rev(repo, rev1)?;
43 let manifest2 = manifest_for_rev(repo, rev2)?;
44 Ok(StatusRevRev {
45 manifest1,
46 manifest2,
47 narrow_matcher,
48 })
49 }
50
51 impl StatusRevRev {
52 pub fn iter(
53 &self,
54 ) -> impl Iterator<Item = Result<(&HgPath, DiffStatus), HgError>> {
55 let iter1 = self.manifest1.iter();
56 let iter2 = self.manifest2.iter();
57
58 let merged =
59 merge_join_results_by(iter1, iter2, |i1, i2| i1.path.cmp(i2.path));
60
61 filter_map_results(merged, |entry| {
62 let (path, status) = match entry {
63 EitherOrBoth::Left(entry) => {
64 let path = entry.path;
65 (path, DiffStatus::Removed)
66 }
67 EitherOrBoth::Right(entry) => {
68 let path = entry.path;
69 (path, DiffStatus::Added)
70 }
71 EitherOrBoth::Both(entry1, entry2) => {
72 let path = entry1.path;
73 if entry1.node_id().unwrap() == entry2.node_id().unwrap()
74 && entry1.flags == entry2.flags
75 {
76 (path, DiffStatus::Matching)
77 } else {
78 (path, DiffStatus::Modified)
79 }
80 }
81 };
82 Ok(if self.narrow_matcher.matches(path) {
83 Some((path, status))
84 } else {
85 None
86 })
87 })
88 }
89 }
@@ -5,6 +5,8 b''
5 5 mod cat;
6 6 mod debugdata;
7 7 mod list_tracked_files;
8 mod status_rev_rev;
8 9 pub use cat::{cat, CatOutput};
9 10 pub use debugdata::{debug_data, DebugDataKind};
10 11 pub use list_tracked_files::{list_rev_tracked_files, FilesForRev};
12 pub use status_rev_rev::{status_rev_rev_no_copies, DiffStatus, StatusRevRev};
@@ -30,11 +30,13 b' use hg::utils::files::{'
30 30 use hg::utils::hg_path::{hg_path_to_path_buf, HgPath};
31 31 use hg::DirstateStatus;
32 32 use hg::PatternFileWarning;
33 use hg::Revision;
33 34 use hg::StatusError;
34 35 use hg::StatusOptions;
35 36 use hg::{self, narrow, sparse};
36 37 use log::info;
37 38 use rayon::prelude::*;
39 use std::borrow::Cow;
38 40 use std::io;
39 41 use std::mem::take;
40 42 use std::path::PathBuf;
@@ -141,6 +143,38 b' pub fn args() -> clap::Command {'
141 143 .action(clap::ArgAction::SetTrue)
142 144 .long("verbose"),
143 145 )
146 .arg(
147 Arg::new("rev")
148 .help("show difference from/to revision")
149 .long("rev")
150 .num_args(1)
151 .action(clap::ArgAction::Append)
152 .value_name("REV"),
153 )
154 }
155
156 fn parse_revpair(
157 repo: &Repo,
158 revs: Option<Vec<String>>,
159 ) -> Result<Option<(Revision, Revision)>, CommandError> {
160 let revs = match revs {
161 None => return Ok(None),
162 Some(revs) => revs,
163 };
164 if revs.is_empty() {
165 return Ok(None);
166 }
167 if revs.len() != 2 {
168 return Err(CommandError::unsupported("expected 0 or 2 --rev flags"));
169 }
170
171 let rev1 = &revs[0];
172 let rev2 = &revs[1];
173 let rev1 = hg::revset::resolve_single(rev1, repo)
174 .map_err(|e| (e, rev1.as_str()))?;
175 let rev2 = hg::revset::resolve_single(rev2, repo)
176 .map_err(|e| (e, rev2.as_str()))?;
177 Ok(Some((rev1, rev2)))
144 178 }
145 179
146 180 /// Pure data type allowing the caller to specify file states to display
@@ -230,6 +264,7 b' pub fn run(invocation: &crate::CliInvoca'
230 264 let config = invocation.config;
231 265 let args = invocation.subcommand_args;
232 266
267 let revs = args.get_many::<String>("rev");
233 268 let print0 = args.get_flag("print0");
234 269 let verbose = args.get_flag("verbose")
235 270 || config.get_bool(b"ui", b"verbose")?
@@ -263,6 +298,7 b' pub fn run(invocation: &crate::CliInvoca'
263 298 || config.get_bool(b"ui", b"statuscopies")?;
264 299
265 300 let repo = invocation.repo?;
301 let revpair = parse_revpair(repo, revs.map(|i| i.cloned().collect()))?;
266 302
267 303 if verbose && has_unfinished_state(repo)? {
268 304 return Err(CommandError::unsupported(
@@ -407,6 +443,57 b' pub fn run(invocation: &crate::CliInvoca'
407 443 ))
408 444 };
409 445 let (narrow_matcher, narrow_warnings) = narrow::matcher(repo)?;
446
447 match revpair {
448 Some((rev1, rev2)) => {
449 let mut ds_status = DirstateStatus::default();
450 if list_copies {
451 return Err(CommandError::unsupported(
452 "status --rev --rev with copy information is not implemented yet",
453 ));
454 }
455
456 let stat = hg::operations::status_rev_rev_no_copies(
457 repo,
458 rev1,
459 rev2,
460 narrow_matcher,
461 )?;
462 for entry in stat.iter() {
463 let (path, status) = entry?;
464 let path = StatusPath {
465 path: Cow::Borrowed(path),
466 copy_source: None,
467 };
468 match status {
469 hg::operations::DiffStatus::Removed => {
470 if display_states.removed {
471 ds_status.removed.push(path)
472 }
473 }
474 hg::operations::DiffStatus::Added => {
475 if display_states.added {
476 ds_status.added.push(path)
477 }
478 }
479 hg::operations::DiffStatus::Modified => {
480 if display_states.modified {
481 ds_status.modified.push(path)
482 }
483 }
484 hg::operations::DiffStatus::Matching => {
485 if display_states.clean {
486 ds_status.clean.push(path)
487 }
488 }
489 }
490 }
491 output.output(display_states, ds_status)?;
492 return Ok(());
493 }
494 None => (),
495 }
496
410 497 let (sparse_matcher, sparse_warnings) = sparse::matcher(repo)?;
411 498 let matcher = match (repo.has_narrow(), repo.has_sparse()) {
412 499 (true, true) => {
@@ -524,13 +524,20 b' fn exit_no_fallback('
524 524 std::process::exit(exit_code(&result, use_detailed_exit_code))
525 525 }
526 526
527 mod commands {
528 pub mod cat;
529 pub mod config;
530 pub mod debugdata;
531 pub mod debugignorerhg;
532 pub mod debugrequirements;
533 pub mod debugrhgsparse;
534 pub mod files;
535 pub mod root;
536 pub mod status;
537 }
538
527 539 macro_rules! subcommands {
528 540 ($( $command: ident )+) => {
529 mod commands {
530 $(
531 pub mod $command;
532 )+
533 }
534 541
535 542 fn add_subcommand_args(app: clap::Command) -> clap::Command {
536 543 app
@@ -88,6 +88,33 b' Status compared to parent of the working'
88 88
89 89 Status between first and second commit. Should ignore dirstate status.
90 90
91 $ hg status -marc --rev 0 --rev 1 --config rhg.on-unsupported=abort
92 M content1_content2_content1-tracked
93 M content1_content2_content1-untracked
94 M content1_content2_content2-tracked
95 M content1_content2_content2-untracked
96 M content1_content2_content3-tracked
97 M content1_content2_content3-untracked
98 M content1_content2_missing-tracked
99 M content1_content2_missing-untracked
100 A missing_content2_content2-tracked
101 A missing_content2_content2-untracked
102 A missing_content2_content3-tracked
103 A missing_content2_content3-untracked
104 A missing_content2_missing-tracked
105 A missing_content2_missing-untracked
106 R content1_missing_content1-tracked
107 R content1_missing_content1-untracked
108 R content1_missing_content3-tracked
109 R content1_missing_content3-untracked
110 R content1_missing_missing-tracked
111 R content1_missing_missing-untracked
112 C content1_content1_content1-tracked
113 C content1_content1_content1-untracked
114 C content1_content1_content3-tracked
115 C content1_content1_content3-untracked
116 C content1_content1_missing-tracked
117 C content1_content1_missing-untracked
91 118 $ hg status -A --rev 0:1 'glob:content1_content2_*'
92 119 M content1_content2_content1-tracked
93 120 M content1_content2_content1-untracked
General Comments 0
You need to be logged in to leave comments. Login now