aboutsummaryrefslogtreecommitdiffstats
path: root/libbe
diff options
context:
space:
mode:
authorW. Trevor King <wking@drexel.edu>2010-01-21 13:14:08 -0500
committerW. Trevor King <wking@drexel.edu>2010-01-21 13:14:08 -0500
commit36b970de8e5a4b2e1b91372742ce86819c4254b5 (patch)
tree4ef1870c35dd3b6daaaf3f7453a4bd60ec33c149 /libbe
parent4ad9a6d7b17db9abe7d4c11477df1df7c6eac5e5 (diff)
parent508c0c0ec73bdcb802d18b30a6e5f40a04dfed52 (diff)
downloadbugseverywhere-36b970de8e5a4b2e1b91372742ce86819c4254b5.tar.gz
Merge assorted bugfixes and optimizations.
Highlights: * `be new` adds creator field like its supposed to (oops :p). * `be list --xml` uses <be-xml> format (was <bugs>). * `be import-xml` handles root comments appropriately. * `be` raises an appropriate help message. * `be help` works. * `be html` prints Comment.id.user() information. * better SavedSettingsObject._get_saved_settings() avoids data loss. * be-mbox-to-xml -> be-mail-to-xml and adds assorted format support. * be-xml-to-mbox and be-handle-mail work with new libbe layout. * BugDir.uuids() now caches on-disk uuids for speed. * Mercurial detection works for mercurial <= 1.1.2 _and_ >= 1.2 * Fix bugs in VCS._children() relative/absolute path handling.
Diffstat (limited to 'libbe')
-rw-r--r--libbe/bugdir.py29
-rw-r--r--libbe/command/commit.py2
-rw-r--r--libbe/command/help.py2
-rw-r--r--libbe/command/html.py5
-rw-r--r--libbe/command/import_xml.py112
-rw-r--r--libbe/command/list.py40
-rw-r--r--libbe/command/new.py6
-rw-r--r--libbe/command/target.py18
-rw-r--r--libbe/command/util.py21
-rw-r--r--libbe/storage/util/settings_object.py28
-rw-r--r--libbe/storage/vcs/arch.py1
-rw-r--r--libbe/storage/vcs/base.py15
-rw-r--r--libbe/storage/vcs/hg.py16
-rw-r--r--libbe/ui/command_line.py25
14 files changed, 247 insertions, 73 deletions
diff --git a/libbe/bugdir.py b/libbe/bugdir.py
index 5967a7e..8389716 100644
--- a/libbe/bugdir.py
+++ b/libbe/bugdir.py
@@ -234,23 +234,22 @@ class BugDir (list, settings_object.SavedSettingsObject):
# methods for managing bugs
- def uuids(self):
- uuids = []
- # list the uuids in memory
- for bug in self:
- uuids.append(bug.uuid)
- yield bug.uuid
- if self.storage != None and self.storage.is_readable():
- # and the ones that are still just in storage
- child_uuids = libbe.util.id.child_uuids(
- self.storage.children(self.id.storage()))
- for id in child_uuids:
- if id not in uuids:
- yield id
+ def uuids(self, use_cached_disk_uuids=True):
+ if use_cached_disk_uuids==False or not hasattr(self, '_uuids_cache'):
+ self._uuids_cache = []
+ # list bugs that are in storage
+ if self.storage != None and self.storage.is_readable():
+ child_uuids = libbe.util.id.child_uuids(
+ self.storage.children(self.id.storage()))
+ for id in child_uuids:
+ self._uuids_cache.append(id)
+ return list(set([bug.uuid for bug in self] + self._uuids_cache))
def _clear_bugs(self):
while len(self) > 0:
self.pop()
+ if hasattr(self, '_uuids_cache'):
+ del(self._uuids_cache)
self._bug_map_gen()
def _load_bug(self, uuid):
@@ -264,9 +263,13 @@ class BugDir (list, settings_object.SavedSettingsObject):
from_storage=False)
self.append(bg)
self._bug_map_gen()
+ if hasattr(self, '_uuids_cache') and not bg.uuid in self._uuids_cache:
+ self._uuids_cache.append(bg.uuid)
return bg
def remove_bug(self, bug):
+ if hasattr(self, '_uuids_cache') and bug.uuid in self._uuids_cache:
+ self._uuids_cache.remove(bug.uuid)
self.remove(bug)
if self.storage != None and self.storage.is_writeable():
bug.remove()
diff --git a/libbe/command/commit.py b/libbe/command/commit.py
index f4c275c..fd15630 100644
--- a/libbe/command/commit.py
+++ b/libbe/command/commit.py
@@ -38,7 +38,7 @@ class Commit (libbe.command.Command):
>>> bd.extra_strings = ['hi there']
>>> bd.flush_reload()
- >>> ui.run(cmd, {'user-id':'Joe'}, ['Making a commit']) # doctest: +ELLIPSIS
+ >>> ui.run(cmd, args=['Making a commit']) # doctest: +ELLIPSIS
Committed ...
>>> ui.cleanup()
>>> bd.cleanup()
diff --git a/libbe/command/help.py b/libbe/command/help.py
index 8e66405..1fc88f0 100644
--- a/libbe/command/help.py
+++ b/libbe/command/help.py
@@ -58,7 +58,7 @@ class Help (libbe.command.Command):
def _run(self, **params):
if params['topic'] == None:
if hasattr(self.ui, 'help'):
- self.ui.help()
+ print >> self.stdout, self.ui.help().rstrip('\n')
elif params['topic'] in libbe.command.commands():
module = libbe.command.get_command(params['topic'])
Class = libbe.command.get_command_class(module,params['topic'])
diff --git a/libbe/command/html.py b/libbe/command/html.py
index d0985cc..0b4cf89 100644
--- a/libbe/command/html.py
+++ b/libbe/command/html.py
@@ -223,7 +223,7 @@ class HTMLGen (object):
comment_entries.append('<div class="comment root">')
else:
comment_entries.append('<div class="comment">')
- template_info = {}
+ template_info = {'shortname': comment.id.user()}
for attr in ['uuid', 'author', 'date', 'body']:
value = getattr(comment, attr)
if attr == 'body':
@@ -611,7 +611,8 @@ class HTMLGen (object):
<td class="bug_comment_label">Comment:</td>
<td class="bug_comment">
--------- Comment ---------<br/>
- Name: %(uuid)s<br/>
+ ID: %(uuid)s<br/>
+ Short name: %(shortname)s<br/>
From: %(author)s<br/>
Date: %(date)s<br/>
<br/>
diff --git a/libbe/command/import_xml.py b/libbe/command/import_xml.py
index 0656154..598ecb8 100644
--- a/libbe/command/import_xml.py
+++ b/libbe/command/import_xml.py
@@ -194,10 +194,19 @@ class Import_XML (libbe.command.Command):
# protect against programmer error causing data loss:
if croot_bug != None:
- comms = [c.uuid for c in croot_comment.traverse()]
+ comms = []
+ for c in croot_comment.traverse():
+ comms.append(c.uuid)
+ if c.alt_id != None:
+ comms.append(c.alt_id)
+ if croot_comment.uuid == libbe.comment.INVALID_UUID:
+ root_text = croot_bug.id.user()
+ else:
+ root_text = croot_comment.id.user()
for new in root_comments:
- assert new.uuid in comms, \
- "comment %s wasn't added to %s" % (new.uuid, croot_comment.uuid)
+ assert new.uuid in comms or new.alt_id in comms, \
+ "comment %s (alt: %s) wasn't added to %s" \
+ % (new.uuid, new.alt_id, root_text)
for new in root_bugs:
if not new in merged_bugs:
assert bugdir.has_bug(new.uuid), \
@@ -364,24 +373,39 @@ if libbe.TESTING == True:
</bug>
</be-xml>
"""
+ self.root_comment_xml = """
+ <be-xml>
+ <comment>
+ <uuid>c1</uuid>
+ <body>So long</body>
+ </comment>
+ <comment>
+ <uuid>c3</uuid>
+ <author>Jed</author>
+ <body>And thanks</body>
+ </comment>
+ </be-xml>
+ """
def tearDown(self):
self.bugdir.cleanup()
self.ui.cleanup()
- def _execute(self, params={}, args=[]):
- self.ui.io.set_stdin(self.xml)
+ def _execute(self, xml, params={}, args=[]):
+ self.ui.io.set_stdin(xml)
self.ui.run(self.cmd, params, args)
self.bugdir.flush_reload()
def testCleanBugdir(self):
uuids = list(self.bugdir.uuids())
self.failUnless(uuids == ['b'], uuids)
def testNotAddOnly(self):
- self._execute({}, ['-'])
+ bugB = self.bugdir.bug_from_uuid('b')
+ self._execute(self.xml, {}, ['-'])
uuids = list(self.bugdir.uuids())
self.failUnless(uuids == ['b'], uuids)
bugB = self.bugdir.bug_from_uuid('b')
self.failUnless(bugB.uuid == 'b', bugB.uuid)
self.failUnless(bugB.creator == 'John', bugB.creator)
self.failUnless(bugB.status == 'fixed', bugB.status)
+ self.failUnless(bugB.summary == 'a test bug', bugB.summary)
estrs = ["don't forget your towel",
'helps with space travel',
'watch out for flying dolphins']
@@ -408,13 +432,87 @@ if libbe.TESTING == True:
self.failUnless(c4.author == 'Jed', c4.author)
self.failUnless(c4.body == 'And thanks\n', c4.body)
def testAddOnly(self):
- self._execute({'add-only':True}, ['-'])
+ bugB = self.bugdir.bug_from_uuid('b')
+ initial_bugB_summary = bugB.summary
+ self._execute(self.xml, {'add-only':True}, ['-'])
+ uuids = list(self.bugdir.uuids())
+ self.failUnless(uuids == ['b'], uuids)
+ bugB = self.bugdir.bug_from_uuid('b')
+ self.failUnless(bugB.uuid == 'b', bugB.uuid)
+ self.failUnless(bugB.creator == 'John', bugB.creator)
+ self.failUnless(bugB.status == 'open', bugB.status)
+ self.failUnless(bugB.summary == initial_bugB_summary, bugB.summary)
+ estrs = ["don't forget your towel",
+ 'helps with space travel']
+ self.failUnless(bugB.extra_strings == estrs, bugB.extra_strings)
+ comments = list(bugB.comments())
+ self.failUnless(len(comments) == 3,
+ ['%s (%s)' % (c.uuid, c.alt_id) for c in comments])
+ c1 = bugB.comment_from_uuid('c1')
+ comments.remove(c1)
+ self.failUnless(c1.uuid == 'c1', c1.uuid)
+ self.failUnless(c1.alt_id == None, c1.alt_id)
+ self.failUnless(c1.author == 'Jane', c1.author)
+ self.failUnless(c1.body == 'Hello\n', c1.body)
+ c2 = bugB.comment_from_uuid('c2')
+ comments.remove(c2)
+ self.failUnless(c2.uuid == 'c2', c2.uuid)
+ self.failUnless(c2.alt_id == None, c2.alt_id)
+ self.failUnless(c2.author == 'Jess', c2.author)
+ self.failUnless(c2.body == 'World\n', c2.body)
+ c4 = comments[0]
+ self.failUnless(len(c4.uuid) == 36, c4.uuid)
+ self.failUnless(c4.alt_id == 'c3', c4.alt_id)
+ self.failUnless(c4.author == 'Jed', c4.author)
+ self.failUnless(c4.body == 'And thanks\n', c4.body)
+ def testRootCommentsNotAddOnly(self):
+ bugB = self.bugdir.bug_from_uuid('b')
+ initial_bugB_summary = bugB.summary
+ self._execute(self.root_comment_xml, {'comment-root':'/b'}, ['-'])
+ uuids = list(self.bugdir.uuids())
+ uuids = list(self.bugdir.uuids())
+ self.failUnless(uuids == ['b'], uuids)
+ bugB = self.bugdir.bug_from_uuid('b')
+ self.failUnless(bugB.uuid == 'b', bugB.uuid)
+ self.failUnless(bugB.creator == 'John', bugB.creator)
+ self.failUnless(bugB.status == 'open', bugB.status)
+ self.failUnless(bugB.summary == initial_bugB_summary, bugB.summary)
+ estrs = ["don't forget your towel",
+ 'helps with space travel']
+ self.failUnless(bugB.extra_strings == estrs, bugB.extra_strings)
+ comments = list(bugB.comments())
+ self.failUnless(len(comments) == 3,
+ ['%s (%s, %s)' % (c.uuid, c.alt_id, c.body)
+ for c in comments])
+ c1 = bugB.comment_from_uuid('c1')
+ comments.remove(c1)
+ self.failUnless(c1.uuid == 'c1', c1.uuid)
+ self.failUnless(c1.alt_id == None, c1.alt_id)
+ self.failUnless(c1.author == 'Jane', c1.author)
+ self.failUnless(c1.body == 'So long\n', c1.body)
+ c2 = bugB.comment_from_uuid('c2')
+ comments.remove(c2)
+ self.failUnless(c2.uuid == 'c2', c2.uuid)
+ self.failUnless(c2.alt_id == None, c2.alt_id)
+ self.failUnless(c2.author == 'Jess', c2.author)
+ self.failUnless(c2.body == 'World\n', c2.body)
+ c4 = comments[0]
+ self.failUnless(len(c4.uuid) == 36, c4.uuid)
+ self.failUnless(c4.alt_id == 'c3', c4.alt_id)
+ self.failUnless(c4.author == 'Jed', c4.author)
+ self.failUnless(c4.body == 'And thanks\n', c4.body)
+ def testRootCommentsAddOnly(self):
+ bugB = self.bugdir.bug_from_uuid('b')
+ initial_bugB_summary = bugB.summary
+ self._execute(self.root_comment_xml,
+ {'comment-root':'/b', 'add-only':True}, ['-'])
uuids = list(self.bugdir.uuids())
self.failUnless(uuids == ['b'], uuids)
bugB = self.bugdir.bug_from_uuid('b')
self.failUnless(bugB.uuid == 'b', bugB.uuid)
self.failUnless(bugB.creator == 'John', bugB.creator)
self.failUnless(bugB.status == 'open', bugB.status)
+ self.failUnless(bugB.summary == initial_bugB_summary, bugB.summary)
estrs = ["don't forget your towel",
'helps with space travel']
self.failUnless(bugB.extra_strings == estrs, bugB.extra_strings)
diff --git a/libbe/command/list.py b/libbe/command/list.py
index 8baeaa2..44be71b 100644
--- a/libbe/command/list.py
+++ b/libbe/command/list.py
@@ -23,6 +23,8 @@ import re
import libbe
import libbe.bug
import libbe.command
+import libbe.command.depend
+import libbe.command.target
import libbe.command.util
# get a list of * for cmp_*() comparing two bugs.
@@ -30,19 +32,31 @@ AVAILABLE_CMPS = [fn[4:] for fn in dir(libbe.bug) if fn[:4] == 'cmp_']
AVAILABLE_CMPS.remove('attr') # a cmp_* template.
class Filter (object):
- def __init__(self, status, severity, assigned, extra_strings_regexps):
+ def __init__(self, status='all', severity='all', assigned='all',
+ target='all', extra_strings_regexps=[]):
self.status = status
self.severity = severity
self.assigned = assigned
+ self.target = target
self.extra_strings_regexps = extra_strings_regexps
- def __call__(self, bug):
- if self.status != "all" and not bug.status in self.status:
+ def __call__(self, bugdir, bug):
+ if self.status != 'all' and not bug.status in self.status:
return False
- if self.severity != "all" and not bug.severity in self.severity:
+ if self.severity != 'all' and not bug.severity in self.severity:
return False
- if self.assigned != "all" and not bug.assigned in self.assigned:
+ if self.assigned != 'all' and not bug.assigned in self.assigned:
return False
+ if self.target == 'all':
+ pass
+ else:
+ target_bug = libbe.command.target.bug_target(bugdir, bug)
+ if self.target in ['none', None]:
+ if target_bug.summary != None:
+ return False
+ else:
+ if target_bug.summary != self.target:
+ return False
if len(bug.extra_strings) == 0:
if len(self.extra_strings_regexps) > 0:
return False
@@ -140,9 +154,10 @@ class List (libbe.command.Command):
bugdir.storage.writeable = False
cmp_list, status, severity, assigned, extra_strings_regexps = \
self._parse_params(params)
- filter = Filter(status, severity, assigned, extra_strings_regexps)
+ filter = Filter(status, severity, assigned,
+ extra_strings_regexps=extra_strings_regexps)
bugs = [bugdir.bug_from_uuid(uuid) for uuid in bugdir.uuids()]
- bugs = [b for b in bugs if filter(b) == True]
+ bugs = [b for b in bugs if filter(bugdir, b) == True]
self.result = bugs
if len(bugs) == 0 and params['xml'] == False:
print >> self.stdout, "No matching bugs found"
@@ -191,13 +206,8 @@ class List (libbe.command.Command):
if params['assigned'] == "all":
assigned = "all"
else:
- possible_assignees = []
- for bug in self.bugdir:
- if bug.assigned != None \
- and not bug.assigned in possible_assignees:
- possible_assignees.append(bug.assigned)
assigned = libbe.command.util.select_values(
- params['assigned'], possible_assignees)
+ params['assigned'], libbe.command.util.assignees())
for i in range(len(assigned)):
if assigned[i] == '-':
assigned[i] = params['user-id']
@@ -218,7 +228,7 @@ class List (libbe.command.Command):
if xml == True:
print >> self.stdout, \
'<?xml version="1.0" encoding="%s" ?>' % self.stdout.encoding
- print >> self.stdout, '<bugs>'
+ print >> self.stdout, '<be-xml>'
if len(bugs) > 0:
for bug in bugs:
if xml == True:
@@ -226,7 +236,7 @@ class List (libbe.command.Command):
else:
print >> self.stdout, bug.string(shortlist=True)
if xml == True:
- print >> self.stdout, '</bugs>'
+ print >> self.stdout, '</be-xml>'
def _long_help(self):
return """
diff --git a/libbe/command/new.py b/libbe/command/new.py
index ac0659b..be18306 100644
--- a/libbe/command/new.py
+++ b/libbe/command/new.py
@@ -38,6 +38,7 @@ class New (libbe.command.Command):
>>> uuid_gen = libbe.util.id.uuid_gen
>>> libbe.util.id.uuid_gen = lambda: 'X'
+ >>> ui._user_id = u'Fran\\xe7ois'
>>> ret = ui.run(cmd, args=['this is a test',])
Created bug with ID abc/X
>>> libbe.util.id.uuid_gen = uuid_gen
@@ -45,6 +46,10 @@ class New (libbe.command.Command):
>>> bug = bd.bug_from_uuid('X')
>>> print bug.summary
this is a test
+ >>> bug.creator
+ u'Fran\\xe7ois'
+ >>> bug.reporter
+ u'Fran\\xe7ois'
>>> bug.time <= int(time.time())
True
>>> print bug.severity
@@ -80,6 +85,7 @@ class New (libbe.command.Command):
summary = params['summary']
bugdir = self._get_bugdir()
bug = bugdir.new_bug(summary=summary.strip())
+ bug.creator = self._get_user_id()
if params['reporter'] != None:
bug.reporter = params['reporter']
else:
diff --git a/libbe/command/target.py b/libbe/command/target.py
index 0161772..6bb348f 100644
--- a/libbe/command/target.py
+++ b/libbe/command/target.py
@@ -46,6 +46,7 @@ class Target (libbe.command.Command):
>>> ui.io.stdout = StringIO.StringIO()
>>> ret = ui.run(cmd, {'resolve':True}, ['tomorrow'])
>>> output = ui.io.get_stdout().strip()
+ >>> bd.flush_reload()
>>> target = bd.bug_from_uuid(output)
>>> print target.summary
tomorrow
@@ -185,15 +186,24 @@ def add_target(bugdir, bug, summary):
return target
def targets(bugdir):
+ """Generate all possible target bug summaries."""
bugdir.load_all_bugs()
for bug in bugdir:
if bug.severity == 'target':
yield bug.summary
-def complete_target(command, argument, fragment=None):
+def target_dict(bugdir):
"""
- List possible command completions for fragment.
-
- argument argument is not used.
+ Return a dict with bug UUID keys and bug summary values for all
+ target bugs.
"""
+ ret = {}
+ bugdir.load_all_bugs()
+ for bug in bugdir:
+ if bug.severity == 'target':
+ ret[bug.uuid] = bug.summary
+ return ret
+
+def complete_target(command, argument, fragment=None):
+ """List possible command completions for fragment."""
return targets(command._get_bugdir())
diff --git a/libbe/command/util.py b/libbe/command/util.py
index c9618ad..977b596 100644
--- a/libbe/command/util.py
+++ b/libbe/command/util.py
@@ -34,12 +34,8 @@ def complete_command(command, argument, fragment=None):
"""
return list(libbe.command.commands())
-def complete_path(command, argument, fragment=None):
- """
- List possible path completions for fragment.
-
- command argument is not used.
- """
+def comp_path(fragment=None):
+ """List possible path completions for fragment."""
if fragment == None:
fragment = '.'
comps = glob.glob(fragment+'*') + glob.glob(fragment+'/*')
@@ -47,6 +43,10 @@ def complete_path(command, argument, fragment=None):
comps.extend(glob.glob(comps[0]+'/*'))
return comps
+def complete_path(command, argument, fragment=None):
+ """List possible path completions for fragment."""
+ return comp_path(fragment)
+
def complete_status(command, argument, fragment=None):
bd = command._get_bugdir()
import libbe.bug
@@ -57,10 +57,13 @@ def complete_severity(command, argument, fragment=None):
import libbe.bug
return libbe.bug.severity_values
+def assignees(bugdir):
+ bugdir.load_all_bugs()
+ return list(set([bug.assigned for bug in bugdir
+ if bug.assigned != None]))
+
def complete_assigned(command, argument, fragment=None):
- if fragment == None:
- return []
- return [fragment]
+ return assignees(command._get_bugdir())
def complete_extra_strings(command, argument, fragment=None):
if fragment == None:
diff --git a/libbe/storage/util/settings_object.py b/libbe/storage/util/settings_object.py
index 9f2b7af..ca94f23 100644
--- a/libbe/storage/util/settings_object.py
+++ b/libbe/storage/util/settings_object.py
@@ -204,18 +204,31 @@ class SavedSettingsObject(object):
self._settings_loaded = True
def save_settings(self):
- """Load the settings from disk."""
+ """Save the settings to disk."""
# Override. Should save the dict output of ._get_saved_settings()
settings = self._get_saved_settings()
pass # write settings to disk....
def _get_saved_settings(self):
+ """
+ In order to avoid overwriting unread on-disk data, make sure
+ we've loaded anything sitting on the disk. In the current
+ implementation, all the settings are stored in a single file,
+ so we need to load _all_ the saved settings. Another approach
+ would be per-setting saves, in which case you could skip this
+ step, since any setting changes would have forced that setting
+ load already.
+ """
settings = {}
- for k,v in self.settings.items():
- if v != None and v != EMPTY:
- settings[k] = v
- for k in self.required_saved_properties:
- settings[k] = getattr(self, self._setting_name_to_attr_name(k))
+ for k in self.settings_properties:
+ if k in self.settings and \
+ not self.settings[k] in [None, EMPTY]:
+ settings[k] = self.settings[k]
+ else:
+ value = getattr(
+ self, self._setting_name_to_attr_name(k))
+ if value not in [None, EMPTY, []]:
+ settings[k] = value
return settings
def clear_cached_setting(self, setting=None):
@@ -313,7 +326,8 @@ if libbe.TESTING == True:
self.failUnless(t.content_type == "text/plain", t.content_type)
self.failUnless(t.settings["Content-type"] == EMPTY,
t.settings["Content-type"])
- self.failUnless(t._get_saved_settings() == {},
+ self.failUnless(t._get_saved_settings() ==
+ {"Content-type":"text/plain"},
t._get_saved_settings())
t.content_type = "text/html"
self.failUnless(t.content_type == "text/html",
diff --git a/libbe/storage/vcs/arch.py b/libbe/storage/vcs/arch.py
index f9b01fd..74ba371 100644
--- a/libbe/storage/vcs/arch.py
+++ b/libbe/storage/vcs/arch.py
@@ -304,7 +304,6 @@ class Arch(base.VCS):
self._invoke_client(
'file-find', '--unescaped', path, revision)
relpath = output.rstrip('\n').splitlines()[-1]
- print >> sys.stderr, 'getting', relpath
return base.VCS._vcs_get_file_contents(self, relpath)
def _vcs_path(self, id, revision):
diff --git a/libbe/storage/vcs/base.py b/libbe/storage/vcs/base.py
index 15460b0..9fc43c1 100644
--- a/libbe/storage/vcs/base.py
+++ b/libbe/storage/vcs/base.py
@@ -749,7 +749,8 @@ os.listdir(self.get_path("bugs")):
if revision == None:
id_to_path = self._cached_path_id.path
else:
- id_to_path = lambda id : self._vcs_path(id, revision)
+ id_to_path = lambda id : os.path.join(
+ self.repo, self._vcs_path(id, revision))
if id==None:
path = self.be_dir
else:
@@ -772,9 +773,12 @@ os.listdir(self.get_path("bugs")):
isdir = os.path.isdir
listdir = os.listdir
else:
- id_to_path = lambda id : self._vcs_path(id, revision)
- isdir = lambda path : self._vcs_isdir(path, revision)
- listdir = lambda path : self._vcs_listdir(path, revision)
+ id_to_path = lambda id : os.path.join(
+ self.repo, self._vcs_path(id, revision))
+ isdir = lambda path : self._vcs_isdir(
+ self._u_rel_path(path), revision)
+ listdir = lambda path : self._vcs_listdir(
+ self._u_rel_path(path), revision)
if id==None:
path = self.be_dir
else:
@@ -1046,7 +1050,8 @@ os.listdir(self.get_path("bugs")):
if revision == None: # don't require connection
return libbe.util.encoding.get_file_contents(
path, decode=True).rstrip('\n')
- contents = self._vcs_get_file_contents(path, revision=revision)
+ relpath = self._u_rel_path(path)
+ contents = self._vcs_get_file_contents(relpath, revision=revision)
if type(contents) != types.UnicodeType:
contents = unicode(contents, self.encoding)
return contents.strip()
diff --git a/libbe/storage/vcs/hg.py b/libbe/storage/vcs/hg.py
index 076943a..088a141 100644
--- a/libbe/storage/vcs/hg.py
+++ b/libbe/storage/vcs/hg.py
@@ -23,11 +23,21 @@ Mercurial (hg) backend.
try:
import mercurial
- import mercurial.version
import mercurial.dispatch
import mercurial.ui
except ImportError:
mercurial = None
+
+try:
+ # mercurial >= 1.2
+ from mercurial.util import version
+except ImportError:
+ try:
+ # mercurial <= 1.1.2
+ from mercurial.version import get_version as version
+ except ImportError:
+ version = None
+
import os
import os.path
import re
@@ -57,9 +67,9 @@ class Hg(base.VCS):
self.__updated = [] # work around http://mercurial.selenic.com/bts/issue618
def _vcs_version(self):
- if mercurial == None:
+ if version == None:
return None
- return mercurial.version.get_version()
+ return version()
def _u_invoke_client(self, *args, **kwargs):
if 'cwd' not in kwargs:
diff --git a/libbe/ui/command_line.py b/libbe/ui/command_line.py
index 7ba6cf5..89d791d 100644
--- a/libbe/ui/command_line.py
+++ b/libbe/ui/command_line.py
@@ -250,6 +250,16 @@ class BE (libbe.command.Command):
def full_version(self, *args):
return libbe.version.version(verbose=True)
+class CommandLine (libbe.command.UserInterface):
+ def __init__(self, *args, **kwargs):
+ libbe.command.UserInterface.__init__(self, *args, **kwargs)
+ self.restrict_file_access = False
+ self.storage_callbacks = None
+ def help(self):
+ be = BE(ui=self)
+ self.setup_command(be)
+ return be.help()
+
def dispatch(ui, command, args):
parser = CmdOptionParser(command)
try:
@@ -273,9 +283,7 @@ def dispatch(ui, command, args):
def main():
io = libbe.command.StdInputOutput()
- ui = libbe.command.UserInterface(io)
- ui.restrict_file_access = False
- ui.storage_callbacks = None
+ ui = CommandLine(io)
be = BE(ui=ui)
ui.setup_command(be)
@@ -285,7 +293,14 @@ def main():
except CallbackExit:
return 0
except libbe.command.UserError, e:
- print >> ui.io.stdout, 'ERROR:\n', e
+ if str(e).endswith('COMMAND'):
+ # no command given, print usage string
+ print >> ui.io.stdout, 'ERROR:'
+ print >> ui.io.stdout, be.usage(), '\n', e
+ print >> ui.io.stdout, 'For example, try'
+ print >> ui.io.stdout, ' be help'
+ else:
+ print >> ui.io.stdout, 'ERROR:\n', e
return 1
command_name = args.pop(0)
@@ -299,7 +314,7 @@ def main():
command = Class(ui=ui)
ui.setup_command(command)
- if command.name in ['comment', 'commit', 'serve']:
+ if command.name in ['comment', 'commit', 'import-xml', 'serve']:
paginate = 'never'
else:
paginate = 'auto'