#pragma once #include #include #include #include "types.h" namespace build { class command_builder { private: indent_t indent_; std::stringstream buffer_; public: command_builder(std::string const & cmd, int indent = 0); template command_builder && operator<<(T const & value) &&; // TODO(samjaffe): Use the type system for things here... command_builder & operator<<(version const & vers) &; command_builder & operator<<(source_file const & file) &; command_builder & operator<<(output_file const & file) &; template command_builder & operator<<(T const & value) &; template command_builder & operator<<(std::vector const & value) &; int execute() const; }; command_builder::command_builder(std::string const & cmd, int indent) : indent_{indent}, buffer_() { buffer_ << cmd; } template command_builder && command_builder::operator<<(T const & value) && { return std::move((*this) << value); } template command_builder & command_builder::operator<<(T const & value) & { buffer_ << ' ' << value; return *this; } command_builder & command_builder::operator<<(version const & vers) & { switch (vers) { case version::cxx11: buffer_ << ' ' << "-std=c++11"; break; case version::cxx14: buffer_ << ' ' << "-std=c++14"; break; case version::cxx17: buffer_ << ' ' << "-std=c++17"; break; case none: break; } return *this; } command_builder & command_builder::operator<<(source_file const & file) & { buffer_ << " -c " << file.get(); return *this; } command_builder & command_builder::operator<<(output_file const & file) & { buffer_ << " -o " << file.get(); return *this; } template command_builder & command_builder::operator<<(std::vector const & value) & { for (T const & v : value) { (*this) << v; } return *this; } std::ostream & operator<<(std::ostream & os, indent_t const & value) { for (int i = 0; i < value.value; ++i) { os << " "; } return os; } int command_builder::execute() const { std::string cmdstr = buffer_.str(); std::cout << indent_ << cmdstr << std::endl; return std::system(cmdstr.c_str()); } }