"""
Tools for interacting with vagrant.
"""

import sys
import os

import json

from flocker import __version__

from admin.runner import run


def box_metadata(name, version, path):
    """
    Generate metadata for a vagrant box.

    This metadate can be used to locally(!) add the box to vagrant,
    with the correct version, for testing.

    :param FilePath path: Directory containting ``Vagrantfile``.
    :param bytes name: Base name of vagrant box. Used to build filename.
    :param bytes version: Version of vagrant box. Used to build filename.
    """
    # Vagrant doesn't like - in version numbers.
    # It also doesn't like _ but we don't generate that.
    dotted_version = version.replace('-', '.')
    return {
        "name": "clusterhq/%s" % (name,),
        "description": "Test clusterhq/%s box." % (name,),
        "versions": [{
            "version": dotted_version,
            "providers": [{
                "name": "virtualbox",
                "url": path.path
                }]
            }]
        }


def build_box(path, name, version, branch):
    """
    Build a vagrant box.

    :param FilePath path: Directory containting ``Vagrantfile``.
    :param bytes name: Base name of vagrant box. Used to build filename.
    :param bytes version: Version of vagrant box. Used to build filename.
    :param bytes branch: Branch to get flocker RPMs from.
    """
    box_path = path.child('%s%s%s.box'
                          % (name, '-' if version else '', version))
    json_path = path.child('%s.json' % (name,))

    # Destroy the box to begin, so that we are guaranteed
    # a clean build.
    run(['vagrant', 'destroy', '-f'], cwd=path.path)

    env = os.environ.copy()
    env.update({
        'FLOCKER_VERSION': version.replace('-', '_'),
        'FLOCKER_BRANCH': branch,
        })
    run(['vagrant', 'up'], cwd=path.path, env=env)
    run(['vagrant', 'package', '--output', box_path.path], cwd=path.path)

    # And destroy at the end to save space.  If one of the above commands fail,
    # this will be skipped, so the image can still be debugged.
    run(['vagrant', 'destroy', '-f'], cwd=path.path)

    metadata = box_metadata(name, version, box_path)
    json_path.setContent(json.dumps(metadata))


def main(args, base_path, top_level):
    if base_path.basename() == 'build':
        path = base_path.parent()
        box = path.basename()
    else:
        try:
            box = args.pop(0)
        except IndexError:
            sys.stderr.write("build-vagrant-box: must specify box\n")
            raise SystemExit(1)
        path = top_level.descendant(['vagrant', box])

    if args:
        branch = args.pop(0)
    else:
        branch = ''

    version = __version__

    if args:
        sys.stderr.write("build-vagrant-box: too many arguments\n")
        raise SystemExit(1)

    sys.stdout.write("Building %s box from %s.\n" % (box, path.path))
    build_box(path, 'flocker-' + box, version, branch)

@@ -1,12 +1,63 @@
+# -*- test-case-name: admin.tests.test_vagrant -*-%0A
 %22%22%22%0ATools fo
@@ -124,16 +124,50 @@
 t json%0A%0A
+from twisted.python import usage%0A%0A
 from flo
@@ -222,16 +222,830 @@
 t run%0A%0A%0A
+class Options(usage.Options):%0A%0A    optParameters = %5B%0A        %5B'branch', None, None, 'branch'%5D,%0A        %5B'box', None, None, 'box'%5D%0A    %5D%0A%0A    def __init__(self, base_path, top_level):%0A        usage.Options.__init__(self)%0A        self.base_path = base_path%0A        self.top_level = top_level%0A%0A    def postOptions(self):%0A        if self.base_path.basename() == 'build':%0A            if self%5B'box'%5D is not None:%0A                raise usage.UsageError(%22Can't specify box when invoked from box directory.%22)%0A            self%5B'path'%5D = self.base_path.parent()%0A            self%5B'box'%5D = self%5B'path'%5D.basename()%0A        else:%0A            if self%5B'box'%5D is None:%0A                raise usage.UsageError(%22Must specify box when invoked directly.%22)%0A            self%5B'path'%5D = self.top_level.descendant(%5B'vagrant', self%5B'box'%5D%5D)%0A%0A%0A
 def box_
@@ -2721,16 +2721,54 @@
      %7D)%0A
+    run(%5B'vagrant', 'box', 'update'%5D)%0A
     run(
@@ -3231,304 +3231,46 @@
     
-if base_path.basename() == 'build':%0A        path = base_path.parent()%0A        box = path.basename()%0A    else:%0A        try:%0A            box = args.pop(0)%0A        except IndexError:%0A            sys.stderr.write(%22build-vagrant-box: must specify box%5Cn%22)%0A            raise SystemExit(1)%0A        
+options = Options(base_path=base_
 path
- =
+,
  top
@@ -3279,247 +3279,45 @@
 evel
-.descendant(%5B'vagrant', box%5D)%0A%0A    if args:%0A        branch = args.pop(0)%0A    else:%0A        branch = ''%0A%0A    version = __version__%0A%0A    if args:%0A        sys.stderr.write(%22build-vagrant-box: too many arguments%5Cn%22)%0A        raise SystemExit(1)
+=top_level)%0A    version = __version__
 %0A%0A  
@@ -3367,21 +3367,37 @@
 .%5Cn%22 %25 (
-box, 
+options.box, options.
 path.pat
@@ -3410,24 +3410,32 @@
   build_box(
+options.
 path, 'flock
@@ -3441,16 +3441,24 @@
 ker-' + 
+options.
 box, ver
@@ -3459,20 +3459,28 @@
 x, version, 
+options.
 branch)%0A

Add some tests.