← Back to team overview

yellow team mailing list archive

[Merge] lp:~frankban/lpsetup/complete-tests into lp:lpsetup

 

Francesco Banconi has proposed merging lp:~frankban/lpsetup/complete-tests into lp:lpsetup.

Requested reviews:
  Yellow Squad (yellow)

For more details, see:
https://code.launchpad.net/~frankban/lpsetup/complete-tests/+merge/115985

Sorry, the diff is huge, I had to change several things to support the "buildbot-http-no-checkout" story, but at least manual tests pass, and *lpsetup install-lxc* exits successfully when run like the following::

    lp-setup install-lxc -B `bzr info | grep parent | cut -c 18-` 
    -u buildbot -E launchpad-pqm@xxxxxxxxxxxxx -f 'Launchpad PQM' -r
    /var/lib/buildbot/slaves/slave --no-checkout -S launchpad_lxc_id_rsa
    --use-http
    
== Changes ==

Changed UI for *finish_inithost* and *update* commands, as described in my email this morning: they now accept a *target_dir* defaulting to current directory. 


handle_lpuser_from_lplogin: the handler no longer raises a ValidationError if --use-http is provided.


handle_target_from_repository: added an handler to calculate the *target_dir*. A target_dir must be passed to both update and finish-inithost commands.


handle_target_dir: just makes namespace.target_dir an absolute path.


Renamed *code_dir* and *working_dir* to *target_dir*.


s/ensure_ssh_keys/setup_ssh: it seemed to me more expressive. Also updated names in the relevant test case.


Added a *setup_home* step to init-host: from the docstring::

     This is a separate step for several reasons::
        - It is directly called by *initlxc* as one of its first steps.
          Note that *initlxc* needs the user's `.ssh` dir to be set up
          to be able to connect to the container.
        - *initlxc* should be able to skip this step when re-executing
          *inithost* from inside the container, to avoid setting up the
          user home two times. Note: the user home is bind mounted by lxc.
          

Consequentially `changed initlxc.inithost_in_lxc` to skip the *setup_home* step.


inithost: moved the code calling *setup_ssh* and *bzr whoami/lp-login* from *initialize_base* to *initialize*, so that the ssh directory and bzr login are set up only once by initlxc.


initlxc: moved initialize() up at the beginning of the file so that it's easier to follow the code flow.


initrepo: setup_bzr_locations is now only called when the user Launchpad login can be retrieved. The check is done defining a call_setup_bzr_locations subcommand method.


install_lxc: steps updated to reflect the new UI. Added support for --no-checkout in *init_repo_in_lxc*. Updated *cmd_in_lxc* to ssh as the given user rather than ssh as root and then run sudo.


Moved lpuser and skip_if_no_lpuser definition from `tests.subcommands.test_initrepo` to `tests.utils` because they are now used by other tests too (see below).


Added a testcase for `handlers.handle_lpuser_from_lplogin`.

-- 
https://code.launchpad.net/~frankban/lpsetup/complete-tests/+merge/115985
Your team Yellow Squad is requested to review the proposed merge of lp:~frankban/lpsetup/complete-tests into lp:lpsetup.
=== modified file 'lpsetup/handlers.py'
--- lpsetup/handlers.py	2012-07-19 17:48:40 +0000
+++ lpsetup/handlers.py	2012-07-20 13:28:21 +0000
@@ -6,11 +6,14 @@
 
 __metaclass__ = type
 __all__ = [
-    'handle_code_dir',
+    'handle_branch_and_checkout',
     'handle_directories',
     'handle_lpuser_as_username',
     'handle_lpuser_from_lplogin',
+    'handle_source',
     'handle_ssh_keys',
+    'handle_target_dir',
+    'handle_target_from_repository',
     'handle_testing',
     'handle_user',
     'handle_userdata',
@@ -85,12 +88,18 @@
 
 def handle_lpuser_from_lplogin(namespace):
     """Handle lpuser argument.
+
+    The validation fails if *lpuser* is not provided, is not retrievable
+    and *use-http* is False.
     """
     if getattr(namespace, 'lpuser', None) is None:
         try:
             namespace.lpuser = run('bzr', 'launchpad-login').strip()
         except subprocess.CalledProcessError:
-            raise ValidationError("No bzr launchpad-login set.")
+            if getattr(namespace, 'use_http', False):
+                namespace.lpuser = None
+            else:
+                raise ValidationError("No bzr launchpad-login set.")
 
 
 def handle_userdata(namespace, whois=bzr_whois):
@@ -276,6 +285,19 @@
         namespace.source = LP_SSH_REPO
 
 
+def handle_target_from_repository(namespace):
+    """Handle *repository*, *branch_name*, *checkout_name* and *no_checkout*.
+
+    These names must be present in the namespace.
+    Produces *target_dir*: the real working dir where the actual code lives.
+    """
+    if namespace.no_checkout:
+        target_name = namespace.branch_name
+    else:
+        target_name = namespace.checkout_name
+    namespace.target_dir = os.path.join(namespace.repository, target_name)
+
+
 def normalize_path(path):
     """Return the absolute, expanded path.
 
@@ -286,6 +308,12 @@
     return os.path.abspath(os.path.expanduser(path))
 
 
+def handle_target_dir(namespace):
+    """Handle path to the working directory."""
+    path = namespace.target_dir
+    namespace.target_dir = os.path.abspath(os.path.expanduser(path))
+
+
 def handle_branch_and_checkout(namespace):
     """Handle branch and checkout names.
 
@@ -315,12 +343,3 @@
         raise ValidationError(
             'branch and checkout: can not use the same name ({0}).'.format(
                 checkout_name))
-
-
-def handle_code_dir(namespace):
-    """Handle the computed value for `code_dir`.
-
-    It must be invoked after handle_directories.
-    """
-    namespace.code_dir = os.path.join(
-        namespace.repository, namespace.checkout_name)

=== modified file 'lpsetup/subcommands/finish_inithost.py'
--- lpsetup/subcommands/finish_inithost.py	2012-07-19 17:48:40 +0000
+++ lpsetup/subcommands/finish_inithost.py	2012-07-20 13:28:21 +0000
@@ -29,28 +29,22 @@
 
 from lpsetup import argparser
 from lpsetup.handlers import (
-    handle_code_dir,
-    handle_directories,
     handle_user,
-    )
-from lpsetup.settings import (
-    LP_CHECKOUT_NAME,
-    LP_REPOSITORY_DIR,
-    )
-
+    handle_target_dir,
+    )
 from lpsetup.utils import call
 
 
-def setup_launchpad(user, code_dir):
+def setup_launchpad(user, target_dir):
     """Set up the Launchpad environment."""
 
     # Launchpad database setup.
     # nested is required for use by python 2.6.
-    with nested(su(user), cd(code_dir)):
+    with nested(su(user), cd(target_dir)):
         call('utilities/launchpad-database-setup', user)
 
     # Make and install launchpad.
-    with cd(code_dir):
+    with cd(target_dir):
         # Using real su because mailman make script uses uid.
         call(*get_su_command(user, ['make', 'schema']))
         call('make', 'install')
@@ -74,30 +68,19 @@
     needs_root = True
 
     steps = (
-        (setup_launchpad, 'user', 'code_dir'),
+        (setup_launchpad, 'user', 'target_dir'),
         )
 
-    handlers = (
-        handle_user,
-        handle_directories,
-        handle_code_dir,
-        )
+    handlers = (handle_user, handle_target_dir)
 
     def add_arguments(self, parser):
         super(SubCommand, self).add_arguments(parser)
         parser.add_argument(
+            'target_dir', nargs='?', default=os.getcwd(),
+            help='The directory of the Launchpad code checkout. '
+                 '[DEFAULT=current directory]')
+        parser.add_argument(
             '-u', '--user',
             help='The name of the system user.  '
                  'The current user is used if this script is not run as '
                  'root and this argument is omitted.')
-        parser.add_argument(
-            '--checkout-name', default=LP_CHECKOUT_NAME,
-            help='Create a checkout with the given name. '
-                 'Ignored if --no-checkout is specified. '
-                 'Defaults to {0}.'.format(LP_CHECKOUT_NAME))
-        parser.add_argument(
-            '-r', '--repository', default=LP_REPOSITORY_DIR,
-            help='The directory of the Launchpad repository to be created. '
-                 'The directory must reside under the home directory of the '
-                 'given user (see -u argument). '
-                 '[DEFAULT={0}]'.format(LP_REPOSITORY_DIR))

=== modified file 'lpsetup/subcommands/inithost.py'
--- lpsetup/subcommands/inithost.py	2012-07-13 15:16:12 +0000
+++ lpsetup/subcommands/inithost.py	2012-07-20 13:28:21 +0000
@@ -99,9 +99,10 @@
     os.chmod(filename, 0644)
 
 
-def ensure_ssh_keys(ssh_dir, private_key, public_key, valid_ssh_keys,
-                    ssh_key_path):
-    """Ensure that SSH is configured correctly for the user."""
+def setup_ssh(ssh_dir, private_key, public_key, valid_ssh_keys, ssh_key_path):
+    """Set up the user's `.ssh` directory.
+
+    Also ensure that SSH is configured correctly for the user."""
     # Set up the user's ssh directory.  The ssh key must be associated
     # with the lpuser's Launchpad account.
     mkdirs(ssh_dir)
@@ -138,29 +139,12 @@
     if not user_exists(user):
         call('useradd', '-m', '-s', '/bin/bash', '-U', user)
 
-    # Add user to the sudo group.
-    subprocess.call(['adduser', user, 'sudo'])
-    # Add the user to his own group.
-    pwd_database = pwd.getpwnam(user)
-    subprocess.call(['addgroup', '--gid', str(pwd_database.pw_gid), user])
-
-
-def initialize(
-    user, full_name, email, lpuser, private_key, public_key, valid_ssh_keys,
-    ssh_key_path):
+
+def initialize(user):
     """Initialize host machine."""
     make_version_dir()
     initialize_base(user)
-    with su(user) as env:
-        ssh_dir = os.path.join(env.home, '.ssh')
-        ensure_ssh_keys(
-            ssh_dir, private_key, public_key, valid_ssh_keys, ssh_key_path)
-
-        # Set up bzr and Launchpad authentication.
-        call('bzr', 'whoami', formataddr([full_name, email]))
-        if valid_ssh_keys:
-            subprocess.call(['bzr', 'lp-login', lpuser])
-
+    with su(user):
         # Create Apache document roots, to avoid warnings.
         mkdirs(*LP_APACHE_ROOTS)
 
@@ -168,6 +152,15 @@
     for module in LP_APACHE_MODULES.split():
         call('a2enmod', module)
 
+    # The user must be added to sudoers if inithost is run in a container
+    # and we are running the developer story.
+    # XXX 2012-07-18 frankban: add the developer/testing check.
+    if running_in_container():
+        subprocess.call(['adduser', user, 'sudo'])
+        # Add the user to his own group.
+        pwd_database = pwd.getpwnam(user)
+        subprocess.call(['addgroup', '--gid', str(pwd_database.pw_gid), user])
+
     # Set up container hosts file.
     lines = [get_file_header()]
     lines.extend(['{0}\t{1}\n'.format(ip, names)
@@ -177,6 +170,32 @@
         file_append(HOSTS_FILE, line)
 
 
+def setup_home(
+    user, full_name, email, lpuser, private_key, public_key, valid_ssh_keys,
+    ssh_key_path):
+    """Initialize the user home directory.
+
+    This is a separate step for several reasons::
+
+        - It is directly called by *initlxc* as one of its first steps.
+          Note that *initlxc* needs the user's `.ssh` dir to be set up
+          to be able to connect to the container.
+        - *initlxc* should be able to skip this step when re-executing
+          *inithost* from inside the container, to avoid setting up the
+          user home two times. Note: the user home is bind mounted by lxc.
+    """
+    with su(user) as env:
+        # Set up the `.ssh` directory.
+        setup_ssh(
+            os.path.join(env.home, '.ssh'), private_key, public_key,
+            valid_ssh_keys, ssh_key_path)
+
+        # Set up bzr and Launchpad authentication.
+        call('bzr', 'whoami', formataddr([full_name, email]))
+        if valid_ssh_keys:
+            subprocess.call(['bzr', 'lp-login', lpuser])
+
+
 def initialize_lxc():
     """Initialize LXC container.
 
@@ -223,10 +242,11 @@
 
 class SubCommand(argparser.StepsBasedSubCommand):
     """Prepare a machine to run Launchpad.  May be an LXC container or not."""
-    initialize_step = (initialize,
+    initialize_step = (initialize, 'user')
+
+    setup_home_step = (setup_home,
          'user', 'full_name', 'email', 'lpuser',
-         'private_key', 'public_key', 'valid_ssh_keys', 'ssh_key_path',
-         )
+         'private_key', 'public_key', 'valid_ssh_keys', 'ssh_key_path')
 
     initialize_lxc_step = (initialize_lxc, )
 
@@ -234,6 +254,7 @@
 
     steps = (
         initialize_step,
+        setup_home_step,
         initialize_lxc_step,
         setup_apt_step,
         )

=== modified file 'lpsetup/subcommands/initlxc.py'
--- lpsetup/subcommands/initlxc.py	2012-07-17 20:17:48 +0000
+++ lpsetup/subcommands/initlxc.py	2012-07-20 13:28:21 +0000
@@ -57,6 +57,14 @@
     )
 
 
+def initialize(user):
+    """Initialize the LXC host."""
+    inithost.initialize_base(user)
+    # haveged is used to fill /dev/random, avoiding
+    # entropy exhaustion during automated parallel tests.
+    apt_get_install('haveged', caller=call)
+
+
 def create_lxc(lxc_name, lxc_arch, lxc_os, user, install_subunit=False):
     """Create the LXC named `lxc_name` sharing `user` home directory.
 
@@ -125,14 +133,6 @@
     retry_ssh(lxc_name, 'true', key=ssh_key_path)
 
 
-def initialize(user):
-    """Initialize the LXC host."""
-    inithost.initialize_base(user)
-    # haveged is used to fill /dev/random, avoiding
-    # entropy exhaustion during automated parallel tests.
-    apt_get_install('haveged', caller=call)
-
-
 def install_lpsetup_in_lxc(lxc_name, ssh_key_path, lxc_os,
                            user, home_dir, lpsetup_branch=None):
     """Initialize LXC container."""
@@ -194,9 +194,7 @@
     """Prepare the Launchpad environment inside an LXC."""
     # Use ssh to call this script from inside the container.
     args = ['init-host', '-u', user, '-E', email, '-f', full_name,
-            '-l', lpuser, '-S', ssh_key_name,
-            ]
-
+            '-l', lpuser, '-S', ssh_key_name, '--skip-steps', 'setup_home']
     cmd = this_command(home_dir, args)
     ssh(lxc_name, cmd, key=ssh_key_path)
 
@@ -230,6 +228,7 @@
 
     steps = (
         (initialize, 'user'),
+        inithost.SubCommand.setup_home_step,
         create_lxc_step,
         start_lxc_step,
         wait_for_lxc_step,

=== modified file 'lpsetup/subcommands/initrepo.py'
--- lpsetup/subcommands/initrepo.py	2012-07-19 14:31:26 +0000
+++ lpsetup/subcommands/initrepo.py	2012-07-20 13:28:21 +0000
@@ -86,7 +86,11 @@
 
 def setup_bzr_locations(
     lpuser, repository, branch_name, template=LP_BZR_LOCATIONS):
-    """Set up bazaar locations."""
+    """Set up bazaar locations.
+
+    Note that this step is guarded by the *call_setup_bzr_locations* method
+    so that it is only called when the user Launchpad login can be retrieved.
+    """
     context = {
         'branch_dir': os.path.join(repository, branch_name),
         'repository': repository,
@@ -128,6 +132,11 @@
         handlers.handle_source,
         )
 
+    def call_setup_bzr_locations(self, namespace, step, args):
+        """Caller that only sets up bzr locations if lpuser exists."""
+        if namespace.lpuser is not None:
+            return step(*args)
+
     @staticmethod
     def add_common_arguments(parser):
         parser.add_argument(

=== modified file 'lpsetup/subcommands/install_lxc.py'
--- lpsetup/subcommands/install_lxc.py	2012-07-19 17:48:40 +0000
+++ lpsetup/subcommands/install_lxc.py	2012-07-20 13:28:21 +0000
@@ -13,9 +13,10 @@
 import os
 
 from lpsetup.handlers import (
-    handle_code_dir,
+    handle_branch_and_checkout,
     handle_directories,
     handle_source,
+    handle_target_from_repository,
     )
 from lpsetup.settings import (
     LXC_IP_COMMAND,
@@ -70,13 +71,13 @@
 
 def cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args, as_user=None):
     cmd = this_command(home_dir, args)
-    if as_user is not None:
-        cmd = "su {} -c '{}'".format(as_user, cmd)
-    ssh(lxc_name, cmd, key=ssh_key_path)
-
-
-def init_repo_in_lxc(lxc_name, ssh_key_path, home_dir, user, source,
-                     use_http, branch_name, checkout_name, repository):
+    print "CMD =", cmd
+    ssh(lxc_name, cmd, key=ssh_key_path, user=as_user)
+
+
+def init_repo_in_lxc(
+    lxc_name, ssh_key_path, home_dir, user, source, use_http,
+    branch_name, checkout_name, repository, no_checkout):
     args = [
         'init-repo', '--source', source,
         '--branch-name', branch_name, '--checkout-name', checkout_name,
@@ -84,26 +85,23 @@
         ]
     if use_http:
         args.append('--use-http')
+    if no_checkout:
+        args.append('--no-checkout')
     cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args, as_user=user)
 
 
-def update_in_lxc(lxc_name, ssh_key_path, home_dir, user, external_path,
-                  use_http, checkout_name, repository):
-    args = [
-        'update', '--external-path', external_path,
-        '-r', repository, '--checkout-name', checkout_name,
-        ]
+def update_in_lxc(
+    lxc_name, ssh_key_path, home_dir, user, external_path,
+    target_dir, use_http):
+    args = ['update', target_dir, '--external-path', external_path]
     if use_http:
         args.append('--use-http')
     cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args, as_user=user)
 
 
-def finish_inithost_in_lxc(lxc_name, ssh_key_path, home_dir, user,
-                           repository, checkout_name):
-    args = [
-        'finish-init-host', '--user', user, '--repository', repository,
-        '--checkout-name', checkout_name,
-        ]
+def finish_inithost_in_lxc(
+    lxc_name, ssh_key_path, home_dir, user, target_dir):
+    args = ['finish-init-host', target_dir, '--user', user]
     cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args)
 
 
@@ -116,12 +114,13 @@
         # Run on host:
         (create_scripts, 'lxc_name', 'ssh_key_path', 'user'),
         # Run inside the container:
-        (init_repo_in_lxc, 'lxc_name', 'ssh_key_path', 'home_dir', 'user',
-          'source', 'use_http', 'branch_name', 'checkout_name', 'repository'),
+        (init_repo_in_lxc,
+         'lxc_name', 'ssh_key_path', 'home_dir', 'user', 'source', 'use_http',
+         'branch_name', 'checkout_name', 'repository', 'no_checkout'),
         (update_in_lxc, 'lxc_name', 'ssh_key_path', 'home_dir', 'user',
-         'external_path', 'use_http', 'checkout_name', 'repository'),
+         'external_path', 'target_dir', 'use_http'),
         (finish_inithost_in_lxc, 'lxc_name', 'ssh_key_path', 'home_dir',
-         'user', 'repository', 'checkout_name'),
+         'user', 'target_dir'),
         )
 
     help = __doc__
@@ -130,8 +129,9 @@
         handlers = super(SubCommand, self).get_handlers(namespace)
         return handlers + (
             handle_directories,
-            handle_code_dir,
+            handle_branch_and_checkout,
             handle_source,
+            handle_target_from_repository,
             )
 
     def call_create_scripts(self, namespace, step, args):

=== modified file 'lpsetup/subcommands/update.py'
--- lpsetup/subcommands/update.py	2012-07-19 17:48:40 +0000
+++ lpsetup/subcommands/update.py	2012-07-20 13:28:21 +0000
@@ -18,50 +18,46 @@
 
 from lpsetup import argparser
 from lpsetup import handlers
-from lpsetup.settings import (
-    LP_CHECKOUT_NAME,
-    LP_REPOSITORY_DIR,
-    LP_SOURCE_DEPS,
-    )
-
-
-def initialize_directories(code_dir, external_path):
+from lpsetup.settings import LP_SOURCE_DEPS
+
+
+def initialize_directories(target_dir, external_path):
     """Initialize the eggs, yui, and sourcecode directories.
 
     Create them if necessary.
     """
     for dir_ in ['eggs', 'yui', 'sourcecode']:
-        mkdirs(os.path.join(code_dir, external_path, dir_))
-
-
-def update_dependencies(code_dir, external_path, use_http):
+        mkdirs(os.path.join(target_dir, external_path, dir_))
+
+
+def update_dependencies(target_dir, external_path, use_http):
     """Update the external dependencies."""
     use_http_param = '--use-http' if use_http else None
-    cmd = os.path.join(code_dir, 'utilities', 'update-sourcecode')
+    cmd = os.path.join(target_dir, 'utilities', 'update-sourcecode')
     abs_external_path = os.path.abspath(
-        os.path.join(code_dir, external_path))
+        os.path.join(target_dir, external_path))
     source_path = os.path.join(abs_external_path, 'sourcecode')
     run(cmd, use_http_param, source_path)
 
     # Update the download cache.
-    download_cache = os.path.join(code_dir, 'download-cache')
+    download_cache = os.path.join(target_dir, 'download-cache')
     if os.path.exists(download_cache):
         run('bzr', 'up', download_cache)
     else:
         run('bzr', 'co', '-v', '--lightweight', LP_SOURCE_DEPS, download_cache)
 
     # Link to the external sourcecode.
-    if abs_external_path != code_dir:
+    if abs_external_path != target_dir:
         cmd = os.path.join(
-            code_dir, 'utilities', 'link-external-sourcecode')
+            target_dir, 'utilities', 'link-external-sourcecode')
         run(cmd,
-            '--target', code_dir,
+            '--target', target_dir,
             '--parent', external_path)
 
 
-def update_tree(code_dir):
-    """Update the tree at code_dir with the latest LP code."""
-    with cd(code_dir):
+def update_tree(target_dir):
+    """Update the tree at target_dir with the latest LP code."""
+    with cd(target_dir):
         run('bzr', 'pull')
 
 
@@ -72,16 +68,15 @@
     """
 
     steps = (
-        (initialize_directories, 'code_dir', 'external_path'),
-        (update_dependencies, 'code_dir', 'external_path', 'use_http'),
-        (update_tree, 'code_dir'),
+        (initialize_directories, 'target_dir', 'external_path'),
+        (update_dependencies, 'target_dir', 'external_path', 'use_http'),
+        (update_tree, 'target_dir'),
         )
     help = __doc__
     handlers = (
         # Normalize paths and default to cwd if none exists.
         handlers.handle_user,
-        handlers.handle_directories,
-        handlers.handle_code_dir,
+        handlers.handle_target_dir,
         )
 
     @staticmethod
@@ -94,19 +89,11 @@
 
     def add_arguments(self, parser):
         super(SubCommand, self).add_arguments(parser)
+        parser.add_argument(
+            'target_dir', nargs='?', default=os.getcwd(),
+            help='Path to branch to update. [DEFAULT=current directory]')
         self.add_common_arguments(parser)
         parser.add_argument(
             '--use-http', default=False, action='store_true',
             help='Force bzr to use http to get the sourcecode '
                  'branches rather than using bzr+ssh.')
-        parser.add_argument(
-            '--checkout-name', default=LP_CHECKOUT_NAME,
-            help='Create a checkout with the given name. '
-                 'Ignored if --no-checkout is specified. '
-                 'Defaults to {0}.'.format(LP_CHECKOUT_NAME))
-        parser.add_argument(
-            '-r', '--repository', default=LP_REPOSITORY_DIR,
-            help='The directory of the Launchpad repository to be created. '
-                 'The directory must reside under the home directory of the '
-                 'given user (see -u argument). '
-                 '[DEFAULT={0}]'.format(LP_REPOSITORY_DIR))

=== modified file 'lpsetup/tests/subcommands/test_finish_inithost.py'
--- lpsetup/tests/subcommands/test_finish_inithost.py	2012-07-19 17:48:40 +0000
+++ lpsetup/tests/subcommands/test_finish_inithost.py	2012-07-20 13:28:21 +0000
@@ -15,25 +15,20 @@
 
 
 setup_launchpad_step = (
-    finish_inithost.setup_launchpad, ['user', 'code_dir'])
+    finish_inithost.setup_launchpad, ['user', 'target_dir'])
 
 
 def get_arguments():
-    repo = '~/' + get_random_string()
-    checkout = get_random_string()
+    target_dir = '~/' + get_random_string()
     user = get_random_string()
-    return ('-r', repo, '--checkout-name', checkout, '-u', user)
+    return (target_dir, '-u', user)
 
 
 class FinishInitHostTest(StepsBasedSubCommandTestMixin, unittest.TestCase):
 
     sub_command_class = finish_inithost.SubCommand
     expected_arguments = get_arguments()
-    expected_handlers = (
-        handlers.handle_user,
-        handlers.handle_directories,
-        handlers.handle_code_dir,
-        )
+    expected_handlers = (handlers.handle_user, handlers.handle_target_dir)
 
     @property
     def expected_steps(self):

=== modified file 'lpsetup/tests/subcommands/test_inithost.py'
--- lpsetup/tests/subcommands/test_inithost.py	2012-07-13 15:16:12 +0000
+++ lpsetup/tests/subcommands/test_inithost.py	2012-07-20 13:28:21 +0000
@@ -18,12 +18,12 @@
     )
 
 
-initialize_step = (
-    inithost.initialize, ['user', 'full_name', 'email', 'lpuser',
+initialize_step = (inithost.initialize, ['user'])
+setup_home_step = (
+    inithost.setup_home, ['user', 'full_name', 'email', 'lpuser',
     'private_key', 'public_key', 'valid_ssh_keys', 'ssh_key_path',
     ])
-initialize_lxc_step = (
-    inithost.initialize_lxc, [])
+initialize_lxc_step = (inithost.initialize_lxc, [])
 setup_apt_step = (inithost.setup_apt, [])
 
 
@@ -52,6 +52,7 @@
         )
     expected_steps = (
         initialize_step,
+        setup_home_step,
         initialize_lxc_step,
         setup_apt_step,)
     needs_root = True
@@ -111,8 +112,8 @@
             '/tmp/foo', 'Hello, world!', 'a+')
 
 
-class EnsureSSHKeysTestCase(unittest.TestCase):
-    """Tests for inithost.ensure_ssh_keys()."""
+class SetupSSHTestCase(unittest.TestCase):
+    """Tests for inithost.setup_ssh()."""
 
     def setUp(self):
         temp_file = tempfile.NamedTemporaryFile()
@@ -123,42 +124,42 @@
         self.addCleanup(os.remove, self.temp_filename)
         self.addCleanup(os.remove, self.temp_filename + ".pub")
 
-    def test_ensure_ssh_keys_writes_to_ssh_key_path(self):
-        # If inithost.ensure_ssh_keys() is told that the keys it has
+    def test_setup_ssh_writes_to_ssh_key_path(self):
+        # If inithost.setup_ssh() is told that the keys it has
         # been passed are valid, it will write them out to the provided
         # ssh_key_path.
         public_key = "Public"
         private_key = "Private"
-        inithost.ensure_ssh_keys(
+        inithost.setup_ssh(
             self.ssh_dir, private_key, public_key, True, self.temp_filename)
         with open(self.temp_filename + '.pub', 'r') as pub_file:
             self.assertIn(public_key, pub_file.read())
         with open(self.temp_filename, 'r') as priv_file:
             self.assertIn(private_key, priv_file.read())
 
-    def test_ensure_ssh_keys_generates_keys_if_not_passed(self):
-        # If SSH keys aren't passed to ensure_ssh_keys(), the function
+    def test_setup_ssh_generates_keys_if_not_passed(self):
+        # If SSH keys aren't passed to setup_ssh(), the function
         # will generate some.
-        inithost.ensure_ssh_keys(
+        inithost.setup_ssh(
             self.ssh_dir, None, None, False, self.temp_filename)
         self.assertTrue(os.path.exists(self.temp_filename))
         self.assertTrue(os.path.exists(self.temp_filename + ".pub"))
 
-    def test_ensure_ssh_keys_generates_other_files(self):
-        # ensure_ssh_keys() also generates an authorized_keys file and a
+    def test_setup_ssh_generates_other_files(self):
+        # setup_ssh() also generates an authorized_keys file and a
         # known_hosts file in the ssh dir.
-        inithost.ensure_ssh_keys(
+        inithost.setup_ssh(
             self.ssh_dir, None, None, False, self.temp_filename)
         self.assertTrue(
             os.path.exists(os.path.join(self.ssh_dir, 'authorized_keys')))
         self.assertTrue(
             os.path.exists(os.path.join(self.ssh_dir, 'known_hosts')))
 
-    def test_ensure_ssh_keys_creates_ssh_dir(self):
-        # If the ssh_dir passed to ensure_ssh_keys() doesn't exist, it
+    def test_setup_ssh_creates_ssh_dir(self):
+        # If the ssh_dir passed to setup_ssh() doesn't exist, it
         # will be created.
         shutil.rmtree(self.ssh_dir)
-        inithost.ensure_ssh_keys(
+        inithost.setup_ssh(
             self.ssh_dir, None, None, False, self.temp_filename)
         self.assertTrue(os.path.exists(self.ssh_dir))
         self.assertTrue(os.path.isdir(self.ssh_dir))

=== modified file 'lpsetup/tests/subcommands/test_initlxc.py'
--- lpsetup/tests/subcommands/test_initlxc.py	2012-07-16 21:12:21 +0000
+++ lpsetup/tests/subcommands/test_initlxc.py	2012-07-20 13:28:21 +0000
@@ -55,6 +55,7 @@
         )
     expected_steps = (
         initialize_step,
+        test_inithost.setup_home_step,
         create_lxc_step,
         start_lxc_step,
         wait_for_lxc_step,

=== modified file 'lpsetup/tests/subcommands/test_initrepo.py'
--- lpsetup/tests/subcommands/test_initrepo.py	2012-07-17 10:46:49 +0000
+++ lpsetup/tests/subcommands/test_initrepo.py	2012-07-20 13:28:21 +0000
@@ -6,7 +6,6 @@
 
 import os
 import shutil
-import subprocess
 import tempfile
 import unittest
 
@@ -23,21 +22,13 @@
 from lpsetup.tests.utils import (
     create_test_branch,
     get_random_string,
+    lpuser,
+    skip_if_no_lpuser,
     StepsBasedSubCommandTestMixin,
     )
 from lpsetup.utils import ConfigParser
 
 
-try:
-    lpuser = run('bzr', 'launchpad-login').strip()
-except subprocess.CalledProcessError:
-    lpuser = None
-# Create a decorator to skip tests if lp login is not set.
-skip_if_no_lpuser = unittest.skipIf(
-    lpuser is None,
-    'You need to set up a Launchpad login is needed to run this test.')
-
-
 fetch_step = (initrepo.fetch,
     ['source', 'repository', 'branch_name', 'checkout_name', 'no_checkout'])
 setup_bzr_locations_step = (initrepo.setup_bzr_locations,

=== modified file 'lpsetup/tests/subcommands/test_install_lxc.py'
--- lpsetup/tests/subcommands/test_install_lxc.py	2012-07-19 17:48:40 +0000
+++ lpsetup/tests/subcommands/test_install_lxc.py	2012-07-20 13:28:21 +0000
@@ -23,19 +23,18 @@
 init_repo_in_lxc_step = (
     install_lxc.init_repo_in_lxc, [
         'lxc_name', 'ssh_key_path', 'home_dir', 'user', 'source', 'use_http',
-        'branch_name', 'checkout_name', 'repository',
+        'branch_name', 'checkout_name', 'repository', 'no_checkout',
         ])
 
 update_in_lxc_step = (
     install_lxc.update_in_lxc, [
         'lxc_name', 'ssh_key_path', 'home_dir', 'user', 'external_path',
-        'use_http', 'checkout_name', 'repository',
+        'target_dir', 'use_http',
         ])
 
 finish_inithost_in_lxc_step = (
     install_lxc.finish_inithost_in_lxc, [
-        'lxc_name', 'ssh_key_path', 'home_dir', 'user', 'repository',
-        'checkout_name',
+        'lxc_name', 'ssh_key_path', 'home_dir', 'user', 'target_dir',
         ])
 
 
@@ -53,8 +52,9 @@
     expected_arguments = get_arguments()
     expected_handlers = test_initlxc.InitLxcTest.expected_handlers + (
         handlers.handle_directories,
-        handlers.handle_code_dir,
+        handlers.handle_branch_and_checkout,
         handlers.handle_source,
+        handlers.handle_target_from_repository,
         )
     expected_steps = test_initlxc.InitLxcTest.expected_steps + (
         create_scripts_step,

=== modified file 'lpsetup/tests/subcommands/test_update.py'
--- lpsetup/tests/subcommands/test_update.py	2012-07-19 17:48:40 +0000
+++ lpsetup/tests/subcommands/test_update.py	2012-07-20 13:28:21 +0000
@@ -15,18 +15,19 @@
 
 
 def get_arguments():
+    target_dir = '~/' + get_random_string()
+    external_path = get_random_string()
     return (
-        '--external-path', get_random_string(),
+        target_dir,
+        '--external-path', external_path,
         '--use-http',
-        '--repository', get_random_string(),
-        '--checkout-name', get_random_string(),
         )
 
 init_dir_step = (
-    update.initialize_directories, ['code_dir', 'external_path'])
+    update.initialize_directories, ['target_dir', 'external_path'])
 update_dep_step = (
-    update.update_dependencies, ['code_dir', 'external_path', 'use_http'])
-update_tree_step = (update.update_tree, ['code_dir'])
+    update.update_dependencies, ['target_dir', 'external_path', 'use_http'])
+update_tree_step = (update.update_tree, ['target_dir'])
 
 
 class UpdateTest(StepsBasedSubCommandTestMixin, unittest.TestCase):
@@ -34,11 +35,7 @@
     sub_command_name = 'update'
     sub_command_class = update.SubCommand
     expected_arguments = get_arguments()
-    expected_handlers = (
-        handlers.handle_user,
-        handlers.handle_directories,
-        handlers.handle_code_dir,
-        )
+    expected_handlers = (handlers.handle_user, handlers.handle_target_dir)
     expected_steps = (
         init_dir_step,
         update_dep_step,

=== modified file 'lpsetup/tests/test_handlers.py'
--- lpsetup/tests/test_handlers.py	2012-07-17 10:28:05 +0000
+++ lpsetup/tests/test_handlers.py	2012-07-20 13:28:21 +0000
@@ -9,20 +9,31 @@
 import getpass
 import os
 import pwd
+import shutil
+import tempfile
 import unittest
 
-from shelltoolbox import cd
+from shelltoolbox import (
+    cd,
+    environ,
+    )
 
 from lpsetup.exceptions import ValidationError
 from lpsetup.handlers import (
     handle_branch_and_checkout,
     handle_directories,
     handle_lpuser_as_username,
+    handle_lpuser_from_lplogin,
     handle_ssh_keys,
+    handle_target_from_repository,
     handle_testing,
     handle_user,
     handle_userdata,
     )
+from lpsetup.tests.utils import (
+    lpuser,
+    skip_if_no_lpuser,
+    )
 
 
 class HandlersTestMixin(object):
@@ -167,7 +178,7 @@
             handle_directories(namespace)
 
 
-class HandleLPUserTest(unittest.TestCase):
+class HandleLPUserAsUsernameTest(unittest.TestCase):
 
     def test_lpuser(self):
         # If lpuser is not provided by namespace, the user name is used.
@@ -177,6 +188,44 @@
         self.assertEqual(username, namespace.lpuser)
 
 
+class HandleLPUserFromLPLoginTest(HandlersTestMixin, unittest.TestCase):
+
+    def temp_home(self):
+        home = tempfile.mkdtemp()
+        self.addCleanup(shutil.rmtree, home)
+        return environ(HOME=home)
+
+    def test_lpuser_in_namespace(self):
+        # Ensure nothing happen if the lpuser exists in the namespace.
+        value = 'myuser'
+        namespace = argparse.Namespace(lpuser=value)
+        handle_lpuser_from_lplogin(namespace)
+        self.assertEqual(value, namespace.lpuser)
+
+    @skip_if_no_lpuser
+    def test_lpuser_retrieval(self):
+        # Ensure lpuser is correctly retrieved using bzr if it does not
+        # exist in the namespace.
+        namespace = argparse.Namespace()
+        handle_lpuser_from_lplogin(namespace)
+        self.assertEqual(lpuser, namespace.lpuser)
+
+    def test_no_lpuser(self):
+        # The validation fails if lpuser is not retrievable.
+        with self.temp_home():
+            namespace = argparse.Namespace()
+            with self.assertNotValid('launchpad-login'):
+                handle_lpuser_from_lplogin(namespace)
+
+    def test_use_http(self):
+        # Ensure lpuser is set to None if not retrievable and
+        # *use_http* is True.
+        with self.temp_home():
+            namespace = argparse.Namespace(use_http=True)
+            handle_lpuser_from_lplogin(namespace)
+        self.assertIsNone(namespace.lpuser)
+
+
 class HandleSSHKeysTest(HandlersTestMixin, unittest.TestCase):
 
     home_dir = '/tmp/__does_not_exist__'
@@ -228,6 +277,36 @@
             handle_ssh_keys(namespace)
 
 
+class HandleTargetFromRepositoryTest(unittest.TestCase):
+
+    branch_name = 'branch'
+    checkout_name = 'checkout'
+    repository = '/repository/'
+
+    def get_target_dir(self, no_checkout):
+        namespace = argparse.Namespace(
+            branch_name=self.branch_name,
+            checkout_name=self.checkout_name,
+            repository=self.repository,
+            no_checkout=no_checkout)
+        handle_target_from_repository(namespace)
+        return namespace.target_dir
+
+    def test_checkout(self):
+        # Ensure the target dir points to branch_name if
+        # lightweight checkout is not used.
+        expected = os.path.join(self.repository, self.checkout_name)
+        target_dir = self.get_target_dir(False)
+        self.assertEqual(expected, target_dir)
+
+    def test_no_checkout(self):
+        # Ensure the target dir points to checkout_name if
+        # lightweight checkout is used.
+        expected = os.path.join(self.repository, self.branch_name)
+        target_dir = self.get_target_dir(True)
+        self.assertEqual(expected, target_dir)
+
+
 class HandleTestingTest(unittest.TestCase):
 
     ctx = {

=== modified file 'lpsetup/tests/utils.py'
--- lpsetup/tests/utils.py	2012-07-17 10:26:46 +0000
+++ lpsetup/tests/utils.py	2012-07-20 13:28:21 +0000
@@ -21,6 +21,7 @@
 import string
 from StringIO import StringIO
 import sys
+import subprocess
 import tempfile
 import unittest
 
@@ -113,6 +114,16 @@
     return ''.join(random.sample(string.ascii_letters, size))
 
 
+# Retrieve the current lpuser to be used in tests.
+try:
+    lpuser = run('bzr', 'launchpad-login').strip()
+except subprocess.CalledProcessError:
+    lpuser = None
+# Create a decorator to skip tests if lp login is not set.
+skip_if_no_lpuser = unittest.skipIf(
+    lpuser is None, 'You need to set up a Launchpad login to run this test.')
+
+
 class SubCommandTestMixin(object):
 
     sub_command_class = examples.SubCommand