##// END OF EJS Templates
convert/bzr: handle empty bzr repositories (issue3233)
Patrick Mezard -
r16061:915e06fa default
parent child Browse files
Show More
@@ -1,280 +1,282 b''
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 getheads(self):
94 def getheads(self):
95 if not self.rev:
95 if not self.rev:
96 heads = sorted([b.last_revision()
96 heads = sorted([b.last_revision()
97 for b in self.sourcerepo.find_branches()])
97 for b in self.sourcerepo.find_branches()])
98 else:
98 else:
99 revid = None
99 revid = None
100 for branch in self.sourcerepo.find_branches():
100 for branch in self.sourcerepo.find_branches():
101 try:
101 try:
102 r = RevisionSpec.from_string(self.rev)
102 r = RevisionSpec.from_string(self.rev)
103 info = r.in_history(branch)
103 info = r.in_history(branch)
104 except errors.BzrError:
104 except errors.BzrError:
105 pass
105 pass
106 revid = info.rev_id
106 revid = info.rev_id
107 if revid is None:
107 if revid is None:
108 raise util.Abort(_('%s is not a valid revision') % self.rev)
108 raise util.Abort(_('%s is not a valid revision') % self.rev)
109 heads = [revid]
109 heads = [revid]
110 # Empty repositories return 'null:', which cannot be retrieved
111 heads = [h for h in heads if h != 'null:']
110 return heads
112 return heads
111
113
112 def getfile(self, name, rev):
114 def getfile(self, name, rev):
113 revtree = self.sourcerepo.revision_tree(rev)
115 revtree = self.sourcerepo.revision_tree(rev)
114 fileid = revtree.path2id(name.decode(self.encoding or 'utf-8'))
116 fileid = revtree.path2id(name.decode(self.encoding or 'utf-8'))
115 kind = None
117 kind = None
116 if fileid is not None:
118 if fileid is not None:
117 kind = revtree.kind(fileid)
119 kind = revtree.kind(fileid)
118 if kind not in supportedkinds:
120 if kind not in supportedkinds:
119 # the file is not available anymore - was deleted
121 # the file is not available anymore - was deleted
120 raise IOError(_('%s is not available in %s anymore') %
122 raise IOError(_('%s is not available in %s anymore') %
121 (name, rev))
123 (name, rev))
122 mode = self._modecache[(name, rev)]
124 mode = self._modecache[(name, rev)]
123 if kind == 'symlink':
125 if kind == 'symlink':
124 target = revtree.get_symlink_target(fileid)
126 target = revtree.get_symlink_target(fileid)
125 if target is None:
127 if target is None:
126 raise util.Abort(_('%s.%s symlink has no target')
128 raise util.Abort(_('%s.%s symlink has no target')
127 % (name, rev))
129 % (name, rev))
128 return target, mode
130 return target, mode
129 else:
131 else:
130 sio = revtree.get_file(fileid)
132 sio = revtree.get_file(fileid)
131 return sio.read(), mode
133 return sio.read(), mode
132
134
133 def getchanges(self, version):
135 def getchanges(self, version):
134 # set up caches: modecache and revtree
136 # set up caches: modecache and revtree
135 self._modecache = {}
137 self._modecache = {}
136 self._revtree = self.sourcerepo.revision_tree(version)
138 self._revtree = self.sourcerepo.revision_tree(version)
137 # get the parentids from the cache
139 # get the parentids from the cache
138 parentids = self._parentids.pop(version)
140 parentids = self._parentids.pop(version)
139 # only diff against first parent id
141 # only diff against first parent id
140 prevtree = self.sourcerepo.revision_tree(parentids[0])
142 prevtree = self.sourcerepo.revision_tree(parentids[0])
141 return self._gettreechanges(self._revtree, prevtree)
143 return self._gettreechanges(self._revtree, prevtree)
142
144
143 def getcommit(self, version):
145 def getcommit(self, version):
144 rev = self.sourcerepo.get_revision(version)
146 rev = self.sourcerepo.get_revision(version)
145 # populate parent id cache
147 # populate parent id cache
146 if not rev.parent_ids:
148 if not rev.parent_ids:
147 parents = []
149 parents = []
148 self._parentids[version] = (revision.NULL_REVISION,)
150 self._parentids[version] = (revision.NULL_REVISION,)
149 else:
151 else:
150 parents = self._filterghosts(rev.parent_ids)
152 parents = self._filterghosts(rev.parent_ids)
151 self._parentids[version] = parents
153 self._parentids[version] = parents
152
154
153 branch = self.recode(rev.properties.get('branch-nick', u'default'))
155 branch = self.recode(rev.properties.get('branch-nick', u'default'))
154 if branch == 'trunk':
156 if branch == 'trunk':
155 branch = 'default'
157 branch = 'default'
156 return commit(parents=parents,
158 return commit(parents=parents,
157 date='%d %d' % (rev.timestamp, -rev.timezone),
159 date='%d %d' % (rev.timestamp, -rev.timezone),
158 author=self.recode(rev.committer),
160 author=self.recode(rev.committer),
159 desc=self.recode(rev.message),
161 desc=self.recode(rev.message),
160 branch=branch,
162 branch=branch,
161 rev=version)
163 rev=version)
162
164
163 def gettags(self):
165 def gettags(self):
164 bytetags = {}
166 bytetags = {}
165 for branch in self.sourcerepo.find_branches():
167 for branch in self.sourcerepo.find_branches():
166 if not branch.supports_tags():
168 if not branch.supports_tags():
167 return {}
169 return {}
168 tagdict = branch.tags.get_tag_dict()
170 tagdict = branch.tags.get_tag_dict()
169 for name, rev in tagdict.iteritems():
171 for name, rev in tagdict.iteritems():
170 bytetags[self.recode(name)] = rev
172 bytetags[self.recode(name)] = rev
171 return bytetags
173 return bytetags
172
174
173 def getchangedfiles(self, rev, i):
175 def getchangedfiles(self, rev, i):
174 self._modecache = {}
176 self._modecache = {}
175 curtree = self.sourcerepo.revision_tree(rev)
177 curtree = self.sourcerepo.revision_tree(rev)
176 if i is not None:
178 if i is not None:
177 parentid = self._parentids[rev][i]
179 parentid = self._parentids[rev][i]
178 else:
180 else:
179 # no parent id, get the empty revision
181 # no parent id, get the empty revision
180 parentid = revision.NULL_REVISION
182 parentid = revision.NULL_REVISION
181
183
182 prevtree = self.sourcerepo.revision_tree(parentid)
184 prevtree = self.sourcerepo.revision_tree(parentid)
183 changes = [e[0] for e in self._gettreechanges(curtree, prevtree)[0]]
185 changes = [e[0] for e in self._gettreechanges(curtree, prevtree)[0]]
184 return changes
186 return changes
185
187
186 def _gettreechanges(self, current, origin):
188 def _gettreechanges(self, current, origin):
187 revid = current._revision_id
189 revid = current._revision_id
188 changes = []
190 changes = []
189 renames = {}
191 renames = {}
190 seen = set()
192 seen = set()
191 # Process the entries by reverse lexicographic name order to
193 # Process the entries by reverse lexicographic name order to
192 # handle nested renames correctly, most specific first.
194 # handle nested renames correctly, most specific first.
193 curchanges = sorted(current.iter_changes(origin),
195 curchanges = sorted(current.iter_changes(origin),
194 key=lambda c: c[1][0] or c[1][1],
196 key=lambda c: c[1][0] or c[1][1],
195 reverse=True)
197 reverse=True)
196 for (fileid, paths, changed_content, versioned, parent, name,
198 for (fileid, paths, changed_content, versioned, parent, name,
197 kind, executable) in curchanges:
199 kind, executable) in curchanges:
198
200
199 if paths[0] == u'' or paths[1] == u'':
201 if paths[0] == u'' or paths[1] == u'':
200 # ignore changes to tree root
202 # ignore changes to tree root
201 continue
203 continue
202
204
203 # bazaar tracks directories, mercurial does not, so
205 # bazaar tracks directories, mercurial does not, so
204 # we have to rename the directory contents
206 # we have to rename the directory contents
205 if kind[1] == 'directory':
207 if kind[1] == 'directory':
206 if kind[0] not in (None, 'directory'):
208 if kind[0] not in (None, 'directory'):
207 # Replacing 'something' with a directory, record it
209 # Replacing 'something' with a directory, record it
208 # so it can be removed.
210 # so it can be removed.
209 changes.append((self.recode(paths[0]), revid))
211 changes.append((self.recode(paths[0]), revid))
210
212
211 if kind[0] == 'directory' and None not in paths:
213 if kind[0] == 'directory' and None not in paths:
212 renaming = paths[0] != paths[1]
214 renaming = paths[0] != paths[1]
213 # neither an add nor an delete - a move
215 # neither an add nor an delete - a move
214 # rename all directory contents manually
216 # rename all directory contents manually
215 subdir = origin.inventory.path2id(paths[0])
217 subdir = origin.inventory.path2id(paths[0])
216 # get all child-entries of the directory
218 # get all child-entries of the directory
217 for name, entry in origin.inventory.iter_entries(subdir):
219 for name, entry in origin.inventory.iter_entries(subdir):
218 # hg does not track directory renames
220 # hg does not track directory renames
219 if entry.kind == 'directory':
221 if entry.kind == 'directory':
220 continue
222 continue
221 frompath = self.recode(paths[0] + '/' + name)
223 frompath = self.recode(paths[0] + '/' + name)
222 if frompath in seen:
224 if frompath in seen:
223 # Already handled by a more specific change entry
225 # Already handled by a more specific change entry
224 # This is important when you have:
226 # This is important when you have:
225 # a => b
227 # a => b
226 # a/c => a/c
228 # a/c => a/c
227 # Here a/c must not be renamed into b/c
229 # Here a/c must not be renamed into b/c
228 continue
230 continue
229 seen.add(frompath)
231 seen.add(frompath)
230 if not renaming:
232 if not renaming:
231 continue
233 continue
232 topath = self.recode(paths[1] + '/' + name)
234 topath = self.recode(paths[1] + '/' + name)
233 # register the files as changed
235 # register the files as changed
234 changes.append((frompath, revid))
236 changes.append((frompath, revid))
235 changes.append((topath, revid))
237 changes.append((topath, revid))
236 # add to mode cache
238 # add to mode cache
237 mode = ((entry.executable and 'x')
239 mode = ((entry.executable and 'x')
238 or (entry.kind == 'symlink' and 's')
240 or (entry.kind == 'symlink' and 's')
239 or '')
241 or '')
240 self._modecache[(topath, revid)] = mode
242 self._modecache[(topath, revid)] = mode
241 # register the change as move
243 # register the change as move
242 renames[topath] = frompath
244 renames[topath] = frompath
243
245
244 # no futher changes, go to the next change
246 # no futher changes, go to the next change
245 continue
247 continue
246
248
247 # we got unicode paths, need to convert them
249 # we got unicode paths, need to convert them
248 path, topath = paths
250 path, topath = paths
249 if path is not None:
251 if path is not None:
250 path = self.recode(path)
252 path = self.recode(path)
251 if topath is not None:
253 if topath is not None:
252 topath = self.recode(topath)
254 topath = self.recode(topath)
253 seen.add(path or topath)
255 seen.add(path or topath)
254
256
255 if topath is None:
257 if topath is None:
256 # file deleted
258 # file deleted
257 changes.append((path, revid))
259 changes.append((path, revid))
258 continue
260 continue
259
261
260 # renamed
262 # renamed
261 if path and path != topath:
263 if path and path != topath:
262 renames[topath] = path
264 renames[topath] = path
263 changes.append((path, revid))
265 changes.append((path, revid))
264
266
265 # populate the mode cache
267 # populate the mode cache
266 kind, executable = [e[1] for e in (kind, executable)]
268 kind, executable = [e[1] for e in (kind, executable)]
267 mode = ((executable and 'x') or (kind == 'symlink' and 'l')
269 mode = ((executable and 'x') or (kind == 'symlink' and 'l')
268 or '')
270 or '')
269 self._modecache[(topath, revid)] = mode
271 self._modecache[(topath, revid)] = mode
270 changes.append((topath, revid))
272 changes.append((topath, revid))
271
273
272 return changes, renames
274 return changes, renames
273
275
274 def _filterghosts(self, ids):
276 def _filterghosts(self, ids):
275 """Filters out ghost revisions which hg does not support, see
277 """Filters out ghost revisions which hg does not support, see
276 <http://bazaar-vcs.org/GhostRevision>
278 <http://bazaar-vcs.org/GhostRevision>
277 """
279 """
278 parentmap = self.sourcerepo.get_parent_map(ids)
280 parentmap = self.sourcerepo.get_parent_map(ids)
279 parents = tuple([parent for parent in ids if parent in parentmap])
281 parents = tuple([parent for parent in ids if parent in parentmap])
280 return parents
282 return parents
@@ -1,238 +1,248 b''
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
11 test empty repo conversion (issue3233)
12
13 $ hg convert source source-hg
14 initializing destination source-hg repository
15 scanning source...
16 sorting...
17 converting...
18
19 back to the rename stuff
20
10 $ cd source
21 $ cd source
11 $ echo a > a
22 $ echo a > a
12 $ echo c > c
23 $ echo c > c
13 $ echo e > e
24 $ echo e > e
14 $ bzr add -q a c e
25 $ bzr add -q a c e
15 $ bzr commit -q -m 'Initial add: a, c, e'
26 $ bzr commit -q -m 'Initial add: a, c, e'
16 $ bzr mv a b
27 $ bzr mv a b
17 a => b
28 a => b
18 $ bzr mv c d
29 $ bzr mv c d
19 c => d
30 c => d
20 $ bzr mv e f
31 $ bzr mv e f
21 e => f
32 e => f
22 $ echo a2 >> a
33 $ echo a2 >> a
23 $ mkdir e
34 $ mkdir e
24 $ bzr add -q a e
35 $ bzr add -q a e
25 $ 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'
26 $ cd ..
37 $ cd ..
27 $ hg convert source source-hg
38 $ hg convert source source-hg
28 initializing destination source-hg repository
29 scanning source...
39 scanning source...
30 sorting...
40 sorting...
31 converting...
41 converting...
32 1 Initial add: a, c, e
42 1 Initial add: a, c, e
33 0 rename a into b, create a, rename c into d
43 0 rename a into b, create a, rename c into d
34 $ glog -R source-hg
44 $ glog -R source-hg
35 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
36 |
46 |
37 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
38
48
39
49
40 manifest
50 manifest
41
51
42 $ hg manifest -R source-hg -r tip
52 $ hg manifest -R source-hg -r tip
43 a
53 a
44 b
54 b
45 d
55 d
46 f
56 f
47
57
48 test --rev option
58 test --rev option
49
59
50 $ hg convert -r 1 source source-1-hg
60 $ hg convert -r 1 source source-1-hg
51 initializing destination source-1-hg repository
61 initializing destination source-1-hg repository
52 scanning source...
62 scanning source...
53 sorting...
63 sorting...
54 converting...
64 converting...
55 0 Initial add: a, c, e
65 0 Initial add: a, c, e
56 $ glog -R source-1-hg
66 $ glog -R source-1-hg
57 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
58
68
59
69
60 test with filemap
70 test with filemap
61
71
62 $ cat > filemap <<EOF
72 $ cat > filemap <<EOF
63 > exclude a
73 > exclude a
64 > EOF
74 > EOF
65 $ hg convert --filemap filemap source source-filemap-hg
75 $ hg convert --filemap filemap source source-filemap-hg
66 initializing destination source-filemap-hg repository
76 initializing destination source-filemap-hg repository
67 scanning source...
77 scanning source...
68 sorting...
78 sorting...
69 converting...
79 converting...
70 1 Initial add: a, c, e
80 1 Initial add: a, c, e
71 0 rename a into b, create a, rename c into d
81 0 rename a into b, create a, rename c into d
72 $ hg -R source-filemap-hg manifest -r tip
82 $ hg -R source-filemap-hg manifest -r tip
73 b
83 b
74 d
84 d
75 f
85 f
76
86
77 convert from lightweight checkout
87 convert from lightweight checkout
78
88
79 $ bzr checkout --lightweight source source-light
89 $ bzr checkout --lightweight source source-light
80 $ hg convert -s bzr source-light source-light-hg
90 $ hg convert -s bzr source-light source-light-hg
81 initializing destination source-light-hg repository
91 initializing destination source-light-hg repository
82 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.
83 $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
84 abort: source-light: missing or unsupported repository
94 abort: source-light: missing or unsupported repository
85 [255]
95 [255]
86
96
87 extract timestamps that look just like hg's {date|isodate}:
97 extract timestamps that look just like hg's {date|isodate}:
88 yyyy-mm-dd HH:MM zzzz (no seconds!)
98 yyyy-mm-dd HH:MM zzzz (no seconds!)
89 compare timestamps
99 compare timestamps
90
100
91 $ cd source
101 $ cd source
92 $ bzr log | \
102 $ bzr log | \
93 > 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/' \
94 > > ../bzr-timestamps
104 > > ../bzr-timestamps
95 $ cd ..
105 $ cd ..
96 $ hg -R source-hg log --template "{date|isodate}\n" > hg-timestamps
106 $ hg -R source-hg log --template "{date|isodate}\n" > hg-timestamps
97 $ diff -u bzr-timestamps hg-timestamps
107 $ diff -u bzr-timestamps hg-timestamps
98 $ cd ..
108 $ cd ..
99
109
100 merge
110 merge
101
111
102 $ mkdir test-merge
112 $ mkdir test-merge
103 $ cd test-merge
113 $ cd test-merge
104 $ cat > helper.py <<EOF
114 $ cat > helper.py <<EOF
105 > import sys
115 > import sys
106 > from bzrlib import workingtree
116 > from bzrlib import workingtree
107 > wt = workingtree.WorkingTree.open('.')
117 > wt = workingtree.WorkingTree.open('.')
108 >
118 >
109 > message, stamp = sys.argv[1:]
119 > message, stamp = sys.argv[1:]
110 > wt.commit(message, timestamp=int(stamp))
120 > wt.commit(message, timestamp=int(stamp))
111 > EOF
121 > EOF
112 $ bzr init -q source
122 $ bzr init -q source
113 $ cd source
123 $ cd source
114 $ echo content > a
124 $ echo content > a
115 $ echo content2 > b
125 $ echo content2 > b
116 $ bzr add -q a b
126 $ bzr add -q a b
117 $ bzr commit -q -m 'Initial add'
127 $ bzr commit -q -m 'Initial add'
118 $ cd ..
128 $ cd ..
119 $ bzr branch -q source source-improve
129 $ bzr branch -q source source-improve
120 $ cd source
130 $ cd source
121 $ echo more >> a
131 $ echo more >> a
122 $ python ../helper.py 'Editing a' 100
132 $ python ../helper.py 'Editing a' 100
123 $ cd ../source-improve
133 $ cd ../source-improve
124 $ echo content3 >> b
134 $ echo content3 >> b
125 $ python ../helper.py 'Editing b' 200
135 $ python ../helper.py 'Editing b' 200
126 $ cd ../source
136 $ cd ../source
127 $ bzr merge -q ../source-improve
137 $ bzr merge -q ../source-improve
128 $ bzr commit -q -m 'Merged improve branch'
138 $ bzr commit -q -m 'Merged improve branch'
129 $ cd ..
139 $ cd ..
130 $ hg convert --datesort source source-hg
140 $ hg convert --datesort source source-hg
131 initializing destination source-hg repository
141 initializing destination source-hg repository
132 scanning source...
142 scanning source...
133 sorting...
143 sorting...
134 converting...
144 converting...
135 3 Initial add
145 3 Initial add
136 2 Editing a
146 2 Editing a
137 1 Editing b
147 1 Editing b
138 0 Merged improve branch
148 0 Merged improve branch
139 $ glog -R source-hg
149 $ glog -R source-hg
140 o 3@source "Merged improve branch" files:
150 o 3@source "Merged improve branch" files:
141 |\
151 |\
142 | o 2@source-improve "Editing b" files: b
152 | o 2@source-improve "Editing b" files: b
143 | |
153 | |
144 o | 1@source "Editing a" files: a
154 o | 1@source "Editing a" files: a
145 |/
155 |/
146 o 0@source "Initial add" files: a b
156 o 0@source "Initial add" files: a b
147
157
148 $ cd ..
158 $ cd ..
149
159
150 symlinks and executable files
160 symlinks and executable files
151
161
152 $ mkdir test-symlinks
162 $ mkdir test-symlinks
153 $ cd test-symlinks
163 $ cd test-symlinks
154 $ bzr init -q source
164 $ bzr init -q source
155 $ cd source
165 $ cd source
156 $ touch program
166 $ touch program
157 $ chmod +x program
167 $ chmod +x program
158 $ ln -s program altname
168 $ ln -s program altname
159 $ mkdir d
169 $ mkdir d
160 $ echo a > d/a
170 $ echo a > d/a
161 $ ln -s a syma
171 $ ln -s a syma
162 $ bzr add -q altname program syma d/a
172 $ bzr add -q altname program syma d/a
163 $ bzr commit -q -m 'Initial setup'
173 $ bzr commit -q -m 'Initial setup'
164 $ touch newprog
174 $ touch newprog
165 $ chmod +x newprog
175 $ chmod +x newprog
166 $ rm altname
176 $ rm altname
167 $ ln -s newprog altname
177 $ ln -s newprog altname
168 $ chmod -x program
178 $ chmod -x program
169 $ bzr add -q newprog
179 $ bzr add -q newprog
170 $ bzr commit -q -m 'Symlink changed, x bits changed'
180 $ bzr commit -q -m 'Symlink changed, x bits changed'
171 $ cd ..
181 $ cd ..
172 $ hg convert source source-hg
182 $ hg convert source source-hg
173 initializing destination source-hg repository
183 initializing destination source-hg repository
174 scanning source...
184 scanning source...
175 sorting...
185 sorting...
176 converting...
186 converting...
177 1 Initial setup
187 1 Initial setup
178 0 Symlink changed, x bits changed
188 0 Symlink changed, x bits changed
179 $ manifest source-hg 0
189 $ manifest source-hg 0
180 % manifest of 0
190 % manifest of 0
181 644 @ altname
191 644 @ altname
182 644 d/a
192 644 d/a
183 755 * program
193 755 * program
184 644 @ syma
194 644 @ syma
185 $ manifest source-hg tip
195 $ manifest source-hg tip
186 % manifest of tip
196 % manifest of tip
187 644 @ altname
197 644 @ altname
188 644 d/a
198 644 d/a
189 755 * newprog
199 755 * newprog
190 644 program
200 644 program
191 644 @ syma
201 644 @ syma
192 $ cd source-hg
202 $ cd source-hg
193
203
194 test the symlinks can be recreated
204 test the symlinks can be recreated
195
205
196 $ hg up
206 $ hg up
197 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
198 $ hg cat syma; echo
208 $ hg cat syma; echo
199 a
209 a
200
210
201 Multiple branches
211 Multiple branches
202
212
203 $ bzr init-repo -q --no-trees repo
213 $ bzr init-repo -q --no-trees repo
204 $ bzr init -q repo/trunk
214 $ bzr init -q repo/trunk
205 $ bzr co repo/trunk repo-trunk
215 $ bzr co repo/trunk repo-trunk
206 $ cd repo-trunk
216 $ cd repo-trunk
207 $ echo a > a
217 $ echo a > a
208 $ bzr add a
218 $ bzr add a
209 adding a
219 adding a
210 $ 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'
211 $ bzr switch -b branch
221 $ bzr switch -b branch
212 Tree is up to date at revision 1.
222 Tree is up to date at revision 1.
213 Switched to branch: *repo/branch/ (glob)
223 Switched to branch: *repo/branch/ (glob)
214 $ echo b > b
224 $ echo b > b
215 $ bzr add b
225 $ bzr add b
216 adding b
226 adding b
217 $ bzr ci -qm addb --commit-time '2012-01-01 00:00:02 +0000'
227 $ bzr ci -qm addb --commit-time '2012-01-01 00:00:02 +0000'
218 $ bzr switch --force ../repo/trunk
228 $ bzr switch --force ../repo/trunk
219 Updated to revision 1.
229 Updated to revision 1.
220 Switched to branch: */repo/trunk/ (glob)
230 Switched to branch: */repo/trunk/ (glob)
221 $ echo a >> a
231 $ echo a >> a
222 $ bzr ci -qm changea --commit-time '2012-01-01 00:00:03 +0000'
232 $ bzr ci -qm changea --commit-time '2012-01-01 00:00:03 +0000'
223 $ cd ..
233 $ cd ..
224 $ hg convert --datesort repo repo-bzr
234 $ hg convert --datesort repo repo-bzr
225 initializing destination repo-bzr repository
235 initializing destination repo-bzr repository
226 scanning source...
236 scanning source...
227 sorting...
237 sorting...
228 converting...
238 converting...
229 2 adda
239 2 adda
230 1 addb
240 1 addb
231 0 changea
241 0 changea
232 $ (cd repo-bzr; glog)
242 $ (cd repo-bzr; glog)
233 o 2@default "changea" files: a
243 o 2@default "changea" files: a
234 |
244 |
235 | o 1@branch "addb" files: b
245 | o 1@branch "addb" files: b
236 |/
246 |/
237 o 0@default "adda" files: a
247 o 0@default "adda" files: a
238
248
General Comments 0
You need to be logged in to leave comments. Login now