#!/usr/bin/env python
#
# Copyright 2019 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Writes Java module descriptor to srcjar file."""

import argparse
import os
import sys
import zipfile

sys.path.append(
    os.path.join(
        os.path.dirname(__file__), "..", "..", "..", "build"))
import action_helpers
import zip_helpers

_TEMPLATE = """\
// This file is autogenerated by
//     components/module_installer/android/module_desc_java.py
// Please do not change its content.

package org.chromium.components.module_installer.builder;

import org.chromium.build.annotations.UsedByReflection;

@UsedByReflection("Module.java")
public class ModuleDescriptor_{MODULE} implements ModuleDescriptor {{
    private static final String[] LIBRARIES = {{{LIBRARIES}}};
    private static final String[] PAKS = {{{PAKS}}};

    @Override
    public String[] getLibraries() {{
        return LIBRARIES;
    }}

    @Override
    public String[] getPaks() {{
        return PAKS;
    }}

    @Override
    public boolean getLoadNativeOnGetImpl() {{
        return {LOAD_NATIVE_ON_GET_IMPL};
    }}
}}
"""


def main():
    parser = argparse.ArgumentParser()
    action_helpers.add_depfile_arg(parser)
    parser.add_argument('--module', required=True, help='The module name.')
    parser.add_argument('--libraries-file',
                        required=True,
                        help='Path to file with GN list of library paths')
    parser.add_argument('--paks', help='GN list of PAK file paths')
    parser.add_argument(
        '--output', required=True, help='Path to the generated srcjar file.')
    parser.add_argument('--load-native-on-get-impl', action='store_true',
        default=False,
        help='Load module automatically on calling Module.getImpl().')
    options = parser.parse_args()
    options.paks = action_helpers.parse_gn_list(options.paks)

    with open(options.libraries_file) as f:
        libraries_list = action_helpers.parse_gn_list(f.read())

    libraries = []
    for path in libraries_list:
        path = path.strip()
        filename = os.path.split(path)[1]
        assert filename.startswith('lib')
        assert filename.endswith('.so')
        # Remove lib prefix and .so suffix.
        libraries += [filename[3:-3]]
    paks = options.paks if options.paks else []

    format_dict = {
        'MODULE': options.module,
        'LIBRARIES': ','.join(['"%s"' % l for l in libraries]),
        'PAKS': ','.join(['"%s"' % os.path.basename(p) for p in paks]),
        'LOAD_NATIVE_ON_GET_IMPL': (
            'true' if options.load_native_on_get_impl else 'false'),
    }
    with action_helpers.atomic_output(options.output) as f:
        with zipfile.ZipFile(f.name, 'w') as srcjar_file:
            zip_path = (f'org/chromium/components/module_installer/builder/'
                        f'ModuleDescriptor_{options.module}.java')
            zip_helpers.add_to_zip_hermetic(
                srcjar_file, zip_path,
                data=_TEMPLATE.format(**format_dict))

    if options.depfile:
        action_helpers.write_depfile(options.depfile,
                                     options.output,
                                     inputs=[options.libraries_file])


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