#!/usr/bin/env python

# Sometimes a file generated by buildbot doesn't get saved
# in S3, breaking buildbot
# This tool fixes such problems by deleting files from s3 and cache, so that
# they can be re-generated

import sys
import os
import s3
from util import file_remove_try_hard, verify_path_exists, run_cmd_throw, load_config
from buildbot import get_stats_cache_dir
from buildbot import verify_started_in_right_directory

# if True, won't actually delete files (locally or in s3)
g_dry_run = False

# convert string in the form "7178.txt" => 7178


def stats_txt_name_to_svn_no(s):
    return int(s.split(".")[0])

# cached
g_s3_files = None


def get_s3_files():
    global g_s3_files
    if g_s3_files == None:
        files = s3.list("sumatrapdf/buildbot/")
        g_s3_files = [f.name for f in files]
    return g_s3_files

g_s3_files_dict = None


def get_s3_files_dict():
    global g_s3_files_dict
    if g_s3_files_dict == None:
        files = get_s3_files()
        g_s3_files_dict = {}
        for f in files:
            g_s3_files_dict[f] = True
    return g_s3_files_dict


def get_s3_vers():
    files = get_s3_files()
    vers = {}
    for f in files:
        parts = f.split("/")
        if len(parts) != 4:
            continue
        ver = int(parts[2])
        vers[ver] = True
    res = vers.keys()
    res.sort()
    return res


def valid_s3_ver(ver):
    files = get_s3_files_dict()
    s3Dir = "sumatrapdf/buildbot/%d/" % ver
    name = s3Dir + "stats.txt"
    if not name in files:
        print("ver %d invalid because s3 file %s not present" % (ver, name))
        return False
    name = s3Dir + "analyze.html"
    if name in files:
        return True
    name = s3Dir + "release_build_log.txt"
    if name in files:
        return True
    print(
        "ver %d invalid because neither analyze.html nor release_build_log.txt not present in %s" %
        (ver, s3Dir))
    return False


def s3_files_for_ver(ver):
    files = get_s3_files()
    res = []
    s3_dir = "sumatrapdf/buildbot/%d/" % ver
    for f in files:
        if f.startswith(s3_dir):
            res.append(f)
    return res


def delete_ver(ver):
    print("deleting ver %d" % ver)
    d = get_stats_cache_dir()
    stats_file = os.path.join(d, "%d.txt" % ver)
    if os.path.exists(stats_file):
        print("  deleting %s" % stats_file)
        if not g_dry_run:
            file_remove_try_hard(stats_file)
    s3_files = s3_files_for_ver(ver)
    for f in s3_files:
        print("  deleting s3 %s" % f)
        if not g_dry_run:
            s3.delete(f)

# delete all stats.txt files cached locally and all files from s3 for
# a given version and later


def fix_from_ver(ver, all_vers, all_vers_s3):
    to_delete = {}
    for v in all_vers:
        if v >= ver:
            to_delete[v] = True
    for v in all_vers_s3:
        if v >= ver:
            to_delete[v] = True
    to_delete = to_delete.keys()
    if len(to_delete) > 10:  # safety check
        to_delete.sort()
        to_delete.reverse()
        print(to_delete)
        print("won't delete because too many version: %d" % len(to_delete))
        return

    map(delete_ver, to_delete)

    src_path = os.path.join("..", "sumatrapdf_buildbot")
    verify_path_exists(src_path)
    os.chdir(src_path)

    run_cmd_throw("svn", "update", "-r", str(ver))
    print("Finished fixing")
    sys.exit(1)


def fix():
    verify_started_in_right_directory()
    conf = load_config()
    s3.set_secrets(conf.aws_access, conf.aws_secret)
    s3.set_bucket("kjkpub")

    d = get_stats_cache_dir()
    files = os.listdir(d)
    all_vers = [stats_txt_name_to_svn_no(f) for f in files]
    all_vers_s3 = get_s3_vers()

    get_s3_files()
    for ver in all_vers_s3:
        if not valid_s3_ver(ver):
            fix_from_ver(ver, all_vers, all_vers_s3)

    prev_ver = all_vers[0]
    to_check = all_vers[1:-1]
    for ver in to_check:
        if ver != prev_ver + 1:
            missing_ver = prev_ver + 1
            print("missing ver %d" % missing_ver)
            fix_from_ver(missing_ver, all_vers, all_vers_s3)
            return
        prev_ver = ver
    print("All are ok!")

if __name__ == "__main__":
    fix()
