diff options
author | W. Trevor King <wking@drexel.edu> | 2010-01-21 13:14:08 -0500 |
---|---|---|
committer | W. Trevor King <wking@drexel.edu> | 2010-01-21 13:14:08 -0500 |
commit | 36b970de8e5a4b2e1b91372742ce86819c4254b5 (patch) | |
tree | 4ef1870c35dd3b6daaaf3f7453a4bd60ec33c149 /libbe | |
parent | 4ad9a6d7b17db9abe7d4c11477df1df7c6eac5e5 (diff) | |
parent | 508c0c0ec73bdcb802d18b30a6e5f40a04dfed52 (diff) | |
download | bugseverywhere-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.py | 29 | ||||
-rw-r--r-- | libbe/command/commit.py | 2 | ||||
-rw-r--r-- | libbe/command/help.py | 2 | ||||
-rw-r--r-- | libbe/command/html.py | 5 | ||||
-rw-r--r-- | libbe/command/import_xml.py | 112 | ||||
-rw-r--r-- | libbe/command/list.py | 40 | ||||
-rw-r--r-- | libbe/command/new.py | 6 | ||||
-rw-r--r-- | libbe/command/target.py | 18 | ||||
-rw-r--r-- | libbe/command/util.py | 21 | ||||
-rw-r--r-- | libbe/storage/util/settings_object.py | 28 | ||||
-rw-r--r-- | libbe/storage/vcs/arch.py | 1 | ||||
-rw-r--r-- | libbe/storage/vcs/base.py | 15 | ||||
-rw-r--r-- | libbe/storage/vcs/hg.py | 16 | ||||
-rw-r--r-- | libbe/ui/command_line.py | 25 |
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' |