Ubuntu logo

Developer

Porting CommandsΒΆ

Since most Quickly commands prior to 13.04 were already in Python, porting them is usually just a matter of wrapping the old code in a new command class. Below is an example of porting the save command from the ubuntu-application template in Quickly 12.08.

Here is the old-style save command:

import sys
import subprocess

import gettext
from gettext import gettext as _
gettext.textdomain('quickly')

from quickly import templatetools

def usage():
    templatetools.print_usage(_('quickly save [comments]'))
def help():
    print _("""This command commits all changes since the last save to bzr. Note that
it does not push changes to any back up location. If you need revert
or otherwise use the revision control, use bzr directly:
$ bzr help""")
templatetools.handle_additional_parameters(sys.argv, help, usage=usage)

#set either a default message or the specified message
commit_msg = " ".join(sys.argv[1:])
if commit_msg == "":
   commit_msg = _('quickly saved')

#save away
subprocess.call(["bzr", "add"])
return_code = subprocess.call(["bzr", "commit", "-m" + commit_msg])
if return_code == 3:
    print _("It seems that you have no change to record.")

sys.exit(return_code)

The first thing to do is to create a new class, and put the code that actually does the work into it’s run method:

import sys
import subprocess

import gettext
from gettext import gettext as _
gettext.textdomain('quickly')

from quickly import templatetools

from quickly.core.commands import BaseCommand

class BzrSave(BaseCommand):

    def run(self):
        def usage():
            templatetools.print_usage(_('quickly save [comments]'))
        def help():
            print _("""This command commits all changes since the last save to bzr. Note that
        it does not push changes to any back up location. If you need revert
        or otherwise use the revision control, use bzr directly:
        $ bzr help""")
        templatetools.handle_additional_parameters(sys.argv, help, usage=usage)

        #set either a default message or the specified message
        commit_msg = " ".join(sys.argv[1:])
        if commit_msg == "":
           commit_msg = _('quickly saved')

        #save away
        subprocess.call(["bzr", "add"])
        return_code = subprocess.call(["bzr", "commit", "-m" + commit_msg])
        if return_code == 3:
            print _("It seems that you have no change to record.")

        sys.exit(return_code)

The new Quickly handles arguement parsing automaticaly, so we don’t need to call templatetools.handle_additional_parameters. We can also convert the usage() and help() functions into Meta-class attributes:

import sys
import subprocess

import gettext
from gettext import gettext as _
gettext.textdomain('quickly')

from quickly.core.commands import BaseCommand

class BzrSave(BaseCommand):

    class Meta:
        usage = 'quickly %(cmd_name)s [comments]'
        help = """This command commits all changes since the last save to bzr. Note that
it does not push changes to any back up location. If you need revert
or otherwise use the revision control, use bzr directly:
$ bzr help"""

    def run(self):
        #set either a default message or the specified message
        commit_msg = " ".join(sys.argv[1:])
        if commit_msg == "":
           commit_msg = _('quickly saved')

        #save away
        subprocess.call(["bzr", "add"])
        return_code = subprocess.call(["bzr", "commit", "-m" + commit_msg])
        if return_code == 3:
            print _("It seems that you have no change to record.")

        sys.exit(return_code)

Now this command took an optional argument for a commit message. We need to add that to the command parser, which requires that we override the __init__ method for this class:

import sys
import subprocess

import gettext
from gettext import gettext as _
gettext.textdomain('quickly')

from quickly.core.commands import BaseCommand

class BzrSave(BaseCommand):

    class Meta:
        usage = 'quickly %(cmd_name)s [comments]'
        help = """This command commits all changes since the last save to bzr. Note that
it does not push changes to any back up location. If you need revert
or otherwise use the revision control, use bzr directly:
$ bzr help"""

    def __init__(self):
        super(BzrSave, self).__init__()
        self.parser.add_argument('commit_msg', default='quickly saved', help=_('The message to use for this commit'))

    def run(self):

        #save away
        subprocess.call(["bzr", "add"])
        return_code = subprocess.call(["bzr", "commit", "-m" + self.options.commit_msg])
        if return_code == 3:
            print _("It seems that you have no change to record.")

        sys.exit(return_code)

Now we need to make sure the new code is Python 3. For example, the print statement must use parenthesis. We also no longer need to return a code, and we certainly don’t want to sys.exit. Remember, if you need to signal an error in your command’s execution, raise an instance of CommandError instead:

import sys
import subprocess

import gettext
from gettext import gettext as _
gettext.textdomain('quickly')

from quickly.core.commands import BaseCommand

class BzrSave(BaseCommand):

    class Meta:
        usage = 'quickly %(cmd_name)s [comments]'
        help = """This command commits all changes since the last save to bzr. Note that
it does not push changes to any back up location. If you need revert
or otherwise use the revision control, use bzr directly:
$ bzr help"""

    def __init__(self):
        super(BzrSave, self).__init__()
        self.parser.add_argument('commit_msg', default='quickly saved', help=_('The message to use for this commit'))

    def run(self):

        #save away
        subprocess.call(["bzr", "add"])
        return_code = subprocess.call(["bzr", "commit", "-m" + self.options.commit_msg])
        if return_code == 3:
            print(_("It seems that you have no change to record."))

Finally, this command must have a project to run against, so we’ll add the project_command decorator to this class, so that it will always check that it’s being run against a project:

import sys
import subprocess

import gettext
from gettext import gettext as _
gettext.textdomain('quickly')

from quickly.core.commands import BaseCommand, project_command

@project_command
class BzrSave(BaseCommand):

    class Meta:
        usage = 'quickly %(cmd_name)s [comments]'
        help = """This command commits all changes since the last save to bzr. Note that
it does not push changes to any back up location. If you need revert
or otherwise use the revision control, use bzr directly:
$ bzr help"""

    def __init__(self):
        super(BzrSave, self).__init__()
        self.parser.add_argument('commit_msg', default='quickly saved', help=_('The message to use for this commit'))

    def run(self):

        #save away
        subprocess.call(["bzr", "add"])
        return_code = subprocess.call(["bzr", "commit", "-m" + self.options.commit_msg])
        if return_code == 3:
            print(_("It seems that you have no change to record."))

Now that your new command class is done, you can add it to the new ubuntu-application template:

from .commands import Create, Run, BzrSave
import os
import logging
import copy

from quickly.core.templates import BaseTemplate

class Template(BaseTemplate):

    class Meta:
        name = 'ubuntu-application'
        version = '1.0'
        icon = 'ubuntu'

    # Add commands to this template
    create = Create(project_root = 'project_root')
    run = Run()
    save = BzrSave()

    # Example of command aliasing
    launch = run.clone()