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