Update to 7

Signed-off-by: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
epel9
Igor Gnatenko 6 years ago
parent 9d3869c340
commit 1b37f08c70
No known key found for this signature in database
GPG Key ID: 695714BD1BBC5F4C

1
.gitignore vendored

@ -1,3 +1,4 @@
/rust2rpm-4.tar.xz
/rust2rpm-5.tar.xz
/rust2rpm-6.tar.xz
/rust2rpm-7.tar.xz

@ -1,37 +0,0 @@
From 0dc9fc182edf0791ca697f587e48dd39948d63c1 Mon Sep 17 00:00:00 2001
From: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
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 <ignatenkobrain@fedoraproject.org>
---
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

@ -1,58 +0,0 @@
From 561280a0ea35f226ef243526be2bbb656db44af6 Mon Sep 17 00:00:00 2001
From: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
Date: Mon, 10 Sep 2018 23:40:18 +0200
Subject: [PATCH 02/19] generate %doc statements
Signed-off-by: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
---
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

@ -1,90 +0,0 @@
From 2050880140d4953b9ebdc7211e30df3ccf5dd61d Mon Sep 17 00:00:00 2001
From: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
Date: Tue, 11 Sep 2018 00:06:50 +0200
Subject: [PATCH 03/19] do better for renamed crates
Signed-off-by: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
---
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

@ -1,27 +0,0 @@
From e6e9cbbb71199c2773b47fa21f1c917a167c1743 Mon Sep 17 00:00:00 2001
From: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
Date: Tue, 11 Sep 2018 10:43:53 +0200
Subject: [PATCH 04/19] remove pre-3.6 leftovers
Signed-off-by: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
---
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

@ -1,44 +0,0 @@
From 2f12c83d14afe71e9efed2d1be62e1e610e602e9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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

@ -1,28 +0,0 @@
From 5a1cde5b8dcaea74ebb2050879036bf46df63adc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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

File diff suppressed because it is too large Load Diff

@ -1,74 +0,0 @@
From a1d3a84645aa7bbe5ca07b60bead1ddf90a21cc1 Mon Sep 17 00:00:00 2001
From: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
Date: Tue, 30 Oct 2018 20:37:38 +0100
Subject: [PATCH 08/19] add support for dependencies with same name
Reported-by: Josh Stone <jistone@redhat.com>
References: https://internals.rust-lang.org/t/optional-dependencies-with-same-name/8728
Signed-off-by: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
---
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

@ -1,148 +0,0 @@
From 197150ee2e862edcd46f7ab02c9e4d17e49ca75d Mon Sep 17 00:00:00 2001
From: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
Date: Wed, 31 Oct 2018 18:03:21 +0100
Subject: [PATCH 09/19] add support for feeding user configuration
Signed-off-by: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
---
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

@ -1,94 +0,0 @@
From 83ea3796cd28ec7689b39e7dc7a70bd11af1abf1 Mon Sep 17 00:00:00 2001
From: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
Date: Wed, 31 Oct 2018 17:00:58 +0100
Subject: [PATCH 10/19] trivial: use f-strings everywhere
Signed-off-by: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
---
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

@ -1,63 +0,0 @@
From 294c6f571c0f4f7ed5a4fcb34142b0d332c55f29 Mon Sep 17 00:00:00 2001
From: Neal Gompa <ngompa13@gmail.com>
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 <pkg>.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 <ngompa13@gmail.com>
---
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

@ -1,26 +0,0 @@
From b4e25038296cd57eba639a059e8baaf139a5d287 Mon Sep 17 00:00:00 2001
From: Josh Stone <jistone@redhat.com>
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

@ -1,34 +0,0 @@
From a04e95bc4f807139bd3c4b75f46fd9a60ec1db8f Mon Sep 17 00:00:00 2001
From: Josh Stone <jistone@redhat.com>
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

@ -1,35 +0,0 @@
From 7c00b0f29085166b1a89aec766945b10dc7aca23 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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

@ -1,31 +0,0 @@
From b0d2756917b380a5d66d2407dbeb8891c51875e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
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

@ -1,160 +0,0 @@
From 00c0c5cec90d5d6abbfd4acb2f5d65439b4bfd27 Mon Sep 17 00:00:00 2001
From: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
Date: Sat, 26 Jan 2019 08:33:37 +0100
Subject: [PATCH 16/19] Add support for prerelease versions
Signed-off-by: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
---
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

@ -1,31 +0,0 @@
From 84a73bfa24ce11602a1f19554dc495125be4d0aa Mon Sep 17 00:00:00 2001
From: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
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 <ignatenkobrain@fedoraproject.org>
---
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

@ -1,26 +0,0 @@
From 7f0a499ff3fca046869ab754151ae068903c4ab9 Mon Sep 17 00:00:00 2001
From: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
Date: Sun, 10 Mar 2019 10:14:28 +0100
Subject: [PATCH 18/19] data: Escape `\n` properly
Signed-off-by: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
---
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

@ -1,77 +0,0 @@
From 604938a8bab778c58333643c3e069533327699e2 Mon Sep 17 00:00:00 2001
From: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
Date: Sat, 9 Mar 2019 22:04:49 +0100
Subject: [PATCH 19/19] Do not pull optional dependencies
Signed-off-by: Igor Gnatenko <ignatenkobrain@fedoraproject.org>
---
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

@ -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 <ignatenkobrain@fedoraproject.org> - 7-1
- Update to 7
* Sun Mar 10 2019 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 6-28
- Install $PWD/Cargo.toml into $REG_DIR/Cargo.toml

@ -1 +1 @@
SHA512 (rust2rpm-6.tar.xz) = 408988351156d858f7429d990d7330f216b54add671c6e90e54917e717ad6f2b3b99e414289c252e6a2b5dfad73ce430ac73f03265f6e174ef53edcee34d0fe2
SHA512 (rust2rpm-7.tar.xz) = 8ef6d882cdb44673a60fac51e43d3ed6913e1df70e5e5596c4b4464c5361bf16cad66b9380eea2cf95ddcacfb1ca0291a20e0fac757756ddcd63bb9dd7dc9e93

Loading…
Cancel
Save