aboutsummaryrefslogtreecommitdiff
path: root/tools/cddl/cddl.py
blob: 28436f270564256dd85b9e879d77b5e50c5957a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import argparse
import os
import subprocess
import sys

def main():
  args = parseInput()

  assert validateHeaderInput(args.header), \
         "Error: '%s' is not a valid .h file" % args.header
  assert validateCodeInput(args.cc), \
         "Error: '%s' is not a valid .cc file" % args.cc
  assert validatePathInput(args.gen_dir), \
         "Error: '%s' is not a valid output directory" % args.gen_dir
  assert validateCddlInput(args.file), \
         "Error: '%s' is not a valid CDDL file" % args.file

  if args.log:
    logPath = os.path.join(args.gen_dir, args.log)
    log = open(logPath, "w")
    log.write("OUTPUT FOR CDDL CODE GENERATION TOOL:\n\n")
    log = open(logPath, "a")

    if (args.verbose):
      print("Logging to %s" % logPath)
  else:
    log = None

  if (args.verbose):
    print('Creating C++ files from provided CDDL file...')
  echoAndRunCommand([args.cddl, "--header", args.header, "--cc", args.cc,
                     "--gen-dir", args.gen_dir, args.file],
                     False, log, args.verbose)

  clangFormatLocation = findClangFormat()
  if not clangFormatLocation:
    if args.verbose:
      print("WARNING: clang-format could not be found")
    return

  for filename in [args.header, args.cc]:
    echoAndRunCommand([clangFormatLocation + 'clang-format', "-i",
                       os.path.join(args.gen_dir, filename)],
                       True, verbose=args.verbose)

def parseInput():
  parser = argparse.ArgumentParser()
  parser.add_argument("--cddl", help="path to the cddl executable to use")
  parser.add_argument("--header", help="Specify the filename of the output \
     header file. This is also the name that will be used for the include \
     guard and as the include path in the source file.")
  parser.add_argument("--cc", help="Specify the filename of the output \
     source file")
  parser.add_argument("--gen-dir", help="Specify the directory prefix that \
     should be added to the output header and source file.")
  parser.add_argument("--log", help="Specify the file to which stdout should \
     be redirected.")
  parser.add_argument("--verbose", help="Specify that we should log info \
     messages to stdout")
  parser.add_argument("file", help="the input file which contains the spec")
  return parser.parse_args()

def validateHeaderInput(headerFile):
  return headerFile and headerFile.endswith('.h')

def validateCodeInput(ccFile):
  return ccFile and ccFile.endswith('.cc')

def validatePathInput(dirPath):
  return dirPath and os.path.isdir(dirPath)

def validateCddlInput(cddlFile):
  return cddlFile and os.path.isfile(cddlFile)

def echoAndRunCommand(commandArray, allowFailure,
                      logfile = None, verbose = False):
  if verbose:
    print("\tExecuting Command: '%s'" % " ".join(commandArray))

  if logfile != None:
    process = subprocess.Popen(commandArray, stdout=logfile, stderr=logfile)
    process.wait()
    logfile.flush()
  else:
    process = subprocess.Popen(commandArray)
    process.wait()

  returncode = process.returncode
  if returncode != None and returncode != 0:
    if not allowFailure:
      sys.exit("\t\tERROR: Command failed with error code: '%i'!" % returncode)
    elif verbose:
      print("\t\tWARNING: Command failed with error code: '%i'!" % returncode)

def findClangFormat():
  executable = "clang-format"

  # Try and run from the environment variable
  for directory in os.environ["PATH"].split(os.pathsep):
    fullPath = os.path.join(directory, executable)
    if os.path.isfile(fullPath):
      return ""

  # Check 2 levels up since this should be correct on the build machine
  path = "../../"
  fullPath = os.path.join(path, executable)
  if os.path.isfile(fullPath):
    return path

  return None

if __name__ == "__main__":
  main()