#!/usr/bin/env python
import subprocess
import os
import shutil
import os.path as p
from functools import partial
import platform as stdplatform
import uuid
import sys
from pprint import pprint

# on windows we have to download a small secondary script that configures
# Python 3 64-bit extensions. Here we define the URL and the local path that
# we will use for this script.
import zipfile

MAGIC_WIN_SCRIPT_URL = 'https://raw.githubusercontent.com/menpo/condaci/master/run_with_env.cmd'
MAGIC_WIN_SCRIPT_PATH = r'C:\run_with_env.cmd'
VS2008_PATCH_URL = 'https://raw.githubusercontent.com/menpo/condaci/master/vs2008_patch.zip'
VS2008_PATCH_PATH = r'C:\vs2008_patch.zip'
VS2008_PATCH_FOLDER_PATH = r'C:\vs2008_patch'

VS2008_PATH = r'C:\Program Files (x86)\Microsoft Visual Studio 9.0'
VS2008_BIN_PATH = os.path.join(VS2008_PATH, 'VC', 'bin')
VS2010_PATH = r'C:\Program Files (x86)\Microsoft Visual Studio 10.0'
VS2010_BIN_PATH = os.path.join(VS2010_PATH, 'VC', 'bin')
VS2010_AMD64_VCVARS_CMD = r'CALL "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64'

# a random string we can use for the miniconda installer
# (to avoid name collisions)
RANDOM_UUID = uuid.uuid4()

# -------------------------------- STATE ------------------------------------ #

# Key globals that need to be set for the rest of the script.
PYTHON_VERSION = None
PYTHON_VERSION_NO_DOT = None
BINSTAR_USER = None
BINSTAR_KEY = None


def set_globals_from_environ(verbose=True):
    global PYTHON_VERSION, BINSTAR_KEY, BINSTAR_USER, PYTHON_VERSION_NO_DOT

    PYTHON_VERSION = os.environ.get('PYTHON_VERSION')
    BINSTAR_USER = os.environ.get('BINSTAR_USER')
    BINSTAR_KEY = os.environ.get('BINSTAR_KEY')

    if verbose:
        print('Environment variables extracted:')
        print('  PYTHON_VERSION: {}'.format(PYTHON_VERSION))
        print('  BINSTAR_USER:   {}'.format(BINSTAR_USER))
        print('  BINSTAR_KEY:    {}'.format('*****' if BINSTAR_KEY is not None
                                            else '-'))

    if PYTHON_VERSION is None:
        raise ValueError('Fatal: PYTHON_VERSION is not set.')
    if PYTHON_VERSION not in ['2.7', '3.4', '3.5']:
        raise ValueError("Fatal: PYTHON_VERSION '{}' is invalid - must be "
                         "either '2.7', '3.4' or '3.5'".format(PYTHON_VERSION))

    # Required when setting Python version in conda
    PYTHON_VERSION_NO_DOT = PYTHON_VERSION.replace('.', '')


# ------------------------------ UTILITIES ---------------------------------- #

# forward stderr to stdout
check = partial(subprocess.check_call, stderr=subprocess.STDOUT)


def execute(cmd, verbose=True, env_additions=None):
    r""" Runs a command, printing the command and it's output to screen.
    """
    env_for_p = os.environ.copy()
    if env_additions is not None:
        env_for_p.update(env_additions)
    if verbose:
        print('> {}'.format(' '.join(cmd)))
        if env_additions is not None:
            print('Additional environment variables: '
                  '{}'.format(', '.join(['{}={}'.format(k, v)
                                         for k, v in env_additions.items()])))
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
                            stderr=subprocess.STDOUT, env=env_for_p)
    sentinal = ''
    if sys.version_info.major == 3:
        sentinal = b''
    for line in iter(proc.stdout.readline, sentinal):
        if verbose:
            if sys.version_info.major == 3:
                # convert bytes to string
                line = line.decode("utf-8")
            sys.stdout.write(line)
            sys.stdout.flush()
    output = proc.communicate()[0]
    if proc.returncode == 0:
        return
    else:
        e = subprocess.CalledProcessError(proc.returncode, cmd, output=output)
        print(' -> {}'.format(e.output))
        raise e


def execute_sequence(*cmds, **kwargs):
    r""" Execute a sequence of commands. If any fails, display an error.
    """
    verbose = kwargs.get('verbose', True)
    for cmd in cmds:
        execute(cmd, verbose)


def extract_zip(zip_path, dest_dir):
    r"""
    Extract a zip file to a destination
    """
    with zipfile.PyZipFile(str(zip_path)) as z:
        z.extractall(path=str(dest_dir))


def download_file(url, path_to_download):
    try:
        from urllib2 import urlopen
    except ImportError:
        from urllib.request import urlopen
    f = urlopen(url)
    with open(path_to_download, "wb") as fp:
        fp.write(f.read())
    fp.close()


def dirs_containing_file(fname, root=os.curdir):
    for path, dirs, files in os.walk(os.path.abspath(root)):
        if fname in files:
            yield path


def host_platform():
    return stdplatform.system()


def host_arch():
    arch = stdplatform.architecture()[0]
    # need to be a little more sneaky to check the platform on Windows:
    # http://stackoverflow.com/questions/2208828/detect-64bit-os-windows-in-python
    if host_platform() == 'Windows':
        if 'APPVEYOR' in os.environ:
            av_platform = os.environ['PLATFORM']
            if av_platform == 'x86':
                arch = '32bit'
            elif av_platform == 'x64':
                arch = '64bit'
            else:
                print('Was unable to interpret the platform "{}"'.format())
    return arch


# ------------------------ MINICONDA INTEGRATION ---------------------------- #

def url_for_platform_version(platform, py_version, arch):
    version = 'latest'
    base_url = 'http://repo.continuum.io/miniconda/Miniconda'
    platform_str = {'Linux': 'Linux',
                    'Darwin': 'MacOSX',
                    'Windows': 'Windows'}
    arch_str = {'64bit': 'x86_64',
                '32bit': 'x86'}
    ext = {'Linux': '.sh',
           'Darwin': '.sh',
           'Windows': '.exe'}

    if py_version in ['3.4', '3.5']:
        base_url += '3'
    elif py_version != '2.7':
        raise ValueError("Python version must be '2.7', '3.4' or '3.5'")
    return '-'.join([base_url, version,
                     platform_str[platform],
                     arch_str[arch]]) + ext[platform]


def appveyor_miniconda_dir():
    if PYTHON_VERSION in ['3.4', '3.5']:
        conda_dir = r'C:\Miniconda3'
    elif PYTHON_VERSION == '2.7':
        conda_dir = r'C:\Miniconda'
    else:
        raise ValueError("Python version must be '2.7', '3.4' or '3.5'")

    if host_arch() == '64bit':
        conda_dir += '-x64'

    return conda_dir


def temp_installer_path():
    # we need a place to download the miniconda installer too. use a random
    # string for the filename to avoid collisions, but choose the dir based
    # on platform
    return ('C:\{}.exe'.format(RANDOM_UUID) if host_platform() == 'Windows'
            else p.expanduser('~/{}.sh'.format(RANDOM_UUID)))


def miniconda_dir():
    # the directory where miniconda will be installed too/is
    if host_platform() == 'Windows':
        path = appveyor_miniconda_dir()
    else:  # Unix
        path = p.expanduser('~/miniconda')
    if is_on_jenkins():
        # jenkins persists miniconda installs between builds, but we want a
        # unique miniconda env for each executor
        if not os.path.isdir(path):
                os.mkdir(path)
        exec_no = os.environ['EXECUTOR_NUMBER']
        j_path = os.path.join(path, exec_no)
        if not os.path.isdir(j_path):
            os.mkdir(j_path)
        path = os.path.join(j_path, PYTHON_VERSION)
    return path


# the script directory inside a miniconda install varies based on platform
def miniconda_script_dir_name():
    return 'Scripts' if host_platform() == 'Windows' else 'bin'


# handles to binaries from a miniconda install
exec_ext = '.exe' if host_platform() == 'Windows' else ''
miniconda_script_dir = lambda mc: p.join(mc, miniconda_script_dir_name())
conda = lambda mc: p.join(miniconda_script_dir(mc), 'conda' + exec_ext)
binstar = lambda mc: p.join(miniconda_script_dir(mc), 'anaconda' + exec_ext)


def acquire_miniconda(url, path_to_download):
    print('Downloading miniconda from {} to {}'.format(url, path_to_download))
    download_file(url, path_to_download)


def install_miniconda(path_to_installer, path_to_install):
    print('Installing miniconda to {}'.format(path_to_install))
    if host_platform() == 'Windows':
        execute([path_to_installer, '/S', '/D={}'.format(path_to_install)])
    else:
        execute(['chmod', '+x', path_to_installer])
        execute([path_to_installer, '-b', '-p', path_to_install])


def setup_miniconda(python_version, installation_path, binstar_user=None):
    conda_cmd = conda(installation_path)
    if os.path.exists(conda_cmd):
        print('conda is already setup at {}'.format(installation_path))
    else:
        print('No existing conda install detected at {}'.format(installation_path))
        url = url_for_platform_version(host_platform(), python_version,
                                       host_arch())
        print('Setting up miniconda from URL {}'.format(url))
        print("(Installing to '{}')".format(installation_path))
        acquire_miniconda(url, temp_installer_path())
        install_miniconda(temp_installer_path(), installation_path)
        # delete the installer now we are done
        os.unlink(temp_installer_path())
    cmds = [[conda_cmd, 'update', '-q', '--yes', 'conda'],
            [conda_cmd, 'install', '-q', '--yes', 'conda-build', 'jinja2',
             'anaconda-client']]
    root_config = os.path.join(installation_path, '.condarc')
    if os.path.exists(root_config):
        print('existing root config at present at {} - removing'.format(root_config))
        os.unlink(root_config)
    if binstar_user is not None:
        print("(adding user channel '{}' for dependencies to root config)".format(binstar_user))
        cmds.append([conda_cmd, 'config', '--system', '--add', 'channels', binstar_user])
    else:
        print("No user channels have been configured (all dependencies have to be "
              "sourced from anaconda)")
    execute_sequence(*cmds)


# ------------------------ CONDA BUILD INTEGRATION -------------------------- #

def get_conda_build_path(mc_dir, recipe_dir):
    path_bytes = subprocess.check_output([conda(mc_dir), 'build',
                                          recipe_dir, '--output'])
    return path_bytes.decode("utf-8").strip()


def conda_build_package_win(mc, path):
    if 'BINSTAR_KEY' in os.environ:
        print('found BINSTAR_KEY in environment on Windows - deleting to '
              'stop vcvarsall from telling the world')
        del os.environ['BINSTAR_KEY']
    os.environ['PYTHON_ARCH'] = host_arch()[:2]
    os.environ['PYTHON_VERSION'] = PYTHON_VERSION
    print('PYTHON_ARCH={} PYTHON_VERSION={}'.format(os.environ['PYTHON_ARCH'],
                                                    os.environ['PYTHON_VERSION']))
    execute(['cmd', '/E:ON', '/V:ON', '/C', MAGIC_WIN_SCRIPT_PATH,
             conda(mc), 'build', '-q', path,
             '--py={}'.format(PYTHON_VERSION_NO_DOT)])


def windows_setup_compiler():
    arch = host_arch()
    if PYTHON_VERSION == '2.7':
        download_file(VS2008_PATCH_URL, VS2008_PATCH_PATH)
        if not os.path.exists(VS2008_PATCH_FOLDER_PATH):
            os.makedirs(VS2008_PATCH_FOLDER_PATH)
        extract_zip(VS2008_PATCH_PATH, VS2008_PATCH_FOLDER_PATH)

        if arch == '64bit':
            execute([os.path.join(VS2008_PATCH_FOLDER_PATH, 'setup_x64.bat')])

            VS2008_AMD64_PATH = os.path.join(VS2008_BIN_PATH, 'amd64')
            if not os.path.exists(VS2008_AMD64_PATH):
                os.makedirs(VS2008_AMD64_PATH)
            shutil.copyfile(os.path.join(VS2008_BIN_PATH, 'vcvars64.bat'),
                            os.path.join(VS2008_AMD64_PATH, 'vcvarsamd64.bat'))
        elif arch == '32bit':
            # For some reason these files seems to be missing on Appveyor
            # execute([os.path.join(VS2008_PATCH_FOLDER_PATH, 'setup_x86.bat')])
            pass
        else:
            raise ValueError('Unexpected architecture {}'.format(arch))
    elif PYTHON_VERSION == '3.4' and arch == '64bit':
        VS2010_AMD64_PATH = os.path.join(VS2010_BIN_PATH, 'amd64')
        if not os.path.exists(VS2010_AMD64_PATH):
            os.makedirs(VS2010_AMD64_PATH)
        VS2010_AMD64_VCVARS_PATH = os.path.join(VS2010_AMD64_PATH,
                                                'vcvars64.bat')
        with open(VS2010_AMD64_VCVARS_PATH, 'w') as f:
            f.write(VS2010_AMD64_VCVARS_CMD)


def build_conda_package(mc, path, binstar_user=None):
    print('Building package at path {}'.format(path))
    v = get_version(path)
    print('Detected version: {}'.format(v))
    print('Setting CONDACI_VERSION environment variable to {}'.format(v))
    os.environ['CONDACI_VERSION'] = v
    print('Setting CONDA_PY environment variable to {}'.format(
        PYTHON_VERSION_NO_DOT))
    os.environ['CONDA_PY'] = PYTHON_VERSION_NO_DOT

    # we want to add the master channel when doing dev builds to source our
    # other dev dependencies
    if not (is_release_tag(v) or is_rc_tag(v)):
        print('building a non-release non-RC build - adding master channel.')
        if binstar_user is None:
            print('warning - no binstar user provided - cannot add master channel')
        else:
            execute([conda(mc), 'config', '--system', '--add', 'channels',
                     binstar_user + '/channel/master'])
    else:
        print('building a RC or tag release - no master channel added.')

    if host_platform() == 'Windows':
        # Before building the package, we may need to edit the environment a bit
        # to handle the nightmare that is Visual Studio compilation
        windows_setup_compiler()
        conda_build_package_win(mc, path)
    else:
        execute([conda(mc), 'build', '-q', path,
                 '--py={}'.format(PYTHON_VERSION_NO_DOT)])


# ------------------------- VERSIONING INTEGRATION -------------------------- #

# versions that match up to master changes (anything after a '+')
same_version_different_build = lambda v1, v2: v2.startswith(v1.split('+')[0])


def versions_from_versioneer():
    # Ideally, we will interrogate versioneer to find out the version of the
    # project we are building. Note that we can't simply look at
    # project.__version__ as we need the version string pre-build, so the
    # package may not be importable.
    for dir_ in dirs_containing_file('_version.py'):
        sys.path.insert(0, dir_)

        try:
            import _version
            yield _version.get_versions()['version']
        except Exception as e:
            print(e)
        finally:
            if '_version' in sys.modules:
                sys.modules.pop('_version')

            sys.path.pop(0)


def version_from_meta_yaml(path):
    meta_yaml_path = os.path.join(path, 'meta.yaml')
    with open(meta_yaml_path, 'rt') as f:
        s = f.read()
    v = s.split('version:', 1)[1].split('\n', 1)[0].strip().strip("'").strip('"')
    if '{{' in v:
        raise ValueError('Trying to establish version from meta.yaml'
                         ' and it seems to be dynamic: {}'.format(v))
    return v


def get_version(path):
    # search for versioneer versions in our subdirs
    versions = list(versions_from_versioneer())

    if len(versions) == 1:
        version = versions[0]
        print('Found unambiguous versioneer version: {}'.format(version))
    elif len(versions) > 1:
        raise ValueError('Multiple versioneer _version.py files - cannot '
                         'resolve unambiguous version. '
                         'Versions found are: {}'.format(versions))
    else:
        # this project doesn't seem to be versioneer controlled - maybe the
        # version is hardcoded? Interrogate meta.yaml
        version = version_from_meta_yaml(path)
    return version

# booleans about the state of the the PEP440 tags.
is_tag = lambda v: '+' not in v
is_dev_tag = lambda v: v.split('.')[-1].startswith('dev')
is_rc_tag = lambda v: 'rc' in v.split('+')[0]
is_release_tag = lambda v: is_tag(v) and not (is_rc_tag(v) or is_dev_tag(v))


# -------------------------- BINSTAR INTEGRATION ---------------------------- #


class LetMeIn:
    def __init__(self, key):
        self.token = key
        self.site = False


def login_to_binstar():
    from binstar_client.utils import get_binstar
    return get_binstar()


def login_to_binstar_with_key(key):
    from binstar_client.utils import get_binstar
    return get_binstar(args=LetMeIn(key))


class BinstarFile(object):

    def __init__(self, full_name):
        self.full_name = full_name

    @property
    def user(self):
        return self.full_name.split('/')[0]

    @property
    def name(self):
        return self.full_name.split('/')[1]

    @property
    def basename(self):
        return '/'.join(self.full_name.split('/')[3:])

    @property
    def version(self):
        return self.full_name.split('/')[2]

    @property
    def platform(self):
        return self.full_name.replace('\\', '/').split('/')[3]

    @property
    def configuration(self):
        return self.full_name.replace('\\', '/').split('/')[4].split('-')[2].split('.')[0]

    def __str__(self):
        return self.full_name

    def __repr__(self):
        return self.full_name

    def all_info(self):
        s = ["         user: {}".format(self.user),
             "         name: {}".format(self.name),
             "     basename: {}".format(self.basename),
             "      version: {}".format(self.version),
             "     platform: {}".format(self.platform),
             "configuration: {}".format(self.configuration)]
        return "\n".join(s)


configuration_from_binstar_filename = lambda fn: fn.split('-')[-1].split('.')[0]
name_from_binstar_filename = lambda fn: fn.split('-')[0]
version_from_binstar_filename = lambda fn: fn.split('-')[1]
platform_from_binstar_filepath = lambda fp: p.split(p.split(fp)[0])[-1]


def binstar_channels_for_user(b, user):
    return b.list_channels(user).keys()


def binstar_files_on_channel(b, user, channel):
    info = b.show_channel(channel, user)
    return [BinstarFile(i['full_name']) for i in info['files']]


def binstar_remove_file(b, bfile):
    b.remove_dist(bfile.user, bfile.name, bfile.version, bfile.basename)


def files_to_remove(b, user, channel, filepath):
    platform_ = platform_from_binstar_filepath(filepath)
    filename = p.split(filepath)[-1]
    name = name_from_binstar_filename(filename)
    version = version_from_binstar_filename(filename)
    configuration = configuration_from_binstar_filename(filename)
    # find all the files on this channel
    all_files = binstar_files_on_channel(b, user, channel)
    # other versions of this exact setup that are not tagged versions should
    # be removed
    print('Removing old releases matching:'
          '\nname: {}\nconfiguration: {}\nplatform: {}'
          '\nversion: {}'.format(name, configuration, platform_, version))
    print('candidate releases with same name are:')
    pprint([f.all_info() for f in all_files if f.name == name])
    return [f for f in all_files if
            f.name == name and
            f.configuration == configuration and
            f.platform == platform_ and
            f.version != version and
            not is_release_tag(f.version) and
            same_version_different_build(version, f.version)]


def purge_old_binstar_files(b, user, channel, filepath):
    to_remove = files_to_remove(b, user, channel, filepath)
    print("Found {} releases to remove".format(len(to_remove)))
    for old_file in to_remove:
        print("Removing '{}'".format(old_file))
        binstar_remove_file(b, old_file)


def binstar_upload_unchecked(mc, key, user, channel, path):
    print('Uploading from {} using {}'.format(path, binstar(mc)))
    try:
        # TODO - could this safely be co? then we would get the binstar error..
        check([binstar(mc), '-t', key, 'upload',
               '--force', '-u', user, '-c', channel, path])
    except subprocess.CalledProcessError as e:
        # mask the binstar key...
        cmd = e.cmd
        cmd[2] = 'BINSTAR_KEY'
        # ...then raise the error
        raise subprocess.CalledProcessError(e.returncode, cmd)


def binstar_upload_if_appropriate(mc, path, user, key):
    if key is None:
        print('No binstar key provided')
    if user is None:
        print('No binstar user provided')
    if user is None or key is None:
        print('-> Unable to upload to binstar')
        return
    print('Have a user ({}) and key - can upload if suitable'.format(user))

    # decide if we should attempt an upload (if it's a PR we can't)
    if resolve_can_upload_from_ci():
        print('Auto resolving channel based on release type and CI status')
        channel = binstar_channel_from_ci(path)
        print("Fit to upload to channel '{}'".format(channel))
        binstar_upload_and_purge(mc, key, user, channel,
                                 get_conda_build_path(mc, path))
    else:
        print("Cannot upload to binstar - must be a PR.")


def binstar_upload_and_purge(mc, key, user, channel, filepath):
    if not os.path.exists(filepath):
        raise ValueError('Built file {} does not exist. '
                         'UPLOAD FAILED.'.format(filepath))
    else:
        print('Uploading to {}/{}'.format(user, channel))
        binstar_upload_unchecked(mc, key, user, channel, filepath)
        b = login_to_binstar_with_key(key)
        if channel != 'main':
            print("Purging old releases from channel '{}'".format(channel))
            purge_old_binstar_files(b, user, channel, filepath)
        else:
            print("On main channel - no purging of releases will be done.")


# -------------- CONTINUOUS INTEGRATION-SPECIFIC FUNCTIONALITY -------------- #

is_on_appveyor = lambda: 'APPVEYOR' in os.environ
is_on_travis = lambda: 'TRAVIS' in os.environ
is_on_jenkins = lambda: 'JENKINS_URL' in os.environ

is_pr_from_travis = lambda: os.environ['TRAVIS_PULL_REQUEST'] != 'false'
is_pr_from_appveyor = lambda: 'APPVEYOR_PULL_REQUEST_NUMBER' in os.environ
is_pr_from_jenkins = lambda: 'ghprbSourceBranch' in os.environ

branch_from_appveyor = lambda: os.environ['APPVEYOR_REPO_BRANCH']


def branch_from_jenkins():
    branch = os.environ['GIT_BRANCH']
    print('Jenkins has set GIT_BRANCH={}'.format(branch))
    if branch.startswith('origin/tags/'):
        print('WARNING - on jenkins and GIT_BRANCH starts with origin/tags/. '
              'This suggests that we are building a tag.')
        print('Jenkins obscures the branch in this scenario, so we assume that'
              ' the branch is "master"')
        return 'master'
    elif branch.startswith('origin/'):
        return branch.split('origin/', 1)[-1]
    else:
        raise ValueError('Error: jenkins branch name seems '
                         'suspicious: {}'.format(branch))


def branch_from_travis():
    tag = os.environ['TRAVIS_TAG']
    branch = os.environ['TRAVIS_BRANCH']
    if tag == branch:
        print('WARNING - on travis and TRAVIS_TAG == TRAVIS_BRANCH. This '
              'suggests that we are building a tag.')
        print('Travis obscures the branch in this scenario, so we assume that'
              ' the branch is "master"')
        return 'master'
    else:
        return branch


def is_pr_on_ci():
    if is_on_travis():
        return is_pr_from_travis()
    elif is_on_appveyor():
        return is_pr_from_appveyor()
    elif is_on_jenkins():
        return is_pr_from_jenkins()
    else:
        raise ValueError("Not on appveyor, travis or jenkins, so can't "
                         "resolve whether we are on a PR or not")


def branch_from_ci():
    if is_on_travis():
        return branch_from_travis()
    elif is_on_appveyor():
        return branch_from_appveyor()
    elif is_on_jenkins():
        return branch_from_jenkins()
    else:
        raise ValueError("We aren't on jenkins, "
                         "Appveyor or Travis so can't "
                         "decide on branch")


def resolve_can_upload_from_ci():
    # can upload as long as this isn't a PR
    can_upload = not is_pr_on_ci()
    print("Can we can upload (i.e. is this not a PR)? : {}".format(can_upload))
    return can_upload


def binstar_channel_from_ci(path):
    v = get_version(path)
    if is_release_tag(v):
        # tagged releases always go to main
        print("current head is a tagged release ({}), "
              "uploading to 'main' channel".format(v))
        return 'main'
    else:
        print('current head is not a release - interrogating CI to decide on '
              'channel to upload to (based on branch)')
        return branch_from_ci()


# -------------------- [EXPERIMENTAL] PYPI INTEGRATION ---------------------- #

# pypirc_path = p.join(p.expanduser('~'), '.pypirc')
# pypi_upload_allowed = (host_platform() == 'Linux' and
#                        host_arch() == '64bit' and
#                        sys.version_info.major == 2)
#
# pypi_template = """[distutils]
# index-servers = pypi
#
# [pypi]
# username:{}
# password:{}"""
#
#
# def pypi_setup_dotfile(username, password):
#     with open(pypirc_path, 'wb') as f:
#         f.write(pypi_template.format(username, password))
#
#
# def upload_to_pypi_if_appropriate(mc, username, password):
#     if username is None or password is None:
#         print('Missing PyPI username or password, skipping upload')
#         return
#     v = get_version()
#     if not is_release_tag(v):
#         print('Not on a tagged release - not uploading to PyPI')
#         return
#     if not pypi_upload_allowed:
#         print('Not on key node (Linux 64 Py2) - no PyPI upload')
#     print('Setting up .pypirc file..')
#     pypi_setup_dotfile(username, password)
#     print("Uploading to PyPI user '{}'".format(username))
#     execute_sequence([python(mc), 'setup.py', 'sdist', 'upload'])


# --------------------------- ARGPARSE COMMANDS ----------------------------- #

def miniconda_dir_cmd(_):
    set_globals_from_environ(verbose=False)
    print(miniconda_dir())


def setup_cmd(_):
    set_globals_from_environ()
    mc = miniconda_dir()
    setup_miniconda(PYTHON_VERSION, mc, binstar_user=BINSTAR_USER)


def build_cmd(args):
    set_globals_from_environ()
    mc = miniconda_dir()
    conda_meta = args.meta_yaml_dir

    if host_platform() == 'Windows':
        print('downloading magical Windows SDK configuration'
              ' script to {}'.format(MAGIC_WIN_SCRIPT_PATH))
        download_file(MAGIC_WIN_SCRIPT_URL, MAGIC_WIN_SCRIPT_PATH)

    build_conda_package(mc, conda_meta, binstar_user=BINSTAR_USER)
    print('successfully built conda package, proceeding to upload')
    binstar_upload_if_appropriate(mc, conda_meta, BINSTAR_USER, BINSTAR_KEY)
    # upload_to_pypi_if_appropriate(mc, args.pypiuser, args.pypipassword)


if __name__ == "__main__":
    from argparse import ArgumentParser
    pa = ArgumentParser(
        description=r"""
        Sets up miniconda, builds, and uploads to Binstar.
        """)
    subp = pa.add_subparsers()

    sp = subp.add_parser('setup', help='setup a miniconda environment')
    sp.set_defaults(func=setup_cmd)

    bp = subp.add_parser('build', help='run a conda build')
    bp.add_argument('meta_yaml_dir',
                    help="path to the dir containing the conda 'meta.yaml'"
                         "build script")

    mp = subp.add_parser('miniconda_dir',
                         help='path to the miniconda root directory')
    mp.set_defaults(func=miniconda_dir_cmd)

    bp.set_defaults(func=build_cmd)
    args = pa.parse_args()
    args.func(args)