mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-29 12:13:52 +00:00
* Fix internal header include paths. The extra leading "CLI/" part of include directives prevents the inclusion of CLI.hpp from a relative directory without an extra -I or /I compiler directive. * Fix single header generation script. Files included with "" should be relative to the header file location first.
176 lines
5.2 KiB
Python
Executable File
176 lines
5.2 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
from __future__ import print_function, unicode_literals
|
|
|
|
import os
|
|
import re
|
|
from argparse import ArgumentParser
|
|
from operator import add
|
|
from copy import copy
|
|
from functools import reduce
|
|
from subprocess import Popen, PIPE
|
|
|
|
includes_local = re.compile(r"""^#include "(.*)"$""", re.MULTILINE)
|
|
includes_system = re.compile(r"""^#include \<(.*)\>$""", re.MULTILINE)
|
|
version_finder = re.compile(r"""^#define CLI11_VERSION \"(.*)\"$""", re.MULTILINE)
|
|
verbatim_tag_str = r"""
|
|
^ # Begin of line
|
|
[^\n^\[]+ # Some characters, not including [ or the end of a line
|
|
\[ # A literal [
|
|
[^\]^\n]* # Anything except a closing ]
|
|
CLI11:verbatim # The tag
|
|
[^\]^\n]* # Anything except a closing ]
|
|
\] # A literal ]
|
|
[^\n]* # Up to end of line
|
|
$ # End of a line
|
|
"""
|
|
verbatim_all = re.compile(
|
|
verbatim_tag_str + "(.*)" + verbatim_tag_str, re.MULTILINE | re.DOTALL | re.VERBOSE
|
|
)
|
|
|
|
DIR = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
|
class HeaderFile(object):
|
|
TAG = "Unknown git revision"
|
|
LICENSE = "// BSD 3 clause"
|
|
VERSION = "Unknown"
|
|
|
|
def __init__(self, base, inc):
|
|
with open(os.path.join(base, inc)) as f:
|
|
inner = f.read()
|
|
|
|
version = version_finder.search(inner)
|
|
if version:
|
|
self.__class__.VERSION = version.groups()[0]
|
|
|
|
# add self.verbatim
|
|
if "CLI11:verbatim" in inner:
|
|
self.verbatim = ["\n\n// Verbatim copy from {0}:".format(inc)]
|
|
self.verbatim += verbatim_all.findall(inner)
|
|
inner = verbatim_all.sub("", inner)
|
|
else:
|
|
self.verbatim = []
|
|
|
|
self.headers = set(includes_system.findall(inner))
|
|
|
|
self.body = "\n// From {0}:\n\n".format(inc) + inner[inner.find("namespace") :]
|
|
|
|
self.namespace = None
|
|
|
|
def __add__(self, other):
|
|
out = copy(self)
|
|
out.headers |= other.headers
|
|
out.body += other.body
|
|
out.verbatim += other.verbatim
|
|
return out
|
|
|
|
@property
|
|
def header_str(self):
|
|
return "\n".join("#include <" + h + ">" for h in sorted(self.headers))
|
|
|
|
@property
|
|
def verbatim_str(self):
|
|
return "\n".join(self.verbatim)
|
|
|
|
def insert_namespace(self, namespace):
|
|
self.namespace = namespace
|
|
|
|
def macro_replacement(self, before, after):
|
|
self.verbatim = [x.replace(before, after) for x in self.verbatim]
|
|
self.body = self.body.replace(before, after)
|
|
|
|
def __str__(self):
|
|
result = """\
|
|
#pragma once
|
|
|
|
// CLI11: Version {self.VERSION}
|
|
// Originally designed by Henry Schreiner
|
|
// https://github.com/CLIUtils/CLI11
|
|
//
|
|
// This is a standalone header file generated by MakeSingleHeader.py in CLI11/scripts
|
|
// from: {self.TAG}
|
|
//
|
|
// From LICENSE:
|
|
//
|
|
{self.LICENSE}
|
|
|
|
// Standard combined includes:
|
|
|
|
{self.header_str}
|
|
""".format(
|
|
self=self
|
|
)
|
|
|
|
if self.namespace:
|
|
result += "\nnamespace " + self.namespace + " {\n\n"
|
|
result += "{self.verbatim_str}\n{self.body}\n".format(self=self)
|
|
if self.namespace:
|
|
result += "} // namespace " + self.namespace + "\n\n"
|
|
|
|
return result
|
|
|
|
|
|
def MakeHeader(
|
|
output, main_header, include_dir="../include", namespace=None, macro=None
|
|
):
|
|
# Set tag if possible to class variable
|
|
try:
|
|
proc = Popen(
|
|
["git", "describe", "--tags", "--always"], cwd=str(DIR), stdout=PIPE
|
|
)
|
|
out, _ = proc.communicate()
|
|
except OSError:
|
|
pass
|
|
else:
|
|
if proc.returncode == 0:
|
|
HeaderFile.TAG = out.decode("utf-8").strip()
|
|
|
|
base_dir = os.path.abspath(os.path.join(DIR, include_dir))
|
|
main_header = os.path.join(base_dir, main_header)
|
|
header_dir = os.path.dirname(main_header)
|
|
licence_file = os.path.abspath(os.path.join(DIR, "../LICENSE"))
|
|
|
|
with open(licence_file) as f:
|
|
HeaderFile.LICENSE = "".join("// " + line for line in f)
|
|
|
|
with open(main_header) as f:
|
|
header = f.read()
|
|
|
|
include_files = includes_local.findall(header)
|
|
|
|
headers = [HeaderFile(header_dir, inc) for inc in include_files]
|
|
single_header = reduce(add, headers)
|
|
|
|
if macro is not None:
|
|
before = "CLI11_"
|
|
print("Converting macros", before, "->", macro)
|
|
single_header.macro_replacement(before, macro)
|
|
|
|
if namespace:
|
|
print("Adding namespace", namespace)
|
|
single_header.insert_namespace(namespace)
|
|
|
|
with open(output, "w") as f:
|
|
f.write(str(single_header))
|
|
|
|
print("Created", output)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = ArgumentParser(
|
|
usage="Convert source to single header include. Can optionally add namespace and search-replace replacements (for macros)."
|
|
)
|
|
parser.add_argument("output", help="Single header file output")
|
|
parser.add_argument(
|
|
"--main",
|
|
default="CLI/CLI.hpp",
|
|
help="The main include file that defines the other files",
|
|
)
|
|
parser.add_argument("--include", default="../include", help="The include directory")
|
|
parser.add_argument("--namespace", help="Add an optional namespace")
|
|
parser.add_argument("--macro", help="Replaces CLI11_ with NEW_PREFIX_")
|
|
args = parser.parse_args()
|
|
|
|
MakeHeader(args.output, args.main, args.include, args.namespace, args.macro)
|