""" The configuration file .pure-py.json has following keys, whose values are all strings. - spago: the path of spago command, default: "spago". - index-mirror: the name of python FFI mirror used, default: "default". - blueprint: the path of `pspy-blueprint`, default: `pspy-blueprint` - python-package: the name of output python package, default to be the name of current directory, with dashs replaced by underscores. - corefn-dir: the name of corefn directory, default to be "output" You'd better add following paths to .gitignore : - pure-py.json - .pure-py/ """ from importlib import import_module from typing import Dict, List, Iterable from subprocess import check_call from distutils.dir_util import copy_tree from purescripto.configure_consts import * from purescripto.utilities import auto_link_repo, import_from_path import json import sys import os import wisepy2 _TEMPLATE = { CKey.CoreFnDir : CValue.CoreFnDir, CKey.EntryModule: CValue.EntryModule, CKey.BluePrint : CValue.BluePrint, CKey.IndexMirror: CValue.IndexMirror, CKey.DataFormat : CValue.DataFormat, } def warn(s: str): print(wisepy2.Yellow(s)) def mk_ps_blueprint_cmd( pspy_blueprint, python_pack_name: str, entry: str, ffi_deps_path: str, format: str, ): return [ pspy_blueprint, "--py-dir", python_pack_name, "--entry-mod", entry, "--ffi-dep", ffi_deps_path, "--out-format", format, ] def solve_ffi(conf: CValue, update_mirror: bool) -> Iterable[str]: mirror_name = conf.IndexMirror mirror_repo = PSPY_HOME / "mirrors" / mirror_name if update_mirror: import git if not mirror_repo.exists(): warn("The mirror {} not found at {}".format(mirror_name, str(mirror_repo))) if mirror_name == "default": warn( "We're going to clone the mirror" "https://github.com/purescript-python/purescript-python-ffi-index,\n" "to ~/.pspy/mirrors/default." ) git.Repo.clone_from( r"https://github.com/purescript-python/purescript-python-ffi-index", str(mirror_repo), ) else: raise IOError("Mirror not found") git.Repo(str(mirror_repo)).git.pull("origin") mirror_entry = mirror_repo / "entry.py" if not mirror_entry.exists(): if mirror_name != "default": raise IOError( "Mirror {} not found in {}".format(mirror_name, mirror_entry.parent) ) else: import git warn("The mirror {} not found at {}".format(mirror_name, str(mirror_repo))) if mirror_name == "default": warn( "We're going to clone the mirror" "https://github.com/purescript-python/purescript-python-ffi-index,\n" "to ~/.pspy/mirrors/default." ) git.Repo.clone_from( r"https://github.com/purescript-python/purescript-python-ffi-index", str(mirror_repo), ) mirror_mod = import_from_path(mirror_name, str(mirror_entry)) solve_github_repo_url = mirror_mod.solve pspy_local_path = Path(STR_PY_PSC_LOCAL_PATH) ffi_deps = pspy_local_path / STR_FFI_DEPS_FILENAME with ffi_deps.open() as f: deps = f.read().splitlines() cache = set() # to avoid returning duplicated repo for dep in deps: parts = Path(dep).parts if len(parts) > 3 and parts[0] == ".spago": _, package_name, version_, *_ = parts # assure unique cache_key = (package_name, version_) if cache_key in cache: continue cache.add(cache_key) version = [int(each) for each in version_[1:].split(".")] # type: List[int] # return a string, available at current machine yield solve_github_repo_url(package_name, version) FILES_TO_IGNORE = ['.pure-py/'] def pspy( run: bool = False, version: bool = False, init: bool = False, update: bool = False ): """PureScript Python compiler --run : running without rebuild(note that `spago run` will rebuild the code) --version : version of your purescript-python wrapper(purescripto) --init : setup purescript-python components for a spago project --update : sync with latest mirror and Python FFI dependencies example use: Create a pspy project: sh> mkdir purescript-xxx && cd purescript-xxx && spago init && pspy --init Update project's dependencies: sh> cd purescript-xxx && pspy --update Build your project: sh> pspy """ path = Path().absolute() pure_py_conf = path / "pure-py.json" py_pack_name_default = path.name.replace("-", "_") if init: if not pure_py_conf.exists(): with pure_py_conf.open("w") as f: json.dump(_TEMPLATE, f, indent=2, sort_keys=True) ignore_file = path / ".gitignore" with ignore_file.open("a+") as f: is_configured = {k: True for k in FILES_TO_IGNORE} for each in f.readlines(): if each in FILES_TO_IGNORE: is_configured[each] = False xs = [k for k, v in is_configured.items() if v] if xs: f.write("\n# purescript-python\n") for x in xs: f.write(x) f.write("\n") local_dir = path / STR_PY_PSC_LOCAL_PATH local_dir.mkdir(parents=True, exist_ok=True) (local_dir / STR_FFI_DEPS_FILENAME).open("w").close() return # init conf if pure_py_conf.exists(): with pure_py_conf.open() as f: conf_dict = json.load(f) # type: Dict[str, str] else: conf_dict = {} conf_dict.setdefault(CKey.IndexMirror, CValue.IndexMirror) conf_dict.setdefault(CKey.BluePrint, CValue.BluePrint) conf_dict.setdefault(CKey.PyPack, py_pack_name_default) conf_dict.setdefault(CKey.CoreFnDir, CValue.CoreFnDir) conf_dict.setdefault(CKey.EntryModule, CValue.EntryModule) conf_dict.setdefault(CKey.DataFormat, CValue.DataFormat) conf = CValue() conf.IndexMirror = conf_dict[CKey.IndexMirror] conf.BluePrint = conf_dict[CKey.BluePrint] conf.PyPack = conf_dict[CKey.PyPack] conf.CoreFnDir = conf_dict[CKey.CoreFnDir] conf.EntryModule = conf_dict[CKey.EntryModule] conf.DataFormat = conf_dict[CKey.DataFormat] # TODO: currently unused. # support custom corefn output path in pspy-blueprint. corefn_dir = path / conf.CoreFnDir # run commands if run: sys.path.append(str(path)) mod = import_module("{}.{}.pure".format(conf.PyPack, conf.EntryModule)) if hasattr(mod, "main"): mod.main() return elif version: from purescripto.version import __version__ print("{}".format(__version__)) return pspy_local_path = Path(STR_PY_PSC_LOCAL_PATH) if not pspy_local_path.exists(): pspy_local_path.mkdir(parents=True) ffi_deps_file = pspy_local_path / STR_FFI_DEPS_FILENAME cmd = mk_ps_blueprint_cmd( conf.BluePrint, conf.PyPack, conf.EntryModule, str(ffi_deps_file), conf.DataFormat, ) try: check_call(cmd) except FileNotFoundError: print( "It seems that your pspy-blueprint command hasn't got installed\n" r"Go to this page: https://github.com/purescript-python/purescript-python/releases," "\n" r"download exe for your platform, and add it to your PATH." ) sys.exit(1) path_join = os.path.join python_ffi_path = Path(conf.PyPack) / "ffi" if not python_ffi_path.exists(): python_ffi_path.mkdir(parents=True) python_ffi_path = str(python_ffi_path) # copy python ffi files for repo_url in solve_ffi(conf, update_mirror=update): repo = auto_link_repo(repo_url, update=update) copy_tree(path_join(repo.working_dir, "python-ffi"), python_ffi_path) python_ffi_provided_by_current_proj = path / "python-ffi" if python_ffi_provided_by_current_proj.exists(): copy_tree(str(python_ffi_provided_by_current_proj), python_ffi_path) # fill __init__.py for dir, _, files in os.walk(conf.PyPack): if "__init__.py" not in files: open(path_join(dir, "__init__.py"), "w").close()