##// END OF EJS Templates
convert/bzr: ignore nested repos when listing branches (issue3254)...
Patrick Mezard -
r16099:4e4c416a default
parent child Browse files
Show More
@@ -1,282 +1,285
1 # bzr.py - bzr support for the convert extension
1 # bzr.py - bzr support for the convert extension
2 #
2 #
3 # Copyright 2008, 2009 Marek Kubica <marek@xivilization.net> and others
3 # Copyright 2008, 2009 Marek Kubica <marek@xivilization.net> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 # This module is for handling 'bzr', that was formerly known as Bazaar-NG;
8 # This module is for handling 'bzr', that was formerly known as Bazaar-NG;
9 # it cannot access 'bar' repositories, but they were never used very much
9 # it cannot access 'bar' repositories, but they were never used very much
10
10
11 import os
11 import os
12 from mercurial import demandimport
12 from mercurial import demandimport
13 # these do not work with demandimport, blacklist
13 # these do not work with demandimport, blacklist
14 demandimport.ignore.extend([
14 demandimport.ignore.extend([
15 'bzrlib.transactions',
15 'bzrlib.transactions',
16 'bzrlib.urlutils',
16 'bzrlib.urlutils',
17 'ElementPath',
17 'ElementPath',
18 ])
18 ])
19
19
20 from mercurial.i18n import _
20 from mercurial.i18n import _
21 from mercurial import util
21 from mercurial import util
22 from common import NoRepo, commit, converter_source
22 from common import NoRepo, commit, converter_source
23
23
24 try:
24 try:
25 # bazaar imports
25 # bazaar imports
26 from bzrlib import bzrdir, revision, errors
26 from bzrlib import bzrdir, revision, errors
27 from bzrlib.revisionspec import RevisionSpec
27 from bzrlib.revisionspec import RevisionSpec
28 except ImportError:
28 except ImportError:
29 pass
29 pass
30
30
31 supportedkinds = ('file', 'symlink')
31 supportedkinds = ('file', 'symlink')
32
32
33 class bzr_source(converter_source):
33 class bzr_source(converter_source):
34 """Reads Bazaar repositories by using the Bazaar Python libraries"""
34 """Reads Bazaar repositories by using the Bazaar Python libraries"""
35
35
36 def __init__(self, ui, path, rev=None):
36 def __init__(self, ui, path, rev=None):
37 super(bzr_source, self).__init__(ui, path, rev=rev)
37 super(bzr_source, self).__init__(ui, path, rev=rev)
38
38
39 if not os.path.exists(os.path.join(path, '.bzr')):
39 if not os.path.exists(os.path.join(path, '.bzr')):
40 raise NoRepo(_('%s does not look like a Bazaar repository')
40 raise NoRepo(_('%s does not look like a Bazaar repository')
41 % path)
41 % path)
42
42
43 try:
43 try:
44 # access bzrlib stuff
44 # access bzrlib stuff
45 bzrdir
45 bzrdir
46 except NameError:
46 except NameError:
47 raise NoRepo(_('Bazaar modules could not be loaded'))
47 raise NoRepo(_('Bazaar modules could not be loaded'))
48
48
49 path = os.path.abspath(path)
49 path = os.path.abspath(path)
50 self._checkrepotype(path)
50 self._checkrepotype(path)
51 try:
51 try:
52 self.sourcerepo = bzrdir.BzrDir.open(path).open_repository()
52 self.sourcerepo = bzrdir.BzrDir.open(path).open_repository()
53 except errors.NoRepositoryPresent:
53 except errors.NoRepositoryPresent:
54 raise NoRepo(_('%s does not look like a Bazaar repository')
54 raise NoRepo(_('%s does not look like a Bazaar repository')
55 % path)
55 % path)
56 self._parentids = {}
56 self._parentids = {}
57
57
58 def _checkrepotype(self, path):
58 def _checkrepotype(self, path):
59 # Lightweight checkouts detection is informational but probably
59 # Lightweight checkouts detection is informational but probably
60 # fragile at API level. It should not terminate the conversion.
60 # fragile at API level. It should not terminate the conversion.
61 try:
61 try:
62 from bzrlib import bzrdir
62 from bzrlib import bzrdir
63 dir = bzrdir.BzrDir.open_containing(path)[0]
63 dir = bzrdir.BzrDir.open_containing(path)[0]
64 try:
64 try:
65 tree = dir.open_workingtree(recommend_upgrade=False)
65 tree = dir.open_workingtree(recommend_upgrade=False)
66 branch = tree.branch
66 branch = tree.branch
67 except (errors.NoWorkingTree, errors.NotLocalUrl):
67 except (errors.NoWorkingTree, errors.NotLocalUrl):
68 tree = None
68 tree = None
69 branch = dir.open_branch()
69 branch = dir.open_branch()
70 if (tree is not None and tree.bzrdir.root_transport.base !=
70 if (tree is not None and tree.bzrdir.root_transport.base !=
71 branch.bzrdir.root_transport.base):
71 branch.bzrdir.root_transport.base):
72 self.ui.warn(_('warning: lightweight checkouts may cause '
72 self.ui.warn(_('warning: lightweight checkouts may cause '
73 'conversion failures, try with a regular '
73 'conversion failures, try with a regular '
74 'branch instead.\n'))
74 'branch instead.\n'))
75 except:
75 except:
76 self.ui.note(_('bzr source type could not be determined\n'))
76 self.ui.note(_('bzr source type could not be determined\n'))
77
77
78 def before(self):
78 def before(self):
79 """Before the conversion begins, acquire a read lock
79 """Before the conversion begins, acquire a read lock
80 for all the operations that might need it. Fortunately
80 for all the operations that might need it. Fortunately
81 read locks don't block other reads or writes to the
81 read locks don't block other reads or writes to the
82 repository, so this shouldn't have any impact on the usage of
82 repository, so this shouldn't have any impact on the usage of
83 the source repository.
83 the source repository.
84
84
85 The alternative would be locking on every operation that
85 The alternative would be locking on every operation that
86 needs locks (there are currently two: getting the file and
86 needs locks (there are currently two: getting the file and
87 getting the parent map) and releasing immediately after,
87 getting the parent map) and releasing immediately after,
88 but this approach can take even 40% longer."""
88 but this approach can take even 40% longer."""
89 self.sourcerepo.lock_read()
89 self.sourcerepo.lock_read()
90
90
91 def after(self):
91 def after(self):
92 self.sourcerepo.unlock()
92 self.sourcerepo.unlock()
93
93
94 def _bzrbranches(self):
95 return self.sourcerepo.find_branches(using=True)
96
94 def getheads(self):
97 def getheads(self):
95 if not self.rev:
98 if not self.rev:
96 heads = sorted([b.last_revision()
99 # Set using=True to avoid nested repositories (see issue3254)
97 for b in self.sourcerepo.find_branches()])
100 heads = sorted([b.last_revision() for b in self._bzrbranches()])
98 else:
101 else:
99 revid = None
102 revid = None
100 for branch in self.sourcerepo.find_branches():
103 for branch in self._bzrbranches():
101 try:
104 try:
102 r = RevisionSpec.from_string(self.rev)
105 r = RevisionSpec.from_string(self.rev)
103 info = r.in_history(branch)
106 info = r.in_history(branch)
104 except errors.BzrError:
107 except errors.BzrError:
105 pass
108 pass
106 revid = info.rev_id
109 revid = info.rev_id
107 if revid is None:
110 if revid is None:
108 raise util.Abort(_('%s is not a valid revision') % self.rev)
111 raise util.Abort(_('%s is not a valid revision') % self.rev)
109 heads = [revid]
112 heads = [revid]
110 # Empty repositories return 'null:', which cannot be retrieved
113 # Empty repositories return 'null:', which cannot be retrieved
111 heads = [h for h in heads if h != 'null:']
114 heads = [h for h in heads if h != 'null:']
112 return heads
115 return heads
113
116
114 def getfile(self, name, rev):
117 def getfile(self, name, rev):
115 revtree = self.sourcerepo.revision_tree(rev)
118 revtree = self.sourcerepo.revision_tree(rev)
116 fileid = revtree.path2id(name.decode(self.encoding or 'utf-8'))
119 fileid = revtree.path2id(name.decode(self.encoding or 'utf-8'))
117 kind = None
120 kind = None
118 if fileid is not None:
121 if fileid is not None:
119 kind = revtree.kind(fileid)
122 kind = revtree.kind(fileid)
120 if kind not in supportedkinds:
123 if kind not in supportedkinds:
121 # the file is not available anymore - was deleted
124 # the file is not available anymore - was deleted
122 raise IOError(_('%s is not available in %s anymore') %
125 raise IOError(_('%s is not available in %s anymore') %
123 (name, rev))
126 (name, rev))
124 mode = self._modecache[(name, rev)]
127 mode = self._modecache[(name, rev)]
125 if kind == 'symlink':
128 if kind == 'symlink':
126 target = revtree.get_symlink_target(fileid)
129 target = revtree.get_symlink_target(fileid)
127 if target is None:
130 if target is None:
128 raise util.Abort(_('%s.%s symlink has no target')
131 raise util.Abort(_('%s.%s symlink has no target')
129 % (name, rev))
132 % (name, rev))
130 return target, mode
133 return target, mode
131 else:
134 else:
132 sio = revtree.get_file(fileid)
135 sio = revtree.get_file(fileid)
133 return sio.read(), mode
136 return sio.read(), mode
134
137
135 def getchanges(self, version):
138 def getchanges(self, version):
136 # set up caches: modecache and revtree
139 # set up caches: modecache and revtree
137 self._modecache = {}
140 self._modecache = {}
138 self._revtree = self.sourcerepo.revision_tree(version)
141 self._revtree = self.sourcerepo.revision_tree(version)
139 # get the parentids from the cache
142 # get the parentids from the cache
140 parentids = self._parentids.pop(version)
143 parentids = self._parentids.pop(version)
141 # only diff against first parent id
144 # only diff against first parent id
142 prevtree = self.sourcerepo.revision_tree(parentids[0])
145 prevtree = self.sourcerepo.revision_tree(parentids[0])
143 return self._gettreechanges(self._revtree, prevtree)
146 return self._gettreechanges(self._revtree, prevtree)
144
147
145 def getcommit(self, version):
148 def getcommit(self, version):
146 rev = self.sourcerepo.get_revision(version)
149 rev = self.sourcerepo.get_revision(version)
147 # populate parent id cache
150 # populate parent id cache
148 if not rev.parent_ids:
151 if not rev.parent_ids:
149 parents = []
152 parents = []
150 self._parentids[version] = (revision.NULL_REVISION,)
153 self._parentids[version] = (revision.NULL_REVISION,)
151 else:
154 else:
152 parents = self._filterghosts(rev.parent_ids)
155 parents = self._filterghosts(rev.parent_ids)
153 self._parentids[version] = parents
156 self._parentids[version] = parents
154
157
155 branch = self.recode(rev.properties.get('branch-nick', u'default'))
158 branch = self.recode(rev.properties.get('branch-nick', u'default'))
156 if branch == 'trunk':
159 if branch == 'trunk':
157 branch = 'default'
160 branch = 'default'
158 return commit(parents=parents,
161 return commit(parents=parents,
159 date='%d %d' % (rev.timestamp, -rev.timezone),
162 date='%d %d' % (rev.timestamp, -rev.timezone),
160 author=self.recode(rev.committer),
163 author=self.recode(rev.committer),
161 desc=self.recode(rev.message),
164 desc=self.recode(rev.message),
162 branch=branch,
165 branch=branch,
163 rev=version)
166 rev=version)
164
167
165 def gettags(self):
168 def gettags(self):
166 bytetags = {}
169 bytetags = {}
167 for branch in self.sourcerepo.find_branches():
170 for branch in self._bzrbranches():
168 if not branch.supports_tags():
171 if not branch.supports_tags():
169 return {}
172 return {}
170 tagdict = branch.tags.get_tag_dict()
173 tagdict = branch.tags.get_tag_dict()
171 for name, rev in tagdict.iteritems():
174 for name, rev in tagdict.iteritems():
172 bytetags[self.recode(name)] = rev
175 bytetags[self.recode(name)] = rev
173 return bytetags
176 return bytetags
174
177
175 def getchangedfiles(self, rev, i):
178 def getchangedfiles(self, rev, i):
176 self._modecache = {}
179 self._modecache = {}
177 curtree = self.sourcerepo.revision_tree(rev)
180 curtree = self.sourcerepo.revision_tree(rev)
178 if i is not None:
181 if i is not None:
179 parentid = self._parentids[rev][i]
182 parentid = self._parentids[rev][i]
180 else:
183 else:
181 # no parent id, get the empty revision
184 # no parent id, get the empty revision
182 parentid = revision.NULL_REVISION
185 parentid = revision.NULL_REVISION
183
186
184 prevtree = self.sourcerepo.revision_tree(parentid)
187 prevtree = self.sourcerepo.revision_tree(parentid)
185 changes = [e[0] for e in self._gettreechanges(curtree, prevtree)[0]]
188 changes = [e[0] for e in self._gettreechanges(curtree, prevtree)[0]]
186 return changes
189 return changes
187
190
188 def _gettreechanges(self, current, origin):
191 def _gettreechanges(self, current, origin):
189 revid = current._revision_id
192 revid = current._revision_id
190 changes = []
193 changes = []
191 renames = {}
194 renames = {}
192 seen = set()
195 seen = set()
193 # Process the entries by reverse lexicographic name order to
196 # Process the entries by reverse lexicographic name order to
194 # handle nested renames correctly, most specific first.
197 # handle nested renames correctly, most specific first.
195 curchanges = sorted(current.iter_changes(origin),
198 curchanges = sorted(current.iter_changes(origin),
196 key=lambda c: c[1][0] or c[1][1],
199 key=lambda c: c[1][0] or c[1][1],
197 reverse=True)
200 reverse=True)
198 for (fileid, paths, changed_content, versioned, parent, name,
201 for (fileid, paths, changed_content, versioned, parent, name,
199 kind, executable) in curchanges:
202 kind, executable) in curchanges:
200
203
201 if paths[0] == u'' or paths[1] == u'':
204 if paths[0] == u'' or paths[1] == u'':
202 # ignore changes to tree root
205 # ignore changes to tree root
203 continue
206 continue
204
207
205 # bazaar tracks directories, mercurial does not, so
208 # bazaar tracks directories, mercurial does not, so
206 # we have to rename the directory contents
209 # we have to rename the directory contents
207 if kind[1] == 'directory':
210 if kind[1] == 'directory':
208 if kind[0] not in (None, 'directory'):
211 if kind[0] not in (None, 'directory'):
209 # Replacing 'something' with a directory, record it
212 # Replacing 'something' with a directory, record it
210 # so it can be removed.
213 # so it can be removed.
211 changes.append((self.recode(paths[0]), revid))
214 changes.append((self.recode(paths[0]), revid))
212
215
213 if kind[0] == 'directory' and None not in paths:
216 if kind[0] == 'directory' and None not in paths:
214 renaming = paths[0] != paths[1]
217 renaming = paths[0] != paths[1]
215 # neither an add nor an delete - a move
218 # neither an add nor an delete - a move
216 # rename all directory contents manually
219 # rename all directory contents manually
217 subdir = origin.inventory.path2id(paths[0])
220 subdir = origin.inventory.path2id(paths[0])
218 # get all child-entries of the directory
221 # get all child-entries of the directory
219 for name, entry in origin.inventory.iter_entries(subdir):
222 for name, entry in origin.inventory.iter_entries(subdir):
220 # hg does not track directory renames
223 # hg does not track directory renames
221 if entry.kind == 'directory':
224 if entry.kind == 'directory':
222 continue
225 continue
223 frompath = self.recode(paths[0] + '/' + name)
226 frompath = self.recode(paths[0] + '/' + name)
224 if frompath in seen:
227 if frompath in seen:
225 # Already handled by a more specific change entry
228 # Already handled by a more specific change entry
226 # This is important when you have:
229 # This is important when you have:
227 # a => b
230 # a => b
228 # a/c => a/c
231 # a/c => a/c
229 # Here a/c must not be renamed into b/c
232 # Here a/c must not be renamed into b/c
230 continue
233 continue
231 seen.add(frompath)
234 seen.add(frompath)
232 if not renaming:
235 if not renaming:
233 continue
236 continue
234 topath = self.recode(paths[1] + '/' + name)
237 topath = self.recode(paths[1] + '/' + name)
235 # register the files as changed
238 # register the files as changed
236 changes.append((frompath, revid))
239 changes.append((frompath, revid))
237 changes.append((topath, revid))
240 changes.append((topath, revid))
238 # add to mode cache
241 # add to mode cache
239 mode = ((entry.executable and 'x')
242 mode = ((entry.executable and 'x')
240 or (entry.kind == 'symlink' and 's')
243 or (entry.kind == 'symlink' and 's')
241 or '')
244 or '')
242 self._modecache[(topath, revid)] = mode
245 self._modecache[(topath, revid)] = mode
243 # register the change as move
246 # register the change as move
244 renames[topath] = frompath
247 renames[topath] = frompath
245
248
246 # no futher changes, go to the next change
249 # no futher changes, go to the next change
247 continue
250 continue
248
251
249 # we got unicode paths, need to convert them
252 # we got unicode paths, need to convert them
250 path, topath = paths
253 path, topath = paths
251 if path is not None:
254 if path is not None:
252 path = self.recode(path)
255 path = self.recode(path)
253 if topath is not None:
256 if topath is not None:
254 topath = self.recode(topath)
257 topath = self.recode(topath)
255 seen.add(path or topath)
258 seen.add(path or topath)
256
259
257 if topath is None:
260 if topath is None:
258 # file deleted
261 # file deleted
259 changes.append((path, revid))
262 changes.append((path, revid))
260 continue
263 continue
261
264
262 # renamed
265 # renamed
263 if path and path != topath:
266 if path and path != topath:
264 renames[topath] = path
267 renames[topath] = path
265 changes.append((path, revid))
268 changes.append((path, revid))
266
269
267 # populate the mode cache
270 # populate the mode cache
268 kind, executable = [e[1] for e in (kind, executable)]
271 kind, executable = [e[1] for e in (kind, executable)]
269 mode = ((executable and 'x') or (kind == 'symlink' and 'l')
272 mode = ((executable and 'x') or (kind == 'symlink' and 'l')
270 or '')
273 or '')
271 self._modecache[(topath, revid)] = mode
274 self._modecache[(topath, revid)] = mode
272 changes.append((topath, revid))
275 changes.append((topath, revid))
273
276
274 return changes, renames
277 return changes, renames
275
278
276 def _filterghosts(self, ids):
279 def _filterghosts(self, ids):
277 """Filters out ghost revisions which hg does not support, see
280 """Filters out ghost revisions which hg does not support, see
278 <http://bazaar-vcs.org/GhostRevision>
281 <http://bazaar-vcs.org/GhostRevision>
279 """
282 """
280 parentmap = self.sourcerepo.get_parent_map(ids)
283 parentmap = self.sourcerepo.get_parent_map(ids)
281 parents = tuple([parent for parent in ids if parent in parentmap])
284 parents = tuple([parent for parent in ids if parent in parentmap])
282 return parents
285 return parents
@@ -1,263 +1,284
1 $ "$TESTDIR/hghave" symlink execbit || exit 80
1 $ "$TESTDIR/hghave" symlink execbit || exit 80
2
2
3 $ . "$TESTDIR/bzr-definitions"
3 $ . "$TESTDIR/bzr-definitions"
4
4
5 create and rename on the same file in the same step
5 create and rename on the same file in the same step
6
6
7 $ mkdir test-createandrename
7 $ mkdir test-createandrename
8 $ cd test-createandrename
8 $ cd test-createandrename
9 $ bzr init -q source
9 $ bzr init -q source
10
10
11 test empty repo conversion (issue3233)
11 test empty repo conversion (issue3233)
12
12
13 $ hg convert source source-hg
13 $ hg convert source source-hg
14 initializing destination source-hg repository
14 initializing destination source-hg repository
15 scanning source...
15 scanning source...
16 sorting...
16 sorting...
17 converting...
17 converting...
18
18
19 back to the rename stuff
19 back to the rename stuff
20
20
21 $ cd source
21 $ cd source
22 $ echo a > a
22 $ echo a > a
23 $ echo c > c
23 $ echo c > c
24 $ echo e > e
24 $ echo e > e
25 $ bzr add -q a c e
25 $ bzr add -q a c e
26 $ bzr commit -q -m 'Initial add: a, c, e'
26 $ bzr commit -q -m 'Initial add: a, c, e'
27 $ bzr mv a b
27 $ bzr mv a b
28 a => b
28 a => b
29 $ bzr mv c d
29 $ bzr mv c d
30 c => d
30 c => d
31 $ bzr mv e f
31 $ bzr mv e f
32 e => f
32 e => f
33 $ echo a2 >> a
33 $ echo a2 >> a
34 $ mkdir e
34 $ mkdir e
35 $ bzr add -q a e
35 $ bzr add -q a e
36 $ bzr commit -q -m 'rename a into b, create a, rename c into d'
36 $ bzr commit -q -m 'rename a into b, create a, rename c into d'
37 $ cd ..
37 $ cd ..
38 $ hg convert source source-hg
38 $ hg convert source source-hg
39 scanning source...
39 scanning source...
40 sorting...
40 sorting...
41 converting...
41 converting...
42 1 Initial add: a, c, e
42 1 Initial add: a, c, e
43 0 rename a into b, create a, rename c into d
43 0 rename a into b, create a, rename c into d
44 $ glog -R source-hg
44 $ glog -R source-hg
45 o 1@source "rename a into b, create a, rename c into d" files: a b c d e f
45 o 1@source "rename a into b, create a, rename c into d" files: a b c d e f
46 |
46 |
47 o 0@source "Initial add: a, c, e" files: a c e
47 o 0@source "Initial add: a, c, e" files: a c e
48
48
49
49
50 manifest
50 manifest
51
51
52 $ hg manifest -R source-hg -r tip
52 $ hg manifest -R source-hg -r tip
53 a
53 a
54 b
54 b
55 d
55 d
56 f
56 f
57
57
58 test --rev option
58 test --rev option
59
59
60 $ hg convert -r 1 source source-1-hg
60 $ hg convert -r 1 source source-1-hg
61 initializing destination source-1-hg repository
61 initializing destination source-1-hg repository
62 scanning source...
62 scanning source...
63 sorting...
63 sorting...
64 converting...
64 converting...
65 0 Initial add: a, c, e
65 0 Initial add: a, c, e
66 $ glog -R source-1-hg
66 $ glog -R source-1-hg
67 o 0@source "Initial add: a, c, e" files: a c e
67 o 0@source "Initial add: a, c, e" files: a c e
68
68
69
69
70 test with filemap
70 test with filemap
71
71
72 $ cat > filemap <<EOF
72 $ cat > filemap <<EOF
73 > exclude a
73 > exclude a
74 > EOF
74 > EOF
75 $ hg convert --filemap filemap source source-filemap-hg
75 $ hg convert --filemap filemap source source-filemap-hg
76 initializing destination source-filemap-hg repository
76 initializing destination source-filemap-hg repository
77 scanning source...
77 scanning source...
78 sorting...
78 sorting...
79 converting...
79 converting...
80 1 Initial add: a, c, e
80 1 Initial add: a, c, e
81 0 rename a into b, create a, rename c into d
81 0 rename a into b, create a, rename c into d
82 $ hg -R source-filemap-hg manifest -r tip
82 $ hg -R source-filemap-hg manifest -r tip
83 b
83 b
84 d
84 d
85 f
85 f
86
86
87 convert from lightweight checkout
87 convert from lightweight checkout
88
88
89 $ bzr checkout --lightweight source source-light
89 $ bzr checkout --lightweight source source-light
90 $ hg convert -s bzr source-light source-light-hg
90 $ hg convert -s bzr source-light source-light-hg
91 initializing destination source-light-hg repository
91 initializing destination source-light-hg repository
92 warning: lightweight checkouts may cause conversion failures, try with a regular branch instead.
92 warning: lightweight checkouts may cause conversion failures, try with a regular branch instead.
93 $TESTTMP/test-createandrename/source-light does not look like a Bazaar repository
93 $TESTTMP/test-createandrename/source-light does not look like a Bazaar repository
94 abort: source-light: missing or unsupported repository
94 abort: source-light: missing or unsupported repository
95 [255]
95 [255]
96
96
97 extract timestamps that look just like hg's {date|isodate}:
97 extract timestamps that look just like hg's {date|isodate}:
98 yyyy-mm-dd HH:MM zzzz (no seconds!)
98 yyyy-mm-dd HH:MM zzzz (no seconds!)
99 compare timestamps
99 compare timestamps
100
100
101 $ cd source
101 $ cd source
102 $ bzr log | \
102 $ bzr log | \
103 > sed '/timestamp/!d;s/.\{15\}\([0-9: -]\{16\}\):.. \(.[0-9]\{4\}\)/\1 \2/' \
103 > sed '/timestamp/!d;s/.\{15\}\([0-9: -]\{16\}\):.. \(.[0-9]\{4\}\)/\1 \2/' \
104 > > ../bzr-timestamps
104 > > ../bzr-timestamps
105 $ cd ..
105 $ cd ..
106 $ hg -R source-hg log --template "{date|isodate}\n" > hg-timestamps
106 $ hg -R source-hg log --template "{date|isodate}\n" > hg-timestamps
107 $ diff -u bzr-timestamps hg-timestamps
107 $ diff -u bzr-timestamps hg-timestamps
108 $ cd ..
108 $ cd ..
109
109
110 merge
110 merge
111
111
112 $ mkdir test-merge
112 $ mkdir test-merge
113 $ cd test-merge
113 $ cd test-merge
114 $ cat > helper.py <<EOF
114 $ cat > helper.py <<EOF
115 > import sys
115 > import sys
116 > from bzrlib import workingtree
116 > from bzrlib import workingtree
117 > wt = workingtree.WorkingTree.open('.')
117 > wt = workingtree.WorkingTree.open('.')
118 >
118 >
119 > message, stamp = sys.argv[1:]
119 > message, stamp = sys.argv[1:]
120 > wt.commit(message, timestamp=int(stamp))
120 > wt.commit(message, timestamp=int(stamp))
121 > EOF
121 > EOF
122 $ bzr init -q source
122 $ bzr init -q source
123 $ cd source
123 $ cd source
124 $ echo content > a
124 $ echo content > a
125 $ echo content2 > b
125 $ echo content2 > b
126 $ bzr add -q a b
126 $ bzr add -q a b
127 $ bzr commit -q -m 'Initial add'
127 $ bzr commit -q -m 'Initial add'
128 $ cd ..
128 $ cd ..
129 $ bzr branch -q source source-improve
129 $ bzr branch -q source source-improve
130 $ cd source
130 $ cd source
131 $ echo more >> a
131 $ echo more >> a
132 $ python ../helper.py 'Editing a' 100
132 $ python ../helper.py 'Editing a' 100
133 $ cd ../source-improve
133 $ cd ../source-improve
134 $ echo content3 >> b
134 $ echo content3 >> b
135 $ python ../helper.py 'Editing b' 200
135 $ python ../helper.py 'Editing b' 200
136 $ cd ../source
136 $ cd ../source
137 $ bzr merge -q ../source-improve
137 $ bzr merge -q ../source-improve
138 $ bzr commit -q -m 'Merged improve branch'
138 $ bzr commit -q -m 'Merged improve branch'
139 $ cd ..
139 $ cd ..
140 $ hg convert --datesort source source-hg
140 $ hg convert --datesort source source-hg
141 initializing destination source-hg repository
141 initializing destination source-hg repository
142 scanning source...
142 scanning source...
143 sorting...
143 sorting...
144 converting...
144 converting...
145 3 Initial add
145 3 Initial add
146 2 Editing a
146 2 Editing a
147 1 Editing b
147 1 Editing b
148 0 Merged improve branch
148 0 Merged improve branch
149 $ glog -R source-hg
149 $ glog -R source-hg
150 o 3@source "Merged improve branch" files:
150 o 3@source "Merged improve branch" files:
151 |\
151 |\
152 | o 2@source-improve "Editing b" files: b
152 | o 2@source-improve "Editing b" files: b
153 | |
153 | |
154 o | 1@source "Editing a" files: a
154 o | 1@source "Editing a" files: a
155 |/
155 |/
156 o 0@source "Initial add" files: a b
156 o 0@source "Initial add" files: a b
157
157
158 $ cd ..
158 $ cd ..
159
159
160 symlinks and executable files
160 symlinks and executable files
161
161
162 $ mkdir test-symlinks
162 $ mkdir test-symlinks
163 $ cd test-symlinks
163 $ cd test-symlinks
164 $ bzr init -q source
164 $ bzr init -q source
165 $ cd source
165 $ cd source
166 $ touch program
166 $ touch program
167 $ chmod +x program
167 $ chmod +x program
168 $ ln -s program altname
168 $ ln -s program altname
169 $ mkdir d
169 $ mkdir d
170 $ echo a > d/a
170 $ echo a > d/a
171 $ ln -s a syma
171 $ ln -s a syma
172 $ bzr add -q altname program syma d/a
172 $ bzr add -q altname program syma d/a
173 $ bzr commit -q -m 'Initial setup'
173 $ bzr commit -q -m 'Initial setup'
174 $ touch newprog
174 $ touch newprog
175 $ chmod +x newprog
175 $ chmod +x newprog
176 $ rm altname
176 $ rm altname
177 $ ln -s newprog altname
177 $ ln -s newprog altname
178 $ chmod -x program
178 $ chmod -x program
179 $ bzr add -q newprog
179 $ bzr add -q newprog
180 $ bzr commit -q -m 'Symlink changed, x bits changed'
180 $ bzr commit -q -m 'Symlink changed, x bits changed'
181 $ cd ..
181 $ cd ..
182 $ hg convert source source-hg
182 $ hg convert source source-hg
183 initializing destination source-hg repository
183 initializing destination source-hg repository
184 scanning source...
184 scanning source...
185 sorting...
185 sorting...
186 converting...
186 converting...
187 1 Initial setup
187 1 Initial setup
188 0 Symlink changed, x bits changed
188 0 Symlink changed, x bits changed
189 $ manifest source-hg 0
189 $ manifest source-hg 0
190 % manifest of 0
190 % manifest of 0
191 644 @ altname
191 644 @ altname
192 644 d/a
192 644 d/a
193 755 * program
193 755 * program
194 644 @ syma
194 644 @ syma
195 $ manifest source-hg tip
195 $ manifest source-hg tip
196 % manifest of tip
196 % manifest of tip
197 644 @ altname
197 644 @ altname
198 644 d/a
198 644 d/a
199 755 * newprog
199 755 * newprog
200 644 program
200 644 program
201 644 @ syma
201 644 @ syma
202 $ cd source-hg
202 $ cd source-hg
203
203
204 test the symlinks can be recreated
204 test the symlinks can be recreated
205
205
206 $ hg up
206 $ hg up
207 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
207 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
208 $ hg cat syma; echo
208 $ hg cat syma; echo
209 a
209 a
210
210
211 Multiple branches
211 Multiple branches
212
212
213 $ bzr init-repo -q --no-trees repo
213 $ bzr init-repo -q --no-trees repo
214 $ bzr init -q repo/trunk
214 $ bzr init -q repo/trunk
215 $ bzr co repo/trunk repo-trunk
215 $ bzr co repo/trunk repo-trunk
216 $ cd repo-trunk
216 $ cd repo-trunk
217 $ echo a > a
217 $ echo a > a
218 $ bzr add a
218 $ bzr add a
219 adding a
219 adding a
220 $ bzr ci -qm adda --commit-time '2012-01-01 00:00:01 +0000'
220 $ bzr ci -qm adda --commit-time '2012-01-01 00:00:01 +0000'
221 $ bzr tag trunk-tag
221 $ bzr tag trunk-tag
222 Created tag trunk-tag.
222 Created tag trunk-tag.
223 $ bzr switch -b branch
223 $ bzr switch -b branch
224 Tree is up to date at revision 1.
224 Tree is up to date at revision 1.
225 Switched to branch: *repo/branch/ (glob)
225 Switched to branch: *repo/branch/ (glob)
226 $ echo b > b
226 $ echo b > b
227 $ bzr add b
227 $ bzr add b
228 adding b
228 adding b
229 $ bzr ci -qm addb --commit-time '2012-01-01 00:00:02 +0000'
229 $ bzr ci -qm addb --commit-time '2012-01-01 00:00:02 +0000'
230 $ bzr tag branch-tag
230 $ bzr tag branch-tag
231 Created tag branch-tag.
231 Created tag branch-tag.
232 $ bzr switch --force ../repo/trunk
232 $ bzr switch --force ../repo/trunk
233 Updated to revision 1.
233 Updated to revision 1.
234 Switched to branch: */repo/trunk/ (glob)
234 Switched to branch: */repo/trunk/ (glob)
235 $ echo a >> a
235 $ echo a >> a
236 $ bzr ci -qm changea --commit-time '2012-01-01 00:00:03 +0000'
236 $ bzr ci -qm changea --commit-time '2012-01-01 00:00:03 +0000'
237 $ cd ..
237 $ cd ..
238 $ hg convert --datesort repo repo-bzr
238 $ hg convert --datesort repo repo-bzr
239 initializing destination repo-bzr repository
239 initializing destination repo-bzr repository
240 scanning source...
240 scanning source...
241 sorting...
241 sorting...
242 converting...
242 converting...
243 2 adda
243 2 adda
244 1 addb
244 1 addb
245 0 changea
245 0 changea
246 updating tags
246 updating tags
247 $ (cd repo-bzr; glog)
247 $ (cd repo-bzr; glog)
248 o 3@default "update tags" files: .hgtags
248 o 3@default "update tags" files: .hgtags
249 |
249 |
250 o 2@default "changea" files: a
250 o 2@default "changea" files: a
251 |
251 |
252 | o 1@branch "addb" files: b
252 | o 1@branch "addb" files: b
253 |/
253 |/
254 o 0@default "adda" files: a
254 o 0@default "adda" files: a
255
255
256
256
257 Test tags (converted identifiers are not stable because bzr ones are
257 Test tags (converted identifiers are not stable because bzr ones are
258 not and get incorporated in extra fields).
258 not and get incorporated in extra fields).
259
259
260 $ hg -R repo-bzr tags
260 $ hg -R repo-bzr tags
261 tip 3:* (glob)
261 tip 3:* (glob)
262 branch-tag 1:* (glob)
262 branch-tag 1:* (glob)
263 trunk-tag 0:* (glob)
263 trunk-tag 0:* (glob)
264
265 Nested repositories (issue3254)
266
267 $ bzr init-repo -q --no-trees repo/inner
268 $ bzr init -q repo/inner/trunk
269 $ bzr co repo/inner/trunk inner-trunk
270 $ cd inner-trunk
271 $ echo b > b
272 $ bzr add b
273 adding b
274 $ bzr ci -qm addb
275 $ cd ..
276 $ hg convert --datesort repo noinner-bzr
277 initializing destination noinner-bzr repository
278 scanning source...
279 sorting...
280 converting...
281 2 adda
282 1 addb
283 0 changea
284 updating tags
General Comments 0
You need to be logged in to leave comments. Login now