X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FVCBackend.cpp;h=96b71d81ea32480fcd5c727a051264d1f22bc5ea;hb=4db3e641ed6765e005343010cb90ee8af26f8f99;hp=a6ce1c36f9554c816473fe596a5a45fdb6341138;hpb=2f9ef2b98a6170d4c890ce3325ddc3ad9105bbad;p=lyx.git diff --git a/src/VCBackend.cpp b/src/VCBackend.cpp index a6ce1c36f9..96b71d81ea 100644 --- a/src/VCBackend.cpp +++ b/src/VCBackend.cpp @@ -34,7 +34,6 @@ using namespace std; using namespace lyx::support; - namespace lyx { @@ -68,7 +67,7 @@ int VCS::doVCCommand(string const & cmd, FileName const & path, bool reportError bool VCS::makeRCSRevision(string const &version, string &revis) const { string rev = revis; - + if (isStrInt(rev)) { int back = convert(rev); // if positive use as the last number in the whole revision string @@ -99,23 +98,21 @@ bool VCS::makeRCSRevision(string const &version, string &revis) const } -bool VCS::checkparentdirs(FileName const & file, std::string const & pathname) +bool VCS::checkparentdirs(FileName const & file, std::string const & vcsdir) { FileName dirname = file.onlyPath(); - FileName tocheck = FileName(addName(dirname.absFileName(),pathname)); - LYXERR(Debug::LYXVC, "check file: " << tocheck.absFileName()); - bool result = tocheck.exists(); - while ( !result && !dirname.empty() ) { + do { + FileName tocheck = FileName(addName(dirname.absFileName(), vcsdir)); + LYXERR(Debug::LYXVC, "check file: " << tocheck.absFileName()); + if (tocheck.exists()) + return true; //this construct because of #8295 dirname = FileName(dirname.absFileName()).parentPath(); - LYXERR(Debug::LYXVC, "check directory: " << dirname.absFileName()); - tocheck = FileName(addName(dirname.absFileName(),pathname)); - result = tocheck.exists(); - } - return result; + } while (!dirname.empty()); + return false; } - + ///////////////////////////////////////////////////////////////////// // // RCS @@ -124,6 +121,8 @@ bool VCS::checkparentdirs(FileName const & file, std::string const & pathname) RCS::RCS(FileName const & m, Buffer * b) : VCS(b) { + // Here we know that the buffer file is either already in RCS or + // about to be registered master_ = m; scanMaster(); } @@ -276,7 +275,7 @@ LyXVC::CommandResult RCS::checkIn(string const & msg, string & log) if (ret) return LyXVC::ErrorCommand; log = "RCS: Proceeded"; - return LyXVC::Success; + return LyXVC::VCSuccess; } @@ -404,7 +403,7 @@ bool RCS::toggleReadOnlyEnabled() // This got broken somewhere along lfuns dispatch reorganization. // reloadBuffer would be needed after this, but thats problematic // since we are inside Buffer::dispatch. - // return return status() != UNVERSIONED; + // return true; return false; } @@ -513,6 +512,8 @@ bool RCS::prepareFileRevisionEnabled() CVS::CVS(FileName const & m, Buffer * b) : VCS(b) { + // Here we know that the buffer file is either already in CVS or + // about to be registered master_ = m; have_rev_info_ = false; scanMaster(); @@ -553,7 +554,6 @@ void CVS::scanMaster() LYXERR(Debug::LYXVC, "\tlooking for `" << tmpf << '\''); string line; static regex const reg("/(.*)/(.*)/(.*)/(.*)/(.*)"); - vcstatus = UNVERSIONED; while (getline(ifs, line)) { LYXERR(Debug::LYXVC, "\t line: " << line); if (contains(line, tmpf)) { @@ -846,7 +846,7 @@ LyXVC::CommandResult CVS::checkIn(string const & msg, string & log) if (unedit()) return LyXVC::ErrorCommand; log = "CVS: Proceeded"; - return LyXVC::Success; + return LyXVC::VCSuccess; case LocallyModified: case LocallyAdded: { int rc = doVCCommand("cvs -q commit -m \"" + msg + "\" " @@ -855,7 +855,7 @@ LyXVC::CommandResult CVS::checkIn(string const & msg, string & log) if (rc) return LyXVC::ErrorCommand; log = "CVS: Proceeded"; - return LyXVC::Success; + return LyXVC::VCSuccess; } case NeedsMerge: case NeedsCheckout: @@ -1139,6 +1139,8 @@ bool CVS::prepareFileRevisionEnabled() SVN::SVN(FileName const & m, 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; scanMaster(); @@ -1173,19 +1175,14 @@ FileName const SVN::findFile(FileName const & file) void SVN::scanMaster() { - // vcstatus code other than UNVERSIONED is somewhat superflous, + // vcstatus code is somewhat superflous, // until we want to implement read-only toggle for svn. - FileName f = findFile(owner_->fileName()); - if (f.empty()) { - vcstatus = UNVERSIONED; - } else { - vcstatus = NOLOCKING; - if (checkLockMode()) { - if (isLocked()) - vcstatus = LOCKED; - else - vcstatus = UNLOCKED; - } + vcstatus = NOLOCKING; + if (checkLockMode()) { + if (isLocked()) + vcstatus = LOCKED; + else + vcstatus = UNLOCKED; } } @@ -1274,7 +1271,7 @@ string SVN::rename(support::FileName const & newFile, string const & msg) f.push_back(owner_->fileName()); f.push_back(newFile); string log; - if (checkIn(f, msg, log) != LyXVC::Success) { + if (checkIn(f, msg, log) != LyXVC::VCSuccess) { cmd = "svn revert -q " + quoteName(onlyFileName(owner_->absFileName())) + ' ' + quoteName(relFile); @@ -1306,7 +1303,7 @@ string SVN::copy(support::FileName const & newFile, string const & msg) return string(); vector f(1, newFile); string log; - if (checkIn(f, msg, log) == LyXVC::Success) + if (checkIn(f, msg, log) == LyXVC::VCSuccess) return log; return string(); } @@ -1336,7 +1333,7 @@ SVN::checkIn(vector const & f, string const & msg, string & l os << " > " << quoteName(tmpf.toFilesystemEncoding()); LyXVC::CommandResult ret = doVCCommand(os.str(), FileName(owner_->filePath())) ? - LyXVC::ErrorCommand : LyXVC::Success; + LyXVC::ErrorCommand : LyXVC::VCSuccess; string res = scanLogFile(tmpf, log); if (!res.empty()) { @@ -1353,7 +1350,7 @@ SVN::checkIn(vector const & f, string const & msg, string & l tmpf.removeFile(); if (!log.empty()) log.insert(0, "SVN: "); - if (ret == LyXVC::Success && log.empty()) + if (ret == LyXVC::VCSuccess && log.empty()) log = "SVN: Proceeded"; return ret; } @@ -1813,6 +1810,8 @@ bool SVN::toggleReadOnlyEnabled() GIT::GIT(FileName const & m, Buffer * b) : VCS(b) { + // Here we know that the buffer file is either already in GIT or + // about to be registered master_ = m; scanMaster(); } @@ -1833,27 +1832,14 @@ FileName const GIT::findFile(FileName const & file) return FileName(); } - // --porcelain selects a format that is supposed to be stable across - // git versions string const fname = onlyFileName(file.absFileName()); LYXERR(Debug::LYXVC, "LyXVC: Checking if file is under git control for `" << fname << '\''); - bool found = 0 == doVCCommandCall("git status --porcelain " + - quoteName(fname) + " > " + - quoteName(tmpf.toFilesystemEncoding()), + doVCCommandCall("git ls-files " + + quoteName(fname) + " > " + + quoteName(tmpf.toFilesystemEncoding()), file.onlyPath()); - if (found) - { - // The output contains a line starting with "??" for unknown - // files, no line for known unmodified files and a line - // starting with "M" or something else for modified/deleted - // etc. files. - ifstream ifs(tmpf.toFilesystemEncoding().c_str()); - string test; - if ((ifs >> test)) - found = (test != "??"); - // else is no error - } + bool found = !tmpf.isFileEmpty(); tmpf.removeFile(); LYXERR(Debug::LYXVC, "GIT control: " << (found ? "enabled" : "disabled")); return found ? file : FileName(); @@ -1862,13 +1848,9 @@ FileName const GIT::findFile(FileName const & file) void GIT::scanMaster() { - // vcstatus code other than UNVERSIONED is somewhat superflous, + // vcstatus code is somewhat superflous, // until we want to implement read-only toggle for git. - FileName f = findFile(owner_->fileName()); - if (f.empty()) - vcstatus = UNVERSIONED; - else - vcstatus = NOLOCKING; + vcstatus = NOLOCKING; } @@ -1916,7 +1898,7 @@ string GIT::rename(support::FileName const & newFile, string const & msg) f.push_back(owner_->fileName()); f.push_back(newFile); string log; - if (checkIn(f, msg, log) != LyXVC::Success) { + if (checkIn(f, msg, log) != LyXVC::VCSuccess) { cmd = "git checkout -q " + quoteName(onlyFileName(owner_->absFileName())) + ' ' + quoteName(relFile); @@ -1966,7 +1948,7 @@ GIT::checkIn(vector const & f, string const & msg, string & l os << " > " << quoteName(tmpf.toFilesystemEncoding()); LyXVC::CommandResult ret = doVCCommand(os.str(), FileName(owner_->filePath())) ? - LyXVC::ErrorCommand : LyXVC::Success; + LyXVC::ErrorCommand : LyXVC::VCSuccess; string res = scanLogFile(tmpf, log); if (!res.empty()) { @@ -1980,7 +1962,7 @@ GIT::checkIn(vector const & f, string const & msg, string & l tmpf.removeFile(); if (!log.empty()) log.insert(0, "GIT: "); - if (ret == LyXVC::Success && log.empty()) + if (ret == LyXVC::VCSuccess && log.empty()) log = "GIT: Proceeded"; return ret; } @@ -2112,12 +2094,99 @@ bool GIT::undoLastEnabled() } -string GIT::revisionInfo(LyXVC::RevisionInfo const /*info*/) +string GIT::revisionInfo(LyXVC::RevisionInfo const info) { + if (info == LyXVC::Tree) { + if (rev_tree_cache_.empty()) + if (!getTreeRevisionInfo()) + rev_tree_cache_ = "?"; + if (rev_tree_cache_ == "?") + return string(); + + return rev_tree_cache_; + } + + // fill the rest of the attributes for a single file + if (rev_file_cache_.empty()) + if (!getFileRevisionInfo()) + rev_file_cache_ = "?"; + + switch (info) { + case LyXVC::File: + if (rev_file_cache_ == "?") + return string(); + return rev_file_cache_; + case LyXVC::Author: + return rev_author_cache_; + case LyXVC::Date: + return rev_date_cache_; + case LyXVC::Time: + return rev_time_cache_; + default: ; + + } + return string(); } +bool GIT::getFileRevisionInfo() +{ + FileName tmpf = FileName::tempName("lyxvcout"); + if (tmpf.empty()) { + LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); + return false; + } + + doVCCommand("git log -n 1 --pretty=format:%H%n%an%n%ai " + quoteName(onlyFileName(owner_->absFileName())) + + " > " + quoteName(tmpf.toFilesystemEncoding()), + FileName(owner_->filePath())); + + if (tmpf.empty()) + return false; + + ifstream ifs(tmpf.toFilesystemEncoding().c_str()); + + if (ifs) + getline(ifs, rev_file_cache_); + if (ifs) + getline(ifs, rev_author_cache_); + if (ifs) { + string line; + getline(ifs, line); + rev_time_cache_ = split(line, rev_date_cache_, ' '); + } + + ifs.close(); + tmpf.removeFile(); + return !rev_file_cache_.empty(); +} + + +bool GIT::getTreeRevisionInfo() +{ + FileName tmpf = FileName::tempName("lyxvcout"); + if (tmpf.empty()) { + LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); + return false; + } + + doVCCommand("git describe --abbrev --dirty --long > " + quoteName(tmpf.toFilesystemEncoding()), + FileName(owner_->filePath())); + + if (tmpf.empty()) + return false; + + // only first line in case something bad happens. + ifstream ifs(tmpf.toFilesystemEncoding().c_str()); + getline(ifs, rev_tree_cache_); + ifs.close(); + tmpf.removeFile(); + + return !rev_tree_cache_.empty(); +} + + void GIT::getLog(FileName const & tmpf) { doVCCommand("git log " + quoteName(onlyFileName(owner_->absFileName())) @@ -2126,15 +2195,50 @@ void GIT::getLog(FileName const & tmpf) } -bool GIT::prepareFileRevision(string const & /*revis*/, string & /*f*/) +//at this moment we don't accept revision SHA, but just number of revision steps back +//GUI and infrastucture needs to be changed first +bool GIT::prepareFileRevision(string const & revis, string & f) { - return false; + // anything positive means we got hash, not "0" or minus revision + int rev = 1; + + // hash is rarely number and should be long + if (isStrInt(revis) && revis.length()<20) + rev = convert(revis); + + // revision and filename + string pointer; + + // go back for "minus" revisions + if (rev <= 0) + pointer = "HEAD~" + convert(-rev); + // normal hash + else + pointer = revis; + + pointer += ":"; + + FileName tmpf = FileName::tempName("lyxvcrev_" + revis + "_"); + if (tmpf.empty()) { + LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); + return false; + } + + doVCCommand("git show " + pointer + "./" + + quoteName(onlyFileName(owner_->absFileName())) + + " > " + quoteName(tmpf.toFilesystemEncoding()), + FileName(owner_->filePath())); + if (tmpf.isFileEmpty()) + return false; + + f = tmpf.absFileName(); + return true; } bool GIT::prepareFileRevisionEnabled() { - return false; + return true; }