Merge lp:~jml/pkgme/extra-files into lp:pkgme

Proposed by Jonathan Lange
Status: Merged
Merged at revision: 65
Proposed branch: lp:~jml/pkgme/extra-files
Merge into: lp:pkgme
Prerequisite: lp:~jml/pkgme/testing-helpers
Diff against target: 151 lines (+73/-1)
4 files modified
pkgme/info_elements.py (+11/-0)
pkgme/package_files.py (+22/-1)
pkgme/tests/test_info_elements.py (+1/-0)
pkgme/tests/test_package_files.py (+39/-0)
To merge this branch: bzr merge lp:~jml/pkgme/extra-files
Reviewer Review Type Date Requested Status
James Westby Needs Information
Review via email: mp+67945@code.launchpad.net

Description of the change

Add a new type of information called 'ExtraFiles', which is a dictionary that maps paths to contents.

It's kind of a hacky implementation, and I haven't tried very hard to make sure it's complete (e.g. I have no idea how an extra_files script would actually work). But it's at a good point to get feedback.

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

90 +class TestExtraFiles(TestCase):
91 +
92 + def test_name(self):
93 + # ExtraFiles information is provided by an 'extra_files' script.
94 + self.assertEqual('extra_files', ExtraFiles.name)
95 +
96 + def test_default(self):
97 + # By default, there are no extra files.
98 + self.assertEqual({}, ExtraFiles.default)

I didn't do these tests for everything else, as they just seemed like they
would make things harder to change without really testing anything that is
likely to be a problem. I'm interested if you disagree with that opinion?

56 - keys = [element.name for element in elements]
57 + # XXX: Kind of hacky. The thing is that the ExtraFiles element isn't
58 + # an informational element used by key files, but rather a way of
59 + # forcing extra files to be written.
60 + keys = [ExtraFiles.name] + [element.name for element in elements]
61 values = project_info.get_all(keys)
62 new_info = DictInfo(values)
63 files = []
64 for file_cls in self.files_cls:
65 files.append(file_cls.from_info(new_info))
66 + extra_files = values.get(ExtraFiles.name, {})
67 + for path, contents in extra_files.items():
68 + files.append(BasicFile(path, contents))

This, perhaps unsurprisingly gives me pause.

I would have expected an ExtraFilesHandler class to be used, rather than a BasicFile
class. This would have been added to the default group, and so avoided the ExtraFiles.name
special casing there.

This class would then have done the for "path, contents in extra_files.items()" bit when
it was asked to write itself out at the end.

Did that approach not suit?

Thanks,

James

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

On Thu, Jul 14, 2011 at 2:31 PM, James Westby <email address hidden> wrote:
> Review: Needs Information
> 90      +class TestExtraFiles(TestCase):
> 91      +
> 92      +    def test_name(self):
> 93      +        # ExtraFiles information is provided by an 'extra_files' script.
> 94      +        self.assertEqual('extra_files', ExtraFiles.name)
> 95      +
> 96      +    def test_default(self):
> 97      +        # By default, there are no extra files.
> 98      +        self.assertEqual({}, ExtraFiles.default)
>
> I didn't do these tests for everything else, as they just seemed like they
> would make things harder to change without really testing anything that is
> likely to be a problem. I'm interested if you disagree with that opinion?
>

Not really. Just added them because they helped me think straight & fast.

> 56      -        keys = [element.name for element in elements]
> 57      +        # XXX: Kind of hacky.  The thing is that the ExtraFiles element isn't
> 58      +        # an informational element used by key files, but rather a way of
> 59      +        # forcing extra files to be written.
> 60      +        keys = [ExtraFiles.name] + [element.name for element in elements]
> 61               values = project_info.get_all(keys)
> 62               new_info = DictInfo(values)
> 63               files = []
> 64               for file_cls in self.files_cls:
> 65                   files.append(file_cls.from_info(new_info))
> 66      +        extra_files = values.get(ExtraFiles.name, {})
> 67      +        for path, contents in extra_files.items():
> 68      +            files.append(BasicFile(path, contents))
>
> This, perhaps unsurprisingly gives me pause.
>
> I would have expected an ExtraFilesHandler class to be used, rather than a BasicFile
> class. This would have been added to the default group, and so avoided the ExtraFiles.name
> special casing there.
>
> This class would then have done the for "path, contents in extra_files.items()" bit when
> it was asked to write itself out at the end.
>
> Did that approach not suit?
>

Perhaps I don't understand you. The way this method is written in
trunk assumes that each thing is one file (file.append, not
files.extend). There's currently no "Handler"-style class that knows
how to write itself, only write_file knows how to do that, and it's
not going to write multiple files.

Will continue conversation on IRC & post back here for posterity.

jml

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

After chatting on IRC, james_w says he's ok with the branch landing as-is. I'll probably follow up with one that changes the interface so that files know how to write themselves, and then blow away the special-casing.

lp:~jml/pkgme/extra-files updated
70. By Jonathan Lange

Merge testing-helpers into extra-files

71. By Jonathan Lange

Merge testing-helpers into extra-files

72. By Jonathan Lange

Remove unwanted tests.

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 2011-07-11 15:55:05 +0000
3+++ pkgme/info_elements.py 2011-07-14 14:02:31 +0000
4@@ -145,3 +145,14 @@
5 name = "version"
6 description = "The version of the project."
7 default = 0
8+
9+
10+class ExtraFiles(InfoElement):
11+
12+ name = 'extra_files'
13+ description = """Any extra files needed to build the package.
14+
15+ This is specified as a dictionary mapping filename to file contents. The
16+ filename must be relative to the directory being packaged.
17+ """
18+ default = {}
19
20=== modified file 'pkgme/package_files.py'
21--- pkgme/package_files.py 2011-07-04 02:49:19 +0000
22+++ pkgme/package_files.py 2011-07-14 14:02:31 +0000
23@@ -10,6 +10,7 @@
24 DebhelperAddons,
25 Depends,
26 Description,
27+ ExtraFiles,
28 Homepage,
29 Maintainer,
30 PackageName,
31@@ -23,6 +24,20 @@
32 DEBIAN_DIR = "debian"
33
34
35+class BasicFile(object):
36+
37+ def __init__(self, path, content, overwrite=True, elements=None):
38+ self.path = path
39+ self._content = content
40+ self.overwrite = overwrite
41+ if elements is None:
42+ elements = []
43+ self.elements = elements
44+
45+ def get_contents(self):
46+ return self._content
47+
48+
49 class PackageFile(object):
50
51 overwrite = True
52@@ -66,12 +81,18 @@
53
54 def get_files(self, project_info):
55 elements = self.get_elements()
56- keys = [element.name for element in elements]
57+ # XXX: Kind of hacky. The thing is that the ExtraFiles element isn't
58+ # an informational element used by key files, but rather a way of
59+ # forcing extra files to be written.
60+ keys = [ExtraFiles.name] + [element.name for element in elements]
61 values = project_info.get_all(keys)
62 new_info = DictInfo(values)
63 files = []
64 for file_cls in self.files_cls:
65 files.append(file_cls.from_info(new_info))
66+ extra_files = values.get(ExtraFiles.name, {})
67+ for path, contents in extra_files.items():
68+ files.append(BasicFile(path, contents))
69 return files
70
71 def get_elements(self):
72
73=== modified file 'pkgme/tests/test_info_elements.py'
74--- pkgme/tests/test_info_elements.py 2011-07-11 15:55:05 +0000
75+++ pkgme/tests/test_info_elements.py 2011-07-14 14:02:31 +0000
76@@ -2,6 +2,7 @@
77
78 from pkgme.info_elements import (
79 BuildDepends,
80+ ExtraFiles,
81 InfoElement,
82 MissingInfoError,
83 )
84
85=== modified file 'pkgme/tests/test_package_files.py'
86--- pkgme/tests/test_package_files.py 2011-07-14 10:59:20 +0000
87+++ pkgme/tests/test_package_files.py 2011-07-14 14:02:31 +0000
88@@ -11,6 +11,7 @@
89 DebhelperAddons,
90 Depends,
91 Description,
92+ ExtraFiles,
93 Homepage,
94 InfoElement,
95 Maintainer,
96@@ -19,6 +20,7 @@
97 Version,
98 )
99 from pkgme.package_files import (
100+ BasicFile,
101 Changelog,
102 Compat,
103 Control,
104@@ -68,6 +70,30 @@
105 return self.cls.from_info(DictInfo(args))
106
107
108+class BasicFileTests(TestCase):
109+
110+ def test_basic_file(self):
111+ f = BasicFile('foo/bar.txt', 'content')
112+ self.assertEqual('foo/bar.txt', f.path)
113+ self.assertEqual('content', f.get_contents())
114+
115+ def test_default_overwrite(self):
116+ f = BasicFile('foo/bar.txt', 'content')
117+ self.assertEqual(True, f.overwrite)
118+
119+ def test_specified_overwrite(self):
120+ f = BasicFile('foo/bar.txt', 'content', overwrite=False)
121+ self.assertEqual(False, f.overwrite)
122+
123+ def test_default_elements(self):
124+ f = BasicFile('foo/bar.txt', 'content')
125+ self.assertEqual([], f.elements)
126+
127+ def test_specified_elements(self):
128+ f = BasicFile('foo/bar.txt', 'content', elements=[TestElement2])
129+ self.assertEqual([TestElement2], f.elements)
130+
131+
132 class PackageFileTests(TestCase):
133
134 def test_empty_by_default(self):
135@@ -379,3 +405,16 @@
136 group.add_file_cls(TestPackageFile)
137 self.assertEqual(
138 set([TestElement1, TestElement2]), group.get_elements())
139+
140+ def test_extra_files(self):
141+ group = PackageFileGroup()
142+ project_info = DictInfo({
143+ ExtraFiles.name: {
144+ 'foo.txt': "Hello world!\n",
145+ 'debian/install': "Bwawahahaha\n",
146+ }})
147+ files = group.get_files(project_info)
148+ [foo, install] = files
149+ self.assertEqual('foo.txt', foo.path)
150+ self.assertEqual("Hello world!\n", foo.get_contents())
151+ self.assertEqual(True, foo.overwrite)

Subscribers

People subscribed via source and target branches