blob: e9470685e28fa6574cf96e259900758c5cdf0bd0 [file] [log] [blame]
Scott Zawalski6bc41ac2010-09-08 12:47:28 -07001# Copyright (c) 2010 The Chromium OS 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
5"""Common python commands used by various build scripts."""
6
Scott Zawalski98ac6b22010-09-08 15:59:23 -07007import os
Scott Zawalski6bc41ac2010-09-08 12:47:28 -07008import subprocess
9import sys
10
11_STDOUT_IS_TTY = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
12
13def RunCommand(cmd, print_cmd=True, error_ok=False, error_message=None,
14 exit_code=False, redirect_stdout=False, redirect_stderr=False,
David James6db8f522010-09-09 10:49:11 -070015 cwd=None, input=None, enter_chroot=False, shell=False):
16 """Runs a command.
Scott Zawalski6bc41ac2010-09-08 12:47:28 -070017
18 Keyword arguments:
David James6db8f522010-09-09 10:49:11 -070019 cmd - cmd to run. Should be input to subprocess.Popen.
Scott Zawalski6bc41ac2010-09-08 12:47:28 -070020 print_cmd -- prints the command before running it.
21 error_ok -- does not raise an exception on error.
22 error_message -- prints out this message when an error occurrs.
23 exit_code -- returns the return code of the shell command.
24 redirect_stdout -- returns the stdout.
25 redirect_stderr -- holds stderr output until input is communicated.
26 cwd -- the working directory to run this cmd.
27 input -- input to pipe into this command through stdin.
28 enter_chroot -- this command should be run from within the chroot. If set,
29 cwd must point to the scripts directory.
David James6db8f522010-09-09 10:49:11 -070030 shell -- If shell is True, the specified command will be executed through the shell.
Scott Zawalski6bc41ac2010-09-08 12:47:28 -070031 Raises:
32 Exception: Raises generic exception on error with optional error_message.
33 """
34 # Set default for variables.
35 stdout = None
36 stderr = None
37 stdin = None
38 output = ''
39
40 # Modify defaults based on parameters.
41 if redirect_stdout: stdout = subprocess.PIPE
42 if redirect_stderr: stderr = subprocess.PIPE
43 if input: stdin = subprocess.PIPE
David James6db8f522010-09-09 10:49:11 -070044 if isinstance(cmd, basestring):
45 if enter_chroot: cmd = './enter_chroot.sh -- ' + cmd
46 cmd_str = cmd
47 else:
48 if enter_chroot: cmd = ['./enter_chroot.sh', '--'] + cmd
49 cmd_str = ' '.join(cmd)
Scott Zawalski6bc41ac2010-09-08 12:47:28 -070050
51 # Print out the command before running.
52 if print_cmd:
David James6db8f522010-09-09 10:49:11 -070053 Info('RunCommand: %s' % cmd_str)
Scott Zawalski6bc41ac2010-09-08 12:47:28 -070054
55 try:
56 proc = subprocess.Popen(cmd, cwd=cwd, stdin=stdin,
David James6db8f522010-09-09 10:49:11 -070057 stdout=stdout, stderr=stderr,
58 shell=shell)
Scott Zawalski6bc41ac2010-09-08 12:47:28 -070059 (output, error) = proc.communicate(input)
60 if exit_code:
61 return proc.returncode
62
63 if not error_ok and proc.returncode:
David James6db8f522010-09-09 10:49:11 -070064 raise Exception('Command "%s" failed.\n' % cmd_str +
Scott Zawalski6bc41ac2010-09-08 12:47:28 -070065 (error_message or error or output or ''))
66 except Exception,e:
67 if not error_ok:
68 raise
69 else:
70 Warning(str(e))
71
72 return output
73
74
75class Color(object):
76 """Conditionally wraps text in ANSI color escape sequences."""
77 BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
78 BOLD = -1
79 COLOR_START = '\033[1;%dm'
80 BOLD_START = '\033[1m'
81 RESET = '\033[0m'
82
83 def __init__(self, enabled=True):
84 self._enabled = enabled
85
86 def Color(self, color, text):
87 """Returns text with conditionally added color escape sequences.
88
89 Keyword arguments:
90 color: Text color -- one of the color constants defined in this class.
91 text: The text to color.
92
93 Returns:
94 If self._enabled is False, returns the original text. If it's True,
95 returns text with color escape sequences based on the value of color.
96 """
97 if not self._enabled:
98 return text
99 if color == self.BOLD:
100 start = self.BOLD_START
101 else:
102 start = self.COLOR_START % (color + 30)
103 return start + text + self.RESET
104
105
106def Die(message):
107 """Emits a red error message and halts execution.
108
109 Keyword arguments:
110 message: The message to be emitted before exiting.
111 """
112 print >> sys.stderr, (
113 Color(_STDOUT_IS_TTY).Color(Color.RED, '\nERROR: ' + message))
114 sys.exit(1)
115
116
117def Warning(message):
118 """Emits a yellow warning message and continues execution.
119
120 Keyword arguments:
121 message: The message to be emitted.
122 """
123 print >> sys.stderr, (
124 Color(_STDOUT_IS_TTY).Color(Color.YELLOW, '\nWARNING: ' + message))
125
126
127def Info(message):
128 """Emits a blue informational message and continues execution.
129
130 Keyword arguments:
131 message: The message to be emitted.
132 """
133 print >> sys.stderr, (
134 Color(_STDOUT_IS_TTY).Color(Color.BLUE, '\nINFO: ' + message))
Scott Zawalski98ac6b22010-09-08 15:59:23 -0700135
136
137def ListFiles(base_dir):
138 """Recurively list files in a directory.
139
140 Keyword arguments:
141 base_dir: directory to start recursively listing in.
142
143 Returns:
144 A list of files relative to the base_dir path or
145 An empty list of there are no files in the directories.
146 """
147 directories = [base_dir]
148 files_list = []
149 while directories:
150 directory = directories.pop()
151 for name in os.listdir(directory):
152 fullpath = os.path.join(directory, name)
153 if os.path.isfile(fullpath):
154 files_list.append(fullpath)
155 elif os.path.isdir(fullpath):
156 directories.append(fullpath)
157
158 return files_list