/****************************************************************************
**
** Copyright (C) 2004-2007 Frank Hemer <frank@hemer.org>,
** Tilo Riemer <riemer@crossvc.com>
**
**
**----------------------------------------------------------------------------
**
**----------------------------------------------------------------------------
**
** CrossVC is available under two different licenses:
**
** If CrossVC is linked against the GPLed version of Qt
** CrossVC is released under the terms of GPL also.
**
** If CrossVC is linked against a nonGPLed version of Qt
** CrossVC is released under the terms of the
** CrossVC License for non-Unix platforms (CLNU)
**
**
** CrossVC License for non-Unix platforms (CLNU):
**
** Redistribution and use in binary form, without modification,
** are permitted provided that the following conditions are met:
**
** 1. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 2. It is not permitted to distribute the binary package under a name
** different than CrossVC.
** 3. The name of the authors may not be used to endorse or promote
** products derived from this software without specific prior written
** permission.
** 4. The source code is the creative property of the authors.
** Extensions and development under the terms of the Gnu Public License
** are limited to the Unix platform. Any distribution or compilation of
** the source code against libraries licensed other than gpl requires
** the written permission of the authors.
**
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
**
**
** CrossVC License for Unix platforms:
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, version 2 of the License.
** This program is distributed in
** the hope that it will be useful, but WITHOUT ANY WARRANTY; without
** even the implied warranty of MERCHANTABILITY or FITNESS FOR A
** PARTICULAR PURPOSE.
**
** See the GNU General Public License version 2 for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software Foundation,
** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
*****************************************************************************/
#include "CvsDirectory.h"
#include <qdir.h>
#include <qregexp.h>
//GUI related -> remove later
#include <qmessagebox.h>
#include <qinputdialog.h>
#include <assert.h>
#include "globals.h"
#include "tzconvert.h"
#include "filesubr.h"
#include "TextDecoder.h"
#include "login.h"
#include "pixmapcache.h"
#include "cvslistview.h"
#include "LinCVSLog.h"
#include "cvsignorelistview.h"
#include "noncvslistview.h"
#include "qtdatetime.h"
#define CVSDIRECTORY 123457
//=========================================== public ===============================================
//top level dir
CvsDirectory::CvsDirectory( QStringList subProjectList,
const QString& fileName)
: Directory(subProjectList)
{
s_topView->setUpdatesEnabled(FALSE);
init(fileName);
s_topView->setUpdatesEnabled(TRUE);
s_topView->triggerUpdate();
}
//----------------------------------------------------------------------------
//subdir
CvsDirectory::CvsDirectory( QListViewItem * parent,
const QString& fileName,
bool virtualDir)
: Directory( parent, virtualDir)
{
bool update;
if (update = s_topView->isUpdatesEnabled()) {
s_topView->setUpdatesEnabled(FALSE);
}
init(fileName);
if (update) {
s_topView->setUpdatesEnabled(TRUE);
s_topView->triggerUpdate();
}
}
//----------------------------------------------------------------------------
CvsDirectory::~CvsDirectory() {
}
//----------------------------------------------------------------------------
int CvsDirectory::rtti() const {
return CVSDIRECTORY;
}
//----------------------------------------------------------------------------
CvsDirectory * CvsDirectory::firstChild() {
QListViewItem * lvi = QListViewItem::firstChild();
while ( lvi && (lvi->rtti() != CVSDIRECTORY) ) {
lvi = lvi->nextSibling();
}
return static_cast<CvsDirectory *>(lvi);
}
//----------------------------------------------------------------------------
CvsDirectory * CvsDirectory::nextSibling() {
QListViewItem * lvi = QListViewItem::nextSibling();
while ( lvi && (lvi->rtti() != CVSDIRECTORY) ) {
lvi = lvi->nextSibling();
}
return static_cast<CvsDirectory *>(lvi);
}
//----------------------------------------------------------------------------
CvsDirectory * CvsDirectory::dyncast_cvsdir(QListViewItem * lvi) {
if ( lvi && (lvi->rtti() == CVSDIRECTORY) ) return static_cast<CvsDirectory *>(lvi);
else return NULL;
}
//=========================================== protected ============================================
//----------------------------------------------------------------------------
//=========================================== privat ===============================================
//--------------------------------- inherited virtual methods --------------------------------------
Directory * CvsDirectory::createChild( const QString& fileName, bool virtualDir) {
return new CvsDirectory(this,
fileName,
virtualDir);
}
//----------------------------------------------------------------------------
bool CvsDirectory::loginOk(CCvsOutput *pMessages, bool showMessage)
{
if(!m_isControlledDir) {//fixme move to CvsDirectory
QString cap = LC_APPNAME;
cap += " - " + QObject::tr("Warning");
QMessageBox::warning(qApp->mainWidget(), cap, QObject::tr("Is not a CVS directory."), 0);
return false;
}
if((m_connectMethod != "pserver") && (m_connectMethod != "sspi")){
return true;
}
if (!m_passwd.isNull()) {
if(showMessage) {
QString cap = LC_APPNAME;
cap += " - " + QObject::tr("Information");
QString msg = QObject::tr("No login necessary. Password is set in CVSROOT.");
msg += "\n" + QObject::tr("Note this is a security risk!");
QMessageBox::information(qApp->mainWidget(), cap, msg, 0);
}
return true;
}
QString cvsRoot = ":" + m_connectMethod + ":" + m_userName +
"@" + m_host + ":" + QString::number(m_port) + m_rootDir;
if (!isInCvsPass(cvsRoot)) {
bool ok = false;
QString pwd = QInputDialog::getText("Enter CVS password",
m_root, QLineEdit::Password, QString::null,
&ok, 0/*dynamic_cast<QWidget *>(this)*/, "Password Dialog");
if (!ok)
return false;
Login *l = new Login( pMessages, m_connectMethod, m_userName, m_host, m_port, m_rootDir);
l->doLogin(pwd);
delete l;
if (!isInCvsPass(cvsRoot)) {
QString cap = LC_APPNAME;
cap += " - " + QObject::tr("Warning");
QMessageBox::warning(qApp->mainWidget(), cap, QObject::tr("Login failed."), 0);
return false;
}
if (showMessage) {
QString cap = LC_APPNAME;
cap += " - " + QObject::tr("Information");
QMessageBox::information(qApp->mainWidget(), cap, QObject::tr("Login successful."), 0);
}
return true;
}
if(showMessage) {
QString cap = LC_APPNAME;
cap += " - " + QObject::tr("Information");
QMessageBox::information(qApp->mainWidget(), cap, QObject::tr("You are already logged in."), 0);
}
return true;
}
//----------------------------------------------------------------------------
void CvsDirectory::removeLogin(CCvsOutput *pMessages) {
if(!m_isControlledDir) {//fixme move to CvsDirectory
QString cap = LC_APPNAME;
cap += " - " + QObject::tr("Warning");
QMessageBox::warning(qApp->mainWidget(), cap, QObject::tr("Is not a CVS directory!"), 0);
return;
}
if (!m_passwd.isNull()) {
QString cap = LC_APPNAME;
cap += " - " + QObject::tr("Information");
QString msg = QObject::tr("Logout impossible! Password is set in CVSROOT.");
msg += "\n" + QObject::tr("Note this is a security risk!");
QMessageBox::information(qApp->mainWidget(), cap, msg, 0);
return;
}
Login *l = new Login( pMessages, m_connectMethod, m_userName, m_host, m_port, m_rootDir);
if (!(l->removeCvsPassEntry())) {
QString cap = LC_APPNAME;
cap += " - " + QObject::tr("Information");
QMessageBox::information(qApp->mainWidget(), cap,
QObject::tr("Logout impossible. You have not been logged in."), 0);
}
delete l;
}
//---------------------------------------------------------------------------
bool CvsDirectory::isModified() {
QString path = m_fullName;
if(path.length() > 1){//is not root
path += "/";
}
QFileInfo fInfo(path);
if (!fInfo.exists()) return false;
// qDebug("dir: "+m_fullName
// +", lastModified: "+m_lastModTimeOfDir.toString("hh:mm:ss:zzz")
// +", new: "+fInfo.lastModified().toString("hh:mm:ss:zzz")
// +", cur: "+QTime::currentTime().toString("hh:mm:ss:zzz"));
if (m_lastModTimeOfDir == fInfo.lastModified()) {
return (entriesFileModified() || entriesLogFileModified());
} else if (fInfo.lastModified() > QDateTime::currentDateTime().addSecs(-1)) {//causes problems on mounted dirs with non-synched timestamp
//fileInfo doesn't contain msec info, so new changes are not
//detected if they are within the same second
//we ignore changes here, so the first run with latest changes
//being in past more than 1 second will return true
// qDebug("dir: "+m_fullName
// +", old: "+m_lastModTimeOfDir.toString("hh:mm:ss:zzz")
// +", new: "+fInfo.lastModified().toString("hh:mm:ss:zzz")
// +", CvsCall: "+m_lastCallTime.toString("hh:mm:ss:zzz"));
if (fInfo.lastModified() <= m_lastCallTime) {
//if fInfo.lastModified() is within the last second from current time
//and the last cvs call happened _after_ that, don't ignore changes
//to prevent an additional view update
m_lastModTimeOfDir = fInfo.lastModified();
return true;
}
return (entriesFileModified() || entriesLogFileModified());
} else {
// qDebug("Dir modified: "+m_fullName);
m_lastModTimeOfDir = fInfo.lastModified();
return true;
}
}
//----------------------------------------------------------------------------
bool CvsDirectory::isControlledTree() {
return (m_isControlledDir || m_hasControlledSubDir);
}
//----------------------------------------------------------------------------
bool CvsDirectory::checkDirForControl( ) {
QString path = m_fullName;
if(path.length() > 1){//is not root
path += "/";
}
QFile f;
QString line;
QString logMsg;
//read Root
f.setName(path + "CVS/Root");
if(f.open(IO_ReadOnly)) {//file is readable
QTextStream textStream(&f);
line = textStream.readLine();
f.close();
m_root = line.stripWhiteSpace();
if (!extractCVSROOT(line,
m_connectMethod,
m_userName,
m_passwd,
m_host,
m_port,
m_rootDir)) {
Debug::g_pLog->log (Debug::LL_GOSSIP_MONGER, "extractCVSROOT failed");
return false;
}
if ((m_connectMethod == "local")
|| (m_connectMethod == "fork")) { //local
m_userName = getenv("USER");
m_host = "localhost";
m_connectMethod = "local";
}
if (Debug::g_logLevel == Debug::LL_GOSSIP_MONGER) {
logMsg += "extracting CVS/Root in: "+m_fullName+"\n";
logMsg += "\tconnectMethod: "+m_connectMethod+"\n";
logMsg += "\tuserName: "+m_userName+"\n";
if (!m_passwd.isEmpty ()) logMsg += "\tpassword set: xxxxx\n";
logMsg += "\thost: "+m_host+"\n";
logMsg += "\tport: "+QString::number (m_port)+"\n";
logMsg += "\trootDir: "+m_rootDir+"\n";
}
} else {
Debug::g_pLog->log (Debug::LL_THE_OLD_MAN_AND_THE_SEA, m_fullName+": cannot read CVS/Root");
return false;
}
//read Repository
f.setName(path + "CVS/Repository");
if(f.open(IO_ReadOnly)) {//file is readable
QTextStream textStream(&f);
m_repository = textStream.readLine().stripWhiteSpace();
f.close();
if (Debug::g_logLevel == Debug::LL_GOSSIP_MONGER) {
logMsg += "extracting CVS/Repository\n";
logMsg += "\trepository: "+m_repository+"\n";
}
} else {
if (Debug::g_logLevel == Debug::LL_THE_OLD_MAN_AND_THE_SEA) {
logMsg += m_fullName+": cannot read CVS/Repository";
Debug::g_pLog->log (Debug::LL_THE_OLD_MAN_AND_THE_SEA, logMsg);
}
return false;
}
//workaround for old cvs version
if(m_repository.find(m_rootDir) == 0){//old cvs version detected
m_repository = m_repository.mid(m_rootDir.length() + 1);
}
// check/set sub-project properties
QString name = shortName();
Directory * p = parent();
if ( p) {
bool addSubProject = false;
if ( p->isControlled()) {
if ( m_root != p->getRoot() ) addSubProject = true;
else if (m_repository != p->repository()+"/"+name) {//maybe sub project
//test for existence in parent entries file
addSubProject = true;
QStringList dirList = parent()->getControledSubdirs();
QStringList::Iterator iterator;
if ( (iterator = dirList.find(name)) != dirList.end() ) {
addSubProject = false;
}
}
} else {
addSubProject = TRUE;
}
if (addSubProject) {
m_isSubProjectRoot = true;
QStringList subList;
QString subProjectName = relativeName();
projectSettings->getSubProjects(m_topDir->shortName(),subList);
if ( subList.find(subProjectName) == subList.end()) {
projectSettings->addSubProject(m_topDir->shortName(),subProjectName);
projectSettings->set(subProjectName,WORKDIR,m_fullName);
m_topDir->getSubProjectList()->append(subProjectName);
}
}
}
Debug::g_pLog->log (Debug::LL_GOSSIP_MONGER, logMsg);
return true;
}
//---------------------------------------------------------------------------
QStringList CvsDirectory::getControledSubdirs() {
QStringList list;
QStringList::Iterator iterator;
QString line;
QTextStream textStream;
textStream.setCodec(I18n::g_pTextDecoder->pTextCodecPool()->pCodecForName(I18n::g_nameOfDecoder));
QFile f(m_fullName+"/CVS/Entries");
if (f.open(IO_ReadOnly)) {
textStream.setDevice(&f);
while (!textStream.eof()) {
line = textStream.readLine();
if (line.at(0) == 'D') {//entry is a directory
list.append(line.section("/",1,1));
}
}
f.close();
f.setName(m_fullName+"/CVS/Entries.Log");
if (f.open(IO_ReadOnly)) {
textStream.setDevice(&f);
while (!textStream.eof()) {
line = textStream.readLine();
if (line.at(2) != 'D') continue;
if (line.at(0) == 'A') {//added
line = line.section('/',1,1);
if (list.findIndex(line) == -1) list.append(line);
} else if (line.at(0) == 'R') {//removed
line = line.section('/',1,1);
iterator = list.find(line);
if (iterator != list.end()) {
list.remove(iterator);
}
}
}
f.close();
}
}
return list;
}
//---------------------------------------------------------------------------
DirBase * CvsDirectory::searchDirOfPath (QString path, bool findVirtual /* = false */) {
if (!findVirtual && m_virtual) {
return NULL;
}
if (path.compare (m_fullName) == 0) {
return this; //it´s my path :-)
}
if (path.find (m_fullName+"/") == 0) {//is subdir
CvsDirectory * myChild = firstChild();
CvsDirectory * result;
while (myChild) {
if ( (result = dyncast_cvsdir (myChild->searchDirOfPath (path, findVirtual))) ) {
return result;
}
else {
myChild = myChild->nextSibling ();
}
}
}
return NULL;
}
//----------------------------------------------------------------------------
//return the deepest valid (not disabled, not virtual) dir in hierarchy
DirBase * CvsDirectory::searchLastValidDirOfPath (QString path) {
if (m_disabled || m_virtual) {
return NULL;
}
if (path.compare(m_fullName) == 0) {
return this; //its my path :-)
}
if (path.find(m_fullName+"/") == 0) {//is subdir
CvsDirectory * myChild = firstChild();
CvsDirectory * result;
while (myChild) {
if ( (result = dyncast_cvsdir (myChild->searchLastValidDirOfPath (path))) ) {
return result;
}
else {
myChild = myChild->nextSibling ();
}
}
return this;
}
return NULL;
}
//---------------------------------------------------------------------------
//recursive check for modifications, only detected by a timestamp
//change of the dir or its CVS/Entries file
//if checkCvsFiles is true, also check for a change in each files timestamp
//if modifications are detected, check and set the new dir state
void CvsDirectory::recCheckForModifications(bool checkCvsFiles) {
if (m_disabled || m_virtual) return;
qApp->processEvents(1);
if (globalStopAction) return;
Directory * C = Directory::firstChild();
while( C ) {
C->recCheckForModifications(checkCvsFiles);
C = C->nextSibling();
}
if ( isModified() || (checkCvsFiles && isFilesModified()) ) {
checkAndShowStatus(NULL,true,Controled|NonControled|Ignored,TRUE);
if ( Debug::g_logLevel == Debug::LL_GOSSIP_MONGER) {
Debug::g_pLog->log(Debug::LL_GOSSIP_MONGER, "Detected changes: "+m_fullName);
}
}
}
//---------------------------------------------------------------------------
//recursive check for modifications, only detected by a timestamp
//change of the CVS/Entries / CVS/Entries.log file
//if modifications are detected, activateItem
bool CvsDirectory::postCallCheck(int type /*=Controled|NonControled|Ignored*/) {
if (m_disabled || m_virtual) return false;
qApp->processEvents(1);
if (globalStopAction) return false;
// qDebug(QString(isSelected() ? "selected" : "not selected")+", "
// +QString((type & Controled) ? "controled" : "not controled")+", "
// +QString(entriesFileModified() ? "entriesFileModified" : "")
// +QString(entriesLogFileModified() ? "entriesLogFileModified" : "")
// +QString((type & Force) ? "Force" : ""));
if (isSelected() && (type & Controled) && (entriesFileModified() || entriesLogFileModified() || (type & Force)) ) {
if (Polling::NONE) activateItem(true);
else activateItem( (type & (NonControled|Ignored)), type );
return true;
}
if (type & Tree) {
CvsDirectory * dir = firstChild();
while (dir) {
if (dir->postCallCheck(type)) return true;
dir = dir->nextSibling();
}
}
return false;
}
//----------------------------------------------------------------------------
void CvsDirectory::validateControlledFilesStatus( bool recursive /* = FALSE*/,
bool forceCacheReset /* = FALSE*/,
bool forceEntriesReset /* = FALSE*/) {
if (forceEntriesReset) {
m_entries.clear();
}
// now check and set state
CvsEntriesIterator it(*getCvsEntries(forceCacheReset));
while(it.current()) {
setStatusInFileListView(NULL, it.current(),true);
++it;
}
if (recursive) {
Directory * C = Directory::firstChild();
while( C ) {
C->validateControlledFilesStatus(recursive,forceCacheReset,forceEntriesReset);
C = C->nextSibling();
}
}
}
//----------------------------------------------------------------------------
//Main function for checking file state and displaying, used by DirWatch,AnalyzeDir,cvscontrol::checkStatus ...
void CvsDirectory::checkAndShowStatus( FileListViewItem *item /* = NULL*/,
bool checkOnly /* =FALSE*/,
int tab /* =Controled|NonControled|Ignored*/,
bool resetCache /* = FALSE*/) {
CvsEntries * cvsEntries = getCvsEntries();
if(item) {//only one item
QString fileName = item->text(0);
CvsEntry * cvsEntry = cvsEntries->find(fileName);
if (cvsEntry) {
setStatusInFileListView(item, cvsEntry);
}
} else { // read entries in directory
QStringList AllFilesInDirectory;
QFile f;
QString line;
QString path = m_fullName;
if(path.length() > 1){//is not root
path += "/";
}
QDir D( path);
D.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden | QDir::System);
AllFilesInDirectory = D.entryList();
// remove . and ..
AllFilesInDirectory.remove( "." );
AllFilesInDirectory.remove( ".." );
AllFilesInDirectory.remove( "CVS" );
// now check and set state
CvsEntriesIterator it(*cvsEntries);
while(it.current()) {
if (tab & Controled) item = setStatusInFileListView(0, it.current(), checkOnly);
if (!it.current ()->isTmp) {
AllFilesInDirectory.remove(it.current()->name);
}
++it;
}
// show 'non-cvs' and 'ignore files' entries
if ( tab & (NonControled|Ignored) ) {
// first read .cvsignore
bool homeIgnoresChanged;
bool dirIgnoresChanged;
const QString homeFilesToIgnore = getHomeFilesToIgnore(m_lastTimeHomeIgnoresChanged,homeIgnoresChanged);
const QString filesToIgnore = getDirFilesToIgnore(homeFilesToIgnore,dirIgnoresChanged);
//reset cache if changes occured
bool ignoreCacheReseted = false;
if (resetCache || dirIgnoresChanged || homeIgnoresChanged) {
m_ignoreFiles.clear();
m_nonFiles.clear();
ignoreCacheReseted = true;
}
// now check the files
for (QStringList::Iterator fileit = AllFilesInDirectory.begin(); fileit != AllFilesInDirectory.end(); fileit++) {
QString name = path + (*fileit);
QFileInfo info(name);
bool IsDir = info.isDir();
if ( IsDir && (checkType(name+"/") == Cvs) ) {// CVS directory -> do NOT show
continue;
}
bool isWritable = info.isWritable();
bool isExecutable = info.isExecutable();
//check wether file belongs to .cvsignore or is not registered
bool doIgnore = false;
bool found;
doIgnore = updateFileCacheAndCheckForIgnores(filesToIgnore,*fileit,ignoreCacheReseted, found);
if (doIgnore) {
// continue here if checkOnly, don't show
if (checkOnly || !(tab & Ignored)) continue;
// show cvsignore entries
item = new FileListViewItem(m_pIgnoreFileListView,IsDir,FileListViewItem::TextNoCase,FileListViewItem::ModDate);
item->setPixmap(0, findEmbeddedPixmap((IsDir) ?
(isExecutable) ? "FolderClosed16x16" : "FolderClosedLocked16x16" :
(isWritable) ? "FileStatus16x16" : "FileLocked16x16"));
} else {
// stop here if checkOnly because now we know the non-cvs state (dir state was allready set in updateFileCacheAndCheckForIgnores
if (checkOnly) return;
if ( !(tab & NonControled) ) continue;
//show non-cvs entries
item = new FileListViewItem(m_pNonFileListView,IsDir,FileListViewItem::TextNoCase,FileListViewItem::ModDate);
item->setPixmap(0, findEmbeddedPixmap((IsDir) ?
(isExecutable) ? "FolderStatus16x16" : "FolderClosedLocked16x16" :
(isWritable) ? "FileUnknown16x16" : "FileLocked16x16"));
}
item->setText(0, *fileit);
QDateTime localDate = info.lastModified();
item->setModifiedDate(1, &localDate, localDate.toString(LookAndFeel::g_dateTimeFormat));
}
checkNonControlledFilesDirState();
}
}
}
//----------------------------------------------------------------------------
//Add a single file, only known by its name, and display it
void CvsDirectory::checkAndUpdateFileCache(QString& file) {
// first read .cvsignore
bool homeIgnoresChanged;
bool dirIgnoresChanged;
const QString homeFilesToIgnore = getHomeFilesToIgnore(m_lastTimeHomeIgnoresChanged,homeIgnoresChanged);
const QString filesToIgnore = getDirFilesToIgnore(homeFilesToIgnore,dirIgnoresChanged);
bool ignoreCacheReseted = false;
if (dirIgnoresChanged || homeIgnoresChanged) {
if (isSelected()) {
activateItem(TRUE);
return;
} else {
m_ignoreFiles.clear();
m_nonFiles.clear();
ignoreCacheReseted = true;
}
}
CvsEntries * cvsEntries = getCvsEntries();
CvsEntry *cvsEntry = cvsEntries->find(file);
if (cvsEntry) {
QListViewItem * item = NULL;
if (isSelected()) {
item = m_pFileListView->firstChild();
while (item) {
if (item->text(0) == file) {
break;
} else item = item->nextSibling();
}
}
setStatusInFileListView( static_cast<FileListViewItem*>(item), cvsEntry, !isSelected());
} else {
bool found;
bool doIgnore = updateFileCacheAndCheckForIgnores(filesToIgnore,file,ignoreCacheReseted,found);
if (isSelected() && (!found) ) {
FileListViewItem * item;
bool IsDir = false;
bool isWritable = false;
bool isExecutable = false;
QFileInfo info(m_fullName+"/"+file);
IsDir = info.isDir();
isWritable = info.isWritable();
isExecutable = info.isExecutable();
if (doIgnore) {
// show cvsignore entries
item = new FileListViewItem(m_pIgnoreFileListView,IsDir,FileListViewItem::TextNoCase,FileListViewItem::ModDate);
item->setPixmap(0, findEmbeddedPixmap((IsDir) ?
(isExecutable) ? "FolderClosed16x16" : "FolderClosedLocked16x16" :
(isWritable) ? "FileStatus16x16" : "FileLocked16x16"));
} else {
//show non-cvs entries
item = new FileListViewItem(m_pNonFileListView,IsDir,FileListViewItem::TextNoCase,FileListViewItem::ModDate);
item->setPixmap(0, findEmbeddedPixmap((IsDir) ?
(isExecutable) ? "FolderStatus16x16" : "FolderClosedLocked16x16" :
(isWritable) ? "FileUnknown16x16" : "FileLocked16x16"));
m_pNonFileListView->signalState();
}
item->setText(0, file);
QDateTime localDate = info.lastModified();
item->setModifiedDate(1, &localDate, localDate.toString(LookAndFeel::g_dateTimeFormat));
}
}
}
//----------------------------------------------------------------------------
void CvsDirectory::removeTmpEntries(QString name) {
QStringList::Iterator it;
if (name.isNull()) {
for ( it = m_tmpEntries.begin(); it != m_tmpEntries.end(); it++ ) {
setEntryState(*it,ES_unknown);//adapt the warn level before removal
m_CvsEntries.remove(*it);
removeEntry(*it);
}
m_tmpEntries.clear();
} else {
it = m_tmpEntries.find (name);
if (it != m_tmpEntries.end ()) {
setEntryState(name,ES_unknown);//adapt the warn level before removal
m_CvsEntries.remove(name);
removeEntry(name);
m_tmpEntries.remove(it);
}
}
//remove virtual dirs
Directory *myChild = Directory::firstChild();
while (myChild) {
if (myChild->isVirtual()) {
Directory * myTmpChild = myChild;
myChild = myChild->nextSibling();
if (name.isNull() || (name == myTmpChild->shortName()) ) {
delete (myTmpChild);
setDirState(ES_unknown,true);//reset state
if (!name.isNull()) break;
}
} else {
myChild = myChild->nextSibling();
}
}
}
//----------------------------------------------------------------------------
void CvsDirectory::recRemoveTmpEntries(bool allProjects) {
if (m_disabled) return;
CvsDirectory * C = firstChild();
while( C ) {
if (allProjects || (C->topControlledDir() == topControlledDir()) ) C->recRemoveTmpEntries(allProjects);
C = C->nextSibling();
}
removeTmpEntries();
}
//----------------------------------------------------------------------------
bool CvsDirectory::recCopyTree(QString src,QString dst, bool deleteSource /*=TRUE*/) {
QDir newDir;
QString dstDir = dst+"/"+src.mid(src.findRev("/"));
if (!newDir.mkdir(dstDir) ) {
qDebug("can't create dir: "+dstDir );
return FALSE;
}
//dirs first
QStringList AllSubDirs;
QDir D( src);
D.setFilter(QDir::Dirs);
AllSubDirs = D.entryList();
// remove . and ..
AllSubDirs.remove( "." );
AllSubDirs.remove( ".." );
AllSubDirs.remove( "CVS" );
QStringList::Iterator fileit; //VC6 does _not_ like it...
for (fileit = AllSubDirs.begin(); fileit != AllSubDirs.end(); fileit++) {
recCopyTree(src+"/"+(*fileit),dstDir,deleteSource);
}
//now the files
QStringList AllFilesInDirectory;
D.setFilter( QDir::Files | QDir::Hidden);
AllFilesInDirectory = D.entryList();
for (fileit = AllFilesInDirectory.begin(); fileit != AllFilesInDirectory.end(); fileit++) {
QString srcName = src+"/"+(*fileit);
QString dstName = dstDir+"/"+(*fileit);
QFileInfo fInfo(srcName);
int permission = 0;
if (fInfo.isReadable()) permission = (permission | READABLE);
if (fInfo.isWritable()) permission = (permission | WRITEABLE);
if (fInfo.isExecutable()) permission = (permission | EXECUTABLE);
if (!copyFile(srcName, dstName, permission, deleteSource) ) {
qDebug("can't copy file: "+srcName+" -> "+dstName);
return FALSE;
}
}
return TRUE;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
bool CvsDirectory::parseCallResult(CvsBuffer *output, int icmd, QStringList *stringList) {
bool retVal = TRUE;
m_lastErrorMsg = "";
CvsDirectory *pCurCvsDir = NULL;
CvsDirectory *pCurCvsLastUpdateDir = NULL;
QStringList curCvsUpdateFileList;
QStringList addedDirList;
QString curCvsFileName;
EntryStates locCurCvsState = ES_unknown ;
unsigned int len = (*output).numLines();
int pos = 0;
EntryStates_E stateToSet = ES_unknown;//init to prevent compiler warning
QString tmp, fullPath, prevFullPath, path, repository;
prevFullPath = "";
fullPath = "";
//some presets
if (stringList && !stringList->isEmpty ()) {
switch (icmd) {
case CVS_UPDATE_FILES_CMD: {
curCvsUpdateFileList = *stringList;
}
default:
break;
}
}
QString line;
for (unsigned int i = 0; i<len;i++) {
line = (*output).textLine(i);
if (line.isEmpty()) continue;
switch(icmd) {
case CVS_COMMIT_CMD:
if (line.startsWith("Removing ")) {// commit after remove
curCvsFileName = line.mid(9, line.length() - 10); //truncate ";"
stateToSet=ES_unknown; // we have to set a state to adapt the warnlevel
} else if(line.startsWith("Checking in ")) {//followed of filename
curCvsFileName = line.mid(12, line.length() - 13); //truncate ";"
stateToSet=ES_up_to_date;
} else if(line.compare("done") == 0){//commit completed successfully
if(pCurCvsDir && curCvsFileName.length()) {
pCurCvsDir->setEntryState(curCvsFileName, stateToSet);
if (stateToSet==ES_unknown) pCurCvsDir->removeEntry(curCvsFileName); // must not appear in entries any more
}
curCvsFileName="";
stateToSet=ES_unknown;
break;
} else if ( (pos = line.find(",v <-- ")) > 0 ) {//cvs 1.12.xxx series
curCvsFileName = rcsToFileName (line.left (pos));
} else if (line.startsWith("new revision: ") || line.startsWith("initial revision: ") ) {//cvs 1.12.xxx series
if (line.startsWith("new revision: delete")) stateToSet=ES_unknown;
else stateToSet=ES_up_to_date;
if(pCurCvsDir && curCvsFileName.length()) {
pCurCvsDir->setEntryState(curCvsFileName, stateToSet);
if (stateToSet==ES_unknown) pCurCvsDir->removeEntry(curCvsFileName); // must not appear in entries any more
}
curCvsFileName="";
stateToSet=ES_unknown;
break;
} else {
continue; //nothing found
}
pos = curCvsFileName.findRev("/");
if (pos > -1) { //located in subdir
fullPath = m_fullName + "/" + curCvsFileName.mid(0, pos);
removeDoubleSlashes(fullPath);
curCvsFileName = curCvsFileName.mid(pos + 1);
if(fullPath.compare(prevFullPath)) { // change subdir
pCurCvsDir = dyncast_cvsdir(searchDirOfPath(fullPath));
prevFullPath = fullPath;
}
} else {
pCurCvsDir = this; //no subdir
fullPath = "";
prevFullPath = "";
}
break;
case CVS_STATUS_CMD:
if((pos = line.find("Examining ")) > -1) {
path = line.mid(pos + 10);
path = path.stripWhiteSpace();
//is a subdir?
if (path.compare(".") == 0) pCurCvsDir = this;
else {
fullPath = m_fullName + "/" + path;
removeDoubleSlashes(fullPath);
//locate dir
pCurCvsDir = dyncast_cvsdir(searchDirOfPath(fullPath));//search only for non-virtual dirs
}
} else if(line.find("File:") == 0){//status output of next file begins
curCvsFileName = line.mid(6, line.find("\t", 6) - 6);
curCvsFileName = curCvsFileName.stripWhiteSpace();
if(curCvsFileName.find("no file") == 0) {
curCvsFileName = curCvsFileName.mid(8);
}
if(line.find("Up-to-date") > -1){
locCurCvsState = ES_up_to_date;
} else if(line.find("Locally Modified") > -1){
locCurCvsState = ES_modified;
} else if(line.find("Needs Patch") > -1){
locCurCvsState = ES_needs_patch;
} else if(line.find("Needs Merge") > -1){
locCurCvsState = ES_needs_merge;
} else if(line.find("Needs Checkout") > -1){
locCurCvsState = ES_needs_checkout;
} else if(line.find("File had conflicts on merge") > -1){
locCurCvsState = ES_conflict;
} else if(line.find("Locally Added") > -1){
locCurCvsState = ES_added;
} else if(line.find("Locally Removed") > -1){
locCurCvsState = ES_removed;
} else if (line.find ("Entry Invalid") > -1) {
locCurCvsState = ES_needs_remove;
}
//set state
if(pCurCvsDir) {
pCurCvsDir->setAndAppendEntry(curCvsFileName, locCurCvsState);
}
}
break;
case CVS_STATUS_FILES_CMD:
if(line.find("File:") == 0){//status output of next file begins
curCvsFileName = line.mid(6, line.find("\t", 6) - 6);
curCvsFileName = curCvsFileName.stripWhiteSpace();
if(curCvsFileName.find("no file") == 0) {
curCvsFileName = curCvsFileName.mid(8);
}
if(line.find("Up-to-date") > -1){
locCurCvsState = ES_up_to_date;
} else if(line.find("Locally Modified") > -1){
locCurCvsState = ES_modified;
} else if(line.find("Needs Patch") > -1){
locCurCvsState = ES_needs_patch;
} else if(line.find("Needs Merge") > -1){
locCurCvsState = ES_needs_merge;
} else if(line.find("Needs Checkout") > -1){
locCurCvsState = ES_needs_checkout;
} else if(line.find("File had conflicts on merge") > -1){
locCurCvsState = ES_conflict;
} else if(line.find("Locally Added") > -1){
locCurCvsState = ES_added;
} else if(line.find("Locally Removed") > -1){
locCurCvsState = ES_removed;
} else if (line.find ("Entry Invalid") > -1) {
locCurCvsState = ES_needs_remove;
}
} else if ( (line.find("Repository revision:") > -1) && ((pos = line.find ("\t/")) > -1) ) {//repository of fileName
QString file = line.mid (pos + 1);
file = rcsToFileName (file.left (file.length ()-2));
if ((pos = file.findRev ("/")) > -1) {
path = file.left (pos);
path = path.stripWhiteSpace ();
file = file.mid (pos + 1);
//is a subdir?
fullPath = m_fullName + "/" + path;
removeDoubleSlashes (fullPath);
//locate dir
pCurCvsDir = dyncast_cvsdir (searchDirOfPath(fullPath));
} else {
pCurCvsDir = this;
}
assert (file == curCvsFileName);
//set state
if(pCurCvsDir) {
pCurCvsDir->setAndAppendEntry(curCvsFileName, locCurCvsState);
}
}
break;
case CVS_GET_TAG_INFO_PROJECT_CMD:
case CVS_GET_TAG_INFO_FILES_CMD:
if (pos == 0) {
if (line.find("Existing Tags:") > -1) pos = 1;
}
else if ( (line.find("No Tags Exist") > -1)
|| (line.startsWith("cvs "))
|| (line.startsWith("===================================================================")) ) {
pos = 0;
} else {
QRegExp rx( "(\\S+)(?:\\s*\\()(\\w+):" );
rx.search(line);
//qDebug("cap(0): ->"+rx.cap(0)+"<- cap(1): ->"+rx.cap(1)+"<- cap(2): ->"+rx.cap(2)+"<-");
QString txt;
if (rx.cap(2).startsWith("branch")) {
txt = "B: "+rx.cap(1);
} else if (rx.cap(2).startsWith("revision")) {
txt = "T: "+rx.cap(1);
} else {
qDebug("unknown line on GET_TAG_INFO: "+line);
continue;
}
if (stringList->find(txt) == stringList->end()) {
stringList->append(txt);
}
}
break;
case CVS_UPDATE_DIR_CMD:
//updating of dir ... welches verzeichnis?
if ((pos = line.find("Updating ")) > -1) {
//cvs changed dir, put last scanned dir to up-to-date or remove if not physically available
if (pCurCvsLastUpdateDir) {
QDir dir(pCurCvsLastUpdateDir->fullName());
if (dir.exists()) {
pCurCvsLastUpdateDir->setFilesToUpToDate(curCvsUpdateFileList);
} else {
((CvsDirectory*)pCurCvsLastUpdateDir->parent())->removeChild(pCurCvsLastUpdateDir->fullName());
}
}
path = line.mid(pos + 9);
path = path.stripWhiteSpace();
//is a subdir?
if (path.compare(".") == 0) fullPath = m_fullName;
else fullPath = m_fullName + "/" + path;
removeDoubleSlashes(fullPath);
//locate dir
pCurCvsLastUpdateDir = dyncast_cvsdir(searchDirOfPath(fullPath));//search only for non-virtual dirs
if (!pCurCvsLastUpdateDir) {//not scanned or just newly added?
addedDirList.append(fullPath);
}
//fill filelist with entries of located dir
curCvsUpdateFileList.clear();
if (pCurCvsLastUpdateDir) pCurCvsLastUpdateDir->fillFileListWithEntries(curCvsUpdateFileList);
}
locCurCvsState = ES_unknown;
//filestate...
if((line.find("P ") == 0)
|| (line.find("U ") == 0)){
curCvsFileName = line.mid(2);
locCurCvsState = ES_up_to_date;
} else if(line.find("M ") == 0){
curCvsFileName = line.mid(2);
locCurCvsState = ES_modified;
} else if(line.find("C ") == 0){
curCvsFileName = line.mid(2);
locCurCvsState = ES_conflict;
} else if(line.find("A ") == 0){
curCvsFileName = line.mid(2);
locCurCvsState = ES_added;
} else if(line.find("R ") == 0){
curCvsFileName = line.mid(2);
locCurCvsState = ES_removed;
} else if(line.find("RCS file: ") == 0) {
curCvsFileName = rcsToFileName (line.left (line.length ()-2).mid (10));
locCurCvsState = ES_modified;
} else if (line.find(": scheduling ") > -1) {
curCvsFileName = line.mid(line.find(": scheduling ")+13);
curCvsFileName.truncate(curCvsFileName.find(" for removal"));
locCurCvsState = ES_removed;
} else if (line.find("warning: conflicts during merge") > -1) {//filename allready extracted at <Merging differences between ...>
locCurCvsState = ES_conflict;
} else {
bool remove = true;
int pos1,pos2;
if (((pos1 = line.find (": ")) > -1) && ((pos2 = line.find (" is no longer in the repository")) > -1)) {
curCvsFileName = line.mid (pos1 + 2, pos2 - pos1 - 2);
} else if (((pos1 = line.find (": ")) > -1) && ((pos2 = line.find (" should be removed and is still there")) > -1)) {
curCvsFileName = line.mid (pos1 + 2, pos2 - pos1 - 2);
m_lastErrorMsg += line+"\n";
retVal = FALSE;
locCurCvsState = ES_conflict;//fixme: untested
remove = false;
} else if (((pos1=line.find("warning: ")) > -1) && ((pos2=line.find(" is not (any longer) pertinent")) > -1)) {
curCvsFileName = line.mid(pos1+9,pos2-pos1-9);
} else if (((pos1=line.find("warning: new-born ")) > -1) && ((pos2=line.find(" has disappeared")) > -1)) {
curCvsFileName = line.mid(pos1+18,pos2-pos1-18);
} else if (((pos1=line.find("conflict: ")) > -1) && ((pos2=line.find(" is modified but no longer in the repository")) > -1)) {
curCvsFileName = line.mid (pos1 + 10, pos2 - pos1 - 10);
m_lastErrorMsg += line+"\n";
retVal = FALSE;
i++;//this is dirty but easier than using a separate check for skipping the next line.
//the next line needs to be skipped to not parse the conflict info given by cvs since it differs from CVS/Entries
locCurCvsState = ES_modified;
remove = false;
} else if ( (((pos1=line.find("conflict: ")) > -1) && ((pos2=line.find(" has been added, but already exists")) > -1))
|| (((pos1=line.find("conflict: ")) > -1) && ((pos2=line.find(" created independently by second party")) > -1)) ) {
curCvsFileName = line.mid (pos1 + 10, pos2 - pos1 - 10);
m_lastErrorMsg += line+"\n";
retVal = FALSE;
i++;//this is dirty but easier than using a separate check for skipping the next line.
//the next line needs to be skipped to not parse the conflict info given by cvs since it differs from CVS/Entries
locCurCvsState = ES_conflict;//fixme: untested
remove = false;
} else if (((pos1 = line.find ("conflict: removed ")) > -1) && ((pos2 = line.find (" was modified by second party")) > -1)) {
curCvsFileName = line.mid (pos1 + 18, pos2 - pos1 - 18);
m_lastErrorMsg += line + "\n";
retVal = FALSE;
i++;//this is dirty but easier than using a separate check for skipping the next line.
//the next line needs to be skipped to not parse the conflict info given by cvs since it differs from CVS/Entries
locCurCvsState = ES_conflict;//fixme: untested
remove = false;
} else if (((pos1 = line.find ("move away ")) > -1) && ((pos2 = line.find ("; it is in the way")) > -1)) {
curCvsFileName = line.mid (pos1 + 10, pos2 - pos1 - 10);
m_lastErrorMsg += line + "\n";
retVal = FALSE;
i++;//this is dirty but easier than using a separate check for skipping the next line.
//the next line needs to be skipped to not parse the conflict info given by cvs since it differs from CVS/Entries
locCurCvsState = ES_needs_patch;
remove = false;
} else {
break;
}
removeFileNameInconsistencies(curCvsFileName);
if((pos1 = curCvsFileName.findRev("/")) > -1) //is a subdir?
curCvsFileName = curCvsFileName.mid(pos1 + 1);
if(pCurCvsLastUpdateDir) {
pCurCvsLastUpdateDir->setAndAppendEntry(curCvsFileName, locCurCvsState);//we have to set a state to adapt the warnlevel
if (remove) pCurCvsLastUpdateDir->removeEntry(curCvsFileName);
curCvsUpdateFileList.remove(curCvsFileName);
}
break;
}
if(locCurCvsState != ES_unknown) {
removeFileNameInconsistencies(curCvsFileName);
//is file located in subdir?
if((pos = curCvsFileName.findRev("/")) > -1)
curCvsFileName = curCvsFileName.mid(pos + 1);
if (pCurCvsLastUpdateDir && curCvsFileName.length ()) {
pCurCvsLastUpdateDir->setAndAppendEntry(curCvsFileName, locCurCvsState);
curCvsUpdateFileList.remove(curCvsFileName);
}
}
break;
case CVS_UPDATE_FILES_CMD:
locCurCvsState = ES_unknown;
//filestate...
if((line.find("P ") == 0)
|| (line.find("U ") == 0)){
curCvsFileName = line.mid(2);
locCurCvsState = ES_up_to_date;
} else if(line.find("M ") == 0){
curCvsFileName = line.mid(2);
locCurCvsState = ES_modified;
} else if(line.find("C ") == 0){
curCvsFileName = line.mid(2);
locCurCvsState = ES_conflict;
} else if(line.find("A ") == 0){
curCvsFileName = line.mid(2);
locCurCvsState = ES_added;
} else if(line.find("R ") == 0){
curCvsFileName = line.mid(2);
locCurCvsState = ES_removed;
} else if(line.find("RCS file: ") == 0) {
curCvsFileName = rcsToFileName (line.left (line.length ()-2).mid (10));
locCurCvsState = ES_modified;
} else if (line.find("warning: conflicts during merge") > -1) {//filename allready extracted at <Merging differences between ...>
locCurCvsState = ES_conflict;
} else if (line.find(": scheduling ") > -1) {
curCvsFileName = line.mid(line.find(": scheduling ")+13);
curCvsFileName.truncate(curCvsFileName.find(" for removal"));
locCurCvsState = ES_removed;
} else {
bool remove = true;
int pos1,pos2;
if (((pos1 = line.find (": ")) > -1) && ((pos2 = line.find (" is no longer in the repository")) > -1)) {
curCvsFileName = line.mid (pos1 + 2, pos2 - pos1 - 2);
} else if (((pos1 = line.find (": ")) > -1) && ((pos2 = line.find (" should be removed and is still there")) > -1)) {
curCvsFileName = line.mid (pos1 + 2, pos2 - pos1 - 2);
m_lastErrorMsg += line+"\n";
retVal = FALSE;
locCurCvsState = ES_conflict;//fixme: untested
remove = false;
} else if (((pos1=line.find("warning: ")) > -1) && ((pos2=line.find(" is not (any longer) pertinent")) > -1)) {
curCvsFileName = line.mid(pos1+9,pos2-pos1-9);
} else if (((pos1=line.find("warning: new-born ")) > -1) && ((pos2=line.find(" has disappeared")) > -1)) {
curCvsFileName = line.mid(pos1+18,pos2-pos1-18);
} else if (((pos1=line.find("conflict: ")) > -1) && ((pos2=line.find(" is modified but no longer in the repository")) > -1)) {
curCvsFileName = line.mid (pos1 + 10, pos2 - pos1 - 10);
m_lastErrorMsg += line+"\n";
retVal = FALSE;
i++;//this is dirty but easier than using a separate check for skipping the next line.
//the next line needs to be skipped to not parse the conflict info given by cvs since it differs from CVS/Entries
locCurCvsState = ES_modified;
remove = false;
} else if ( (((pos1=line.find("conflict: ")) > -1) && ((pos2=line.find(" has been added, but already exists")) > -1))
|| (((pos1=line.find("conflict: ")) > -1) && ((pos2=line.find(" created independently by second party")) > -1)) ) {
curCvsFileName = line.mid (pos1 + 10, pos2 - pos1 - 10);
m_lastErrorMsg += line+"\n";
retVal = FALSE;
i++;//this is dirty but easier than using a separate check for skipping the next line.
//the next line needs to be skipped to not parse the conflict info given by cvs since it differs from CVS/Entries
locCurCvsState = ES_conflict;//fixme: untested
remove = false;
} else if (((pos1 = line.find ("conflict: removed ")) > -1) && ((pos2 = line.find (" was modified by second party")) > -1)) {
curCvsFileName = line.mid (pos1 + 18, pos2 - pos1 - 18);
m_lastErrorMsg += line + "\n";
retVal = FALSE;
i++;//this is dirty but easier than using a separate check for skipping the next line.
//the next line needs to be skipped to not parse the conflict info given by cvs since it differs from CVS/Entries
locCurCvsState = ES_conflict;//fixme: untested
remove = false;
} else if (((pos1 = line.find ("move away ")) > -1) && ((pos2 = line.find ("; it is in the way")) > -1)) {
curCvsFileName = line.mid (pos1 + 10, pos2 - pos1 - 10);
m_lastErrorMsg += line + "\n";
retVal = FALSE;
i++;//this is dirty but easier than using a separate check for skipping the next line.
//the next line needs to be skipped to not parse the conflict info given by cvs since it differs from CVS/Entries
locCurCvsState = ES_needs_patch;
remove = false;
} else {
break;
}
removeFileNameInconsistencies(curCvsFileName);
setAndAppendEntry(curCvsFileName, locCurCvsState);//we have to set a state to adapt the warnlevel
if (remove) removeEntry(curCvsFileName);
break;
}
curCvsFileName = curCvsFileName.stripWhiteSpace();
if(locCurCvsState != ES_unknown ) {
removeFileNameInconsistencies(curCvsFileName);
curCvsUpdateFileList.remove (curCvsFileName);
if (curCvsFileName.length ()) {
//remove tmp entries in case the file was there but not under cvs control
//the tmp entrie is the result of query update command
removeTmpEntries (curCvsFileName);
setAndAppendEntry(curCvsFileName, locCurCvsState);
}
}
break;
case CVS_QUERY_UPDATE_ALL_CMD:
case CVS_QUERY_UPDATE_CMD:
locCurCvsState = ES_unknown;
if((pos = line.find("Updating ")) > -1) {
path = line.mid(pos + 9);
path = path.stripWhiteSpace();
//is a subdir?
if (path.compare(".") == 0) fullPath = m_fullName;
else fullPath = m_fullName + "/" + path;
removeDoubleSlashes(fullPath);
//locate dir
pCurCvsDir = dyncast_cvsdir(searchDirOfPath(fullPath,VIRTUAL));
if (!pCurCvsDir) {
Directory * tmpDir = dyncast_dir(searchLastValidDirOfPath(fullPath));
if (tmpDir && !CvsOptions::g_bShowVirtualInFiletab) addDir(fullPath, VIRTUAL);//add as virtual
pCurCvsDir = dyncast_cvsdir(searchDirOfPath(fullPath,VIRTUAL));//let's see if it's there
}
//put all files of dir into list
//and don't clear list because buggy cvs output returns filenames in wrong order
//and so we set untouched files up-to-date after we parsed the whole output
if (pCurCvsDir) {
pCurCvsDir->fillFileListWithFullNameEntries(curCvsUpdateFileList);
}
break;
}
//filestate... differs from CVS_UPDATE_DIR_CMD 'cause it's just a query
else if((line.find("M ") == 0)){
if (curCvsFileName == line.mid(2)) break;//skip modified info after 'needs merge'
curCvsFileName = line.mid(2);
locCurCvsState = ES_modified;
} else if((line.find("U ") == 0)){
curCvsFileName = line.mid(2);
locCurCvsState = ES_needs_patch;
} else if((line.find("P ") == 0)){
curCvsFileName = line.mid(2);
locCurCvsState = ES_needs_patch;
} else if(line.find("C ") == 0){
curCvsFileName = line.mid(2);
locCurCvsState = ES_needs_merge;
} else if(line.find("A ") == 0){
curCvsFileName = line.mid(2);
locCurCvsState = ES_added;
} else if(line.find("R ") == 0){
curCvsFileName = line.mid(2);
locCurCvsState = ES_removed;
} else if(line.find("RCS file: ") == 0) {
curCvsFileName = rcsToFileName (line.left (line.length ()-2).mid (10));
locCurCvsState = ES_needs_merge;
// } else if (line.find("warning: conflicts during merge") > -1) {//filename allready extracted at <Merging differences between ...>
// locCurCvsState = ES_conflict;
} else {
int pos1,pos2;
if (((pos1 = line.find (": ")) > -1) && ((pos2 = line.find (" is no longer in the repository")) > -1)) {
curCvsFileName = line.mid (pos1 + 2, pos2 - pos1 - 2);
locCurCvsState = ES_needs_remove;
} else if (((pos1 = line.find ("warning: ")) > -1) && ((pos2 = line.find (" is not (any longer) pertinent")) > -1)) {
curCvsFileName = line.mid (pos1 + 9, pos2 - pos1 - 9);
locCurCvsState = ES_needs_checkout;
} else if ( ((pos1 = line.find ("New directory ")) > -1) && ((pos2 = line.find(" -- ignored" )) > -1) ) {
curCvsFileName = line.mid (pos1 + 14, pos2 - pos1 - 14);
locCurCvsState = ES_missing_dir;
} else if (((pos1 = line.find (": ")) > -1) && ((pos2 = line.find (" should be removed and is still there")) > -1)) {
curCvsFileName = line.mid (pos1 + 2, pos2 - pos1 - 2);
locCurCvsState = ES_conflict;//fixme: untested
} else if (((pos1 = line.find ("warning: new-born ")) > -1) && ((pos2 = line.find (" has disappeared")) > -1)) {
curCvsFileName = line.mid (pos1 + 18, pos2 - pos1 - 18);
locCurCvsState = ES_removed;
} else if (((pos1=line.find("conflict: ")) > -1) && ((pos2=line.find(" is modified but no longer in the repository")) > -1)) {
curCvsFileName = line.mid (pos1 + 10, pos2 - pos1 - 10);
m_lastErrorMsg += line+"\n";
retVal = FALSE;
i++;//this is dirty but easier than using a separate check for skipping the next line.
//the next line needs to be skipped to not parse the conflict info given by cvs since it differs from CVS/Entries
locCurCvsState = ES_conflict;//fixme: untested
} else if ( (((pos1=line.find("conflict: ")) > -1) && ((pos2=line.find(" has been added, but already exists")) > -1))
|| (((pos1=line.find("conflict: ")) > -1) && ((pos2=line.find(" created independently by second party")) > -1)) ) {
curCvsFileName = line.mid (pos1 + 10, pos2 - pos1 - 10);
m_lastErrorMsg += line+"\n";
retVal = FALSE;
i++;//this is dirty but easier than using a separate check for skipping the next line.
//the next line needs to be skipped to not parse the conflict info given by cvs since it differs from CVS/Entries
locCurCvsState = ES_conflict;
}
}
if (locCurCvsState != ES_unknown) {
removeFileNameInconsistencies(curCvsFileName);
curCvsUpdateFileList.remove(m_fullName+"/"+curCvsFileName); //don't set to up-to-date
//now set new state
//is file located in subdir?
if((pos = curCvsFileName.findRev("/")) > -1) {
path = curCvsFileName.left(pos);
path = path.stripWhiteSpace();
QString fn = curCvsFileName.mid(pos + 1);
//is a subdir?
fullPath = m_fullName + "/" + path;
removeDoubleSlashes(fullPath);
//locate dir
pCurCvsDir = dyncast_cvsdir(searchDirOfPath(fullPath,VIRTUAL));
if (pCurCvsDir) { //subdir
if (locCurCvsState == ES_needs_checkout && pCurCvsDir->m_entries.find(fn)) {
//state is bivalent in this case
locCurCvsState = ES_needs_patch;
}
switch (locCurCvsState) {
case ES_needs_checkout: {
//if file doesn't exists in entries, we have to add it to be displayable in cvs-views
pCurCvsDir->setAndAppendTmpEntryQueryUpdate(fn);
QFileInfo fInfo (m_fullName + "/" + fn);
if (fInfo.exists ()) {
locCurCvsState = ES_needs_patch;
}
pCurCvsDir->setAndAppendEntry(fn, locCurCvsState);
break;
}
case ES_missing_dir: {
if (CvsOptions::g_bShowVirtualInFiletab) {
//if file doesn't exists in entries, we have to add it to be displayable in cvs-views
if (pCurCvsDir->setAndAppendTmpEntryQueryUpdate(fn)) {
pCurCvsDir->setAndAppendEntry(fn, locCurCvsState);
}
} else {
if (!searchDirOfPath(fullPath+"/"+fn, VIRTUAL)) {//don't ever add twice
addDir(fullPath+"/"+fn, VIRTUAL);//add as virtual
}
}
break;
}
default: {
pCurCvsDir->setAndAppendEntry(fn, locCurCvsState);
break;
}
}
}
} else if (curCvsFileName.length ()) {
if (locCurCvsState == ES_needs_checkout && m_entries.find(curCvsFileName)) {
//state is bivalent in this case
locCurCvsState = ES_needs_patch;
}
switch (locCurCvsState) {
case ES_needs_checkout: {
//if file doesn't exists in entries, we have to add it to be displayable in cvs-views
setAndAppendTmpEntryQueryUpdate(curCvsFileName);
QFileInfo fInfo (fullPath + "/" + curCvsFileName);
if (fInfo.exists ()) {
locCurCvsState = ES_needs_patch;
}
setAndAppendEntry(curCvsFileName, locCurCvsState); // local dir
break;
}
case ES_missing_dir: {
if (CvsOptions::g_bShowVirtualInFiletab) {
//if file doesn't exists in entries, we have to add it to be displayable in cvs-views
if (setAndAppendTmpEntryQueryUpdate(curCvsFileName)) {
setAndAppendEntry(curCvsFileName, locCurCvsState); // local dir
}
} else {
if (!searchDirOfPath(m_fullName+"/"+curCvsFileName, VIRTUAL)) {//don't ever add twice
addDir(m_fullName+"/"+curCvsFileName, VIRTUAL);//add as virtual
}
}
break;
}
default: {
setAndAppendEntry(curCvsFileName, locCurCvsState); // local dir
break;
}
}
}
}
break;
case CVS_ADD_CMD:
if ( (pos=line.find("scheduling file ")) > -1) {
pos += 16;
int endPos;
if ( (endPos=line.find(" for addition",pos)) > -1) {
curCvsFileName = line.mid(pos,endPos-pos);
removeFileNameInconsistencies(curCvsFileName);
setAndAppendEntry(curCvsFileName, ES_added);
}
} else if ( (pos=line.find("Re-adding file ")) > -1) {
pos += 15;
int endPos;
if ( (endPos=line.find(" after dead revision",pos)) > -1) {
curCvsFileName = line.mid(pos,endPos-pos);
removeFileNameInconsistencies(curCvsFileName);
setAndAppendEntry(curCvsFileName, ES_added);
}
} else if(line.find("U ")==0){//get the filename
curCvsFileName = line.mid(2);
curCvsFileName = curCvsFileName.stripWhiteSpace();
setAndAppendEntry(curCvsFileName, ES_probably_up_to_date);
}
break;
case CVS_REMOVE_CMD:
if ( (pos=line.find("scheduling ")) > -1) {
pos += 11;
int endPos;
if ( (endPos=line.find(" for removal",pos)) > -1) {
curCvsFileName = line.mid(pos,endPos-pos);
removeFileNameInconsistencies(curCvsFileName);
setAndAppendEntry(curCvsFileName, ES_removed);
}
}
break;
case CVS_REMOVEDIR_CMD:
//removing of dir ...
if((pos = line.find("Removing ")) > -1) {
path = line.mid(pos + 9);
path = path.stripWhiteSpace();
//is a subdir?
if (path.compare(".") == 0) fullPath = m_fullName;
else fullPath = m_fullName + "/" + path;
removeDoubleSlashes(fullPath);
//locate dir
pCurCvsLastUpdateDir = dyncast_cvsdir(searchDirOfPath(fullPath));
} else if ( (pos=line.find("scheduling ")) > -1) {
pos += 11;
int endPos;
if ( (endPos=line.find(" for removal",pos)) > -1) {
QString curCvsFileName = line.mid(pos,endPos-pos);
removeFileNameInconsistencies(curCvsFileName);
//is file located in subdir?
if((pos = curCvsFileName.findRev("/")) > -1) {
curCvsFileName = curCvsFileName.mid(pos + 1);
}
if(pCurCvsLastUpdateDir) {
pCurCvsLastUpdateDir->setAndAppendEntry(curCvsFileName, ES_removed);
}
}
}
break;
case CVS_MERGE_REV_INTO_CMD:
if (line.find("RCS file: ") == 0) {
curCvsFileName = rcsToFileName (line.left (line.length ()-2).mid (10));
setAndAppendEntry(curCvsFileName, ES_modified);
} else if (curCvsFileName.length () && (line.find("warning: conflicts during merge") > -1)) {//filename allready extracted at <Merging differences between ...>
locCurCvsState = ES_conflict;
setAndAppendEntry(curCvsFileName, ES_conflict);
}
break;
case CVS_RESURRECT_CMD:
if(line.find("U ")==0){//get the filename
curCvsFileName = line.mid(2);
curCvsFileName = curCvsFileName.stripWhiteSpace();
} else if (line.findRev("resurrected")>=0) {//finished, set the state
setAndAppendEntry(curCvsFileName, ES_up_to_date);
}
break;
}
}
//some things have to be done when parsing has finished
switch(icmd) {
case CVS_QUERY_UPDATE_ALL_CMD:
case CVS_QUERY_UPDATE_CMD: { //set all file not mentioned to up-to-date
QString tmp,file;
while (!curCvsUpdateFileList.isEmpty()) {
file = tmp = curCvsUpdateFileList.first();
//is file located in subdir?
if((pos = tmp.findRev("/")) > -1) {
path = tmp.left(pos);
path = path.stripWhiteSpace();
tmp = tmp.mid(pos + 1);
removeDoubleSlashes(path);
//locate dir
pCurCvsDir = dyncast_cvsdir(searchDirOfPath(path));
if(pCurCvsDir) { //subdir
pCurCvsDir->setAndAppendEntry(tmp, ES_up_to_date);
}
} else if (tmp.length ()) {
setAndAppendEntry(tmp, ES_up_to_date); // local dir
}
curCvsUpdateFileList.remove(file);
}
break;
}
case CVS_UPDATE_FILES_CMD: {//set files not mentioned by cvs output to up-to-date
while (!curCvsUpdateFileList.isEmpty()) {
QString tmp = curCvsUpdateFileList.first();
curCvsUpdateFileList.remove (tmp);
pCurCvsDir = NULL;
QString fileName = tmp;
if (fileName.length ()) {
pCurCvsDir = this;
}
if (!pCurCvsDir || !pCurCvsDir->setEntryState (fileName, ES_up_to_date)) {
Debug::g_pLog->log (Debug::LL_THE_OLD_MAN_AND_THE_SEA, "Filename not found in entries: "+tmp);
}
}
break;
}
case CVS_UPDATE_DIR_CMD: { //we didn't set states to up-to-date for the finally scanned dir yet
if (pCurCvsLastUpdateDir) {
QDir dir(pCurCvsLastUpdateDir->fullName());
if (dir.exists()) {
pCurCvsLastUpdateDir->setFilesToUpToDate(curCvsUpdateFileList);
} else {
((CvsDirectory*)pCurCvsLastUpdateDir->parent())->removeChild(pCurCvsLastUpdateDir->fullName());
}
}
while (!addedDirList.isEmpty()) {//add new dirs, all in up to date state since they are just updated
QString dirName = addedDirList.first();
CvsDirectory * tmpDir = dyncast_cvsdir(searchLastValidDirOfPath(dirName));
if (tmpDir) {
QString newDir = dirName.left(dirName.find("/",tmpDir->fullName().length()+1));
if ( !getDisabled(newDir) && tmpDir->fullName().compare(newDir)) {//only add once
//check if exists, don't know wether cvs runns in 'prune empty dirs' mode
QFileInfo info(newDir);
if (info.exists()) {
if (tmpDir->m_isAnalyzedDir) {//don't continue if not analyzed in on-the-fly-mode
DirBase * vDir = searchDirOfPath(dirName,true);
if (vDir && vDir->isVirtual()) {//remove virtual dir before adding the real dir
delete vDir;
setDirState(ES_unknown,true);
}
CvsDirectory * unanalyzedDir = dyncast_cvsdir(tmpDir->addDir(newDir));//add in case it was just updated
if (unanalyzedDir && tmpDir->isOpen()) {//will not be analyzed on open() because it is allready open
unanalyzedDir->analyzeDirs();
}
}
}
}
} else {
Debug::g_pLog->log (Debug::LL_INFO, "No valid dir path found for: "+dirName);
}
addedDirList.remove(dirName);
}
break;
}
case CVS_UNEDIT_CMD: {
if (stringList) {
while (!stringList->isEmpty()) {
QString fileName = stringList->first();
stringList->remove(fileName);
setEntryState(fileName,ES_unknown);
removeEntry(fileName);
}
} else {
m_entries.clear();
QString fileName = "dummy";
setAndAppendEntry(fileName,ES_unknown);
removeEntry(fileName);
}
break;
}
default: {
break;
}
}
return retVal;
}
//--------------------------------------------------------------------------------------------
QString CvsDirectory::rcsToFileName (QString s, bool checkForAttic /* = true */) {
assert (!s.isEmpty ());
int pos = s.findRev ("/");
assert (pos > -1);
if (checkForAttic && (pos > 6) && (s.mid (pos - 6, 7) == "/Attic/")) {
s = s.remove (pos - 6, 6);
pos -= 6;
}
QString file = s.mid (pos + 1);
QString rcs = m_rootDir + "/" + m_repository + "/";
if (s.startsWith (rcs)) {
QString subPath = s.left (pos).mid (rcs.length ());
if (!subPath.isEmpty ()) {
CvsDirectory * dir = dyncast_cvsdir (searchDirOfPath (m_fullName + "/" + subPath));//search only for non-virtual dirs
if (dir) {
QString retVal = dir->rcsToFileName (s, false);
if (!retVal.isEmpty ()) {
return subPath + "/" + retVal;
}
}
} else {
return file;
}
} else {//iter
CvsDirectory * C = firstChild();
while( C ) {
QString retVal = C->rcsToFileName (s, false);
if (!retVal.isEmpty ()) {
return C->shortName () + "/" + retVal;
}
C = C->nextSibling();
}
}
return "";
}
//--------------------------------------------------------------------------------------------
void CvsDirectory::removeFileNameInconsistencies(QString & fileName) {
fileName = fileName.stripWhiteSpace();
if (fileName.startsWith("`")) fileName=fileName.mid(1);
if (fileName.endsWith("'")) fileName.truncate(fileName.length()-1);
}
// ------------------------ functions telling about cvs file state -------------------------------
bool CvsDirectory::isControlled(QString fileName) {
CvsEntries * cvsEntries = getCvsEntries();
CvsEntry * cvsEntry = cvsEntries->find(fileName);
if (cvsEntry) {
return TRUE;
} else return FALSE;
}
//--------------------------------------------------------------------------------------------
bool CvsDirectory::isBinary(QString fileName) {
CvsEntries * cvsEntries = getCvsEntries();
CvsEntry * cvsEntry = cvsEntries->find(fileName);
if (cvsEntry) {
return cvsEntry->option.b;
} else return FALSE;
}
//--------------------------------------------------------------------------------------------
bool CvsDirectory::analyzeDirs() {
if (m_isAnalyzedDir) {//don't analyze twice on setOpen()
return m_isControlledDir || m_hasControlledSubDir;
}
// qDebug("analyzing: "+m_fullName+", depth: "+QString::number(depth()));
QDir myDir(m_fullName);
myDir.setFilter( QDir::Dirs | QDir::Hidden);
QStringList subDirList = myDir.entryList();
QString path = m_fullName;
QString curSubDirName;
QFileInfo fileInfo;
Directory *item;
//is the current dir or the parent dir -- ignore it
subDirList.remove(".");
subDirList.remove("..");
subDirList.remove("CVS");
if(!subDirList.isEmpty()) {//has subdirs
if(m_fullName.length() > 1){//is not root
path += "/";
}
for(unsigned int i = 0; i < subDirList.count(); i++) {
if(globalStopAction) break; //cancel this action
curSubDirName = subDirList[i];
fileInfo.setFile(path + curSubDirName);
//ignore symlinks
if( fileInfo.isSymLink()) continue;
//ignore non-cvs dirs
if ( (!bSCANNONCVS) && (!QFileInfo(path+curSubDirName+"/CVS").exists()) ) continue;
if(fileInfo.isReadable() && fileInfo.isExecutable()) {//is a dir and readable
//at the moment lacks a test for enough mem
m_isAnalyzedDir = true;//no need to analyze again in onthefly mode
item = Directory::createChildInstance(this, path + curSubDirName);
if(item->isControlledTree()) { // fails if dir is disabled and returns true even if
// there are dirs in between that have no CVS dir
m_hasControlledSubDir = true;
}
else if (item->isDisabled()) continue;
else if (ONTHEFLYSCANNING && !item->isAnalyzed()) continue;//don't know jet if there are cvs dirs somewhere in depth
else {
delete item;
item = 0; // paranoia
}
}
}
calcDirChilds_ES_Max();
} else {//has no subdirs
m_isAnalyzedDir = true;//no need to analyze again in onthefly mode
}
if (m_isControlledDir || m_hasControlledSubDir) {
// check and set FolderState and therewith initialize caches
checkAndShowStatus(NULL,true);
return true;
} else {
return false;
}
}
//--------------------------------------------------------------------------------------------
Entries * CvsDirectory::getEntries(bool resetCache/*=false*/) {
return getCvsEntries(resetCache);
}
//----------------------------------------------------------------------------
//return QString* of files to ignore, taken from hardcoded presets plus:
//$HOME/.cvsignore plus $CVSIGNORE
//lastChecked: when this dir's ignores were last checked for changes
//changed: set to true if there was a change detected (so the dir's file cache needs a refresh)
const QString CvsDirectory::getHomeFilesToIgnore(QDateTime& lastChecked, bool& changed) {
static QString ignoreString;
static QDateTime modTimeOfIgnores;
static bool noIgnores = FALSE;
changed = TRUE;
QFile cvsignore;
cvsignore.setName(QDir::homeDirPath() + "/.cvsignore");
if (cvsignore.exists()) {
QDateTime lastModTimeOfIgnores = QFileInfo(cvsignore).lastModified();
if ( (!modTimeOfIgnores.isValid()) || (modTimeOfIgnores != lastModTimeOfIgnores)) {
ignoreString = "";
QString ign_line;
if(cvsignore.open(IO_ReadOnly)) {
QTextStream ignoreStream(&cvsignore);
while(!ignoreStream.eof()) {
ign_line = ignoreStream.readLine();
ignoreString += " " + ign_line.stripWhiteSpace();
}
cvsignore.close();
}
ignoreString = ignoreString.stripWhiteSpace();
modTimeOfIgnores = lastModTimeOfIgnores;
lastChecked = lastModTimeOfIgnores;
} else if ( lastChecked.isValid() && (lastChecked >= lastModTimeOfIgnores) ) {
changed = FALSE;
return ignoreString;
} else {
lastChecked = lastModTimeOfIgnores;
return ignoreString;
}
noIgnores = FALSE;
} else if (!noIgnores) {
noIgnores = TRUE;
} else {
changed = FALSE;
return ignoreString;
}
QString retval = CVSIGNOREFILES + " " + ignoreString;
retval = retval.stripWhiteSpace();
retval += " " + QString(getenv( "CVSIGNORE")).simplifyWhiteSpace();
int pos;
if ( (pos = retval.findRev("!")) > -1) {
ignoreString = retval.mid(pos + 1);
ignoreString = ignoreString.stripWhiteSpace();
return ignoreString;
}
//use reverse order to encrease parsing speed
ignoreString += " " + QString(getenv( "CVSIGNORE")).stripWhiteSpace() + " " + CVSIGNOREFILES;
ignoreString = ignoreString.stripWhiteSpace();
return ignoreString;
}
//--------------------------------------------------------------------------------------------
//return QString* of files to ignore, taken from per dir .cvsignore
//homeIgnores: QString* holding the files to ignore from getHomeFilesToIgnore(QDateTime& lastChecked, bool& changed)
//changed: set to true if there was a change detected (so the dir's file cache needs a refresh)
const QString CvsDirectory::getDirFilesToIgnore(const QString homeIgnores, bool& changed) {
changed = FALSE;
QFile cvsignore;
cvsignore.setName(m_fullName + "/.cvsignore");
if (cvsignore.exists()) {
QDateTime lastModTimeOfIgnores = QFileInfo(cvsignore).lastModified();
m_checkedForIgnoresFile = FALSE;
if ( (!m_lastTimeDirIgnoresChanged.isValid()) || (m_lastTimeDirIgnoresChanged != lastModTimeOfIgnores) ) {
m_pDirIgnores = "";
if(cvsignore.open(IO_ReadOnly)) {//read per dir .cvsignore
QString ign_line;
QTextStream ignoreStream(&cvsignore);
while(!ignoreStream.eof()) {
ign_line = ignoreStream.readLine();
m_pDirIgnores = m_pDirIgnores + " " + ign_line.stripWhiteSpace();
}
cvsignore.close();
}
m_pDirIgnores = m_pDirIgnores.stripWhiteSpace();
m_lastTimeDirIgnoresChanged = lastModTimeOfIgnores;
changed = TRUE;
} else {
return m_pDirIgnores;
}
} else if (!m_checkedForIgnoresFile) {
m_checkedForIgnoresFile = TRUE;
changed = TRUE;
} else {
return m_pDirIgnores;
}
int pos;
if ( (pos = m_pDirIgnores.findRev("!")) > -1) {
m_pDirIgnores = m_pDirIgnores.mid(pos + 1);
} else {
//reverse order to increase parsing speed
m_pDirIgnores = m_pDirIgnores + " " + homeIgnores;
}
m_pDirIgnores = m_pDirIgnores.stripWhiteSpace();
return m_pDirIgnores;
}
//------------------------- private local methods ---------------------------------------------------
void CvsDirectory::init(const QString& fileName)
{
m_checkedForIgnoresFile = false;
m_CvsEntries.setAutoDelete(true);
m_entriesCached = false;
Directory::init(fileName);
}
//--------------------------------------------------------------------------------------------
void CvsDirectory::fillFileListWithEntries(QStringList& fileList) {
CvsEntriesIterator it(m_CvsEntries);
while(it.current()) {
if (getEntryState(it.current()->name) != ES_missing_dir) fileList.append(it.current()->name);
++it;
}
}
//----------------------------------------------------------------------------
void CvsDirectory::fillFileListWithFullNameEntries(QStringList& fileList) {
CvsEntriesIterator it(m_CvsEntries);
while(it.current()) {
if (getEntryState(it.current()->name) != ES_missing_dir) fileList.append(m_fullName+"/"+it.current()->name);
++it;
}
}
//----------------------------------------------------------------------------
CvsEntries * CvsDirectory::getCvsEntries(bool resetCache/*=false*/) {
bool modified = FALSE;
if ( !m_entriesCached ||
(modified = entriesFileModified()) ||
(modified = entriesLogFileModified()) ||
resetCache) { // not initialized or cached jet
QFile f;
QString line;
QString logMsg;
QString path = m_fullName;
if(path.length() > 1){//is not root
path += "/";
}
m_CvsEntries.clear();
QStringList oldTmpEntries = m_tmpEntries;
m_tmpEntries.clear();
if (Debug::g_logLevel == Debug::LL_GOSSIP_MONGER) {
logMsg = m_fullName+" reading CVS dir:\n";
}
//read Tag
f.setName( path + "CVS/Tag");
if(f.open(IO_ReadOnly)) {//file is readable
QTextStream textStream(&f);
while(!textStream.atEnd()) {
line = textStream.readLine();
if ( (line.at(0)=='T') || (line.at(0)=='N') || (line.at(0)=='D') ) {
m_dirTag = line.stripWhiteSpace();
break;
} else {
qDebug(m_fullName+"/CVS/Tag contains unknown entrie: "+line);
}
}
if (Debug::g_logLevel == Debug::LL_GOSSIP_MONGER) {
f.at(0);
QTextStream s(&f);
logMsg += "CVS/Tag:\n"+s.read();
}
f.close();
} else {
m_dirTag = "";
}
//read Entries
QStringList entrieList;
f.setName(path + "CVS/Entries");
if(f.open(IO_ReadOnly)) {//file is readable
QTextStream textStream(&f);
textStream.setCodec(I18n::g_pTextDecoder->pTextCodecPool()->pCodecForName(I18n::g_nameOfDecoder));
QFileInfo fInfo(f);
m_modTimeOfEntries = fInfo.lastModified();
if (modified && (m_lastCallTime < m_modTimeOfEntries) ) {//clear align-cache, only in case of an external modification of CVS dir
if (Debug::g_logLevel == Debug::LL_GOSSIP_MONGER) {
logMsg += "Clearing entries cache, callTime: " + m_lastCallTime.toString ("yyyy/MM/dd hh:mm:ss:zzz")
+ ", modTimeOfEntries: " + m_modTimeOfEntries.toString ("yyyy/MM/dd hh:mm:ss:zzz");
}
m_entries.clear();
m_lastCallTime = m_modTimeOfEntries;
}
// read CVS/Entries and initialize cache
while(!textStream.eof()) {
line = textStream.readLine();
if(line.at(0) == 'D') {
continue; //entry is a directory
}
if(line.at(0)=='/') {//entry seems to be correct
entrieList.append(line);
}
}
if (Debug::g_logLevel == Debug::LL_GOSSIP_MONGER) {
f.at(0);
QTextStream s(&f);
logMsg += "CVS/Entries:\n"+s.read();
}
f.close();
} else {
//qDebug("file: "+path+"CVS/Entries not readable");//will give output on each checkAndShowStatus if no CVS/Entries file
}
//read Entries.log
f.setName(path + "CVS/Entries.Log");
if(f.open(IO_ReadOnly)) {//file is readable
QTextStream textStream(&f);
QFileInfo fInfo(f);
m_modTimeOfEntriesLog = fInfo.lastModified();
if (modified && (m_lastCallTime < m_modTimeOfEntriesLog) ) {//clear align-cache, only in case of an external modification of CVS dir
if (Debug::g_logLevel == Debug::LL_GOSSIP_MONGER) {
logMsg += "Clearing entries cache, callTime: " + m_lastCallTime.toString ("yyyy/MM/dd hh:mm:ss:zzz")
+ ", modTimeOfEntriesLog: " + m_modTimeOfEntriesLog.toString ("yyyy/MM/dd hh:mm:ss:zzz");
}
m_entries.clear();
m_lastCallTime = m_modTimeOfEntriesLog;
}
// read CVS/Entries and initialize cache
while(!textStream.eof()) {
line = textStream.readLine();
if(line.at(2) == 'D') {
continue; //entry is a directory
}
if(line.at(0)=='A') {//add entry
line = line.mid(2);
QString removeEntry = line.left(line.find("/",1)+1);
QStringList::Iterator test = entrieList.begin();
while (test != entrieList.end()) {
if ((*test).startsWith(removeEntry)) {
entrieList.remove(test);
break;
}
++test;
}
entrieList.append(line);
} else if (line.at(0)=='R') {//remove entry
line = line.mid(2);
QString removeEntry = line.left(line.find("/",1)+1);
QStringList::Iterator test = entrieList.begin();
while (test != entrieList.end()) {
if ((*test).startsWith(removeEntry)) {
entrieList.remove(test);
break;
}
++test;
}
} else {
qDebug("unknown line in: "+m_fullName+"/CVS/Entries.log: "+line);
}
}
if (Debug::g_logLevel == Debug::LL_GOSSIP_MONGER) {
f.at(0);
QTextStream s(&f);
logMsg += "CVS/Entries.log:\n"+s.read();
}
f.close();
} else {
//qDebug("file: "+path+"CVS/Entries.Log not readable");//will give output on each checkAndShowStatus if no CVS/Entries.Log file
}
QStringList::Iterator it;
for (it = entrieList.begin(); it != entrieList.end(); it++) {
int posLeft,posRight;
line = (*it);
if((posLeft = line.find("/", 1)) > 1) {
//cvsEntry->name = line.mid(1, posLeft - 1);
CvsEntry * cvsEntry = new CvsEntry(line.section("/",1,1));
if((posRight = line.find("/", posLeft + 1)) > 1) {
if (line.find("-",posLeft + 1) == (posLeft + 1)) {
cvsEntry->rev.missing = true;
posLeft++;
} else {
cvsEntry->rev.missing = false;
}
cvsEntry->rev.string = line.mid(posLeft + 1, posRight - 1 - posLeft);
posLeft = posRight;
if((posRight = line.find("/", posLeft + 1)) > 1) {
cvsEntry->date.string = line.mid(posLeft + 1, posRight - 1 - posLeft).simplifyWhiteSpace();
if (cvsEntry->date.string.find("dummy timestamp") > -1) {
cvsEntry->date.dummy = true;
if(cvsEntry->date.string.find("from new-entry",16) > -1) {//modified file after switching to a different branch where this file doesn't exist ...
cvsEntry->date.newDummy = true;
} else {
cvsEntry->date.newDummy = false;
}
} else if(cvsEntry->date.string.find("Initial ") > -1) {//same as befor but in :local: mode
cvsEntry->date.dummy = true;
cvsEntry->date.newDummy = false;
} else if (cvsEntry->rev.string == "0") {//only in :local: mode?
cvsEntry->date.dummy = true;
cvsEntry->date.newDummy = false;
cvsEntry->date.string = "";
} else {
cvsEntry->date.dummy = false;
cvsEntry->date.newDummy = false;
}
QDateTime tmpTime = *((QDateTime *) &QtDateTime::fromString(cvsEntry->date.string)); // bugfix for qt3.3.8 datetime parsing bug
cvsEntry->date.datetime = tmpTime;
bool invalid = false;
if (!tmpTime.isValid()) {//no date in entries but "Result of merge" or alike
cvsEntry->date.localdatetime = QFileInfo(path+cvsEntry->name).lastModified().addSecs(-1);//has to be marked as modified
cvsEntry->date.datetime = getAsUTC(cvsEntry->date.localdatetime,m_hasDSTBug);
invalid = true;
}
if (WINVERSION > 0) {//fix for cvs windows version that doesn't consider daylight settings
//seems to be a w2k bug: create a file, note timestamp and change system date from
//winter to summer. Surprised?
if (CVSVERSION == "cvs") {
if (winOnly_isDayLight) {
cvsEntry->date.datetime = cvsEntry->date.datetime.addSecs(3600);
}
if (!invalid) {//date.string might hold merge or dummy timestamp marker
cvsEntry->date.localdatetime = getAsLocal(cvsEntry->date.datetime,m_hasDSTBug);
cvsEntry->date.string = cvsEntry->date.localdatetime.toString(LookAndFeel::g_dateTimeFormat);
}
} else if (!invalid) {
cvsEntry->date.localdatetime = getAsLocal(tmpTime,m_hasDSTBug);//convert to local time
cvsEntry->date.string = cvsEntry->date.localdatetime.toString(LookAndFeel::g_dateTimeFormat);
}
} else if (!invalid) {
cvsEntry->date.localdatetime = getAsLocal(tmpTime,m_hasDSTBug);//convert to local time
cvsEntry->date.string = cvsEntry->date.localdatetime.toString(LookAndFeel::g_dateTimeFormat);
}
cvsEntry->date.date = cvsEntry->date.datetime.date();
cvsEntry->date.time = cvsEntry->date.datetime.time();
if (cvsEntry->date.string.find("Result of merge+")> -1) {
cvsEntry->date.conflict = true;
} else {
cvsEntry->date.conflict = false;
}
} else {
cvsEntry->date.string = "";
}
posLeft = posRight;
if((posRight = line.find("/", posLeft + 1)) > 1) {
if ( (posRight-posLeft)>1) {
cvsEntry->option.string = line.mid(posLeft + 1, posRight - 1 - posLeft).stripWhiteSpace();
switch (cvsEntry->option.string.at(2).latin1()) {
case 'b': {
cvsEntry->option.b = true;
cvsEntry->option.o = false;
cvsEntry->option.v = false;
break;
}
case 'o': {
cvsEntry->option.b = false;
cvsEntry->option.o = true;
cvsEntry->option.v = false;
break;
}
case 'v': {
cvsEntry->option.b = false;
cvsEntry->option.o = false;
cvsEntry->option.v = true;
break;
}
default: {
cvsEntry->option.b = false;
cvsEntry->option.o = false;
cvsEntry->option.v = false;
}
}
} else {
cvsEntry->option.string = "";
cvsEntry->option.b = false;
cvsEntry->option.o = false;
cvsEntry->option.v = false;
}
}
posLeft = line.findRev("/");
cvsEntry->sticky.string = line.mid(posLeft+2);
if( line.find("T",posLeft) > 0) { //sticky tag
cvsEntry->sticky.T = true;
} else {
cvsEntry->sticky.T = false;
}
if( line.find("D",posLeft) > 0) { //sticky date
cvsEntry->sticky.D = true;
} else {
cvsEntry->sticky.D = false;
}
} else {
delete cvsEntry;
cvsEntry = 0;
continue;
}
if (m_CvsEntries.size() <= m_CvsEntries.count()) m_CvsEntries.resize( nextPrime(m_CvsEntries.size()));
if (cvsEntry) m_CvsEntries.insert(cvsEntry->name,cvsEntry);
} else {
continue;
}
}
//read previous tmp entries
QStringList::Iterator iter;
for ( iter = oldTmpEntries.begin(); iter != oldTmpEntries.end(); iter++ ) {
setAndAppendTmpEntryQueryUpdate(*iter);
}
if ( Debug::g_logLevel == Debug::LL_GOSSIP_MONGER) {
if ( !m_tmpEntries.isEmpty()) {
logMsg += "tmp entries:\n\""+m_tmpEntries.join(" ")+"\"";
}
Debug::g_pLog->log(Debug::LL_GOSSIP_MONGER, logMsg);
}
//and set cache flag
m_entriesCached = TRUE;
// QDictIterator<CvsEntries>iterator(m_CvsEntries);
// while(iterator.current()) {
// qDebug( "checking name: " + iterator.current()->name );
// qDebug( "rev: " + iterator.current()->rev.string );
// qDebug( "rev-missing: " + QString(iterator.current()->rev.missing ? "true" : "false") );
// qDebug( "datestring: " + iterator.current()->date.string );
// qDebug( "datetime: " + iterator.current()->date.datetime.toString() );
// qDebug( "date: " + iterator.current()->date.date.toString() );
// qDebug( "date-dummy: " + QString(iterator.current()->date.dummy ? "true" : "false") );
// qDebug( "date-missing: " + QString(iterator.current()->date.conflict ? "true" : "false") );
// qDebug( "sticky-T: " + QString(iterator.current()->sticky.T ? "true" : "false") );
// qDebug( "sticky-D: " + QString(iterator.current()->sticky.D ? "true" : "false") );
// qDebug( "==============================================================");
// ++iterator;
// }
}
return &m_CvsEntries;
}
//----------------------------------------------------------------------------
EntryStates CvsDirectory::alignWithEntries(QString name, EntryStates stateId) {
EntryState *entry = m_entries.find(name);
if(entry) {//file allready registered
//get and set state
switch(stateId)
{
case ES_modified:
if((entry->state() == ES_needs_patch)
|| (entry->state() == ES_needs_merge)
|| (entry->state() == ES_needs_remove)
|| (entry->state() == ES_conflict)) {
entry->setState(entry->state());
stateId = entry->state();
} else if(entry->state() == ES_added) {
stateId = ES_added;
} else {
entry->setState(ES_modified);
}
break;
case ES_missing:
if(entry->state() == ES_needs_checkout) {
stateId = ES_needs_checkout;
} else if (entry->state() == ES_missing_dir) {
stateId = ES_missing_dir;
break;
} else if (entry->state() == ES_needs_remove) {
stateId = ES_needs_remove;
break;
} else if (entry->state() != ES_missing) {
entry->setState(ES_needs_checkout);
stateId = ES_needs_checkout;
}
break;
case ES_added://special for merge, added files are displayed as U
if(entry->state() == ES_up_to_date) {
entry->setState(ES_added);
}
break;
case ES_probably_up_to_date:
if((entry->state() == ES_added) || (entry->state() == ES_modified)) {
entry->setState(ES_probably_up_to_date);
} else {
stateId = entry->state();
}
break;
case ES_removed://special if files are removed from outside lincvs
entry->setState(ES_removed);
break;
case ES_probably_up_to_date_and_timezone_incorrect:
if((entry->state() == ES_added) || (entry->state() == ES_modified)) {
entry->setState(ES_probably_up_to_date);
}
stateId = entry->state();
break;
default:
stateId = entry->state();
break;
}
}
else {
appendEntry(name, new EntryState(name, stateId, this));
}
return stateId;
}
//----------------------------------------------------------------------------
// This method is a fix for showing dirs and files detected to be missing by QUERY_UPDATE_CMD
// For displaying, these have to be added to Entries. We don't modify CVS/Entries, but
// add temporarily until next modification of CVS/Entries.
bool CvsDirectory::setAndAppendTmpEntryQueryUpdate(QString m_curCvsFileName) {
if (getCvsEntries()->find(m_curCvsFileName)) return false; //entry found
QFileInfo fInfo(m_fullName+"/"+m_curCvsFileName);
if (fInfo.exists() && fInfo.isDir ()) return false;//don't add existing dirs as tmp, they might allready be in one of the other tabs
CvsEntry * cvsEntry = new CvsEntry(m_curCvsFileName);
cvsEntry->rev.string = "locally missing";
cvsEntry->rev.missing = false;
cvsEntry->date.string = "unknown";
cvsEntry->date.dummy = false;
cvsEntry->date.newDummy = false;
cvsEntry->date.conflict = false;
cvsEntry->date.datetime = QDateTime::currentDateTime();
cvsEntry->date.date = cvsEntry->date.datetime.date();
cvsEntry->date.time = cvsEntry->date.datetime.time();
cvsEntry->option.string = "";
cvsEntry->option.b = false;
cvsEntry->option.o = false;
cvsEntry->option.v = false;
cvsEntry->sticky.string = "";
cvsEntry->sticky.D = false;
cvsEntry->sticky.T = false;
cvsEntry->isTmp = true;
m_CvsEntries.insert(cvsEntry->name,cvsEntry);
m_tmpEntries.append(m_curCvsFileName);
return true;
}
//----------------------------------------------------------------------------
inline FileListViewItem * CvsDirectory::setStatusInFileListView(FileListViewItem *item, Entry * entry, bool checkOnly /* = FALSE*/) {
CvsEntry * cvsEntry = static_cast<CvsEntry*>(entry);
assert(cvsEntry);
EntryStates stateId = ES_unknown;
QString modDateLocal;
int type = FileState::S_i;
bool sticky = false;
QDateTime localDate, localDateUtc;
QString path = m_fullName;
if(path.length() > 1){//is not root
path += "/";
}
if (cvsEntry->sticky.T || cvsEntry->sticky.D) sticky = true;
//status?
if (!cvsEntry->isTmp) {
if ( getFileModTime(path+cvsEntry->name,localDate,&type) ) {
localDateUtc = getAsUTC(localDate,m_hasDSTBug);
if(localDateUtc == cvsEntry->date.datetime){
stateId = ES_probably_up_to_date;
} else if(cvsEntry->date.dummy) {
if (cvsEntry->rev.missing) {
stateId = ES_removed;
} else if (cvsEntry->date.newDummy) {
stateId = ES_modified;
} else {
stateId = ES_added;
}
} else if (cvsEntry->date.conflict) {
stateId = ES_conflict;
/*} else if ( (localDateUtc.time().second() == cvsEntry->date.time.second()) &&
(localDateUtc.time().minute() == cvsEntry->date.time.minute())) {
// cout << "timezone: " << cvsEntry->name.ascii() <<
// ", utc: ->" << modDateUtc << "<- entry: ->" <<
// cvsEntry->date.string << "<-!!!\n";
stateId = ES_probably_up_to_date_and_timezone_incorrect;*/
} else {
stateId = ES_modified;
}
} else if (cvsEntry->rev.missing) {
stateId = ES_removed;
} else {
stateId = ES_missing;
}
}
stateId = alignWithEntries(cvsEntry->name, stateId);
if (checkOnly) return NULL; // we only check and set the states, displaying is timeconsuming
switch (stateId) {
case ES_probably_up_to_date_and_timezone_incorrect:
case ES_modified:
case ES_added:
if (localDate.isValid()) modDateLocal = localDate.toString(LookAndFeel::g_dateTimeFormat);
break;
case ES_needs_patch:
case ES_needs_merge:
case ES_needs_checkout:
case ES_conflict:
if ( localDate.isValid() && (localDateUtc != cvsEntry->date.datetime) ) {
modDateLocal = localDate.toString(LookAndFeel::g_dateTimeFormat);
}
break;
default:
break;
}
if( item == 0 ) {
item = new FileListViewItem(m_pFileListView,
FileListViewItem::TextNoCase,
FileListViewItem::Rev,
FileListViewItem::TextNoCase,
FileListViewItem::TextNoCase,
FileListViewItem::Text,
FileListViewItem::Date,
FileListViewItem::ModDate);
}
item->setText(0, cvsEntry->name );
item->setText(1, cvsEntry->rev.string );
item->setText(2, cvsEntry->sticky.string );
item->setText(3, cvsEntry->option.string );
item->setText(4, getState(stateId) );
item->setDate(5, &cvsEntry->date.localdatetime, cvsEntry->date.string);
item->setModifiedDate(6, &localDate, modDateLocal);
item->setPixmap(0, findEmbeddedPixmap (getPix(stateId,type)));
if (sticky) {
item->setPixmap(2, findEmbeddedPixmap ("Tag16x16"));
} else {
item->setPixmap(2, 0);
}
if (cvsEntry->option.b) {
item->setPixmap(3, findEmbeddedPixmap ("FileBinary16x16"));
} else {
item->setPixmap(3, 0);
}
return item;
}
//----------------------------------------------------------------------------
inline QString CvsDirectory::getState(const EntryStates & stateId) {
switch(stateId) {
case ES_probably_up_to_date:
return tr("seems up to date");
case ES_probably_up_to_date_and_timezone_incorrect:
return tr("!!check timezone: incorrect!!");
case ES_up_to_date:
return tr("up to date");
case ES_modified:
return tr("modified");
case ES_needs_patch:
return tr("needs patch");
case ES_needs_merge:
return tr("needs merge");
case ES_needs_checkout:
return tr("needs checkout");
case ES_missing:
return tr("missing");
case ES_missing_dir:
return tr("needs checkout");
case ES_needs_remove:
return tr("update to remove");
case ES_conflict:
return tr("conflict");
case ES_added:
return tr("commit to add");
case ES_removed:
return tr("commit to remove");
default:
return tr("unknown");
}
}
//----------------------------------------------------------------------------
inline char * CvsDirectory::getPix(const EntryStates & stateId, const int & type) {
switch(stateId) {
case ES_modified:
return "FileModified16x16";
case ES_needs_patch:
return "FileNeedsPatch16x16";
case ES_needs_merge:
return "FileNeedsMerge16x16";
case ES_needs_checkout:
return "FileNeedsCheckout16x16";
case ES_needs_remove:
return "FileRemoved16x16";
case ES_missing:
return "FileRemoved16x16";
case ES_missing_dir:
return "FolderMissing16x16";
case ES_conflict:
return "FileConflict16x16";
case ES_added:
return "FileAdded16x16";
case ES_removed:
return "FileRemoved16x16";
case ES_probably_up_to_date:
case ES_probably_up_to_date_and_timezone_incorrect:
case ES_up_to_date:
default:
switch(type) {
case FileState::S_Ro:
return "FileUnchanged16x16";
case FileState::S_Rw:
return "FileWriteable16x16";
default:
return "lincvs-missing";
}
}
}
//----------------------------------------------------------------------------
//check all files for differences between timestamp of CVS/Entries
//returns true if modified files are detected that are not jet in modified state
bool CvsDirectory::isFilesModified() {
CvsEntriesIterator it(*getCvsEntries());
QString path = m_fullName+"/";
while(it.current()) {
EntryStates es = getEntryState(it.current()->name);
if (es <= ES_up_to_date) {
QDateTime localTime;
if (!getFileModTime(path + it.current()->name,localTime)) return true;//file missing
localTime = getAsUTC(localTime,m_hasDSTBug);
if ( (it.current()->date.datetime != localTime)
&& (es != ES_probably_up_to_date_and_timezone_incorrect) ) {
// qDebug("File modified: "+path+it.current()->name);
return true;
}
}
++it;
}
return false;
}
//----------------------------------------------------------------------------
bool CvsDirectory::entriesFileModified() { // returns true if modified or m_modTimeOfEntries not set( so, nothing cached yet)
QString path = m_fullName;
if(path.length() > 1){//is not root
path += "/";
}
QFileInfo fInfo(path + "CVS/Entries");
if (!fInfo.exists()) return false;
if (m_modTimeOfEntries == fInfo.lastModified()) {
// qDebug("CVS not modified: "+m_fullName
// +", old: "+m_modTimeOfEntries.toString()
// +", cur: "+QTime::currentTime().toString());
return false;
} else if (m_disabled) {
return false;
} else {
// qDebug("CVS modified: "+m_fullName
// +", old: "+m_modTimeOfEntries.toString()
// +", new: "+fInfo.lastModified().toString()
// +", cur: "+QTime::currentTime().toString());
return true;
}
}
//----------------------------------------------------------------------------
bool CvsDirectory::entriesLogFileModified() { // returns true if modified or m_modTimeOfEntriesLog not set( so, nothing cached yet)
QString path = m_fullName;
if(path.length() > 1){//is not root
path += "/";
}
QFileInfo fInfo(path + "CVS/Entries.Log");
if (!fInfo.exists()) return false;
if (m_modTimeOfEntriesLog == fInfo.lastModified()) {
return false;
} else if (m_disabled) {
return false;
} else {
// qDebug("entriesLogFileModified");
return true;
}
}
//----------------------------------------------------------------------------
void CvsDirectory::getNameAndRevOfFirstSelectedFile(QString *name, QString *rev) {
QListViewItem *myChild = m_pFileListView->firstChild();
while(myChild) {
if(myChild->isSelected()) {
*name = myChild->text(0).stripWhiteSpace();
*rev = myChild->text(1).stripWhiteSpace();
break;
}
myChild = myChild->nextSibling();
}
}
//----------------------------------------------------------------------------
QString CvsDirectory::getRev(QString *fileToFind) {
QListViewItem *myChild = m_pFileListView->firstChild();
while(myChild) {
if (myChild->text(0).stripWhiteSpace() == (*fileToFind)) {
return myChild->text(1).stripWhiteSpace();
}
myChild = myChild->nextSibling();
}
return QString::null;
}
//----------------------------------------------------------------------------
bool CvsDirectory::backupFiles(QStringList list) {
QString srcPath = m_fullName+"/";
QString dstDir = srcPath+"CVS/LinCVS-tmp";
QDir d;
if (d.mkdir(dstDir)) {
QString dstPath = dstDir+"/";
QStringList copyList;
QStringList::Iterator it;
for (it = list.begin(); it != list.end(); ++it) {
QString srcName = srcPath+*it;
QString dstName = dstPath+*it;
QFileInfo fInfo(srcName);
int permission = 0;
if (fInfo.isReadable()) permission = (permission | READABLE);
if (fInfo.isWritable()) permission = (permission | WRITEABLE);
if (fInfo.isExecutable()) permission = (permission | EXECUTABLE);
if (!copyFile(srcName, dstName, permission, false) ) {
qDebug("can't copy file: "+srcName+" -> "+dstName+", aborting");
for (it = copyList.begin(); it != copyList.end(); ++it) {
QFile file(*it);
setPermission(file,READABLE | WRITEABLE);
file.remove();
}
d.rmdir(dstDir);
return false;
} else {
copyList.append(dstName);
}
}
}
return true;
}
//----------------------------------------------------------------------------
bool CvsDirectory::restoreFiles(QStringList list) {
QString dstPath = m_fullName+"/";
QString srcPath = dstPath+"CVS/LinCVS-tmp/";
QDir d;
QStringList::Iterator it;
for (it = list.begin(); it != list.end(); ++it) {
QString srcName = srcPath+*it;
QString dstName = dstPath+*it;
QFileInfo fInfo(srcName);
int permission = 0;
if (fInfo.isReadable()) permission = (permission | READABLE);
if (fInfo.isWritable()) permission = (permission | WRITEABLE);
if (fInfo.isExecutable()) permission = (permission | EXECUTABLE);
if (!copyFile(srcName, dstName, permission, true) ) {
qDebug("can't copy file: "+srcName+" -> "+dstName);
}
}
d.rmdir(dstPath+"CVS/LinCVS-tmp");//won't be removed if not empty
return true;
}
//----------------------------------------------------------------------------
syntax highlighted by Code2HTML, v. 0.9.1