X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FVCBackend.cpp;h=421a748451923bb63b707f4c6f12601e9c08e414;hb=4594b1425b484138fcae28996f460312d810b8d5;hp=ff722f0d1976e86c6dfc0ba7e571105368ba0eb3;hpb=9fdbf7eff5a29a4a6e3161c2cc3ca75af71be0c9;p=lyx.git diff --git a/src/VCBackend.cpp b/src/VCBackend.cpp index ff722f0d19..421a748451 100644 --- a/src/VCBackend.cpp +++ b/src/VCBackend.cpp @@ -3,7 +3,7 @@ * This file is part of LyX, the document processor. * Licence details can be found in the file COPYING. * - * \author Lars Gullik Bjønnes + * \author Lars Gullik Bjønnes * * Full author contact details are available in file CREDITS. */ @@ -36,17 +36,27 @@ using boost::smatch; namespace lyx { -int VCS::doVCCommand(string const & cmd, FileName const & path) -{ - LYXERR(Debug::LYXVC, "doVCCommand: " << cmd); +int VCS::doVCCommandCall(string const & cmd, FileName const & path){ + LYXERR(Debug::LYXVC, "doVCCommandCall: " << cmd); Systemcall one; support::PathChanger p(path); - int const ret = one.startscript(Systemcall::Wait, cmd); + return one.startscript(Systemcall::Wait, cmd); +} + +int VCS::doVCCommand(string const & cmd, FileName const & path) +{ + if (owner_) + owner_->setBusy(true); + + int const ret = doVCCommandCall(cmd, path); + + if (owner_) + owner_->setBusy(false); if (ret) frontend::Alert::error(_("Revision control error."), bformat(_("Some problem occured while running the command:\n" "'%1$s'."), - from_ascii(cmd))); + from_utf8(cmd))); return ret; } @@ -70,7 +80,7 @@ FileName const RCS::findFile(FileName const & file) FileName tmp(file.absFilename() + ",v"); LYXERR(Debug::LYXVC, "LyXVC: Checking if file is under rcs: " << tmp); if (tmp.isReadableFile()) { - LYXERR(Debug::LYXVC, "Yes " << file << " is under rcs."); + LYXERR(Debug::LYXVC, "Yes, " << file << " is under rcs."); return tmp; } @@ -78,7 +88,7 @@ FileName const RCS::findFile(FileName const & file) tmp = FileName(addName(addPath(onlyPath(file.absFilename()), "RCS"), file.absFilename()) + ",v"); LYXERR(Debug::LYXVC, "LyXVC: Checking if file is under rcs: " << tmp); if (tmp.isReadableFile()) { - LYXERR(Debug::LYXVC, "Yes " << file << " it is under rcs."); + LYXERR(Debug::LYXVC, "Yes, " << file << " is under rcs."); return tmp; } @@ -89,14 +99,17 @@ FileName const RCS::findFile(FileName const & file) void RCS::retrieve(FileName const & file) { LYXERR(Debug::LYXVC, "LyXVC::RCS: retrieve.\n\t" << file); - VCS::doVCCommand("co -q -r " + quoteName(file.toFilesystemEncoding()), + doVCCommandCall("co -q -r " + quoteName(file.toFilesystemEncoding()), FileName()); } void RCS::scanMaster() { - LYXERR(Debug::LYXVC, "LyXVC::RCS: scanMaster."); + if (master_.empty()) + return; + + LYXERR(Debug::LYXVC, "LyXVC::RCS: scanMaster: " << master_); ifstream ifs(master_.toFilesystemEncoding().c_str()); @@ -164,11 +177,12 @@ void RCS::registrer(string const & msg) } -void RCS::checkIn(string const & msg) +string RCS::checkIn(string const & msg) { - doVCCommand("ci -q -u -m\"" + msg + "\" " + int ret = doVCCommand("ci -q -u -m\"" + msg + "\" " + quoteName(onlyFilename(owner_->absFileName())), FileName(owner_->filePath())); + return ret ? string() : "RCS: Proceeded"; } bool RCS::checkInEnabled() @@ -176,11 +190,12 @@ bool RCS::checkInEnabled() return owner_ && !owner_->isReadonly(); } -void RCS::checkOut() +string RCS::checkOut() { owner_->markClean(); - doVCCommand("co -q -l " + quoteName(onlyFilename(owner_->absFileName())), + int ret = doVCCommand("co -q -l " + quoteName(onlyFilename(owner_->absFileName())), FileName(owner_->filePath())); + return ret ? string() : "RCS: Proceeded"; } @@ -189,6 +204,18 @@ bool RCS::checkOutEnabled() return owner_ && owner_->isReadonly(); } +string RCS::lockingToggle() +{ + lyxerr << "Sorry, not implemented." << endl; + return string(); +} + + +bool RCS::lockingToggleEnabled() +{ + return false; +} + void RCS::revert() { @@ -218,7 +245,7 @@ bool RCS::undoLastEnabled() void RCS::getLog(FileName const & tmpf) { doVCCommand("rlog " + quoteName(onlyFilename(owner_->absFileName())) - + " > " + tmpf.toFilesystemEncoding(), + + " > " + quoteName(tmpf.toFilesystemEncoding()), FileName(owner_->filePath())); } @@ -321,11 +348,12 @@ void CVS::registrer(string const & msg) } -void CVS::checkIn(string const & msg) +string CVS::checkIn(string const & msg) { - doVCCommand("cvs -q commit -m \"" + msg + "\" " + int ret = doVCCommand("cvs -q commit -m \"" + msg + "\" " + quoteName(onlyFilename(owner_->absFileName())), FileName(owner_->filePath())); + return ret ? string() : "CVS: Proceeded"; } @@ -335,12 +363,13 @@ bool CVS::checkInEnabled() } -void CVS::checkOut() +string CVS::checkOut() { // cvs update or perhaps for cvs this should be a noop // we need to detect conflict (eg "C" in output) // before we can do this. - lyxerr << "Sorry not implemented." << endl; + lyxerr << "Sorry, not implemented." << endl; + return string(); } @@ -350,16 +379,31 @@ bool CVS::checkOutEnabled() } +string CVS::lockingToggle() +{ + lyxerr << "Sorry, not implemented." << endl; + return string(); +} + + +bool CVS::lockingToggleEnabled() +{ + return false; +} + + void CVS::revert() { - // This is sensitive operation, so at lest some check before - if (doVCCommand("cvs --help", FileName(owner_->filePath()))) - return; // Reverts to the version in CVS repository and // gets the updated version from the repository. string const fil = quoteName(onlyFilename(owner_->absFileName())); - - doVCCommand("rm -f " + fil + "; cvs update " + fil, + // This is sensitive operation, so at lest some check about + // existence of cvs program and its file + if (doVCCommand("cvs log "+ fil, FileName(owner_->filePath()))) + return; + FileName f(owner_->absFileName()); + f.removeFile(); + doVCCommand("cvs update " + fil, FileName(owner_->filePath())); owner_->markClean(); } @@ -370,7 +414,7 @@ void CVS::undoLast() // merge the current with the previous version // in a reverse patch kind of way, so that the // result is to revert the last changes. - lyxerr << "Sorry not implemented." << endl; + lyxerr << "Sorry, not implemented." << endl; } @@ -383,7 +427,7 @@ bool CVS::undoLastEnabled() void CVS::getLog(FileName const & tmpf) { doVCCommand("cvs log " + quoteName(onlyFilename(owner_->absFileName())) - + " > " + tmpf.toFilesystemEncoding(), + + " > " + quoteName(tmpf.toFilesystemEncoding()), FileName(owner_->filePath())); } @@ -400,22 +444,24 @@ bool CVS::toggleReadOnlyEnabled() SVN::SVN(FileName const & m, FileName const & f) { + owner_ = 0; master_ = m; file_ = f; + locked_mode_ = 0; scanMaster(); } FileName const SVN::findFile(FileName const & file) { - // First we look for the CVS/Entries in the same dir + // First we look for the .svn/entries in the same dir // where we have file. FileName const entries(onlyPath(file.absFilename()) + "/.svn/entries"); string const tmpf = onlyFilename(file.absFilename()); LYXERR(Debug::LYXVC, "LyXVC: Checking if file is under svn in `" << entries << "' for `" << tmpf << '\''); if (entries.isReadableFile()) { - // Ok we are at least in a CVS dir. Parse the CVS/Entries + // Ok we are at least in a SVN dir. Parse the .svn/entries // and see if we can find this file. We do a fast and // dirty parse here. ifstream ifs(entries.toFilesystemEncoding().c_str()); @@ -434,81 +480,243 @@ FileName const SVN::findFile(FileName const & file) void SVN::scanMaster() { - // if we want some locking under svn - // we need different infrastructure around - locker_ = "Unlocked"; - vcstatus = UNLOCKED; + locker_.clear(); + vcstatus = NOLOCKING; + if (checkLockMode()) { + if (isLocked()) { + locker_ = "Locked"; + vcstatus = LOCKED; + } else { + locker_ = "Unlocked"; + vcstatus = LOCKED; + } + } +} + + +bool SVN::checkLockMode() +{ + FileName tmpf = FileName::tempName("lyxvcout"); + if (tmpf.empty()){ + LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); + return N_("Error: Could not generate logfile."); + } + + LYXERR(Debug::LYXVC, "Detecting locking mode..."); + if (doVCCommandCall("svn proplist " + quoteName(file_.onlyFileName()) + + " > " + quoteName(tmpf.toFilesystemEncoding()), + file_.onlyPath())) + return false; + + ifstream ifs(tmpf.toFilesystemEncoding().c_str()); + string line; + bool ret = false; + + while (ifs) { + getline(ifs, line); + LYXERR(Debug::LYXVC, line); + if (contains(line, "svn:needs-lock")) + ret = true; + } + LYXERR(Debug::LYXVC, "Locking enabled: " << ret); + ifs.close(); + locked_mode_ = ret; + return ret; + +} + + +bool SVN::isLocked() const +{ + //refresh file info + FileName file(file_.absFilename()); + return !file.isReadOnly(); } -void SVN::registrer(string const & msg) +void SVN::registrer(string const & /*msg*/) { - doVCCommand("svn -q add " + quoteName(onlyFilename(owner_->absFileName())), + doVCCommand("svn add -q " + quoteName(onlyFilename(owner_->absFileName())), FileName(owner_->filePath())); } -void SVN::checkIn(string const & msg) +string SVN::checkIn(string const & msg) { - doVCCommand("svn -q commit -m \"" + msg + "\" " - + quoteName(onlyFilename(owner_->absFileName())), + FileName tmpf = FileName::tempName("lyxvcout"); + if (tmpf.empty()){ + LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); + return N_("Error: Could not generate logfile."); + } + + doVCCommand("svn commit -m \"" + msg + "\" " + + quoteName(onlyFilename(owner_->absFileName())) + + " > " + quoteName(tmpf.toFilesystemEncoding()), FileName(owner_->filePath())); + + string log; + string res = scanLogFile(tmpf, log); + if (!res.empty()) + frontend::Alert::error(_("Revision control error."), + _("Error when committing to repository.\n" + "You have to manually resolve the problem.\n" + "After pressing OK, LyX will reopen the document.")); + else + fileLock(false, tmpf, log); + + tmpf.erase(); + return "SVN: " + log; } bool SVN::checkInEnabled() { - return true; + if (locked_mode_) + return isLocked(); + else + return true; } + // FIXME Correctly return code should be checked instead of this. // This would need another solution than just plain startscript. -string SVN::scanLogFile(FileName const & f) +// Hint from Andre': QProcess::readAllStandardError()... +string SVN::scanLogFile(FileName const & f, string & status) { ifstream ifs(f.toFilesystemEncoding().c_str()); string line; - while (ifs){ - getline(ifs,line); - lyxerr<absFileName())) + + " > " + quoteName(tmpf.toFilesystemEncoding()), + FileName(owner_->filePath())); + + ifstream ifs(tmpf.toFilesystemEncoding().c_str()); + string line; + while (ifs) { + getline(ifs, line); + if (!line.empty()) status += line + "; "; + } + ifs.close(); + + if (!isLocked() && lock) + frontend::Alert::error(_("Revision control error."), + _("Error when acquiring write lock.\n" + "Most probably another user is editing\n" + "the current document now!\n" + "Also check the access to the repository.")); + if (isLocked() && !lock) + frontend::Alert::error(_("Revision control error."), + _("Error when releasing write lock.\n" + "Check the access to the repository.")); +} + + +string SVN::checkOut() { FileName tmpf = FileName::tempName("lyxvcout"); - if (tmpf.empty()){ + if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); - return; + return N_("Error: Could not generate logfile."); } doVCCommand("svn update " + quoteName(onlyFilename(owner_->absFileName())) - + " > " + tmpf.toFilesystemEncoding(), + + " > " + quoteName(tmpf.toFilesystemEncoding()), FileName(owner_->filePath())); - string res = scanLogFile(tmpf); + string log; + string res = scanLogFile(tmpf, log); if (!res.empty()) frontend::Alert::error(_("Revision control error."), bformat(_("Error when updating from repository.\n" "You have to manually resolve the conflicts NOW!\n'%1$s'.\n\n" "After pressing OK, LyX will try to reopen resolved document."), - from_ascii(res))); + from_local8bit(res))); + + fileLock(true, tmpf, log); + tmpf.erase(); + return "SVN: " + log; } bool SVN::checkOutEnabled() { - return true; + if (locked_mode_) + return !isLocked(); + else + return true; } +string SVN::lockingToggle() +{ + FileName tmpf = FileName::tempName("lyxvcout"); + if (tmpf.empty()) { + LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); + return N_("Error: Could not generate logfile."); + } + + int ret = doVCCommand("svn proplist " + quoteName(onlyFilename(owner_->absFileName())) + + " > " + quoteName(tmpf.toFilesystemEncoding()), + FileName(owner_->filePath())); + if (ret) + return string(); + + string log; + string res = scanLogFile(tmpf, log); + bool locking = contains(res, "svn:needs-lock"); + if (!locking) + ret = doVCCommand("svn propset svn:needs-lock ON " + + quoteName(onlyFilename(owner_->absFileName())) + + " > " + quoteName(tmpf.toFilesystemEncoding()), + FileName(owner_->filePath())); + else + ret = doVCCommand("svn propdel svn:needs-lock " + + quoteName(onlyFilename(owner_->absFileName())) + + " > " + quoteName(tmpf.toFilesystemEncoding()), + FileName(owner_->filePath())); + if (ret) + return string(); + + tmpf.erase(); + frontend::Alert::warning(_("VCN File Locking"), + (locking ? _("Locking property unset.") : _("Locking property set.")) + "\n" + + _("Do not forget to commit the locking property into the repository."), + true); + + return string("SVN: ") + N_("Locking property set."); +} + + +bool SVN::lockingToggleEnabled() +{ + return true; +} + void SVN::revert() { // Reverts to the version in CVS repository and @@ -526,7 +734,7 @@ void SVN::undoLast() // merge the current with the previous version // in a reverse patch kind of way, so that the // result is to revert the last changes. - lyxerr << "Sorry not implemented." << endl; + lyxerr << "Sorry, not implemented." << endl; } @@ -539,7 +747,7 @@ bool SVN::undoLastEnabled() void SVN::getLog(FileName const & tmpf) { doVCCommand("svn log " + quoteName(onlyFilename(owner_->absFileName())) - + " > " + tmpf.toFilesystemEncoding(), + + " > " + quoteName(tmpf.toFilesystemEncoding()), FileName(owner_->filePath())); }