"""This script provides methods for clobbering build directories."""
import argparse
import os
import shutil
import subprocess
import sys
def extract_gn_build_commands(build_ninja_file):
"""Extracts from a build.ninja the commands to run GN.
The commands to run GN are the gn rule and build.ninja build step at the
top of the build.ninja file. We want to keep these when deleting GN builds
since we want to preserve the command-line flags to GN.
On error, returns the empty string."""
result = ""
with open(build_ninja_file, 'r') as f:
found_build_dot_ninja_target = False
for line in f.readlines():
result += line
if line.startswith('build build.ninja:'):
found_build_dot_ninja_target = True
if found_build_dot_ninja_target and line[0] == '\n':
return result
return ''
def _rmtree(d):
if sys.platform.startswith('win'):
subprocess.check_call(['rmdir', '/s', '/q', d], shell=True)
else:
shutil.rmtree(d)
def _clean_dir(build_dir):
for e in os.scandir(build_dir):
if e.is_dir():
_rmtree(e.path)
else:
os.remove(e.path)
def delete_build_dir(build_dir):
build_ninja_d_file = os.path.join(build_dir, 'build.ninja.d')
if not os.path.exists(build_ninja_d_file):
_clean_dir(build_dir)
return
build_ninja_file = os.path.join(build_dir, 'build.ninja')
build_commands = extract_gn_build_commands(build_ninja_file)
try:
gn_args_file = os.path.join(build_dir, 'args.gn')
with open(gn_args_file, 'r') as f:
args_contents = f.read()
except IOError:
args_contents = ''
exception_during_rm = None
try:
_clean_dir(build_dir)
except Exception as e:
exception_during_rm = e
if args_contents != '':
with open(gn_args_file, 'w') as f:
f.write(args_contents)
with open(os.path.join(build_dir, 'build.ninja'), 'w') as f:
if build_commands != '':
f.write(build_commands)
else:
f.write('''ninja_required_version = 1.7.2
rule gn
command = gn -q gen //out/%s/
description = Regenerating ninja files
build build.ninja: gn
generator = 1
depfile = build.ninja.d
''' % (os.path.split(build_dir)[1]))
with open(build_ninja_d_file, 'w') as f:
f.write('build.ninja: nonexistant_file.gn\n')
if exception_during_rm:
raise exception_during_rm
def clobber(out_dir):
"""Clobber contents of build directory.
Don't delete the directory itself: some checkouts have the build directory
mounted."""
for f in os.listdir(out_dir):
path = os.path.join(out_dir, f)
if os.path.isfile(path):
os.unlink(path)
elif os.path.isdir(path):
delete_build_dir(path)
def main():
parser = argparse.ArgumentParser()
parser.add_argument('out_dir', help='The output directory to clobber')
args = parser.parse_args()
clobber(args.out_dir)
return 0
if __name__ == '__main__':
sys.exit(main())