diff options
Diffstat (limited to 'Source/cmQtAutoGenerator.cxx')
-rw-r--r-- | Source/cmQtAutoGenerator.cxx | 613 |
1 files changed, 108 insertions, 505 deletions
diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx index e2d7deb..e1c435b 100644 --- a/Source/cmQtAutoGenerator.cxx +++ b/Source/cmQtAutoGenerator.cxx @@ -14,10 +14,33 @@ #include "cmSystemTools.h" #include "cmake.h" -#include <algorithm> -#include <utility> +cmQtAutoGenerator::Logger::Logger() +{ + // Initialize logger + { + std::string verbose; + if (cmSystemTools::GetEnv("VERBOSE", verbose) && !verbose.empty()) { + unsigned long iVerbose = 0; + if (cmSystemTools::StringToULong(verbose.c_str(), &iVerbose)) { + SetVerbosity(static_cast<unsigned int>(iVerbose)); + } else { + // Non numeric verbosity + SetVerbose(cmSystemTools::IsOn(verbose)); + } + } + } + { + std::string colorEnv; + cmSystemTools::GetEnv("COLOR", colorEnv); + if (!colorEnv.empty()) { + SetColorOutput(cmSystemTools::IsOn(colorEnv)); + } else { + SetColorOutput(true); + } + } +} -// -- Class methods +cmQtAutoGenerator::Logger::~Logger() = default; void cmQtAutoGenerator::Logger::RaiseVerbosity(std::string const& value) { @@ -43,8 +66,8 @@ std::string cmQtAutoGenerator::Logger::HeadLine(std::string const& title) return head; } -void cmQtAutoGenerator::Logger::Info(GeneratorT genType, - std::string const& message) +void cmQtAutoGenerator::Logger::Info(GenT genType, + std::string const& message) const { std::string msg = GeneratorName(genType); msg += ": "; @@ -58,8 +81,8 @@ void cmQtAutoGenerator::Logger::Info(GeneratorT genType, } } -void cmQtAutoGenerator::Logger::Warning(GeneratorT genType, - std::string const& message) +void cmQtAutoGenerator::Logger::Warning(GenT genType, + std::string const& message) const { std::string msg; if (message.find('\n') == std::string::npos) { @@ -82,9 +105,9 @@ void cmQtAutoGenerator::Logger::Warning(GeneratorT genType, } } -void cmQtAutoGenerator::Logger::WarningFile(GeneratorT genType, +void cmQtAutoGenerator::Logger::WarningFile(GenT genType, std::string const& filename, - std::string const& message) + std::string const& message) const { std::string msg = " "; msg += Quoted(filename); @@ -94,8 +117,8 @@ void cmQtAutoGenerator::Logger::WarningFile(GeneratorT genType, Warning(genType, msg); } -void cmQtAutoGenerator::Logger::Error(GeneratorT genType, - std::string const& message) +void cmQtAutoGenerator::Logger::Error(GenT genType, + std::string const& message) const { std::string msg; msg += HeadLine(GeneratorName(genType) + " error"); @@ -111,9 +134,9 @@ void cmQtAutoGenerator::Logger::Error(GeneratorT genType, } } -void cmQtAutoGenerator::Logger::ErrorFile(GeneratorT genType, +void cmQtAutoGenerator::Logger::ErrorFile(GenT genType, std::string const& filename, - std::string const& message) + std::string const& message) const { std::string emsg = " "; emsg += Quoted(filename); @@ -124,8 +147,8 @@ void cmQtAutoGenerator::Logger::ErrorFile(GeneratorT genType, } void cmQtAutoGenerator::Logger::ErrorCommand( - GeneratorT genType, std::string const& message, - std::vector<std::string> const& command, std::string const& output) + GenT genType, std::string const& message, + std::vector<std::string> const& command, std::string const& output) const { std::string msg; msg.push_back('\n'); @@ -153,528 +176,101 @@ void cmQtAutoGenerator::Logger::ErrorCommand( } } -std::string cmQtAutoGenerator::FileSystem::GetRealPath( - std::string const& filename) -{ - std::lock_guard<std::mutex> lock(Mutex_); - return cmSystemTools::GetRealPath(filename); -} - -std::string cmQtAutoGenerator::FileSystem::CollapseCombinedPath( - std::string const& dir, std::string const& file) -{ - std::lock_guard<std::mutex> lock(Mutex_); - return cmSystemTools::CollapseCombinedPath(dir, file); -} - -void cmQtAutoGenerator::FileSystem::SplitPath( - const std::string& p, std::vector<std::string>& components, - bool expand_home_dir) -{ - std::lock_guard<std::mutex> lock(Mutex_); - cmSystemTools::SplitPath(p, components, expand_home_dir); -} - -std::string cmQtAutoGenerator::FileSystem::JoinPath( - const std::vector<std::string>& components) -{ - std::lock_guard<std::mutex> lock(Mutex_); - return cmSystemTools::JoinPath(components); -} - -std::string cmQtAutoGenerator::FileSystem::JoinPath( - std::vector<std::string>::const_iterator first, - std::vector<std::string>::const_iterator last) -{ - std::lock_guard<std::mutex> lock(Mutex_); - return cmSystemTools::JoinPath(first, last); -} - -std::string cmQtAutoGenerator::FileSystem::GetFilenameWithoutLastExtension( - const std::string& filename) -{ - std::lock_guard<std::mutex> lock(Mutex_); - return cmSystemTools::GetFilenameWithoutLastExtension(filename); -} - -std::string cmQtAutoGenerator::FileSystem::SubDirPrefix( - std::string const& filename) -{ - std::lock_guard<std::mutex> lock(Mutex_); - return cmQtAutoGen::SubDirPrefix(filename); -} - -void cmQtAutoGenerator::FileSystem::setupFilePathChecksum( - std::string const& currentSrcDir, std::string const& currentBinDir, - std::string const& projectSrcDir, std::string const& projectBinDir) -{ - std::lock_guard<std::mutex> lock(Mutex_); - FilePathChecksum_.setupParentDirs(currentSrcDir, currentBinDir, - projectSrcDir, projectBinDir); -} - -std::string cmQtAutoGenerator::FileSystem::GetFilePathChecksum( - std::string const& filename) -{ - std::lock_guard<std::mutex> lock(Mutex_); - return FilePathChecksum_.getPart(filename); -} - -bool cmQtAutoGenerator::FileSystem::FileExists(std::string const& filename) -{ - std::lock_guard<std::mutex> lock(Mutex_); - return cmSystemTools::FileExists(filename); -} - -bool cmQtAutoGenerator::FileSystem::FileExists(std::string const& filename, - bool isFile) -{ - std::lock_guard<std::mutex> lock(Mutex_); - return cmSystemTools::FileExists(filename, isFile); -} - -unsigned long cmQtAutoGenerator::FileSystem::FileLength( - std::string const& filename) -{ - std::lock_guard<std::mutex> lock(Mutex_); - return cmSystemTools::FileLength(filename); -} - -bool cmQtAutoGenerator::FileSystem::FileIsOlderThan( - std::string const& buildFile, std::string const& sourceFile, - std::string* error) -{ - bool res(false); - int result = 0; - { - std::lock_guard<std::mutex> lock(Mutex_); - res = cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result); - } - if (res) { - res = (result < 0); - } else { - if (error != nullptr) { - error->append( - "File modification time comparison failed for the files\n "); - error->append(Quoted(buildFile)); - error->append("\nand\n "); - error->append(Quoted(sourceFile)); - } - } - return res; -} - -bool cmQtAutoGenerator::FileSystem::FileRead(std::string& content, - std::string const& filename, - std::string* error) -{ - bool success = false; - if (FileExists(filename, true)) { - unsigned long const length = FileLength(filename); - { - std::lock_guard<std::mutex> lock(Mutex_); - cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary)); - if (ifs) { - content.reserve(length); - content.assign(std::istreambuf_iterator<char>{ ifs }, - std::istreambuf_iterator<char>{}); - if (ifs) { - success = true; - } else { - content.clear(); - if (error != nullptr) { - error->append("Reading from the file failed."); - } - } - } else if (error != nullptr) { - error->append("Opening the file for reading failed."); - } - } - } else if (error != nullptr) { - error->append( - "The file does not exist, is not readable or is a directory."); - } - return success; -} - -bool cmQtAutoGenerator::FileSystem::FileRead(GeneratorT genType, - std::string& content, - std::string const& filename) -{ - std::string error; - if (!FileRead(content, filename, &error)) { - Log()->ErrorFile(genType, filename, error); - return false; - } - return true; -} - -bool cmQtAutoGenerator::FileSystem::FileWrite(std::string const& filename, - std::string const& content, - std::string* error) -{ - bool success = false; - // Make sure the parent directory exists - if (MakeParentDirectory(filename)) { - std::lock_guard<std::mutex> lock(Mutex_); - cmsys::ofstream outfile; - outfile.open(filename.c_str(), - (std::ios::out | std::ios::binary | std::ios::trunc)); - if (outfile) { - outfile << content; - // Check for write errors - if (outfile.good()) { - success = true; - } else { - if (error != nullptr) { - error->assign("File writing failed"); - } - } - } else { - if (error != nullptr) { - error->assign("Opening file for writing failed"); - } - } - } else { - if (error != nullptr) { - error->assign("Could not create parent directory"); - } - } - return success; -} - -bool cmQtAutoGenerator::FileSystem::FileWrite(GeneratorT genType, - std::string const& filename, - std::string const& content) -{ - std::string error; - if (!FileWrite(filename, content, &error)) { - Log()->ErrorFile(genType, filename, error); - return false; - } - return true; -} - -bool cmQtAutoGenerator::FileSystem::FileDiffers(std::string const& filename, - std::string const& content) -{ - bool differs = true; - { - std::string oldContents; - if (FileRead(oldContents, filename)) { - differs = (oldContents != content); - } - } - return differs; -} - -bool cmQtAutoGenerator::FileSystem::FileRemove(std::string const& filename) -{ - std::lock_guard<std::mutex> lock(Mutex_); - return cmSystemTools::RemoveFile(filename); -} - -bool cmQtAutoGenerator::FileSystem::Touch(std::string const& filename, - bool create) -{ - std::lock_guard<std::mutex> lock(Mutex_); - return cmSystemTools::Touch(filename, create); -} - -bool cmQtAutoGenerator::FileSystem::MakeDirectory(std::string const& dirname) -{ - std::lock_guard<std::mutex> lock(Mutex_); - return cmSystemTools::MakeDirectory(dirname); -} - -bool cmQtAutoGenerator::FileSystem::MakeDirectory(GeneratorT genType, - std::string const& dirname) -{ - if (!MakeDirectory(dirname)) { - Log()->ErrorFile(genType, dirname, "Could not create directory"); - return false; - } - return true; -} - -bool cmQtAutoGenerator::FileSystem::MakeParentDirectory( - std::string const& filename) +bool cmQtAutoGenerator::MakeParentDirectory(std::string const& filename) { bool success = true; std::string const dirName = cmSystemTools::GetFilenamePath(filename); if (!dirName.empty()) { - success = MakeDirectory(dirName); + success = cmSystemTools::MakeDirectory(dirName); } return success; } -bool cmQtAutoGenerator::FileSystem::MakeParentDirectory( - GeneratorT genType, std::string const& filename) +bool cmQtAutoGenerator::FileRead(std::string& content, + std::string const& filename, + std::string* error) { - if (!MakeParentDirectory(filename)) { - Log()->ErrorFile(genType, filename, "Could not create parent directory"); + content.clear(); + if (!cmSystemTools::FileExists(filename, true)) { + if (error != nullptr) { + *error = "Not a file."; + } return false; } - return true; -} -int cmQtAutoGenerator::ReadOnlyProcessT::PipeT::init(uv_loop_t* uv_loop, - ReadOnlyProcessT* process) -{ - Process_ = process; - Target_ = nullptr; - return UVPipe_.init(*uv_loop, 0, this); -} - -int cmQtAutoGenerator::ReadOnlyProcessT::PipeT::startRead(std::string* target) -{ - Target_ = target; - return uv_read_start(uv_stream(), &PipeT::UVAlloc, &PipeT::UVData); -} + unsigned long const length = cmSystemTools::FileLength(filename); + cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary)); -void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::reset() -{ - Process_ = nullptr; - Target_ = nullptr; - UVPipe_.reset(); - Buffer_.clear(); - Buffer_.shrink_to_fit(); -} - -void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::UVAlloc(uv_handle_t* handle, - size_t suggestedSize, - uv_buf_t* buf) -{ - auto& pipe = *reinterpret_cast<PipeT*>(handle->data); - pipe.Buffer_.resize(suggestedSize); - buf->base = &pipe.Buffer_.front(); - buf->len = pipe.Buffer_.size(); -} - -void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::UVData(uv_stream_t* stream, - ssize_t nread, - const uv_buf_t* buf) -{ - auto& pipe = *reinterpret_cast<PipeT*>(stream->data); - if (nread > 0) { - // Append data to merged output - if ((buf->base != nullptr) && (pipe.Target_ != nullptr)) { - pipe.Target_->append(buf->base, nread); + // Use lambda to save destructor calls of ifs + return [&ifs, length, &content, error]() -> bool { + if (!ifs) { + if (error != nullptr) { + *error = "Opening the file for reading failed."; + } + return false; } - } else if (nread < 0) { - // EOF or error - auto* proc = pipe.Process_; - // Check it this an unusual error - if (nread != UV_EOF) { - if (!proc->Result()->error()) { - proc->Result()->ErrorMessage = - "libuv reading from pipe failed with error code "; - proc->Result()->ErrorMessage += std::to_string(nread); + content.reserve(length); + typedef std::istreambuf_iterator<char> IsIt; + content.assign(IsIt{ ifs }, IsIt{}); + if (!ifs) { + content.clear(); + if (error != nullptr) { + *error = "Reading from the file failed."; } + return false; } - // Clear libuv pipe handle and try to finish - pipe.reset(); - proc->UVTryFinish(); - } -} - -void cmQtAutoGenerator::ProcessResultT::reset() -{ - ExitStatus = 0; - TermSignal = 0; - if (!StdOut.empty()) { - StdOut.clear(); - StdOut.shrink_to_fit(); - } - if (!StdErr.empty()) { - StdErr.clear(); - StdErr.shrink_to_fit(); - } - if (!ErrorMessage.empty()) { - ErrorMessage.clear(); - ErrorMessage.shrink_to_fit(); - } + return true; + }(); } -void cmQtAutoGenerator::ReadOnlyProcessT::setup( - ProcessResultT* result, bool mergedOutput, - std::vector<std::string> const& command, std::string const& workingDirectory) +bool cmQtAutoGenerator::FileWrite(std::string const& filename, + std::string const& content, + std::string* error) { - Setup_.WorkingDirectory = workingDirectory; - Setup_.Command = command; - Setup_.Result = result; - Setup_.MergedOutput = mergedOutput; -} - -bool cmQtAutoGenerator::ReadOnlyProcessT::start( - uv_loop_t* uv_loop, std::function<void()>&& finishedCallback) -{ - if (IsStarted() || (Result() == nullptr)) { - return false; - } - - // Reset result before the start - Result()->reset(); - - // Fill command string pointers - if (!Setup().Command.empty()) { - CommandPtr_.reserve(Setup().Command.size() + 1); - for (std::string const& arg : Setup().Command) { - CommandPtr_.push_back(arg.c_str()); - } - CommandPtr_.push_back(nullptr); - } else { - Result()->ErrorMessage = "Empty command"; - } - - if (!Result()->error()) { - if (UVPipeOut_.init(uv_loop, this) != 0) { - Result()->ErrorMessage = "libuv stdout pipe initialization failed"; - } - } - if (!Result()->error()) { - if (UVPipeErr_.init(uv_loop, this) != 0) { - Result()->ErrorMessage = "libuv stderr pipe initialization failed"; - } - } - if (!Result()->error()) { - // -- Setup process stdio options - // stdin - UVOptionsStdIO_[0].flags = UV_IGNORE; - UVOptionsStdIO_[0].data.stream = nullptr; - // stdout - UVOptionsStdIO_[1].flags = - static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE); - UVOptionsStdIO_[1].data.stream = UVPipeOut_.uv_stream(); - // stderr - UVOptionsStdIO_[2].flags = - static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE); - UVOptionsStdIO_[2].data.stream = UVPipeErr_.uv_stream(); - - // -- Setup process options - std::fill_n(reinterpret_cast<char*>(&UVOptions_), sizeof(UVOptions_), 0); - UVOptions_.exit_cb = &ReadOnlyProcessT::UVExit; - UVOptions_.file = CommandPtr_[0]; - UVOptions_.args = const_cast<char**>(&CommandPtr_.front()); - UVOptions_.cwd = Setup_.WorkingDirectory.c_str(); - UVOptions_.flags = UV_PROCESS_WINDOWS_HIDE; - UVOptions_.stdio_count = static_cast<int>(UVOptionsStdIO_.size()); - UVOptions_.stdio = &UVOptionsStdIO_.front(); - - // -- Spawn process - if (UVProcess_.spawn(*uv_loop, UVOptions_, this) != 0) { - Result()->ErrorMessage = "libuv process spawn failed"; - } - } - // -- Start reading from stdio streams - if (!Result()->error()) { - if (UVPipeOut_.startRead(&Result()->StdOut) != 0) { - Result()->ErrorMessage = "libuv start reading from stdout pipe failed"; - } - } - if (!Result()->error()) { - if (UVPipeErr_.startRead(Setup_.MergedOutput ? &Result()->StdOut - : &Result()->StdErr) != 0) { - Result()->ErrorMessage = "libuv start reading from stderr pipe failed"; + // Make sure the parent directory exists + if (!cmQtAutoGenerator::MakeParentDirectory(filename)) { + if (error != nullptr) { + *error = "Could not create parent directory."; } + return false; } + cmsys::ofstream ofs; + ofs.open(filename.c_str(), + (std::ios::out | std::ios::binary | std::ios::trunc)); - if (!Result()->error()) { - IsStarted_ = true; - FinishedCallback_ = std::move(finishedCallback); - } else { - // Clear libuv handles and finish - UVProcess_.reset(); - UVPipeOut_.reset(); - UVPipeErr_.reset(); - CommandPtr_.clear(); - } - - return IsStarted(); -} - -void cmQtAutoGenerator::ReadOnlyProcessT::UVExit(uv_process_t* handle, - int64_t exitStatus, - int termSignal) -{ - auto& proc = *reinterpret_cast<ReadOnlyProcessT*>(handle->data); - if (proc.IsStarted() && !proc.IsFinished()) { - // Set error message on demand - proc.Result()->ExitStatus = exitStatus; - proc.Result()->TermSignal = termSignal; - if (!proc.Result()->error()) { - if (termSignal != 0) { - proc.Result()->ErrorMessage = "Process was terminated by signal "; - proc.Result()->ErrorMessage += - std::to_string(proc.Result()->TermSignal); - } else if (exitStatus != 0) { - proc.Result()->ErrorMessage = "Process failed with return value "; - proc.Result()->ErrorMessage += - std::to_string(proc.Result()->ExitStatus); + // Use lambda to save destructor calls of ofs + return [&ofs, &content, error]() -> bool { + if (!ofs) { + if (error != nullptr) { + *error = "Opening file for writing failed."; } + return false; } - - // Reset process handle and try to finish - proc.UVProcess_.reset(); - proc.UVTryFinish(); - } -} - -void cmQtAutoGenerator::ReadOnlyProcessT::UVTryFinish() -{ - // There still might be data in the pipes after the process has finished. - // Therefore check if the process is finished AND all pipes are closed - // before signaling the worker thread to continue. - if (UVProcess_.get() == nullptr) { - if (UVPipeOut_.uv_pipe() == nullptr) { - if (UVPipeErr_.uv_pipe() == nullptr) { - IsFinished_ = true; - FinishedCallback_(); + ofs << content; + if (!ofs.good()) { + if (error != nullptr) { + *error = "File writing failed."; } + return false; } - } + return true; + }(); } -cmQtAutoGenerator::cmQtAutoGenerator() - : FileSys_(&Logger_) +bool cmQtAutoGenerator::FileDiffers(std::string const& filename, + std::string const& content) { - // Initialize logger - { - std::string verbose; - if (cmSystemTools::GetEnv("VERBOSE", verbose) && !verbose.empty()) { - unsigned long iVerbose = 0; - if (cmSystemTools::StringToULong(verbose.c_str(), &iVerbose)) { - Logger_.SetVerbosity(static_cast<unsigned int>(iVerbose)); - } else { - // Non numeric verbosity - Logger_.SetVerbose(cmSystemTools::IsOn(verbose)); - } - } - } - { - std::string colorEnv; - cmSystemTools::GetEnv("COLOR", colorEnv); - if (!colorEnv.empty()) { - Logger_.SetColorOutput(cmSystemTools::IsOn(colorEnv)); - } else { - Logger_.SetColorOutput(true); - } + bool differs = true; + std::string oldContents; + if (FileRead(oldContents, filename) && (oldContents == content)) { + differs = false; } - - // Initialize libuv loop - uv_disable_stdio_inheritance(); -#ifdef CMAKE_UV_SIGNAL_HACK - UVHackRAII_ = cm::make_unique<cmUVSignalHackRAII>(); -#endif - UVLoop_ = cm::make_unique<uv_loop_t>(); - uv_loop_init(UVLoop()); + return differs; } -cmQtAutoGenerator::~cmQtAutoGenerator() -{ - // Close libuv loop - uv_loop_close(UVLoop()); -} +cmQtAutoGenerator::cmQtAutoGenerator() = default; + +cmQtAutoGenerator::~cmQtAutoGenerator() = default; bool cmQtAutoGenerator::Run(std::string const& infoFile, std::string const& config) @@ -682,6 +278,13 @@ bool cmQtAutoGenerator::Run(std::string const& infoFile, // Info settings InfoFile_ = infoFile; cmSystemTools::ConvertToUnixSlashes(InfoFile_); + if (!InfoFileTime_.Load(InfoFile_)) { + std::string msg = "AutoGen: The info file "; + msg += Quoted(InfoFile_); + msg += " is not readable\n"; + cmSystemTools::Stderr(msg); + return false; + } InfoDir_ = cmSystemTools::GetFilenamePath(infoFile); InfoConfig_ = config; |