#!/usr/bin/env python
from __future__ import print_function

import argparse
import re
import subprocess

from itertools import chain


def _strip_image_tag(image):
    """
    Remove the tag part from a Docker tag and return the rest. Full tags are of
    the form [REGISTRYHOST/][NAME/...]NAME[:TAG] where the REGISTRYHOST may
    contain a ':' but the NAME parts may not.
    """
    match = re.match('^((?:.+\/)?[^:]+)(?::.+)?$', image)
    if match is None:
        raise RuntimeError('Unable to parse tag "%s"' % (image,))

    return match.group(1)


def _strip_image_registry(image):
    # TODO: Not yet sure how to differentiate REGISTRYHOST from a NAME segment.
    return image


class DockerCiDeployRunner(object):

    def __init__(self, dry_run=False, verbose=False):
        self.dry_run = dry_run
        self.verbose = verbose

    def _log(self, *args, **kwargs):
        if kwargs.get('if_verbose', False):
            if self.verbose:
                print(*args)
        else:
            print(*args)

    def _docker_cmd(self, *cmds, **kwargs):
        """ Run a Docker command or print it if ``dry_run=True``. """
        if self.dry_run:
            if 'obfuscated' in kwargs:
                cmds = kwargs['obfuscated']
            self._log(*(('docker',) + cmds))
        else:
            subprocess.check_output(('docker',) + cmds)

    def docker_tag(self, in_tag, out_tag):
        """ Run ``docker tag`` with the given tags. """
        self._docker_cmd('tag', in_tag, out_tag)

    def docker_login(self, username, password, registry):
        """ Run ``docker login`` with the given credentials. """
        cmd = [
            'login',
            '--username', username,
            '--password', password,
            registry,
        ]
        obfuscated = list(cmd)
        obfuscated[4] = '<password>'
        self._docker_cmd(*cmd, obfuscated=tuple(obfuscated))

    def docker_push(self, tag):
        """ Run ``docker push`` with the given tag. """
        self._docker_cmd('push', tag)

    def run(self, image, tags=None, login=None, registry=None):
        """
        Run the script - tag, login and push as necessary.

        :param image:
            The full source image tag.
        :param tags:
            A list of tags to tag the image with or None if no new tags are
            required.
        :param login:
            Login details for the Docker registry in the form
            <username>:<password>.
        :param registry:
            The address to the Docker registry host.
        """
        # Build list of tags to push with provided tags
        push_tags = []
        if tags is not None:
            stripped_tag = _strip_image_tag(image)
            for tag in tags:
                push_tags.append('%s:%s' % (stripped_tag, tag,))
        else:
            push_tags = [image]

        # Update tags with registry host information
        if registry is not None:
            for i, tag in enumerate(push_tags):
                stripped_tag = _strip_image_registry(tag)
                push_tags[i] = '%s/%s' % (registry, stripped_tag,)

        # Actually tag the image
        for tag in push_tags:
            self._log('Tagging "%s" as "%s"...' % (image, tag,),
                      if_verbose=True)
            self.docker_tag(image, tag)

        # Login if login details provided
        if login is not None:
            username, password = login.split(':', 2)
            self._log('Logging in as "%s"...' % (username,), if_verbose=True)
            self.docker_login(username, password, registry)

        # Finally, push the tags
        for tag in push_tags:
            self._log('Pushing tag "%s"...' % (tag,), if_verbose=True)
            self.docker_push(tag)


def main():
    parser = argparse.ArgumentParser(
        description='Tag and push Docker images to a registry.')
    parser.add_argument('-t', '--tag', nargs='*',
                        action='append',
                        help='Tags to tag the image with before pushing')
    parser.add_argument('-l', '--login', nargs='?',
                        help='Login details in the form <username>:<password> '
                             'to login to the registry')
    parser.add_argument('-r', '--registry', nargs='?',
                        help='Address for the registry to login and push to')
    parser.add_argument('-v', '--verbose', action='store_true',
                        help='Verbose logging output')
    parser.add_argument('--dry-run', action='store_true',
                        help='Print but do not execute any Docker commands')
    parser.add_argument('image', help='Tag (full image name) to push')

    args = parser.parse_args()

    runner = DockerCiDeployRunner(dry_run=args.dry_run, verbose=args.verbose)
    # Flatten list of tags
    tags = chain.from_iterable(args.tag) if args.tag is not None else None
    runner.run(args.image, tags=tags, login=args.login, registry=args.registry)


if __name__ == "__main__":
    main()

@@ -1044,19 +1044,19 @@
 (self, *
-cmd
+arg
 s, **kwa
@@ -1211,19 +1211,19 @@
         
-cmd
+arg
 s = kwar
@@ -1277,19 +1277,19 @@
 er',) + 
-cmd
+arg
 s))%0A    
@@ -1348,19 +1348,19 @@
 er',) + 
-cmd
+arg
 s)%0A%0A    

Rename cmds param to args