censor: make rhg fall back to python when encountering a censored node
authorArseniy Alekseyev <aalekseyev@janestreet.com>
Thu, 05 May 2022 15:38:29 +0100
changeset 49174 3f86ee422095
parent 49173 90f7d8276e26
child 49175 34decbaf4da3
censor: make rhg fall back to python when encountering a censored node This is to make it support censor.policy=ignore without having to duplicate that logic. Also, change the censor test in such a way that it uses rhg now, because extensions are disabled except when we call [hg censor]. Differential Revision: https://phab.mercurial-scm.org/D12607
rust/hg-core/src/errors.rs
rust/hg-core/src/revlog/filelog.rs
rust/hg-core/src/revlog/revlog.rs
rust/rhg/src/error.rs
tests/test-censor.t
--- a/rust/hg-core/src/errors.rs	Wed May 04 16:01:55 2022 -0400
+++ b/rust/hg-core/src/errors.rs	Thu May 05 15:38:29 2022 +0100
@@ -42,6 +42,9 @@
     /// and syntax of each value.
     #[from]
     ConfigValueParseError(ConfigValueParseError),
+
+    /// Censored revision data.
+    CensoredNodeError,
 }
 
 /// Details about where an I/O error happened
@@ -101,6 +104,9 @@
             HgError::UnsupportedFeature(explanation) => {
                 write!(f, "unsupported feature: {}", explanation)
             }
+            HgError::CensoredNodeError => {
+                write!(f, "encountered a censored node")
+            }
             HgError::ConfigValueParseError(error) => error.fmt(f),
         }
     }
--- a/rust/hg-core/src/revlog/filelog.rs	Wed May 04 16:01:55 2022 -0400
+++ b/rust/hg-core/src/revlog/filelog.rs	Thu May 05 15:38:29 2022 +0100
@@ -95,7 +95,7 @@
         // Let’s call `file_data_len` what would be returned by
         // `self.data().file_data().len()`.
 
-        if self.0.is_cencored() {
+        if self.0.is_censored() {
             let file_data_len = 0;
             return other_len != file_data_len;
         }
--- a/rust/hg-core/src/revlog/revlog.rs	Wed May 04 16:01:55 2022 -0400
+++ b/rust/hg-core/src/revlog/revlog.rs	Thu May 05 15:38:29 2022 +0100
@@ -378,7 +378,7 @@
         }
     }
 
-    pub fn is_cencored(&self) -> bool {
+    pub fn is_censored(&self) -> bool {
         (self.flags & REVISION_FLAG_CENSORED) != 0
     }
 
@@ -389,7 +389,7 @@
     }
 
     /// The data for this entry, after resolving deltas if any.
-    pub fn data(&self) -> Result<Cow<'a, [u8]>, HgError> {
+    pub fn rawdata(&self) -> Result<Cow<'a, [u8]>, HgError> {
         let mut entry = self.clone();
         let mut delta_chain = vec![];
 
@@ -414,6 +414,13 @@
             Revlog::build_data_from_deltas(entry, &delta_chain)?.into()
         };
 
+        Ok(data)
+    }
+
+    fn check_data(
+        &self,
+        data: Cow<'a, [u8]>,
+    ) -> Result<Cow<'a, [u8]>, HgError> {
         if self.revlog.check_hash(
             self.p1,
             self.p2,
@@ -426,6 +433,14 @@
         }
     }
 
+    pub fn data(&self) -> Result<Cow<'a, [u8]>, HgError> {
+        let data = self.rawdata()?;
+        if self.is_censored() {
+            return Err(HgError::CensoredNodeError);
+        }
+        self.check_data(data)
+    }
+
     /// Extract the data contained in the entry.
     /// This may be a delta. (See `is_delta`.)
     fn data_chunk(&self) -> Result<Cow<'a, [u8]>, HgError> {
--- a/rust/rhg/src/error.rs	Wed May 04 16:01:55 2022 -0400
+++ b/rust/rhg/src/error.rs	Thu May 05 15:38:29 2022 +0100
@@ -73,6 +73,9 @@
             HgError::UnsupportedFeature(message) => {
                 CommandError::unsupported(message)
             }
+            HgError::CensoredNodeError => {
+                CommandError::unsupported("Encountered a censored node")
+            }
             HgError::Abort {
                 message,
                 detailed_exit_code,
--- a/tests/test-censor.t	Wed May 04 16:01:55 2022 -0400
+++ b/tests/test-censor.t	Thu May 05 15:38:29 2022 +0100
@@ -10,10 +10,6 @@
 
 #endif
 
-  $ cat >> $HGRCPATH <<EOF
-  > [extensions]
-  > censor=
-  > EOF
   $ cp $HGRCPATH $HGRCPATH.orig
 
 Create repo with unimpeachable content
@@ -81,7 +77,7 @@
 (this also tests file pattern matching: path relative to cwd case)
 
   $ mkdir -p foo/bar/baz
-  $ hg --cwd foo/bar/baz censor -r $C2 -t "remove password" ../../../target
+  $ hg --config extensions.censor= --cwd foo/bar/baz censor -r $C2 -t "remove password" ../../../target
   $ hg cat -r $H1 target | head -n 10
   Tainted file is now sanitized
   $ hg cat -r $H2 target | head -n 10
@@ -99,7 +95,7 @@
 
 (this also tests file pattern matching: with 'path:' scheme)
 
-  $ hg --cwd foo/bar/baz censor -r $C1 path:target
+  $ hg --config extensions.censor= --cwd foo/bar/baz censor -r $C1 path:target
   $ hg cat -r $H1 target | head -n 10
   Tainted file is now sanitized
   $ hg cat -r $H2 target | head -n 10
@@ -242,7 +238,7 @@
   $ echo 'advanced head H1' > target
   $ hg ci -m 'advance head H1' target
   $ H1=`hg id --debug -i`
-  $ hg censor -r $C3 target
+  $ hg --config extensions.censor= censor -r $C3 target
   $ hg update -r $H2
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg merge -r $C3
@@ -254,14 +250,14 @@
 
   $ hg update -C -r $H2
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ hg censor -r $H2 target
+  $ hg --config extensions.censor= censor -r $H2 target
   abort: cannot censor file in heads (78a8fc215e79)
   (clean/delete and commit first)
   [255]
   $ echo 'twiddling thumbs' > bystander
   $ hg ci -m 'bystander commit'
   $ H2=`hg id --debug -i`
-  $ hg censor -r "$H2^" target
+  $ hg --config extensions.censor= censor -r "$H2^" target
   abort: cannot censor file in heads (efbe78065929)
   (clean/delete and commit first)
   [255]
@@ -273,7 +269,7 @@
   $ H2=`hg id --debug -i`
   $ hg update -r "$H2^"
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ hg censor -r . target
+  $ hg --config extensions.censor= censor -r . target
   abort: cannot censor working directory
   (clean/delete/update first)
   [255]
@@ -286,7 +282,7 @@
   $ hg rm target
   $ hg ci -m 'delete target so it may be censored'
   $ H2=`hg id --debug -i`
-  $ hg censor -r $C4 target
+  $ hg --config extensions.censor= censor -r $C4 target
   $ hg cat -r $C4 target | head -n 10
   $ hg cat -r "$H2^^" target | head -n 10
   Tainted file now super sanitized
@@ -314,7 +310,7 @@
   $ hg revert -r "$H2^" target
   $ hg ci -m 'cleaned 100k passwords'
   $ H2=`hg id --debug -i`
-  $ hg censor -r $C5 target
+  $ hg --config extensions.censor= censor -r $C5 target
   $ hg cat -r $C5 target | head -n 10
   $ hg cat -r $H2 target | head -n 10
   fresh start
@@ -393,7 +389,7 @@
   $ CLEANREV=$H2
   $ hg cat -r $REV target | head -n 10
   Passwords: hunter2hunter2
-  $ hg censor -r $REV target
+  $ hg --config extensions.censor= censor -r $REV target
   $ hg cat -r $REV target | head -n 10
   $ hg cat -r $CLEANREV target | head -n 10
   Re-sanitized; nothing to see here
@@ -503,7 +499,7 @@
 Can import bundle where first revision of a file is censored
 
   $ hg init ../rinit
-  $ hg censor -r 0 target
+  $ hg --config extensions.censor= censor -r 0 target
   $ hg bundle -r 0 --base null ../rinit/initbundle
   1 changesets found
   $ cd ../rinit
@@ -553,7 +549,7 @@
 
   $ hg cat -r $B1 target | wc -l
    *50002 (re)
-  $ hg censor -r $B1 target
+  $ hg --config extensions.censor= censor -r $B1 target
   $ hg cat -r $B1 target | wc -l
    *0 (re)