6 commits - pykolab/cli pykolab/Makefile.am pykolab/utils.py

Jeroen van Meeuwen vanmeeuwen at kolabsys.com
Sat Nov 10 18:06:08 CET 2012


 pykolab/Makefile.am              |    4 
 pykolab/cli/__init__.py          |    6 
 pykolab/cli/commands.py          |    9 +
 pykolab/cli/sieve/cmd_list.py    |  104 ++++++++++++++
 pykolab/cli/sieve/cmd_put.py     |   93 ++++++++++++
 pykolab/cli/sieve/cmd_refresh.py |  286 +++++++++++++++++++++++++++++++++++++++
 pykolab/cli/sieve/cmd_test.py    |  129 +++++++++++++++++
 pykolab/utils.py                 |   20 ++
 8 files changed, 650 insertions(+), 1 deletion(-)

New commits:
commit 8eddcc101d0b2f1a6e80df0110b0a504003925f1
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Sat Nov 10 17:04:55 2012 +0000

    Initial sieve script management command-line invocations

diff --git a/pykolab/Makefile.am b/pykolab/Makefile.am
index 15f95ea..5ef6974 100644
--- a/pykolab/Makefile.am
+++ b/pykolab/Makefile.am
@@ -15,6 +15,10 @@ pykolab_clidir = $(pythondir)/$(PACKAGE)/cli
 pykolab_cli_PYTHON = \
 	$(wildcard cli/*.py)
 
+pykolab_clisievedir = $(pythondir)/$(PACKAGE)/cli/sieve
+pykolab_clisieve_PYTHON = \
+	$(wildcard cli/sieve/*.py)
+
 pykolab_clitelemetrydir = $(pythondir)/$(PACKAGE)/cli/telemetry
 pykolab_clitelemetry_PYTHON = \
 	$(wildcard cli/telemetry/*.py)
diff --git a/pykolab/cli/sieve/__init__.py b/pykolab/cli/sieve/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pykolab/cli/sieve/cmd_list.py b/pykolab/cli/sieve/cmd_list.py
new file mode 100644
index 0000000..e89a42e
--- /dev/null
+++ b/pykolab/cli/sieve/cmd_list.py
@@ -0,0 +1,104 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.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; version 3 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 Library 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 sys
+import time
+from urlparse import urlparse
+
+import pykolab
+
+from pykolab.auth import Auth
+from pykolab.cli import commands
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+def __init__():
+    commands.register('list', execute, group='sieve', description=description())
+
+def description():
+    return """List a user's sieve scripts."""
+
+def execute(*args, **kw):
+    try:
+        address = conf.cli_args.pop(0)
+    except:
+        address = utils.ask_question(_("Email Address"))
+
+    auth = Auth()
+    auth.connect()
+
+    user = auth.find_recipient(address)
+
+    # Get the main, default backend
+    backend = conf.get('kolab', 'imap_backend')
+
+    if len(address.split('@')) > 1:
+        domain = address.split('@')[1]
+    else:
+        domain = conf.get('kolab', 'primary_domain')
+
+    if conf.has_section(domain) and conf.has_option(domain, 'imap_backend'):
+        backend = conf.get(domain, 'imap_backend')
+
+    if conf.has_section(domain) and conf.has_option(domain, 'imap_uri'):
+        uri = conf.get(domain, 'imap_uri')
+    else:
+        uri = conf.get(backend, 'uri')
+
+    hostname = None
+    port = None
+
+    result = urlparse(uri)
+
+    if hasattr(result, 'hostname'):
+        hostname = result.hostname
+    else:
+        scheme = uri.split(':')[0]
+        (hostname, port) = uri.split('/')[2].split(':')
+
+    port = 4190
+
+    # Get the credentials
+    admin_login = conf.get(backend, 'admin_login')
+    admin_password = conf.get(backend, 'admin_password')
+
+    import sievelib.managesieve
+
+    sieveclient = sievelib.managesieve.Client(hostname, port, conf.debuglevel > 8)
+    sieveclient.connect(None, None, True)
+    result = sieveclient._plain_authentication(admin_login, admin_password, address)
+    if not result:
+        print "LOGIN FAILED??"
+    
+    sieveclient.authenticated = True
+
+    result = sieveclient.listscripts()
+    
+    if result == None:
+        print "No scripts"
+        sys.exit(0)
+
+    (active, scripts) = result
+
+    print "%s (active)" % (active)
+    for script in scripts:
+        print script
+
diff --git a/pykolab/cli/sieve/cmd_put.py b/pykolab/cli/sieve/cmd_put.py
new file mode 100644
index 0000000..b514653
--- /dev/null
+++ b/pykolab/cli/sieve/cmd_put.py
@@ -0,0 +1,93 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.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; version 3 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 Library 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 pykolab
+
+from pykolab.auth import Auth
+from pykolab.cli import commands
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+import time
+from urlparse import urlparse
+
+def __init__():
+    commands.register('put', execute, group='sieve', description=description())
+
+def description():
+    return """Put a script to a user's list of sieve scripts."""
+
+def execute(*args, **kw):
+    try:
+        address = conf.cli_args.pop(0)
+    except:
+        address = utils.ask_question(_("Email Address"))
+
+    script_to_put = conf.cli_args.pop(0)
+    
+    script_put_name = conf.cli_args.pop(0)
+
+    auth = Auth()
+    auth.connect()
+
+    user = auth.find_recipient(address)
+
+    # Get the main, default backend
+    backend = conf.get('kolab', 'imap_backend')
+
+    if len(address.split('@')) > 1:
+        domain = address.split('@')[1]
+    else:
+        domain = conf.get('kolab', 'primary_domain')
+
+    if conf.has_section(domain) and conf.has_option(domain, 'imap_backend'):
+        backend = conf.get(domain, 'imap_backend')
+
+    if conf.has_section(domain) and conf.has_option(domain, 'imap_uri'):
+        uri = conf.get(domain, 'imap_uri')
+    else:
+        uri = conf.get(backend, 'uri')
+
+    hostname = None
+    port = None
+
+    result = urlparse(uri)
+
+    if hasattr(result, 'hostname'):
+        hostname = result.hostname
+    else:
+        scheme = uri.split(':')[0]
+        (hostname, port) = uri.split('/')[2].split(':')
+
+    port = 4190
+
+    # Get the credentials
+    admin_login = conf.get(backend, 'admin_login')
+    admin_password = conf.get(backend, 'admin_password')
+
+    import sievelib.managesieve
+ 
+    sieveclient = sievelib.managesieve.Client(hostname, port, False)
+    sieveclient.connect(None, None, True)
+    sieveclient._plain_authentication(admin_login, admin_password, address)
+    sieveclient.authenticated = True
+
+    sieveclient.putscript(script_put_name, open(script_to_put, "r").read())
diff --git a/pykolab/cli/sieve/cmd_refresh.py b/pykolab/cli/sieve/cmd_refresh.py
new file mode 100644
index 0000000..f34c65c
--- /dev/null
+++ b/pykolab/cli/sieve/cmd_refresh.py
@@ -0,0 +1,286 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.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; version 3 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 Library 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 pykolab
+
+from pykolab import utils
+from pykolab.auth import Auth
+from pykolab.cli import commands
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+import sys
+import time
+from urlparse import urlparse
+
+def __init__():
+    commands.register('refresh', execute, group='sieve', description=description())
+
+def description():
+    return """Refresh a user's managed and contributed sieve scripts."""
+
+def execute(*args, **kw):
+    try:
+        address = conf.cli_args.pop(0)
+    except:
+        address = utils.ask_question(_("Email Address"))
+
+    auth = Auth()
+    auth.connect()
+
+    user = auth.find_recipient(address)
+
+    # Get the main, default backend
+    backend = conf.get('kolab', 'imap_backend')
+
+    if len(address.split('@')) > 1:
+        domain = address.split('@')[1]
+    else:
+        domain = conf.get('kolab', 'primary_domain')
+
+    if conf.has_section(domain) and conf.has_option(domain, 'imap_backend'):
+        backend = conf.get(domain, 'imap_backend')
+
+    if conf.has_section(domain) and conf.has_option(domain, 'imap_uri'):
+        uri = conf.get(domain, 'imap_uri')
+    else:
+        uri = conf.get(backend, 'uri')
+
+    hostname = None
+    port = None
+
+    result = urlparse(uri)
+
+    if hasattr(result, 'hostname'):
+        hostname = result.hostname
+    else:
+        scheme = uri.split(':')[0]
+        (hostname, port) = uri.split('/')[2].split(':')
+
+    port = 4190
+
+    # Get the credentials
+    admin_login = conf.get(backend, 'admin_login')
+    admin_password = conf.get(backend, 'admin_password')
+
+    import sievelib.managesieve
+ 
+    sieveclient = sievelib.managesieve.Client(hostname, port, conf.debuglevel > 8)
+    sieveclient.connect(None, None, True)
+    sieveclient._plain_authentication(admin_login, admin_password, address)
+    sieveclient.authenticated = True
+
+    result = sieveclient.listscripts()
+    
+    if result == None:
+        active = None
+        scripts = []
+    else:
+        active, scripts = result
+        
+
+    print "Found the following scripts: %s" % (','.join(scripts))
+    print "And the following script is active: %s" % (active)
+
+    mgmt_required_extensions = []
+
+    mgmt_script = """#
+# MANAGEMENT
+#
+"""
+
+    user = auth.get_entry_attributes(domain, user, ['*'])
+
+    #
+    # Delivery to Folder
+    #
+    dtf_active_attr = conf.get('sieve', 'deliver_to_folder_active')
+    if not dtf_active_attr == None:
+        if user.has_key(dtf_active_attr):
+            dtf_active = utils.true_or_false(user[dtf_active_attr])
+        else:
+            dtf_active = False
+    else:
+        # TODO: Not necessarily de-activated, the *Active attributes are
+        # not supposed to charge this - check the deliver_to_folder_attr
+        # attribute value for a value.
+        dtf_active = False
+
+    if dtf_active:
+        dtf_folder_name_attr = conf.get('sieve', 'deliver_to_folder_attr')
+        if not dtf_folder_name_attr == None:
+            if user.has_key(dtf_folder_name_attr):
+                dtf_folder = user[dtf_folder_name_attr]
+            else:
+                log.warning(_("Delivery to folder active, but no folder name attribute available for user %r") % (user))
+                dtf_active = False
+        else:
+            log.error(_("Delivery to folder active, but no folder name attribute configured"))
+            dtf_active = False
+
+    #
+    # Folder name to delivery spam to.
+    #
+    # Global or local.
+    #
+    sdf_filter = True
+    sdf = conf.get('sieve', 'spam_global_folder')
+
+    if sdf == None:
+        sdf = conf.get('sieve', 'spam_personal_folder')
+        if sdf == None:
+            sdf_filter = False
+
+    #
+    # Mail forwarding
+    #
+    forward_active = None
+    forward_addresses = []
+    forward_keepcopy = None
+    forward_uce = None
+
+    forward_active_attr = conf.get('sieve', 'forward_address_active')
+    if not forward_active_attr == None:
+        if user.has_key(forward_active_attr):
+            forward_active = utils.true_or_false(user[forward_active_attr])
+        else:
+            forward_active = False
+
+    if not forward_active == False:
+        forward_address_attr = conf.get('sieve', 'forward_address_attr')
+        if user.has_key(forward_address_attr):
+            if isinstance(user[forward_address_attr], basestring):
+                forward_addresses = [ user[forward_address_attr] ]
+            elif isinstance(user[forward_address_attr], str):
+                forward_addresses = [ user[forward_address_attr] ]
+            else:
+                forward_addresses = user[forward_address_attr]
+
+        forward_keepcopy_attr = conf.get('sieve', 'forward_keepcopy_active')
+        if not forward_keepcopy_attr == None:
+            if user.has_key(forward_keepcopy_attr):
+                forward_keepcopy = utils.true_or_false(user[forward_keepcopy_attr])
+            else:
+                forward_keepcopy = False
+
+        forward_uce_attr = conf.get('sieve', 'forward_uce_active')
+        if not forward_uce_attr == None:
+            if user.has_key(forward_uce_attr):
+                forward_uce = utils.true_or_false(user[forward_uce_attr])
+            else:
+                forward_uce = False
+
+    print mgmt_script
+
+    if forward_active:
+        mgmt_required_extensions.append('redirect')
+
+    if dtf_active:
+        mgmt_required_extensions.append('fileinto')
+
+    if sdf_filter:
+        mgmt_required_extensions.append('fileinto')
+
+    import sievelib.factory
+
+    mgmt_script = sievelib.factory.FiltersSet("MANAGEMENT")
+
+    for required_extension in mgmt_required_extensions:
+        mgmt_script.require(required_extension)
+
+    if forward_active:
+        if forward_uce:
+            if forward_keepcopy:
+                mgmt_script.addfilter('forward-uce-keepcopy', ['true'], [("redirect", ":copy", forward_addresses)])
+            else:
+                mgmt_script.addfilter('forward-uce', ['true'], [("redirect", forward_addresses)])
+        else:
+            if forward_keepcopy:
+                mgmt_script.addfilter('forward-keepcopy', [("X-Spam-Status", ":matches", "No,*")], [("redirect", ":copy", forward_addresses)])
+            else:
+                mgmt_script.addfilter('forward', [("X-Spam-Status", ":matches", "No,*")], [("redirect", forward_addresses)])
+    
+    if sdf_filter:
+        mgmt_script.addfilter('spam_delivery_folder', [("X-Spam-Status", ":matches", "Yes,*")], [("fileinto", "INBOX/Spam"), ("stop")])
+
+    #if dtf_active:
+        
+    print mgmt_script.__str__()
+
+    result = sieveclient.putscript("MANAGEMENT", mgmt_script.__str__())
+
+    if not result:
+        print "Putting in script MANAGEMENT failed...?"
+    else:
+        print "Putting in script MANAGEMENT succeeded"
+
+    user_script = """#
+# User
+#
+
+require ["include"];
+"""
+
+    for script in scripts:
+        if not script in [ "MASTER", "MANAGEMENT", "USER" ]:
+            print "Including script %s in USER" % (script)
+            user_script = """%s
+
+include :personal "%s";
+""" % (user_script, script)
+
+    result = sieveclient.putscript("USER", user_script)
+    if not result:
+        print "Putting in script USER failed...?"
+    else:
+        print "Putting in script USER succeeded"
+
+    result = sieveclient.putscript("MASTER", """#
+# MASTER
+# 
+# This file is authoritative for your system and MUST BE KEPT ACTIVE.
+#
+# Altering it is likely to render your account dysfunctional and may
+# be violating your organizational or corporate policies.
+# 
+# For more information on the mechanism and the conventions behind
+# this script, see http://wiki.kolab.org/KEP:14
+#
+
+require ["include"];
+
+# OPTIONAL: Includes for all or a group of users
+# include :global "all-users";
+# include :global "this-group-of-users";
+
+# The script maintained by the general management system
+include :personal "MANAGEMENT";
+
+# The script(s) maintained by one or more editors available to the user
+include :personal "USER";
+""")
+
+    if not result:
+        print "Putting in script MASTER failed...?"
+    else:
+        print "Putting in script MASTER succeeded"
+
+    sieveclient.setactive("MASTER")
diff --git a/pykolab/cli/sieve/cmd_test.py b/pykolab/cli/sieve/cmd_test.py
new file mode 100644
index 0000000..d396aa2
--- /dev/null
+++ b/pykolab/cli/sieve/cmd_test.py
@@ -0,0 +1,129 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.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; version 3 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 Library 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 pykolab
+
+from pykolab.auth import Auth
+from pykolab.cli import commands
+from pykolab.translate import _
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+import time
+from urlparse import urlparse
+
+
+def __init__():
+    commands.register('test', execute, group='sieve', description=description())
+
+def description():
+    return """Syntactically check a user's sieve scripts."""
+
+def execute(*args, **kw):
+    try:
+        address = conf.cli_args.pop(0)
+    except:
+        address = utils.ask_question(_("Email Address"))
+
+    auth = Auth()
+    auth.connect()
+
+    user = auth.find_recipient(address)
+
+    # Get the main, default backend
+    backend = conf.get('kolab', 'imap_backend')
+
+    if len(address.split('@')) > 1:
+        domain = address.split('@')[1]
+    else:
+        domain = conf.get('kolab', 'primary_domain')
+
+    if conf.has_section(domain) and conf.has_option(domain, 'imap_backend'):
+        backend = conf.get(domain, 'imap_backend')
+
+    if conf.has_section(domain) and conf.has_option(domain, 'imap_uri'):
+        uri = conf.get(domain, 'imap_uri')
+    else:
+        uri = conf.get(backend, 'uri')
+
+    hostname = None
+    port = None
+
+    result = urlparse(uri)
+
+    if hasattr(result, 'hostname'):
+        hostname = result.hostname
+    else:
+        scheme = uri.split(':')[0]
+        (hostname, port) = uri.split('/')[2].split(':')
+
+    port = 4190
+
+    # Get the credentials
+    admin_login = conf.get(backend, 'admin_login')
+    admin_password = conf.get(backend, 'admin_password')
+
+    import sievelib.managesieve
+ 
+    sieveclient = sievelib.managesieve.Client(hostname, port, True)
+    sieveclient.connect(None, None, True)
+    sieveclient._plain_authentication(admin_login, admin_password, address)
+    sieveclient.authenticated = True
+
+    active, scripts = sieveclient.listscripts()
+
+    print "%s (active)" % (active)
+    
+    _all_scripts = [ active ] + scripts
+    _used_scripts = [ active ]
+    _included_scripts = []
+
+    _a_script = sieveclient.getscript(active)
+
+    print _a_script
+
+    import sievelib.parser
+
+    _a_parser = sievelib.parser.Parser(debug=True)
+    _a_parsed = _a_parser.parse(_a_script)
+
+    #print "%r" % (_a_parsed)
+
+    if not _a_parsed:
+        print _a_parser.error
+
+    print "%r" % (_a_parser.result)
+
+    for _a_command in _a_parser.result:
+        print _a_command.name, _a_command.arguments
+        if len(_a_command.children) > 0:
+            for _a_child in _a_command.children:
+                print "  ", _a_child.name, _a_child.arguments
+
+        if _a_command.name == "include":
+            if _a_command.arguments["script"].strip('"') in scripts:
+                print "OK"
+                _used_scripts.append(_a_command.arguments["script"].strip('"'))
+            else:
+                print "Not OK"
+
+    for script in scripts:
+        print script
+


commit a70c6d6fc211fab8f0329c3bccc0c136e552738c
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Sat Nov 10 17:03:32 2012 +0000

    Supply your very basic "does this value represent True or False?" function

diff --git a/pykolab/utils.py b/pykolab/utils.py
index d4b1a09..a4d8455 100644
--- a/pykolab/utils.py
+++ b/pykolab/utils.py
@@ -368,6 +368,26 @@ def translate(mystring, locale_name='en_US'):
 
     return result
 
+def true_or_false(val):
+    if val == None:
+        return False
+
+    if isinstance(val, bool):
+        return val
+
+    if isinstance(val, basestring) or isinstance(val, str):
+        val = val.lower()
+        if val in [ "true", "yes", "y" ]:
+            return True
+        else:
+            return False
+
+    if isinstance(val, int) or isinstance(val, float):
+        if val >= 1:
+            return True
+        else:
+            return False
+
 def is_service(services):
     """
         Checks each item in list services to see if it has a RC script in


commit 0d49633f453164fffc03fd62460b1b39a7cfe5a4
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Sat Nov 10 17:02:40 2012 +0000

    Allow a grouped command to be executed like so:
    
      $ kolab sieve list

diff --git a/pykolab/cli/__init__.py b/pykolab/cli/__init__.py
index a51a3aa..5860fd9 100644
--- a/pykolab/cli/__init__.py
+++ b/pykolab/cli/__init__.py
@@ -51,6 +51,12 @@ class Cli(object):
             if not arg.startswith('-') and len(sys.argv) >= arg_num:
                 if commands.commands.has_key(sys.argv[arg_num].replace('-','_')):
                     to_execute.append(sys.argv[arg_num].replace('-','_'))
+                    
+                if commands.commands.has_key("%s_%s" % (
+                        '_'.join(to_execute),sys.argv[arg_num].replace('-','_')
+                    )):
+
+                    to_execute.append(sys.argv[arg_num].replace('-','_'))
 
         commands.execute('_'.join(to_execute))
 


commit 80af0d0ca6be1b2a4c6547a92c521cc2a69fe66d
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Sat Nov 10 16:26:03 2012 +0000

    Display help if an unknown command is specified (and do not bail out on --help).
    Fix typo

diff --git a/pykolab/cli/commands.py b/pykolab/cli/commands.py
index 7376234..d2f6d82 100644
--- a/pykolab/cli/commands.py
+++ b/pykolab/cli/commands.py
@@ -108,6 +108,10 @@ def list_commands(*args, **kw):
                     print "%-4s%-21s" % ('',__command.replace('_','-'))
 
 def execute(cmd_name, *args, **kw):
+    if cmd_name == "":
+        execute("help")
+        sys.exit(0)
+
     if not commands.has_key(cmd_name):
         log.error(_("No such command."))
         sys.exit(1)
@@ -190,7 +194,7 @@ def register(cmd_name, func, group=None, description=None, aliases=[]):
             commands[alias] = {
                     'cmd_name': cmd_name,
                     'function': func,
-                    'description': _("Alias for %s") % (cmd_name,replace('_','-'))
+                    'description': _("Alias for %s") % (cmd_name.replace('_','-'))
                 }
 
 ##


commit 84071b889670c1aa09360c4edd60572136fa69c3
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Sat Nov 10 16:24:32 2012 +0000

    Exclude group commands from the upper-level list of commands.

diff --git a/pykolab/cli/commands.py b/pykolab/cli/commands.py
index 21c2bb4..7376234 100644
--- a/pykolab/cli/commands.py
+++ b/pykolab/cli/commands.py
@@ -85,6 +85,9 @@ def list_commands(*args, **kw):
     _commands.sort()
 
     for _command in _commands:
+        if __commands[_command].has_key('group'):
+            continue
+
         if __commands[_command].has_key('function'):
             # This is a top-level command
             if not __commands[_command]['description'] == None:


commit 2352c500125ec777308aff554541efc311245bfb
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Sat Nov 10 16:23:32 2012 +0000

    Fix names of commands referred to in the description of alias commands.

diff --git a/pykolab/cli/commands.py b/pykolab/cli/commands.py
index 6dedc6c..21c2bb4 100644
--- a/pykolab/cli/commands.py
+++ b/pykolab/cli/commands.py
@@ -187,7 +187,7 @@ def register(cmd_name, func, group=None, description=None, aliases=[]):
             commands[alias] = {
                     'cmd_name': cmd_name,
                     'function': func,
-                    'description': _("Alias for %s") % (cmd_name)
+                    'description': _("Alias for %s") % (cmd_name,replace('_','-'))
                 }
 
 ##





More information about the commits mailing list