#101 Add %version_no_operators macro
Opened 3 months ago by gordonmessmer. Modified a month ago
rpms/ gordonmessmer/python-rpm-macros rawhide  into  rawhide

file modified
+11
@@ -221,3 +221,14 @@ 

          end

      end

  }}

+ 

+ %version_no_operators() %{lua:

+     local ver = rpm.expand('%1')

+ \

+     if ver == '%1' then

+         ver = rpm.expand('%version')

+     end

+     ver = ver:gsub('[~^]+', '')

+ \

+     print(ver)

+ } 

\ No newline at end of file

file modified
+32 -11
@@ -73,6 +73,16 @@ 

      assert rpm_eval(f'%py_dist_name {argument}') == [result]

  

  

+ @pytest.mark.parametrize('argument, result', [

+     ('7.5.0~~dev1', '7.5.0dev1'),

+     ('7.5.0~b4', '7.5.0b4'),

+     ('7.5.0', '7.5.0'),

+     ('7.5.0^post1', '7.5.0post1'),

+ ])

+ def test_version_no_operators(argument, result):

+     assert rpm_eval(f'%version_no_operators {argument}') == [result]

+ 

+ 

  def test_py2_dist():

      assert rpm_eval(f'%py2_dist Aha[Boom] a') == ['python2dist(aha[boom]) python2dist(a)']

  
@@ -90,7 +100,8 @@ 

  

  

  def test_python_provide_python3():

-     lines = rpm_eval('%python_provide python3-foo', version='6', release='1.fc66')

+     lines = rpm_eval('%python_provide python3-foo', version='6', release='1.fc66',

+                      __default_python3_version=X_Y)

Can we set __default_python3_version as a default in the rpm_eval() function instead?

      assert 'Obsoletes: python-foo < 6-1.fc66' in lines

      assert 'Provides: python-foo = 6-1.fc66' in lines

      assert f'Provides: python{X_Y}-foo = 6-1.fc66' in lines
@@ -98,7 +109,8 @@ 

  

  

  def test_python_provide_python3_epoched():

-     lines = rpm_eval('%python_provide python3-foo', epoch='1', version='6', release='1.fc66')

+     lines = rpm_eval('%python_provide python3-foo', epoch='1', version='6', release='1.fc66',

+                      __default_python3_version=X_Y)

      assert 'Obsoletes: python-foo < 1:6-1.fc66' in lines

      assert 'Provides: python-foo = 1:6-1.fc66' in lines

      assert f'Provides: python{X_Y}-foo = 1:6-1.fc66' in lines
@@ -106,7 +118,8 @@ 

  

  

  def test_python_provide_python3X():

-     lines = rpm_eval(f'%python_provide python{X_Y}-foo', version='6', release='1.fc66')

+     lines = rpm_eval(f'%python_provide python{X_Y}-foo', version='6', release='1.fc66',

+                      __default_python3_version=X_Y)

      assert 'Obsoletes: python-foo < 6-1.fc66' in lines

      assert 'Provides: python-foo = 6-1.fc66' in lines

      assert 'Provides: python3-foo = 6-1.fc66' in lines
@@ -114,7 +127,8 @@ 

  

  

  def test_python_provide_python3X_epoched():

-     lines = rpm_eval(f'%python_provide python{X_Y}-foo', epoch='1', version='6', release='1.fc66')

+     lines = rpm_eval(f'%python_provide python{X_Y}-foo', epoch='1', version='6', release='1.fc66',

+                      __default_python3_version=X_Y)

      assert 'Obsoletes: python-foo < 1:6-1.fc66' in lines

      assert 'Provides: python-foo = 1:6-1.fc66' in lines

      assert 'Provides: python3-foo = 1:6-1.fc66' in lines
@@ -123,7 +137,8 @@ 

  

  def test_python_provide_doubleuse():

      lines = rpm_eval('%{python_provide python3-foo}%{python_provide python3-foo}',

-                      version='6', release='1.fc66')

+                      version='6', release='1.fc66',

+                      __default_python3_version=X_Y)

      assert 'Obsoletes: python-foo < 6-1.fc66' in lines

      assert 'Provides: python-foo = 6-1.fc66' in lines

      assert f'Provides: python{X_Y}-foo = 6-1.fc66' in lines
@@ -144,7 +159,8 @@ 

  

  

  def test_py_provides_python3():

-     lines = rpm_eval('%py_provides python3-foo', version='6', release='1.fc66')

+     lines = rpm_eval('%py_provides python3-foo', version='6', release='1.fc66',

+                      __default_python3_version=X_Y)

      assert 'Provides: python3-foo = 6-1.fc66' in lines

      assert 'Provides: python-foo = 6-1.fc66' in lines

      assert f'Provides: python{X_Y}-foo = 6-1.fc66' in lines
@@ -152,7 +168,8 @@ 

  

  

  def test_py_provides_python3_epoched():

-     lines = rpm_eval('%py_provides python3-foo', epoch='1', version='6', release='1.fc66')

+     lines = rpm_eval('%py_provides python3-foo', epoch='1', version='6', release='1.fc66',

+                      __default_python3_version=X_Y)

      assert 'Provides: python3-foo = 1:6-1.fc66' in lines

      assert 'Provides: python-foo = 1:6-1.fc66' in lines

      assert f'Provides: python{X_Y}-foo = 1:6-1.fc66' in lines
@@ -160,7 +177,8 @@ 

  

  

  def test_py_provides_python3X():

-     lines = rpm_eval(f'%py_provides python{X_Y}-foo', version='6', release='1.fc66')

+     lines = rpm_eval(f'%py_provides python{X_Y}-foo', version='6', release='1.fc66',

+                      __default_python3_version=X_Y)

      assert f'Provides: python{X_Y}-foo = 6-1.fc66' in lines

      assert 'Provides: python-foo = 6-1.fc66' in lines

      assert 'Provides: python3-foo = 6-1.fc66' in lines
@@ -168,7 +186,8 @@ 

  

  

  def test_py_provides_python3X_epoched():

-     lines = rpm_eval(f'%py_provides python{X_Y}-foo', epoch='1', version='6', release='1.fc66')

+     lines = rpm_eval(f'%py_provides python{X_Y}-foo', epoch='1', version='6', release='1.fc66',

+                      __default_python3_version=X_Y)

      assert f'Provides: python{X_Y}-foo = 1:6-1.fc66' in lines

      assert 'Provides: python-foo = 1:6-1.fc66' in lines

      assert 'Provides: python3-foo = 1:6-1.fc66' in lines
@@ -177,7 +196,8 @@ 

  

  def test_py_provides_doubleuse():

      lines = rpm_eval('%{py_provides python3-foo}%{py_provides python3-foo}',

-                      version='6', release='1.fc66')

+                      version='6', release='1.fc66',

+                      __default_python3_version=X_Y)

      assert 'Provides: python3-foo = 6-1.fc66' in lines

      assert 'Provides: python-foo = 6-1.fc66' in lines

      assert f'Provides: python{X_Y}-foo = 6-1.fc66' in lines
@@ -187,7 +207,8 @@ 

  

  def test_py_provides_with_evr():

      lines = rpm_eval('%py_provides python3-foo 123',

-                      version='6', release='1.fc66')

+                      version='6', release='1.fc66',

+                      __default_python3_version=X_Y)

      assert 'Provides: python3-foo = 123' in lines

      assert 'Provides: python-foo = 123' in lines

      assert f'Provides: python{X_Y}-foo = 123' in lines

@churchyard suggested something like version_no_operators in https://github.com/fedora-python/pyp2rpm/pull/260 and https://github.com/rpm-software-management/rpm/issues/1219

I also updated some tests so that they pass when, for example, I run tests in the "rawhide" branch from a Fedora 34 system, where /usr/bin/python3 doesn't match the __default_python3_version in the repo macros files.

Build failed. More information on how to proceed and troubleshoot errors available at https://fedoraproject.org/wiki/Zuul-based-ci

Can we set __default_python3_version as a default in the rpm_eval() function instead?

I'd pretty much preferred if %version_no_operators was defined (in this order):

I'm also not sure if %version_no_operators should not also strip pluses :/

Thank you @gordonmessmer! I hope we might eventually have a macro like this available!

See also https://pagure.io/packaging-committee/pull-request/1073#comment-151977

I'd pretty much preferred if %version_no_operators was defined (in this order):

That said, RPM is clearly no interested in this and redhat-rpm-config is not maintained much. Maybe this is best place for the macro.

Thoughts? @pviktori @torsava

I think I'm missing some context. Where will this be used? pypi_source?
IMO, adding it only to python-rpm-macros makes it a Python-specific macro; the name is too generic for that.

You would use it anywhere in spec where you need to use that version. Instead of doing:

%global base_version 1.2.3
%global prerelease b2
%global upstream_version %{base_version}%{?prerelease}
Version:    %{base_version}%{?prerelease:~%{prerelease}}
...
Source0:  https....-%{upstream_version}.tar.gz

...
%files
%{python_sitelib}/...-%{upstream_version}.dist-info

You would do:

Version:    1.2.3~b2
...
Source0:  https....-%{version_no_operators}.tar.gz

...
%files
%{python_sitelib}/...-%{version_no_operators}.dist-info

But I agree that the name is too generic for being here. however not sure what to call it instead.

That said, RPM is clearly no interested in this and redhat-rpm-config is not maintained much. Maybe this is best place for the macro.

Can we please reconsider the location: redhat-rpm-config seems like a much better place. I want to use this in various places (at least everywhere where %version_no_tilde appears). Was the equivalent pull request submitted against redhat-rpm-config already?

Maybe I'm naïve, but both %version_no_tilde and %version_no_operators look over-generalized.
I see it'd be used in Python and Rust. Are there any more use cases? Is this really language-specific, but Rust & Python just happen to agree here?
It seems to me that the purpose of the macro, is to take a RPM version generated from a Python (PEP 440) version, and convert it back to the Python version. This is achieved by "removing operators", but IMO that should be an implementation detail.
Would it be better to name it %py_version or %pep440_version?

For RPM versions that aren't generated from Python-style versions, like 0.5.0~rc1^20200701gdeadf00f, a snapshot version, this macro won't be any good.

The usefulness of %version_no_operators comes from the expectation that upstream will use dashes in the name, and we will generally convert it to ~ or ^ in packaging. And then you need to do the reverse for Source links and similar, and simply having a trivial operator that replaces ~ with ^ works surprisingly well.

See https://src.fedoraproject.org/rpms/systemd/blob/rawhide/f/systemd.spec#_50 for example: it's neither python nor rust, but having the macro makes the spec file simpler. Since ~ is used much more often than ^, %version_no_tilde already covers maybe 80% of similar cases, and %version_no_operators would cover 90%. The remaining cases can be handled with %(...) or whatever.

The problem with %version_no_tilde is that it converts the tilde to dash. We don't want that and the only way to use the macro is %{version_no_tilde %{quote:}} which is rather silly.

I think we want a dedicated macro that undoes the PEP440→RPM version conversion, even if it would currently be 99% similar to a macro that covers 90% of other cases.

Whether we want the general-purpose macro is another question. But, I'd rather name it according to the exact operation it does rather than intended usage, because in this case the usage doesn't really hint at what the macro would actually do.
As an idea, maybe we could approach something like %{tr %version -d ~} & %{tr %version ~ -}?

As an idea, maybe we could approach something like %{tr %version -d ~} & %{tr %version ~ -}?

That sounds doable. In the upstream ticket, I suggested %{version/~/} but that would require changes in rpm.

Please don't strip + as that can show up in actual Git tags.