2
by abentley
Added baz2bzr file(doh!) |
1 |
#!/usr/bin/env python
|
14
by abentley
GPLed the project, ignored files |
2 |
|
3 |
# Copyright (C) 2005 Aaron Bentley
|
|
4 |
# <aaron.bentley@utoronto.ca>
|
|
5 |
#
|
|
6 |
# This program is free software; you can redistribute it and/or modify
|
|
7 |
# it under the terms of the GNU General Public License as published by
|
|
8 |
# the Free Software Foundation; either version 2 of the License, or
|
|
9 |
# (at your option) any later version.
|
|
10 |
#
|
|
11 |
# This program is distributed in the hope that it will be useful,
|
|
12 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14 |
# GNU General Public License for more details.
|
|
15 |
#
|
|
16 |
# You should have received a copy of the GNU General Public License
|
|
17 |
# along with this program; if not, write to the Free Software
|
|
18 |
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
19 |
||
2
by abentley
Added baz2bzr file(doh!) |
20 |
try: |
21 |
import pybaz |
|
61
by Aaron Bentley
Factored out bzr to baz id conversion |
22 |
import pybaz.errors |
2
by abentley
Added baz2bzr file(doh!) |
23 |
except ImportError: |
24 |
print "This command requires PyBaz. Please ensure that it is installed." |
|
25 |
import sys |
|
26 |
sys.exit(1) |
|
3
by abentley
Added add_file and add_dir functions |
27 |
from pybaz.backends.baz import null_cmd |
2
by abentley
Added baz2bzr file(doh!) |
28 |
import tempfile |
29 |
import os |
|
30 |
import os.path |
|
31 |
import shutil |
|
7
by abentley
Completed initial construction |
32 |
import bzrlib |
45
by Aaron Bentley
Silenced commits |
33 |
import bzrlib.trace |
57
by Aaron Bentley
Added John Meinel's update-with-no-{arch} patch |
34 |
import bzrlib.merge |
8
by abentley
Added ability to run from the commandline |
35 |
import sys |
37
by Aaron Bentley
More log fixups for baz2bzr |
36 |
import email.Utils |
11
by abentley
refactored out progress.py |
37 |
from progress import * |
2
by abentley
Added baz2bzr file(doh!) |
38 |
|
3
by abentley
Added add_file and add_dir functions |
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 |
||
2
by abentley
Added baz2bzr file(doh!) |
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="baz2bzr-") |
|
65 |
os.environ["HOME"] = os.path.join(tdir, "home") |
|
66 |
os.mkdir(os.environ["HOME"]) |
|
3
by abentley
Added add_file and add_dir functions |
67 |
arch_dir = os.path.join(tdir, "archive_dir") |
68 |
pybaz.make_archive("test@example.com", arch_dir) |
|
2
by abentley
Added baz2bzr file(doh!) |
69 |
work_dir = os.path.join(tdir, "work_dir") |
70 |
os.mkdir(work_dir) |
|
71 |
os.chdir(work_dir) |
|
3
by abentley
Added add_file and add_dir functions |
72 |
pybaz.init_tree(work_dir, "test@example.com/test--test--0") |
2
by abentley
Added baz2bzr file(doh!) |
73 |
lib_dir = os.path.join(tdir, "lib_dir") |
74 |
os.mkdir(lib_dir) |
|
75 |
pybaz.register_revision_library(lib_dir) |
|
6
by abentley
added commit, timport, commit_test_revisions |
76 |
pybaz.set_my_id("Test User<test@example.org>") |
2
by abentley
Added baz2bzr file(doh!) |
77 |
return tdir |
78 |
||
5
by abentley
changed add_file, add_dir interfaces |
79 |
def add_file(path, text, id): |
3
by abentley
Added add_file and add_dir functions |
80 |
"""
|
81 |
>>> q = test_environ()
|
|
5
by abentley
changed add_file, add_dir interfaces |
82 |
>>> add_file("path with space", "text", "lalala")
|
3
by abentley
Added add_file and add_dir functions |
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) |
|
5
by abentley
changed add_file, add_dir interfaces |
90 |
add_id([path], id) |
91 |
||
92 |
||
93 |
def add_dir(path, id): |
|
3
by abentley
Added add_file and add_dir functions |
94 |
"""
|
95 |
>>> q = test_environ()
|
|
5
by abentley
changed add_file, add_dir interfaces |
96 |
>>> add_dir("path with\(sp) space", "lalala")
|
3
by abentley
Added add_file and add_dir functions |
97 |
>>> tree = pybaz.tree_root(".")
|
98 |
>>> inv = list(tree.iter_inventory_ids(source=True, both=True))
|
|
4
by abentley
made test case trickier, by using pika escaping sequence in filename. |
99 |
>>> ("x_lalala", "path with\(sp) space") in inv
|
3
by abentley
Added add_file and add_dir functions |
100 |
True
|
101 |
>>> teardown_environ(q)
|
|
102 |
"""
|
|
103 |
os.mkdir(path) |
|
5
by abentley
changed add_file, add_dir interfaces |
104 |
add_id([path], id) |
3
by abentley
Added add_file and add_dir functions |
105 |
|
2
by abentley
Added baz2bzr file(doh!) |
106 |
def teardown_environ(tdir): |
107 |
os.chdir("/") |
|
108 |
shutil.rmtree(tdir) |
|
109 |
||
6
by abentley
added commit, timport, commit_test_revisions |
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)
|
|
7
by abentley
Completed initial construction |
141 |
3
|
142 |
>>> str(revisions[2])
|
|
143 |
'test@example.com/test--test--0--base-0'
|
|
6
by abentley
added commit, timport, commit_test_revisions |
144 |
>>> str(revisions[1])
|
7
by abentley
Completed initial construction |
145 |
'test@example.com/test--test--0--patch-1'
|
6
by abentley
added commit, timport, commit_test_revisions |
146 |
>>> str(revisions[0])
|
7
by abentley
Completed initial construction |
147 |
'test@example.com/test--test--0--patch-2'
|
6
by abentley
added commit, timport, commit_test_revisions |
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") |
|
7
by abentley
Completed initial construction |
155 |
add_file("ofile", "this is another file", "ofile by aaron") |
156 |
commit(tree, "altered mainfile") |
|
157 |
||
68
by Aaron Bentley
got dry run and continued import under test |
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 |
||
7
by abentley
Completed initial construction |
176 |
def version_ancestry(version): |
177 |
"""
|
|
178 |
>>> q = test_environ()
|
|
179 |
>>> commit_test_revisions()
|
|
180 |
>>> version = pybaz.Version("test@example.com/test--test--0")
|
|
181 |
>>> ancestors = version_ancestry(version)
|
|
182 |
>>> str(ancestors[0])
|
|
183 |
'test@example.com/test--test--0--base-0'
|
|
184 |
>>> str(ancestors[1])
|
|
185 |
'test@example.com/test--test--0--patch-1'
|
|
186 |
>>> teardown_environ(q)
|
|
187 |
"""
|
|
35
by Aaron Bentley
Fixed, and got test cases passing |
188 |
revision = version.iter_revisions(reverse=True).next() |
31
by Aaron Bentley
Further updates |
189 |
ancestors = list(revision.iter_ancestors(metoo=True)) |
190 |
ancestors.reverse() |
|
7
by abentley
Completed initial construction |
191 |
return ancestors |
192 |
||
66
by Aaron Bentley
Continued symlink fix, cleaned up merge, error message |
193 |
def get_last_revision(branch): |
194 |
last_patch = branch.last_patch() |
|
195 |
try: |
|
196 |
return arch_revision(last_patch) |
|
197 |
except NotArchRevision: |
|
198 |
raise UserError( |
|
199 |
"Directory \"%s\" already exists, and the last revision is not" |
|
200 |
" an Arch revision (%s)" % (output_dir, last_patch)) |
|
201 |
||
202 |
||
62
by Aaron Bentley
Refactored, made version optional |
203 |
def get_remaining_revisions(output_dir, version): |
204 |
last_patch = None |
|
205 |
old_revno = None |
|
206 |
if os.path.exists(output_dir): |
|
207 |
# We are starting from an existing directory, figure out what
|
|
208 |
# the current version is
|
|
209 |
branch = bzrlib.Branch(output_dir) |
|
66
by Aaron Bentley
Continued symlink fix, cleaned up merge, error message |
210 |
last_patch = get_last_revision(branch) |
62
by Aaron Bentley
Refactored, made version optional |
211 |
if version is None: |
212 |
version = last_patch.version |
|
213 |
elif version is None: |
|
214 |
raise UserError("No version specified, and directory does not exist.") |
|
215 |
||
216 |
ancestors = version_ancestry(version) |
|
217 |
||
218 |
if last_patch: |
|
219 |
for i in range(len(ancestors)): |
|
220 |
if ancestors[i] == last_patch: |
|
221 |
break
|
|
222 |
else: |
|
223 |
raise UserError("Directory \"%s\" already exists, and the last " |
|
224 |
"revision (%s) is not in the ancestry of %s" % |
|
225 |
(output_dir, last_patch, version)) |
|
226 |
# Strip off all of the ancestors which are already present
|
|
227 |
# And get a directory starting with the latest ancestor
|
|
228 |
latest_ancestor = ancestors[i] |
|
229 |
old_revno = bzrlib.Branch(output_dir).revno() |
|
230 |
ancestors = ancestors[i+1:] |
|
231 |
return ancestors, old_revno |
|
10
by abentley
Refactored, made progress bar |
232 |
|
60
by Aaron Bentley
Made symlink-skipping an option |
233 |
def import_version(output_dir, version, fancy=True, fast=False, verbose=False, |
234 |
dry_run=False, max_count=None, skip_symlinks=False): |
|
7
by abentley
Completed initial construction |
235 |
"""
|
236 |
>>> q = test_environ()
|
|
237 |
>>> result_path = os.path.join(q, "result")
|
|
238 |
>>> commit_test_revisions()
|
|
239 |
>>> version = pybaz.Version("test@example.com/test--test--0")
|
|
68
by Aaron Bentley
got dry run and continued import under test |
240 |
>>> import_version(result_path, version, fancy=False, dry_run=True)
|
241 |
not fancy
|
|
242 |
....
|
|
243 |
Dry run, not modifying output_dir
|
|
244 |
Cleaning up
|
|
35
by Aaron Bentley
Fixed, and got test cases passing |
245 |
>>> import_version(result_path, version, fancy=False)
|
246 |
not fancy
|
|
247 |
....
|
|
59
by Aaron Bentley
Applied John Meinel's options patch |
248 |
Cleaning up
|
35
by Aaron Bentley
Fixed, and got test cases passing |
249 |
Import complete.
|
68
by Aaron Bentley
got dry run and continued import under test |
250 |
>>> import_version(result_path, version, fancy=False)
|
251 |
Tree is up-to-date with test@example.com/test--test--0--patch-2
|
|
7
by abentley
Completed initial construction |
252 |
>>> teardown_environ(q)
|
253 |
"""
|
|
62
by Aaron Bentley
Refactored, made version optional |
254 |
ancestors, old_revno = get_remaining_revisions(output_dir, version) |
255 |
if len(ancestors) == 0: |
|
66
by Aaron Bentley
Continued symlink fix, cleaned up merge, error message |
256 |
last_revision = get_last_revision(bzrlib.Branch(output_dir)) |
68
by Aaron Bentley
got dry run and continued import under test |
257 |
print 'Tree is up-to-date with %s' % last_revision |
258 |
return
|
|
62
by Aaron Bentley
Refactored, made version optional |
259 |
|
47
by Aaron Bentley
merged ETA changes |
260 |
progress_bar = ProgressBar() |
51
by Aaron Bentley
Ensured temp dir is on same filesystem as output dir |
261 |
tempdir = tempfile.mkdtemp(prefix="baz2bzr-", |
262 |
dir=os.path.dirname(output_dir)) |
|
7
by abentley
Completed initial construction |
263 |
try: |
35
by Aaron Bentley
Fixed, and got test cases passing |
264 |
if not fancy: |
265 |
print "not fancy" |
|
68
by Aaron Bentley
got dry run and continued import under test |
266 |
try: |
267 |
for result in iter_import_version(output_dir, ancestors, tempdir, |
|
268 |
fast=fast, verbose=verbose, dry_run=dry_run, |
|
269 |
max_count=max_count, skip_symlinks=skip_symlinks): |
|
270 |
if fancy: |
|
271 |
progress_bar(result) |
|
272 |
else: |
|
273 |
sys.stdout.write('.') |
|
274 |
finally: |
|
35
by Aaron Bentley
Fixed, and got test cases passing |
275 |
if fancy: |
68
by Aaron Bentley
got dry run and continued import under test |
276 |
clear_progress_bar() |
35
by Aaron Bentley
Fixed, and got test cases passing |
277 |
else: |
68
by Aaron Bentley
got dry run and continued import under test |
278 |
sys.stdout.write('\n') |
62
by Aaron Bentley
Refactored, made version optional |
279 |
|
280 |
if dry_run: |
|
68
by Aaron Bentley
got dry run and continued import under test |
281 |
print 'Dry run, not modifying output_dir' |
282 |
return
|
|
62
by Aaron Bentley
Refactored, made version optional |
283 |
if os.path.exists(output_dir): |
284 |
# Move the bzr control directory back, and update the working tree
|
|
285 |
tmp_bzr_dir = os.path.join(tempdir, '.bzr') |
|
286 |
||
287 |
bzr_dir = os.path.join(output_dir, '.bzr') |
|
288 |
new_bzr_dir = os.path.join(tempdir, "rd", '.bzr') |
|
289 |
||
290 |
os.rename(bzr_dir, tmp_bzr_dir) # Move the original bzr out of the way |
|
291 |
os.rename(new_bzr_dir, bzr_dir) |
|
292 |
try: |
|
66
by Aaron Bentley
Continued symlink fix, cleaned up merge, error message |
293 |
bzrlib.merge.merge(('.', -1), ('.', old_revno), |
294 |
check_clean=False, this_dir=output_dir, |
|
295 |
ignore_zero=True) |
|
62
by Aaron Bentley
Refactored, made version optional |
296 |
except: |
297 |
# If something failed, move back the original bzr directory
|
|
298 |
os.rename(bzr_dir, new_bzr_dir) |
|
299 |
os.rename(tmp_bzr_dir, bzr_dir) |
|
300 |
raise
|
|
301 |
else: |
|
67
by Aaron Bentley
Ensured all tests pass |
302 |
revdir = os.path.join(tempdir, "rd") |
62
by Aaron Bentley
Refactored, made version optional |
303 |
os.rename(revdir, output_dir) |
304 |
||
29
by Aaron Bentley
Nicer handling of unsupported file types |
305 |
finally: |
59
by Aaron Bentley
Applied John Meinel's options patch |
306 |
print 'Cleaning up' |
7
by abentley
Completed initial construction |
307 |
shutil.rmtree(tempdir) |
29
by Aaron Bentley
Nicer handling of unsupported file types |
308 |
print "Import complete." |
10
by abentley
Refactored, made progress bar |
309 |
|
12
by abentley
Error early when the user specifies an output directory that already exists |
310 |
class UserError(Exception): |
311 |
def __init__(self, message): |
|
312 |
"""Exception to throw when a user makes an impossible request
|
|
313 |
:param message: The message to emit when printing this exception
|
|
314 |
:type message: string
|
|
315 |
"""
|
|
316 |
Exception.__init__(self, message) |
|
317 |
||
46
by Aaron Bentley
Made bzr revision ids predictable |
318 |
def revision_id(arch_revision): |
319 |
"""
|
|
320 |
Generate a Bzr revision id from an Arch revision id. 'x' in the id
|
|
321 |
designates a revision imported with an experimental algorithm. A number
|
|
322 |
would indicate a particular standardized version.
|
|
323 |
||
324 |
:param arch_revision: The Arch revision to generate an ID for.
|
|
325 |
||
326 |
>>> revision_id(pybaz.Revision("you@example.com/cat--br--0--base-0"))
|
|
327 |
'Arch-x:you@example.com%cat--br--0--base-0'
|
|
328 |
"""
|
|
329 |
return "Arch-x:%s" % str(arch_revision).replace('/', '%') |
|
330 |
||
61
by Aaron Bentley
Factored out bzr to baz id conversion |
331 |
class NotArchRevision(Exception): |
332 |
def __init__(self, revision_id): |
|
333 |
msg = "The revision id %s does not look like it came from Arch."\ |
|
334 |
% revision_id |
|
335 |
Exception.__init__(self, msg) |
|
336 |
||
337 |
def arch_revision(revision_id): |
|
338 |
"""
|
|
67
by Aaron Bentley
Ensured all tests pass |
339 |
>>> str(arch_revision("Arch-x:jrandom@example.com%test--test--0"))
|
340 |
Traceback (most recent call last):
|
|
341 |
NotArchRevision: The revision id Arch-x:jrandom@example.com%test--test--0 does not look like it came from Arch.
|
|
342 |
>>> str(arch_revision("Arch-x:jrandom@example.com%test--test--0--base-5"))
|
|
343 |
Traceback (most recent call last):
|
|
344 |
NotArchRevision: The revision id Arch-x:jrandom@example.com%test--test--0--base-5 does not look like it came from Arch.
|
|
345 |
>>> str(arch_revision("Arch-x:jrandom@example.com%test--test--0--patch-5"))
|
|
346 |
'jrandom@example.com/test--test--0--patch-5'
|
|
61
by Aaron Bentley
Factored out bzr to baz id conversion |
347 |
"""
|
348 |
if revision_id is None: |
|
349 |
return None |
|
350 |
if revision_id[:7] != 'Arch-x:': |
|
351 |
raise NotArchRevision(revision_id) |
|
352 |
else: |
|
353 |
try: |
|
354 |
return pybaz.Revision(revision_id[7:].replace('%', '/')) |
|
355 |
except pybaz.errors.NamespaceError, e: |
|
356 |
raise NotArchRevision(revision_id) |
|
357 |
||
62
by Aaron Bentley
Refactored, made version optional |
358 |
def iter_import_version(output_dir, ancestors, tempdir, fast=False, |
60
by Aaron Bentley
Made symlink-skipping an option |
359 |
verbose=False, dry_run=False, max_count=None, |
360 |
skip_symlinks=False): |
|
10
by abentley
Refactored, made progress bar |
361 |
revdir = None |
57
by Aaron Bentley
Added John Meinel's update-with-no-{arch} patch |
362 |
|
56
by Aaron Bentley
Applied John Meinel's 'update' patch |
363 |
# Uncomment this for testing, it basically just has baz2bzr only update
|
364 |
# 5 patches at a time
|
|
59
by Aaron Bentley
Applied John Meinel's options patch |
365 |
if max_count: |
366 |
ancestors = ancestors[:max_count] |
|
367 |
||
368 |
# Not sure if I want this output. basically it tells you ahead of time
|
|
369 |
# what it is going to do, but then later it tells you as it is doing it.
|
|
370 |
# what probably would be best would be to collapse it into ranges, so that
|
|
371 |
# this gives the simple view, and then later it gives the blow by blow.
|
|
372 |
#if verbose:
|
|
373 |
# print 'Adding the following revisions:'
|
|
374 |
# for a in ancestors:
|
|
375 |
# print '\t%s' % a
|
|
376 |
||
377 |
previous_version=None |
|
56
by Aaron Bentley
Applied John Meinel's 'update' patch |
378 |
|
10
by abentley
Refactored, made progress bar |
379 |
for i in range(len(ancestors)): |
380 |
revision = ancestors[i] |
|
59
by Aaron Bentley
Applied John Meinel's options patch |
381 |
if verbose: |
382 |
version = str(revision.version) |
|
383 |
if version != previous_version: |
|
384 |
clear_progress_bar() |
|
385 |
print '\rOn version: %s' % version |
|
386 |
yield Progress(str(revision.patchlevel), i, len(ancestors)) |
|
387 |
previous_version = version |
|
388 |
else: |
|
389 |
yield Progress("revisions", i, len(ancestors)) |
|
10
by abentley
Refactored, made progress bar |
390 |
if revdir is None: |
391 |
revdir = os.path.join(tempdir, "rd") |
|
60
by Aaron Bentley
Made symlink-skipping an option |
392 |
baz_inv, log = get_revision(revdir, revision, |
393 |
skip_symlinks=skip_symlinks) |
|
62
by Aaron Bentley
Refactored, made version optional |
394 |
if os.path.exists(output_dir): |
395 |
bzr_dir = os.path.join(output_dir, '.bzr') |
|
396 |
new_bzr_dir = os.path.join(tempdir, "rd", '.bzr') |
|
397 |
# This would be much faster with a simple os.rename(), but if
|
|
398 |
# we fail, we have corrupted the original .bzr directory. Is
|
|
399 |
# that a big problem, as we can just back out the last
|
|
400 |
# revisions in .bzr/revision_history I don't really know
|
|
401 |
shutil.copytree(bzr_dir, new_bzr_dir) |
|
402 |
# Now revdir should have a tree with the latest .bzr, and the
|
|
403 |
# next revision of the baz tree
|
|
404 |
branch = bzrlib.Branch(revdir) |
|
405 |
else: |
|
406 |
branch = bzrlib.Branch(revdir, init=True) |
|
10
by abentley
Refactored, made progress bar |
407 |
else: |
408 |
old = os.path.join(revdir, ".bzr") |
|
409 |
new = os.path.join(tempdir, ".bzr") |
|
410 |
os.rename(old, new) |
|
60
by Aaron Bentley
Made symlink-skipping an option |
411 |
baz_inv, log = apply_revision(revdir, revision, |
412 |
skip_symlinks=skip_symlinks) |
|
10
by abentley
Refactored, made progress bar |
413 |
os.rename(new, old) |
414 |
branch = bzrlib.Branch(revdir) |
|
37
by Aaron Bentley
More log fixups for baz2bzr |
415 |
timestamp = email.Utils.mktime_tz(log.date + (0,)) |
46
by Aaron Bentley
Made bzr revision ids predictable |
416 |
rev_id = revision_id(revision) |
52
by Aaron Bentley
Updated for new Branch locking |
417 |
branch.lock_write() |
45
by Aaron Bentley
Silenced commits |
418 |
try: |
52
by Aaron Bentley
Updated for new Branch locking |
419 |
branch.set_inventory(baz_inv) |
420 |
bzrlib.trace.silent = True |
|
45
by Aaron Bentley
Silenced commits |
421 |
branch.commit(log.summary, verbose=False, committer=log.creator, |
46
by Aaron Bentley
Made bzr revision ids predictable |
422 |
timestamp=timestamp, timezone=0, rev_id=rev_id) |
45
by Aaron Bentley
Silenced commits |
423 |
finally: |
424 |
bzrlib.trace.silent = False |
|
52
by Aaron Bentley
Updated for new Branch locking |
425 |
branch.unlock() |
10
by abentley
Refactored, made progress bar |
426 |
yield Progress("revisions", len(ancestors), len(ancestors)) |
57
by Aaron Bentley
Added John Meinel's update-with-no-{arch} patch |
427 |
unlink_unversioned(branch, revdir) |
10
by abentley
Refactored, made progress bar |
428 |
|
429 |
def unlink_unversioned(branch, revdir): |
|
430 |
for unversioned in branch.working_tree().extras(): |
|
431 |
path = os.path.join(revdir, unversioned) |
|
432 |
if os.path.isdir(path): |
|
433 |
shutil.rmtree(path) |
|
434 |
else: |
|
435 |
os.unlink(path) |
|
7
by abentley
Completed initial construction |
436 |
|
37
by Aaron Bentley
More log fixups for baz2bzr |
437 |
def get_log(tree, revision): |
438 |
log = tree.iter_logs(version=revision.version, reverse=True).next() |
|
439 |
assert log.revision == revision |
|
440 |
return log |
|
441 |
||
60
by Aaron Bentley
Made symlink-skipping an option |
442 |
def get_revision(revdir, revision, skip_symlinks=False): |
7
by abentley
Completed initial construction |
443 |
revision.get(revdir) |
444 |
tree = pybaz.tree_root(revdir) |
|
37
by Aaron Bentley
More log fixups for baz2bzr |
445 |
log = get_log(tree, revision) |
29
by Aaron Bentley
Nicer handling of unsupported file types |
446 |
try: |
60
by Aaron Bentley
Made symlink-skipping an option |
447 |
return bzr_inventory_data(tree, skip_symlinks=skip_symlinks), log |
29
by Aaron Bentley
Nicer handling of unsupported file types |
448 |
except BadFileKind, e: |
449 |
raise UserError("Cannot convert %s because %s is a %s" % (revision,e.path, e.kind) ) |
|
450 |
||
7
by abentley
Completed initial construction |
451 |
|
60
by Aaron Bentley
Made symlink-skipping an option |
452 |
def apply_revision(revdir, revision, skip_symlinks=False): |
13
by abentley
Used replay to get next revision |
453 |
tree = pybaz.tree_root(revdir) |
454 |
revision.apply(tree) |
|
37
by Aaron Bentley
More log fixups for baz2bzr |
455 |
log = get_log(tree, revision) |
29
by Aaron Bentley
Nicer handling of unsupported file types |
456 |
try: |
60
by Aaron Bentley
Made symlink-skipping an option |
457 |
return bzr_inventory_data(tree, skip_symlinks=skip_symlinks), log |
29
by Aaron Bentley
Nicer handling of unsupported file types |
458 |
except BadFileKind, e: |
459 |
raise UserError("Cannot convert %s because %s is a %s" % (revision,e.path, e.kind) ) |
|
460 |
||
461 |
||
462 |
||
463 |
||
464 |
class BadFileKind(Exception): |
|
465 |
"""The file kind is not permitted in bzr inventories"""
|
|
466 |
def __init__(self, tree_root, path, kind): |
|
467 |
self.tree_root = tree_root |
|
468 |
self.path = path |
|
469 |
self.kind = kind |
|
470 |
Exception.__init__(self, "File %s is of forbidden type %s" % |
|
471 |
(os.path.join(tree_root, path), kind)) |
|
13
by abentley
Used replay to get next revision |
472 |
|
60
by Aaron Bentley
Made symlink-skipping an option |
473 |
def bzr_inventory_data(tree, skip_symlinks=False): |
7
by abentley
Completed initial construction |
474 |
inv_iter = tree.iter_inventory_ids(source=True, both=True) |
475 |
inv_map = {} |
|
476 |
for file_id, path in inv_iter: |
|
8
by abentley
Added ability to run from the commandline |
477 |
inv_map[path] = file_id |
7
by abentley
Completed initial construction |
478 |
|
479 |
bzr_inv = [] |
|
8
by abentley
Added ability to run from the commandline |
480 |
for path, file_id in inv_map.iteritems(): |
29
by Aaron Bentley
Nicer handling of unsupported file types |
481 |
full_path = os.path.join(tree, path) |
482 |
kind = bzrlib.osutils.file_kind(full_path) |
|
60
by Aaron Bentley
Made symlink-skipping an option |
483 |
if skip_symlinks and kind == "symlink": |
55
by Aaron Bentley
Skip symlinks while importing |
484 |
continue
|
29
by Aaron Bentley
Nicer handling of unsupported file types |
485 |
if kind not in ("file", "directory"): |
486 |
raise BadFileKind(tree, path, kind) |
|
7
by abentley
Completed initial construction |
487 |
parent_dir = os.path.dirname(path) |
488 |
if parent_dir != "": |
|
489 |
parent_id = inv_map[parent_dir] |
|
490 |
else: |
|
491 |
parent_id = bzrlib.inventory.ROOT_ID |
|
492 |
bzr_inv.append((path, file_id, parent_id, kind)) |
|
493 |
bzr_inv.sort() |
|
494 |
return bzr_inv |
|
6
by abentley
added commit, timport, commit_test_revisions |
495 |
|
59
by Aaron Bentley
Applied John Meinel's options patch |
496 |
def main(args): |
497 |
"""Just the main() function for this script.
|
|
498 |
||
499 |
By separating it into a function, this can be called as a child from some other
|
|
500 |
script.
|
|
501 |
||
502 |
:param args: The arguments to this script. Essentially sys.argv[1:]
|
|
503 |
"""
|
|
504 |
import optparse |
|
62
by Aaron Bentley
Refactored, made version optional |
505 |
parser = optparse.OptionParser(usage='%prog [options] [VERSION] OUTDIR' |
59
by Aaron Bentley
Applied John Meinel's options patch |
506 |
'\n VERSION is the arch version to import.' |
507 |
'\n OUTDIR can be an existing directory to be updated' |
|
508 |
'\n or a new directory which will be created from scratch.') |
|
509 |
parser.add_option('--verbose', action='store_true' |
|
510 |
, help='Get chatty') |
|
511 |
||
60
by Aaron Bentley
Made symlink-skipping an option |
512 |
parser.add_option('--skip-symlinks', action="store_true", |
513 |
dest="skip_symlinks", |
|
514 |
help="Ignore any symlinks present in the Arch tree.") |
|
515 |
||
59
by Aaron Bentley
Applied John Meinel's options patch |
516 |
g = optparse.OptionGroup(parser, 'Test options', 'Options useful while testing process.') |
517 |
g.add_option('--test', action='store_true' |
|
518 |
, help='Run the self-tests and exit.') |
|
519 |
g.add_option('--dry-run', action='store_true' |
|
520 |
, help='Do the update, but don\'t copy the result to OUTDIR') |
|
521 |
g.add_option('--max-count', type='int', metavar='COUNT', default=None |
|
522 |
, help='At most, add COUNT patches.') |
|
523 |
g.add_option('--safe', action='store_false', dest='fast') |
|
524 |
g.add_option('--fast', action='store_true', default=False |
|
525 |
, help='By default the .bzr control directory will be copied, so that an error' |
|
526 |
' does not modify the original. --fast allows the directory to be renamed instead.') |
|
527 |
parser.add_option_group(g) |
|
528 |
||
529 |
(opts, args) = parser.parse_args(args) |
|
530 |
||
531 |
if opts.test: |
|
532 |
print "Running tests" |
|
533 |
import doctest |
|
534 |
nfail, ntests = doctest.testmod(verbose=opts.verbose) |
|
535 |
if nfail > 0: |
|
536 |
return 1 |
|
537 |
else: |
|
538 |
return 0 |
|
62
by Aaron Bentley
Refactored, made version optional |
539 |
if len(args) == 2: |
540 |
output_dir = os.path.realpath(args[1]) |
|
541 |
version = pybaz.Version(args[0]) |
|
542 |
elif len(args) == 1: |
|
543 |
output_dir = os.path.realpath(args[0]) |
|
544 |
version = None |
|
545 |
else: |
|
59
by Aaron Bentley
Applied John Meinel's options patch |
546 |
print 'Invalid number of arguments, try --help for more info' |
547 |
return 1 |
|
62
by Aaron Bentley
Refactored, made version optional |
548 |
|
549 |
try: |
|
550 |
||
551 |
import_version(output_dir, version, |
|
552 |
verbose=opts.verbose, fast=opts.fast, |
|
66
by Aaron Bentley
Continued symlink fix, cleaned up merge, error message |
553 |
dry_run=opts.dry_run, max_count=opts.max_count, |
554 |
skip_symlinks=opts.skip_symlinks) |
|
62
by Aaron Bentley
Refactored, made version optional |
555 |
return 0 |
556 |
except UserError, e: |
|
557 |
print e |
|
558 |
return 1 |
|
559 |
except KeyboardInterrupt: |
|
560 |
print "Aborted." |
|
561 |
return 1 |
|
59
by Aaron Bentley
Applied John Meinel's options patch |
562 |
|
563 |
||
564 |
if __name__ == '__main__': |
|
565 |
sys.exit(main(sys.argv[1:])) |
|
566 |