You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
508 lines
15 KiB
508 lines
15 KiB
/**
|
|
Copyright (C) 2004-2005 Mickael Marchand <marchand@kde.org>
|
|
|
|
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; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
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 for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; see the file COPYING. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "subversion_fileinfo.h"
|
|
#include "subversion_core.h"
|
|
#include <kdebug.h>
|
|
#include <tqfileinfo.h>
|
|
#include <tqdir.h>
|
|
#include <kdevproject.h>
|
|
#include <unistd.h>
|
|
#include <tdeapplication.h>
|
|
#include <kdevmainwindow.h>
|
|
#include <tdemainwindow.h>
|
|
#include <tqregexp.h>
|
|
|
|
#include <tdeio/netaccess.h>
|
|
#include <tdelocale.h>
|
|
|
|
SVNFileInfoProvider::SVNFileInfoProvider(subversionPart *parent, const char *name)
|
|
: KDevVCSFileInfoProvider( parent, "svnfileinfoprovider" ),
|
|
m_cachedDirEntries( 0 ), m_recursiveDirEntries(0) {
|
|
Q_UNUSED(name);
|
|
m_part = parent;
|
|
}
|
|
|
|
SVNFileInfoProvider::~SVNFileInfoProvider() {
|
|
delete m_cachedDirEntries;
|
|
m_cachedDirEntries = 0;
|
|
delete m_recursiveDirEntries;
|
|
m_recursiveDirEntries = 0;
|
|
}
|
|
|
|
//synchronous
|
|
const VCSFileInfoMap *SVNFileInfoProvider::status( const TQString &dirPath ) {
|
|
if ( !m_cachedDirEntries )
|
|
m_cachedDirEntries = new VCSFileInfoMap;
|
|
// return m_cachedDirEntries;
|
|
|
|
kdDebug(9036) << "svn provider : status " << dirPath << endl;
|
|
|
|
if ( dirPath != m_previousDirPath ) {
|
|
m_previousDirPath = dirPath;
|
|
KURL servURL = "kdevsvn+http://fakeserver_this_is_normal_behavior/";
|
|
TQByteArray parms;
|
|
TQDataStream s( parms, IO_WriteOnly );
|
|
int cmd = 9;
|
|
TQString rPath = projectDirectory( );
|
|
rPath += TQDir::separator() + dirPath;
|
|
kdDebug(9036) << "DIR : " << rPath << " " << KURL( TQFileInfo( rPath ).absFilePath() ) << endl;
|
|
|
|
// s << cmd << KURL( TQFileInfo( rPath ).absFilePath() ) << true << true; //original line
|
|
|
|
// Dukju Ahn: if checkRepos is set, status() accesses remote repository,
|
|
// which causes significant delaym_owner especially when network speed is not fast enough.
|
|
// Of course, the user cannot get information about the out-of-dateness of his local copy.
|
|
s << cmd << KURL( TQFileInfo( rPath ).absFilePath() ) << false/*checkRepos*/ << false /*fullRecurse*/;
|
|
|
|
TDEIO::SimpleJob *job2 = TDEIO::special(servURL, parms, false);
|
|
job2->setWindow( m_part->mainWindow()->main() );
|
|
|
|
|
|
TQMap<TQString,TQString> ma;
|
|
|
|
TDEIO::NetAccess::synchronousRun(job2, m_part->mainWindow()->main(), 0, 0, &ma );
|
|
|
|
TQValueList<TQString> keys = ma.keys();
|
|
qHeapSort( keys );
|
|
TQValueList<TQString>::Iterator begin = keys.begin(), end = keys.end(), it;
|
|
|
|
TQString path;
|
|
int text_status = 0, prop_status = 0, repos_text_status = 0, repos_prop_status = 0;
|
|
long int rev = 0;
|
|
int curIdx, lastIdx;
|
|
|
|
TQRegExp rx( "([0-9]*)(.*)" );
|
|
for ( it = begin; it != end; ) {
|
|
kdDebug(9036) << "METADATA : " << *it << ":" << ma[ *it ] << endl;
|
|
if ( rx.search( *it ) == -1 ) return m_cachedDirEntries; // something is wrong ! :)
|
|
/* if some notification comes here, consume these notification metadatas */
|
|
if ( rx.cap( 2 ) == "action" ){
|
|
curIdx = lastIdx = rx.cap( 1 ).toInt();
|
|
while ( curIdx == lastIdx ){
|
|
++it;
|
|
if ( it == end ) break;
|
|
if ( rx.search( *it ) == -1 ) continue; // something is wrong
|
|
curIdx = rx.cap( 1 ).toInt();
|
|
}
|
|
continue;
|
|
}
|
|
curIdx = lastIdx = rx.cap( 1 ).toInt();
|
|
while ( curIdx == lastIdx ) {
|
|
if ( rx.cap( 2 ) == "path" )
|
|
path = ma[ *it ];
|
|
else if ( rx.cap( 2 ) == "text" )
|
|
text_status = ma[ *it ].toInt();
|
|
else if ( rx.cap( 2 ) == "prop" )
|
|
prop_status = ma[ *it ].toInt();
|
|
else if ( rx.cap( 2 ) == "reptxt" )
|
|
repos_text_status = ma[ *it ].toInt();
|
|
else if ( rx.cap( 2 ) == "repprop" )
|
|
repos_prop_status = ma[ *it ].toInt();
|
|
else if ( rx.cap( 2 ) == "rev" )
|
|
rev = ma[ *it ].toLong();
|
|
++it;
|
|
if ( it == end )
|
|
break;
|
|
if ( rx.search( *it ) == -1 ) break; // something is wrong ! :)
|
|
curIdx = rx.cap( 1 ).toInt();
|
|
}
|
|
slotStatus(path, text_status, prop_status, repos_text_status, repos_prop_status, rev);
|
|
}
|
|
}
|
|
kdDebug(9036) << " Returning VcsFileInfoMap. provider::status() finished " << endl;
|
|
return m_cachedDirEntries;
|
|
}
|
|
|
|
bool SVNFileInfoProvider::requestStatus( const TQString &dirPath, void *callerData, bool recursive, bool checkRepos ) {
|
|
kdDebug(9036) << "##################################################################################### svn provider : request status" << endl;
|
|
m_savedCallerData = callerData;
|
|
// Flush old cache
|
|
if (m_cachedDirEntries)
|
|
{
|
|
delete m_cachedDirEntries;
|
|
m_cachedDirEntries = 0;
|
|
m_previousDirPath = dirPath;
|
|
}
|
|
|
|
TQByteArray parms;
|
|
TQDataStream s( parms, IO_WriteOnly );
|
|
int cmd = 9;
|
|
TQString rPath = projectDirectory( );
|
|
rPath += TQDir::separator() + dirPath;
|
|
|
|
if( ! m_part->isValidDirectory( rPath ) ){
|
|
return false;
|
|
}
|
|
|
|
kdDebug(9036) << "DIR : " << rPath << " " << TQFileInfo( rPath ).absFilePath() << endl;
|
|
s << cmd << KURL( TQFileInfo( rPath ).absFilePath() ) << checkRepos << recursive;
|
|
KURL servURL = "kdevsvn+http://fakeserver_this_is_normal_behavior/";
|
|
job = TDEIO::special(servURL, parms, false);
|
|
connect( job, TQ_SIGNAL( result( TDEIO::Job * ) ), this, TQ_SLOT( slotResult( TDEIO::Job * ) ) );
|
|
if( checkRepos )
|
|
m_part->svncore()->initProcessDlg( job, dirPath, i18n("Subversion File/Directory Status") );
|
|
return true;
|
|
}
|
|
|
|
void SVNFileInfoProvider::slotResult( TDEIO::Job *j ) {
|
|
if ( j->error() )
|
|
j->showErrorDialog( m_part->mainWindow()->main() );
|
|
|
|
TDEIO::MetaData ma = j->metaData();
|
|
TQValueList<TQString> keys = ma.keys();
|
|
qHeapSort( keys );
|
|
TQValueList<TQString>::Iterator begin = keys.begin(), end = keys.end(), it;
|
|
|
|
TQString path;
|
|
int text_status = 0, prop_status = 0, repos_text_status = 0, repos_prop_status = 0;
|
|
long int rev = 0;
|
|
int curIdx, lastIdx;
|
|
|
|
TQRegExp rx( "([0-9]*)(.*)" );
|
|
for ( it = begin; it != end; ) {
|
|
kdDebug(9036) << "METADATA : " << *it << ":" << ma[ *it ] << endl;
|
|
if ( rx.search( *it ) == -1 ) return; // something is wrong ! :)
|
|
/* if some notification comes here, consume these notification metadatas */
|
|
if ( rx.cap( 2 ) == "action" ){
|
|
curIdx = lastIdx = rx.cap( 1 ).toInt();
|
|
while ( curIdx == lastIdx ){
|
|
++it;
|
|
if ( it == end ) break;
|
|
if ( rx.search( *it ) == -1 ) continue; // something is wrong
|
|
curIdx = rx.cap( 1 ).toInt();
|
|
}
|
|
continue;
|
|
}
|
|
curIdx = lastIdx = rx.cap( 1 ).toInt();
|
|
while ( curIdx == lastIdx ) {
|
|
if ( rx.cap( 2 ) == "path" )
|
|
path = ma[ *it ];
|
|
else if ( rx.cap( 2 ) == "text" )
|
|
text_status = ma[ *it ].toInt();
|
|
else if ( rx.cap( 2 ) == "prop" )
|
|
prop_status = ma[ *it ].toInt();
|
|
else if ( rx.cap( 2 ) == "reptxt" )
|
|
repos_text_status = ma[ *it ].toInt();
|
|
else if ( rx.cap( 2 ) == "repprop" )
|
|
repos_prop_status = ma[ *it ].toInt();
|
|
else if ( rx.cap( 2 ) == "rev" )
|
|
rev = ma[ *it ].toLong();
|
|
++it;
|
|
if ( it == end )
|
|
break;
|
|
if ( rx.search( *it ) == -1 ) break; // something is wrong ! :)
|
|
curIdx = rx.cap( 1 ).toInt();
|
|
}
|
|
slotStatus(path, text_status, prop_status, repos_text_status, repos_prop_status, rev);
|
|
}
|
|
|
|
if ( m_cachedDirEntries )
|
|
emit statusReady(*m_cachedDirEntries, m_savedCallerData);
|
|
}
|
|
|
|
void SVNFileInfoProvider::slotStatus( const TQString& path,int text_status, int prop_status,int repos_text_status, int repos_prop_status, long int rev) {
|
|
// kdDebug(9036) << "##################################################################################### svn provider : slotstatus"
|
|
// << " path " << path << " text_status " << text_status << " prop_status " << prop_status << " repos_text_status " << repos_text_status
|
|
// << " repos_prop_status " << repos_prop_status << " rev " << rev
|
|
// << endl;
|
|
|
|
if ( !m_cachedDirEntries )
|
|
m_cachedDirEntries = new VCSFileInfoMap;
|
|
|
|
TQString wRev = TQString::number( rev ); //work rev
|
|
TQString rRev = TQString::number( rev );// repo rev
|
|
VCSFileInfo::FileState state = VCSFileInfo::Unknown;
|
|
|
|
switch ( text_status ) {
|
|
case 1:
|
|
break;
|
|
case 2:
|
|
break;
|
|
case 3:
|
|
state = VCSFileInfo::Uptodate;
|
|
break;
|
|
case 4:
|
|
state = VCSFileInfo::Added;
|
|
break;
|
|
case 5:
|
|
break;
|
|
case 6: //deleted
|
|
state = VCSFileInfo::Deleted;
|
|
break;
|
|
case 7: //replaced
|
|
state = VCSFileInfo::Replaced;
|
|
break;
|
|
case 8: //modified
|
|
state = VCSFileInfo::Modified;
|
|
break;
|
|
case 9: //merged
|
|
break;
|
|
case 10: //conflicted
|
|
state = VCSFileInfo::Conflict;
|
|
break;
|
|
case 11: //ignored
|
|
break;
|
|
case 12: //obstructed
|
|
break;
|
|
case 13: //external
|
|
break;
|
|
case 14: //incomplete
|
|
break;
|
|
}
|
|
switch( prop_status ) {
|
|
case 8:
|
|
state = VCSFileInfo::Modified;
|
|
break;
|
|
}
|
|
switch ( repos_text_status ) {
|
|
case 1:
|
|
break;
|
|
case 2:
|
|
break;
|
|
case 3:
|
|
break;
|
|
case 4:
|
|
break;
|
|
case 5:
|
|
break;
|
|
case 6: //deleted
|
|
break;
|
|
case 7: //replaced
|
|
break;
|
|
case 8: //modified
|
|
state = VCSFileInfo::NeedsPatch;
|
|
break;
|
|
case 9: //merged
|
|
break;
|
|
case 10: //conflicted
|
|
break;
|
|
case 11: //ignored
|
|
break;
|
|
case 12: //obstructed
|
|
break;
|
|
case 13: //external
|
|
break;
|
|
case 14: //incomplete
|
|
break;
|
|
}
|
|
|
|
VCSFileInfo info(TQFileInfo( path ).fileName(),wRev,rRev,state);
|
|
kdDebug(9036) << "Inserting " << info.toString() << endl;
|
|
m_cachedDirEntries->insert( TQFileInfo( path ).fileName(), info);
|
|
}
|
|
|
|
TQString SVNFileInfoProvider::projectDirectory() const {
|
|
return owner()->project()->projectDirectory();
|
|
}
|
|
|
|
const VCSFileInfoMap *SVNFileInfoProvider::statusExt( const TQString &dirPath,
|
|
bool checkRepos, bool fullRecurse, bool getAll, bool noIgnore )
|
|
{
|
|
if ( !m_recursiveDirEntries )
|
|
m_recursiveDirEntries = new VCSFileInfoMap;
|
|
|
|
// if ( dirPath != m_recursivePreviousDirPath ) {
|
|
m_recursiveDirEntries->clear();
|
|
m_recursivePreviousDirPath = dirPath;
|
|
KURL servURL = "kdevsvn+http://fakeserver_this_is_normal_behavior/";
|
|
TQByteArray parms;
|
|
TQDataStream s( parms, IO_WriteOnly );
|
|
int cmd = 109;
|
|
TQString rPath = projectDirectory( );
|
|
rPath += TQDir::separator() + dirPath;
|
|
kdDebug(9036) << "DIR : " << rPath << " " << KURL( TQFileInfo( rPath ).absFilePath() ) << endl;
|
|
s << cmd << checkRepos << fullRecurse << getAll << noIgnore << -1 << "WORKING" << KURL( TQFileInfo( rPath ).absFilePath() );
|
|
TDEIO::SimpleJob *job2 = TDEIO::special(servURL, parms, false);
|
|
job2->setWindow( m_part->mainWindow()->main() );
|
|
|
|
|
|
TQMap<TQString,TQString> ma;
|
|
TDEIO::NetAccess::synchronousRun(job2, m_part->mainWindow()->main(), 0, 0, &ma );
|
|
|
|
TQValueList<TQString> keys = ma.keys();
|
|
qHeapSort( keys );
|
|
TQValueList<TQString>::Iterator begin = keys.begin(), end = keys.end(), it;
|
|
|
|
TQString path;
|
|
int text_status = 0, prop_status = 0, repos_text_status = 0, repos_prop_status = 0;
|
|
long int rev = 0;
|
|
int curIdx, lastIdx;
|
|
|
|
TQRegExp rx( "([0-9]*)(.*)" );
|
|
for ( it = begin; it != end; ) {
|
|
kdDebug(9036) << "METADATA : " << *it << ":" << ma[ *it ] << endl;
|
|
if ( rx.search( *it ) == -1 ) return m_recursiveDirEntries; // something is wrong ! :)
|
|
/* if some notification comes here, consume these notification metadatas */
|
|
if ( rx.cap( 2 ) == "action" ){
|
|
curIdx = lastIdx = rx.cap( 1 ).toInt();
|
|
while ( curIdx == lastIdx ){
|
|
++it;
|
|
if ( it == end ) break;
|
|
if ( rx.search( *it ) == -1 ) continue; // something is wrong
|
|
curIdx = rx.cap( 1 ).toInt();
|
|
}
|
|
continue;
|
|
}
|
|
/* get properties */
|
|
curIdx = lastIdx = rx.cap( 1 ).toInt();
|
|
while ( curIdx == lastIdx ) {
|
|
if ( rx.cap( 2 ) == "path" )
|
|
path = ma[ *it ];
|
|
else if ( rx.cap( 2 ) == "text" )
|
|
text_status = ma[ *it ].toInt();
|
|
else if ( rx.cap( 2 ) == "prop" )
|
|
prop_status = ma[ *it ].toInt();
|
|
else if ( rx.cap( 2 ) == "reptxt" )
|
|
repos_text_status = ma[ *it ].toInt();
|
|
else if ( rx.cap( 2 ) == "repprop" )
|
|
repos_prop_status = ma[ *it ].toInt();
|
|
else if ( rx.cap( 2 ) == "rev" )
|
|
rev = ma[ *it ].toLong();
|
|
++it;
|
|
if ( it == end )
|
|
break;
|
|
if ( rx.search( *it ) == -1 ) break; // something is wrong ! :)
|
|
curIdx = rx.cap( 1 ).toInt();
|
|
}
|
|
slotStatusExt(dirPath, path, text_status, prop_status, repos_text_status, repos_prop_status, rev);
|
|
}
|
|
// }
|
|
|
|
return m_recursiveDirEntries;
|
|
}
|
|
|
|
void SVNFileInfoProvider::slotStatusExt(
|
|
const TQString& reqPath, const TQString& path,int text_status, int prop_status,int repos_text_status, int repos_prop_status, long int rev)
|
|
{
|
|
|
|
if ( !m_recursiveDirEntries )
|
|
m_recursiveDirEntries = new VCSFileInfoMap;
|
|
|
|
TQString wRev = TQString::number( rev ); //work rev
|
|
TQString rRev = TQString::number( rev );// repo rev
|
|
VCSFileInfo::FileState state = VCSFileInfo::Unknown;
|
|
|
|
switch ( text_status ) {
|
|
case 1: // does not exist
|
|
break;
|
|
case 2: // unversioned
|
|
break;
|
|
case 3:
|
|
state = VCSFileInfo::Uptodate;
|
|
break;
|
|
case 4:
|
|
state = VCSFileInfo::Added;
|
|
break;
|
|
case 5: // missing
|
|
break;
|
|
case 6: //deleted
|
|
state = VCSFileInfo::Deleted;
|
|
break;
|
|
case 7: //replaced
|
|
state = VCSFileInfo::Replaced;
|
|
break;
|
|
case 8: //modified
|
|
state = VCSFileInfo::Modified;
|
|
break;
|
|
case 9: //merged
|
|
break;
|
|
case 10: //conflicted
|
|
state = VCSFileInfo::Conflict;
|
|
break;
|
|
case 11: //ignored
|
|
break;
|
|
case 12: //obstructed
|
|
break;
|
|
case 13: //external
|
|
break;
|
|
case 14: //incomplete
|
|
break;
|
|
}
|
|
switch( prop_status ) {
|
|
case 8:
|
|
state = VCSFileInfo::Modified;
|
|
break;
|
|
}
|
|
switch ( repos_text_status ) {
|
|
case 1:
|
|
break;
|
|
case 2:
|
|
break;
|
|
case 3:
|
|
break;
|
|
case 4:
|
|
break;
|
|
case 5:
|
|
break;
|
|
case 6: //deleted
|
|
break;
|
|
case 7: //replaced
|
|
break;
|
|
case 8: //modified
|
|
state = VCSFileInfo::NeedsPatch;
|
|
break;
|
|
case 9: //merged
|
|
break;
|
|
case 10: //conflicted
|
|
break;
|
|
case 11: //ignored
|
|
break;
|
|
case 12: //obstructed
|
|
break;
|
|
case 13: //external
|
|
break;
|
|
case 14: //incomplete
|
|
break;
|
|
}
|
|
|
|
TQString relativeReqPath;
|
|
if (reqPath == "./"){
|
|
// case of project top directory
|
|
TQString reqAbsPath = projectDirectory();
|
|
|
|
if( path == reqAbsPath ){
|
|
//key of VCSInfo is project directory itself. So it is set to .
|
|
relativeReqPath = ".";
|
|
}
|
|
else{
|
|
relativeReqPath = path.right( path.length() - reqAbsPath.length() - 1 );
|
|
}
|
|
}
|
|
else {
|
|
TQString reqAbsPath = projectDirectory() + TQDir::separator() + reqPath;
|
|
relativeReqPath = path.right( path.length() - reqAbsPath.length() - 1 );
|
|
|
|
if (relativeReqPath == reqAbsPath){
|
|
// case of requested directory itself.
|
|
relativeReqPath = ".";
|
|
}
|
|
}
|
|
|
|
VCSFileInfo info(relativeReqPath, wRev, rRev, state);
|
|
m_recursiveDirEntries->insert( relativeReqPath, info );
|
|
|
|
// VCSFileInfo info(TQFileInfo( path ).fileName(),wRev,rRev,state);
|
|
kdDebug(9036) << "Inserting " << info.toString() << endl;
|
|
// m_recursiveDirEntries->insert( TQFileInfo( path ).fileName(), info);
|
|
}
|
|
|
|
#include "subversion_fileinfo.moc"
|
|
|