~mvo/ubuntu-sso-client/strawman-lp711413

« back to all changes in this revision

Viewing changes to ubuntu_sso/utils/runner/tx.py

  • Committer: Natalia B. Bidart
  • Date: 2011-12-20 16:29:34 UTC
  • Revision ID: natalia.bidart@canonical.com-20111220162934-2s5xou06v3usxyr6
Tags: ubuntu-sso-client-2_99_0
- Release v2.99.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: utf-8 -*-
2
 
#
3
 
# Copyright 2012 Canonical Ltd.
4
 
#
5
 
# This program is free software: you can redistribute it and/or modify it
6
 
# under the terms of the GNU General Public License version 3, as published
7
 
# by the Free Software Foundation.
8
 
#
9
 
# This program is distributed in the hope that it will be useful, but
10
 
# WITHOUT ANY WARRANTY; without even the implied warranties of
11
 
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12
 
# PURPOSE.  See the GNU General Public License for more details.
13
 
#
14
 
# You should have received a copy of the GNU General Public License along
15
 
# with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 
#
17
 
# In addition, as a special exception, the copyright holders give
18
 
# permission to link the code of portions of this program with the
19
 
# OpenSSL library under certain conditions as described in each
20
 
# individual source file, and distribute linked combinations
21
 
# including the two.
22
 
# You must obey the GNU General Public License in all respects
23
 
# for all of the code used other than OpenSSL.  If you modify
24
 
# file(s) with this exception, you may extend this exception to your
25
 
# version of the file(s), but you are not obligated to do so.  If you
26
 
# do not wish to do so, delete this exception statement from your
27
 
# version.  If you delete this exception statement from all source
28
 
# files in the program, then also delete it here.
29
 
"""Utility to spawn another program from a mainloop."""
30
 
 
31
 
import os
32
 
import sys
33
 
 
34
 
from twisted.internet import utils
35
 
 
36
 
from ubuntu_sso.logger import setup_logging
37
 
 
38
 
 
39
 
logger = setup_logging("ubuntu_sso.utils.runner.tx")
40
 
 
41
 
NO_SUCH_FILE_OR_DIR = 'OSError: [Errno 2]'
42
 
 
43
 
 
44
 
EXE_EXT = ''
45
 
if sys.platform == 'win32':
46
 
    EXE_EXT = '.exe'
47
 
 
48
 
 
49
 
def spawn_program(args, reply_handler, error_handler):
50
 
    """Spawn the program specified by 'args' using the twisted reactor.
51
 
 
52
 
    When the program finishes, 'reply_handler' will be called with a single
53
 
    argument that will be the porgram status code.
54
 
 
55
 
    If there is an error, error_handler will be called with an instance of
56
 
    SpawnError.
57
 
 
58
 
    """
59
 
 
60
 
    def child_watch((stdout, stderr, exit_code)):
61
 
        """Handle child termination."""
62
 
        if stdout:
63
 
            logger.debug('Returned stdout is (exit code was %r): %r',
64
 
                         exit_code, stdout)
65
 
        if stderr:
66
 
            logger.warning('Returned stderr is (exit code was %r): %r',
67
 
                           exit_code, stderr)
68
 
 
69
 
        if OSError.__name__ in stderr:
70
 
            failed_to_start = NO_SUCH_FILE_OR_DIR in stderr
71
 
            error_handler(msg=stderr, failed_to_start=failed_to_start)
72
 
        else:
73
 
            reply_handler(exit_code)
74
 
 
75
 
    def handle_error(failure):
76
 
        """Handle error when spawning the process."""
77
 
        error_handler(msg=failure.getErrorMessage())
78
 
 
79
 
    args = list(args)
80
 
    program = args[0]
81
 
    argv = args[1:]
82
 
 
83
 
    bytes_args = []
84
 
    for arg in argv:
85
 
        if isinstance(arg, unicode):
86
 
            arg = arg.encode('utf-8')
87
 
        if not isinstance(arg, basestring):
88
 
            arg = str(arg)
89
 
        bytes_args.append(arg)
90
 
 
91
 
    if program and not os.access(program, os.X_OK):
92
 
        # handle searching the executable in the PATH, since
93
 
        # twisted will not solve that for us :-/
94
 
        paths = os.environ['PATH'].split(os.pathsep)
95
 
        for path in paths:
96
 
            target = os.path.join(path, program)
97
 
            if not target.endswith(EXE_EXT):
98
 
                target += EXE_EXT
99
 
            if os.access(target, os.X_OK):
100
 
                program = target
101
 
                break
102
 
 
103
 
    try:
104
 
        d = utils.getProcessOutputAndValue(program, bytes_args, env=os.environ)
105
 
    except OSError, e:
106
 
        error_handler(msg=e, failed_to_start=True)
107
 
    except Exception, e:
108
 
        error_handler(msg=e, failed_to_start=False)
109
 
    else:
110
 
        logger.debug('Spawning the program %r with the twisted reactor '
111
 
                     '(returned deferred is %r).', repr(args), d)
112
 
        d.addCallback(child_watch)
113
 
        d.addErrback(handle_error)