1# Copyright 2018 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import argparse 6import os 7import subprocess 8import sys 9 10def main(): 11 args = parseInput() 12 13 assert validateHeaderInput(args.header), \ 14 "Error: '%s' is not a valid .h file" % args.header 15 assert validateCodeInput(args.cc), \ 16 "Error: '%s' is not a valid .cc file" % args.cc 17 assert validatePathInput(args.gen_dir), \ 18 "Error: '%s' is not a valid output directory" % args.gen_dir 19 assert validateCddlInput(args.file), \ 20 "Error: '%s' is not a valid CDDL file" % args.file 21 22 if args.log: 23 logPath = os.path.join(args.gen_dir, args.log) 24 log = open(logPath, "w") 25 log.write("OUTPUT FOR CDDL CODE GENERATION TOOL:\n\n") 26 log = open(logPath, "a") 27 28 if (args.verbose): 29 print("Logging to %s" % logPath) 30 else: 31 log = None 32 33 if (args.verbose): 34 print('Creating C++ files from provided CDDL file...') 35 echoAndRunCommand([args.cddl, "--header", args.header, "--cc", args.cc, 36 "--gen-dir", args.gen_dir, args.file], 37 False, log, args.verbose) 38 39 clangFormatLocation = findClangFormat() 40 if not clangFormatLocation: 41 if args.verbose: 42 print("WARNING: clang-format could not be found") 43 return 44 45 for filename in [args.header, args.cc]: 46 echoAndRunCommand([clangFormatLocation + 'clang-format', "-i", 47 os.path.join(args.gen_dir, filename)], 48 True, verbose=args.verbose) 49 50def parseInput(): 51 parser = argparse.ArgumentParser() 52 parser.add_argument("--cddl", help="path to the cddl executable to use") 53 parser.add_argument("--header", help="Specify the filename of the output \ 54 header file. This is also the name that will be used for the include \ 55 guard and as the include path in the source file.") 56 parser.add_argument("--cc", help="Specify the filename of the output \ 57 source file") 58 parser.add_argument("--gen-dir", help="Specify the directory prefix that \ 59 should be added to the output header and source file.") 60 parser.add_argument("--log", help="Specify the file to which stdout should \ 61 be redirected.") 62 parser.add_argument("--verbose", help="Specify that we should log info \ 63 messages to stdout") 64 parser.add_argument("file", help="the input file which contains the spec") 65 return parser.parse_args() 66 67def validateHeaderInput(headerFile): 68 return headerFile and headerFile.endswith('.h') 69 70def validateCodeInput(ccFile): 71 return ccFile and ccFile.endswith('.cc') 72 73def validatePathInput(dirPath): 74 return dirPath and os.path.isdir(dirPath) 75 76def validateCddlInput(cddlFile): 77 return cddlFile and os.path.isfile(cddlFile) 78 79def echoAndRunCommand(commandArray, allowFailure, 80 logfile = None, verbose = False): 81 if verbose: 82 print("\tExecuting Command: '%s'" % " ".join(commandArray)) 83 84 if logfile != None: 85 process = subprocess.Popen(commandArray, stdout=logfile, stderr=logfile) 86 process.wait() 87 logfile.flush() 88 else: 89 process = subprocess.Popen(commandArray) 90 process.wait() 91 92 returncode = process.returncode 93 if returncode != None and returncode != 0: 94 if not allowFailure: 95 sys.exit("\t\tERROR: Command failed with error code: '%i'!" % returncode) 96 elif verbose: 97 print("\t\tWARNING: Command failed with error code: '%i'!" % returncode) 98 99def findClangFormat(): 100 executable = "clang-format" 101 102 # Try and run from the environment variable 103 for directory in os.environ["PATH"].split(os.pathsep): 104 fullPath = os.path.join(directory, executable) 105 if os.path.isfile(fullPath): 106 return "" 107 108 # Check 2 levels up since this should be correct on the build machine 109 path = "../../" 110 fullPath = os.path.join(path, executable) 111 if os.path.isfile(fullPath): 112 return path 113 114 return None 115 116if __name__ == "__main__": 117 main() 118