mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-29 13:04:58 +00:00
* implementation of status check and use it for checkIn and revert.
helps the user to avoid errors and leads to more informative messages. * implementation of diff and use it for the repoUpdate operation. * add the check for merge conflicts in checkOut. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@35813 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
parent
ba19e8b5dd
commit
bcbe6ae960
@ -47,7 +47,7 @@ int VCS::doVCCommandCall(string const & cmd, FileName const & path)
|
||||
}
|
||||
|
||||
|
||||
int VCS::doVCCommand(string const & cmd, FileName const & path)
|
||||
int VCS::doVCCommand(string const & cmd, FileName const & path, bool reportError)
|
||||
{
|
||||
if (owner_)
|
||||
owner_->setBusy(true);
|
||||
@ -56,7 +56,7 @@ int VCS::doVCCommand(string const & cmd, FileName const & path)
|
||||
|
||||
if (owner_)
|
||||
owner_->setBusy(false);
|
||||
if (ret)
|
||||
if (ret && reportError)
|
||||
frontend::Alert::error(_("Revision control error."),
|
||||
bformat(_("Some problem occured while running the command:\n"
|
||||
"'%1$s'."),
|
||||
@ -383,7 +383,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 tmpf = '/' + onlyFileName(file_.absFileName()) + '/';
|
||||
string name = onlyFileName(file_.absFileName());
|
||||
string tmpf = '/' + name + '/';
|
||||
LYXERR(Debug::LYXVC, "\tlooking for `" << tmpf << '\'');
|
||||
string line;
|
||||
static regex const reg("/(.*)/(.*)/(.*)/(.*)/(.*)");
|
||||
@ -402,21 +403,22 @@ void CVS::scanMaster()
|
||||
|
||||
//sm[4]; // options
|
||||
//sm[5]; // tag or tagdate
|
||||
// FIXME: must double check file is stattable/existing
|
||||
time_t mod = file_.lastModified();
|
||||
string mod_date = rtrim(asctime(gmtime(&mod)), "\n");
|
||||
LYXERR(Debug::LYXVC, "Date in Entries: `" << file_date
|
||||
<< "'\nModification date of file: `" << mod_date << '\'');
|
||||
//FIXME this whole locking bussiness is not working under cvs and the machinery
|
||||
// conforms to the ci usage, not cvs.
|
||||
if (file_date == mod_date) {
|
||||
locker_ = "Unlocked";
|
||||
vcstatus = UNLOCKED;
|
||||
if (file_.isReadableFile()) {
|
||||
time_t mod = file_.lastModified();
|
||||
string 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;
|
||||
} 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;
|
||||
}
|
||||
} else {
|
||||
// Here we should also do some more checking
|
||||
// to see if there are conflicts or not.
|
||||
locker_ = "Locked";
|
||||
vcstatus = LOCKED;
|
||||
vcstatus = NOLOCKING;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -424,64 +426,269 @@ void CVS::scanMaster()
|
||||
}
|
||||
|
||||
|
||||
void CVS::registrer(string const & msg)
|
||||
string const CVS::getTarget(OperationMode opmode) const
|
||||
{
|
||||
doVCCommand("cvs -q add -m \"" + msg + "\" "
|
||||
+ quoteName(onlyFileName(owner_->absFileName())),
|
||||
FileName(owner_->filePath()));
|
||||
switch(opmode) {
|
||||
case Directory:
|
||||
return quoteName(owner_->filePath());
|
||||
case File:
|
||||
return quoteName(onlyFileName(owner_->absFileName()));
|
||||
}
|
||||
return string();
|
||||
}
|
||||
|
||||
|
||||
docstring CVS::toString(CvsStatus status) const
|
||||
{
|
||||
switch (status) {
|
||||
case UpToDate:
|
||||
return _("Up-to-date");
|
||||
case LocallyModified:
|
||||
return _("Locally Modified");
|
||||
case LocallyAdded:
|
||||
return _("Locally Added");
|
||||
case NeedsMerge:
|
||||
return _("Needs Merge");
|
||||
case NeedsCheckout:
|
||||
return _("Needs Checkout");
|
||||
case NoCvsFile:
|
||||
return _("No CVS file");
|
||||
case StatusError:
|
||||
return _("Cannot retrieve CVS status");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
CVS::CvsStatus CVS::getStatus()
|
||||
{
|
||||
FileName tmpf = FileName::tempName("lyxvcout");
|
||||
if (tmpf.empty()) {
|
||||
LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf);
|
||||
return StatusError;
|
||||
}
|
||||
|
||||
if (doVCCommand("cvs status " + getTarget(File)
|
||||
+ " > " + quoteName(tmpf.toFilesystemEncoding()),
|
||||
FileName(owner_->filePath()))) {
|
||||
tmpf.removeFile();
|
||||
return StatusError;
|
||||
}
|
||||
|
||||
ifstream ifs(tmpf.toFilesystemEncoding().c_str());
|
||||
CvsStatus status = NoCvsFile;
|
||||
|
||||
while (ifs) {
|
||||
string line;
|
||||
getline(ifs, line);
|
||||
LYXERR(Debug::LYXVC, line << "\n");
|
||||
if (prefixIs(line, "File:")) {
|
||||
if (contains(line, "Up-to-date"))
|
||||
status = UpToDate;
|
||||
else if (contains(line, "Locally Modified"))
|
||||
status = LocallyModified;
|
||||
else if (contains(line, "Locally Added"))
|
||||
status = LocallyAdded;
|
||||
else if (contains(line, "Needs Merge"))
|
||||
status = NeedsMerge;
|
||||
else if (contains(line, "Needs Checkout"))
|
||||
status = NeedsCheckout;
|
||||
}
|
||||
}
|
||||
tmpf.removeFile();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void CVS::registrer(string const & msg)
|
||||
{
|
||||
doVCCommand("cvs -q add -m \"" + msg + "\" "
|
||||
+ getTarget(File),
|
||||
FileName(owner_->filePath()));
|
||||
}
|
||||
|
||||
|
||||
void CVS::getDiff(OperationMode opmode, FileName const & tmpf)
|
||||
{
|
||||
doVCCommand("cvs diff " + getTarget(opmode)
|
||||
+ " > " + quoteName(tmpf.toFilesystemEncoding()),
|
||||
FileName(owner_->filePath()), false);
|
||||
}
|
||||
|
||||
|
||||
int CVS::edit()
|
||||
{
|
||||
vcstatus = LOCKED;
|
||||
return doVCCommand("cvs -q edit " + getTarget(File),
|
||||
FileName(owner_->filePath()));
|
||||
}
|
||||
|
||||
|
||||
int CVS::unedit()
|
||||
{
|
||||
vcstatus = UNLOCKED;
|
||||
return doVCCommand("cvs -q unedit " + getTarget(File),
|
||||
FileName(owner_->filePath()));
|
||||
}
|
||||
|
||||
|
||||
int CVS::update(OperationMode opmode, FileName const & tmpf)
|
||||
{
|
||||
string const redirection = tmpf.empty() ? ""
|
||||
: " > " + quoteName(tmpf.toFilesystemEncoding());
|
||||
|
||||
return doVCCommand("cvs -q update "
|
||||
+ getTarget(opmode) + redirection,
|
||||
FileName(owner_->filePath()));
|
||||
}
|
||||
|
||||
|
||||
string CVS::scanLogFile(FileName const & f, string & status)
|
||||
{
|
||||
ifstream ifs(f.toFilesystemEncoding().c_str());
|
||||
|
||||
while (ifs) {
|
||||
string line;
|
||||
getline(ifs, line);
|
||||
LYXERR(Debug::LYXVC, line << "\n");
|
||||
if (!line.empty())
|
||||
status += line + "; ";
|
||||
if (prefixIs(line, "C ")) {
|
||||
ifs.close();
|
||||
return line;
|
||||
}
|
||||
}
|
||||
ifs.close();
|
||||
return string();
|
||||
}
|
||||
|
||||
|
||||
string CVS::checkIn(string const & msg)
|
||||
{
|
||||
int ret = doVCCommand("cvs -q commit -m \"" + msg + "\" "
|
||||
+ quoteName(onlyFileName(owner_->absFileName())),
|
||||
CvsStatus status = getStatus();
|
||||
switch (status) {
|
||||
case UpToDate:
|
||||
if (vcstatus != NOLOCKING)
|
||||
unedit();
|
||||
return "CVS: Proceeded";
|
||||
case LocallyModified:
|
||||
case LocallyAdded: {
|
||||
int rc = doVCCommand("cvs -q commit -m \"" + msg + "\" "
|
||||
+ getTarget(File),
|
||||
FileName(owner_->filePath()));
|
||||
return ret ? string() : "CVS: Proceeded";
|
||||
return rc ? string() : "CVS: Proceeded";
|
||||
}
|
||||
case NeedsMerge:
|
||||
case NeedsCheckout:
|
||||
frontend::Alert::error(_("Revision control error."),
|
||||
_("The repository version is newer then the current check out.\n"
|
||||
"You have to update from repository first or revert your changes.")) ;
|
||||
break;
|
||||
default:
|
||||
frontend::Alert::error(_("Revision control error."),
|
||||
bformat(_("Bad status when checking in changes.\n"
|
||||
"\n'%1$s'\n\n"),
|
||||
toString(status)));
|
||||
break;
|
||||
}
|
||||
return string();
|
||||
}
|
||||
|
||||
|
||||
bool CVS::isLocked() const
|
||||
{
|
||||
FileName fn(owner_->absFileName());
|
||||
fn.refresh();
|
||||
return !fn.isReadOnly();
|
||||
}
|
||||
|
||||
|
||||
bool CVS::checkInEnabled()
|
||||
{
|
||||
return !owner_->isReadonly();
|
||||
if (vcstatus != NOLOCKING)
|
||||
return isLocked();
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
string CVS::checkOut()
|
||||
{
|
||||
// to be sure we test it again...
|
||||
if (!checkOutEnabled())
|
||||
if (vcstatus != NOLOCKING && edit())
|
||||
return string();
|
||||
|
||||
int ret = doVCCommand("cvs -q edit "
|
||||
+ quoteName(onlyFileName(owner_->absFileName())),
|
||||
FileName(owner_->filePath()));
|
||||
if (ret)
|
||||
FileName tmpf = FileName::tempName("lyxvcout");
|
||||
if (tmpf.empty()) {
|
||||
LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf);
|
||||
return string();
|
||||
|
||||
ret = doVCCommand("cvs update "
|
||||
+ quoteName(onlyFileName(owner_->absFileName())),
|
||||
FileName(owner_->filePath()));
|
||||
return ret ? string() : "CVS: Proceeded";
|
||||
}
|
||||
|
||||
int rc = update(File, tmpf);
|
||||
string log;
|
||||
string const 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 the resolved document."),
|
||||
from_local8bit(res)));
|
||||
|
||||
tmpf.erase();
|
||||
return rc ? string() : log.empty() ? "CVS: Proceeded" : "CVS: " + log;
|
||||
}
|
||||
|
||||
|
||||
bool CVS::checkOutEnabled()
|
||||
{
|
||||
return owner_->isReadonly();
|
||||
if (vcstatus != NOLOCKING)
|
||||
return !isLocked();
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
string CVS::repoUpdate()
|
||||
{
|
||||
lyxerr << "Sorry, not implemented." << endl;
|
||||
return string();
|
||||
FileName tmpf = FileName::tempName("lyxvcout");
|
||||
if (tmpf.empty()) {
|
||||
LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf);
|
||||
return string();
|
||||
}
|
||||
|
||||
getDiff(Directory, tmpf);
|
||||
docstring res = tmpf.fileContents("UTF-8");
|
||||
if (!res.empty()) {
|
||||
LYXERR(Debug::LYXVC, "Diff detected:\n" << res);
|
||||
docstring const file = from_utf8(owner_->filePath());
|
||||
docstring text = bformat(_("There were detected changes "
|
||||
"in the working directory:\n%1$s\n\n"
|
||||
"In case of file conflict you have to resolve them "
|
||||
"manually or revert to repository version later."), file);
|
||||
int ret = frontend::Alert::prompt(_("Changes detected"),
|
||||
text, 0, 1, _("&Continue"), _("&Abort"), _("View &Log ..."));
|
||||
if (ret == 2 ) {
|
||||
dispatch(FuncRequest(LFUN_DIALOG_SHOW, "file " + tmpf.absFileName()));
|
||||
ret = frontend::Alert::prompt(_("Changes detected"),
|
||||
text, 0, 1, _("&Continue"), _("&Abort"));
|
||||
hideDialogs("file", 0);
|
||||
}
|
||||
if (ret == 1 ) {
|
||||
tmpf.removeFile();
|
||||
return string();
|
||||
}
|
||||
}
|
||||
|
||||
int rc = update(Directory, tmpf);
|
||||
res += "Update log:\n" + tmpf.fileContents("UTF-8");
|
||||
tmpf.removeFile();
|
||||
|
||||
LYXERR(Debug::LYXVC, res);
|
||||
return rc ? string() : "CVS: Proceeded" ;
|
||||
}
|
||||
|
||||
|
||||
bool CVS::repoUpdateEnabled()
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -502,16 +709,33 @@ void CVS::revert()
|
||||
{
|
||||
// Reverts to the version in CVS repository and
|
||||
// gets the updated version from the repository.
|
||||
string const fil = quoteName(onlyFileName(owner_->absFileName()));
|
||||
// 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 -q update " + fil,
|
||||
FileName(owner_->filePath()));
|
||||
owner_->markClean();
|
||||
CvsStatus status = getStatus();
|
||||
switch (status) {
|
||||
case UpToDate:
|
||||
if (vcstatus != NOLOCKING)
|
||||
unedit();
|
||||
break;
|
||||
case NeedsMerge:
|
||||
case NeedsCheckout:
|
||||
case LocallyModified: {
|
||||
FileName f(owner_->absFileName());
|
||||
f.removeFile();
|
||||
update(File, FileName());
|
||||
owner_->markClean();
|
||||
break;
|
||||
}
|
||||
case LocallyAdded:
|
||||
frontend::Alert::error(_("Revision control error."),
|
||||
_("The current file is not in repository.\n"
|
||||
"You have to check in the first revision before you can revert.")) ;
|
||||
break;
|
||||
default:
|
||||
frontend::Alert::error(_("Revision control error."),
|
||||
bformat(_("Bad status when checking in changes.\n"
|
||||
"\n'%1$s'\n\n"),
|
||||
toString(status)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -532,7 +756,7 @@ bool CVS::undoLastEnabled()
|
||||
|
||||
void CVS::getLog(FileName const & tmpf)
|
||||
{
|
||||
doVCCommand("cvs log " + quoteName(onlyFileName(owner_->absFileName()))
|
||||
doVCCommand("cvs log " + getTarget(File)
|
||||
+ " > " + quoteName(tmpf.toFilesystemEncoding()),
|
||||
FileName(owner_->filePath()));
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ protected:
|
||||
virtual void scanMaster() = 0;
|
||||
|
||||
// GUI container for doVCCommandCall
|
||||
int doVCCommand(std::string const & cmd, support::FileName const & path);
|
||||
int doVCCommand(std::string const & cmd, support::FileName const & path, bool reportError = true);
|
||||
/**
|
||||
* doVCCommandCall - call out to the version control utility
|
||||
* @param cmd the command to execute
|
||||
@ -210,6 +210,10 @@ public:
|
||||
|
||||
virtual void getLog(support::FileName const &);
|
||||
|
||||
/// Check for messages in cvs output.
|
||||
/// Returns conflict line.
|
||||
std::string scanLogFile(support::FileName const & f, std::string & status);
|
||||
|
||||
virtual std::string const versionString() const {
|
||||
return "CVS: " + version_;
|
||||
}
|
||||
@ -224,13 +228,46 @@ public:
|
||||
|
||||
protected:
|
||||
virtual void scanMaster();
|
||||
/// the mode of operation for some VC commands
|
||||
enum OperationMode {
|
||||
Directory = 0,
|
||||
File = 1
|
||||
};
|
||||
/// possible status values of file
|
||||
enum CvsStatus {
|
||||
UpToDate = 0,
|
||||
LocallyModified = 1,
|
||||
LocallyAdded = 2,
|
||||
NeedsMerge = 3,
|
||||
NeedsCheckout = 4,
|
||||
NoCvsFile = 5,
|
||||
StatusError = 6
|
||||
};
|
||||
|
||||
private:
|
||||
support::FileName file_;
|
||||
// revision number from scanMaster
|
||||
std::string version_;
|
||||
/// The user currently keeping the lock on the VC file.
|
||||
std::string locker_;
|
||||
|
||||
/// return the quoted pathname if Directory or filename if File
|
||||
virtual std::string const getTarget(OperationMode opmode) const;
|
||||
/// collect the diff of file or directory against repository
|
||||
/// result is placed in temporary file
|
||||
void getDiff(OperationMode opmode, support::FileName const & tmpf);
|
||||
/// make the file ready for editing:
|
||||
/// save a copy in CVS/Base and change file permissions to rw if needed
|
||||
virtual int edit();
|
||||
/// revert the edit operation
|
||||
virtual int unedit();
|
||||
/// retrieve repository changes into working copy
|
||||
virtual int update(OperationMode opmode, support::FileName const & tmpf);
|
||||
/// check readonly state for file
|
||||
/// assume true when file is writable
|
||||
virtual bool isLocked() const;
|
||||
/// query and parse the cvs status of file
|
||||
virtual CvsStatus getStatus();
|
||||
/// convert enum to string
|
||||
virtual docstring toString(CvsStatus status) const;
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user