KDevelop API Documentation

cvsfileinfoprovider.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2003 by Mario Scalas                                    *
00003  *   mario.scalas@libero.it                                                *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  ***************************************************************************/
00011 
00012 #include <qregexp.h>
00013 #include <kurl.h>
00014 #include <kdebug.h>
00015 
00016 #include <urlutil.h>
00017 #include <kdevproject.h>
00018 
00019 #include <dcopref.h>
00020 #include <cvsjob_stub.h>
00021 #include <cvsservice_stub.h>
00022 
00023 #include "cvspart.h"
00024 #include "cvsdir.h"
00025 #include "cvsentry.h"
00026 #include "cvsfileinfoprovider.h"
00027 
00028 
00030 // class CVSFileInfoProvider
00032 
00033 CVSFileInfoProvider::CVSFileInfoProvider( CvsServicePart *parent, CvsService_stub *cvsService )
00034     : KDevVCSFileInfoProvider( parent, "cvsfileinfoprovider" ),
00035     m_requestStatusJob( 0 ), m_cvsService( cvsService ), m_cachedDirEntries( 0 )
00036 {
00037 }
00038 
00040 
00041 CVSFileInfoProvider::~CVSFileInfoProvider()
00042 {
00043    if (m_requestStatusJob && m_requestStatusJob->isRunning())
00044       m_requestStatusJob->cancel();
00045    delete m_requestStatusJob;
00046    delete m_cachedDirEntries;
00047 }
00048 
00050 
00051 const VCSFileInfoMap *CVSFileInfoProvider::status( const QString &dirPath ) const
00052 {
00053     // Same dir: we can do with cache ...
00054     if (dirPath != m_previousDirPath)
00055     {
00056         // ... different dir: flush old cache and cache new dir
00057         delete m_cachedDirEntries;
00058         CVSDir cvsdir( projectDirectory() + QDir::separator() + dirPath );
00059         m_previousDirPath = dirPath;
00060         m_cachedDirEntries = cvsdir.cacheableDirStatus();
00061     }
00062     return m_cachedDirEntries;
00063 }
00064 
00066 
00067 bool CVSFileInfoProvider::requestStatus( const QString &dirPath, void *callerData )
00068 {
00069     m_savedCallerData = callerData;
00070     if (m_requestStatusJob)
00071     {
00072         delete m_requestStatusJob;
00073         m_requestStatusJob = 0;
00074     }
00075     // Flush old cache
00076     if (m_cachedDirEntries)
00077     {
00078         delete m_cachedDirEntries;
00079         m_cachedDirEntries = 0;
00080         m_previousDirPath = dirPath;
00081     }
00082 
00083     // path, recursive, tagInfo: hmmm ... we may use tagInfo for collecting file tags ...
00084     DCOPRef job = m_cvsService->status( dirPath, true, false );
00085     m_requestStatusJob = new CvsJob_stub( job.app(), job.obj() );
00086 
00087     kdDebug(9006) << "Running command : " << m_requestStatusJob->cvsCommand() << endl;
00088     connectDCOPSignal( job.app(), job.obj(), "jobExited(bool, int)", "slotJobExited(bool, int)", true );
00089     connectDCOPSignal( job.app(), job.obj(), "receivedStdout(QString)", "slotReceivedOutput(QString)", true );
00090     return m_requestStatusJob->execute();
00091 }
00092 
00094 
00095 void CVSFileInfoProvider::slotJobExited( bool normalExit, int /*exitStatus*/ )
00096 {
00097     kdDebug(9006) << "CVSFileInfoProvider::slotJobExited(bool,int)" << endl;
00098     if (!normalExit)
00099         return;
00100 
00101 //    m_cachedDirEntries = parse( m_requestStatusJob->output() );
00102     m_cachedDirEntries = parse( m_statusLines );
00103     // Remove me when not debugging
00104     printOutFileInfoMap( *m_cachedDirEntries );
00105 
00106     emit statusReady( *m_cachedDirEntries, m_savedCallerData );
00107 }
00108 
00110 
00111 void CVSFileInfoProvider::slotReceivedOutput( QString someOutput )
00112 {
00113     QStringList strings = m_bufferedReader.process( someOutput );
00114     if (strings.count() > 0)
00115     {
00116         m_statusLines += strings;
00117     }
00118 }
00119 
00121 
00122 void CVSFileInfoProvider::slotReceivedErrors( QString /*someErrors*/ )
00123 {
00124     /* Nothing to do */
00125 }
00126 
00128 
00129 QString CVSFileInfoProvider::projectDirectory() const
00130 {
00131     return owner()->project()->projectDirectory();
00132 }
00133 
00135 
00136 VCSFileInfoMap *CVSFileInfoProvider::parse( QStringList stringStream )
00137 {
00138     QRegExp rx_recordStart( "^=+$" );
00139     QRegExp rx_fileName( "^File: (\\.|\\-|\\w)+" );
00140     QRegExp rx_fileStatus( "Status: (\\.|-|\\s|\\w)+" );
00141     QRegExp rx_fileWorkRev( "\\bWorking revision:" );
00142     QRegExp rx_fileRepoRev( "\\bRepository revision:" );
00143     //QRegExp rx_stickyTag( "\\s+(Sticky Tag:\\W+(w+|\\(none\\)))" );
00144     //QRegExp rx_stickyDate( "" ); // @todo but are they useful?? :-/
00145     //QRegExp rx_stickyOptions( "" ); //@todo
00146 
00147     QString fileName,
00148         fileStatus,
00149         workingRevision,
00150         repositoryRevision,
00151         stickyTag,
00152         stickyDate,
00153         stickyOptions;
00154 
00155     VCSFileInfoMap *vcsStates = new VCSFileInfoMap;
00156 
00157     int state = 0;
00158     const int lastAcceptableState = 4;
00159     // This is where the dirty parsing is done: from a string stream representing the
00160     // 'cvs log' output we build a map with more useful strunctured data ;-)
00161     for (QStringList::const_iterator it=stringStream.begin(); it != stringStream.end(); ++it)
00162     {
00163         QString s = (*it).stripWhiteSpace();
00164         kdDebug(9006) << ">> Parsing: " << s << endl;
00165 
00166         if (rx_recordStart.exactMatch( s ))
00167             state = 1;
00168         else if (state == 1 && rx_fileName.search( s ) >= 0 && rx_fileStatus.search( s ) >= 0)    // FileName
00169         {
00170             fileName = rx_fileName.cap().replace( "File:", "" ).stripWhiteSpace();
00171             fileStatus = rx_fileStatus.cap().replace( "Status:", "" ).stripWhiteSpace();
00172             ++state; // Next state
00173             kdDebug(9006) << ">> " << fileName << ", " << fileStatus << endl;
00174         }
00175         else if (state == 2 && rx_fileWorkRev.search( s ) >= 0)
00176         {
00177             workingRevision = s.replace( "Working revision:", "" ).stripWhiteSpace();
00178 
00179             QRegExp rx_revision( "\\b(((\\d)+\\.?)*|New file!)" );
00180             if (rx_revision.search( workingRevision ) >= 0)
00181             {
00182                 workingRevision = rx_revision.cap();
00183                 kdDebug(9006) << ">> WorkRev: " << workingRevision << endl;
00184                 ++state;
00185             }
00186         }
00187         else if (state == 3 && rx_fileRepoRev.search( s ) >= 0)
00188         {
00189             repositoryRevision = s.replace( "Repository revision:", "" ).stripWhiteSpace();
00190 
00191             QRegExp rx_revision( "\\b(((\\d)+\\.?)*|No revision control file)" );
00192             if (rx_revision.search( s ) >= 0)
00193             {
00194                 repositoryRevision = rx_revision.cap();
00195                 kdDebug(9006) << ">> RepoRev: " << repositoryRevision << endl;
00196                 ++state;
00197             }
00198         }
00199 /*
00200         else if (state == 4 && rx_stickyTag.search( s ) >= 0)
00201         {
00202             stickyTag = rx_stickyTag.cap();
00203             ++state;
00204         }
00205 */
00206         else if (state >= lastAcceptableState) // OK, parsed all useful info?
00207         {
00208             // Package stuff, put into map and get ready for a new record
00209             VCSFileInfo vcsInfo( fileName, workingRevision, repositoryRevision,
00210                 String2EnumState( fileStatus ) );
00211             kdDebug(9006) << "== Inserting: " << vcsInfo.toString() << endl;
00212             vcsStates->insert( fileName, vcsInfo );
00213         }
00214     }
00215     return vcsStates;
00216 }
00217 
00219 
00220 VCSFileInfo::FileState CVSFileInfoProvider::String2EnumState( QString stateAsString )
00221 {
00222     // @todo add more status as "Conflict" and "Sticky" (but I dunno how CVS writes it so I'm going
00223     // to await until I have a conflict or somebody else fix it ;-)
00224     // @todo use QRegExp for better matching since it seems strings have changed between CVS releases :-(
00225     // @todo a new state for 'Needs patch'
00226     if (stateAsString == "Up-to-date")
00227         return VCSFileInfo::Uptodate;
00228     else if (stateAsString == "Locally Modified")
00229         return VCSFileInfo::Modified;
00230     else if (stateAsString == "Locally Added")
00231         return VCSFileInfo::Added;
00232     else if (stateAsString == "Unresolved Conflict")
00233         return VCSFileInfo::Conflict;
00234     else if (stateAsString == "Needs Patch")
00235         return VCSFileInfo::NeedsPatch;
00236     else if (stateAsString == "Needs Checkout")
00237         return VCSFileInfo::NeedsCheckout;
00238     else
00239         return VCSFileInfo::Unknown; 
00240 }
00241 
00243 
00244 void CVSFileInfoProvider::printOutFileInfoMap( const VCSFileInfoMap &map )
00245 {
00246     kdDebug(9006) << "Files parsed:" << endl;
00247     for (VCSFileInfoMap::const_iterator it = map.begin(); it != map.end(); ++it)
00248     {
00249         const VCSFileInfo &vcsInfo = *it;
00250         kdDebug(9006) << vcsInfo.toString() << endl;
00251     }
00252 }
00253 
00254 #include "cvsfileinfoprovider.moc"
KDE Logo
This file is part of the documentation for KDevelop Version 3.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 23 00:03:59 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003