#
# Copyright 2023 (C) Weidmueller GmbH & Co KG
# Author: Lukas Funke <lukas.funke@weidmueller.com>
#
# Handle Go vendor support for offline builds
#
# When importing Go modules, Go downloads the imported modules using
# a network (proxy) connection ahead of the compile stage. This contradicts 
# the yocto build concept of fetching every source ahead of build-time
# and supporting offline builds.
#
# To support offline builds, we use Go 'vendoring': module dependencies are 
# downloaded during the fetch-phase and unpacked into the modules 'vendor'
# folder. Additionally a manifest file is generated for the 'vendor' folder
# 

inherit go-mod

def go_src_uri(repo, version, path=None, subdir=None, \
                vcs='git', replaces=None, pathmajor=None):

    destsuffix = "git/src/import/vendor.fetch"
    module_path = repo if not path else path

    src_uri = "{}://{};name={}".format(vcs, repo, module_path.replace('/', '.'))
    src_uri += ";destsuffix={}/{}@{}".format(destsuffix, repo, version)

    if vcs == "git":
        src_uri += ";nobranch=1;protocol=https"

    src_uri += ";go_module_path={}".format(module_path)

    if replaces:
        src_uri += ";go_module_replacement={}".format(replaces)
    if subdir:
        src_uri += ";go_subdir={}".format(subdir)
    if pathmajor:
        src_uri += ";go_pathmajor={}".format(pathmajor)
    src_uri += ";is_go_dependency=1"

    return src_uri

python do_vendor_unlink() {
    go_import = d.getVar('GO_IMPORT')
    source_dir = d.getVar('S')
    linkname = os.path.join(source_dir, *['src', go_import, 'vendor'])

    os.unlink(linkname)
}

addtask vendor_unlink before do_package after do_install

python do_go_vendor() {
    import shutil

    src_uri = (d.getVar('SRC_URI') or "").split()

    if not src_uri:
        bb.fatal("SRC_URI is empty")

    default_destsuffix = "git/src/import/vendor.fetch"
    fetcher = bb.fetch2.Fetch(src_uri, d)
    go_import = d.getVar('GO_IMPORT')
    source_dir = d.getVar('S')

    linkname = os.path.join(source_dir, *['src', go_import, 'vendor'])
    vendor_dir = os.path.join(source_dir, *['src', 'import', 'vendor'])
    import_dir = os.path.join(source_dir, *['src', 'import', 'vendor.fetch'])

    if os.path.exists(vendor_dir):
        # Nothing to do except re-establish link to actual vendor folder
        if not os.path.exists(linkname):
            os.symlink(vendor_dir, linkname)
        return

    bb.utils.mkdirhier(vendor_dir)

    modules = {}

    for url in fetcher.urls:
        srcuri = fetcher.ud[url].host + fetcher.ud[url].path

        # Skip non Go module src uris
        if not fetcher.ud[url].parm.get('is_go_dependency'):
            continue

        destsuffix = fetcher.ud[url].parm.get('destsuffix')
        # We derive the module repo / version in the following manner (exmaple):
        # 
        # destsuffix = git/src/import/vendor.fetch/github.com/foo/bar@v1.2.3
        # p = github.com/foo/bar@v1.2.3
        # repo = github.com/foo/bar
        # version = v1.2.3

        p = destsuffix[len(default_destsuffix)+1:]
        repo, version = p.split('@')

        module_path = fetcher.ud[url].parm.get('go_module_path')

        subdir = fetcher.ud[url].parm.get('go_subdir')
        subdir = None if not subdir else subdir

        pathMajor = fetcher.ud[url].parm.get('go_pathmajor')
        pathMajor = None if not pathMajor else pathMajor.strip('/')

        if not (repo, version) in modules:
            modules[(repo, version)] =   {
                                "repo_path": os.path.join(import_dir, p),
                                "module_path": module_path,
                                "subdir": subdir,
                                "pathMajor": pathMajor }

    for module_key, module in modules.items():

        # only take the version which is explicitly listed
        # as a dependency in the go.mod
        module_path = module['module_path']
        rootdir = module['repo_path']
        subdir = module['subdir']
        pathMajor = module['pathMajor']

        src = rootdir

        if subdir:
            src = os.path.join(rootdir, subdir)

        # If the module is released at major version 2 or higher, the module
        # path must end with a major version suffix like /v2.
        # This may or may not be part of the subdirectory name
        #
        # https://go.dev/ref/mod#modules-overview
        if pathMajor:
            tmp = os.path.join(src, pathMajor)
            # source directory including major version path may or may not exist
            if os.path.exists(tmp):
                src = tmp

        dst = os.path.join(vendor_dir, module_path)

        bb.debug(1, "cp %s --> %s" % (src, dst))
        shutil.copytree(src, dst, symlinks=True, dirs_exist_ok=True, \
            ignore=shutil.ignore_patterns(".git", \
                                            "vendor", \
                                            "*._test.go"))

        # If the root directory has a LICENSE file but not the subdir
        # we copy the root license to the sub module since the license
        # applies to all modules in the repository
        # see https://go.dev/ref/mod#vcs-license
        if subdir:
            rootdirLicese = os.path.join(rootdir, "LICENSE")
            subdirLicense = os.path.join(src, "LICENSE")

            if not os.path.exists(subdir) and \
                os.path.exists(rootdirLicese):
                shutil.copy2(rootdirLicese, subdirLicense)

    # Copy vendor manifest
    modules_txt_src = os.path.join(d.getVar('WORKDIR'), "modules.txt")
    bb.debug(1, "cp %s --> %s" % (modules_txt_src, vendor_dir))
    shutil.copy2(modules_txt_src, vendor_dir)

    # Clean up vendor dir
    # We only require the modules in the modules_txt file
    fetched_paths = set([os.path.relpath(x[0], vendor_dir) for x in os.walk(vendor_dir)])

    # Remove toplevel dir
    fetched_paths.remove('.')

    vendored_paths = set()
    replaced_paths = dict()
    with open(modules_txt_src) as f:
        for line in f:
            if not line.startswith("#"):
                line = line.strip()
                vendored_paths.add(line)

                # Add toplevel dirs into vendored dir, as we want to keep them
                topdir = os.path.dirname(line)
                while len(topdir):
                    if not topdir in vendored_paths:
                        vendored_paths.add(topdir)

                    topdir = os.path.dirname(topdir)
            else:
                replaced_module = line.split("=>")
                if len(replaced_module) > 1:
                    # This module has been replaced, use a local path
                    # we parse the line that has a pattern "# module-name [module-version] => local-path
                    actual_path = replaced_module[1].strip()
                    vendored_name = replaced_module[0].split()[1]
                    bb.debug(1, "added vendored name %s for actual path %s" % (vendored_name, actual_path))
                    replaced_paths[vendored_name] = actual_path

    for path in fetched_paths:
        if path not in vendored_paths:
            realpath = os.path.join(vendor_dir, path)
            if os.path.exists(realpath):
                shutil.rmtree(realpath)

    for vendored_name, replaced_path in replaced_paths.items():
        symlink_target = os.path.join(source_dir, *['src', go_import, replaced_path])
        symlink_name = os.path.join(vendor_dir, vendored_name)
        bb.debug(1, "vendored name %s, symlink name %s" % (vendored_name, symlink_name))
        os.symlink(symlink_target, symlink_name)

    # Create a symlink to the actual directory
    os.symlink(vendor_dir, linkname)
}

addtask go_vendor before do_patch after do_unpack
