You need to sign in before continuing.

Commit f862849488557eeee0397814a47449ecfdae0383

Authored by Henry Schreiner
Committed by GitHub
1 parent 32e6c3f3

refactor: new version of MakeSingleFiles (#546)

* refactor: new version of MakeSingleFiles

* fix: use CMake and set version
.github/workflows/build.yml
... ... @@ -22,11 +22,8 @@ jobs:
22 22  
23 23 - uses: actions/setup-python@v2
24 24  
25   - - name: Make header
26   - run: python ./scripts/MakeSingleHeader.py CLI11.hpp
27   -
28 25 - name: Prepare CMake config
29   - run: cmake -S . -B build
  26 + run: cmake -S . -B build -DCLI11_SINGLE_FILE=ON
30 27  
31 28 - name: Make package
32 29 run: cmake --build build --target package_source
... ... @@ -37,10 +34,13 @@ jobs:
37 34 cp build/CLI11-*-Source.* CLI11-Source
38 35 cp build/CLI11-*-Source.* .
39 36  
  37 + - name: Make header
  38 + run: cmake --build build --target CLI11-generate-single-file
  39 +
40 40 - uses: actions/upload-artifact@v2
41 41 with:
42 42 name: CLI11.hpp
43   - path: CLI11.hpp
  43 + path: build/include/CLI11.hpp
44 44  
45 45 - uses: actions/upload-artifact@v2
46 46 with:
... ...
CLI11.hpp.in 0 → 100644
  1 +// CLI11: Version {version}
  2 +// Originally designed by Henry Schreiner
  3 +// https://github.com/CLIUtils/CLI11
  4 +//
  5 +// This is a standalone header file generated by MakeSingleHeader.py in CLI11/scripts
  6 +// from: {git}
  7 +//
  8 +// CLI11 {version} Copyright (c) 2017-2020 University of Cincinnati, developed by Henry
  9 +// Schreiner under NSF AWARD 1414736. All rights reserved.
  10 +//
  11 +// Redistribution and use in source and binary forms of CLI11, with or without
  12 +// modification, are permitted provided that the following conditions are met:
  13 +//
  14 +// 1. Redistributions of source code must retain the above copyright notice, this
  15 +// list of conditions and the following disclaimer.
  16 +// 2. Redistributions in binary form must reproduce the above copyright notice,
  17 +// this list of conditions and the following disclaimer in the documentation
  18 +// and/or other materials provided with the distribution.
  19 +// 3. Neither the name of the copyright holder nor the names of its contributors
  20 +// may be used to endorse or promote products derived from this software without
  21 +// specific prior written permission.
  22 +//
  23 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  24 +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  25 +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  26 +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  27 +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  28 +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  29 +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  30 +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  32 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33 +
  34 +// Standard combined includes:
  35 +{public_includes}
  36 +
  37 +{version_hpp}
  38 +
  39 +{macros_hpp}
  40 +
  41 +{validators_hpp_filesystem}
  42 +
  43 +namespace {namespace} {{
  44 +
  45 +{string_tools_hpp}
  46 +
  47 +{error_hpp}
  48 +
  49 +{type_tools_hpp}
  50 +
  51 +{split_hpp}
  52 +
  53 +{config_fwd_hpp}
  54 +
  55 +{validators_hpp}
  56 +
  57 +{formatter_fwd_hpp}
  58 +
  59 +{option_hpp}
  60 +
  61 +{app_hpp}
  62 +
  63 +{config_hpp}
  64 +
  65 +{formatter_hpp}
  66 +
  67 +}} // namespace {namespace}
... ...
CMakeLists.txt
... ... @@ -247,7 +247,10 @@ if(CLI11_SINGLE_FILE)
247 247 add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp"
248 248 COMMAND Python::Interpreter
249 249 "${CMAKE_CURRENT_SOURCE_DIR}/scripts/MakeSingleHeader.py"
250   - "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp"
  250 + ${CLI11_headers}
  251 + --main "${CMAKE_CURRENT_SOURCE_DIR}/CLI11.hpp.in"
  252 + --output "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp"
  253 + --version "${CLI11_VERSION}"
251 254 DEPENDS
252 255 "${CMAKE_CURRENT_SOURCE_DIR}/include/CLI/CLI.hpp"
253 256 ${CLI11_headers})
... ...
include/CLI/App.hpp
... ... @@ -6,6 +6,7 @@
6 6  
7 7 #pragma once
8 8  
  9 +// [CLI11:public_includes:set]
9 10 #include <algorithm>
10 11 #include <cstdint>
11 12 #include <functional>
... ... @@ -18,6 +19,7 @@
18 19 #include <string>
19 20 #include <utility>
20 21 #include <vector>
  22 +// [CLI11:public_includes:end]
21 23  
22 24 // CLI Library includes
23 25 #include "ConfigFwd.hpp"
... ... @@ -30,6 +32,7 @@
30 32 #include "TypeTools.hpp"
31 33  
32 34 namespace CLI {
  35 +// [CLI11:app_hpp:verbatim]
33 36  
34 37 #ifndef CLI11_PARSE
35 38 #define CLI11_PARSE(app, argc, argv) \
... ... @@ -3234,4 +3237,5 @@ struct AppFriend {
3234 3237 };
3235 3238 } // namespace detail
3236 3239  
  3240 +// [CLI11:app_hpp:end]
3237 3241 } // namespace CLI
... ...
include/CLI/Config.hpp
... ... @@ -6,19 +6,21 @@
6 6  
7 7 #pragma once
8 8  
  9 +// [CLI11:public_includes:set]
9 10 #include <algorithm>
10 11 #include <fstream>
11 12 #include <iostream>
12 13 #include <string>
13 14 #include <utility>
14 15 #include <vector>
  16 +// [CLI11:public_includes:set]
15 17  
16 18 #include "App.hpp"
17 19 #include "ConfigFwd.hpp"
18 20 #include "StringTools.hpp"
19 21  
20 22 namespace CLI {
21   -
  23 +// [CLI11:config_hpp:verbatim]
22 24 namespace detail {
23 25  
24 26 inline std::string convert_arg_for_ini(const std::string &arg) {
... ... @@ -348,4 +350,5 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description,
348 350 return out.str();
349 351 }
350 352  
  353 +// [CLI11:config_hpp:end]
351 354 } // namespace CLI
... ...
include/CLI/ConfigFwd.hpp
... ... @@ -6,16 +6,19 @@
6 6  
7 7 #pragma once
8 8  
  9 +// [CLI11:public_includes:set]
9 10 #include <algorithm>
10 11 #include <fstream>
11 12 #include <iostream>
12 13 #include <string>
13 14 #include <vector>
  15 +// [CLI11:public_includes:end]
14 16  
15 17 #include "Error.hpp"
16 18 #include "StringTools.hpp"
17 19  
18 20 namespace CLI {
  21 +// [CLI11:config_fwd_hpp:verbatim]
19 22  
20 23 class App;
21 24  
... ... @@ -128,4 +131,5 @@ class ConfigINI : public ConfigTOML {
128 131 valueDelimiter = '=';
129 132 }
130 133 };
  134 +// [CLI11:config_fwd_hpp:end]
131 135 } // namespace CLI
... ...
include/CLI/Error.hpp
... ... @@ -6,16 +6,19 @@
6 6  
7 7 #pragma once
8 8  
  9 +// [CLI11:public_includes:set]
9 10 #include <exception>
10 11 #include <stdexcept>
11 12 #include <string>
12 13 #include <utility>
13 14 #include <vector>
  15 +// [CLI11:public_includes:end]
14 16  
15 17 // CLI library includes
16 18 #include "StringTools.hpp"
17 19  
18 20 namespace CLI {
  21 +// [CLI11:error_hpp:verbatim]
19 22  
20 23 // Use one of these on all error classes.
21 24 // These are temporary and are undef'd at the end of this file.
... ... @@ -344,4 +347,5 @@ class OptionNotFound : public Error {
344 347  
345 348 /// @}
346 349  
  350 +// [CLI11:error_hpp:end]
347 351 } // namespace CLI
... ...
include/CLI/Formatter.hpp
... ... @@ -6,14 +6,17 @@
6 6  
7 7 #pragma once
8 8  
  9 +// [CLI11:public_includes:set]
9 10 #include <algorithm>
10 11 #include <string>
11 12 #include <vector>
  13 +// [CLI11:public_includes:end]
12 14  
13 15 #include "App.hpp"
14 16 #include "FormatterFwd.hpp"
15 17  
16 18 namespace CLI {
  19 +// [CLI11:formatter_hpp:verbatim]
17 20  
18 21 inline std::string
19 22 Formatter::make_group(std::string group, bool is_positional, std::vector<const Option *> opts) const {
... ... @@ -285,4 +288,5 @@ inline std::string Formatter::make_option_usage(const Option *opt) const {
285 288 return opt->get_required() ? out.str() : "[" + out.str() + "]";
286 289 }
287 290  
  291 +// [CLI11:formatter_hpp:end]
288 292 } // namespace CLI
... ...
include/CLI/FormatterFwd.hpp
... ... @@ -6,14 +6,17 @@
6 6  
7 7 #pragma once
8 8  
  9 +// [CLI11:public_includes:set]
9 10 #include <map>
10 11 #include <string>
11 12 #include <utility>
12 13 #include <vector>
  14 +// [CLI11:public_includes:end]
13 15  
14 16 #include "StringTools.hpp"
15 17  
16 18 namespace CLI {
  19 +// [CLI11:formatter_fwd_hpp:verbatim]
17 20  
18 21 class Option;
19 22 class App;
... ... @@ -177,4 +180,5 @@ class Formatter : public FormatterBase {
177 180 ///@}
178 181 };
179 182  
  183 +// [CLI11:formatter_fwd_hpp:end]
180 184 } // namespace CLI
... ...
include/CLI/Macros.hpp
... ... @@ -6,7 +6,7 @@
6 6  
7 7 #pragma once
8 8  
9   -// [CLI11:verbatim]
  9 +// [CLI11:macros_hpp:verbatim]
10 10  
11 11 // The following version macro is very similar to the one in PyBind11
12 12 #if !(defined(_MSC_VER) && __cplusplus == 199711L) && !defined(__INTEL_COMPILER)
... ... @@ -41,4 +41,4 @@
41 41 #define CLI11_DEPRECATED(reason) __attribute__((deprecated(reason)))
42 42 #endif
43 43  
44   -// [CLI11:verbatim]
  44 +// [CLI11:macros_hpp:end]
... ...
include/CLI/Option.hpp
... ... @@ -6,6 +6,7 @@
6 6  
7 7 #pragma once
8 8  
  9 +// [CLI11:public_includes:set]
9 10 #include <algorithm>
10 11 #include <functional>
11 12 #include <memory>
... ... @@ -14,6 +15,7 @@
14 15 #include <tuple>
15 16 #include <utility>
16 17 #include <vector>
  18 +// [CLI11:public_includes:end]
17 19  
18 20 #include "Error.hpp"
19 21 #include "Macros.hpp"
... ... @@ -22,6 +24,7 @@
22 24 #include "Validators.hpp"
23 25  
24 26 namespace CLI {
  27 +// [CLI11:option_hpp:verbatim]
25 28  
26 29 using results_t = std::vector<std::string>;
27 30 /// callback function definition
... ... @@ -1316,4 +1319,5 @@ class Option : public OptionBase&lt;Option&gt; {
1316 1319 }
1317 1320 }; // namespace CLI
1318 1321  
  1322 +// [CLI11:option_hpp:end]
1319 1323 } // namespace CLI
... ...
include/CLI/Split.hpp
... ... @@ -6,15 +6,19 @@
6 6  
7 7 #pragma once
8 8  
  9 +// [CLI11:public_includes:set]
9 10 #include <string>
10 11 #include <tuple>
11 12 #include <utility>
12 13 #include <vector>
  14 +// [CLI11:public_includes:end]
13 15  
14 16 #include "Error.hpp"
15 17 #include "StringTools.hpp"
16 18  
17 19 namespace CLI {
  20 +// [CLI11:split_hpp:verbatim]
  21 +
18 22 namespace detail {
19 23  
20 24 // Returns false if not a short option. Otherwise, sets opt name and rest and returns true
... ... @@ -135,4 +139,5 @@ get_names(const std::vector&lt;std::string&gt; &amp;input) {
135 139 }
136 140  
137 141 } // namespace detail
  142 +// [CLI11:split_hpp:end]
138 143 } // namespace CLI
... ...
include/CLI/StringTools.hpp
... ... @@ -6,6 +6,7 @@
6 6  
7 7 #pragma once
8 8  
  9 +// [CLI11:public_includes:set]
9 10 #include <algorithm>
10 11 #include <iomanip>
11 12 #include <locale>
... ... @@ -14,9 +15,12 @@
14 15 #include <string>
15 16 #include <type_traits>
16 17 #include <vector>
  18 +// [CLI11:public_includes:end]
17 19  
18 20 namespace CLI {
19 21  
  22 +// [CLI11:string_tools_hpp:verbatim]
  23 +
20 24 /// Include the items in this namespace to get free conversion of enums to/from streams.
21 25 /// (This is available inside CLI as well, so CLI11 will use this without a using statement).
22 26 namespace enums {
... ... @@ -409,4 +413,6 @@ inline std::string &amp;add_quotes_if_needed(std::string &amp;str) {
409 413  
410 414 } // namespace detail
411 415  
  416 +// [CLI11:string_tools_hpp:end]
  417 +
412 418 } // namespace CLI
... ...
include/CLI/TypeTools.hpp
... ... @@ -6,7 +6,7 @@
6 6  
7 7 #pragma once
8 8  
9   -#include "StringTools.hpp"
  9 +// [CLI11:public_includes:set]
10 10 #include <cstdint>
11 11 #include <exception>
12 12 #include <memory>
... ... @@ -14,8 +14,12 @@
14 14 #include <type_traits>
15 15 #include <utility>
16 16 #include <vector>
  17 +// [CLI11:public_includes:end]
  18 +
  19 +#include "StringTools.hpp"
17 20  
18 21 namespace CLI {
  22 +// [CLI11:type_tools_hpp:verbatim]
19 23  
20 24 // Type tools
21 25  
... ... @@ -1540,4 +1544,5 @@ void sum_flag_vector(const std::vector&lt;std::string&gt; &amp;flags, T &amp;output) {
1540 1544 #endif
1541 1545  
1542 1546 } // namespace detail
  1547 +// [CLI11:type_tools_hpp:end]
1543 1548 } // namespace CLI
... ...
include/CLI/Validators.hpp
... ... @@ -10,6 +10,7 @@
10 10 #include "StringTools.hpp"
11 11 #include "TypeTools.hpp"
12 12  
  13 +// [CLI11:public_includes:set]
13 14 #include <cmath>
14 15 #include <cstdint>
15 16 #include <functional>
... ... @@ -20,8 +21,9 @@
20 21 #include <string>
21 22 #include <utility>
22 23 #include <vector>
  24 +// [CLI11:public_includes:end]
23 25  
24   -// [CLI11:verbatim]
  26 +// [CLI11:validators_hpp_filesystem:verbatim]
25 27  
26 28 // C standard library
27 29 // Only needed for existence checking
... ... @@ -55,9 +57,10 @@
55 57 #include <sys/types.h>
56 58 #endif
57 59  
58   -// [CLI11:verbatim]
  60 +// [CLI11:validators_hpp_filesystem:end]
59 61  
60 62 namespace CLI {
  63 +// [CLI11:validators_hpp:verbatim]
61 64  
62 65 class Option;
63 66  
... ... @@ -1112,4 +1115,5 @@ inline std::pair&lt;std::string, std::string&gt; split_program_name(std::string comman
1112 1115 } // namespace detail
1113 1116 /// @}
1114 1117  
  1118 +// [CLI11:validators_hpp:end]
1115 1119 } // namespace CLI
... ...
include/CLI/Version.hpp
... ... @@ -6,11 +6,11 @@
6 6  
7 7 #pragma once
8 8  
9   -// [CLI11:verbatim]
  9 +// [CLI11:version_hpp:verbatim]
10 10  
11 11 #define CLI11_VERSION_MAJOR 1
12 12 #define CLI11_VERSION_MINOR 9
13 13 #define CLI11_VERSION_PATCH 1
14 14 #define CLI11_VERSION "1.9.1"
15 15  
16   -// [CLI11:verbatim]
  16 +// [CLI11:version_hpp:end]
... ...
scripts/MakeSingleHeader.py
... ... @@ -5,171 +5,136 @@ from __future__ import print_function, unicode_literals
5 5 import os
6 6 import re
7 7 from argparse import ArgumentParser
8   -from operator import add
9   -from copy import copy
10   -from functools import reduce
11 8 from subprocess import Popen, PIPE
12   -
13   -includes_local = re.compile(r"""^#include "(.*)"$""", re.MULTILINE)
14   -includes_system = re.compile(r"""^#include \<(.*)\>$""", re.MULTILINE)
15   -version_finder = re.compile(r"""^#define CLI11_VERSION \"(.*)\"$""", re.MULTILINE)
16   -verbatim_tag_str = r"""
17   -^ # Begin of line
18   -[^\n^\[]+ # Some characters, not including [ or the end of a line
19   -\[ # A literal [
20   -[^\]^\n]* # Anything except a closing ]
21   -CLI11:verbatim # The tag
22   -[^\]^\n]* # Anything except a closing ]
23   -\] # A literal ]
24   -[^\n]* # Up to end of line
25   -$ # End of a line
  9 +import warnings
  10 +
  11 +tag_str = r"""
  12 +^ # Begin of line
  13 +[/\s]+ # Whitespace or comment // chars
  14 +\[ # A literal [
  15 +{tag}: # The tag
  16 +(?P<name>[\w_]+) # name: group name
  17 +: # Colon
  18 +(?P<action>[\w_]+) # action: type of include
  19 +\] # A literal ]
  20 +\s* # Whitespace
  21 +$ # End of a line
  22 +
  23 +(?P<content>.*) # All
  24 +
  25 +^ # Begin of line
  26 +[/\s]+ # Whitespace or comment // chars
  27 +\[ # A literal [
  28 +{tag}: # The tag
  29 +(?P=name) # Repeated name
  30 +: # Colon
  31 +end # Literal "end"
  32 +\] # A literal ]
  33 +\s* # Whitespace
  34 +$ # End of a line
26 35 """
27   -verbatim_all = re.compile(
28   - verbatim_tag_str + "(.*)" + verbatim_tag_str, re.MULTILINE | re.DOTALL | re.VERBOSE
29   -)
30 36  
31 37 DIR = os.path.dirname(os.path.abspath(__file__))
32 38  
33 39  
34   -class HeaderFile(object):
35   - TAG = "Unknown git revision"
36   - LICENSE = "// BSD 3 clause"
37   - VERSION = "Unknown"
  40 +class HeaderGroups(dict):
  41 + def __init__(self, tag):
  42 + self.re_matcher = re.compile(
  43 + tag_str.format(tag=tag), re.MULTILINE | re.DOTALL | re.VERBOSE
  44 + )
  45 + super(HeaderGroups, self).__init__()
38 46  
39   - def __init__(self, base, inc):
40   - with open(os.path.join(base, inc)) as f:
  47 + def read_header(self, filename):
  48 + with open(filename) as f:
41 49 inner = f.read()
42 50  
43   - version = version_finder.search(inner)
44   - if version:
45   - self.__class__.VERSION = version.groups()[0]
46   -
47   - # add self.verbatim
48   - if "CLI11:verbatim" in inner:
49   - self.verbatim = ["\n\n// Verbatim copy from {0}:".format(inc)]
50   - self.verbatim += verbatim_all.findall(inner)
51   - inner = verbatim_all.sub("", inner)
52   - else:
53   - self.verbatim = []
54   -
55   - self.headers = set(includes_system.findall(inner))
56   -
57   - self.body = "\n// From {0}:\n\n".format(inc) + inner[inner.find("namespace") :]
58   -
59   - self.namespace = None
60   -
61   - def __add__(self, other):
62   - out = copy(self)
63   - out.headers |= other.headers
64   - out.body += other.body
65   - out.verbatim += other.verbatim
66   - return out
67   -
68   - @property
69   - def header_str(self):
70   - return "\n".join("#include <" + h + ">" for h in sorted(self.headers))
71   -
72   - @property
73   - def verbatim_str(self):
74   - return "\n".join(self.verbatim)
75   -
76   - def insert_namespace(self, namespace):
77   - self.namespace = namespace
78   -
79   - def macro_replacement(self, before, after):
80   - self.verbatim = [x.replace(before, after) for x in self.verbatim]
81   - self.body = self.body.replace(before, after)
82   -
83   - def __str__(self):
84   - result = """\
85   -#pragma once
86   -
87   -// CLI11: Version {self.VERSION}
88   -// Originally designed by Henry Schreiner
89   -// https://github.com/CLIUtils/CLI11
90   -//
91   -// This is a standalone header file generated by MakeSingleHeader.py in CLI11/scripts
92   -// from: {self.TAG}
93   -//
94   -// From LICENSE:
95   -//
96   -{self.LICENSE}
97   -
98   -// Standard combined includes:
99   -
100   -{self.header_str}
101   -""".format(
102   - self=self
103   - )
  51 + matches = self.re_matcher.findall(inner)
  52 +
  53 + if not matches:
  54 + warnings.warn(
  55 + "Failed to find any matches in {filename}".format(filename=filename)
  56 + )
104 57  
105   - if self.namespace:
106   - result += "\nnamespace " + self.namespace + " {\n\n"
107   - result += "{self.verbatim_str}\n{self.body}\n".format(self=self)
108   - if self.namespace:
109   - result += "} // namespace " + self.namespace + "\n\n"
  58 + for name, action, content in matches:
  59 + if action == "verbatim":
  60 + assert (
  61 + name not in self
  62 + ), "{name} read in more than once! Quitting.".format(name=name)
  63 + self[name] = content
  64 + elif action == "set":
  65 + self[name] = self.get(name, set()) | set(content.strip().splitlines())
  66 + else:
  67 + raise RuntimeError("Action not understood, must be verbatim or set")
110 68  
111   - return result
  69 + def post_process(self):
  70 + for key in self:
  71 + if isinstance(self[key], set):
  72 + self[key] = "\n".join(self[key])
112 73  
113 74  
114   -def MakeHeader(
115   - output, main_header, include_dir="../include", namespace=None, macro=None
116   -):
  75 +def MakeHeader(output, main_header, files, tag, namespace, macro=None, version=None):
  76 + groups = HeaderGroups(tag)
  77 +
117 78 # Set tag if possible to class variable
118 79 try:
119 80 proc = Popen(
120 81 ["git", "describe", "--tags", "--always"], cwd=str(DIR), stdout=PIPE
121 82 )
122 83 out, _ = proc.communicate()
  84 + groups["git"] = out.decode("utf-8").strip() if proc.returncode == 0 else ""
123 85 except OSError:
124   - pass
125   - else:
126   - if proc.returncode == 0:
127   - HeaderFile.TAG = out.decode("utf-8").strip()
128   -
129   - base_dir = os.path.abspath(os.path.join(DIR, include_dir))
130   - main_header = os.path.join(base_dir, main_header)
131   - header_dir = os.path.dirname(main_header)
132   - licence_file = os.path.abspath(os.path.join(DIR, "../LICENSE"))
  86 + groups["git"] = ""
133 87  
134   - with open(licence_file) as f:
135   - HeaderFile.LICENSE = "".join("// " + line for line in f)
  88 + for f in files:
  89 + groups.read_header(f)
136 90  
137   - with open(main_header) as f:
138   - header = f.read()
  91 + groups["namespace"] = namespace
  92 + groups["version"] = version or groups["git"]
139 93  
140   - include_files = includes_local.findall(header)
  94 + groups.post_process()
141 95  
142   - headers = [HeaderFile(header_dir, inc) for inc in include_files]
143   - single_header = reduce(add, headers)
  96 + with open(main_header) as f:
  97 + single_header = f.read().format(**groups)
144 98  
145 99 if macro is not None:
146   - before = "CLI11_"
147   - print("Converting macros", before, "->", macro)
148   - single_header.macro_replacement(before, macro)
  100 + before, after = macro
  101 + print("Converting macros", before, "->", after)
  102 + single_header.replace(before, after)
149 103  
150   - if namespace:
151   - print("Adding namespace", namespace)
152   - single_header.insert_namespace(namespace)
  104 + if output is not None:
  105 + with open(output, "w") as f:
  106 + f.write(single_header)
153 107  
154   - with open(output, "w") as f:
155   - f.write(str(single_header))
156   -
157   - print("Created", output)
  108 + print("Created", output)
  109 + else:
  110 + print(single_header)
158 111  
159 112  
160 113 if __name__ == "__main__":
161 114 parser = ArgumentParser(
162 115 usage="Convert source to single header include. Can optionally add namespace and search-replace replacements (for macros)."
163 116 )
164   - parser.add_argument("output", help="Single header file output")
  117 + parser.add_argument("--output", default=None, help="Single header file output")
165 118 parser.add_argument(
166 119 "--main",
167   - default="CLI/CLI.hpp",
  120 + default="CLI11.hpp.in",
168 121 help="The main include file that defines the other files",
169 122 )
170   - parser.add_argument("--include", default="../include", help="The include directory")
171   - parser.add_argument("--namespace", help="Add an optional namespace")
172   - parser.add_argument("--macro", help="Replaces CLI11_ with NEW_PREFIX_")
  123 + parser.add_argument("files", nargs="*", help="The header files")
  124 + parser.add_argument("--namespace", default="CLI", help="Set the namespace")
  125 + parser.add_argument("--tag", default="CLI11", help="Tag to look up")
  126 + parser.add_argument(
  127 + "--macro", nargs=2, help="Replaces OLD_PREFIX_ with NEW_PREFIX_"
  128 + )
  129 + parser.add_argument("--version", help="Include this version in the generated file")
173 130 args = parser.parse_args()
174 131  
175   - MakeHeader(args.output, args.main, args.include, args.namespace, args.macro)
  132 + MakeHeader(
  133 + args.output,
  134 + args.main,
  135 + args.files,
  136 + args.tag,
  137 + args.namespace,
  138 + args.macro,
  139 + args.version,
  140 + )
... ...