
import tinys3
import os
import click
from subprocess import check_call, check_output
from string import Template
import shutil


@click.command()
@click.option('--aws-access-key-id', prompt='AWS ACCESS KEY ID',
              envvar='AWS_ACCESS_KEY_ID')
@click.option('--aws-secret-access-key', prompt='AWS SECRET ACCESS KEY',
              hide_input=True, envvar='AWS_SECRET_ACCESS_KEY')
@click.option('-v', '--version', prompt='New version please(ex 1.0.4)')
@click.option('-n', '--dry-run', is_flag=True, default=False)
@click.option('--local-test', is_flag=True, default=False)
@click.option('-m', '--changelog', prompt='Write changelog')
@click.option('--email', prompt='Write your email(used in changelog)')
@click.option('--name', prompt='Write your name(used in changelog)')
@click.option('--gpg-keyname', prompt='Write gpg key name(used in signing dpkg)')
@click.option('--ssh-keypath', prompt='SSH private key path(used in connecting to apt repository')
def distribute(aws_access_key_id, aws_secret_access_key,
               version, dry_run, local_test,
               changelog, email, name,
               gpg_keyname, ssh_keypath):
    context = {
        'access_key': aws_access_key_id,
        'secret_key': aws_secret_access_key,
        'version': version,
        'dry_run': dry_run,
        'local_test': local_test,
        'changelog': changelog,
        'email': email,
        'name': name,
        'gpg_keyname': gpg_keyname,
        'ssh_keypath': ssh_keypath
    }

    do_move_to_temp_dir(context)
    do_create_git_tag(context)
    do_update_latest_file(context)

    do_update_brew_executable_file(context)
    do_update_homebrew(context)

    do_update_debian_dir(context)
    do_build_linux_executable_file(context)
    do_make_dpkg(context)
    do_publish_dpkg(context)


def do_move_to_temp_dir(context):
    tmp_dir = 'tmp-distribute'
    shutil.rmtree(tmp_dir, ignore_errors=True)
    os.mkdir(tmp_dir)
    os.chdir(tmp_dir)


def do_create_git_tag(context):
    create_git_tag(context)
    push_git_tag(context)


def do_update_latest_file(context):
    update_version_file(context)
    upload_latest(context)


def do_update_brew_executable_file(context):
    build_macOS_go(context)
    compress_executable(context)
    sha256 = create_sha256(context)
    context['sha256'] = sha256
    upload_executable(context)


def do_update_homebrew(context):
    clone_homebrew(context)
    if not context['dry_run']:
        os.chdir('homebrew-kodebox')
    update_homebrew_version_sha256(context)
    push_homebrew(context)
    if not context['dry_run']:
        os.chdir('..')


def do_update_debian_dir(context):
    copy_debian_dir(context)
    update_change_log(context)


def do_build_linux_executable_file(context):
    build_linux_go(context)


def do_make_dpkg(context):
    command = 'debuild -b -k' + context['gpg_keyname']
    print ''
    print 'run debuild using gpg key ' + context['gpg_keyname']
    if not context['dry_run']:
        os.chdir('kodebox-' + context['version'])
        check_output(command.split(' '))
        os.chdir('..')


def do_publish_dpkg(context):
    ssh_keypath = context['ssh_keypath']
    src_file = 'kodebox_' + context['version'] + '_amd64.deb'
    host = 'ubuntu@dl.kodebox.io'
    dest = host + ':~/'

    remote_command = 'cd debian && reprepro --ask-passphrase -Vb . includedeb stable ~/' + src_file

    print ''
    print 'upload dpkg file'
    if not context['dry_run'] and not context['local_test']:
        check_call([
            'scp', '-i', ssh_keypath, src_file, dest
        ])

        check_call([
            'ssh', '-i', ssh_keypath, host, remote_command
        ])


def create_git_tag(context):
    tag_name = 'v' + context['version']
    print ''
    print 'Creating git tag ' + tag_name
    if not context['dry_run']:
        check_call(['git', 'tag', tag_name])


def push_git_tag(context):
    print ''
    print 'Pushing tags'
    if not context['dry_run'] and not context['local_test']:
        check_call(['git', 'push', 'origin', 'master'])
        check_call(['git', 'push', '--tags'])


def update_version_file(context):
    template = Template(
        '{"version":"$version","downloadUrl":"https://kodebox.io/cli/install", "test": 1}')
    latest_content = template.substitute(version=context['version'])
    print ''
    print 'Write to latest.json :'
    print latest_content
    if not context['dry_run']:
        write_to_file('latest.json', latest_content)


def upload_latest(context):
    bucket_name = 'kodebox-cli'
    upload_file_name = 'latest'
    print ''
    print 'Upload latest.json to ' + bucket_name + '/' + upload_file_name
    if not context['dry_run'] and not context['local_test']:
        conn = tinys3.Connection(context['access_key'], context['secret_key'])
        latest_file = open('latest.json', 'rb')
        conn.upload(upload_file_name, latest_file,
                    bucket=bucket_name, close=True)


def build_macOS_go(context):
    print ''
    print 'running go build'
    if not context['dry_run']:
        check_call([
            'env', 'GOOS=darwin', 'GOARCH=amd64',
            'go', 'build', '-o', 'kodebox',
            '-ldflags', '-X main.Version=' + context['version'],
            '..'])


def build_linux_go(context):
    print ''
    print 'running go build'
    if not context['dry_run']:
        check_call([
            'env', 'GOOS=linux', 'GOARCH=amd64',
            'go', 'build', '-o', 'kodebox',
            '-ldflags', '-X main.Version=' + context['version'],
            '..'])
        shutil.copy2('kodebox', 'kodebox-' + context['version'])


def compress_executable(context):
    print ''
    print 'compress executable to ' + get_compressed_filename(context)
    if not context['dry_run']:
        check_call(
            ['tar', '-cvzf', get_compressed_filename(context), 'kodebox'])


def create_sha256(context):
    print ''
    compressed_filename = get_compressed_filename(context)
    print 'create sha256 of compressed file ' + compressed_filename
    if not context['dry_run']:
        shasum_out = check_output(
            ['shasum', '-a', '256', compressed_filename])
        return shasum_out.split(' ')[0]
    else:
        return ''


def upload_executable(context):
    bucket_name = 'kodebox-cli'
    upload_file_name = get_compressed_filename(context)
    print ''
    print 'Upload compressed file to ' + bucket_name + '/' + upload_file_name
    if not context['dry_run'] and not context['local_test']:
        conn = tinys3.Connection(context['access_key'], context['secret_key'])
        latest_file = open(get_compressed_filename(context), 'rb')
        conn.upload(upload_file_name, latest_file,
                    bucket=bucket_name, close=True)


def get_compressed_filename(context):
    return 'kodebox-macOS-{version}.tar.gz'.format(version=context['version'])


def clone_homebrew(context):
    print ''
    print 'clone homebrew repo'
    if not context['dry_run']:
        check_call(
            ['git', 'clone', 'git@github.com:kodebox-io/homebrew-kodebox.git'])


def update_homebrew_version_sha256(context):
    template = Template('''
require "language/go"


class Kodebox < Formula
  desc "Tool for snippet upload"
  homepage "https://kodebox.io"
  url "https://s3-us-west-1.amazonaws.com/kodebox-cli/$compressed_file_name"
  sha256 "$sha256"

  bottle :unneeded

  def install
    bin.install "kodebox"
  end

  test do
    system "#{bin}/kodebox", "-v"
  end
end
''')
    new_formula = template.substitute(compressed_file_name=get_compressed_filename(context),
                                      sha256=context['sha256'])

    print ''
    print 'new formula file will be'
    print '=========FORMULA========='
    print new_formula
    print '=========FORMULA========='
    if not context['dry_run']:
        write_to_file('Formula/kodebox.rb', new_formula)


def push_homebrew(context):
    commit_msg = 'Release ' + context['version']
    print ''
    print 'homebrew commit : ' + commit_msg
    print 'push homebrew repo '
    if not context['dry_run']:
        check_call(['git', 'commit', '-a', '-m', commit_msg])
        if not context['local_test']:
            check_call(['git', 'push', 'origin', 'master'])


def copy_debian_dir(context):
    print ''
    print 'Copying debian dir'
    if not context['dry_run']:
        debian_pkg_dir = 'kodebox-' + context['version']
        shutil.rmtree(debian_pkg_dir, ignore_errors=True)
        os.mkdir(debian_pkg_dir)
        shutil.copytree('../distribute/debian', debian_pkg_dir + '/debian')


def update_change_log(context):
    command_template = Template(
        'env\tEMAIL=$email\tNAME=$name\tdebchange\t-v\t$version\t$changelog')
    command = command_template.substitute(**context)
    print ''
    print 'Run changelog command ' + command
    if not context['dry_run']:
        os.chdir('kodebox-' + context['version'])
        check_call(command.split('\t'))
        os.chdir('..')


def write_to_file(file_name, content):
    file_ = open(file_name, 'w')
    file_.write(content)
    file_.close()


if __name__ == '__main__':
    distribute()
