These two methods are needed for upgradepath, but they can be generally
useful for any check or library call working with epochs.
Details
Details
Tests added.
Diff Detail
Diff Detail
- Lint
Lint Skipped - Unit
Unit Tests Skipped
These two methods are needed for upgradepath, but they can be generally
useful for any check or library call working with epochs.
Tests added.
Lint Skipped |
Unit Tests Skipped |
Path | |||
---|---|---|---|
M | libtaskotron/koji_utils.py (38 lines) | ||
M | libtaskotron/rpm_utils.py (27 lines) | ||
M | testing/test_koji_utils.py (28 lines) | ||
M | testing/test_rpm_utils.py (42 lines) |
Commit | Tree | Parents | Author | Summary | Date |
---|---|---|---|---|---|
752a9dd4807e | 7c37e47be6db | ff41db8250e6 | Kamil Páral | add koji_utils.getNEVR() and rpm_utils.cmpNEVR() (Show More…) | Apr 24 2014, 4:52 PM |
1 | # -*- coding: utf-8 -*- | ||||
---|---|---|---|---|---|
2 | # Copyright 2014, Red Hat, Inc. | ||||
3 | # License: GNU General Public License version 2 or later | ||||
4 | | ||||
5 | ''' Utility methods related to Koji ''' | ||||
6 | | ||||
7 | import collections | ||||
1 | import koji | 8 | import koji | ||
9 | import hawkey | ||||
2 | 10 | | |||
3 | from libtaskotron import file_utils | 11 | from libtaskotron import file_utils | ||
4 | from libtaskotron.logger import log | 12 | from libtaskotron.logger import log | ||
5 | from libtaskotron.exceptions import TaskotronRemoteError | 13 | from libtaskotron import exceptions as exc | ||
14 | from libtaskotron import rpm_utils | ||||
6 | 15 | | |||
7 | KOJI_URL = 'http://koji.fedoraproject.org/kojihub' | 16 | KOJI_URL = 'http://koji.fedoraproject.org/kojihub' | ||
8 | PKG_URL = 'http://kojipkgs.fedoraproject.org/packages' | 17 | PKG_URL = 'http://kojipkgs.fedoraproject.org/packages' | ||
9 | 18 | | |||
10 | class KojiClient(object): | 19 | class KojiClient(object): | ||
11 | def __init__(self, koji_session=None): | 20 | def __init__(self, koji_session=None): | ||
12 | self.session = koji_session | 21 | self.session = koji_session | ||
13 | 22 | | |||
Show All 16 Lines | 29 | def nvr_to_urls(self, nvr, arches=None, debuginfo=False, src=True): | |||
30 | ksession = self.get_koji_session() | 39 | ksession = self.get_koji_session() | ||
31 | 40 | | |||
32 | # add i686 arch if i386 is present in arches | 41 | # add i686 arch if i386 is present in arches | ||
33 | if arches and 'i386' in arches and 'i686' not in arches: | 42 | if arches and 'i386' in arches and 'i686' not in arches: | ||
34 | arches.append('i686') | 43 | arches.append('i686') | ||
35 | 44 | | |||
36 | info = ksession.getBuild(nvr) | 45 | info = ksession.getBuild(nvr) | ||
37 | if info is None: | 46 | if info is None: | ||
38 | raise TaskotronRemoteError( | 47 | raise exc.TaskotronRemoteError( | ||
39 | "No build information found for %s" % nvr) | 48 | "No build information found for %s" % nvr) | ||
40 | 49 | | |||
41 | baseurl = '/'.join((PKG_URL, info['package_name'], | 50 | baseurl = '/'.join((PKG_URL, info['package_name'], | ||
42 | info['version'], info['release'])) | 51 | info['version'], info['release'])) | ||
43 | 52 | | |||
44 | rpms = ksession.listRPMs(buildID=info['id'], arches=arches) | 53 | rpms = ksession.listRPMs(buildID=info['id'], arches=arches) | ||
45 | if not debuginfo: | 54 | if not debuginfo: | ||
46 | rpms = [r for r in rpms if not r['name'].endswith('-debuginfo')] | 55 | rpms = [r for r in rpms if not r['name'].endswith('-debuginfo')] | ||
47 | if not src: | 56 | if not src: | ||
48 | rpms = [r for r in rpms if not r['arch'] == 'src'] | 57 | rpms = [r for r in rpms if not r['arch'] == 'src'] | ||
49 | 58 | | |||
50 | urls = ['%s/%s' % (baseurl, koji.pathinfo.rpm(r)) for r in rpms] | 59 | urls = ['%s/%s' % (baseurl, koji.pathinfo.rpm(r)) for r in rpms] | ||
51 | if len(urls) == 0: | 60 | if len(urls) == 0: | ||
52 | raise TaskotronRemoteError('No RPMs found for %s' % nvr) | 61 | raise exc.TaskotronRemoteError('No RPMs found for %s' % nvr) | ||
53 | 62 | | |||
54 | return sorted(urls) | 63 | return sorted(urls) | ||
55 | 64 | | |||
56 | def get_nvr_rpms(self, nvr, rpm_dir, arches=None, debuginfo=False, | 65 | def get_nvr_rpms(self, nvr, rpm_dir, arches=None, debuginfo=False, | ||
57 | src=False): | 66 | src=False): | ||
58 | '''Retrieve the RPMs associated with a build NVR into the specified | 67 | '''Retrieve the RPMs associated with a build NVR into the specified | ||
59 | directory. | 68 | directory. | ||
60 | 69 | | |||
Show All 27 Lines | 90 | def get_tagged_rpms(self, tag, dest, arches): | |||
88 | opts = {} | 97 | opts = {} | ||
89 | tag_data = ksession.listTagged(tag, **opts) | 98 | tag_data = ksession.listTagged(tag, **opts) | ||
90 | 99 | | |||
91 | nvrs = ["%(nvr)s" % x for x in tag_data] | 100 | nvrs = ["%(nvr)s" % x for x in tag_data] | ||
92 | rpms = [] | 101 | rpms = [] | ||
93 | for nvr in nvrs: | 102 | for nvr in nvrs: | ||
94 | rpms.append(self.get_nvr_rpms(nvr, dest, arches)) | 103 | rpms.append(self.get_nvr_rpms(nvr, dest, arches)) | ||
95 | return rpms | 104 | return rpms | ||
105 | | ||||
106 | | ||||
107 | def getNEVR(build): | ||||
108 | '''Extract RPM version identifier in NEVR format from Koji build object | ||||
109 | | ||||
110 | @param build Koji buildinfo dictionary (as returned from @module koji | ||||
111 | methods like getBuild()) | ||||
112 | @return NEVR string; epoch is included when non-zero, otherwise omitted | ||||
113 | @raise TaskotronValueError if @param build is of incorrect type | ||||
114 | ''' | ||||
115 | # validate input | ||||
116 | if (not isinstance(build, collections.Mapping) or 'nvr' not in build or | ||||
117 | 'epoch' not in build): | ||||
118 | raise exc.TaskotronValueError("Input argument doesn't look like " | ||||
119 | "a Koji build object: %s" % build) | ||||
120 | | ||||
121 | rpmver = hawkey.split_nevra(build['nvr'] + '.noarch') | ||||
122 | rpmver.epoch = build['epoch'] or 0 | ||||
123 | nevr = '%s-%s' % (rpmver.name, rpmver.evr()) | ||||
124 | # supress 0 epoch (evr() method always includes epoch, even if 0) | ||||
125 | nevr = rpm_utils.rpmformat(nevr, fmt='nevr') | ||||
126 | | ||||
127 | return nevr |
1 | # -*- coding: utf-8 -*- | 1 | # -*- coding: utf-8 -*- | ||
---|---|---|---|---|---|
2 | # Copyright 2014, Red Hat, Inc. | 2 | # Copyright 2014, Red Hat, Inc. | ||
3 | # License: GNU General Public License version 2 or later | 3 | # License: GNU General Public License version 2 or later | ||
4 | 4 | | |||
5 | ''' Utility methods related to RPM and YUM/DNF ''' | 5 | ''' Utility methods related to RPM ''' | ||
6 | 6 | | |||
7 | import os | 7 | import os | ||
8 | import hawkey | 8 | import hawkey | ||
9 | 9 | | |||
10 | from . import exceptions as exc | 10 | from libtaskotron import exceptions as exc | ||
11 | 11 | | |||
12 | 12 | | |||
13 | def basearch(arch=None): | 13 | def basearch(arch=None): | ||
14 | ''' | 14 | ''' | ||
15 | This returns the 'base' architecture identifier for a specified architecture | 15 | This returns the 'base' architecture identifier for a specified architecture | ||
16 | (e.g. i386 for i[3-6]86), to be used by YUM etc. | 16 | (e.g. i386 for i[3-6]86), to be used by YUM etc. | ||
17 | 17 | | |||
18 | @param arch an arch (string) to be converted to a basearch. If None, then | 18 | @param arch an arch (string) to be converted to a basearch. If None, then | ||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Line(s) | 29 | def rpmformat(rpmstr, fmt='nvr', end_arch=False): | |||
77 | 77 | | |||
78 | result = '%s-%s' % (nevra.name, evr) | 78 | result = '%s-%s' % (nevra.name, evr) | ||
79 | 79 | | |||
80 | # append arch if requested | 80 | # append arch if requested | ||
81 | if 'a' in fmt: | 81 | if 'a' in fmt: | ||
82 | result += '.' + nevra.arch | 82 | result += '.' + nevra.arch | ||
83 | 83 | | |||
84 | return result | 84 | return result | ||
85 | | ||||
86 | | ||||
87 | def cmpNEVR(nevr1, nevr2): | ||||
88 | '''Compare two RPM version identifiers in NEVR format. | ||||
89 | | ||||
90 | @param nevr1 a string in N(E)VR format | ||||
91 | @param nevr2 a string in N(E)VR format | ||||
92 | @return -1/0/1 if nevr1 < nevr2 / nevr1 == nevr2 / nevr1 > nevr2 | ||||
93 | @raise TaskotronValueError if name in nevr1 doesn't match name in nevr2 | ||||
94 | ''' | ||||
95 | rpmver1 = hawkey.split_nevra(nevr1 + '.noarch') | ||||
96 | rpmver2 = hawkey.split_nevra(nevr2 + '.noarch') | ||||
97 | | ||||
98 | if rpmver1.name != rpmver2.name: | ||||
99 | raise exc.TaskotronValueError("Name in nevr1 doesn't match name in " | ||||
100 | "nevr2: %s, %s" % (nevr1, nevr2)) | ||||
101 | | ||||
102 | # sack is needed for the comparison, because it can be influence the | ||||
103 | # comparison (for example epoch can be set to be ignored). A default empty | ||||
104 | # sack should match Fedora customs | ||||
105 | sack = hawkey.Sack() | ||||
106 | | ||||
107 | return rpmver1.evr_cmp(rpmver2, sack) |
1 | # -*- coding: utf-8 -*- | ||||
---|---|---|---|---|---|
2 | # Copyright 2014, Red Hat, Inc. | ||||
3 | # License: GNU General Public License version 2 or later | ||||
4 | | ||||
5 | '''Unit tests for libtaskotron/koji_utils.py''' | ||||
6 | | ||||
1 | import pytest | 7 | import pytest | ||
2 | from dingus import Dingus | 8 | from dingus import Dingus | ||
3 | 9 | | |||
4 | from libtaskotron import koji_utils | 10 | from libtaskotron import koji_utils | ||
11 | from libtaskotron import exceptions as exc | ||||
5 | 12 | | |||
6 | class TestKojiClient(): | 13 | class TestKojiClient(): | ||
7 | def setup_method(self, method): | 14 | def setup_method(self, method): | ||
8 | self.ref_nvr = 'foo-1.2-3.fc99' | 15 | self.ref_nvr = 'foo-1.2-3.fc99' | ||
9 | self.ref_arch = 'noarch' | 16 | self.ref_arch = 'noarch' | ||
10 | self.ref_name = 'foo' | 17 | self.ref_name = 'foo' | ||
11 | self.ref_version = '1.2' | 18 | self.ref_version = '1.2' | ||
12 | self.ref_release = '3.fc99' | 19 | self.ref_release = '3.fc99' | ||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Line(s) | |||||
70 | def should_throw_exception_norpms(self): | 77 | def should_throw_exception_norpms(self): | ||
71 | stub_koji = Dingus(getBuild__returns = self.ref_build) | 78 | stub_koji = Dingus(getBuild__returns = self.ref_build) | ||
72 | 79 | | |||
73 | test_koji = koji_utils.KojiClient(stub_koji) | 80 | test_koji = koji_utils.KojiClient(stub_koji) | ||
74 | 81 | | |||
75 | with pytest.raises(Exception): | 82 | with pytest.raises(Exception): | ||
76 | test_koji.nvr_to_urls(self.ref_nvr, arches = [self.ref_arch]) | 83 | test_koji.nvr_to_urls(self.ref_nvr, arches = [self.ref_arch]) | ||
77 | 84 | | |||
85 | | ||||
86 | class TestGetENVR(object): | ||||
87 | | ||||
88 | def test_epoch(self): | ||||
89 | '''Epoch included in build''' | ||||
90 | build = {'nvr': 'foo-1.2-3.fc20', | ||||
91 | 'epoch': 1, | ||||
92 | } | ||||
93 | assert koji_utils.getNEVR(build) == 'foo-1:1.2-3.fc20' | ||||
94 | | ||||
95 | def test_no_epoch(self): | ||||
96 | '''Epoch not included in build''' | ||||
97 | build = {'nvr': 'foo-1.2-3.fc20', | ||||
98 | 'epoch': None, | ||||
99 | } | ||||
100 | assert koji_utils.getNEVR(build) == 'foo-1.2-3.fc20' | ||||
101 | | ||||
102 | def test_raise(self): | ||||
103 | '''Invalid input param''' | ||||
104 | with pytest.raises(exc.TaskotronValueError): | ||||
105 | koji_utils.getNEVR('foo-1.2-3.fc20') |
1 | # -*- coding: utf-8 -*- | 1 | # -*- coding: utf-8 -*- | ||
---|---|---|---|---|---|
2 | # Copyright 2014, Red Hat, Inc. | 2 | # Copyright 2014, Red Hat, Inc. | ||
3 | # License: GNU General Public License version 2 or later | 3 | # License: GNU General Public License version 2 or later | ||
4 | 4 | | |||
5 | '''Unit tests for libtaskotron/rpm_utils.py''' | 5 | '''Unit tests for libtaskotron/rpm_utils.py''' | ||
6 | 6 | | |||
7 | import pytest | 7 | import pytest | ||
8 | 8 | | |||
9 | from libtaskotron.rpm_utils import basearch, rpmformat | 9 | from libtaskotron.rpm_utils import basearch, rpmformat, cmpNEVR | ||
10 | from libtaskotron import exceptions as exc | 10 | from libtaskotron import exceptions as exc | ||
11 | 11 | | |||
12 | 12 | | |||
13 | class TestBasearch: | 13 | class TestBasearch: | ||
14 | 14 | | |||
15 | def test_basearch_i386(self): | 15 | def test_basearch_i386(self): | ||
16 | '''i386-like archs''' | 16 | '''i386-like archs''' | ||
17 | assert basearch('i386') == 'i386' | 17 | assert basearch('i386') == 'i386' | ||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Line(s) | 100 | def test_raise(self): | |||
102 | with pytest.raises(exc.TaskotronValueError): | 102 | with pytest.raises(exc.TaskotronValueError): | ||
103 | rpmformat('foo-1.2-3.fc20', 'x') | 103 | rpmformat('foo-1.2-3.fc20', 'x') | ||
104 | 104 | | |||
105 | with pytest.raises(exc.TaskotronValueError): | 105 | with pytest.raises(exc.TaskotronValueError): | ||
106 | rpmformat('foo-1.2-3.fc20', 'envra') | 106 | rpmformat('foo-1.2-3.fc20', 'envra') | ||
107 | 107 | | |||
108 | with pytest.raises(exc.TaskotronValueError): | 108 | with pytest.raises(exc.TaskotronValueError): | ||
109 | rpmformat('foo-1.2-3.fc20', 'n-v-r') | 109 | rpmformat('foo-1.2-3.fc20', 'n-v-r') | ||
110 | | ||||
111 | | ||||
112 | class TestCmpNEVR(object): | ||||
113 | | ||||
114 | def test_no_epoch(self): | ||||
115 | '''Both params without epoch''' | ||||
116 | assert cmpNEVR('foo-1.2-3.fc20', 'foo-1.2-2.fc20') == 1 | ||||
117 | assert cmpNEVR('foo-1.2-3.fc20', 'foo-1.2-3.fc20') == 0 | ||||
118 | assert cmpNEVR('foo-1.2-3.fc20', 'foo-1.2-4.fc20') == -1 | ||||
119 | | ||||
120 | assert cmpNEVR('foo-1.2-3.fc20', 'foo-1.1-4.fc20') == 1 | ||||
121 | assert cmpNEVR('foo-1.2-3.fc20', 'foo-2.1-1.fc20') == -1 | ||||
122 | assert cmpNEVR('foo-1.2-3.fc20', 'foo-1.2-3.fc19') == 1 | ||||
123 | | ||||
124 | def test_epoch(self): | ||||
125 | '''Both params with epoch''' | ||||
126 | assert cmpNEVR('foo-1:1.2-3.fc20', 'foo-1:1.2-2.fc20') == 1 | ||||
127 | assert cmpNEVR('foo-1:1.2-3.fc20', 'foo-1:1.2-3.fc20') == 0 | ||||
128 | assert cmpNEVR('foo-0:1.2-3.fc20', 'foo-0:1.2-3.fc20') == 0 | ||||
129 | assert cmpNEVR('foo-3:1.2-3.fc20', 'foo-3:1.2-4.fc20') == -1 | ||||
130 | | ||||
131 | assert cmpNEVR('foo-2:1.2-3.fc20', 'foo-2:1.1-4.fc20') == 1 | ||||
132 | assert cmpNEVR('foo-2:1.2-3.fc20', 'foo-2:2.1-1.fc20') == -1 | ||||
133 | assert cmpNEVR('foo-2:1.2-3.fc20', 'foo-2:1.2-3.fc19') == 1 | ||||
134 | | ||||
135 | assert cmpNEVR('foo-1:1.2-3.fc20', 'foo-2:1.2-3.fc20') == -1 | ||||
136 | assert cmpNEVR('foo-1:1.2-3.fc20', 'foo-0:1.2-3.fc20') == 1 | ||||
137 | assert cmpNEVR('foo-1:1.2-3.fc20', 'foo-0:2.2-3.fc20') == 1 | ||||
138 | | ||||
139 | def test_some_epoch(self): | ||||
140 | '''One param with epoch''' | ||||
141 | assert cmpNEVR('foo-1:1.2-3.fc20', 'foo-1.2-3.fc20') == 1 | ||||
142 | assert cmpNEVR('foo-1:1.2-3.fc20', 'foo-2.2-3.fc20') == 1 | ||||
143 | assert cmpNEVR('foo-0:1.2-3.fc20', 'foo-1.2-3.fc20') == 0 | ||||
144 | assert cmpNEVR('foo-1.2-3.fc20', 'foo-2:0.1-1.fc19') == -1 | ||||
145 | | ||||
146 | def test_raise(self): | ||||
147 | '''Invalid input param''' | ||||
148 | with pytest.raises(exc.TaskotronValueError): | ||||
149 | cmpNEVR('foo-1.2-3.fc20', 'bar-1.2-3.fc20') |