pkgmap-py 0.2.0__tar.gz → 0.2.1__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.
- {pkgmap_py-0.2.0 → pkgmap_py-0.2.1}/PKG-INFO +3 -3
- {pkgmap_py-0.2.0 → pkgmap_py-0.2.1}/README.md +2 -2
- {pkgmap_py-0.2.0 → pkgmap_py-0.2.1}/pyproject.toml +1 -1
- {pkgmap_py-0.2.0 → pkgmap_py-0.2.1}/pyproject.toml.orig +1 -1
- {pkgmap_py-0.2.0 → pkgmap_py-0.2.1}/src/pkgmap/__init__.py +2 -0
- {pkgmap_py-0.2.0 → pkgmap_py-0.2.1}/src/pkgmap/resolver.py +47 -17
- {pkgmap_py-0.2.0 → pkgmap_py-0.2.1}/src/pkgmap/schema.py +7 -0
- {pkgmap_py-0.2.0 → pkgmap_py-0.2.1}/src/pkgmap/apps.py +0 -0
- {pkgmap_py-0.2.0 → pkgmap_py-0.2.1}/src/pkgmap/cli.py +0 -0
- {pkgmap_py-0.2.0 → pkgmap_py-0.2.1}/src/pkgmap/consumer.py +0 -0
- {pkgmap_py-0.2.0 → pkgmap_py-0.2.1}/src/pkgmap/db.py +0 -0
- {pkgmap_py-0.2.0 → pkgmap_py-0.2.1}/src/pkgmap/downloader.py +0 -0
- {pkgmap_py-0.2.0 → pkgmap_py-0.2.1}/src/pkgmap/logger.py +0 -0
- {pkgmap_py-0.2.0 → pkgmap_py-0.2.1}/src/pkgmap/pipeline.py +0 -0
- {pkgmap_py-0.2.0 → pkgmap_py-0.2.1}/src/pkgmap/repos.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: pkgmap-py
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Cross-distribution Linux package name resolution
|
|
5
5
|
Author: Levizor
|
|
6
6
|
Author-email: Levizor <levizor@disroot.org>
|
|
@@ -126,8 +126,8 @@ pkgmap update --full
|
|
|
126
126
|
|
|
127
127
|
| Variant | File | Compressed Size | Coverage | Default For |
|
|
128
128
|
| :--- | :--- | :--- | :--- | :--- |
|
|
129
|
-
| **Core** | `pkgmap-core.db` | ~
|
|
130
|
-
| **Full** | `pkgmap.db` | ~
|
|
129
|
+
| **Core** | `pkgmap-core.db` | ~12 MB | Top 10 repositories (Nixpkgs, Arch, AUR, Debian, Ubuntu, Fedora, Alpine, openSUSE, Gentoo, Void) | **CLI & Web UI** |
|
|
130
|
+
| **Full** | `pkgmap.db` | ~40 MB | All 330+ Repology repositories | **Python Library** |
|
|
131
131
|
|
|
132
132
|
- **CLI behavior**: Defaults to the **Core** database (`~/.cache/pkgmap/pkgmap-core.db`) unless the Full database is already downloaded locally or `--full` is passed. If you query a repository not present in Core, the CLI prompts you to run `pkgmap update --full`. You can also pass `--core` or `--full` to any CLI command (`resolve`, `update`, `repos`).
|
|
133
133
|
- **Python library behavior**: Defaults to the **Full** database (`~/.cache/pkgmap/pkgmap.db`). Call `set_default_variant("core")` (or set `PKGMAP_DB_VARIANT=core`) to use the Core database instead.
|
|
@@ -111,8 +111,8 @@ pkgmap update --full
|
|
|
111
111
|
|
|
112
112
|
| Variant | File | Compressed Size | Coverage | Default For |
|
|
113
113
|
| :--- | :--- | :--- | :--- | :--- |
|
|
114
|
-
| **Core** | `pkgmap-core.db` | ~
|
|
115
|
-
| **Full** | `pkgmap.db` | ~
|
|
114
|
+
| **Core** | `pkgmap-core.db` | ~12 MB | Top 10 repositories (Nixpkgs, Arch, AUR, Debian, Ubuntu, Fedora, Alpine, openSUSE, Gentoo, Void) | **CLI & Web UI** |
|
|
115
|
+
| **Full** | `pkgmap.db` | ~40 MB | All 330+ Repology repositories | **Python Library** |
|
|
116
116
|
|
|
117
117
|
- **CLI behavior**: Defaults to the **Core** database (`~/.cache/pkgmap/pkgmap-core.db`) unless the Full database is already downloaded locally or `--full` is passed. If you query a repository not present in Core, the CLI prompts you to run `pkgmap update --full`. You can also pass `--core` or `--full` to any CLI command (`resolve`, `update`, `repos`).
|
|
118
118
|
- **Python library behavior**: Defaults to the **Full** database (`~/.cache/pkgmap/pkgmap.db`). Call `set_default_variant("core")` (or set `PKGMAP_DB_VARIANT=core`) to use the Core database instead.
|
|
@@ -17,6 +17,7 @@ from pkgmap.resolver import (
|
|
|
17
17
|
resolve_batch_all,
|
|
18
18
|
resolve_project,
|
|
19
19
|
)
|
|
20
|
+
from pkgmap.schema import normalize_nix_package_name
|
|
20
21
|
|
|
21
22
|
__version__ = "0.2.0"
|
|
22
23
|
__all__ = [
|
|
@@ -26,6 +27,7 @@ __all__ = [
|
|
|
26
27
|
"get_database_path",
|
|
27
28
|
"get_default_variant",
|
|
28
29
|
"list_repositories",
|
|
30
|
+
"normalize_nix_package_name",
|
|
29
31
|
"resolve",
|
|
30
32
|
"resolve_all",
|
|
31
33
|
"resolve_batch",
|
|
@@ -3,7 +3,11 @@ from collections.abc import Sequence
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
5
|
from pkgmap.db import ensure_database
|
|
6
|
-
from pkgmap.schema import
|
|
6
|
+
from pkgmap.schema import (
|
|
7
|
+
PackageResolution,
|
|
8
|
+
Repository,
|
|
9
|
+
normalize_nix_package_name,
|
|
10
|
+
)
|
|
7
11
|
|
|
8
12
|
DEFAULT_ALIASES: dict[str, str] = {
|
|
9
13
|
"debian": "debian_12",
|
|
@@ -96,13 +100,14 @@ BATCH_CHUNK_SIZE = 500
|
|
|
96
100
|
|
|
97
101
|
def _rank_match(
|
|
98
102
|
query_pkg: str, res: PackageResolution
|
|
99
|
-
) -> tuple[str, int, int, int, int, str]:
|
|
103
|
+
) -> tuple[str, int, int, int, int, int, str]:
|
|
100
104
|
lower_q = query_pkg.lower()
|
|
101
105
|
lower_name = res.name.lower()
|
|
102
106
|
return (
|
|
103
107
|
res.repo,
|
|
104
108
|
0 if lower_name == lower_q else 1,
|
|
105
109
|
1 if lower_name.endswith(("-git", "-bin")) else 0,
|
|
110
|
+
1 if "-unwrapped" in lower_name else 0,
|
|
106
111
|
1 if ("." in res.name or "/" in res.name) else 0,
|
|
107
112
|
len(res.name),
|
|
108
113
|
res.name,
|
|
@@ -162,19 +167,30 @@ def resolve_batch_all(
|
|
|
162
167
|
for row in cursor.fetchall():
|
|
163
168
|
key = row[0]
|
|
164
169
|
if key in results:
|
|
170
|
+
name = row[1]
|
|
171
|
+
repo_family = row[4]
|
|
172
|
+
if repo_family == "nix":
|
|
173
|
+
name = normalize_nix_package_name(name)
|
|
165
174
|
results[key].append(
|
|
166
175
|
PackageResolution(
|
|
167
|
-
name=
|
|
176
|
+
name=name,
|
|
168
177
|
version=row[2],
|
|
169
178
|
repo=row[3],
|
|
170
|
-
repo_family=
|
|
179
|
+
repo_family=repo_family,
|
|
171
180
|
)
|
|
172
181
|
)
|
|
173
182
|
|
|
174
183
|
if src_repo:
|
|
175
184
|
unmatched = [pkg for pkg in chunk if not results[pkg]]
|
|
176
185
|
if unmatched:
|
|
177
|
-
|
|
186
|
+
proj_to_pkgs: dict[str, list[str]] = {}
|
|
187
|
+
for pkg in unmatched:
|
|
188
|
+
proj_to_pkgs.setdefault(pkg, []).append(pkg)
|
|
189
|
+
norm = normalize_nix_package_name(pkg)
|
|
190
|
+
if norm != pkg:
|
|
191
|
+
proj_to_pkgs.setdefault(norm, []).append(pkg)
|
|
192
|
+
|
|
193
|
+
u_placeholders = ",".join("?" for _ in proj_to_pkgs)
|
|
178
194
|
fallback_sql = f"""
|
|
179
195
|
SELECT DISTINCT pr.name, dst.package_name, dst.version, dst_repo.name, dst_repo.family
|
|
180
196
|
FROM projects pr
|
|
@@ -184,7 +200,7 @@ def resolve_batch_all(
|
|
|
184
200
|
JOIN repositories dst_repo ON dst.repo_id = dst_repo.id
|
|
185
201
|
WHERE src_repo.name = ? AND pr.name IN ({u_placeholders})
|
|
186
202
|
"""
|
|
187
|
-
fallback_params: list[str] = [src_repo, *
|
|
203
|
+
fallback_params: list[str] = [src_repo, *proj_to_pkgs.keys()]
|
|
188
204
|
if dst_repo:
|
|
189
205
|
fallback_sql += " AND dst_repo.name = ?"
|
|
190
206
|
fallback_params.append(dst_repo)
|
|
@@ -192,22 +208,36 @@ def resolve_batch_all(
|
|
|
192
208
|
|
|
193
209
|
cursor.execute(fallback_sql, fallback_params)
|
|
194
210
|
for row in cursor.fetchall():
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
results
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
211
|
+
pr_name = row[0]
|
|
212
|
+
for input_key in proj_to_pkgs.get(pr_name, []):
|
|
213
|
+
if input_key in results:
|
|
214
|
+
name = row[1]
|
|
215
|
+
repo_family = row[4]
|
|
216
|
+
if repo_family == "nix":
|
|
217
|
+
name = normalize_nix_package_name(name)
|
|
218
|
+
results[input_key].append(
|
|
219
|
+
PackageResolution(
|
|
220
|
+
name=name,
|
|
221
|
+
version=row[2],
|
|
222
|
+
repo=row[3],
|
|
223
|
+
repo_family=repo_family,
|
|
224
|
+
)
|
|
203
225
|
)
|
|
204
|
-
)
|
|
205
226
|
|
|
206
227
|
for pkg, matches in results.items():
|
|
207
|
-
|
|
208
|
-
|
|
228
|
+
seen: set[tuple[str, str, str | None]] = set()
|
|
229
|
+
deduped: list[PackageResolution] = []
|
|
230
|
+
for m in matches:
|
|
231
|
+
dedup_key = (m.repo, m.name, m.version)
|
|
232
|
+
if dedup_key not in seen:
|
|
233
|
+
seen.add(dedup_key)
|
|
234
|
+
deduped.append(m)
|
|
235
|
+
if len(deduped) > 1:
|
|
236
|
+
deduped.sort(key=lambda r: _rank_match(pkg, r))
|
|
237
|
+
results[pkg] = deduped
|
|
209
238
|
|
|
210
239
|
return results
|
|
240
|
+
|
|
211
241
|
finally:
|
|
212
242
|
conn.close()
|
|
213
243
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import re
|
|
1
2
|
from typing import NamedTuple
|
|
2
3
|
|
|
3
4
|
|
|
@@ -35,6 +36,11 @@ class PackageResolution(NamedTuple):
|
|
|
35
36
|
REPOLOGY_SCHEMA_URL = "https://github.com/repology/repology-updater/blob/master/sql.d/schema/create_schema_tables.sql"
|
|
36
37
|
|
|
37
38
|
|
|
39
|
+
def normalize_nix_package_name(name: str) -> str:
|
|
40
|
+
"""Normalize Nix package names by stripping unwrapped derivation markers."""
|
|
41
|
+
return re.sub(r"-unwrapped(?=($|[\"_-]))", "", name)
|
|
42
|
+
|
|
43
|
+
|
|
38
44
|
class RepologyPackageRow(NamedTuple):
|
|
39
45
|
"""Repology 'packages' table row schema extracted from PostgreSQL dumps.
|
|
40
46
|
|
|
@@ -61,6 +67,7 @@ class RepologyPackageRow(NamedTuple):
|
|
|
61
67
|
package_name = self.srcname
|
|
62
68
|
elif self.category:
|
|
63
69
|
package_name = f"{self.category}.{self.visiblename}"
|
|
70
|
+
package_name = normalize_nix_package_name(package_name)
|
|
64
71
|
|
|
65
72
|
return PackageRecord(
|
|
66
73
|
repo=self.repo,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|