8000 upip: Initial steps towards self-hosted package manager. · micropython/micropython-lib@3cccc69 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3cccc69

Browse files
author
Paul Sokolovsky
committed
upip: Initial steps towards self-hosted package manager.
Already capable of installing packages from command line, resolving dependencies recursively. Downloading is handled via wget due to SSL, so currently this is not self-hosted.
1 parent e8813f3 commit 3cccc69

File tree

1 file changed

+158
-0
lines changed

1 file changed

+158
-0
lines changed

upip/upip.py

Lines changed: 158 additions & 0 deletions
< 6135 td data-grid-cell-id="diff-445ef71219c26019c882967276b2daca0491fdcab8f77c0a1159eb7cbc0d7ce3-empty-151-0" data-selected="false" role="gridcell" style="background-color:var(--diffBlob-additionNum-bgColor, var(--diffBlob-addition-bgColor-num));text-align:center" tabindex="-1" valign="top" class="focusable-grid-cell diff-line-number position-relative left-side">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import sys
2+
import os
3+
import os.path
4+
import errno
5+
import gzip
6+
try:
7+
import utarfile as tarfile
8+
except ImportError:
9+
import tarfile
10+
try:
11+
import ujson as json
12+
except ImportError:
13+
import json
14+
15+
16+
DEFAULT_MICROPYPATH = "~/.micropython/lib:/usr/lib/micropython"
17+
18+
def save_file(fname, subf):
19+
outf = open(fname, "wb")
20+
while True:
21+
buf = subf.read(1024)
22+
if not buf:
23+
break
24+
outf.write(buf)
25+
outf.close()
26+
27+
def install_tar(f, prefix):
28+
meta = {}
29+
for info in f:
30+
#print(info)
31+
fname = info.name
32+
try:
33+
fname = fname[fname.index("/") + 1:]
34+
except ValueError:
35+
fname = ""
36+
37+
save = True
38+
for p in ("setup.", "PKG-INFO"):
39+
#print(fname, p)
40+
if fname.startswith(p) or ".egg-info" in fname:
41+
if fname.endswith("/requires.txt"):
42+
meta["deps"] = f.extractfile(info).read()
43+
save = False
44+
print("Skipping", fname)
45+
break
46+
47+
if save:
48+
outfname = prefix + fname
49+
if info.type == tarfile.DIRTYPE:
50+
try:
51+
os.makedirs(outfname)
52+
print("Created " + outfname)
53+
except OSError as e:
54+
if e.args[0] != errno.EEXIST:
55+
raise
56+
else:
57+
print("Extracting " + outfname)
58+
subf = f.extractfile(info)
59+
save_file(outfname, subf)
60+
return meta
61+
62+
def expandhome(s):
63+
h = os.getenv("HOME")
64+
s = s.replace("~/", h + "/")
65+
return s
66+
67+
def download(url, local_name):
68+
os.system("wget -q %s -O %s" % (url, local_name))
69+
70+
def get_pkg_metadata(name):
71+
download("https://pypi.python.org/pypi/%s/json" % name, "pkg.json")
72+
with open("pkg.json") as f:
73+
s = f.read()
74+
return json.loads(s)
75+
76+
77+
def fatal(msg):
78+
print(msg)
79+
sys.exit(1)
80+
81+
def gzdecompress(package_fname):
82+
f = open(package_fname, "rb")
83+
zipdata = f.read()
84+
data = gzip.decompress(zipdata)
85+
return data
86+
87+
def gzdecompress_(package_fname):
88+
os.system("gzip -d -c %s > ungz" % package_fname)
89+
with open("ungz", "rb") as f:
90+
return f.read()
91+
92+
def install_pkg(pkg_spec, install_path):
93+
data = get_pkg_metadata(pkg_spec)
94+
95+
latest_ver = data["info"]["version"]
96+
print("Installing %s %s" % (pkg_spec, latest_ver))
97+
packages = data["releases"][latest_ver]
98+
assert len(packages) == 1
99+
package_url = packages[0]["url"]
100+
package_fname = os.path.basename(package_url)
101+
print(package_url)
102+
download(package_url, package_fname)
103+
104+
data = gzdecompress(package_fname)
105+
106+
f = open("pkg.tar", "wb")
107+
f.write(data)
108+
f.close()
109+
110+
f = tarfile.TarFile("pkg.tar")
111+
return install_tar(f, install_path)
112+
113+
def main():
114+
install_path = None
115+
116+
if sys.argv[1] != "install":
117+
fatal("Only 'install' command supported")
118+
119+
i = 2
120+
while sys.argv[i][0] == "-":
121+
opt = sys.argv[i][1]
122+
i += 1
123+
if opt == "p":
124+
install_path = sys.argv[i]
125+
i += 1
126+
else:
127+
fatal("Unknown/unsupported option: " + opt)
128+
129+
if install_path is None:
130+
install_path = DEFAULT_MICROPYPATH
131+
132+
install_path = install_path.split(":", 1)[0]
133+
134+
install_path = expandhome(install_path)
135+
136+
if install_path[-1] != "/":
137+
install_path += "/"
138+
139+
print("Installing to: " + install_path)
140+
141+
to_install = sys.argv[i:]
142+
# sets would be perfect here, but don't depend on them
143+
installed = []
144+
while to_install:
145+
print("Queue:", to_install)
146+
pkg_spec = to_install.pop(0)
147+
if pkg_spec in installed:
148+
continue
149+
meta = install_pkg(pkg_spec, install_path)
150+
installed.append(pkg_spec)
151+
print(meta)
152+
deps = meta.get("deps", "").rstrip()
153+
if deps:
154+
deps = deps.decode("utf-8").split("\n")
155+
to_install.extend(deps)
156+
157+
158+
main()

0 commit comments

Comments
 (0)
0