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