#!/usr/bin/env python3
#
# Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.

# Dart SDK promote tools.

import json
import optparse
import os
import sys
import time
import urllib
import bots.bot_utils as bot_utils

from os.path import join
from utils import Version

DART_PATH = os.path.abspath(os.path.join(__file__, '..', '..'))
DRY_RUN = False


def BuildOptions():
    usage = """usage: %prog promote [options]
  where:
    promote - Will promote builds from raw/signed locations to release
              locations.

    Example: Promote version 2.5.0 on the stable channel:
        python3 tools/promote.py promote --channel=stable --version=2.5.0
  """

    result = optparse.OptionParser(usage=usage)

    group = optparse.OptionGroup(result, 'Promote',
                                 'options used to promote code')
    group.add_option(
        '--revision',
        '--version',
        help='The version to promote',
        action='store')
    group.add_option(
        '--channel',
        type='string',
        help='The channel to promote.',
        default=None)
    group.add_option(
        '--source-channel',
        type='string',
        help='The channel to promote from. Defaults to the --channel value.',
        default=None)
    group.add_option('--dry',
                     help='Dry run',
                     default=False,
                     action='store_true')
    result.add_option_group(group)

    return result


def main():
    parser = BuildOptions()
    (options, args) = parser.parse_args()

    def die(msg):
        print(msg)
        parser.print_help()
        sys.exit(1)

    if not args:
        die('At least one command must be specified')

    if args[0] == 'promote':
        command = 'promote'
        if options.revision is None:
            die('You must specify the --version to promote')

        # Make sure options.channel is a valid
        if not options.channel:
            die('Specify --channel=beta/dev/stable')
        if options.channel not in bot_utils.Channel.ALL_CHANNELS:
            die('You must supply a valid --channel to promote')
        if (options.source_channel and
                options.source_channel not in bot_utils.Channel.ALL_CHANNELS):
            die('You must supply a valid --source-channel to promote from')
    else:
        die('Invalid command specified: {0}.  See help below'.format(args[0]))

    if options.dry:
        global DRY_RUN
        DRY_RUN = True
    if command == 'promote':
        source = options.source_channel or options.channel
        _PromoteDartArchiveBuild(options.channel, source, options.revision)


def GetLatestRelease(channel):
    release_namer = bot_utils.GCSNamer(channel, bot_utils.ReleaseType.RELEASE)
    version_object = release_namer.version_filepath('latest')
    global DRY_RUN
    was_dry = DRY_RUN
    DRY_RUN = False
    (stdout, _, _) = Gsutil(['cat', version_object])
    DRY_RUN = was_dry
    version = json.loads(stdout)['version']
    return Version(version=version)


def UpdateDocs():
    try:
        print('Updating docs')
        url = 'http://api.dartlang.org/docs/releases/latest/?force_reload=true'
        f = urllib.urlopen(url)
        f.read()
        print('Successfully updated api docs')
    except Exception as e:
        print('Could not update api docs, please manually update them')
        print('Failed with: %s' % e)


def _PromoteDartArchiveBuild(channel, source_channel, revision):
    # These namer objects will be used to create GCS object URIs. For the
    # structure we use, please see tools/bots/bot_utils.py:GCSNamer
    raw_namer = bot_utils.GCSNamer(source_channel, bot_utils.ReleaseType.RAW)
    signed_namer = bot_utils.GCSNamer(source_channel,
                                      bot_utils.ReleaseType.SIGNED)
    release_namer = bot_utils.GCSNamer(channel, bot_utils.ReleaseType.RELEASE)

    def promote(to_revision):
        def safety_check_on_gs_path(gs_path, revision, channel):
            if not (revision != None and len(channel) > 0 and
                    ('%s' % revision) in gs_path and channel in gs_path):
                raise Exception(
                    'InternalError: Sanity check failed on GS URI: %s' %
                    gs_path)

        def exists(gs_path):
            (_, _, exit_code) = Gsutil(['ls', gs_path], throw_on_error=False)
            # gsutil will exit 0 if the "directory" exists
            return exit_code == 0

        # Google cloud storage has read-after-write, read-after-update,
        # and read-after-delete consistency, but not list after delete consistency.
        # Because gsutil uses list to figure out if it should do the unix styly
        # copy to or copy into, this means that if the directory is reported as
        # still being there (after it has been deleted) gsutil will copy
        # into the directory instead of to the directory.
        def wait_for_delete_to_be_consistent_with_list(gs_path):
            if DRY_RUN:
                return
            while exists(gs_path):
                time.sleep(1)

        def remove_gs_directory(gs_path):
            safety_check_on_gs_path(gs_path, to_revision, channel)
            # Only delete existing directories
            if exists(gs_path):
                Gsutil(['-m', 'rm', '-R', '-f', gs_path])
                wait_for_delete_to_be_consistent_with_list(gs_path)

        # Copy the signed sdk directory.
        from_loc = signed_namer.sdk_directory(revision)
        to_loc = release_namer.sdk_directory(to_revision)
        remove_gs_directory(to_loc)
        has_signed = exists(from_loc)
        if has_signed:
            Gsutil(['-m', 'cp', '-R', from_loc, to_loc])
            # Because gsutil copies differently to existing directories, we need
            # to use the base directory for the next recursive copy.
            to_loc = release_namer.base_directory(to_revision)

        # Copy the unsigned sdk directory without clobbering signed files.
        from_loc = raw_namer.sdk_directory(revision)
        Gsutil(['-m', 'cp', '-n', '-R', from_loc, to_loc])

        # Copy api-docs zipfile.
        from_loc = raw_namer.apidocs_zipfilepath(revision)
        to_loc = release_namer.apidocs_zipfilepath(to_revision)
        Gsutil(['-m', 'cp', from_loc, to_loc])

        # Copy linux deb and src packages.
        from_loc = raw_namer.linux_packages_directory(revision)
        to_loc = release_namer.linux_packages_directory(to_revision)
        remove_gs_directory(to_loc)
        Gsutil(['-m', 'cp', '-R', from_loc, to_loc])

        # Copy VERSION file.
        from_loc = raw_namer.version_filepath(revision)
        to_loc = release_namer.version_filepath(to_revision)
        # Never cache the latest VERSION file for quick new version detection.
        no_cache = []
        if to_revision == 'latest':
            no_cache = ['-h', 'Cache-Control: no-cache']
        Gsutil(no_cache + ['cp', from_loc, to_loc])

    promote(revision)
    # Promote to latest unless it's an older version.
    if GetLatestRelease(channel) <= Version(version=revision):
        promote('latest')
    # Promote beta to stable if stable becomes ahead of beta.
    if channel == 'stable' and \
       GetLatestRelease('beta') <= Version(version=revision):
        _PromoteDartArchiveBuild('beta', 'stable', revision)


def Gsutil(cmd, throw_on_error=True):
    gsutilTool = join(DART_PATH, 'third_party', 'gsutil', 'gsutil')
    command = [sys.executable, gsutilTool] + cmd
    if DRY_RUN:
        print('DRY running: %s' % command)
        return (None, None, 0)
    return bot_utils.run(command, throw_on_error=throw_on_error)


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