diff --git a/pyp2rpm/filters.py b/pyp2rpm/filters.py index f6e59e1..167974e 100644 --- a/pyp2rpm/filters.py +++ b/pyp2rpm/filters.py @@ -52,7 +52,7 @@ def module_to_path(name, module): if name == module: return "%{pypi_name}" else: - return module + return rpm_escape(module) def package_to_path(package, module): @@ -62,7 +62,7 @@ def package_to_path(package, module): if package == module: return "%{pypi_name}" else: - return package + return rpm_escape(package) def macroed_url(url): @@ -126,6 +126,28 @@ def rpm_version(version, use_macro=True): return '{}~{}'.format(rpm_version, rpm_suffix) +def rpm_escape(text): + """Escapes RPM directives and macros in text to prevent code injection. + + RPM spec files interpret percent signs (%) as the start of macros, + directives, or Lua scriptlets. To prevent malicious package metadata + from injecting arbitrary commands, all percent signs must be escaped + by doubling them (%%). + + Args: + text: String that may contain user-controlled content + + Returns: + String with all percent signs escaped (% becomes %%) + """ + if text is None: + return '' + if not isinstance(text, str): + text = str(text) + # Escape all percent signs by doubling them + return text.replace('%', '%%') + + __all__ = [name_for_python_version, script_name_for_python_version, sitedir_for_python_version, @@ -135,4 +157,5 @@ def rpm_version(version, use_macro=True): package_to_path, macroed_url, rpm_version_410, - rpm_version] + rpm_version, + rpm_escape] diff --git a/pyp2rpm/package_data.py b/pyp2rpm/package_data.py index d875d9d..6f3e1c2 100644 --- a/pyp2rpm/package_data.py +++ b/pyp2rpm/package_data.py @@ -5,6 +5,7 @@ from pyp2rpm import version from pyp2rpm import utils +from pyp2rpm import filters logger = logging.getLogger(__name__) diff --git a/pyp2rpm/templates/epel6.spec b/pyp2rpm/templates/epel6.spec index 43ebbeb..9e19885 100644 --- a/pyp2rpm/templates/epel6.spec +++ b/pyp2rpm/templates/epel6.spec @@ -1,9 +1,9 @@ {{ data.credit_line }} {% from 'macros.spec' import dependencies, for_python_versions, underscored_or_pypi -%} -%global pypi_name {{ data.name }} -%global pypi_version {{ data.version }} +%global pypi_name {{ data.name|rpm_escape }} +%global pypi_version {{ data.version|rpm_escape }} {%- if data.srcname %} -%global srcname {{ data.srcname }} +%global srcname {{ data.srcname|rpm_escape }} {%- endif %} {%- for pv in data.python_versions %} %global with_python{{ pv }} 1 @@ -12,11 +12,11 @@ Name: {{ data.pkg_name|macroed_pkg_name(data.srcname) }} Version: {{ data.version|rpm_version_410 }} Release: 1%{?dist} -Summary: {{ data.summary }} +Summary: {{ data.summary|rpm_escape }} -License: {{ data.license }} -URL: {{ data.home_page }} -Source0: {{ data.source0|replace(data.name, '%{pypi_name}')|replace(data.version, '%{pypi_version}') }} +License: {{ data.license|rpm_escape }} +URL: {{ data.home_page|rpm_escape }} +Source0: {{ data.source0|rpm_escape|replace(data.name|rpm_escape, '%{pypi_name}')|replace(data.version|rpm_escape, '%{pypi_version}') }} {%- if not data.has_extension %} BuildArch: noarch @@ -27,20 +27,20 @@ BuildArch: noarch {{ dependencies(data.runtime_deps, True, data.base_python_version, data.base_python_version) }} %description -{{ data.description|truncate(400)|wordwrap }} +{{ data.description|truncate(400)|wordwrap|rpm_escape }} {% call(pv) for_python_versions(data.python_versions) -%} %package -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv) }} -Summary: {{ data.summary }} +Summary: {{ data.summary|rpm_escape }} {{ dependencies(data.runtime_deps, True, pv, pv) }} %description -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv) }} -{{ data.description|truncate(400)|wordwrap }} +{{ data.description|truncate(400)|wordwrap|rpm_escape }} {%- endcall %} {%- if data.sphinx_dir %} %package -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(None, True) }}-doc -Summary: {{ data.name }} documentation +Summary: {{ data.name|rpm_escape }} documentation %description -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(None, True) }}-doc -Documentation for {{ data.name }} +Documentation for {{ data.name|rpm_escape }} {%- endif %} %prep @@ -58,7 +58,7 @@ find python{{pv}} -name '*.py' | xargs sed -i '1s|^#!python|#!%{__python{{pv}}}| {%- if data.sphinx_dir %} # generate html docs {# TODO: generate properly for other versions (pushd/popd into their dirs...) # #} -PYTHONPATH=${PWD} {{ "sphinx-build"|script_name_for_python_version(data.base_python_version, False, False) }} {{ data.sphinx_dir }} html +PYTHONPATH=${PWD} {{ "sphinx-build"|script_name_for_python_version(data.base_python_version, False, False) }} {{ data.sphinx_dir|rpm_escape }} html # remove the sphinx-build leftovers rm -rf html/.{doctrees,buildinfo} {%- endif %} @@ -109,11 +109,11 @@ popd {% call(pv) for_python_versions(data.sorted_python_versions, data.base_python_version) -%} %files{% if pv != data.base_python_version %} -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv) }}{% endif %} {%- if data.doc_files %} -%doc {{ data.doc_files|join(' ') }} +%doc {{ data.doc_files|map('rpm_escape')|join(' ') }} {%- endif %} {%- if pv == data.base_python_version %} {%- for script in data.scripts %} -%{_bindir}/{{ script }} +%{_bindir}/{{ script|rpm_escape }} {%- endfor %} {%- endif %} {%- if data.py_modules %} @@ -151,7 +151,7 @@ popd %files -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv, True) }}-doc %doc html {%- if data.doc_license %} -%license {{data.doc_license|join(' ')}} +%license {{data.doc_license|map('rpm_escape')|join(' ')}} {%- endif %} {% endif %} %changelog diff --git a/pyp2rpm/templates/epel7.spec b/pyp2rpm/templates/epel7.spec index f551eb6..947511e 100644 --- a/pyp2rpm/templates/epel7.spec +++ b/pyp2rpm/templates/epel7.spec @@ -1,19 +1,19 @@ {{ data.credit_line }} {% from 'macros.spec' import dependencies, for_python_versions, underscored_or_pypi -%} -%global pypi_name {{ data.name }} -%global pypi_version {{ data.version }} +%global pypi_name {{ data.name|rpm_escape }} +%global pypi_version {{ data.version|rpm_escape }} {%- if data.srcname %} -%global srcname {{ data.srcname }} +%global srcname {{ data.srcname|rpm_escape }} {%- endif %} Name: {{ data.pkg_name|macroed_pkg_name(data.srcname) }} Version: {{ data.version|rpm_version_410 }} Release: 1%{?dist} -Summary: {{ data.summary }} +Summary: {{ data.summary|rpm_escape }} -License: {{ data.license }} -URL: {{ data.home_page }} -Source0: {{ data.source0|replace(data.name, '%{pypi_name}')|replace(data.version, '%{pypi_version}') }} +License: {{ data.license|rpm_escape }} +URL: {{ data.home_page|rpm_escape }} +Source0: {{ data.source0|rpm_escape|replace(data.name|rpm_escape, '%{pypi_name}')|replace(data.version|rpm_escape, '%{pypi_version}') }} {%- if not data.has_extension %} BuildArch: noarch @@ -23,23 +23,23 @@ BuildArch: noarch {%- endfor %} %description -{{ data.description|truncate(400)|wordwrap }} +{{ data.description|truncate(400)|wordwrap|rpm_escape }} {% for pv in data.sorted_python_versions %} %package -n {{data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv, True)}} -Summary: {{ data.summary }} +Summary: {{ data.summary|rpm_escape }} {{ dependencies(data.runtime_deps, True, pv, pv, use_with=False) }} %description -n {{data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv, True)}} -{{ data.description|truncate(400)|wordwrap }} +{{ data.description|truncate(400)|wordwrap|rpm_escape }} {% endfor -%} {%- if data.sphinx_dir %} %package -n python-%{pypi_name}-doc -Summary: {{ data.name }} documentation +Summary: {{ data.name|rpm_escape }} documentation %description -n python-%{pypi_name}-doc -Documentation for {{ data.name }} +Documentation for {{ data.name|rpm_escape }} {%- endif %} %prep -%autosetup -n {{ data.dirname|replace(data.name, '%{pypi_name}')|replace(data.version, '%{pypi_version}')|default('%{pypi_name}-%{pypi_version}', true) }} +%autosetup -n {{ data.dirname|rpm_escape|replace(data.name|rpm_escape, '%{pypi_name}')|replace(data.version|rpm_escape, '%{pypi_version}')|default('%{pypi_name}-%{pypi_version}', true) }} {%- if data.has_bundled_egg_info %} # Remove bundled egg-info rm -rf %{pypi_name}.egg-info @@ -51,7 +51,7 @@ rm -rf %{pypi_name}.egg-info {%- endfor %} {%- if data.sphinx_dir %} # generate html docs -PYTHONPATH=${PWD} {{ "sphinx-build"|script_name_for_python_version(data.base_python_version, True, False) }} {{ data.sphinx_dir }} html +PYTHONPATH=${PWD} {{ "sphinx-build"|script_name_for_python_version(data.base_python_version, True, False) }} {{ data.sphinx_dir|rpm_escape }} html # remove the sphinx-build leftovers rm -rf html/.{doctrees,buildinfo} {%- endif %} @@ -77,11 +77,11 @@ rm -rf %{buildroot}%{_bindir}/* {% for pv in data.sorted_python_versions %} %files -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv, True) }} {%- if data.doc_files %} -%doc {{data.doc_files|join(' ') }} +%doc {{data.doc_files|map('rpm_escape')|join(' ') }} {%- endif %} {%- if pv == data.base_python_version %} {%- for script in data.scripts %} -%{_bindir}/{{ script }} +%{_bindir}/{{ script|rpm_escape }} {%- endfor %} {%- endif %} {%- if data.py_modules %} @@ -119,7 +119,7 @@ rm -rf %{buildroot}%{_bindir}/* %files -n python-%{pypi_name}-doc %doc html {%- if data.doc_license %} -%license {{data.doc_license|join(' ')}} +%license {{data.doc_license|map('rpm_escape')|join(' ')}} {%- endif %} {% endif %} %changelog diff --git a/pyp2rpm/templates/fedora.spec b/pyp2rpm/templates/fedora.spec index b095edc..8e2e2fe 100644 --- a/pyp2rpm/templates/fedora.spec +++ b/pyp2rpm/templates/fedora.spec @@ -1,19 +1,19 @@ {{ data.credit_line }} {% from 'macros.spec' import dependencies, for_python_versions, underscored_or_pypi, macroed_url -%} -%global pypi_name {{ data.name }} -%global pypi_version {{ data.version }} +%global pypi_name {{ data.name|rpm_escape }} +%global pypi_version {{ data.version|rpm_escape }} {%- if data.srcname %} -%global srcname {{ data.srcname }} +%global srcname {{ data.srcname|rpm_escape }} {%- endif %} Name: {{ data.pkg_name|macroed_pkg_name(data.srcname) }} Version: {{ data.version|rpm_version }} Release: 1%{?dist} -Summary: {{ data.summary }} +Summary: {{ data.summary|rpm_escape }} -License: {{ data.license }} -URL: {{ data.home_page }} -Source0: {{ data.source0|replace(data.name, '%{pypi_name}')|replace(data.version, '%{pypi_version}')|macroed_url }} +License: {{ data.license|rpm_escape }} +URL: {{ data.home_page|rpm_escape }} +Source0: {{ data.source0|rpm_escape|replace(data.name|rpm_escape, '%{pypi_name}')|replace(data.version|rpm_escape, '%{pypi_version}')|macroed_url }} {%- if not data.has_extension %} BuildArch: noarch @@ -23,24 +23,24 @@ BuildArch: noarch {%- endfor %} %description -{{ data.description|truncate(400)|wordwrap }} +{{ data.description|truncate(400)|wordwrap|rpm_escape }} {% for pv in data.sorted_python_versions %} %package -n {{data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv, True) }} Summary: %{summary} %{?python_provide:%python_provide {{data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv, True)}}} {{ dependencies(data.runtime_deps, True, pv, pv) }} %description -n {{data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv, True) }} -{{ data.description|truncate(400)|wordwrap }} +{{ data.description|truncate(400)|wordwrap|rpm_escape }} {% endfor -%} {%- if data.sphinx_dir %} %package -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(None, True) }}-doc -Summary: {{ data.name }} documentation +Summary: {{ data.name|rpm_escape }} documentation %description -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(None, True) }}-doc -Documentation for {{ data.name }} +Documentation for {{ data.name|rpm_escape }} {%- endif %} %prep -%autosetup -n {{ data.dirname|replace(data.name, '%{pypi_name}')|replace(data.version, '%{pypi_version}')|default('%{pypi_name}-%{pypi_version}', true) }} +%autosetup -n {{ data.dirname|rpm_escape|replace(data.name|rpm_escape, '%{pypi_name}')|replace(data.version|rpm_escape, '%{pypi_version}')|default('%{pypi_name}-%{pypi_version}', true) }} {%- if data.has_bundled_egg_info %} # Remove bundled egg-info rm -rf %{pypi_name}.egg-info @@ -52,7 +52,7 @@ rm -rf %{pypi_name}.egg-info {%- endfor %} {%- if data.sphinx_dir %} # generate html docs -PYTHONPATH=${PWD} {{ "sphinx-build"|script_name_for_python_version(data.base_python_version, False, True) }} {{ data.sphinx_dir }} html +PYTHONPATH=${PWD} {{ "sphinx-build"|script_name_for_python_version(data.base_python_version, False, True) }} {{ data.sphinx_dir|rpm_escape }} html # remove the sphinx-build leftovers rm -rf html/.{doctrees,buildinfo} {%- endif %} @@ -78,14 +78,14 @@ rm -rf %{buildroot}%{_bindir}/* {% for pv in data.sorted_python_versions %} %files -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv, True) }} {%- if data.doc_license %} -%license {{data.doc_license|join(' ')}} +%license {{data.doc_license|map('rpm_escape')|join(' ')}} {%- endif %} {%- if data.doc_files %} -%doc {{data.doc_files|join(' ') }} +%doc {{data.doc_files|map('rpm_escape')|join(' ') }} {%- endif %} {%- if pv == data.base_python_version %} {%- for script in data.scripts %} -%{_bindir}/{{ script }} +%{_bindir}/{{ script|rpm_escape }} {%- endfor %} {%- endif %} {%- if data.py_modules %} @@ -122,7 +122,7 @@ rm -rf %{buildroot}%{_bindir}/* %files -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(None, True) }}-doc %doc html {%- if data.doc_license %} -%license {{data.doc_license|join(' ')}} +%license {{data.doc_license|map('rpm_escape')|join(' ')}} {%- endif %} {% endif %} %changelog diff --git a/pyp2rpm/templates/macros.spec b/pyp2rpm/templates/macros.spec index 531d653..ad35a66 100644 --- a/pyp2rpm/templates/macros.spec +++ b/pyp2rpm/templates/macros.spec @@ -1,6 +1,6 @@ {# prints a single dependency for a specific python version #} {%- macro one_dep(dep, python_version) %} -{{ dep[0] }}:{{ ' ' * (15 - dep[0]|length) }}{{ dep[2].format(name=dep[1]|name_for_python_version(python_version, True)) }} +{{ dep[0] }}:{{ ' ' * (15 - dep[0]|length) }}{{ dep[2].format(name=dep[1]|rpm_escape|name_for_python_version(python_version, True)) }} {%- endmacro %} {# Prints given deps (runtime or buildtime for given python_version, diff --git a/pyp2rpm/templates/mageia.spec b/pyp2rpm/templates/mageia.spec index c29f9d1..5d3a732 100644 --- a/pyp2rpm/templates/mageia.spec +++ b/pyp2rpm/templates/mageia.spec @@ -1,19 +1,19 @@ {{ data.credit_line }} {% from 'macros.spec' import dependencies, for_python_versions, underscored_or_pypi -%} -%global pypi_name {{ data.name }} -%global pypi_version {{ data.version }} +%global pypi_name {{ data.name|rpm_escape }} +%global pypi_version {{ data.version|rpm_escape }} {%- if data.srcname %} -%global srcname {{ data.srcname }} +%global srcname {{ data.srcname|rpm_escape }} {%- endif %} Name: {{ data.pkg_name|macroed_pkg_name(data.srcname) }} Version: {{ data.version|rpm_version }} Release: %mkrel 1 -Summary: {{ data.summary }} +Summary: {{ data.summary|rpm_escape }} Group: Development/Python -License: {{ data.license }} -URL: {{ data.home_page }} -Source0: {{ data.source0|replace(data.name, '%{pypi_name}')|replace(data.version, '%{pypi_version}') }} +License: {{ data.license|rpm_escape }} +URL: {{ data.home_page|rpm_escape }} +Source0: {{ data.source0|rpm_escape|replace(data.name|rpm_escape, '%{pypi_name}')|replace(data.version|rpm_escape, '%{pypi_version}') }} {%- if not data.has_extension %} BuildArch: noarch @@ -23,24 +23,24 @@ BuildArch: noarch {%- endfor %} %description -{{ data.description|truncate(400)|wordwrap }} +{{ data.description|truncate(400)|wordwrap|rpm_escape }} {% for pv in data.sorted_python_versions %} %package -n {{data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv, True) }} Summary: %{summary} %{?python_provide:%python_provide {{data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv, True)}}} {{ dependencies(data.runtime_deps, True, pv, pv) }} %description -n {{data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv, True) }} -{{ data.description|truncate(400)|wordwrap }} +{{ data.description|truncate(400)|wordwrap|rpm_escape }} {% endfor -%} {%- if data.sphinx_dir %} %package -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(None, True) }}-doc -Summary: {{ data.name }} documentation +Summary: {{ data.name|rpm_escape }} documentation %description -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(None, True) }}-doc -Documentation for {{ data.name }} +Documentation for {{ data.name|rpm_escape }} {%- endif %} %prep -%autosetup -n {{ data.dirname|replace(data.name, '%{pypi_name}')|replace(data.version, '%{pypi_version}')|default('%{pypi_name}-%{pypi_version}', true) }} +%autosetup -n {{ data.dirname|rpm_escape|replace(data.name|rpm_escape, '%{pypi_name}')|replace(data.version|rpm_escape, '%{pypi_version}')|default('%{pypi_name}-%{pypi_version}', true) }} {%- if data.has_bundled_egg_info %} # Remove bundled egg-info rm -rf %{pypi_name}.egg-info @@ -52,7 +52,7 @@ rm -rf %{pypi_name}.egg-info {%- endfor %} {%- if data.sphinx_dir %} # generate html docs -PYTHONPATH=${PWD} {{ "sphinx-build"|script_name_for_python_version(data.base_python_version, False, True) }} {{ data.sphinx_dir }} html +PYTHONPATH=${PWD} {{ "sphinx-build"|script_name_for_python_version(data.base_python_version, False, True) }} {{ data.sphinx_dir|rpm_escape }} html # remove the sphinx-build leftovers rm -rf html/.{doctrees,buildinfo} {%- endif %} @@ -78,14 +78,14 @@ rm -rf %{buildroot}%{_bindir}/* {% for pv in data.sorted_python_versions %} %files -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv, True) }} {%- if data.doc_license %} -%license {{data.doc_license|join(' ')}} +%license {{data.doc_license|map('rpm_escape')|join(' ')}} {%- endif %} {%- if data.doc_files %} -%doc {{data.doc_files|join(' ') }} +%doc {{data.doc_files|map('rpm_escape')|join(' ') }} {%- endif %} {%- if pv == data.base_python_version %} {%- for script in data.scripts %} -%{_bindir}/{{ script }} +%{_bindir}/{{ script|rpm_escape }} {%- endfor %} {%- endif %} {%- if data.py_modules %} @@ -122,6 +122,6 @@ rm -rf %{buildroot}%{_bindir}/* %files -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(None, True) }}-doc %doc html {%- if data.doc_license %} -%license {{data.doc_license|join(' ')}} +%license {{data.doc_license|map('rpm_escape')|join(' ')}} {%- endif %} {% endif %} diff --git a/pyp2rpm/templates/pld.spec b/pyp2rpm/templates/pld.spec index 0160333..46ee6e0 100644 --- a/pyp2rpm/templates/pld.spec +++ b/pyp2rpm/templates/pld.spec @@ -40,19 +40,19 @@ %bcond_without python{{ pv }} # CPython {{ pv }}.x module {%- endfor %} -%define module {{ data.name }} -%define egg_name {{ data.underscored_name }} -%define pypi_name {{ data.name }} -%define pypi_version {{ data.version }} -Summary: {{ data.summary }} +%define module {{ data.name|rpm_escape }} +%define egg_name {{ data.underscored_name|rpm_escape }} +%define pypi_name {{ data.name|rpm_escape }} +%define pypi_version {{ data.version|rpm_escape }} +Summary: {{ data.summary|rpm_escape }} Name: python-%{pypi_name} Version: {{ data.version|rpm_version }} Release: 0.1 -License: {{ data.license }} +License: {{ data.license|rpm_escape }} Group: Libraries/Python -Source0: {{ data.source0|replace(data.name, '%{pypi_name}')|replace(data.version, '%{pypi_version}') }} +Source0: {{ data.source0|rpm_escape|replace(data.name|rpm_escape, '%{pypi_name}')|replace(data.version|rpm_escape, '%{pypi_version}') }} # Source0-md5: - -URL: {{ data.home_page }} +URL: {{ data.home_page|rpm_escape }} BuildRequires: rpm-pythonprov BuildRequires: rpmbuild(macros) >= 1.714 {# build deps for each Python version #} @@ -67,15 +67,15 @@ BuildArch: noarch BuildRoot: %{tmpdir}/%{name}-%{pypi_version}-root-%(id -u -n) %description -{{ data.description|truncate(400)|wordwrap }} +{{ data.description|truncate(400)|wordwrap|rpm_escape }} {% call(pv) for_python_versions(data.python_versions, use_with=False) -%} %package -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv) }} -Summary: {{ data.summary }} +Summary: {{ data.summary|rpm_escape }} Group: Libraries/Python %description -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv) }} -{{ data.description|truncate(400)|wordwrap }} +{{ data.description|truncate(400)|wordwrap|rpm_escape }} {%- endcall %} %prep @@ -89,7 +89,7 @@ Group: Libraries/Python {% call(pv) for_python_versions([data.base_python_version] + data.python_versions, data.base_python_version, use_with=False) -%} {%- if data.sphinx_dir %} # generate html docs {# TODO: generate properly for other versions (pushd/popd into their dirs...) #} -{% if pv != data.base_python_version %}python{{ pv }}-{% endif %}sphinx-build {{ data.sphinx_dir }} html +{% if pv != data.base_python_version %}python{{ pv }}-{% endif %}sphinx-build {{ data.sphinx_dir|rpm_escape }} html # remove the sphinx-build leftovers %{__rm} -r html/.{doctrees,buildinfo} {%- endif %} @@ -114,7 +114,7 @@ rm -rf $RPM_BUILD_ROOT {%- if data.scripts %} {%- for script in data.scripts %} -mv $RPM_BUILD_ROOT%{_bindir}/{{ script }} $RPM_BUILD_ROOT%{_bindir}/{{ script|script_name_for_python_version(pv) }} +mv $RPM_BUILD_ROOT%{_bindir}/{{ script|rpm_escape }} $RPM_BUILD_ROOT%{_bindir}/{{ script|script_name_for_python_version(pv)|rpm_escape }} {%- endfor %} {%- endif %} @@ -127,11 +127,11 @@ rm -rf $RPM_BUILD_ROOT %files{% if pv != data.base_python_version %} -n {{ data.pkg_name|macroed_pkg_name(data.srcname)|name_for_python_version(pv) }}{% endif %} %defattr(644,root,root,755) -%doc {% if data.sphinx_dir %}html {% endif %}{{ data.doc_files|join(' ') }} +%doc {% if data.sphinx_dir %}html {% endif %}{{ data.doc_files|map('rpm_escape')|join(' ') }} {%- if data.scripts %} {%- for script in data.scripts %} -%attr(755,root,root) %{_bindir}/{{ script|script_name_for_python_version(pv) }} +%attr(755,root,root) %{_bindir}/{{ script|script_name_for_python_version(pv)|rpm_escape }} {%- endfor %} {%- endif %} diff --git a/tests/test_data/python-Jinja2_dnfnc.spec b/tests/test_data/python-Jinja2_dnfnc.spec index 9886c37..bd8af15 100644 --- a/tests/test_data/python-Jinja2_dnfnc.spec +++ b/tests/test_data/python-Jinja2_dnfnc.spec @@ -26,9 +26,9 @@ BuildRequires: python3-sphinx %description Jinja2 is a template engine written in pure Python. It provides a Django_ inspired non-XML syntax but supports inline expressions and an optional -sandboxed_ environment.Nutshell Here a small example of a Jinja template:: {% -extends 'base.html' %} {% block title %}Memberlist{% endblock %} {% block -content %}