- Add new Python dependency generator (provides only for now) (#1340885)

This commit is contained in:
Florian Festi 2016-06-13 16:06:01 +02:00
parent ae2bf135f8
commit 82f61bba7f
4 changed files with 264 additions and 1 deletions

View File

@ -0,0 +1,20 @@
--- rpm-4.13.0-rc1/scripts/Makefile.am.orig 2015-09-01 19:45:43.896822977 +0200
+++ rpm-4.13.0-rc1/scripts/Makefile.am 2016-06-13 15:46:34.281390084 +0200
@@ -11,7 +11,7 @@
check-files check-prereqs \
check-buildroot check-rpaths check-rpaths-worker \
find-debuginfo.sh find-lang.sh \
- perl.prov perl.req pythondeps.sh \
+ perl.prov perl.req pythondeps.sh pythondistdeps.py \
rpmdb_loadcvt rpm.daily rpm.log rpm.supp rpm2cpio.sh \
tgpg vpkg-provides.sh \
find-requires find-provides \
@@ -30,7 +30,7 @@
check-files check-prereqs \
check-buildroot check-rpaths check-rpaths-worker \
find-lang.sh find-requires find-provides \
- perl.prov perl.req pythondeps.sh \
+ perl.prov perl.req pythondeps.sh pythondistdeps.py \
mono-find-requires mono-find-provides \
pkgconfigdeps.sh libtooldeps.sh \
ocaml-find-requires.sh ocaml-find-provides.sh \

View File

@ -0,0 +1,8 @@
--- rpm-4.13.0-rc1/fileattrs/python.attr.orig 2016-06-13 15:49:10.072832164 +0200
+++ rpm-4.13.0-rc1/fileattrs/python.attr 2016-06-13 15:50:46.687106846 +0200
@@ -1,4 +1,4 @@
-%__python_provides %{_rpmconfigdir}/pythondeps.sh --provides
+%__python_provides %{_rpmconfigdir}/pythondistdeps.py --provides
%__python_requires %{_rpmconfigdir}/pythondeps.sh --requires
%__python_path ^((/usr/lib(64)?/python[[:digit:]]\\.[[:digit:]]/.*\\.(py[oc]?|so))|(%{_bindir}/python[[:digit:]]\\.[[:digit:]]))$
%__python_magic [Pp]ython.*(executable|byte-compiled)

View File

@ -0,0 +1,229 @@
diff --git a/scripts/pythondistdeps.py b/scripts/pythondistdeps.py
new file mode 100755
index 0000000..8a2f43d
--- /dev/null
+++ b/scripts/pythondistdeps.py
@@ -0,0 +1,223 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2010 Per Øyvind Karlsen <proyvind@moondrake.org>
+# Copyright 2015 Neal Gompa <ngompa13@gmail.com>
+#
+# This program is free software. It may be redistributed and/or modified under
+# the terms of the LGPL version 2.1 (or later).
+#
+# RPM python dependency generator, using .egg-info/.egg-link/.dist-info data
+#
+
+from __future__ import print_function
+from getopt import getopt
+from os.path import basename, dirname, isdir, sep
+from sys import argv, stdin, version
+from distutils.sysconfig import get_python_lib
+
+
+opts, args = getopt(
+ argv[1:], 'hPRrCEMLl:',
+ ['help', 'provides', 'requires', 'recommends', 'conflicts', 'extras', 'majorver-provides', 'legacy-provides' , 'legacy'])
+
+Provides = False
+Requires = False
+Recommends = False
+Conflicts = False
+Extras = False
+Provides_PyMajorVer_Variant = False
+legacy_Provides = False
+legacy = False
+
+for o, a in opts:
+ if o in ('-h', '--help'):
+ print('-h, --help\tPrint help')
+ print('-P, --provides\tPrint Provides')
+ print('-R, --requires\tPrint Requires')
+ print('-r, --recommends\tPrint Recommends')
+ print('-C, --conflicts\tPrint Conflicts')
+ print('-E, --extras\tPrint Extras ')
+ print('-M, --majorver-provides\tPrint extra Provides with Python major version only')
+ print('-L, --legacy-provides\tPrint extra legacy pythonegg Provides')
+ print('-l, --legacy\tPrint legacy pythonegg Provides/Requires instead')
+ exit(1)
+ elif o in ('-P', '--provides'):
+ Provides = True
+ elif o in ('-R', '--requires'):
+ Requires = True
+ elif o in ('-r', '--recommends'):
+ Recommends = True
+ elif o in ('-C', '--conflicts'):
+ Conflicts = True
+ elif o in ('-E', '--extras'):
+ Extras = True
+ elif o in ('-M', '--majorver-provides'):
+ Provides_PyMajorVer_Variant = True
+ elif o in ('-L', '--legacy-provides'):
+ legacy_Provides = True
+ elif o in ('-l', '--legacy'):
+ legacy = True
+
+if Requires:
+ py_abi = True
+else:
+ py_abi = False
+py_deps = {}
+if args:
+ files = args
+else:
+ files = stdin.readlines()
+
+for f in files:
+ f = f.strip()
+ lower = f.lower()
+ name = 'python(abi)'
+ # add dependency based on path, versioned if within versioned python directory
+ if py_abi and (lower.endswith('.py') or lower.endswith('.pyc') or lower.endswith('.pyo')):
+ if name not in py_deps:
+ py_deps[name] = []
+ purelib = get_python_lib(standard_lib=1, plat_specific=0).split(version[:3])[0]
+ platlib = get_python_lib(standard_lib=1, plat_specific=1).split(version[:3])[0]
+ for lib in (purelib, platlib):
+ if lib in f:
+ spec = ('==', f.split(lib)[1].split(sep)[0])
+ if spec not in py_deps[name]:
+ py_deps[name].append(spec)
+
+ # XXX: hack to workaround RPM internal dependency generator not passing directories
+ lower_dir = dirname(lower)
+ if lower_dir.endswith('.egg') or \
+ lower_dir.endswith('.egg-info') or \
+ lower_dir.endswith('.egg-link') or \
+ lower_dir.endswith('.dist-info'):
+ lower = lower_dir
+ f = dirname(f)
+ # Determine provide, requires, conflicts & recommends based on egg/dist metadata
+ if lower.endswith('.egg') or \
+ lower.endswith('.egg-info') or \
+ lower.endswith('.egg-link') or \
+ lower.endswith('.dist-info'):
+ # This import is very slow, so only do it if needed
+ from pkg_resources import Distribution, FileMetadata, PathMetadata
+ dist_name = basename(f)
+ if isdir(f):
+ path_item = dirname(f)
+ metadata = PathMetadata(path_item, f)
+ else:
+ path_item = f
+ metadata = FileMetadata(f)
+ dist = Distribution.from_location(path_item, dist_name, metadata)
+ if (Provides_PyMajorVer_Variant or legacy_Provides or legacy) and Provides:
+ # Get the Python major version
+ pyver_major = dist.py_version.split('.')[0]
+ if Provides:
+ # If egg/dist metadata says package name is python, we provide python(abi)
+ if dist.key == 'python':
+ name = 'python(abi)'
+ if name not in py_deps:
+ py_deps[name] = []
+ py_deps[name].append(('==', dist.py_version))
+ if not legacy:
+ name = 'python{}dist({})'.format(dist.py_version, dist.key)
+ if name not in py_deps:
+ py_deps[name] = []
+ if Provides_PyMajorVer_Variant:
+ pymajor_name = 'python{}dist({})'.format(pyver_major, dist.key)
+ if pymajor_name not in py_deps:
+ py_deps[pymajor_name] = []
+ if legacy or legacy_Provides:
+ legacy_name = 'pythonegg({})({})'.format(pyver_major, dist.key)
+ if legacy_name not in py_deps:
+ py_deps[legacy_name] = []
+ if dist.version:
+ spec = ('==', dist.version)
+ if spec not in py_deps[name]:
+ if not legacy:
+ py_deps[name].append(spec)
+ if Provides_PyMajorVer_Variant:
+ py_deps[pymajor_name].append(spec)
+ if legacy or legacy_Provides:
+ py_deps[legacy_name].append(spec)
+ if Requires or (Recommends and dist.extras):
+ name = 'python(abi)'
+ # If egg/dist metadata says package name is python, we don't add dependency on python(abi)
+ if dist.key == 'python':
+ py_abi = False
+ if name in py_deps:
+ py_deps.pop(name)
+ elif py_abi and dist.py_version:
+ if name not in py_deps:
+ py_deps[name] = []
+ spec = ('==', dist.py_version)
+ if spec not in py_deps[name]:
+ py_deps[name].append(spec)
+ deps = dist.requires()
+ if Recommends:
+ depsextras = dist.requires(extras=dist.extras)
+ if not Requires:
+ for dep in reversed(depsextras):
+ if dep in deps:
+ depsextras.remove(dep)
+ deps = depsextras
+ # add requires/recommends based on egg/dist metadata
+ for dep in deps:
+ if legacy:
+ name = 'pythonegg({})({})'.format(pyver_major, dep.key)
+ else:
+ name = 'python{}dist({})'.format(dist.py_version, dep.key)
+ for spec in dep.specs:
+ if spec[0] != '!=':
+ if name not in py_deps:
+ py_deps[name] = []
+ if spec not in py_deps[name]:
+ py_deps[name].append(spec)
+ if not dep.specs:
+ py_deps[name] = []
+ # Unused, for automatic sub-package generation based on 'extras' from egg/dist metadata
+ # TODO: implement in rpm later, or...?
+ if Extras:
+ deps = dist.requires()
+ extras = dist.extras
+ print(extras)
+ for extra in extras:
+ print('%%package\textras-{}'.format(extra))
+ print('Summary:\t{} extra for {} python package'.format(extra, dist.key))
+ print('Group:\t\tDevelopment/Python')
+ depsextras = dist.requires(extras=[extra])
+ for dep in reversed(depsextras):
+ if dep in deps:
+ depsextras.remove(dep)
+ deps = depsextras
+ for dep in deps:
+ for spec in dep.specs:
+ if spec[0] == '!=':
+ print('Conflicts:\t{} {} {}'.format(dep.key, '==', spec[1]))
+ else:
+ print('Requires:\t{} {} {}'.format(dep.key, spec[0], spec[1]))
+ print('%%description\t{}'.format(extra))
+ print('{} extra for {} python package'.format(extra, dist.key))
+ print('%%files\t\textras-{}\n'.format(extra))
+ if Conflicts:
+ # Should we really add conflicts for extras?
+ # Creating a meta package per extra with recommends on, which has
+ # the requires/conflicts in stead might be a better solution...
+ for dep in dist.requires(extras=dist.extras):
+ name = dep.key
+ for spec in dep.specs:
+ if spec[0] == '!=':
+ if name not in py_deps:
+ py_deps[name] = []
+ spec = ('==', spec[1])
+ if spec not in py_deps[name]:
+ py_deps[name].append(spec)
+names = list(py_deps.keys())
+names.sort()
+for name in names:
+ if py_deps[name]:
+ # Print out versioned provides, requires, recommends, conflicts
+ for spec in py_deps[name]:
+ print('{} {} {}'.format(name, spec[0], spec[1]))
+ else:
+ # Print out unversioned provides, requires, recommends, conflicts
+ print(name)

View File

@ -29,7 +29,7 @@
Summary: The RPM package management system
Name: rpm
Version: %{rpmver}
Release: %{?snapver:0.%{snapver}.}37%{?dist}
Release: %{?snapver:0.%{snapver}.}38%{?dist}
Group: System Environment/Base
Url: http://www.rpm.org/
Source0: http://rpm.org/releases/rpm-4.12.x/%{name}-%{srcver}.tar.bz2
@ -85,6 +85,9 @@ Patch129: rpm-4.13.0-filter-unversioned.patch
Patch130: rpm-4.13.0-armv7hl-isa.patch
Patch131: rpm-4.13.0-non-ASCII-keys.patch
Patch132: rpm-4.13.0-_buildhost-macro.diff
Patch133: rpm-4.13.x-pythondistdeps.patch
Patch134: rpm-4.13.x-pythondistdeps-Makefile.patch
Patch135: rpm-4.13.x-pythondistdeps-fileattr.patch
# These are not yet upstream
Patch302: rpm-4.7.1-geode-i686.patch
@ -596,6 +599,9 @@ exit 0
%doc doc/librpm/html/*
%changelog
* Mon Jun 13 2016 Florian Festi <ffesti@rpm.org> - 4.4.13.0-0.rc1.38
- Add new Python dependency generator (provides only for now) (#1340885)
* Thu Jun 02 2016 Florian Festi <ffesti@rpm.org> - 4.4.13.0-0.rc1.37
- Add support for _buildhost macro (#1309367)