83
by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin |
1 |
# Copyright (C) 2005 by Aaron Bentley
|
2 |
||
3 |
# This program is free software; you can redistribute it and/or modify
|
|
4 |
# it under the terms of the GNU General Public License as published by
|
|
5 |
# the Free Software Foundation; either version 2 of the License, or
|
|
6 |
# (at your option) any later version.
|
|
7 |
||
8 |
# This program is distributed in the hope that it will be useful,
|
|
9 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11 |
# GNU General Public License for more details.
|
|
12 |
||
13 |
# You should have received a copy of the GNU General Public License
|
|
14 |
# along with this program; if not, write to the Free Software
|
|
15 |
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
115
by aaron.bentley at utoronto
Import fixes from magnus@therning.org |
16 |
from bzrlib.branch import Branch |
83
by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin |
17 |
from bzrlib.commands import Command |
105
by Aaron Bentley
Fixed NoPyBaz detection |
18 |
from errors import NoPyBaz |
83
by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin |
19 |
try: |
20 |
import pybaz |
|
21 |
import pybaz.errors |
|
105
by Aaron Bentley
Fixed NoPyBaz detection |
22 |
from pybaz.backends.baz import null_cmd |
83
by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin |
23 |
except ImportError: |
100
by Aaron Bentley
Fixed up the baz-import plugin |
24 |
raise NoPyBaz |
83
by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin |
25 |
import tempfile |
26 |
import os |
|
27 |
import os.path |
|
28 |
import shutil |
|
29 |
import bzrlib |
|
30 |
from bzrlib.errors import BzrError |
|
31 |
import bzrlib.trace |
|
32 |
import bzrlib.merge |
|
97
by aaron.bentley at utoronto
Added now-required imports |
33 |
import bzrlib.inventory |
34 |
import bzrlib.osutils |
|
83
by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin |
35 |
import sys |
36 |
import email.Utils |
|
37 |
from progress import * |
|
38 |
||
39 |
def add_id(files, id=None): |
|
40 |
"""Adds an explicit id to a list of files.
|
|
41 |
||
42 |
:param files: the name of the file to add an id to
|
|
43 |
:type files: list of str
|
|
44 |
:param id: tag one file using the specified id, instead of generating id
|
|
45 |
:type id: str
|
|
46 |
"""
|
|
47 |
args = ["add-id"] |
|
48 |
if id is not None: |
|
49 |
args.extend(["--id", id]) |
|
50 |
args.extend(files) |
|
51 |
return null_cmd(args) |
|
52 |
||
53 |
def test_environ(): |
|
54 |
"""
|
|
55 |
>>> q = test_environ()
|
|
56 |
>>> os.path.exists(q)
|
|
57 |
True
|
|
58 |
>>> os.path.exists(os.path.join(q, "home", ".arch-params"))
|
|
59 |
True
|
|
60 |
>>> teardown_environ(q)
|
|
61 |
>>> os.path.exists(q)
|
|
62 |
False
|
|
63 |
"""
|
|
64 |
tdir = tempfile.mkdtemp(prefix="testdir-") |
|
65 |
os.environ["HOME"] = os.path.join(tdir, "home") |
|
66 |
os.mkdir(os.environ["HOME"]) |
|
67 |
arch_dir = os.path.join(tdir, "archive_dir") |
|
68 |
pybaz.make_archive("test@example.com", arch_dir) |
|
69 |
work_dir = os.path.join(tdir, "work_dir") |
|
70 |
os.mkdir(work_dir) |
|
71 |
os.chdir(work_dir) |
|
72 |
pybaz.init_tree(work_dir, "test@example.com/test--test--0") |
|
73 |
lib_dir = os.path.join(tdir, "lib_dir") |
|
74 |
os.mkdir(lib_dir) |
|
75 |
pybaz.register_revision_library(lib_dir) |
|
76 |
pybaz.set_my_id("Test User<test@example.org>") |
|
77 |
return tdir |
|
78 |
||
79 |
def add_file(path, text, id): |
|
80 |
"""
|
|
81 |
>>> q = test_environ()
|
|
82 |
>>> add_file("path with space", "text", "lalala")
|
|
83 |
>>> tree = pybaz.tree_root(".")
|
|
84 |
>>> inv = list(tree.iter_inventory_ids(source=True, both=True))
|
|
85 |
>>> ("x_lalala", "path with space") in inv
|
|
86 |
True
|
|
87 |
>>> teardown_environ(q)
|
|
88 |
"""
|
|
89 |
file(path, "wb").write(text) |
|
90 |
add_id([path], id) |
|
91 |
||
92 |
||
93 |
def add_dir(path, id): |
|
94 |
"""
|
|
95 |
>>> q = test_environ()
|
|
96 |
>>> add_dir("path with\(sp) space", "lalala")
|
|
97 |
>>> tree = pybaz.tree_root(".")
|
|
98 |
>>> inv = list(tree.iter_inventory_ids(source=True, both=True))
|
|
99 |
>>> ("x_lalala", "path with\(sp) space") in inv
|
|
100 |
True
|
|
101 |
>>> teardown_environ(q)
|
|
102 |
"""
|
|
103 |
os.mkdir(path) |
|
104 |
add_id([path], id) |
|
105 |
||
106 |
def teardown_environ(tdir): |
|
107 |
os.chdir("/") |
|
108 |
shutil.rmtree(tdir) |
|
109 |
||
110 |
def timport(tree, summary): |
|
111 |
msg = tree.log_message() |
|
112 |
msg["summary"] = summary |
|
113 |
tree.import_(msg) |
|
114 |
||
115 |
def commit(tree, summary): |
|
116 |
"""
|
|
117 |
>>> q = test_environ()
|
|
118 |
>>> tree = pybaz.tree_root(".")
|
|
119 |
>>> timport(tree, "import")
|
|
120 |
>>> commit(tree, "commit")
|
|
121 |
>>> logs = [str(l.revision) for l in tree.iter_logs()]
|
|
122 |
>>> len(logs)
|
|
123 |
2
|
|
124 |
>>> logs[0]
|
|
125 |
'test@example.com/test--test--0--base-0'
|
|
126 |
>>> logs[1]
|
|
127 |
'test@example.com/test--test--0--patch-1'
|
|
128 |
>>> teardown_environ(q)
|
|
129 |
"""
|
|
130 |
msg = tree.log_message() |
|
131 |
msg["summary"] = summary |
|
132 |
tree.commit(msg) |
|
133 |
||
134 |
def commit_test_revisions(): |
|
135 |
"""
|
|
136 |
>>> q = test_environ()
|
|
137 |
>>> commit_test_revisions()
|
|
138 |
>>> a = pybaz.Archive("test@example.com")
|
|
139 |
>>> revisions = list(a.iter_revisions("test--test--0"))
|
|
140 |
>>> len(revisions)
|
|
141 |
3
|
|
142 |
>>> str(revisions[2])
|
|
143 |
'test@example.com/test--test--0--base-0'
|
|
144 |
>>> str(revisions[1])
|
|
145 |
'test@example.com/test--test--0--patch-1'
|
|
146 |
>>> str(revisions[0])
|
|
147 |
'test@example.com/test--test--0--patch-2'
|
|
148 |
>>> teardown_environ(q)
|
|
149 |
"""
|
|
150 |
tree = pybaz.tree_root(".") |
|
151 |
add_file("mainfile", "void main(void){}", "mainfile by aaron") |
|
152 |
timport(tree, "Created mainfile") |
|
153 |
file("mainfile", "wb").write("or something like that") |
|
154 |
commit(tree, "altered mainfile") |
|
155 |
add_file("ofile", "this is another file", "ofile by aaron") |
|
156 |
commit(tree, "altered mainfile") |
|
157 |
||
158 |
||
159 |
def commit_more_test_revisions(): |
|
160 |
"""
|
|
161 |
>>> q = test_environ()
|
|
162 |
>>> commit_test_revisions()
|
|
163 |
>>> commit_more_test_revisions()
|
|
164 |
>>> a = pybaz.Archive("test@example.com")
|
|
165 |
>>> revisions = list(a.iter_revisions("test--test--0"))
|
|
166 |
>>> len(revisions)
|
|
167 |
4
|
|
168 |
>>> str(revisions[0])
|
|
169 |
'test@example.com/test--test--0--patch-3'
|
|
170 |
>>> teardown_environ(q)
|
|
171 |
"""
|
|
172 |
tree = pybaz.tree_root(".") |
|
173 |
add_file("trainfile", "void train(void){}", "trainfile by aaron") |
|
174 |
commit(tree, "altered trainfile") |
|
175 |
||
176 |
class NoSuchVersion(Exception): |
|
177 |
def __init__(self, version): |
|
178 |
Exception.__init__(self, "The version %s does not exist." % version) |
|
179 |
self.version = version |
|
180 |
||
181 |
def version_ancestry(version): |
|
182 |
"""
|
|
183 |
>>> q = test_environ()
|
|
184 |
>>> commit_test_revisions()
|
|
185 |
>>> version = pybaz.Version("test@example.com/test--test--0")
|
|
186 |
>>> ancestors = version_ancestry(version)
|
|
187 |
>>> str(ancestors[0])
|
|
188 |
'test@example.com/test--test--0--base-0'
|
|
189 |
>>> str(ancestors[1])
|
|
190 |
'test@example.com/test--test--0--patch-1'
|
|
191 |
>>> version = pybaz.Version("test@example.com/test--test--0.5")
|
|
192 |
>>> ancestors = version_ancestry(version)
|
|
193 |
Traceback (most recent call last):
|
|
194 |
NoSuchVersion: The version test@example.com/test--test--0.5 does not exist.
|
|
195 |
>>> teardown_environ(q)
|
|
196 |
"""
|
|
197 |
try: |
|
198 |
revision = version.iter_revisions(reverse=True).next() |
|
199 |
except: |
|
200 |
if not version.exists(): |
|
201 |
raise NoSuchVersion(version) |
|
202 |
else: |
|
203 |
raise
|
|
204 |
ancestors = list(revision.iter_ancestors(metoo=True)) |
|
205 |
ancestors.reverse() |
|
206 |
return ancestors |
|
207 |
||
208 |
def get_last_revision(branch): |
|
209 |
last_patch = branch.last_patch() |
|
210 |
try: |
|
211 |
return arch_revision(last_patch) |
|
212 |
except NotArchRevision: |
|
213 |
raise UserError( |
|
214 |
"Directory \"%s\" already exists, and the last revision is not" |
|
215 |
" an Arch revision (%s)" % (output_dir, last_patch)) |
|
216 |
||
217 |
||
218 |
def get_remaining_revisions(output_dir, version): |
|
219 |
last_patch = None |
|
220 |
old_revno = None |
|
221 |
if os.path.exists(output_dir): |
|
222 |
# We are starting from an existing directory, figure out what
|
|
223 |
# the current version is
|
|
224 |
branch = find_branch(output_dir) |
|
225 |
last_patch = get_last_revision(branch) |
|
226 |
if version is None: |
|
227 |
version = last_patch.version |
|
228 |
elif version is None: |
|
229 |
raise UserError("No version specified, and directory does not exist.") |
|
230 |
||
231 |
try: |
|
232 |
ancestors = version_ancestry(version) |
|
233 |
except NoSuchVersion, e: |
|
234 |
raise UserError(e) |
|
235 |
||
236 |
if last_patch: |
|
237 |
for i in range(len(ancestors)): |
|
238 |
if ancestors[i] == last_patch: |
|
239 |
break
|
|
240 |
else: |
|
241 |
raise UserError("Directory \"%s\" already exists, and the last " |
|
242 |
"revision (%s) is not in the ancestry of %s" % |
|
243 |
(output_dir, last_patch, version)) |
|
244 |
# Strip off all of the ancestors which are already present
|
|
245 |
# And get a directory starting with the latest ancestor
|
|
246 |
latest_ancestor = ancestors[i] |
|
247 |
old_revno = find_branch(output_dir).revno() |
|
248 |
ancestors = ancestors[i+1:] |
|
249 |
return ancestors, old_revno |
|
250 |
||
251 |
def import_version(output_dir, version, fancy=True, fast=False, verbose=False, |
|
252 |
dry_run=False, max_count=None, skip_symlinks=False): |
|
253 |
"""
|
|
254 |
>>> q = test_environ()
|
|
255 |
>>> result_path = os.path.join(q, "result")
|
|
256 |
>>> commit_test_revisions()
|
|
257 |
>>> version = pybaz.Version("test@example.com/test--test--0.1")
|
|
258 |
>>> import_version('/', version, fancy=False, dry_run=True)
|
|
259 |
Traceback (most recent call last):
|
|
260 |
UserError: / exists, but is not a bzr branch.
|
|
261 |
>>> import_version(result_path, version, fancy=False, dry_run=True)
|
|
262 |
Traceback (most recent call last):
|
|
263 |
UserError: The version test@example.com/test--test--0.1 does not exist.
|
|
264 |
>>> version = pybaz.Version("test@example.com/test--test--0")
|
|
265 |
>>> import_version(result_path, version, fancy=False, dry_run=True)
|
|
266 |
not fancy
|
|
267 |
....
|
|
268 |
Dry run, not modifying output_dir
|
|
269 |
Cleaning up
|
|
270 |
>>> import_version(result_path, version, fancy=False)
|
|
271 |
not fancy
|
|
272 |
....
|
|
273 |
Cleaning up
|
|
274 |
Import complete.
|
|
275 |
>>> import_version(result_path, version, fancy=False)
|
|
276 |
Tree is up-to-date with test@example.com/test--test--0--patch-2
|
|
277 |
>>> commit_more_test_revisions()
|
|
278 |
>>> import_version(result_path, version, fancy=False)
|
|
279 |
not fancy
|
|
280 |
..
|
|
281 |
Cleaning up
|
|
282 |
Import complete.
|
|
283 |
>>> teardown_environ(q)
|
|
284 |
"""
|
|
285 |
try: |
|
286 |
ancestors, old_revno = get_remaining_revisions(output_dir, version) |
|
287 |
except NotInABranch, e: |
|
288 |
raise UserError("%s exists, but is not a bzr branch." % e.path) |
|
289 |
if len(ancestors) == 0: |
|
290 |
last_revision = get_last_revision(find_branch(output_dir)) |
|
291 |
print 'Tree is up-to-date with %s' % last_revision |
|
292 |
return
|
|
293 |
||
294 |
progress_bar = ProgressBar() |
|
295 |
tempdir = tempfile.mkdtemp(prefix="baz2bzr-", |
|
296 |
dir=os.path.dirname(output_dir)) |
|
297 |
try: |
|
298 |
if not fancy: |
|
299 |
print "not fancy" |
|
300 |
try: |
|
301 |
for result in iter_import_version(output_dir, ancestors, tempdir, |
|
302 |
fast=fast, verbose=verbose, dry_run=dry_run, |
|
303 |
max_count=max_count, skip_symlinks=skip_symlinks): |
|
304 |
if fancy: |
|
102
by Aaron Bentley
Got baz2bzr/annotate working now that ProgressBar is a function |
305 |
show_progress(progress_bar, result) |
83
by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin |
306 |
else: |
307 |
sys.stdout.write('.') |
|
308 |
finally: |
|
309 |
if fancy: |
|
90
by Aaron Bentley
Adapted bzrlib's progress bar |
310 |
progress_bar.clear() |
83
by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin |
311 |
else: |
312 |
sys.stdout.write('\n') |
|
313 |
||
314 |
if dry_run: |
|
315 |
print 'Dry run, not modifying output_dir' |
|
316 |
return
|
|
317 |
if os.path.exists(output_dir): |
|
318 |
# Move the bzr control directory back, and update the working tree
|
|
319 |
tmp_bzr_dir = os.path.join(tempdir, '.bzr') |
|
320 |
||
321 |
bzr_dir = os.path.join(output_dir, '.bzr') |
|
322 |
new_bzr_dir = os.path.join(tempdir, "rd", '.bzr') |
|
323 |
||
324 |
os.rename(bzr_dir, tmp_bzr_dir) # Move the original bzr out of the way |
|
325 |
os.rename(new_bzr_dir, bzr_dir) |
|
326 |
try: |
|
327 |
bzrlib.merge.merge((output_dir, -1), (output_dir, old_revno), |
|
328 |
check_clean=False, this_dir=output_dir, |
|
329 |
ignore_zero=True) |
|
330 |
except: |
|
331 |
# If something failed, move back the original bzr directory
|
|
332 |
os.rename(bzr_dir, new_bzr_dir) |
|
333 |
os.rename(tmp_bzr_dir, bzr_dir) |
|
334 |
raise
|
|
335 |
else: |
|
336 |
revdir = os.path.join(tempdir, "rd") |
|
337 |
os.rename(revdir, output_dir) |
|
338 |
||
339 |
finally: |
|
340 |
print 'Cleaning up' |
|
341 |
shutil.rmtree(tempdir) |
|
342 |
print "Import complete." |
|
343 |
||
344 |
class UserError(Exception): |
|
345 |
def __init__(self, message): |
|
346 |
"""Exception to throw when a user makes an impossible request
|
|
347 |
:param message: The message to emit when printing this exception
|
|
348 |
:type message: string
|
|
349 |
"""
|
|
350 |
Exception.__init__(self, message) |
|
351 |
||
352 |
def revision_id(arch_revision): |
|
353 |
"""
|
|
354 |
Generate a Bzr revision id from an Arch revision id. 'x' in the id
|
|
355 |
designates a revision imported with an experimental algorithm. A number
|
|
356 |
would indicate a particular standardized version.
|
|
357 |
||
358 |
:param arch_revision: The Arch revision to generate an ID for.
|
|
359 |
||
360 |
>>> revision_id(pybaz.Revision("you@example.com/cat--br--0--base-0"))
|
|
361 |
'Arch-x:you@example.com%cat--br--0--base-0'
|
|
362 |
"""
|
|
363 |
return "Arch-x:%s" % str(arch_revision).replace('/', '%') |
|
364 |
||
365 |
class NotArchRevision(Exception): |
|
366 |
def __init__(self, revision_id): |
|
367 |
msg = "The revision id %s does not look like it came from Arch."\ |
|
368 |
% revision_id |
|
369 |
Exception.__init__(self, msg) |
|
370 |
||
371 |
def arch_revision(revision_id): |
|
372 |
"""
|
|
373 |
>>> str(arch_revision("Arch-x:jrandom@example.com%test--test--0"))
|
|
374 |
Traceback (most recent call last):
|
|
375 |
NotArchRevision: The revision id Arch-x:jrandom@example.com%test--test--0 does not look like it came from Arch.
|
|
376 |
>>> str(arch_revision("Arch-x:jrandom@example.com%test--test--0--base-5"))
|
|
377 |
Traceback (most recent call last):
|
|
378 |
NotArchRevision: The revision id Arch-x:jrandom@example.com%test--test--0--base-5 does not look like it came from Arch.
|
|
379 |
>>> str(arch_revision("Arch-x:jrandom@example.com%test--test--0--patch-5"))
|
|
380 |
'jrandom@example.com/test--test--0--patch-5'
|
|
381 |
"""
|
|
382 |
if revision_id is None: |
|
383 |
return None |
|
384 |
if revision_id[:7] != 'Arch-x:': |
|
385 |
raise NotArchRevision(revision_id) |
|
386 |
else: |
|
387 |
try: |
|
388 |
return pybaz.Revision(revision_id[7:].replace('%', '/')) |
|
389 |
except pybaz.errors.NamespaceError, e: |
|
390 |
raise NotArchRevision(revision_id) |
|
391 |
||
392 |
def iter_import_version(output_dir, ancestors, tempdir, fast=False, |
|
393 |
verbose=False, dry_run=False, max_count=None, |
|
394 |
skip_symlinks=False): |
|
395 |
revdir = None |
|
396 |
||
397 |
# Uncomment this for testing, it basically just has baz2bzr only update
|
|
398 |
# 5 patches at a time
|
|
399 |
if max_count: |
|
400 |
ancestors = ancestors[:max_count] |
|
401 |
||
402 |
# Not sure if I want this output. basically it tells you ahead of time
|
|
403 |
# what it is going to do, but then later it tells you as it is doing it.
|
|
404 |
# what probably would be best would be to collapse it into ranges, so that
|
|
405 |
# this gives the simple view, and then later it gives the blow by blow.
|
|
406 |
#if verbose:
|
|
407 |
# print 'Adding the following revisions:'
|
|
408 |
# for a in ancestors:
|
|
409 |
# print '\t%s' % a
|
|
410 |
||
411 |
previous_version=None |
|
412 |
||
413 |
for i in range(len(ancestors)): |
|
414 |
revision = ancestors[i] |
|
415 |
if verbose: |
|
416 |
version = str(revision.version) |
|
417 |
if version != previous_version: |
|
418 |
clear_progress_bar() |
|
419 |
print '\rOn version: %s' % version |
|
420 |
yield Progress(str(revision.patchlevel), i, len(ancestors)) |
|
421 |
previous_version = version |
|
422 |
else: |
|
423 |
yield Progress("revisions", i, len(ancestors)) |
|
424 |
if revdir is None: |
|
425 |
revdir = os.path.join(tempdir, "rd") |
|
426 |
baz_inv, log = get_revision(revdir, revision, |
|
427 |
skip_symlinks=skip_symlinks) |
|
428 |
if os.path.exists(output_dir): |
|
429 |
bzr_dir = os.path.join(output_dir, '.bzr') |
|
430 |
new_bzr_dir = os.path.join(tempdir, "rd", '.bzr') |
|
431 |
# This would be much faster with a simple os.rename(), but if
|
|
432 |
# we fail, we have corrupted the original .bzr directory. Is
|
|
433 |
# that a big problem, as we can just back out the last
|
|
434 |
# revisions in .bzr/revision_history I don't really know
|
|
435 |
shutil.copytree(bzr_dir, new_bzr_dir) |
|
436 |
# Now revdir should have a tree with the latest .bzr, and the
|
|
437 |
# next revision of the baz tree
|
|
438 |
branch = find_branch(revdir) |
|
439 |
else: |
|
158
by Aaron Bentley
Updated to match API changes |
440 |
branch = Branch.initialize(revdir) |
83
by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin |
441 |
else: |
442 |
old = os.path.join(revdir, ".bzr") |
|
443 |
new = os.path.join(tempdir, ".bzr") |
|
444 |
os.rename(old, new) |
|
445 |
baz_inv, log = apply_revision(revdir, revision, |
|
446 |
skip_symlinks=skip_symlinks) |
|
447 |
os.rename(new, old) |
|
448 |
branch = find_branch(revdir) |
|
449 |
timestamp = email.Utils.mktime_tz(log.date + (0,)) |
|
450 |
rev_id = revision_id(revision) |
|
451 |
branch.lock_write() |
|
452 |
try: |
|
453 |
branch.set_inventory(baz_inv) |
|
454 |
bzrlib.trace.silent = True |
|
455 |
branch.commit(log.summary, verbose=False, committer=log.creator, |
|
456 |
timestamp=timestamp, timezone=0, rev_id=rev_id) |
|
457 |
finally: |
|
458 |
bzrlib.trace.silent = False |
|
459 |
branch.unlock() |
|
460 |
yield Progress("revisions", len(ancestors), len(ancestors)) |
|
461 |
unlink_unversioned(branch, revdir) |
|
462 |
||
463 |
def unlink_unversioned(branch, revdir): |
|
464 |
for unversioned in branch.working_tree().extras(): |
|
465 |
path = os.path.join(revdir, unversioned) |
|
466 |
if os.path.isdir(path): |
|
467 |
shutil.rmtree(path) |
|
468 |
else: |
|
469 |
os.unlink(path) |
|
470 |
||
471 |
def get_log(tree, revision): |
|
472 |
log = tree.iter_logs(version=revision.version, reverse=True).next() |
|
133
by Aaron Bentley
Weakened check so baz-import works |
473 |
assert str(log.revision) == str(revision), (log.revision, revision) |
83
by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin |
474 |
return log |
475 |
||
476 |
def get_revision(revdir, revision, skip_symlinks=False): |
|
477 |
revision.get(revdir) |
|
478 |
tree = pybaz.tree_root(revdir) |
|
479 |
log = get_log(tree, revision) |
|
480 |
try: |
|
481 |
return bzr_inventory_data(tree, skip_symlinks=skip_symlinks), log |
|
482 |
except BadFileKind, e: |
|
483 |
raise UserError("Cannot convert %s because %s is a %s" % (revision,e.path, e.kind) ) |
|
484 |
||
485 |
||
486 |
def apply_revision(revdir, revision, skip_symlinks=False): |
|
487 |
tree = pybaz.tree_root(revdir) |
|
488 |
revision.apply(tree) |
|
489 |
log = get_log(tree, revision) |
|
490 |
try: |
|
491 |
return bzr_inventory_data(tree, skip_symlinks=skip_symlinks), log |
|
492 |
except BadFileKind, e: |
|
493 |
raise UserError("Cannot convert %s because %s is a %s" % (revision,e.path, e.kind) ) |
|
494 |
||
495 |
||
496 |
||
497 |
||
498 |
class BadFileKind(Exception): |
|
499 |
"""The file kind is not permitted in bzr inventories"""
|
|
500 |
def __init__(self, tree_root, path, kind): |
|
501 |
self.tree_root = tree_root |
|
502 |
self.path = path |
|
503 |
self.kind = kind |
|
504 |
Exception.__init__(self, "File %s is of forbidden type %s" % |
|
505 |
(os.path.join(tree_root, path), kind)) |
|
506 |
||
507 |
def bzr_inventory_data(tree, skip_symlinks=False): |
|
508 |
inv_iter = tree.iter_inventory_ids(source=True, both=True) |
|
509 |
inv_map = {} |
|
106
by Aaron Bentley
Used limited url-encoding for file ids |
510 |
for arch_id, path in inv_iter: |
511 |
bzr_file_id = arch_id.replace('%', '%25').replace('/', '%2f') |
|
512 |
inv_map[path] = bzr_file_id |
|
83
by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin |
513 |
|
514 |
bzr_inv = [] |
|
515 |
for path, file_id in inv_map.iteritems(): |
|
516 |
full_path = os.path.join(tree, path) |
|
517 |
kind = bzrlib.osutils.file_kind(full_path) |
|
518 |
if skip_symlinks and kind == "symlink": |
|
519 |
continue
|
|
520 |
if kind not in ("file", "directory"): |
|
521 |
raise BadFileKind(tree, path, kind) |
|
522 |
parent_dir = os.path.dirname(path) |
|
523 |
if parent_dir != "": |
|
524 |
parent_id = inv_map[parent_dir] |
|
525 |
else: |
|
526 |
parent_id = bzrlib.inventory.ROOT_ID |
|
527 |
bzr_inv.append((path, file_id, parent_id, kind)) |
|
528 |
bzr_inv.sort() |
|
529 |
return bzr_inv |
|
530 |
||
531 |
class NotInABranch(Exception): |
|
532 |
def __init__(self, path): |
|
533 |
Exception.__init__(self, "%s is not in a branch." % path) |
|
534 |
self.path = path |
|
535 |
||
536 |
||
537 |
def find_branch(path): |
|
538 |
"""
|
|
539 |
>>> find_branch('/')
|
|
540 |
Traceback (most recent call last):
|
|
541 |
NotInABranch: / is not in a branch.
|
|
542 |
>>> sb = bzrlib.ScratchBranch()
|
|
123
by aaron.bentley at utoronto
changed branch references |
543 |
>>> isinstance(find_branch(sb.base), Branch)
|
83
by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin |
544 |
True
|
545 |
"""
|
|
546 |
try: |
|
158
by Aaron Bentley
Updated to match API changes |
547 |
return Branch.open(path) |
83
by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin |
548 |
except BzrError, e: |
549 |
if e.args[0].endswith("' is not in a branch"): |
|
550 |
raise NotInABranch(path) |
|
551 |
||
552 |
class cmd_baz_import(Command): |
|
553 |
"""Import an Arch or Baz branch into a bzr branch"""
|
|
554 |
takes_args = ['to_location', 'from_branch?'] |
|
555 |
takes_options = ['verbose'] |
|
556 |
||
557 |
def run(self, to_location, from_branch=None, skip_symlinks=False, |
|
558 |
fast=False, max_count=None, verbose=False, dry_run=False): |
|
559 |
to_location = os.path.realpath(str(to_location)) |
|
560 |
if from_branch is not None: |
|
561 |
try: |
|
100
by Aaron Bentley
Fixed up the baz-import plugin |
562 |
from_branch = pybaz.Version(from_branch) |
83
by Aaron Bentley
Moved most baz2bzr code to baz_import, added Python plugin |
563 |
except pybaz.errors.NamespaceError: |
564 |
print "%s is not a valid Arch branch." % from_branch |
|
565 |
return 1 |
|
90
by Aaron Bentley
Adapted bzrlib's progress bar |
566 |
import_version(to_location, from_branch) |