Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Side by Side Diff: build/landmines.py

Issue 11175016: Selective build clobbering feature (landmines.py and android build scripts). (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Rebase and add note to keep functions in sync Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « build/gyp_helper.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """
7 This file holds a list of reasons why a particular build needs to be clobbered
8 (or a list of 'landmines').
9
10 This script runs every build as a hook. If it detects that the build should
11 be clobbered, it will touch the file <build_dir>/.landmine_triggered. The
12 various build scripts will then check for the presence of this file and clobber
13 accordingly. The script will also emit the reasons for the clobber to stdout.
14
15 A landmine is tripped when a builder checks out a different revision, and the
16 diff between the new landmines and the old ones is non-null. At this point, the
17 build is clobbered.
18 """
19
20 import difflib
21 import functools
22 import gyp_helper
23 import os
24 import shlex
25 import sys
26 import time
27
28 SRC_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
29
30 def memoize(default=None):
31 """This decorator caches the return value of a parameterless pure function"""
32 def memoizer(func):
33 val = []
34 @functools.wraps(func)
35 def inner():
36 if not val:
37 ret = func()
38 val.append(ret if ret is not None else default)
39 print '%s -> %r' % (func.__name__, val[0])
40 return val[0]
41 return inner
42 return memoizer
43
44
45 @memoize()
46 def IsWindows():
47 return sys.platform.startswith('win') or sys.platform == 'cygwin'
48
49
50 @memoize()
51 def IsLinux():
52 return sys.platform.startswith('linux')
53
54
55 @memoize()
56 def IsMac():
57 return sys.platform.startswith('darwin')
58
59
60 @memoize()
61 def gyp_defines():
62 """Parses and returns GYP_DEFINES env var as a dictionary."""
63 return dict(arg.split('=', 1)
64 for arg in shlex.split(os.environ.get('GYP_DEFINES', '')))
65
66
67 @memoize()
68 def distributor():
69 """
70 Returns a string which is the distributed build engine in use (if any).
71 Possible values: 'goma', 'ib', ''
72 """
73 if 'goma' in gyp_defines():
74 return 'goma'
75 elif IsWindows():
76 if 'CHROME_HEADLESS' in os.environ:
77 return 'ib' # use (win and !goma and headless) as approximation of ib
78
79
80 @memoize()
81 def platform():
82 """
83 Returns a string representing the platform this build is targetted for.
84 Possible values: 'win', 'mac', 'linux', 'ios', 'android'
85 """
86 if 'OS' in gyp_defines():
87 if 'android' in gyp_defines()['OS']:
88 return 'android'
89 else:
90 return gyp_defines()['OS']
91 elif IsWindows():
92 return 'win'
93 elif IsLinux():
94 return 'linux'
95 else:
96 return 'mac'
97
98
99 @memoize()
100 def builder():
101 """
102 Returns a string representing the build engine (not compiler) to use.
103 Possible values: 'make', 'ninja', 'xcode', 'msvs', 'scons'
104 """
105 if 'GYP_GENERATORS' in os.environ:
106 # for simplicity, only support the first explicit generator
107 generator = os.environ['GYP_GENERATORS'].split(',')[0]
108 if generator.endswith('-android'):
109 return generator.split('-')[0]
110 else:
111 return generator
112 else:
113 if platform() == 'android':
114 # Good enough for now? Do any android bots use make?
115 return 'ninja'
116 elif platform() == 'ios':
117 return 'xcode'
118 elif IsWindows():
119 return 'msvs'
120 elif IsLinux():
121 return 'make'
122 elif IsMac():
123 return 'xcode'
124 else:
125 assert False, 'Don\'t know what builder we\'re using!'
126
127
128 def get_landmines(target):
129 """
130 ALL LANDMINES ARE DEFINED HERE.
131 target is 'Release' or 'Debug'
132 """
133 landmines = []
134 add = lambda item: landmines.append(item + '\n')
135
136 if (distributor() == 'goma' and platform() == 'win32' and
137 builder() == 'ninja'):
138 add('Need to clobber winja goma due to backend cwd cache fix.')
139
140 return landmines
141
142
143 def get_target_build_dir(build_tool, target, is_iphone=False):
144 """
145 Returns output directory absolute path dependent on build and targets.
146 Examples:
147 r'c:\b\build\slave\win\build\src\out\Release'
148 '/mnt/data/b/build/slave/linux/build/src/out/Debug'
149 '/b/build/slave/ios_rel_device/build/src/xcodebuild/Release-iphoneos'
150
151 Keep this function in sync with tools/build/scripts/slave/compile.py
152 """
153 ret = None
154 if build_tool == 'xcode':
155 ret = os.path.join(SRC_DIR, 'xcodebuild',
156 target + ('-iphoneos' if is_iphone else ''))
157 elif build_tool == 'make':
158 ret = os.path.join(SRC_DIR, 'out', target)
159 elif build_tool == 'ninja':
160 ret = os.path.join(SRC_DIR, 'out', target)
161 elif build_tool == 'msvs':
162 ret = os.path.join(SRC_DIR, 'build', target)
163 elif build_tool == 'scons':
164 ret = os.path.join(SRC_DIR, 'sconsbuild', target)
165 else:
166 raise NotImplementedError()
167 return os.path.abspath(ret)
168
169
170 def main(argv):
171 if len(argv) > 1:
172 print('Unknown arguments %s' % argv[1:])
173 return 1
174
175 gyp_helper.apply_chromium_gyp_env()
176
177 for target in ('Debug', 'Release'):
178 out_dir = get_target_build_dir(builder(), target,
179 platform() == 'ios')
180
181 landmines_path = os.path.join(out_dir, '.landmines')
182 if not os.path.exists(out_dir):
183 os.makedirs(out_dir)
184
185 new_landmines = get_landmines(target)
186
187 if not os.path.exists(landmines_path):
188 with open(landmines_path, 'w') as f:
189 f.writelines(new_landmines)
190 else:
191 triggered = os.path.join(out_dir, '.landmines_triggered')
192 with open(landmines_path, 'r') as f:
193 old_landmines = f.readlines()
194 if old_landmines != new_landmines:
195 old_date = time.ctime(os.stat(landmines_path).st_ctime)
196 diff = difflib.unified_diff(old_landmines, new_landmines,
197 fromfile='old_landmines', tofile='new_landmines',
198 fromfiledate=old_date, tofiledate=time.ctime(), n=0)
199
200 with open(triggered, 'w') as f:
201 f.writelines(diff)
202 elif os.path.exists(triggered):
203 # Remove false triggered landmines.
204 os.remove(triggered)
205
206 return 0
207
208
209 if __name__ == '__main__':
210 sys.exit(main(sys.argv))
OLDNEW
« no previous file with comments | « build/gyp_helper.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698