X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FVCBackend.cpp;h=ca603c9e1f8ed89c1c3ea9cd35ed045815485c41;hb=fd5adacef25eb40f813dedd961920c353448213a;hp=2235c073f41e35527b7d3617034b61f5fbdae268;hpb=ac4cca6ed46754ef73109a9ab8eb1c714f111d49;p=features.git diff --git a/src/VCBackend.cpp b/src/VCBackend.cpp index 2235c073f4..ca603c9e1f 100644 --- a/src/VCBackend.cpp +++ b/src/VCBackend.cpp @@ -13,7 +13,6 @@ #include "VCBackend.h" #include "Buffer.h" -#include "DispatchResult.h" #include "LyX.h" #include "FuncRequest.h" @@ -27,10 +26,11 @@ #include "support/lstrings.h" #include "support/PathChanger.h" #include "support/Systemcall.h" -#include "support/regex.h" #include "support/TempFile.h" #include +#include +#include #include using namespace std; @@ -58,11 +58,15 @@ int VCS::doVCCommand(string const & cmd, FileName const & path, bool reportError if (owner_) owner_->setBusy(false); - if (ret && reportError) + if (ret && reportError) { + docstring rcsmsg; + if (prefixIs(cmd, "ci ")) + rcsmsg = "\n" + _("Check whether the GNU RCS package is installed on your system."); frontend::Alert::error(_("Revision control error."), bformat(_("Some problem occurred while running the command:\n" - "'%1$s'."), + "'%1$s'.") + rcsmsg, from_utf8(cmd))); + } return ret; } @@ -101,18 +105,18 @@ bool VCS::makeRCSRevision(string const &version, string &revis) const } -bool VCS::checkparentdirs(FileName const & file, std::string const & vcsdir) +FileName VCS::checkParentDirs(FileName const & start, std::string const & file) { - FileName dirname = file.onlyPath(); + FileName dirname = start.onlyPath(); do { - FileName tocheck = FileName(addName(dirname.absFileName(), vcsdir)); + FileName tocheck = FileName(addPathName(dirname.absFileName(), file)); LYXERR(Debug::LYXVC, "check file: " << tocheck.absFileName()); if (tocheck.exists()) - return true; - //this construct because of #8295 + return tocheck; + // this construct because of #8295 dirname = FileName(dirname.absFileName()).parentPath(); } while (!dirname.empty()); - return false; + return FileName(); } @@ -157,8 +161,8 @@ bool RCS::retrieve(FileName const & file) { LYXERR(Debug::LYXVC, "LyXVC::RCS: retrieve.\n\t" << file); // The caller ensures that file does not exist, so no need to check that. - return doVCCommandCall("co -q -r " + quoteName(file.toFilesystemEncoding()), - FileName()) == 0; + int const ret = doVCCommandCall("co -q -r " + quoteName(file.toFilesystemEncoding())); + return ret == 0; } @@ -170,6 +174,8 @@ void RCS::scanMaster() LYXERR(Debug::LYXVC, "LyXVC::RCS: scanMaster: " << master_); ifstream ifs(master_.toFilesystemEncoding().c_str()); + // limit the size of strings we read to avoid memory problems + ifs >> setw(65636); string token; bool read_enough = false; @@ -195,7 +201,7 @@ void RCS::scanMaster() // get locker here if (contains(token, ';')) { locker_ = "Unlocked"; - vcstatus = UNLOCKED; + vcstatus_ = UNLOCKED; continue; } string tmpt; @@ -209,7 +215,7 @@ void RCS::scanMaster() // s2 is user, and s1 is version if (s1 == version_) { locker_ = s2; - vcstatus = LOCKED; + vcstatus_ = LOCKED; break; } } while (!contains(tmpt, ';')); @@ -284,7 +290,7 @@ LyXVC::CommandResult RCS::checkIn(string const & msg, string & log) bool RCS::checkInEnabled() { - return owner_ && !owner_->isReadonly(); + return owner_ && !owner_->hasReadonlyFlag(); } @@ -326,7 +332,7 @@ string RCS::checkOut() bool RCS::checkOutEnabled() { - return owner_ && owner_->isReadonly(); + return owner_ && owner_->hasReadonlyFlag(); } @@ -389,7 +395,7 @@ void RCS::undoLast() bool RCS::undoLastEnabled() { - return true; + return owner_->hasReadonlyFlag(); } @@ -427,7 +433,8 @@ string RCS::revisionInfo(LyXVC::RevisionInfo const info) return rev_date_cache_; case LyXVC::Time: return rev_time_cache_; - default: ; + default: + break; } return string(); @@ -531,6 +538,8 @@ FileName const CVS::findFile(FileName const & file) { // First we look for the CVS/Entries in the same dir // where we have file. + // Note that it is not necessary to search parent directories, since + // there will be a CVS/Entries file in every subdirectory. FileName const entries(onlyPath(file.absFileName()) + "/CVS/Entries"); string const tmpf = '/' + onlyFileName(file.absFileName()) + '/'; LYXERR(Debug::LYXVC, "LyXVC: Checking if file is under cvs in `" << entries @@ -556,8 +565,8 @@ void CVS::scanMaster() LYXERR(Debug::LYXVC, "LyXVC::CVS: scanMaster. \n Checking: " << master_); // Ok now we do the real scan... ifstream ifs(master_.toFilesystemEncoding().c_str()); - string name = onlyFileName(owner_->absFileName()); - string tmpf = '/' + name + '/'; + string const name = onlyFileName(owner_->absFileName()); + string const tmpf = '/' + name + '/'; LYXERR(Debug::LYXVC, "\tlooking for `" << tmpf << '\''); string line; static regex const reg("/(.*)/(.*)/(.*)/(.*)/(.*)"); @@ -566,10 +575,10 @@ void CVS::scanMaster() if (contains(line, tmpf)) { // Ok extract the fields. smatch sm; - - // false positive from coverity - // coverity[CHECKED_RETURN] - regex_match(line, sm, reg); + if (!regex_match(line, sm, reg)) { + LYXERR(Debug::LYXVC, "\t Cannot parse line. Skipping."); + continue; + } //sm[0]; // whole matched string //sm[1]; // filename @@ -580,21 +589,21 @@ void CVS::scanMaster() //sm[5]; // tag or tagdate FileName file(owner_->absFileName()); if (file.isReadableFile()) { - time_t mod = file.lastModified(); - string mod_date = rtrim(asctime(gmtime(&mod)), "\n"); + time_t const mod = file.lastModified(); + string const mod_date = rtrim(asctime(gmtime(&mod)), "\n"); LYXERR(Debug::LYXVC, "Date in Entries: `" << file_date << "'\nModification date of file: `" << mod_date << '\''); if (file.isReadOnly()) { // readonly checkout is unlocked - vcstatus = UNLOCKED; + vcstatus_ = UNLOCKED; } else { FileName bdir(addPath(master_.onlyPath().absFileName(),"Base")); FileName base(addName(bdir.absFileName(),name)); // if base version is existent "cvs edit" was used to lock - vcstatus = base.isReadableFile() ? LOCKED : NOLOCKING; + vcstatus_ = base.isReadableFile() ? LOCKED : NOLOCKING; } } else { - vcstatus = NOLOCKING; + vcstatus_ = NOLOCKING; } break; } @@ -730,12 +739,14 @@ void CVS::getRevisionInfo() LYXERR(Debug::LYXVC, line << '\n'); if (prefixIs(line, "date:")) { smatch sm; - regex_match(line, sm, reg); - //sm[0]; // whole matched string - rev_date_cache_ = sm[1]; - rev_time_cache_ = sm[2]; - //sm[3]; // GMT offset - rev_author_cache_ = sm[4]; + if (regex_match(line, sm, reg)) { + //sm[0]; // whole matched string + rev_date_cache_ = sm[1]; + rev_time_cache_ = sm[2]; + //sm[3]; // GMT offset + rev_author_cache_ = sm[4]; + } else + LYXERR(Debug::LYXVC, "\tCannot parse line. Skipping."); break; } } @@ -802,7 +813,7 @@ void CVS::getDiff(OperationMode opmode, FileName const & tmpf) int CVS::edit() { - vcstatus = LOCKED; + vcstatus_ = LOCKED; return doVCCommand("cvs -q edit " + getTarget(File), FileName(owner_->filePath())); } @@ -810,7 +821,7 @@ int CVS::edit() int CVS::unedit() { - vcstatus = UNLOCKED; + vcstatus_ = UNLOCKED; return doVCCommand("cvs -q unedit " + getTarget(File), FileName(owner_->filePath())); } @@ -849,7 +860,7 @@ LyXVC::CommandResult CVS::checkIn(string const & msg, string & log) CvsStatus status = getStatus(); switch (status) { case UpToDate: - if (vcstatus != NOLOCKING) + if (vcstatus_ != NOLOCKING) if (unedit()) return LyXVC::ErrorCommand; log = "CVS: Proceeded"; @@ -891,7 +902,7 @@ bool CVS::isLocked() const bool CVS::checkInEnabled() { - if (vcstatus != NOLOCKING) + if (vcstatus_ != NOLOCKING) return isLocked(); else return true; @@ -907,7 +918,7 @@ bool CVS::isCheckInWithConfirmation() string CVS::checkOut() { - if (vcstatus != NOLOCKING && edit()) + if (vcstatus_ != NOLOCKING && edit()) return string(); TempFile tempfile("lyxvout"); FileName tmpf = tempfile.name(); @@ -934,7 +945,7 @@ string CVS::checkOut() bool CVS::checkOutEnabled() { - if (vcstatus != NOLOCKING) + if (vcstatus_ != NOLOCKING) return !isLocked(); else return true; @@ -965,7 +976,7 @@ string CVS::repoUpdate() dispatch(FuncRequest(LFUN_DIALOG_SHOW, "file " + tmpf.absFileName())); ret = frontend::Alert::prompt(_("Changes detected"), text, 0, 1, _("&Continue"), _("&Abort")); - hideDialogs("file", 0); + hideDialogs("file", nullptr); } if (ret == 1) return string(); @@ -1024,7 +1035,7 @@ bool CVS::revert() CvsStatus status = getStatus(); switch (status) { case UpToDate: - if (vcstatus != NOLOCKING) + if (vcstatus_ != NOLOCKING) return 0 == unedit(); break; case NeedsMerge: @@ -1099,7 +1110,8 @@ string CVS::revisionInfo(LyXVC::RevisionInfo const info) return rev_date_cache_; case LyXVC::Time: return rev_time_cache_; - default: ; + default: + break; } } return string(); @@ -1144,39 +1156,30 @@ bool CVS::prepareFileRevisionEnabled() // ///////////////////////////////////////////////////////////////////// -SVN::SVN(FileName const & m, Buffer * b) : VCS(b) +SVN::SVN(Buffer * b) : VCS(b) { // Here we know that the buffer file is either already in SVN or // about to be registered - master_ = m; - locked_mode_ = 0; + locked_mode_ = false; scanMaster(); } -FileName const SVN::findFile(FileName const & file) +bool SVN::findFile(FileName const & file) { // First we check the existence of repository meta data. - if (!VCS::checkparentdirs(file, ".svn")) { + if (VCS::checkParentDirs(file, ".svn").empty()) { LYXERR(Debug::LYXVC, "Cannot find SVN meta data for " << file); - return FileName(); + return false; } // Now we check the status of the file. - TempFile tempfile("lyxvcout"); - FileName tmpf = tempfile.name(); - if (tmpf.empty()) { - LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); - return FileName(); - } - string const fname = onlyFileName(file.absFileName()); LYXERR(Debug::LYXVC, "LyXVC: Checking if file is under svn control for `" << fname << '\''); - bool found = 0 == doVCCommandCall("svn info " + quoteName(fname) - + " > " + quoteName(tmpf.toFilesystemEncoding()), + bool found = 0 == doVCCommandCall("svn info " + quoteName(fname), file.onlyPath()); LYXERR(Debug::LYXVC, "SVN control: " << (found ? "enabled" : "disabled")); - return found ? file : FileName(); + return found; } @@ -1184,13 +1187,9 @@ void SVN::scanMaster() { // vcstatus code is somewhat superflous, // until we want to implement read-only toggle for svn. - vcstatus = NOLOCKING; - if (checkLockMode()) { - if (isLocked()) - vcstatus = LOCKED; - else - vcstatus = UNLOCKED; - } + vcstatus_ = NOLOCKING; + if (checkLockMode()) + vcstatus_ = isLocked() ? LOCKED : UNLOCKED; } @@ -1246,7 +1245,7 @@ bool SVN::retrieve(FileName const & file) void SVN::registrer(string const & /*msg*/) { - doVCCommand("svn add -q " + quoteName(onlyFileName(owner_->absFileName())), + doVCCommand("svn add -q --parents " + quoteName(onlyFileName(owner_->absFileName())), FileName(owner_->filePath())); } @@ -1435,7 +1434,7 @@ bool SVN::fileLock(bool lock, FileName const & tmpf, string &status) + " > " + quoteName(tmpf.toFilesystemEncoding()), FileName(owner_->filePath())); - // Lock error messages go unfortunately on stderr and are unreachible this way. + // Lock error messages go unfortunately on stderr and are unreachable this way. ifstream ifs(tmpf.toFilesystemEncoding().c_str()); string line; while (ifs) { @@ -1525,7 +1524,7 @@ string SVN::repoUpdate() dispatch(FuncRequest(LFUN_DIALOG_SHOW, "file " + tmpf.absFileName())); ret = frontend::Alert::prompt(_("Changes detected"), text, 0, 1, _("&Yes"), _("&No")); - hideDialogs("file", 0); + hideDialogs("file", nullptr); } if (ret == 1) return string(); @@ -1663,8 +1662,8 @@ string SVN::revisionInfo(LyXVC::RevisionInfo const info) return rev_date_cache_; case LyXVC::Time: return rev_time_cache_; - default: ; - + default: + break; } return string(); @@ -1817,21 +1816,20 @@ bool SVN::toggleReadOnlyEnabled() // ///////////////////////////////////////////////////////////////////// -GIT::GIT(FileName const & m, Buffer * b) : VCS(b) +GIT::GIT(Buffer * b) : VCS(b) { // Here we know that the buffer file is either already in GIT or // about to be registered - master_ = m; scanMaster(); } -FileName const GIT::findFile(FileName const & file) +bool GIT::findFile(FileName const & file) { // First we check the existence of repository meta data. - if (!VCS::checkparentdirs(file, ".git")) { + if (VCS::checkParentDirs(file, ".git").empty()) { LYXERR(Debug::LYXVC, "Cannot find GIT meta data for " << file); - return FileName(); + return false; } // Now we check the status of the file. @@ -1839,7 +1837,7 @@ FileName const GIT::findFile(FileName const & file) FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); - return FileName(); + return false; } string const fname = onlyFileName(file.absFileName()); @@ -1852,7 +1850,7 @@ FileName const GIT::findFile(FileName const & file) tmpf.refresh(); bool found = !tmpf.isFileEmpty(); LYXERR(Debug::LYXVC, "GIT control: " << (found ? "enabled" : "disabled")); - return found ? file : FileName(); + return found; } @@ -1860,7 +1858,7 @@ void GIT::scanMaster() { // vcstatus code is somewhat superflous, // until we want to implement read-only toggle for git. - vcstatus = NOLOCKING; + vcstatus_ = NOLOCKING; } @@ -2118,22 +2116,28 @@ string GIT::revisionInfo(LyXVC::RevisionInfo const info) // fill the rest of the attributes for a single file if (rev_file_cache_.empty()) - if (!getFileRevisionInfo()) + if (!getFileRevisionInfo()) { rev_file_cache_ = "?"; + rev_file_abbrev_cache_ = "?"; + } switch (info) { case LyXVC::File: if (rev_file_cache_ == "?") return string(); return rev_file_cache_; + case LyXVC::FileAbbrev: + if (rev_file_abbrev_cache_ == "?") + return string(); + return rev_file_abbrev_cache_; case LyXVC::Author: return rev_author_cache_; case LyXVC::Date: return rev_date_cache_; case LyXVC::Time: return rev_time_cache_; - default: ; - + default: + break; } return string(); @@ -2149,7 +2153,7 @@ bool GIT::getFileRevisionInfo() return false; } - doVCCommand("git log -n 1 --pretty=format:%H%n%an%n%ai " + quoteName(onlyFileName(owner_->absFileName())) + doVCCommand("git log -n 1 --pretty=format:%H%n%h%n%an%n%ai " + quoteName(onlyFileName(owner_->absFileName())) + " > " + quoteName(tmpf.toFilesystemEncoding()), FileName(owner_->filePath())); @@ -2160,6 +2164,8 @@ bool GIT::getFileRevisionInfo() if (ifs) getline(ifs, rev_file_cache_); + if (ifs) + getline(ifs, rev_file_abbrev_cache_); if (ifs) getline(ifs, rev_author_cache_); if (ifs) { @@ -2183,7 +2189,8 @@ bool GIT::getTreeRevisionInfo() } doVCCommand("git describe --abbrev --dirty --long > " + quoteName(tmpf.toFilesystemEncoding()), - FileName(owner_->filePath())); + FileName(owner_->filePath()), + false); //git describe returns $?=128 when no tag found (but git repo still exists) if (tmpf.empty()) return false;