Merge lp:~broder/ubuntu-dev-tools/fix-785854 into lp:~ubuntu-dev/ubuntu-dev-tools/trunk

Proposed by Evan Broder
Status: Superseded
Proposed branch: lp:~broder/ubuntu-dev-tools/fix-785854
Merge into: lp:~ubuntu-dev/ubuntu-dev-tools/trunk
Diff against target: 486 lines (+147/-19) (has conflicts)
21 files modified
404main (+2/-1)
ack-sync (+1/-1)
backportpackage (+1/-1)
debian/changelog (+11/-0)
dgetlp (+2/-1)
get-branches (+1/-1)
import-bug-from-debian (+1/-1)
lp-project-upload (+2/-1)
pbuilder-dist (+1/-1)
syncpackage (+1/-1)
ubuntu-iso (+2/-1)
ubuntutools/archive.py (+1/-1)
ubuntutools/builder.py (+1/-1)
ubuntutools/misc.py (+1/-1)
ubuntutools/requestsync/common.py (+2/-1)
ubuntutools/requestsync/mail.py (+1/-1)
ubuntutools/sponsor_patch/patch.py (+2/-1)
ubuntutools/sponsor_patch/sponsor_patch.py (+1/-1)
ubuntutools/subprocess.py (+109/-0)
ubuntutools/test/test_help.py (+1/-1)
ubuntutools/test/test_pylint.py (+3/-1)
Text conflict in debian/changelog
To merge this branch: bzr merge lp:~broder/ubuntu-dev-tools/fix-785854
Reviewer Review Type Date Requested Status
Barry Warsaw (community) Needs Fixing
Review via email: mp+62180@code.launchpad.net

This proposal has been superseded by a proposal from 2011-06-19.

To post a comment you must log in.
Revision history for this message
Barry Warsaw (barry) wrote :

Hi Evan,

I totally see why you've added this, and changed the code to use it. Thanks for making ubuntu-dev-tools better! Of course, once we migrate u-d-t to Python 3.2 this change won't be necessary <wink>.

I'm a little concerned that what you've written isn't entirely API compatible with Python's version. Python's subprocess.Popen is a class while ubuntutools.subprocess.Popen is a function. I have no idea whether people actually try to subclass subprocess.Popen, and within u-d-t it's easy enough to guarantee this, but is it possible there are would be external clients that could be broken by this? It makes me uncomfortable that your docs claim API compatibility when it's really not.

Two thoughts: could this be implemented as a subprocess.Popen subclass?

Or, would it make sense to just use a different API rather than promoting something that looks like stdlib subprocess.Popen but isn't quite? The way you have it does mean that existing code in u-d-t doesn't have to change, except for the import statement. I'm not sure whether that's good or not ;).

You might also call inspect.getargspec() at module scope and then not redefine, but simply expose the stdlib subprocess functions directly in ubuntutools.subprocess.Popen.

Anyway, just some thoughts. At the least, please do indicate in the docs about this difference. I'm happy to chat about alternatives in IRC if you want.

review: Needs Fixing
1093. By Evan Broder

Reimplement ubuntutools.subprocess.Popen as a class instead of a factory function.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '404main'
--- 404main 2010-12-27 19:32:07 +0000
+++ 404main 2011-06-19 21:23:31 +0000
@@ -24,12 +24,13 @@
24# This script is used to check if a package and all its build24# This script is used to check if a package and all its build
25# dependencies are in main or not.25# dependencies are in main or not.
2626
27import subprocess
28import sys27import sys
2928
30import apt_pkg29import apt_pkg
31import apt30import apt
3231
32from ubuntutools import subprocess
33
33def process_deps(cache, deps):34def process_deps(cache, deps):
34 """Takes a list of (build) dependencies and processes it."""35 """Takes a list of (build) dependencies and processes it."""
3536
3637
=== modified file 'ack-sync'
--- ack-sync 2011-05-23 21:44:45 +0000
+++ ack-sync 2011-06-19 21:23:31 +0000
@@ -22,7 +22,6 @@
22import lazr.restfulclient22import lazr.restfulclient
23import os23import os
24import re24import re
25import subprocess
26import sys25import sys
27import logging26import logging
28import glob27import glob
@@ -31,6 +30,7 @@
31from launchpadlib.launchpad import Launchpad30from launchpadlib.launchpad import Launchpad
3231
33from ubuntutools.config import UDTConfig32from ubuntutools.config import UDTConfig
33from ubuntutools import subprocess
3434
35COMMAND_LINE_SYNTAX_ERROR = 135COMMAND_LINE_SYNTAX_ERROR = 1
36VERSION_DETECTION_FAILED = 236VERSION_DETECTION_FAILED = 2
3737
=== modified file 'backportpackage'
--- backportpackage 2011-05-28 17:41:07 +0000
+++ backportpackage 2011-06-19 21:23:31 +0000
@@ -21,7 +21,6 @@
21import optparse21import optparse
22import os22import os
23import shutil23import shutil
24import subprocess
25import sys24import sys
26import tempfile25import tempfile
2726
@@ -34,6 +33,7 @@
34from ubuntutools.config import UDTConfig, ubu_email33from ubuntutools.config import UDTConfig, ubu_email
35from ubuntutools.builder import get_builder34from ubuntutools.builder import get_builder
36from ubuntutools.question import YesNoQuestion35from ubuntutools.question import YesNoQuestion
36from ubuntutools import subprocess
3737
38def error(msg):38def error(msg):
39 Logger.error(msg)39 Logger.error(msg)
4040
=== modified file 'debian/changelog'
--- debian/changelog 2011-06-16 19:02:04 +0000
+++ debian/changelog 2011-06-19 21:23:31 +0000
@@ -47,7 +47,18 @@
47 * mk-sbuild:47 * mk-sbuild:
48 - maintainer_name isn't mandatory any more (LP: #787051)48 - maintainer_name isn't mandatory any more (LP: #787051)
4949
50<<<<<<< TREE
50 -- Benjamin Drung <bdrung@debian.org> Wed, 25 May 2011 18:27:46 +020051 -- Benjamin Drung <bdrung@debian.org> Wed, 25 May 2011 18:27:46 +0200
52=======
53 [ Evan Broder ]
54 * ubuntutools.subprocess:
55 - New drop-in replacement wrapper module around subprocess that
56 backports the restore_signals kwarg and defaults close_fds=True
57 - Switch everything previously using subprocess to use
58 ubuntutools.subprocess instead (LP: #785854)
59
60 -- Evan Broder <evan@ebroder.net> Tue, 24 May 2011 20:21:47 +0200
61>>>>>>> MERGE-SOURCE
5162
52ubuntu-dev-tools (0.123) unstable; urgency=low63ubuntu-dev-tools (0.123) unstable; urgency=low
5364
5465
=== modified file 'dgetlp'
--- dgetlp 2011-02-12 22:08:15 +0000
+++ dgetlp 2011-06-19 21:23:31 +0000
@@ -32,7 +32,6 @@
32import hashlib32import hashlib
33import optparse33import optparse
34import os34import os
35import subprocess
36import sys35import sys
37import urllib236import urllib2
3837
@@ -43,6 +42,8 @@
43 "use this utility.")42 "use this utility.")
44 sys.exit(1)43 sys.exit(1)
4544
45from ubuntutools import subprocess
46
46USAGE = u"""Usage: %prog [-d|(-v|-q)] <Launchpad URL>47USAGE = u"""Usage: %prog [-d|(-v|-q)] <Launchpad URL>
4748
48This scripts simulates «dget»'s behaviour for files hosted at49This scripts simulates «dget»'s behaviour for files hosted at
4950
=== modified file 'get-branches'
--- get-branches 2010-12-27 19:49:00 +0000
+++ get-branches 2011-06-19 21:23:31 +0000
@@ -25,10 +25,10 @@
25#25#
2626
27import os27import os
28import subprocess
29import sys28import sys
30from optparse import OptionParser29from optparse import OptionParser
31from ubuntutools.lp.lpapicache import PersonTeam30from ubuntutools.lp.lpapicache import PersonTeam
31from ubuntutools import subprocess
3232
33def main():33def main():
34 usage = "Usage: %prog [-d <directory>] -t <team> [-o <operation>]"34 usage = "Usage: %prog [-d <directory>] -t <team> [-o <operation>]"
3535
=== modified file 'import-bug-from-debian'
--- import-bug-from-debian 2011-02-28 22:30:54 +0000
+++ import-bug-from-debian 2011-06-19 21:23:31 +0000
@@ -25,7 +25,6 @@
25from optparse import OptionParser, SUPPRESS_HELP25from optparse import OptionParser, SUPPRESS_HELP
26import re26import re
27import sys27import sys
28import subprocess
2928
30try:29try:
31 import SOAPpy30 import SOAPpy
@@ -37,6 +36,7 @@
37from launchpadlib.launchpad import Launchpad36from launchpadlib.launchpad import Launchpad
3837
39from ubuntutools.config import UDTConfig38from ubuntutools.config import UDTConfig
39from ubuntutools import subprocess
4040
41def main():41def main():
42 bug_re = re.compile(r"bug=(\d+)")42 bug_re = re.compile(r"bug=(\d+)")
4343
=== modified file 'lp-project-upload'
--- lp-project-upload 2011-06-09 11:36:06 +0000
+++ lp-project-upload 2011-06-19 21:23:31 +0000
@@ -22,13 +22,14 @@
2222
23import datetime23import datetime
24import os24import os
25import subprocess
26import sys25import sys
27import tempfile26import tempfile
2827
29from launchpadlib.launchpad import Launchpad28from launchpadlib.launchpad import Launchpad
30from launchpadlib.errors import HTTPError29from launchpadlib.errors import HTTPError
3130
31from ubuntutools import subprocess
32
32def create_release(project, version):33def create_release(project, version):
33 '''Create new release and milestone for LP project.'''34 '''Create new release and milestone for LP project.'''
3435
3536
=== modified file 'pbuilder-dist'
--- pbuilder-dist 2011-05-23 21:41:00 +0000
+++ pbuilder-dist 2011-06-19 21:23:31 +0000
@@ -30,13 +30,13 @@
30# that the target distribution is always meant to be Ubuntu Hardy.30# that the target distribution is always meant to be Ubuntu Hardy.
3131
32import os32import os
33import subprocess
34import sys33import sys
3534
36from devscripts.logger import Logger35from devscripts.logger import Logger
3736
38from ubuntutools.distro_info import DebianDistroInfo37from ubuntutools.distro_info import DebianDistroInfo
39import ubuntutools.misc38import ubuntutools.misc
39from ubuntutools import subprocess
4040
41class PbuilderDist:41class PbuilderDist:
42 def __init__(self, builder):42 def __init__(self, builder):
4343
=== modified file 'syncpackage'
--- syncpackage 2011-05-23 21:41:00 +0000
+++ syncpackage 2011-06-19 21:23:31 +0000
@@ -25,7 +25,6 @@
25import optparse25import optparse
26import os26import os
27import shutil27import shutil
28import subprocess
29import sys28import sys
3029
31from devscripts.logger import Logger30from devscripts.logger import Logger
@@ -38,6 +37,7 @@
38from ubuntutools.requestsync.lp import getDebianSrcPkg, getUbuntuSrcPkg37from ubuntutools.requestsync.lp import getDebianSrcPkg, getUbuntuSrcPkg
39from ubuntutools.lp import udtexceptions38from ubuntutools.lp import udtexceptions
40from ubuntutools.lp.lpapicache import Launchpad39from ubuntutools.lp.lpapicache import Launchpad
40from ubuntutools import subprocess
4141
4242
43class Version(debian.debian_support.Version):43class Version(debian.debian_support.Version):
4444
=== modified file 'ubuntu-iso'
--- ubuntu-iso 2010-12-27 13:01:03 +0000
+++ ubuntu-iso 2011-06-19 21:23:31 +0000
@@ -21,7 +21,8 @@
21# ##################################################################21# ##################################################################
2222
23import sys23import sys
24import subprocess24
25from ubuntutools import subprocess
2526
26def extract(iso, path):27def extract(iso, path):
27 command = ['isoinfo', '-R', '-i', iso, '-x', path]28 command = ['isoinfo', '-R', '-i', iso, '-x', path]
2829
=== modified file 'ubuntutools/archive.py'
--- ubuntutools/archive.py 2011-05-30 13:55:15 +0000
+++ ubuntutools/archive.py 2011-06-19 21:23:31 +0000
@@ -31,7 +31,6 @@
3131
32import hashlib32import hashlib
33import os.path33import os.path
34import subprocess
35import urllib234import urllib2
36import urlparse35import urlparse
37import re36import re
@@ -45,6 +44,7 @@
45from ubuntutools.config import UDTConfig44from ubuntutools.config import UDTConfig
46from ubuntutools.lp.lpapicache import (Launchpad, Distribution,45from ubuntutools.lp.lpapicache import (Launchpad, Distribution,
47 SourcePackagePublishingHistory)46 SourcePackagePublishingHistory)
47from ubuntutools import subprocess
4848
49class DownloadError(Exception):49class DownloadError(Exception):
50 "Unable to pull a source package"50 "Unable to pull a source package"
5151
=== modified file 'ubuntutools/builder.py'
--- ubuntutools/builder.py 2011-05-23 21:41:00 +0000
+++ ubuntutools/builder.py 2011-06-19 21:23:31 +0000
@@ -19,9 +19,9 @@
19#19#
2020
21import os21import os
22import subprocess
2322
24from devscripts.logger import Logger23from devscripts.logger import Logger
24from ubuntutools import subprocess
2525
26def _build_preparation(result_directory):26def _build_preparation(result_directory):
27 """prepares the builder for building a package"""27 """prepares the builder for building a package"""
2828
=== modified file 'ubuntutools/misc.py'
--- ubuntutools/misc.py 2011-02-13 14:15:24 +0000
+++ ubuntutools/misc.py 2011-06-19 21:23:31 +0000
@@ -25,10 +25,10 @@
25import locale25import locale
26import os26import os
27import os.path27import os.path
28from subprocess import Popen, PIPE
29import sys28import sys
3029
31from ubuntutools.lp.udtexceptions import PocketDoesNotExistError30from ubuntutools.lp.udtexceptions import PocketDoesNotExistError
31from ubuntutools.subprocess import Popen, PIPE
3232
33_system_distribution = None33_system_distribution = None
34def system_distribution():34def system_distribution():
3535
=== modified file 'ubuntutools/requestsync/common.py'
--- ubuntutools/requestsync/common.py 2010-12-22 22:01:39 +0000
+++ ubuntutools/requestsync/common.py 2011-06-19 21:23:31 +0000
@@ -24,9 +24,10 @@
24import urllib224import urllib2
25import re25import re
26import tempfile26import tempfile
27import subprocess
28from debian.changelog import Changelog27from debian.changelog import Changelog
2928
29from ubuntutools import subprocess
30
30def raw_input_exit_on_ctrlc(*args, **kwargs):31def raw_input_exit_on_ctrlc(*args, **kwargs):
31 '''32 '''
32 A wrapper around raw_input() to exit with a normalized message on Control-C33 A wrapper around raw_input() to exit with a normalized message on Control-C
3334
=== modified file 'ubuntutools/requestsync/mail.py'
--- ubuntutools/requestsync/mail.py 2011-03-05 22:48:24 +0000
+++ ubuntutools/requestsync/mail.py 2011-06-19 21:23:31 +0000
@@ -22,13 +22,13 @@
2222
23import os23import os
24import sys24import sys
25import subprocess
26import smtplib25import smtplib
27import socket26import socket
28from debian.changelog import Version27from debian.changelog import Version
29from ubuntutools.archive import rmadison, FakeSPPH28from ubuntutools.archive import rmadison, FakeSPPH
30from ubuntutools.distro_info import DebianDistroInfo29from ubuntutools.distro_info import DebianDistroInfo
31from ubuntutools.requestsync.common import raw_input_exit_on_ctrlc30from ubuntutools.requestsync.common import raw_input_exit_on_ctrlc
31from ubuntutools import subprocess
32from ubuntutools.lp.udtexceptions import PackageNotFoundException32from ubuntutools.lp.udtexceptions import PackageNotFoundException
3333
34__all__ = [34__all__ = [
3535
=== modified file 'ubuntutools/sponsor_patch/patch.py'
--- ubuntutools/sponsor_patch/patch.py 2010-12-27 14:20:49 +0000
+++ ubuntutools/sponsor_patch/patch.py 2011-06-19 21:23:31 +0000
@@ -16,7 +16,8 @@
16# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.16# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1717
18import os18import os
19import subprocess19
20from ubuntutools import subprocess
2021
21class Patch(object):22class Patch(object):
22 def __init__(self, patch_file):23 def __init__(self, patch_file):
2324
=== modified file 'ubuntutools/sponsor_patch/sponsor_patch.py'
--- ubuntutools/sponsor_patch/sponsor_patch.py 2011-06-03 17:18:38 +0000
+++ ubuntutools/sponsor_patch/sponsor_patch.py 2011-06-19 21:23:31 +0000
@@ -19,7 +19,6 @@
19import pwd19import pwd
20import re20import re
21import shutil21import shutil
22import subprocess
23import sys22import sys
2423
25import debian.changelog24import debian.changelog
@@ -28,6 +27,7 @@
2827
29from devscripts.logger import Logger28from devscripts.logger import Logger
3029
30from ubuntutools import subprocess
31from ubuntutools.update_maintainer import update_maintainer31from ubuntutools.update_maintainer import update_maintainer
32from ubuntutools.question import Question, YesNoQuestion, input_number32from ubuntutools.question import Question, YesNoQuestion, input_number
3333
3434
=== added file 'ubuntutools/subprocess.py'
--- ubuntutools/subprocess.py 1970-01-01 00:00:00 +0000
+++ ubuntutools/subprocess.py 2011-06-19 21:23:31 +0000
@@ -0,0 +1,109 @@
1"""Drop-in replacement for subprocess with better defaults
2
3This is an API-compatible replacement for the built-in subprocess
4module whose defaults better line up with our tastes.
5
6In particular, it:
7 - Adds support for the restore_signals flag if subprocess itself
8 doesn't support it
9 - Defaults close_fds to True
10"""
11
12
13from __future__ import absolute_import
14
15import inspect
16import signal
17import subprocess
18
19from subprocess import PIPE, STDOUT, CalledProcessError
20
21__all__ = ['Popen', 'call', 'check_call', 'check_output', 'CalledProcessError', 'PIPE', 'STDOUT']
22
23
24class Popen(subprocess.Popen):
25 def __init__(self, *args, **kwargs):
26 kwargs.setdefault('close_fds', True)
27
28 if 'restore_signals' not in inspect.getargspec(subprocess.Popen.__init__)[0]:
29 given_preexec_fn = kwargs.pop('preexec_fn', None)
30 restore_signals = kwargs.pop('restore_signals', True)
31 def preexec_fn():
32 if restore_signals:
33 for sig in ('SIGPIPE', 'SIGXFZ', 'SIGXFSZ'):
34 if hasattr(signal, sig):
35 signal.signal(getattr(signal, sig),
36 signal.SIG_DFL)
37
38 if given_preexec_fn:
39 given_preexec_fn()
40 kwargs['preexec_fn'] = preexec_fn
41
42 subprocess.Popen.__init__(self, *args, **kwargs)
43
44
45# call, check_call, and check_output are copied directly from the
46# subprocess module shipped with Python 2.7.1-5ubuntu2
47
48
49def call(*popenargs, **kwargs):
50 """Run command with arguments. Wait for command to complete, then
51 return the returncode attribute.
52
53 The arguments are the same as for the Popen constructor. Example:
54
55 retcode = call(["ls", "-l"])
56 """
57 return Popen(*popenargs, **kwargs).wait()
58
59
60def check_call(*popenargs, **kwargs):
61 """Run command with arguments. Wait for command to complete. If
62 the exit code was zero then return, otherwise raise
63 CalledProcessError. The CalledProcessError object will have the
64 return code in the returncode attribute.
65
66 The arguments are the same as for the Popen constructor. Example:
67
68 check_call(["ls", "-l"])
69 """
70 retcode = call(*popenargs, **kwargs)
71 if retcode:
72 cmd = kwargs.get("args")
73 if cmd is None:
74 cmd = popenargs[0]
75 raise CalledProcessError(retcode, cmd)
76 return 0
77
78
79def check_output(*popenargs, **kwargs):
80 r"""Run command with arguments and return its output as a byte string.
81
82 If the exit code was non-zero it raises a CalledProcessError. The
83 CalledProcessError object will have the return code in the returncode
84 attribute and output in the output attribute.
85
86 The arguments are the same as for the Popen constructor. Example:
87
88 >>> check_output(["ls", "-l", "/dev/null"])
89 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
90
91 The stdout argument is not allowed as it is used internally.
92 To capture standard error in the result, use stderr=STDOUT.
93
94 >>> check_output(["/bin/sh", "-c",
95 ... "ls -l non_existent_file ; exit 0"],
96 ... stderr=STDOUT)
97 'ls: non_existent_file: No such file or directory\n'
98 """
99 if 'stdout' in kwargs:
100 raise ValueError('stdout argument not allowed, it will be overridden.')
101 process = Popen(stdout=PIPE, *popenargs, **kwargs)
102 output, unused_err = process.communicate()
103 retcode = process.poll()
104 if retcode:
105 cmd = kwargs.get("args")
106 if cmd is None:
107 cmd = popenargs[0]
108 raise CalledProcessError(retcode, cmd, output=output)
109 return output
0110
=== modified file 'ubuntutools/test/test_help.py'
--- ubuntutools/test/test_help.py 2011-05-21 15:53:16 +0000
+++ ubuntutools/test/test_help.py 2011-06-19 21:23:31 +0000
@@ -18,10 +18,10 @@
18import os18import os
19import select19import select
20import signal20import signal
21import subprocess
22import time21import time
2322
24import setup23import setup
24from ubuntutools import subprocess
25from ubuntutools.test import unittest25from ubuntutools.test import unittest
2626
27BLACKLIST = {27BLACKLIST = {
2828
=== modified file 'ubuntutools/test/test_pylint.py'
--- ubuntutools/test/test_pylint.py 2011-05-30 13:55:15 +0000
+++ ubuntutools/test/test_pylint.py 2011-06-19 21:23:31 +0000
@@ -15,10 +15,10 @@
15# PERFORMANCE OF THIS SOFTWARE.15# PERFORMANCE OF THIS SOFTWARE.
1616
17import re17import re
18import subprocess
1918
20import setup19import setup
21from ubuntutools.test import unittest20from ubuntutools.test import unittest
21from ubuntutools import subprocess
2222
23WHITELIST = [re.compile(': %s$' % x) for x in (23WHITELIST = [re.compile(': %s$' % x) for x in (
24 # Wildcard import:24 # Wildcard import:
@@ -28,6 +28,8 @@
28 # mox:28 # mox:
29 r"Instance of '.+' has no '(WithSideEffects|MultipleTimes|AndReturn)' "29 r"Instance of '.+' has no '(WithSideEffects|MultipleTimes|AndReturn)' "
30 r"member",30 r"member",
31 # pylint doesn't like *args/**kwargs
32 r"Instance of 'Popen' has no '.*' member",
31)]33)]
3234
33class PylintTestCase(unittest.TestCase):35class PylintTestCase(unittest.TestCase):

Subscribers

People subscribed via source and target branches

to status/vote changes: