Refactor python to rpm names conversion

Split convert_names_to_rpm method of py2rpm helper into two
higher-level methods:
- names_to_rpm_names, which returns a dict name -> rpm_name, which
  allows to get rid of unsafe zip(...) usage -- reqs and rpm names will
  never be out of sync again;
- names_to_rpm_requires, which returns list of RPM-styled requirements
  with versions for usage in specfile rendering.

Change-Id: I71faa244ae53bd2cefe872d0bf595c9aa4049812
This commit is contained in:
Ivan A. Melnikov
2014-01-14 17:20:05 +04:00
parent 2b20ab526d
commit b66b2f32c2
2 changed files with 49 additions and 28 deletions

View File

@@ -14,6 +14,10 @@
# License for the specific language governing permissions and limitations
# under the License.
import collections
import six
from anvil import log as logging
from anvil import settings
from anvil import shell as sh
@@ -62,36 +66,52 @@ class Helper(object):
out_filename = sh.joinpths(self._log_dir, "%s.log" % sh.basename(filename))
sh.execute_save_output(cmdline, cwd=marks_dir, out_filename=out_filename)
def convert_names_to_rpm(self, python_names, only_name=True):
def _convert_names_to_rpm(self, python_names, only_name):
if not python_names:
return []
return {}
cmdline = self._start_cmdline() + ["--convert"] + python_names
rpm_names = []
receive_names = set()
result = collections.defaultdict(set)
current_source = None
for line in sh.execute(cmdline)[0].splitlines():
# NOTE(harlowja): format is "Requires: rpm-name <=> X" or when
# the original requirement is denoted by the following comment
# lines "# Source: python-requirement" (used to make sure all
# requirements sent in come back out).
# lines "# Source: python-requirement"
if line.startswith("Requires:"):
line = line[len("Requires:"):].strip()
line = line[len("Requires:"):]
if only_name:
positions = [line.find(">"), line.find("<"), line.find("=")]
positions = sorted([p for p in positions if p != -1])
if positions:
line = line[0:positions[0]].strip()
if line:
rpm_names.append(line)
line = line[0:positions[0]]
result[current_source].add(line.strip())
elif line.startswith("# Source:"):
line = line[len("# Source:"):].strip()
if line:
receive_names.add(line)
current_source = line[len("# Source:"):].strip()
missing_names = set(python_names) - receive_names
missing_names = set(python_names) - set(result.keys())
if missing_names:
raise AssertionError("%s package names were lost during"
" conversion" % (missing_names))
return rpm_names
raise AssertionError("Python names were lost during conversion: %s"
% ', '.join(sorted(missing_names)))
extra_names = set(result.keys()) - set(python_names)
if extra_names:
raise AssertionError("Extra python names were found during conversion: %s"
% ', '.join(sorted(extra_names)))
return result
def names_to_rpm_names(self, python_names):
mapping = self._convert_names_to_rpm(python_names, only_name=True)
result = {}
for k, v in six.iteritems(mapping):
assert len(v) == 1, ('There should be exactly one RPM name for '
'python module %s, but we have: %s'
% (k, sorted(v)))
result[k] = v.pop()
return result
def names_to_rpm_requires(self, python_names):
mapping = self._convert_names_to_rpm(python_names, only_name=False)
return [req
for value in six.itervalues(mapping)
for req in value]
def build_all_srpms(self, package_files, tracewriter, jobs):
(_fn, content) = utils.load_template(sh.joinpths("packaging", "makefiles"), "source.mk")

View File

@@ -297,10 +297,11 @@ class YumDependencyHandler(base.DependencyHandler):
req_to_install = [pip_helper.extract_requirement(line)
for line in self.pips_to_install]
requested_names = [req.key for req in req_to_install]
rpm_to_install = self.py2rpm_helper.convert_names_to_rpm(requested_names)
rpm_names = self.py2rpm_helper.names_to_rpm_names(requested_names)
satisfied_list = []
for (req, rpm_name) in zip(req_to_install, rpm_to_install):
for req in req_to_install:
rpm_name = rpm_names[req.key]
(version, repo) = self._find_yum_match(yum_map, req, rpm_name)
if not repo:
# We need the source requirement incase its a url.
@@ -333,15 +334,15 @@ class YumDependencyHandler(base.DependencyHandler):
def _filter_package_files(package_files):
package_reqs = []
package_keys = []
for filename in package_files:
package_details = pip_helper.get_archive_details(filename)
package_reqs.append(package_details['req'])
package_keys.append(package_details['req'].key)
package_rpm_names = self.py2rpm_helper.convert_names_to_rpm(package_keys)
package_rpm_names = self.py2rpm_helper.names_to_rpm_names(
[req.key for req in package_reqs])
filtered_files = []
for (filename, req, rpm_name) in zip(package_files, package_reqs,
package_rpm_names):
for filename, req in zip(package_files, package_reqs):
rpm_name = package_rpm_names[req.key]
if req.key in no_pips:
LOG.info(("Dependency %s was downloaded additionally "
"but it is disallowed."), colorizer.quote(req))
@@ -383,7 +384,7 @@ class YumDependencyHandler(base.DependencyHandler):
if egg_info:
def ei_names(key):
requires_python = [str(req) for req in egg_info[key]]
return self.py2rpm_helper.convert_names_to_rpm(requires_python, False)
return self.py2rpm_helper.names_to_rpm_requires(requires_python)
requires_what.extend(ei_names('dependencies'))
test_requires_what.extend(ei_names('test_dependencies'))
@@ -605,9 +606,9 @@ class YumDependencyHandler(base.DependencyHandler):
for line in [line.strip() for line in requires if line.strip()]:
py_reqs.add(pip_helper.extract_requirement(line))
py_reqs = list(py_reqs)
rpm_names = self.py2rpm_helper.convert_names_to_rpm(map(str, py_reqs))
desired_rpms.extend(zip(rpm_names, py_reqs))
rpm_names = self.py2rpm_helper.names_to_rpm_names([req.key
for req in py_reqs])
desired_rpms.extend((rpm_names[req.key], req) for req in py_reqs)
def _format_name(rpm_name, py_req):
full_name = str(rpm_name).strip()