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

Side by Side Diff: build/landmines.py

Issue 709813003: Make landmines handle GN build directories better. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: early return Created 6 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 | « no previous file | 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
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """ 6 """
7 This script runs every build as the first hook (See DEPS). If it detects that 7 This script runs every build as the first hook (See DEPS). If it detects that
8 the build should be clobbered, it will delete the contents of the build 8 the build should be clobbered, it will delete the contents of the build
9 directory. 9 directory.
10 10
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
48 'output_dir' in landmine_utils.gyp_generator_flags()): 48 'output_dir' in landmine_utils.gyp_generator_flags()):
49 output_dir = landmine_utils.gyp_generator_flags()['output_dir'] 49 output_dir = landmine_utils.gyp_generator_flags()['output_dir']
50 else: 50 else:
51 output_dir = os.environ.get('CHROMIUM_OUT_DIR', 'out') 51 output_dir = os.environ.get('CHROMIUM_OUT_DIR', 'out')
52 ret = os.path.join(SRC_DIR, output_dir) 52 ret = os.path.join(SRC_DIR, output_dir)
53 else: 53 else:
54 raise NotImplementedError('Unexpected GYP_GENERATORS (%s)' % build_tool) 54 raise NotImplementedError('Unexpected GYP_GENERATORS (%s)' % build_tool)
55 return os.path.abspath(ret) 55 return os.path.abspath(ret)
56 56
57 57
58 def extract_gn_build_commands(build_ninja_file):
59 """Extracts from a build.ninja the commands to run GN.
60
61 The commands to run GN are the gn rule and build.ninja build step at the
62 top of the build.ninja file. We want to keep these when deleting GN builds
63 since we want to preserve the command-line flags to GN.
64
65 On error, returns the empty string."""
66 result = ""
67 with open(build_ninja_file, 'r') as f:
68 # Read until the second blank line. The first thing GN writes to the file
69 # is the "rule gn" and the second is the section for "build build.ninja",
70 # separated by blank lines.
71 num_blank_lines = 0
72 while num_blank_lines < 2:
73 line = f.readline()
74 if len(line) == 0:
75 return '' # Unexpected EOF.
76 result += line
77 if line[0] == '\n':
78 num_blank_lines = num_blank_lines + 1
79 return result
80
81 def delete_build_dir(build_dir):
82 # GN writes a build.ninja.d file. Note that not all GN builds have args.gn.
83 build_ninja_d_file = os.path.join(build_dir, 'build.ninja.d')
84 if not os.path.exists(build_ninja_d_file):
85 shutil.rmtree(build_dir)
86 return
87
88 # GN builds aren't automatically regenerated when you sync. To avoid
89 # messing with the GN workflow, erase everything but the args file, and
90 # write a dummy build.ninja file that will automatically rerun GN the next
91 # time Ninja is run.
92 build_ninja_file = os.path.join(build_dir, 'build.ninja')
93 build_commands = extract_gn_build_commands(build_ninja_file)
94
95 try:
96 gn_args_file = os.path.join(build_dir, 'args.gn')
97 with open(gn_args_file, 'r') as f:
98 args_contents = f.read()
99 except IOError:
100 args_contents = ''
101
102 shutil.rmtree(build_dir)
103
104 # Put back the args file (if any).
105 os.mkdir(build_dir)
106 if args_contents != '':
107 with open(gn_args_file, 'w') as f:
108 f.write(args_contents)
109
110 # Write the build.ninja file sufficiently to regenerate itself.
111 with open(os.path.join(build_dir, 'build.ninja'), 'w') as f:
112 if build_commands != '':
113 f.write(build_commands)
114 else:
115 # Couldn't parse the build.ninja file, write a default thing.
116 f.write('''rule gn
117 command = gn -q gen //out/%s/
118 description = Regenerating ninja files
119
120 build build.ninja: gn
121 generator = 1
122 depfile = build.ninja.d
123 ''' % (os.path.split(build_dir)[1]))
124
125 # Write a .d file for the build which references a nonexistant file. This
126 # will make Ninja always mark the build as dirty.
127 with open(build_ninja_d_file, 'w') as f:
128 f.write('build.ninja: nonexistant_file.gn\n')
129
130
58 def clobber_if_necessary(new_landmines): 131 def clobber_if_necessary(new_landmines):
59 """Does the work of setting, planting, and triggering landmines.""" 132 """Does the work of setting, planting, and triggering landmines."""
60 out_dir = get_build_dir(landmine_utils.builder()) 133 out_dir = get_build_dir(landmine_utils.builder())
61 landmines_path = os.path.normpath(os.path.join(out_dir, '..', '.landmines')) 134 landmines_path = os.path.normpath(os.path.join(out_dir, '..', '.landmines'))
62 try: 135 try:
63 os.makedirs(out_dir) 136 os.makedirs(out_dir)
64 except OSError as e: 137 except OSError as e:
65 if e.errno == errno.EEXIST: 138 if e.errno == errno.EEXIST:
66 pass 139 pass
67 140
68 if os.path.exists(landmines_path): 141 if os.path.exists(landmines_path):
69 with open(landmines_path, 'r') as f: 142 with open(landmines_path, 'r') as f:
70 old_landmines = f.readlines() 143 old_landmines = f.readlines()
71 if old_landmines != new_landmines: 144 if old_landmines != new_landmines:
72 old_date = time.ctime(os.stat(landmines_path).st_ctime) 145 old_date = time.ctime(os.stat(landmines_path).st_ctime)
73 diff = difflib.unified_diff(old_landmines, new_landmines, 146 diff = difflib.unified_diff(old_landmines, new_landmines,
74 fromfile='old_landmines', tofile='new_landmines', 147 fromfile='old_landmines', tofile='new_landmines',
75 fromfiledate=old_date, tofiledate=time.ctime(), n=0) 148 fromfiledate=old_date, tofiledate=time.ctime(), n=0)
76 sys.stdout.write('Clobbering due to:\n') 149 sys.stdout.write('Clobbering due to:\n')
77 sys.stdout.writelines(diff) 150 sys.stdout.writelines(diff)
78 151
79 # Clobber contents of build directory but not directory itself: some 152 # Clobber contents of build directory but not directory itself: some
80 # checkouts have the build directory mounted. 153 # checkouts have the build directory mounted.
81 for f in os.listdir(out_dir): 154 for f in os.listdir(out_dir):
82 path = os.path.join(out_dir, f) 155 path = os.path.join(out_dir, f)
83 if os.path.isfile(path): 156 if os.path.isfile(path):
84 os.unlink(path) 157 os.unlink(path)
85 elif os.path.isdir(path): 158 elif os.path.isdir(path):
86 shutil.rmtree(path) 159 delete_build_dir(path)
87 160
88 # Save current set of landmines for next time. 161 # Save current set of landmines for next time.
89 with open(landmines_path, 'w') as f: 162 with open(landmines_path, 'w') as f:
90 f.writelines(new_landmines) 163 f.writelines(new_landmines)
91 164
92 165
93 def process_options(): 166 def process_options():
94 """Returns a list of landmine emitting scripts.""" 167 """Returns a list of landmine emitting scripts."""
95 parser = optparse.OptionParser() 168 parser = optparse.OptionParser()
96 parser.add_option( 169 parser.add_option(
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 proc = subprocess.Popen([sys.executable, s], stdout=subprocess.PIPE) 206 proc = subprocess.Popen([sys.executable, s], stdout=subprocess.PIPE)
134 output, _ = proc.communicate() 207 output, _ = proc.communicate()
135 landmines.extend([('%s\n' % l.strip()) for l in output.splitlines()]) 208 landmines.extend([('%s\n' % l.strip()) for l in output.splitlines()])
136 clobber_if_necessary(landmines) 209 clobber_if_necessary(landmines)
137 210
138 return 0 211 return 0
139 212
140 213
141 if __name__ == '__main__': 214 if __name__ == '__main__':
142 sys.exit(main()) 215 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698