#!/usr/bin/env python
import argparse
import docker_buildtool
import logging
import os
import re
import sys
import traceback
import yaml

from docker_buildtool import error, utils

logger = logging.getLogger()
formatter = logging.Formatter('[%(asctime)s] %(message)s')
handler = logging.StreamHandler(sys.stderr)
handler.setFormatter(formatter)
logger.addHandler(handler)

class Error(Exception):
    pass

class UserError(Error):
    pass

def path(*args):
    return os.path.abspath(os.path.join(os.path.dirname(__file__), *args))

class Builder(object):
    def __init__(self, dockerfile, tag):
        self.dockerfile = dockerfile
        self.tag = tag

    def run(self, dryrun):
        if self.tag is None:
            docker_repo = None
            tag = None
        else:
            parsed_tag = self.tag.split(':')
            if len(parsed_tag) > 1:
                docker_repo = parsed_tag[0]
                tag = parsed_tag[1]
            else:
                docker_repo = parsed_tag[0]
                tag = 'latest'

        spec = docker_buildtool.DockerfileBuildSpec(self.dockerfile)
        if spec.frontmatter is None:
            raise error.Error("""Your Dockerfile has no frontmatter, meaning the entire build context would be ignored. That is, you would not have access to any of the files on local disk.

To fix this, add something like this to the head of your Dockerfile:

# ---
# setup: pip install -e .
# build_root: ../..
# ignore:
#  - gym-vnc-envs/vnc-flashgames/out
#  - gym-vnc/go-vncdriver
# include:
#  - gym-vnc-envs/vnc-flashgames
#  - {'path': 'gym-vnc', 'git': 'git@github.com:openai/gym-vnc.git', 'setup': 'pip install -e .'}
# ---""")

        build = docker_buildtool.DockerBuild(
            dockerfile=spec.dockerfile,
            build_root=spec.build_root,
            include=spec.include,
            workdir=spec.workdir,
            ignore=spec.ignore,
            docker_repo=docker_repo,
            tag=tag)
        build.run(dryrun=dryrun)

def build(args):
    builder = Builder(
        dockerfile=args.dockerfile,
        tag=args.tag,
    )
    builder.run(dryrun=args.dryrun)

class Puller(object):
    def __init__(self, dockerfile):
        self.dockerfile = dockerfile

    def run(self, dryrun):
        if os.path.exists(self.dockerfile):
            spec = docker_buildtool.DockerfileBuildSpec(self.dockerfile)
            spec.run_setup(dryrun)

            for include in spec.include:
                if not include.installable:
                    continue
                include.install(dryrun=dryrun, build_root=spec.build_root)
        else:
            logger.info("\n\nPulling global dependencies. cd into a specific project directory (or point at the project Dockerfile with -f) to also pull dependencies for that project.\n\n")

        with open(path('../autopull.yml')) as f:
            autopull = yaml.load(f)

        for name, spec in autopull.items():
            # TODO: DRY this up
            repo_path = os.path.join(path('../..'), name)
            if not os.path.exists(repo_path):
                utils.execute_command(dryrun, ['git', 'clone', spec['git']], cwd=repo_path)

            # Pull in these tooling repos
            utils.execute_command(dryrun, ['git', 'pull'], cwd=repo_path)
            # Installed executables become unhappy when their
            # version changes, which means we need to
            # reinstall them.
            #
            # Also just make sure people haven't installed the Pypi
            # version of things.
            utils.execute_command(dryrun, spec['setup'], cwd=repo_path, shell=True)

def pull(args):
    puller = Puller(dockerfile=args.dockerfile)
    puller.run(dryrun=args.dryrun)

def main():
    parser = argparse.ArgumentParser(description=None)
    parser.add_argument('-v', '--verbose', action='count', dest='verbosity', default=0, help='Set verbosity.')
    parser.add_argument('-f', '--dockerfile', default='Dockerfile', help='Which Dockerfile to use.')

    subparsers = parser.add_subparsers()
    sub = subparsers.add_parser('build')
    sub.add_argument('-t', '--tag', help='The tag to use.')
    sub.add_argument('-n', '--dryrun', action='store_true', help='Do not actually run')
    sub.set_defaults(func=build)

    sub = subparsers.add_parser('pull')
    sub.add_argument('-n', '--dryrun', action='store_true', help='Do not actually run')
    sub.set_defaults(func=pull)

    args = parser.parse_args()

    if args.verbosity == 0:
        logger.setLevel(logging.INFO)
    elif args.verbosity >= 1:
        logger.setLevel(logging.DEBUG)

    args.func(args)

    return 0

if __name__ == '__main__':
    sys.exit(main())
