#!/usr/bin/env python3.8
# Copyright 2018 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""
This script allows for the conversion between ids.txt and .build-id formats.
"""

import os
import sys
import argparse

# rel_to is expected to be absolute
def abs_path(path, rel_to):
    if os.path.isabs(path):
        return path
    else:
        return os.path.abspath(os.path.join(rel_to, path))

# rel_to is assumed to be absolute
def read_ids_txt(ids_path, rel_to):
    with open(ids_path) as f:
        return {build_id:abs_path(path, rel_to) for (build_id, path) in (x.split() for x in f.readlines())}

# build_id_dir is assumed to be absolute
def read_build_id_dir(build_id_dir):
    out = {}
    for root, dirs, files in os.walk(build_id_dir):
        if len(files) != 0 and len(dirs) != 0:
            raise Exception("%s is not a valid .build-id directory" % build_id_dir)
        for f in files:
            suffix = ".debug"
            if f.endswith(suffix):
                out[os.path.basename(root) + f[:-len(suffix)]] = os.path.join(root, f)
    return out

def link(src, dst):
    src = os.path.realpath(src)
    if os.path.exists(dst):
        os.remove(dst)
    os.link(src, dst)

def mkdir(path):
    try:
        os.makedirs(path)
    except OSError as e:
        if e.errno != os.errno.EEXIST:
            raise e

def touch(path):
    if os.path.exists(path):
        os.utime(path, None)
    else:
        with open(path, 'w'):
            return

def write_build_id_dir(build_id_dir, mods):
    for build_id, path in mods.items():
        mkdir(os.path.join(build_id_dir, build_id[:2]))
        link(path, os.path.join(build_id_dir, build_id[:2], build_id[2:] + ".debug"))

# rel_to and path are assumed to be absolute
# if rel_to is None fix_path returns the absolute path. If rel_to
# is not None it turns the path into a relative path.
def fix_path(path, rel_to):
    if rel_to is None:
        return path
    return os.path.relpath(path, rel_to)

# rel_to is assumed to be an absolute path
def write_ids_txt(ids_path, rel_to, mods):
    with open(ids_path, "w") as f:
        for build_id, path in sorted(mods.items()):
            path = fix_path(mods[build_id], rel_to)
            f.write("%s %s\n" % (build_id, path))

def main():
    ids_fmt = "ids.txt"
    build_id_fmt = ".build-id"

    parser = argparse.ArgumentParser(description="Convert between ids.txt and .build-id")
    parser.add_argument("-O", "--output-format", help="Sets the output format.",
                        metavar="FMT",
                        choices=[ids_fmt, build_id_fmt])
    parser.add_argument("--ids-rel-to-in",
                        help="When reading ids.txt use paths relative to DIR",
                        metavar="DIR")
    parser.add_argument("--ids-rel-to-out",
                        help="When writing ids.txt use paths relative to DIR",
                        metavar="DIR")
    parser.add_argument("--stamp",
                        help="Touch STAMP after finishing",
                        metavar="STAMP")
    parser.add_argument("--input", action="append",
                        help=".build-id directories or ids.txt files depending on the output format")
    parser.add_argument("output")

    args = parser.parse_args()

    input_paths = map(os.path.abspath, args.input)
    input_paths = list(filter(os.path.exists, input_paths)) # conventionally ignore empty inputs
    input_dirs = list(map(os.path.isdir, input_paths))
    if len(input_dirs) > 0:
        assert len(input_dirs) == len(input_paths), "input formats cannot be mixed"
        in_fmt = build_id_fmt
    else:
        in_fmt = ids_fmt

    output_path = args.output
    rel_to_in = os.path.abspath(args.ids_rel_to_in) if args.ids_rel_to_in is not None else None
    rel_to_out = os.path.abspath(args.ids_rel_to_out) if args.ids_rel_to_out is not None else None

    mods = {}
    for input_path in input_paths:
        if in_fmt == ids_fmt:
            if rel_to_in is None:
                rel_to_in = os.path.abspath(os.path.dirname(input_path))
            mods.update(read_ids_txt(input_path, rel_to_in))
        else:
            mods.update(read_build_id_dir(input_path))

    if args.output_format == None:
        if in_fmt == ids_fmt:
            out_fmt = build_id_fmt
        else:
            out_fmt = ids_fmt
    else:
        out_fmt = args.output_format

    if out_fmt == ids_fmt:
        write_ids_txt(output_path, rel_to_out, mods)
    else:
        write_build_id_dir(output_path, mods)

    if args.stamp is not None:
        touch(args.stamp)

if __name__ == "__main__":
    main()
