1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <fstream>
18 #include <iostream>
19 #include <iterator>
20 #include <map>
21 #include <string>
22 #include <utility>
23
24 #include <boost/filesystem.hpp>
25
26 namespace fs = boost::filesystem;
27
28 namespace {
29
30 constexpr std::size_t string_literal_max_size = 16380; // MSVC C2026
31
from_components(fs::path::const_iterator begin,fs::path::const_iterator end)32 fs::path from_components(
33 fs::path::const_iterator begin, fs::path::const_iterator end) {
34 fs::path tmp;
35 while (begin != end) {
36 tmp /= *begin++;
37 }
38 return tmp;
39 }
40
41 } // namespace
42
main(int argc,char ** argv)43 int main(int argc, char** argv) {
44 if (argc != 2) {
45 std::cerr << "usage: " << argv[0] << " templates-dir" << std::endl;
46 return 1;
47 }
48
49 auto const path = fs::path(argv[1]);
50
51 // read the templates into memory
52
53 // using an ordered map to enable deterministic builds
54 std::map<std::string, std::string> templates;
55 for (auto const& e : fs::recursive_directory_iterator(path)) {
56 auto const& p = e.path();
57 if (p.extension() == ".mustache" && fs::is_regular_file(p)) {
58 using buf_it = std::istreambuf_iterator<char>;
59 auto mm = std::mismatch(p.begin(), p.end(), path.begin(), path.end());
60 assert(mm.second == path.end());
61 auto rel = from_components(mm.first, p.end());
62 auto in = std::ifstream(p.string());
63 auto buf = std::string(buf_it(in), buf_it());
64 templates[rel.generic_string()] = std::move(buf);
65 }
66 }
67
68 // emit a c library to stdout
69
70 const char* const tag = "__FBTHRIFT_TAG__";
71
72 std::string const at = "@";
73 std::string const endl = "\n";
74
75 std::cout << "// " << at << "generated" << endl;
76
77 std::cout << endl;
78
79 std::cout << "#include <thrift/compiler/generate/templates.h>" << endl;
80
81 std::cout << endl;
82
83 std::cout << "namespace apache {" << endl;
84 std::cout << "namespace thrift {" << endl;
85 std::cout << "namespace compiler {" << endl;
86
87 std::cout << endl;
88
89 std::cout << "std::size_t const templates_size = " << templates.size() << ";"
90 << endl;
91
92 std::cout << endl;
93
94 std::cout << "std::size_t const templates_name_sizes[] = {" << endl;
95 for (auto const& kvp : templates) {
96 std::cout << "// " << kvp.first << endl;
97 std::cout << kvp.first.size() << "," << endl;
98 }
99 std::cout << "};" << endl;
100
101 std::cout << endl;
102
103 std::cout << "char const* const templates_name_datas[] = {" << endl;
104 for (auto const& kvp : templates) {
105 std::cout << "// " << kvp.first << endl;
106 std::cout << "\"" << kvp.first << "\"," << endl;
107 }
108 std::cout << "};" << endl;
109
110 std::cout << endl;
111
112 std::cout << "std::size_t const templates_content_sizes[] = {" << endl;
113 for (auto const& kvp : templates) {
114 std::cout << "// " << kvp.first << endl;
115 std::cout << kvp.second.size() << "," << endl;
116 }
117 std::cout << "};" << endl;
118
119 std::cout << endl;
120
121 std::cout << "char const* const templates_content_datas[] = {" << endl;
122 for (auto const& kvp : templates) {
123 std::cout << "// " << kvp.first << endl;
124 auto const max_size = string_literal_max_size;
125 auto const num_pieces = (kvp.second.size() + max_size - 1u) / max_size;
126 for (std::size_t i = 0; i < num_pieces; ++i) {
127 if (i != 0) {
128 std::cout << " /* stitch */ ";
129 }
130 auto const piece = kvp.second.substr(i * max_size, max_size);
131 std::cout << "R\"" << tag << "(" << piece << ")" << tag << "\"";
132 }
133 std::cout << "," << endl;
134 }
135 std::cout << "};" << endl;
136
137 std::cout << endl;
138
139 std::cout << "} // namespace compiler" << endl;
140 std::cout << "} // namespace thrift" << endl;
141 std::cout << "} // namespace apache" << endl;
142
143 return 0;
144 }
145