You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
702 lines
24 KiB
702 lines
24 KiB
From a61a367883b7cd60f600d25958fb634c530500fa Mon Sep 17 00:00:00 2001
|
|
From: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
|
|
Date: Fri, 26 Oct 2018 11:20:13 +0200
|
|
Subject: [PATCH 7/7] split features into subpackages
|
|
|
|
References: https://discussion.fedoraproject.org/t/rfc-new-crates-packaging-design-features-have-their-own-subpackages/563?u=ignatenkobrain
|
|
Signed-off-by: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
|
|
---
|
|
data/cargo.attr | 4 +-
|
|
data/macros.cargo | 10 ++
|
|
rust2rpm/__main__.py | 11 +-
|
|
rust2rpm/inspector.py | 22 ++-
|
|
rust2rpm/metadata.py | 315 +++++++++++++++++------------------
|
|
rust2rpm/templates/main.spec | 141 ++++++++--------
|
|
6 files changed, 259 insertions(+), 244 deletions(-)
|
|
|
|
diff --git a/data/cargo.attr b/data/cargo.attr
|
|
index 392a72b..4910b5c 100644
|
|
--- a/data/cargo.attr
|
|
+++ b/data/cargo.attr
|
|
@@ -1,3 +1,3 @@
|
|
-%__cargo_provides %{_bindir}/cargo-inspector --provides
|
|
-%__cargo_requires %{_bindir}/cargo-inspector --requires
|
|
+%__cargo_provides %{_bindir}/cargo-inspector --provides --feature=%{__cargo_feature_from_name -n %{name}}
|
|
+%__cargo_requires %{_bindir}/cargo-inspector --requires --feature=%{__cargo_feature_from_name -n %{name}}
|
|
%__cargo_path ^%{cargo_registry}/[^/]+/Cargo\\.toml$
|
|
diff --git a/data/macros.cargo b/data/macros.cargo
|
|
index a0c456a..7fb025b 100644
|
|
--- a/data/macros.cargo
|
|
+++ b/data/macros.cargo
|
|
@@ -84,3 +84,13 @@ if %__cargo_is_bin; then \
|
|
%{__rm} %{buildroot}%{_prefix}/.crates.toml \
|
|
fi \
|
|
)
|
|
+
|
|
+%__cargo_feature_from_name(n:) %{lua:
|
|
+local name = rpm.expand("%{-n*}")
|
|
+local feature = string.match(name, "^.+%+(.+)-devel$")
|
|
+if feature == nil then
|
|
+ print()
|
|
+else
|
|
+ print(feature)
|
|
+end
|
|
+}
|
|
diff --git a/rust2rpm/__main__.py b/rust2rpm/__main__.py
|
|
index f23ebbc..d19cb47 100644
|
|
--- a/rust2rpm/__main__.py
|
|
+++ b/rust2rpm/__main__.py
|
|
@@ -18,15 +18,19 @@ import requests
|
|
import tqdm
|
|
|
|
from . import Metadata, licensing
|
|
+from .metadata import normalize_deps
|
|
|
|
DEFAULT_EDITOR = "vi"
|
|
XDG_CACHE_HOME = os.getenv("XDG_CACHE_HOME", os.path.expanduser("~/.cache"))
|
|
CACHEDIR = os.path.join(XDG_CACHE_HOME, "rust2rpm")
|
|
API_URL = "https://crates.io/api/v1/"
|
|
JINJA_ENV = jinja2.Environment(loader=jinja2.ChoiceLoader([
|
|
- jinja2.FileSystemLoader(["/"]),
|
|
- jinja2.PackageLoader("rust2rpm", "templates"), ]),
|
|
- trim_blocks=True, lstrip_blocks=True)
|
|
+ jinja2.FileSystemLoader(["/"]),
|
|
+ jinja2.PackageLoader("rust2rpm", "templates"),
|
|
+ ]),
|
|
+ extensions=["jinja2.ext.do"],
|
|
+ trim_blocks=True,
|
|
+ lstrip_blocks=True)
|
|
|
|
def get_default_target():
|
|
# TODO: add fallback for /usr/lib/os-release
|
|
@@ -227,6 +231,7 @@ def main():
|
|
patch=args.patch,
|
|
store=args.store_crate)
|
|
|
|
+ JINJA_ENV.globals["normalize_deps"] = normalize_deps
|
|
template = JINJA_ENV.get_template("main.spec")
|
|
|
|
if args.patch and len(diff) > 0:
|
|
diff --git a/rust2rpm/inspector.py b/rust2rpm/inspector.py
|
|
index 2d488b2..9e79e88 100644
|
|
--- a/rust2rpm/inspector.py
|
|
+++ b/rust2rpm/inspector.py
|
|
@@ -1,8 +1,8 @@
|
|
import argparse
|
|
-import itertools
|
|
import sys
|
|
|
|
from . import Metadata
|
|
+from .metadata import normalize_deps
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
@@ -10,18 +10,23 @@ def main():
|
|
group.add_argument("-n", "--name", action="store_true", help="Print name")
|
|
group.add_argument("-v", "--version", action="store_true", help="Print version")
|
|
group.add_argument("-t", "--target-kinds", action="store_true", help="Print target kinds")
|
|
+ group.add_argument("-l", "--list-features", action="store_true", help="Print features")
|
|
group.add_argument("-P", "--provides", action="store_true", help="Print Provides")
|
|
group.add_argument("-R", "--requires", action="store_true", help="Print Requires")
|
|
group.add_argument("-BR", "--build-requires", action="store_true", help="Print BuildRequires")
|
|
group.add_argument("-TR", "--test-requires", action="store_true", help="Print TestRequires")
|
|
+ parser.add_argument("-f", "--feature", help="Feature to work on")
|
|
parser.add_argument("file", nargs="*", help="Path(s) to Cargo.toml")
|
|
args = parser.parse_args()
|
|
|
|
files = args.file or sys.stdin.readlines()
|
|
|
|
+ if not args.feature:
|
|
+ args.feature = None
|
|
+
|
|
def print_deps(deps):
|
|
if len(deps) > 0:
|
|
- print("\n".join(str(dep) for dep in deps))
|
|
+ print("\n".join(sorted(normalize_deps(deps))))
|
|
|
|
for f in files:
|
|
f = f.rstrip()
|
|
@@ -32,17 +37,20 @@ def main():
|
|
print(md.version)
|
|
if args.target_kinds:
|
|
print("\n".join(set(tgt.kind for tgt in md.targets)))
|
|
+ if args.list_features:
|
|
+ for f in sorted(f for f in md.dependencies if f is not None):
|
|
+ print(f)
|
|
if args.provides:
|
|
- print_deps(md.provides)
|
|
- if args.requires or args.build_requires:
|
|
- print_deps(list(itertools.chain(md.requires, md.build_requires)))
|
|
- if args.test_requires:
|
|
- print_deps(md.test_requires)
|
|
+ print(md.provides(args.feature))
|
|
if args.requires:
|
|
# Someone should own /usr/share/cargo/registry
|
|
print("cargo")
|
|
+ print_deps(md.requires(args.feature))
|
|
if args.build_requires:
|
|
print("rust-packaging")
|
|
+ print_deps(md.requires(args.feature or "default", resolve=True))
|
|
+ if args.test_requires:
|
|
+ print_deps(md.dev_dependencies)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
diff --git a/rust2rpm/metadata.py b/rust2rpm/metadata.py
|
|
index 5adeb65..119dea5 100644
|
|
--- a/rust2rpm/metadata.py
|
|
+++ b/rust2rpm/metadata.py
|
|
@@ -1,208 +1,205 @@
|
|
__all__ = ["Dependency", "Metadata"]
|
|
|
|
-import itertools
|
|
+import copy
|
|
import json
|
|
import subprocess
|
|
-import sys
|
|
|
|
import semantic_version as semver
|
|
import rustcfg
|
|
|
|
-class Target(object):
|
|
- def __init__(self, kind, name):
|
|
- self.kind = kind
|
|
+class Target:
|
|
+ def __init__(self, name, kind):
|
|
self.name = name
|
|
+ self.kind = kind
|
|
|
|
def __repr__(self):
|
|
- return "<Target {self.kind}|{self.name}>".format(self=self)
|
|
-
|
|
-
|
|
-def _req_to_str(name, spec=None, feature=None):
|
|
- f_part = "/{}".format(feature) if feature is not None else ""
|
|
- basestr = "crate({}{})".format(name, f_part)
|
|
- if spec is None:
|
|
- return basestr
|
|
- if spec.kind == spec.KIND_EQUAL:
|
|
- spec.kind = spec.KIND_SHORTEQ
|
|
- if spec.kind == spec.KIND_ANY:
|
|
- if spec.spec == "":
|
|
- # Just wildcard
|
|
- return basestr
|
|
- else:
|
|
- # Wildcard in string
|
|
- assert False, spec.spec
|
|
- version = str(spec.spec).replace("-", "~")
|
|
- return "{} {} {}".format(basestr, spec.kind, version)
|
|
+ return f"<Target {self.name} ({self.kind})>"
|
|
|
|
-class Dependency(object):
|
|
- def __init__(self, name, req, features=(), provides=False):
|
|
+class Dependency:
|
|
+ def __init__(self, name, req=None, features=(), optional=False):
|
|
self.name = name
|
|
- self.spec = self._parse_req(req)
|
|
+ self.req = req
|
|
self.features = features
|
|
- self.provides = provides
|
|
- if self.provides:
|
|
- if len(self.spec.specs) > 1 or \
|
|
- (len(self.spec.specs) == 1 and self.spec.specs[0].kind != self.spec.specs[0].KIND_EQUAL):
|
|
- raise Exception("Provides can't be applied to ranged version, {!r}".format(self.spec))
|
|
-
|
|
- def __repr__(self):
|
|
- if self.provides:
|
|
- spec = self.spec.specs[0]
|
|
- provs = [_req_to_str(self.name, spec)]
|
|
- for feature in self.features:
|
|
- provs.append(_req_to_str(self.name, spec, feature))
|
|
- return " and ".join(provs)
|
|
-
|
|
- reqs = [_req_to_str(self.name, spec=req) for req in self.spec.specs]
|
|
- features = [_req_to_str(self.name, feature=feature) for feature in self.features]
|
|
+ self.optional = optional
|
|
|
|
- use_rich = False
|
|
- if len(reqs) > 1:
|
|
- reqstr = "({})".format(" with ".join(reqs))
|
|
- use_rich = True
|
|
- elif len(reqs) == 1:
|
|
- reqstr = reqs[0]
|
|
- else:
|
|
- reqstr = ""
|
|
- if len(features) > 0:
|
|
- featurestr = " with ".join(features)
|
|
- use_rich = True
|
|
- else:
|
|
- featurestr = ""
|
|
-
|
|
- if use_rich:
|
|
- if reqstr and featurestr:
|
|
- return "({} with {})".format(reqstr, featurestr)
|
|
- elif reqstr and not featurestr:
|
|
- return reqstr
|
|
- elif not reqstr and featurestr:
|
|
- return "({})".format(featurestr)
|
|
- else:
|
|
- assert False
|
|
- else:
|
|
- return reqstr
|
|
+ @classmethod
|
|
+ def from_json(cls, metadata):
|
|
+ features = set(metadata['features'])
|
|
+ if metadata['uses_default_features']:
|
|
+ features.add('default')
|
|
+ kwargs = {'name': metadata['name'],
|
|
+ 'req': metadata['req'],
|
|
+ 'optional': metadata['optional'],
|
|
+ 'features': features}
|
|
+ return cls(**kwargs)
|
|
|
|
@staticmethod
|
|
- def _parse_req(s):
|
|
- if "*" in s and s != "*":
|
|
- # XXX: https://github.com/rbarrois/python-semanticversion/issues/51
|
|
- s = "~{}".format(s.replace(".*", "", 1))
|
|
- if ".*" in s:
|
|
- s = s.replace(".*", "")
|
|
- spec = semver.Spec(s.replace(" ", ""))
|
|
- parsed = []
|
|
+ def _normalize_req(req):
|
|
+ if "*" in req:
|
|
+ return NotImplemented
|
|
+ spec = semver.Spec(req.replace(" ", ""))
|
|
+ reqs = []
|
|
for req in spec.specs:
|
|
- ver = req.spec
|
|
if req.kind == req.KIND_ANY:
|
|
- parsed.append("*")
|
|
+ # Any means any
|
|
continue
|
|
+ ver = req.spec
|
|
+ if ver.prerelease or req.kind in (req.KIND_NEQ, req.KIND_EMPTY):
|
|
+ return NotImplemented
|
|
coerced = semver.Version.coerce(str(ver))
|
|
- if req.kind in (req.KIND_CARET, req.KIND_TILDE):
|
|
- if ver.prerelease:
|
|
- # pre-release versions only match the same x.y.z
|
|
- if ver.patch is not None:
|
|
- upper = ver.next_patch()
|
|
- elif ver.minor is not None:
|
|
- upper = ver.next_minor()
|
|
- else:
|
|
- upper = ver.next_major()
|
|
- elif 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()
|
|
+ if req.kind == req.KIND_EQUAL:
|
|
+ req.kind = req.KIND_SHORTEQ
|
|
+ if req.kind in (req.KIND_CARET, req.KIND_COMPATIBLE):
|
|
+ if ver.major == 0:
|
|
+ if ver.minor is not None:
|
|
+ if ver.minor != 0 or ver.patch is None:
|
|
+ upper = ver.next_minor()
|
|
else:
|
|
- upper = ver.next_major()
|
|
+ upper = ver.next_patch()
|
|
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
|
|
- parsed.append(">={}".format(coerced))
|
|
- parsed.append("<{}".format(upper))
|
|
- elif req.kind == req.KIND_NEQ:
|
|
- parsed.append(">{}".format(coerced))
|
|
- parsed.append("<{}".format(coerced))
|
|
- elif req.kind in (req.KIND_EQUAL, req.KIND_GT, req.KIND_GTE, req.KIND_LT, req.KIND_LTE):
|
|
- parsed.append("{}{}".format(req.kind, coerced))
|
|
+ upper = ver.next_major()
|
|
+ reqs.append((">=", coerced))
|
|
+ reqs.append(("<", upper))
|
|
+ elif req.kind == req.KIND_TILDE:
|
|
+ if ver.minor is None:
|
|
+ upper = ver.next_major()
|
|
+ else:
|
|
+ upper = ver.next_minor()
|
|
+ reqs.append((">=", coerced))
|
|
+ reqs.append(("<", upper))
|
|
+ elif req.kind in (req.KIND_SHORTEQ,
|
|
+ req.KIND_GT,
|
|
+ req.KIND_GTE,
|
|
+ req.KIND_LT,
|
|
+ req.KIND_LTE):
|
|
+ reqs.append((str(req.kind), coerced))
|
|
else:
|
|
- assert False, req.kind
|
|
- return semver.Spec(",".join(parsed))
|
|
+ raise AssertionError(f"Found unhandled kind: {req.kind}")
|
|
+ return reqs
|
|
|
|
-class Metadata(object):
|
|
- def __init__(self):
|
|
- self.name = None
|
|
+ @staticmethod
|
|
+ def _apply_reqs(name, reqs, feature=None):
|
|
+ fstr = f"/{feature}" if feature is not None else ""
|
|
+ cap = f"crate({name}{fstr})"
|
|
+ if not reqs:
|
|
+ return cap
|
|
+ deps = " with ".join(f"{cap} {op} {version}" for op, version in reqs)
|
|
+ if len(reqs) > 1:
|
|
+ return f"({deps})"
|
|
+ else:
|
|
+ return deps
|
|
+
|
|
+ def normalize(self):
|
|
+ return [self._apply_reqs(self.name, self._normalize_req(self.req), feature)
|
|
+ for feature in self.features or (None,)]
|
|
+
|
|
+ def __repr__(self):
|
|
+ return f"<Dependency: {self.name} {self.req} ({', '.join(sorted(self.features))})>"
|
|
+
|
|
+ def __str__(self):
|
|
+ return "\n".join(self.normalize())
|
|
+
|
|
+class Metadata:
|
|
+ def __init__(self, name, version):
|
|
+ self.name = name
|
|
+ self.version = version
|
|
self.license = None
|
|
self.license_file = None
|
|
self.readme = None
|
|
self.description = None
|
|
- self.version = None
|
|
- self._targets = []
|
|
- self.provides = []
|
|
- self.requires = []
|
|
- self.build_requires = []
|
|
- self.test_requires = []
|
|
+ self.targets = set()
|
|
+ self.dependencies = {}
|
|
+ self.dev_dependencies = set()
|
|
|
|
@classmethod
|
|
def from_json(cls, metadata):
|
|
- self = cls()
|
|
-
|
|
md = metadata
|
|
- self.name = md["name"]
|
|
+ self = cls(md["name"], md["version"])
|
|
+
|
|
self.license = md["license"]
|
|
self.license_file = md["license_file"]
|
|
self.readme = md["readme"]
|
|
self.description = md.get("description")
|
|
- self.version = md["version"]
|
|
- version = "={}".format(self.version)
|
|
-
|
|
- # Targets
|
|
- self.targets = [Target(tgt["kind"][0], tgt["name"]) for tgt in md["targets"]]
|
|
-
|
|
- # Provides
|
|
- # All optional dependencies are also features
|
|
- # https://github.com/rust-lang/cargo/issues/4911
|
|
- features = itertools.chain((x["name"] for x in md["dependencies"] if x["optional"]),
|
|
- md["features"])
|
|
- provides = Dependency(self.name, version, features=features, provides=True)
|
|
- self.provides = str(provides).split(" and ")
|
|
-
|
|
- ev = rustcfg.Evaluator.platform()
|
|
-
|
|
- # Dependencies
|
|
- for dep in md["dependencies"]:
|
|
- kind = dep["kind"]
|
|
- if kind is None:
|
|
- requires = self.requires
|
|
- elif kind == "build":
|
|
- requires = self.build_requires
|
|
- elif kind == "dev":
|
|
- requires = self.test_requires
|
|
- else:
|
|
- raise ValueError("Unknown kind: {!r}, please report bug.".format(kind))
|
|
|
|
- target = dep["target"]
|
|
- if target is None:
|
|
- pass
|
|
+ # dependencies + build-dependencies → runtime
|
|
+ deps_by_name = {dep["name"]: Dependency.from_json(dep)
|
|
+ for dep in md["dependencies"]
|
|
+ if dep["kind"] != "dev"}
|
|
+
|
|
+ deps_by_feature = {}
|
|
+ for feature, f_deps in md["features"].items():
|
|
+ features = {None}
|
|
+ deps = set()
|
|
+ for dep in f_deps:
|
|
+ if dep in md["features"]:
|
|
+ features.add(dep)
|
|
+ else:
|
|
+ pkg, _, f = dep.partition("/")
|
|
+ dep = copy.deepcopy(deps_by_name[pkg])
|
|
+ if f:
|
|
+ dep.features = {f}
|
|
+ deps.add(dep)
|
|
+ deps_by_feature[feature] = (features, deps)
|
|
+
|
|
+ mandatory_deps = set()
|
|
+ for dep in deps_by_name.values():
|
|
+ if dep.optional:
|
|
+ deps_by_feature[dep.name] = ({None}, {copy.deepcopy(dep)})
|
|
else:
|
|
- cond = ev.parse_and_eval(target)
|
|
- if not cond:
|
|
- print(f'Dependency {dep["name"]} for target {target!r} is not needed, ignoring.',
|
|
- file=sys.stderr)
|
|
- continue
|
|
+ mandatory_deps.add(copy.deepcopy(dep))
|
|
+ deps_by_feature[None] = (set(), mandatory_deps)
|
|
+
|
|
+ if "default" not in deps_by_feature:
|
|
+ deps_by_feature["default"] = ({None}, set())
|
|
|
|
- requires.append(Dependency(dep["name"], dep["req"], features=dep["features"]))
|
|
+ self.dependencies = deps_by_feature
|
|
+ self.dev_dependencies = {Dependency.from_json(dep)
|
|
+ for dep in md["dependencies"]
|
|
+ if dep["kind"] == "dev"}
|
|
+
|
|
+ self.targets = {Target(tgt["name"], tgt["kind"][0])
|
|
+ for tgt in md["targets"]}
|
|
|
|
return self
|
|
|
|
@classmethod
|
|
def from_file(cls, path):
|
|
metadata = subprocess.check_output(["cargo", "read-manifest",
|
|
- "--manifest-path={}".format(path)])
|
|
+ f"--manifest-path={path}"])
|
|
return cls.from_json(json.loads(metadata))
|
|
+
|
|
+ @property
|
|
+ def all_dependencies(self):
|
|
+ return set().union(*(x[1] for x in self.dependencies.values()))
|
|
+
|
|
+ def provides(self, feature=None):
|
|
+ if feature not in self.dependencies:
|
|
+ raise KeyError(f"Feature {feature!r} doesn't exist")
|
|
+ return Dependency(self.name, f"={self.version}", features={feature})
|
|
+
|
|
+ @classmethod
|
|
+ def _resolve(cls, deps_by_feature, feature):
|
|
+ all_features = set()
|
|
+ all_deps = set()
|
|
+ ff, dd = copy.deepcopy(deps_by_feature[feature])
|
|
+ all_features |= ff
|
|
+ all_deps |= dd
|
|
+ for f in ff:
|
|
+ ff1, dd1 = cls._resolve(deps_by_feature, f)
|
|
+ all_features |= ff1
|
|
+ all_deps |= dd1
|
|
+ return all_features, all_deps
|
|
+
|
|
+ def requires(self, feature=None, resolve=False):
|
|
+ if resolve:
|
|
+ return self._resolve(self.dependencies, feature)[1]
|
|
+ else:
|
|
+ features, deps = self.dependencies[feature]
|
|
+ fdeps = set(Dependency(self.name, f"={self.version}", features={feature})
|
|
+ for feature in features)
|
|
+ return fdeps | deps
|
|
+
|
|
+def normalize_deps(deps):
|
|
+ return set().union(*(d.normalize() for d in deps))
|
|
diff --git a/rust2rpm/templates/main.spec b/rust2rpm/templates/main.spec
|
|
index 7dbcc3f..27a448f 100644
|
|
--- a/rust2rpm/templates/main.spec
|
|
+++ b/rust2rpm/templates/main.spec
|
|
@@ -48,82 +48,101 @@ Patch0: {{ patch_file }}
|
|
ExclusiveArch: %{rust_arches}
|
|
|
|
BuildRequires: rust-packaging
|
|
-{% if include_build_requires %}
|
|
-{% if md.requires|length > 0 %}
|
|
-# [dependencies]
|
|
-{% for req in md.requires|sort(attribute="name") %}
|
|
+{# We will put all non-optional and optional dependencies until
|
|
+ https://github.com/rust-lang/cargo/issues/5133
|
|
+ is solved
|
|
+{% set buildrequires = normalize_deps(md.requires("default", resolve=True))|sort %}
|
|
+#}
|
|
+{% set buildrequires = normalize_deps(md.all_dependencies)|sort %}
|
|
+{% for req in buildrequires %}
|
|
BuildRequires: {{ req }}
|
|
{% endfor %}
|
|
-{% endif %}
|
|
-{% if md.build_requires|length > 0 %}
|
|
-# [build-dependencies]
|
|
-{% for req in md.build_requires|sort(attribute="name") %}
|
|
-BuildRequires: {{ req }}
|
|
-{% endfor %}
|
|
-{% endif %}
|
|
-{% if md.test_requires|length > 0 %}
|
|
+{% set testrequires = normalize_deps(md.dev_dependencies)|sort %}
|
|
+{% if testrequires|length > 0 %}
|
|
%if %{with check}
|
|
-# [dev-dependencies]
|
|
-{% for req in md.test_requires|sort(attribute="name") %}
|
|
+ {% for req in testrequires %}
|
|
BuildRequires: {{ req }}
|
|
-{% endfor %}
|
|
+ {% endfor %}
|
|
%endif
|
|
{% endif %}
|
|
-{% endif %}
|
|
|
|
-%description
|
|
+%global _description \
|
|
+{% if md.description is none %}
|
|
%{summary}.
|
|
+{% else %}
|
|
+{{ md.description|wordwrap(wrapstring="\\\n")|trim }}
|
|
+{% endif %}
|
|
+
|
|
+%description %{_description}
|
|
|
|
{% if include_main %}
|
|
%package -n %{crate}
|
|
Summary: %{summary}
|
|
-{% if rust_group is defined %}
|
|
+ {% if rust_group is defined %}
|
|
Group: # FIXME
|
|
-{% endif %}
|
|
+ {% endif %}
|
|
|
|
%description -n %{crate}
|
|
%{summary}.
|
|
|
|
-{% endif %}
|
|
+%files -n %{crate}
|
|
+ {% if md.license_file is not none %}
|
|
+%license {{ md.license_file }}
|
|
+ {% endif %}
|
|
+ {% if md.readme is not none %}
|
|
+%doc {{ md.readme }}
|
|
+ {% endif %}
|
|
+ {% for bin in bins %}
|
|
+%{_bindir}/{{ bin.name }}
|
|
+ {% endfor %}
|
|
+{% endif -%}
|
|
+
|
|
{% if include_devel %}
|
|
-%package devel
|
|
+ {% set features = md.dependencies.keys()|list %}
|
|
+ {% do features.remove(None) %}
|
|
+ {% do features.remove("default") %}
|
|
+ {% set features = features|sort %}
|
|
+ {% do features.insert(0, None) %}
|
|
+ {% do features.insert(1, "default") %}
|
|
+ {% for feature in features %}
|
|
+ {% set pkg = "-n %%{name}+%s-devel"|format(feature) if feature is not none else " devel" %}
|
|
+%package {{ pkg }}
|
|
Summary: %{summary}
|
|
-{% if rust_group is defined %}
|
|
+ {% if rust_group is defined %}
|
|
Group: {{ rust_group }}
|
|
-{% endif %}
|
|
+ {% endif %}
|
|
BuildArch: noarch
|
|
-{% if include_provides %}
|
|
-{% for prv in md.provides %}
|
|
-Provides: {{ prv }}
|
|
-{% endfor %}
|
|
-{% endif %}
|
|
-{% if include_requires %}
|
|
+ {% if include_provides %}
|
|
+Provides: {{ md.provides(feature) }}
|
|
+ {% endif %}
|
|
+ {% if include_requires %}
|
|
Requires: cargo
|
|
-{% if md.requires|length > 0 %}
|
|
-# [dependencies]
|
|
-{% for req in md.requires|sort(attribute="name") %}
|
|
-Requires: {{ req }}
|
|
-{% endfor %}
|
|
-{% endif %}
|
|
-{% if md.build_requires|length > 0 %}
|
|
-# [build-dependencies]
|
|
-{% for req in md.build_requires|sort(attribute="name") %}
|
|
+ {% for req in md.requires(feature)|map("string")|sort %}
|
|
Requires: {{ req }}
|
|
-{% endfor %}
|
|
-{% endif %}
|
|
-{% endif %}
|
|
+ {% endfor %}
|
|
+ {% endif %}
|
|
|
|
-%description devel
|
|
-{% if md.description is none %}
|
|
-%{summary}.
|
|
-{% else %}
|
|
-{{ md.description|wordwrap|trim }}
|
|
-{% endif %}
|
|
+%description {{ pkg }} %{_description}
|
|
|
|
This package contains library source intended for building other packages
|
|
-which use %{crate} from crates.io.
|
|
+which use {% if feature is not none %}"{{ feature }}" feature of {% endif %}"%{crate}" crate.
|
|
+
|
|
+%files {{ pkg }}
|
|
+ {% if feature is none %}
|
|
+ {% if md.license_file is not none %}
|
|
+%license {{ md.license_file }}
|
|
+ {% endif %}
|
|
+ {% if md.readme is not none %}
|
|
+%doc {{ md.readme }}
|
|
+ {% endif %}
|
|
+%{cargo_registry}/%{crate}-%{version}/
|
|
+ {% else %}
|
|
+%ghost %{cargo_registry}/%{crate}-%{version}/Cargo.toml
|
|
+ {% endif %}
|
|
+
|
|
+ {% endfor %}
|
|
+{% endif -%}
|
|
|
|
-{% endif %}
|
|
%prep
|
|
{% if md.name != crate %}
|
|
%autosetup -n %{real_crate}-%{version} -p1
|
|
@@ -143,29 +162,5 @@ which use %{crate} from crates.io.
|
|
%cargo_test
|
|
%endif
|
|
|
|
-{% if include_main %}
|
|
-%files -n %{crate}
|
|
-{% if md.license_file is not none %}
|
|
-%license {{ md.license_file }}
|
|
-{% endif %}
|
|
-{% if md.readme is not none %}
|
|
-%doc {{ md.readme }}
|
|
-{% endif %}
|
|
-{% for bin in bins %}
|
|
-%{_bindir}/{{ bin.name }}
|
|
-{% endfor %}
|
|
-
|
|
-{% endif %}
|
|
-{% if include_devel %}
|
|
-%files devel
|
|
-{% if md.license_file is not none %}
|
|
-%license {{ md.license_file }}
|
|
-{% endif %}
|
|
-{% if md.readme is not none %}
|
|
-%doc {{ md.readme }}
|
|
-{% endif %}
|
|
-%{cargo_registry}/%{crate}-%{version}/
|
|
-
|
|
-{% endif %}
|
|
%changelog
|
|
{% include target ~ "-changelog.spec.inc" %}
|
|
--
|
|
2.19.1
|
|
|