aboutsummaryrefslogtreecommitdiff
path: root/test/script_loader.py
blob: cc73d4c338749e58f15257e9c5fa14ee21ca6612 (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# 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 of 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 *

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

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

    return path

script_cache = {}

def load_script(path, code_to_add=None):
    """
    `path` is a .js file path in Haketilo sources. It may be absolute or
    specified relative to Haketilo's project directory. `code_to_add` is
    optional code to be appended to the end of the main file being imported.
    it can contain directives like `#IMPORT`.

    Return a string containing script from `path` together with all other
    scripts it depends on. 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 executed in global scope instead of within an anonymous function
    and imported variables are defined with `let` instead of `const` to allow
    a dependency to be substituted by a mocked value.
    """
    path = make_relative_path(path)
    key = (str(path), code_to_add)
    if key in script_cache:
        return script_cache[key]

    append_flags = () if code_to_add is None else ('-A', ':'.join(key))

    awk = subprocess.run(['awk', '-f', awk_script_name, '--',
                          *unit_test_defines, *append_flags,
                          '--output=amalgamate-js:' + str(path)],
                         stdout=subprocess.PIPE, cwd=script_root, check=True)
    script = awk.stdout.decode()
    script_cache[key] = script

    return script