aboutsummaryrefslogtreecommitdiff
# SPDX-License-Identifier: GPL-3.0-or-later

"""
Loading of parts of Haketilo source for testing in browser
"""

# This file is part of Haketilo.
#
# Copyright (C) 2021 Wojtek Kosior <koszko@koszko.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
# I, Wojtek Kosior, thereby promise not to sue for violation of this file's
# license. Although I request that you do not make use this code in a
# proprietary program, I am not going to enforce this in court.

from pathlib import Path
import subprocess, re

from .misc_constants import *

script_root = here.parent
awk_script = script_root / 'compute_scripts.awk'

def make_relative_path(path):
    path = Path(path)

    if path.is_absolute():
        path = path.relative_to(script_root)

    return path

"""Used to ignore hidden files and emacs auto-save files."""
script_name_regex = re.compile(r'^[^.#].*\.js$')

def available_scripts(directory):
    for script in directory.rglob('*.js'):
        if script_name_regex.match(script.name):
            yield script

def wrapped_script(script_path, wrap_partially=True):
    if script_path == 'exports_init.js':
        with open(script_root / 'MOZILLA_exports_init.js') as script:
            return script.read()

    command = 'partially_wrapped_code' if wrap_partially else 'wrapped_code'
    awk_command = ['awk', '-f', str(awk_script), command, str(script_path)]
    awk = subprocess.run(awk_command, stdout=subprocess.PIPE, cwd=script_root,
                         check=True)

    return awk.stdout.decode()

def load_script(path, import_dirs):
    """
    `path` and `import_dirs` are .js file path and a list of directory paths,
    respectively. They may be absolute or specified relative to Haketilo's
    project directory.

    Return a string containing script from `path` together with all other
    scripts it depends. Dependencies are wrapped in the same way Haketilo's
    build system wraps them, with imports properly satisfied. The main script
    being loaded is wrapped partially - it also has its imports satisfied, but
    its code is not placed inside an anonymous function, so the
    """
    path = make_relative_path(path)

    import_dirs = [make_relative_path(dir) for dir in import_dirs]
    available = [s for dir in import_dirs for s in available_scripts(dir)]

    awk = subprocess.run(['awk', '-f', str(awk_script), 'script_dependencies',
                          str(path), *[str(s) for s in available]],
                         stdout=subprocess.PIPE, cwd=script_root, check=True)

    to_load = awk.stdout.decode().split()
    texts = [wrapped_script(path, wrap_partially=(i == len(to_load) - 1))
             for i, path in enumerate(to_load)]

    return '\n'.join(texts)