Skip to content
This repository was archived by the owner on May 17, 2019. It is now read-only.

Commit 1fc24c3

Browse files
authored
from stoeffel/hardy
1 parent 79c9921 commit 1fc24c3

File tree

1 file changed

+230
-0
lines changed

1 file changed

+230
-0
lines changed

native_package_install.py

+230
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
#! /usr/bin/env python
2+
3+
4+
import argparse
5+
import json
6+
import os
7+
import subprocess
8+
import sys
9+
import tarfile
10+
import urllib2
11+
12+
13+
def read_native_elm_package(package_file):
14+
"""
15+
Reads elm-native-package.json.
16+
"""
17+
18+
with open(package_file) as f:
19+
return json.load(f)
20+
21+
22+
def format_url(package):
23+
"""
24+
Creates the url to fetch the tar from github.
25+
>>> format_url({'namespace': 'elm-lang', 'name': 'navigation', 'version': '2.0.0'})
26+
'https://github.com/elm-lang/navigation/archive/2.0.0.tar.gz'
27+
"""
28+
return "https://github.com/{namespace}/{name}/archive/{version}.tar.gz".format(**package)
29+
30+
31+
def parse_json(raw):
32+
"""
33+
Parses the json and returns a list of {version, namespace, name}.
34+
>>> parse_json({'elm-lang/navigation': '2.0.0'})
35+
[{'version': '2.0.0', 'namespace': 'elm-lang', 'name': 'navigation'}]
36+
"""
37+
result = []
38+
39+
for name, version in raw.items():
40+
namespace, package_name = name.split('/')
41+
result.append({
42+
'namespace': namespace,
43+
'name': package_name,
44+
'version': version
45+
})
46+
47+
return result
48+
49+
50+
def format_vendor_dir(base, namespace):
51+
"""
52+
Creates the path in the vendor folder.
53+
>>> format_vendor_dir('foo', 'bar')
54+
'foo/bar'
55+
"""
56+
path = os.path.join(base, namespace)
57+
58+
try:
59+
os.makedirs(path)
60+
except Exception as e:
61+
pass
62+
63+
return path
64+
65+
66+
def package_dir(vendor_dir, package):
67+
"""
68+
Creates the path to the elm package.
69+
>>> package_dir('vendor/assets/elm', {'version': '2.0.0', 'namespace': 'elm-lang', 'name': 'navigation'})
70+
'vendor/assets/elm/elm-lang/navigation-2.0.0'
71+
"""
72+
return "{vendor_dir}/{package_name}-{version}".format(
73+
vendor_dir=format_vendor_dir(vendor_dir, package['namespace']),
74+
package_name=package['name'],
75+
version=package['version']
76+
)
77+
78+
79+
def fetch_packages(vendor_dir, packages):
80+
"""
81+
Fetches all packages from github.
82+
"""
83+
for package in packages:
84+
tar_filename = format_tar_file(vendor_dir, package)
85+
vendor = format_vendor_dir(vendor_dir, package['namespace'])
86+
url = format_url(package)
87+
88+
tar_file = urllib2.urlopen(url)
89+
with open(tar_filename, 'w') as tar:
90+
tar.write(tar_file.read())
91+
92+
with tarfile.open(tar_filename) as tar:
93+
tar.extractall(vendor, members=tar.getmembers())
94+
95+
return packages
96+
97+
98+
def format_tar_file(vendor_dir, package):
99+
"""
100+
The name of the tar.
101+
>>> format_tar_file('vendor/assets/elm', {'namespace': 'elm-lang', 'name': 'navigation', 'version': '2.0.0'})
102+
'vendor/assets/elm/elm-lang/navigation-2.0.0-tar.gz'
103+
"""
104+
vendor = format_vendor_dir(vendor_dir, package['namespace'])
105+
return package_dir(vendor_dir, package) + "-tar.gz"
106+
107+
def format_native_name(namespace, name):
108+
"""
109+
Formates the package to the namespace used in elm native.
110+
>>> format_native_name('elm-lang', 'navigation')
111+
'_elm_lang$navigation'
112+
"""
113+
114+
underscored_namespace = namespace.replace("-", "_")
115+
underscored_name = name.replace("-", "_")
116+
return "_{owner}${repo}".format(owner=underscored_namespace, repo=underscored_name)
117+
118+
119+
def namespace_from_repo(repository):
120+
"""
121+
Namespace and name from repository.
122+
>>> namespace_from_repo('https://github.com/NoRedInk/noredink.git')
123+
['NoRedInk', 'noredink']
124+
"""
125+
126+
repo_without_domain = repository.lstrip('https://github.com/').rstrip('.git')
127+
128+
(namespace, name) = repo_without_domain.split('/')
129+
return [namespace, name]
130+
131+
132+
def get_source_dirs(vendor_dir, package):
133+
""" get the source-directories out of an elm-package file """
134+
elm_package_filename = os.path.join(package_dir(vendor_dir, package), 'elm-package.json')
135+
with open(elm_package_filename) as f:
136+
data = json.load(f)
137+
138+
return data['source-directories']
139+
140+
141+
def munge_names(vendor_dir, repository, packages):
142+
"""
143+
Replaces the namespaced function names in all native code by the namespace from the given elm-package.json.
144+
"""
145+
namespace, name = namespace_from_repo(repository)
146+
for package in packages:
147+
subprocess.Popen((
148+
"find",
149+
package_dir(vendor_dir, package),
150+
"-type",
151+
"f",
152+
"-exec",
153+
"sed",
154+
"-i",
155+
"",
156+
"-e",
157+
"s/{0}/{1}/g".format(
158+
format_native_name(package['namespace'], package['name']),
159+
format_native_name(namespace, name)
160+
),
161+
"{}",
162+
";"
163+
))
164+
165+
166+
def update_elm_package(vendor_dir, configs, packages):
167+
"""
168+
Gets the repo name and updates the source-directories in the given elm-package.json.
169+
"""
170+
171+
repository = ""
172+
173+
for config in configs:
174+
with open(config) as f:
175+
data = json.load(f)
176+
177+
repository = data['repository']
178+
source_directories = data['source-directories']
179+
path = '../' * config.count('/')
180+
181+
for package in packages:
182+
current_package_dirs = get_source_dirs(vendor_dir, package)
183+
184+
for dir_name in current_package_dirs:
185+
relative_path = os.path.join(path, package_dir(vendor_dir, package), dir_name)
186+
187+
if relative_path not in data['source-directories']:
188+
data['source-directories'].append(relative_path)
189+
190+
with open(config, 'w') as f:
191+
f.write(json.dumps(data, indent=4))
192+
193+
return repository
194+
195+
196+
def filter_packages(vendor_dir, packages):
197+
return [x for x in packages if not os.path.isdir(format_tar_file(vendor_dir, x))]
198+
199+
200+
def main(native_elm_package, configs, vendor):
201+
raw_json = read_native_elm_package(native_elm_package)
202+
parsed = parse_json(raw_json)
203+
packages = filter_packages(vendor, parsed)
204+
fetch_packages(vendor, packages)
205+
repository = update_elm_package(vendor, configs, packages)
206+
munge_names(vendor, repository, packages)
207+
208+
209+
def test():
210+
import doctest
211+
doctest.testmod()
212+
213+
214+
if __name__ == '__main__':
215+
parser = argparse.ArgumentParser(description='Fetch elm packages')
216+
parser.add_argument(
217+
'native_elm_package',
218+
help='The elm-native-package.json file you want to use',
219+
default='elm-native-package.json'
220+
)
221+
parser.add_argument('--elm-config', '-e', nargs='+')
222+
parser.add_argument('--vendor-dir', default='vendor/assets/elm')
223+
parser.add_argument('--test', '-t', action='store_true')
224+
225+
args = parser.parse_args()
226+
if args.test:
227+
test()
228+
exit()
229+
230+
main(args.native_elm_package, args.elm_config, args.vendor_dir)

0 commit comments

Comments
 (0)