forceupdate 0.1.0__py3-none-any.whl
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.
- forceupdate/__init__.py +9 -0
- forceupdate/__main__.py +5 -0
- forceupdate/advisories/__init__.py +30 -0
- forceupdate/advisories/cvss.py +95 -0
- forceupdate/advisories/osv.py +584 -0
- forceupdate/checks/__init__.py +49 -0
- forceupdate/checks/base.py +98 -0
- forceupdate/checks/deprecated.py +115 -0
- forceupdate/checks/outdated.py +183 -0
- forceupdate/checks/priority.py +82 -0
- forceupdate/checks/vulns.py +201 -0
- forceupdate/cli.py +309 -0
- forceupdate/detect/__init__.py +5 -0
- forceupdate/detect/languages.py +266 -0
- forceupdate/detect/manifests.py +478 -0
- forceupdate/engine.py +313 -0
- forceupdate/models.py +510 -0
- forceupdate/net/__init__.py +20 -0
- forceupdate/net/cache.py +217 -0
- forceupdate/net/http.py +270 -0
- forceupdate/parsers/__init__.py +43 -0
- forceupdate/parsers/base.py +22 -0
- forceupdate/parsers/json_spans.py +123 -0
- forceupdate/parsers/lockfiles.py +231 -0
- forceupdate/parsers/npm.py +1257 -0
- forceupdate/parsers/python.py +1421 -0
- forceupdate/parsers/toml_spans.py +297 -0
- forceupdate/registries/__init__.py +52 -0
- forceupdate/registries/base.py +294 -0
- forceupdate/registries/npm.py +153 -0
- forceupdate/registries/pypi.py +242 -0
- forceupdate/report/__init__.py +359 -0
- forceupdate/report/json.py +34 -0
- forceupdate/report/markdown.py +169 -0
- forceupdate/report/terminal.py +376 -0
- forceupdate/sources/__init__.py +1 -0
- forceupdate/sources/base.py +45 -0
- forceupdate/sources/local.py +183 -0
- forceupdate/update/__init__.py +8 -0
- forceupdate/update/constraints.py +317 -0
- forceupdate/update/planner.py +531 -0
- forceupdate/versions/__init__.py +40 -0
- forceupdate/versions/base.py +229 -0
- forceupdate/versions/npm.py +432 -0
- forceupdate/versions/pypi.py +220 -0
- forceupdate-0.1.0.dist-info/METADATA +79 -0
- forceupdate-0.1.0.dist-info/RECORD +50 -0
- forceupdate-0.1.0.dist-info/WHEEL +4 -0
- forceupdate-0.1.0.dist-info/entry_points.txt +2 -0
- forceupdate-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"""Les versions PyPI : PEP 440, avec ``packaging``.
|
|
2
|
+
|
|
3
|
+
Une contrainte est d'abord lue comme un ``SpecifierSet`` de PEP 440 (``>=2.25, <3``,
|
|
4
|
+
``~=1.4``, ``==1.2.*``). Ce que ``SpecifierSet`` refuse est de la syntaxe Poetry ou
|
|
5
|
+
Pipfile, que les parseurs gardent telle qu'écrite (E03), traduite ici en PEP 440 :
|
|
6
|
+
|
|
7
|
+
- ``^1.2.3`` → ``>=1.2.3,<2.0.0``, ``^0.2.3`` → ``>=0.2.3,<0.3.0``, ``^0.0.3`` →
|
|
8
|
+
``>=0.0.3,<0.0.4`` : la borne haute est la prochaine version « cassante » ;
|
|
9
|
+
- ``~1.2.3`` → ``>=1.2.3,<1.3.0``, ``~1`` → ``>=1,<2`` ;
|
|
10
|
+
- ``1.2.*`` (ou ``1.2.x``) → ``==1.2.*``, une version nue ``6.0.2`` → ``==6.0.2`` ;
|
|
11
|
+
- ``*`` (Poetry et Pipfile) : toutes les versions ;
|
|
12
|
+
- plusieurs contraintes séparées par des virgules ou des espaces (``>= 1.2 < 2.0``) ;
|
|
13
|
+
- ``||`` : une union. ``SpecifierSet`` ne sait faire que des intersections, d'où une
|
|
14
|
+
liste d'ensembles.
|
|
15
|
+
|
|
16
|
+
Une contrainte est un ensemble de versions : ``2.0rc1`` respecte ``>=1.0``. Ce sont
|
|
17
|
+
les candidates (``VersionScheme.candidates``) qui écartent les pré-versions.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import functools
|
|
21
|
+
import re
|
|
22
|
+
|
|
23
|
+
from packaging.specifiers import InvalidSpecifier, SpecifierSet
|
|
24
|
+
from packaging.version import InvalidVersion as _PackagingInvalidVersion
|
|
25
|
+
from packaging.version import Version
|
|
26
|
+
|
|
27
|
+
from forceupdate.models import Ecosystem, Gap
|
|
28
|
+
from forceupdate.versions.base import Constraint, InvalidConstraint, InvalidVersion, VersionScheme
|
|
29
|
+
|
|
30
|
+
_LOWER_OPERATORS = frozenset({">=", ">", "==", "~=", "==="})
|
|
31
|
+
"""Les opérateurs qui donnent une borne basse ; ``!=``, ``<`` et ``<=`` n'en donnent pas."""
|
|
32
|
+
|
|
33
|
+
_OR = re.compile(r"\s*\|\|?\s*")
|
|
34
|
+
_OPERATOR = re.compile(r"===|==|!=|<>|<=|>=|~=|<|>|=|\^|~")
|
|
35
|
+
_SINGLE = re.compile(rf"(?P<op>{_OPERATOR.pattern})?\s*(?P<version>\S+)")
|
|
36
|
+
_ANY = re.compile(r"v?[xX*](?:\.[xX*])*")
|
|
37
|
+
_WILDCARD = re.compile(r"v?(?P<prefix>[0-9]+(?:\.[0-9]+)*)(?:\.[xX*])+")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class PypiConstraint(Constraint[Version]):
|
|
41
|
+
"""Une contrainte PEP 440, ou une union de contraintes (``||`` de Poetry)."""
|
|
42
|
+
|
|
43
|
+
def __init__(self, sets: tuple[SpecifierSet, ...]) -> None:
|
|
44
|
+
self.sets = sets
|
|
45
|
+
"""Les ensembles de l'union : une version doit en respecter au moins un."""
|
|
46
|
+
|
|
47
|
+
def __repr__(self) -> str:
|
|
48
|
+
return f"PypiConstraint({' || '.join(str(s) or '*' for s in self.sets)})"
|
|
49
|
+
|
|
50
|
+
def contains(self, version: Version) -> bool:
|
|
51
|
+
return any(specifiers.contains(version, prereleases=True) for specifiers in self.sets)
|
|
52
|
+
|
|
53
|
+
def lower_bound(self) -> str | None:
|
|
54
|
+
"""La plus haute borne basse de chaque ensemble, puis la plus petite de l'union. Une
|
|
55
|
+
borne exclue (``>1.2``) est rendue telle quelle : PEP 440 n'a pas de « version
|
|
56
|
+
suivante », c'est la meilleure approximation."""
|
|
57
|
+
lowest: tuple[Version, str] | None = None
|
|
58
|
+
for specifiers in self.sets:
|
|
59
|
+
bounds = []
|
|
60
|
+
for specifier in specifiers:
|
|
61
|
+
if specifier.operator not in _LOWER_OPERATORS:
|
|
62
|
+
continue
|
|
63
|
+
text = specifier.version.removesuffix(".*")
|
|
64
|
+
try:
|
|
65
|
+
bounds.append((Version(text), text))
|
|
66
|
+
except _PackagingInvalidVersion:
|
|
67
|
+
continue # « === » accepte n'importe quel texte
|
|
68
|
+
if not bounds:
|
|
69
|
+
return None
|
|
70
|
+
bound = max(bounds, key=lambda pair: pair[0])
|
|
71
|
+
if lowest is None or bound[0] < lowest[0]:
|
|
72
|
+
lowest = bound
|
|
73
|
+
return None if lowest is None else lowest[1]
|
|
74
|
+
|
|
75
|
+
def exact(self) -> str | None:
|
|
76
|
+
"""``==1.2.3`` (sans joker) ou ``===1.2.3``, seul : sa version. Une version nue de
|
|
77
|
+
Poetry (``6.0.2``) est traduite en ``==``."""
|
|
78
|
+
if len(self.sets) != 1:
|
|
79
|
+
return None
|
|
80
|
+
specifiers = list(self.sets[0])
|
|
81
|
+
if len(specifiers) != 1:
|
|
82
|
+
return None
|
|
83
|
+
(specifier,) = specifiers
|
|
84
|
+
if specifier.operator == "===" or (
|
|
85
|
+
specifier.operator == "==" and not specifier.version.endswith(".*")
|
|
86
|
+
):
|
|
87
|
+
return specifier.version
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class PypiVersions(VersionScheme[Version]):
|
|
92
|
+
"""PEP 440. L'époque (``1!2.0``) compte : en changer est une majeure."""
|
|
93
|
+
|
|
94
|
+
ecosystem = Ecosystem.PYPI
|
|
95
|
+
|
|
96
|
+
def parse(self, version: str) -> Version:
|
|
97
|
+
return _parse(version)
|
|
98
|
+
|
|
99
|
+
def parse_constraint(self, constraint: str) -> PypiConstraint:
|
|
100
|
+
return _parse_constraint(constraint)
|
|
101
|
+
|
|
102
|
+
def _release(self, version: Version) -> tuple[int, int, int]:
|
|
103
|
+
major, minor, patch = (*version.release, 0, 0)[:3]
|
|
104
|
+
return major, minor, patch
|
|
105
|
+
|
|
106
|
+
def _is_pre(self, version: Version) -> bool:
|
|
107
|
+
return version.is_prerelease
|
|
108
|
+
|
|
109
|
+
def _same_release(self, a: Version, b: Version) -> bool:
|
|
110
|
+
return (a.epoch, _stripped(a.release)) == (b.epoch, _stripped(b.release))
|
|
111
|
+
|
|
112
|
+
def _gap(self, a: Version, b: Version) -> Gap:
|
|
113
|
+
if a.epoch != b.epoch:
|
|
114
|
+
return Gap.MAJOR
|
|
115
|
+
return super()._gap(a, b)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
PYPI = PypiVersions()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _stripped(release: tuple[int, ...]) -> tuple[int, ...]:
|
|
122
|
+
"""``(1, 2, 0)`` → ``(1, 2)`` : ``1.2`` et ``1.2.0`` sont la même version."""
|
|
123
|
+
end = len(release)
|
|
124
|
+
while end > 1 and release[end - 1] == 0:
|
|
125
|
+
end -= 1
|
|
126
|
+
return release[:end]
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@functools.lru_cache(maxsize=4096)
|
|
130
|
+
def _parse(version: str) -> Version:
|
|
131
|
+
try:
|
|
132
|
+
return Version(version)
|
|
133
|
+
except _PackagingInvalidVersion:
|
|
134
|
+
raise InvalidVersion(f"version PEP 440 illisible : {version!r}") from None
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@functools.lru_cache(maxsize=1024)
|
|
138
|
+
def _parse_constraint(constraint: str) -> PypiConstraint:
|
|
139
|
+
try:
|
|
140
|
+
return PypiConstraint((SpecifierSet(constraint),))
|
|
141
|
+
except InvalidSpecifier:
|
|
142
|
+
pass
|
|
143
|
+
try:
|
|
144
|
+
return PypiConstraint(tuple(_poetry_set(part) for part in _OR.split(constraint.strip())))
|
|
145
|
+
except ValueError: # InvalidSpecifier et InvalidVersion de packaging en sont
|
|
146
|
+
message = f"contrainte PEP 440 ou Poetry illisible : {constraint!r}"
|
|
147
|
+
raise InvalidConstraint(message) from None
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _poetry_set(text: str) -> SpecifierSet:
|
|
151
|
+
"""Un membre d'une union Poetry : des contraintes séparées par des virgules ou des
|
|
152
|
+
espaces, toutes à respecter. Un opérateur seul (``>= 1.2``) va avec ce qui suit. Un
|
|
153
|
+
membre vide (``^1 || || ^2``) est refusé, comme le fait Poetry."""
|
|
154
|
+
if not text.strip():
|
|
155
|
+
raise ValueError(text)
|
|
156
|
+
specifiers: list[str] = []
|
|
157
|
+
operator = ""
|
|
158
|
+
for token in re.split(r"[\s,]+", text):
|
|
159
|
+
if not token:
|
|
160
|
+
continue
|
|
161
|
+
if _OPERATOR.fullmatch(token):
|
|
162
|
+
if operator:
|
|
163
|
+
raise ValueError(token)
|
|
164
|
+
operator = token
|
|
165
|
+
continue
|
|
166
|
+
specifiers.extend(_poetry_single(operator + token))
|
|
167
|
+
operator = ""
|
|
168
|
+
if operator:
|
|
169
|
+
raise ValueError(operator)
|
|
170
|
+
return SpecifierSet(",".join(specifiers))
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _poetry_single(text: str) -> list[str]:
|
|
174
|
+
"""Une contrainte Poetry, en spécificateurs PEP 440 (aucun pour ``*``)."""
|
|
175
|
+
match = _SINGLE.fullmatch(text)
|
|
176
|
+
if match is None:
|
|
177
|
+
raise ValueError(text)
|
|
178
|
+
operator, written = match.group("op") or "", match.group("version")
|
|
179
|
+
if _ANY.fullmatch(written):
|
|
180
|
+
if operator not in ("", "=", "==", ">="):
|
|
181
|
+
raise ValueError(text)
|
|
182
|
+
return []
|
|
183
|
+
wildcard = _WILDCARD.fullmatch(written)
|
|
184
|
+
if wildcard is not None:
|
|
185
|
+
if operator not in ("", "=", "==", "!="):
|
|
186
|
+
raise ValueError(text)
|
|
187
|
+
return [f"{'!=' if operator == '!=' else '=='}{wildcard.group('prefix')}.*"]
|
|
188
|
+
version = Version(written)
|
|
189
|
+
if operator == "^":
|
|
190
|
+
return [f">={version}", f"<{_next_breaking(version)}"]
|
|
191
|
+
if operator == "~":
|
|
192
|
+
index = 0 if len(version.release) == 1 else 1
|
|
193
|
+
return [f">={version}", f"<{_bump(version, index)}"]
|
|
194
|
+
if operator in ("", "="):
|
|
195
|
+
return [f"=={version}"]
|
|
196
|
+
if operator == "<>":
|
|
197
|
+
return [f"!={version}"]
|
|
198
|
+
return [f"{operator}{version}"]
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _next_breaking(version: Version) -> str:
|
|
202
|
+
"""La borne haute de ``^`` : la prochaine majeure, ou en 0.x la prochaine mineure
|
|
203
|
+
(``^0.2.3`` → ``0.3.0``), ou en 0.0.x le prochain correctif (``^0.0.3`` → ``0.0.4``).
|
|
204
|
+
Comme Poetry, ``^0`` va jusqu'à ``1`` et ``^0.0`` jusqu'à ``0.1``."""
|
|
205
|
+
release = version.release
|
|
206
|
+
if release[0] > 0 or len(release) == 1:
|
|
207
|
+
return _bump(version, 0)
|
|
208
|
+
if release[1] > 0 or len(release) == 2:
|
|
209
|
+
return _bump(version, 1)
|
|
210
|
+
return _bump(version, 2)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _bump(version: Version, index: int) -> str:
|
|
214
|
+
"""La version stable où le nombre ``index`` monte de 1 et ceux d'après passent à 0,
|
|
215
|
+
écrite avec autant de nombres que ``version`` : ``1.2.3`` monté en 1 donne ``1.3.0``."""
|
|
216
|
+
release = version.release
|
|
217
|
+
width = max(len(release), index + 1)
|
|
218
|
+
numbers = (*release[:index], release[index] + 1, *([0] * (width - index - 1)))
|
|
219
|
+
text = ".".join(str(number) for number in numbers)
|
|
220
|
+
return f"{version.epoch}!{text}" if version.epoch else text
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: forceupdate
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Trouve les dépendances à mettre à jour (versions, failles, fins de vie) et fait les mises à jour : en local, ou par pull request sur GitHub, GitLab et Bitbucket.
|
|
5
|
+
Project-URL: Homepage, https://github.com/Pauzzle-ozz/forceupdate
|
|
6
|
+
Project-URL: Repository, https://github.com/Pauzzle-ozz/forceupdate
|
|
7
|
+
Project-URL: Issues, https://github.com/Pauzzle-ozz/forceupdate/issues
|
|
8
|
+
Author: Pauzzle
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: dependencies,end-of-life,osv,outdated,pull-request,update,vulnerabilities
|
|
12
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Environment :: Web Environment
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Natural Language :: French
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Topic :: Security
|
|
25
|
+
Classifier: Topic :: Software Development
|
|
26
|
+
Classifier: Topic :: System :: Software Distribution
|
|
27
|
+
Classifier: Topic :: Utilities
|
|
28
|
+
Requires-Python: >=3.11
|
|
29
|
+
Requires-Dist: httpx>=0.28.1
|
|
30
|
+
Requires-Dist: packaging>=26.3
|
|
31
|
+
Requires-Dist: platformdirs>=4.13.6
|
|
32
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
33
|
+
Requires-Dist: rich>=15.0.0
|
|
34
|
+
Requires-Dist: typer>=0.27.3
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# forceupdate
|
|
38
|
+
|
|
39
|
+
On donne du code à l'outil : un dossier, un fichier, ou tous ses dépôts GitHub,
|
|
40
|
+
GitLab et Bitbucket. Dans une interface web qui tourne sur son ordinateur, il
|
|
41
|
+
montre les langages et les dépendances, et dit ce qui doit être mis à jour :
|
|
42
|
+
versions en retard, failles, fins de vie, paquets dépréciés. On coche les mises à
|
|
43
|
+
jour voulues, puis il les fait : en local il réécrit les fichiers, sur une forge il
|
|
44
|
+
ouvre une pull request par dépôt.
|
|
45
|
+
|
|
46
|
+
En construction. L'outil sera publié gratuitement sur PyPI
|
|
47
|
+
(`uv tool install forceupdate`), sous licence MIT.
|
|
48
|
+
|
|
49
|
+
Déjà là, en ligne de commande, pour Python et npm : `forceupdate scan <dossier>`
|
|
50
|
+
dit quelles dépendances ont une faille connue (d'après [OSV](https://osv.dev),
|
|
51
|
+
indirectes comprises, avec la version qui la corrige), une version plus récente,
|
|
52
|
+
une version retirée, ou sont dépréciées.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
forceupdate scan . # rapport dans le terminal
|
|
56
|
+
forceupdate scan . --format json -o rapport.json # ou md ; toujours en UTF-8
|
|
57
|
+
forceupdate scan . --fail-on vuln # code 1 si une faille est connue
|
|
58
|
+
forceupdate scan . --fail-on major # code 1 si une majeure (ou pire) attend
|
|
59
|
+
forceupdate scan . --offline # seulement le cache, sans réseau
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Autres options : `--no-dev`, `--transitive`, `--no-cache` (`forceupdate scan --help`).
|
|
63
|
+
|
|
64
|
+
`forceupdate update <dossier>` montre, pour l'instant sans rien écrire, les mises à
|
|
65
|
+
jour qu'il ferait : vers quelle version, quelle contrainte réécrire (dans son style :
|
|
66
|
+
`^4.17.0` devient `^4.21.2`), quel lockfile régénérer. Correctifs, mineures et
|
|
67
|
+
corrections de failles sont choisis ; les majeures sont proposées à part.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
forceupdate update . # correctifs et mineures (--level minor)
|
|
71
|
+
forceupdate update . --level major # majeures comprises
|
|
72
|
+
forceupdate update . --security-only # seulement les corrections de failles
|
|
73
|
+
forceupdate update . --exclude "eslint*" --ecosystem npm
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- [docs/BRIEF.md](docs/BRIEF.md) : l'idée, les décisions prises, les pièges
|
|
77
|
+
- [docs/JSON_FORMAT.md](docs/JSON_FORMAT.md) : le format du rapport JSON
|
|
78
|
+
- [PLAN.md](PLAN.md) : le plan étape par étape, et l'avancement
|
|
79
|
+
- [reference/README.md](reference/README.md) : le code déjà disponible, repris d'Argos
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
forceupdate/__init__.py,sha256=nvXmzV66i6mGi0cA6KGe9XAFI6ZFsC_JAGh2hXRBhiw,294
|
|
2
|
+
forceupdate/__main__.py,sha256=qdONtCBWrdHpmsR0pgXnNG0aES0L1naFQfF4ii-ZMyY,145
|
|
3
|
+
forceupdate/cli.py,sha256=2mlXt_EFwln4aKCVYK6d7Br-Cw1cMoPHna1rBjciElc,10266
|
|
4
|
+
forceupdate/engine.py,sha256=MiWJZPidF3DIdNiLHcMr0rcYbWuAoPkAT09C56XdQ04,13502
|
|
5
|
+
forceupdate/models.py,sha256=1cPhuI2PSYpFiuxezYQD5Rjv9gHaXrLKzpK5ZbHmCSo,21051
|
|
6
|
+
forceupdate/advisories/__init__.py,sha256=FlLhOJuX4IrWypwkASzO1EmkgkE5sRkoCvPBDxiu4ZA,726
|
|
7
|
+
forceupdate/advisories/cvss.py,sha256=OG2BRnq4wfeQO21gQLQMH7LSLZgpkBg4Vfu7V1JjdL8,3910
|
|
8
|
+
forceupdate/advisories/osv.py,sha256=B3WMX_kbMdnKwQWvzU8XOTxLPNHoNO1GqHVcfXYpe4A,24468
|
|
9
|
+
forceupdate/checks/__init__.py,sha256=df1PxBVmvYVZ9b1-_Reo8qR2pT4Bg7XXDXvIHehLNFo,1992
|
|
10
|
+
forceupdate/checks/base.py,sha256=eCWBN52oMB16IIWm8KiqRMEkycRpYY0y_tqtDxtaFcc,4530
|
|
11
|
+
forceupdate/checks/deprecated.py,sha256=-ltM-uk70bagACwPI28ppisvcdKHDuSKeJQ7TkwRh5w,4896
|
|
12
|
+
forceupdate/checks/outdated.py,sha256=AGLce2rwGHMLt_a_oEJQjxS-zgiEeM2joALFaTSHpaU,8466
|
|
13
|
+
forceupdate/checks/priority.py,sha256=8glruncOQ9B9dqtzV_9ktpJTwmZUF87OBG153Y74tlk,3257
|
|
14
|
+
forceupdate/checks/vulns.py,sha256=qbyvE7VOPoTXIlxJjlN-VfVpLwo7QWsPs03PbNTkcAc,9074
|
|
15
|
+
forceupdate/detect/__init__.py,sha256=pMbCQpPnourANnrMc-REg1xdxSFRsRUX1thsjVpqOPs,252
|
|
16
|
+
forceupdate/detect/languages.py,sha256=OrPZ-XKsb65S_j6ZNmnKxhtbVWb-Li1mwZqFgQyAFuk,8182
|
|
17
|
+
forceupdate/detect/manifests.py,sha256=FuoQwBGSs1gl3yMHV-YdhGhnNSX3OxWxeBuYv45qK3U,16855
|
|
18
|
+
forceupdate/net/__init__.py,sha256=gcRKy3BPqjSXWNl3IHp5n2VOFOAA1cOsmK20swFQZWI,613
|
|
19
|
+
forceupdate/net/cache.py,sha256=RRLpVQ6Vjx-lvb128j03CwcVzImcFQmKNsGorZhsQSc,8357
|
|
20
|
+
forceupdate/net/http.py,sha256=LSYu_NkCrfV5d94Ab8SO1WYc91FnJELk1162QRK6XoI,10756
|
|
21
|
+
forceupdate/parsers/__init__.py,sha256=6h1t46qCtJfFL5yqIfuFGShkGM4Rmnvp1KPmgDbDF9U,2050
|
|
22
|
+
forceupdate/parsers/base.py,sha256=VrXxJA2Ji3PzMW4-2vWSVaZNZ42oRaUJ6gNKjY88Ff8,852
|
|
23
|
+
forceupdate/parsers/json_spans.py,sha256=ywu0LyEvwloh3ggu-gIKIRlI-2KY4ofqrIrBrVs7oiA,4615
|
|
24
|
+
forceupdate/parsers/lockfiles.py,sha256=pjqTEY1rttqXhCGKI9e744ufgiGhYhZX55OQ2AUrAd8,9276
|
|
25
|
+
forceupdate/parsers/npm.py,sha256=ToMjPZ2NR06MKcF0FZK9VSWOQPrMg6QqiT7dLCeTxuY,51959
|
|
26
|
+
forceupdate/parsers/python.py,sha256=35l3wylybIi3P7FXnZBkK5e6HBEiQIeh0M2MfxiRigg,54764
|
|
27
|
+
forceupdate/parsers/toml_spans.py,sha256=_RQ6XE8aPYeuGgDhcTXZJrI5aSB6htSe0stpvhsU0cA,11277
|
|
28
|
+
forceupdate/registries/__init__.py,sha256=t4RB2YnItGB6SSdvFRLI29-kXoTC02gAlicw_yhODx4,1585
|
|
29
|
+
forceupdate/registries/base.py,sha256=EszlJsJcoQAlr4eQxG7Rg1o5rTeh-CYMes2qntuqxkc,11958
|
|
30
|
+
forceupdate/registries/npm.py,sha256=qCJEnwxSJLhXZc4CB_PJlkSUF9tziPtmdBR9wiX3KrM,6000
|
|
31
|
+
forceupdate/registries/pypi.py,sha256=1Bzxtc6ntk8tUy3Y16OaEngRhJm142TcZcWcFhxPLnM,9503
|
|
32
|
+
forceupdate/report/__init__.py,sha256=cKQ7z_8Zcc1Mus1IZ4Ph-WitZTDEj0XwPnZqdDbgvjc,14008
|
|
33
|
+
forceupdate/report/json.py,sha256=VeC-edvPMMfJO3GyDjHJYp7bWbYsRujVLayu4d6nGWk,1249
|
|
34
|
+
forceupdate/report/markdown.py,sha256=HxFo1kqmFfF-6aU4n37CaKXXeHxk46ID2nfheU4pLUw,6873
|
|
35
|
+
forceupdate/report/terminal.py,sha256=I9AeLVAdk5DLNBbb7la-_Hne4FQ7A07S0iA__Mc-sE8,14434
|
|
36
|
+
forceupdate/sources/__init__.py,sha256=cCTdZagiRUJX9xfvGq-xSQ9wfO9NTIxCUnNm52uc1yU,92
|
|
37
|
+
forceupdate/sources/base.py,sha256=hi30KkEJ906hmGg2Dw2KGupbb_LDJQiJq8p_VwRmwac,1465
|
|
38
|
+
forceupdate/sources/local.py,sha256=o33l7kuzrisc3zc2QJEcBQJWqkeYlJJklTmzStQGDE4,6728
|
|
39
|
+
forceupdate/update/__init__.py,sha256=hY4Jv05vixin7erLsgFgV6dc8YdtAcGoOWvGKNG6Y64,387
|
|
40
|
+
forceupdate/update/constraints.py,sha256=JwmTmu5MEBFTAYWhC3KA2bc0yYorIr3YE_-MMhMiX_I,13686
|
|
41
|
+
forceupdate/update/planner.py,sha256=veqf1e5AcZh83XXr-ADsIYmCdpW9GuJ-4qU0Ra5SUtA,24177
|
|
42
|
+
forceupdate/versions/__init__.py,sha256=ncj35iHZmtN1REuNiZ050ngZEFZ13MSnrQCuD37-Imo,1355
|
|
43
|
+
forceupdate/versions/base.py,sha256=ovJJ3fpy83j-E-6PVIKSsEyHTg5svWd3JYYBLpgf5_E,9747
|
|
44
|
+
forceupdate/versions/npm.py,sha256=3afAoPKY3PhTlTy-N_hON2mCyFeGuy8fvf7sf_Mql9I,16108
|
|
45
|
+
forceupdate/versions/pypi.py,sha256=p2_U7LrUpwOq7-RXw2vp0GinLF2_LLHSKeGhKa2aD70,8831
|
|
46
|
+
forceupdate-0.1.0.dist-info/METADATA,sha256=uLpo1mYMxUcnO36xisrd5JG3-YonmytaUUzrYsHxS7o,3861
|
|
47
|
+
forceupdate-0.1.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
48
|
+
forceupdate-0.1.0.dist-info/entry_points.txt,sha256=z9xkY45qdOeWnoRw-Ll0ZoYHiHvXaSy7E6jkxQ_vKts,52
|
|
49
|
+
forceupdate-0.1.0.dist-info/licenses/LICENSE,sha256=UtjnCPB9u2A_FtDj1lqxhH8XUS8wqjAkh2Df-dIIpMY,1064
|
|
50
|
+
forceupdate-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pauzzle
|
|
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.
|