Commit 3ee02d21 authored by Evgeniy Ivanov's avatar Evgeniy Ivanov
Browse files

CCMAIL: thomas.burdick@gmail.com

FEATURE: basic Git and Mercurial support.
implemented DVCS base class which hould be used in all DVCS plugins, it prevents plugins from duplicating code
fixed bug in git: now all system environment variables are set
fixed bug in mercurial: job<<" "<<" " or job<<"";job<<""; should be used instead of job<<"one two"

Thomas, sorry for removing your code. I was commiting to http://repo.or.cz/w/kdevelopdvcssupport.git because mercurial plugin had a bug (you did the same bug with job<< usage). If you want to help with DVCS: Bazaar is not implemented yet (but it required much less job, than you did to implement mercurial).
parent af9d2b69
......@@ -7,27 +7,29 @@ include_directories( ${KDE4_INCLUDES}
${CMAKE_SOURCE_DIR}/vcs
${CMAKE_SOURCE_DIR}/vcs/interfaces
${CMAKE_SOURCE_DIR}/vcs/models
${CMAKE_SOURCE_DIR}/vcs/dvcs/
)
########### next target ###############
set(kdevgit_PART_SRCS
${CMAKE_SOURCE_DIR}/vcs/dvcs/dvcsjob.cpp
${CMAKE_SOURCE_DIR}/vcs/dvcs/commitdialog.cpp
${CMAKE_SOURCE_DIR}/vcs/dvcs/dvcsplugin.cpp
${CMAKE_SOURCE_DIR}/vcs/dvcs/dvcsmainview.cpp
${CMAKE_SOURCE_DIR}/vcs/dvcs/dvcsgenericoutputview.cpp
${CMAKE_SOURCE_DIR}/vcs/dvcs/importdialog.cpp
${CMAKE_SOURCE_DIR}/vcs/dvcs/importmetadatawidget.cpp
gitplugin.cpp
gitjob.cpp
gitproxy.cpp
commitdialog.cpp
gitmainview.cpp
gitgenericoutputview.cpp
importdialog.cpp
importmetadatawidget.cpp
gitexecutor.cpp
)
set(kdevgit_PART_UI
commitdialog.ui
cvsgenericoutputview.ui
cvsmainview.ui
importmetadatawidget.ui
${CMAKE_SOURCE_DIR}/vcs/dvcs/commitdialog.ui
${CMAKE_SOURCE_DIR}/vcs/dvcs/cvsgenericoutputview.ui
${CMAKE_SOURCE_DIR}/vcs/dvcs/cvsmainview.ui
${CMAKE_SOURCE_DIR}/vcs/dvcs/importmetadatawidget.ui
)
kde4_add_ui_files(kdevgit_PART_SRCS ${kdevgit_PART_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()
{
}
#include "commitdialog.moc"
/***************************************************************************
* 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) version 3 or any later version *
* accepted by the membership of KDE e.V. (or its successor approved *
* by the membership of KDE e.V.), which shall act as a proxy *
* defined in Section 14 of version 3 of the license. *
* *
* 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. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef COMMITDIALOG_H
#define COMMITDIALOG_H
#include <QDialog>
#include <KTextEdit>
#include "ui_commitdialog.h"
/**
* Allows to enter text which can them be used as
* parameter for @code cvs commit @endcode
* @author Robert Gruber <rgruber@users.sourceforge.net>
*/
class CommitDialog : public QDialog, private Ui::CommitDialogBase
{
Q_OBJECT
public:
CommitDialog(QDialog *parent = 0);
virtual ~CommitDialog();
/**
* @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>
<ui version="4.0" >
<class>CvsGenericOutputViewBase</class>
<widget class="QWidget" name="CvsGenericOutputViewBase" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>112</height>
</rect>
</property>
<layout class="QVBoxLayout" >
<property name="spacing" >
<number>0</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<widget class="QTextEdit" name="textArea" >
<property name="frameShape" >
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWrapMode" >
<enum>QTextEdit::NoWrap</enum>
</property>
<property name="readOnly" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
<ui version="4.0" >
<class>CvsMainViewBase</class>
<widget class="QWidget" name="CvsMainViewBase" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<layout class="QGridLayout" >
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item row="0" column="0" >
<widget class="KTabWidget" name="tabwidget" />
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KTabWidget</class>
<extends>QTabWidget</extends>
<header>ktabwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
......@@ -22,8 +22,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#include "gitproxy.h"
#include <QFileInfo>
#include <QDir>
#include <QFileInfo>
......@@ -35,24 +33,25 @@
#include <kshell.h>
#include <KDebug>
#include "gitjob.h"
#include <dvcsjob.h>
#include <iplugin.h>
GitProxy::GitProxy(KDevelop::IPlugin* parent)
#include "gitexecutor.h"
GitExecutor::GitExecutor(KDevelop::IPlugin* parent)
: QObject(parent), vcsplugin(parent)
{
}
GitProxy::~GitProxy()
GitExecutor::~GitExecutor()
{
}
//TODO: write tests for this method!
//maybe func()const?
bool GitProxy::isValidDirectory(const KUrl & dirPath)
bool GitExecutor::isValidDirectory(const KUrl & dirPath)
{
GitJob* job = new GitJob(vcsplugin);
DVCSjob* job = new DVCSjob(vcsplugin);
if (job)
{
job->clear();
......@@ -74,27 +73,27 @@ bool GitProxy::isValidDirectory(const KUrl & dirPath)
return false;
}
bool GitProxy::prepareJob(GitJob* job, const QString& repository, enum RequestedOperation op)
bool GitExecutor::prepareJob(DVCSjob* job, const QString& repository, enum RequestedOperation op)
{
// Only do this check if it's a normal operation like diff, log ...
// For other operations like "git clone" isValidDirectory() would fail as the
// directory is not yet under git control
if (op == GitProxy::NormalOperation &&
if (op == GitExecutor::NormalOperation &&
!isValidDirectory(repository)) {
kDebug(9500) << repository << " is not a valid git repository";
return false;
}
// clear commands and args from a possible previous run
job->clear();
job->clear();
// setup the working directory for the new job
job->setDirectory(repository);
job->setDirectory(repository);
return true;
return true;
}
bool GitProxy::addFileList(GitJob* job, const QString& repository, const KUrl::List& urls)
bool GitExecutor::addFileList(DVCSjob* job, const QString& repository, const KUrl::List& urls)
{
QStringList args;
......@@ -111,7 +110,7 @@ bool GitProxy::addFileList(GitJob* job, const QString& repository, const KUrl::L
return true;
}
// QString GitProxy::convertVcsRevisionToString(const KDevelop::VcsRevision & rev)
// QString GitExecutor::convertVcsRevisionToString(const KDevelop::VcsRevision & rev)
// {
// QString str;
//
......@@ -138,10 +137,10 @@ bool GitProxy::addFileList(GitJob* job, const QString& repository, const KUrl::L
// return str;
// }
GitJob* GitProxy::init(const KUrl &directory)
DVCSjob* GitExecutor::init(const KUrl &directory)
{
GitJob* job = new GitJob(vcsplugin);
if (prepareJob(job, directory.toLocalFile(), GitProxy::Init) ) {
DVCSjob* job = new DVCSjob(vcsplugin);
if (prepareJob(job, directory.toLocalFile(), GitExecutor::Init) ) {
*job << "git-init";
return job;
}
......@@ -149,10 +148,10 @@ GitJob* GitProxy::init(const KUrl &directory)
return NULL;
}
GitJob* GitProxy::clone(const KUrl &repository, const KUrl directory)
DVCSjob* GitExecutor::clone(const KUrl &repository, const KUrl directory)
{
GitJob* job = new GitJob(vcsplugin);
if (prepareJob(job, directory.toLocalFile(), GitProxy::Init) ) {
DVCSjob* job = new DVCSjob(vcsplugin);
if (prepareJob(job, directory.toLocalFile(), GitExecutor::Init) ) {
*job << "git-clone";
*job << repository.path();
// addFileList(job, repository.path(), directory); //TODO it's temp, should work only with local repos
......@@ -162,9 +161,9 @@ GitJob* GitProxy::clone(const KUrl &repository, const KUrl directory)
return NULL;
}
GitJob* GitProxy::add(const QString& repository, const KUrl::List &files)
DVCSjob* GitExecutor::add(const QString& repository, const KUrl::List &files)
{
GitJob* job = new GitJob(vcsplugin);
DVCSjob* job = new DVCSjob(vcsplugin);
if (prepareJob(job, repository) ) {
*job << "git";
*job << "add";
......@@ -179,13 +178,15 @@ GitJob* GitProxy::add(const QString& repository, const KUrl::List &files)
//TODO: git doesn't like empty messages, but "KDevelop didn't provide any message, it may be a bug" looks ugly...
//If no files specified then commit already added files
GitJob* GitProxy::commit(const QString& repository,
DVCSjob* GitExecutor::commit(const QString& repository,
const QString &message, /*= "KDevelop didn't provide any message, it may be a bug"*/
const KUrl::List &files /*= QStringList("-a")*/)
const KUrl::List &args /*= QStringList("")*/)
{
GitJob* job = new GitJob(vcsplugin);
DVCSjob* job = new DVCSjob(vcsplugin);
if (prepareJob(job, repository) ) {
*job << "git-commit";
foreach(KUrl arg, args)
*job<<arg.path(); //TODO much better to use QStringlist, but IBasicVS...
*job << "-m";
*job << KShell::quoteArg( message );
return job;
......@@ -194,9 +195,9 @@ GitJob* GitProxy::commit(const QString& repository,
return NULL;
}
GitJob* GitProxy::remove(const QString& repository, const KUrl::List &files)
DVCSjob* GitExecutor::remove(const QString& repository, const KUrl::List &files)
{
GitJob* job = new GitJob(vcsplugin);
DVCSjob* job = new DVCSjob(vcsplugin);
if (prepareJob(job, repository) ) {
*job << "git-rm";
addFileList(job, repository, files);
......@@ -206,86 +207,9 @@ GitJob* GitProxy::remove(const QString& repository, const KUrl::List &files)
return NULL;
}
// //TODO: now just only "git log" or "git log file", no extensions
// GitJob* GitProxy::log(const KUrl& url, const KDevelop::VcsRevision& rev)
// {
// QFileInfo info(url.toLocalFile());
// if (!info.isFile())
// return false;
//
// GitJob* job = new GitJob(vcsplugin);
// if ( prepareJob(job, info.absolutePath()) ) {
// *job << "cvs";
// *job << "log";
//
// QString convRev = convertVcsRevisionToString(rev);
// if (!convRev.isEmpty()) {
// convRev.replace("-D", "-d");
// *job << convRev;
// }
//
// *job << KShell::quoteArg(info.fileName());
//
// return job;
// }
// if (job) delete job;
// return NULL;
// }
//
// GitJob* GitProxy::diff(const KUrl& url,
// const KDevelop::VcsRevision& revA,
// const KDevelop::VcsRevision& revB,
// const QString& diffOptions)
// {
// QFileInfo info(url.toLocalFile());
//
// GitJob* job = new GitJob(vcsplugin);
// if ( prepareJob(job, info.absolutePath()) ) {
// *job << "cvs";
// *job << "diff";
//
// if (!diffOptions.isEmpty())
// *job << diffOptions;
//
// QString rA = convertVcsRevisionToString(revA);
// if (!rA.isEmpty())
// *job << rA;
// QString rB = convertVcsRevisionToString(revB);
// if (!rB.isEmpty())
// *job << rB;
//
// *job << KShell::quoteArg(info.fileName());
//
// return job;
// }
// if (job) delete job;
// return NULL;
// }
//
// GitJob* GitProxy::annotate(const KUrl & url, const KDevelop::VcsRevision& rev)
// {
// QFileInfo info(url.toLocalFile());
//
// GitJob* job = new GitJob(vcsplugin);
// if ( prepareJob(job, info.absolutePath()) ) {
// *job << "cvs";
// *job << "annotate";
//
// QString revision = convertVcsRevisionToString(rev);
// if (!revision.isEmpty())
// *job << revision;
//
// *job << KShell::quoteArg(info.fileName());
//
// return job;
// }
// if (job) delete job;
// return NULL;
// }
GitJob* GitProxy::status(const QString & repository, const KUrl::List & files, bool recursive, bool taginfo)
DVCSjob* GitExecutor::status(const QString & repository, const KUrl::List & files, bool recursive, bool taginfo)
{
GitJob* job = new GitJob(vcsplugin);
DVCSjob* job = new DVCSjob(vcsplugin);
if (prepareJob(job, repository) ) {
*job << "git";
*job << "status";
......@@ -297,19 +221,31 @@ GitJob* GitProxy::status(const QString & repository, const KUrl::List & files, b
return NULL;
}
// GitJob* GitProxy::is_inside_work_tree(const QString& repository)
// DVCSjob* GitExecutor::is_inside_work_tree(const QString& repository)
// {
//
// return NULL;
// }
GitJob* GitProxy::empty_cmd() const
DVCSjob* GitExecutor::var(const QString & repository)
{
DVCSjob* job = new DVCSjob(vcsplugin);
if (prepareJob(job, repository) ) {
*job << "git-var";
*job << "-l";
return job;
}
if (job) delete job;
return NULL;
}
DVCSjob* GitExecutor::empty_cmd() const
{
///TODO: maybe just "" command?
GitJob* job = new GitJob(vcsplugin);
DVCSjob* job = new DVCSjob(vcsplugin);
*job << "echo";
*job << "-n";
return job;
}
#include "gitproxy.moc"
// #include "hgexetor.moc"
......@@ -22,16 +22,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef GIT_PROXY_H
#define GIT_PROXY_H
#ifndef GIT_EXECUTOR_H
#define GIT_EXECUTOR_H
#include <KUrl>
#include <KJob>
#include <QStringList>
#include <idvcsexecutor.h>
#include "vcsrevision.h"
class GitJob;
class DVCSjob;
namespace KDevelop
{
......@@ -40,13 +42,13 @@ namespace KDevelop
/**
* This proxy acts as a single point of entry for most of the common git commands.
* It is very easy to use, as the caller does not have to deal which the GitJob class directly.
* All the command line generation and job handling is done internally. The caller gets a GitJob
* It is very easy to use, as the caller does not have to deal which the DVCSjob class directly.
* All the command line generation and job handling is done internally. The caller gets a DVCSjob
* object returned from the proxy and can then call it's start() method.
*
* Here is and example of how to user the proxy:
* @code
* GitJob* job = proxy->editors( repo, urls );
* DVCSjob* job = proxy->editors( repo, urls );
* if ( job ) {
* connect(job, SIGNAL( result(KJob*) ),
* this, SIGNAL( jobFinished(KJob*) ));
......@@ -62,44 +64,38 @@ namespace KDevelop
* @author Robert Gruber <rgruber@users.sourceforge.net>
* @author Evgeniy Ivanov <powerfox@kde.ru>
*/
class GitProxy : public QObject
class GitExecutor : public QObject, public KDevelop::IDVCSexecutor
{
Q_OBJECT
public:
GitProxy(KDevelop::IPlugin* parent = 0);
~GitProxy();
GitExecutor(KDevelop::IPlugin* parent = 0);
~GitExecutor();
bool isValidDirectory(const KUrl &dirPath);
GitJob* init(const KUrl & directory);
GitJob* clone(const KUrl &directory, const KUrl repository);
GitJob* add(const QString& repository, const KUrl::List &files);
GitJob* commit(const QString& repository,
DVCSjob* init(const KUrl & directory);
DVCSjob* clone(const KUrl &directory, const KUrl repository);
DVCSjob* add(const QString& repository, const KUrl::List &files);
DVCSjob* commit(const QString& repository,
const QString& message = "KDevelop didn't provide any message, it may be a bug",
const KUrl::List& files = QStringList("-a"));
GitJob* remove(const QString& repository, const KUrl::List& files);
GitJob* status(const QString & repo, const KUrl::List & files,
const KUrl::List& args = QStringList());
DVCSjob* remove(const QString& repository, const KUrl::List& files);
DVCSjob* status(const QString & repo, const KUrl::List & files,
bool recursive=false, bool taginfo=false);
/* GitJob* is_inside_work_tree(const QString& repository);*/
GitJob* empty_cmd() const;