Merge lp:~jml/pkgme/build-source-package into lp:pkgme

Proposed by Jonathan Lange
Status: Merged
Approved by: James Westby
Approved revision: 92
Merged at revision: 72
Proposed branch: lp:~jml/pkgme/build-source-package
Merge into: lp:pkgme
Diff against target: 179 lines (+101/-10)
5 files modified
pkgme/bin/main.py (+23/-5)
pkgme/debuild.py (+34/-0)
pkgme/errors.py (+5/-0)
pkgme/testing.py (+15/-0)
pkgme/tests/test_script.py (+24/-5)
To merge this branch: bzr merge lp:~jml/pkgme/build-source-package
Reviewer Review Type Date Requested Status
James Westby Approve
Review via email: mp+69498@code.launchpad.net

Description of the change

Does what it says on the packet.

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

6 -test_command=python -m subunit.run $IDLIST
7 +test_command=PYTHONPATH=`pwd` python -m subunit.run $IDLIST

Is that not implicit?

41 + stdout, stderr = proc.communicate()

Perhaps we want to do something with the returncode? Also reporting the
stdout, stderr if it fails?

Also, I think it should use that new logging framework that some bright spark
wrote to log a message about what it is doing.

We're going to want to do something with GPG keys as well, but I'm fine deferring
that for now.

Thanks,

James

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

On Wed, Jul 27, 2011 at 5:42 PM, James Westby <email address hidden> wrote:
> Review: Needs Fixing
> 6       -test_command=python -m subunit.run $IDLIST
> 7       +test_command=PYTHONPATH=`pwd` python -m subunit.run $IDLIST
>
> Is that not implicit?
>

Well, sort of. It's there so that the spawned backend scripts will
have the top-level of the tree in their PYTHONPATH, so that they will
use the development version of pkgme libs instead of the system
installed one.

> 41      + stdout, stderr = proc.communicate()
>
> Perhaps we want to do something with the returncode? Also reporting the
> stdout, stderr if it fails?
>
> Also, I think it should use that new logging framework that some bright spark
> wrote to log a message about what it is doing.
>

Good calls both. Will address.

> We're going to want to do something with GPG keys as well, but I'm fine deferring
> that for now.
>

Agreed. Was thinking that. Should have said it.

jml

Revision history for this message
James Westby (james-w) wrote :

> On Wed, Jul 27, 2011 at 5:42 PM, James Westby <email address hidden>
> wrote:
> > Review: Needs Fixing
> > 6       -test_command=python -m subunit.run $IDLIST
> > 7       +test_command=PYTHONPATH=`pwd` python -m subunit.run $IDLIST
> >
> > Is that not implicit?
> >
>
> Well, sort of. It's there so that the spawned backend scripts will
> have the top-level of the tree in their PYTHONPATH, so that they will
> use the development version of pkgme libs instead of the system
> installed one.

Does that only apply if not using virtualenv + setup.py develop?

Thanks,

James

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

 * debug stuff done in another branch, merged to trunk
 * don't prompt for gpg passphrase during test run
 * actual tests to show we create these files
 * don't run lintian, because, you know, why bother?
 * raise an error if retcode is non-zero
 * basic infrastructure for showing nice errors, rather than stack traces
 * lots of debugging stuff

Revision history for this message
James Westby (james-w) wrote :

37 + except PkgmeError, e:
38 + sys.stderr.write("ERROR: %s" % (e,))
39 + return 3

Don't we have a --debug option now? Could it turn this in to a "raise" or something?

78 + if stdout:
79 + trace.debug('D: %s' % (stdout.rstrip('\n'),))

Why the prefix on the message there?

Otherwise this looks great, thanks. It's certainly a valuable feature to have, even
if there are some more details to work out later.

Thanks,

James

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

Changed the error to raise when debug is set.

The prefix is to make the output more readable. I started without a prefix, then added one and thought the output was more useful.

lp:~jml/pkgme/build-source-package updated
93. By Jonathan Lange

Raise on debug.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'pkgme/bin/main.py'
2--- pkgme/bin/main.py 2011-07-29 14:40:05 +0000
3+++ pkgme/bin/main.py 2011-08-01 09:02:27 +0000
4@@ -5,10 +5,22 @@
5 import sys
6
7 from pkgme import __version__, write_packaging
8+from pkgme.debuild import build_source_package
9+from pkgme.errors import PkgmeError
10 from pkgme import trace
11
12
13-def main(argv=None, target_dir=None):
14+def build_package(target_dir, interactive):
15+ """Where the magic happens."""
16+ trace.debug("Building packaging for %s" % (target_dir,))
17+ write_packaging(target_dir)
18+ trace.debug("Built packaging for %s" % (target_dir,))
19+ trace.debug("Building source package for %s" % (target_dir,))
20+ build_source_package(target_dir, sign=interactive)
21+ trace.debug("Built source package for %s" % (target_dir,))
22+
23+
24+def main(argv=None, target_dir=None, interactive=True):
25 if argv is None:
26 argv = sys.argv[1:]
27 parser = argparse.ArgumentParser(
28@@ -23,10 +35,16 @@
29 trace.set_debug()
30 if target_dir is None:
31 target_dir = os.getcwd()
32- trace.debug("Building packaging for %s" % (target_dir,))
33- write_packaging(target_dir)
34- trace.debug("Built packaging for %s" % (target_dir,))
35+ try:
36+ build_package(target_dir, interactive=interactive)
37+ except PkgmeError, e:
38+ if options.debug:
39+ raise
40+ else:
41+ sys.stderr.write("ERROR: %s" % (e,))
42+ return 3
43+ return 0
44
45
46 if __name__ == '__main__':
47- main()
48+ sys.exit(main())
49
50=== added file 'pkgme/debuild.py'
51--- pkgme/debuild.py 1970-01-01 00:00:00 +0000
52+++ pkgme/debuild.py 2011-08-01 09:02:27 +0000
53@@ -0,0 +1,34 @@
54+import subprocess
55+
56+from pkgme.errors import PkgmeError
57+from pkgme import trace
58+
59+
60+class DebuildError(PkgmeError):
61+
62+ def __init__(self, command, retcode, output_lines):
63+ super(DebuildError, self).__init__(
64+ "%s failed with %s. Output:\n%s" % (
65+ ' '.join(command),
66+ retcode,
67+ ''.join(' | %s' % (line,) for line in output_lines if line)))
68+
69+
70+def build_source_package(directory, sign=True):
71+ cmd = ['debuild', '--no-lintian', '-S']
72+ if not sign:
73+ cmd.extend(['-uc', '-us'])
74+ trace.debug("Running %s" % ' '.join(cmd))
75+ proc = subprocess.Popen(
76+ cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=directory)
77+ output = []
78+ while True:
79+ stdout = proc.stdout.readline()
80+ output.append(stdout)
81+ if stdout:
82+ trace.debug('D: %s' % (stdout.rstrip('\n'),))
83+ else:
84+ break
85+ retcode = proc.wait()
86+ if retcode != 0:
87+ raise DebuildError(cmd, retcode, output)
88
89=== added file 'pkgme/errors.py'
90--- pkgme/errors.py 1970-01-01 00:00:00 +0000
91+++ pkgme/errors.py 2011-08-01 09:02:27 +0000
92@@ -0,0 +1,5 @@
93+"""Exceptions raised by pkgme."""
94+
95+
96+class PkgmeError(Exception):
97+ """Base pkgme error."""
98
99=== modified file 'pkgme/testing.py'
100--- pkgme/testing.py 2011-07-15 09:22:59 +0000
101+++ pkgme/testing.py 2011-08-01 09:02:27 +0000
102@@ -64,6 +64,21 @@
103 return "Path exists and is a directory"
104
105
106+class DirContains(Matcher):
107+
108+ def __init__(self, filenames):
109+ self.filenames = filenames
110+
111+ def match(self, path):
112+ mismatch = PathExists().match(path)
113+ if mismatch is not None:
114+ return mismatch
115+ mismatch = IsDirectory().match(path)
116+ if mismatch is not None:
117+ return mismatch
118+ return Equals(sorted(self.filenames)).match(sorted(os.listdir(path)))
119+
120+
121 class FileContains(Matcher):
122
123 def __init__(self, contents):
124
125=== modified file 'pkgme/tests/test_script.py'
126--- pkgme/tests/test_script.py 2011-07-15 09:22:47 +0000
127+++ pkgme/tests/test_script.py 2011-08-01 09:02:27 +0000
128@@ -1,23 +1,26 @@
129-import os
130-
131 import pkg_resources
132+from StringIO import StringIO
133
134-from fixtures import TestWithFixtures
135+from fixtures import MonkeyPatch
136 from testtools import TestCase
137
138 from pkgme.testing import (
139+ DirContains,
140 DirExists,
141 TempdirFixture,
142 )
143
144
145-class ScriptTests(TestCase, TestWithFixtures):
146+class ScriptTests(TestCase):
147 """Smoke tests for the top-level pkgme script."""
148
149 def run_script(self, cwd):
150 ep = pkg_resources.load_entry_point(
151 "pkgme", "console_scripts", "pkgme")
152- ep(argv=[], target_dir=cwd)
153+ stderr = StringIO()
154+ with MonkeyPatch('sys.stderr', stderr):
155+ ep(argv=[], target_dir=cwd, interactive=False)
156+ self.assertEqual('', stderr.getvalue())
157
158 def test_writes_files(self):
159 tempdir = self.useFixture(TempdirFixture())
160@@ -28,3 +31,19 @@
161 """)
162 self.run_script(tempdir.path)
163 self.assertThat(tempdir.abspath("debian"), DirExists())
164+
165+ def test_builds_source_package(self):
166+ tempdir = self.useFixture(TempdirFixture())
167+ tempdir.create_file(
168+ "foo/setup.py", """from distutils.core import setup
169+
170+setup(name="foo")
171+""")
172+ self.run_script(tempdir.abspath('foo'))
173+ self.assertThat(tempdir.path, DirContains(
174+ ["foo_0.0.0.tar.gz",
175+ "foo_0.0.0.dsc",
176+ "foo_0.0.0_source.build",
177+ "foo_0.0.0_source.changes",
178+ "foo",
179+ ]))

Subscribers

People subscribed via source and target branches