[PATCH 1 of 2] convert: fix a test failure due to git change (issue3428)

Augie Fackler raf at durin42.com
Fri Feb 8 07:47:33 CST 2013


I'm going to split this patch some and then push.

On Feb 8, 2013, at 1:38 PM, Augie Fackler <raf at durin42.com> wrote:

> # HG changeset patch
> # User Ross Lagerwall <rosslagerwall at gmail.com>
> # Date 1343838158 -7200
> # Node ID d6b5ff41e899ffcd73ebbfaa9199cc2d235f918e
> # Parent  8bd338c7c4c9831850e1c4ddf24b747222a44131
> convert: fix a test failure due to git change (issue3428)
> 
> Since git v1.7.8.2-327-g926f1dd (the change was first released in
> git 1.7.10), git does not return non-zero when
> "git ls-remote --tags ..." is run and the repository is damaged.
> This causes the "damaged repository with missing commit" test in
> test-convert-git.t to unexpectedly succeed.
> 
> Fix by aborting if git outputs any lines beginning with "error:".
> 
> In addition, this error would show up only intermittently since the
> test depended on the order of the directories returned by os.walk.
> 
> The damage repository test would delete the first object file it came
> across. However, the order of the directory listing is arbitrary (it seems
> to depend on the filesystem). This meant that sometimes a commit object
> was deleted, sometimes a blob object and sometimes a tree object.
> 
> So, fix by hardcoding which object to delete. Delete a commit object, a
> blob object and a tree object in three separate tests.
> 
> diff --git a/hgext/convert/git.py b/hgext/convert/git.py
> --- a/hgext/convert/git.py
> +++ b/hgext/convert/git.py
> @@ -6,6 +6,7 @@
> # GNU General Public License version 2 or any later version.
> 
> import os
> +import subprocess
> from mercurial import util, config
> from mercurial.node import hex, nullid
> from mercurial.i18n import _
> @@ -29,13 +30,15 @@
>     # cannot remove environment variable. Just assume none have
>     # both issues.
>     if util.safehasattr(os, 'unsetenv'):
> -        def gitopen(self, s, noerr=False):
> +        def gitopen(self, s, err=None):
>             prevgitdir = os.environ.get('GIT_DIR')
>             os.environ['GIT_DIR'] = self.path
>             try:
> -                if noerr:
> +                if err == subprocess.PIPE:
>                     (stdin, stdout, stderr) = util.popen3(s)
>                     return stdout
> +                elif err == subprocess.STDOUT:
> +                    return self.popen_with_stderr(s)
>                 else:
>                     return util.popen(s, 'rb')
>             finally:
> @@ -44,13 +47,26 @@
>                 else:
>                     os.environ['GIT_DIR'] = prevgitdir
>     else:
> -        def gitopen(self, s, noerr=False):
> -            if noerr:
> +        def gitopen(self, s, err=None):
> +            if err == subprocess.PIPE:
>                 (sin, so, se) = util.popen3('GIT_DIR=%s %s' % (self.path, s))
>                 return so
> +            elif err == subprocess.STDOUT:
> +                    return self.popen_with_stderr(s)
>             else:
>                 return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb')
> 
> +    close_fds = os.name == 'posix'
> +    def popen_with_stderr(self, s):
> +        p = subprocess.Popen(s, shell=True, bufsize=-1,
> +                             close_fds=self.close_fds,
> +                             stdin=subprocess.PIPE,
> +                             stdout=subprocess.PIPE,
> +                             stderr=subprocess.STDOUT,
> +                             universal_newlines=False,
> +                             env=None)
> +        return p.stdout
> +
>     def gitread(self, s):
>         fh = self.gitopen(s)
>         data = fh.read()
> @@ -209,12 +225,15 @@
>     def gettags(self):
>         tags = {}
>         alltags = {}
> -        fh = self.gitopen('git ls-remote --tags "%s"' % self.path)
> +        fh = self.gitopen('git ls-remote --tags "%s"' % self.path,
> +                          err=subprocess.STDOUT)
>         prefix = 'refs/tags/'
> 
>         # Build complete list of tags, both annotated and bare ones
>         for line in fh:
>             line = line.strip()
> +            if line.startswith("error:"):
> +                raise util.Abort(_('cannot read tags from %s') % self.path)
>             node, tag = line.split(None, 1)
>             if not tag.startswith(prefix):
>                 continue
> @@ -266,7 +285,7 @@
>         # Origin heads
>         for reftype in gitcmd:
>             try:
> -                fh = self.gitopen(gitcmd[reftype], noerr=True)
> +                fh = self.gitopen(gitcmd[reftype], err=subprocess.PIPE)
>                 for line in fh:
>                     line = line.strip()
>                     rev, name = line.split(None, 1)
> diff --git a/tests/test-convert-git.t b/tests/test-convert-git.t
> --- a/tests/test-convert-git.t
> +++ b/tests/test-convert-git.t
> @@ -281,24 +281,6 @@
>   abort: --sourcesort is not supported by this data source
>   [255]
> 
> -damage git repository and convert again
> -
> -  $ cat > damage.py <<EOF
> -  > import os
> -  > import stat
> -  > for root, dirs, files in os.walk('git-repo4/.git/objects'):
> -  >     if files:
> -  >         path = os.path.join(root, files[0])
> -  >         if os.name == 'nt':
> -  >             os.chmod(path, stat.S_IWUSR)
> -  >         os.remove(path)
> -  >         break
> -  > EOF
> -  $ python damage.py
> -  $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | \
> -  >     grep 'abort:' | sed 's/abort:.*/abort:/g'
> -  abort:
> -
> test sub modules
> 
>   $ mkdir git-repo5
> @@ -345,3 +327,32 @@
>   $ cd git-repo5
>   $ cat foo
>   sub
> +
> +  $ cd ../..
> +
> +damaged git repository tests:
> +In case the hard-coded hashes change, the following commands can be used to
> +list the hashes and their corresponding types in the repository:
> +cd git-repo4/.git/objects
> +find . -type f | cut -c 3- | sed 's_/__' | xargs -n 1 -t git cat-file -t
> +cd ../../..
> +
> +damage git repository by renaming a commit object
> +  $ COMMIT_OBJ=1c/0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
> +  $ mv git-repo4/.git/objects/$COMMIT_OBJ git-repo4/.git/objects/$COMMIT_OBJ.tmp
> +  $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
> +  abort: cannot read tags from git-repo4/.git
> +  $ mv git-repo4/.git/objects/$COMMIT_OBJ.tmp git-repo4/.git/objects/$COMMIT_OBJ
> +damage git repository by renaming a blob object
> +
> +  $ BLOB_OBJ=8b/137891791fe96927ad78e64b0aad7bded08bdc
> +  $ mv git-repo4/.git/objects/$BLOB_OBJ git-repo4/.git/objects/$BLOB_OBJ.tmp
> +  $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
> +  abort: cannot read 'blob' object at 8b137891791fe96927ad78e64b0aad7bded08bdc
> +  $ mv git-repo4/.git/objects/$BLOB_OBJ.tmp git-repo4/.git/objects/$BLOB_OBJ
> +damage git repository by renaming a tree object
> +
> +  $ TREE_OBJ=72/49f083d2a63a41cc737764a86981eb5f3e4635
> +  $ mv git-repo4/.git/objects/$TREE_OBJ git-repo4/.git/objects/$TREE_OBJ.tmp
> +  $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:'
> +  abort: cannot read changes in 1c0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel



More information about the Mercurial-devel mailing list