##// END OF EJS Templates
convert/git: check status when reading output stream
Patrick Mezard -
r10987:b3af02b1 stable
parent child Browse files
Show More
@@ -1,166 +1,170 b''
1 1 # git.py - git support for the convert extension
2 2 #
3 3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 import os
9 9 from mercurial import util
10 10 from mercurial.i18n import _
11 11
12 12 from common import NoRepo, commit, converter_source, checktool
13 13
14 14 class convert_git(converter_source):
15 15 # Windows does not support GIT_DIR= construct while other systems
16 16 # cannot remove environment variable. Just assume none have
17 17 # both issues.
18 18 if hasattr(os, 'unsetenv'):
19 19 def gitopen(self, s):
20 20 prevgitdir = os.environ.get('GIT_DIR')
21 21 os.environ['GIT_DIR'] = self.path
22 22 try:
23 23 return util.popen(s, 'rb')
24 24 finally:
25 25 if prevgitdir is None:
26 26 del os.environ['GIT_DIR']
27 27 else:
28 28 os.environ['GIT_DIR'] = prevgitdir
29 29 else:
30 30 def gitopen(self, s):
31 31 return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb')
32 32
33 33 def gitread(self, s):
34 34 fh = self.gitopen(s)
35 35 data = fh.read()
36 36 return data, fh.close()
37 37
38 38 def __init__(self, ui, path, rev=None):
39 39 super(convert_git, self).__init__(ui, path, rev=rev)
40 40
41 41 if os.path.isdir(path + "/.git"):
42 42 path += "/.git"
43 43 if not os.path.exists(path + "/objects"):
44 44 raise NoRepo(_("%s does not look like a Git repository") % path)
45 45
46 46 checktool('git', 'git')
47 47
48 48 self.path = path
49 49
50 50 def getheads(self):
51 51 if not self.rev:
52 52 heads, ret = self.gitread('git rev-parse --branches --remotes')
53 53 heads = heads.splitlines()
54 54 else:
55 55 heads, ret = self.gitread("git rev-parse --verify %s" % self.rev)
56 56 heads = [heads[:-1]]
57 57 if ret:
58 58 raise util.Abort(_('cannot retrieve git heads'))
59 59 return heads
60 60
61 61 def catfile(self, rev, type):
62 62 if rev == "0" * 40:
63 63 raise IOError()
64 64 data, ret = self.gitread("git cat-file %s %s" % (type, rev))
65 65 if ret:
66 66 raise util.Abort(_('cannot read %r object at %s') % (type, rev))
67 67 return data
68 68
69 69 def getfile(self, name, rev):
70 70 return self.catfile(rev, "blob")
71 71
72 72 def getmode(self, name, rev):
73 73 return self.modecache[(name, rev)]
74 74
75 75 def getchanges(self, version):
76 76 self.modecache = {}
77 77 fh = self.gitopen("git diff-tree -z --root -m -r %s" % version)
78 78 changes = []
79 79 seen = set()
80 80 entry = None
81 81 for l in fh.read().split('\x00'):
82 82 if not entry:
83 83 if not l.startswith(':'):
84 84 continue
85 85 entry = l
86 86 continue
87 87 f = l
88 88 if f not in seen:
89 89 seen.add(f)
90 90 entry = entry.split()
91 91 h = entry[3]
92 92 p = (entry[1] == "100755")
93 93 s = (entry[1] == "120000")
94 94 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
95 95 changes.append((f, h))
96 96 entry = None
97 if fh.close():
98 raise util.Abort(_('cannot read changes in %s') % version)
97 99 return (changes, {})
98 100
99 101 def getcommit(self, version):
100 102 c = self.catfile(version, "commit") # read the commit hash
101 103 end = c.find("\n\n")
102 104 message = c[end + 2:]
103 105 message = self.recode(message)
104 106 l = c[:end].splitlines()
105 107 parents = []
106 108 author = committer = None
107 109 for e in l[1:]:
108 110 n, v = e.split(" ", 1)
109 111 if n == "author":
110 112 p = v.split()
111 113 tm, tz = p[-2:]
112 114 author = " ".join(p[:-2])
113 115 if author[0] == "<": author = author[1:-1]
114 116 author = self.recode(author)
115 117 if n == "committer":
116 118 p = v.split()
117 119 tm, tz = p[-2:]
118 120 committer = " ".join(p[:-2])
119 121 if committer[0] == "<": committer = committer[1:-1]
120 122 committer = self.recode(committer)
121 123 if n == "parent":
122 124 parents.append(v)
123 125
124 126 if committer and committer != author:
125 127 message += "\ncommitter: %s\n" % committer
126 128 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
127 129 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
128 130 date = tm + " " + str(tz)
129 131
130 132 c = commit(parents=parents, date=date, author=author, desc=message,
131 133 rev=version)
132 134 return c
133 135
134 136 def gettags(self):
135 137 tags = {}
136 138 fh = self.gitopen('git ls-remote --tags "%s"' % self.path)
137 139 prefix = 'refs/tags/'
138 140 for line in fh:
139 141 line = line.strip()
140 142 if not line.endswith("^{}"):
141 143 continue
142 144 node, tag = line.split(None, 1)
143 145 if not tag.startswith(prefix):
144 146 continue
145 147 tag = tag[len(prefix):-3]
146 148 tags[tag] = node
149 if fh.close():
150 raise util.Abort(_('cannot read tags from %s') % self.path)
147 151
148 152 return tags
149 153
150 154 def getchangedfiles(self, version, i):
151 155 changes = []
152 156 if i is None:
153 157 fh = self.gitopen("git diff-tree --root -m -r %s" % version)
154 158 for l in fh:
155 159 if "\t" not in l:
156 160 continue
157 161 m, f = l[:-1].split("\t")
158 162 changes.append(f)
159 fh.close()
160 163 else:
161 164 fh = self.gitopen('git diff-tree --name-only --root -r %s "%s^%s" --'
162 165 % (version, version, i + 1))
163 166 changes = [f.rstrip('\n') for f in fh]
164 fh.close()
167 if fh.close():
168 raise util.Abort(_('cannot read changes in %s') % version)
165 169
166 170 return changes
@@ -1,173 +1,186 b''
1 1 #!/bin/sh
2 2
3 3 "$TESTDIR/hghave" git || exit 80
4 4
5 5 echo "[extensions]" >> $HGRCPATH
6 6 echo "convert=" >> $HGRCPATH
7 7 echo 'hgext.graphlog =' >> $HGRCPATH
8 8
9 9 GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
10 10 GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
11 11 GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0000"; export GIT_AUTHOR_DATE
12 12 GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
13 13 GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
14 14 GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
15 15
16 16 count=10
17 17 commit()
18 18 {
19 19 GIT_AUTHOR_DATE="2007-01-01 00:00:$count +0000"
20 20 GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
21 21 git commit "$@" >/dev/null 2>/dev/null || echo "git commit error"
22 22 count=`expr $count + 1`
23 23 }
24 24
25 25 mkdir git-repo
26 26 cd git-repo
27 27 git init-db >/dev/null 2>/dev/null
28 28 echo a > a
29 29 mkdir d
30 30 echo b > d/b
31 31 git add a d
32 32 commit -a -m t1
33 33
34 34 # Remove the directory, then try to replace it with a file
35 35 # (issue 754)
36 36 git rm -f d/b
37 37 commit -m t2
38 38 echo d > d
39 39 git add d
40 40 commit -m t3
41 41
42 42 echo b >> a
43 43 commit -a -m t4.1
44 44
45 45 git checkout -b other HEAD~ >/dev/null 2>/dev/null
46 46 echo c > a
47 47 echo a >> a
48 48 commit -a -m t4.2
49 49
50 50 git checkout master >/dev/null 2>/dev/null
51 51 git pull --no-commit . other > /dev/null 2>/dev/null
52 52 commit -m 'Merge branch other'
53 53 cd ..
54 54
55 55 hg convert --datesort git-repo
56 56 hg up -q -R git-repo-hg
57 57 hg -R git-repo-hg tip -v
58 58
59 59 count=10
60 60 mkdir git-repo2
61 61 cd git-repo2
62 62 git init-db >/dev/null 2>/dev/null
63 63
64 64 echo foo > foo
65 65 git add foo
66 66 commit -a -m 'add foo'
67 67
68 68 echo >> foo
69 69 commit -a -m 'change foo'
70 70
71 71 git checkout -b Bar HEAD~ >/dev/null 2>/dev/null
72 72 echo quux >> quux
73 73 git add quux
74 74 commit -a -m 'add quux'
75 75
76 76 echo bar > bar
77 77 git add bar
78 78 commit -a -m 'add bar'
79 79
80 80 git checkout -b Baz HEAD~ >/dev/null 2>/dev/null
81 81 echo baz > baz
82 82 git add baz
83 83 commit -a -m 'add baz'
84 84
85 85 git checkout master >/dev/null 2>/dev/null
86 86 git pull --no-commit . Bar Baz > /dev/null 2>/dev/null
87 87 commit -m 'Octopus merge'
88 88
89 89 echo bar >> bar
90 90 commit -a -m 'change bar'
91 91
92 92 git checkout -b Foo HEAD~ >/dev/null 2>/dev/null
93 93 echo >> foo
94 94 commit -a -m 'change foo'
95 95
96 96 git checkout master >/dev/null 2>/dev/null
97 97 git pull --no-commit -s ours . Foo > /dev/null 2>/dev/null
98 98 commit -m 'Discard change to foo'
99 99
100 100 cd ..
101 101
102 102 glog()
103 103 {
104 104 hg glog --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
105 105 }
106 106
107 107 splitrepo()
108 108 {
109 109 msg="$1"
110 110 files="$2"
111 111 opts=$3
112 112 echo "% $files: $msg"
113 113 prefix=`echo "$files" | sed -e 's/ /-/g'`
114 114 fmap="$prefix.fmap"
115 115 repo="$prefix.repo"
116 116 for i in $files; do
117 117 echo "include $i" >> "$fmap"
118 118 done
119 119 hg -q convert $opts --filemap "$fmap" --datesort git-repo2 "$repo"
120 120 hg up -q -R "$repo"
121 121 glog -R "$repo"
122 122 hg -R "$repo" manifest --debug
123 123 }
124 124
125 125 echo '% full conversion'
126 126 hg -q convert --datesort git-repo2 fullrepo
127 127 hg up -q -R fullrepo
128 128 glog -R fullrepo
129 129 hg -R fullrepo manifest --debug
130 130
131 131 splitrepo 'octopus merge' 'foo bar baz'
132 132
133 133 splitrepo 'only some parents of an octopus merge; "discard" a head' 'foo baz quux'
134 134
135 135 echo
136 136 echo '% test binary conversion (issue 1359)'
137 137 mkdir git-repo3
138 138 cd git-repo3
139 139 git init-db >/dev/null 2>/dev/null
140 140 python -c 'file("b", "wb").write("".join([chr(i) for i in range(256)])*16)'
141 141 git add b
142 142 commit -a -m addbinary
143 143 cd ..
144 144
145 145 echo '% convert binary file'
146 146 hg convert git-repo3 git-repo3-hg
147 147
148 148 cd git-repo3-hg
149 149 hg up -C
150 150 python -c 'print len(file("b", "rb").read())'
151 151 cd ..
152 152
153 153 echo
154 154 echo '% test author vs committer'
155 155 mkdir git-repo4
156 156 cd git-repo4
157 157 git init-db >/dev/null 2>/dev/null
158 158 echo >> foo
159 159 git add foo
160 160 commit -a -m addfoo
161 161 echo >> foo
162 162 GIT_AUTHOR_NAME="nottest"
163 163 commit -a -m addfoo2
164 164 cd ..
165 165
166 166 echo '% convert author committer'
167 167 hg convert git-repo4 git-repo4-hg
168 168 hg -R git-repo4-hg log -v
169 169
170 170 echo '% --sourceorder should fail'
171 171 hg convert --sourcesort git-repo4 git-repo4-sourcesort-hg
172 172
173 echo '% damage git repository and convert again'
174 cat > damage.py <<EOF
175 import os
176 for root, dirs, files in os.walk('git-repo4/.git/objects'):
177 if files:
178 path = os.path.join(root, files[0])
179 os.remove(path)
180 break
181 EOF
182 python damage.py
183 hg convert git-repo4 git-repo4-broken-hg 2>&1 | \
184 sed 's/fatal:.*/fatal: git error/g'
185
173 186 true
@@ -1,129 +1,137 b''
1 1 rm 'd/b'
2 2 assuming destination git-repo-hg
3 3 initializing destination git-repo-hg repository
4 4 scanning source...
5 5 sorting...
6 6 converting...
7 7 5 t1
8 8 4 t2
9 9 3 t3
10 10 2 t4.1
11 11 1 t4.2
12 12 0 Merge branch other
13 13 changeset: 5:c78094926be2
14 14 tag: tip
15 15 parent: 3:f5f5cb45432b
16 16 parent: 4:4e174f80c67c
17 17 user: test <test@example.org>
18 18 date: Mon Jan 01 00:00:15 2007 +0000
19 19 files: a
20 20 description:
21 21 Merge branch other
22 22
23 23
24 24 % full conversion
25 25 @ 9 "Discard change to foo" files: foo
26 26 |\
27 27 | o 8 "change foo" files: foo
28 28 | |
29 29 o | 7 "change bar" files: bar
30 30 |/
31 31 o 6 "(octopus merge fixup)" files:
32 32 |\
33 33 | o 5 "Octopus merge" files: baz
34 34 | |\
35 35 o | | 4 "add baz" files: baz
36 36 | | |
37 37 +---o 3 "add bar" files: bar
38 38 | |
39 39 o | 2 "add quux" files: quux
40 40 | |
41 41 | o 1 "change foo" files: foo
42 42 |/
43 43 o 0 "add foo" files: foo
44 44
45 45 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
46 46 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
47 47 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
48 48 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
49 49 % foo bar baz: octopus merge
50 50 @ 8 "Discard change to foo" files: foo
51 51 |\
52 52 | o 7 "change foo" files: foo
53 53 | |
54 54 o | 6 "change bar" files: bar
55 55 |/
56 56 o 5 "(octopus merge fixup)" files:
57 57 |\
58 58 | o 4 "Octopus merge" files: baz
59 59 | |\
60 60 o | | 3 "add baz" files: baz
61 61 | | |
62 62 +---o 2 "add bar" files: bar
63 63 | |
64 64 | o 1 "change foo" files: foo
65 65 |/
66 66 o 0 "add foo" files: foo
67 67
68 68 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
69 69 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
70 70 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
71 71 % foo baz quux: only some parents of an octopus merge; "discard" a head
72 72 @ 6 "Discard change to foo" files: foo
73 73 |
74 74 o 5 "change foo" files: foo
75 75 |
76 76 o 4 "Octopus merge" files:
77 77 |\
78 78 | o 3 "add baz" files: baz
79 79 | |
80 80 | o 2 "add quux" files: quux
81 81 | |
82 82 o | 1 "change foo" files: foo
83 83 |/
84 84 o 0 "add foo" files: foo
85 85
86 86 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
87 87 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
88 88 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
89 89
90 90 % test binary conversion (issue 1359)
91 91 % convert binary file
92 92 initializing destination git-repo3-hg repository
93 93 scanning source...
94 94 sorting...
95 95 converting...
96 96 0 addbinary
97 97 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
98 98 4096
99 99
100 100 % test author vs committer
101 101 % convert author committer
102 102 initializing destination git-repo4-hg repository
103 103 scanning source...
104 104 sorting...
105 105 converting...
106 106 1 addfoo
107 107 0 addfoo2
108 108 changeset: 1:d63e967f93da
109 109 tag: tip
110 110 user: nottest <test@example.org>
111 111 date: Mon Jan 01 00:00:21 2007 +0000
112 112 files: foo
113 113 description:
114 114 addfoo2
115 115
116 116 committer: test <test@example.org>
117 117
118 118
119 119 changeset: 0:0735477b0224
120 120 user: test <test@example.org>
121 121 date: Mon Jan 01 00:00:20 2007 +0000
122 122 files: foo
123 123 description:
124 124 addfoo
125 125
126 126
127 127 % --sourceorder should fail
128 128 initializing destination git-repo4-sourcesort-hg repository
129 129 abort: --sourcesort is not supported by this data source
130 % damage git repository and convert again
131 fatal: git error
132 initializing destination git-repo4-broken-hg repository
133 scanning source...
134 sorting...
135 converting...
136 1 addfoo
137 abort: cannot read changes in 6a101ac3f6d8b2524a64295ffd9be87ed927bfeb
General Comments 0
You need to be logged in to leave comments. Login now