Skip to content

Commit e00861e

Browse files
committed
Add flatpak poetry generator script
1 parent b8f9302 commit e00861e

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#!/usr/bin/env python3
2+
3+
"""From https://github.com/flatpak/flatpak-builder-tools/tree/master/poetry"""
4+
5+
__license__ = "MIT"
6+
7+
import argparse
8+
import json
9+
import re
10+
import sys
11+
import urllib.parse
12+
import urllib.request
13+
from collections import OrderedDict
14+
15+
import toml
16+
17+
18+
def get_pypi_source(name: str, version: str, hashes: list) -> tuple:
19+
"""Get the source information for a dependency.
20+
21+
Args:
22+
name (str): The package name.
23+
version (str): The package version.
24+
hashes (list): The list of hashes for the package version.
25+
26+
Returns (tuple): The url and sha256 hash.
27+
28+
"""
29+
url = "https://pypi.org/pypi/{}/json".format(name)
30+
print("Extracting download url and hash for {}, version {}".format(name, version))
31+
with urllib.request.urlopen(url) as response:
32+
body = json.loads(response.read().decode("utf-8"))
33+
for release, source_list in body["releases"].items():
34+
if release == version:
35+
for source in source_list:
36+
if (
37+
source["packagetype"] == "bdist_wheel"
38+
and "py3" in source["python_version"]
39+
and source["digests"]["sha256"] in hashes
40+
):
41+
return source["url"], source["digests"]["sha256"]
42+
for source in source_list:
43+
if (
44+
source["packagetype"] == "sdist"
45+
and "source" in source["python_version"]
46+
and source["digests"]["sha256"] in hashes
47+
):
48+
return source["url"], source["digests"]["sha256"]
49+
else:
50+
raise Exception("Failed to extract url and hash from {}".format(url))
51+
52+
53+
def get_module_sources(parsed_lockfile: dict, include_devel: bool = True) -> list:
54+
"""Gets the list of sources from a toml parsed lockfile.
55+
56+
Args:
57+
parsed_lockfile (dict): The dictionary of the parsed lockfile.
58+
include_devel (bool): Include dev dependencies, defaults to True.
59+
60+
Returns (list): The sources.
61+
62+
"""
63+
sources = []
64+
hash_re = re.compile(r"(sha1|sha224|sha384|sha256|sha512|md5):([a-f0-9]+)")
65+
for section, packages in parsed_lockfile.items():
66+
if section == "package":
67+
for package in packages:
68+
# Check for old metadata format (poetry version < 1.0.0b2)
69+
if "hashes" in parsed_lockfile["metadata"]:
70+
hashes = parsed_lockfile["metadata"]["hashes"][package["name"]]
71+
# Else new metadata format
72+
else:
73+
hashes = []
74+
for package_name in parsed_lockfile["metadata"]["files"]:
75+
if package_name == package["name"]:
76+
package_files = parsed_lockfile["metadata"]["files"][
77+
package["name"]
78+
]
79+
num_files = len(package_files)
80+
for num in range(num_files):
81+
match = hash_re.search(package_files[num]["hash"])
82+
if match:
83+
hashes.append(match.group(2))
84+
url, hash = get_pypi_source(package["name"], package["version"], hashes)
85+
source = {"type": "file", "url": url, "sha256": hash}
86+
sources.append(source)
87+
return sources
88+
89+
90+
def get_dep_names(parsed_lockfile: dict, include_devel: bool = True) -> list:
91+
"""Gets the list of dependency names.
92+
93+
Args:
94+
parsed_lockfile (dict): The dictionary of the parsed lockfile.
95+
include_devel (bool): Include dev dependencies, defaults to True.
96+
97+
Returns (list): The dependency names.
98+
99+
"""
100+
dep_names = []
101+
for section, packages in parsed_lockfile.items():
102+
if section == "package":
103+
for package in packages:
104+
dep_names.append(package["name"])
105+
return dep_names
106+
107+
108+
def main():
109+
parser = argparse.ArgumentParser(description="Flatpak Poetry generator")
110+
parser.add_argument("lockfile", type=str)
111+
parser.add_argument(
112+
"-o", type=str, dest="outfile", default="generated-poetry-sources.json"
113+
)
114+
parser.add_argument("--production", action="store_true", default=False)
115+
args = parser.parse_args()
116+
117+
include_devel = not args.production
118+
outfile = args.outfile
119+
lockfile = args.lockfile
120+
121+
print('Scanning "%s" ' % lockfile, file=sys.stderr)
122+
123+
with open(lockfile, "r") as f:
124+
parsed_lockfile = toml.load(f)
125+
dep_names = get_dep_names(parsed_lockfile, include_devel=include_devel)
126+
pip_command = [
127+
"pip3",
128+
"install",
129+
"--use-pep517",
130+
"--no-index",
131+
'--find-links="file://${PWD}"',
132+
"--prefix=${FLATPAK_DEST}",
133+
" ".join(dep_names),
134+
]
135+
main_module = OrderedDict(
136+
[
137+
("name", "poetry-deps"),
138+
("buildsystem", "simple"),
139+
("build-commands", [" ".join(pip_command)]),
140+
]
141+
)
142+
sources = get_module_sources(parsed_lockfile, include_devel=include_devel)
143+
main_module["sources"] = sources
144+
145+
print(" ... %d new entries" % len(sources), file=sys.stderr)
146+
147+
print('Writing to "%s"' % outfile)
148+
with open(outfile, "w") as f:
149+
f.write(json.dumps(main_module, indent=4))
150+
151+
152+
if __name__ == "__main__":
153+
main()

0 commit comments

Comments
 (0)