Line data Source code
1 : #include <utility>
2 :
3 : /**
4 : * @file
5 : *
6 : * @brief
7 : *
8 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
9 : */
10 :
11 : #include "template.hpp"
12 :
13 : #include <algorithm>
14 : #include <command.hpp>
15 : #include <fstream>
16 :
17 : #include <gen/templates.hpp>
18 :
19 : #include "highlevel/highlevel.hpp"
20 :
21 9 : GenTemplate::GenTemplate (std::string templateBaseName, std::vector<std::string> allParts, std::vector<std::string> partials,
22 9 : const std::unordered_map<std::string, bool> & parameters)
23 27 : : _templateBaseName (std::move (templateBaseName)), _allParts (std::move (allParts)), _parts (), _partials (std::move (partials)),
24 90 : _parameters (), _requiredParameters ()
25 : {
26 162 : std::for_each (parameters.begin (), parameters.end (), [this](const std::pair<std::string, bool> & p) {
27 324 : _parameters[p.first] = "";
28 81 : if (p.second)
29 : {
30 0 : _requiredParameters.insert (p.first);
31 : }
32 108 : });
33 9 : }
34 :
35 27 : void GenTemplate::render (std::ostream & output, const std::string & outputName, const std::string & part, const kdb::KeySet & ks,
36 : const std::string & parentKey) const
37 : {
38 : using namespace kainjow::mustache;
39 :
40 : auto missingParam = std::find_if (_requiredParameters.begin (), _requiredParameters.end (),
41 108 : [this](const std::string & p) { return getParameter (p).empty (); });
42 :
43 54 : if (missingParam != _requiredParameters.end ())
44 : {
45 0 : throw CommandAbortException ("missing required parameter " + *missingParam);
46 : }
47 :
48 135 : if (std::find (_parts.begin (), _parts.end (), part) == _parts.end ())
49 : {
50 2 : return;
51 : }
52 :
53 52 : auto name = _templateBaseName + part;
54 162 : std::replace_if (name.begin (), name.end (), std::not1 (std::ptr_fun (isalnum)), '_');
55 :
56 51 : auto data = getTemplateData (outputName, part, ks, parentKey);
57 :
58 26 : if (data.is_false ())
59 : {
60 2 : return;
61 : }
62 :
63 48 : auto tmpl = mustache (kdbgenTemplates.at (name));
64 162 : std::function<std::string (const std::string &)> escapeFunction = [this](const std::string & str) {
65 162 : return this->escapeFunction (str);
66 234 : };
67 24 : tmpl.set_custom_escape (escapeFunction);
68 :
69 408 : for (const auto & partial : getPartials ())
70 : {
71 624 : data[partial.first] = partial.second;
72 : }
73 24 : tmpl.render (data, output);
74 :
75 24 : if (!tmpl.is_valid ())
76 : {
77 0 : throw CommandAbortException ("Error during template rendering: " + tmpl.error_message ());
78 : }
79 : }
80 :
81 0 : std::string GenTemplate::escapeFunction (const std::string & str) const
82 : {
83 0 : return kainjow::mustache::html_escape (str);
84 : }
85 :
86 306 : std::string GenTemplate::getParameter (const std::string & name, const std::string & defaultValue) const
87 : {
88 612 : auto search = _parameters.find (name);
89 1251 : auto param = search != _parameters.end () ? search->second : "";
90 918 : return param.empty () ? defaultValue : param;
91 : }
92 :
93 27 : bool GenTemplate::getBoolParameter (const std::string & name, bool defaultValue) const
94 : {
95 216 : return getParameter<bool> (name, { { "", defaultValue }, { "0", false }, { "1", true } });
96 : }
97 :
98 4 : void GenTemplate::setParameter (const std::string & name, const std::string & value)
99 : {
100 8 : auto param = _parameters.find (name);
101 8 : if (param != _parameters.end ())
102 : {
103 4 : param->second = value;
104 : }
105 4 : }
106 :
107 0 : void GenTemplate::clearParameters ()
108 : {
109 : std::for_each (_parameters.begin (), _parameters.end (),
110 270 : [this](const std::pair<std::string, std::string> & param) { _parameters[param.first] = ""; });
111 0 : }
112 :
113 9 : std::vector<std::string> GenTemplate::getActualParts () const
114 : {
115 9 : return _allParts;
116 : }
117 :
118 9 : void GenTemplate::loadParts ()
119 : {
120 18 : _parts = getActualParts ();
121 9 : }
122 :
123 9 : const std::vector<std::string> & GenTemplate::getParts () const
124 : {
125 9 : return _parts;
126 : }
127 :
128 24 : std::unordered_map<std::string, kainjow::mustache::partial> GenTemplate::getPartials () const
129 : {
130 : using namespace kainjow::mustache;
131 :
132 : std::unordered_map<std::string, partial> partials;
133 :
134 408 : for (const auto & partialFile : _partials)
135 : {
136 1007 : partials["partial." + partialFile] = [&]() {
137 213 : auto name = _templateBaseName + "/" + partialFile;
138 426 : std::replace_if (name.begin (), name.end (), std::not1 (std::ptr_fun (isalnum)), '_');
139 213 : return kdbgenTemplates.at (name);
140 936 : };
141 : }
142 :
143 24 : return partials;
144 : }
145 :
146 : template <class genClass>
147 9 : void GenTemplateList::addTemplate (const std::string & name)
148 : {
149 27 : std::unique_ptr<GenTemplate> tmpl (new genClass ());
150 27 : _templates[name] = std::move (tmpl);
151 9 : }
152 :
153 9 : const GenTemplate * GenTemplateList::getTemplate (const std::string & name,
154 : const std::unordered_map<std::string, std::string> & parameters) const
155 : {
156 18 : auto search = _templates.find (name);
157 18 : if (search == _templates.end ())
158 : {
159 0 : return &EmptyGenTemplate::getInstance ();
160 : }
161 :
162 18 : auto tmpl = search->second.get ();
163 9 : tmpl->clearParameters ();
164 : std::for_each (parameters.begin (), parameters.end (),
165 31 : [tmpl](const std::pair<std::string, std::string> & param) { tmpl->setParameter (param.first, param.second); });
166 9 : tmpl->loadParts ();
167 : return tmpl;
168 : }
169 :
170 18 : GenTemplateList::GenTemplateList () : _templates ()
171 : {
172 36 : addTemplate<HighlevelGenTemplate> ("highlevel");
173 10755 : }
|