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