Commit 0fc8dddf authored by Francis Herne's avatar Francis Herne

Remove unmaintained and buggy CVS plugin

The plugin causes hangs or crashes of KDevelop during some of the most
 common operations.

We haven't received any external bug reports for
 this (nor from 5.0-beta1 to 5.2.1 when the plugin was entirely
 non-functional), so it appears that no-one has attempted to use this
 feature.

Advertising this as a "feature" when it's unusable with no real prospect
 of being fixed will only hurt KDevelop's reputation if anyone does try
 to use it. Of course the code is in git history in case it's wanted in
 future.
parent edb437a9
......@@ -84,7 +84,6 @@ endif()
# BEGIN: VCS
ecm_optional_add_subdirectory(bazaar)
ecm_optional_add_subdirectory(cvs)
ecm_optional_add_subdirectory(git)
ecm_optional_add_subdirectory(perforce)
......
add_definitions(-DTRANSLATION_DOMAIN=\"kdevcvs\")
########### next target ###############
ecm_qt_declare_logging_category(kdevcvs_LOG_PART_SRCS
HEADER debug.h
IDENTIFIER PLUGIN_CVS
CATEGORY_NAME "kdevelop.plugins.cvs"
)
set(kdevcvs_PART_SRCS
cvsplugin.cpp
cvsmainview.cpp
cvsgenericoutputview.cpp
cvsjob.cpp
cvsproxy.cpp
editorsview.cpp
commitdialog.cpp
importmetadatawidget.cpp
importdialog.cpp
checkoutdialog.cpp
cvsannotatejob.cpp
cvslogjob.cpp
cvsdiffjob.cpp
cvsstatusjob.cpp
${kdevcvs_LOG_PART_SRCS}
)
set(kdevcvs_PART_UI
cvsmainview.ui
cvsgenericoutputview.ui
editorsview.ui
commitdialog.ui
importmetadatawidget.ui
checkoutdialog.ui
)
ki18n_wrap_ui(kdevcvs_PART_SRCS ${kdevcvs_PART_UI})
qt5_add_resources(kdevcvs_PART_SRCS kdevcvs.qrc)
kdevplatform_add_plugin(kdevcvs JSON kdevcvs.json SOURCES ${kdevcvs_PART_SRCS})
target_link_libraries(kdevcvs
KF5::KIOWidgets
KF5::Parts
KDev::Util
KDev::Interfaces
KDev::Vcs
KDev::Project
KDev::Language
)
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
CVS plugin for KDevelop4
========================
(C) Robert Gruber [rgruber A users!sourceforge!net]
The CVS plugin is separated into three part.
1) The CvsPart (cvspart.h)
It is the main entry point to the CVS plugin. By implementing
the IVersionControl interface it offers a lot of slots that will
invoke the different CVS actions.
This class serves as a dispatcher. It takes the urls and options
for the requested CVS action and passes them to the CvsProxy (#2)
to get a CvsJob returned. After starting, the job's result() signal
gets connected either directly to CvsMainView (#3) or to a custom
output view.
2) CvsProxy (cvsproxy.h) and CvsJob (cvsjob.h)
The CvsProxy serves as a single point of entry for creating the
CvsJobs. The proxy offers a list of methods for the different
supported CVS actions. Each of these methods will return a CvsJob
object. So the caller does not have to worry about the whole
job and commandline creation. Calling the appropriate method will
do all the work and return a CvsJob object ready for starting.
3) The CvsMainView (cvsmainview.h) and custom view (like editorsview.h)
The CvsMainView displays output from finished jobs. It holds a
KTabWidget to which everbody can add custom output views. For
instance when the user requested a "cvs log" action, a new view
will be added. This view will then parse the output of the "cvs log"
job and display it in a nice way.
But it does not make sense to add new views for every cvs action.
For example, adding a new view everytime "cvs commit", "cvs edit" or
similar actions get executed would be an overkill. Therefore
CvsMainView also provides a generic output view that just displays
the plain text output from such jobs. Unlike custom views, this
generic view can not be closed and it will simply append the output
from each job that got connected to it.
The workflow of the CVS plugin looks like this:
1) The user requests a CVS action
2) The matching slot from CvsPart will be called
3) Optional: The user may be prompted for additional input
[ see: CvsPart::commit() ]
4) CvsPart passes all needed options to the CvsProxy by calling
it's method for the requested action.
5) CvsProxy assembles the commandline, creates a CvsJob object and
returns a pointer to the CvsJobs object
6) CvsPart calls start() for the returned CvsJob object and continues
with either #6.1 or #6.2
6.1) Connectes the job's result() signal to the generic output view
from CvsMainView
6.2) Creates a custom view, connects the job's result() signal to it
and adds the view to CvsMainView
#!/bin/sh
$EXTRACTRC `find . -name \*.rc` `find . -name \*.ui` >> rc.cpp
$XGETTEXT `find . -name \*.cc -o -name \*.cpp -o -name \*.h` -o $podir/kdevcvs.pot
rm -f rc.cpp
/***************************************************************************
* Copyright 2007 Robert Gruber <rgruber@users.sourceforge.net> *
* *
* 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 "checkoutdialog.h"
#include <KLocalizedString>
#include <KMessageBox>
#include <interfaces/icore.h>
#include <interfaces/iruncontroller.h>
#include "cvsplugin.h"
#include "cvsjob.h"
#include "cvsproxy.h"
#include "debug.h"
CheckoutDialog::CheckoutDialog(CvsPlugin* plugin, QWidget *parent)
: QDialog(parent), Ui::CheckoutDialogBase(), m_plugin(plugin)
{
Ui::CheckoutDialogBase::setupUi(this);
localWorkingDir->setMode(KFile::Directory);
}
CheckoutDialog::~CheckoutDialog()
{
}
void CheckoutDialog::accept()
{
CvsJob *job = m_plugin->proxy()->checkout(
localWorkingDir->url(),
serverPath->text(),
module->currentText(),
QString(),
tag->text());
if (job) {
connect(job, &CvsJob::result,
this, &CheckoutDialog::jobFinished);
KDevelop::ICore::self()->runController()->registerJob(job);
}
}
void CheckoutDialog::jobFinished(KJob * job)
{
if (job->error()) {
KMessageBox::error(this, i18n("Error on checkout"), i18n("Checkout Error"));
return;
}
// The job finished, now let's check the output is everything was OK
CvsJob* cvsjob = static_cast<CvsJob*>(job);
static QRegExp re_file(QStringLiteral("^.\\s(.*)"));
bool error = false;
const QStringList lines = cvsjob->output().split(QLatin1Char('\n'));
for (const QString& line : lines) {
if (line.isEmpty()) {
// ignore empty lines
continue;
} else if (re_file.exactMatch(line)) {
// line that tell us that a file has been checkedout
continue;
} else {
// any other line must mean that an error occurred
qCDebug(PLUGIN_CVS) << line;
error = true;
}
}
if (error) {
KMessageBox::error(this,
i18n("Some errors occurred while checking out into %1", localWorkingDir->url().toLocalFile()),
i18n("Checkout Error"));
} else {
QDialog::accept();
}
}
/***************************************************************************
* Copyright 2007 Robert Gruber <rgruber@users.sourceforge.net> *
* *
* 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_CHECKOUTDIALOG_H
#define KDEVPLATFORM_PLUGIN_CHECKOUTDIALOG_H
#include <QDialog>
#include <QUrl>
#include <KJob>
#include "ui_checkoutdialog.h"
class CvsPlugin;
/**
* Allows the user to define from where to checkout
* @author Robert Gruber <rgruber@users.sourceforge.net>
*/
class CheckoutDialog : public QDialog, private Ui::CheckoutDialogBase
{
Q_OBJECT
public:
explicit CheckoutDialog(CvsPlugin* plugin, QWidget *parent=nullptr);
~CheckoutDialog() override;
public Q_SLOTS:
void accept() override;
void jobFinished(KJob* job);
private:
CvsPlugin* m_plugin;
};
#endif
<ui version="4.0" >
<class>CheckoutDialogBase</class>
<widget class="QDialog" name="CheckoutDialogBase" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>252</height>
</rect>
</property>
<property name="windowTitle" >
<string>Checkout</string>
</property>
<layout class="QVBoxLayout" >
<item>
<layout class="QVBoxLayout" >
<item>
<widget class="QLabel" name="textLabel1" >
<property name="text" >
<string>&amp;Local destination directory:</string>
</property>
<property name="wordWrap" >
<bool>false</bool>
</property>
<property name="buddy" >
<cstring>localWorkingDir</cstring>
</property>
</widget>
</item>
<item>
<widget class="KUrlRequester" name="localWorkingDir" />
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" >
<item>
<widget class="QLabel" name="textLabel2" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="MinimumExpanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string>&amp;Server path (e.g. :pserver:username@cvs.example.com:/cvsroot):</string>
</property>
<property name="wordWrap" >
<bool>false</bool>
</property>
<property name="buddy" >
<cstring>serverPath</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="serverPath" />
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" >
<item>
<widget class="QLabel" name="textLabel3" >
<property name="text" >
<string>&amp;Module:</string>
</property>
<property name="buddy" >
<cstring>module</cstring>
</property>
</widget>
</item>
<item>
<widget class="KComboBox" name="module" >
<property name="editable" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" >
<item>
<widget class="QLabel" name="textLabel4" >
<property name="text" >
<string>Tag/Branch:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="tag" />
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KComboBox</class>
<extends>QComboBox</extends>
<header>kcombobox.h</header>
</customwidget>
<customwidget>
<class>KUrlRequester</class>
<extends>QWidget</extends>
<header>kurlrequester.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>CheckoutDialogBase</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel" >
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>CheckoutDialogBase</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
/***************************************************************************
* Copyright 2007 Robert Gruber <rgruber@users.sourceforge.net> *
* *
* 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 "commitdialog.h"
CommitDialog::CommitDialog(QDialog *parent)
: QDialog(parent), Ui::CommitDialogBase()
{
Ui::CommitDialogBase::setupUi(this);
}
CommitDialog::~CommitDialog()
{
}
/***************************************************************************
* Copyright 2007 Robert Gruber <rgruber@users.sourceforge.net> *
* *
* 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_COMMITDIALOG_H
#define KDEVPLATFORM_PLUGIN_COMMITDIALOG_H
#include <QDialog>
#include <KTextEdit>
#include "ui_commitdialog.h"
/**
* Allows to enter text which can them be used as
* parameter for <tt>cvs commit</tt>
* @author Robert Gruber <rgruber@users.sourceforge.net>
*/
class CommitDialog : public QDialog, private Ui::CommitDialogBase
{
Q_OBJECT
public:
explicit CommitDialog(QDialog *parent = nullptr);
~CommitDialog() override;
/**
* @return The text entered by the user
*/
QString message() { return textedit->toPlainText(); }
};
#endif
<ui version="4.0" >
<class>CommitDialogBase</class>
<widget class="QDialog" name="CommitDialogBase" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>387</width>
<height>269</height>
</rect>
</property>
<property name="windowTitle" >
<string>Commit to Repository</string>
</property>
<layout class="QVBoxLayout" >
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Message</string>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="KTextEdit" name="textedit" />
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KTextEdit</class>
<extends>QTextEdit</extends>
<header>ktextedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>CommitDialogBase</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel" >
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>CommitDialogBase</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
/***************************************************************************
* Copyright 2008 Robert Gruber <rgruber@users.sourceforge.net> *
* *
* 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 "cvsannotatejob.h"
#include "debug.h"
#include <QUrl>
#include <QDir>
#include <QLocale>
#include <QDateTime>
#include <vcs/vcsrevision.h>
CvsAnnotateJob::CvsAnnotateJob(KDevelop::IPlugin* parent, KDevelop::OutputJob::OutputJobVerbosity verbosity)
: CvsJob(parent, verbosity)
{
}
CvsAnnotateJob::~CvsAnnotateJob()
{
}
QVariant CvsAnnotateJob::fetchResults()
{
// Convert job's output into KDevelop::VcsAnnotation
KDevelop::VcsAnnotation annotateInfo;
parseOutput(output(), getDirectory(), annotateInfo);
QList<QVariant> lines;
lines.reserve(annotateInfo.lineCount());
for(int i=0; i < annotateInfo.lineCount(); i++) {
KDevelop::VcsAnnotationLine line = annotateInfo.line(i);
lines.append( qVariantFromValue( line ) );
}
return lines;
}
void CvsAnnotateJob::parseOutput(const QString& jobOutput, const QString& workingDirectory, KDevelop::VcsAnnotation& annotateInfo)
{
// each annotation line looks like this:
// 1.1 (kdedev 10-Nov-07): #include <QApplication>
static QRegExp re(QStringLiteral("([^\\s]+)\\s+\\(([^\\s]+)\\s+([^\\s]+)\\):\\s(.*)"));
// the file is pomoted like this:
// Annotations for main.cpp
static QRegExp reFile(QStringLiteral("Annotations for\\s(.*)"));
QStringList lines = jobOutput.split(QLatin1Char('\n'));
for (int i=0, linenumber=0; i<lines.count(); ++i) {
QString s = lines[i];
if (re.exactMatch(s)) {
KDevelop::VcsAnnotationLine item;
item.setLineNumber( linenumber );
item.setText( re.cap(4) );
item.setAuthor( re.cap(2) );
KDevelop::VcsRevision rev;
rev.setRevisionValue( re.cap(1), KDevelop::VcsRevision::FileNumber );
item.setRevision( rev );
// cvs annotate always prints the date with english month names.
// Using QDate::fromString() directly would fail as it works with
// localized month names. So we let QLocale do the work .
QDate date(QLocale::c().toDate(re.cap(3), QStringLiteral("dd-MMM-yy")));
if (date.year() < 1970)
date = date.addYears(100);
item.setDate( QDateTime(date, QTime(), Qt::UTC) );
annotateInfo.insertLine( linenumber, item );
linenumber++;