Merge ~smoser/curtin:fix/1786795-get_package_version into curtin:master

Proposed by Scott Moser
Status: Merged
Approved by: Scott Moser
Approved revision: 3814cacbd756549fa139cf0eae3ae3e8542a884e
Merge reported by: Server Team CI bot
Merged at revision: not available
Proposed branch: ~smoser/curtin:fix/1786795-get_package_version
Merge into: curtin:master
Diff against target: 137 lines (+93/-6)
2 files modified
curtin/util.py (+31/-6)
tests/unittests/test_util.py (+62/-0)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Ryan Harper (community) Approve
Review via email: mp+353010@code.launchpad.net

Commit message

parse_dpkg_version: support non-numeric in version string.

This fixes parse_dpkg_version for packages with non-numeric (0-9.)
in their versions. It also improves it to work for native packages.
Native packages do not have '-'. Also adds tests of parse_dpkg_version.

LP: #1786795

Description of the change

see commit message

To post a comment you must log in.
Revision history for this message
Ryan Harper (raharper) wrote :

Really nice clean up. Thanks!

review: Approve
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Needs Fixing (continuous-integration)
3814cac... by Scott Moser

flake8

Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/curtin/util.py b/curtin/util.py
2index 7d06c09..3c868b7 100644
3--- a/curtin/util.py
4+++ b/curtin/util.py
5@@ -810,13 +810,37 @@ def parse_dpkg_version(raw, name=None, semx=None):
6 """Parse a dpkg version string into various parts and calcualate a
7 numerical value of the version for use in comparing package versions
8
9- returns a dictionary with the results
10+ Native packages (without a '-'), will have the package version treated
11+ as the upstream version.
12+
13+ returns a dictionary with fields:
14+ 'major' (int), 'minor' (int), 'micro' (int),
15+ 'semantic_version' (int),
16+ 'extra' (string), 'raw' (string), 'upstream' (string),
17+ 'name' (present only if name is not None)
18 """
19+ if not isinstance(raw, string_types):
20+ raise TypeError(
21+ "Invalid type %s for parse_dpkg_version" % raw.__class__)
22+
23 if semx is None:
24 semx = (10000, 100, 1)
25
26- upstream = raw.split('-')[0]
27- toks = upstream.split(".", 2)
28+ if "-" in raw:
29+ upstream = raw.rsplit('-', 1)[0]
30+ else:
31+ # this is a native package, package version treated as upstream.
32+ upstream = raw
33+
34+ match = re.search(r'[^0-9.]', upstream)
35+ if match:
36+ extra = upstream[match.start():]
37+ upstream_base = upstream[:match.start()]
38+ else:
39+ upstream_base = upstream
40+ extra = None
41+
42+ toks = upstream_base.split(".", 2)
43 if len(toks) == 3:
44 major, minor, micro = toks
45 elif len(toks) == 2:
46@@ -825,9 +849,10 @@ def parse_dpkg_version(raw, name=None, semx=None):
47 major, minor, micro = (toks[0], 0, 0)
48
49 version = {
50- 'major': major,
51- 'minor': minor,
52- 'micro': micro,
53+ 'major': int(major),
54+ 'minor': int(minor),
55+ 'micro': int(micro),
56+ 'extra': extra,
57 'raw': raw,
58 'upstream': upstream,
59 }
60diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
61index 483cd5d..7fb332d 100644
62--- a/tests/unittests/test_util.py
63+++ b/tests/unittests/test_util.py
64@@ -4,6 +4,7 @@ from unittest import skipIf
65 import mock
66 import os
67 import stat
68+import sys
69 from textwrap import dedent
70
71 from curtin import util
72@@ -1035,4 +1036,65 @@ class TestLoadKernelModule(CiTestCase):
73 self.assertEqual(0, self.m_subp.call_count)
74
75
76+class TestParseDpkgVersion(CiTestCase):
77+ """test parse_dpkg_version."""
78+
79+ def test_none_raises_type_error(self):
80+ self.assertRaises(TypeError, util.parse_dpkg_version, None)
81+
82+ @skipIf(sys.version_info.major < 3, "python 2 bytes are strings.")
83+ def test_bytes_raises_type_error(self):
84+ self.assertRaises(TypeError, util.parse_dpkg_version, b'1.2.3-0')
85+
86+ def test_simple_native_package_version(self):
87+ """dpkg versions must have a -. If not present expect value error."""
88+ self.assertEqual(
89+ {'major': 2, 'minor': 28, 'micro': 0, 'extra': None,
90+ 'raw': '2.28', 'upstream': '2.28', 'name': 'germinate',
91+ 'semantic_version': 22800},
92+ util.parse_dpkg_version('2.28', name='germinate'))
93+
94+ def test_complex_native_package_version(self):
95+ dver = '1.0.106ubuntu2+really1.0.97ubuntu1'
96+ self.assertEqual(
97+ {'major': 1, 'minor': 0, 'micro': 106,
98+ 'extra': 'ubuntu2+really1.0.97ubuntu1',
99+ 'raw': dver, 'upstream': dver, 'name': 'debootstrap',
100+ 'semantic_version': 100106},
101+ util.parse_dpkg_version(dver, name='debootstrap',
102+ semx=(100000, 1000, 1)))
103+
104+ def test_simple_valid(self):
105+ self.assertEqual(
106+ {'major': 1, 'minor': 2, 'micro': 3, 'extra': None,
107+ 'raw': '1.2.3-0', 'upstream': '1.2.3', 'name': 'foo',
108+ 'semantic_version': 10203},
109+ util.parse_dpkg_version('1.2.3-0', name='foo'))
110+
111+ def test_simple_valid_with_semx(self):
112+ self.assertEqual(
113+ {'major': 1, 'minor': 2, 'micro': 3, 'extra': None,
114+ 'raw': '1.2.3-0', 'upstream': '1.2.3',
115+ 'semantic_version': 123},
116+ util.parse_dpkg_version('1.2.3-0', semx=(100, 10, 1)))
117+
118+ def test_upstream_with_hyphen(self):
119+ """upstream versions may have a hyphen."""
120+ cver = '18.2-14-g6d48d265-0ubuntu1'
121+ self.assertEqual(
122+ {'major': 18, 'minor': 2, 'micro': 0, 'extra': '-14-g6d48d265',
123+ 'raw': cver, 'upstream': '18.2-14-g6d48d265',
124+ 'name': 'cloud-init', 'semantic_version': 180200},
125+ util.parse_dpkg_version(cver, name='cloud-init'))
126+
127+ def test_upstream_with_plus(self):
128+ """multipath tools has a + in it."""
129+ mver = '0.5.0+git1.656f8865-5ubuntu2.5'
130+ self.assertEqual(
131+ {'major': 0, 'minor': 5, 'micro': 0, 'extra': '+git1.656f8865',
132+ 'raw': mver, 'upstream': '0.5.0+git1.656f8865',
133+ 'semantic_version': 500},
134+ util.parse_dpkg_version(mver))
135+
136+
137 # vi: ts=4 expandtab syntax=python

Subscribers

People subscribed via source and target branches