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 |
|
22 |
except ImportError: |
|
23 |
print "This command requires PyBaz. Please ensure that it is installed." |
|
24 |
import sys |
|
25 |
sys.exit(1) |
|
3
by abentley
Added add_file and add_dir functions |
26 |
from pybaz.backends.baz import null_cmd |
2
by abentley
Added baz2bzr file(doh!) |
27 |
import tempfile |
28 |
import os |
|
29 |
import os.path |
|
30 |
import shutil |
|
7
by abentley
Completed initial construction |
31 |
import bzrlib |
8
by abentley
Added ability to run from the commandline |
32 |
import sys |
37
by Aaron Bentley
More log fixups for baz2bzr |
33 |
import email.Utils |
11
by abentley
refactored out progress.py |
34 |
from progress import * |
2
by abentley
Added baz2bzr file(doh!) |
35 |
|
3
by abentley
Added add_file and add_dir functions |
36 |
def add_id(files, id=None): |
37 |
"""Adds an explicit id to a list of files.
|
|
38 |
||
39 |
:param files: the name of the file to add an id to
|
|
40 |
:type files: list of str
|
|
41 |
:param id: tag one file using the specified id, instead of generating id
|
|
42 |
:type id: str
|
|
43 |
"""
|
|
44 |
args = ["add-id"] |
|
45 |
if id is not None: |
|
46 |
args.extend(["--id", id]) |
|
47 |
args.extend(files) |
|
48 |
return null_cmd(args) |
|
49 |
||
2
by abentley
Added baz2bzr file(doh!) |
50 |
def test_environ(): |
51 |
"""
|
|
52 |
>>> q = test_environ()
|
|
53 |
>>> os.path.exists(q)
|
|
54 |
True
|
|
55 |
>>> os.path.exists(os.path.join(q, "home", ".arch-params"))
|
|
56 |
True
|
|
57 |
>>> teardown_environ(q)
|
|
58 |
>>> os.path.exists(q)
|
|
59 |
False
|
|
60 |
"""
|
|
61 |
tdir = tempfile.mkdtemp(prefix="baz2bzr-") |
|
62 |
os.environ["HOME"] = os.path.join(tdir, "home") |
|
63 |
os.mkdir(os.environ["HOME"]) |
|
3
by abentley
Added add_file and add_dir functions |
64 |
arch_dir = os.path.join(tdir, "archive_dir") |
65 |
pybaz.make_archive("test@example.com", arch_dir) |
|
2
by abentley
Added baz2bzr file(doh!) |
66 |
work_dir = os.path.join(tdir, "work_dir") |
67 |
os.mkdir(work_dir) |
|
68 |
os.chdir(work_dir) |
|
3
by abentley
Added add_file and add_dir functions |
69 |
pybaz.init_tree(work_dir, "test@example.com/test--test--0") |
2
by abentley
Added baz2bzr file(doh!) |
70 |
lib_dir = os.path.join(tdir, "lib_dir") |
71 |
os.mkdir(lib_dir) |
|
72 |
pybaz.register_revision_library(lib_dir) |
|
6
by abentley
added commit, timport, commit_test_revisions |
73 |
pybaz.set_my_id("Test User<test@example.org>") |
2
by abentley
Added baz2bzr file(doh!) |
74 |
return tdir |
75 |
||
5
by abentley
changed add_file, add_dir interfaces |
76 |
def add_file(path, text, id): |
3
by abentley
Added add_file and add_dir functions |
77 |
"""
|
78 |
>>> q = test_environ()
|
|
5
by abentley
changed add_file, add_dir interfaces |
79 |
>>> add_file("path with space", "text", "lalala")
|
3
by abentley
Added add_file and add_dir functions |
80 |
>>> tree = pybaz.tree_root(".")
|
81 |
>>> inv = list(tree.iter_inventory_ids(source=True, both=True))
|
|
82 |
>>> ("x_lalala", "path with space") in inv
|
|
83 |
True
|
|
84 |
>>> teardown_environ(q)
|
|
85 |
"""
|
|
86 |
file(path, "wb").write(text) |
|
5
by abentley
changed add_file, add_dir interfaces |
87 |
add_id([path], id) |
88 |
||
89 |
||
90 |
def add_dir(path, id): |
|
3
by abentley
Added add_file and add_dir functions |
91 |
"""
|
92 |
>>> q = test_environ()
|
|
5
by abentley
changed add_file, add_dir interfaces |
93 |
>>> add_dir("path with\(sp) space", "lalala")
|
3
by abentley
Added add_file and add_dir functions |
94 |
>>> tree = pybaz.tree_root(".")
|
95 |
>>> inv = list(tree.iter_inventory_ids(source=True, both=True))
|
|
4
by abentley
made test case trickier, by using pika escaping sequence in filename. |
96 |
>>> ("x_lalala", "path with\(sp) space") in inv
|
3
by abentley
Added add_file and add_dir functions |
97 |
True
|
98 |
>>> teardown_environ(q)
|
|
99 |
"""
|
|
100 |
os.mkdir(path) |
|
5
by abentley
changed add_file, add_dir interfaces |
101 |
add_id([path], id) |
3
by abentley
Added add_file and add_dir functions |
102 |
|
2
by abentley
Added baz2bzr file(doh!) |
103 |
def teardown_environ(tdir): |
104 |
os.chdir("/") |
|
105 |
shutil.rmtree(tdir) |
|
106 |
||
6
by abentley
added commit, timport, commit_test_revisions |
107 |
def timport(tree, summary): |
108 |
msg = tree.log_message() |
|
109 |
msg["summary"] = summary |
|
110 |
tree.import_(msg) |
|
111 |
||
112 |
def commit(tree, summary): |
|
113 |
"""
|
|
114 |
>>> q = test_environ()
|
|
115 |
>>> tree = pybaz.tree_root(".")
|
|
116 |
>>> timport(tree, "import")
|
|
117 |
>>> commit(tree, "commit")
|
|
118 |
>>> logs = [str(l.revision) for l in tree.iter_logs()]
|
|
119 |
>>> len(logs)
|
|
120 |
2
|
|
121 |
>>> logs[0]
|
|
122 |
'test@example.com/test--test--0--base-0'
|
|
123 |
>>> logs[1]
|
|
124 |
'test@example.com/test--test--0--patch-1'
|
|
125 |
>>> teardown_environ(q)
|
|
126 |
"""
|
|
127 |
msg = tree.log_message() |
|
128 |
msg["summary"] = summary |
|
129 |
tree.commit(msg) |
|
130 |
||
131 |
def commit_test_revisions(): |
|
132 |
"""
|
|
133 |
>>> q = test_environ()
|
|
134 |
>>> commit_test_revisions()
|
|
135 |
>>> a = pybaz.Archive("test@example.com")
|
|
136 |
>>> revisions = list(a.iter_revisions("test--test--0"))
|
|
137 |
>>> len(revisions)
|
|
7
by abentley
Completed initial construction |
138 |
3
|
139 |
>>> str(revisions[2])
|
|
140 |
'test@example.com/test--test--0--base-0'
|
|
6
by abentley
added commit, timport, commit_test_revisions |
141 |
>>> str(revisions[1])
|
7
by abentley
Completed initial construction |
142 |
'test@example.com/test--test--0--patch-1'
|
6
by abentley
added commit, timport, commit_test_revisions |
143 |
>>> str(revisions[0])
|
7
by abentley
Completed initial construction |
144 |
'test@example.com/test--test--0--patch-2'
|
6
by abentley
added commit, timport, commit_test_revisions |
145 |
>>> teardown_environ(q)
|
146 |
"""
|
|
147 |
tree = pybaz.tree_root(".") |
|
148 |
add_file("mainfile", "void main(void){}", "mainfile by aaron") |
|
149 |
timport(tree, "Created mainfile") |
|
150 |
file("mainfile", "wb").write("or something like that") |
|
151 |
commit(tree, "altered mainfile") |
|
7
by abentley
Completed initial construction |
152 |
add_file("ofile", "this is another file", "ofile by aaron") |
153 |
commit(tree, "altered mainfile") |
|
154 |
||
155 |
def version_ancestry(version): |
|
156 |
"""
|
|
157 |
>>> q = test_environ()
|
|
158 |
>>> commit_test_revisions()
|
|
159 |
>>> version = pybaz.Version("test@example.com/test--test--0")
|
|
160 |
>>> ancestors = version_ancestry(version)
|
|
161 |
>>> str(ancestors[0])
|
|
162 |
'test@example.com/test--test--0--base-0'
|
|
163 |
>>> str(ancestors[1])
|
|
164 |
'test@example.com/test--test--0--patch-1'
|
|
165 |
>>> teardown_environ(q)
|
|
166 |
"""
|
|
35
by Aaron Bentley
Fixed, and got test cases passing |
167 |
revision = version.iter_revisions(reverse=True).next() |
31
by Aaron Bentley
Further updates |
168 |
ancestors = list(revision.iter_ancestors(metoo=True)) |
169 |
ancestors.reverse() |
|
7
by abentley
Completed initial construction |
170 |
return ancestors |
171 |
||
10
by abentley
Refactored, made progress bar |
172 |
|
35
by Aaron Bentley
Fixed, and got test cases passing |
173 |
def import_version(output_dir, version, fancy=True): |
7
by abentley
Completed initial construction |
174 |
"""
|
175 |
>>> q = test_environ()
|
|
176 |
>>> result_path = os.path.join(q, "result")
|
|
177 |
>>> commit_test_revisions()
|
|
178 |
>>> version = pybaz.Version("test@example.com/test--test--0")
|
|
35
by Aaron Bentley
Fixed, and got test cases passing |
179 |
>>> import_version(result_path, version, fancy=False)
|
180 |
not fancy
|
|
181 |
....
|
|
182 |
Import complete.
|
|
7
by abentley
Completed initial construction |
183 |
>>> teardown_environ(q)
|
184 |
"""
|
|
185 |
tempdir = tempfile.mkdtemp(prefix="baz2bzr") |
|
186 |
try: |
|
35
by Aaron Bentley
Fixed, and got test cases passing |
187 |
if not fancy: |
188 |
print "not fancy" |
|
10
by abentley
Refactored, made progress bar |
189 |
for result in iter_import_version(output_dir, version, tempdir): |
35
by Aaron Bentley
Fixed, and got test cases passing |
190 |
if fancy: |
191 |
progress_bar(result) |
|
192 |
else: |
|
193 |
sys.stdout.write('.') |
|
29
by Aaron Bentley
Nicer handling of unsupported file types |
194 |
finally: |
35
by Aaron Bentley
Fixed, and got test cases passing |
195 |
if fancy: |
196 |
clear_progress_bar() |
|
197 |
else: |
|
198 |
sys.stdout.write('\n') |
|
7
by abentley
Completed initial construction |
199 |
shutil.rmtree(tempdir) |
29
by Aaron Bentley
Nicer handling of unsupported file types |
200 |
print "Import complete." |
10
by abentley
Refactored, made progress bar |
201 |
|
12
by abentley
Error early when the user specifies an output directory that already exists |
202 |
class UserError(Exception): |
203 |
def __init__(self, message): |
|
204 |
"""Exception to throw when a user makes an impossible request
|
|
205 |
:param message: The message to emit when printing this exception
|
|
206 |
:type message: string
|
|
207 |
"""
|
|
208 |
Exception.__init__(self, message) |
|
209 |
||
10
by abentley
Refactored, made progress bar |
210 |
def iter_import_version(output_dir, version, tempdir): |
211 |
revdir = None |
|
212 |
ancestors = version_ancestry(version) |
|
213 |
for i in range(len(ancestors)): |
|
214 |
revision = ancestors[i] |
|
215 |
yield Progress("revisions", i, len(ancestors)) |
|
216 |
if revdir is None: |
|
217 |
revdir = os.path.join(tempdir, "rd") |
|
218 |
baz_inv, log = get_revision(revdir, revision) |
|
219 |
branch = bzrlib.Branch(revdir, init=True) |
|
220 |
else: |
|
221 |
old = os.path.join(revdir, ".bzr") |
|
222 |
new = os.path.join(tempdir, ".bzr") |
|
223 |
os.rename(old, new) |
|
13
by abentley
Used replay to get next revision |
224 |
baz_inv, log = apply_revision(revdir, revision) |
10
by abentley
Refactored, made progress bar |
225 |
os.rename(new, old) |
226 |
branch = bzrlib.Branch(revdir) |
|
227 |
branch.set_inventory(baz_inv) |
|
37
by Aaron Bentley
More log fixups for baz2bzr |
228 |
timestamp = email.Utils.mktime_tz(log.date + (0,)) |
36
by Aaron Bentley
Improved converted log output |
229 |
|
37
by Aaron Bentley
More log fixups for baz2bzr |
230 |
branch.commit(log.summary, verbose=False, |
231 |
committer=log.creator, timestamp=timestamp, timezone=0) |
|
10
by abentley
Refactored, made progress bar |
232 |
yield Progress("revisions", len(ancestors), len(ancestors)) |
233 |
unlink_unversioned(branch, revdir) |
|
234 |
os.rename(revdir, output_dir) |
|
235 |
||
236 |
def unlink_unversioned(branch, revdir): |
|
237 |
for unversioned in branch.working_tree().extras(): |
|
238 |
path = os.path.join(revdir, unversioned) |
|
239 |
if os.path.isdir(path): |
|
240 |
shutil.rmtree(path) |
|
241 |
else: |
|
242 |
os.unlink(path) |
|
7
by abentley
Completed initial construction |
243 |
|
37
by Aaron Bentley
More log fixups for baz2bzr |
244 |
def get_log(tree, revision): |
245 |
log = tree.iter_logs(version=revision.version, reverse=True).next() |
|
246 |
assert log.revision == revision |
|
247 |
return log |
|
248 |
||
7
by abentley
Completed initial construction |
249 |
def get_revision(revdir, revision): |
250 |
revision.get(revdir) |
|
251 |
tree = pybaz.tree_root(revdir) |
|
37
by Aaron Bentley
More log fixups for baz2bzr |
252 |
log = get_log(tree, revision) |
29
by Aaron Bentley
Nicer handling of unsupported file types |
253 |
try: |
254 |
return bzr_inventory_data(tree), log |
|
255 |
except BadFileKind, e: |
|
256 |
raise UserError("Cannot convert %s because %s is a %s" % (revision,e.path, e.kind) ) |
|
257 |
||
7
by abentley
Completed initial construction |
258 |
|
13
by abentley
Used replay to get next revision |
259 |
def apply_revision(revdir, revision): |
260 |
tree = pybaz.tree_root(revdir) |
|
261 |
revision.apply(tree) |
|
37
by Aaron Bentley
More log fixups for baz2bzr |
262 |
log = get_log(tree, revision) |
29
by Aaron Bentley
Nicer handling of unsupported file types |
263 |
try: |
264 |
return bzr_inventory_data(tree), log |
|
265 |
except BadFileKind, e: |
|
266 |
raise UserError("Cannot convert %s because %s is a %s" % (revision,e.path, e.kind) ) |
|
267 |
||
268 |
||
269 |
||
270 |
||
271 |
class BadFileKind(Exception): |
|
272 |
"""The file kind is not permitted in bzr inventories"""
|
|
273 |
def __init__(self, tree_root, path, kind): |
|
274 |
self.tree_root = tree_root |
|
275 |
self.path = path |
|
276 |
self.kind = kind |
|
277 |
Exception.__init__(self, "File %s is of forbidden type %s" % |
|
278 |
(os.path.join(tree_root, path), kind)) |
|
13
by abentley
Used replay to get next revision |
279 |
|
7
by abentley
Completed initial construction |
280 |
def bzr_inventory_data(tree): |
281 |
inv_iter = tree.iter_inventory_ids(source=True, both=True) |
|
282 |
inv_map = {} |
|
283 |
for file_id, path in inv_iter: |
|
8
by abentley
Added ability to run from the commandline |
284 |
inv_map[path] = file_id |
7
by abentley
Completed initial construction |
285 |
|
286 |
bzr_inv = [] |
|
8
by abentley
Added ability to run from the commandline |
287 |
for path, file_id in inv_map.iteritems(): |
29
by Aaron Bentley
Nicer handling of unsupported file types |
288 |
full_path = os.path.join(tree, path) |
289 |
kind = bzrlib.osutils.file_kind(full_path) |
|
290 |
if kind not in ("file", "directory"): |
|
291 |
raise BadFileKind(tree, path, kind) |
|
7
by abentley
Completed initial construction |
292 |
parent_dir = os.path.dirname(path) |
293 |
if parent_dir != "": |
|
294 |
parent_id = inv_map[parent_dir] |
|
295 |
else: |
|
296 |
parent_id = bzrlib.inventory.ROOT_ID |
|
297 |
bzr_inv.append((path, file_id, parent_id, kind)) |
|
298 |
bzr_inv.sort() |
|
299 |
return bzr_inv |
|
6
by abentley
added commit, timport, commit_test_revisions |
300 |
|
8
by abentley
Added ability to run from the commandline |
301 |
if len(sys.argv) == 2 and sys.argv[1] == "test": |
302 |
print "Running tests" |
|
303 |
import doctest |
|
304 |
doctest.testmod() |
|
305 |
elif len(sys.argv) == 3: |
|
12
by abentley
Error early when the user specifies an output directory that already exists |
306 |
try: |
307 |
output_dir = sys.argv[2] |
|
308 |
if os.path.exists(output_dir): |
|
309 |
raise UserError("Directory \"%s\" already exists" % output_dir) |
|
310 |
import_version(output_dir, pybaz.Version(sys.argv[1])) |
|
311 |
except UserError, e: |
|
312 |
print e |
|
8
by abentley
Added ability to run from the commandline |
313 |
else: |
314 |
print "usage: %s VERSION OUTDIR" % os.path.basename(sys.argv[0]) |