From 1b37f08c707d7f52a93555b56e31303a81e2684f Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Tue, 23 Apr 2019 16:18:29 +0200 Subject: [PATCH] Update to 7 Signed-off-by: Igor Gnatenko --- .gitignore | 1 + ...e-spec-patch_file-by-real-crate-name.patch | 37 - 0002-generate-doc-statements.patch | 58 - 0003-do-better-for-renamed-crates.patch | 90 -- 0004-remove-pre-3.6-leftovers.patch | 27 - 0005-Remove-half-downloaded-crate-on-C.patch | 44 - ...n-error-if-s-is-used-without-a-crate.patch | 28 - 0007-split-features-into-subpackages.patch | 1064 ----------------- ...port-for-dependencies-with-same-name.patch | 74 -- ...pport-for-feeding-user-configuration.patch | 148 --- 0010-trivial-use-f-strings-everywhere.patch | 94 -- ...t-generate-a-default-changelog-entry.patch | 63 - ...-Set-CARGO_HOME-to-the-local-.config.patch | 26 - ...et-the-install-root-in-.cargo-config.patch | 34 - ...censing-fix-zlib-license-translation.patch | 35 - ...ename-EPL-to-EPL-1.0-and-add-EPL-2.0.patch | 31 - ...-Add-support-for-prerelease-versions.patch | 160 --- ...argo-doesn-t-escape-paths-with-space.patch | 31 - 0018-data-Escape-n-properly.patch | 26 - 0019-Do-not-pull-optional-dependencies.patch | 77 -- rust-packaging.spec | 28 +- sources | 2 +- 22 files changed, 7 insertions(+), 2171 deletions(-) delete mode 100644 0001-name-spec-patch_file-by-real-crate-name.patch delete mode 100644 0002-generate-doc-statements.patch delete mode 100644 0003-do-better-for-renamed-crates.patch delete mode 100644 0004-remove-pre-3.6-leftovers.patch delete mode 100644 0005-Remove-half-downloaded-crate-on-C.patch delete mode 100644 0006-Throw-an-error-if-s-is-used-without-a-crate.patch delete mode 100644 0007-split-features-into-subpackages.patch delete mode 100644 0008-add-support-for-dependencies-with-same-name.patch delete mode 100644 0009-add-support-for-feeding-user-configuration.patch delete mode 100644 0010-trivial-use-f-strings-everywhere.patch delete mode 100644 0011-Add-option-to-not-generate-a-default-changelog-entry.patch delete mode 100644 0012-Set-CARGO_HOME-to-the-local-.config.patch delete mode 100644 0013-Set-the-install-root-in-.cargo-config.patch delete mode 100644 0014-licensing-fix-zlib-license-translation.patch delete mode 100644 0015-licensing-rename-EPL-to-EPL-1.0-and-add-EPL-2.0.patch delete mode 100644 0016-Add-support-for-prerelease-versions.patch delete mode 100644 0017-data-Cargo-doesn-t-escape-paths-with-space.patch delete mode 100644 0018-data-Escape-n-properly.patch delete mode 100644 0019-Do-not-pull-optional-dependencies.patch diff --git a/.gitignore b/.gitignore index 388ca95..aa71c2c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /rust2rpm-4.tar.xz /rust2rpm-5.tar.xz /rust2rpm-6.tar.xz +/rust2rpm-7.tar.xz diff --git a/0001-name-spec-patch_file-by-real-crate-name.patch b/0001-name-spec-patch_file-by-real-crate-name.patch deleted file mode 100644 index d8df04a..0000000 --- a/0001-name-spec-patch_file-by-real-crate-name.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0dc9fc182edf0791ca697f587e48dd39948d63c1 Mon Sep 17 00:00:00 2001 -From: Igor Gnatenko -Date: Mon, 10 Sep 2018 23:37:40 +0200 -Subject: [PATCH 01/19] name spec/patch_file by real crate name - -When renaming using patch file, we really want to change file names too. - -Signed-off-by: Igor Gnatenko ---- - rust2rpm/__main__.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/rust2rpm/__main__.py b/rust2rpm/__main__.py -index dc78828..1575ce6 100644 ---- a/rust2rpm/__main__.py -+++ b/rust2rpm/__main__.py -@@ -218,7 +218,7 @@ def main(): - template = JINJA_ENV.get_template("main.spec") - - if args.patch and len(diff) > 0: -- patch_file = "{}-fix-metadata.diff".format(crate) -+ patch_file = "{}-fix-metadata.diff".format(metadata.name) - else: - patch_file = None - -@@ -269,7 +269,7 @@ def main(): - kwargs["license"] = license - kwargs["license_comments"] = comments - -- spec_file = "rust-{}.spec".format(crate) -+ spec_file = "rust-{}.spec".format(metadata.name) - spec_contents = template.render(md=metadata, patch_file=patch_file, **kwargs) - if args.stdout: - print("# {}".format(spec_file)) --- -2.21.0 - diff --git a/0002-generate-doc-statements.patch b/0002-generate-doc-statements.patch deleted file mode 100644 index 7d5550b..0000000 --- a/0002-generate-doc-statements.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 561280a0ea35f226ef243526be2bbb656db44af6 Mon Sep 17 00:00:00 2001 -From: Igor Gnatenko -Date: Mon, 10 Sep 2018 23:40:18 +0200 -Subject: [PATCH 02/19] generate %doc statements - -Signed-off-by: Igor Gnatenko ---- - rust2rpm/metadata.py | 2 ++ - rust2rpm/templates/main.spec | 6 ++++++ - 2 files changed, 8 insertions(+) - -diff --git a/rust2rpm/metadata.py b/rust2rpm/metadata.py -index 5dae1d3..f52d968 100644 ---- a/rust2rpm/metadata.py -+++ b/rust2rpm/metadata.py -@@ -140,6 +140,7 @@ class Metadata(object): - self.name = None - self.license = None - self.license_file = None -+ self.readme = None - self.description = None - self.version = None - self._targets = [] -@@ -156,6 +157,7 @@ class Metadata(object): - self.name = md["name"] - 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) -diff --git a/rust2rpm/templates/main.spec b/rust2rpm/templates/main.spec -index 1aeb969..2e9f841 100644 ---- a/rust2rpm/templates/main.spec -+++ b/rust2rpm/templates/main.spec -@@ -137,6 +137,9 @@ which use %{crate} from crates.io. - {% 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 %} -@@ -147,6 +150,9 @@ which use %{crate} from crates.io. - {% 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 %} --- -2.21.0 - diff --git a/0003-do-better-for-renamed-crates.patch b/0003-do-better-for-renamed-crates.patch deleted file mode 100644 index 97d5815..0000000 --- a/0003-do-better-for-renamed-crates.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 2050880140d4953b9ebdc7211e30df3ccf5dd61d Mon Sep 17 00:00:00 2001 -From: Igor Gnatenko -Date: Tue, 11 Sep 2018 00:06:50 +0200 -Subject: [PATCH 03/19] do better for renamed crates - -Signed-off-by: Igor Gnatenko ---- - rust2rpm/__main__.py | 7 ++++--- - rust2rpm/templates/main.spec | 13 ++++++++++++- - 2 files changed, 16 insertions(+), 4 deletions(-) - -diff --git a/rust2rpm/__main__.py b/rust2rpm/__main__.py -index 1575ce6..e993e7b 100644 ---- a/rust2rpm/__main__.py -+++ b/rust2rpm/__main__.py -@@ -180,7 +180,7 @@ def make_diff_metadata(crate, version, patch=False, store=False): - diff = make_patch(toml, enabled=patch) - metadata = Metadata.from_file(toml) - if store: -- shutil.copy2(cratef, os.path.join(os.getcwd(), f"{crate}-{version}.crate")) -+ shutil.copy2(cratef, os.path.join(os.getcwd(), f"{metadata.name}-{version}.crate")) - return crate, diff, metadata - - def main(): -@@ -218,11 +218,12 @@ def main(): - template = JINJA_ENV.get_template("main.spec") - - if args.patch and len(diff) > 0: -- patch_file = "{}-fix-metadata.diff".format(metadata.name) -+ patch_file = f"{metadata.name}-fix-metadata.diff" - else: - patch_file = None - - kwargs = {} -+ kwargs["crate"] = crate - kwargs["target"] = args.target - bins = [tgt for tgt in metadata.targets if tgt.kind == "bin"] - libs = [tgt for tgt in metadata.targets if tgt.kind in ("lib", "rlib", "proc-macro")] -@@ -269,7 +270,7 @@ def main(): - kwargs["license"] = license - kwargs["license_comments"] = comments - -- spec_file = "rust-{}.spec".format(metadata.name) -+ spec_file = f"rust-{metadata.name}.spec" - spec_contents = template.render(md=metadata, patch_file=patch_file, **kwargs) - if args.stdout: - print("# {}".format(spec_file)) -diff --git a/rust2rpm/templates/main.spec b/rust2rpm/templates/main.spec -index 2e9f841..7dbcc3f 100644 ---- a/rust2rpm/templates/main.spec -+++ b/rust2rpm/templates/main.spec -@@ -6,6 +6,9 @@ - {% endif %} - - %global crate {{ md.name }} -+{% if md.name != crate %} -+%global real_crate {{ crate }} -+{% endif %} - - Name: rust-%{crate} - Version: {{ md.version }} -@@ -27,8 +30,12 @@ License: {{ license|default("# FIXME") }} - {% if license_comments is not none %} - {{ license_comments }} - {% endif %} --URL: https://crates.io/crates/{{ md.name }} -+URL: https://crates.io/crates/{{ crate }} -+{% if md.name != crate %} -+Source0: https://crates.io/api/v1/crates/%{real_crate}/%{version}/download#/%{crate}-%{version}.crate -+{% else %} - Source0: https://crates.io/api/v1/crates/%{crate}/%{version}/download#/%{crate}-%{version}.crate -+{% endif %} - {% if patch_file is not none %} - {% if target == "opensuse" %} - # PATCH-FIX-OPENSUSE {{ patch_file }} -- Initial patched metadata -@@ -118,7 +125,11 @@ which use %{crate} from crates.io. - - {% endif %} - %prep -+{% if md.name != crate %} -+%autosetup -n %{real_crate}-%{version} -p1 -+{% else %} - %autosetup -n %{crate}-%{version} -p1 -+{% endif %} - %cargo_prep - - %build --- -2.21.0 - diff --git a/0004-remove-pre-3.6-leftovers.patch b/0004-remove-pre-3.6-leftovers.patch deleted file mode 100644 index 017fb26..0000000 --- a/0004-remove-pre-3.6-leftovers.patch +++ /dev/null @@ -1,27 +0,0 @@ -From e6e9cbbb71199c2773b47fa21f1c917a167c1743 Mon Sep 17 00:00:00 2001 -From: Igor Gnatenko -Date: Tue, 11 Sep 2018 10:43:53 +0200 -Subject: [PATCH 04/19] remove pre-3.6 leftovers - -Signed-off-by: Igor Gnatenko ---- - rust2rpm/metadata.py | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/rust2rpm/metadata.py b/rust2rpm/metadata.py -index f52d968..5adeb65 100644 ---- a/rust2rpm/metadata.py -+++ b/rust2rpm/metadata.py -@@ -203,8 +203,6 @@ class Metadata(object): - - @classmethod - def from_file(cls, path): -- do_decode = sys.version_info < (3, 6) - metadata = subprocess.check_output(["cargo", "read-manifest", -- "--manifest-path={}".format(path)], -- universal_newlines=do_decode) -+ "--manifest-path={}".format(path)]) - return cls.from_json(json.loads(metadata)) --- -2.21.0 - diff --git a/0005-Remove-half-downloaded-crate-on-C.patch b/0005-Remove-half-downloaded-crate-on-C.patch deleted file mode 100644 index 033815b..0000000 --- a/0005-Remove-half-downloaded-crate-on-C.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 2f12c83d14afe71e9efed2d1be62e1e610e602e9 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= -Date: Fri, 17 Aug 2018 10:03:48 +0200 -Subject: [PATCH 05/19] Remove half-downloaded crate on ^C - -Subsequent invocations would fail with an error about a corrupted file. -We don't have support for resuming a failed download, so let's remove the -partial download results. ---- - rust2rpm/__main__.py | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/rust2rpm/__main__.py b/rust2rpm/__main__.py -index e993e7b..8e6f6eb 100644 ---- a/rust2rpm/__main__.py -+++ b/rust2rpm/__main__.py -@@ -83,6 +83,14 @@ def file_mtime(path): - t = datetime.fromtimestamp(os.stat(path).st_mtime, timezone.utc) - return t.astimezone().isoformat() - -+@contextlib.contextmanager -+def remove_on_error(path): -+ try: -+ yield -+ except: # this is supposed to include ^C -+ os.unlink(path) -+ raise -+ - def local_toml(toml, version): - if os.path.isdir(toml): - toml = os.path.join(toml, "Cargo.toml") -@@ -110,7 +118,8 @@ def download(crate, version): - req = requests.get(url, stream=True) - req.raise_for_status() - total = int(req.headers["Content-Length"]) -- with open(cratef, "wb") as f: -+ with remove_on_error(cratef), \ -+ open(cratef, "wb") as f: - for chunk in tqdm.tqdm(req.iter_content(), "Downloading {}".format(cratef_base), - total=total, unit="B", unit_scale=True): - f.write(chunk) --- -2.21.0 - diff --git a/0006-Throw-an-error-if-s-is-used-without-a-crate.patch b/0006-Throw-an-error-if-s-is-used-without-a-crate.patch deleted file mode 100644 index 861d233..0000000 --- a/0006-Throw-an-error-if-s-is-used-without-a-crate.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 5a1cde5b8dcaea74ebb2050879036bf46df63adc Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= -Date: Fri, 17 Aug 2018 10:18:59 +0200 -Subject: [PATCH 06/19] Throw an error if -s is used without a crate - -In the future we might want to be smarter and find the crate, but let's at least -not ignore the option completely. ---- - rust2rpm/__main__.py | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/rust2rpm/__main__.py b/rust2rpm/__main__.py -index 8e6f6eb..f23ebbc 100644 ---- a/rust2rpm/__main__.py -+++ b/rust2rpm/__main__.py -@@ -178,6 +178,9 @@ def make_diff_metadata(crate, version, patch=False, store=False): - if crate.endswith(".crate"): - cratef, crate, version = local_crate(crate, version) - else: -+ if store: -+ raise ValueError('--store-crate can only be used for a crate') -+ - toml, crate, version = local_toml(crate, version) - diff = make_patch(toml, enabled=patch, tmpfile=True) - metadata = Metadata.from_file(toml) --- -2.21.0 - diff --git a/0007-split-features-into-subpackages.patch b/0007-split-features-into-subpackages.patch deleted file mode 100644 index acf5911..0000000 --- a/0007-split-features-into-subpackages.patch +++ /dev/null @@ -1,1064 +0,0 @@ -From 2cac5e5ad5ff5472923ce333bef59679612bbaa2 Mon Sep 17 00:00:00 2001 -From: Igor Gnatenko -Date: Fri, 26 Oct 2018 11:20:13 +0200 -Subject: [PATCH 07/19] 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 ---- - data/cargo.attr | 4 +- - data/macros.cargo | 10 + - rust2rpm/__main__.py | 11 +- - rust2rpm/inspector.py | 22 ++- - rust2rpm/metadata.py | 317 ++++++++++++++++---------------- - rust2rpm/templates/main.spec | 142 +++++++------- - test.py | 347 ++++------------------------------- - 7 files changed, 298 insertions(+), 555 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..4929cdd 100644 ---- a/rust2rpm/metadata.py -+++ b/rust2rpm/metadata.py -@@ -1,208 +1,207 @@ - __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 "".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"" - --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 and req != "*": -+ raise NotImplementedError(f"'*' is not supported: {req}") -+ 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: -+ raise NotImplementedError(f"Pre-release requirement is not supported: {ver}") -+ if req.kind in (req.KIND_NEQ, req.KIND_EMPTY): -+ raise NotImplementedError(f"'!=' and empty kinds are not supported: {req}") - 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"" -+ -+ 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..0d9a80b 100644 ---- a/rust2rpm/templates/main.spec -+++ b/rust2rpm/templates/main.spec -@@ -48,82 +48,102 @@ 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 +163,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" %} -diff --git a/test.py b/test.py -index b856fdd..30263b4 100644 ---- a/test.py -+++ b/test.py -@@ -1,318 +1,43 @@ --import os --import shutil --import subprocess --import sys --import tempfile --import textwrap -- - import pytest - - import rust2rpm - --DUMMY_LIB = """ --pub fn say_hello() { -- println!("Hello, World!"); --} --""" --DEPGEN = os.path.join(os.path.dirname(__file__), "cargodeps.py") -- -- --@pytest.mark.parametrize("req, features, rpmdep", [ -- ("=1.0.0", [], -- "crate(test) = 1.0.0"), -- ("=1.0.0", ["feature"], -- "(crate(test) = 1.0.0 with crate(test/feature))"), -- (">=1.0.0,<2.0.0", [], -+@pytest.mark.parametrize("req, rpmdep", [ -+ ("^1.2.3", -+ "(crate(test) >= 1.2.3 with crate(test) < 2.0.0)"), -+ ("^1.2", -+ "(crate(test) >= 1.2.0 with crate(test) < 2.0.0)"), -+ ("^1", - "(crate(test) >= 1.0.0 with crate(test) < 2.0.0)"), -- (">=1.0.0,<2.0.0", ["feature"], -- "((crate(test) >= 1.0.0 with crate(test) < 2.0.0) with crate(test/feature))"), -+ ("^0.2.3", -+ "(crate(test) >= 0.2.3 with crate(test) < 0.3.0)"), -+ ("^0.2", -+ "(crate(test) >= 0.2.0 with crate(test) < 0.3.0)"), -+ ("^0.0.3", -+ "(crate(test) >= 0.0.3 with crate(test) < 0.0.4)"), -+ ("^0.0", -+ "(crate(test) >= 0.0.0 with crate(test) < 0.1.0)"), -+ ("^0", -+ "(crate(test) >= 0.0.0 with crate(test) < 1.0.0)"), -+ ("~1.2.3", -+ "(crate(test) >= 1.2.3 with crate(test) < 1.3.0)"), -+ ("~1.2", -+ "(crate(test) >= 1.2.0 with crate(test) < 1.3.0)"), -+ ("~1", -+ "(crate(test) >= 1.0.0 with crate(test) < 2.0.0)"), -+ ("*", -+ "crate(test)"), -+ (">= 1.2.0", -+ "crate(test) >= 1.2.0"), -+ ("> 1", -+ "crate(test) > 1.0.0"), -+ ("< 2", -+ "crate(test) < 2.0.0"), -+ ("= 1.2.3", -+ "crate(test) = 1.2.3"), -+ (">= 1.2, < 1.5", -+ "(crate(test) >= 1.2.0 with crate(test) < 1.5.0)"), - ]) --def test_dependency(req, features, rpmdep): -- dep = rust2rpm.Dependency("test", req, features) -+def test_dependency(req, rpmdep): -+ dep = rust2rpm.Dependency("test", req) - assert str(dep) == rpmdep -- --@pytest.fixture --def cargo_toml(request): -- def make_cargo_toml(contents): -- toml = os.path.join(tmpdir, "Cargo.toml") -- with open(toml, "w") as fobj: -- fobj.write(textwrap.dedent(contents)) -- return toml -- -- tmpdir = tempfile.mkdtemp(prefix="cargo-deps-") -- srcdir = os.path.join(tmpdir, "src") -- os.mkdir(srcdir) -- with open(os.path.join(srcdir, "lib.rs"), "w") as fobj: -- fobj.write(DUMMY_LIB) -- -- def finalize(): -- shutil.rmtree(tmpdir) -- request.addfinalizer(finalize) -- -- return make_cargo_toml -- --@pytest.mark.parametrize("toml, provides, requires", [ -- -- # Basic provides -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- """, -- ["crate(hello) = 0.0.0"], -- []), -- -- # Basic provides for feature -- (""" -- [package] -- name = "hello" -- version = "1.2.3" -- -- [features] -- color = [] -- """, -- ["crate(hello) = 1.2.3", -- "crate(hello/color) = 1.2.3"], -- []), -- -- # Provides for optional dependencies -- (""" -- [package] -- name = "hello" -- version = "1.2.3" -- -- [dependencies] -- non_optional = "1" -- serde = { version = "1", optional = true } -- rand = { version = "0.4", optional = true } -- -- [features] -- std = [] -- v1 = ["rand"] -- """, -- ["crate(hello) = 1.2.3", -- "crate(hello/rand) = 1.2.3", -- "crate(hello/serde) = 1.2.3", -- "crate(hello/std) = 1.2.3", -- "crate(hello/v1) = 1.2.3"], -- ["(crate(non_optional) >= 1.0.0 with crate(non_optional) < 2.0.0)", -- "(crate(rand) >= 0.4.0 with crate(rand) < 0.5.0)", -- "(crate(serde) >= 1.0.0 with crate(serde) < 2.0.0)"]), -- -- # Caret requirements -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "^0" -- """, -- ["crate(hello) = 0.0.0"], -- ["(crate(libc) >= 0.0.0 with crate(libc) < 1.0.0)"]), -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "^0.0" -- """, -- ["crate(hello) = 0.0.0"], -- ["(crate(libc) >= 0.0.0 with crate(libc) < 0.1.0)"]), -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "^0.0.3" -- """, -- ["crate(hello) = 0.0.0"], -- ["(crate(libc) >= 0.0.3 with crate(libc) < 0.0.4)"]), -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "^0.2.3" -- """, -- ["crate(hello) = 0.0.0"], -- ["(crate(libc) >= 0.2.3 with crate(libc) < 0.3.0)"]), -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "^1" -- """, -- ["crate(hello) = 0.0.0"], -- ["(crate(libc) >= 1.0.0 with crate(libc) < 2.0.0)"]), -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "^1.2" -- """, -- ["crate(hello) = 0.0.0"], -- ["(crate(libc) >= 1.2.0 with crate(libc) < 2.0.0)"]), -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "^1.2.3" -- """, -- ["crate(hello) = 0.0.0"], -- ["(crate(libc) >= 1.2.3 with crate(libc) < 2.0.0)"]), -- -- # Tilde requirements -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "~1" -- """, -- ["crate(hello) = 0.0.0"], -- ["(crate(libc) >= 1.0.0 with crate(libc) < 2.0.0)"]), -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "~1.2" -- """, -- ["crate(hello) = 0.0.0"], -- ["(crate(libc) >= 1.2.0 with crate(libc) < 1.3.0)"]), -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "~1.2.3" -- """, -- ["crate(hello) = 0.0.0"], -- ["(crate(libc) >= 1.2.3 with crate(libc) < 1.3.0)"]), -- -- # Wildcard requirements -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "*" -- """, -- ["crate(hello) = 0.0.0"], -- ["crate(libc)"]), -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "1.*" -- """, -- ["crate(hello) = 0.0.0"], -- ["(crate(libc) >= 1.0.0 with crate(libc) < 2.0.0)"]), -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "1.2.*" -- """, -- ["crate(hello) = 0.0.0"], -- ["(crate(libc) >= 1.2.0 with crate(libc) < 1.3.0)"]), -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "1.*.*" -- """, -- ["crate(hello) = 0.0.0"], -- ["(crate(libc) >= 1.0.0 with crate(libc) < 2.0.0)"]), -- -- # Inequality requirements -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = ">= 1.2.0" -- """, -- ["crate(hello) = 0.0.0"], -- ["crate(libc) >= 1.2.0"]), -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "> 1" -- """, -- ["crate(hello) = 0.0.0"], -- ["crate(libc) > 1.0.0"]), -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "< 2" -- """, -- ["crate(hello) = 0.0.0"], -- ["crate(libc) < 2.0.0"]), -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = "= 1.2.3" -- """, -- ["crate(hello) = 0.0.0"], -- ["crate(libc) = 1.2.3"]), -- -- # Multiple requirements -- (""" -- [package] -- name = "hello" -- version = "0.0.0" -- -- [dependencies] -- libc = ">= 1.2, < 1.5" -- """, -- ["crate(hello) = 0.0.0"], -- ["(crate(libc) >= 1.2.0 with crate(libc) < 1.5.0)"]), -- -- # Pre-release requirements -- (""" -- [package] -- name = "hello" -- version = "0.0.0-alpha" -- -- [dependencies] -- foo-bar = "1.2.3-beta" -- """, -- ["crate(hello) = 0.0.0~alpha"], -- ["(crate(foo-bar) >= 1.2.3~beta with crate(foo-bar) < 1.2.3)"]), -- --]) --def test_depgen(toml, provides, requires, cargo_toml): -- md = rust2rpm.Metadata.from_file(cargo_toml(toml)) -- assert [str(x) for x in md.provides] == provides -- assert [str(x) for x in md.requires] == requires --- -2.21.0 - diff --git a/0008-add-support-for-dependencies-with-same-name.patch b/0008-add-support-for-dependencies-with-same-name.patch deleted file mode 100644 index 5412d76..0000000 --- a/0008-add-support-for-dependencies-with-same-name.patch +++ /dev/null @@ -1,74 +0,0 @@ -From a1d3a84645aa7bbe5ca07b60bead1ddf90a21cc1 Mon Sep 17 00:00:00 2001 -From: Igor Gnatenko -Date: Tue, 30 Oct 2018 20:37:38 +0100 -Subject: [PATCH 08/19] add support for dependencies with same name - -Reported-by: Josh Stone -References: https://internals.rust-lang.org/t/optional-dependencies-with-same-name/8728 -Signed-off-by: Igor Gnatenko ---- - rust2rpm/metadata.py | 32 ++++++++++++++++++++------------ - 1 file changed, 20 insertions(+), 12 deletions(-) - -diff --git a/rust2rpm/metadata.py b/rust2rpm/metadata.py -index 4929cdd..328b67a 100644 ---- a/rust2rpm/metadata.py -+++ b/rust2rpm/metadata.py -@@ -1,5 +1,6 @@ - __all__ = ["Dependency", "Metadata"] - -+import collections - import copy - import json - import subprocess -@@ -126,9 +127,11 @@ class Metadata: - self.description = md.get("description") - - # dependencies + build-dependencies → runtime -- deps_by_name = {dep["name"]: Dependency.from_json(dep) -- for dep in md["dependencies"] -- if dep["kind"] != "dev"} -+ deps_by_name = collections.defaultdict(list) -+ for dep in md["dependencies"]: -+ if dep["kind"] == "dev": -+ continue -+ deps_by_name[dep["name"]].append(Dependency.from_json(dep)) - - deps_by_feature = {} - for feature, f_deps in md["features"].items(): -@@ -139,18 +142,23 @@ class Metadata: - features.add(dep) - else: - pkg, _, f = dep.partition("/") -- dep = copy.deepcopy(deps_by_name[pkg]) -- if f: -- dep.features = {f} -- deps.add(dep) -+ for dep in deps_by_name[pkg]: -+ dep = copy.deepcopy(dep) -+ 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: -- mandatory_deps.add(copy.deepcopy(dep)) -+ for name, deps in deps_by_name.items(): -+ fdeps = set() -+ for dep in deps: -+ if dep.optional: -+ fdeps.add(copy.deepcopy(dep)) -+ else: -+ mandatory_deps.add(copy.deepcopy(dep)) -+ if fdeps: -+ deps_by_feature[name] = ({None}, fdeps) - deps_by_feature[None] = (set(), mandatory_deps) - - if "default" not in deps_by_feature: --- -2.21.0 - diff --git a/0009-add-support-for-feeding-user-configuration.patch b/0009-add-support-for-feeding-user-configuration.patch deleted file mode 100644 index 8985513..0000000 --- a/0009-add-support-for-feeding-user-configuration.patch +++ /dev/null @@ -1,148 +0,0 @@ -From 197150ee2e862edcd46f7ab02c9e4d17e49ca75d Mon Sep 17 00:00:00 2001 -From: Igor Gnatenko -Date: Wed, 31 Oct 2018 18:03:21 +0100 -Subject: [PATCH 09/19] add support for feeding user configuration - -Signed-off-by: Igor Gnatenko ---- - README.md | 26 ++++++++++++++++++++++++++ - README.rst | 5 ----- - rust2rpm/__main__.py | 13 +++++++++++++ - rust2rpm/templates/main.spec | 17 ++++++++++++++++- - 4 files changed, 55 insertions(+), 6 deletions(-) - create mode 100644 README.md - delete mode 100644 README.rst - -diff --git a/README.md b/README.md -new file mode 100644 -index 0000000..22b4b30 ---- /dev/null -+++ b/README.md -@@ -0,0 +1,26 @@ -+# rust2rpm -+ -+Convert Rust crates to RPM. -+ -+## `.rust2rpm.conf` -+ -+You can place configuration file which is used as source for additional -+information for spec generation. -+ -+Some simple example would be better than many words ;) -+ -+```ini -+[DEFAULT] -+buildrequires = -+ pkgconfig(foo) >= 1.2.3 -+lib.requires = -+ pkgconfig(foo) >= 1.2.3 -+ -+[fedora] -+bin.requires = -+ findutils -+buildrequires = -+lib.requires = -+lib+default.requires = -+ pkgconfig(bar) >= 2.0.0 -+``` -diff --git a/README.rst b/README.rst -deleted file mode 100644 -index 8866027..0000000 ---- a/README.rst -+++ /dev/null -@@ -1,5 +0,0 @@ --======== --rust2rpm --======== -- --Convert Rust crates to RPM. -diff --git a/rust2rpm/__main__.py b/rust2rpm/__main__.py -index d19cb47..c691274 100644 ---- a/rust2rpm/__main__.py -+++ b/rust2rpm/__main__.py -@@ -199,6 +199,11 @@ def make_diff_metadata(crate, version, patch=False, store=False): - shutil.copy2(cratef, os.path.join(os.getcwd(), f"{metadata.name}-{version}.crate")) - return crate, diff, metadata - -+def to_list(s): -+ if not s: -+ return [] -+ return list(filter(None, (l.strip() for l in s.splitlines()))) -+ - def main(): - parser = argparse.ArgumentParser("rust2rpm", - formatter_class=argparse.RawTextHelpFormatter) -@@ -232,6 +237,7 @@ def main(): - store=args.store_crate) - - JINJA_ENV.globals["normalize_deps"] = normalize_deps -+ JINJA_ENV.globals["to_list"] = to_list - template = JINJA_ENV.get_template("main.spec") - - if args.patch and len(diff) > 0: -@@ -287,6 +293,13 @@ def main(): - kwargs["license"] = license - kwargs["license_comments"] = comments - -+ conf = configparser.ConfigParser(interpolation=configparser.ExtendedInterpolation()) -+ conf.read(".rust2rpm.conf") -+ if args.target not in conf: -+ conf.add_section(args.target) -+ -+ kwargs["distconf"] = conf[args.target] -+ - spec_file = f"rust-{metadata.name}.spec" - spec_contents = template.render(md=metadata, patch_file=patch_file, **kwargs) - if args.stdout: -diff --git a/rust2rpm/templates/main.spec b/rust2rpm/templates/main.spec -index 0d9a80b..d901e6d 100644 ---- a/rust2rpm/templates/main.spec -+++ b/rust2rpm/templates/main.spec -@@ -65,6 +65,9 @@ BuildRequires: {{ req }} - {% endfor %} - %endif - {% endif %} -+{% for req in to_list(distconf.get("buildrequires"))|sort %} -+BuildRequires: {{ req }} -+{% endfor %} - - %global _description \ - {% if md.description is none %} -@@ -81,6 +84,9 @@ Summary: %{summary} - {% if rust_group is defined %} - Group: # FIXME - {% endif %} -+ {% for req in to_list(distconf.get("bin.requires"))|sort %} -+Requires: {{ req }} -+ {% endfor %} - - %description -n %{crate} - %{summary}. -@@ -106,7 +112,13 @@ Group: # FIXME - {% 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" %} -+ {% if feature is none %} -+ {% set pkg = " devel" %} -+ {% set conf_prefix = "lib" %} -+ {% else %} -+ {% set pkg = "-n %%{name}+%s-devel"|format(feature) %} -+ {% set conf_prefix = "lib+%s"|format(feature) %} -+ {% endif %} - %package {{ pkg }} - Summary: %{summary} - {% if rust_group is defined %} -@@ -122,6 +134,9 @@ Requires: cargo - Requires: {{ req }} - {% endfor %} - {% endif %} -+ {% for req in to_list(distconf.get("%s.requires"|format(conf_prefix)))|sort %} -+Requires: {{ req }} -+ {% endfor %} - - %description {{ pkg }} %{_description} - --- -2.21.0 - diff --git a/0010-trivial-use-f-strings-everywhere.patch b/0010-trivial-use-f-strings-everywhere.patch deleted file mode 100644 index c98be77..0000000 --- a/0010-trivial-use-f-strings-everywhere.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 83ea3796cd28ec7689b39e7dc7a70bd11af1abf1 Mon Sep 17 00:00:00 2001 -From: Igor Gnatenko -Date: Wed, 31 Oct 2018 17:00:58 +0100 -Subject: [PATCH 10/19] trivial: use f-strings everywhere - -Signed-off-by: Igor Gnatenko ---- - rust2rpm/__main__.py | 22 +++++++++++----------- - 1 file changed, 11 insertions(+), 11 deletions(-) - -diff --git a/rust2rpm/__main__.py b/rust2rpm/__main__.py -index c691274..b60e6c4 100644 ---- a/rust2rpm/__main__.py -+++ b/rust2rpm/__main__.py -@@ -79,7 +79,7 @@ def detect_packager(): - if git is not None: - name = subprocess.check_output([git, "config", "user.name"], universal_newlines=True).strip() - email = subprocess.check_output([git, "config", "user.email"], universal_newlines=True).strip() -- return "{} <{}>".format(name, email) -+ return f"{name} <{email}>" - - return None - -@@ -108,23 +108,23 @@ def local_crate(crate, version): - def download(crate, version): - if version is None: - # Now we need to get latest version -- url = requests.compat.urljoin(API_URL, "crates/{}/versions".format(crate)) -+ url = requests.compat.urljoin(API_URL, f"crates/{crate}/versions") - req = requests.get(url) - req.raise_for_status() - versions = req.json()["versions"] - version = next(version["num"] for version in versions if not version["yanked"]) - - os.makedirs(CACHEDIR, exist_ok=True) -- cratef_base = "{}-{}.crate".format(crate, version) -+ cratef_base = f"{crate}-{version}.crate" - cratef = os.path.join(CACHEDIR, cratef_base) - if not os.path.isfile(cratef): -- url = requests.compat.urljoin(API_URL, "crates/{}/{}/download#".format(crate, version)) -+ url = requests.compat.urljoin(API_URL, f"crates/{crate}/{version}/download#") - req = requests.get(url, stream=True) - req.raise_for_status() - total = int(req.headers["Content-Length"]) - with remove_on_error(cratef), \ - open(cratef, "wb") as f: -- for chunk in tqdm.tqdm(req.iter_content(), "Downloading {}".format(cratef_base), -+ for chunk in tqdm.tqdm(req.iter_content(), f"Downloading {cratef_base}".format(cratef_base), - total=total, unit="B", unit_scale=True): - f.write(chunk) - return cratef, crate, version -@@ -132,14 +132,14 @@ def download(crate, version): - @contextlib.contextmanager - def toml_from_crate(cratef, crate, version): - with tempfile.TemporaryDirectory() as tmpdir: -- target_dir = "{}/".format(tmpdir) -+ target_dir = f"{tmpdir}/" - with tarfile.open(cratef, "r") as archive: - for n in archive.getnames(): - if not os.path.abspath(os.path.join(target_dir, n)).startswith(target_dir): - raise Exception("Unsafe filenames!") - archive.extractall(target_dir) -- toml_relpath = "{}-{}/Cargo.toml".format(crate, version) -- toml = "{}/{}".format(tmpdir, toml_relpath) -+ toml_relpath = f"{crate}-{version}/Cargo.toml" -+ toml = f"{tmpdir}/{toml_relpath}" - if not os.path.isfile(toml): - raise IOError("crate does not contain Cargo.toml file") - yield toml -@@ -270,7 +270,7 @@ def main(): - kwargs["include_provides"] = True - kwargs["include_requires"] = True - else: -- assert False, "Unknown target {!r}".format(args.target) -+ assert False, f"Unknown target {args.target!r}" - - if args.target == "mageia": - kwargs["pkg_release"] = "%mkrel 1" -@@ -303,10 +303,10 @@ def main(): - spec_file = f"rust-{metadata.name}.spec" - spec_contents = template.render(md=metadata, patch_file=patch_file, **kwargs) - if args.stdout: -- print("# {}".format(spec_file)) -+ print(f"# {spec_file}") - print(spec_contents) - if patch_file is not None: -- print("# {}".format(patch_file)) -+ print(f"# {patch_file}") - print("".join(diff), end="") - else: - with open(spec_file, "w") as fobj: --- -2.21.0 - diff --git a/0011-Add-option-to-not-generate-a-default-changelog-entry.patch b/0011-Add-option-to-not-generate-a-default-changelog-entry.patch deleted file mode 100644 index 8457b4a..0000000 --- a/0011-Add-option-to-not-generate-a-default-changelog-entry.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 294c6f571c0f4f7ed5a4fcb34142b0d332c55f29 Mon Sep 17 00:00:00 2001 -From: Neal Gompa -Date: Sun, 11 Nov 2018 11:06:27 -0500 -Subject: [PATCH 11/19] Add option to not generate a default changelog entry - -For Rust packages created through the OBS source service, the -changelog is managed by an external .changes file that is -transformed into an RPM changelog and appended to the spec file -automatically by the Open Build Service. - -Having a default entry means that the changelog handling will not -always work correctly and package builds may fail due to changelog -entries not being in reverse chronological order. - -This also is a future enabler for other workflows for external -changelog management in automated package builds. - -Signed-off-by: Neal Gompa ---- - rust2rpm/__main__.py | 7 +++++++ - rust2rpm/templates/main.spec | 4 +++- - 2 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/rust2rpm/__main__.py b/rust2rpm/__main__.py -index b60e6c4..747328e 100644 ---- a/rust2rpm/__main__.py -+++ b/rust2rpm/__main__.py -@@ -209,6 +209,8 @@ def main(): - formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument("--show-license-map", action="store_true", - help="Print license mappings and exit") -+ parser.add_argument("--no-auto-changelog-entry", action="store_true", -+ help="Do not generate a changelog entry") - parser.add_argument("-", "--stdout", action="store_true", - help="Print spec and patches into stdout") - parser.add_argument("-t", "--target", action="store", -@@ -261,6 +263,11 @@ def main(): - raise ValueError("No bins and no libs") - kwargs["include_devel"] = is_lib - -+ if args.no_auto_changelog_entry: -+ kwargs["auto_changelog_entry"] = False -+ else: -+ kwargs["auto_changelog_entry"] = True -+ - if args.target in ("fedora", "mageia", "opensuse"): - kwargs["include_build_requires"] = True - kwargs["include_provides"] = False -diff --git a/rust2rpm/templates/main.spec b/rust2rpm/templates/main.spec -index d901e6d..84bd97d 100644 ---- a/rust2rpm/templates/main.spec -+++ b/rust2rpm/templates/main.spec -@@ -179,4 +179,6 @@ which use {% if feature is not none %}"{{ feature }}" feature of {% endif %}"%{c - %endif - - %changelog --{% include target ~ "-changelog.spec.inc" %} -+{% if auto_changelog_entry %} -+ {% include target ~ "-changelog.spec.inc" %} -+{% endif %} --- -2.21.0 - diff --git a/0012-Set-CARGO_HOME-to-the-local-.config.patch b/0012-Set-CARGO_HOME-to-the-local-.config.patch deleted file mode 100644 index e9e37de..0000000 --- a/0012-Set-CARGO_HOME-to-the-local-.config.patch +++ /dev/null @@ -1,26 +0,0 @@ -From b4e25038296cd57eba639a059e8baaf139a5d287 Mon Sep 17 00:00:00 2001 -From: Josh Stone -Date: Fri, 7 Dec 2018 13:58:41 -0800 -Subject: [PATCH 12/19] Set CARGO_HOME to the local .config - ---- - data/macros.cargo | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/data/macros.cargo b/data/macros.cargo -index 7fb025b..e760721 100644 ---- a/data/macros.cargo -+++ b/data/macros.cargo -@@ -1,4 +1,8 @@ --%__cargo %{_bindir}/cargo -+# Since cargo 1.31, install only uses $CARGO_HOME/config, ignoring $PWD. -+# https://github.com/rust-lang/cargo/issues/6397 -+# But we can set CARGO_HOME locally, which is a good idea anyway to make sure -+# it never writes to ~/.cargo during rpmbuild. -+%__cargo %{_bindir}/env CARGO_HOME=.cargo %{_bindir}/cargo - %__cargo_common_opts %{?_smp_mflags} - %__cargo_inspector %{_bindir}/cargo-inspector - --- -2.21.0 - diff --git a/0013-Set-the-install-root-in-.cargo-config.patch b/0013-Set-the-install-root-in-.cargo-config.patch deleted file mode 100644 index 0b97943..0000000 --- a/0013-Set-the-install-root-in-.cargo-config.patch +++ /dev/null @@ -1,34 +0,0 @@ -From a04e95bc4f807139bd3c4b75f46fd9a60ec1db8f Mon Sep 17 00:00:00 2001 -From: Josh Stone -Date: Fri, 7 Dec 2018 13:59:03 -0800 -Subject: [PATCH 13/19] Set the install root in .cargo/config - ---- - data/macros.cargo | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/data/macros.cargo b/data/macros.cargo -index e760721..9a9ce6a 100644 ---- a/data/macros.cargo -+++ b/data/macros.cargo -@@ -20,6 +20,9 @@ rustc = "%{__rustc}"\ - rustdoc = "%{__rustdoc}"\ - rustflags = %{__global_rustflags_toml}\ - \ -+[install]\ -+root = "%{buildroot}%{_prefix}"\ -+\ - [term]\ - verbose = true\ - \ -@@ -81,7 +84,6 @@ if %__cargo_is_bin; then \ - %{shrink:%{__cargo} install \ - %{__cargo_common_opts} \ - --path . \ -- --root %{buildroot}%{_prefix} \ - %{__cargo_parse_opts %{-n} %{-a} %{-f:-f%{-f*}}} \ - %* \ - }\ --- -2.21.0 - diff --git a/0014-licensing-fix-zlib-license-translation.patch b/0014-licensing-fix-zlib-license-translation.patch deleted file mode 100644 index a04f0db..0000000 --- a/0014-licensing-fix-zlib-license-translation.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 7c00b0f29085166b1a89aec766945b10dc7aca23 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= -Date: Sat, 1 Dec 2018 15:40:08 +0100 -Subject: [PATCH 14/19] licensing: fix zlib license translation - -The file was mangled, and something about "teeworlds" was inserted -into the line for zlib. The spdx database doesn't list "teeworlds -license", so let's just remove that part. -Both [1] and [2] agree that "zlib" and "zlib license" are the same thing. - -[1] https://spdx.org/licenses/Zlib -[2] https://fedoraproject.org/wiki/Licensing:Main#Good_Licenses - -Fixes #61. ---- - rust2rpm/spdx_to_fedora.csv | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/rust2rpm/spdx_to_fedora.csv b/rust2rpm/spdx_to_fedora.csv -index 829571a..1ca5a7e 100644 ---- a/rust2rpm/spdx_to_fedora.csv -+++ b/rust2rpm/spdx_to_fedora.csv -@@ -306,8 +306,7 @@ Zed License,Zed,Zed,,, - Zend License v2.0,Zend-2.0,Zend,,, - Zimbra Public License v1.3,Zimbra-1.3,,,Fedora bad list, - Zimbra Public License v1.4,Zimbra-1.4,,,not on Fedora list, --zlib License,Zlib,"zlib --Teeworlds",,,Teeworlds License -+zlib License,Zlib,zlib,,, - zlib/libpng License with Acknowledgement,zlib-acknowledgement,zlib with acknowledgement,,, - Zope Public License 1.1,ZPL-1.1,,,This specific version not on Fedora list, - Zope Public License 2.0,ZPL-2.0,ZPLv2.0,,, --- -2.21.0 - diff --git a/0015-licensing-rename-EPL-to-EPL-1.0-and-add-EPL-2.0.patch b/0015-licensing-rename-EPL-to-EPL-1.0-and-add-EPL-2.0.patch deleted file mode 100644 index ffe83aa..0000000 --- a/0015-licensing-rename-EPL-to-EPL-1.0-and-add-EPL-2.0.patch +++ /dev/null @@ -1,31 +0,0 @@ -From b0d2756917b380a5d66d2407dbeb8891c51875e8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= -Date: Sat, 1 Dec 2018 15:46:08 +0100 -Subject: [PATCH 15/19] licensing: rename EPL to EPL-1.0 and add EPL-2.0 - -According to https://fedoraproject.org/wiki/Licensing:Main#Software_License_List -EPL-1.0 and EPL-2.0 are the short tags that should be used now. -(C.f. https://spdx.org/licenses/EPL-2.0.html.) - -Fixes #64. ---- - rust2rpm/spdx_to_fedora.csv | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/rust2rpm/spdx_to_fedora.csv b/rust2rpm/spdx_to_fedora.csv -index 1ca5a7e..c42e66e 100644 ---- a/rust2rpm/spdx_to_fedora.csv -+++ b/rust2rpm/spdx_to_fedora.csv -@@ -112,7 +112,8 @@ DOC License,DOC,DOC,,, - Dotseqn License,Dotseqn,Dotseqn,,, - DSDP License,DSDP,DSDP,,, - dvipdfm License,dvipdfm,dvipdfm,,, --Eclipse Public License 1.0,EPL-1.0,EPL,,, -+Eclipse Public License 1.0,EPL-1.0,EPL-1.0,,, -+Eclipse Public License 2.0,EPL-2.0,EPL-2.0,,, - Educational Community License v1.0,ECL-1.0,ECL 1.0,,, - Educational Community License v2.0,ECL-2.0,ECL 2.0,,, - eGenix.com Public License 1.1.0,eGenix,eGenix,,, --- -2.21.0 - diff --git a/0016-Add-support-for-prerelease-versions.patch b/0016-Add-support-for-prerelease-versions.patch deleted file mode 100644 index cbffd10..0000000 --- a/0016-Add-support-for-prerelease-versions.patch +++ /dev/null @@ -1,160 +0,0 @@ -From 00c0c5cec90d5d6abbfd4acb2f5d65439b4bfd27 Mon Sep 17 00:00:00 2001 -From: Igor Gnatenko -Date: Sat, 26 Jan 2019 08:33:37 +0100 -Subject: [PATCH 16/19] Add support for prerelease versions - -Signed-off-by: Igor Gnatenko ---- - data/macros.rust-srpm | 38 ++++++++++++++++++++++++++++++++++++ - rust2rpm/metadata.py | 18 +++++++++++------ - rust2rpm/templates/main.spec | 10 +++------- - test.py | 8 ++++++++ - 4 files changed, 61 insertions(+), 13 deletions(-) - -diff --git a/data/macros.rust-srpm b/data/macros.rust-srpm -index f2bae9d..872b87f 100644 ---- a/data/macros.rust-srpm -+++ b/data/macros.rust-srpm -@@ -1 +1,39 @@ - %rust_arches x86_64 i686 armv7hl aarch64 ppc64 ppc64le s390x -+%version_no_tilde() %{lua: -+ local sep = rpm.expand('%1') -+ local ver = rpm.expand('%2') -+\ -+ if sep == '%1' then -+ sep = '-' -+ end -+\ -+ if ver == '%2' then -+ ver = rpm.expand('%version') -+ end -+ ver = ver:gsub('~', sep) -+\ -+ print(ver) -+} -+%__crates_url https://crates.io/api/v1/crates/ -+%crates_source() %{lua: -+ local crate = rpm.expand('%1') -+ local version = rpm.expand('%2') -+ local url = rpm.expand('%__crates_url') -+\ -+ if crate == '%1' then -+ crate = rpm.expand('%real_crate') -+ end -+ if crate == '%real_crate' then -+ crate = rpm.expand('%crate') -+ end -+ if crate == '%crate' then -+ crate = rpm.expand('%name') -+ end -+\ -+ if version == '%2' then -+ version = rpm.expand('%version') -+ end -+ version = version:gsub('~', '-') -+\ -+ print(url .. crate .. '/' .. version .. '/download#/' .. crate .. '-' .. version .. '.crate') -+} -diff --git a/rust2rpm/metadata.py b/rust2rpm/metadata.py -index 328b67a..f0718d5 100644 ---- a/rust2rpm/metadata.py -+++ b/rust2rpm/metadata.py -@@ -45,11 +45,13 @@ class Dependency: - # Any means any - continue - ver = req.spec -- if ver.prerelease: -- raise NotImplementedError(f"Pre-release requirement is not supported: {ver}") - if req.kind in (req.KIND_NEQ, req.KIND_EMPTY): - raise NotImplementedError(f"'!=' and empty kinds are not supported: {req}") -- coerced = semver.Version.coerce(str(ver)) -+ coerced = str(semver.Version.coerce(str(ver))) -+ if ver.prerelease: -+ coerced = coerced.replace("-", "~") -+ # This will advance us to closest stable version (2.0.0-beta.6 → 2.0.0) -+ ver = ver.next_patch() - if req.kind == req.KIND_EQUAL: - req.kind = req.KIND_SHORTEQ - if req.kind in (req.KIND_CARET, req.KIND_COMPATIBLE): -@@ -107,7 +109,11 @@ class Dependency: - class Metadata: - def __init__(self, name, version): - self.name = name -- self.version = version -+ self._version = version -+ version_normalized = Dependency._normalize_req(f"={self._version}") -+ if len(version_normalized) != 1: -+ raise Exception(f"Incorrect version: {self._version}") -+ self.version = version_normalized[0][1] - self.license = None - self.license_file = None - self.readme = None -@@ -187,7 +193,7 @@ class Metadata: - 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}) -+ return Dependency(self.name, f"={self._version}", features={feature}) - - @classmethod - def _resolve(cls, deps_by_feature, feature): -@@ -207,7 +213,7 @@ class Metadata: - return self._resolve(self.dependencies, feature)[1] - else: - features, deps = self.dependencies[feature] -- fdeps = set(Dependency(self.name, f"={self.version}", features={feature}) -+ fdeps = set(Dependency(self.name, f"={self._version}", features={feature}) - for feature in features) - return fdeps | deps - -diff --git a/rust2rpm/templates/main.spec b/rust2rpm/templates/main.spec -index 84bd97d..1ebef7b 100644 ---- a/rust2rpm/templates/main.spec -+++ b/rust2rpm/templates/main.spec -@@ -31,11 +31,7 @@ License: {{ license|default("# FIXME") }} - {{ license_comments }} - {% endif %} - URL: https://crates.io/crates/{{ crate }} --{% if md.name != crate %} --Source0: https://crates.io/api/v1/crates/%{real_crate}/%{version}/download#/%{crate}-%{version}.crate --{% else %} --Source0: https://crates.io/api/v1/crates/%{crate}/%{version}/download#/%{crate}-%{version}.crate --{% endif %} -+Source: %{crates_source} - {% if patch_file is not none %} - {% if target == "opensuse" %} - # PATCH-FIX-OPENSUSE {{ patch_file }} -- Initial patched metadata -@@ -161,9 +157,9 @@ which use {% if feature is not none %}"{{ feature }}" feature of {% endif %}"%{c - - %prep - {% if md.name != crate %} --%autosetup -n %{real_crate}-%{version} -p1 -+%autosetup -n %{real_crate}-%{version_no_tilde} -p1 - {% else %} --%autosetup -n %{crate}-%{version} -p1 -+%autosetup -n %{crate}-%{version_no_tilde} -p1 - {% endif %} - %cargo_prep - -diff --git a/test.py b/test.py -index 30263b4..035df79 100644 ---- a/test.py -+++ b/test.py -@@ -37,6 +37,14 @@ import rust2rpm - "crate(test) = 1.2.3"), - (">= 1.2, < 1.5", - "(crate(test) >= 1.2.0 with crate(test) < 1.5.0)"), -+ ("^2.0.0-alpha.6", -+ "(crate(test) >= 2.0.0~alpha.6 with crate(test) < 3.0.0)"), -+ ("^0.1.0-alpha.6", -+ "(crate(test) >= 0.1.0~alpha.6 with crate(test) < 0.2.0)"), -+ ("^0.0.1-alpha.6", -+ "(crate(test) >= 0.0.1~alpha.6 with crate(test) < 0.0.2)"), -+ ("^0.0.0-alpha.6", -+ "(crate(test) >= 0.0.0~alpha.6 with crate(test) < 0.0.1)"), - ]) - def test_dependency(req, rpmdep): - dep = rust2rpm.Dependency("test", req) --- -2.21.0 - diff --git a/0017-data-Cargo-doesn-t-escape-paths-with-space.patch b/0017-data-Cargo-doesn-t-escape-paths-with-space.patch deleted file mode 100644 index 0d031b0..0000000 --- a/0017-data-Cargo-doesn-t-escape-paths-with-space.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 84a73bfa24ce11602a1f19554dc495125be4d0aa Mon Sep 17 00:00:00 2001 -From: Igor Gnatenko -Date: Sun, 17 Feb 2019 17:19:25 +0100 -Subject: [PATCH 17/19] data: Cargo doesn't escape paths with space - -When building matrixmultiply v0.2.2: - -BUILDSTDERR: /usr/bin/cp: cannot stat 'spare': No such file or directory -BUILDSTDERR: /usr/bin/cp: failed to get attributes of 'kernels': No such file or directory - -Signed-off-by: Igor Gnatenko ---- - data/macros.cargo | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/data/macros.cargo b/data/macros.cargo -index 9a9ce6a..9a375d0 100644 ---- a/data/macros.cargo -+++ b/data/macros.cargo -@@ -74,7 +74,7 @@ if %__cargo_is_lib; then \ - CRATE_VERSION=$(%__cargo_inspector --version Cargo.toml) \ - REG_DIR=%{buildroot}%{cargo_registry}/$CRATE_NAME-$CRATE_VERSION \ - %{__mkdir} -p $REG_DIR \ -- %{__cargo} package -l | xargs %{__cp} --parents -a -t $REG_DIR \ -+ %{__cargo} package -l | xargs -d '\n' %{__cp} --parents -a -t $REG_DIR \ - %if ! %{with check} \ - %{__cp} -a Cargo.toml.orig $REG_DIR/Cargo.toml \ - %endif \ --- -2.21.0 - diff --git a/0018-data-Escape-n-properly.patch b/0018-data-Escape-n-properly.patch deleted file mode 100644 index c9bffdf..0000000 --- a/0018-data-Escape-n-properly.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 7f0a499ff3fca046869ab754151ae068903c4ab9 Mon Sep 17 00:00:00 2001 -From: Igor Gnatenko -Date: Sun, 10 Mar 2019 10:14:28 +0100 -Subject: [PATCH 18/19] data: Escape `\n` properly - -Signed-off-by: Igor Gnatenko ---- - data/macros.cargo | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/data/macros.cargo b/data/macros.cargo -index 9a375d0..96dc354 100644 ---- a/data/macros.cargo -+++ b/data/macros.cargo -@@ -74,7 +74,7 @@ if %__cargo_is_lib; then \ - CRATE_VERSION=$(%__cargo_inspector --version Cargo.toml) \ - REG_DIR=%{buildroot}%{cargo_registry}/$CRATE_NAME-$CRATE_VERSION \ - %{__mkdir} -p $REG_DIR \ -- %{__cargo} package -l | xargs -d '\n' %{__cp} --parents -a -t $REG_DIR \ -+ %{__cargo} package -l | xargs -d '\\\n' %{__cp} --parents -a -t $REG_DIR \ - %if ! %{with check} \ - %{__cp} -a Cargo.toml.orig $REG_DIR/Cargo.toml \ - %endif \ --- -2.21.0 - diff --git a/0019-Do-not-pull-optional-dependencies.patch b/0019-Do-not-pull-optional-dependencies.patch deleted file mode 100644 index 814c920..0000000 --- a/0019-Do-not-pull-optional-dependencies.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 604938a8bab778c58333643c3e069533327699e2 Mon Sep 17 00:00:00 2001 -From: Igor Gnatenko -Date: Sat, 9 Mar 2019 22:04:49 +0100 -Subject: [PATCH 19/19] Do not pull optional dependencies - -Signed-off-by: Igor Gnatenko ---- - data/macros.cargo | 20 +++++++++++--------- - rust2rpm/templates/main.spec | 5 ----- - 2 files changed, 11 insertions(+), 14 deletions(-) - -diff --git a/data/macros.cargo b/data/macros.cargo -index 96dc354..999d787 100644 ---- a/data/macros.cargo -+++ b/data/macros.cargo -@@ -2,8 +2,10 @@ - # https://github.com/rust-lang/cargo/issues/6397 - # But we can set CARGO_HOME locally, which is a good idea anyway to make sure - # it never writes to ~/.cargo during rpmbuild. --%__cargo %{_bindir}/env CARGO_HOME=.cargo %{_bindir}/cargo --%__cargo_common_opts %{?_smp_mflags} -+# We also need RUSTC_BOOTSTRAP since we use -Z avoid-dev-deps -+# until it gets stabilized: https://github.com/rust-lang/cargo/issues/5133 -+%__cargo %{_bindir}/env CARGO_HOME=.cargo RUSTC_BOOTSTRAP=1 %{_bindir}/cargo -+%__cargo_common_opts %{?_smp_mflags} -Z avoid-dev-deps - %__cargo_inspector %{_bindir}/cargo-inspector - - %cargo_registry %{_datadir}/cargo/registry -@@ -36,10 +38,6 @@ registry = "https://crates.io"\ - replace-with = "local-registry"\ - EOF\ - %{__rm} -f Cargo.lock \ --%if ! %{with check} \ --# https://github.com/rust-lang/cargo/issues/3732 \ --%{__awk} -i inplace -v INPLACE_SUFFIX=.orig '/^\\\[dev-dependencies/{f=1;next} /^\\\[/{f=0}; !f' Cargo.toml \ --%endif \ - ) - - %__cargo_parse_opts(naf:) %{shrink:\ -@@ -74,10 +72,14 @@ if %__cargo_is_lib; then \ - CRATE_VERSION=$(%__cargo_inspector --version Cargo.toml) \ - REG_DIR=%{buildroot}%{cargo_registry}/$CRATE_NAME-$CRATE_VERSION \ - %{__mkdir} -p $REG_DIR \ -+# Drop all dependency/features information \ -+# so that cargo doesn't fail resolving dependencies: \ -+# https://github.com/rust-lang/cargo/pull/6729 \ -+ %{__awk} -i inplace -v INPLACE_SUFFIX=.deps '/^\\\[((.+\\\.)?((dev|build)-)?dependencies|features)/{f=1;next} /^\\\[/{f=0}; !f' Cargo.toml \ - %{__cargo} package -l | xargs -d '\\\n' %{__cp} --parents -a -t $REG_DIR \ --%if ! %{with check} \ -- %{__cp} -a Cargo.toml.orig $REG_DIR/Cargo.toml \ --%endif \ -+ %{__mv} Cargo.toml{.deps,} \ -+ %{__cp} -a Cargo.toml $REG_DIR/Cargo.toml \ -+ %{__rm} -f $REG_DIR/Cargo.toml.orig \ - echo '{"files":{},"package":""}' > $REG_DIR/.cargo-checksum.json \ - fi \ - if %__cargo_is_bin; then \ -diff --git a/rust2rpm/templates/main.spec b/rust2rpm/templates/main.spec -index 1ebef7b..f0c5445 100644 ---- a/rust2rpm/templates/main.spec -+++ b/rust2rpm/templates/main.spec -@@ -44,12 +44,7 @@ Patch0: {{ patch_file }} - ExclusiveArch: %{rust_arches} - - BuildRequires: rust-packaging --{# 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 %} --- -2.21.0 - diff --git a/rust-packaging.spec b/rust-packaging.spec index 7412fdf..f9db08f 100644 --- a/rust-packaging.spec +++ b/rust-packaging.spec @@ -4,33 +4,13 @@ %global debug_package %{nil} Name: rust-packaging -Version: 6 -Release: 28%{?dist} +Version: 7 +Release: 1%{?dist} Summary: RPM macros for building Rust packages on various architectures License: MIT URL: https://pagure.io/fedora-rust/rust2rpm Source0: https://releases.pagure.org/fedora-rust/rust2rpm/rust2rpm-%{version}.tar.xz -Patch0001: 0001-name-spec-patch_file-by-real-crate-name.patch -Patch0002: 0002-generate-doc-statements.patch -Patch0003: 0003-do-better-for-renamed-crates.patch -Patch0004: 0004-remove-pre-3.6-leftovers.patch -Patch0005: 0005-Remove-half-downloaded-crate-on-C.patch -Patch0006: 0006-Throw-an-error-if-s-is-used-without-a-crate.patch -Patch0007: 0007-split-features-into-subpackages.patch -Patch0008: 0008-add-support-for-dependencies-with-same-name.patch -Patch0009: 0009-add-support-for-feeding-user-configuration.patch -Patch0010: 0010-trivial-use-f-strings-everywhere.patch -Patch0011: 0011-Add-option-to-not-generate-a-default-changelog-entry.patch -Patch0012: 0012-Set-CARGO_HOME-to-the-local-.config.patch -Patch0013: 0013-Set-the-install-root-in-.cargo-config.patch -Patch0014: 0014-licensing-fix-zlib-license-translation.patch -Patch0015: 0015-licensing-rename-EPL-to-EPL-1.0-and-add-EPL-2.0.patch -Patch0016: 0016-Add-support-for-prerelease-versions.patch -Patch0017: 0017-data-Cargo-doesn-t-escape-paths-with-space.patch -Patch0018: 0018-data-Escape-n-properly.patch -# https://pagure.io/fedora-rust/rust2rpm/pull-request/68 -Patch0019: 0019-Do-not-pull-optional-dependencies.patch ExclusiveArch: %{rust_arches} @@ -53,7 +33,6 @@ BuildRequires: python3-setuptools BuildRequires: python3-pytest BuildRequires: cargo BuildRequires: python3dist(semantic-version) -BuildRequires: python3dist(rustcfg) %endif Requires: cargo Provides: rust2rpm = %{version}-%{release} @@ -91,6 +70,9 @@ py.test-%{python3_version} -vv test.py %{python3_sitelib}/rust2rpm/ %changelog +* Tue Apr 23 16:17:30 CEST 2019 Igor Gnatenko - 7-1 +- Update to 7 + * Sun Mar 10 2019 Igor Gnatenko - 6-28 - Install $PWD/Cargo.toml into $REG_DIR/Cargo.toml diff --git a/sources b/sources index 9f6fa6f..bd3fb1f 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (rust2rpm-6.tar.xz) = 408988351156d858f7429d990d7330f216b54add671c6e90e54917e717ad6f2b3b99e414289c252e6a2b5dfad73ce430ac73f03265f6e174ef53edcee34d0fe2 +SHA512 (rust2rpm-7.tar.xz) = 8ef6d882cdb44673a60fac51e43d3ed6913e1df70e5e5596c4b4464c5361bf16cad66b9380eea2cf95ddcacfb1ca0291a20e0fac757756ddcd63bb9dd7dc9e93