refactor metadata parser to class
Signed-off-by: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
This commit is contained in:
parent
99f6926156
commit
4ff91cb101
1 changed files with 110 additions and 62 deletions
172
cargodeps.py
172
cargodeps.py
|
@ -14,54 +14,109 @@ REQ_TO_CON = {">": "<=",
|
|||
">=": "<",
|
||||
"<=": ">"}
|
||||
|
||||
def get_metadata(path):
|
||||
# --no-deps is to disable recursive scanning of deps
|
||||
metadata = subprocess.check_output(["cargo", "metadata", "--no-deps",
|
||||
"--manifest-path={}".format(path)])
|
||||
return json.loads(metadata)["packages"][0]
|
||||
class Dependency(object):
|
||||
def __init__(self, name, spec, feature=None, inverted=False):
|
||||
self.name = name
|
||||
self.spec = spec
|
||||
self.feature = feature
|
||||
self.inverted = inverted
|
||||
|
||||
def parse_req(s):
|
||||
if "*" in s:
|
||||
raise NotImplementedError("https://github.com/rbarrois/python-semanticversion/issues/51")
|
||||
spec = semver.Spec(s.replace(" ", ""))
|
||||
specs = spec.specs
|
||||
if len(specs) == 1:
|
||||
req = specs[0]
|
||||
if req.kind in (req.KIND_CARET, req.KIND_TILDE):
|
||||
ver = req.spec
|
||||
lower = semver.Version.coerce(str(ver))
|
||||
if req.kind == req.KIND_CARET:
|
||||
if ver.major == 0:
|
||||
if ver.minor is not None:
|
||||
if ver.patch is None or ver.minor != 0:
|
||||
upper = ver.next_minor()
|
||||
else:
|
||||
upper = ver.next_patch()
|
||||
else:
|
||||
upper = ver.next_major()
|
||||
else:
|
||||
upper = ver.next_major()
|
||||
elif req.kind == req.KIND_TILDE:
|
||||
if ver.minor is None:
|
||||
upper = ver.next_major()
|
||||
else:
|
||||
upper = ver.next_minor()
|
||||
else:
|
||||
assert False
|
||||
return (semver.Spec(">={}".format(lower)).specs[0],
|
||||
semver.Spec("<{}".format(upper)).specs[0])
|
||||
def __repr__(self):
|
||||
f_part = "/{}".format(self.feature) if self.feature is not None else ""
|
||||
if self.inverted:
|
||||
kind = REQ_TO_CON[self.spec.kind]
|
||||
else:
|
||||
return (req, None)
|
||||
elif len(specs) == 2:
|
||||
return (specs[0], specs[1])
|
||||
else:
|
||||
# it's something uber-complicated
|
||||
raise NotImplementedError("More than two ranges are unsupported, probably something is wrong with metadata")
|
||||
assert False
|
||||
kind = self.spec.kind
|
||||
return "crate({}{}) {} {}".format(self.name, f_part, kind.replace("==", "="), self.spec.spec)
|
||||
|
||||
def print_dep(name, spec, kind="=", feature=None):
|
||||
f_part = "/{}".format(feature) if feature is not None else ""
|
||||
print("crate({}{}) {} {}".format(name, f_part, kind.replace("==", "="), spec))
|
||||
class Metadata(object):
|
||||
def __init__(self, path):
|
||||
self._provides = []
|
||||
self._requires = []
|
||||
self._conflicts = []
|
||||
|
||||
# --no-deps is to disable recursive scanning of deps
|
||||
metadata = subprocess.check_output(["cargo", "metadata", "--no-deps",
|
||||
"--manifest-path={}".format(path)])
|
||||
self._parse_metadata(json.loads(metadata))
|
||||
|
||||
@staticmethod
|
||||
def _parse_req(s):
|
||||
if "*" in s:
|
||||
raise NotImplementedError("https://github.com/rbarrois/python-semanticversion/issues/51")
|
||||
spec = semver.Spec(s.replace(" ", ""))
|
||||
specs = spec.specs
|
||||
if len(specs) == 1:
|
||||
req = specs[0]
|
||||
if req.kind in (req.KIND_CARET, req.KIND_TILDE):
|
||||
ver = req.spec
|
||||
lower = semver.Version.coerce(str(ver))
|
||||
if req.kind == req.KIND_CARET:
|
||||
if ver.major == 0:
|
||||
if ver.minor is not None:
|
||||
if ver.patch is None or ver.minor != 0:
|
||||
upper = ver.next_minor()
|
||||
else:
|
||||
upper = ver.next_patch()
|
||||
else:
|
||||
upper = ver.next_major()
|
||||
else:
|
||||
upper = ver.next_major()
|
||||
elif req.kind == req.KIND_TILDE:
|
||||
if ver.minor is None:
|
||||
upper = ver.next_major()
|
||||
else:
|
||||
upper = ver.next_minor()
|
||||
else:
|
||||
assert False
|
||||
return (semver.Spec(">={}".format(lower)).specs[0],
|
||||
semver.Spec("<{}".format(upper)).specs[0])
|
||||
else:
|
||||
return (req, None)
|
||||
elif len(specs) == 2:
|
||||
return (specs[0], specs[1])
|
||||
else:
|
||||
# it's something uber-complicated
|
||||
raise NotImplementedError("More than two ranges are unsupported, "
|
||||
"probably something is wrong with metadata")
|
||||
assert False
|
||||
|
||||
def _parse_metadata(self, metadata):
|
||||
md = metadata["packages"][0]
|
||||
name = md["name"]
|
||||
version = semver.SpecItem("={}".format(md["version"]))
|
||||
|
||||
# Provides
|
||||
self._provides = [Dependency(name, version)]
|
||||
for feature in md["features"]:
|
||||
self._provides.append(Dependency(name, version, feature=feature))
|
||||
|
||||
# Requires, Conflicts
|
||||
self._requires = []
|
||||
self._conflicts = []
|
||||
for dep in md["dependencies"]:
|
||||
if dep["kind"] is not None:
|
||||
# kind: build -> build dependencies
|
||||
# kind: dev -> test dependencies
|
||||
continue
|
||||
req, con = self._parse_req(dep["req"])
|
||||
assert req is not None
|
||||
for feature in dep["features"] or [None]:
|
||||
self._requires.append(Dependency(dep["name"], req, feature=feature))
|
||||
if con is not None:
|
||||
self._conflicts.append(Dependency(dep["name"], con, feature=feature, inverted=True))
|
||||
|
||||
@property
|
||||
def provides(self):
|
||||
return self._provides[:]
|
||||
|
||||
@property
|
||||
def requires(self):
|
||||
return self._requires[:]
|
||||
|
||||
@property
|
||||
def conflicts(self):
|
||||
return self._conflicts[:]
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
|
@ -74,23 +129,16 @@ if __name__ == "__main__":
|
|||
|
||||
files = args.file or sys.stdin.readlines()
|
||||
|
||||
def print_deps(deps):
|
||||
if len(deps) > 0:
|
||||
print("\n".join(str(dep) for dep in deps))
|
||||
|
||||
for f in files:
|
||||
f = f.rstrip()
|
||||
md = get_metadata(f)
|
||||
md = Metadata(f)
|
||||
if args.provides:
|
||||
print_dep(md["name"], md["version"])
|
||||
for feature in md["features"]:
|
||||
print_dep(md["name"], md["version"], feature=feature)
|
||||
if args.requires or args.conflicts:
|
||||
for dep in md["dependencies"]:
|
||||
if dep["kind"] is not None:
|
||||
# kind: build -> build dependencies
|
||||
# kind: dev -> test dependencies
|
||||
continue
|
||||
req, con = parse_req(dep["req"])
|
||||
assert req is not None
|
||||
for feature in dep["features"] or [None]:
|
||||
if args.requires:
|
||||
print_dep(dep["name"], req.spec, req.kind, feature=feature)
|
||||
if args.conflicts and con is not None:
|
||||
print_dep(dep["name"], con.spec, REQ_TO_CON[con.kind], feature=feature)
|
||||
print_deps(md.provides)
|
||||
if args.requires:
|
||||
print_deps(md.requires)
|
||||
if args.conflicts:
|
||||
print_deps(md.conflicts)
|
||||
|
|
Loading…
Reference in a new issue