|
1 # Copyright (c) 2005-2009 Nokia Corporation |
|
2 # |
|
3 # Licensed under the Apache License, Version 2.0 (the "License"); |
|
4 # you may not use this file except in compliance with the License. |
|
5 # You may obtain a copy of the License at |
|
6 # |
|
7 # http://www.apache.org/licenses/LICENSE-2.0 |
|
8 # |
|
9 # Unless required by applicable law or agreed to in writing, software |
|
10 # distributed under the License is distributed on an "AS IS" BASIS, |
|
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
12 # See the License for the specific language governing permissions and |
|
13 # limitations under the License. |
|
14 |
|
15 import sys |
|
16 import stat |
|
17 import re |
|
18 import shutil |
|
19 import thread |
|
20 import os.path |
|
21 from os.path import normpath |
|
22 from subprocess import * |
|
23 from threading import Thread |
|
24 import zipfile |
|
25 import tarfile |
|
26 |
|
27 |
|
28 class CommandFailedException(Exception): |
|
29 pass |
|
30 |
|
31 |
|
32 class BuildFailedException(Exception): |
|
33 pass |
|
34 |
|
35 |
|
36 class ConfigureError(Exception): |
|
37 pass |
|
38 |
|
39 |
|
40 def log(str): |
|
41 """Prints the log in PyS60 format. |
|
42 This must be used in place of "print" to get uniformity in logs |
|
43 """ |
|
44 print "PyS60: " + str |
|
45 |
|
46 |
|
47 def run_shell_command(cmd, stdin='', mixed_stderr=0, verbose=0, |
|
48 exception_on_error=1): |
|
49 """Internal method to execute shell commands""" |
|
50 stdout_buf = [] |
|
51 if mixed_stderr: |
|
52 stderr_buf = stdout_buf |
|
53 else: |
|
54 stderr_buf = [] |
|
55 if verbose: |
|
56 print '- ', cmd |
|
57 p = Popen(cmd, |
|
58 stdin=PIPE, |
|
59 stdout=PIPE, |
|
60 stderr=PIPE, |
|
61 shell=True) |
|
62 p.stdin.write(stdin) |
|
63 p.stdin.close() |
|
64 |
|
65 def handle_stderr(): |
|
66 while 1: |
|
67 line = p.stderr.readline() |
|
68 if len(line) == 0: |
|
69 break |
|
70 if verbose: |
|
71 print " ** " + line |
|
72 stderr_buf.append(line) |
|
73 stderr_thread = Thread(target=handle_stderr) |
|
74 stderr_thread.start() |
|
75 while 1: |
|
76 line = p.stdout.readline() |
|
77 if len(line) == 0: |
|
78 break |
|
79 if verbose: |
|
80 print " -- " + line, |
|
81 stdout_buf.append(line) |
|
82 retcode = p.wait() |
|
83 stderr_thread.join() |
|
84 if retcode != 0 and exception_on_error: |
|
85 raise CommandFailedException('Command "%s" failed with code "%s"' |
|
86 % (cmd, retcode)) |
|
87 if mixed_stderr: |
|
88 return {'stdout': ''.join(stdout_buf), |
|
89 'return_code': retcode} |
|
90 else: |
|
91 return {'stdout': ''.join(stdout_buf), |
|
92 'stderr': ''.join(stderr_buf), |
|
93 'return_code': retcode} |
|
94 |
|
95 |
|
96 def run_cmd(cmd, verbose=1, exception_on_error=1): |
|
97 """Method to execute shell commands. |
|
98 Set verbose to 0 to stop logging messages. |
|
99 """ |
|
100 log('Executing command :<%s>' % cmd) |
|
101 run_shell_command(cmd, mixed_stderr=1, verbose=verbose, |
|
102 exception_on_error=exception_on_error) |
|
103 |
|
104 |
|
105 def rename_file(fromfile, tofile): |
|
106 if not os.path.exists(fromfile): |
|
107 log("shellutil.py: Error: %s File does not exists" % (fromfile)) |
|
108 return |
|
109 fromfile = normpath(fromfile) |
|
110 tofile = normpath(tofile) |
|
111 delete_file(tofile) |
|
112 log("shellutil.py: Renaming: %s -> %s" % (fromfile, tofile)) |
|
113 os.rename(fromfile, tofile) |
|
114 |
|
115 |
|
116 def copy_file(fromfile, tofile): |
|
117 """Method to copy files""" |
|
118 fromfile = normpath(fromfile) |
|
119 tofile = normpath(tofile) |
|
120 if fromfile == tofile: |
|
121 log("shellutil.py: No need to copy, source and target are the same:" + |
|
122 "%s -> %s" % (fromfile, tofile)) |
|
123 else: |
|
124 log("shellutil.py: Copying: %s -> %s" % (fromfile, tofile)) |
|
125 targetdir = os.path.dirname(os.path.abspath(tofile)) |
|
126 if not os.path.exists(targetdir): |
|
127 os.makedirs(targetdir) |
|
128 content = open(fromfile, 'rb').read() |
|
129 open(tofile, 'wb').write(content) |
|
130 |
|
131 |
|
132 def delete_file(filename): |
|
133 """Method to delete a particular file if that exists |
|
134 If access is denied will give an error. |
|
135 """ |
|
136 if os.path.exists(filename): |
|
137 log("Deleting: %s" % filename) |
|
138 os.remove(filename) |
|
139 |
|
140 |
|
141 def deltree_if_exists(dirname): |
|
142 """Delete an entire directory.""" |
|
143 if os.path.exists(dirname): |
|
144 shutil.rmtree(dirname) |
|
145 |
|
146 |
|
147 def files_matching_regex(topdir, regex): |
|
148 """Find the matching files in a directory |
|
149 Return an empty list if file not found |
|
150 """ |
|
151 files = [] |
|
152 compiled_regex = re.compile(regex, re.I) |
|
153 for path, dirnames, filenames in os.walk(topdir): |
|
154 for x in filenames: |
|
155 pathname = os.path.join(path, x) |
|
156 if compiled_regex.match(pathname): |
|
157 files.append(pathname) |
|
158 return files |
|
159 |
|
160 |
|
161 def setcapas(output, capas, compression_type='', verbose=0): |
|
162 """Method to apply new capability set & compression type on dlls or exes |
|
163 This is used as post linker |
|
164 """ |
|
165 compression_opt = '' |
|
166 if compression_type != '': |
|
167 compression_opt = '-compressionmethod ' + compression_type |
|
168 run_cmd('elftran -capability "%s" %s %s' \ |
|
169 % (capas, compression_opt, output)) |
|
170 if verbose: |
|
171 run_cmd('elftran -dump s %s' % output, exception_on_error=0) |
|
172 |
|
173 |
|
174 def create_archive_from_directory(archive_name, topdir, archive_dir='', |
|
175 archive_type='zip'): |
|
176 """Creates a compressed archive from the contents of the given directory. |
|
177 The archive types supported are tar.gz and zip. |
|
178 """ |
|
179 archive_name = os.path.normpath(archive_name) |
|
180 topdir = os.path.normpath(topdir) |
|
181 print "Creating archive %s from directory %s..." % (archive_name, topdir) |
|
182 |
|
183 if archive_type == 'tar.gz': |
|
184 archive = tarfile.open(archive_name, 'w:gz') |
|
185 else: |
|
186 archive = zipfile.ZipFile(archive_name, 'w') |
|
187 abs_topdir = os.path.abspath(topdir) |
|
188 for root, dirs, files in os.walk(topdir): |
|
189 if '.svn' in dirs: |
|
190 dirs.remove('.svn') |
|
191 abs_root = os.path.abspath(root) |
|
192 # Remove the common part from the directory name, |
|
193 # leaving just the relative part |
|
194 relative_path = abs_root[len(abs_topdir) + 1:] |
|
195 for name in files: |
|
196 absolute_filename = os.path.join(abs_root, name) |
|
197 archive_filename = os.path.join(relative_path, name) |
|
198 archive_filename = os.path.join(archive_dir, archive_filename) |
|
199 print "Adding %s as %s" % (absolute_filename, archive_filename) |
|
200 if archive_type == 'tar.gz': |
|
201 archive.add(absolute_filename, archive_filename) |
|
202 else: |
|
203 archive.write(absolute_filename, archive_filename, |
|
204 zipfile.ZIP_DEFLATED) |
|
205 archive.close() |
|
206 print "Created: ", archive_name |
|
207 |
|
208 |
|
209 class tee(object): |
|
210 """Class that implements stdout redirection to both file and screen""" |
|
211 |
|
212 def __init__(self, name, mode): |
|
213 self.file = open(name, mode) |
|
214 self.stdout = sys.stdout |
|
215 sys.stdout = self |
|
216 |
|
217 def close(self): |
|
218 if self.stdout is not None: |
|
219 sys.stdout = self.stdout |
|
220 self.stdout = None |
|
221 if self.file is not None: |
|
222 self.file.close() |
|
223 self.file = None |
|
224 |
|
225 def write(self, data): |
|
226 data = data.replace("\r", "") |
|
227 self.file.write(data) |
|
228 self.stdout.write(data) |
|
229 |
|
230 def flush(self): |
|
231 self.file.flush() |
|
232 self.stdout.flush() |
|
233 |
|
234 def __del__(self): |
|
235 self.close() |