hgext/convert/git.py
author Patrick Mezard <pmezard@gmail.com>
Sun, 26 Aug 2007 16:49:26 +0200
changeset 5246 7d3dcdd92a1a
parent 5121 ef338e34a906
parent 5217 149742a628fd
child 5247 20770c5d41e0
permissions -rw-r--r--
Merge with crew-stable
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
4536
cc9b79216a76 Split convert extension into common and repository type modules
Brendan Cully <brendan@kublai.com>
parents: 4532
diff changeset
     1
# git support for the convert extension
3821
158fce02dc40 Teach convert-repo to deal with mixed charsets in git
Matt Mackall <mpm@selenic.com>
parents: 2657
diff changeset
     2
4536
cc9b79216a76 Split convert extension into common and repository type modules
Brendan Cully <brendan@kublai.com>
parents: 4532
diff changeset
     3
import os
3938
0fab73b3f453 convert-repo: add some smarts
Matt Mackall <mpm@selenic.com>
parents: 3917
diff changeset
     4
4536
cc9b79216a76 Split convert extension into common and repository type modules
Brendan Cully <brendan@kublai.com>
parents: 4532
diff changeset
     5
from common import NoRepo, commit, converter_source
3954
9af4b853ed4d convert-repo: add CVS branch support
Matt Mackall <mpm@selenic.com>
parents: 3953
diff changeset
     6
4448
af013ae3ca10 use documented convert-repo interface
Daniel Holth <dholth@fastmail.fm>
parents: 4447
diff changeset
     7
class convert_git(converter_source):
5217
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
     8
    # Windows does not support GIT_DIR= construct while other systems
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
     9
    # cannot remove environment variable. Just assume none have
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
    10
    # both issues.
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
    11
    if hasattr(os, 'unsetenv'):
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
    12
        def gitcmd(self, s):
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
    13
            prevgitdir = os.environ.get('GIT_DIR')
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
    14
            os.environ['GIT_DIR'] = self.path
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
    15
            try:
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
    16
                return os.popen(s)
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
    17
            finally:
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
    18
                if prevgitdir is None:
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
    19
                    del os.environ['GIT_DIR']
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
    20
                else:
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
    21
                    os.environ['GIT_DIR'] = prevgitdir
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
    22
    else:
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
    23
        def gitcmd(self, s):
149742a628fd convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
Patrick Mezard <pmezard@gmail.com>
parents: 5216
diff changeset
    24
            return os.popen('GIT_DIR=%s %s' % (self.path, s))
4767
2d0a823cbba5 convert: gitcmd wrapper for os.popen
Brendan Cully <brendan@kublai.com>
parents: 4760
diff changeset
    25
4760
07efcce17d28 convert: add -r argument specifying latest revision to convert
Brendan Cully <brendan@kublai.com>
parents: 4759
diff changeset
    26
    def __init__(self, ui, path, rev=None):
4807
15a3cbfc6568 convert: call superclass init from engine init functions
Brendan Cully <brendan@kublai.com>
parents: 4768
diff changeset
    27
        super(convert_git, self).__init__(ui, path, rev=rev)
15a3cbfc6568 convert: call superclass init from engine init functions
Brendan Cully <brendan@kublai.com>
parents: 4768
diff changeset
    28
3938
0fab73b3f453 convert-repo: add some smarts
Matt Mackall <mpm@selenic.com>
parents: 3917
diff changeset
    29
        if os.path.isdir(path + "/.git"):
0fab73b3f453 convert-repo: add some smarts
Matt Mackall <mpm@selenic.com>
parents: 3917
diff changeset
    30
            path += "/.git"
4102
06d65498f73b convert-repo: use .git/objects/ rather than .git/HEAD to detect git repos
Matt Mackall <mpm@selenic.com>
parents: 4082
diff changeset
    31
        if not os.path.exists(path + "/objects"):
3953
fad134931327 convert-repo: add basic CVS import support
Matt Mackall <mpm@selenic.com>
parents: 3939
diff changeset
    32
            raise NoRepo("couldn't open GIT repo %s" % path)
316
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    33
        self.path = path
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    34
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    35
    def getheads(self):
4768
f52bfe566583 convert: import all branches from git repositories
Brendan Cully <brendan@kublai.com>
parents: 4767
diff changeset
    36
        if not self.rev:
f52bfe566583 convert: import all branches from git repositories
Brendan Cully <brendan@kublai.com>
parents: 4767
diff changeset
    37
            return self.gitcmd('git-rev-parse --branches').read().splitlines()
f52bfe566583 convert: import all branches from git repositories
Brendan Cully <brendan@kublai.com>
parents: 4767
diff changeset
    38
        else:
f52bfe566583 convert: import all branches from git repositories
Brendan Cully <brendan@kublai.com>
parents: 4767
diff changeset
    39
            fh = self.gitcmd("git-rev-parse --verify %s" % self.rev)
f52bfe566583 convert: import all branches from git repositories
Brendan Cully <brendan@kublai.com>
parents: 4767
diff changeset
    40
            return [fh.read()[:-1]]
316
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    41
692
695dd9a491da convert-repo: deal with packed git and other fixes
mpm@selenic.com
parents: 450
diff changeset
    42
    def catfile(self, rev, type):
695dd9a491da convert-repo: deal with packed git and other fixes
mpm@selenic.com
parents: 450
diff changeset
    43
        if rev == "0" * 40: raise IOError()
5216
39e6deaa8b81 convert: gitcmd wrapper for os.popen
Brendan Cully <brendan@kublai.com>
parents: 4721
diff changeset
    44
        fh = self.gitcmd("git-cat-file %s %s 2>/dev/null" % (type, rev))
692
695dd9a491da convert-repo: deal with packed git and other fixes
mpm@selenic.com
parents: 450
diff changeset
    45
        return fh.read()
695dd9a491da convert-repo: deal with packed git and other fixes
mpm@selenic.com
parents: 450
diff changeset
    46
316
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    47
    def getfile(self, name, rev):
692
695dd9a491da convert-repo: deal with packed git and other fixes
mpm@selenic.com
parents: 450
diff changeset
    48
        return self.catfile(rev, "blob")
316
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    49
3956
558f52943cd2 convert-repo: add CVS exec bit support
Matt Mackall <mpm@selenic.com>
parents: 3954
diff changeset
    50
    def getmode(self, name, rev):
558f52943cd2 convert-repo: add CVS exec bit support
Matt Mackall <mpm@selenic.com>
parents: 3954
diff changeset
    51
        return self.modecache[(name, rev)]
558f52943cd2 convert-repo: add CVS exec bit support
Matt Mackall <mpm@selenic.com>
parents: 3954
diff changeset
    52
316
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    53
    def getchanges(self, version):
3956
558f52943cd2 convert-repo: add CVS exec bit support
Matt Mackall <mpm@selenic.com>
parents: 3954
diff changeset
    54
        self.modecache = {}
5216
39e6deaa8b81 convert: gitcmd wrapper for os.popen
Brendan Cully <brendan@kublai.com>
parents: 4721
diff changeset
    55
        fh = self.gitcmd("git-diff-tree --root -m -r %s" % version)
316
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    56
        changes = []
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    57
        for l in fh:
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    58
            if "\t" not in l: continue
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    59
            m, f = l[:-1].split("\t")
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    60
            m = m.split()
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    61
            h = m[3]
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    62
            p = (m[1] == "100755")
4082
6b2909e84203 convert-repo converts symlinks from git
Daniel Holth <dholth@fastmail.fm>
parents: 4062
diff changeset
    63
            s = (m[1] == "120000")
6b2909e84203 convert-repo converts symlinks from git
Daniel Holth <dholth@fastmail.fm>
parents: 4062
diff changeset
    64
            self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
3956
558f52943cd2 convert-repo: add CVS exec bit support
Matt Mackall <mpm@selenic.com>
parents: 3954
diff changeset
    65
            changes.append((f, h))
5121
ef338e34a906 convert: look up copies in getchanges instead of getcommit
Brendan Cully <brendan@kublai.com>
parents: 4873
diff changeset
    66
        return (changes, {})
316
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    67
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    68
    def getcommit(self, version):
692
695dd9a491da convert-repo: deal with packed git and other fixes
mpm@selenic.com
parents: 450
diff changeset
    69
        c = self.catfile(version, "commit") # read the commit hash
316
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    70
        end = c.find("\n\n")
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    71
        message = c[end+2:]
4759
20ec5cc02f18 convert: ove recode method into converter_source
Brendan Cully <brendan@kublai.com>
parents: 4721
diff changeset
    72
        message = self.recode(message)
316
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    73
        l = c[:end].splitlines()
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    74
        manifest = l[0].split()[1]
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    75
        parents = []
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    76
        for e in l[1:]:
4532
c3a78a49d7f0 Some small cleanups for convert extension:
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4521
diff changeset
    77
            n, v = e.split(" ", 1)
316
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    78
            if n == "author":
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    79
                p = v.split()
1385
adb3de56635b convert-repo: Fix timezone handling
Matt Mackall <mpm@selenic.com>
parents: 1335
diff changeset
    80
                tm, tz = p[-2:]
316
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    81
                author = " ".join(p[:-2])
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    82
                if author[0] == "<": author = author[1:-1]
4759
20ec5cc02f18 convert: ove recode method into converter_source
Brendan Cully <brendan@kublai.com>
parents: 4721
diff changeset
    83
                author = self.recode(author)
692
695dd9a491da convert-repo: deal with packed git and other fixes
mpm@selenic.com
parents: 450
diff changeset
    84
            if n == "committer":
431
dfc44f3f587c convert-repo fixups
mpm@selenic.com
parents: 316
diff changeset
    85
                p = v.split()
1385
adb3de56635b convert-repo: Fix timezone handling
Matt Mackall <mpm@selenic.com>
parents: 1335
diff changeset
    86
                tm, tz = p[-2:]
431
dfc44f3f587c convert-repo fixups
mpm@selenic.com
parents: 316
diff changeset
    87
                committer = " ".join(p[:-2])
dfc44f3f587c convert-repo fixups
mpm@selenic.com
parents: 316
diff changeset
    88
                if committer[0] == "<": committer = committer[1:-1]
4759
20ec5cc02f18 convert: ove recode method into converter_source
Brendan Cully <brendan@kublai.com>
parents: 4721
diff changeset
    89
                committer = self.recode(committer)
3910
4bc5a2405b12 convert-repo: fix recoding of committer
Matt Mackall <mpm@selenic.com>
parents: 3821
diff changeset
    90
                message += "\ncommitter: %s\n" % committer
316
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
    91
            if n == "parent": parents.append(v)
1385
adb3de56635b convert-repo: Fix timezone handling
Matt Mackall <mpm@selenic.com>
parents: 1335
diff changeset
    92
adb3de56635b convert-repo: Fix timezone handling
Matt Mackall <mpm@selenic.com>
parents: 1335
diff changeset
    93
        tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
2093
5cc414722587 convert-repo: fix reversed time zone offset
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1715
diff changeset
    94
        tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
1385
adb3de56635b convert-repo: Fix timezone handling
Matt Mackall <mpm@selenic.com>
parents: 1335
diff changeset
    95
        date = tm + " " + str(tz)
4721
96614af3c679 convert: "unknown" is a string
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4684
diff changeset
    96
        author = author or "unknown"
3954
9af4b853ed4d convert-repo: add CVS branch support
Matt Mackall <mpm@selenic.com>
parents: 3953
diff changeset
    97
4873
28b23b9073a8 convert: record the source revision in the changelog
Brendan Cully <brendan@kublai.com>
parents: 4810
diff changeset
    98
        c = commit(parents=parents, date=date, author=author, desc=message,
28b23b9073a8 convert: record the source revision in the changelog
Brendan Cully <brendan@kublai.com>
parents: 4810
diff changeset
    99
                   rev=version)
3954
9af4b853ed4d convert-repo: add CVS branch support
Matt Mackall <mpm@selenic.com>
parents: 3953
diff changeset
   100
        return c
316
c48d069163d6 Add new convert-repo script
mpm@selenic.com
parents:
diff changeset
   101
694
51eb248d3348 Teach convert-repo about tags
mpm@selenic.com
parents: 692
diff changeset
   102
    def gettags(self):
51eb248d3348 Teach convert-repo about tags
mpm@selenic.com
parents: 692
diff changeset
   103
        tags = {}
5216
39e6deaa8b81 convert: gitcmd wrapper for os.popen
Brendan Cully <brendan@kublai.com>
parents: 4721
diff changeset
   104
        fh = self.gitcmd('git-ls-remote --tags "%s" 2>/dev/null' % self.path)
4062
516f883e3d79 convert-repo: handle packed git tags
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4047
diff changeset
   105
        prefix = 'refs/tags/'
516f883e3d79 convert-repo: handle packed git tags
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4047
diff changeset
   106
        for line in fh:
516f883e3d79 convert-repo: handle packed git tags
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4047
diff changeset
   107
            line = line.strip()
516f883e3d79 convert-repo: handle packed git tags
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4047
diff changeset
   108
            if not line.endswith("^{}"):
516f883e3d79 convert-repo: handle packed git tags
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4047
diff changeset
   109
                continue
516f883e3d79 convert-repo: handle packed git tags
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4047
diff changeset
   110
            node, tag = line.split(None, 1)
516f883e3d79 convert-repo: handle packed git tags
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4047
diff changeset
   111
            if not tag.startswith(prefix):
516f883e3d79 convert-repo: handle packed git tags
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4047
diff changeset
   112
                continue
516f883e3d79 convert-repo: handle packed git tags
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4047
diff changeset
   113
            tag = tag[len(prefix):-3]
516f883e3d79 convert-repo: handle packed git tags
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4047
diff changeset
   114
            tags[tag] = node
516f883e3d79 convert-repo: handle packed git tags
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4047
diff changeset
   115
694
51eb248d3348 Teach convert-repo about tags
mpm@selenic.com
parents: 692
diff changeset
   116
        return tags