Skip to content

Commit a230626

Browse files
committed
add binary install feature&bump up
1 parent 45cfc08 commit a230626

File tree

6 files changed

+228
-7
lines changed

6 files changed

+228
-7
lines changed

purescripto/configure.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,24 @@ def solve_ffi(conf: CValue, update_mirror: bool) -> Iterable[str]:
128128
yield solve_github_repo_url(package_name, version)
129129

130130

131+
FILES_TO_IGNORE = ['.pure-py/']
131132
def pspy(
132133
run: bool = False, version: bool = False, init: bool = False, update: bool = False
133134
):
134-
"""PureScript Python compiler"""
135+
"""PureScript Python compiler
136+
--run : running without rebuild(note that `spago run` will rebuild the code)
137+
--version : version of your purescript-python wrapper(purescripto)
138+
--init : setup purescript-python components for a spago project
139+
--update : sync with latest mirror and Python FFI dependencies
140+
141+
example use:
142+
Create a pspy project:
143+
sh> mkdir purescript-xxx && cd purescript-xxx && spago init && pspy --init
144+
Update project's dependencies:
145+
sh> cd purescript-xxx && pspy --update
146+
Build your project:
147+
sh> pspy
148+
"""
135149
path = Path().absolute()
136150
pure_py_conf = path / "pure-py.json"
137151
py_pack_name_default = path.name.replace("-", "_")
@@ -142,9 +156,9 @@ def pspy(
142156

143157
ignore_file = path / ".gitignore"
144158
with ignore_file.open("a+") as f:
145-
is_configured = {".pure-py/": True, "pure-py.json": True}
159+
is_configured = {k: True for k in FILES_TO_IGNORE}
146160
for each in f.readlines():
147-
if each in (".pure-py/", "pure-py.json"):
161+
if each in FILES_TO_IGNORE:
148162
is_configured[each] = False
149163

150164
xs = [k for k, v in is_configured.items() if v]

purescripto/installer.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import re
2+
import io
3+
import os
4+
import requests
5+
import zipfile
6+
import stat
7+
from pathlib import Path
8+
from distutils.util import get_platform
9+
10+
tag = re.compile('refs/tags/v(\S+)')
11+
12+
13+
def make_executable(cmd_path):
14+
# always modify mode to READ + EXEC
15+
os.chmod(cmd_path, stat.S_IREAD | stat.S_IEXEC)
16+
17+
18+
def show_tags(url=r"https://github.com/purescript-python/purescript-python"):
19+
"""
20+
Use ls-remote in gitPython
21+
https://stackoverflow.com/questions/35585236/git-ls-remote-in-gitpython
22+
"""
23+
import git
24+
g = git.cmd.Git()
25+
for ref in g.ls_remote(url).split('\n'):
26+
found = tag.findall(ref.split('\t')[-1].strip())
27+
if not found:
28+
continue
29+
yield found[0]
30+
31+
32+
def mk_tmplt(template):
33+
if isinstance(template, dict):
34+
35+
def check(data,
36+
*,
37+
tmplt=tuple((k, mk_tmplt(v)) for k, v in template.items())):
38+
if not isinstance(data, dict):
39+
return False
40+
for k, v in tmplt:
41+
if k not in data:
42+
return False
43+
if not v(data[k]):
44+
return False
45+
return True
46+
47+
elif isinstance(template, list):
48+
49+
def check(data, *, tmplt=tuple(map(mk_tmplt, template))):
50+
if not isinstance(data, list):
51+
return False
52+
if len(data) != len(tmplt):
53+
return False
54+
for t, v in zip(tmplt, data):
55+
if not t(v):
56+
return False
57+
return True
58+
59+
elif isinstance(template, type):
60+
61+
def check(data, *, t=template):
62+
return isinstance(data, t)
63+
64+
elif template is any:
65+
check = lambda _: True
66+
elif hasattr(template, 'match'):
67+
check = template.match
68+
else:
69+
70+
def check(data, *, o=template):
71+
return data == o
72+
73+
return check
74+
75+
76+
def traverse(f, data):
77+
if isinstance(data, dict):
78+
for each in data.values():
79+
yield from traverse(f, each)
80+
elif isinstance(data, list):
81+
for each in data:
82+
yield from traverse(f, each)
83+
if f(data):
84+
yield data
85+
86+
87+
def gq(tmp, data):
88+
return traverse(mk_tmplt(tmp), data)
89+
90+
def get_binary(out_path):
91+
"""out_path is the directory of executable, instead of the path
92+
"""
93+
if isinstance(out_path, str):
94+
out_path = Path(out_path)
95+
elif not isinstance(out_path, Path):
96+
raise TypeError(type(out_path))
97+
from purescripto.version import __blueprint_version__
98+
max_fit_tag = max(filter(lambda x: x.startswith(__blueprint_version__), show_tags()))
99+
100+
print('Downloading binaries from purescript-python/purescript-python...')
101+
data = requests.get(
102+
r"https://api.github.com/repos/purescript-python/purescript-python/releases/tags/v{}"
103+
.format(max_fit_tag)).json()
104+
print('Binaries downloaded.')
105+
plat_name = get_platform()
106+
107+
matcher = re.compile('\S+' + re.escape(plat_name))
108+
tmplt = {'browser_download_url': matcher}
109+
try:
110+
each = next(gq(tmplt, data))
111+
except StopIteration:
112+
import sys
113+
print(
114+
"It seems that binaries for your platform is not available.\n"
115+
"Following way must work, but can be quite time-consuming:\n"
116+
"Firstly, Install Haskell Stack Build Tool: https://docs.haskellstack.org/en/stable/README/\n"
117+
"Second, Clone https://github.com/purescript-python/purescript-python, then do `stack install .`"
118+
)
119+
sys.exit(1)
120+
121+
url = each['browser_download_url']
122+
zf = zipfile.ZipFile(io.BytesIO(requests.get(url).content))
123+
exe = "pspy-blueprint.exe"
124+
out_path.mkdir(exist_ok=True, parents=True, mode=0o777)
125+
zf.extract(exe, path=str(out_path))
126+
make_executable(str(out_path / exe))

purescripto/pspy.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
from purescripto.configure import pspy
2+
from purescripto.installer import get_binary
3+
from purescripto.template_setup import gen_setup, gen_init
24

5+
def cmd_get_binary():
6+
import wisepy2
7+
wisepy2.wise(get_binary)()
8+
9+
10+
def cmd_gen_setup():
11+
import wisepy2
12+
wisepy2.wise(gen_setup)()
13+
14+
def cmd_gen_init():
15+
import wisepy2
16+
wisepy2.wise(gen_init)()
317

4-
def main():
18+
def cmd_pspy():
519
import wisepy2
6-
wisepy2.wise(pspy)()
20+
wisepy2.wise(pspy)()

purescripto/template_setup.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
def gen_setup():
2+
meta_setup = r"""
3+
import sys
4+
import os
5+
from setuptools import setup
6+
from pathlib import Path
7+
from purescripto.version import __version__
8+
readme = ''
9+
10+
setup(
11+
name='pspy-executable',
12+
version=__version__,
13+
keywords="", # keywords of your project that separated by comma ","
14+
description="", # a concise introduction of your project
15+
long_description=readme,
16+
long_description_content_type="text/markdown",
17+
license='mit',
18+
python_requires='>=3.5.0',
19+
url='https://github.com/purescript-python/installer',
20+
author='thautawarm',
21+
author_email='[email protected]',
22+
packages=['pspy_executable'],
23+
install_requires=[],
24+
package_data={
25+
'pspy_executable': [
26+
each.name for each in Path('pspy_executable').iterdir()
27+
if each.name.startswith('pspy')
28+
]
29+
},
30+
entry_points={"console_scripts": [
31+
"pspy-blueprint=pspy_executable:exe",
32+
"pspy-blueprint-check=pspy_executable:check"
33+
]},
34+
platforms="any",
35+
classifiers=[
36+
"Programming Language :: Python :: 3.5",
37+
"Programming Language :: Python :: 3.6",
38+
"Programming Language :: Python :: 3.7",
39+
"Programming Language :: Python :: 3.8",
40+
"Programming Language :: Python :: 3.9",
41+
"Programming Language :: Python :: Implementation :: CPython",
42+
],
43+
zip_safe=False,
44+
)
45+
"""
46+
print(meta_setup)
47+
48+
def gen_init():
49+
meta_init = r"""
50+
def exe():
51+
from pathlib import Path
52+
from subprocess import call
53+
import sys
54+
cmd = str((Path(__file__).parent / "pspy-blueprint.exe").absolute())
55+
call([cmd, *sys.argv[1:]])
56+
57+
def check():
58+
print("pspy-executable installed")
59+
"""
60+
print(meta_init)

purescripto/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
__version__ = "0.8.4"
1+
__version__ = "0.8.5"
22
__blueprint_version__ = '0.1.3'

setup.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@
1919
author="thautawarm",
2020
author_email="[email protected]",
2121
packages=["purescripto"],
22-
entry_points={"console_scripts": ["pspy=purescripto.pspy:main"]},
22+
entry_points={
23+
"console_scripts": [
24+
"pspy=purescripto.pspy:cmd_pspy",
25+
"pspy-get-binary=purescripto.pspy:cmd_get_binary",
26+
"pspy-gen-setup=purescripto.pspy:cmd_gen_setup",
27+
"pspy-gen-init=purescripto.pspy:cmd_gen_init",
28+
]
29+
},
2330
# above option specifies what commands to install,
2431
# e.g: entry_points={"console_scripts": ["yapypy=yapypy.cmd:compiler"]}
2532
install_requires=[

0 commit comments

Comments
 (0)