Newer
Older
NewLang / build.py
# SPDX-License-Identifier: LGPL-2.1
# Copyright 2022 Jookia <contact@jookia.org>

import pathlib
import zipfile


def reproducible_date():
    return (2000, 1, 1, 1, 1, 1)


def open_new_file(path):
    path.unlink(missing_ok=True)
    file = path.open("xb")
    mode = path.stat().st_mode
    new_mode = mode | 0o100  # Executable
    path.chmod(new_mode)
    return file


def write_shebang(file):
    shebang = "#!/usr/bin/env python3\n"
    file.write(shebang.encode("utf-8"))


def open_zip(file):
    return zipfile.ZipFile(
        file, mode="a", compression=zipfile.ZIP_DEFLATED, compresslevel=9
    )


def close_zip(zip):
    zip.close()


def close_file(file):
    file.close()


def find_all_src(srcpath):
    paths = srcpath.glob("**/*")
    new_paths = [srcpath]
    for p in paths:
        if "__pycache__" in p.as_posix():
            continue
        if p.name[0] == ".":
            continue
        new_paths.append(p)
    return new_paths


def write_zip_entry(zip, name, data, date):
    info = zipfile.ZipInfo(filename=name, date_time=date)
    info.create_system = 3  # UNIX
    zip.writestr(info, data, compress_type=zipfile.ZIP_DEFLATED, compresslevel=9)


def write_main(zip, date):
    name = "__main__.py"
    data = "import src.main\nsrc.main.wait_main()"
    write_zip_entry(zip, name, data, date)


def write_dir(zip, path, date):
    # For some reason Python needs empty files with the names of directories ending in /
    name = path.as_posix() + "/"
    data = ""
    write_zip_entry(zip, name, data, date)


def write_file(zip, path, date):
    file = path.open("rb")
    data = file.read()
    new_data = data.replace(b"\r\n", b"\n")
    file.close()
    name = path.as_posix()
    write_zip_entry(zip, name, new_data, date)


def write_src(zip, date):
    srcs = sorted(find_all_src(pathlib.Path("src")))
    for p in srcs:
        if p.is_dir():
            write_dir(zip, p, date)
        else:
            write_file(zip, p, date)


def main():
    date = reproducible_date()
    file = open_new_file(pathlib.Path("NewLang.pyz"))
    write_shebang(file)
    zip = open_zip(file)
    write_src(zip, date)
    write_main(zip, date)
    close_zip(zip)
    close_file(file)


if __name__ == "__main__":
    main()