44
55#include " ssLogger/ssLog.hpp"
66
7+ #include " ghc/filesystem.hpp"
8+
9+
710// TODO: Merge long and short options into a single structure
811int ParseArgs ( const std::unordered_map<std::string, runcpp2::OptionInfo>& longOptionsMap,
912 const std::unordered_map<std::string, const runcpp2::OptionInfo&>& shortOptionsMap,
@@ -88,7 +91,7 @@ int main(int argc, char* argv[])
8891 // std::unordered_set<runcpp2::CmdOptions> currentOptions;
8992
9093 {
91- static_assert (static_cast <int >(runcpp2::CmdOptions::COUNT) == 8 , " Update this" );
94+ static_assert (static_cast <int >(runcpp2::CmdOptions::COUNT) == 9 , " Update this" );
9295 std::unordered_map<std::string, runcpp2::OptionInfo> longOptionsMap =
9396 {
9497 {
@@ -118,10 +121,14 @@ int main(int argc, char* argv[])
118121 {
119122 " --show-config-path" ,
120123 runcpp2::OptionInfo (runcpp2::CmdOptions::SHOW_USER_CONFIG, false )
124+ },
125+ {
126+ " --create-script-template" ,
127+ runcpp2::OptionInfo (runcpp2::CmdOptions::SCRIPT_TEMPLATE, true )
121128 }
122129 };
123130
124- static_assert (static_cast <int >(runcpp2::CmdOptions::COUNT) == 8 , " Update this" );
131+ static_assert (static_cast <int >(runcpp2::CmdOptions::COUNT) == 9 , " Update this" );
125132 std::unordered_map<std::string, const runcpp2::OptionInfo&> shortOptionsMap =
126133 {
127134 {" -r" , longOptionsMap.at (" --reset-cache" )},
@@ -130,7 +137,9 @@ int main(int argc, char* argv[])
130137 {" -h" , longOptionsMap.at (" --help" )},
131138 {" -d" , longOptionsMap.at (" --remove-dependencies" )},
132139 {" -l" , longOptionsMap.at (" --local" )},
133- {" -s" , longOptionsMap.at (" --show-config-path" )}
140+ {" -s" , longOptionsMap.at (" --show-config-path" )},
141+ {" -t" , longOptionsMap.at (" --create-script-template" )}
142+
134143 };
135144
136145 currentArgIndex = ParseArgs (longOptionsMap, shortOptionsMap, currentOptions, argc, argv);
@@ -147,20 +156,22 @@ int main(int argc, char* argv[])
147156 // Help message
148157 if (currentOptions.count (runcpp2::CmdOptions::HELP))
149158 {
150- static_assert (static_cast <int >(runcpp2::CmdOptions::COUNT) == 8 , " Update this" );
159+ static_assert (static_cast <int >(runcpp2::CmdOptions::COUNT) == 9 , " Update this" );
151160 ssLOG_BASE (" Usage: runcpp2 [options] [input_file]" );
152161 ssLOG_BASE (" Options:" );
153- ssLOG_BASE (" -r, --[r]eset-cache Deletes all cache and build everything from scratch" );
154- ssLOG_BASE (" -c, --reset-user-[c]onfig Replace current user config with the default one" );
155- ssLOG_BASE (" -e, --[e]xecutable Runs as executable instead of shared library" );
156- ssLOG_BASE (" -h, --[h]elp Show this help message" );
157- ssLOG_BASE (" -d, --remove-[d]ependencies Remove dependencies listed in the script" );
158- ssLOG_BASE (" -l, --[l]ocal Build the script and dependencies locally" );
159- ssLOG_BASE (" -s, --[s]how-config-path Show where runcpp2 is reading the config from" );
162+ ssLOG_BASE (" -r, --[r]eset-cache Deletes all cache and build everything from scratch" );
163+ ssLOG_BASE (" -c, --reset-user-[c]onfig Replace current user config with the default one" );
164+ ssLOG_BASE (" -e, --[e]xecutable Runs as executable instead of shared library" );
165+ ssLOG_BASE (" -h, --[h]elp Show this help message" );
166+ ssLOG_BASE (" -d, --remove-[d]ependencies Remove dependencies listed in the script" );
167+ ssLOG_BASE (" -l, --[l]ocal Build the script and dependencies locally" );
168+ ssLOG_BASE (" -s, --[s]how-config-path Show where runcpp2 is reading the config from" );
169+ ssLOG_BASE (" -t, --create-script-[t]emplate <file> Creates/prepend runcpp2 script info template" );
160170
161171 return 0 ;
162172 }
163173
174+ // Show user config path
164175 if (currentOptions.count (runcpp2::CmdOptions::SHOW_USER_CONFIG))
165176 {
166177 ssLOG_BASE (runcpp2::GetConfigFilePath ());
@@ -180,6 +191,92 @@ int main(int argc, char* argv[])
180191 return 0 ;
181192 }
182193
194+ // Generate script info template
195+ if (currentOptions.count (runcpp2::CmdOptions::SCRIPT_TEMPLATE))
196+ {
197+ std::string& outputFilePathStr = currentOptions.at (runcpp2::CmdOptions::SCRIPT_TEMPLATE);
198+ if (outputFilePathStr.empty ())
199+ {
200+ ssLOG_ERROR (" Missing output file path for -t/--create-script-template option" );
201+ return -1 ;
202+ }
203+
204+ std::string defaultScriptInfo;
205+ runcpp2::GetDefaultScriptInfo (defaultScriptInfo);
206+
207+ // Check if output filepath exists, if so check if it is a directory
208+ std::error_code e;
209+ if (ghc::filesystem::exists (outputFilePathStr, e))
210+ {
211+ if (ghc::filesystem::is_directory (outputFilePathStr, e))
212+ {
213+ ssLOG_ERROR (outputFilePathStr << " is a directory. " <<
214+ " Cannot output script template to a directory" );
215+ return -1 ;
216+ }
217+
218+ // If exists, check if it is a cpp/cc file.
219+ ghc::filesystem::path outputFilePath = outputFilePathStr;
220+ std::ifstream readOutputFile (outputFilePath);
221+ std::stringstream buffer;
222+
223+ if (!readOutputFile)
224+ {
225+ ssLOG_ERROR (" Failed to open file: " << outputFilePathStr);
226+ return false ;
227+ }
228+
229+ if (outputFilePath.extension () == " .cpp" || outputFilePath.extension () == " .cc" )
230+ {
231+ // If so, prepend the script info template but wrapped in block comment
232+ buffer << " /* runcpp2" << std::endl << std::endl;
233+ buffer << defaultScriptInfo << std::endl;
234+ buffer << " */" << std::endl << std::endl;
235+ buffer << readOutputFile.rdbuf ();
236+ }
237+ // If not, check if it is yaml/yml.
238+ else if (outputFilePath.extension () == " .yaml" || outputFilePath.extension () == " .yml" )
239+ {
240+ // If so just prepend it normally
241+ buffer << defaultScriptInfo << std::endl << std::endl;
242+ buffer << readOutputFile.rdbuf ();
243+ }
244+ // If not prepend it still but output a warning
245+ else
246+ {
247+ ssLOG_WARNING (" Outputing script info template to non yaml file, is the intended?" );
248+ buffer << defaultScriptInfo << std::endl << std::endl;
249+ buffer << readOutputFile.rdbuf ();
250+ }
251+
252+ readOutputFile.close ();
253+
254+ std::ofstream writeOutputFile (outputFilePath);
255+ if (!writeOutputFile)
256+ {
257+ ssLOG_ERROR (" Failed to open file: " << outputFilePathStr);
258+ return false ;
259+ }
260+
261+ writeOutputFile << buffer.rdbuf ();
262+ }
263+ // Otherwise write it to the file
264+ else
265+ {
266+ std::ofstream writeOutputFile (outputFilePathStr);
267+ if (!writeOutputFile)
268+ {
269+ ssLOG_ERROR (" Failed to open file: " << outputFilePathStr);
270+ return false ;
271+ }
272+
273+ writeOutputFile << defaultScriptInfo;
274+ }
275+
276+ return 0 ;
277+ }
278+
279+
183280 std::vector<runcpp2::Data::Profile> profiles;
184281 std::string preferredProfile;
185282
0 commit comments