OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 # Copyright 2015 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 """This script provides methods for clobbering build directories.""" | |
7 | |
8 import argparse | |
9 import os | |
10 import shutil | |
11 import sys | |
12 | |
13 | |
14 def extract_gn_build_commands(build_ninja_file): | |
15 """Extracts from a build.ninja the commands to run GN. | |
16 | |
17 The commands to run GN are the gn rule and build.ninja build step at the | |
18 top of the build.ninja file. We want to keep these when deleting GN builds | |
19 since we want to preserve the command-line flags to GN. | |
20 | |
21 On error, returns the empty string.""" | |
22 result = "" | |
23 with open(build_ninja_file, 'r') as f: | |
24 # Read until the second blank line. The first thing GN writes to the file | |
25 # is the "rule gn" and the second is the section for "build build.ninja", | |
26 # separated by blank lines. | |
27 num_blank_lines = 0 | |
28 while num_blank_lines < 2: | |
29 line = f.readline() | |
30 if len(line) == 0: | |
31 return '' # Unexpected EOF. | |
32 result += line | |
33 if line[0] == '\n': | |
34 num_blank_lines = num_blank_lines + 1 | |
35 return result | |
36 | |
37 | |
38 def delete_build_dir(build_dir): | |
39 # GN writes a build.ninja.d file. Note that not all GN builds have args.gn. | |
40 build_ninja_d_file = os.path.join(build_dir, 'build.ninja.d') | |
41 if not os.path.exists(build_ninja_d_file): | |
42 shutil.rmtree(build_dir) | |
43 return | |
44 | |
45 # GN builds aren't automatically regenerated when you sync. To avoid | |
46 # messing with the GN workflow, erase everything but the args file, and | |
47 # write a dummy build.ninja file that will automatically rerun GN the next | |
48 # time Ninja is run. | |
49 build_ninja_file = os.path.join(build_dir, 'build.ninja') | |
50 build_commands = extract_gn_build_commands(build_ninja_file) | |
51 | |
52 try: | |
53 gn_args_file = os.path.join(build_dir, 'args.gn') | |
54 with open(gn_args_file, 'r') as f: | |
55 args_contents = f.read() | |
56 except IOError: | |
57 args_contents = '' | |
58 | |
59 shutil.rmtree(build_dir) | |
60 | |
61 # Put back the args file (if any). | |
62 os.mkdir(build_dir) | |
63 if args_contents != '': | |
64 with open(gn_args_file, 'w') as f: | |
65 f.write(args_contents) | |
66 | |
67 # Write the build.ninja file sufficiently to regenerate itself. | |
68 with open(os.path.join(build_dir, 'build.ninja'), 'w') as f: | |
69 if build_commands != '': | |
70 f.write(build_commands) | |
71 else: | |
72 # Couldn't parse the build.ninja file, write a default thing. | |
73 f.write('''rule gn | |
74 command = gn -q gen //out/%s/ | |
75 description = Regenerating ninja files | |
76 | |
77 build build.ninja: gn | |
78 generator = 1 | |
79 depfile = build.ninja.d | |
80 ''' % (os.path.split(build_dir)[1])) | |
81 | |
82 # Write a .d file for the build which references a nonexistant file. This | |
83 # will make Ninja always mark the build as dirty. | |
84 with open(build_ninja_d_file, 'w') as f: | |
85 f.write('build.ninja: nonexistant_file.gn\n') | |
86 | |
87 | |
88 def clobber(out_dir): | |
89 """Clobber contents of build directory. | |
90 | |
91 Don't delete the directory itself: some checkouts have the build directory | |
92 mounted.""" | |
93 for f in os.listdir(out_dir): | |
94 path = os.path.join(out_dir, f) | |
95 if os.path.isfile(path): | |
96 os.unlink(path) | |
97 elif os.path.isdir(path): | |
98 delete_build_dir(path) | |
99 | |
100 | |
101 def main(): | |
102 parser = argparse.ArgumentParser() | |
103 parser.add_argument('out_dir', help='The output directory to clobber') | |
104 args = parser.parse_args() | |
105 clobber(args.out_dir) | |
106 return 0 | |
107 | |
108 | |
109 if __name__ == '__main__': | |
110 sys.exit(main()) | |
OLD | NEW |