#! /usr/bin/env python
#
# Copyright (C) 2017 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1.  Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
# 2.  Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import argparse
import glob
import json
import os.path
import shutil
import subprocess
import sys
import tarfile

if sys.version_info > (3, 0):
    from urllib.request import urlopen
else:
    from urllib2 import urlopen

LKGR_URL = 'https://storage.googleapis.com/wasm-llvm/builds/%s/lkgr.json'
TORTURE_FILE = 'wasm-torture-emwasm-%s.tbz2'
TORTURE_URL = 'https://storage.googleapis.com/wasm-llvm/builds/%s/%s/%s'
TORTURE_DIR = 'emwasm-torture-out'
WATERFALL_DIR = 'waterfall'
WATERFALL_GIT = 'https://github.com/WebAssembly/waterfall.git'
WATERFALL_KNOWN_FAILURES = 'src/test/run_known_gcc_test_failures.txt'

DESCRIPTION = """GCC torture test packager for jsc testing

Obtain the GCC torture tests as compiled for WebAssembly by the waterfall, using
Emscripten with its embedded libc. Create a yaml file which can be executed with
run-jsc-stress-tests."""


def parse_args():
    parser = argparse.ArgumentParser(
        description=DESCRIPTION,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog='See http://wasm-stat.us for current waterfall status')
    parser.add_argument('--lkgr', default=None, help='LKGR value to use')
    parser.add_argument('--platform', default='mac', help='Waterfall platform to sync to')
    parser.add_argument('--nountar', default=False, action='store_true', help='If set, torture tests are assumed to already be in their destination folder')
    parser.add_argument('--waterfall_hash', default=None, help='git hash to use for the waterfall repo')
    parser.add_argument('--yaml', default='gcc-torture.yaml', help='yaml test file to generate')
    return parser.parse_args()


def update_lkgr(args):
    lkgr_url = LKGR_URL % args.platform
    if not args.lkgr:
        print('Downloading: %s' % lkgr_url)
        args.lkgr = json.loads(urlopen(lkgr_url).read())['build']
    print('lkgr: %s' % args.lkgr)


def untar_torture(args):
    torture_file = TORTURE_FILE % args.lkgr
    torture_url = TORTURE_URL % (args.platform, args.lkgr, torture_file)
    if not os.path.exists(torture_file):
        print('Downloading: %s' % torture_url)
        torture_download = urlopen(torture_url)
        with open(torture_file, 'wb') as f:
            f.write(torture_download.read())
    if not args.nountar:
        if os.path.isdir(TORTURE_DIR):
            shutil.rmtree(TORTURE_DIR)
        with tarfile.open(torture_file, 'r') as torture_tar:
            print('Extracting: %s -> %s' % (torture_file, TORTURE_DIR))
            torture_tar.extractall()
    assert os.path.isdir(TORTURE_DIR)


def list_js_files(args):
    js_files = sorted([os.path.basename(f) for f in glob.glob(os.path.join(TORTURE_DIR, '*.js'))])
    print('Found %s JavaScript tests' % len(js_files))
    assert len(js_files) > 1200
    return js_files


def waterfall_known_failures(args):
    if not os.path.isdir(WATERFALL_DIR):
        subprocess.check_call(['git', 'clone', WATERFALL_GIT, WATERFALL_DIR])
    else:
        subprocess.check_call(['git', 'pull'], cwd=WATERFALL_DIR)
    if args.waterfall_hash:
        subprocess.check_call(['git', 'checkout', args.waterfall_hash], cwd=WATERFALL_DIR)
    else:
        args.waterfall_hash = subprocess.check_output(['git', 'log', '-n1', '--pretty=format:%H'], cwd=WATERFALL_DIR).strip()
    print('Waterfall at: %s' % args.waterfall_hash)
    known_failures = []
    with open(os.path.join(WATERFALL_DIR, WATERFALL_KNOWN_FAILURES)) as failures_file:
        for line in failures_file:
            line = line.strip()
            if '#' in line:
                line = line[:line.index('#')].strip()
            tokens = line.split()
            if not tokens:
                continue
            test_file = tokens[0]
            if len(tokens) > 1:
                attributes = set(tokens[1].split(','))
                if 'emwasm' not in attributes:
                    continue
            if os.path.splitext(test_file)[-1] != '.js':
                continue
            known_failures.append(test_file)
    assert known_failures
    return set(known_failures)


def create_yaml(args, js_files, known_failures):
    with open(args.yaml, 'w+') as yaml:
        yaml.write('# GCC torture tests\n')
        yaml.write('# Auto-generated by: %s\n' % sys.argv[0])
        yaml.write('# lkgr: %s\n' % args.lkgr)
        yaml.write('# Waterfall hash: %s\n' % args.waterfall_hash)
        for js in js_files:
            yaml.write('\n- path: %s/%s\n' % (TORTURE_DIR, js))
            yaml.write('  cmd: runWebAssemblyEmscripten :%s\n' % ('normal' if js not in known_failures else 'skip'))


def main():
    args = parse_args()
    update_lkgr(args)
    untar_torture(args)
    js_files = list_js_files(args)
    known_failures = waterfall_known_failures(args)
    create_yaml(args, js_files, known_failures)


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