File indexing completed on 2024-05-05 04:41:02
0001 /* 0002 SPDX-FileCopyrightText: 2007 Dukju Ahn <dukjuahn@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "svnjobbase.h" 0008 0009 #include <QStandardItemModel> 0010 0011 #include <KPasswordDialog> 0012 #include <KLocalizedString> 0013 #include <KMessageBox> 0014 0015 #include <ThreadWeaver/QObjectDecorator> 0016 0017 #include <interfaces/icore.h> 0018 #include <interfaces/iplugincontroller.h> 0019 #include <interfaces/iplugin.h> 0020 #include <outputview/ioutputview.h> 0021 0022 #include "svninternaljobbase.h" 0023 #include "svnssldialog.h" 0024 0025 SvnJobBase::SvnJobBase( KDevSvnPlugin* parent, KDevelop::OutputJob::OutputJobVerbosity verbosity ) 0026 : VcsJob( parent, verbosity ), m_part( parent ), 0027 m_status( KDevelop::VcsJob::JobNotStarted ) 0028 { 0029 setCapabilities( KJob::Killable ); 0030 setTitle( QStringLiteral("Subversion") ); 0031 } 0032 0033 SvnJobBase::~SvnJobBase() 0034 { 0035 } 0036 0037 void SvnJobBase::startInternalJob() 0038 { 0039 auto job = internalJob(); 0040 connect( job.data(), &SvnInternalJobBase::failed, 0041 this, &SvnJobBase::internalJobFailed, Qt::QueuedConnection ); 0042 connect( job.data(), &SvnInternalJobBase::done, 0043 this, &SvnJobBase::internalJobDone, Qt::QueuedConnection ); 0044 connect( job.data(), &SvnInternalJobBase::started, 0045 this, &SvnJobBase::internalJobStarted, Qt::QueuedConnection ); 0046 // add as shared pointer 0047 // the signals "done" & "failed" are emitted when the queue and the executor still 0048 // have and use a reference to the job, in the execution thread. 0049 // As the this parent job will be deleted in the main/other thread 0050 // (due to deleteLater() being called on it in the KJob::exec()) 0051 // and the ThreadWeaver queue will release the last reference to the passed 0052 // JobInterface pointer only after the JobInterface::execute() method has been left, 0053 // the internal threaded job thus needs to get shared memory management via the QSharedPointer. 0054 m_part->jobQueue()->stream() << job; 0055 } 0056 0057 bool SvnJobBase::doKill() 0058 { 0059 internalJob()->kill(); 0060 m_status = VcsJob::JobCanceled; 0061 return true; 0062 } 0063 0064 0065 KDevelop::VcsJob::JobStatus SvnJobBase::status() const 0066 { 0067 return m_status; 0068 } 0069 0070 void SvnJobBase::askForLogin( const QString& realm ) 0071 { 0072 qCDebug(PLUGIN_SVN) << "login"; 0073 KPasswordDialog dlg( nullptr, KPasswordDialog::ShowUsernameLine | KPasswordDialog::ShowKeepPassword ); 0074 dlg.setPrompt( i18n("Enter Login for: %1", realm ) ); 0075 if (dlg.exec()) { // krazy:exclude=crashy 0076 internalJob()->m_login_username = dlg.username(); 0077 internalJob()->m_login_password = dlg.password(); 0078 internalJob()->m_maySave = dlg.keepPassword(); 0079 } else { 0080 internalJob()->m_login_username.clear(); 0081 internalJob()->m_login_password.clear(); 0082 } 0083 internalJob()->m_guiSemaphore.release( 1 ); 0084 } 0085 0086 void SvnJobBase::showNotification( const QString& path, const QString& msg ) 0087 { 0088 Q_UNUSED(path); 0089 outputMessage(msg); 0090 } 0091 0092 void SvnJobBase::askForCommitMessage() 0093 { 0094 qCDebug(PLUGIN_SVN) << "commit msg"; 0095 internalJob()->m_guiSemaphore.release( 1 ); 0096 } 0097 0098 void SvnJobBase::askForSslServerTrust( const QStringList& failures, const QString& host, 0099 const QString& print, const QString& from, 0100 const QString& until, const QString& issuer, 0101 const QString& realm ) 0102 { 0103 0104 qCDebug(PLUGIN_SVN) << "servertrust"; 0105 SvnSSLTrustDialog dlg; 0106 dlg.setCertInfos( host, print, from, until, issuer, realm, failures ); 0107 if( dlg.exec() == QDialog::Accepted ) 0108 { 0109 qCDebug(PLUGIN_SVN) << "accepted with:" << dlg.useTemporarily(); 0110 if( dlg.useTemporarily() ) 0111 { 0112 internalJob()->m_trustAnswer = svn::ContextListener::ACCEPT_TEMPORARILY; 0113 }else 0114 { 0115 internalJob()->m_trustAnswer = svn::ContextListener::ACCEPT_PERMANENTLY; 0116 } 0117 }else 0118 { 0119 qCDebug(PLUGIN_SVN) << "didn't accept"; 0120 internalJob()->m_trustAnswer = svn::ContextListener::DONT_ACCEPT; 0121 } 0122 internalJob()->m_guiSemaphore.release( 1 ); 0123 } 0124 0125 void SvnJobBase::askForSslClientCert( const QString& realm ) 0126 { 0127 KMessageBox::information( nullptr, realm ); 0128 qCDebug(PLUGIN_SVN) << "clientrust"; 0129 internalJob()->m_guiSemaphore.release( 1 ); 0130 } 0131 0132 void SvnJobBase::askForSslClientCertPassword( const QString& ) 0133 { 0134 qCDebug(PLUGIN_SVN) << "clientpw"; 0135 internalJob()->m_guiSemaphore.release( 1 ); 0136 } 0137 0138 void SvnJobBase::internalJobStarted() 0139 { 0140 qCDebug(PLUGIN_SVN) << "job started" << static_cast<void*>(internalJob().data()); 0141 m_status = KDevelop::VcsJob::JobRunning; 0142 } 0143 0144 void SvnJobBase::internalJobDone() 0145 { 0146 qCDebug(PLUGIN_SVN) << "job done" << internalJob(); 0147 if ( m_status == VcsJob::JobFailed ) { 0148 // see: https://bugs.kde.org/show_bug.cgi?id=273759 0149 // this gets also called when the internal job failed 0150 // then the emit result in internalJobFailed might trigger 0151 // a nested event loop (i.e. error dialog) 0152 // during that the internalJobDone gets called and triggers 0153 // deleteLater and eventually deletes this job 0154 // => havoc 0155 // 0156 // catching this state here works but I don't like it personally... 0157 return; 0158 } 0159 0160 outputMessage(i18n("Completed")); 0161 if( m_status != VcsJob::JobCanceled ) { 0162 m_status = KDevelop::VcsJob::JobSucceeded; 0163 } 0164 0165 emitResult(); 0166 } 0167 0168 void SvnJobBase::internalJobFailed() 0169 { 0170 qCDebug(PLUGIN_SVN) << "job failed" << internalJob(); 0171 0172 setError( 255 ); 0173 QString msg = internalJob()->errorMessage(); 0174 if( !msg.isEmpty() ) 0175 setErrorText( i18n( "Error executing Job:\n%1", msg ) ); 0176 outputMessage(errorText()); 0177 qCDebug(PLUGIN_SVN) << "Job failed"; 0178 if( m_status != VcsJob::JobCanceled ) 0179 { 0180 m_status = KDevelop::VcsJob::JobFailed; 0181 } 0182 0183 emitResult(); 0184 } 0185 0186 KDevelop::IPlugin* SvnJobBase::vcsPlugin() const 0187 { 0188 return m_part; 0189 } 0190 0191 void SvnJobBase::outputMessage(const QString& message) 0192 { 0193 if (!model()) return; 0194 if (verbosity() == KDevelop::OutputJob::Silent) return; 0195 0196 auto *m = qobject_cast<QStandardItemModel*>(model()); 0197 QStandardItem *previous = m->item(m->rowCount()-1); 0198 if (message == QLatin1String(".") && previous && previous->text().contains(QRegExp(QStringLiteral("\\.+")))) 0199 previous->setText(previous->text() + message); 0200 else 0201 m->appendRow(new QStandardItem(message)); 0202 KDevelop::IPlugin* i = KDevelop::ICore::self()->pluginController()->pluginForExtension(QStringLiteral("org.kdevelop.IOutputView")); 0203 if( i ) 0204 { 0205 auto* view = i->extension<KDevelop::IOutputView>(); 0206 if( view ) 0207 { 0208 view->raiseOutput( outputId() ); 0209 } 0210 } 0211 } 0212 0213 #include "moc_svnjobbase.cpp"