flatpak-cargo-generator 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flatpak_cargo_generator-0.1.0/LICENSE.md +21 -0
- flatpak_cargo_generator-0.1.0/PKG-INFO +24 -0
- flatpak_cargo_generator-0.1.0/README.md +5 -0
- flatpak_cargo_generator-0.1.0/flatpak_cargo_generator/__init__.py +0 -0
- flatpak_cargo_generator-0.1.0/flatpak_cargo_generator/script.py +436 -0
- flatpak_cargo_generator-0.1.0/pyproject.toml +29 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: flatpak-cargo-generator
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Unofficial Pypi distribution of the Flatpak's cargo dependency generator
|
|
5
|
+
Author: Flatpak team
|
|
6
|
+
Requires-Python: >=3.8
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: Unix
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Dist: aiohttp (>=3.9.5,<4.0.0)
|
|
16
|
+
Requires-Dist: toml (>=0.10.2,<0.11.0)
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# Flatpak Cargo Generator
|
|
20
|
+
|
|
21
|
+
This is an unofficial Pypi distribution of the [flatpak-cargo-generator](https://github.com/flatpak/flatpak-builder-tools/blob/master/cargo/flatpak-cargo-generator.py) script, ensuring library dependencies are installed and the script is available on your PATH as `flatpak-cargo-generator`.
|
|
22
|
+
|
|
23
|
+
See [here](https://github.com/flatpak/flatpak-builder-tools/blob/master/cargo/README.md) for instructions.
|
|
24
|
+
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Flatpak Cargo Generator
|
|
2
|
+
|
|
3
|
+
This is an unofficial Pypi distribution of the [flatpak-cargo-generator](https://github.com/flatpak/flatpak-builder-tools/blob/master/cargo/flatpak-cargo-generator.py) script, ensuring library dependencies are installed and the script is available on your PATH as `flatpak-cargo-generator`.
|
|
4
|
+
|
|
5
|
+
See [here](https://github.com/flatpak/flatpak-builder-tools/blob/master/cargo/README.md) for instructions.
|
|
File without changes
|
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
__license__ = 'MIT'
|
|
4
|
+
import json
|
|
5
|
+
from urllib.parse import urlparse, ParseResult, parse_qs
|
|
6
|
+
import os
|
|
7
|
+
import contextlib
|
|
8
|
+
import copy
|
|
9
|
+
import glob
|
|
10
|
+
import subprocess
|
|
11
|
+
import argparse
|
|
12
|
+
import logging
|
|
13
|
+
import hashlib
|
|
14
|
+
import asyncio
|
|
15
|
+
from typing import Any, Dict, List, NamedTuple, Optional, Tuple, TypedDict
|
|
16
|
+
|
|
17
|
+
import aiohttp
|
|
18
|
+
import toml
|
|
19
|
+
|
|
20
|
+
CRATES_IO = 'https://static.crates.io/crates'
|
|
21
|
+
CARGO_HOME = 'cargo'
|
|
22
|
+
CARGO_CRATES = f'{CARGO_HOME}/vendor'
|
|
23
|
+
VENDORED_SOURCES = 'vendored-sources'
|
|
24
|
+
GIT_CACHE = 'flatpak-cargo/git'
|
|
25
|
+
COMMIT_LEN = 7
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@contextlib.contextmanager
|
|
29
|
+
def workdir(path: str):
|
|
30
|
+
oldpath = os.getcwd()
|
|
31
|
+
os.chdir(path)
|
|
32
|
+
try:
|
|
33
|
+
yield
|
|
34
|
+
finally:
|
|
35
|
+
os.chdir(oldpath)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def canonical_url(url: str) -> ParseResult:
|
|
39
|
+
'Converts a string to a Cargo Canonical URL, as per https://github.com/rust-lang/cargo/blob/35c55a93200c84a4de4627f1770f76a8ad268a39/src/cargo/util/canonical_url.rs#L19'
|
|
40
|
+
# Hrm. The upstream cargo does not replace those URLs, but if we don't then it doesn't work too well :(
|
|
41
|
+
url = url.replace('git+https://', 'https://')
|
|
42
|
+
u = urlparse(url)
|
|
43
|
+
# It seems cargo drops query and fragment
|
|
44
|
+
u = ParseResult(u.scheme, u.netloc, u.path, '', '', '')
|
|
45
|
+
u = u._replace(path = u.path.rstrip('/'))
|
|
46
|
+
|
|
47
|
+
if u.netloc == 'github.com':
|
|
48
|
+
u = u._replace(scheme = 'https')
|
|
49
|
+
u = u._replace(path = u.path.lower())
|
|
50
|
+
|
|
51
|
+
if u.path.endswith('.git'):
|
|
52
|
+
u = u._replace(path = u.path[:-len('.git')])
|
|
53
|
+
|
|
54
|
+
return u
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def get_git_tarball(repo_url: str, commit: str) -> str:
|
|
58
|
+
url = canonical_url(repo_url)
|
|
59
|
+
path = url.path.split('/')[1:]
|
|
60
|
+
|
|
61
|
+
assert len(path) == 2
|
|
62
|
+
owner = path[0]
|
|
63
|
+
if path[1].endswith('.git'):
|
|
64
|
+
repo = path[1].replace('.git', '')
|
|
65
|
+
else:
|
|
66
|
+
repo = path[1]
|
|
67
|
+
if url.hostname == 'github.com':
|
|
68
|
+
return f'https://codeload.{url.hostname}/{owner}/{repo}/tar.gz/{commit}'
|
|
69
|
+
elif url.hostname.split('.')[0] == 'gitlab': # type: ignore
|
|
70
|
+
return f'https://{url.hostname}/{owner}/{repo}/-/archive/{commit}/{repo}-{commit}.tar.gz'
|
|
71
|
+
elif url.hostname == 'bitbucket.org':
|
|
72
|
+
return f'https://{url.hostname}/{owner}/{repo}/get/{commit}.tar.gz'
|
|
73
|
+
else:
|
|
74
|
+
raise ValueError(f'Don\'t know how to get tarball for {repo_url}')
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
async def get_remote_sha256(url: str) -> str:
|
|
78
|
+
logging.info(f"started sha256({url})")
|
|
79
|
+
sha256 = hashlib.sha256()
|
|
80
|
+
async with aiohttp.ClientSession(raise_for_status=True) as http_session:
|
|
81
|
+
async with http_session.get(url) as response:
|
|
82
|
+
while True:
|
|
83
|
+
data = await response.content.read(4096)
|
|
84
|
+
if not data:
|
|
85
|
+
break
|
|
86
|
+
sha256.update(data)
|
|
87
|
+
logging.info(f"done sha256({url})")
|
|
88
|
+
return sha256.hexdigest()
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
_TomlType = Dict[str, Any]
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def load_toml(tomlfile: str = 'Cargo.lock') -> _TomlType:
|
|
95
|
+
with open(tomlfile, 'r') as f:
|
|
96
|
+
toml_data = toml.load(f)
|
|
97
|
+
return toml_data
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def git_repo_name(git_url: str, commit: str) -> str:
|
|
101
|
+
name = canonical_url(git_url).path.split('/')[-1]
|
|
102
|
+
return f'{name}-{commit[:COMMIT_LEN]}'
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def fetch_git_repo(git_url: str, commit: str) -> str:
|
|
106
|
+
repo_dir = git_url.replace('://', '_').replace('/', '_')
|
|
107
|
+
cache_dir = os.environ.get('XDG_CACHE_HOME', os.path.expanduser('~/.cache'))
|
|
108
|
+
clone_dir = os.path.join(cache_dir, 'flatpak-cargo', repo_dir)
|
|
109
|
+
if not os.path.isdir(os.path.join(clone_dir, '.git')):
|
|
110
|
+
subprocess.run(['git', 'clone', '--depth=1', git_url, clone_dir], check=True)
|
|
111
|
+
rev_parse_proc = subprocess.run(['git', 'rev-parse', 'HEAD'], cwd=clone_dir, check=True,
|
|
112
|
+
stdout=subprocess.PIPE)
|
|
113
|
+
head = rev_parse_proc.stdout.decode().strip()
|
|
114
|
+
if head[:COMMIT_LEN] != commit[:COMMIT_LEN]:
|
|
115
|
+
subprocess.run(['git', 'fetch', 'origin', commit], cwd=clone_dir, check=True)
|
|
116
|
+
subprocess.run(['git', 'checkout', commit], cwd=clone_dir, check=True)
|
|
117
|
+
|
|
118
|
+
# Get the submodules as they might contain dependencies. This is a noop if
|
|
119
|
+
# there are no submodules in the repository
|
|
120
|
+
subprocess.run(['git', 'submodule', 'update', '--init', '--recursive'], cwd=clone_dir, check=True)
|
|
121
|
+
|
|
122
|
+
return clone_dir
|
|
123
|
+
|
|
124
|
+
def update_workspace_keys(pkg, workspace):
|
|
125
|
+
for key, item in pkg.items():
|
|
126
|
+
# There cannot be a 'workspace' key if the item is not a dict.
|
|
127
|
+
if not isinstance(item, dict):
|
|
128
|
+
continue;
|
|
129
|
+
|
|
130
|
+
# Recurse for keys under target.cfg(..)
|
|
131
|
+
if key == 'target':
|
|
132
|
+
for target in item.values():
|
|
133
|
+
update_workspace_keys(target, workspace)
|
|
134
|
+
continue;
|
|
135
|
+
# dev-dependencies and build-dependencies should reference root dependencies table from workspace
|
|
136
|
+
elif key == 'dev-dependencies' or key == 'build-dependencies':
|
|
137
|
+
update_workspace_keys(item, workspace.get('dependencies', None))
|
|
138
|
+
continue;
|
|
139
|
+
|
|
140
|
+
if not workspace or not key in workspace:
|
|
141
|
+
continue;
|
|
142
|
+
|
|
143
|
+
workspace_item = workspace[key]
|
|
144
|
+
|
|
145
|
+
if 'workspace' in item:
|
|
146
|
+
if isinstance(workspace_item, dict):
|
|
147
|
+
del item['workspace']
|
|
148
|
+
|
|
149
|
+
for dep_key, workspace_value in workspace_item.items():
|
|
150
|
+
# features are additive
|
|
151
|
+
if dep_key == 'features' and 'features' in item:
|
|
152
|
+
item['features'] += workspace_value
|
|
153
|
+
else:
|
|
154
|
+
item[dep_key] = workspace_value
|
|
155
|
+
elif len(item) > 1:
|
|
156
|
+
del item['workspace']
|
|
157
|
+
item.update({ 'version': workspace_item })
|
|
158
|
+
else:
|
|
159
|
+
pkg[key] = workspace_item
|
|
160
|
+
else:
|
|
161
|
+
update_workspace_keys(item, workspace_item)
|
|
162
|
+
|
|
163
|
+
class _GitPackage(NamedTuple):
|
|
164
|
+
path: str
|
|
165
|
+
package: _TomlType
|
|
166
|
+
workspace: Optional[_TomlType]
|
|
167
|
+
|
|
168
|
+
@property
|
|
169
|
+
def normalized(self) -> _TomlType:
|
|
170
|
+
package = copy.deepcopy(self.package)
|
|
171
|
+
if self.workspace is None:
|
|
172
|
+
return package
|
|
173
|
+
|
|
174
|
+
update_workspace_keys(package, self.workspace)
|
|
175
|
+
|
|
176
|
+
return package
|
|
177
|
+
|
|
178
|
+
_GitPackagesType = Dict[str, _GitPackage]
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
async def get_git_repo_packages(git_url: str, commit: str) -> _GitPackagesType:
|
|
182
|
+
logging.info('Loading packages from %s', git_url)
|
|
183
|
+
git_repo_dir = fetch_git_repo(git_url, commit)
|
|
184
|
+
packages: _GitPackagesType = {}
|
|
185
|
+
|
|
186
|
+
def get_cargo_toml_packages(root_dir: str, workspace: Optional[_TomlType] = None):
|
|
187
|
+
assert not os.path.isabs(root_dir) and os.path.isdir(root_dir)
|
|
188
|
+
|
|
189
|
+
with workdir(root_dir):
|
|
190
|
+
if os.path.exists('Cargo.toml'):
|
|
191
|
+
cargo_toml = load_toml('Cargo.toml')
|
|
192
|
+
workspace = cargo_toml.get('workspace') or workspace
|
|
193
|
+
|
|
194
|
+
if 'package' in cargo_toml:
|
|
195
|
+
packages[cargo_toml['package']['name']] = _GitPackage(
|
|
196
|
+
path=os.path.normpath(root_dir),
|
|
197
|
+
package=cargo_toml,
|
|
198
|
+
workspace=workspace
|
|
199
|
+
)
|
|
200
|
+
for child in os.scandir(root_dir):
|
|
201
|
+
if child.is_dir():
|
|
202
|
+
# the workspace can be referenced by any subdirectory
|
|
203
|
+
get_cargo_toml_packages(child.path, workspace)
|
|
204
|
+
|
|
205
|
+
with workdir(git_repo_dir):
|
|
206
|
+
get_cargo_toml_packages('.')
|
|
207
|
+
|
|
208
|
+
assert packages, f"No packages found in {git_repo_dir}"
|
|
209
|
+
logging.debug(
|
|
210
|
+
'Packages in %s:\n%s',
|
|
211
|
+
git_url,
|
|
212
|
+
json.dumps(
|
|
213
|
+
{k: v.path for k, v in packages.items()},
|
|
214
|
+
indent=4,
|
|
215
|
+
),
|
|
216
|
+
)
|
|
217
|
+
return packages
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
_FlatpakSourceType = Dict[str, Any]
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
async def get_git_repo_sources(
|
|
224
|
+
url: str,
|
|
225
|
+
commit: str,
|
|
226
|
+
tarball: bool = False,
|
|
227
|
+
) -> List[_FlatpakSourceType]:
|
|
228
|
+
name = git_repo_name(url, commit)
|
|
229
|
+
if tarball:
|
|
230
|
+
tarball_url = get_git_tarball(url, commit)
|
|
231
|
+
git_repo_sources = [{
|
|
232
|
+
'type': 'archive',
|
|
233
|
+
'archive-type': 'tar-gzip',
|
|
234
|
+
'url': tarball_url,
|
|
235
|
+
'sha256': await get_remote_sha256(tarball_url),
|
|
236
|
+
'dest': f'{GIT_CACHE}/{name}',
|
|
237
|
+
}]
|
|
238
|
+
else:
|
|
239
|
+
git_repo_sources = [{
|
|
240
|
+
'type': 'git',
|
|
241
|
+
'url': url,
|
|
242
|
+
'commit': commit,
|
|
243
|
+
'dest': f'{GIT_CACHE}/{name}',
|
|
244
|
+
}]
|
|
245
|
+
return git_repo_sources
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
_GitRepo = TypedDict('_GitRepo', {'lock': asyncio.Lock, 'commits': Dict[str, _GitPackagesType]})
|
|
249
|
+
_GitReposType = Dict[str, _GitRepo]
|
|
250
|
+
_VendorEntryType = Dict[str, Dict[str, str]]
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
async def get_git_package_sources(
|
|
254
|
+
package: _TomlType,
|
|
255
|
+
git_repos: _GitReposType,
|
|
256
|
+
) -> Tuple[List[_FlatpakSourceType], _VendorEntryType]:
|
|
257
|
+
name = package['name']
|
|
258
|
+
source = package['source']
|
|
259
|
+
commit = urlparse(source).fragment
|
|
260
|
+
assert commit, 'The commit needs to be indicated in the fragement part'
|
|
261
|
+
canonical = canonical_url(source)
|
|
262
|
+
repo_url = canonical.geturl()
|
|
263
|
+
|
|
264
|
+
git_repo = git_repos.setdefault(repo_url, {
|
|
265
|
+
'commits': {},
|
|
266
|
+
'lock': asyncio.Lock(),
|
|
267
|
+
})
|
|
268
|
+
async with git_repo['lock']:
|
|
269
|
+
if commit not in git_repo['commits']:
|
|
270
|
+
git_repo['commits'][commit] = await get_git_repo_packages(repo_url, commit)
|
|
271
|
+
|
|
272
|
+
cargo_vendored_entry: _VendorEntryType = {
|
|
273
|
+
repo_url: {
|
|
274
|
+
'git': repo_url,
|
|
275
|
+
'replace-with': VENDORED_SOURCES,
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
rev = parse_qs(urlparse(source).query).get('rev')
|
|
279
|
+
tag = parse_qs(urlparse(source).query).get('tag')
|
|
280
|
+
branch = parse_qs(urlparse(source).query).get('branch')
|
|
281
|
+
if rev:
|
|
282
|
+
assert len(rev) == 1
|
|
283
|
+
cargo_vendored_entry[repo_url]['rev'] = rev[0]
|
|
284
|
+
elif tag:
|
|
285
|
+
assert len(tag) == 1
|
|
286
|
+
cargo_vendored_entry[repo_url]['tag'] = tag[0]
|
|
287
|
+
elif branch:
|
|
288
|
+
assert len(branch) == 1
|
|
289
|
+
cargo_vendored_entry[repo_url]['branch'] = branch[0]
|
|
290
|
+
|
|
291
|
+
logging.info("Adding package %s from %s", name, repo_url)
|
|
292
|
+
git_pkg = git_repo['commits'][commit][name]
|
|
293
|
+
pkg_repo_dir = os.path.join(GIT_CACHE, git_repo_name(repo_url, commit), git_pkg.path)
|
|
294
|
+
git_sources: List[_FlatpakSourceType] = [
|
|
295
|
+
{
|
|
296
|
+
'type': 'shell',
|
|
297
|
+
'commands': [
|
|
298
|
+
f'cp -r --reflink=auto "{pkg_repo_dir}" "{CARGO_CRATES}/{name}"'
|
|
299
|
+
],
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
'type': 'inline',
|
|
303
|
+
'contents': toml.dumps(git_pkg.normalized),
|
|
304
|
+
'dest': f'{CARGO_CRATES}/{name}', #-{version}',
|
|
305
|
+
'dest-filename': 'Cargo.toml',
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
'type': 'inline',
|
|
309
|
+
'contents': json.dumps({'package': None, 'files': {}}),
|
|
310
|
+
'dest': f'{CARGO_CRATES}/{name}', #-{version}',
|
|
311
|
+
'dest-filename': '.cargo-checksum.json',
|
|
312
|
+
}
|
|
313
|
+
]
|
|
314
|
+
|
|
315
|
+
return (git_sources, cargo_vendored_entry)
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
async def get_package_sources(
|
|
319
|
+
package: _TomlType,
|
|
320
|
+
cargo_lock: _TomlType,
|
|
321
|
+
git_repos: _GitReposType,
|
|
322
|
+
) -> Optional[Tuple[List[_FlatpakSourceType], _VendorEntryType]]:
|
|
323
|
+
metadata = cargo_lock.get('metadata')
|
|
324
|
+
name = package['name']
|
|
325
|
+
version = package['version']
|
|
326
|
+
|
|
327
|
+
if 'source' not in package:
|
|
328
|
+
logging.debug('%s has no source', name)
|
|
329
|
+
return None
|
|
330
|
+
source = package['source']
|
|
331
|
+
|
|
332
|
+
if source.startswith('git+'):
|
|
333
|
+
return await get_git_package_sources(package, git_repos)
|
|
334
|
+
|
|
335
|
+
key = f'checksum {name} {version} ({source})'
|
|
336
|
+
if metadata is not None and key in metadata:
|
|
337
|
+
checksum = metadata[key]
|
|
338
|
+
elif 'checksum' in package:
|
|
339
|
+
checksum = package['checksum']
|
|
340
|
+
else:
|
|
341
|
+
logging.warning(f'{name} doesn\'t have checksum')
|
|
342
|
+
return None
|
|
343
|
+
crate_sources = [
|
|
344
|
+
{
|
|
345
|
+
'type': 'archive',
|
|
346
|
+
'archive-type': 'tar-gzip',
|
|
347
|
+
'url': f'{CRATES_IO}/{name}/{name}-{version}.crate',
|
|
348
|
+
'sha256': checksum,
|
|
349
|
+
'dest': f'{CARGO_CRATES}/{name}-{version}',
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
'type': 'inline',
|
|
353
|
+
'contents': json.dumps({'package': checksum, 'files': {}}),
|
|
354
|
+
'dest': f'{CARGO_CRATES}/{name}-{version}',
|
|
355
|
+
'dest-filename': '.cargo-checksum.json',
|
|
356
|
+
},
|
|
357
|
+
]
|
|
358
|
+
return (crate_sources, {'crates-io': {'replace-with': VENDORED_SOURCES}})
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
async def generate_sources(
|
|
362
|
+
cargo_lock: _TomlType,
|
|
363
|
+
git_tarballs: bool = False,
|
|
364
|
+
) -> List[_FlatpakSourceType]:
|
|
365
|
+
# {
|
|
366
|
+
# "git-repo-url": {
|
|
367
|
+
# "lock": asyncio.Lock(),
|
|
368
|
+
# "commits": {
|
|
369
|
+
# "commit-hash": {
|
|
370
|
+
# "package-name": "./relative/package/path"
|
|
371
|
+
# }
|
|
372
|
+
# }
|
|
373
|
+
# }
|
|
374
|
+
# }
|
|
375
|
+
git_repos: _GitReposType = {}
|
|
376
|
+
sources: List[_FlatpakSourceType] = []
|
|
377
|
+
package_sources = []
|
|
378
|
+
cargo_vendored_sources = {
|
|
379
|
+
VENDORED_SOURCES: {'directory': f'{CARGO_CRATES}'},
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
pkg_coros = [get_package_sources(p, cargo_lock, git_repos) for p in cargo_lock['package']]
|
|
383
|
+
for pkg in await asyncio.gather(*pkg_coros):
|
|
384
|
+
if pkg is None:
|
|
385
|
+
continue
|
|
386
|
+
else:
|
|
387
|
+
pkg_sources, cargo_vendored_entry = pkg
|
|
388
|
+
package_sources.extend(pkg_sources)
|
|
389
|
+
cargo_vendored_sources.update(cargo_vendored_entry)
|
|
390
|
+
|
|
391
|
+
logging.debug('Adding collected git repos:\n%s', json.dumps(list(git_repos), indent=4))
|
|
392
|
+
git_repo_coros = []
|
|
393
|
+
for git_url, git_repo in git_repos.items():
|
|
394
|
+
for git_commit in git_repo['commits']:
|
|
395
|
+
git_repo_coros.append(get_git_repo_sources(git_url, git_commit, git_tarballs))
|
|
396
|
+
sources.extend(sum(await asyncio.gather(*git_repo_coros), []))
|
|
397
|
+
|
|
398
|
+
sources.extend(package_sources)
|
|
399
|
+
|
|
400
|
+
logging.debug('Vendored sources:\n%s', json.dumps(cargo_vendored_sources, indent=4))
|
|
401
|
+
sources.append({
|
|
402
|
+
'type': 'inline',
|
|
403
|
+
'contents': toml.dumps({
|
|
404
|
+
'source': cargo_vendored_sources,
|
|
405
|
+
}),
|
|
406
|
+
'dest': CARGO_HOME,
|
|
407
|
+
'dest-filename': 'config'
|
|
408
|
+
})
|
|
409
|
+
return sources
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def main():
|
|
413
|
+
parser = argparse.ArgumentParser()
|
|
414
|
+
parser.add_argument('cargo_lock', help='Path to the Cargo.lock file')
|
|
415
|
+
parser.add_argument('-o', '--output', required=False, help='Where to write generated sources')
|
|
416
|
+
parser.add_argument('-t', '--git-tarballs', action='store_true', help='Download git repos as tarballs')
|
|
417
|
+
parser.add_argument('-d', '--debug', action='store_true')
|
|
418
|
+
args = parser.parse_args()
|
|
419
|
+
if args.output is not None:
|
|
420
|
+
outfile = args.output
|
|
421
|
+
else:
|
|
422
|
+
outfile = 'generated-sources.json'
|
|
423
|
+
if args.debug:
|
|
424
|
+
loglevel = logging.DEBUG
|
|
425
|
+
else:
|
|
426
|
+
loglevel = logging.INFO
|
|
427
|
+
logging.basicConfig(level=loglevel)
|
|
428
|
+
|
|
429
|
+
generated_sources = asyncio.run(generate_sources(load_toml(args.cargo_lock),
|
|
430
|
+
git_tarballs=args.git_tarballs))
|
|
431
|
+
with open(outfile, 'w') as out:
|
|
432
|
+
json.dump(generated_sources, out, indent=4, sort_keys=False)
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
if __name__ == '__main__':
|
|
436
|
+
main()
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "flatpak-cargo-generator"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Unofficial Pypi distribution of the Flatpak's cargo dependency generator"
|
|
5
|
+
authors = [
|
|
6
|
+
"Flatpak team",
|
|
7
|
+
]
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Programming Language :: Python :: 3",
|
|
11
|
+
"License :: OSI Approved :: MIT License",
|
|
12
|
+
"Operating System :: Unix",
|
|
13
|
+
]
|
|
14
|
+
include = ["flatpak_cargo_generator/script.py"]
|
|
15
|
+
|
|
16
|
+
[tool.poetry.dependencies]
|
|
17
|
+
python = ">=3.8"
|
|
18
|
+
aiohttp = "^3.9.5"
|
|
19
|
+
toml = "^0.10.2"
|
|
20
|
+
|
|
21
|
+
[tool.poetry.scripts]
|
|
22
|
+
flatpak-cargo-generator = "flatpak_cargo_generator.script:main"
|
|
23
|
+
|
|
24
|
+
[build-system]
|
|
25
|
+
requires = ["poetry-core"]
|
|
26
|
+
build-backend = "poetry.core.masonry.api"
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/flatpak/flatpak-builder-tools"
|