# 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.rglob("*") 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 newlang.main\nnewlang.main.wait_main(None)" write_zip_entry(zip, name, data, date) def write_dir(zip, path, name, date): # For some reason Python needs empty files with the names of directories ending in / name = name + "/" data = "" write_zip_entry(zip, name, data, date) def write_file(zip, path, name, date): file = path.open("rb") data = file.read() new_data = data.replace(b"\r\n", b"\n") file.close() write_zip_entry(zip, name, new_data, date) def write_src(zip, date): srcs = sorted(find_all_src(pathlib.Path("src/newlang"))) for p in srcs: name = p.relative_to("src").as_posix() if p.is_dir(): write_dir(zip, p, name, date) else: write_file(zip, p, name, 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()