#!/usr/bin/python3

# Copyright (c) 2017, Ximin Luo <infinity0@debian.org>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

'''
TODO, from DebConf 2018 WebExt packaging BoF:

- autodetect extension short name for dh_webext, avoids override_dh_webext
- Guide for maintainers to define transitional packages from old xul-ext stuff
  - wiki.d.o/RenamingPackages
  - see adblock-plus git history for an example
  - done in d/control so we can't really automate it in dh_webext but at least
    we can give a central documentation for packagers to do it
- extra substvars, see TODOs further below
- better documentation, e.g. syntax for the debian/install-webext file
- versioned Depends for firefox >= 60 etc

Other stuff:
- chase up https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=890392
  - if chromium maintainer doesn't co-operate, alternative is to add
    that file to a webext-common package and depend on it for every webext
'''

import argparse
import datetime
import json
import os
import shlex
import subprocess
import sys
import time

self_script = "dh_webext"

app_packages_debian = {
    "gecko": [
        "firefox",
        #"thunderbird", thunderbird does not support webext yet
    ],
    "chromium": ["chromium"],
}

app_extension_paths = {
    "gecko": [
        "/usr/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}",
        #"/usr/share/mozilla/extensions/{3550f703-e582-4d05-9a08-453d09bdfdc6}", thunderbird does not support webext yet
    ],
    "chromium": ["/usr/share/chromium/extensions"],
}

def log(*args):
    print(self_script + ":", *args)

def run(cmdline, verbose=False):
    if verbose:
        print("  ", " ".join(shlex.quote(a) for a in cmdline))
    subprocess.check_call(cmdline)

def get_all_packages():
    lines = open("debian/control").readlines()
    package_lines = [x for x in lines if x.find("Package:") >= 0]
    packages = [p[p.find(":")+1:].strip() for p in package_lines]
    packages = [p for p in packages if p.startswith("webext-")]
    if not packages:
        print("dh_webext: warning: no webext-* packages detected, no substvars " +
              "will be generated. THIS IS PROBABLY NOT WHAT YOU WANT.", file=sys.stderr)
    return packages

def generate_substvars(package, name, supported, verbose=False):
    ext_name = name
    for prefix in ("webext-",):
        if ext_name.startswith(prefix):
            ext_name = ext_name[len(prefix):]

    filename = "debian/%s.substvars" % package
    # TODO: read old file and merge the new values in

    lines = []
    debian_apps = sorted(set(deb for app in supported
        for deb in app_packages_debian[app]))

    # TODO: depends, recommends, breaks, replaces, conflicts

    enhances = debian_apps
    lines.append("webext:Enhances=" + ", ".join(enhances) + "\n")

    provided = [prefix + "-" + ext_name for prefix in debian_apps]
    lines.append("webext:Provides=" + ", ".join(provided) + "\n")

    with open(filename, 'w+') as fp:
        fp.writelines(lines)

def install_for_app(extname, appname, appextname, supported, verbose=False):
    for p in app_extension_paths[appname]:
        run(["dh_link", "/usr/share/webext/%s" % extname,
            os.path.join(p, appextname)], verbose=verbose)
    supported.append(appname)

def install_webext(*args):
    parser = argparse.ArgumentParser(
        description="Debhelper command to install an unpacked WebExtension")
    parser.add_argument(
        "-p", "--package", dest="packages", metavar="PACKAGE", action="append", default=[],
        help="calculate substvars only for the specified PACKAGE")
    parser.add_argument(
        "-I", "--dh-install-arg", dest="dh_install_args", metavar="ARG", action="append", default=[],
        help="extra arguments to pass to dh_install")
    parser.add_argument(
        "-v", "--verbose", action="store_true", dest="verbose", default=False,
        help="print more information")
    parser.add_argument(
        'home', metavar='PATH', default='.',
        help='Path to the main directory. (Default: %(default)s)')
    parser.add_argument(
        'name', metavar='NAME', nargs='?', default=None,
        help='Short name of the extension.')
    # TODO: need to handle/ignore other debhelper options, see dh_xul-ext
    # for an example and `man debhelper` "COMMON DEBHELPER OPTIONS" for full list
    # TODO: import any useful options like -x from install-xpi
    args = parser.parse_args(args)
    packages = args.packages or get_all_packages()

    home = args.home
    name = args.name
    manifest = os.path.join(home, "manifest.json")
    if not os.path.exists(manifest):
        raise ValueError("does not exist: %s" % manifest)

    # reproducible timestamp, see https://reproducible-builds.org/specs/source-date-epoch/
    build_date = int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))
    # touch the manifest, firefox needs this to reload its extension cache
    os.utime(manifest, (build_date, build_date))

    with open(manifest) as fp:
        manifest = json.load(fp)

        if name is None:
            name = manifest["name"]
        if name.startswith("_"):
            raise ValueError("name in manifest.json starts with _, please give actual name to %s" % self_script)

        run(["dh_install", "-X.git", "-X.pc", "-Xdebian"] + args.dh_install_args +
            [home, "usr/share/webext/%s" % name], verbose=args.verbose)

        supported = []

        for appname, details in list(manifest["applications"].items()):
            if appname in app_extension_paths:
                install_for_app(name, appname, details["id"], supported, args.verbose)
            else:
                log("unrecognised application in manifest: %s", appname)

        if "minimum_chrome_version" in manifest:
            install_for_app(name, "chromium", name, supported, args.verbose)

        if os.path.exists("debian/install-webext"):
            with open("debian/install-webext") as install_fp:
                for line in install_fp.readlines():
                    line = line.rstrip("\n")
                    if " " in line:
                        appname, extid = line.split(" ")
                    else:
                        appname, extid = line, name
                    install_for_app(name, appname, extid, supported, args.verbose)

        for package in packages:
            generate_substvars(package, name, supported, args.verbose)

        return 0
    return 1

if __name__ == '__main__':
    sys.exit(install_webext(*sys.argv[1:]))
