changeset 50497:f57f5ab0e220

branching: merge stable into default
author Raphaël Gomès <rgomes@octobus.net>
date Tue, 09 May 2023 11:35:50 +0200
parents e06331275a53 (current diff) 558d08dc7dd4 (diff)
children a52aae8bcc7a
files mercurial/configitems.py mercurial/transaction.py rust/rhg/src/commands/status.rs tests/test-status.t
diffstat 16 files changed, 391 insertions(+), 73 deletions(-) [+]
line wrap: on
line diff
--- a/.hgsigs	Fri Apr 28 12:12:42 2023 +0200
+++ b/.hgsigs	Tue May 09 11:35:50 2023 +0200
@@ -243,3 +243,4 @@
 f14864fffdcab725d9eac6d4f4c07be05a35f59a 0 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
+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
--- a/.hgtags	Fri Apr 28 12:12:42 2023 +0200
+++ b/.hgtags	Tue May 09 11:35:50 2023 +0200
@@ -259,3 +259,4 @@
 f14864fffdcab725d9eac6d4f4c07be05a35f59a 6.4
 83ea6ce48b4fd09fb79c4e34cc5750c805699a53 6.4.1
 f952be90b0514a576dcc8bbe758ce3847faba9bb 6.4.2
+fc445f8abcf90b33db7c463816a1b3560681767f 6.4.3
--- a/contrib/chg/chg.c	Fri Apr 28 12:12:42 2023 +0200
+++ b/contrib/chg/chg.c	Tue May 09 11:35:50 2023 +0200
@@ -31,6 +31,8 @@
 #define PATH_MAX 4096
 #endif
 
+extern char **environ;
+
 struct cmdserveropts {
 	char sockname[PATH_MAX];
 	char initsockname[PATH_MAX];
@@ -232,18 +234,12 @@
 			hgcmd = "hg";
 #endif
 	}
-	/* Set $CHGHG to the path to the seleted hg executable if it wasn't
-	 * already set. This has the effect of ensuring that a new command
-	 * server will be spawned if the existing command server is running from
-	 * an executable at a different path. */
-	if (setenv("CHGHG", hgcmd, 1) != 0)
-		abortmsgerrno("failed to setenv");
 	return hgcmd;
 }
 
-static void execcmdserver(const char *hgcmd, const struct cmdserveropts *opts)
+static void execcmdserver(const struct cmdserveropts *opts)
 {
-
+	const char *hgcmd = gethgcmd();
 	const char *baseargv[] = {
 	    hgcmd,     "serve",     "--no-profile",     "--cmdserver",
 	    "chgunix", "--address", opts->initsockname, "--daemon-postexec",
@@ -380,16 +376,11 @@
 
 	debugmsg("start cmdserver at %s", opts->initsockname);
 
-	/* Get the path to the hg executable before we fork because this
-	 * function might update the environment, and we want this to be
-	 * reflected in both the parent and child processes. */
-	const char *hgcmd = gethgcmd();
-
 	pid_t pid = fork();
 	if (pid < 0)
 		abortmsg("failed to fork cmdserver process");
 	if (pid == 0) {
-		execcmdserver(hgcmd, opts);
+		execcmdserver(opts);
 	} else {
 		hgc = retryconnectcmdserver(opts, pid);
 	}
@@ -523,6 +514,16 @@
 		}
 	}
 
+	/* Set $CHGHG to the path of the hg executable we intend to use. This
+	 * is a no-op if $CHGHG was expliclty specified, but otherwise this
+	 * ensures that we will spawn a new command server if we connect to an
+	 * existing one running from a different executable. This should only
+	 * only be needed when chg is built with HGPATHREL since otherwise the
+	 * hg executable used when CHGHG is absent should be deterministic.
+	 * */
+	if (setenv("CHGHG", gethgcmd(), 1) != 0)
+		abortmsgerrno("failed to setenv");
+
 	hgclient_t *hgc;
 	size_t retry = 0;
 	while (1) {
--- a/hgext/fix.py	Fri Apr 28 12:12:42 2023 +0200
+++ b/hgext/fix.py	Tue May 09 11:35:50 2023 +0200
@@ -9,6 +9,13 @@
 Provides a command that runs configured tools on the contents of modified files,
 writing back any fixes to the working copy or replacing changesets.
 
+Fixer tools are run in the repository's root directory. This allows them to read
+configuration files from the working copy, or even write to the working copy.
+The working copy is not updated to match the revision being fixed. In fact,
+several revisions may be fixed in parallel. Writes to the working copy are not
+amended into the revision being fixed; fixer tools MUST always read content to
+be fixed from stdin, and write fixed file content back to stdout.
+
 Here is an example configuration that causes :hg:`fix` to apply automatic
 formatting fixes to modified lines in C++ code::
 
@@ -113,13 +120,6 @@
     mapping fixer tool names to lists of metadata values returned from
     executions that modified a file. This aggregates the same metadata
     previously passed to the "postfixfile" hook.
-
-Fixer tools are run in the repository's root directory. This allows them to read
-configuration files from the working copy, or even write to the working copy.
-The working copy is not updated to match the revision being fixed. In fact,
-several revisions may be fixed in parallel. Writes to the working copy are not
-amended into the revision being fixed; fixer tools should always write fixed
-file content back to stdout as documented above.
 """
 
 
@@ -239,7 +239,8 @@
 def fix(ui, repo, *pats, **opts):
     """rewrite file content in changesets or working directory
 
-    Runs any configured tools to fix the content of files. Only affects files
+    Runs any configured tools to fix the content of files. (See
+    :hg:`help -e fix` for details about configuring tools.) Only affects files
     with changes, unless file arguments are provided. Only affects changed lines
     of files, unless the --whole flag is used. Some tools may always affect the
     whole file regardless of --whole.
--- a/mercurial/configitems.py	Fri Apr 28 12:12:42 2023 +0200
+++ b/mercurial/configitems.py	Tue May 09 11:35:50 2023 +0200
@@ -616,6 +616,10 @@
     b'bundle2.debug',
     default=False,
 )
+# which kind of delta to put in the bundled changegroup. Possible value
+# - '': use default behavior
+# - p1: force to always use delta against p1
+# - full: force to always use full content
 coreconfigitem(
     b'devel',
     b'bundle.delta',
--- a/mercurial/revlogutils/deltas.py	Fri Apr 28 12:12:42 2023 +0200
+++ b/mercurial/revlogutils/deltas.py	Tue May 09 11:35:50 2023 +0200
@@ -684,6 +684,15 @@
         yield None
         return
 
+    if target_rev is None:
+        target_rev = len(revlog)
+
+    if not revlog._generaldelta:
+        # before general delta, there is only one possible delta base
+        yield (target_rev - 1,)
+        yield None
+        return
+
     if (
         cachedelta is not None
         and nullrev == cachedelta[0]
@@ -716,9 +725,7 @@
         group = []
         for rev in temptative:
             # skip over empty delta (no need to include them in a chain)
-            while revlog._generaldelta and not (
-                rev == nullrev or rev in tested or deltalength(rev)
-            ):
+            while not (rev == nullrev or rev in tested or deltalength(rev)):
                 tested.add(rev)
                 rev = deltaparent(rev)
             # no need to try a delta against nullrev, this will be done as a
@@ -901,27 +908,27 @@
 
     The group order aims at providing fast or small candidates first.
     """
-    gdelta = revlog._generaldelta
-    # gate sparse behind general-delta because of issue6056
-    sparse = gdelta and revlog._sparserevlog
+    # Why search for delta base if we cannot use a delta base ?
+    assert revlog._generaldelta
+    # also see issue6056
+    sparse = revlog._sparserevlog
     curr = len(revlog)
     prev = curr - 1
     deltachain = lambda rev: revlog._deltachain(rev)[0]
 
-    if gdelta:
-        # exclude already lazy tested base if any
-        parents = [p for p in (p1, p2) if p != nullrev]
+    # exclude already lazy tested base if any
+    parents = [p for p in (p1, p2) if p != nullrev]
 
-        if not revlog._deltabothparents and len(parents) == 2:
-            parents.sort()
-            # To minimize the chance of having to build a fulltext,
-            # pick first whichever parent is closest to us (max rev)
-            yield (parents[1],)
-            # then the other one (min rev) if the first did not fit
-            yield (parents[0],)
-        elif len(parents) > 0:
-            # Test all parents (1 or 2), and keep the best candidate
-            yield parents
+    if not revlog._deltabothparents and len(parents) == 2:
+        parents.sort()
+        # To minimize the chance of having to build a fulltext,
+        # pick first whichever parent is closest to us (max rev)
+        yield (parents[1],)
+        # then the other one (min rev) if the first did not fit
+        yield (parents[0],)
+    elif len(parents) > 0:
+        # Test all parents (1 or 2), and keep the best candidate
+        yield parents
 
     if sparse and parents:
         if snapshot_cache is None:
@@ -1126,7 +1133,7 @@
 
         return delta
 
-    def _builddeltainfo(self, revinfo, base, fh):
+    def _builddeltainfo(self, revinfo, base, fh, target_rev=None):
         # can we use the cached delta?
         revlog = self.revlog
         debug_search = self._write_debug is not None and self._debug_search
@@ -1134,6 +1141,13 @@
         if revlog._generaldelta:
             deltabase = base
         else:
+            if target_rev is not None and base != target_rev - 1:
+                msg = (
+                    b'general delta cannot use delta for something else '
+                    b'than `prev`: %d<-%d'
+                )
+                msg %= (base, target_rev)
+                raise error.ProgrammingError(msg)
             deltabase = chainbase
         snapshotdepth = None
         if revlog._sparserevlog and deltabase == nullrev:
@@ -1364,7 +1378,12 @@
 
                 if debug_search:
                     delta_start = util.timer()
-                candidatedelta = self._builddeltainfo(revinfo, candidaterev, fh)
+                candidatedelta = self._builddeltainfo(
+                    revinfo,
+                    candidaterev,
+                    fh,
+                    target_rev=target_rev,
+                )
                 if debug_search:
                     delta_end = util.timer()
                     msg = b"DBG-DELTAS-SEARCH:     delta-search-time=%f\n"
--- a/mercurial/transaction.py	Fri Apr 28 12:12:42 2023 +0200
+++ b/mercurial/transaction.py	Tue May 09 11:35:50 2023 +0200
@@ -414,6 +414,11 @@
         if vfs.exists(file):
             filepath = vfs.join(file)
             backuppath = vfs.join(backupfile)
+            # store encoding may result in different directory here.
+            # so we have to ensure the destination directory exist
+            final_dir_name = os.path.dirname(backuppath)
+            util.makedirs(final_dir_name, mode=vfs.createmode, notindexed=True)
+            # then we can copy the backup
             util.copyfile(filepath, backuppath, hardlink=hardlink)
         else:
             backupfile = b''
--- a/mercurial/upgrade_utils/engine.py	Fri Apr 28 12:12:42 2023 +0200
+++ b/mercurial/upgrade_utils/engine.py	Tue May 09 11:35:50 2023 +0200
@@ -655,9 +655,14 @@
             pass
 
     assert srcrepo.dirstate._use_dirstate_v2 == (old == b'v2')
+    use_v2 = new == b'v2'
+    if use_v2:
+        # Write the requirements *before* upgrading
+        scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
+
     srcrepo.dirstate._map.preload()
-    srcrepo.dirstate._use_dirstate_v2 = new == b'v2'
-    srcrepo.dirstate._map._use_dirstate_v2 = srcrepo.dirstate._use_dirstate_v2
+    srcrepo.dirstate._use_dirstate_v2 = use_v2
+    srcrepo.dirstate._map._use_dirstate_v2 = use_v2
     srcrepo.dirstate._dirty = True
     try:
         srcrepo.vfs.unlink(b'dirstate')
@@ -667,8 +672,9 @@
         pass
 
     srcrepo.dirstate.write(None)
-
-    scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
+    if not use_v2:
+        # Remove the v2 requirement *after* downgrading
+        scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
 
 
 def upgrade_tracked_hint(ui, srcrepo, upgrade_op, add):
--- a/mercurial/vfs.py	Fri Apr 28 12:12:42 2023 +0200
+++ b/mercurial/vfs.py	Tue May 09 11:35:50 2023 +0200
@@ -599,6 +599,10 @@
     def __init__(self, vfs: "vfs"):
         self.vfs = vfs
 
+    @property
+    def createmode(self):
+        return self.vfs.createmode
+
     def _auditpath(self, path, mode):
         return self.vfs._auditpath(path, mode)
 
--- a/relnotes/6.4	Fri Apr 28 12:12:42 2023 +0200
+++ b/relnotes/6.4	Tue May 09 11:35:50 2023 +0200
@@ -1,3 +1,16 @@
+= Mercurial 6.4.3 =
+
+ * chg: declare environ (issue6812)
+ * chg: set CHGHG before connecting to command server
+ * delta-find: never do anything fancy when general delta is off
+ * delta-find: add a simple safeguard to prevent bad non-general-delta
+ * debug-delta: add minimal documentation for `devel.bundle-delta` option
+ * fix: highlight the required configuration and behavior of the fixer tools
+ * rhg: don't print copy source when --no-status is passed
+ * rhg: correctly relativize copy source path
+ * repo-upgrade: write new requirement before upgrading the dirstate
+ * backup: fix issue when the backup end up in a different directory
+
 = Mercurial 6.4.2 =
 
 Exceptional bugfix release due to a corruption bug that happens when using
--- a/rust/rhg/src/commands/status.rs	Fri Apr 28 12:12:42 2023 +0200
+++ b/rust/rhg/src/commands/status.rs	Tue May 09 11:35:50 2023 +0200
@@ -552,12 +552,17 @@
         // TODO: get the stdout lock once for the whole loop
         // instead of in each write
         for StatusPath { path, copy_source } in paths {
-            let relative;
-            let path = if let Some(relativize) = &self.relativize {
-                relative = relativize.relativize(&path);
-                &*relative
+            let relative_path;
+            let relative_source;
+            let (path, copy_source) = if let Some(relativize) =
+                &self.relativize
+            {
+                relative_path = relativize.relativize(&path);
+                relative_source =
+                    copy_source.as_ref().map(|s| relativize.relativize(s));
+                (&*relative_path, relative_source.as_deref())
             } else {
-                path.as_bytes()
+                (path.as_bytes(), copy_source.as_ref().map(|s| s.as_bytes()))
             };
             // TODO: Add a way to use `write_bytes!` instead of `format_bytes!`
             // in order to stream to stdout instead of allocating an
@@ -570,10 +575,10 @@
                 &format_bytes!(b"{}{}", path, linebreak),
                 label,
             )?;
-            if let Some(source) = copy_source {
+            if let Some(source) = copy_source.filter(|_| !self.no_status) {
                 let label = "status.copied";
                 self.ui.write_stdout_labelled(
-                    &format_bytes!(b"  {}{}", source.as_bytes(), linebreak),
+                    &format_bytes!(b"  {}{}", source, linebreak),
                     label,
                 )?
             }
--- a/tests/test-chg.t	Fri Apr 28 12:12:42 2023 +0200
+++ b/tests/test-chg.t	Tue May 09 11:35:50 2023 +0200
@@ -553,3 +553,20 @@
   $ filteredchg log -r . --no-profile
   $ filteredchg log -r .
   Sample count: * (glob)
+
+chg setting CHGHG itself
+------------------------
+
+If CHGHG is not set, chg will set it before spawning the command server.
+  $ hg --kill-chg-daemon
+  $ HG=$CHGHG CHGHG= CHGDEBUG= hg debugshell -c \
+  >   'ui.write(b"CHGHG=%s\n" % ui.environ.get(b"CHGHG"))' 2>&1 \
+  >   | egrep 'CHGHG|start'
+  chg: debug: * start cmdserver at * (glob)
+  CHGHG=/*/install/bin/hg (glob)
+
+Running the same command a second time shouldn't spawn a new command server.
+  $ HG=$CHGHG CHGHG= CHGDEBUG= hg debugshell -c \
+  >   'ui.write(b"CHGHG=%s\n" % ui.environ.get(b"CHGHG"))' 2>&1 \
+  >   | egrep 'CHGHG|start'
+  CHGHG=/*/install/bin/hg (glob)
--- a/tests/test-fix.t	Fri Apr 28 12:12:42 2023 +0200
+++ b/tests/test-fix.t	Tue May 09 11:35:50 2023 +0200
@@ -84,10 +84,11 @@
   
   rewrite file content in changesets or working directory
   
-      Runs any configured tools to fix the content of files. Only affects files
-      with changes, unless file arguments are provided. Only affects changed
-      lines of files, unless the --whole flag is used. Some tools may always
-      affect the whole file regardless of --whole.
+      Runs any configured tools to fix the content of files. (See 'hg help -e
+      fix' for details about configuring tools.) Only affects files with
+      changes, unless file arguments are provided. Only affects changed lines of
+      files, unless the --whole flag is used. Some tools may always affect the
+      whole file regardless of --whole.
   
       If --working-dir is used, files with uncommitted changes in the working
       copy will be fixed. Note that no backup are made.
@@ -125,6 +126,13 @@
   Provides a command that runs configured tools on the contents of modified
   files, writing back any fixes to the working copy or replacing changesets.
   
+  Fixer tools are run in the repository's root directory. This allows them to
+  read configuration files from the working copy, or even write to the working
+  copy. The working copy is not updated to match the revision being fixed. In
+  fact, several revisions may be fixed in parallel. Writes to the working copy
+  are not amended into the revision being fixed; fixer tools MUST always read
+  content to be fixed from stdin, and write fixed file content back to stdout.
+  
   Here is an example configuration that causes 'hg fix' to apply automatic
   formatting fixes to modified lines in C++ code:
   
@@ -231,13 +239,6 @@
       executions that modified a file. This aggregates the same metadata
       previously passed to the "postfixfile" hook.
   
-  Fixer tools are run in the repository's root directory. This allows them to
-  read configuration files from the working copy, or even write to the working
-  copy. The working copy is not updated to match the revision being fixed. In
-  fact, several revisions may be fixed in parallel. Writes to the working copy
-  are not amended into the revision being fixed; fixer tools should always write
-  fixed file content back to stdout as documented above.
-  
   list of commands:
   
    fix           rewrite file content in changesets or working directory
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-pullling-to-general-delta.t	Tue May 09 11:35:50 2023 +0200
@@ -0,0 +1,196 @@
+============================================================================
+Pulling from modern to a non-general delta target (and other related checks)
+============================================================================
+
+There is various issue that can arise when we update the code with modern
+storage in mind while working on delta processing. So this file is meant for
+various scenario that might break in the future or have break in the past.
+
+Setup
+=====
+
+Create a modern server with an older clone
+
+  $ cat << EOF >> $HGRCPATH
+  > [command-templates]
+  > log = "{desc} {tags}\n"
+  > EOF
+
+  $ hg init server
+
+  $ hg clone --quiet --pull server client --config format.usegeneraldelta=no
+  $ hg debugformat -R client | grep generaldelta
+  generaldelta:        no
+
+Create some complexe history
+
+  $ cd server
+  $ hg debugbuilddag -n '.+3:a$.+5:b/a:k$.+7:c/b:l$.+6:d/a:m<k+6/l+1/m'
+  $ hg log -G
+  o    r36 tip
+  |\
+  | o  r35
+  | |
+  | o    r34
+  | |\
+  | | o  r33
+  | | |
+  | | o  r32
+  | | |
+  | | o  r31
+  | | |
+  | | o  r30
+  | | |
+  | | o  r29
+  | | |
+  | | o  r28
+  | | |
+  o | |    r27 m
+  |\ \ \
+  | o | |  r26 d
+  | | | |
+  | o | |  r25
+  | | | |
+  | o | |  r24
+  | | | |
+  | o | |  r23
+  | | | |
+  | o | |  r22
+  | | | |
+  | o | |  r21
+  | | | |
+  | o | |  r20
+  |  / /
+  | o |    r19 l
+  | |\ \
+  | | o |  r18 c
+  | | | |
+  | | o |  r17
+  | | | |
+  | | o |  r16
+  | | | |
+  | | o |  r15
+  | | | |
+  | | o |  r14
+  | | | |
+  | | o |  r13
+  | | | |
+  | | o |  r12
+  | | | |
+  | | o |  r11
+  | |  /
+  +---o  r10 k
+  | |/
+  | o  r9 b
+  | |
+  | o  r8
+  | |
+  | o  r7
+  | |
+  | o  r6
+  | |
+  | o  r5
+  | |
+  | o  r4
+  |
+  o  r3 a
+  |
+  o  r2
+  |
+  o  r1
+  |
+  o  r0
+  
+  $ cd ..
+
+
+Pull it in the client
+=====================
+
+
+pull with default value
+-----------------------
+
+  $ cp -R client client-simple-pull
+  $ hg -R client-simple-pull pull
+  pulling from $TESTTMP/server
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 37 changesets with 37 changes to 37 files
+  new changesets 61246295ee1e:b4b117cbbcf3
+  (run 'hg update' to get a working copy)
+  $ hg -R client-simple-pull verify
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  checking dirstate
+  checked 37 changesets with 37 changes to 37 files
+
+
+pull with "no-reuse" policy
+---------------------------
+
+  $ cp -R client client-no-reuse
+  $ hg -R client-no-reuse pull --config paths.default:pulled-delta-reuse-policy=no-reuse
+  pulling from $TESTTMP/server
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 37 changesets with 37 changes to 37 files
+  new changesets 61246295ee1e:b4b117cbbcf3
+  (run 'hg update' to get a working copy)
+  $ hg -R client-no-reuse verify
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  checking dirstate
+  checked 37 changesets with 37 changes to 37 files
+
+
+pull with "try-base" policy
+---------------------------
+
+  $ cp -R client client-try-base
+  $ hg -R client-try-base pull --config paths.default:pulled-delta-reuse-policy=try-base
+  pulling from $TESTTMP/server
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 37 changesets with 37 changes to 37 files
+  new changesets 61246295ee1e:b4b117cbbcf3
+  (run 'hg update' to get a working copy)
+  $ hg -R client-try-base verify
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  checking dirstate
+  checked 37 changesets with 37 changes to 37 files
+
+
+pull with "forced" policy
+-------------------------
+
+  $ cp -R client client-forced
+  $ hg -R client-forced pull --config paths.default:pulled-delta-reuse-policy=forced
+  pulling from $TESTTMP/server
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 37 changesets with 37 changes to 37 files
+  new changesets 61246295ee1e:b4b117cbbcf3
+  (run 'hg update' to get a working copy)
+  $ hg -R client-forced verify
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  checking dirstate
+  checked 37 changesets with 37 changes to 37 files
--- a/tests/test-status.t	Fri Apr 28 12:12:42 2023 +0200
+++ b/tests/test-status.t	Tue May 09 11:35:50 2023 +0200
@@ -1005,3 +1005,27 @@
       0         -1 set                 subdir
 
 #endif
+
+
+Test copy source formatting.
+  $ cd ..
+  $ hg init copy-source-repo
+  $ cd copy-source-repo
+  $ mkdir -p foo/bar
+  $ cd foo/bar
+  $ touch file
+  $ hg addremove
+  adding foo/bar/file
+  $ hg commit -m 'add file'
+  $ hg mv file copy
+
+Copy source respects relative path setting.
+  $ hg st --config ui.statuscopies=true --config commands.status.relative=true
+  A copy
+    file
+  R file
+
+Copy source is not shown when --no-status is passed.
+  $ hg st --config ui.statuscopies=true --no-status
+  foo/bar/copy
+  foo/bar/file
--- a/tests/test-transaction-rollback-on-revlog-split.t	Fri Apr 28 12:12:42 2023 +0200
+++ b/tests/test-transaction-rollback-on-revlog-split.t	Tue May 09 11:35:50 2023 +0200
@@ -1,6 +1,9 @@
 Test correctness of revlog inline -> non-inline transition
 ----------------------------------------------------------
 
+We test various file length and naming pattern as this created issue in the
+past.
+
 Helper extension to intercept renames and kill process
 
   $ cat > $TESTTMP/intercept_before_rename.py << EOF
@@ -76,13 +79,30 @@
 
   $ hg init troffset-computation
   $ cd troffset-computation
-  $ printf '%20d' '1' > file
+  $ files="
+  > file
+  > Directory_With,Special%Char/Complex_File.babar
+  > foo/bar/babar_celeste/foo
+  > 1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/f
+  > "
+  $ for f in $files; do
+  >     mkdir -p `dirname $f`
+  > done
+  $ for f in $files; do
+  >     printf '%20d' '1' > $f
+  > done
   $ hg commit -Aqma
-  $ printf '%1024d' '1' > file
+  $ for f in $files; do
+  >     printf '%1024d' '1' > $f
+  > done
   $ hg commit -Aqmb
-  $ printf '%20d' '1' > file
+  $ for f in $files; do
+  >     printf '%20d' '1' > $f
+  > done
   $ hg commit -Aqmc
-  $ dd if=/dev/zero of=file bs=1k count=128 > /dev/null 2>&1
+  $ for f in $files; do
+  >     dd if=/dev/zero of=$f bs=1k count=128 > /dev/null 2>&1
+  > done
   $ hg commit -AqmD --traceback
 
 Reference size:
@@ -163,7 +183,7 @@
   $ f -s .hg/store/data/file*
   .hg/store/data/file.i: size=1174
   $ hg tip
-  changeset:   1:cfa8d6e60429
+  changeset:   1:cc8dfb126534
   tag:         tip
   user:        test
   date:        Thu Jan 01 00:00:00 1970 +0000
@@ -233,7 +253,7 @@
   $ f -s .hg/store/data/file*
   .hg/store/data/file.i: size=1174
   $ hg tip
-  changeset:   1:cfa8d6e60429
+  changeset:   1:cc8dfb126534
   tag:         tip
   user:        test
   date:        Thu Jan 01 00:00:00 1970 +0000
@@ -297,7 +317,7 @@
   $ f -s .hg/store/data/file*
   .hg/store/data/file.i: size=1174
   $ hg tip
-  changeset:   1:cfa8d6e60429
+  changeset:   1:cc8dfb126534
   tag:         tip
   user:        test
   date:        Thu Jan 01 00:00:00 1970 +0000
@@ -337,7 +357,7 @@
 
 
   $ hg tip
-  changeset:   1:cfa8d6e60429
+  changeset:   1:cc8dfb126534
   tag:         tip
   user:        test
   date:        Thu Jan 01 00:00:00 1970 +0000