Merge lp:~jml/pkgme/clean-package-name into lp:pkgme

Proposed by Jonathan Lange
Status: Merged
Approved by: James Westby
Approved revision: 103
Merged at revision: 99
Proposed branch: lp:~jml/pkgme/clean-package-name
Merge into: lp:pkgme
Diff against target: 155 lines (+68/-6)
4 files modified
pkgme/info_elements.py (+22/-1)
pkgme/tests/test_info_elements.py (+38/-0)
pkgme/tests/test_package_files.py (+6/-3)
pkgme/tests/test_write_packaging.py (+2/-2)
To merge this branch: bzr merge lp:~jml/pkgme/clean-package-name
Reviewer Review Type Date Requested Status
James Westby Approve
Review via email: mp+91561@code.launchpad.net

Commit message

Enforce Debian package name policy in PackageName.

Description of the change

Encodes http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Source into the PackageName info element.

This takes some of the burden that lp:pkgme-binary has in guessing the package name when it's not provided. The general method is to remove offending characters and produce a clean result if we can, only raising an exception when it becomes impossible to clean by removing (i.e. when the package name is too short).

To post a comment you must log in.
Revision history for this message
James Westby (james-w) wrote :

Hi,

This looks good.

I'm not entirely sure that dropping invalid chars rather than
substituting them or erroring is the right thing, but I'm not
entirely unsure either.

Thanks,

James

review: Approve
Revision history for this message
Jonathan Lange (jml) wrote :

Likewise. I guess this is part & parcel of doing guesswork.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'pkgme/info_elements.py'
2--- pkgme/info_elements.py 2012-01-10 15:02:34 +0000
3+++ pkgme/info_elements.py 2012-02-04 18:33:20 +0000
4@@ -1,5 +1,9 @@
5 import json
6-
7+import re
8+
9+
10+class InvalidInfoError(Exception):
11+ pass
12
13 class MissingInfoError(Exception):
14 pass
15@@ -65,6 +69,23 @@
16 description = "The name of the package."
17 required = True
18
19+ @classmethod
20+ def clean(cls, value):
21+ # Package names (both source and binary, see Package, Section 5.6.7)
22+ # must consist only of lower case letters (a-z), digits (0-9), plus
23+ # (+) and minus (-) signs, and periods (.). They must be at least two
24+ # characters long and must start with an alphanumeric character.
25+ #
26+ # http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Source
27+ cleaned = value.lower()
28+ cleaned = re.sub(r'[^a-z0-9+.-]', '', cleaned)
29+ cleaned = cleaned.lstrip('.+-')
30+ if len(cleaned) < 2:
31+ raise InvalidInfoError(
32+ "Package name must be at least two characters long: %r"
33+ % (value,))
34+ return cleaned
35+
36
37 class Section(InfoElement):
38
39
40=== modified file 'pkgme/tests/test_info_elements.py'
41--- pkgme/tests/test_info_elements.py 2012-01-10 15:02:34 +0000
42+++ pkgme/tests/test_info_elements.py 2012-02-04 18:33:20 +0000
43@@ -9,7 +9,9 @@
44 ExtraFiles,
45 ExtraFilesFromPaths,
46 InfoElement,
47+ InvalidInfoError,
48 MissingInfoError,
49+ PackageName,
50 )
51 from pkgme.project_info import DictInfo
52
53@@ -261,3 +263,39 @@
54 self.assertEqual("""initial synopsis
55 follow-up line
56 more information""", cleaned)
57+
58+
59+class TestPackageName(TestCase):
60+
61+ def test_valid(self):
62+ cleaned = PackageName.clean('foo')
63+ self.assertEqual('foo', cleaned)
64+
65+ def test_capitals(self):
66+ cleaned = PackageName.clean('Foo')
67+ self.assertEqual('foo', cleaned)
68+
69+ def test_too_short(self):
70+ e = self.assertRaises(InvalidInfoError, PackageName.clean, 'f')
71+ self.assertEqual(
72+ "Package name must be at least two characters long: 'f'", str(e))
73+
74+ def test_invalid_characters(self):
75+ cleaned = PackageName.clean('foo&ba@r')
76+ self.assertEqual('foobar', cleaned)
77+
78+ def test_too_short_after_stripping(self):
79+ e = self.assertRaises(InvalidInfoError, PackageName.clean, 'f&&&')
80+ self.assertEqual(
81+ "Package name must be at least two characters long: 'f&&&'",
82+ str(e))
83+ e = self.assertRaises(InvalidInfoError, PackageName.clean, '+++f')
84+ self.assertEqual(
85+ "Package name must be at least two characters long: '+++f'",
86+ str(e))
87+
88+ def test_invalid_start_character(self):
89+ self.assertEqual('foobar', PackageName.clean('+foobar'))
90+ self.assertEqual('foobar', PackageName.clean('-foobar'))
91+ self.assertEqual('foobar', PackageName.clean('.foobar'))
92+
93
94=== modified file 'pkgme/tests/test_package_files.py'
95--- pkgme/tests/test_package_files.py 2011-12-22 22:05:20 +0000
96+++ pkgme/tests/test_package_files.py 2012-02-04 18:33:20 +0000
97@@ -78,6 +78,9 @@
98 args.update(other_args)
99 return self.cls.from_info(DictInfo(args))
100
101+ def get_package_name(self):
102+ return PackageName.clean(self.getUniqueString())
103+
104
105 class BasicFileTests(TestCase):
106
107@@ -281,7 +284,7 @@
108 self.assertEqual(True, package_file.overwrite)
109
110 def test_get_contents_sets_package_name(self):
111- package_name = self.getUniqueString()
112+ package_name = self.get_package_name()
113 args = {PackageName.name: package_name}
114 package_file = self.get_object(args)
115 self.assertThat(
116@@ -289,7 +292,7 @@
117 ControlSourceStanzaHasField("Source", package_name))
118
119 def test_get_contents_sets_binary_package_name(self):
120- package_name = self.getUniqueString()
121+ package_name = self.get_package_name()
122 args = {PackageName.name: package_name}
123 package_file = self.get_object(args)
124 self.assertThat(
125@@ -399,7 +402,7 @@
126 }
127
128 def test_path(self):
129- package_name = self.getUniqueString()
130+ package_name = self.get_package_name()
131 package_file = self.get_object({PackageName.name: package_name})
132 self.assertEqual('%s.desktop' % package_name, package_file.path)
133
134
135=== modified file 'pkgme/tests/test_write_packaging.py'
136--- pkgme/tests/test_write_packaging.py 2011-11-01 18:51:24 +0000
137+++ pkgme/tests/test_write_packaging.py 2012-02-04 18:33:20 +0000
138@@ -43,7 +43,7 @@
139 return info
140
141 def test_write_packaging(self):
142- name = self.getUniqueString()
143+ name = PackageName.clean(self.getUniqueString())
144 info = self.make_info(name)
145 tempdir = self.useFixture(TempdirFixture())
146 backend = StaticBackend(
147@@ -53,7 +53,7 @@
148 self.assert_control_has_source_name(name, tempdir)
149
150 def test_write_packaging_passes_allowed_backend_names(self):
151- name = self.getUniqueString()
152+ name = PackageName.clean(self.getUniqueString())
153 other_name = name+"WRONG"
154 info1 = self.make_info(name)
155 info2 = self.make_info(other_name)

Subscribers

People subscribed via source and target branches