diff --git a/plugins/subversion/svnblamejob.cpp b/plugins/subversion/svnblamejob.cpp index 69ed9d1d2f..7e065d36cd 100644 --- a/plugins/subversion/svnblamejob.cpp +++ b/plugins/subversion/svnblamejob.cpp @@ -1,191 +1,191 @@ /*************************************************************************** * This file is part of KDevelop * * Copyright 2007 Andreas Pakulat * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library 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 Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "svnblamejob.h" #include "svnblamejob_p.h" #include #include #include "svnclient.h" #include SvnInternalBlameJob::SvnInternalBlameJob( SvnJobBase* parent ) : SvnInternalJobBase( parent ) { m_startRevision.setRevisionValue( qVariantFromValue( KDevelop::VcsRevision::Start ), KDevelop::VcsRevision::Special ); m_endRevision.setRevisionValue( qVariantFromValue( KDevelop::VcsRevision::Head ), KDevelop::VcsRevision::Special ); } void SvnInternalBlameJob::run(ThreadWeaver::JobPointer /*self*/, ThreadWeaver::Thread* /*thread*/) { initBeforeRun(); QByteArray ba = location().toString( QUrl::PreferLocalFile | QUrl::StripTrailingSlash ).toUtf8(); svn::Client cli(m_ctxt); svn::AnnotatedFile* file; try { file = cli.annotate( ba.data(), createSvnCppRevisionFromVcsRevision( startRevision() ), createSvnCppRevisionFromVcsRevision( endRevision() ) ); }catch( svn::ClientException ce ) { qCDebug(PLUGIN_SVN) << "Exception while blaming file: " << location() << QString::fromUtf8( ce.message() ); setErrorMessage( QString::fromUtf8( ce.message() ) ); m_success = false; return; } svn_revnum_t minrev = -1, maxrev = -1; for( svn::AnnotatedFile::const_iterator it = file->begin(); it != file->end(); ++it ) { if( (*it).revision() < minrev || minrev == -1 ) { minrev = (*it).revision(); } if( (*it).revision() > maxrev || maxrev == -1 ) { maxrev = (*it).revision(); } } QHash commitMessages; try { const svn::LogEntries* entries = cli.log( ba.data(), svn::Revision(minrev), svn::Revision(maxrev), false, false ); for( svn::LogEntries::const_iterator it = entries->begin(); it != entries->end(); ++it ) { commitMessages[(*it).revision] = QString::fromUtf8( (*it).message.c_str() ); } }catch( svn::ClientException ce ) { qCDebug(PLUGIN_SVN) << "Exception while fetching log messages for blame: " << location() << QString::fromUtf8( ce.message() ); setErrorMessage( QString::fromUtf8( ce.message() ) ); m_success = false; } for( svn::AnnotatedFile::const_iterator it = file->begin(); it != file->end(); ++it ) { KDevelop::VcsAnnotationLine line; line.setAuthor( QString::fromUtf8( it->author().c_str() ) ); line.setDate( QDateTime::fromString( QString::fromUtf8( it->date().c_str() ), Qt::ISODate ) ); line.setText( QString::fromUtf8( it->line().c_str() ) ); KDevelop::VcsRevision rev; rev.setRevisionValue( QVariant( qlonglong( it->revision() ) ), KDevelop::VcsRevision::GlobalNumber ); line.setRevision( rev ); line.setLineNumber( it->lineNumber() ); line.setCommitMessage( commitMessages[it->revision()] ); emit blameLine( line ); } } void SvnInternalBlameJob::setLocation( const QUrl &url ) { QMutexLocker l( &m_mutex ); m_location = url; } QUrl SvnInternalBlameJob::location() const { QMutexLocker l( &m_mutex ); return m_location; } KDevelop::VcsRevision SvnInternalBlameJob::startRevision() const { QMutexLocker l( &m_mutex ); return m_startRevision; } KDevelop::VcsRevision SvnInternalBlameJob::endRevision() const { QMutexLocker l( &m_mutex ); return m_endRevision; } void SvnInternalBlameJob::setStartRevision( const KDevelop::VcsRevision& rev ) { QMutexLocker l( &m_mutex ); m_startRevision = rev; } void SvnInternalBlameJob::setEndRevision( const KDevelop::VcsRevision& rev ) { QMutexLocker l( &m_mutex ); m_endRevision = rev; } SvnBlameJob::SvnBlameJob( KDevSvnPlugin* parent ) : SvnJobBaseImpl( parent, KDevelop::OutputJob::Silent ) { setType( KDevelop::VcsJob::Annotate ); - connect(m_job, &SvnInternalBlameJob::blameLine, + connect(m_job.data(), &SvnInternalBlameJob::blameLine, this, &SvnBlameJob::blameLineReceived); setObjectName(i18n("Subversion Annotate")); } QVariant SvnBlameJob::fetchResults() { QList results = m_annotations; m_annotations.clear(); return results; } void SvnBlameJob::start() { if ( !m_job->location().isValid() ) { internalJobFailed(); setErrorText( i18n( "Not enough information to blame location" ) ); } else { qCDebug(PLUGIN_SVN) << "blaming url:" << m_job->location(); startInternalJob(); } } void SvnBlameJob::setLocation( const QUrl &url ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setLocation( url ); } void SvnBlameJob::setStartRevision( const KDevelop::VcsRevision& rev ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setStartRevision( rev ); } void SvnBlameJob::setEndRevision( const KDevelop::VcsRevision& rev ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setEndRevision( rev ); } void SvnBlameJob::blameLineReceived( const KDevelop::VcsAnnotationLine& line ) { m_annotations.append( qVariantFromValue( line ) ); emit resultsReady( this ); } diff --git a/plugins/subversion/svndiffjob.cpp b/plugins/subversion/svndiffjob.cpp index e036157753..9542ccc3ed 100644 --- a/plugins/subversion/svndiffjob.cpp +++ b/plugins/subversion/svndiffjob.cpp @@ -1,341 +1,341 @@ /*************************************************************************** * This file is part of KDevelop * * Copyright 2007 Andreas Pakulat * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library 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 Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "svndiffjob.h" #include "svndiffjob_p.h" #include #include #include #include #include #include #include "kdevsvncpp/path.hpp" #include "kdevsvncpp/revision.hpp" #include "icore.h" #include "iruncontroller.h" #include "svnclient.h" ///@todo The subversion library returns borked diffs, where the headers are at the end. This function /// takes those headers, and moves them into the correct place to create a valid working diff. /// Find the source of this problem. QString repairDiff(const QString& diff) { qCDebug(PLUGIN_SVN) << "diff before repair:" << diff; QStringList lines = diff.split('\n'); QMap headers; for(int a = 0; a < lines.size()-1; ++a) { if(lines[a].startsWith(QLatin1String("Index: ")) && lines[a+1].startsWith(QLatin1String("====="))) { QString fileName = lines[a].mid(strlen("Index: ")).trimmed(); headers[fileName] = lines[a]; qCDebug(PLUGIN_SVN) << "found header for" << fileName; lines[a] = QString(); if(lines[a+1].startsWith(QLatin1String("======"))) { headers[fileName] += '\n' + lines[a+1]; lines[a+1] = QString(); } } } QRegExp spaceRegExp("\\s"); for(int a = 0; a < lines.size()-1; ++a) { if(lines[a].startsWith(QLatin1String("--- "))) { QString tail = lines[a].mid(strlen("--- ")); if(tail.indexOf(spaceRegExp) != -1) { QString file = tail.left(tail.indexOf(spaceRegExp)); qCDebug(PLUGIN_SVN) << "checking for" << file; if(headers.contains(file)) { qCDebug(PLUGIN_SVN) << "adding header for" << file << ":" << headers[file]; lines[a] = headers[file] + '\n' + lines[a]; } } } } QString ret = lines.join(QLatin1Char('\n')); qCDebug(PLUGIN_SVN) << "repaired diff:" << ret; return ret; } //@TODO: Handle raw diffs by using SvnCatJob to fetch both files/revisions SvnInternalDiffJob::SvnInternalDiffJob( SvnJobBase* parent ) : SvnInternalJobBase( parent ) { m_pegRevision.setRevisionValue( KDevelop::VcsRevision::Head, KDevelop::VcsRevision::Special ); } void SvnInternalDiffJob::run(ThreadWeaver::JobPointer /*self*/, ThreadWeaver::Thread* /*thread*/) { initBeforeRun(); SvnClient cli(m_ctxt); try { QString diff; if( destination().isValid() ) { QByteArray srcba; if( source().type() == KDevelop::VcsLocation::LocalLocation ) { srcba = source().localUrl().toString( QUrl::PreferLocalFile | QUrl::StripTrailingSlash ).toUtf8(); }else { srcba = source().repositoryServer().toUtf8(); } QByteArray dstba; if( destination().type() == KDevelop::VcsLocation::LocalLocation ) { dstba = destination().localUrl().toString( QUrl::PreferLocalFile | QUrl::StripTrailingSlash ).toUtf8(); }else { dstba = destination().repositoryServer().toUtf8(); } svn::Revision srcRev = createSvnCppRevisionFromVcsRevision( srcRevision() ); svn::Revision dstRev = createSvnCppRevisionFromVcsRevision( dstRevision() ); if( srcba.isEmpty() || ( dstba.isEmpty() && srcRev.kind() == svn_opt_revision_unspecified && dstRev.kind() == svn_opt_revision_unspecified ) ) { throw svn::ClientException( "Not enough information for a diff"); } diff = cli.diff( svn::Path( srcba.data() ), srcRev, svn::Path( dstba.data() ), dstRev, recursive(), ignoreAncestry(), noDiffOnDelete(), ignoreContentType() ); }else { QByteArray srcba; if( source().type() == KDevelop::VcsLocation::LocalLocation ) { srcba = source().localUrl().toString( QUrl::PreferLocalFile | QUrl::StripTrailingSlash ).toUtf8(); }else { srcba = source().repositoryServer().toUtf8(); } svn::Revision pegRev = createSvnCppRevisionFromVcsRevision( pegRevision() ); svn::Revision srcRev = createSvnCppRevisionFromVcsRevision( srcRevision() ); svn::Revision dstRev = createSvnCppRevisionFromVcsRevision( dstRevision() ); if( srcba.isEmpty() || pegRev.kind() == svn_opt_revision_unspecified || dstRev.kind() == svn_opt_revision_unspecified || srcRev.kind() == svn_opt_revision_unspecified) { throw svn::ClientException( "Not enough information for a diff"); } diff = cli.diff( svn::Path( srcba.data() ), pegRev, srcRev, dstRev, recursive(), ignoreAncestry(), noDiffOnDelete(), ignoreContentType() ); } diff = repairDiff(diff); emit gotDiff( diff ); }catch( svn::ClientException ce ) { qCDebug(PLUGIN_SVN) << "Exception while doing a diff: " << m_source.localUrl() << m_source.repositoryServer() << m_srcRevision.prettyValue() << m_destination.localUrl() << m_destination.repositoryServer() << m_dstRevision.prettyValue() << QString::fromUtf8( ce.message() ); setErrorMessage( QString::fromUtf8( ce.message() ) ); m_success = false; } } void SvnInternalDiffJob::setSource( const KDevelop::VcsLocation& src ) { QMutexLocker l( &m_mutex ); m_source = src; } void SvnInternalDiffJob::setDestination( const KDevelop::VcsLocation& dst ) { QMutexLocker l( &m_mutex ); m_destination = dst; } void SvnInternalDiffJob::setSrcRevision( const KDevelop::VcsRevision& srcRev ) { QMutexLocker l( &m_mutex ); m_srcRevision = srcRev; } void SvnInternalDiffJob::setDstRevision( const KDevelop::VcsRevision& dstRev ) { QMutexLocker l( &m_mutex ); m_dstRevision = dstRev; } void SvnInternalDiffJob::setPegRevision( const KDevelop::VcsRevision& pegRev ) { QMutexLocker l( &m_mutex ); m_pegRevision = pegRev; } void SvnInternalDiffJob::setRecursive( bool recursive ) { QMutexLocker l( &m_mutex ); m_recursive = recursive; } void SvnInternalDiffJob::setIgnoreAncestry( bool ignoreAncestry ) { QMutexLocker l( &m_mutex ); m_ignoreAncestry = ignoreAncestry; } void SvnInternalDiffJob::setIgnoreContentType( bool ignoreContentType ) { QMutexLocker l( &m_mutex ); m_ignoreContentType = ignoreContentType; } void SvnInternalDiffJob::setNoDiffOnDelete( bool noDiffOnDelete ) { QMutexLocker l( &m_mutex ); m_noDiffOnDelete = noDiffOnDelete; } bool SvnInternalDiffJob::recursive() const { QMutexLocker l( &m_mutex ); return m_recursive; } bool SvnInternalDiffJob::ignoreAncestry() const { QMutexLocker l( &m_mutex ); return m_ignoreAncestry; } bool SvnInternalDiffJob::ignoreContentType() const { QMutexLocker l( &m_mutex ); return m_ignoreContentType; } bool SvnInternalDiffJob::noDiffOnDelete() const { QMutexLocker l( &m_mutex ); return m_noDiffOnDelete; } KDevelop::VcsLocation SvnInternalDiffJob::source() const { QMutexLocker l( &m_mutex ); return m_source; } KDevelop::VcsLocation SvnInternalDiffJob::destination() const { QMutexLocker l( &m_mutex ); return m_destination; } KDevelop::VcsRevision SvnInternalDiffJob::srcRevision() const { QMutexLocker l( &m_mutex ); return m_srcRevision; } KDevelop::VcsRevision SvnInternalDiffJob::dstRevision() const { QMutexLocker l( &m_mutex ); return m_dstRevision; } KDevelop::VcsRevision SvnInternalDiffJob::pegRevision() const { QMutexLocker l( &m_mutex ); return m_pegRevision; } SvnDiffJob::SvnDiffJob( KDevSvnPlugin* parent ) : SvnJobBaseImpl( parent, KDevelop::OutputJob::Silent ) { setType( KDevelop::VcsJob::Add ); - connect( m_job, &SvnInternalDiffJob::gotDiff, + connect( m_job.data(), &SvnInternalDiffJob::gotDiff, this, &SvnDiffJob::setDiff, Qt::QueuedConnection ); setObjectName(i18n("Subversion Diff")); } QVariant SvnDiffJob::fetchResults() { return qVariantFromValue( m_diff ); } void SvnDiffJob::start() { if( !m_job->source().isValid() || ( !m_job->destination().isValid() && ( m_job->srcRevision().revisionType() == KDevelop::VcsRevision::Invalid || m_job->dstRevision().revisionType() == KDevelop::VcsRevision::Invalid ) ) ) { internalJobFailed(); setErrorText( i18n( "Not enough information given to execute diff" ) ); } else { startInternalJob(); } } void SvnDiffJob::setSource( const KDevelop::VcsLocation& source ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setSource( source ); } void SvnDiffJob::setDestination( const KDevelop::VcsLocation& destination ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setDestination( destination ); } void SvnDiffJob::setPegRevision( const KDevelop::VcsRevision& pegRevision ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setPegRevision( pegRevision ); } void SvnDiffJob::setSrcRevision( const KDevelop::VcsRevision& srcRevision ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setSrcRevision( srcRevision ); } void SvnDiffJob::setDstRevision( const KDevelop::VcsRevision& dstRevision ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setDstRevision( dstRevision ); } void SvnDiffJob::setRecursive( bool recursive ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setRecursive( recursive ); } void SvnDiffJob::setIgnoreAncestry( bool ignoreAncestry ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setIgnoreAncestry( ignoreAncestry ); } void SvnDiffJob::setIgnoreContentType( bool ignoreContentType ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setIgnoreContentType( ignoreContentType ); } void SvnDiffJob::setNoDiffOnDelete( bool noDiffOnDelete ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setNoDiffOnDelete( noDiffOnDelete ); } void SvnDiffJob::setDiff( const QString& diff ) { m_diff = KDevelop::VcsDiff(); m_diff.setBaseDiff(QUrl::fromLocalFile(QStringLiteral("/"))); m_diff.setDiff( diff ); emit resultsReady( this ); } diff --git a/plugins/subversion/svninfojob.cpp b/plugins/subversion/svninfojob.cpp index d8fef29823..a23a25f8e7 100644 --- a/plugins/subversion/svninfojob.cpp +++ b/plugins/subversion/svninfojob.cpp @@ -1,153 +1,153 @@ /*************************************************************************** * This file is part of KDevelop * * Copyright 2007 Andreas Pakulat * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library 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 Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "svninfojob.h" #include "svninfojob_p.h" #include #include #include "kdevsvncpp/client.hpp" #include "kdevsvncpp/info.hpp" SvnInternalInfoJob::SvnInternalInfoJob( SvnJobBase* parent ) : SvnInternalJobBase( parent ) { } void SvnInternalInfoJob::run(ThreadWeaver::JobPointer /*self*/, ThreadWeaver::Thread* /*thread*/) { initBeforeRun(); svn::Client cli(m_ctxt); try { QByteArray ba = location().toString( QUrl::PreferLocalFile | QUrl::StripTrailingSlash ).toUtf8(); svn::InfoVector v = cli.info( ba.data() ); svn::Info i = v.at(0); SvnInfoHolder h; h.name = QString::fromUtf8( i.path().path().c_str() ); h.url = QUrl::fromUserInput( QString::fromUtf8( i.url() ) ); h.rev = qlonglong( i.revision() ); h.kind = i.kind(); h.repoUrl = QUrl::fromUserInput( QString::fromUtf8( i.repos() ) ); h.repouuid = QString::fromUtf8( i.uuid() ); h.lastChangedRev = qlonglong( i.lastChangedRevision() ); h.lastChangedDate = QDateTime::fromTime_t( i.lastChangedDate() ); h.lastChangedAuthor = QString::fromUtf8( i.lastChangedAuthor() ); h.scheduled = i.schedule(); h.copyFromUrl = QUrl::fromUserInput( QString::fromUtf8( i.copyFromUrl() ) ); h.copyFromRevision = qlonglong( i.copyFromRevision() ); h.textTime = QDateTime::fromTime_t( i.textTime() ); h.propertyTime = QDateTime::fromTime_t( i.propertyTime() ); h.oldFileConflict = QString::fromUtf8( i.oldConflictFile() ); h.newFileConflict = QString::fromUtf8( i.newConflictFile() ); h.workingCopyFileConflict = QString::fromUtf8( i.workingConflictFile() ); h.propertyRejectFile = QString::fromUtf8( i.propertyRejectFile() ); emit gotInfo( h ); }catch( svn::ClientException ce ) { qCDebug(PLUGIN_SVN) << "Exception while getting info for file: " << m_location << QString::fromUtf8( ce.message() ); setErrorMessage( QString::fromUtf8( ce.message() ) ); m_success = false; } } void SvnInternalInfoJob::setLocation( const QUrl &url ) { QMutexLocker l( &m_mutex ); m_location = url; } QUrl SvnInternalInfoJob::location() const { QMutexLocker l( &m_mutex ); return m_location; } SvnInfoJob::SvnInfoJob( KDevSvnPlugin* parent ) : SvnJobBaseImpl( parent, KDevelop::OutputJob::Silent ), m_provideInfo( SvnInfoJob::AllInfo ) { setType( KDevelop::VcsJob::Add ); - connect( m_job, &SvnInternalInfoJob::gotInfo, + connect( m_job.data(), &SvnInternalInfoJob::gotInfo, this, &SvnInfoJob::setInfo, Qt::QueuedConnection ); setObjectName(i18n("Subversion Info")); } QVariant SvnInfoJob::fetchResults() { if( m_provideInfo == RepoUrlOnly ) { return QVariant(m_info.url); }else if( m_provideInfo == RevisionOnly ) { KDevelop::VcsRevision rev; svn::Revision svnRev( m_info.rev ); switch( m_provideRevisionType ) { case KDevelop::VcsRevision::Date: rev.setRevisionValue( QVariant( QDateTime::fromTime_t( svnRev.date() ) ), KDevelop::VcsRevision::Date ); break; default: rev.setRevisionValue( QVariant( qlonglong( svnRev.revnum() ) ), KDevelop::VcsRevision::GlobalNumber ); break; } return qVariantFromValue( rev ); } return qVariantFromValue( m_info ); } void SvnInfoJob::start() { if (!m_job->location().isValid()) { internalJobFailed(); setErrorText( i18n( "Not enough information to execute info job" ) ); } else { startInternalJob(); } } void SvnInfoJob::setLocation( const QUrl &url ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setLocation( url ); } void SvnInfoJob::setProvideInformation( ProvideInformationType type ) { m_provideInfo = type; } void SvnInfoJob::setProvideRevisionType( KDevelop::VcsRevision::RevisionType t ) { m_provideRevisionType = t; } void SvnInfoJob::setInfo( const SvnInfoHolder& info ) { m_info = info; emit resultsReady( this ); } diff --git a/plugins/subversion/svninternaljobbase.cpp b/plugins/subversion/svninternaljobbase.cpp index 09a356acef..1d90f52492 100644 --- a/plugins/subversion/svninternaljobbase.cpp +++ b/plugins/subversion/svninternaljobbase.cpp @@ -1,381 +1,382 @@ /*************************************************************************** * This file is part of KDevelop * * Copyright 2007 Andreas Pakulat * * Copyright 2007 Dukju Ahn * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library 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 Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "svninternaljobbase.h" #include #include #include #include extern "C" { #include } #include #include #include "kdevsvncpp/context.hpp" #include "kdevsvncpp/apr.hpp" #include "kdevsvncpp/revision.hpp" -SvnInternalJobBase::SvnInternalJobBase( SvnJobBase* parent ) - : QObject(parent) - , m_ctxt( new svn::Context() ) +SvnInternalJobBase::SvnInternalJobBase(SvnJobBase* parentJob) + : m_ctxt( new svn::Context() ) , m_guiSemaphore( 0 ) , m_mutex() , m_killMutex() + , m_parentJob(parentJob) { m_ctxt->setListener(this); } SvnInternalJobBase::~SvnInternalJobBase() { m_ctxt->setListener(nullptr); delete m_ctxt; m_ctxt = nullptr; } void SvnInternalJobBase::defaultBegin(const ThreadWeaver::JobPointer& self, ThreadWeaver::Thread *thread) { emit started(); ThreadWeaver::Job::defaultBegin(self, thread); } void SvnInternalJobBase::defaultEnd(const ThreadWeaver::JobPointer& self, ThreadWeaver::Thread *thread) { ThreadWeaver::Job::defaultEnd(self, thread); if (!self->success()) { emit failed(); } emit done(); + // at this ppint this object cannot yet be deleted (e.g. as part of the parent job destruction, + // ThreadWeaver logic still holds and uses a reference to finish the execution logic } bool SvnInternalJobBase::contextGetLogin( const std::string& realm, std::string& username, std::string& password, bool& maySave ) { emit needLogin( QString::fromUtf8( realm.c_str() ) ); m_guiSemaphore.acquire( 1 ); QMutexLocker l(&m_mutex); if( m_login_username.isEmpty() || m_login_password.isEmpty() ) return false; username = std::string( m_login_username.toUtf8() ); password = std::string( m_login_password.toUtf8() ); maySave = this->m_maySave; return true; } void SvnInternalJobBase::contextNotify( const char* path, svn_wc_notify_action_t action, svn_node_kind_t kind, const char* mimetype, svn_wc_notify_state_t contentState, svn_wc_notify_state_t propState, svn_revnum_t rev ) { QString notifyString; switch( action ){ case svn_wc_notify_add: notifyString = i18nc( "A file was marked to be added to svn", "Added %1", QString::fromUtf8( path ) ); break; case svn_wc_notify_delete: notifyString = i18nc( "A file was marked for deletion from svn", "Deleted %1", QString::fromUtf8( path ) ); break; // various update notifications case svn_wc_notify_update_delete: notifyString = i18nc( "A file was deleted during an svn update operation", "Deleted %1", QString::fromUtf8( path ) ); break; case svn_wc_notify_update_add: notifyString = i18nc( "A file was added during an svn update operation", "Added %1", QString::fromUtf8( path ) ); break; case svn_wc_notify_update_update: /* If this is an inoperative dir change, do no notification. An inoperative dir change is when a directory gets closed without any props having been changed. */ if (! ((kind == svn_node_dir) && ((propState == svn_wc_notify_state_inapplicable) || (propState == svn_wc_notify_state_unknown) || (propState == svn_wc_notify_state_unchanged)))) { if (kind == svn_node_file) { if (contentState == svn_wc_notify_state_conflicted) notifyString = QStringLiteral("Conflict On File"); else if (contentState == svn_wc_notify_state_merged) notifyString = QStringLiteral("File Merged"); else if (contentState == svn_wc_notify_state_changed) notifyString = QStringLiteral("File Updated"); } if (propState == svn_wc_notify_state_conflicted) notifyString += QLatin1String(" Conflict On Property"); else if (propState == svn_wc_notify_state_merged) notifyString += QLatin1String(" Properties Merged"); else if (propState == svn_wc_notify_state_changed) notifyString += QLatin1String(" Properties Updated"); else notifyString += ' '; if (! ((contentState == svn_wc_notify_state_unchanged || contentState == svn_wc_notify_state_unknown) && (propState == svn_wc_notify_state_unchanged || propState == svn_wc_notify_state_unknown))) notifyString += QStringLiteral( " " ) + QString::fromUtf8( path ); } break; case svn_wc_notify_update_completed: // The last notification in an update (including updates of externals). notifyString = i18n("Revision %1", rev ); break; case svn_wc_notify_update_external: notifyString = i18n("Updating externals: %1", QString::fromUtf8( path ) ); break; case svn_wc_notify_status_completed: break; case svn_wc_notify_status_external: break; // various commit notifications case svn_wc_notify_commit_modified: notifyString = i18n( "Sending %1", QString::fromUtf8( path ) ); break; case svn_wc_notify_commit_added: if( mimetype ){ notifyString = i18n( "Adding %1 using mimetype %2.", QString::fromUtf8( path ), mimetype ); } else { notifyString = i18n( "Adding %1.", QString::fromUtf8( path ) ); } break; case svn_wc_notify_commit_deleted: notifyString = i18n( "Deleting %1.", QString::fromUtf8( path ) ); break; case svn_wc_notify_commit_replaced: notifyString = i18n( "Replacing %1.", QString::fromUtf8( path ) ); break; case svn_wc_notify_commit_postfix_txdelta: if ( sendFirstDelta ) { sendFirstDelta = false; notifyString=i18n("Transmitting file data "); } else { notifyString='.'; } break; case svn_wc_notify_blame_revision: notifyString = i18n( "Blame finished for revision %1, path %2", rev, QString::fromUtf8( path ) ); break; case svn_wc_notify_revert: notifyString = i18n( "Reverted working copy %1", QString::fromUtf8( path ) ); break; case svn_wc_notify_failed_revert: notifyString = i18n( "Reverting failed on working copy %1", QString::fromUtf8( path ) ); break; case svn_wc_notify_copy: notifyString = i18n( "Copied %1", QString::fromUtf8( path ) ); break; default: break; } emit showNotification( QString::fromUtf8( path ), notifyString ); } bool SvnInternalJobBase::contextCancel() { QMutexLocker lock( &m_killMutex ); return killed; } bool SvnInternalJobBase::contextGetLogMessage( std::string& msg ) { emit needCommitMessage(); m_guiSemaphore.acquire( 1 ); QMutexLocker l( &m_mutex ); QByteArray ba = m_commitMessage.toUtf8(); msg = std::string( ba.data() ); return true; } void SvnInternalJobBase::initBeforeRun() { - auto parentJob = static_cast(parent()); connect( this, &SvnInternalJobBase::needCommitMessage, - parentJob, &SvnJobBase::askForCommitMessage, Qt::QueuedConnection ); + m_parentJob, &SvnJobBase::askForCommitMessage, Qt::QueuedConnection ); connect( this, &SvnInternalJobBase::needLogin, - parentJob, &SvnJobBase::askForLogin, Qt::QueuedConnection ); + m_parentJob, &SvnJobBase::askForLogin, Qt::QueuedConnection ); connect( this, &SvnInternalJobBase::needSslServerTrust, - parentJob, &SvnJobBase::askForSslServerTrust, Qt::QueuedConnection ); + m_parentJob, &SvnJobBase::askForSslServerTrust, Qt::QueuedConnection ); connect( this, &SvnInternalJobBase::showNotification, - parentJob, &SvnJobBase::showNotification, Qt::QueuedConnection ); + m_parentJob, &SvnJobBase::showNotification, Qt::QueuedConnection ); connect( this, &SvnInternalJobBase::needSslClientCert, - parentJob, &SvnJobBase::askForSslClientCert, Qt::QueuedConnection ); + m_parentJob, &SvnJobBase::askForSslClientCert, Qt::QueuedConnection ); connect( this, &SvnInternalJobBase::needSslClientCertPassword, - parentJob, &SvnJobBase::askForSslClientCertPassword, Qt::QueuedConnection ); + m_parentJob, &SvnJobBase::askForSslClientCertPassword, Qt::QueuedConnection ); } svn::ContextListener::SslServerTrustAnswer SvnInternalJobBase::contextSslServerTrustPrompt( const svn::ContextListener::SslServerTrustData& data, apr_uint32_t& acceptedFailures ) { std::string host = data.hostname; std::string print = data.fingerprint; std::string from = data.validFrom; std::string until = data.validUntil; std::string issue = data.issuerDName; std::string realm = data.realm; acceptedFailures = data.failures; QStringList failures; if( data.failures & SVN_AUTH_SSL_NOTYETVALID ) { failures << i18n("Certificate is not yet valid."); } if( data.failures & SVN_AUTH_SSL_EXPIRED ) { failures << i18n("Certificate has expired."); } if( data.failures & SVN_AUTH_SSL_CNMISMATCH ) { failures << i18n("Certificate's CN (hostname) doesn't match the remote hostname."); } if( data.failures & SVN_AUTH_SSL_UNKNOWNCA ) { failures << i18n("Certificate authority is unknown."); } if( data.failures & SVN_AUTH_SSL_NOTYETVALID ) { failures << i18n("Other unknown error."); } emit needSslServerTrust( failures, QString::fromUtf8( host.c_str() ), QString::fromUtf8( print.c_str() ), QString::fromUtf8( from.c_str() ), QString::fromUtf8( until.c_str() ), QString::fromUtf8( issue.c_str() ), QString::fromUtf8( realm.c_str() ) ); m_guiSemaphore.acquire(1); QMutexLocker l(&m_mutex); return m_trustAnswer; } bool SvnInternalJobBase::contextSslClientCertPrompt( std::string& cert ) { emit needSslClientCert( QString::fromUtf8( cert.c_str() ) ); m_guiSemaphore.acquire( 1 ); return true; } bool SvnInternalJobBase::contextSslClientCertPwPrompt( std::string& pw, const std::string& realm, bool& maySave ) { Q_UNUSED(pw); Q_UNUSED(maySave); emit needSslClientCertPassword( QString::fromUtf8( realm.c_str() ) ); m_guiSemaphore.acquire( 1 ); return false; } bool SvnInternalJobBase::success() const { return m_success; } svn::Revision SvnInternalJobBase::createSvnCppRevisionFromVcsRevision( const KDevelop::VcsRevision& revision ) { svn::Revision rev; QVariant value = revision.revisionValue(); switch( revision.revisionType() ) { case KDevelop::VcsRevision::Special: { if( value.canConvert() ) { KDevelop::VcsRevision::RevisionSpecialType specialtype = value.value(); switch( specialtype ) { case KDevelop::VcsRevision::Head: rev = svn::Revision( svn::Revision::HEAD ); break; case KDevelop::VcsRevision::Working: rev = svn::Revision( svn::Revision::WORKING ); break; case KDevelop::VcsRevision::Base: rev = svn::Revision( svn::Revision::BASE ); break; case KDevelop::VcsRevision::Previous: rev = svn::Revision( svn_opt_revision_previous ); break; case KDevelop::VcsRevision::Start: rev = svn::Revision( svn::Revision::START ); break; default: break; } } break; } case KDevelop::VcsRevision::GlobalNumber: case KDevelop::VcsRevision::FileNumber: { bool ok; qlonglong number = value.toLongLong(&ok); if( ok ) { rev = svn::Revision( number ); } break; } case KDevelop::VcsRevision::Date: { QDateTime dt = value.toDateTime(); if( dt.isValid() ) { rev = svn::Revision( dt.toTime_t() ); } break; } default: break; } return rev; } void SvnInternalJobBase::setErrorMessage( const QString& msg ) { QMutexLocker lock( &m_mutex ); m_errorMessage = msg; } QString SvnInternalJobBase::errorMessage() const { QMutexLocker lock( &m_mutex ); return m_errorMessage; } void SvnInternalJobBase::kill() { QMutexLocker lock( &m_killMutex ); killed = true; } diff --git a/plugins/subversion/svninternaljobbase.h b/plugins/subversion/svninternaljobbase.h index c33c278f97..a9b8fef01e 100644 --- a/plugins/subversion/svninternaljobbase.h +++ b/plugins/subversion/svninternaljobbase.h @@ -1,127 +1,128 @@ /*************************************************************************** * This file is part of KDevelop * * Copyright 2007 Andreas Pakulat * * Copyright 2007 Dukju Ahn * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library 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 Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #ifndef KDEVPLATFORM_PLUGIN_SVNINTERNALJOBBASE_H #define KDEVPLATFORM_PLUGIN_SVNINTERNALJOBBASE_H #include #include #include extern "C" { #include } #include "kdevsvncpp/context_listener.hpp" namespace KDevelop { class VcsRevision; } namespace svn { class Context; class Revision; } class SvnJobBase; class SvnInternalJobBase : public QObject, public ThreadWeaver::Job, public svn::ContextListener { Q_OBJECT public: - explicit SvnInternalJobBase( SvnJobBase* parent = nullptr ); + explicit SvnInternalJobBase(SvnJobBase* parentJob); ~SvnInternalJobBase() override; bool success() const override; bool contextGetLogin( const std::string& realm, std::string& username, std::string& password, bool& maySave ) override; void contextNotify( const char* path, svn_wc_notify_action_t action, svn_node_kind_t kind, const char* mimetype, svn_wc_notify_state_t contentState, svn_wc_notify_state_t propState, svn_revnum_t rev ) override; bool contextCancel() override; bool contextGetLogMessage( std::string& msg ) override; svn::ContextListener::SslServerTrustAnswer contextSslServerTrustPrompt( const svn::ContextListener::SslServerTrustData& data, apr_uint32_t& acceptedFailures ) override; bool contextSslClientCertPrompt( std::string& cert ) override; bool contextSslClientCertPwPrompt( std::string& pw, const std::string& realm, bool& maySave ) override; void initBeforeRun(); void kill(); bool wasKilled(); QString errorMessage() const; svn::Context* m_ctxt; QSemaphore m_guiSemaphore; QString m_login_username; QString m_login_password; bool m_maySave; QString m_commitMessage; svn::ContextListener::SslServerTrustAnswer m_trustAnswer; static svn::Revision createSvnCppRevisionFromVcsRevision( const KDevelop::VcsRevision& ); Q_SIGNALS: void needLogin( const QString& ); void showNotification( const QString&, const QString& ); void needCommitMessage(); void needSslServerTrust( const QStringList&, const QString&, const QString&, const QString&, const QString&, const QString&, const QString& ); void needSslClientCert( const QString& ); void needSslClientCertPassword( const QString& ); /** This signal is emitted when this job is being processed by a thread. */ void started(); /** This signal is emitted when the job has been finished (no matter if it succeeded or not). */ void done(); /** This job has failed. * * This signal is emitted when success() returns false after the job is executed. */ void failed(); protected: void defaultBegin(const ThreadWeaver::JobPointer& job, ThreadWeaver::Thread *thread) override; void defaultEnd(const ThreadWeaver::JobPointer& job, ThreadWeaver::Thread *thread) override; mutable QMutex m_mutex; mutable QMutex m_killMutex; bool m_success = true; void setErrorMessage( const QString& ); private: bool sendFirstDelta = false; bool killed = false; QString m_errorMessage; + SvnJobBase* m_parentJob; }; #endif diff --git a/plugins/subversion/svnjobbase.cpp b/plugins/subversion/svnjobbase.cpp index 7df620d8d7..e3e628505d 100644 --- a/plugins/subversion/svnjobbase.cpp +++ b/plugins/subversion/svnjobbase.cpp @@ -1,209 +1,217 @@ /*************************************************************************** * Copyright 2007 Dukju Ahn * * * * 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. * * * ***************************************************************************/ #include "svnjobbase.h" #include #include #include #include #include #include #include #include #include #include "svninternaljobbase.h" #include "svnssldialog.h" SvnJobBase::SvnJobBase( KDevSvnPlugin* parent, KDevelop::OutputJob::OutputJobVerbosity verbosity ) : VcsJob( parent, verbosity ), m_part( parent ), m_status( KDevelop::VcsJob::JobNotStarted ) { setCapabilities( KJob::Killable ); setTitle( QStringLiteral("Subversion") ); } SvnJobBase::~SvnJobBase() { } void SvnJobBase::startInternalJob() { auto job = internalJob(); - connect( job, &SvnInternalJobBase::failed, + connect( job.data(), &SvnInternalJobBase::failed, this, &SvnJobBase::internalJobFailed, Qt::QueuedConnection ); - connect( job, &SvnInternalJobBase::done, + connect( job.data(), &SvnInternalJobBase::done, this, &SvnJobBase::internalJobDone, Qt::QueuedConnection ); - connect( job, &SvnInternalJobBase::started, + connect( job.data(), &SvnInternalJobBase::started, this, &SvnJobBase::internalJobStarted, Qt::QueuedConnection ); - m_part->jobQueue()->stream() << ThreadWeaver::make_job_raw(job); + // add as shared pointer + // the signals "done" & "failed" are emitted when the queue and the executor still + // have and use a reference to the job, in the execution thread. + // As the this parent job will be deleted in the main/other thread + // (due to deleteLater() being called on it in the KJob::exec()) + // and the ThreadWeaver queue will release the last reference to the passed + // JobInterface pointer only after the JobInterface::execute() method has been left, + // the internal threaded job thus needs to get shared memory management via the QSharedPointer. + m_part->jobQueue()->stream() << job; } bool SvnJobBase::doKill() { internalJob()->kill(); m_status = VcsJob::JobCanceled; return true; } KDevelop::VcsJob::JobStatus SvnJobBase::status() const { return m_status; } void SvnJobBase::askForLogin( const QString& realm ) { qCDebug(PLUGIN_SVN) << "login"; KPasswordDialog dlg( nullptr, KPasswordDialog::ShowUsernameLine | KPasswordDialog::ShowKeepPassword ); dlg.setPrompt( i18n("Enter Login for: %1", realm ) ); if (dlg.exec()) { // krazy:exclude=crashy internalJob()->m_login_username = dlg.username(); internalJob()->m_login_password = dlg.password(); internalJob()->m_maySave = dlg.keepPassword(); } else { internalJob()->m_login_username.clear(); internalJob()->m_login_password.clear(); } internalJob()->m_guiSemaphore.release( 1 ); } void SvnJobBase::showNotification( const QString& path, const QString& msg ) { Q_UNUSED(path); outputMessage(msg); } void SvnJobBase::askForCommitMessage() { qCDebug(PLUGIN_SVN) << "commit msg"; internalJob()->m_guiSemaphore.release( 1 ); } void SvnJobBase::askForSslServerTrust( const QStringList& failures, const QString& host, const QString& print, const QString& from, const QString& until, const QString& issuer, const QString& realm ) { qCDebug(PLUGIN_SVN) << "servertrust"; SvnSSLTrustDialog dlg; dlg.setCertInfos( host, print, from, until, issuer, realm, failures ); if( dlg.exec() == QDialog::Accepted ) { qCDebug(PLUGIN_SVN) << "accepted with:" << dlg.useTemporarily(); if( dlg.useTemporarily() ) { internalJob()->m_trustAnswer = svn::ContextListener::ACCEPT_TEMPORARILY; }else { internalJob()->m_trustAnswer = svn::ContextListener::ACCEPT_PERMANENTLY; } }else { qCDebug(PLUGIN_SVN) << "didn't accept"; internalJob()->m_trustAnswer = svn::ContextListener::DONT_ACCEPT; } internalJob()->m_guiSemaphore.release( 1 ); } void SvnJobBase::askForSslClientCert( const QString& realm ) { KMessageBox::information( nullptr, realm ); qCDebug(PLUGIN_SVN) << "clientrust"; internalJob()->m_guiSemaphore.release( 1 ); } void SvnJobBase::askForSslClientCertPassword( const QString& ) { qCDebug(PLUGIN_SVN) << "clientpw"; internalJob()->m_guiSemaphore.release( 1 ); } void SvnJobBase::internalJobStarted() { - qCDebug(PLUGIN_SVN) << "job started" << static_cast(internalJob()); + qCDebug(PLUGIN_SVN) << "job started" << static_cast(internalJob().data()); m_status = KDevelop::VcsJob::JobRunning; } void SvnJobBase::internalJobDone() { qCDebug(PLUGIN_SVN) << "job done" << internalJob(); if ( m_status == VcsJob::JobFailed ) { // see: https://bugs.kde.org/show_bug.cgi?id=273759 // this gets also called when the internal job failed // then the emit result in internalJobFailed might trigger // a nested event loop (i.e. error dialog) // during that the internalJobDone gets called and triggers // deleteLater and eventually deletes this job // => havoc // // catching this state here works but I don't like it personally... return; } outputMessage(i18n("Completed")); if( m_status != VcsJob::JobCanceled ) { m_status = KDevelop::VcsJob::JobSucceeded; } emitResult(); } void SvnJobBase::internalJobFailed() { qCDebug(PLUGIN_SVN) << "job failed" << internalJob(); setError( 255 ); QString msg = internalJob()->errorMessage(); if( !msg.isEmpty() ) setErrorText( i18n( "Error executing Job:\n%1", msg ) ); outputMessage(errorText()); qCDebug(PLUGIN_SVN) << "Job failed"; if( m_status != VcsJob::JobCanceled ) { m_status = KDevelop::VcsJob::JobFailed; } emitResult(); } KDevelop::IPlugin* SvnJobBase::vcsPlugin() const { return m_part; } void SvnJobBase::outputMessage(const QString& message) { if (!model()) return; if (verbosity() == KDevelop::OutputJob::Silent) return; QStandardItemModel *m = qobject_cast(model()); QStandardItem *previous = m->item(m->rowCount()-1); if (message == QLatin1String(".") && previous && previous->text().contains(QRegExp("\\.+"))) previous->setText(previous->text() + message); else m->appendRow(new QStandardItem(message)); KDevelop::IPlugin* i = KDevelop::ICore::self()->pluginController()->pluginForExtension(QStringLiteral("org.kdevelop.IOutputView")); if( i ) { KDevelop::IOutputView* view = i->extension(); if( view ) { view->raiseOutput( outputId() ); } } } diff --git a/plugins/subversion/svnjobbase.h b/plugins/subversion/svnjobbase.h index 6b79acf727..4e45957208 100644 --- a/plugins/subversion/svnjobbase.h +++ b/plugins/subversion/svnjobbase.h @@ -1,90 +1,92 @@ /*************************************************************************** * Copyright 2007 Dukju Ahn * * * * 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. * * * ***************************************************************************/ #ifndef KDEVPLATFORM_PLUGIN_SVNJOBBASE_H #define KDEVPLATFORM_PLUGIN_SVNJOBBASE_H #include #include "kdevsvncpp/context_listener.hpp" #include "kdevsvnplugin.h" #include "debug.h" #include +#include extern "C" { #include } class SvnInternalJobBase; +using SvnInternalJobBasePtr = QSharedPointer; namespace ThreadWeaver { class Job; } class KDevSvnPlugin; class SvnJobBase : public KDevelop::VcsJob { Q_OBJECT public: explicit SvnJobBase( KDevSvnPlugin*, KDevelop::OutputJob::OutputJobVerbosity verbosity = KDevelop::OutputJob::Verbose ); ~SvnJobBase() override; - virtual SvnInternalJobBase* internalJob() const = 0; + virtual SvnInternalJobBasePtr internalJob() const = 0; KDevelop::VcsJob::JobStatus status() const override; KDevelop::IPlugin* vcsPlugin() const override; public Q_SLOTS: void askForLogin( const QString& ); void showNotification( const QString&, const QString& ); void askForCommitMessage(); void askForSslServerTrust( const QStringList&, const QString&, const QString&, const QString&, const QString&, const QString&, const QString& ); void askForSslClientCert( const QString& ); void askForSslClientCertPassword( const QString& ); protected Q_SLOTS: void internalJobStarted(); void internalJobDone(); void internalJobFailed(); protected: void startInternalJob(); bool doKill() override; KDevSvnPlugin* m_part; private: void outputMessage(const QString &message); KDevelop::VcsJob::JobStatus m_status; }; template class SvnJobBaseImpl : public SvnJobBase { public: explicit SvnJobBaseImpl(KDevSvnPlugin* plugin, KDevelop::OutputJob::OutputJobVerbosity verbosity = KDevelop::OutputJob::Verbose) : SvnJobBase(plugin, verbosity) + , m_job(new InternalJobClass(this)) { - m_job = new InternalJobClass(this); } - SvnInternalJobBase* internalJob() const override + SvnInternalJobBasePtr internalJob() const override { return m_job; } protected: - InternalJobClass* m_job = nullptr; + QSharedPointer m_job; }; #endif diff --git a/plugins/subversion/svnlogjob.cpp b/plugins/subversion/svnlogjob.cpp index 11a25d79e0..b99887ba9e 100644 --- a/plugins/subversion/svnlogjob.cpp +++ b/plugins/subversion/svnlogjob.cpp @@ -1,170 +1,170 @@ /*************************************************************************** * This file is part of KDevelop * * Copyright 2007 Andreas Pakulat * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library 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 Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "svnlogjob.h" #include "svnlogjob_p.h" #include #include #include "svnclient.h" SvnInternalLogJob::SvnInternalLogJob( SvnJobBase* parent ) : SvnInternalJobBase( parent ) { m_endRevision.setRevisionValue( qVariantFromValue( KDevelop::VcsRevision::Start ), KDevelop::VcsRevision::Special ); m_startRevision.setRevisionValue( qVariantFromValue( KDevelop::VcsRevision::Head ), KDevelop::VcsRevision::Special ); m_limit = 0; } void SvnInternalLogJob::run(ThreadWeaver::JobPointer /*self*/, ThreadWeaver::Thread* /*thread*/) { initBeforeRun(); SvnClient cli(m_ctxt); connect( &cli, &SvnClient::logEventReceived, this, &SvnInternalLogJob::logEvent ); try { QByteArray ba = location().toString( QUrl::PreferLocalFile | QUrl::StripTrailingSlash ).toUtf8(); cli.log( ba.data(), createSvnCppRevisionFromVcsRevision( startRevision() ), createSvnCppRevisionFromVcsRevision( endRevision() ), limit() ); }catch( svn::ClientException ce ) { qCDebug(PLUGIN_SVN) << "Exception while logging file: " << location() << QString::fromUtf8( ce.message() ); setErrorMessage( QString::fromUtf8( ce.message() ) ); m_success = false; } } void SvnInternalLogJob::setLocation( const QUrl &url ) { QMutexLocker l( &m_mutex ); m_location = url; } QUrl SvnInternalLogJob::location() const { QMutexLocker l( &m_mutex ); return m_location; } KDevelop::VcsRevision SvnInternalLogJob::startRevision() const { QMutexLocker l( &m_mutex ); return m_startRevision; } KDevelop::VcsRevision SvnInternalLogJob::endRevision() const { QMutexLocker l( &m_mutex ); return m_endRevision; } int SvnInternalLogJob::limit() const { QMutexLocker l( &m_mutex ); return m_limit; } void SvnInternalLogJob::setStartRevision( const KDevelop::VcsRevision& rev ) { QMutexLocker l( &m_mutex ); m_startRevision = rev; } void SvnInternalLogJob::setEndRevision( const KDevelop::VcsRevision& rev ) { QMutexLocker l( &m_mutex ); m_endRevision = rev; } void SvnInternalLogJob::setLimit( int limit ) { QMutexLocker l( &m_mutex ); m_limit = limit; } SvnLogJob::SvnLogJob( KDevSvnPlugin* parent ) : SvnJobBaseImpl( parent, KDevelop::OutputJob::Silent ) { setType( KDevelop::VcsJob::Log ); - connect( m_job, &SvnInternalLogJob::logEvent, + connect( m_job.data(), &SvnInternalLogJob::logEvent, this, &SvnLogJob::logEventReceived ); setObjectName(i18n("Subversion Log")); } QVariant SvnLogJob::fetchResults() { QList list = m_eventList; m_eventList.clear(); return list; } void SvnLogJob::start() { if( !m_job->location().isValid() ) { internalJobFailed(); setErrorText( i18n( "Not enough information to log location" ) ); }else { qCDebug(PLUGIN_SVN) << "logging url:" << m_job->location(); startInternalJob(); } } void SvnLogJob::setLocation( const QUrl &url ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setLocation( url ); } void SvnLogJob::setStartRevision( const KDevelop::VcsRevision& rev ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setStartRevision( rev ); } void SvnLogJob::setEndRevision( const KDevelop::VcsRevision& rev ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setEndRevision( rev ); } void SvnLogJob::setLimit( int limit ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setLimit( limit ); } void SvnLogJob::logEventReceived( const KDevelop::VcsEvent& ev ) { m_eventList << qVariantFromValue( ev ); emit resultsReady( this ); } diff --git a/plugins/subversion/svnstatusjob.cpp b/plugins/subversion/svnstatusjob.cpp index e7b800a676..325094c647 100644 --- a/plugins/subversion/svnstatusjob.cpp +++ b/plugins/subversion/svnstatusjob.cpp @@ -1,177 +1,177 @@ /*************************************************************************** * This file is part of KDevelop * * Copyright 2007 Andreas Pakulat * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library 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 Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "svnstatusjob.h" #include "svnstatusjob_p.h" #include #include #include extern "C" { #include } #include #include "kdevsvncpp/client.hpp" #include "kdevsvncpp/status.hpp" KDevelop::VcsStatusInfo::State getState( const svn::Status& st ) { KDevelop::VcsStatusInfo::State state; if( st.isVersioned() ) { if( st.textStatus() == svn_wc_status_added ) { state = KDevelop::VcsStatusInfo::ItemAdded; }else if( st.textStatus() == svn_wc_status_modified || st.propStatus() == svn_wc_status_modified ) { state = KDevelop::VcsStatusInfo::ItemModified; }else if( st.textStatus() == svn_wc_status_deleted ) { state = KDevelop::VcsStatusInfo::ItemDeleted; }else if( st.textStatus() == svn_wc_status_conflicted || st.propStatus() == svn_wc_status_conflicted ) { state = KDevelop::VcsStatusInfo::ItemHasConflicts; }else { state = KDevelop::VcsStatusInfo::ItemUpToDate; } }else { state = KDevelop::VcsStatusInfo::ItemUnknown; } return state; } SvnInternalStatusJob::SvnInternalStatusJob( SvnJobBase* parent ) : SvnInternalJobBase( parent ) { } void SvnInternalStatusJob::setRecursive( bool recursive ) { QMutexLocker l( &m_mutex ); m_recursive = recursive; } void SvnInternalStatusJob::setLocations( const QList& urls ) { QMutexLocker l( &m_mutex ); m_locations = urls; } QList SvnInternalStatusJob::locations() const { QMutexLocker l( &m_mutex ); return m_locations; } bool SvnInternalStatusJob::recursive() const { QMutexLocker l( &m_mutex ); return m_recursive; } void SvnInternalStatusJob::run(ThreadWeaver::JobPointer /*self*/, ThreadWeaver::Thread* /*thread*/) { qCDebug(PLUGIN_SVN) << "Running internal status job with urls:" << m_locations; initBeforeRun(); svn::Client cli(m_ctxt); QList l = locations(); foreach( const QUrl &url, l ) { //qCDebug(PLUGIN_SVN) << "Fetching status info for:" << url; try { QByteArray ba = url.toString( QUrl::PreferLocalFile | QUrl::StripTrailingSlash ).toUtf8(); svn::StatusEntries se = cli.status( ba.data(), recursive() ); for( svn::StatusEntries::const_iterator it = se.begin(); it != se.end() ; ++it ) { KDevelop::VcsStatusInfo info; info.setUrl( QUrl::fromLocalFile( QString::fromUtf8( (*it).path() ) ) ); info.setState( getState( *it ) ); emit gotNewStatus( info ); } }catch( svn::ClientException ce ) { qCDebug(PLUGIN_SVN) << "Couldn't get status: " << url << QString::fromUtf8( ce.message() ); setErrorMessage( QString::fromUtf8( ce.message() ) ); m_success = false; } } } SvnStatusJob::SvnStatusJob( KDevSvnPlugin* parent ) : SvnJobBaseImpl( parent, KDevelop::OutputJob::Silent ) { setType( KDevelop::VcsJob::Status ); - connect(m_job, &SvnInternalStatusJob::gotNewStatus, + connect(m_job.data(), &SvnInternalStatusJob::gotNewStatus, this, &SvnStatusJob::addToStats, Qt::QueuedConnection); setObjectName(i18n("Subversion Status")); } QVariant SvnStatusJob::fetchResults() { QList temp = m_stats; m_stats.clear(); return QVariant(temp); } void SvnStatusJob::start() { if( m_job->locations().isEmpty() ) { internalJobFailed(); setErrorText( i18n( "Not enough information to execute status job" ) ); } else { qCDebug(PLUGIN_SVN) << "Starting status job"; startInternalJob(); } } void SvnStatusJob::setLocations( const QList& urls ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setLocations( urls ); } void SvnStatusJob::setRecursive( bool recursive ) { if( status() == KDevelop::VcsJob::JobNotStarted ) m_job->setRecursive( recursive ); } void SvnStatusJob::addToStats( const KDevelop::VcsStatusInfo& info ) { //qCDebug(PLUGIN_SVN) << "new status info:" << info.url() << info.state(); if( !m_stats.contains( qVariantFromValue( info ) ) ) { m_stats << qVariantFromValue( info ); emit resultsReady( this ); }else { qCDebug(PLUGIN_SVN) << "Already have this info:"; } }