📦 Out of Context リポジトリ

リポジトリ / emssr / independent_common_compiler

r2
r2 emssr1
# -*- coding: utf-8 -*-
r2 emssr2
"""このフォルダだけで動くようにファイルを揃える。標準機能だけで書く。
r2 emssr3
r2 emssr4
    python setup.py              runtime/ を揃え、Pyodide をこのフォルダへコピーする
r2 emssr5
    python setup.py --runtime    runtime/ だけ
r2 emssr6
    python setup.py --vendor     Pyodide と web の library だけ
r2 emssr7
    python setup.py --version 314.0.7    版を指定する
r2 emssr8
    python setup.py --dist <DIR>         配布用フォルダを作る
r2 emssr9
r2 emssr10
揃うもの。
r2 emssr11
r2 emssr12
    runtime/         lane64 の実行台と commonc の image。server.py がここから配信する
r2 emssr13
    vendor/pyodide/  ブラウザの中の CPython。約 15 MB
r2 emssr14
    vendor/web/      marked(Markdown)と KaTeX(数式)。約 0.6 MB
r2 emssr15
r2 emssr16
Pyodide の版は npm の registry へ訊く。CDN の `full/` には wheel も揃っているので、
r2 emssr17
そこから四本と numpy の wheel を取る。numpy は束ねの道(vcpu_vec)が使う。
r2 emssr18
"""
r2 emssr19
r2 emssr20
import json
r2 emssr21
import os
r2 emssr22
import shutil
r2 emssr23
import sys
r2 emssr24
import urllib.request
r2 emssr25
r2 emssr26
HERE = os.path.dirname(os.path.abspath(__file__))
r2 emssr27
RUNTIME = os.path.join(HERE, "runtime")
r2 emssr28
VENDOR = os.path.join(HERE, "vendor", "pyodide")
r2 emssr29
WEB = os.path.join(HERE, "vendor", "web")
r2 emssr30
ASSETS = os.path.join(HERE, "assets")
r2 emssr31
r2 emssr32
REGISTRY = "https://registry.npmjs.org/pyodide/latest"
r2 emssr33
CDN = "https://cdn.jsdelivr.net/pyodide/v%s/full/"
r2 emssr34
CORE = ("pyodide.js", "pyodide.mjs", "pyodide.asm.mjs", "pyodide.asm.wasm",
r2 emssr35
        "python_stdlib.zip", "pyodide-lock.json")
r2 emssr36
r2 emssr37
# runtime/ に置く名前と、repository での在り処
r2 emssr38
SOURCES = (
r2 emssr39
    ("vcpu.py", "continuous_republic/common_systems/Python_vCPU/vcpu.py"),
r2 emssr40
    ("vcpu_vec.py", "continuous_republic/common_systems/Python_vCPU/vcpu_vec.py"),
r2 emssr41
    ("lex.py", "continuous_republic/common_systems/Python_vCPU/lex.py"),
r2 emssr42
    ("toolchain.py", "continuous_republic/common_systems/Python_vCPU/toolchain.py"),
r2 emssr43
    ("commonc_lane64.bin", "builds/commonc/commonc_lane64.bin"),
r2 emssr44
    ("joinrank.dic", "continuous_republic/common_apps/joinrank/joinrank/joinrank.dic"),
r2 emssr45
)
r2 emssr46
r2 emssr47
r2 emssr48
def root():
r2 emssr49
    return os.path.abspath(os.path.join(HERE, os.pardir, os.pardir, os.pardir))
r2 emssr50
r2 emssr51
r2 emssr52
def get(url, path):
r2 emssr53
    print("  %s" % os.path.basename(path))
r2 emssr54
    with urllib.request.urlopen(url) as r, open(path, "wb") as f:
r2 emssr55
        shutil.copyfileobj(r, f)
r2 emssr56
r2 emssr57
r2 emssr58
# ===== runtime =====
r2 emssr59
r2 emssr60
def runtime():
r2 emssr61
    os.path.isdir(RUNTIME) or os.makedirs(RUNTIME)
r2 emssr62
    R = root()
r2 emssr63
    miss = []
r2 emssr64
    for name, rel in SOURCES:
r2 emssr65
        src = os.path.join(R, rel.replace("/", os.sep))
r2 emssr66
        if os.path.exists(src):
r2 emssr67
            shutil.copyfile(src, os.path.join(RUNTIME, name))
r2 emssr68
            print("  %s" % name)
r2 emssr69
        elif not os.path.exists(os.path.join(RUNTIME, name)):
r2 emssr70
            miss.append(rel)
r2 emssr71
    for name in ("joinrank.bin", "anf.bin"):
r2 emssr72
        dst = os.path.join(RUNTIME, name)
r2 emssr73
        if os.path.exists(dst):
r2 emssr74
            continue
r2 emssr75
        built = os.path.join(R, "continuous_republic", "common_apps", "joinrank",
r2 emssr76
                             "build", name)
r2 emssr77
        if os.path.exists(built):
r2 emssr78
            shutil.copyfile(built, dst)
r2 emssr79
            print("  %s" % name)
r2 emssr80
        else:
r2 emssr81
            miss.append("%s(common_apps/joinrank/build.py で作る)" % name)
r2 emssr82
    if miss:
r2 emssr83
        print("揃わなかったもの:")
r2 emssr84
        for m in miss:
r2 emssr85
            print("  %s" % m)
r2 emssr86
        return 1
r2 emssr87
    return 0
r2 emssr88
r2 emssr89
r2 emssr90
# ===== Pyodide =====
r2 emssr91
r2 emssr92
def vendor(version=None):
r2 emssr93
    if version is None:
r2 emssr94
        with urllib.request.urlopen(REGISTRY) as r:
r2 emssr95
            version = json.load(r)["version"]
r2 emssr96
    base = CDN % version
r2 emssr97
    os.path.isdir(VENDOR) or os.makedirs(VENDOR)
r2 emssr98
    print("Pyodide %s" % version)
r2 emssr99
    for n in CORE:
r2 emssr100
        get(base + n, os.path.join(VENDOR, n))
r2 emssr101
    lock = json.load(open(os.path.join(VENDOR, "pyodide-lock.json"), encoding="utf-8"))
r2 emssr102
    wheel = lock["packages"]["numpy"]["file_name"]
r2 emssr103
    get(base + wheel, os.path.join(VENDOR, wheel))
r2 emssr104
    open(os.path.join(VENDOR, "version.txt"), "w").write(version)
r2 emssr105
    return 0
r2 emssr106
r2 emssr107
r2 emssr108
# ===== web の library =====
r2 emssr109
#
r2 emssr110
# notebook の説明セルは Markdown と LaTeX で書く。描くのは browser なので、
r2 emssr111
# marked と KaTeX をこのフォルダへ置く。KaTeX は font を伴う。
r2 emssr112
r2 emssr113
MARKED = "https://cdn.jsdelivr.net/npm/marked@%s/lib/marked.umd.js"
r2 emssr114
KATEX = "https://cdn.jsdelivr.net/npm/katex@%s/dist/%s"
r2 emssr115
KATEX_FONTS = (
r2 emssr116
    "KaTeX_AMS-Regular", "KaTeX_Caligraphic-Bold", "KaTeX_Caligraphic-Regular",
r2 emssr117
    "KaTeX_Fraktur-Bold", "KaTeX_Fraktur-Regular", "KaTeX_Main-Bold",
r2 emssr118
    "KaTeX_Main-BoldItalic", "KaTeX_Main-Italic", "KaTeX_Main-Regular",
r2 emssr119
    "KaTeX_Math-BoldItalic", "KaTeX_Math-Italic", "KaTeX_SansSerif-Bold",
r2 emssr120
    "KaTeX_SansSerif-Italic", "KaTeX_SansSerif-Regular", "KaTeX_Script-Regular",
r2 emssr121
    "KaTeX_Size1-Regular", "KaTeX_Size2-Regular", "KaTeX_Size3-Regular",
r2 emssr122
    "KaTeX_Size4-Regular", "KaTeX_Typewriter-Regular",
r2 emssr123
)
r2 emssr124
r2 emssr125
r2 emssr126
def latest(name):
r2 emssr127
    with urllib.request.urlopen("https://registry.npmjs.org/%s/latest" % name) as r:
r2 emssr128
        return json.load(r)["version"]
r2 emssr129
r2 emssr130
r2 emssr131
def web(marked_v=None, katex_v=None):
r2 emssr132
    marked_v = marked_v or latest("marked")
r2 emssr133
    katex_v = katex_v or latest("katex")
r2 emssr134
    os.path.isdir(os.path.join(WEB, "fonts")) or os.makedirs(os.path.join(WEB, "fonts"))
r2 emssr135
    print("marked %s / KaTeX %s" % (marked_v, katex_v))
r2 emssr136
    get(MARKED % marked_v, os.path.join(WEB, "marked.umd.js"))
r2 emssr137
    for n in ("katex.min.js", "katex.min.css"):
r2 emssr138
        get(KATEX % (katex_v, n), os.path.join(WEB, n))
r2 emssr139
    get(KATEX % (katex_v, "contrib/auto-render.min.js"),
r2 emssr140
        os.path.join(WEB, "auto-render.min.js"))
r2 emssr141
    for f in KATEX_FONTS:
r2 emssr142
        get(KATEX % (katex_v, "fonts/" + f + ".woff2"),
r2 emssr143
            os.path.join(WEB, "fonts", f + ".woff2"))
r2 emssr144
    open(os.path.join(WEB, "version.txt"), "w").write(
r2 emssr145
        "marked %s\nkatex %s\n" % (marked_v, katex_v))
r2 emssr146
    return 0
r2 emssr147
r2 emssr148
r2 emssr149
# ===== 配布用フォルダ =====
r2 emssr150
#
r2 emssr151
# repository の外へ出しても動く形にまとめる。runtime/ と vendor/ を抱えるので、
r2 emssr152
# 受け取った側は展開して server.py を動かすだけでよい。
r2 emssr153
#
r2 emssr154
# 例題の .cmn は tools/independent_compile_test の examples をそのまま使う。
r2 emssr155
# セルへドロップして実行できる。
r2 emssr156
r2 emssr157
APP = ("server.py", "setup.py", "test_notebook.py", "README.md")
r2 emssr158
TREES = ("kernel", "web", "notebooks", "vscode", "runtime", "vendor", "assets")
r2 emssr159
EXAMPLES = "tools/independent_compile_test/examples"
r2 emssr160
r2 emssr161
r2 emssr162
r2 emssr163
def dist(dst):
r2 emssr164
    if runtime():
r2 emssr165
        return 1
r2 emssr166
    if not os.path.isdir(VENDOR):
r2 emssr167
        print("vendor/ がありません。先に python setup.py --vendor を実行してください")
r2 emssr168
        return 1
r2 emssr169
    os.path.isdir(dst) or os.makedirs(dst)
r2 emssr170
    for n in APP:
r2 emssr171
        shutil.copyfile(os.path.join(HERE, n), os.path.join(dst, n))
r2 emssr172
    for n in TREES:
r2 emssr173
        src = os.path.join(HERE, n)
r2 emssr174
        if not os.path.isdir(src):
r2 emssr175
            continue
r2 emssr176
        shutil.copytree(src, os.path.join(dst, n), dirs_exist_ok=True,
r2 emssr177
                        ignore=shutil.ignore_patterns("__pycache__", "*.pyc", "_cell.dic"))
r2 emssr178
    ex = os.path.join(root(), *EXAMPLES.split("/"))
r2 emssr179
    if os.path.isdir(ex):
r2 emssr180
        shutil.copytree(ex, os.path.join(dst, "examples"), dirs_exist_ok=True,
r2 emssr181
                        ignore=shutil.ignore_patterns("__pycache__", "*.pyc"))
r2 emssr182
    open(os.path.join(dst, "start.ps1"), "w", encoding="utf-8", newline="\r\n").write(
r2 emssr183
        "# Common scope notebook を起動する\n"
r2 emssr184
        "$here = Split-Path -Parent $MyInvocation.MyCommand.Path\n"
r2 emssr185
        "python \"$here\\server.py\"\n")
r2 emssr186
    open(os.path.join(dst, "start.sh"), "w", encoding="utf-8", newline="\n").write(
r2 emssr187
        "#!/bin/sh\n"
r2 emssr188
        "# Common scope notebook を起動する\n"
r2 emssr189
        'exec python3 "$(dirname "$0")/server.py" "$@"\n')
r2 emssr190
    n = sum(len(f) for _b, _d, f in os.walk(dst))
r2 emssr191
    size = sum(os.path.getsize(os.path.join(b, f))
r2 emssr192
               for b, _d, fs in os.walk(dst) for f in fs)
r2 emssr193
    print("%s   %d ファイル   %.1f MB" % (dst, n, size / 1e6))
r2 emssr194
    return 0
r2 emssr195
r2 emssr196
r2 emssr197
def main(argv):
r2 emssr198
    do_rt = do_ve = True
r2 emssr199
    version = None
r2 emssr200
    it = iter(argv)
r2 emssr201
    for a in it:
r2 emssr202
        if a == "--runtime":
r2 emssr203
            do_ve = False
r2 emssr204
        elif a == "--vendor":
r2 emssr205
            do_rt = False
r2 emssr206
        elif a == "--version":
r2 emssr207
            version = next(it)
r2 emssr208
        elif a == "--dist":
r2 emssr209
            return dist(os.path.abspath(next(it)))
r2 emssr210
        else:
r2 emssr211
            print(__doc__)
r2 emssr212
            return 2
r2 emssr213
    bad = 0
r2 emssr214
    if do_rt:
r2 emssr215
        print("runtime/ を揃えます")
r2 emssr216
        bad |= runtime()
r2 emssr217
    if do_ve:
r2 emssr218
        try:
r2 emssr219
            vendor(version)
r2 emssr220
            web()
r2 emssr221
        except Exception as e:                    # noqa: BLE001
r2 emssr222
            print("library を取れません: %s" % e)
r2 emssr223
            print("  network が無い場所では、別の PC で --vendor を実行して vendor/ をコピーします")
r2 emssr224
            bad = 1
r2 emssr225
    if not bad:
r2 emssr226
        print("")
r2 emssr227
        print("起動:  python server.py")
r2 emssr228
    return bad
r2 emssr229
r2 emssr230
r2 emssr231
if __name__ == "__main__":
r2 emssr232
    sys.exit(main(sys.argv[1:]))