diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..8212e53 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,77 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Configure: Debug", + "type": "shell", + "command": "./scripts/build_script configure -b debug", + "group": { + "isDefault": false + }, + "problemMatcher": [], + "detail": "Configure Debug" + }, + { + "label": "Build: Debug", + "type": "shell", + "command": "./scripts/build_script build -b debug", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [], + "detail": "Build Debug" + }, + { + "label": "Configure: Relwithdeb", + "type": "shell", + "command": "./scripts/build_script configure -b relwithdeb", + "group": { + "isDefault": false + }, + "problemMatcher": [], + "detail": "Configure Release with debug info" + }, + { + "label": "Build: Relwithdeb", + "type": "shell", + "command": "./scripts/build_script build -b relwithdeb", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [], + "detail": "Build Release with debug info" + }, + { + "label": "Clean: Debug", + "type": "shell", + "command": "./scripts/build_script clean -b debug", + "group": { + "isDefault": false + }, + "detail": "Clean debug files" + }, + { + "label": "Build: All", + "type": "shell", + "command": "./scripts/build_script build", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [], + "detail": "Build all types" + }, + { + "label": "Clean: All", + "type": "shell", + "command": "./scripts/build_script clean", + "group": { + "isDefault": false + }, + "problemMatcher": [], + "detail": "Clean All files" + } + ] +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cc9e01..97c7346 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,3 +29,7 @@ target_link_libraries(${PROJECT_NAME} PUBLIC structopt spdlog ) + +# Structopt includes an outdated version of magic_enum that breaks some default defines +# This is needed to bypass it. Im not happy about it, but it is what it is +target_link_options(build_script PRIVATE -Wl,--allow-multiple-definition) diff --git a/src/actions.cpp b/src/actions.cpp new file mode 100644 index 0000000..d983187 --- /dev/null +++ b/src/actions.cpp @@ -0,0 +1,80 @@ +#include "actions.h" + +int runCmd(std::string cmd, bool dryrun) { + if (dryrun) { + spdlog::get("cmd")->warn("[DRYRUN] Running '{}'", cmd); + return 0; + } + + spdlog::get("cmd")->debug("Running '{}'", cmd); + spdlog::get("cmd")->debug("Opening pipe"); + FILE* pipe = popen(cmd.c_str(), "r"); + if (!pipe) { + spdlog::get("cmd")->warn("Failed to start the process"); + return 1; + } + + spdlog::get("cmd")->debug("Buffering and offloading pipe"); + std::array buffer; + while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) { + std::cout << buffer.data() << std::flush; + } + + spdlog::get("filesystem")->debug("Closing pipe"); + int exitCode = pclose(pipe); + spdlog::get("cmd")->info("Process ended with exit code: {}", exitCode); + + return exitCode; +} + +void buildDir(const std::filesystem::path& path, bool dryrun) { + if (dryrun) { + spdlog::get("build")->warn("[DRYRUN] Building '{}'", path.string()); + return; + } + + spdlog::get("build")->info("Building '{}'", path.string()); + if (int exitCode = + runCmd(std::format("cd {} && ninja", path.string()), dryrun); + exitCode != 0) { + spdlog::get("build")->critical("Command exited with exit code: {}", + exitCode); + exit(EXIT_FAILURE); + } +} + +void configureDir(const std::filesystem::path& path, std::string buildStr, + bool dryrun) { + if (dryrun) { + spdlog::get("configure") + ->warn("[DRYRUN] Configuring '{}'", path.string()); + return; + } + + spdlog::get("configure")->info("Configuring '{}'", path.string()); + if (int exitCode = runCmd( + std::format("cd {} && cmake ../../ -G Ninja -DCMAKE_BUILD_TYPE={}", + path.string(), buildStr), + dryrun); + exitCode != 0) { + spdlog::get("configure") + ->critical("Command exited with exit code: {}", exitCode); + exit(EXIT_FAILURE); + } +} + +void cleanDir(const std::filesystem::path& path, bool dryrun) { + if (dryrun) { + spdlog::get("clean")->warn("[DRYRUN] Cleaning '{}'", path.string()); + return; + } + + spdlog::get("clean")->info("Cleaning '{}'", path.string()); + if (int exitCode = + runCmd(std::format("cd {} && ninja clean", path.string()), dryrun); + exitCode != 0) { + spdlog::get("clean")->critical("Command exited with exit code: {}", + exitCode); + exit(EXIT_FAILURE); + } +} diff --git a/src/actions.h b/src/actions.h new file mode 100644 index 0000000..a63c2d8 --- /dev/null +++ b/src/actions.h @@ -0,0 +1,15 @@ +#ifndef BUILD_SCRIPT_ACTIONS +#define BUILD_SCRIPT_ACTIONS + +#include + +#include "filesystem.h" +#include "logging.h" + +int runCmd(std::string cmd, bool dryrun); +void buildDir(const std::filesystem::path& path, bool dryrun); +void configureDir(const std::filesystem::path& path, std::string buildStr, + bool dryrun); +void cleanDir(const std::filesystem::path& path, bool dryrun); + +#endif // !BUILD_SCRIPT_ACTIONS diff --git a/src/args.cpp b/src/args.cpp new file mode 100644 index 0000000..a8ee892 --- /dev/null +++ b/src/args.cpp @@ -0,0 +1,14 @@ +#include "args.h" + +Options parse(int argc, char** argv) { + Options options; + try { + options = structopt::app(argv[0], "1.0.0").parse(argc, argv); + } catch (structopt::exception& e) { + std::cout << e.what() << std::endl; + std::cout << e.help(); + exit(EXIT_FAILURE); + } + + return options; +} diff --git a/src/args.h b/src/args.h new file mode 100644 index 0000000..adc64f8 --- /dev/null +++ b/src/args.h @@ -0,0 +1,19 @@ +#ifndef BUILD_SCRIPT_ARGS +#define BUILD_SCRIPT_ARGS + +#include + +#include "types.h" + +struct Options { + Command command; + std::optional buildType = BuildType::none; + + std::optional verbose = false; + std::optional dryrun = false; +}; +STRUCTOPT(Options, command, buildType, verbose, dryrun); + +Options parse(int argc, char** argv); + +#endif // !BUILD_SCRIPT_ARGS diff --git a/src/commands.cpp b/src/commands.cpp new file mode 100644 index 0000000..e5a4b16 --- /dev/null +++ b/src/commands.cpp @@ -0,0 +1,109 @@ +#include "commands.h" + +void buildProject(const BuildType buildType, bool dryrun) { + checkBuildDirs(buildType, dryrun); + switch (buildType) { + case none: + configureDir("build/debug", "Debug", dryrun); + buildDir("build/debug", dryrun); + configureDir("build/release", "Release", dryrun); + buildDir("build/release", dryrun); + configureDir("build/relwithdeb", "RelWithDeb", dryrun); + buildDir("build/relwithdeb", dryrun); + configureDir("build/minsizerel", "MinSizeRel", dryrun); + buildDir("build/minsizerel", dryrun); + break; + case debug: + configureDir("build/debug", "Debug", dryrun); + buildDir("build/debug", dryrun); + break; + case release: + configureDir("build/release", "Release", dryrun); + buildDir("build/release", dryrun); + break; + case relwithdeb: + configureDir("build/relwithdeb", "RelWithDeb", dryrun); + buildDir("build/relwithdeb", dryrun); + break; + case minsizerel: + configureDir("build/minsizerel", "MinSizeRel", dryrun); + buildDir("build/minsizerel", dryrun); + break; + } +} + +void configureProject(const BuildType buildType, bool dryrun) { + checkBuildDirs(buildType, dryrun); + switch (buildType) { + case none: + configureDir("build/debug", "Debug", dryrun); + configureDir("build/release", "Release", dryrun); + configureDir("build/relwithdeb", "RelWithDeb", dryrun); + configureDir("build/minsizerel", "MinSizeRel", dryrun); + break; + case debug: + configureDir("build/debug", "Debug", dryrun); + break; + case release: + configureDir("build/release", "Release", dryrun); + break; + case relwithdeb: + configureDir("build/RelWithDeb", "RelWithDeb", dryrun); + break; + case minsizerel: + configureDir("build/minsizerel", "MinSizeRel", dryrun); + break; + } +} + +void cleanProject(const BuildType buildType, bool dryrun) { + checkBuildDirs(buildType, dryrun); + + switch (buildType) { + case none: + cleanDir("build/debug", dryrun); + cleanDir("build/release", dryrun); + cleanDir("build/relwithdeb", dryrun); + cleanDir("build/minsizerel", dryrun); + break; + case debug: + cleanDir("build/debug", dryrun); + break; + case release: + cleanDir("build/release", dryrun); + break; + case relwithdeb: + cleanDir("build/RelWithDeb", dryrun); + break; + case minsizerel: + cleanDir("build/minsizerel", dryrun); + break; + } +} + +void deleteProject(const BuildType buildType, bool dryrun) { + switch (buildType) { + case none: + deleteDir("build", dryrun); + break; + case debug: + deleteDir("build/debug", dryrun); + break; + case release: + deleteDir("build/release", dryrun); + break; + case relwithdeb: + deleteDir("build/relwithdeb", dryrun); + break; + case minsizerel: + deleteDir("build/minsizerel", dryrun); + break; + } +} + +void rebuildProject(const BuildType buildType, bool dryrun) { + deleteProject(buildType, dryrun); + checkBuildDirs(buildType, dryrun); + configureProject(buildType, dryrun); + buildProject(buildType, dryrun); +} diff --git a/src/commands.h b/src/commands.h new file mode 100644 index 0000000..c589768 --- /dev/null +++ b/src/commands.h @@ -0,0 +1,13 @@ +#ifndef BUILD_SCRIPT_COMMANDS +#define BUILD_SCRIPT_COMMANDS + +#include "actions.h" +#include "types.h" + +void buildProject(const BuildType buildType, bool dryrun); +void configureProject(const BuildType buildType, bool dryrun); +void cleanProject(const BuildType buildType, bool dryrun); +void deleteProject(const BuildType buildType, bool dryrun); +void rebuildProject(const BuildType buildType, bool dryrun); + +#endif // !BUILD_SCRIPT_COMMANDS diff --git a/src/filesystem.cpp b/src/filesystem.cpp new file mode 100644 index 0000000..7740013 --- /dev/null +++ b/src/filesystem.cpp @@ -0,0 +1,170 @@ +#include "filesystem.h" + +#include + +#include "logging.h" + +void deleteDir(const std::filesystem::path& path, bool dryrun) { + if (dryrun) { + spdlog::get("filesystem") + ->warn("[DRYRUN] Deleting '{}'", path.string()); + return; + } + + spdlog::get("filesystem")->warn("DELETING '{}' directory.", path.string()); + spdlog::get("filesystem")->debug("Checking '{}'", path.string()); + if (!std::filesystem::exists(path) || + !std::filesystem::is_directory(path)) { + spdlog::get("filesystem") + ->info( + "The {} directory either doesn't exist or its a file. " + "Continuing...", + path.string()); + return; + } + + spdlog::get("filesystem")->debug("Deleting '{}'", path.string()); + std::filesystem::remove_all(path); +} + +void createDir(const std::filesystem::path& path, bool dryrun) { + if (dryrun) { + spdlog::get("filesystem") + ->warn("[DRYRUN] Creating '{}'", path.string()); + return; + } + + spdlog::get("filesystem")->debug("Creating '{}'", path.string()); + if (const bool res = std::filesystem::create_directories(path); !res) { + spdlog::get("filesystem") + ->warn("Failed to create directory: '{}'", path.string()); + } +} + +void checkBuildDirs(const BuildType buildType, bool dryrun) { + spdlog::get("filesystem")->debug("Checking 'build' directory."); + if (!std::filesystem::is_directory("build")) { + spdlog::get("filesystem") + ->warn("'build' is not a directory. Deleting."); + deleteDir("build", dryrun); + } + if (!std::filesystem::exists("build")) { + spdlog::get("filesystem")->info("Creating 'build' directory"); + createDir("build", dryrun); + } + + switch (buildType) { + case none: + spdlog::get("filesystem") + ->debug("Checking 'build/debug' directory."); + if (!std::filesystem::is_directory("build/debug")) { + spdlog::get("filesystem") + ->warn("'build/debug' is not a directory. Deleting."); + deleteDir("build/debug", dryrun); + } + if (!std::filesystem::exists("build/debug")) { + spdlog::get("filesystem") + ->info("Creating 'build/debug' directory."); + createDir("build/debug", dryrun); + } + + spdlog::get("filesystem") + ->debug("Checking 'build/release' directory."); + if (!std::filesystem::is_directory("build/release")) { + spdlog::get("filesystem") + ->warn("'build/release' is not a directory. Deleting."); + deleteDir("build/release", dryrun); + } + if (!std::filesystem::exists("build/release")) { + spdlog::get("filesystem") + ->info("Creating 'build/release' directory."); + createDir("build/release", dryrun); + } + + spdlog::get("filesystem") + ->debug("Checking 'build/relwithdeb' directory."); + if (!std::filesystem::is_directory("build/relwithdeb")) { + spdlog::get("filesystem") + ->warn("'build/relwithdeb' is not a directory. Deleting."); + deleteDir("build/relwithdeb", dryrun); + } + if (!std::filesystem::exists("build/relwithdeb")) { + spdlog::get("filesystem") + ->info("Creating 'build/relwithdeb' directory."); + createDir("build/relwithdeb", dryrun); + } + + spdlog::get("filesystem") + ->debug("Checking 'build/minsizerel' directory."); + if (!std::filesystem::is_directory("build/minsizerel")) { + spdlog::get("filesystem") + ->warn("'build/minsizerel' is not a directory. Deleting."); + deleteDir("build/minsizerel", dryrun); + } + if (!std::filesystem::exists("build/minsizerel")) { + spdlog::get("filesystem") + ->info("Creating 'build/minsizerel' directory."); + createDir("build/minsizerel", dryrun); + }; + + break; + case debug: + spdlog::get("filesystem") + ->debug("Checking 'build/debug' directory."); + if (!std::filesystem::is_directory("build/debug")) { + spdlog::get("filsystem") + ->warn("'build/debug' is not a directory. Deleting."); + deleteDir("build/debug", dryrun); + } + if (!std::filesystem::exists("build/debug")) { + spdlog::get("filesystem") + ->info("Creating 'build/debug' directory."); + createDir("build/debug", dryrun); + } + break; + case release: + spdlog::get("filesystem") + ->debug("Checking 'build/release' directory."); + if (!std::filesystem::is_directory("build/release")) { + spdlog::get("filesystem") + ->warn("'build/release' is not a directory. Deleting."); + deleteDir("build/release", dryrun); + } + if (!std::filesystem::exists("build/release")) { + spdlog::get("filesystem") + ->info("Creating 'build/release' directory."); + createDir("build/release", dryrun); + } + break; + case relwithdeb: + spdlog::get("filesystem") + ->debug("Checking 'build/relwithdeb' directory."); + if (!std::filesystem::is_directory("build/relwithdeb")) { + spdlog::get("filesystem") + ->warn("'build/relwithdeb' is not a directory. Deleting."); + deleteDir("build/relwithdeb", dryrun); + } + if (!std::filesystem::exists("build/relwithdeb")) { + spdlog::get("filesystem") + ->info("Creating 'build/relwithdeb' directory."); + createDir("build/relwithdeb", dryrun); + }; + break; + case minsizerel: + spdlog::get("filesystem") + ->debug("Checking 'build/minsizerel' directory."); + if (!std::filesystem::is_directory("build/minsizerel")) { + spdlog::get("filesystem") + ->warn("'build/minsizerel' is not a directory. Deleting."); + deleteDir("build/minsizerel", dryrun); + } + if (!std::filesystem::exists("build/minsizerel")) { + spdlog::get("filesystem") + ->info("Creating 'build/minsizerel' directory."); + createDir("build/minsizerel", dryrun); + }; + break; + } + + spdlog::get("filesystem")->info("All directories checked."); +} diff --git a/src/filesystem.h b/src/filesystem.h new file mode 100644 index 0000000..d383c2f --- /dev/null +++ b/src/filesystem.h @@ -0,0 +1,12 @@ +#ifndef BUILD_SCRIPT_FILESYSTEM +#define BUILD_SCRIPT_FILESYSTEM + +#include + +#include "types.h" + +void deleteDir(const std::filesystem::path& path, bool dryrun); +void createDir(const std::filesystem::path& path, bool dryrun); +void checkBuildDirs(const BuildType buildType, bool dryrun); + +#endif // !BUILD_SCRIPT_FILESYSTEM diff --git a/src/logging.cpp b/src/logging.cpp new file mode 100644 index 0000000..bde7cab --- /dev/null +++ b/src/logging.cpp @@ -0,0 +1,40 @@ +#include "logging.h" + +void initLogging() { + spdlog::init_thread_pool(8192, 1); + spdlog::flush_every(std::chrono::seconds(1)); +} + +void createLogger(const char* name, const char* filename, const bool verbose) { + std::vector sinks; + + const auto stdout_sink = + std::make_shared(); + stdout_sink->set_level(spdlog::level::debug); + stdout_sink->set_pattern("%^[%D %r %z] [%n] [%l] %v%$"); + sinks.push_back(stdout_sink); + + if (filename != nullptr) { + const auto file_sink = + std::make_shared(filename); + file_sink->set_level(spdlog::level::debug); + file_sink->set_pattern("[%D %r %z] [%n] [%l] %v"); + sinks.push_back(file_sink); + } + + const auto logger = std::make_shared( + name, sinks.begin(), sinks.end(), spdlog::thread_pool(), + spdlog::async_overflow_policy::block); + logger->flush_on(spdlog::level::warn); + +#ifdef DEBUG + logger->set_level(spdlog::level::debug); +#else + if (verbose) + logger->set_level(spdlog::level::debug); + else + logger->set_level(spdlog::level::info); +#endif + + spdlog::register_logger(logger); +} diff --git a/src/logging.h b/src/logging.h new file mode 100644 index 0000000..6afe005 --- /dev/null +++ b/src/logging.h @@ -0,0 +1,12 @@ +#ifndef BUILD_SCRIPT_LOGGING +#define BUILD_SCRIPT_LOGGING + +#include +#include +#include +#include + +void initLogging(); +void createLogger(const char* name, const char* filename, const bool verbose); + +#endif // !BUILD_SCRIPT_LOGGING diff --git a/src/main.cpp b/src/main.cpp index 648c874..2b5d760 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,449 +1,15 @@ -#include -#include -#include -#include - -#include -#include -#include -#include +#include "args.h" +#include "commands.h" +#include "logging.h" +#include "types.h" #ifdef _WIN32 #define popen _popen #define pclose _pclose #endif -enum Command { - build, - configure, - clean, - del, - rebuild, -}; - -enum BuildType { - none, - debug, - release, - relwithdeb, - minsizerel, -}; - -struct Options { - Command command; - std::optional buildType = BuildType::none; - - std::optional verbose = false; - std::optional dryrun = false; -}; -STRUCTOPT(Options, command, buildType, verbose, dryrun); - -bool g_DryRun = false; - -void initLogging() { - spdlog::init_thread_pool(8192, 1); - spdlog::flush_every(std::chrono::seconds(1)); -} - -void createLogger(const char* name, const char* filename, const bool verbose) { - std::vector sinks; - - const auto stdout_sink = - std::make_shared(); - stdout_sink->set_level(spdlog::level::debug); - stdout_sink->set_pattern("%^[%D %r %z] [%n] [%l] %v%$"); - sinks.push_back(stdout_sink); - - if (filename != nullptr) { - const auto file_sink = - std::make_shared(filename); - file_sink->set_level(spdlog::level::debug); - file_sink->set_pattern("[%D %r %z] [%n] [%l] %v"); - sinks.push_back(file_sink); - } - - const auto logger = std::make_shared( - name, sinks.begin(), sinks.end(), spdlog::thread_pool(), - spdlog::async_overflow_policy::block); - logger->flush_on(spdlog::level::warn); - -#ifdef DEBUG - logger->set_level(spdlog::level::debug); -#else - if (verbose) - logger->set_level(spdlog::level::debug); - else - logger->set_level(spdlog::level::info); -#endif - - spdlog::register_logger(logger); -} - -void deleteDir(const std::filesystem::path& path) { - if (g_DryRun) { - spdlog::get("filesystem") - ->warn("[DRYRUN] Deleting '{}'", path.string()); - return; - } - - spdlog::get("filesystem")->warn("DELETING '{}' directory.", path.string()); - spdlog::get("filesystem")->debug("Checking '{}'", path.string()); - if (!std::filesystem::exists(path) || - !std::filesystem::is_directory(path)) { - spdlog::get("filesystem") - ->info( - "The {} directory either doesn't exist or its a file. " - "Continuing...", - path.string()); - return; - } - - spdlog::get("filesystem")->debug("Deleting '{}'", path.string()); - std::filesystem::remove_all(path); -} - -void createDir(const std::filesystem::path& path) { - if (g_DryRun) { - spdlog::get("filesystem") - ->warn("[DRYRUN] Creating '{}'", path.string()); - return; - } - - spdlog::get("filesystem")->debug("Creating '{}'", path.string()); - if (const bool res = std::filesystem::create_directories(path); !res) { - spdlog::get("filesystem") - ->warn("Failed to create directory: '{}'", path.string()); - } -} - -void checkBuildDirs(const BuildType buildType) { - spdlog::get("filesystem")->debug("Checking 'build' directory."); - if (!std::filesystem::is_directory("build")) { - spdlog::get("filesystem") - ->warn("'build' is not a directory. Deleting."); - deleteDir("build"); - } - if (!std::filesystem::exists("build")) { - spdlog::get("filesystem")->info("Creating 'build' directory"); - createDir("build"); - } - - switch (buildType) { - case none: - spdlog::get("filesystem") - ->debug("Checking 'build/debug' directory."); - if (!std::filesystem::is_directory("build/debug")) { - spdlog::get("filesystem") - ->warn("'build/debug' is not a directory. Deleting."); - deleteDir("build/debug"); - } - if (!std::filesystem::exists("build/debug")) { - spdlog::get("filesystem") - ->info("Creating 'build/debug' directory."); - createDir("build/debug"); - } - - spdlog::get("filesystem") - ->debug("Checking 'build/release' directory."); - if (!std::filesystem::is_directory("build/release")) { - spdlog::get("filesystem") - ->warn("'build/release' is not a directory. Deleting."); - deleteDir("build/release"); - } - if (!std::filesystem::exists("build/release")) { - spdlog::get("filesystem") - ->info("Creating 'build/release' directory."); - createDir("build/release"); - } - - spdlog::get("filesystem") - ->debug("Checking 'build/relwithdeb' directory."); - if (!std::filesystem::is_directory("build/relwithdeb")) { - spdlog::get("filesystem") - ->warn("'build/relwithdeb' is not a directory. Deleting."); - deleteDir("build/relwithdeb"); - } - if (!std::filesystem::exists("build/relwithdeb")) { - spdlog::get("filesystem") - ->info("Creating 'build/relwithdeb' directory."); - createDir("build/relwithdeb"); - } - - spdlog::get("filesystem") - ->debug("Checking 'build/minsizerel' directory."); - if (!std::filesystem::is_directory("build/minsizerel")) { - spdlog::get("filesystem") - ->warn("'build/minsizerel' is not a directory. Deleting."); - deleteDir("build/minsizerel"); - } - if (!std::filesystem::exists("build/minsizerel")) { - spdlog::get("filesystem") - ->info("Creating 'build/minsizerel' directory."); - createDir("build/minsizerel"); - }; - - break; - case debug: - spdlog::get("filesystem") - ->debug("Checking 'build/debug' directory."); - if (!std::filesystem::is_directory("build/debug")) { - spdlog::get("filsystem") - ->warn("'build/debug' is not a directory. Deleting."); - deleteDir("build/debug"); - } - if (!std::filesystem::exists("build/debug")) { - spdlog::get("filesystem") - ->info("Creating 'build/debug' directory."); - createDir("build/debug"); - } - break; - case release: - spdlog::get("filesystem") - ->debug("Checking 'build/release' directory."); - if (!std::filesystem::is_directory("build/release")) { - spdlog::get("filesystem") - ->warn("'build/release' is not a directory. Deleting."); - deleteDir("build/release"); - } - if (!std::filesystem::exists("build/release")) { - spdlog::get("filesystem") - ->info("Creating 'build/release' directory."); - createDir("build/release"); - } - break; - case relwithdeb: - spdlog::get("filesystem") - ->debug("Checking 'build/relwithdeb' directory."); - if (!std::filesystem::is_directory("build/relwithdeb")) { - spdlog::get("filesystem") - ->warn("'build/relwithdeb' is not a directory. Deleting."); - deleteDir("build/relwithdeb"); - } - if (!std::filesystem::exists("build/relwithdeb")) { - spdlog::get("filesystem") - ->info("Creating 'build/relwithdeb' directory."); - createDir("build/relwithdeb"); - }; - break; - case minsizerel: - spdlog::get("filesystem") - ->debug("Checking 'build/minsizerel' directory."); - if (!std::filesystem::is_directory("build/minsizerel")) { - spdlog::get("filesystem") - ->warn("'build/minsizerel' is not a directory. Deleting."); - deleteDir("build/minsizerel"); - } - if (!std::filesystem::exists("build/minsizerel")) { - spdlog::get("filesystem") - ->info("Creating 'build/minsizerel' directory."); - createDir("build/minsizerel"); - }; - break; - } - - spdlog::get("filesystem")->info("All directories checked."); -} - -int runCmd(std::string cmd) { - if (g_DryRun) { - spdlog::get("cmd")->warn("[DRYRUN] Running '{}'", cmd); - return 0; - } - - spdlog::get("cmd")->debug("Running '{}'", cmd); - spdlog::get("cmd")->debug("Opening pipe"); - FILE* pipe = popen(cmd.c_str(), "r"); - if (!pipe) { - spdlog::get("cmd")->warn("Failed to start the process"); - return 1; - } - - spdlog::get("cmd")->debug("Buffering and offloading pipe"); - std::array buffer; - while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) { - std::cout << buffer.data() << std::flush; - } - - spdlog::get("filesystem")->debug("Closing pipe"); - int exitCode = pclose(pipe); - spdlog::get("cmd")->info("Process ended with exit code: {}", exitCode); - - return exitCode; -} - -void buildDir(const std::filesystem::path& path) { - if (g_DryRun) { - spdlog::get("build")->warn("[DRYRUN] Building '{}'", path.string()); - return; - } - - spdlog::get("build")->info("Building '{}'", path.string()); - if (int exitCode = runCmd(std::format("cd {} && ninja", path.string())); - exitCode != 0) { - spdlog::get("build")->critical("Command exited with exit code: {}", - exitCode); - exit(EXIT_FAILURE); - } -} - -void configureDir(const std::filesystem::path& path, std::string buildStr) { - if (g_DryRun) { - spdlog::get("configure") - ->warn("[DRYRUN] Configuring '{}'", path.string()); - return; - } - - spdlog::get("configure")->info("Configuring '{}'", path.string()); - if (int exitCode = runCmd( - std::format("cd {} && cmake ../../ -G Ninja -DCMAKE_BUILD_TYPE={}", - path.string(), buildStr)); - exitCode != 0) { - spdlog::get("configure") - ->critical("Command exited with exit code: {}", exitCode); - exit(EXIT_FAILURE); - } -} - -void cleanDir(const std::filesystem::path& path) { - if (g_DryRun) { - spdlog::get("clean")->warn("[DRYRUN] Cleaning '{}'", path.string()); - return; - } - - spdlog::get("clean")->info("Cleaning '{}'", path.string()); - if (int exitCode = - runCmd(std::format("cd {} && cmake clean", path.string())); - exitCode != 0) { - spdlog::get("clean")->critical("Command exited with exit code: {}", - exitCode); - exit(EXIT_FAILURE); - } -} - -void buildProject(const BuildType buildType) { - checkBuildDirs(buildType); - switch (buildType) { - case none: - configureDir("build/debug", "Debug"); - buildDir("build/debug"); - configureDir("build/release", "Release"); - buildDir("build/release"); - configureDir("build/relwithdeb", "RelWithDeb"); - buildDir("build/relwithdeb"); - configureDir("build/minsizerel", "MinSizeRel"); - buildDir("build/minsizerel"); - break; - case debug: - configureDir("build/debug", "Debug"); - buildDir("build/debug"); - break; - case release: - configureDir("build/release", "Release"); - buildDir("build/release"); - break; - case relwithdeb: - configureDir("build/relwithdeb", "RelWithDeb"); - buildDir("build/relwithdeb"); - break; - case minsizerel: - configureDir("build/minsizerel", "MinSizeRel"); - buildDir("build/minsizerel"); - break; - } -} - -void configureProject(const BuildType buildType) { - checkBuildDirs(buildType); - switch (buildType) { - case none: - configureDir("build/debug", "Debug"); - configureDir("build/release", "Release"); - configureDir("build/relwithdeb", "RelWithDeb"); - configureDir("build/minsizerel", "MinSizeRel"); - break; - case debug: - configureDir("build/debug", "Debug"); - break; - case release: - configureDir("build/release", "Release"); - break; - case relwithdeb: - configureDir("build/RelWithDeb", "RelWithDeb"); - break; - case minsizerel: - configureDir("build/minsizerel", "MinSizeRel"); - break; - } -} - -void cleanProject(const BuildType buildType) { - checkBuildDirs(buildType); - - switch (buildType) { - case none: - cleanDir("build/debug"); - cleanDir("build/release"); - cleanDir("build/relwithdeb"); - cleanDir("build/minsizerel"); - break; - case debug: - cleanDir("build/debug"); - break; - case release: - cleanDir("build/release"); - break; - case relwithdeb: - cleanDir("build/RelWithDeb"); - break; - case minsizerel: - cleanDir("build/minsizerel"); - break; - } -} - -void deleteProject(const BuildType buildType) { - switch (buildType) { - case none: - deleteDir("build"); - break; - case debug: - deleteDir("build/debug"); - break; - case release: - deleteDir("build/release"); - break; - case relwithdeb: - deleteDir("build/relwithdeb"); - break; - case minsizerel: - deleteDir("build/minsizerel"); - break; - } -} - -void rebuildProject(const BuildType buildType) { - deleteProject(buildType); - checkBuildDirs(buildType); - configureProject(buildType); - buildProject(buildType); -} - int main(const int argc, char** argv) { - Options options; - try { - options = structopt::app(argv[0], "1.0.0").parse(argc, argv); - } catch (structopt::exception& e) { - std::cout << e.what() << std::endl; - std::cout << e.help(); - exit(EXIT_FAILURE); - } - - assert(options.verbose.has_value()); - - assert(options.dryrun.has_value()); - assert(options.buildType.has_value()); - - g_DryRun = options.dryrun.value(); + Options options = parse(argc, argv); initLogging(); createLogger("app", nullptr, options.verbose.value()); @@ -462,19 +28,19 @@ int main(const int argc, char** argv) { spdlog::get("app")->debug("Running command"); switch (options.command) { case build: - buildProject(options.buildType.value()); + buildProject(options.buildType.value(), options.dryrun.value()); break; case configure: - configureProject(options.buildType.value()); + configureProject(options.buildType.value(), options.dryrun.value()); break; case clean: - cleanProject(options.buildType.value()); + cleanProject(options.buildType.value(), options.dryrun.value()); break; case del: - deleteProject(options.buildType.value()); + deleteProject(options.buildType.value(), options.dryrun.value()); break; case rebuild: - rebuildProject(options.buildType.value()); + rebuildProject(options.buildType.value(), options.dryrun.value()); break; } diff --git a/src/types.h b/src/types.h new file mode 100644 index 0000000..40b8cb3 --- /dev/null +++ b/src/types.h @@ -0,0 +1,20 @@ +#ifndef BUILD_SCRIPT_TYPES +#define BUILD_SCRIPT_TYPES + +enum Command { + build, + configure, + clean, + del, + rebuild, +}; + +enum BuildType { + none, + debug, + release, + relwithdeb, + minsizerel, +}; + +#endif // !BUILD_SCRIPT_TYPES