- add sources.
[platform/framework/web/crosswalk.git] / src / tools / python / google / process_utils.py
1 # Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4 """Shared process-related utility functions."""
5
6 import errno
7 import os
8 import subprocess
9 import sys
10
11 class CommandNotFound(Exception): pass
12
13
14 TASKKILL = os.path.join(os.environ['WINDIR'], 'system32', 'taskkill.exe')
15 TASKKILL_PROCESS_NOT_FOUND_ERR = 128
16 # On windows 2000 there is no taskkill.exe, we need to have pskill somewhere
17 # in the path.
18 PSKILL = 'pskill.exe'
19 PSKILL_PROCESS_NOT_FOUND_ERR = -1
20
21 def KillAll(executables):
22   """Tries to kill all copies of each process in the processes list.  Returns
23   an error if any running processes couldn't be killed.
24   """
25   result = 0
26   if os.path.exists(TASKKILL):
27     command = [TASKKILL, '/f', '/im']
28     process_not_found_err = TASKKILL_PROCESS_NOT_FOUND_ERR
29   else:
30     command = [PSKILL, '/t']
31     process_not_found_err = PSKILL_PROCESS_NOT_FOUND_ERR
32
33   for name in executables:
34     new_error = RunCommand(command + [name])
35     # Ignore "process not found" error.
36     if new_error != 0 and new_error != process_not_found_err:
37       result = new_error
38   return result
39
40 def RunCommandFull(command, verbose=True, collect_output=False,
41                    print_output=True):
42   """Runs the command list.
43
44   Prints the given command (which should be a list of one or more strings).
45   If specified, prints its stderr (and optionally stdout) to stdout,
46   line-buffered, converting line endings to CRLF (see note below).  If
47   specified, collects the output as a list of lines and returns it.  Waits
48   for the command to terminate and returns its status.
49
50   Args:
51     command: the full command to run, as a list of one or more strings
52     verbose: if True, combines all output (stdout and stderr) into stdout.
53              Otherwise, prints only the command's stderr to stdout.
54     collect_output: if True, collects the output of the command as a list of
55                     lines and returns it
56     print_output: if True, prints the output of the command
57
58   Returns:
59     A tuple consisting of the process's exit status and output.  If
60     collect_output is False, the output will be [].
61
62   Raises:
63     CommandNotFound if the command executable could not be found.
64   """
65   print '\n' + subprocess.list2cmdline(command).replace('\\', '/') + '\n', ###
66
67   if verbose:
68     out = subprocess.PIPE
69     err = subprocess.STDOUT
70   else:
71     out = file(os.devnull, 'w')
72     err = subprocess.PIPE
73   try:
74     proc = subprocess.Popen(command, stdout=out, stderr=err, bufsize=1)
75   except OSError, e:
76     if e.errno == errno.ENOENT:
77       raise CommandNotFound('Unable to find "%s"' % command[0])
78     raise
79
80   output = []
81
82   if verbose:
83     read_from = proc.stdout
84   else:
85     read_from = proc.stderr
86   line = read_from.readline()
87   while line:
88     line = line.rstrip()
89
90     if collect_output:
91       output.append(line)
92
93     if print_output:
94       # Windows Python converts \n to \r\n automatically whenever it
95       # encounters it written to a text file (including stdout).  The only
96       # way around it is to write to a binary file, which isn't feasible for
97       # stdout. So we end up with \r\n here even though we explicitly write
98       # \n.  (We could write \r instead, which doesn't get converted to \r\n,
99       # but that's probably more troublesome for people trying to read the
100       # files.)
101       print line + '\n',
102
103       # Python on windows writes the buffer only when it reaches 4k. This is
104       # not fast enough for all purposes.
105       sys.stdout.flush()
106     line = read_from.readline()
107
108   # Make sure the process terminates.
109   proc.wait()
110
111   if not verbose:
112     out.close()
113   return (proc.returncode, output)
114
115 def RunCommand(command, verbose=True):
116   """Runs the command list, printing its output and returning its exit status.
117
118   Prints the given command (which should be a list of one or more strings),
119   then runs it and prints its stderr (and optionally stdout) to stdout,
120   line-buffered, converting line endings to CRLF.  Waits for the command to
121   terminate and returns its status.
122
123   Args:
124     command: the full command to run, as a list of one or more strings
125     verbose: if True, combines all output (stdout and stderr) into stdout.
126              Otherwise, prints only the command's stderr to stdout.
127
128   Returns:
129     The process's exit status.
130
131   Raises:
132     CommandNotFound if the command executable could not be found.
133   """
134   return RunCommandFull(command, verbose)[0]
135
136 def RunCommandsInParallel(commands, verbose=True, collect_output=False,
137                           print_output=True):
138   """Runs a list of commands in parallel, waits for all commands to terminate
139   and returns their status. If specified, the ouput of commands can be
140   returned and/or printed.
141
142   Args:
143     commands: the list of commands to run, each as a list of one or more
144               strings.
145     verbose: if True, combines stdout and stderr into stdout.
146              Otherwise, prints only the command's stderr to stdout.
147     collect_output: if True, collects the output of the each command as a list
148                     of lines and returns it.
149     print_output: if True, prints the output of each command.
150
151   Returns:
152     A list of tuples consisting of each command's exit status and output.  If
153     collect_output is False, the output will be [].
154
155   Raises:
156     CommandNotFound if any of the command executables could not be found.
157   """
158
159   command_num = len(commands)
160   outputs = [[] for i in xrange(command_num)]
161   procs = [None for i in xrange(command_num)]
162   eofs = [False for i in xrange(command_num)]
163
164   for command in commands:
165     print '\n' + subprocess.list2cmdline(command).replace('\\', '/') + '\n',
166
167   if verbose:
168     out = subprocess.PIPE
169     err = subprocess.STDOUT
170   else:
171     out = file(os.devnull, 'w')
172     err = subprocess.PIPE
173
174   for i in xrange(command_num):
175     try:
176       command = commands[i]
177       procs[i] = subprocess.Popen(command, stdout=out, stderr=err, bufsize=1)
178     except OSError, e:
179       if e.errno == errno.ENOENT:
180         raise CommandNotFound('Unable to find "%s"' % command[0])
181       raise
182       # We could consider terminating the processes already started.
183       # But Popen.kill() is only available in version 2.6.
184       # For now the clean up is done by KillAll.
185
186   while True:
187     eof_all = True
188     for i in xrange(command_num):
189       if eofs[i]:
190         continue
191       if verbose:
192         read_from = procs[i].stdout
193       else:
194         read_from = procs[i].stderr
195       line = read_from.readline()
196       if line:
197         eof_all = False
198         line = line.rstrip()
199         outputs[i].append(line)
200         if print_output:
201           # Windows Python converts \n to \r\n automatically whenever it
202           # encounters it written to a text file (including stdout).  The only
203           # way around it is to write to a binary file, which isn't feasible
204           # for stdout. So we end up with \r\n here even though we explicitly
205           # write \n.  (We could write \r instead, which doesn't get converted
206           # to \r\n, but that's probably more troublesome for people trying to
207           # read the files.)
208           print line + '\n',
209       else:
210         eofs[i] = True
211     if eof_all:
212       break
213
214   # Make sure the process terminates.
215   for i in xrange(command_num):
216     procs[i].wait()
217
218   if not verbose:
219     out.close()
220
221   return [(procs[i].returncode, outputs[i]) for i in xrange(command_num)]