1#!/usr/bin/env python 2 3""" 4Implements the "make clean" target 5 6(C) 2017 Jack Lloyd 7 8Botan is released under the Simplified BSD License (see license.txt) 9""" 10 11import os 12import sys 13import stat 14import re 15import optparse # pylint: disable=deprecated-module 16import logging 17import json 18import shutil 19import errno 20 21def remove_dir(d): 22 try: 23 if os.access(d, os.X_OK): 24 logging.debug('Removing directory "%s"', d) 25 shutil.rmtree(d) 26 else: 27 logging.debug('Directory %s was missing', d) 28 except Exception as e: # pylint: disable=broad-except 29 logging.error('Failed removing directory "%s": %s', d, e) 30 31def remove_file(f): 32 try: 33 logging.debug('Removing file "%s"', f) 34 os.unlink(f) 35 except OSError as e: 36 if e.errno != errno.ENOENT: 37 logging.error('Failed removing file "%s": %s', f, e) 38 39def remove_all_in_dir(d): 40 if os.access(d, os.X_OK): 41 logging.debug('Removing all files in directory "%s"', d) 42 43 for f in os.listdir(d): 44 full_path = os.path.join(d, f) 45 mode = os.lstat(full_path).st_mode 46 47 if stat.S_ISDIR(mode): 48 remove_dir(full_path) 49 else: 50 remove_file(full_path) 51 52def parse_options(args): 53 parser = optparse.OptionParser() 54 parser.add_option('--build-dir', default='build', metavar='DIR', 55 help='specify build dir to clean (default %default)') 56 57 parser.add_option('--distclean', action='store_true', default=False, 58 help='clean everything') 59 parser.add_option('--verbose', action='store_true', default=False, 60 help='noisy logging') 61 62 (options, args) = parser.parse_args(args) 63 64 if len(args) > 1: 65 raise Exception("Unknown arguments") 66 67 return options 68 69def main(args=None): 70 if args is None: 71 args = sys.argv 72 73 options = parse_options(args) 74 75 logging.basicConfig(stream=sys.stderr, 76 format='%(levelname) 7s: %(message)s', 77 level=logging.DEBUG if options.verbose else logging.INFO) 78 79 build_dir = options.build_dir 80 81 if os.access(build_dir, os.X_OK) != True: 82 logging.debug('No build directory found') 83 # No build dir: clean enough! 84 return 0 85 86 build_config_path = os.path.join(build_dir, 'build_config.json') 87 build_config_str = None 88 89 try: 90 build_config_file = open(build_config_path) 91 build_config_str = build_config_file.read() 92 build_config_file.close() 93 except Exception: # pylint: disable=broad-except 94 # Ugh have to do generic catch as different exception type thrown in Python2 95 logging.error("Unable to access build_config.json in build dir") 96 return 1 97 98 build_config = json.loads(build_config_str) 99 100 if options.distclean: 101 build_dir = build_config['build_dir'] 102 remove_file(build_config['makefile_path']) 103 remove_dir(build_dir) 104 else: 105 for dir_type in ['libobj_dir', 'cliobj_dir', 'testobj_dir', 'depsobj_dir']: 106 dir_path = build_config[dir_type] 107 if dir_path: 108 remove_all_in_dir(dir_path) 109 110 remove_file(build_config['cli_exe']) 111 remove_file(build_config['test_exe']) 112 113 if options.distclean: 114 if 'generated_files' in build_config: 115 for f in build_config['generated_files'].split(' '): 116 remove_file(f) 117 118 return 0 119 120if __name__ == '__main__': 121 sys.exit(main()) 122