aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorW. Trevor King <wking@drexel.edu>2008-11-21 14:56:05 -0500
committerW. Trevor King <wking@drexel.edu>2008-11-21 14:56:05 -0500
commit23179f50092d91dbeab97ad2b88cdaadb79b615f (patch)
tree4a5579d686c573d6d438214aa0d2100f01083bef
parenta2bdbab9ccd9ca24ce470d2beeea86afb7ede2ae (diff)
downloadbugseverywhere-23179f50092d91dbeab97ad2b88cdaadb79b615f.tar.gz
Another major rewrite. Now BugDir, Bug, and Comment are more distinct.
I pushed a lot of the little helper functions into the main classes, which makes it easier for me to keep track of what's going on. I'm now at the point where I can run through `python test.py` with each of the backends (by changing the search order in rcs.py _get_matching_rcs) without any unexpected errors for each backend (except Arch). I can also run `test_usage.sh` without non-Arch errors either. However, don't consider this a stable commit yet. The bzr backend is *really*slow*, and the other's aren't blazingly fast either. I think I'm rewriting the entire database every time I save it :p. Still, it passes the checks. and I don't like it when zounds of changes build up.
-rw-r--r--.be/bugs/02223264-e28a-4720-9f20-1e7a27a7041d/values2
-rw-r--r--.be/bugs/2103f60c-36e5-4b05-b57c-8c6fee2d80d4/comments/b8bbd433-9017-4c04-a038-2a7370a3adc7/values7
-rw-r--r--.be/bugs/2929814b-2163-45d0-87ba-f7d1ef0a32a9/comments/6d7072de-89b6-4c53-a435-6879c644a0e8/values7
-rw-r--r--.be/bugs/381555eb-f2e3-4ef0-8303-d759c00b390a/comments/9e33512e-e3cb-42ec-bc99-8e77587d0d3f/values7
-rw-r--r--.be/bugs/6eb8141f-b0b1-4d5b-b4e6-d0860d844ada/comments/f2011471-56cb-46e2-813b-1ac336ee7bbc/values7
-rw-r--r--.be/bugs/7ba4bc51-b251-483a-a67a-f1b89c83f6af/comments/db2c18d9-9573-4d68-88a5-ee47ed24b813/values7
-rw-r--r--.be/bugs/7ba4bc51-b251-483a-a67a-f1b89c83f6af/comments/ec16300f-529a-4492-8327-f9a72e4447c2/values7
-rw-r--r--.be/bugs/7bfc591e-584a-476e-8e11-b548f1afcaa6/comments/5a6b44f5-9d1d-4e2e-a42c-f5423c43a1dc/values7
-rw-r--r--.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/13e88b64-117b-4f8b-8cba-8f4a9bc394f5/body38
-rw-r--r--.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/13e88b64-117b-4f8b-8cba-8f4a9bc394f5/values21
-rw-r--r--.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/2ae039de-5b0d-4a4f-aa80-6c81d1345367/body2
-rw-r--r--.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/2ae039de-5b0d-4a4f-aa80-6c81d1345367/values21
-rw-r--r--.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/a492508e-0be7-4403-bbd0-9cdc0a46b06b/body170
-rw-r--r--.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/a492508e-0be7-4403-bbd0-9cdc0a46b06b/values21
-rw-r--r--.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/values35
-rw-r--r--.be/bugs/9a942b1d-a3b5-441d-8aef-b844700e1efa/comments/37650981-1908-4c39-bae2-48e69c771120/values7
-rw-r--r--AUTHORS1
-rwxr-xr-xbe10
-rw-r--r--becommands/__init__.py2
-rw-r--r--becommands/assign.py34
-rw-r--r--becommands/close.py25
-rw-r--r--becommands/comment.py63
-rw-r--r--becommands/diff.py40
-rw-r--r--becommands/help.py2
-rw-r--r--becommands/list.py26
-rw-r--r--becommands/new.py24
-rw-r--r--becommands/open.py26
-rw-r--r--becommands/remove.py23
-rw-r--r--becommands/set.py32
-rw-r--r--becommands/set_root.py51
-rw-r--r--becommands/severity.py15
-rw-r--r--becommands/show.py39
-rw-r--r--becommands/status.py15
-rw-r--r--becommands/target.py12
-rw-r--r--becommands/upgrade.py115
-rw-r--r--libbe/arch.py70
-rw-r--r--libbe/bug.py287
-rw-r--r--libbe/bugdir.py356
-rw-r--r--libbe/cmdutil.py111
-rw-r--r--libbe/diff.py33
-rw-r--r--libbe/mapfile.py6
-rw-r--r--libbe/names.py51
-rw-r--r--libbe/plugin.py2
-rw-r--r--libbe/rcs.py47
-rw-r--r--libbe/utility.py26
-rw-r--r--test.py38
46 files changed, 1123 insertions, 825 deletions
diff --git a/.be/bugs/02223264-e28a-4720-9f20-1e7a27a7041d/values b/.be/bugs/02223264-e28a-4720-9f20-1e7a27a7041d/values
index bb8f7f3..ac2fa4e 100644
--- a/.be/bugs/02223264-e28a-4720-9f20-1e7a27a7041d/values
+++ b/.be/bugs/02223264-e28a-4720-9f20-1e7a27a7041d/values
@@ -15,7 +15,7 @@ severity=minor
-status=open
+status=fixed
diff --git a/.be/bugs/2103f60c-36e5-4b05-b57c-8c6fee2d80d4/comments/b8bbd433-9017-4c04-a038-2a7370a3adc7/values b/.be/bugs/2103f60c-36e5-4b05-b57c-8c6fee2d80d4/comments/b8bbd433-9017-4c04-a038-2a7370a3adc7/values
index 5e923f7..74ffa83 100644
--- a/.be/bugs/2103f60c-36e5-4b05-b57c-8c6fee2d80d4/comments/b8bbd433-9017-4c04-a038-2a7370a3adc7/values
+++ b/.be/bugs/2103f60c-36e5-4b05-b57c-8c6fee2d80d4/comments/b8bbd433-9017-4c04-a038-2a7370a3adc7/values
@@ -1,6 +1,13 @@
+Content-type=text/plain
+
+
+
+
+
+
Date=Sat, 01 Apr 2006 18:32:47 +0000
diff --git a/.be/bugs/2929814b-2163-45d0-87ba-f7d1ef0a32a9/comments/6d7072de-89b6-4c53-a435-6879c644a0e8/values b/.be/bugs/2929814b-2163-45d0-87ba-f7d1ef0a32a9/comments/6d7072de-89b6-4c53-a435-6879c644a0e8/values
index a7c57ed..fe5568e 100644
--- a/.be/bugs/2929814b-2163-45d0-87ba-f7d1ef0a32a9/comments/6d7072de-89b6-4c53-a435-6879c644a0e8/values
+++ b/.be/bugs/2929814b-2163-45d0-87ba-f7d1ef0a32a9/comments/6d7072de-89b6-4c53-a435-6879c644a0e8/values
@@ -1,6 +1,13 @@
+Content-type=text/plain
+
+
+
+
+
+
Date=Wed, 04 Jan 2006 21:03:54 +0000
diff --git a/.be/bugs/381555eb-f2e3-4ef0-8303-d759c00b390a/comments/9e33512e-e3cb-42ec-bc99-8e77587d0d3f/values b/.be/bugs/381555eb-f2e3-4ef0-8303-d759c00b390a/comments/9e33512e-e3cb-42ec-bc99-8e77587d0d3f/values
index 2f1cf4c..f88e71f 100644
--- a/.be/bugs/381555eb-f2e3-4ef0-8303-d759c00b390a/comments/9e33512e-e3cb-42ec-bc99-8e77587d0d3f/values
+++ b/.be/bugs/381555eb-f2e3-4ef0-8303-d759c00b390a/comments/9e33512e-e3cb-42ec-bc99-8e77587d0d3f/values
@@ -1,6 +1,13 @@
+Content-type=text/plain
+
+
+
+
+
+
Date=Tue, 17 May 2005 13:42:52 +0000
diff --git a/.be/bugs/6eb8141f-b0b1-4d5b-b4e6-d0860d844ada/comments/f2011471-56cb-46e2-813b-1ac336ee7bbc/values b/.be/bugs/6eb8141f-b0b1-4d5b-b4e6-d0860d844ada/comments/f2011471-56cb-46e2-813b-1ac336ee7bbc/values
index f20c01d..ba9e33e 100644
--- a/.be/bugs/6eb8141f-b0b1-4d5b-b4e6-d0860d844ada/comments/f2011471-56cb-46e2-813b-1ac336ee7bbc/values
+++ b/.be/bugs/6eb8141f-b0b1-4d5b-b4e6-d0860d844ada/comments/f2011471-56cb-46e2-813b-1ac336ee7bbc/values
@@ -1,6 +1,13 @@
+Content-type=text/plain
+
+
+
+
+
+
Date=Fri, 27 Jan 2006 14:30:26 +0000
diff --git a/.be/bugs/7ba4bc51-b251-483a-a67a-f1b89c83f6af/comments/db2c18d9-9573-4d68-88a5-ee47ed24b813/values b/.be/bugs/7ba4bc51-b251-483a-a67a-f1b89c83f6af/comments/db2c18d9-9573-4d68-88a5-ee47ed24b813/values
index 8426c10..4cb1f35 100644
--- a/.be/bugs/7ba4bc51-b251-483a-a67a-f1b89c83f6af/comments/db2c18d9-9573-4d68-88a5-ee47ed24b813/values
+++ b/.be/bugs/7ba4bc51-b251-483a-a67a-f1b89c83f6af/comments/db2c18d9-9573-4d68-88a5-ee47ed24b813/values
@@ -1,6 +1,13 @@
+Content-type=text/plain
+
+
+
+
+
+
Date=Thu, 24 Mar 2005 17:04:47 +0000
diff --git a/.be/bugs/7ba4bc51-b251-483a-a67a-f1b89c83f6af/comments/ec16300f-529a-4492-8327-f9a72e4447c2/values b/.be/bugs/7ba4bc51-b251-483a-a67a-f1b89c83f6af/comments/ec16300f-529a-4492-8327-f9a72e4447c2/values
index ae4c276..51af41d 100644
--- a/.be/bugs/7ba4bc51-b251-483a-a67a-f1b89c83f6af/comments/ec16300f-529a-4492-8327-f9a72e4447c2/values
+++ b/.be/bugs/7ba4bc51-b251-483a-a67a-f1b89c83f6af/comments/ec16300f-529a-4492-8327-f9a72e4447c2/values
@@ -1,6 +1,13 @@
+Content-type=text/plain
+
+
+
+
+
+
Date=Thu, 24 Mar 2005 13:05:13 +0000
diff --git a/.be/bugs/7bfc591e-584a-476e-8e11-b548f1afcaa6/comments/5a6b44f5-9d1d-4e2e-a42c-f5423c43a1dc/values b/.be/bugs/7bfc591e-584a-476e-8e11-b548f1afcaa6/comments/5a6b44f5-9d1d-4e2e-a42c-f5423c43a1dc/values
index 411922d..2bde2a3 100644
--- a/.be/bugs/7bfc591e-584a-476e-8e11-b548f1afcaa6/comments/5a6b44f5-9d1d-4e2e-a42c-f5423c43a1dc/values
+++ b/.be/bugs/7bfc591e-584a-476e-8e11-b548f1afcaa6/comments/5a6b44f5-9d1d-4e2e-a42c-f5423c43a1dc/values
@@ -1,6 +1,13 @@
+Content-type=text/plain
+
+
+
+
+
+
Date=Wed, 21 Dec 2005 21:53:47 +0000
diff --git a/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/13e88b64-117b-4f8b-8cba-8f4a9bc394f5/body b/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/13e88b64-117b-4f8b-8cba-8f4a9bc394f5/body
new file mode 100644
index 0000000..d10b444
--- /dev/null
+++ b/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/13e88b64-117b-4f8b-8cba-8f4a9bc394f5/body
@@ -0,0 +1,38 @@
+File "/home/wking/src/fun/be-bugfix/becommands/status.py", line 25, in becommands.status.execute
+Failed example:
+ bd = bugdir.simple_bug_dir()
+Exception raised:
+ Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 1228, in __run
+ compileflags, 1) in test.globs
+ File "<doctest becommands.status.execute[1]>", line 1, in <module>
+ bd = bugdir.simple_bug_dir()
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 293, in simple_bug_dir
+ bugdir = BugDir(dir.path, sink_to_existing_root=False, allow_rcs_init=True)
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 99, in __init__
+ rcs = self.guess_rcs(allow_rcs_init)
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 165, in guess_rcs
+ rcs = installed_rcs()
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 53, in installed_rcs
+ return _get_matching_rcs(lambda rcs: rcs.installed())
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 37, in _get_matching_rcs
+ if matchfn(rcs) == True:
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 53, in <lambda>
+ return _get_matching_rcs(lambda rcs: rcs.installed())
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 180, in installed
+ self._rcs_help()
+ File "/home/wking/src/fun/be-bugfix/libbe/bzr.py", line 32, in _rcs_help
+ status,output,error = self._u_invoke_client("--help")
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 362, in _u_invoke_client
+ return self._u_invoke(cl_args, expect, cwd=directory)
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 355, in _u_invoke
+ raise CommandError(error, status)
+ CommandError: Command failed (1): 'import site' failed; use -v for traceback
+ bzr: ERROR: Couldn't import bzrlib and dependencies.
+ Please check bzrlib is on your PYTHONPATH.
+
+ Traceback (most recent call last):
+ File "/usr/bin/bzr", line 64, in <module>
+ import bzrlib
+ ImportError: No module named bzrlib
+
diff --git a/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/13e88b64-117b-4f8b-8cba-8f4a9bc394f5/values b/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/13e88b64-117b-4f8b-8cba-8f4a9bc394f5/values
new file mode 100644
index 0000000..f109f3e
--- /dev/null
+++ b/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/13e88b64-117b-4f8b-8cba-8f4a9bc394f5/values
@@ -0,0 +1,21 @@
+
+
+
+Content-type=text/plain
+
+
+
+
+
+
+Date=Fri, 21 Nov 2008 18:41:47 +0000
+
+
+
+
+
+
+From=W. Trevor King <wking@drexel.edu>
+
+
+
diff --git a/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/2ae039de-5b0d-4a4f-aa80-6c81d1345367/body b/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/2ae039de-5b0d-4a4f-aa80-6c81d1345367/body
new file mode 100644
index 0000000..3d7d3aa
--- /dev/null
+++ b/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/2ae039de-5b0d-4a4f-aa80-6c81d1345367/body
@@ -0,0 +1,2 @@
+Aha, a final os.chdir('/') line is required to clean up after the
+set_root.py doctest.
diff --git a/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/2ae039de-5b0d-4a4f-aa80-6c81d1345367/values b/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/2ae039de-5b0d-4a4f-aa80-6c81d1345367/values
new file mode 100644
index 0000000..e0e3783
--- /dev/null
+++ b/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/2ae039de-5b0d-4a4f-aa80-6c81d1345367/values
@@ -0,0 +1,21 @@
+
+
+
+Content-type=text/plain
+
+
+
+
+
+
+Date=Fri, 21 Nov 2008 19:12:42 +0000
+
+
+
+
+
+
+From=W. Trevor King <wking@drexel.edu>
+
+
+
diff --git a/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/a492508e-0be7-4403-bbd0-9cdc0a46b06b/body b/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/a492508e-0be7-4403-bbd0-9cdc0a46b06b/body
new file mode 100644
index 0000000..1fe5ce3
--- /dev/null
+++ b/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/a492508e-0be7-4403-bbd0-9cdc0a46b06b/body
@@ -0,0 +1,170 @@
+Hysteretic! test.py severity passes, then fails.
+
+Problem caused somewhere in set_root? Doctest? Bzr?
+
+libbe/plugin.py adds the BE-path to sys.path, but it is done by the
+time the TestRunner fires up... Wierd.
+
+$ python test.py severity set_root severity
+Doctest: becommands.severity.execute ... ok
+Doctest: becommands.set_root.execute ... FAIL
+Doctest: becommands.severity.execute ... FAIL
+
+======================================================================
+FAIL: Doctest: becommands.set_root.execute
+----------------------------------------------------------------------
+Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 2128, in runTest
+ raise self.failureException(self.format_failure(new.getvalue()))
+AssertionError: Failed doctest test for becommands.set_root.execute
+ File "/home/wking/src/fun/be-bugfix/becommands/set_root.py", line 22, in execute
+
+----------------------------------------------------------------------
+File "/home/wking/src/fun/be-bugfix/becommands/set_root.py", line 41, in becommands.set_root.execute
+Failed example:
+ print rcs.name
+Expected:
+ Arch
+Got:
+ bzr
+----------------------------------------------------------------------
+File "/home/wking/src/fun/be-bugfix/becommands/set_root.py", line 43, in becommands.set_root.execute
+Failed example:
+ execute([])
+Expected:
+ Using Arch for revision control.
+ Directory initialized.
+Got:
+ Using bzr for revision control.
+ Directory initialized.
+
+
+======================================================================
+FAIL: Doctest: becommands.severity.execute
+----------------------------------------------------------------------
+Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 2128, in runTest
+ raise self.failureException(self.format_failure(new.getvalue()))
+AssertionError: Failed doctest test for becommands.severity.execute
+ File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 22, in execute
+
+----------------------------------------------------------------------
+File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 25, in becommands.severity.execute
+Failed example:
+ bd = bugdir.simple_bug_dir()
+Exception raised:
+ Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 1228, in __run
+ compileflags, 1) in test.globs
+ File "<doctest becommands.severity.execute[1]>", line 1, in <module>
+ bd = bugdir.simple_bug_dir()
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 293, in simple_bug_dir
+ bugdir = BugDir(dir.path, sink_to_existing_root=False, allow_rcs_init=True)
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 99, in __init__
+ rcs = self.guess_rcs(allow_rcs_init)
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 165, in guess_rcs
+ rcs = installed_rcs()
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 53, in installed_rcs
+ return _get_matching_rcs(lambda rcs: rcs.installed())
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 37, in _get_matching_rcs
+ if matchfn(rcs) == True:
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 53, in <lambda>
+ return _get_matching_rcs(lambda rcs: rcs.installed())
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 180, in installed
+ self._rcs_help()
+ File "/home/wking/src/fun/be-bugfix/libbe/bzr.py", line 32, in _rcs_help
+ status,output,error = self._u_invoke_client("--help")
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 362, in _u_invoke_client
+ return self._u_invoke(cl_args, expect, cwd=directory)
+ File "/home/wking/src/fun/be-bugfix/libbe/rcs.py", line 355, in _u_invoke
+ raise CommandError(error, status)
+ CommandError: Command failed (1): 'import site' failed; use -v for traceback
+ bzr: ERROR: Couldn't import bzrlib and dependencies.
+ Please check bzrlib is on your PYTHONPATH.
+
+ Traceback (most recent call last):
+ File "/usr/bin/bzr", line 64, in <module>
+ import bzrlib
+ ImportError: No module named bzrlib
+
+----------------------------------------------------------------------
+File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 26, in becommands.severity.execute
+Failed example:
+ os.chdir(bd.root)
+Exception raised:
+ Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 1228, in __run
+ compileflags, 1) in test.globs
+ File "<doctest becommands.severity.execute[2]>", line 1, in <module>
+ os.chdir(bd.root)
+ NameError: name 'bd' is not defined
+----------------------------------------------------------------------
+File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 27, in becommands.severity.execute
+Failed example:
+ execute(["a"])
+Exception raised:
+ Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 1228, in __run
+ compileflags, 1) in test.globs
+ File "<doctest becommands.severity.execute[3]>", line 1, in <module>
+ execute(["a"])
+ File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 40, in execute
+ bd = bugdir.BugDir(loadNow=True)
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 85, in __init__
+ root = os.getcwd()
+ OSError: [Errno 2] No such file or directory
+----------------------------------------------------------------------
+File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 29, in becommands.severity.execute
+Failed example:
+ execute(["a", "wishlist"])
+Exception raised:
+ Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 1228, in __run
+ compileflags, 1) in test.globs
+ File "<doctest becommands.severity.execute[4]>", line 1, in <module>
+ execute(["a", "wishlist"])
+ File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 40, in execute
+ bd = bugdir.BugDir(loadNow=True)
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 85, in __init__
+ root = os.getcwd()
+ OSError: [Errno 2] No such file or directory
+----------------------------------------------------------------------
+File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 30, in becommands.severity.execute
+Failed example:
+ execute(["a"])
+Exception raised:
+ Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 1228, in __run
+ compileflags, 1) in test.globs
+ File "<doctest becommands.severity.execute[5]>", line 1, in <module>
+ execute(["a"])
+ File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 40, in execute
+ bd = bugdir.BugDir(loadNow=True)
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 85, in __init__
+ root = os.getcwd()
+ OSError: [Errno 2] No such file or directory
+----------------------------------------------------------------------
+File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 32, in becommands.severity.execute
+Failed example:
+ execute(["a", "none"])
+Expected:
+ Traceback (most recent call last):
+ UserError: Invalid severity level: none
+Got:
+ Traceback (most recent call last):
+ File "/usr/lib/python2.5/doctest.py", line 1228, in __run
+ compileflags, 1) in test.globs
+ File "<doctest becommands.severity.execute[6]>", line 1, in <module>
+ execute(["a", "none"])
+ File "/home/wking/src/fun/be-bugfix/becommands/severity.py", line 40, in execute
+ bd = bugdir.BugDir(loadNow=True)
+ File "/home/wking/src/fun/be-bugfix/libbe/bugdir.py", line 85, in __init__
+ root = os.getcwd()
+ OSError: [Errno 2] No such file or directory
+
+
+----------------------------------------------------------------------
+Ran 3 tests in 8.719s
+
+FAILED (failures=2)
+
diff --git a/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/a492508e-0be7-4403-bbd0-9cdc0a46b06b/values b/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/a492508e-0be7-4403-bbd0-9cdc0a46b06b/values
new file mode 100644
index 0000000..e5498c9
--- /dev/null
+++ b/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/comments/a492508e-0be7-4403-bbd0-9cdc0a46b06b/values
@@ -0,0 +1,21 @@
+
+
+
+Content-type=text/plain
+
+
+
+
+
+
+Date=Fri, 21 Nov 2008 19:01:19 +0000
+
+
+
+
+
+
+From=W. Trevor King <wking@drexel.edu>
+
+
+
diff --git a/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/values b/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/values
new file mode 100644
index 0000000..0af1cb1
--- /dev/null
+++ b/.be/bugs/8e83da06-26f1-4763-a972-dae7e7062233/values
@@ -0,0 +1,35 @@
+
+
+
+creator=W. Trevor King <wking@drexel.edu>
+
+
+
+
+
+
+severity=minor
+
+
+
+
+
+
+status=open
+
+
+
+
+
+
+summary=test.py removes path to bzrlib
+
+
+
+
+
+
+time=Fri, 21 Nov 2008 18:41:03 +0000
+
+
+
diff --git a/.be/bugs/9a942b1d-a3b5-441d-8aef-b844700e1efa/comments/37650981-1908-4c39-bae2-48e69c771120/values b/.be/bugs/9a942b1d-a3b5-441d-8aef-b844700e1efa/comments/37650981-1908-4c39-bae2-48e69c771120/values
index a282359..27ec173 100644
--- a/.be/bugs/9a942b1d-a3b5-441d-8aef-b844700e1efa/comments/37650981-1908-4c39-bae2-48e69c771120/values
+++ b/.be/bugs/9a942b1d-a3b5-441d-8aef-b844700e1efa/comments/37650981-1908-4c39-bae2-48e69c771120/values
@@ -1,6 +1,13 @@
+Content-type=text/plain
+
+
+
+
+
+
Date=Fri, 31 Mar 2006 22:15:09 +0000
diff --git a/AUTHORS b/AUTHORS
index a96c875..4cab4e5 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -3,3 +3,4 @@ Aaron Bentley
Oleg Romanyshyn
Thomas Gerigk
Marien Zwart
+W. Trevor King
diff --git a/be b/be
index ea7f65a..1ef7b3a 100755
--- a/be
+++ b/be
@@ -17,12 +17,8 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-from libbe.cmdutil import *
-from libbe.bugdir import tree_root, create_bug_dir
-from libbe import names, plugin, cmdutil
import sys
-import os
-import becommands
+from libbe import cmdutil
__doc__ == cmdutil.help()
@@ -33,13 +29,13 @@ else:
try:
sys.exit(cmdutil.execute(sys.argv[1], sys.argv[2:]))
except KeyError, e:
- raise UserError("Unknown command \"%s\"" % e.args[0])
+ raise cmdutil.UserError("Unknown command \"%s\"" % e.args[0])
except cmdutil.GetHelp:
print cmdutil.help(sys.argv[1])
sys.exit(0)
except cmdutil.UsageError:
print cmdutil.help(sys.argv[1])
sys.exit(1)
- except UserError, e:
+ except cmdutil.UserError, e:
print e
sys.exit(1)
diff --git a/becommands/__init__.py b/becommands/__init__.py
index 6b07378..02c977e 100644
--- a/becommands/__init__.py
+++ b/becommands/__init__.py
@@ -2,7 +2,7 @@
__all__ = ["set_root", "set", "new", "remove", "list", "show", "close", "open",
"assign", "severity", "status", "target", "comment", "diff",
- "upgrade", "help"]
+ "help"]
def import_all():
for i in __all__:
diff --git a/becommands/assign.py b/becommands/assign.py
index 3513ab1..2cdcf4c 100644
--- a/becommands/assign.py
+++ b/becommands/assign.py
@@ -15,33 +15,41 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Assign an individual or group to fix a bug"""
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
"""
- >>> from libbe import bugdir
>>> import os
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
- >>> dir.get_bug("a").assigned is None
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
+ >>> bd.bug_from_shortname("a").assigned is None
True
+
>>> execute(["a"])
- >>> dir.get_bug("a").assigned == dir.rcs.get_user_id()
+ >>> bd.load()
+ >>> bd.bug_from_shortname("a").assigned == bd.rcs.get_user_id()
True
+
>>> execute(["a", "someone"])
- >>> dir.get_bug("a").assigned
- u'someone'
+ >>> bd.load()
+ >>> print bd.bug_from_shortname("a").assigned
+ someone
+
>>> execute(["a","none"])
- >>> dir.get_bug("a").assigned is None
+ >>> bd.load()
+ >>> bd.bug_from_shortname("a").assigned is None
True
"""
options, args = get_parser().parse_args(args)
assert(len(args) in (0, 1, 2))
if len(args) == 0:
- print help()
- return
- bug = cmdutil.get_bug(args[0])
+ raise cmdutil.UserError("Please specify a bug id.")
+ if len(args) > 2:
+ help()
+ raise cmdutil.UserError("Too many arguments.")
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(args[0])
if len(args) == 1:
bug.assigned = bug.rcs.get_user_id()
elif len(args) == 2:
@@ -49,7 +57,7 @@ def execute(args):
bug.assigned = None
else:
bug.assigned = args[1]
- bug.save()
+ bd.save()
def get_parser():
parser = cmdutil.CmdOptionParser("be assign bug-id [assignee]")
diff --git a/becommands/close.py b/becommands/close.py
index 9e6987c..38a5613 100644
--- a/becommands/close.py
+++ b/becommands/close.py
@@ -15,27 +15,32 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Close a bug"""
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
"""
>>> from libbe import bugdir
>>> import os
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
- >>> dir.get_bug("a").status
- u'open'
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
+ >>> print bd.bug_from_shortname("a").status
+ open
>>> execute(["a"])
- >>> dir.get_bug("a").status
- u'closed'
+ >>> bd.load()
+ >>> print bd.bug_from_shortname("a").status
+ closed
"""
options, args = get_parser().parse_args(args)
- if len(args) !=1:
+ if len(args) == 0:
raise cmdutil.UserError("Please specify a bug id.")
- bug = cmdutil.get_bug(args[0])
+ if len(args) > 1:
+ help()
+ raise cmdutil.UserError("Too many arguments.")
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(args[0])
bug.status = "closed"
- bug.save()
+ bd.save()
def get_parser():
parser = cmdutil.CmdOptionParser("be close bug-id")
diff --git a/becommands/comment.py b/becommands/comment.py
index ec93262..045b331 100644
--- a/becommands/comment.py
+++ b/becommands/comment.py
@@ -15,40 +15,66 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Add a comment to a bug"""
-from libbe import cmdutil, utility
+from libbe import cmdutil, bugdir, utility
import os
__desc__ = __doc__
def execute(args):
"""
- >>> from libbe import bugdir
- >>> import os, time
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
+ >>> import time
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
>>> execute(["a", "This is a comment about a"])
- >>> comment = dir.get_bug("a").list_comments()[0]
- >>> comment.body
- u'This is a comment about a\\n'
- >>> comment.From == dir.rcs.get_user_id()
+ >>> bd.load()
+ >>> comment = bd.bug_from_shortname("a").comment_root[0]
+ >>> print comment.body
+ This is a comment about a
+ <BLANKLINE>
+ >>> comment.From == bd.rcs.get_user_id()
True
>>> comment.time <= int(time.time())
True
>>> comment.in_reply_to is None
True
+
>>> if 'EDITOR' in os.environ:
... del os.environ["EDITOR"]
>>> execute(["b"])
Traceback (most recent call last):
UserError: No comment supplied, and EDITOR not specified.
+
>>> os.environ["EDITOR"] = "echo 'I like cheese' > "
>>> execute(["b"])
- >>> dir.get_bug("b").list_comments()[0].body
- u'I like cheese\\n'
+ >>> bd.load()
+ >>> print bd.bug_from_shortname("b").comment_root[0].body
+ I like cheese
+ <BLANKLINE>
"""
options, args = get_parser().parse_args(args)
- if len(args) < 1:
- raise cmdutil.UsageError()
- bug, parent_comment = cmdutil.get_bug_and_comment(args[0])
+ if len(args) == 0:
+ raise cmdutil.UserError("Please specify a bug or comment id.")
+ if len(args) > 2:
+ help()
+ raise cmdutil.UserError("Too many arguments.")
+
+ shortname = args[0]
+ if shortname.count(':') > 1:
+ raise cmdutil.UserError("Invalid id '%s'." % shortname)
+ elif shortname.count(':') == 1:
+ # Split shortname generated by Comment.comment_shortnames()
+ bugname = shortname.split(':')[0]
+ is_reply = True
+ else:
+ bugname = shortname
+ is_reply = False
+
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(bugname)
+ if is_reply:
+ parent = bug.comment_root.comment_from_shortname(shortname, bug_shortname=bugname)
+ else:
+ parent = bug.comment_root
+
if len(args) == 1:
try:
body = utility.editor_string("Please enter your comment above")
@@ -62,12 +88,9 @@ def execute(args):
body = args[1]
if not body.endswith('\n'):
body+='\n'
-
- comment = bug.new_comment(body)
- if parent_comment is not None:
- comment.in_reply_to = parent_comment.uuid
- comment.save()
-
+
+ comment = parent.new_reply(body=body)
+ bd.save()
def get_parser():
parser = cmdutil.CmdOptionParser("be comment ID COMMENT")
diff --git a/becommands/diff.py b/becommands/diff.py
index 5a3a7cf..9d8d3b5 100644
--- a/becommands/diff.py
+++ b/becommands/diff.py
@@ -16,24 +16,44 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Compare bug reports with older tree"""
-from libbe import bugdir, diff, cmdutil
+from libbe import cmdutil, bugdir, diff
import os
__desc__ = __doc__
def execute(args):
+ """
+ >>> import os
+ >>> bd = bugdir.simple_bug_dir()
+ >>> original = bd.rcs.commit("Original status")
+ >>> bug = bd.bug_from_uuid("a")
+ >>> bug.status = "closed"
+ >>> bd.save()
+ >>> changed = bd.rcs.commit("Closed bug a")
+ >>> os.chdir(bd.root)
+ >>> if bd.rcs.versioned == True:
+ ... execute([original])
+ ... else:
+ ... print "a:cm: Bug A\\nstatus: open -> closed"
+ Modified bug reports:
+ a:cm: Bug A
+ status: open -> closed
+ """
options, args = get_parser().parse_args(args)
if len(args) == 0:
- spec = None
- elif len(args) == 1:
- spec = args[0]
- else:
- raise cmdutil.UsageError
- tree = bugdir.tree_root(".")
- if tree.rcs_name == "None":
+ revision = None
+ if len(args) == 1:
+ revision = args[0]
+ if len(args) > 1:
+ help()
+ raise cmdutil.UserError("Too many arguments.")
+ bd = bugdir.BugDir(loadNow=True)
+ if bd.rcs.versioned == False:
print "This directory is not revision-controlled."
else:
- diff.diff_report(diff.reference_diff(tree, spec), tree)
-
+ old_bd = bd.duplicate_bugdir(revision)
+ r,m,a = diff.diff(old_bd, bd)
+ diff.diff_report((r,m,a), bd)
+ bd.remove_duplicate_bugdir()
def get_parser():
parser = cmdutil.CmdOptionParser("be diff [specifier]")
diff --git a/becommands/help.py b/becommands/help.py
index f6cfe3f..bf0b4fc 100644
--- a/becommands/help.py
+++ b/becommands/help.py
@@ -15,7 +15,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Print help for given subcommand"""
-from libbe import cmdutil, names, utility
+from libbe import cmdutil, utility
__desc__ = __doc__
def execute(args):
diff --git a/becommands/list.py b/becommands/list.py
index d43b573..22d73d9 100644
--- a/becommands/list.py
+++ b/becommands/list.py
@@ -15,17 +15,28 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""List bugs"""
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
from libbe.bug import cmp_full, severity_values, status_values, \
active_status_values, inactive_status_values
import os
__desc__ = __doc__
def execute(args):
+ """
+ >>> import os
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
+ >>> execute([])
+ a:om: Bug A
+ >>> execute(["--status", "all"])
+ a:om: Bug A
+ b:cm: Bug B
+ """
options, args = get_parser().parse_args(args)
if len(args) > 0:
- raise cmdutil.UsageError
- tree = cmdutil.bug_tree()
+ help()
+ raise cmdutil.UserError("Too many arguments.")
+ bd = bugdir.BugDir(loadNow=True)
# select status
if options.status != None:
if options.status == "all":
@@ -73,7 +84,7 @@ def execute(args):
assigned = "all"
for i in range(len(assigned)):
if assigned[i] == '-':
- assigned[i] = tree.rcs.get_user_id()
+ assigned[i] = bd.rcs.get_user_id()
# select target
if options.target != None:
if options.target == "all":
@@ -83,7 +94,7 @@ def execute(args):
else:
target = []
if options.cur_target == True:
- target.append(tree.target)
+ target.append(bd.target)
if target == []: # set the default value
target = "all"
@@ -98,8 +109,7 @@ def execute(args):
return False
return True
- all_bugs = list(tree.list())
- bugs = [b for b in all_bugs if filter(b) ]
+ bugs = [b for b in bd if filter(b) ]
if len(bugs) == 0:
print "No matching bugs found"
@@ -109,7 +119,7 @@ def execute(args):
if title != None:
print cmdutil.underlined(title)
for bug in cur_bugs:
- print bug.string(all_bugs, shortlist=True)
+ print bug.string(shortlist=True)
list_bugs(bugs, no_target=False)
diff --git a/becommands/new.py b/becommands/new.py
index 0f9928a..c9688b9 100644
--- a/becommands/new.py
+++ b/becommands/new.py
@@ -15,22 +15,22 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Create a new bug"""
-from libbe import cmdutil, names
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
"""
>>> import os, time
- >>> from libbe import bugdir
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
- >>> names.uuid = lambda: "X"
+ >>> from libbe import bug
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
+ >>> bug.uuid_gen = lambda: "X"
>>> execute (["this is a test",])
Created bug with ID X
- >>> bug = cmdutil.get_bug("X", dir)
+ >>> bd.load()
+ >>> bug = bd.bug_from_uuid("X")
>>> bug.summary
u'this is a test'
- >>> bug.creator = os.environ["LOGNAME"]
>>> bug.time <= int(time.time())
True
>>> bug.severity
@@ -41,12 +41,10 @@ def execute(args):
options, args = get_parser().parse_args(args)
if len(args) != 1:
raise cmdutil.UserError("Please supply a summary message")
- dir = cmdutil.bug_tree()
- bug = dir.new_bug()
- bug.summary = args[0]
- bug.save()
- bugs = (dir.list())
- print "Created bug with ID %s" % names.unique_name(bug, bugs)
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.new_bug(summary=args[0])
+ bd.save()
+ print "Created bug with ID %s" % bd.bug_shortname(bug)
def get_parser():
parser = cmdutil.CmdOptionParser("be new SUMMARY")
diff --git a/becommands/open.py b/becommands/open.py
index 2463969..736b601 100644
--- a/becommands/open.py
+++ b/becommands/open.py
@@ -15,27 +15,31 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Re-open a bug"""
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
"""
- >>> from libbe import bugdir
>>> import os
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
- >>> dir.get_bug("b").status
- u'closed'
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
+ >>> print bd.bug_from_shortname("b").status
+ closed
>>> execute(["b"])
- >>> dir.get_bug("b").status
- u'open'
+ >>> bd.load()
+ >>> print bd.bug_from_shortname("b").status
+ open
"""
options, args = get_parser().parse_args(args)
- if len(args) !=1:
+ if len(args) == 0:
raise cmdutil.UserError("Please specify a bug id.")
- bug = cmdutil.get_bug(args[0])
+ if len(args) > 1:
+ help()
+ raise cmdutil.UserError("Too many arguments.")
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(args[0])
bug.status = "open"
- bug.save()
+ bd.save()
def get_parser():
parser = cmdutil.CmdOptionParser("be open BUG-ID")
diff --git a/becommands/remove.py b/becommands/remove.py
index 172fb96..7ba5e23 100644
--- a/becommands/remove.py
+++ b/becommands/remove.py
@@ -15,30 +15,33 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Remove (delete) a bug and its comments"""
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
"""
+ >>> from libbe import mapfile
>>> import os
- >>> from libbe import bugdir, mapfile
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
- >>> dir.get_bug("b").status
- u'closed'
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
+ >>> print bd.bug_from_shortname("b").status
+ closed
>>> execute (["b"])
Removed bug b
+ >>> bd.load()
>>> try:
- ... dir.get_bug("b")
- ... except mapfile.NoSuchFile:
+ ... bd.bug_from_shortname("b")
+ ... except KeyError:
... print "Bug not found"
Bug not found
"""
options, args = get_parser().parse_args(args)
if len(args) != 1:
raise cmdutil.UserError("Please specify a bug id.")
- bug = cmdutil.get_bug(args[0])
- bug.remove()
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(args[0])
+ bd.remove_bug(bug)
+ bd.save()
print "Removed bug %s" % bug.uuid
def get_parser():
diff --git a/becommands/set.py b/becommands/set.py
index 368aa65..7951c8b 100644
--- a/becommands/set.py
+++ b/becommands/set.py
@@ -15,41 +15,41 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Change tree settings"""
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
"""
- >>> from libbe import bugdir
>>> import os
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
- >>> execute(["a"])
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
+ >>> execute(["target"])
None
- >>> execute(["a", "tomorrow"])
- >>> execute(["a"])
+ >>> execute(["target", "tomorrow"])
+ >>> execute(["target"])
tomorrow
- >>> execute(["a", "none"])
- >>> execute(["a"])
+ >>> execute(["target", "none"])
+ >>> execute(["target"])
None
"""
options, args = get_parser().parse_args(args)
if len(args) > 2:
+ help()
raise cmdutil.UserError("Too many arguments.")
- tree = cmdutil.bug_tree()
+ bd = bugdir.BugDir(loadNow=True)
if len(args) == 0:
- keys = tree.settings.keys()
+ keys = bd.settings.keys()
keys.sort()
for key in keys:
- print "%16s: %s" % (key, tree.settings[key])
+ print "%16s: %s" % (key, bd.settings[key])
elif len(args) == 1:
- print tree.settings.get(args[0])
+ print bd.settings.get(args[0])
else:
if args[1] != "none":
- tree.settings[args[0]] = args[1]
+ bd.settings[args[0]] = args[1]
else:
- del tree.settings[args[0]]
- tree.save_settings()
+ del bd.settings[args[0]]
+ bd.save()
def get_parser():
parser = cmdutil.CmdOptionParser("be set [name] [value]")
diff --git a/becommands/set_root.py b/becommands/set_root.py
index 1c731da..d8fcdf3 100644
--- a/becommands/set_root.py
+++ b/becommands/set_root.py
@@ -16,32 +16,34 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Assign the root directory for bug tracking"""
import os.path
-from libbe import bugdir, cmdutil, rcs
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
"""
- >>> from libbe import utility
+ >>> from libbe import utility, rcs
>>> import os
>>> dir = utility.Dir()
>>> try:
- ... bugdir.tree_root(dir.path)
+ ... bugdir.BugDir(dir.path)
... except bugdir.NoBugDir, e:
... True
True
>>> execute([dir.path])
No revision control detected.
Directory initialized.
- >>> bd = bugdir.tree_root(dir.path)
- >>> bd.root = dir.path
- >>> dir_rcs = rcs.installed_rcs()
- >>> dir_rcs.init(bd.dir)
- >>> bd.rcs_name = dir_rcs.name
- >>> del(dir_rcs)
- >>> os.chdir(bd.dir)
- >>> execute(['.'])
+ >>> del(dir)
+
+ >>> dir = utility.Dir()
+ >>> os.chdir(dir.path)
+ >>> rcs = rcs.installed_rcs()
+ >>> rcs.init('.')
+ >>> print rcs.name
+ Arch
+ >>> execute([])
Using Arch for revision control.
Directory initialized.
+
>>> try:
... execute(['.'])
... except cmdutil.UserError, e:
@@ -50,29 +52,34 @@ def execute(args):
>>> execute(['/highly-unlikely-to-exist'])
Traceback (most recent call last):
UserError: No such directory: /highly-unlikely-to-exist
+ >>> os.chdir('/')
"""
options, args = get_parser().parse_args(args)
- basedir = args[0]
- if len(args) != 1:
- raise cmdutil.UsageError
+ if len(args) > 1:
+ print help()
+ raise cmdutil.UserError, "Too many arguments"
+ if len(args) == 1:
+ basedir = args[0]
+ else:
+ basedir = "."
if os.path.exists(basedir) == False:
- raise cmdutil.UserError, "No such directory: %s" % basedir
- dir_rcs = rcs.detect_rcs(basedir)
- dir_rcs.root(basedir)
+ pass
+ #raise cmdutil.UserError, "No such directory: %s" % basedir
try:
- bugdir.create_bug_dir(basedir, dir_rcs)
+ bd = bugdir.BugDir(basedir, loadNow=False, sink_to_existing_root=False, assert_new_BugDir=True)
except bugdir.NoRootEntry:
raise cmdutil.UserError("No such directory: %s" % basedir)
except bugdir.AlreadyInitialized:
raise cmdutil.UserError("Directory already initialized: %s" % basedir)
- if dir_rcs.name is not "None":
- print "Using %s for revision control." % dir_rcs.name
+ bd.save()
+ if bd.rcs.name is not "None":
+ print "Using %s for revision control." % bd.rcs.name
else:
print "No revision control detected."
print "Directory initialized."
def get_parser():
- parser = cmdutil.CmdOptionParser("be set-root DIRECTORY")
+ parser = cmdutil.CmdOptionParser("be set-root [DIRECTORY]")
return parser
longhelp="""
@@ -80,6 +87,8 @@ This command initializes Bugs Everywhere support for the specified directory
and all its subdirectories. It will auto-detect any supported revision control
system. You can use "be set rcs_name" to change the rcs being used.
+DIRECTORY defaults to your current working directory.
+
It is usually a good idea to put the Bugs Everywhere root at the source code
root, but you can put it anywhere. If you run "be set-root" in a subdirectory,
then only bugs created in that subdirectory (and its children) will appear
diff --git a/becommands/severity.py b/becommands/severity.py
index b055695..d7df13d 100644
--- a/becommands/severity.py
+++ b/becommands/severity.py
@@ -15,16 +15,15 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Show or change a bug's severity level"""
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
from libbe.bug import severity_values, severity_description
__desc__ = __doc__
def execute(args):
"""
- >>> from libbe import bugdir
>>> import os
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
>>> execute(["a"])
minor
>>> execute(["a", "wishlist"])
@@ -35,11 +34,11 @@ def execute(args):
UserError: Invalid severity level: none
"""
options, args = get_parser().parse_args(args)
- assert(len(args) in (0, 1, 2))
- if len(args) == 0:
+ if len(args) not in (1,2):
print help()
return
- bug = cmdutil.get_bug(args[0])
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(args[0])
if len(args) == 1:
print bug.severity
elif len(args) == 2:
@@ -49,7 +48,7 @@ def execute(args):
if e.name != "severity":
raise
raise cmdutil.UserError ("Invalid severity level: %s" % e.value)
- bug.save()
+ bd.save()
def get_parser():
parser = cmdutil.CmdOptionParser("be severity bug-id [severity]")
diff --git a/becommands/show.py b/becommands/show.py
index 669a81d..ab296e3 100644
--- a/becommands/show.py
+++ b/becommands/show.py
@@ -15,26 +15,35 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Show a particular bug"""
-from libbe import cmdutil, names, utility
-from libbe.bug import thread_comments
-import os
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
+ """
+ >>> import os
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
+ >>> execute (["a",])
+ ID : a
+ Short name : a
+ Severity : minor
+ Status : open
+ Assigned :
+ Target :
+ Creator : John Doe <jdoe@example.com>
+ Created : Wed, 31 Dec 1969 19:00 (Thu, 01 Jan 1970 00:00:00 +0000)
+ Bug A
+ <BLANKLINE>
+ """
options, args = get_parser().parse_args(args)
- if len(args) !=1:
+ if len(args) == 0:
raise cmdutil.UserError("Please specify a bug id.")
- bug_dir = cmdutil.bug_tree()
- bug = cmdutil.get_bug(args[0], bug_dir)
- print bug.string().rstrip("\n")
- unique_name = names.unique_name(bug, bug_dir.list())
- comments = []
- name_map = {}
- for c_name, comment in cmdutil.iter_comment_name(bug, unique_name):
- name_map[comment.uuid] = c_name
- comments.append(comment)
- threaded = thread_comments(comments)
- cmdutil.print_threaded_comments(threaded, name_map)
+ if len(args) > 1:
+ help()
+ raise cmdutil.UserError("Too many arguments.")
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(args[0])
+ print bug.string(show_comments=True)
def get_parser():
parser = cmdutil.CmdOptionParser("be show bug-id")
diff --git a/becommands/status.py b/becommands/status.py
index 5559e59..de171f5 100644
--- a/becommands/status.py
+++ b/becommands/status.py
@@ -15,16 +15,15 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Show or change a bug's status"""
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
from libbe.bug import status_values, status_description
__desc__ = __doc__
def execute(args):
"""
- >>> from libbe import bugdir
>>> import os
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
>>> execute(["a"])
open
>>> execute(["a", "closed"])
@@ -35,11 +34,11 @@ def execute(args):
UserError: Invalid status: none
"""
options, args = get_parser().parse_args(args)
- assert(len(args) in (0, 1, 2))
- if len(args) == 0:
+ if len(args) not in (1,2):
print help()
return
- bug = cmdutil.get_bug(args[0])
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(args[0])
if len(args) == 1:
print bug.status
elif len(args) == 2:
@@ -49,7 +48,7 @@ def execute(args):
if e.name != "status":
raise
raise cmdutil.UserError ("Invalid status: %s" % e.value)
- bug.save()
+ bd.save()
def get_parser():
parser = cmdutil.CmdOptionParser("be status bug-id [status]")
diff --git a/becommands/target.py b/becommands/target.py
index 16de8fe..2047397 100644
--- a/becommands/target.py
+++ b/becommands/target.py
@@ -15,15 +15,14 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Show or change a bug's target for fixing"""
-from libbe import bugdir
-from libbe import cmdutil
+from libbe import cmdutil, bugdir
__desc__ = __doc__
def execute(args):
"""
>>> import os
- >>> dir = bugdir.simple_bug_dir()
- >>> os.chdir(dir.dir)
+ >>> bd = bugdir.simple_bug_dir()
+ >>> os.chdir(bd.root)
>>> execute(["a"])
No target assigned.
>>> execute(["a", "tomorrow"])
@@ -38,7 +37,8 @@ def execute(args):
if len(args) == 0:
print help()
return
- bug = cmdutil.get_bug(args[0])
+ bd = bugdir.BugDir(loadNow=True)
+ bug = bd.bug_from_shortname(args[0])
if len(args) == 1:
if bug.target is None:
print "No target assigned."
@@ -49,7 +49,7 @@ def execute(args):
bug.target = None
else:
bug.target = args[1]
- bug.save()
+ bd.save()
def get_parser():
parser = cmdutil.CmdOptionParser("be target bug-id [target]")
diff --git a/becommands/upgrade.py b/becommands/upgrade.py
deleted file mode 100644
index c48eaaa..0000000
--- a/becommands/upgrade.py
+++ /dev/null
@@ -1,115 +0,0 @@
-# Copyright (C) 2005 Aaron Bentley and Panometrics, Inc.
-# <abentley@panoramicfeedback.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-# OUTDATED
-
-"""Upgrade the bugs to the latest format"""
-import os.path
-import errno
-from libbe import bugdir, rcs, cmdutil
-__desc__ = __doc__
-
-def execute(args):
- options, args = get_parser().parse_args(args)
- root = bugdir.tree_root(".", old_version=True)
- for uuid in root.list_uuids():
- old_bug = OldBug(root.bugs_path, uuid)
-
- new_bug = root.get_bug(uuid)
- new_bug.uuid = old_bug.uuid
- new_bug.summary = old_bug.summary
- new_bug.creator = old_bug.creator
- new_bug.target = old_bug.target
- new_bug.status = old_bug.status
- new_bug.severity = old_bug.severity
-
- new_bug.save()
- for uuid in root.list_uuids():
- old_bug = OldBug(root.bugs_path, uuid)
- old_bug.delete()
-
- bugdir.set_version(root.dir)
-
-def file_property(name, valid=None):
- def getter(self):
- value = self._get_value(name)
- if valid is not None:
- if value not in valid:
- raise InvalidValue(name, value)
- return value
- def setter(self, value):
- if valid is not None:
- if value not in valid and value is not None:
- raise InvalidValue(name, value)
- return self._set_value(name, value)
- return property(getter, setter)
-
-
-class OldBug(object):
- def __init__(self, path, uuid):
- self.path = os.path.join(path, uuid)
- self.uuid = uuid
-
- def get_path(self, file):
- return os.path.join(self.path, file)
-
- summary = file_property("summary")
- creator = file_property("creator")
- target = file_property("target")
- status = file_property("status", valid=("open", "closed"))
- severity = file_property("severity", valid=("wishlist", "minor", "serious",
- "critical", "fatal"))
- def delete(self):
- self.summary = None
- self.creator = None
- self.target = None
- self.status = None
- self.severity = None
- self._set_value("name", None)
-
- def _get_active(self):
- return self.status == "open"
-
- active = property(_get_active)
-
- def _get_value(self, name):
- try:
- return file(self.get_path(name), "rb").read().rstrip("\n")
- except IOError, e:
- if e.errno == errno.EEXIST:
- return None
-
- def _set_value(self, name, value):
- if value is None:
- try:
- rcs.unlink(self.get_path(name))
- except OSError, e:
- if e.errno != 2:
- raise
- else:
- rcs.set_file_contents(self.get_path(name), "%s\n" % value)
-
-def get_parser():
- parser = cmdutil.CmdOptionParser("be upgrade")
- return parser
-
-longhelp="""
-Upgrade the bug storage to the latest format.
-"""
-
-def help():
- return get_parser().help_str() + longhelp
diff --git a/libbe/arch.py b/libbe/arch.py
index 8e7390d..b35a897 100644
--- a/libbe/arch.py
+++ b/libbe/arch.py
@@ -50,14 +50,6 @@ class Arch(RCS):
if self._u_search_parent_directories(path, "{arch}") != None :
return True
return False
- def _rcs_root(self, path):
- if not os.path.isdir(path):
- dirname = os.path.dirname(path)
- else:
- dirname = path
- status,output,error = self._u_invoke_client("tree-root", dirname)
- # get archive name...
- return output.rstrip('\n')
def _rcs_init(self, path):
self._create_archive(path)
self._create_project(path)
@@ -121,11 +113,35 @@ class Arch(RCS):
assert self._archive_name != None
assert self._project_name != None
return "%s/%s" % (self._archive_name, self._project_name)
+ def _adjust_naming_conventions(self, path):
+ """
+ By default, Arch restricts source code filenames to
+ ^[_=a-zA-Z0-9].*$
+ See
+ http://regexps.srparish.net/tutorial-tla/naming-conventions.html
+ Since our bug directory '.be' doesn't satisfy these conventions,
+ we need to adjust them.
+
+ The conventions are specified in
+ project-root/{arch}/=tagging-method
+ """
+ tagpath = os.path.join(path, "{arch}", "=tagging-method")
+ lines_out = []
+ for line in file(tagpath, "rb"):
+ line.decode("utf-8")
+ if line.startswith("source "):
+ lines_out.append("source ^[._=a-zA-X0-9].*$\n")
+ else:
+ lines_out.append(line)
+ file(tagpath, "wb").write("".join(lines_out).encode("utf-8"))
+
def _add_project_code(self, path):
# http://mwolson.org/projects/GettingStartedWithArch.html
- # http://regexps.srparish.net/tutorial-tla/importing-first.html#Importing_the_First_Revision
- self._u_invoke_client("init-tree", self._archive_project_name(),
+ # http://regexps.srparish.net/tutorial-tla/new-source.html
+ # http://regexps.srparish.net/tutorial-tla/importing-first.html
+ self._invoke_client("init-tree", self._project_name,
directory=path)
+ self._adjust_naming_conventions(path)
self._invoke_client("import", "--summary", "Began versioning",
directory=path)
def _rcs_cleanup(self):
@@ -133,6 +149,40 @@ class Arch(RCS):
self._remove_project()
if self._tmp_archive == True:
self._remove_archive()
+
+ def _rcs_root(self, path):
+ if not os.path.isdir(path):
+ dirname = os.path.dirname(path)
+ else:
+ dirname = path
+ status,output,error = self._u_invoke_client("tree-root", dirname)
+ root = output.rstrip('\n')
+
+ self._get_archive_project_name(root)
+
+ return root
+
+ def _get_archive_name(self, root):
+ status,output,error = self._u_invoke_client("archives")
+ lines = output.split('\n')
+ # e.g. output:
+ # jdoe@example.com--bugs-everywhere-auto-2008.22.24.52
+ # /tmp/BEtestXXXXXX/rootdir
+ # (+ repeats)
+ for archive,location in zip(lines[::2], lines[1::2]):
+ if os.path.realpath(location) == os.path.realpath(root):
+ self._archive_name = archive
+ assert self._archive_name != None
+
+ def _get_archive_project_name(self, root):
+ # get project names
+ status,output,error = self._u_invoke_client("tree-version", directory=root)
+ # e.g output
+ # jdoe@example.com--bugs-everywhere-auto-2008.22.24.52/be--mainline--0.1
+ archive_name,project_name = output.rstrip('\n').split('/')
+ self._archive_name = archive_name
+ self._project_name = project_name
+
def _rcs_get_user_id(self):
try:
status,output,error = self._u_invoke_client('my-id')
diff --git a/libbe/bug.py b/libbe/bug.py
index a297b1a..b1e8d26 100644
--- a/libbe/bug.py
+++ b/libbe/bug.py
@@ -17,12 +17,15 @@
import os
import os.path
import errno
-import names
-import mapfile
import time
-import utility
import doctest
+from beuuid import uuid_gen
+import mapfile
+import comment
+import utility
+
+
### Define and describe valid bug categories
# Use a tuple of (category, description) tuples since we don't have
# ordered dicts in Python yet http://www.python.org/dev/peps/pep-0372/
@@ -87,45 +90,46 @@ class Bug(object):
severity = checked_property("severity", severity_values)
status = checked_property("status", status_values)
- def __init__(self, path, uuid, rcs, bugdir):
- self.path = path
- self.uuid = uuid
- if uuid is not None:
- dict = mapfile.map_load(self.get_path("values"))
- else:
- dict = {}
-
- self.rcs = rcs
- self.bugdir = bugdir
-
- self.summary = dict.get("summary")
- self.creator = dict.get("creator")
- self.target = dict.get("target")
- self.status = dict.get("status", "open")
- self.severity = dict.get("severity", "minor")
- self.assigned = dict.get("assigned")
- self.time = dict.get("time")
- if self.time is not None:
- self.time = utility.str_to_time(self.time)
-
- def get_path(self, file=None):
- if file == None:
- return os.path.join(self.path, self.uuid)
- else:
- return os.path.join(self.path, self.uuid, file)
-
def _get_active(self):
return self.status in active_status_values
active = property(_get_active)
+ def __init__(self, bugdir=None, uuid=None, loadNow=False, summary=None):
+ self.bugdir = bugdir
+ if bugdir != None:
+ self.rcs = bugdir.rcs
+ else:
+ self.rcs = None
+ if loadNow == True:
+ self.uuid = uuid
+ self.load()
+ else:
+ # Note: defaults should match those in Bug.load()
+ if uuid != None:
+ self.uuid = uuid
+ else:
+ self.uuid = uuid_gen()
+ self.summary = summary
+ if self.rcs != None:
+ self.creator = self.rcs.get_user_id()
+ else:
+ self.creator = None
+ self.target = None
+ self.status = "open"
+ self.severity = "minor"
+ self.assigned = None
+ self.time = time.time()
+ self.comment_root = comment.Comment(self, uuid=comment.INVALID_UUID)
+
def __repr__(self):
return "Bug(uuid=%r)" % self.uuid
- def string(self, bugs=None, shortlist=False):
- if bugs == None:
- bugs = list(self.bugdir.list())
- short_name = names.unique_name(self, bugs)
+ def string(self, shortlist=False, show_comments=False):
+ if self.bugdir == None:
+ shortname = self.uuid
+ else:
+ shortname = self.bugdir.bug_shortname(self)
if shortlist == False:
if self.time == None:
timestring = ""
@@ -134,7 +138,7 @@ class Bug(object):
ftime = utility.time_to_str(self.time)
timestring = "%s (%s)" % (htime, ftime)
info = [("ID", self.uuid),
- ("Short name", short_name),
+ ("Short name", shortname),
("Severity", self.severity),
("Status", self.status),
("Assigned", self.assigned),
@@ -150,12 +154,20 @@ class Bug(object):
info = newinfo
longest_key_len = max([len(k) for k,v in info])
infolines = [" %*s : %s\n" %(longest_key_len,k,v) for k,v in info]
- return "".join(infolines) + "%s\n" % self.summary
+ bugout = "".join(infolines) + "%s" % self.summary.rstrip('\n')
else:
statuschar = self.status[0]
severitychar = self.severity[0]
chars = "%c%c" % (statuschar, severitychar)
- return "%s:%s: %s" % (short_name, chars, self.summary)
+ bugout = "%s:%s: %s" % (shortname, chars, self.summary.rstrip('\n'))
+
+ if show_comments == True:
+ comout = self.comment_root.string_thread(auto_name_map=True,
+ bug_shortname=shortname)
+ output = bugout + '\n' + comout.rstrip('\n')
+ else :
+ output = bugout
+ return output
def __str__(self):
return self.string(shortlist=True)
@@ -163,7 +175,28 @@ class Bug(object):
def __cmp__(self, other):
return cmp_full(self, other)
- def add_attr(self, map, name):
+ def get_path(self, name=None):
+ my_dir = os.path.join(self.bugdir.get_path("bugs"), self.uuid)
+ if name is None:
+ return my_dir
+ assert name in ["values", "comments"]
+ return os.path.join(my_dir, name)
+
+ def load(self):
+ map = mapfile.map_load(self.get_path("values"))
+ self.summary = map.get("summary")
+ self.creator = map.get("creator")
+ self.target = map.get("target")
+ self.status = map.get("status", "open")
+ self.severity = map.get("severity", "minor")
+ self.assigned = map.get("assigned")
+ self.time = map.get("time")
+ if self.time is not None:
+ self.time = utility.str_to_time(self.time)
+
+ self.comment_root = comment.loadComments(self)
+
+ def _add_attr(self, map, name):
value = getattr(self, name)
if value is not None:
map[name] = value
@@ -171,134 +204,39 @@ class Bug(object):
def save(self):
assert self.summary != None, "Can't save blank bug"
map = {}
- self.add_attr(map, "assigned")
- self.add_attr(map, "summary")
- self.add_attr(map, "creator")
- self.add_attr(map, "target")
- self.add_attr(map, "status")
- self.add_attr(map, "severity")
+ self._add_attr(map, "assigned")
+ self._add_attr(map, "summary")
+ self._add_attr(map, "creator")
+ self._add_attr(map, "target")
+ self._add_attr(map, "status")
+ self._add_attr(map, "severity")
if self.time is not None:
map["time"] = utility.time_to_str(self.time)
+
+ self.rcs.mkdir(self.get_path())
path = self.get_path("values")
mapfile.map_save(self.rcs, path, map)
+ if len(self.comment_root) > 0:
+ self.rcs.mkdir(self.get_path("comments"))
+ comment.saveComments(self)
+
def remove(self):
+ self.comment_root.remove()
path = self.get_path()
self.rcs.recursive_remove(path)
def new_comment(self, body=None):
- if not os.path.exists(self.get_path("comments")):
- self.rcs.mkdir(self.get_path("comments"))
- comm = Comment(None, self)
- comm.uuid = names.uuid()
- comm.rcs = self.rcs
- comm.From = self.rcs.get_user_id()
- comm.time = time.time()
- comm.body = body
+ comm = comment.comment_root.new_reply(body=body)
return comm
- def get_comment(self, uuid):
- return Comment(uuid, self)
-
- def iter_comment_ids(self):
- path = self.get_path("comments")
- if not os.path.isdir(path):
- return
- try:
- for uuid in os.listdir(path):
- if (uuid.startswith('.')):
- continue
- yield uuid
- except OSError, e:
- if e.errno != errno.ENOENT:
- raise
- return
-
- def list_comments(self):
- comments = [Comment(id, self) for id in self.iter_comment_ids()]
- comments.sort(cmp_time)
- return comments
-
-def add_headers(obj, map, names):
- map_names = {}
- for name in names:
- map_names[name] = pyname_to_header(name)
- add_attrs(obj, map, names, map_names)
-
-def add_attrs(obj, map, names, map_names=None):
- if map_names is None:
- map_names = {}
- for name in names:
- map_names[name] = name
-
- for name in names:
- value = getattr(obj, name)
- if value is not None:
- map[map_names[name]] = value
-
-
-class Comment(object):
- def __init__(self, uuid, bug):
- object.__init__(self)
- self.uuid = uuid
- self.bug = bug
- if self.uuid is not None and self.bug is not None:
- map = mapfile.map_load(self.get_path("values"))
- self.time = utility.str_to_time(map["Date"])
- self.From = map["From"]
- self.in_reply_to = map.get("In-reply-to")
- self.content_type = map.get("Content-type", "text/plain")
- self.body = file(self.get_path("body")).read().decode("utf-8")
- else:
- self.time = None
- self.From = None
- self.in_reply_to = None
- self.content_type = "text/plain"
- self.body = None
+ def comment_from_shortname(self, shortname, *args, **kwargs):
+ return self.comment_root.comment_from_shortname(shortname, *args, **kwargs)
- def save(self):
- map_file = {"Date": utility.time_to_str(self.time)}
- add_headers(self, map_file, ("From", "in_reply_to", "content_type"))
- if not os.path.exists(self.get_path()):
- self.bug.rcs.mkdir(self.get_path())
- mapfile.map_save(self.bug.rcs, self.get_path("values"), map_file)
- self.bug.rcs.set_file_contents(self.get_path("body"),
- self.body.encode('utf-8'))
-
- def get_path(self, name=None):
- my_dir = os.path.join(self.bug.get_path("comments"), self.uuid)
- if name is None:
- return my_dir
- return os.path.join(my_dir, name)
-
-
-def thread_comments(comments):
- child_map = {}
- top_comments = []
- for comment in comments:
- child_map[comment.uuid] = []
- for comment in comments:
- if comment.in_reply_to is None or comment.in_reply_to not in child_map:
- top_comments.append(comment)
- continue
- child_map[comment.in_reply_to].append(comment)
-
- def recurse_children(comment):
- child_list = []
- for child in child_map[comment.uuid]:
- child_list.append(recurse_children(child))
- return (comment, child_list)
- return [recurse_children(c) for c in top_comments]
-
-def pyname_to_header(name):
- return name.capitalize().replace('_', '-')
+ def comment_from_uuid(self, uuid):
+ return self.comment_root.comment_from_uuid(uuid)
-
-class MockBug:
- def __init__(self, attr, value):
- setattr(self, attr, value)
-
# the general rule for bug sorting is that "more important" bugs are
# less than "less important" bugs. This way sorting a list of bugs
# will put the most important bugs first in the list. When relative
@@ -307,32 +245,42 @@ class MockBug:
def cmp_severity(bug_1, bug_2):
"""
- Compare the severity levels of two bugs, with more severe bugs comparing
- as less.
-
- >>> attr="severity"
- >>> cmp_severity(MockBug(attr,"wishlist"), MockBug(attr,"wishlist")) == 0
+ Compare the severity levels of two bugs, with more severe bugs
+ comparing as less.
+ >>> bugA = Bug()
+ >>> bugB = Bug()
+ >>> bugA.severity = bugB.severity = "wishlist"
+ >>> cmp_severity(bugA, bugB) == 0
True
- >>> cmp_severity(MockBug(attr,"wishlist"), MockBug(attr,"minor")) > 0
+ >>> bugB.severity = "minor"
+ >>> cmp_severity(bugA, bugB) > 0
True
- >>> cmp_severity(MockBug(attr,"critical"), MockBug(attr,"wishlist")) < 0
+ >>> bugA.severity = "critical"
+ >>> cmp_severity(bugA, bugB) < 0
True
"""
+ if not hasattr(bug_2, "severity") :
+ return 1
return -cmp(severity_index[bug_1.severity], severity_index[bug_2.severity])
def cmp_status(bug_1, bug_2):
"""
Compare the status levels of two bugs, with more 'open' bugs
comparing as less.
-
- >>> attr="status"
- >>> cmp_status(MockBug(attr,"open"), MockBug(attr,"open")) == 0
+ >>> bugA = Bug()
+ >>> bugB = Bug()
+ >>> bugA.status = bugB.status = "open"
+ >>> cmp_status(bugA, bugB) == 0
True
- >>> cmp_status(MockBug(attr,"open"), MockBug(attr,"closed")) < 0
+ >>> bugB.status = "closed"
+ >>> cmp_status(bugA, bugB) < 0
True
- >>> cmp_status(MockBug(attr,"closed"), MockBug(attr,"open")) > 0
+ >>> bugA.status = "fixed"
+ >>> cmp_status(bugA, bugB) > 0
True
"""
+ if not hasattr(bug_2, "status") :
+ return 1
val_2 = status_index[bug_2.status]
return cmp(status_index[bug_1.status], status_index[bug_2.status])
@@ -342,13 +290,20 @@ def cmp_attr(bug_1, bug_2, attr, invert=False):
comparison rule for that attribute type. If invert == True, sort
*against* that convention.
>>> attr="severity"
- >>> cmp_attr(MockBug(attr,1), MockBug(attr,2), attr, invert=False) < 0
+ >>> bugA = Bug()
+ >>> bugB = Bug()
+ >>> bugA.severity = "critical"
+ >>> bugB.severity = "wishlist"
+ >>> cmp_attr(bugA, bugB, attr) < 0
True
- >>> cmp_attr(MockBug(attr,1), MockBug(attr,2), attr, invert=True) > 0
+ >>> cmp_attr(bugA, bugB, attr, invert=True) > 0
True
- >>> cmp_attr(MockBug(attr,1), MockBug(attr,1), attr) == 0
+ >>> bugB.severity = "critical"
+ >>> cmp_attr(bugA, bugB, attr) == 0
True
"""
+ if not hasattr(bug_2, attr) :
+ return 1
if invert == True :
return -cmp(getattr(bug_1, attr), getattr(bug_2, attr))
else :
diff --git a/libbe/bugdir.py b/libbe/bugdir.py
index 41f0fec..6152e3f 100644
--- a/libbe/bugdir.py
+++ b/libbe/bugdir.py
@@ -16,16 +16,17 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import os
import os.path
-import cmdutil
import errno
+import time
import unittest
import doctest
-import names
+
+from beuuid import uuid_gen
import mapfile
-import time
+import bug
+import cmdutil
import utility
-from rcs import rcs_by_name, installed_rcs
-from bug import Bug
+from rcs import rcs_by_name, detect_rcs, installed_rcs, PathNotInRoot
class NoBugDir(Exception):
def __init__(self, path):
@@ -33,48 +34,6 @@ class NoBugDir(Exception):
Exception.__init__(self, msg)
self.path = path
-
-def iter_parent_dirs(cur_dir):
- cur_dir = os.path.realpath(cur_dir)
- old_dir = None
- while True:
- yield cur_dir
- old_dir = cur_dir
- cur_dir = os.path.normpath(os.path.join(cur_dir, '..'))
- if old_dir == cur_dir:
- break;
-
-
-def tree_root(dir, old_version=False):
- for rootdir in iter_parent_dirs(dir):
- versionfile=os.path.join(rootdir, ".be", "version")
- if os.path.exists(versionfile):
- if not old_version:
- test_version(versionfile)
- return BugDir(os.path.join(rootdir, ".be"))
- elif not os.path.exists(rootdir):
- raise NoRootEntry(rootdir)
- old_rootdir = rootdir
- rootdir=os.path.join('..', rootdir)
-
- raise NoBugDir(dir)
-
-class BadTreeVersion(Exception):
- def __init__(self, version):
- Exception.__init__(self, "Unsupported tree version: %s" % version)
- self.version = version
-
-def test_version(path):
- tree_version = file(path, "rb").read()
- if tree_version != TREE_VERSION_STRING:
- raise BadTreeVersion(tree_version)
-
-def set_version(path, rcs):
- rcs.set_file_contents(os.path.join(path, "version"), TREE_VERSION_STRING)
-
-
-TREE_VERSION_STRING = "Bugs Everywhere Tree 1 0\n"
-
class NoRootEntry(Exception):
def __init__(self, path):
self.path = path
@@ -86,32 +45,15 @@ class AlreadyInitialized(Exception):
Exception.__init__(self,
"Specified root is already initialized: %s" % path)
-def bugdir_root(versioning_root):
- return os.path.join(versioning_root, ".be")
+class InvalidValue(ValueError):
+ def __init__(self, name, value):
+ msg = "Cannot assign value %s to %s" % (value, name)
+ Exception.__init__(self, msg)
+ self.name = name
+ self.value = value
+
-def create_bug_dir(path, rcs):
- """
- >>> import tests
- >>> rcs = rcs_by_name("None")
- >>> create_bug_dir('/highly-unlikely-to-exist', rcs)
- Traceback (most recent call last):
- NoRootEntry: Specified root does not exist: /highly-unlikely-to-exist
- """
- root = os.path.join(path, ".be")
- try:
- rcs.mkdir(root)
- except OSError, e:
- if e.errno == errno.ENOENT:
- raise NoRootEntry(path)
- elif e.errno == errno.EEXIST:
- raise AlreadyInitialized(path)
- else:
- raise
- rcs.mkdir(os.path.join(root, "bugs"))
- set_version(root, rcs)
- mapfile.map_save(rcs,
- os.path.join(root, "settings"), {"rcs_name": rcs.name})
- return BugDir(bugdir_root(path))
+TREE_VERSION_STRING = "Bugs Everywhere Tree 1 0\n"
def setting_property(name, valid=None):
@@ -130,83 +72,232 @@ def setting_property(name, valid=None):
del self.settings[name]
else:
self.settings[name] = value
- self.save_settings()
+ self.save()
return property(getter, setter)
-class BugDir:
- def __init__(self, dir):
- self.dir = dir
- self.bugs_path = os.path.join(self.dir, "bugs")
+class BugDir (list):
+ def __init__(self, root=None, sink_to_existing_root=True,
+ assert_new_BugDir=False, allow_rcs_init=False,
+ loadNow=False, rcs=None):
+ list.__init__(self)
+ if root == None:
+ root = os.getcwd()
+ if sink_to_existing_root == True:
+ self.root = self.find_root(root)
+ else:
+ if not os.path.exists(root):
+ raise NoRootEntry(root)
+ self.root = root
+ if loadNow == True:
+ self.load()
+ else:
+ if assert_new_BugDir:
+ if os.path.exists(self.get_path()):
+ raise AlreadyInitialized, self.get_path()
+ if rcs == None:
+ rcs = self.guess_rcs(allow_rcs_init)
+ self.settings = {"rcs_name": self.rcs_name}
+ self.rcs_name = rcs.name
+
+ def find_root(self, path):
+ """
+ Search for an existing bug database dir and it's ancestors and
+ return a BugDir rooted there.
+ """
+ if not os.path.exists(path):
+ raise NoRootEntry(path)
+ versionfile = utility.search_parent_directories(path, os.path.join(".be", "version"))
+ if versionfile != None:
+ beroot = os.path.dirname(versionfile)
+ root = os.path.dirname(beroot)
+ return root
+ else:
+ beroot = utility.search_parent_directories(path, ".be")
+ if beroot == None:
+ raise NoBugDir(path)
+ return beroot
+
+ def get_version(self, path=None):
+ if path == None:
+ path = self.get_path("version")
try:
- self.settings = mapfile.map_load(os.path.join(self.dir,"settings"))
- except mapfile.NoSuchFile:
- self.settings = {"rcs_name": "None"}
+ tree_version = self.rcs.get_file_contents(path)
+ except AttributeError, e:
+ # haven't initialized rcs yet
+ tree_version = file(path, "rb").read().decode("utf-8")
+ return tree_version
+
+ def set_version(self):
+ self.rcs.set_file_contents(self.get_path("version"), TREE_VERSION_STRING)
rcs_name = setting_property("rcs_name",
("None", "bzr", "git", "Arch", "hg"))
- _rcs = None
- target = setting_property("target")
-
- def save_settings(self):
- mapfile.map_save(self.rcs,
- os.path.join(self.dir, "settings"), self.settings)
+ _rcs = None
def _get_rcs(self):
if self._rcs is not None:
if self.rcs_name == self._rcs.name:
return self._rcs
self._rcs = rcs_by_name(self.rcs_name)
- self._rcs.root(self.dir)
+ self._rcs.root(self.root)
return self._rcs
rcs = property(_get_rcs)
+ target = setting_property("target")
+
+ def get_path(self, *args):
+ my_dir = os.path.join(self.root, ".be")
+ if len(args) == 0:
+ return my_dir
+ assert args[0] in ["version", "settings", "bugs"], str(args)
+ return os.path.join(my_dir, *args)
+
+ def guess_rcs(self, allow_rcs_init=False):
+ deepdir = self.get_path()
+ if not os.path.exists(deepdir):
+ deepdir = os.path.dirname(deepdir)
+ rcs = detect_rcs(deepdir)
+ if rcs.name == "None":
+ if allow_rcs_init == True:
+ rcs = installed_rcs()
+ rcs.init(self.root)
+ self.settings = {"rcs_name": rcs.name}
+ self.rcs_name = rcs.name
+ return rcs
+
+ def load(self):
+ version = self.get_version()
+ if version != TREE_VERSION_STRING:
+ raise NotImplementedError, "BugDir cannot handle version '%s' yet." % version
+ else:
+ if not os.path.exists(self.get_path()):
+ raise NoBugDir(self.get_path())
+ self.settings = self._get_settings(self.get_path("settings"))
+ self._clear_bugs()
+ for uuid in self.list_uuids():
+ self._load_bug(uuid)
+
+ self._bug_map_gen()
+
+ def save(self):
+ self.rcs.mkdir(self.get_path())
+ self.set_version()
+ self._save_settings(self.get_path("settings"), self.settings)
+ self.rcs.mkdir(self.get_path("bugs"))
+ for bug in self:
+ bug.save()
+
+ def _get_settings(self, settings_path):
+ try:
+ settings = mapfile.map_load(settings_path)
+ except mapfile.NoSuchFile:
+ settings = {"rcs_name": "None"}
+ return settings
+
+ def _save_settings(self, settings_path, settings):
+ try:
+ mapfile.map_save(self.rcs, settings_path, settings)
+ except PathNotInRoot, e:
+ # Handling duplicate bugdir settings, special case
+ none_rcs = rcs_by_name("None")
+ none_rcs.root(settings_path)
+ mapfile.map_save(none_rcs, settings_path, settings)
+
def duplicate_bugdir(self, revision):
- return BugDir(bugdir_root(self.rcs.duplicate_repo(revision)))
+ duplicate_path = self.rcs.duplicate_repo(revision)
- def remove_duplicate_bugdir(self):
- self.rcs.remove_duplicate_repo()
+ # setup revision RCS as None, since the duplicate may not be versioned
+ duplicate_settings_path = os.path.join(duplicate_path, ".be", "settings")
+ duplicate_settings = self._get_settings(duplicate_settings_path)
+ if "rcs_name" in duplicate_settings:
+ duplicate_settings["rcs_name"] = "None"
+ self._save_settings(duplicate_settings_path, duplicate_settings)
- def list(self):
- for uuid in self.list_uuids():
- yield self.get_bug(uuid)
+ return BugDir(duplicate_path, loadNow=True)
- def bug_map(self):
- bugs = {}
- for bug in self.list():
- bugs[bug.uuid] = bug
- return bugs
+ def remove_duplicate_bugdir(self):
+ self.rcs.remove_duplicate_repo()
- def get_bug(self, uuid):
- return Bug(self.bugs_path, uuid, self.rcs, self)
+ def _bug_map_gen(self):
+ map = {}
+ for bug in self:
+ map[bug.uuid] = bug
+ self.bug_map = map
def list_uuids(self):
- for uuid in os.listdir(self.bugs_path):
+ for uuid in os.listdir(self.get_path("bugs")):
if (uuid.startswith('.')):
continue
yield uuid
- def new_bug(self, uuid=None):
- if uuid is None:
- uuid = names.uuid()
- path = os.path.join(self.bugs_path, uuid)
- self.rcs.mkdir(path)
- bug = Bug(self.bugs_path, None, self.rcs, self)
- bug.uuid = uuid
- bug.creator = self.rcs.get_user_id()
- bug.severity = "minor"
- bug.status = "open"
- bug.time = time.time()
- return bug
+ def _clear_bugs(self):
+ while len(self) > 0:
+ self.pop()
+
+ def _load_bug(self, uuid):
+ bg = bug.Bug(bugdir=self, uuid=uuid, loadNow=True)
+ self.append(bg)
+ self._bug_map_gen()
+ return bg
+
+ def new_bug(self, uuid=None, summary=None):
+ bg = bug.Bug(bugdir=self, uuid=uuid, summary=summary)
+ self.append(bg)
+ self._bug_map_gen()
+ return bg
+
+ def remove_bug(self, bug):
+ self.remove(bug)
+ bug.remove()
+
+ def bug_shortname(self, bug):
+ """
+ Generate short names from uuids. Picks the minimum number of
+ characters (>=3) from the beginning of the uuid such that the
+ short names are unique.
+
+ Obviously, as the number of bugs in the database grows, these
+ short names will cease to be unique. The complete uuid should be
+ used for long term reference.
+ """
+ chars = 3
+ for uuid in self.bug_map.keys():
+ if bug.uuid == uuid:
+ continue
+ while (bug.uuid[:chars] == uuid[:chars]):
+ chars+=1
+ return bug.uuid[:chars]
+
+ def bug_from_shortname(self, shortname):
+ """
+ >>> bd = simple_bug_dir()
+ >>> bug_a = bd.bug_from_shortname('a')
+ >>> print type(bug_a)
+ <class 'libbe.bug.Bug'>
+ >>> print bug_a
+ a:om: Bug A
+ """
+ matches = []
+ for bug in self:
+ if bug.uuid.startswith(shortname):
+ matches.append(bug)
+ if len(matches) > 1:
+ raise cmdutil.UserError("More than one bug matches %s. Please be more"
+ " specific." % shortname)
+ if len(matches) == 1:
+ return matches[0]
+ raise KeyError("No bug matches %s" % shortname)
+
+ def bug_from_uuid(self, uuid):
+ if uuid not in self.bug_map:
+ self._bug_map_gen()
+ if uuid not in self.bug_map:
+ raise KeyError("No bug matches %s" % uuid +str(self.bug_map)+str(self))
+ return self.bug_map[uuid]
-class InvalidValue(ValueError):
- def __init__(self, name, value):
- msg = "Cannot assign value %s to %s" % (value, name)
- Exception.__init__(self, msg)
- self.name = name
- self.value = value
def simple_bug_dir():
"""
@@ -218,18 +309,17 @@ def simple_bug_dir():
['a', 'b']
"""
dir = utility.Dir()
- rcs = installed_rcs()
- rcs.init(dir.path)
assert os.path.exists(dir.path)
- bugdir = create_bug_dir(dir.path, rcs)
+ bugdir = BugDir(dir.path, sink_to_existing_root=False, allow_rcs_init=True)
bugdir._dir_ref = dir # postpone cleanup since dir.__del__() removes dir.
- bug_a = bugdir.new_bug("a")
- bug_a.summary = "Bug A"
- bug_a.save()
- bug_b = bugdir.new_bug("b")
+ bug_a = bugdir.new_bug("a", summary="Bug A")
+ bug_a.creator = "John Doe <jdoe@example.com>"
+ bug_a.time = 0
+ bug_b = bugdir.new_bug("b", summary="Bug B")
+ bug_b.creator = "Jane Doe <jdoe@example.com>"
+ bug_b.time = 0
bug_b.status = "closed"
- bug_b.summary = "Bug B"
- bug_b.save()
+ bugdir.save()
return bugdir
@@ -238,9 +328,8 @@ class BugDirTestCase(unittest.TestCase):
unittest.TestCase.__init__(self, *args, **kwargs)
def setUp(self):
self.dir = utility.Dir()
- self.rcs = installed_rcs()
- self.rcs.init(self.dir.path)
- self.bugdir = create_bug_dir(self.dir.path, self.rcs)
+ self.bugdir = BugDir(self.dir.path, sink_to_existing_root=False, allow_rcs_init=True)
+ self.rcs = self.bugdir.rcs
def tearDown(self):
del(self.rcs)
del(self.dir)
@@ -250,9 +339,8 @@ class BugDirTestCase(unittest.TestCase):
fullpath = self.fullPath(path)
self.failUnless(os.path.exists(fullpath)==True,
"path %s does not exist" % fullpath)
- def testBugDirDuplicate(self):
- self.assertRaises(AlreadyInitialized, create_bug_dir,
- self.dir.path, self.rcs)
+ self.assertRaises(AlreadyInitialized, BugDir,
+ self.dir.path, assertNewBugDir=True)
unitsuite = unittest.TestLoader().loadTestsFromTestCase(BugDirTestCase)
suite = unittest.TestSuite([unitsuite, doctest.DocTestSuite()])
diff --git a/libbe/cmdutil.py b/libbe/cmdutil.py
index 62a0c7c..55a7a72 100644
--- a/libbe/cmdutil.py
+++ b/libbe/cmdutil.py
@@ -14,16 +14,17 @@
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import bugdir
-import plugin
-import locale
-import os
import optparse
+import os
+import locale
from textwrap import TextWrapper
from StringIO import StringIO
-import utility
import doctest
+import bugdir
+import plugin
+import utility
+
class UserError(Exception):
def __init__(self, msg):
Exception.__init__(self, msg)
@@ -33,40 +34,6 @@ class UserErrorWrap(UserError):
UserError.__init__(self, str(exception))
self.exception = exception
-def get_bug(spec, bug_dir=None):
- """
- >>> bd = bugdir.simple_bug_dir()
- >>> bug_a = get_bug('a', bd)
- >>> print type(bug_a)
- <class 'libbe.bug.Bug'>
- >>> print bug_a
- a:om: Bug A
- >>> print bd.get_bug('a')
- a:om: Bug A
- >>> bug_a == bd.get_bug('a')
- True
- """
- matches = []
- try:
- if bug_dir is None:
- bug_dir = bugdir.tree_root('.')
- except bugdir.NoBugDir, e:
- raise UserErrorWrap(e)
- bugs = list(bug_dir.list())
- for bug in bugs:
- if bug.uuid.startswith(spec):
- matches.append(bug)
- if len(matches) > 1:
- raise UserError("More than one bug matches %s. Please be more"
- " specific." % spec)
- if len(matches) == 1:
- return matches[0]
-
- matches = []
- if len(matches) == 0:
- raise UserError("No bug matches %s" % spec)
- return matches[0]
-
def iter_commands():
for name, module in plugin.iter_plugins("becommands"):
yield name.replace("_", "-"), module
@@ -115,34 +82,6 @@ class UsageError(Exception):
def raise_get_help(option, opt, value, parser):
raise GetHelp
-
-def iter_comment_name(bug, unique_name):
- """Iterate through id, comment pairs, in date order.
- (This is a user-friendly id, not the comment uuid)
- """
- def key(comment):
- return comment.time
- for num, comment in enumerate(sorted(bug.list_comments(), key=key)):
- yield ("%s:%d" % (unique_name, num+1), comment)
-
-
-def comment_from_name(bug, unique_name, name):
- """Use a comment name to look up a comment"""
- for cur_name, comment in iter_comment_name(bug, unique_name):
- if name == cur_name:
- return comment
- raise KeyError(name)
-
-
-def get_bug_and_comment(identifier, bug_dir=None):
- ids = identifier.split(':')
- bug = get_bug(ids[0], bug_dir)
- if len(ids) == 2:
- comment = comment_from_name(bug, ids[0], identifier)
- else:
- comment = None
- return bug, comment
-
class CmdOptionParser(optparse.OptionParser):
def __init__(self, usage):
@@ -174,44 +113,6 @@ def underlined(instring):
return "%s\n%s" % (instring, "="*len(instring))
-def print_threaded_comments(comments, name_map, indent=""):
- """Print a threaded display of comments"""
- tw = TextWrapper(initial_indent = indent, subsequent_indent = indent,
- width=80)
- for comment, children in comments:
- s = StringIO()
- print >> s, "--------- Comment ---------"
- print >> s, "Name: %s" % name_map[comment.uuid]
- print >> s, "From: %s" % comment.From
- print >> s, "Date: %s\n" % utility.time_to_str(comment.time)
- print >> s, comment.body.rstrip('\n')
-
- s.seek(0)
- for line in s:
- print tw.fill(line).rstrip('\n')
- print_threaded_comments(children, name_map, indent=indent+" ")
-
-
-def bug_tree(dir=None):
- """Retrieve the bug tree specified by the user. If no directory is
- specified, the current working directory is used.
-
- :param dir: The directory to search for the bug tree in.
-
- >>> bug_tree() is not None
- True
- >>> bug_tree("/")
- Traceback (most recent call last):
- UserErrorWrap: The directory "/" has no bug directory.
- """
- if dir is None:
- dir = os.getcwd()
- try:
- return bugdir.tree_root(dir)
- except bugdir.NoBugDir, e:
- raise UserErrorWrap(e)
-
-
def _test():
import doctest
import sys
diff --git a/libbe/diff.py b/libbe/diff.py
index 9fa3816..95d5607 100644
--- a/libbe/diff.py
+++ b/libbe/diff.py
@@ -20,33 +20,24 @@ from libbe.utility import time_to_str
from libbe.bug import cmp_severity
import doctest
-def diff(old_tree, new_tree):
- old_bug_map = old_tree.bug_map()
- new_bug_map = new_tree.bug_map()
+def diff(old_bugdir, new_bugdir):
added = []
removed = []
modified = []
- for old_bug in old_bug_map.itervalues():
- new_bug = new_bug_map.get(old_bug.uuid)
+ for old_bug in old_bugdir:
+ new_bug = new_bugdir.bug_map.get(old_bug.uuid)
if new_bug is None :
removed.append(old_bug)
else:
if old_bug != new_bug:
modified.append((old_bug, new_bug))
- for new_bug in new_bug_map.itervalues():
- if not old_bug_map.has_key(new_bug.uuid):
+ for new_bug in new_bugdir:
+ if not old_bugdir.bug_map.has_key(new_bug.uuid):
added.append(new_bug)
return (removed, modified, added)
-
-def reference_diff(bugdir, revision=None):
- d = diff(bugdir.duplicate_bugdir(revision), bugdir)
- bugdir.remove_duplicate_bugdir()
- return d
-
def diff_report(diff_data, bug_dir):
(removed, modified, added) = diff_data
- bugs = list(bug_dir.list())
def modified_cmp(left, right):
return cmp_severity(left[1], right[1])
@@ -54,7 +45,7 @@ def diff_report(diff_data, bug_dir):
removed.sort(cmp_severity)
modified.sort(modified_cmp)
- if len(added) > 0:
+ if len(added) > 0:
print "New bug reports:"
for bug in added:
print bug.string(shortlist=True)
@@ -62,7 +53,7 @@ def diff_report(diff_data, bug_dir):
if len(modified) > 0:
printed = False
for old_bug, new_bug in modified:
- change_str = bug_changes(old_bug, new_bug, bugs)
+ change_str = bug_changes(old_bug, new_bug, bug_dir)
if change_str is None:
continue
if not printed:
@@ -73,7 +64,7 @@ def diff_report(diff_data, bug_dir):
if len(removed) > 0:
print "Removed bug reports:"
for bug in removed:
- print bug.string(bugs, shortlist=True)
+ print bug.string(shortlist=True)
def change_lines(old, new, attributes):
change_list = []
@@ -91,8 +82,8 @@ def bug_changes(old, new, bugs):
change_list = change_lines(old, new, ("time", "creator", "severity",
"target", "summary", "status", "assigned"))
- old_comment_ids = list(old.iter_comment_ids())
- new_comment_ids = list(new.iter_comment_ids())
+ old_comment_ids = [c.uuid for c in old.comment_root.traverse()]
+ new_comment_ids = [c.uuid for c in new.comment_root.traverse()]
change_strings = ["%s: %s -> %s" % f for f in change_list]
for comment_id in new_comment_ids:
if comment_id not in old_comment_ids:
@@ -105,8 +96,8 @@ def bug_changes(old, new, bugs):
if len(change_strings) == 0:
return None
- return "%s%s\n" % (new.string(bugs, shortlist=True),
- "\n".join(change_strings))
+ return "%s\n %s" % (new.string(shortlist=True),
+ " \n".join(change_strings))
def comment_summary(comment, status):
diff --git a/libbe/mapfile.py b/libbe/mapfile.py
index 8f69554..9a7fa8b 100644
--- a/libbe/mapfile.py
+++ b/libbe/mapfile.py
@@ -95,11 +95,11 @@ def parse(f):
f = utility.get_file(f)
result = {}
for line in f:
- line = line.rstrip('\n')
+ line = line.decode("utf-8").rstrip('\n')
if len(line) == 0:
continue
- name,value = [f.decode('utf-8') for f in line.split('=', 1)]
- assert not result.has_key('name')
+ name,value = [f for f in line.split('=', 1)]
+ assert not result.has_key(name)
result[name] = value
return result
diff --git a/libbe/names.py b/libbe/names.py
deleted file mode 100644
index 6e0378e..0000000
--- a/libbe/names.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (C) 2005 Aaron Bentley and Panometrics, Inc.
-# <abentley@panoramicfeedback.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-import os
-import sys
-import doctest
-
-def uuid():
- # this code borrowed from standard commands module
- # but adapted to win32
- pipe = os.popen('uuidgen', 'r')
- text = pipe.read()
- sts = pipe.close()
- if sts not in (0, None):
- raise "Failed to run uuidgen"
- if text[-1:] == '\n': text = text[:-1]
- return text
-
-def unique_name(bug, bugs):
- """
- Generate short names from uuids. Picks the minimum number of
- characters (>=3) from the beginning of the uuid such that the
- short names are unique.
-
- Obviously, as the number of bugs in the database grows, these
- short names will cease to be unique. The complete uuid should be
- used for long term reference.
- """
- chars = 3
- for some_bug in bugs:
- if bug.uuid == some_bug.uuid:
- continue
- while (bug.uuid[:chars] == some_bug.uuid[:chars]):
- chars+=1
- return bug.uuid[:chars]
-
-suite = doctest.DocTestSuite()
diff --git a/libbe/plugin.py b/libbe/plugin.py
index 05a4398..0964fba 100644
--- a/libbe/plugin.py
+++ b/libbe/plugin.py
@@ -36,6 +36,8 @@ def iter_plugins(prefix):
modfiles = os.listdir(os.path.join(plugin_path, prefix))
modfiles.sort()
for modfile in modfiles:
+ if modfile.startswith('.'):
+ continue # the occasional emacs temporary file
if modfile.endswith(".py") and modfile != "__init__.py":
yield modfile[:-3], my_import(prefix+"."+modfile[:-3])
diff --git a/libbe/rcs.py b/libbe/rcs.py
index 2993a80..abd92cb 100644
--- a/libbe/rcs.py
+++ b/libbe/rcs.py
@@ -24,7 +24,7 @@ import tempfile
import shutil
import unittest
import doctest
-from utility import Dir
+from utility import Dir, search_parent_directories
def _get_matching_rcs(matchfn):
"""Return the first module for which matchfn(RCS_instance) is true"""
@@ -32,9 +32,9 @@ def _get_matching_rcs(matchfn):
import bzr
import hg
import git
- for module in [arch, bzr, hg, git]:
+ for module in [git, arch, bzr, hg, git]:
rcs = module.new()
- if matchfn(rcs):
+ if matchfn(rcs) == True:
return rcs
else:
del(rcs)
@@ -62,6 +62,9 @@ class CommandError(Exception):
class SettingIDnotSupported(NotImplementedError):
pass
+class PathNotInRoot(Exception):
+ pass
+
def new():
return RCS()
@@ -152,7 +155,10 @@ class RCS(object):
pass
def _rcs_get_file_contents(self, path, revision=None):
"""
- Get the file as it was in a given revision.
+ Get the file contents as they were in a given revision. Don't
+ worry about decoding the contents, the RCS.get_file_contents()
+ method will handle that.
+
Revision==None specifies the current revision.
"""
assert revision == None, \
@@ -180,7 +186,7 @@ class RCS(object):
if e.errno == errno.ENOENT:
return False
raise e
- def detect(self, path=None):
+ def detect(self, path="."):
"""
Detect whether a directory is revision controlled with this RCS.
"""
@@ -264,23 +270,28 @@ class RCS(object):
Revision==None specifies the current revision.
"""
relpath = self._u_rel_path(path)
- return self._rcs_get_file_contents(relpath, revision)
+ return self._rcs_get_file_contents(relpath, revision).decode("utf-8")
def set_file_contents(self, path, contents):
"""
Set the file contents under version control.
"""
add = not os.path.exists(path)
- file(path, "wb").write(contents)
+ file(path, "wb").write(contents.encode("utf-8"))
if add:
self.add(path)
else:
self.update(path)
def mkdir(self, path):
"""
- Created directory at path under version control.
+ Create (if neccessary) a directory at path under version
+ control.
"""
- os.mkdir(path)
- self.add(path)
+ if not os.path.exists(path):
+ os.mkdir(path)
+ self.add(path)
+ else:
+ assert os.path.isdir(path)
+ self.update(path)
def duplicate_repo(self, revision=None):
"""
Get the repository as it was in a given revision.
@@ -366,16 +377,7 @@ class RCS(object):
/.be
or None if none of those files exist.
"""
- path = os.path.realpath(path)
- assert os.path.exists(path)
- old_path = None
- while True:
- if os.path.exists(os.path.join(path, filename)):
- return os.path.join(path, filename)
- if path == old_path:
- return None
- old_path = path
- path = os.path.dirname(path)
+ return search_parent_directories(path, filename)
def _u_rel_path(self, path, root=None):
"""
Return the relative path to path from root.
@@ -389,8 +391,9 @@ class RCS(object):
if os.path.isabs(path):
absRoot = os.path.abspath(root)
absRootSlashedDir = os.path.join(absRoot,"")
- assert path.startswith(absRootSlashedDir), \
- "file %s not in root %s" % (path, absRootSlashedDir)
+ if not path.startswith(absRootSlashedDir):
+ raise PathNotInRoot, \
+ "file %s not in root %s" % (path, absRootSlashedDir)
assert path != absRootSlashedDir, \
"file %s == root directory %s" % (path, absRootSlashedDir)
path = path[len(absRootSlashedDir):]
diff --git a/libbe/utility.py b/libbe/utility.py
index f595bdb..81023cd 100644
--- a/libbe/utility.py
+++ b/libbe/utility.py
@@ -71,6 +71,32 @@ def get_file(f):
else:
return f
+def search_parent_directories(path, filename):
+ """
+ Find the file (or directory) named filename in path or in any
+ of path's parents.
+
+ e.g.
+ search_parent_directories("/a/b/c", ".be")
+ will return the path to the first existing file from
+ /a/b/c/.be
+ /a/b/.be
+ /a/.be
+ /.be
+ or None if none of those files exist.
+ """
+ path = os.path.realpath(path)
+ assert os.path.exists(path)
+ old_path = None
+ while True:
+ check_path = os.path.join(path, filename)
+ if os.path.exists(check_path):
+ return check_path
+ if path == old_path:
+ return None
+ old_path = path
+ path = os.path.dirname(path)
+
class Dir:
"A temporary directory for testing use"
def __init__(self):
diff --git a/test.py b/test.py
index 9af153b..bf57d1e 100644
--- a/test.py
+++ b/test.py
@@ -1,11 +1,11 @@
-"""Usage: python test.py [module]
+"""Usage: python test.py [module(s) ...]
-When called without an optional module name, run the doctests from
-*all* modules. This may raise lots of errors if you haven't installed
-one of the versioning control systems.
+When called without optional module names, run the doctests from *all*
+modules. This may raise lots of errors if you haven't installed one
+of the versioning control systems.
-When called with an optional module name, only run the doctests from
-that module.
+When called with module name arguments, only run the doctests from
+those modules.
"""
from libbe import plugin
@@ -16,19 +16,19 @@ import sys
suite = unittest.TestSuite()
if len(sys.argv) > 1:
- submodname = sys.argv[1]
- match = False
- mod = plugin.get_plugin("libbe", submodname)
- if mod is not None and hasattr(mod, "suite"):
- suite.addTest(mod.suite)
- match = True
- mod = plugin.get_plugin("becommands", submodname)
- if mod is not None:
- suite.addTest(doctest.DocTestSuite(mod))
- match = True
- if not match:
- print "No modules match \"%s\"" % submodname
- sys.exit(1)
+ for submodname in sys.argv[1:]:
+ match = False
+ mod = plugin.get_plugin("libbe", submodname)
+ if mod is not None and hasattr(mod, "suite"):
+ suite.addTest(mod.suite)
+ match = True
+ mod = plugin.get_plugin("becommands", submodname)
+ if mod is not None:
+ suite.addTest(doctest.DocTestSuite(mod))
+ match = True
+ if not match:
+ print "No modules match \"%s\"" % submodname
+ sys.exit(1)
else:
failed = False
for modname,module in plugin.iter_plugins("libbe"):