diff --git a/Examples/InteractiveTutorial.cpp b/Examples/InteractiveTutorial.cpp index 2cab460..78fdef8 100644 --- a/Examples/InteractiveTutorial.cpp +++ b/Examples/InteractiveTutorial.cpp @@ -40,6 +40,7 @@ Defines: ["ssLOG_USE_SOURCE=1"] std::string runcpp2ExecutablePath = ""; std::string downloadBranch = "heads/master"; bool integrationTest = false; +std::string extraOptions = ""; #define DELAYED_OUTPUT(str) \ do \ @@ -124,7 +125,7 @@ bool InitializeRuncpp2ExecutablePath() while(true) { System2CommandInfo commandInfo = {0}; - SYSTEM2_RESULT result = System2CppRun("runcpp2 --version", commandInfo); + SYSTEM2_RESULT result = System2CppRun("runcpp2 version", commandInfo); if(result != SYSTEM2_RESULT_SUCCESS) return false; @@ -309,17 +310,16 @@ int main(int, char**) DELAYED_OUTPUT("A simple hello world file is created (\"tutorial/main.cpp\")."); DELAYED_OUTPUT("Now, let's run it."); - if(!RunCommandWithPrompt(runcpp2ExecutablePath + " tutorial/main.cpp")) + if(!RunCommandWithPrompt(runcpp2ExecutablePath + " run" + extraOptions + " tutorial/main.cpp")) return false; DELAYED_OUTPUT("Seems simple enough.\n"); DELAYED_OUTPUT("Let's build the script instead of running it."); - DELAYED_OUTPUT("Unless specified, input file is treated as `Executable`\n"); DELAYED_OUTPUT( "We can get the binary files of the script by " - "using the `--build` (or `-b`) option."); - DELAYED_OUTPUT( "And we can specify the output directory for the binary files with `--output` " + "using the `build` option."); + DELAYED_OUTPUT( "And we can specify the output directory for the binary files with `--output-dir` " "(or `-o`)"); DELAYED_OUTPUT( "We also need to pass the `--executable` (or `-e`) option to " "explicitly get an executable file. \n" @@ -328,8 +328,8 @@ int main(int, char**) DELAYED_OUTPUT("Let's try it"); if(!RunCommandWithPrompt( runcpp2ExecutablePath + - " --build --output ./tutorial --executable " - "tutorial/main.cpp")) + " build --output-dir ./tutorial --executable" + extraOptions + + " tutorial/main.cpp")) { return false; } @@ -355,37 +355,43 @@ int main(int, char**) DELAYED_OUTPUT( "Sometimes you want to remove the cache of the script before running it again.\n" "You can do that by using the `--rebuild` (or `-rb`) option."); - if(!RunCommandWithPrompt(runcpp2ExecutablePath + " --rebuild ./tutorial/main.cpp")) + if(!RunCommandWithPrompt( runcpp2ExecutablePath + " build --rebuild" + extraOptions + + " ./tutorial/main.cpp")) + { return false; + } DELAYED_OUTPUT("You can also see the build/run process by changing the log level to `info`."); DELAYED_OUTPUT("Let's rebuild the cache again and see the build process."); if(!RunCommandWithPrompt( runcpp2ExecutablePath + - " --rebuild --log-level info ./tutorial/main.cpp")) + " build --rebuild --log-level info" + extraOptions + + " ./tutorial/main.cpp")) { return false; } - DELAYED_OUTPUT( "runcpp2 also can give realtime error feedback by using " - "the `--watch` (or `-w`) option."); + DELAYED_OUTPUT( "runcpp2 also can give realtime error feedback by using the `watch` option."); DELAYED_OUTPUT("I would love to show it here but it will block this tutorial."); DELAYED_OUTPUT("Feel free to try it yourself. " - "Make a change, or an error, then run `runcpp2 --watch tutorial/main.cpp`"); + "Make a change, or an error, then run `runcpp2 watch tutorial/main.cpp`"); DELAYED_OUTPUT("Once you are done, you can revert the changes and continue the tutorial."); DELAYED_OUTPUT("Press enter to continue..."); GetInput(true); DELAYED_OUTPUT( "You can find the path to your config file and all the builds " - "with the `--show-config-path` (or `-sc`) option."); - if(!RunCommandWithPrompt(runcpp2ExecutablePath + " --show-config-path")) + "with the `show-config-path` option."); + if(!RunCommandWithPrompt(runcpp2ExecutablePath + " show-config-path")) return false; DELAYED_OUTPUT("Feel free to make any changes to the config file.\n"); DELAYED_OUTPUT( "Finally, you can specify your script to be built in the current directory " "with the `--local` (or `-l`) option. \n" "This will create and build in the `.runcpp2` directory"); - if(!RunCommandWithPrompt("cd tutorial && " + runcpp2ExecutablePath + " --local main.cpp")) + if(!RunCommandWithPrompt( "cd tutorial && " + runcpp2ExecutablePath + " run --local" + + extraOptions + " main.cpp")) + { return false; + } #ifdef _WIN32 if(!RunCommandWithPrompt("dir tutorial")) @@ -485,8 +491,11 @@ bool Chapter2_BuildConfig() DELAYED_OUTPUT("I have just added the output line"); DELAYED_OUTPUT("Now let's run the script"); - if(!RunCommandWithPrompt("cd tutorial && " + runcpp2ExecutablePath + " main.cpp")) + if(!RunCommandWithPrompt( "cd tutorial && " + runcpp2ExecutablePath + " run" + extraOptions + + " main.cpp")) + { return false; + } DELAYED_OUTPUT( "You should see the output `42`. \n" "You can specify different settings for different platforms and profiles."); @@ -560,8 +569,11 @@ bool Chapter2_BuildConfig() } DELAYED_OUTPUT("Now let me run the script again, nothing should have changed."); - if(!RunCommandWithPrompt("cd tutorial && " + runcpp2ExecutablePath + " main.cpp")) + if(!RunCommandWithPrompt( "cd tutorial && " + runcpp2ExecutablePath + " run" + extraOptions + + " main.cpp")) + { return false; + } DELAYED_OUTPUT(""); DELAYED_OUTPUT("A common build config is to specify other source files."); @@ -664,8 +676,11 @@ void CallHello(); } DELAYED_OUTPUT("Let's run the script again."); - if(!RunCommandWithPrompt("cd tutorial && " + runcpp2ExecutablePath + " main.cpp")) + if(!RunCommandWithPrompt( "cd tutorial && " + runcpp2ExecutablePath + " run" + extraOptions + + " main.cpp")) + { return false; + } DELAYED_OUTPUT("You should see the output `Hello from another C++ file`."); DELAYED_OUTPUT(""); @@ -687,8 +702,11 @@ IncludePaths: ["./"] DELAYED_OUTPUT("I have just updated the YAML file to omit `DefaultPlatform` and `DefaultProfile`."); DELAYED_OUTPUT("It's much more concise now. Let's run the script again."); - if(!RunCommandWithPrompt("cd tutorial && " + runcpp2ExecutablePath + " main.cpp")) + if(!RunCommandWithPrompt( "cd tutorial && " + runcpp2ExecutablePath + " run" + extraOptions + + " main.cpp")) + { return false; + } DELAYED_OUTPUT("You should see the same output as before."); DELAYED_OUTPUT(""); @@ -723,7 +741,8 @@ IncludePaths: ["./"] "it will use the \"-E\" flag."); DELAYED_OUTPUT("If you are using msvc and you are on Windows, it will use the \"/P\" flag."); DELAYED_OUTPUT("Let's run the script now."); - RunCommandWithPrompt("cd tutorial && " + runcpp2ExecutablePath + " main.cpp"); + RunCommandWithPrompt( "cd tutorial && " + runcpp2ExecutablePath + " run" + extraOptions + + " main.cpp"); DELAYED_OUTPUT(""); DELAYED_OUTPUT( "You probably see some errors for linking, this is expected since the " @@ -746,7 +765,7 @@ IncludePaths: ["./"] DELAYED_OUTPUT("You can do that by using the `--create-script-template`/ `-t` option."); DELAYED_OUTPUT("This will either create a new file or prepend the template to the existing file."); - if(!RunCommandWithPrompt(runcpp2ExecutablePath + " -t tutorial/template.yaml")) + if(!RunCommandWithPrompt(runcpp2ExecutablePath + " template tutorial/template.yaml")) return false; DELAYED_OUTPUT("You can see the template in tutorial/template.yaml"); @@ -809,8 +828,11 @@ bool Chapter3_ExternalDependencies() DELAYED_OUTPUT( "Next, you have \"LibraryType\" which tells runcpp2 what type of dependency " "this is. Other options include \"Static\", \"Object\" and \"Shared\""); DELAYED_OUTPUT("That's pretty much it for a header only library. Let's run it shall we?"); - if(!RunCommandWithPrompt("cd tutorial && " + runcpp2ExecutablePath + " Logging.cpp")) + if(!RunCommandWithPrompt( "cd tutorial && " + runcpp2ExecutablePath + " run" + extraOptions + + " Logging.cpp")) + { return false; + } DELAYED_OUTPUT("Let's try an external shared library"); DELAYED_OUTPUT("Let me query and download an example for you."); @@ -864,14 +886,20 @@ bool Chapter3_ExternalDependencies() "the script for the first time. Let's run it now."); if(!integrationTest) { - if(!RunCommandWithPrompt("cd tutorial && " + runcpp2ExecutablePath + " SDLWindow.cpp")) + if(!RunCommandWithPrompt( "cd tutorial && " + runcpp2ExecutablePath + " run" + + extraOptions + " SDLWindow.cpp")) + { return false; + } } else { DELAYED_OUTPUT("running SDLWindow.cpp skipped for integration testing"); - if(!RunCommandWithPrompt("cd tutorial && " + runcpp2ExecutablePath + " --build SDLWindow.cpp")) + if(!RunCommandWithPrompt( "cd tutorial && " + runcpp2ExecutablePath + " build" + + extraOptions + " SDLWindow.cpp")) + { return false; + } } DELAYED_OUTPUT("You can also have a dependency as a standalone YAML file which you can import."); @@ -1021,14 +1049,20 @@ bool Chapter3_ExternalDependencies() DELAYED_OUTPUT("Let's run it now."); if(!integrationTest) { - if(!RunCommandWithPrompt("cd tutorial && " + runcpp2ExecutablePath + " SDLWindow.cpp")) + if(!RunCommandWithPrompt( "cd tutorial && " + runcpp2ExecutablePath + " run" + + extraOptions + " SDLWindow.cpp")) + { return false; + } } else { DELAYED_OUTPUT("running SDLWindow.cpp skipped for integration testing"); - if(!RunCommandWithPrompt("cd tutorial && " + runcpp2ExecutablePath + " --build SDLWindow.cpp")) + if(!RunCommandWithPrompt( "cd tutorial && " + runcpp2ExecutablePath + " build" + + extraOptions + " SDLWindow.cpp")) + { return false; + } } DELAYED_OUTPUT("This concludes the 3rd chapter of the tutorial."); @@ -1077,14 +1111,15 @@ int main(int argc, char* argv[]) return 1; } - runcpp2ExecutablePath = exePath.string() + " -l -c " + configPath.string(); + runcpp2ExecutablePath = exePath.string(); + extraOptions = " -l -c " + configPath.string(); } //Get runcpp2 version { System2CommandInfo commandInfo = {0}; commandInfo.RedirectOutput = true; - SYSTEM2_RESULT result = System2CppRun(runcpp2ExecutablePath + " --version", commandInfo); + SYSTEM2_RESULT result = System2CppRun(runcpp2ExecutablePath + " version", commandInfo); #define CHECK_RESULT() \ if(result != SYSTEM2_RESULT_SUCCESS) \ { \ diff --git a/External/DSResult b/External/DSResult index a8edc10..c1b54d0 160000 --- a/External/DSResult +++ b/External/DSResult @@ -1 +1 @@ -Subproject commit a8edc10d20a7441d01276280f451e8a0c2100c9b +Subproject commit c1b54d0ea1179f2396c95a470174cf3199f719ef diff --git a/Jenkinsfile b/Jenkinsfile index 41ad2f1..2beb1a7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -358,10 +358,10 @@ pipeline unstash 'linux_build' bash "ls -lah" bash "ls -lah ./Build/Src/Tests" - bash "cd ./Build && ./runcpp2 -l " + + bash "cd ./Build && ./runcpp2 run -l " + "-c ../DefaultYAMLs/DefaultUserConfig.yaml " + "--log-level info ../Tests/Test.cpp" - bash "cd ./Build && ./runcpp2 -l -b -o . " + + bash "cd ./Build && ./runcpp2 build -l -o . " + "-c ../DefaultYAMLs/DefaultUserConfig.yaml " + "--log-level info ../Tests/Test.cpp" bash "ls -lah ./Build" @@ -372,7 +372,7 @@ pipeline unstash 'linux_build' bash "ls -lah" bash "ls -lah ./Build/Src/Tests" - bash "cd ./Build && ./runcpp2 -l -b -o . " + + bash "cd ./Build && ./runcpp2 build -l -o . " + "-c ../DefaultYAMLs/DefaultUserConfig.yaml " + "--log-level info ../Tests/TestStatic.cpp" bash "ls -lah ./Build" @@ -383,7 +383,7 @@ pipeline unstash 'linux_build' bash "ls -lah" bash "ls -lah ./Build/Src/Tests" - bash "cd ./Build && ./runcpp2 -l " + + bash "cd ./Build && ./runcpp2 run -l " + "-c ../DefaultYAMLs/DefaultUserConfig.yaml " + "--log-level info ../Tests/TestLocalDependency.cpp" @@ -392,7 +392,7 @@ pipeline unstash 'linux_build' bash "ls -lah" bash "ls -lah ./Build/Src/Tests" - bash "cd ./Build && ./runcpp2 -l " + + bash "cd ./Build && ./runcpp2 run -l " + "-c ../DefaultYAMLs/DefaultUserConfig.yaml " + "--log-level info ../Tests/TestSeparateYaml.cpp" @@ -404,7 +404,7 @@ pipeline script { def retResult = - sh( script: "cd ./Build && ./runcpp2 -l " + + sh( script: "cd ./Build && ./runcpp2 run -l " + "-c ../DefaultYAMLs/DefaultUserConfig.yaml " + "--log-level info ../Tests/TestMissingSource.yaml", returnStatus: true) @@ -416,7 +416,7 @@ pipeline unstash 'linux_build' bash "ls -lah" bash "ls -lah ./Build/Src/Tests" - bash "cd ./Build && ./runcpp2 -l " + + bash "cd ./Build && ./runcpp2 run -l " + "-c ../DefaultYAMLs/DefaultUserConfig.yaml " + "--log-level info ../Tests/YamlOnlyTest.yaml" @@ -425,7 +425,7 @@ pipeline unstash 'linux_build' bash "ls -lah" bash "ls -lah ./Build/Src/Tests" - bash "cd ./Build && ./runcpp2 -l " + + bash "cd ./Build && ./runcpp2 run -l " + "-c ../DefaultYAMLs/DefaultUserConfig.yaml " + "../Examples/InteractiveTutorial.cpp --test " + "./runcpp2 ../DefaultYAMLs/DefaultUserConfig.yaml" @@ -458,10 +458,10 @@ pipeline bat 'dir' unstash 'windows_build' bat 'dir' - bat "cd .\\Build\\Debug && .\\runcpp2.exe -l " + + bat "cd .\\Build\\Debug && .\\runcpp2.exe run -l " + "-c ..\\..\\DefaultYAMLs\\DefaultUserConfig.yaml " + "--log-level info ..\\..\\Tests\\Test.cpp" - bat "cd .\\Build\\Debug && .\\runcpp2.exe -l -b -o . " + + bat "cd .\\Build\\Debug && .\\runcpp2.exe build -l -o . " + "-c ..\\..\\DefaultYAMLs\\DefaultUserConfig.yaml " + "--log-level info ..\\..\\Tests\\Test.cpp" bat "dir .\\Build\\Debug" @@ -471,7 +471,7 @@ pipeline bat 'dir' unstash 'windows_build' bat 'dir' - bat "cd .\\Build\\Debug && .\\runcpp2.exe -l -b -o . " + + bat "cd .\\Build\\Debug && .\\runcpp2.exe build -l -o . " + "-c ..\\..\\DefaultYAMLs\\DefaultUserConfig.yaml " + "--log-level info ..\\..\\Tests\\TestStatic.cpp" bat "dir .\\Build\\Debug" @@ -481,7 +481,7 @@ pipeline bat 'dir' unstash 'windows_build' bat 'dir' - bat "cd .\\Build\\Debug && .\\runcpp2.exe -l " + + bat "cd .\\Build\\Debug && .\\runcpp2.exe run -l " + "-c ..\\..\\DefaultYAMLs\\DefaultUserConfig.yaml " + "--log-level info ..\\..\\Tests\\TestLocalDependency.cpp" @@ -489,7 +489,7 @@ pipeline bat 'dir' unstash 'windows_build' bat 'dir' - bat "cd .\\Build\\Debug && .\\runcpp2.exe -l " + + bat "cd .\\Build\\Debug && .\\runcpp2.exe run -l " + "-c ..\\..\\DefaultYAMLs\\DefaultUserConfig.yaml " + "--log-level info ..\\..\\Tests\\TestSeparateYaml.cpp" @@ -500,7 +500,7 @@ pipeline script { def retResult = - bat(script: "cd .\\Build\\Debug && .\\runcpp2.exe -l " + + bat(script: "cd .\\Build\\Debug && .\\runcpp2.exe run -l " + "-c ..\\..\\DefaultYAMLs\\DefaultUserConfig.yaml " + "--log-level info ..\\..\\Tests\\TestMissingSource.yaml", returnStatus: true) @@ -511,7 +511,7 @@ pipeline bat 'dir' unstash 'windows_build' bat 'dir' - bat "cd .\\Build\\Debug && .\\runcpp2.exe -l " + + bat "cd .\\Build\\Debug && .\\runcpp2.exe run -l " + "-c ..\\..\\DefaultYAMLs\\DefaultUserConfig.yaml " + "--log-level info ..\\..\\Tests\\YamlOnlyTest.yaml" @@ -519,7 +519,7 @@ pipeline bat 'dir' unstash 'windows_build' bat 'dir' - bat "cd .\\Build\\Debug && .\\runcpp2.exe -l " + + bat "cd .\\Build\\Debug && .\\runcpp2.exe run -l " + "-c ..\\..\\DefaultYAMLs\\DefaultUserConfig.yaml " + "..\\..\\Examples\\InteractiveTutorial.cpp --test " + ".\\runcpp2.exe ..\\..\\DefaultYAMLs\\DefaultUserConfig.yaml" diff --git a/README.md b/README.md index 046a325..079c8ac 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ runcpp2 is a simple declarable, scriptable, flexible cross-platform build system build system for c or c++ -- 🚀 **Simple**: `runcpp2 main.cpp`, this is all you need to get started +- 🚀 **Simple**: `runcpp2 run main.cpp`, this is all you need to get started - 📝 **Declarable**: *Quick, Concise, Minimal* YAML format - 🔧 **Scriptable**: *Customize, Run And Debug* your build pipeline with c++, or just use it as a script. No longer need to juggle between CMake, Python, Bash, Batch, Lua, etc... @@ -32,7 +32,7 @@ you can run c++ files anywhere you want. ### Interactive Tutorial -You can get started by running the tutorial with `runcpp2 --tutorial` and follow the instructions +You can get started by running the tutorial with `runcpp2 tutorial` and follow the instructions ### User Guide diff --git a/Src/runcpp2/ConfigParsing.hpp b/Src/runcpp2/ConfigParsing.hpp index a334c5e..2ec3d1a 100644 --- a/Src/runcpp2/ConfigParsing.hpp +++ b/Src/runcpp2/ConfigParsing.hpp @@ -264,7 +264,7 @@ namespace namespace runcpp2 { - inline DS::Result GetConfigFilePath() + inline DS::Result GetConfigFilePath() { CO_INSERT_IMPL(OverrideInstance, DS::Result, ()); @@ -416,7 +416,7 @@ namespace runcpp2 ssLOG_FUNC_INFO(); ghc::filesystem::path configPath = !customConfigPath.empty() ? - customConfigPath : + ghc::filesystem::path(customConfigPath) : GetConfigFilePath().DS_VALUE_OR(); DS_CHECK_PREV(); ghc::filesystem::path configVersionPath = configPath.parent_path() / ".version"; diff --git a/Src/runcpp2/Data/CmdOptions.hpp b/Src/runcpp2/Data/CmdOptions.hpp deleted file mode 100644 index ed05981..0000000 --- a/Src/runcpp2/Data/CmdOptions.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef RUNCPP2_DATA_CMD_OPTIONS_HPP -#define RUNCPP2_DATA_CMD_OPTIONS_HPP - -//TODO: Get rid of this -namespace runcpp2 -{ - enum class CmdOptions - { - NONE, - RESET_CACHE, - RESET_USER_CONFIG, - EXECUTABLE, - HELP, - RESET_DEPENDENCIES, - LOCAL, - SHOW_USER_CONFIG, - SCRIPT_TEMPLATE, - WATCH, - BUILD, - OUTPUT, - VERSION, - LOG_LEVEL, - CONFIG_FILE, - CLEANUP, - BUILD_SOURCE_ONLY, - THREADS, - TUTORIAL, - PARAMETERS, - COUNT - }; -} - -#endif diff --git a/Src/runcpp2/Data/PipelineResult.hpp b/Src/runcpp2/Data/PipelineResult.hpp deleted file mode 100644 index a38bc0a..0000000 --- a/Src/runcpp2/Data/PipelineResult.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef RUNCPP2_PIPELINE_RESULT_HPP -#define RUNCPP2_PIPELINE_RESULT_HPP - -namespace runcpp2 -{ - enum class PipelineResult - { - UNEXPECTED_FAILURE, - SUCCESS, - EMPTY_PROFILES, - INVALID_SCRIPT_PATH, - INVALID_CONFIG_PATH, - INVALID_BUILD_DIR, - INVALID_SCRIPT_INFO, - NO_AVAILABLE_PROFILE, - DEPENDENCIES_FAILED, - COMPILE_LINK_FAILED, - INVALID_PROFILE, - RUN_SCRIPT_FAILED, - INVALID_OPTION, - COUNT - }; -} - -#endif diff --git a/Src/runcpp2/DependenciesHelper.hpp b/Src/runcpp2/DependenciesHelper.hpp index 07eda23..15dff22 100644 --- a/Src/runcpp2/DependenciesHelper.hpp +++ b/Src/runcpp2/DependenciesHelper.hpp @@ -140,7 +140,7 @@ namespace runcpp2 DS_ASSERT_EQ(availableDependencies.size(), dependenciesLocalCopiesPaths.size()); //Split dependency names if not "all" - std::unordered_set dependencyNames; + std::unordered_map dependencyNames; if(dependenciesToReset != "all") { std::string currentName; @@ -154,11 +154,12 @@ namespace runcpp2 if(!currentName.empty()) { runcpp2::Trim(currentName); + //TODO: v Maybe this is not a good idea? //Convert to lowercase for case-insensitive comparison for(int j = 0; j < currentName.size(); ++j) currentName[j] = std::tolower(currentName[j]); - dependencyNames.insert(currentName); + dependencyNames[currentName] = false; currentName.clear(); } } @@ -182,6 +183,8 @@ namespace runcpp2 ssLOG_DEBUG(availableDependencies.at(i)->Name << " not in list to remove"); continue; } + + dependencyNames[depName] = true; } std::error_code e; @@ -211,6 +214,14 @@ namespace runcpp2 ssLOG_DEBUG(availableDependencies.at(i)->Name << " removed"); } + for(std::unordered_map::iterator it = dependencyNames.begin(); + it != dependencyNames.end(); + ++it) + { + if(!it->second) + ssLOG_WARNING("Dependency " << it->first << " not found for resetting"); + } + return {}; } diff --git a/Src/runcpp2/PipelineSteps.hpp b/Src/runcpp2/PipelineSteps.hpp index 539eb9e..853edba 100644 --- a/Src/runcpp2/PipelineSteps.hpp +++ b/Src/runcpp2/PipelineSteps.hpp @@ -2,10 +2,8 @@ #define RUNCPP2_PIPELINE_STEPS_HPP #include "runcpp2/Data/Profile.hpp" -#include "runcpp2/Data/PipelineResult.hpp" #include "runcpp2/Data/ProfilesCommands.hpp" #include "runcpp2/Data/ScriptInfo.hpp" -#include "runcpp2/Data/CmdOptions.hpp" #include "runcpp2/Data/BuildTypeHelper.hpp" #include "runcpp2/Data/BuildType.hpp" #include "runcpp2/Data/DependencyInfo.hpp" @@ -272,7 +270,7 @@ namespace runcpp2 " with return code " + DS_STR(returnCode) + "\n"; errorMsg += "Was trying to run: " + cmd + "\n"; errorMsg += "Output: \n" + output; - return DS_ERROR_MSG_EC(errorMsg, (int)PipelineResult::UNEXPECTED_FAILURE); + return DS_ERROR_MSG(errorMsg); } ssLOG_INFO(commandType << " command ran: \n" << cmd); @@ -284,44 +282,6 @@ namespace runcpp2 return {}; } - inline DS::Result ValidateInputs( const std::string& scriptPath, - const std::vector& profiles, - ghc::filesystem::path& outAbsoluteScriptPath, - ghc::filesystem::path& outScriptDirectory, - std::string& outScriptName) - { - ssLOG_FUNC_INFO(); - - if(profiles.empty()) - return DS_ERROR_MSG_EC("No compiler profiles found", (int)PipelineResult::EMPTY_PROFILES); - - //Check if input file exists - std::error_code _; - if(!ghc::filesystem::exists(scriptPath, _)) - { - return DS_ERROR_MSG_EC( "File does not exist: " + scriptPath, - (int)PipelineResult::INVALID_SCRIPT_PATH); - } - - if(ghc::filesystem::is_directory(scriptPath, _)) - { - return DS_ERROR_MSG_EC( "The input file must not be a directory: " + scriptPath, - (int)PipelineResult::INVALID_SCRIPT_PATH); - } - - outAbsoluteScriptPath = ghc::filesystem::absolute(ghc::filesystem::canonical(scriptPath, _)); - outScriptDirectory = outAbsoluteScriptPath.parent_path(); - outScriptName = outAbsoluteScriptPath.stem().string(); - - ssLOG_DEBUG("scriptPath: " << scriptPath); - ssLOG_DEBUG("absoluteScriptPath: " << outAbsoluteScriptPath.string()); - ssLOG_DEBUG("scriptDirectory: " << outScriptDirectory.string()); - ssLOG_DEBUG("scriptName: " << outScriptName); - ssLOG_DEBUG("is_directory: " << ghc::filesystem::is_directory(outScriptDirectory)); - - return {}; - } - inline DS::Result ParseAndValidateScriptInfo( const ghc::filesystem::path& absoluteScriptPath, const ghc::filesystem::path& scriptDirectory, @@ -370,16 +330,13 @@ namespace runcpp2 { std::string errorMsg = e.message(); errorMsg += "\nFailed to get last write time for: " + scriptInfoFile.string(); - return DS_ERROR_MSG_EC(errorMsg, (int)PipelineResult::INVALID_SCRIPT_INFO); + return DS_ERROR_MSG(errorMsg); } inputFile.open(scriptInfoFile); if(!inputFile) - { - return DS_ERROR_MSG_EC( "Failed to open file: " + scriptInfoFile.string(), - (int)PipelineResult::INVALID_SCRIPT_PATH); - } + return DS_ERROR_MSG( "Failed to open file: " + scriptInfoFile.string()); std::stringstream buffer; buffer << inputFile.rdbuf(); @@ -392,7 +349,6 @@ namespace runcpp2 .DS_TRY_ACT(DS_TMP_ERROR.Message += "\nAn error has been encountered when parsing info: " + scriptInfoFile.string(); - DS_TMP_ERROR.ErrorCode = (int)PipelineResult::INVALID_SCRIPT_INFO; DS_APPEND_TRACE(DS_TMP_ERROR); return DS::Error(DS_TMP_ERROR)); } @@ -402,7 +358,6 @@ namespace runcpp2 ParseScriptInfo(parsableInfo, inputParameters, outScriptInfo) .DS_TRY_ACT(DS_APPEND_TRACE(DS_TMP_ERROR); DS_TMP_ERROR.Message += "\nContent trying to parse: \n" + parsableInfo; - DS_TMP_ERROR.ErrorCode = (int)PipelineResult::INVALID_SCRIPT_INFO; return DS::Error(DS_TMP_ERROR)); if(!parsableInfo.empty()) @@ -448,9 +403,8 @@ namespace runcpp2 if(!runcpp2::RunCommand(cmd, true, scriptDirectory, output, returnCode)) { - return DS_ERROR_MSG_EC( "Cleanup command failed: " + cmd + " with return code " + - DS_STR(returnCode) + "\nOutput: \n" + output, - (int)PipelineResult::UNEXPECTED_FAILURE); + return DS_ERROR_MSG("Cleanup command failed: " + cmd + " with return code " + + DS_STR(returnCode) + "\nOutput: \n" + output); } ssLOG_INFO("Cleanup command ran: \n" << cmd); @@ -462,28 +416,19 @@ namespace runcpp2 //Remove build directory std::error_code e; if(!ghc::filesystem::remove_all(buildDir, e)) - { - return DS_ERROR_MSG_EC( "Failed to remove build directory: " + buildDir.string(), - (int)PipelineResult::UNEXPECTED_FAILURE); - } + return DS_ERROR_MSG("Failed to remove build directory: " + buildDir.string()); if(!buildsManager.RemoveBuildMapping(absoluteScriptPath)) - { - return DS_ERROR_MSG_EC( "Failed to remove build mapping", - (int)PipelineResult::UNEXPECTED_FAILURE); - } + return DS_ERROR_MSG("Failed to remove build mapping"); if(!buildsManager.SaveBuildsMappings()) - { - return DS_ERROR_MSG_EC( "Failed to save build mappings", - (int)PipelineResult::UNEXPECTED_FAILURE); - } + return DS_ERROR_MSG("Failed to save build mappings"); return {}; } inline DS::Result - InitializeBuildDirectory( const ghc::filesystem::path& configDir, + InitializeBuildDirectory( const ghc::filesystem::path& defaultBuildDir, const ghc::filesystem::path& absoluteScriptPath, bool useLocalBuildDir, BuildsManager& outBuildsManager, @@ -495,16 +440,13 @@ namespace runcpp2 //Create build directory ghc::filesystem::path buildDirPath = useLocalBuildDir ? ghc::filesystem::current_path() / ".runcpp2" : - configDir; + defaultBuildDir; //Create a class that manages build folder outBuildsManager = BuildsManager(buildDirPath); if(!outBuildsManager.Initialize()) - { - return DS_ERROR_MSG_EC( "Failed to initialize builds manager", - (int)PipelineResult::INVALID_BUILD_DIR); - } + return DS_ERROR_MSG("Failed to initialize builds manager"); bool createdBuildDir = false; bool writeMapping = false; @@ -521,17 +463,13 @@ namespace runcpp2 if(!createdBuildDir) { - return DS_ERROR_MSG_EC( "Failed to create local build directory for: " + - DS_STR(absoluteScriptPath), - (int)PipelineResult::INVALID_BUILD_DIR); + return DS_ERROR_MSG("Failed to create local build directory for: " + + DS_STR(absoluteScriptPath)); } outIncludeManager = IncludeManager(); if(!outIncludeManager.Initialize(outBuildDir)) - { - return DS_ERROR_MSG_EC( "Failed to initialize include manager", - (int)PipelineResult::INVALID_BUILD_DIR); - } + return DS_ERROR_MSG("Failed to initialize include manager"); return {}; } @@ -543,11 +481,7 @@ namespace runcpp2 ssLOG_FUNC_INFO(); //Resolve all the script info imports first before evaluating it - ResolveImports(scriptInfo, scriptDirectory, buildDir) - .DS_TRY_ACT(DS_TMP_ERROR.ErrorCode = (int)PipelineResult::UNEXPECTED_FAILURE; - DS_APPEND_TRACE(DS_TMP_ERROR); - return DS::Error(DS_TMP_ERROR)); - + ResolveImports(scriptInfo, scriptDirectory, buildDir).DS_TRY(); return {}; } @@ -557,7 +491,6 @@ namespace runcpp2 const Data::Profile& profile, const ghc::filesystem::path& scriptDirectory, const Data::ScriptInfo* lastScriptInfo, - const int maxThreads, const std::unordered_map parameters, bool& outAllRecompileNeeded, bool& outRelinkNeeded, @@ -670,10 +603,7 @@ namespace runcpp2 { std::ofstream writeOutputFile(lastScriptInfoFilePath); if(!writeOutputFile) - { - return DS_ERROR_MSG_EC( "Failed to open file: " + DS_STR(lastScriptInfoFilePath), - (int)PipelineResult::INVALID_BUILD_DIR); - } + return DS_ERROR_MSG( "Failed to open file: " + DS_STR(lastScriptInfoFilePath)); std::string scriptInfoString = scriptInfo.ToString("").DS_TRY(); writeOutputFile << scriptInfoString; @@ -687,14 +617,47 @@ namespace runcpp2 return {}; } + inline DS::Result + ResetDependencies( Data::ScriptInfo& scriptInfo, + const Data::Profile& profile, + const ghc::filesystem::path& scriptDirectory, + const ghc::filesystem::path& buildDir, + const std::string& targetDepToReset) + { + ssLOG_FUNC_INFO(); + + std::vector availableDependencies; + for(int i = 0; i < scriptInfo.Dependencies.size(); ++i) + { + if(IsDependencyAvailableForThisPlatform(scriptInfo.Dependencies.at(i))) + availableDependencies.push_back(&scriptInfo.Dependencies.at(i)); + } + + std::vector dependenciesLocalCopiesPaths; + std::vector dependenciesSourcePaths; + GetDependenciesPaths( availableDependencies, + dependenciesLocalCopiesPaths, + dependenciesSourcePaths, + scriptDirectory, + buildDir).DS_TRY(); + + CleanupDependencies(profile, + scriptInfo, + availableDependencies, + dependenciesLocalCopiesPaths, + targetDepToReset).DS_TRY(); + + return {}; + } + inline DS::Result ProcessDependencies(Data::ScriptInfo& scriptInfo, const Data::Profile& profile, const ghc::filesystem::path& scriptDirectory, const ghc::filesystem::path& buildDir, - const std::unordered_map& currentOptions, const std::vector& changedDependencies, + bool buildSourceOnly, const int maxThreads, std::vector& outAvailableDependencies, std::vector& outGatheredBinariesPaths) @@ -713,64 +676,42 @@ namespace runcpp2 dependenciesLocalCopiesPaths, dependenciesSourcePaths, scriptDirectory, - buildDir) - .DS_TRY_ACT(DS_TMP_ERROR.ErrorCode = (int)PipelineResult::DEPENDENCIES_FAILED; - DS_APPEND_TRACE(DS_TMP_ERROR); - return DS::Error(DS_TMP_ERROR)); + buildDir).DS_TRY(); - if(currentOptions.count(CmdOptions::RESET_DEPENDENCIES) > 0 || !changedDependencies.empty()) + if(!changedDependencies.empty()) { - if(currentOptions.count(CmdOptions::BUILD_SOURCE_ONLY) > 0) + if(buildSourceOnly) { - std::string errorMsg = - "Dependencies settings have changed or being reset explicitly.\n" - "Cannot just build source files only without building dependencies"; - return DS_ERROR_MSG_EC(errorMsg, (int)PipelineResult::INVALID_OPTION); + return DS_ERROR_MSG("Dependencies settings have changed or being reset explicitly.\n" + "Cannot just build source files only without building " + "dependencies"); } - std::string depsToReset = "all"; - if(!changedDependencies.empty()) - { - depsToReset = changedDependencies[0]; - for(int i = 1; i < changedDependencies.size(); ++i) - depsToReset += "," + changedDependencies[i]; - } + std::string depsToReset = changedDependencies[0]; + for(int i = 1; i < changedDependencies.size(); ++i) + depsToReset += "," + changedDependencies[i]; CleanupDependencies(profile, scriptInfo, outAvailableDependencies, dependenciesLocalCopiesPaths, - currentOptions.count(CmdOptions::RESET_DEPENDENCIES) > 0 ? - currentOptions.at(CmdOptions::RESET_DEPENDENCIES) : - depsToReset) - .DS_TRY_ACT(DS_TMP_ERROR.ErrorCode = (int)PipelineResult::DEPENDENCIES_FAILED; - DS_APPEND_TRACE(DS_TMP_ERROR); - return DS::Error(DS_TMP_ERROR)); + depsToReset).DS_TRY(); } - if(currentOptions.count(CmdOptions::RESET_DEPENDENCIES) > 0) - return {}; - SetupDependenciesIfNeeded( profile, buildDir, scriptInfo, outAvailableDependencies, dependenciesLocalCopiesPaths, dependenciesSourcePaths, - maxThreads) - .DS_TRY_ACT(DS_TMP_ERROR.ErrorCode = (int)PipelineResult::DEPENDENCIES_FAILED; - DS_APPEND_TRACE(DS_TMP_ERROR); - return DS::Error(DS_TMP_ERROR)); + maxThreads).DS_TRY(); //Sync local dependencies before building SyncLocalDependencies( outAvailableDependencies, dependenciesSourcePaths, - dependenciesLocalCopiesPaths) - .DS_TRY_ACT(DS_TMP_ERROR.ErrorCode = (int)PipelineResult::DEPENDENCIES_FAILED; - DS_APPEND_TRACE(DS_TMP_ERROR); - return DS::Error(DS_TMP_ERROR)); + dependenciesLocalCopiesPaths).DS_TRY(); - if(currentOptions.count(CmdOptions::BUILD_SOURCE_ONLY) == 0) + if(buildSourceOnly) { BuildDependencies( profile, scriptInfo, @@ -781,8 +722,7 @@ namespace runcpp2 ( DS_TMP_ERROR.Message += "\nFailed to build script dependencies. Maybe try resetting dependencies " - "with \"-rd all\" and run again?"; - DS_TMP_ERROR.ErrorCode = (int)PipelineResult::DEPENDENCIES_FAILED; + "and run again?"; DS_APPEND_TRACE(DS_TMP_ERROR); return DS::Error(DS_TMP_ERROR); ); @@ -791,10 +731,7 @@ namespace runcpp2 GatherDependenciesBinaries( outAvailableDependencies, dependenciesLocalCopiesPaths, profile, - outGatheredBinariesPaths) - .DS_TRY_ACT(DS_TMP_ERROR.ErrorCode = (int)PipelineResult::DEPENDENCIES_FAILED; - DS_APPEND_TRACE(DS_TMP_ERROR); - return DS::Error(DS_TMP_ERROR)); + outGatheredBinariesPaths).DS_TRY(); return {}; } @@ -891,7 +828,6 @@ namespace runcpp2 const ghc::filesystem::path& absoluteScriptPath, const Data::ScriptInfo& scriptInfo, const std::vector& runArgs, - const std::unordered_map& currentOptions, int& returnStatus) { ssLOG_FUNC_INFO(); @@ -906,10 +842,7 @@ namespace runcpp2 std::error_code e; if(target.empty() || !ghc::filesystem::exists(target, e)) - { - return DS_ERROR_MSG_EC( "Failed to find the compiled file to run", - (int)PipelineResult::COMPILE_LINK_FAILED); - } + return DS_ERROR_MSG("Failed to find the compiled file to run"); //Prepare run arguments std::vector finalRunArgs; @@ -925,13 +858,13 @@ namespace runcpp2 { //Running the script with modified args if(!RunCompiledScript(target, absoluteScriptPath, finalRunArgs, returnStatus)) - return DS_ERROR_MSG_EC("Failed to run script", (int)PipelineResult::RUN_SCRIPT_FAILED); + return DS_ERROR_MSG("Failed to run script"); } else { //Load the shared library and run it with modified args if(!RunCompiledSharedLib(absoluteScriptPath, target, finalRunArgs, returnStatus)) - return DS_ERROR_MSG_EC("Failed to run script", (int)PipelineResult::RUN_SCRIPT_FAILED); + return DS_ERROR_MSG("Failed to run script"); } return {}; @@ -941,8 +874,7 @@ namespace runcpp2 GetBuiltTargetPaths(const ghc::filesystem::path& buildDir, const std::string& scriptName, const Data::Profile& profile, - const std::unordered_map< CmdOptions, - std::string>& currentOptions, + bool buildExecutable, const Data::ScriptInfo& scriptInfo, std::vector& outTargets, ghc::filesystem::path* outRunnableTarget) @@ -953,7 +885,7 @@ namespace runcpp2 outTargets.clear(); //Validate executable option against build type - if( currentOptions.count(CmdOptions::EXECUTABLE) > 0 && + if( buildExecutable && scriptInfo.CurrentBuildType != Data::BuildType::INTERNAL_EXECUTABLE_SHARED && scriptInfo.CurrentBuildType != Data::BuildType::INTERNAL_EXECUTABLE_EXECUTABLE) { @@ -962,7 +894,7 @@ namespace runcpp2 Data::BuildTypeToString(scriptInfo.CurrentBuildType) + " output. Please remove --executable flag or change build type to Executable"; - return DS_ERROR_MSG_EC(errMsg, (int)PipelineResult::INVALID_OPTION); + return DS_ERROR_MSG(errMsg); } //Get all target paths @@ -974,9 +906,8 @@ namespace runcpp2 outTargets, isRunnable)) { - return DS_ERROR_MSG_EC( "Extension or prefix not found in compiler profile for build type: " + - runcpp2::Data::BuildTypeToString(scriptInfo.CurrentBuildType), - (int)PipelineResult::INVALID_SCRIPT_INFO); + return DS_ERROR_MSG("Extension or prefix not found in compiler profile for build type: " + + runcpp2::Data::BuildTypeToString(scriptInfo.CurrentBuildType)); } //Verify all targets exist @@ -986,7 +917,6 @@ namespace runcpp2 { ssLOG_WARNING("Failed to find the compiled file: " << target.string()); continue; - //return PipelineResult::COMPILE_LINK_FAILED; } } diff --git a/Src/runcpp2/main.cpp b/Src/runcpp2/main.cpp index fd53193..a097d11 100644 --- a/Src/runcpp2/main.cpp +++ b/Src/runcpp2/main.cpp @@ -1,6 +1,4 @@ -#include "runcpp2/Data/CmdOptions.hpp" #include "runcpp2/Data/ParseCommon.hpp" -#include "runcpp2/Data/PipelineResult.hpp" #include "runcpp2/Data/Profile.hpp" #include "runcpp2/Data/ScriptInfo.hpp" @@ -26,43 +24,38 @@ #include #include -#define OUTPUT_ERROR() ssLOG_ERROR(DS_TMP_ERROR.ToString()); +struct OptionInfo +{ + std::string LongOption; + bool ValueExists; +}; //TODO: Merge long and short options into a single structure -int ParseArgs( const std::unordered_map& longOptionsMap, - const std::unordered_map& shortOptionsMap, - std::unordered_map& outOptions, +int ParseArgs( const std::unordered_map& longOptionsMap, + const std::unordered_map& shortOptionsMap, + std::unordered_map& outLongOptions, int argc, char* argv[]) { int currentArgIndex = 0; - runcpp2::CmdOptions optionForCapturingValue = runcpp2::CmdOptions::NONE; + std::string optionForCapturingValue = ""; for(int i = 1; i < argc; ++i) { std::string currentArg = std::string(argv[i]); //Storing value for last option - if(optionForCapturingValue != runcpp2::CmdOptions::NONE) + if(!optionForCapturingValue.empty()) { //If the current argument matches one of the options, error out if(longOptionsMap.count(currentArg) || shortOptionsMap.count(currentArg)) { - //Find the string for the option to error out - for(auto it = longOptionsMap.begin(); it != longOptionsMap.end(); ++it) - { - if(it->second.Option == optionForCapturingValue) - { - ssLOG_ERROR("Missing value for option: " << it->first); - return -1; - } - } - + ssLOG_ERROR("Missing value for option: " << optionForCapturingValue); return -1; } - outOptions[optionForCapturingValue] = currentArg; - optionForCapturingValue = runcpp2::CmdOptions::NONE; + outLongOptions[optionForCapturingValue] = currentArg; + optionForCapturingValue.clear(); currentArgIndex = i; ssLOG_DEBUG("currentArgIndex: " << currentArgIndex); ssLOG_DEBUG("argv: " << argv[i]); @@ -75,13 +68,13 @@ int ParseArgs( const std::unordered_map& long currentArgIndex = i; ssLOG_DEBUG("currentArgIndex: " << currentArgIndex); ssLOG_DEBUG("argv: " << argv[i]); - const runcpp2::OptionInfo& currentInfo = longOptionsMap.count(currentArg) ? - longOptionsMap.at(currentArg) : - shortOptionsMap.at(currentArg); + const OptionInfo& currentInfo = longOptionsMap.count(currentArg) ? + longOptionsMap.at(currentArg) : + shortOptionsMap.at(currentArg); if(currentInfo.ValueExists) - optionForCapturingValue = currentInfo.Option; + optionForCapturingValue = currentInfo.LongOption; else - outOptions[currentInfo.Option] = ""; + outLongOptions[currentInfo.LongOption] = ""; continue; } @@ -98,38 +91,29 @@ int ParseArgs( const std::unordered_map& long return currentArgIndex; } -bool GenerateScriptTemplate(const std::string& outputFilePathStr) +DS::Result GenerateScriptTemplate(const ghc::filesystem::path& outputFilePath) { - if(outputFilePathStr.empty()) - { - ssLOG_ERROR("Missing output file path for -t/--create-script-template option"); - return false; - } + DS_ASSERT_FALSE(outputFilePath.empty()); std::string defaultScriptInfo; runcpp2::GetDefaultScriptInfo(defaultScriptInfo); //Check if output filepath exists, if so check if it is a directory std::error_code e; - if(ghc::filesystem::exists(outputFilePathStr, e)) + if(ghc::filesystem::exists(outputFilePath, e)) { - if(ghc::filesystem::is_directory(outputFilePathStr, e)) + if(ghc::filesystem::is_directory(outputFilePath, e)) { - ssLOG_ERROR(outputFilePathStr << " is a directory. " << - "Cannot output script template to a directory"); - return false; + return DS_ERROR_MSG(outputFilePath.string() + " is a directory. " + + "Cannot output script template to a directory"); } //If exists, check if it is a cpp/cc file. - ghc::filesystem::path outputFilePath = outputFilePathStr; std::ifstream readOutputFile(outputFilePath); std::stringstream buffer; if(!readOutputFile) - { - ssLOG_ERROR("Failed to open file: " << outputFilePathStr); - return false; - } + return DS_ERROR_MSG("Failed to open file: " + outputFilePath.string()); if(outputFilePath.extension() == ".cpp" || outputFilePath.extension() == ".cc") { @@ -158,195 +142,45 @@ bool GenerateScriptTemplate(const std::string& outputFilePathStr) std::ofstream writeOutputFile(outputFilePath); if(!writeOutputFile) - { - ssLOG_ERROR("Failed to open file: " << outputFilePathStr); - return false; - } + return DS_ERROR_MSG("Failed to open file: " + outputFilePath.string()); writeOutputFile << buffer.rdbuf(); } //Otherwise write it to the file else { - std::ofstream writeOutputFile(outputFilePathStr); + std::ofstream writeOutputFile(outputFilePath); if(!writeOutputFile) - { - ssLOG_ERROR("Failed to open file: " << outputFilePathStr); - return false; - } + return DS_ERROR_MSG("Failed to open file: " + outputFilePath.string()); writeOutputFile << defaultScriptInfo; } - return true; + return {}; } +std::string PadSpaceRight(const std::string& s, int padCol) +{ + if(s.size() > padCol) + return s; + return s + std::string(padCol - s.size(), ' '); +} -int main(int argc, char* argv[]) +const int CMD_COLS_BEFORE_DESC = 56; +void PrintGeneralOptions() { - ssLOG_SET_CURRENT_THREAD_TARGET_LEVEL(ssLOG_LEVEL_WARNING); - - //TODO: Rework this - //Parse command line options - int currentArgIndex = 0; - std::unordered_map currentOptions; - { - static_assert((int)runcpp2::CmdOptions::COUNT == 20, "Update this"); - std::unordered_map longOptionsMap = - { - { - "--rebuild", - runcpp2::OptionInfo(runcpp2::CmdOptions::RESET_CACHE, false) - }, - { - "--reset-user-config", - runcpp2::OptionInfo(runcpp2::CmdOptions::RESET_USER_CONFIG, false) - }, - { - "--executable", - runcpp2::OptionInfo(runcpp2::CmdOptions::EXECUTABLE, false) - }, - { - "--help", - runcpp2::OptionInfo(runcpp2::CmdOptions::HELP, false) - }, - { - "--reset-dependencies", - runcpp2::OptionInfo(runcpp2::CmdOptions::RESET_DEPENDENCIES, true) - }, - { - "--local", - runcpp2::OptionInfo(runcpp2::CmdOptions::LOCAL, false) - }, - { - "--show-config-path", - runcpp2::OptionInfo(runcpp2::CmdOptions::SHOW_USER_CONFIG, false) - }, - { - "--create-script-template", - runcpp2::OptionInfo(runcpp2::CmdOptions::SCRIPT_TEMPLATE, true) - }, - { - "--watch", - runcpp2::OptionInfo(runcpp2::CmdOptions::WATCH, false) - }, - { - "--build", - runcpp2::OptionInfo(runcpp2::CmdOptions::BUILD, false) - }, - { - "--output", - runcpp2::OptionInfo(runcpp2::CmdOptions::OUTPUT, true) - }, - { - "--version", - runcpp2::OptionInfo(runcpp2::CmdOptions::VERSION, false) - }, - { - "--log-level", - runcpp2::OptionInfo(runcpp2::CmdOptions::LOG_LEVEL, true) - }, - { - "--config", - runcpp2::OptionInfo(runcpp2::CmdOptions::CONFIG_FILE, true) - }, - { - "--cleanup", - runcpp2::OptionInfo(runcpp2::CmdOptions::CLEANUP, false) - }, - { - "--source-only", - runcpp2::OptionInfo(runcpp2::CmdOptions::BUILD_SOURCE_ONLY, false) - }, - { - "--jobs", - runcpp2::OptionInfo(runcpp2::CmdOptions::THREADS, true) - }, - { - "--tutorial", - runcpp2::OptionInfo(runcpp2::CmdOptions::TUTORIAL, false) - }, - { - "--parameters", - runcpp2::OptionInfo(runcpp2::CmdOptions::PARAMETERS, true) - } - }; - - static_assert((int)runcpp2::CmdOptions::COUNT == 20, "Update this"); - std::unordered_map shortOptionsMap = - { - {"-rb", longOptionsMap.at("--rebuild")}, - {"-ru", longOptionsMap.at("--reset-user-config")}, - {"-e", longOptionsMap.at("--executable")}, - {"-h", longOptionsMap.at("--help")}, - {"-rd", longOptionsMap.at("--reset-dependencies")}, - {"-l", longOptionsMap.at("--local")}, - {"-sc", longOptionsMap.at("--show-config-path")}, - {"-t", longOptionsMap.at("--create-script-template")}, - {"-w", longOptionsMap.at("--watch")}, - {"-b", longOptionsMap.at("--build")}, - {"-o", longOptionsMap.at("--output")}, - {"-v", longOptionsMap.at("--version")}, - {"-c", longOptionsMap.at("--config")}, - {"-cu", longOptionsMap.at("--cleanup")}, - {"-s", longOptionsMap.at("--source-only")}, - {"-j", longOptionsMap.at("--jobs")}, - {"-p", longOptionsMap.at("--parameters")}, - }; - - currentArgIndex = ParseArgs(longOptionsMap, shortOptionsMap, currentOptions, argc, argv); - - if(currentArgIndex == -1) - { - ssLOG_ERROR("Failed to parse arguments. See --help for details"); - return -1; - } - - ++currentArgIndex; - } - - //Help message - if(currentOptions.count(runcpp2::CmdOptions::HELP)) - { - static_assert((int)runcpp2::CmdOptions::COUNT == 20, "Update this"); - ssLOG_BASE("Usage: runcpp2 [options] [input_file]"); - ssLOG_BASE("Options:"); - ssLOG_BASE(" Run/Build:"); - ssLOG_BASE(" -b, --[b]uild Build the script but don't run it"); - ssLOG_BASE(" -o, --[o]utput Output files to the directory specified, must be used with --build"); - ssLOG_BASE(" -w, --[w]atch Watch script changes and output any compiling errors"); - ssLOG_BASE(" -l, --[l]ocal Build in the current working directory under .runcpp2 directory"); - ssLOG_BASE(" -e, --[e]xecutable Runs as executable instead of shared library"); - ssLOG_BASE(" -c, --[c]onfig Use specified config file instead of default"); - ssLOG_BASE(" -t, --create-script-[t]emplate Creates/prepend runcpp2 script info template"); - ssLOG_BASE(" -s, --[s]ource-only (Re)Builds source files only without building dependencies."); - ssLOG_BASE(" The previous built binaries will be used for dependencies."); - ssLOG_BASE(" Requires dependencies to be built already."); - ssLOG_BASE(" -j, --[j]obs Maximum number of threads running. Defaults to 8"); - ssLOG_BASE(" -p, --[p]arameters Parameter values in the order of name and value separated by colons"); - ssLOG_BASE(" Reset/Cleanup:"); - ssLOG_BASE(" -rb, --[r]e[b]uild Deletes compiled source files cache and rebuild"); - ssLOG_BASE(" -ru, --[r]eset-[u]ser-config Replace current user config with the default one"); - ssLOG_BASE(" -rd, --[r]eset-[d]ependencies Reset dependencies (comma-separated names, or \"all\" for all)"); - ssLOG_BASE(" -cu, --[c]lean[u]p Run cleanup commands and remove build directory"); - ssLOG_BASE(" Settings:"); - ssLOG_BASE(" -sc, --[s]how-[c]onfig-path Show where runcpp2 is reading the config from"); - ssLOG_BASE(" -v, --[v]ersion Show the version of runcpp2"); - ssLOG_BASE(" -h, --[h]elp Show this help message"); - ssLOG_BASE(" --log-level Sets the log level (Normal, Info, Debug) for runcpp2"); - ssLOG_BASE(" Others:"); - ssLOG_BASE(" --tutorial Start interactive tutorial"); - return 0; - } - - //Set Log level - if(currentOptions.count(runcpp2::CmdOptions::LOG_LEVEL)) + ssLOG_BASE( PadSpaceRight(" --log-level ", CMD_COLS_BEFORE_DESC) + + "Sets the log level (Normal, Info, Debug) for runcpp2"); +} + +DS::Result ProcessGeneralOptions(int argc, char* argv[], int& argIndex) +{ + if(strcmp(argv[argIndex], "--log-level") == 0) { - std::string level = currentOptions.at(runcpp2::CmdOptions::LOG_LEVEL); - runcpp2::Trim(level); - for(int i = 0; i < level.size(); ++i) - level[i] = std::tolower(level[i]); + if(argIndex == argc - 1) + return DS_ERROR_MSG("Expecting value after --log-level"); + std::string level = argv[++argIndex]; if(level == "info") ssLOG_SET_CURRENT_THREAD_TARGET_LEVEL(ssLOG_LEVEL_INFO); else if(level == "debug") @@ -354,266 +188,600 @@ int main(int argc, char* argv[]) else if(level == "normal") ssLOG_SET_CURRENT_THREAD_TARGET_LEVEL(ssLOG_LEVEL_WARNING); else - { - ssLOG_ERROR("Invalid level: " << level); - return -1; - } + return DS_ERROR_MSG("Invalid level: " + DS_STR(level)); + + return true; } - ssLOG_FUNC_INFO(); - INTERNAL_RUNCPP2_SAFE_START(); - - //Show user config path - std::string configFilePath = runcpp2::GetConfigFilePath().DS_TRY_ACT(OUTPUT_ERROR(); return 1); - if(currentOptions.count(runcpp2::CmdOptions::SHOW_USER_CONFIG)) + return false; +} + +void PrintRunBuildWatchCommonOptions(bool includeSourceOnly) +{ + ssLOG_BASE(PadSpaceRight(" -h, --[h]elp", CMD_COLS_BEFORE_DESC) + "Show this help message"); + ssLOG_BASE( PadSpaceRight(" -l, --[l]ocal", CMD_COLS_BEFORE_DESC) + + "Build in the current working directory under .runcpp2 directory"); + ssLOG_BASE( PadSpaceRight(" -e, --[e]xecutable", CMD_COLS_BEFORE_DESC) + + "Runs as executable instead of shared library"); + if(includeSourceOnly) { - ssLOG_BASE(configFilePath); - return 0; + ssLOG_BASE( PadSpaceRight(" -s, --[s]ource-only", CMD_COLS_BEFORE_DESC) + + "Builds source files only without building dependencies.\n" + + PadSpaceRight("", CMD_COLS_BEFORE_DESC) + + "The previous built binaries will be used for dependencies.\n" + + PadSpaceRight("", CMD_COLS_BEFORE_DESC) + + "Requires dependencies to be built already."); } + ssLOG_BASE( PadSpaceRight( " -p, --[p]arameters ", + CMD_COLS_BEFORE_DESC) + + "Colon separated parameter name value pairs that perform text replacement on the " + "build config"); + + ssLOG_BASE( PadSpaceRight(" -j, --[j]obs ", CMD_COLS_BEFORE_DESC) + + "Maximum number of threads running. Defaults to 8"); + ssLOG_BASE( PadSpaceRight(" -c, --[c]onfig ", CMD_COLS_BEFORE_DESC) + + "Use specified config file instead of default"); +} - //Check if the version flag is present - if(currentOptions.count(runcpp2::CmdOptions::VERSION)) +DS::Result ExtractRunBuildWatchOptions( int argc, + char* argv[], + int& argIndex, + bool includeSourceOnly, + + bool& outLocal, + bool& outExecutable, + bool& outSourceOnly, + std::string& outParams, + std::string& outJobs, + std::string& outConfigPath) +{ + if(strcmp(argv[argIndex], "-l") == 0 || strcmp(argv[argIndex], "--local") == 0) + outLocal = true; + else if(strcmp(argv[argIndex], "-e") == 0 || strcmp(argv[argIndex], "--executable") == 0) + outExecutable = true; + else if(includeSourceOnly && + (strcmp(argv[argIndex], "-s") == 0 || strcmp(argv[argIndex], "--source-only") == 0)) { - ssLOG_BASE("runcpp2 version " << RUNCPP2_VERSION); - return 0; + outSourceOnly = true; } - - //Download tutorial - if(currentOptions.count(runcpp2::CmdOptions::TUTORIAL)) + else if(strcmp(argv[argIndex], "-p") == 0 || strcmp(argv[argIndex], "--parameters") == 0) { - if(!runcpp2::DownloadTutorial(argv[0])) - return -1; - return 0; + if(argIndex == argc - 1) + return DS_ERROR_MSG("Expecting value after -p or --parameters"); + outParams = argv[++argIndex]; + } + else if(strcmp(argv[argIndex], "-j") == 0 || strcmp(argv[argIndex], "--jobs") == 0) + { + if(argIndex == argc - 1) + return DS_ERROR_MSG("Expecting value after -j or --jobs"); + outJobs = argv[++argIndex]; + } + else if(strcmp(argv[argIndex], "-c") == 0 || strcmp(argv[argIndex], "--config") == 0) + { + if(argIndex == argc - 1) + return DS_ERROR_MSG("Expecting value after -c or --config"); + outConfigPath = argv[++argIndex]; } + else + return false; - //Resetting user config - if(currentOptions.count(runcpp2::CmdOptions::RESET_USER_CONFIG)) + return true; +} + +DS::Result HandleRun(int argc, char* argv[]) +{ + //runcpp2 run <...> + if(argc <= 2 || strcmp(argv[2], "--help") == 0 || strcmp(argv[2], "-h") == 0) { - ssLOG_INFO("Resetting user config"); - runcpp2::WriteDefaultConfigs(configFilePath, true, true).DS_TRY_ACT(OUTPUT_ERROR(); return -1); - ssLOG_BASE("User config reset successful"); + ssLOG_BASE("Usage: runcpp2 run [options] [run args]"); + ssLOG_BASE("Options:"); + + PrintRunBuildWatchCommonOptions(true); + PrintGeneralOptions(); + return 0; } - //TODO: Rename this to build template - //Generate script info template - if(currentOptions.count(runcpp2::CmdOptions::SCRIPT_TEMPLATE)) + bool local = false; + bool executable = false; + bool sourceOnly = false; + std::string params = ""; + int argIndex; + std::string jobs = ""; + std::string configPath = ""; + for(argIndex = 2; argIndex < argc; ++argIndex) { - if(!GenerateScriptTemplate(currentOptions.at(runcpp2::CmdOptions::SCRIPT_TEMPLATE))) - return -1; - else + bool parsed = ExtractRunBuildWatchOptions( argc, + argv, + argIndex, + true, + local, + executable, + sourceOnly, + params, + jobs, + configPath).DS_TRY(); + if(!parsed) { - ssLOG_BASE("Script template generated"); - return 0; + parsed = ProcessGeneralOptions(argc, argv, argIndex).DS_TRY(); + if(!parsed) + break; } } + if(argIndex >= argc) + return DS_ERROR_MSG("Input file expected"); + ghc::filesystem::path script = argv[argIndex++]; + + std::vector scriptArgs; + for(; argIndex < argc; ++argIndex) + { + ssLOG_DEBUG("argv[" << argIndex << "]: " << argv[argIndex]); + scriptArgs.emplace_back(argv[argIndex]); + } + std::vector profiles; std::string preferredProfile; - - std::string configPath; - if(currentOptions.count(runcpp2::CmdOptions::CONFIG_FILE)) - configPath = currentOptions.at(runcpp2::CmdOptions::CONFIG_FILE); - - runcpp2::ReadUserConfig(profiles, - preferredProfile, - configPath).DS_TRY_ACT(OUTPUT_ERROR(); return -1); + runcpp2::ReadUserConfig(profiles, preferredProfile, configPath).DS_TRY(); ssLOG_DEBUG("\nprofiles:"); for(int i = 0; i < profiles.size(); ++i) ssLOG_DEBUG("\n" << profiles.at(i).ToString(" ")); - std::vector scriptArgs; - if(currentArgIndex >= argc) + runcpp2::Data::ScriptInfo parsedScriptInfo; + ghc::filesystem::file_time_type finalSourceWriteTime; + ghc::filesystem::file_time_type finalIncludeWriteTime; + runcpp2::RunParams runParams + { + { + script, + profiles, + params, + executable, + local, + preferredProfile + }, + false, + false, + sourceOnly, + false, + scriptArgs, + jobs, + nullptr, + "" + }; + int result = runcpp2::Run( runParams, + //Outputs + parsedScriptInfo, + finalSourceWriteTime, + finalIncludeWriteTime).DS_TRY(); + return result; +} + +DS::Result HandleBuild(int argc, char* argv[]) +{ + //runcpp2 build <...> + if(argc <= 2 || strcmp(argv[2], "--help") == 0 || strcmp(argv[2], "-h") == 0) { - ssLOG_ERROR("An input file is required. See --help for details"); - return 1; + ssLOG_BASE("Usage: runcpp2 build [options] "); + ssLOG_BASE("Options:"); + PrintRunBuildWatchCommonOptions(true); + ssLOG_BASE( PadSpaceRight(" -rb, --[r]e[b]uild", CMD_COLS_BEFORE_DESC) + + "Deletes compiled source files cache and rebuild"); + ssLOG_BASE( PadSpaceRight(" -o, --[o]utput-dir", CMD_COLS_BEFORE_DESC) + + "Specify a directory to output to."); + PrintGeneralOptions(); + return {}; } - std::string script = argv[currentArgIndex++]; - - if(currentOptions.count(runcpp2::CmdOptions::WATCH) && currentArgIndex < argc) - ssLOG_WARNING("-w/--watch doesn't run the script and doesn't except any run arguments"); - else + bool local = false; + bool executable = false; + bool sourceOnly = false; + std::string params = ""; + int argIndex; + std::string jobs = ""; + std::string configPath = ""; + bool rebuild = false; + ghc::filesystem::path outputDir = ""; + for(argIndex = 2; argIndex < argc; ++argIndex) { - for(; currentArgIndex < argc; ++currentArgIndex) + bool parsed = ExtractRunBuildWatchOptions( argc, + argv, + argIndex, + true, + local, + executable, + sourceOnly, + params, + jobs, + configPath).DS_TRY(); + if(!parsed) { - ssLOG_DEBUG("argv[" << currentArgIndex << "]: " << argv[currentArgIndex]); - scriptArgs.push_back(std::string(argv[currentArgIndex])); + if(strcmp(argv[argIndex], "-rb") == 0 || strcmp(argv[argIndex], "--rebuild") == 0) + rebuild = true; + else if(strcmp(argv[argIndex], "-o") == 0 || strcmp(argv[argIndex], "--output-dir") == 0) + { + if(argIndex == argc - 1) + return DS_ERROR_MSG("Expecting value after -o or --output-dir"); + outputDir = argv[++argIndex]; + } + else + { + parsed = ProcessGeneralOptions(argc, argv, argIndex).DS_TRY(); + if(!parsed) + break; + } } } - if( currentOptions.count(runcpp2::CmdOptions::BUILD) > 0 && - currentOptions.count(runcpp2::CmdOptions::WATCH) > 0) + if(argIndex >= argc) + return DS_ERROR_MSG("Input file expected"); + ghc::filesystem::path script = argv[argIndex++]; + + std::vector profiles; + std::string preferredProfile; + runcpp2::ReadUserConfig(profiles, preferredProfile, configPath).DS_TRY(); + + ssLOG_DEBUG("\nprofiles:"); + for(int i = 0; i < profiles.size(); ++i) + ssLOG_DEBUG("\n" << profiles.at(i).ToString(" ")); + + runcpp2::Data::ScriptInfo parsedScriptInfo; + ghc::filesystem::file_time_type finalSourceWriteTime; + ghc::filesystem::file_time_type finalIncludeWriteTime; + runcpp2::RunParams runParams + { + { + script, + profiles, + params, + executable, + local, + preferredProfile + }, + rebuild, + false, + sourceOnly, + true, + {}, + jobs, + nullptr, + outputDir + }; + runcpp2::Run( runParams, + //Outputs + parsedScriptInfo, + finalSourceWriteTime, + finalIncludeWriteTime).DS_TRY(); + return {}; +} + +DS::Result HandleWatch(int argc, char* argv[]) +{ + //runcpp2 watch + if(argc <= 2 || strcmp(argv[2], "--help") == 0 || strcmp(argv[2], "-h") == 0) { - ssLOG_ERROR("--build option is not compatible with --watch option"); - return -1; + ssLOG_BASE("Usage: runcpp2 watch [options] "); + ssLOG_BASE("Options:"); + PrintRunBuildWatchCommonOptions(true); + PrintGeneralOptions(); + return {}; } - if( currentOptions.count(runcpp2::CmdOptions::OUTPUT) > 0 && - currentOptions.count(runcpp2::CmdOptions::BUILD) == 0) + bool local = false; + bool executable = false; + bool sourceOnly = false; + std::string params = ""; + int argIndex; + std::string jobs = ""; + std::string configPath = ""; + for(argIndex = 2; argIndex < argc; ++argIndex) { - ssLOG_ERROR("--build option must be supplied when specifying output directory"); - return -1; + bool parsed = ExtractRunBuildWatchOptions( argc, + argv, + argIndex, + true, + local, + executable, + sourceOnly, + params, + jobs, + configPath).DS_TRY(); + parsed = ProcessGeneralOptions(argc, argv, argIndex).DS_TRY(); + if(!parsed) + break; } + if(argIndex >= argc) + return DS_ERROR_MSG("Input file expected"); + ghc::filesystem::path script = argv[argIndex++]; + + std::vector profiles; + std::string preferredProfile; + runcpp2::ReadUserConfig(profiles, preferredProfile, configPath).DS_TRY(); + + ssLOG_DEBUG("\nprofiles:"); + for(int i = 0; i < profiles.size(); ++i) + ssLOG_DEBUG("\n" << profiles.at(i).ToString(" ")); + + runcpp2::Data::ScriptInfo* lastParsedScriptInfo = nullptr; runcpp2::Data::ScriptInfo parsedScriptInfo; + ghc::filesystem::file_time_type lastFinalSourceWriteTime; + ghc::filesystem::file_time_type lastFinalIncludeWriteTime; + bool needsRunning = true; //First run always needs running - if(currentOptions.count(runcpp2::CmdOptions::WATCH)) + runcpp2::CoreParams coreParams = { script, profiles, params, executable, local, preferredProfile }; + while(true) { - std::error_code e; - if(!ghc::filesystem::exists(script, e)) + //Check if sources need update + bool needsUpdate = false; + if(!needsRunning) //Skip check on first run { - ssLOG_ERROR("Script path " << script << " doesn't exist"); - return -1; + needsRunning = runcpp2::CheckSourcesNeedUpdate( coreParams, + jobs, + lastParsedScriptInfo, + lastFinalSourceWriteTime, + lastFinalIncludeWriteTime).DS_TRY(); + if(needsUpdate) + { + ssLOG_INFO("Source files have changed"); + needsRunning = true; + } } - runcpp2::Data::ScriptInfo* lastParsedScriptInfo = nullptr; - ghc::filesystem::file_time_type lastFinalSourceWriteTime; - ghc::filesystem::file_time_type lastFinalIncludeWriteTime; - bool needsRunning = true; //First run always needs running - - while(true) + if(needsRunning) { - //Check if sources need update - bool needsUpdate = false; - if(!needsRunning) //Skip check on first run + //Clear the screen + if(ssLOG_GET_CURRENT_THREAD_TARGET_LEVEL() <= ssLOG_LEVEL_WARNING) { - if(runcpp2::CheckSourcesNeedUpdate( script, - profiles, - preferredProfile, - lastParsedScriptInfo ? *lastParsedScriptInfo : - parsedScriptInfo, - currentOptions, - lastFinalSourceWriteTime, - lastFinalIncludeWriteTime, - needsUpdate) != runcpp2::PipelineResult::SUCCESS) - { - ssLOG_ERROR("Failed to check if sources need update"); - return -1; - } - - if(needsUpdate) - { - ssLOG_INFO("Source files have changed"); - needsRunning = true; - } + #if defined(_WIN32) + system("cls"); + #else + //https://stackoverflow.com/a/53925508 + std::cout << "\033c"; + #endif } - - if(needsRunning) - { - //Clear the screen - if(ssLOG_GET_CURRENT_THREAD_TARGET_LEVEL() <= ssLOG_LEVEL_WARNING) - { - #if defined(_WIN32) - system("cls"); - #else - //https://stackoverflow.com/a/53925508 - std::cout << "\033c"; - #endif - } - - ssLOG_LINE("Changes detected, running..."); - - int result = 0; - runcpp2::PipelineResult pipelineResult = - runcpp2::StartPipeline( script, - profiles, - preferredProfile, - currentOptions, - scriptArgs, - lastParsedScriptInfo, - "", - parsedScriptInfo, - lastFinalSourceWriteTime, - lastFinalIncludeWriteTime, - result); - static_assert(static_cast(runcpp2::PipelineResult::COUNT) == 13, "Update this"); - switch(pipelineResult) - { - case runcpp2::PipelineResult::INVALID_SCRIPT_PATH: - case runcpp2::PipelineResult::INVALID_CONFIG_PATH: - case runcpp2::PipelineResult::EMPTY_PROFILES: - ssLOG_ERROR("Watch failed"); - return -1; - - case runcpp2::PipelineResult::UNEXPECTED_FAILURE: - case runcpp2::PipelineResult::INVALID_BUILD_DIR: - case runcpp2::PipelineResult::INVALID_SCRIPT_INFO: - case runcpp2::PipelineResult::NO_AVAILABLE_PROFILE: - case runcpp2::PipelineResult::DEPENDENCIES_FAILED: - case runcpp2::PipelineResult::COMPILE_LINK_FAILED: - case runcpp2::PipelineResult::INVALID_PROFILE: - case runcpp2::PipelineResult::RUN_SCRIPT_FAILED: - case runcpp2::PipelineResult::INVALID_OPTION: - ssLOG_LINE("Watching..."); - break; - case runcpp2::PipelineResult::SUCCESS: - ssLOG_LINE("No error. Watching..."); - break; - } - - lastParsedScriptInfo = &parsedScriptInfo; - needsRunning = false; - } + ssLOG_LINE("Changes detected, running..."); + runcpp2::RunParams runParams + { + coreParams, + false, + true, + sourceOnly, + true, + {}, + jobs, + lastParsedScriptInfo, + "" + }; + runcpp2::Run( runParams, + //Outputs + parsedScriptInfo, + lastFinalSourceWriteTime, + lastFinalIncludeWriteTime).DS_TRY(); + + lastParsedScriptInfo = &parsedScriptInfo; + needsRunning = false; + } //if(needsRunning) + + std::this_thread::sleep_for(std::chrono::seconds(5)); + } + + return {}; +} - std::this_thread::sleep_for(std::chrono::seconds(5)); - } //while(true) - } //if(currentOptions.count(runcpp2::CmdOptions::WATCH)) +DS::Result HandleTemplate(int argc, char* argv[]) +{ + //runcpp2 template + if(argc <= 2 || strcmp(argv[2], "--help") == 0 || strcmp(argv[2], "-h") == 0) + { + ssLOG_BASE("Usage: runcpp2 template [options] "); + ssLOG_BASE("Options:"); + PrintGeneralOptions(); + return {}; + } + + int argIndex; + for(argIndex = 2; argIndex < argc; ++argIndex) + { + bool parsed = ProcessGeneralOptions(argc, argv, argIndex).DS_TRY(); + if(!parsed) + break; + } - int result = 0; + if(argIndex >= argc) + return DS_ERROR_MSG("Output file expected"); + ghc::filesystem::path templatePath = argv[argIndex++]; - std::string outputDir; - if( currentOptions.count(runcpp2::CmdOptions::BUILD) > 0 && - currentOptions.count(runcpp2::CmdOptions::OUTPUT) > 0) + GenerateScriptTemplate(templatePath).DS_TRY(); + ssLOG_BASE("Script template generated"); + return {}; +} + +DS::Result HandleRegenUserConfig(int argc, char* argv[]) +{ + //runcpp2 reset-user-config + if(argc <= 2 || strcmp(argv[2], "--help") == 0 || strcmp(argv[2], "-h") == 0) { - auto buildOutputDir = ghc::filesystem::path(currentOptions.at(runcpp2::CmdOptions::OUTPUT)); - if(buildOutputDir.is_absolute()) - outputDir = buildOutputDir.string(); - else - outputDir = (ghc::filesystem::current_path() / buildOutputDir).string(); + ssLOG_BASE("Usage: runcpp2 regen-user-config [options]"); + ssLOG_BASE("Options:"); + ssLOG_BASE( PadSpaceRight(" -c, --[c]onfig-directory ", CMD_COLS_BEFORE_DESC) + + "Use specified config directory instead of default"); + PrintGeneralOptions(); + return {}; } - ghc::filesystem::file_time_type finalSourceWriteTime; - ghc::filesystem::file_time_type finalIncludeWriteTime; - if(runcpp2::StartPipeline( script, - profiles, - preferredProfile, - currentOptions, - scriptArgs, - nullptr, - outputDir, - parsedScriptInfo, - finalSourceWriteTime, - finalIncludeWriteTime, - result) != runcpp2::PipelineResult::SUCCESS) + int argIndex; + for(argIndex = 2; argIndex < argc; ++argIndex) + { + bool parsed = ProcessGeneralOptions(argc, argv, argIndex).DS_TRY(); + if(!parsed) + break; + } + + ghc::filesystem::path configFilePath = runcpp2::GetConfigFilePath().DS_TRY(); + runcpp2::WriteDefaultConfigs(configFilePath, true, true).DS_TRY(); + ssLOG_BASE("User config regenerated"); + return {}; +} + +DS::Result HandleReset(int argc, char* argv[]) +{ + //runcpp2 reset [options] + if(argc <= 2 || strcmp(argv[2], "--help") == 0 || strcmp(argv[2], "-h") == 0) { - return -1; + ssLOG_BASE("Usage: runcpp2 reset [options] "); + ssLOG_BASE("Options:"); + PrintRunBuildWatchCommonOptions(false); + ssLOG_BASE( PadSpaceRight(" -d, --[d]ependencies ", + CMD_COLS_BEFORE_DESC) + + "Reset dependencies only (comma-separated names, or \"all\" for all dependencies)"); + PrintGeneralOptions(); + return {}; } - std::vector actions; - if(currentOptions.count(runcpp2::CmdOptions::RESET_CACHE) > 0) - actions.push_back("Rebuild"); - if(currentOptions.count(runcpp2::CmdOptions::CLEANUP) > 0) - actions.push_back("Cleanup"); - if(currentOptions.count(runcpp2::CmdOptions::RESET_DEPENDENCIES) > 0) - actions.push_back("Dependencies Reset"); - if(currentOptions.count(runcpp2::CmdOptions::BUILD) > 0) - actions.push_back("Build"); + bool local = false; + bool executable = false; + bool sourceOnly = false; + std::string params = ""; + int argIndex; + std::string jobs = ""; + std::string configPath = ""; + std::string deps = "all"; + bool depsOnly = false; + for(argIndex = 2; argIndex < argc; ++argIndex) + { + bool parsed = ExtractRunBuildWatchOptions( argc, + argv, + argIndex, + false, + local, + executable, + sourceOnly, + params, + jobs, + configPath).DS_TRY(); + if(!parsed) + { + if(strcmp(argv[argIndex], "-d") == 0 || strcmp(argv[argIndex], "--dependencies") == 0) + { + if(argIndex == argc - 1) + return DS_ERROR_MSG("Expecting value after -d or --dependencies"); + deps = argv[++argIndex]; + depsOnly = true; + } + else + { + parsed = ProcessGeneralOptions(argc, argv, argIndex).DS_TRY(); + if(!parsed) + break; + } + } + } - std::string action; - if(!actions.empty()) + if(argIndex >= argc) + return DS_ERROR_MSG("Input file expected"); + ghc::filesystem::path script = argv[argIndex++]; + + std::vector profiles; + std::string preferredProfile; + runcpp2::ReadUserConfig(profiles, preferredProfile, configPath).DS_TRY(); + + ssLOG_DEBUG("\nprofiles:"); + for(int i = 0; i < profiles.size(); ++i) + ssLOG_DEBUG("\n" << profiles.at(i).ToString(" ")); + + runcpp2::CoreParams coreParams = { script, profiles, params, executable, local, preferredProfile }; + runcpp2::RunResetDependencies(coreParams, deps).DS_TRY(); + if(!depsOnly) { - action = actions.front(); - for(int i = 1; i < actions.size(); ++i) - action += ", " + actions[i]; - - ssLOG_BASE(action << " success"); + runcpp2::RunCleanup(coreParams).DS_TRY(); + } + + return {}; +} + +DS::Result Main(int argc, char* argv[]) +{ + INTERNAL_RUNCPP2_SAFE_START() + + ssLOG_SET_CURRENT_THREAD_TARGET_LEVEL(ssLOG_LEVEL_WARNING); + + //Help + if( argc == 1 || + strcmp(argv[1], "--help") == 0 || + strcmp(argv[1], "-h") == 0 || + strcmp(argv[1], "help") == 0) + { + ssLOG_BASE("Usage: runcpp2 [options] [input file] [run args]"); + ssLOG_BASE("Actions:"); + ssLOG_BASE(PadSpaceRight(" run", CMD_COLS_BEFORE_DESC) + "Runs the input file"); + ssLOG_BASE(PadSpaceRight(" build", CMD_COLS_BEFORE_DESC) + "Build the input file"); + ssLOG_BASE( PadSpaceRight(" watch", CMD_COLS_BEFORE_DESC) + + "Watch for any changes in source files and output any compiling errors"); + ssLOG_BASE( PadSpaceRight(" template", CMD_COLS_BEFORE_DESC) + + "Creates/prepend runcpp2 build info template to the input file"); + ssLOG_BASE( PadSpaceRight(" regen-user-config", CMD_COLS_BEFORE_DESC) + + "Replace current user config with the default one"); + ssLOG_BASE( PadSpaceRight(" reset", CMD_COLS_BEFORE_DESC) + + "Perform cleanup on both/either the source and/or the dependencies"); + ssLOG_BASE( PadSpaceRight(" show-config-path", CMD_COLS_BEFORE_DESC) + + "Show where runcpp2 is reading the config from"); + ssLOG_BASE(PadSpaceRight(" version", CMD_COLS_BEFORE_DESC) + "Show the version of runcpp2"); + ssLOG_BASE(PadSpaceRight(" tutorial", CMD_COLS_BEFORE_DESC) + "Start interactive tutorial"); + ssLOG_BASE(PadSpaceRight(" help", CMD_COLS_BEFORE_DESC) + "Show this help message"); + return 0; } - return result; - INTERNAL_RUNCPP2_SAFE_CATCH_RETURN(-1); + if(strcmp(argv[1], "run") == 0) + { + int result = HandleRun(argc, argv).DS_TRY(); + return result; + } + else if(strcmp(argv[1], "build") == 0) + { + HandleBuild(argc, argv).DS_TRY(); + } + else if(strcmp(argv[1], "watch") == 0) + { + HandleWatch(argc, argv).DS_TRY(); + } + else if(strcmp(argv[1], "template") == 0) + { + HandleTemplate(argc, argv).DS_TRY(); + } + else if(strcmp(argv[1], "regen-user-config") == 0) + { + HandleRegenUserConfig(argc, argv).DS_TRY(); + } + else if(strcmp(argv[1], "reset") == 0) + { + HandleReset(argc, argv).DS_TRY(); + } + else if(strcmp(argv[1], "show-config-path") == 0) + { + ghc::filesystem::path configFilePath = runcpp2::GetConfigFilePath().DS_TRY(); + ssLOG_BASE(configFilePath); + } + else if(strcmp(argv[1], "version") == 0) + ssLOG_BASE("runcpp2 version " << RUNCPP2_VERSION); + else if(strcmp(argv[1], "tutorial") == 0) + { + runcpp2::DownloadTutorial(argv[0]).DS_TRY(); + } + else + return DS_ERROR_MSG("Invalid action: " + DS_STR(argv[1])); + + return 0; + + INTERNAL_RUNCPP2_SAFE_CATCH_RETURN(-1) +} + +int main(int argc, char* argv[]) +{ + int result = Main(argc, argv).DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); return 1); + return result; } #include "runcpp2/DefaultYAMLs.c" diff --git a/Src/runcpp2/runcpp2.hpp b/Src/runcpp2/runcpp2.hpp index e3aa6fe..bbda511 100644 --- a/Src/runcpp2/runcpp2.hpp +++ b/Src/runcpp2/runcpp2.hpp @@ -2,10 +2,8 @@ #define RUNCPP2_RUNCPP2_HPP #include "runcpp2/Data/BuildTypeHelper.hpp" -#include "runcpp2/Data/CmdOptions.hpp" #include "runcpp2/Data/Profile.hpp" #include "runcpp2/Data/ScriptInfo.hpp" -#include "runcpp2/Data/PipelineResult.hpp" #include "runcpp2/Data/FileProperties.hpp" #include "runcpp2/Data/FilesTypesInfo.hpp" #include "runcpp2/Data/ParseCommon.hpp" @@ -272,20 +270,6 @@ namespace namespace runcpp2 { - struct OptionInfo - { - CmdOptions Option; - bool ValueExists; - std::string Value; - - inline OptionInfo( CmdOptions option, - bool valueExists = false, - const std::string& value = "") : Option(option), - ValueExists(valueExists), - Value(value) - {} - }; - inline void GetDefaultScriptInfo(std::string& scriptInfo) { scriptInfo = std::string( reinterpret_cast(DefaultScriptInfo), @@ -304,352 +288,478 @@ namespace runcpp2 else ssLOG_ERROR("Invalid log level: " << logLevel); } - - //NOTE: This should be run after running StartPipeline first - inline PipelineResult - CheckSourcesNeedUpdate( const std::string& scriptPath, - const std::vector& profiles, - const std::string& configPreferredProfile, - const Data::ScriptInfo& scriptInfo, - const std::unordered_map< CmdOptions, - std::string>& currentOptions, - const ghc::filesystem::file_time_type& prevFinalSourceWriteTime, - const ghc::filesystem::file_time_type& prevFinalIncludeWriteTime, - bool& outNeedsUpdate) + + inline void CreateParameterValues( const std::string rawParams, + std::unordered_map& outParameters) { - INTERNAL_RUNCPP2_SAFE_START(); - ssLOG_FUNC_INFO(); + std::vector paramNameVals; + SplitString(rawParams, ":", paramNameVals); + if(paramNameVals.size() % 2 != 0) + { + ssLOG_ERROR("Failed to parse parameters. Defaults to no parameters"); + return; + } + + for(int i = 0; i < paramNameVals.size(); i += 2) + outParameters[paramNameVals[i]] = paramNameVals[i + 1]; + } - //Validate inputs and get paths - ghc::filesystem::path absoluteScriptPath; - ghc::filesystem::path scriptDirectory; - std::string scriptName; + inline DS::Result GetScriptInfoData( const ghc::filesystem::path& scriptPath, + const std::string& rawParameters, + bool executable, + + Data::ScriptInfo& outScriptInfo, + ghc::filesystem::path& outAbsoluteScriptPath, + ghc::filesystem::path& outScriptDirectory, + std::string& outScriptName, + std::unordered_map< std::string, + std::string>& outParameterValues) + { + ssLOG_FUNC_INFO(); - ValidateInputs(scriptPath, profiles, absoluteScriptPath, scriptDirectory, scriptName) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return (PipelineResult)DS_TMP_ERROR.ErrorCode); + //Validate inputs and get paths + { + //Check if input file exists + std::error_code _; + if(!ghc::filesystem::exists(scriptPath, _)) + return DS_ERROR_MSG("File does not exist: " + scriptPath.string()); + + if(ghc::filesystem::is_directory(scriptPath, _)) + return DS_ERROR_MSG( "The input file must not be a directory: " + scriptPath.string()); + + outAbsoluteScriptPath = + ghc::filesystem::absolute(ghc::filesystem::canonical(scriptPath, _)); + outScriptDirectory = outAbsoluteScriptPath.parent_path(); + outScriptName = outAbsoluteScriptPath.stem().string(); + + ssLOG_DEBUG("scriptPath: " << scriptPath); + ssLOG_DEBUG("absoluteScriptPath: " << outAbsoluteScriptPath.string()); + ssLOG_DEBUG("scriptDirectory: " << outScriptDirectory.string()); + ssLOG_DEBUG("scriptName: " << outScriptName); + ssLOG_DEBUG("is_directory: " << ghc::filesystem::is_directory(outScriptDirectory)); + } - //First check if script info file has changed - std::error_code e; - ghc::filesystem::path dedicatedYamlLoc = - scriptDirectory / ghc::filesystem::path(scriptName + ".yaml"); + //Create parameters + std::unordered_map parameterValues; + CreateParameterValues(rawParameters, parameterValues); + + //Parse script info + ParseAndValidateScriptInfo( outAbsoluteScriptPath, + outScriptDirectory, + outScriptName, + executable, + parameterValues, + outScriptInfo).DS_TRY(); - ghc::filesystem::file_time_type currentWriteTime; - if(ghc::filesystem::exists(dedicatedYamlLoc, e)) - currentWriteTime = ghc::filesystem::last_write_time(dedicatedYamlLoc, e); - else - currentWriteTime = ghc::filesystem::last_write_time(absoluteScriptPath, e); + return {}; + } - if(e) + inline DS::Result GetDefaultBuildDir() + { + ghc::filesystem::path configDir = GetConfigFilePath().DS_TRY(); + + //Parse and get the config directory { - ssLOG_ERROR("Failed to get write time for script info"); - return PipelineResult::UNEXPECTED_FAILURE; + std::error_code e; + if(ghc::filesystem::is_directory(configDir, e)) + return DS_ERROR_MSG("Unexpected path for config file: " + configDir.string()); + + configDir = configDir.parent_path(); + if(!ghc::filesystem::is_directory(configDir, e)) + return DS_ERROR_MSG("Unexpected path for config directory: " + configDir.string()); } + + return configDir; + } - //If script info file is newer than last check, we need to update - if(currentWriteTime > scriptInfo.LastWriteTime) + struct CoreParams + { + const ghc::filesystem::path& scriptPath; + const std::vector& profiles; + const std::string rawParameters; + bool runAsExecutable; + bool buildLocally; + const std::string& configPreferredProfile; + }; + + inline DS::Result RunCleanup(CoreParams params) + { + ghc::filesystem::path absoluteScriptPath; + ghc::filesystem::path scriptDirectory; + std::string scriptName; + std::unordered_map parameters; + Data::ScriptInfo scriptInfo; + GetScriptInfoData( params.scriptPath, + params.rawParameters, + params.runAsExecutable, + + //Output: + scriptInfo, + absoluteScriptPath, + scriptDirectory, + scriptName, + parameters).DS_TRY(); + + if(params.profiles.empty()) + return DS_ERROR_MSG("No compiler profiles found"); + + int profileIndex = GetPreferredProfileIndex( absoluteScriptPath, + scriptInfo, + params.profiles, + params.configPreferredProfile).DS_TRY(); { - outNeedsUpdate = true; - return PipelineResult::SUCCESS; + ghc::filesystem::path buildDir = GetDefaultBuildDir().DS_TRY(); + BuildsManager buildsManager("/tmp"); + IncludeManager includeManager; + InitializeBuildDirectory( buildDir, + absoluteScriptPath, + params.buildLocally, + buildsManager, + buildDir, + includeManager).DS_TRY(); + HandleCleanup( scriptInfo, + params.profiles.at(profileIndex), + scriptDirectory, + buildDir, + absoluteScriptPath, + buildsManager).DS_TRY(); } + + return {}; + } + + inline DS::Result RunResetDependencies( CoreParams params, + const std::string& targetDepToReset) + { + ghc::filesystem::path absoluteScriptPath; + ghc::filesystem::path scriptDirectory; + std::string scriptName; + std::unordered_map parameters; + Data::ScriptInfo scriptInfo; + GetScriptInfoData( params.scriptPath, + params.rawParameters, + false, //NOTE: Don't care + //Output: + scriptInfo, + absoluteScriptPath, + scriptDirectory, + scriptName, + parameters).DS_TRY(); + + if(params.profiles.empty()) + return DS_ERROR_MSG("No compiler profiles found"); + + int profileIndex = GetPreferredProfileIndex( absoluteScriptPath, + scriptInfo, + params.profiles, + params.configPreferredProfile).DS_TRY(); + + + //Parsing the script, setting up dependencies, compiling and linking + std::vector filesToCopyPaths; + ghc::filesystem::path buildDir = GetDefaultBuildDir().DS_TRY(); + + BuildsManager buildsManager("/tmp"); + IncludeManager includeManager; + InitializeBuildDirectory( buildDir, + absoluteScriptPath, + params.buildLocally, + buildsManager, + buildDir, + includeManager).DS_TRY(); + + //Resolve imports + ResolveScriptImports(scriptInfo, scriptDirectory, buildDir).DS_TRY(); + + //Process Dependencies + ResetDependencies( scriptInfo, + params.profiles.at(profileIndex), + scriptDirectory, + buildDir, + targetDepToReset).DS_TRY(); + return {}; + } - //Initialize BuildsManager and IncludeManager - ghc::filesystem::path configDir = - GetConfigFilePath().DS_TRY_ACT( ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return PipelineResult::INVALID_CONFIG_PATH); + inline DS::Result + CheckSourcesNeedUpdate( CoreParams params, + const std::string rawMaxThreads, + const Data::ScriptInfo* lastScriptInfo, + const ghc::filesystem::file_time_type& prevFinalSourceWriteTime, + const ghc::filesystem::file_time_type& prevFinalIncludeWriteTime) + { + ghc::filesystem::path absoluteScriptPath; + ghc::filesystem::path scriptDirectory; + std::string scriptName; + std::unordered_map parameters; + Data::ScriptInfo scriptInfo; + + //TODO: Reduce number of parameters here + GetScriptInfoData( params.scriptPath, + params.rawParameters, + params.runAsExecutable, + + //Output: + scriptInfo, + absoluteScriptPath, + scriptDirectory, + scriptName, + parameters).DS_TRY(); - configDir = configDir.parent_path(); - if(!ghc::filesystem::is_directory(configDir, e)) + //First check if script info file has changed { - ssLOG_FATAL("Unexpected path for config directory: " << configDir.string()); - return PipelineResult::INVALID_CONFIG_PATH; + std::error_code e; + ghc::filesystem::path dedicatedYamlLoc = + scriptDirectory / ghc::filesystem::path(scriptName + ".yaml"); + + ghc::filesystem::file_time_type currentWriteTime; + if(ghc::filesystem::exists(dedicatedYamlLoc, e)) + currentWriteTime = ghc::filesystem::last_write_time(dedicatedYamlLoc, e); + else + currentWriteTime = ghc::filesystem::last_write_time(absoluteScriptPath, e); + + if(e) + return DS_ERROR_MSG("Failed to get write time for script info" + e.message()); + + //If script info file is newer than last check, we need to update + if(currentWriteTime > scriptInfo.LastWriteTime) + return true; } - ghc::filesystem::path buildDir; + if(params.profiles.empty()) + return DS_ERROR_MSG("No compiler profiles found"); + + int profileIndex = GetPreferredProfileIndex( absoluteScriptPath, + scriptInfo, + params.profiles, + params.configPreferredProfile).DS_TRY(); + + //Parsing the script, setting up dependencies, compiling and linking + std::vector filesToCopyPaths; + ghc::filesystem::path buildDir = GetDefaultBuildDir().DS_TRY(); BuildsManager buildsManager("/tmp"); IncludeManager includeManager; - - const bool useLocalBuildDir = currentOptions.count(CmdOptions::LOCAL) > 0; - InitializeBuildDirectory( configDir, + InitializeBuildDirectory( buildDir, absoluteScriptPath, - useLocalBuildDir, + params.buildLocally, buildsManager, buildDir, - includeManager) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return (PipelineResult)DS_TMP_ERROR.ErrorCode); - - //Get profile and gather source files - const int profileIndex = GetPreferredProfileIndex( scriptPath, - scriptInfo, - profiles, - configPreferredProfile) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return PipelineResult::NO_AVAILABLE_PROFILE); + includeManager).DS_TRY(); + + const int maxThreads = rawMaxThreads.empty() ? 8 : strtol( rawMaxThreads.c_str(), + nullptr, + 10); + if(maxThreads <= 0) + return DS_ERROR_MSG("Invalid number of threads passed in"); + + //Resolve imports + ResolveScriptImports(scriptInfo, scriptDirectory, buildDir).DS_TRY(); + + //Check if script info has changed if provided and run setup if needed + bool recompileNeeded = false; + bool relinkNeeded = false; + std::vector changedDependencies; + CheckScriptInfoChanges( buildDir, + scriptInfo, + params.profiles.at(profileIndex), + scriptDirectory, + lastScriptInfo, + parameters, + recompileNeeded, + relinkNeeded, + changedDependencies).DS_TRY(); + if(relinkNeeded) + return true; - const Data::Profile& currentProfile = profiles.at(profileIndex); + std::vector gatheredBinariesPaths; + //Process Dependencies + std::vector availableDependencies; + ProcessDependencies(scriptInfo, + params.profiles.at(profileIndex), + scriptDirectory, + buildDir, + changedDependencies, + maxThreads, + false, + availableDependencies, + gatheredBinariesPaths).DS_TRY(); + + //Get all the files we are trying to compile std::vector sourceFiles; - GatherSourceFiles(absoluteScriptPath, scriptInfo, currentProfile, sourceFiles) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return PipelineResult::UNEXPECTED_FAILURE); - - for(int i = 0; i < sourceFiles.size(); ++i) - ssLOG_DEBUG("sourceFiles.at(i).string(): " << sourceFiles.at(i).string()); - + GatherSourceFiles( absoluteScriptPath, + scriptInfo, + params.profiles.at(profileIndex), + sourceFiles).DS_TRY(); + + //Get all include paths + std::vector includePaths; + GatherIncludePaths( scriptDirectory, + scriptInfo, + params.profiles.at(profileIndex), + availableDependencies, + includePaths).DS_TRY(); + + //Check if we have already compiled before. std::vector sourceHasCache; std::vector cachedObjectsFiles; ghc::filesystem::file_time_type finalObjectWriteTime; ghc::filesystem::file_time_type finalSourceWriteTime; ghc::filesystem::file_time_type finalIncludeWriteTime; - - HasCompiledCache( absoluteScriptPath.parent_path(), - sourceFiles, - buildDir, - currentProfile, + HasCompiledCache( scriptDirectory, + sourceFiles, + buildDir, + params.profiles.at(profileIndex), includeManager, sourceHasCache, cachedObjectsFiles, finalObjectWriteTime, finalSourceWriteTime, - finalIncludeWriteTime) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - //TODO: Maybe add a pipeline result for this? - return PipelineResult::UNEXPECTED_FAILURE); + finalIncludeWriteTime).DS_TRY(); if( finalSourceWriteTime > prevFinalSourceWriteTime || finalIncludeWriteTime > prevFinalIncludeWriteTime) { - outNeedsUpdate = true; + return true; } else - outNeedsUpdate = false; - - return PipelineResult::SUCCESS; - - INTERNAL_RUNCPP2_SAFE_CATCH_RETURN(PipelineResult::UNEXPECTED_FAILURE); + return false; } - inline void CreateParameterValues( const std::unordered_map< CmdOptions, - std::string>& currentOptions, - std::unordered_map& outParameters) + struct RunParams { - if(currentOptions.count(CmdOptions::PARAMETERS) == 0) - return; - - const std::string& rawParams = currentOptions.at(CmdOptions::PARAMETERS); - - std::vector paramNameVals; - SplitString(rawParams, ":", paramNameVals); - if(paramNameVals.size() % 2 != 0) - { - ssLOG_ERROR("Failed to parse parameters. Defaults to no parameters"); - return; - } - - for(int i = 0; i < paramNameVals.size(); i += 2) - outParameters[paramNameVals[i]] = paramNameVals[i + 1]; - } + CoreParams Core; + bool rebuild; + bool compileOnly; + bool buildSourceOnly; + bool buildOnly; + const std::vector& runArgs; + const std::string rawMaxThreads; + const Data::ScriptInfo* lastScriptInfo; + const ghc::filesystem::path& buildOutputDir; + }; - inline PipelineResult StartPipeline(const std::string& scriptPath, - const std::vector& profiles, - const std::string& configPreferredProfile, - const std::unordered_map< CmdOptions, - std::string>& currentOptions, - const std::vector& runArgs, - const Data::ScriptInfo* lastScriptInfo, - const std::string& buildOutputDir, - Data::ScriptInfo& outScriptInfo, - ghc::filesystem::file_time_type& outFinalSourceWriteTime, - ghc::filesystem::file_time_type& outFinalIncludeWriteTime, - int& returnStatus) + inline DS::Result Run( RunParams runParams, + Data::ScriptInfo& outScriptInfo, + ghc::filesystem::file_time_type& outFinalSourceWriteTime, + ghc::filesystem::file_time_type& outFinalIncludeWriteTime) { - INTERNAL_RUNCPP2_SAFE_START(); - ssLOG_FUNC_INFO(); - - //Validate inputs and get paths ghc::filesystem::path absoluteScriptPath; ghc::filesystem::path scriptDirectory; std::string scriptName; - ValidateInputs(scriptPath, profiles, absoluteScriptPath, scriptDirectory, scriptName) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return (PipelineResult)DS_TMP_ERROR.ErrorCode); - - ghc::filesystem::path configDir = - GetConfigFilePath().DS_TRY_ACT( ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return PipelineResult::INVALID_CONFIG_PATH); - ghc::filesystem::path buildDir; - - //Create parameters - std::unordered_map parameterValues; - CreateParameterValues(currentOptions, parameterValues); - - //Parse script info + std::unordered_map parameters; Data::ScriptInfo scriptInfo; - ParseAndValidateScriptInfo( absoluteScriptPath, - scriptDirectory, - scriptName, - currentOptions.count(CmdOptions::EXECUTABLE) > 0, - parameterValues, - scriptInfo) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return (PipelineResult)DS_TMP_ERROR.ErrorCode); - //Parse and get the config directory - { - std::error_code e; - if(ghc::filesystem::is_directory(configDir, e)) - { - ssLOG_FATAL("Unexpected path for config file: " << configDir.string()); - return PipelineResult::INVALID_CONFIG_PATH; - } - - configDir = configDir.parent_path(); - if(!ghc::filesystem::is_directory(configDir, e)) - { - ssLOG_FATAL("Unexpected path for config directory: " << configDir.string()); - return PipelineResult::INVALID_CONFIG_PATH; - } - } + //TODO: Reduce number of parameters here + GetScriptInfoData( runParams.Core.scriptPath, + runParams.Core.rawParameters, + runParams.Core.runAsExecutable, + + //Output: + scriptInfo, + absoluteScriptPath, + scriptDirectory, + scriptName, + parameters).DS_TRY(); + + if(runParams.Core.profiles.empty()) + return DS_ERROR_MSG("No compiler profiles found"); int profileIndex = GetPreferredProfileIndex( absoluteScriptPath, scriptInfo, - profiles, - configPreferredProfile) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return PipelineResult::NO_AVAILABLE_PROFILE); - + runParams.Core.profiles, + runParams.Core.configPreferredProfile).DS_TRY(); + //Parsing the script, setting up dependencies, compiling and linking std::vector filesToCopyPaths; + ghc::filesystem::path buildDir = GetDefaultBuildDir().DS_TRY(); { - const int maxThreads = - currentOptions.count(CmdOptions::THREADS) ? - strtol(currentOptions.at(CmdOptions::THREADS).c_str(), nullptr, 10) : - 8; - if(maxThreads == 0) - { - ssLOG_ERROR("Invalid number of threads passed in"); - return PipelineResult::INVALID_OPTION; - } - BuildsManager buildsManager("/tmp"); IncludeManager includeManager; - InitializeBuildDirectory( configDir, + InitializeBuildDirectory( buildDir, absoluteScriptPath, - currentOptions.count(CmdOptions::LOCAL) > 0, + runParams.Core.buildLocally, buildsManager, buildDir, - includeManager) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return (PipelineResult)DS_TMP_ERROR.ErrorCode); - - //Handle cleanup command if present - if(currentOptions.count(CmdOptions::CLEANUP) > 0) - { - HandleCleanup( scriptInfo, - profiles.at(profileIndex), - scriptDirectory, - buildDir, - absoluteScriptPath, - buildsManager) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return (PipelineResult)DS_TMP_ERROR.ErrorCode); - } + includeManager).DS_TRY(); + + const int maxThreads = runParams.rawMaxThreads.empty() ? + 8 : + strtol(runParams.rawMaxThreads.c_str(), nullptr, 10); + if(maxThreads <= 0) + return DS_ERROR_MSG("Invalid number of threads passed in"); //Resolve imports - ResolveScriptImports(scriptInfo, absoluteScriptPath.parent_path(), buildDir) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return (PipelineResult)DS_TMP_ERROR.ErrorCode); + ResolveScriptImports(scriptInfo, scriptDirectory, buildDir).DS_TRY(); //Check if script info has changed if provided and run setup if needed bool recompileNeeded = false; bool relinkNeeded = false; std::vector changedDependencies; - CheckScriptInfoChanges( buildDir, scriptInfo, - profiles.at(profileIndex), - absoluteScriptPath.parent_path(), - lastScriptInfo, - maxThreads, - parameterValues, + runParams.Core.profiles.at(profileIndex), + scriptDirectory, + runParams.lastScriptInfo, + parameters, recompileNeeded, relinkNeeded, - changedDependencies) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return (PipelineResult)DS_TMP_ERROR.ErrorCode); - - //if(!lastScriptInfo || recompileNeeded || !changedDependencies.empty() || relinkNeeded) - outScriptInfo = scriptInfo; + changedDependencies).DS_TRY(); + outScriptInfo = scriptInfo; std::vector gatheredBinariesPaths; //Process Dependencies std::vector availableDependencies; ProcessDependencies(scriptInfo, - profiles.at(profileIndex), - absoluteScriptPath.parent_path(), + runParams.Core.profiles.at(profileIndex), + scriptDirectory, buildDir, - currentOptions, changedDependencies, maxThreads, + runParams.buildSourceOnly, availableDependencies, - gatheredBinariesPaths) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return (PipelineResult)DS_TMP_ERROR.ErrorCode); + gatheredBinariesPaths).DS_TRY(); - if(currentOptions.count(CmdOptions::RESET_DEPENDENCIES) > 0) - return PipelineResult::SUCCESS; - //Get all the files we are trying to compile std::vector sourceFiles; GatherSourceFiles( absoluteScriptPath, scriptInfo, - profiles.at(profileIndex), - sourceFiles) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return PipelineResult::INVALID_SCRIPT_INFO); + runParams.Core.profiles.at(profileIndex), + sourceFiles).DS_TRY(); //Get all include paths std::vector includePaths; GatherIncludePaths( scriptDirectory, scriptInfo, - profiles.at(profileIndex), + runParams.Core.profiles.at(profileIndex), availableDependencies, - includePaths) - .DS_TRY_ACT(DS_TMP_ERROR.Message += "Failed to gather include paths"; - ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return PipelineResult::INVALID_SCRIPT_INFO); + includePaths).DS_TRY(); //Check if we have already compiled before. std::vector sourceHasCache; std::vector cachedObjectsFiles; ghc::filesystem::file_time_type finalObjectWriteTime; - - if(currentOptions.count(CmdOptions::RESET_CACHE) > 0 || recompileNeeded) + if(runParams.rebuild || recompileNeeded) sourceHasCache = std::vector(sourceFiles.size(), false); else { - HasCompiledCache( absoluteScriptPath.parent_path(), + HasCompiledCache( scriptDirectory, sourceFiles, buildDir, - profiles.at(profileIndex), + runParams.Core.profiles.at(profileIndex), includeManager, sourceHasCache, cachedObjectsFiles, finalObjectWriteTime, outFinalSourceWriteTime, - outFinalIncludeWriteTime) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - //TODO: Maybe add a pipeline result for this? - return PipelineResult::UNEXPECTED_FAILURE); + outFinalIncludeWriteTime).DS_TRY(); } runcpp2::SourceIncludeMap sourcesIncludes; - runcpp2::GatherFilesIncludes(sourceFiles, sourceHasCache, includePaths, sourcesIncludes) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return PipelineResult::UNEXPECTED_FAILURE); - + runcpp2::GatherFilesIncludes( sourceFiles, + sourceHasCache, + includePaths, + sourcesIncludes).DS_TRY(); for(int i = 0; i < sourceFiles.size(); ++i) { if(!sourceHasCache.at(i)) @@ -668,8 +778,8 @@ namespace runcpp2 ); if(!writeResult) { - ssLOG_ERROR("Failed to write include record for " << sourceFiles.at(i).string()); - return PipelineResult::UNEXPECTED_FAILURE; + return DS_ERROR_MSG("Failed to write include record for " + + sourceFiles.at(i).string()); } } else @@ -680,7 +790,7 @@ namespace runcpp2 } std::vector linkFilesPaths; - SeparateDependencyFiles(profiles.at(profileIndex).FilesTypes, + SeparateDependencyFiles(runParams.Core.profiles.at(profileIndex).FilesTypes, gatheredBinariesPaths, linkFilesPaths, filesToCopyPaths); @@ -692,10 +802,7 @@ namespace runcpp2 for(int i = 0; i < linkFilesPaths.size(); ++i) { if(!ghc::filesystem::exists(linkFilesPaths.at(i), e)) - { - ssLOG_ERROR(linkFilesPaths.at(i) << " reported as cached but doesn't exist"); - return PipelineResult::UNEXPECTED_FAILURE; - } + return DS_ERROR_MSG(linkFilesPaths.at(i) + " reported as cached but doesn't exist"); ghc::filesystem::file_time_type lastWriteTime = ghc::filesystem::last_write_time(linkFilesPaths.at(i), e); @@ -705,15 +812,13 @@ namespace runcpp2 } //Run PreBuild commands before compilation - HandlePreBuild(scriptInfo, profiles.at(profileIndex), buildDir) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return (PipelineResult)DS_TMP_ERROR.ErrorCode); + HandlePreBuild(scriptInfo, runParams.Core.profiles.at(profileIndex), buildDir).DS_TRY(); //Compiling/Linking bool outputCache = false; if(!HasOutputCache( sourceHasCache, buildDir, - profiles.at(profileIndex), + runParams.Core.profiles.at(profileIndex), scriptInfo, scriptName, linkFilesPaths, @@ -722,7 +827,6 @@ namespace runcpp2 { ssLOG_WARNING( "Error detected when trying to use output cache. " "A cleanup is recommended"); - //return PipelineResult::UNEXPECTED_FAILURE; } if(!outputCache || relinkNeeded) @@ -731,145 +835,103 @@ namespace runcpp2 linkFilesPaths.push_back(cachedObjectsFiles.at(i)); //TODO: Compile and link for watch as well. Load library as well - if(currentOptions.count(CmdOptions::WATCH) > 0) + if(runParams.compileOnly) { CompileScriptOnly( buildDir, - absoluteScriptPath.parent_path(), + scriptDirectory, sourceFiles, sourceHasCache, includePaths, scriptInfo, availableDependencies, - profiles.at(profileIndex), - maxThreads) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return PipelineResult::COMPILE_LINK_FAILED); - - return PipelineResult::SUCCESS; + runParams.Core.profiles.at(profileIndex), + maxThreads).DS_TRY(); + return 0; } else { CompileAndLinkScript( buildDir, - absoluteScriptPath.parent_path(), - ghc::filesystem::path(absoluteScriptPath).stem(), + scriptDirectory, + ghc::filesystem::path(scriptName), sourceFiles, sourceHasCache, includePaths, scriptInfo, availableDependencies, - profiles.at(profileIndex), + runParams.Core.profiles.at(profileIndex), linkFilesPaths, maxThreads) .DS_TRY_ACT(DS_TMP_ERROR.Message += "\nFailed to compile or link script."; - ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return PipelineResult::COMPILE_LINK_FAILED); + DS_APPEND_TRACE(DS_TMP_ERROR); + return DS::Error(DS_TMP_ERROR)); } } } - + //Trigger post build and run the script if needed + int returnStatus = -1; { std::vector targets; ghc::filesystem::path runnableTarget; GetBuiltTargetPaths(buildDir, scriptName, - profiles.at(profileIndex), - currentOptions, + runParams.Core.profiles.at(profileIndex), + runParams.Core.runAsExecutable, scriptInfo, targets, - &runnableTarget) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return (PipelineResult)DS_TMP_ERROR.ErrorCode); + &runnableTarget).DS_TRY(); if(targets.empty()) { ssLOG_WARNING("No target files found"); - return PipelineResult::SUCCESS; + return 0; } //Copy files to build directory std::vector copiedPaths; - if(!buildOutputDir.empty()) + if(!runParams.buildOutputDir.empty()) { - buildDir = buildOutputDir; + std::error_code e; + if(!ghc::filesystem::exists(runParams.buildOutputDir, e)) + { + if(!ghc::filesystem::create_directories(runParams.buildOutputDir, e)) + return DS_ERROR_MSG("Failed to create output directory"); + } + + buildDir = runParams.buildOutputDir; //filesToCopyPaths.push_back(runnableTarget.string()); for(const ghc::filesystem::path& target : targets) filesToCopyPaths.push_back(target.string()); } CopyFiles(buildDir, filesToCopyPaths, copiedPaths) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - ssLOG_ERROR("Failed to copy binaries before running the script"); - return PipelineResult::UNEXPECTED_FAILURE); + .DS_TRY_ACT(DS_TMP_ERROR.Message += "\nFailed to copy binaries before running the " + "script"; + DS_APPEND_TRACE(DS_TMP_ERROR); + return DS::Error(DS_TMP_ERROR)); //Run PostBuild commands after successful compilation - HandlePostBuild(scriptInfo, profiles.at(profileIndex), buildDir.string()) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return (PipelineResult)DS_TMP_ERROR.ErrorCode); - - //Don't run if we are just watching, reseting source cache or building - if( currentOptions.count(CmdOptions::WATCH) > 0 || - currentOptions.count(CmdOptions::RESET_CACHE) > 0 || - currentOptions.count(CmdOptions::BUILD) > 0) - { - return PipelineResult::SUCCESS; - } + HandlePostBuild(scriptInfo, + runParams.Core.profiles.at(profileIndex), + buildDir.string()).DS_TRY(); + + //Don't run if we are just watching or building + if(runParams.buildOnly) + return 0; //Run otherwise ssLOG_INFO("Running script..."); RunCompiledOutput( runnableTarget, absoluteScriptPath, scriptInfo, - runArgs, - currentOptions, - returnStatus) - .DS_TRY_ACT(ssLOG_ERROR(DS_TMP_ERROR.ToString()); - return (PipelineResult)DS_TMP_ERROR.ErrorCode); + runParams.runArgs, + returnStatus).DS_TRY(); } - - return PipelineResult::SUCCESS; - INTERNAL_RUNCPP2_SAFE_CATCH_RETURN(PipelineResult::UNEXPECTED_FAILURE); + return returnStatus; } - - inline std::string PipelineResultToString(PipelineResult result) - { - static_assert(static_cast(PipelineResult::COUNT) == 13, "PipelineResult enum has changed"); - switch(result) - { - case PipelineResult::UNEXPECTED_FAILURE: - return "UNEXPECTED_FAILURE"; - case PipelineResult::SUCCESS: - return "SUCCESS"; - case PipelineResult::EMPTY_PROFILES: - return "EMPTY_PROFILES"; - case PipelineResult::INVALID_SCRIPT_PATH: - return "INVALID_SCRIPT_PATH"; - case PipelineResult::INVALID_CONFIG_PATH: - return "INVALID_CONFIG_PATH"; - case PipelineResult::INVALID_BUILD_DIR: - return "INVALID_BUILD_DIR"; - case PipelineResult::INVALID_SCRIPT_INFO: - return "INVALID_SCRIPT_INFO"; - case PipelineResult::NO_AVAILABLE_PROFILE: - return "NO_AVAILABLE_PROFILE"; - case PipelineResult::DEPENDENCIES_FAILED: - return "DEPENDENCIES_FAILED"; - case PipelineResult::COMPILE_LINK_FAILED: - return "COMPILE_LINK_FAILED"; - case PipelineResult::INVALID_PROFILE: - return "INVALID_PROFILE"; - case PipelineResult::RUN_SCRIPT_FAILED: - return "RUN_SCRIPT_FAILED"; - case PipelineResult::INVALID_OPTION: - return "INVALID_OPTION"; - default: - return "UNKNOWN_PIPELINE_RESULT"; - } - } - - inline bool DownloadTutorial(char* runcppPath) + inline DS::Result DownloadTutorial(char* runcppPath) { std::string dummy; int returnCode = 0; @@ -882,10 +944,7 @@ namespace runcpp2 "Continue? [Y/n]"); if(!std::getline(std::cin, input)) - { - ssLOG_ERROR("IO Error when trying to get cin"); - return false; - } + return DS_ERROR_MSG("IO Error when trying to get cin"); if(!input.empty()) { @@ -894,7 +953,7 @@ namespace runcpp2 else if(input == "n" || input == "N") { ssLOG_BASE("Not continuing"); - return 0; + return {}; } else ssLOG_BASE("Please only answer with y or n"); @@ -918,7 +977,7 @@ namespace runcpp2 dummy, returnCode)) { - return false; + return DS_ERROR_MSG("Failed to download tutorial"); } #else if(!RunCommand( "curl -L -o InteractiveTutorial.cpp " @@ -929,15 +988,15 @@ namespace runcpp2 dummy, returnCode)) { - return false; + return DS_ERROR_MSG("Failed to download tutorial"); } #endif ssLOG_INFO("targetBranch: " << targetBranch); ssLOG_BASE("Downloaded InteractiveTutorial.cpp from github."); - ssLOG_BASE("Do `" << runcppPath << " InteractiveTutorial.cpp to start the tutorial."); + ssLOG_BASE("Do `" << runcppPath << " run InteractiveTutorial.cpp to start the tutorial."); - return true; + return {}; } } diff --git a/mkdocs/docs/TODO.md b/mkdocs/docs/TODO.md index 62bd6ca..e702ef3 100644 --- a/mkdocs/docs/TODO.md +++ b/mkdocs/docs/TODO.md @@ -8,6 +8,8 @@ - Rename "OtherFilesToBeCompiled" to "SourceFiles" - Migrate to libyaml - Migrate to DSResult and remove ssTest +- Parameters for build config/script +- Ability to compile runcpp2 as single cpp ### v0.3.1 - Check last run is shared lib or executable. Reset cache when necessary if different type @@ -32,11 +34,11 @@ ### v0.4.0 - Allow runcpp2 to be library for scriptable pipeline -- Parameters for build config/script +- Parameters for dependencies - Parameters for profiles - Add more default profiles -- Ability to compile runcpp2 as single cpp, ditch cmake -- Move to variant-lite, mpark-variant is unreadable +- Ditch cmake +- Move to variant-lite instead of mpark-variant ## High Priority diff --git a/mkdocs/docs/guides/basics.md b/mkdocs/docs/guides/basics.md index 2418170..ae49602 100644 --- a/mkdocs/docs/guides/basics.md +++ b/mkdocs/docs/guides/basics.md @@ -50,12 +50,12 @@ runcpp2 ./script.cpp ``` !!! note - On Unix, if you have added runcpp2 to your PATH and add this line `//bin/true;runcpp2 "$0" "$@"; exit $?;` + On Unix, if you have added runcpp2 to your PATH and add this line `//bin/true;runcpp2 run "$0" "$@"; exit $?;` to the top of your script, you can run the script directly by `./script.cpp ` ??? example ```cpp title="script.cpp" - //bin/true;runcpp2 "$0" "$@"; exit $?; + //bin/true;runcpp2 run "$0" "$@"; exit $?; #include int main(int, char**) { std::cout << "Hello World" << std::endl; } ``` @@ -73,7 +73,7 @@ binary will be the name of the YAML file. If you want to edit the script but want to have feedback for any error, you can use "watch" mode. ```shell title="shell" -runcpp2 --watch ./script.cpp +runcpp2 watch ./script.cpp ``` --- @@ -122,9 +122,8 @@ can be spcified inlined inside a source file or as a separate yaml file in the f For a complete list of build settings, see [Build Settings](../build_settings.md) or generate the template with ```shell -runcpp2 --create-script-template ./script.cpp # Embeds the build settings template as comment -runcpp2 --create-script-template ./script.yaml # Creates the build settings template as dedicated yaml file -runcpp2 -t ./script.cpp # Short form +runcpp2 template ./script.cpp # Embeds the build settings template as comment +runcpp2 template ./script.yaml # Creates the build settings template as dedicated yaml file ``` --- diff --git a/mkdocs/docs/index.md b/mkdocs/docs/index.md index 260ba97..f29c3dc 100644 --- a/mkdocs/docs/index.md +++ b/mkdocs/docs/index.md @@ -4,7 +4,7 @@ runcpp2 is a simple declarable, scriptable, flexible cross-platform build system build system for c or c++ -- 🚀 **Simple**: `#!shell runcpp2 main.cpp`, this is all you need to get started +- 🚀 **Simple**: `#!shell runcpp2 run main.cpp`, this is all you need to get started - 📝 **Declarable**: *Quick, Concise, Minimal* YAML format - 🔧 **Scriptable**: *Customize, Run And Debug* your build pipeline with c++, or just use it as a script. No longer need to juggle between CMake, Python, Bash, Batch, Lua, etc... @@ -31,7 +31,7 @@ you can run c++ files anywhere you want. ### Interactive Tutorial -You can get started by running the tutorial with `runcpp2 --tutorial` and follow the instructions +You can get started by running the tutorial with `runcpp2 tutorial` and follow the instructions ### User Guide diff --git a/mkdocs/docs/program_manual.md b/mkdocs/docs/program_manual.md index 3d6d8a7..6a2d1e8 100644 --- a/mkdocs/docs/program_manual.md +++ b/mkdocs/docs/program_manual.md @@ -1,35 +1,19 @@ # Program Manual -## Usage -`#!shell runcpp2 [options] [input_file]` - ## Options ```text -Options: - Run/Build: - -b, --[b]uild Build the script but don't run it - -o, --[o]utput Output files to the directory specified, must be used with --build - -w, --[w]atch Watch script changes and output any compiling errors - -l, --[l]ocal Build in the current working directory under .runcpp2 directory - -e, --[e]xecutable Runs as executable instead of shared library - -c, --[c]onfig Use specified config file instead of default - -t, --create-script-[t]emplate Creates/prepend runcpp2 script info template - -s, --[s]ource-only (Re)Builds source files only without building dependencies. - The previous built binaries will be used for dependencies. - Requires dependencies to be built already. - -j, --[j]obs Maximum number of threads running. Defaults to 8 - Reset/Cleanup: - -rb, --[r]e[b]uild Deletes compiled source files cache and rebuild - -ru, --[r]eset-[u]ser-config Replace current user config with the default one - -rd, --[r]eset-[d]ependencies Reset dependencies (comma-separated names, or "all" for all) - -cu, --[c]lean[u]p Run cleanup commands and remove build directory - Settings: - -sc, --[s]how-[c]onfig-path Show where runcpp2 is reading the config from - -v, --[v]ersion Show the version of runcpp2 - -h, --[h]elp Show this help message - --log-level Sets the log level (Normal, Info, Debug) for runcpp2 - Others: - --tutorial Start interactive tutorial +Usage: runcpp2 [options] [input file] [run args] +Actions: + run Runs the input file + build Build the input file + watch Watch for any changes in source files and output any compiling errors + template Creates/prepend runcpp2 build info template to the input file + regen-user-config Replace current user config with the default one + reset Perform cleanup on both/either the source and/or the dependencies + show-config-path Show where runcpp2 is reading the config from + version Show the version of runcpp2 + tutorial Start interactive tutorial + help Show this help message ```