Commit a59992c9 authored by Andreas Pakulat's avatar Andreas Pakulat
Browse files

Re-Add mercurial plugin, written from scratch by Fabian Wiesel, thanks.

Also includes some refactoring on how dvcs plugins work, idvcsexecutor is
gone now.
CCMAIL:fabian.wiesel@fu-berlin.de
parent a802762b
......@@ -5,7 +5,6 @@ add_subdirectory(tests)
set(kdevgit_PART_SRCS
gitplugin.cpp
gitexecutor.cpp
)
kde4_add_plugin(kdevgit ${kdevgit_PART_SRCS})
......@@ -16,6 +15,7 @@ target_link_libraries(kdevgit
kdevplatformutil
kdevplatforminterfaces
kdevplatformvcs
kdevplatformshell
kdevplatformproject
)
......
This diff is collapsed.
/***************************************************************************
* This file was partly taken from KDevelop's cvs plugin *
* Copyright 2007 Robert Gruber <rgruber@users.sourceforge.net> *
* *
* Adapted for Git *
* Copyright 2008 Evgeniy Ivanov <powerfox@kde.ru> *
* *
* 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 GIT_EXECUTOR_H
#define GIT_EXECUTOR_H
#include <KUrl>
#include <KJob>
#include <QStringList>
#include <vcs/dvcs/idvcsexecutor.h>
#include <vcs/vcsrevision.h>
class DVCSjob;
namespace KDevelop
{
class IPlugin;
class VcsStatusInfo;
}
/**
* 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 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
* DVCSjob* job = proxy->editors( repo, urls );
* if ( job ) {
* connect(job, SIGNAL( result(KJob*) ),
* this, SIGNAL( jobFinished(KJob*) ));
* job->start();
* }
* @endcode
*
* @note All actions that take a KUrl::List also need an url to the repository which
* must be a common base directory to all files from the KUrl::List.
* Actions that just take a single KUrl don't need a repository, the git command will be
* called directly in the directory of the given file
*
* @author Robert Gruber <rgruber@users.sourceforge.net>
* @author Evgeniy Ivanov <powerfox@kde.ru>
*/
class GitExecutor : public QObject, public KDevelop::IDVCSexecutor
{
Q_OBJECT
public:
explicit GitExecutor(KDevelop::IPlugin* parent = 0);
~GitExecutor();
bool isValidDirectory(const KUrl &dirPath);
bool isInRepo(const KUrl &path);
QString name() const;
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 did not provide any message, it may be a bug",
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);
DVCSjob* log(const KUrl& url);
DVCSjob* var(const QString &directory);
DVCSjob* empty_cmd() const;
DVCSjob* checkout(const QString &repository, const QString &branch);
DVCSjob* branch(const QString &repository, const QString &basebranch = QString(), const QString &branch = QString(),
const QStringList &args = QStringList());
DVCSjob* reset(const QString &repository, const QStringList &args, const KUrl::List &files);
DVCSjob* lsFiles(const QString &repository, const QStringList &args);
DVCSjob* gitRevParse(const QString &repository, const QStringList &args);
DVCSjob* gitRevList(const QString &repository, const QStringList &args);
public:
//parsers for branch:
QString curBranch(const QString &repository);
QStringList branches(const QString &repository);
//commit dialog helpers, send to main helper the arg for git-ls-files:
QList<QVariant> getModifiedFiles(const QString &directory);
QList<QVariant> getCachedFiles(const QString &directory);
QList<QVariant> getOtherFiles(const QString &directory);
//graph helpers
QList<DVCScommit> getAllCommits(const QString &repo);
//used in log
void parseOutput(const QString& jobOutput, QList<DVCScommit>& commits) const;
private slots:
void status_slot(DVCSjob *statusJob);
private:
//commit dialog "main" helper
QStringList getLsFiles(const QString &directory, const QStringList &args = QStringList());
void initBranchHash(const QString &repo);
KDevelop::VcsStatusInfo::State charToState(const char ch);
QList<QStringList> branchesShas;
KDevelop::IPlugin* vcsplugin;
};
#endif
This diff is collapsed.
......@@ -23,7 +23,9 @@
#include <vcs/interfaces/idistributedversioncontrol.h>
#include <vcs/dvcs/dvcsplugin.h>
#include <qobject.h>
#include <QObject>
#include <vcs/vcsstatusinfo.h>
namespace KDevelop
{
......@@ -31,8 +33,6 @@ namespace KDevelop
class VcsRevision;
}
class GitExecutor;
/**
* This is the main class of KDevelop's Git plugin.
*
......@@ -43,20 +43,86 @@ class GitPlugin: public KDevelop::DistributedVersionControlPlugin
{
Q_OBJECT
Q_INTERFACES(KDevelop::IBasicVersionControl KDevelop::IDistributedVersionControl)
friend class GitExecutor;
friend class GitInitTest;
public:
GitPlugin(QObject *parent, const QVariantList & args = QVariantList() );
~GitPlugin();
//TODO:Things to be moved to DVCSplugin, but not moved because require executor changes in all implemented DVCS
QString name() const;
bool isVersionControlled(const KUrl &path);
KDevelop::VcsJob* add(const KUrl::List& localLocations,
KDevelop::IBasicVersionControl::RecursionMode recursion = KDevelop::IBasicVersionControl::Recursive);
KDevelop::VcsJob* remove(const KUrl::List& files);
KDevelop::VcsJob* status(const KUrl::List& localLocations,
KDevelop::IBasicVersionControl::RecursionMode recursion = KDevelop::IBasicVersionControl::Recursive);
KDevelop::VcsJob* commit(const QString& message,
const KUrl::List& localLocations,
KDevelop::IBasicVersionControl::RecursionMode recursion = KDevelop::IBasicVersionControl::Recursive);
KDevelop::VcsJob* log(const KUrl& localLocation,
const KDevelop::VcsRevision& rev,
unsigned long limit);
KDevelop::VcsJob* log(const KUrl& localLocation,
const KDevelop::VcsRevision& rev,
const KDevelop::VcsRevision& limit);
// Begin: KDevelop::IDistributedVersionControl
KDevelop::VcsJob* init(const KUrl & directory);
KDevelop::VcsJob* clone(const KDevelop::VcsLocation & localOrRepoLocationSrc,
const KUrl& localRepositoryRoot);
KDevelop::VcsJob* reset(const KUrl& repository,
const QStringList &args,
const KUrl::List& files);
// End: KDevelop::IDistributedVersionControl
DVcsJob* var(const QString &directory);
// Branch management
DVcsJob* switchBranch(const QString &repository,
const QString &branch);
DVcsJob* branch(const QString &repository,
const QString &basebranch = QString(),
const QString &branch = QString(),
const QStringList &args = QStringList());
QString curBranch(const QString &repository);
QStringList branches(const QString &repository);
//commit dialog helpers, send to main helper the arg for git-ls-files:
QList<QVariant> getModifiedFiles(const QString &directory);
QList<QVariant> getCachedFiles(const QString &directory);
QList<QVariant> getOtherFiles(const QString &directory);
//graph helpers
QList<DVcsEvent> getAllCommits(const QString &repo);
//used in log
void parseLogOutput(const DVcsJob * job,
QList<DVcsEvent>& commits) const;
protected:
bool isValidDirectory(const KUrl &dirPath);
DVcsJob* lsFiles(const QString &repository,
const QStringList &args);
DVcsJob* gitRevList(const QString &repository,
const QStringList &args);
DVcsJob* gitRevParse(const QString &repository,
const QStringList &args);
private:
//commit dialog "main" helper
QStringList getLsFiles(const QString &directory, const QStringList &args = QStringList());
void initBranchHash(const QString &repo);
static KDevelop::VcsStatusInfo::State charToState(const char ch);
static KDevelop::VcsStatusInfo::State lsTagToState(const char ch);
QList<QStringList> branchesShas;
};
#endif
......@@ -18,13 +18,14 @@ FIND_PROGRAM(GIT NAMES git
if (GIT)
set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
set(gitInitTest_SRCS initTest.cpp ../gitexecutor.cpp)
set(gitInitTest_SRCS initTest.cpp ../gitplugin.cpp)
kde4_add_unit_test(kdevgit-test ${gitInitTest_SRCS})
target_link_libraries(kdevgit-test
${QT_QTTEST_LIBRARY}
${KDE4_KDECORE_LIBS}
kdevplatformutil
kdevplatformvcs
kdevplatformtestshell
)
endif (GIT)
......
......@@ -26,18 +26,17 @@
#include <qtest_kde.h>
#include <QtTest/QtTest>
#include <shell/testcore.h>
#include <tests/common/autotestshell.h>
#include <KUrl>
#include <KDebug>
#include <kio/netaccess.h>
#include <vcs/dvcs/dvcsjob.h>
#include "../gitexecutor.h"
#include "../gitplugin.h"
const QString tempDir = QDir::tempPath();
const QString GitTestDir1("kdevGit_testdir");
const QString gitTest_BaseDir(tempDir + "/kdevGit_testdir/");
const QString gitTest_BaseDirNoTrSlash(tempDir + "/kdevGit_testdir");
const QString gitTest_BaseDir2(tempDir + "/kdevGit_testdir2/");
const QString gitRepo(gitTest_BaseDir + ".git");
const QString gitSrcDir(gitTest_BaseDir + "src/");
......@@ -45,10 +44,14 @@ const QString gitTest_FileName("testfile");
const QString gitTest_FileName2("foo");
const QString gitTest_FileName3("bar");
using namespace KDevelop;
void GitInitTest::initTestCase()
{
m_proxy = new GitExecutor;
AutoTestShell::init();
m_testCore = new KDevelop::TestCore();
m_testCore->initialize(KDevelop::Core::NoUi);
m_plugin = new GitPlugin(m_testCore);
removeTempDirs();
// Now create the basic directory structure
......@@ -60,39 +63,42 @@ void GitInitTest::initTestCase()
void GitInitTest::cleanupTestCase()
{
delete m_proxy;
if ( QFileInfo(gitTest_BaseDir).exists() )
KIO::NetAccess::del(KUrl(gitTest_BaseDir), 0);
if ( QFileInfo(gitTest_BaseDir2).exists() )
KIO::NetAccess::del(KUrl(gitTest_BaseDir2), 0);
delete m_plugin;
m_testCore->cleanup();
delete m_testCore;
if (QFileInfo(gitTest_BaseDir).exists())
KIO::NetAccess::del(KUrl(gitTest_BaseDir), 0);
if (QFileInfo(gitTest_BaseDir2).exists())
KIO::NetAccess::del(KUrl(gitTest_BaseDir2), 0);
}
void GitInitTest::repoInit()
{
kDebug() << "Trying to init repo";
// make job that creates the local repository
DVCSjob* j = m_proxy->init(KUrl(gitTest_BaseDir));
QVERIFY( j );
VcsJob* j = m_plugin->init(KUrl(gitTest_BaseDir));
QVERIFY(j);
// try to start the job
QVERIFY( j->exec() );
QVERIFY(j->exec());
QVERIFY(j->status() == KDevelop::VcsJob::JobSucceeded);
//check if the CVSROOT directory in the new local repository exists now
QVERIFY( QFileInfo(gitRepo).exists() );
QVERIFY(QFileInfo(gitRepo).exists());
//check if isValidDirectory works
QVERIFY(m_proxy->isValidDirectory(KUrl(gitTest_BaseDir)));
QVERIFY(m_plugin->isValidDirectory(KUrl(gitTest_BaseDir)));
//and for non-git dir, I hope nobody has /tmp under git
QVERIFY(!m_proxy->isValidDirectory(KUrl("/tmp")));
QVERIFY(!m_plugin->isValidDirectory(KUrl("/tmp")));
//we have nothing, so ouput should be empty
j = m_proxy->gitRevParse(gitRepo, QStringList(QString("--branches")));
QVERIFY(j->exec());
QString out = j->output();
QVERIFY(j->output().isEmpty());
DVcsJob * j2 = m_plugin->gitRevParse(gitRepo, QStringList(QString("--branches")));
QVERIFY(j2);
QVERIFY(j2->exec());
QString out = j2->output();
QVERIFY(j2->output().isEmpty());
}
void GitInitTest::addFiles()
......@@ -101,131 +107,134 @@ void GitInitTest::addFiles()
//we start it after repoInit, so we still have empty git repo
QFile f(gitTest_BaseDir + gitTest_FileName);
if(f.open(QIODevice::WriteOnly)) {
QTextStream input( &f );
if (f.open(QIODevice::WriteOnly)) {
QTextStream input(&f);
input << "HELLO WORLD";
}
f.flush();
f.close();
f.setFileName(gitTest_BaseDir + gitTest_FileName2);
if(f.open(QIODevice::WriteOnly)) {
QTextStream input( &f );
if (f.open(QIODevice::WriteOnly)) {
QTextStream input(&f);
input << "No, bar()!";
}
f.flush();
f.close();
//test git-status exitCode (see DVCSjob::setExitCode). It will be 1, but job should be marked as Succeeded
DVCSjob* j = m_proxy->status(gitTest_BaseDir, KUrl::List(), 0, 0);
QVERIFY( j );
QVERIFY(!j->exec() );
QVERIFY(j->status() == KDevelop::VcsJob::JobSucceeded);
f.close();
// /tmp/kdevGit_testdir/ and kdevGit_testdir
//add always should use relative path to the any directory of the repository, let's check:
j = m_proxy->add(gitTest_BaseDir, KUrl::List(QStringList(GitTestDir1)));
QVERIFY( j );
QVERIFY(j->exec() );
//test git-status exitCode (see DVcsJob::setExitCode).
VcsJob* j = m_plugin->status(KUrl::List(gitTest_BaseDir));
QVERIFY(j);
QVERIFY(j->exec());
QVERIFY(j->status() == KDevelop::VcsJob::JobSucceeded);
// /tmp/kdevGit_testdir/ and testfile
j = m_proxy->add(gitTest_BaseDir, KUrl::List(QStringList(gitTest_FileName)));
QVERIFY( j );
QVERIFY(j->exec() );
QVERIFY(j->status() == KDevelop::VcsJob::JobSucceeded);
//repository path without trailing slash
j = m_proxy->add(gitTest_BaseDirNoTrSlash, KUrl::List(QStringList(gitTest_FileName)));
QVERIFY( j );
QVERIFY(j->exec() );
j = m_plugin->add(KUrl::List(gitTest_BaseDir + gitTest_FileName));
QVERIFY(j);
QVERIFY(j->exec());
QVERIFY(j->status() == KDevelop::VcsJob::JobSucceeded);
f.setFileName(gitSrcDir + gitTest_FileName3);
if(f.open(QIODevice::WriteOnly)) {
QTextStream input( &f );
if (f.open(QIODevice::WriteOnly)) {
QTextStream input(&f);
input << "No, foo()! It's bar()!";
}
f.flush();
f.close();
//test git-status exitCode again
j = m_proxy->status(gitTest_BaseDir, KUrl::List(), 0, 0);
QVERIFY( j );
QVERIFY(j->exec() );
j = m_plugin->status(KUrl::List(gitTest_BaseDir));
QVERIFY(j);
QVERIFY(j->exec());
QVERIFY(j->status() == KDevelop::VcsJob::JobSucceeded);
//repository path without trailing slash and a file in a parent directory
// /tmp/repo and /tmp/repo/src/bar
j = m_proxy->add(gitTest_BaseDirNoTrSlash, KUrl::List(QStringList(gitSrcDir + gitTest_FileName3)));
QVERIFY( j );
QVERIFY(j->exec() );
j = m_plugin->add(KUrl::List(QStringList(gitSrcDir + gitTest_FileName3)));
QVERIFY(j);
QVERIFY(j->exec());
QVERIFY(j->status() == KDevelop::VcsJob::JobSucceeded);
//let's use absolute path, because it's used in ContextMenus
j = m_proxy->add(gitTest_BaseDir, KUrl::List(QStringList(gitTest_BaseDir + gitTest_FileName2)));
j = m_plugin->add(KUrl::List(QStringList(gitTest_BaseDir + gitTest_FileName2)));
QVERIFY(j);
QVERIFY(j->exec() );
QVERIFY(j->exec());
QVERIFY(j->status() == KDevelop::VcsJob::JobSucceeded);
//Now let's create several files and try "git add file1 file2 file3"
f.setFileName(gitTest_BaseDir + "file1");
if(f.open(QIODevice::WriteOnly)) {
QTextStream input( &f );
if (f.open(QIODevice::WriteOnly)) {
QTextStream input(&f);
input << "file1";
}
f.flush();
f.close();
f.setFileName(gitTest_BaseDir + "file2");
if(f.open(QIODevice::WriteOnly)) {
QTextStream input( &f );
if (f.open(QIODevice::WriteOnly)) {
QTextStream input(&f);
input << "file2";
}
f.flush();
f.close();
QStringList multipleFiles;
multipleFiles<<"file1";
multipleFiles<<"file2";
j = m_proxy->add(gitTest_BaseDir, KUrl::List(multipleFiles));
multipleFiles << (gitTest_BaseDir + "file1");
multipleFiles << (gitTest_BaseDir + "file2");
j = m_plugin->add(KUrl::List(multipleFiles));
QVERIFY(j);
QVERIFY(j->exec() );
QVERIFY(j->exec());
QVERIFY(j->status() == KDevelop::VcsJob::JobSucceeded);
}
void GitInitTest::commitFiles()
{
kDebug() << "\nListing variables with KProcess\n";
DVCSjob* j_var = m_proxy->var(gitTest_BaseDir);
QVERIFY(j_var->exec() );
DVcsJob* j_var = m_plugin->var(gitTest_BaseDir);
QVERIFY(j_var->exec());
QVERIFY(j_var->status() == KDevelop::VcsJob::JobSucceeded);
kDebug() << "Committing...";
//we start it after addFiles, so we just have to commit
///TODO: if "" is ok?
DVCSjob* j = m_proxy->commit(gitTest_BaseDir, QString("Test commit"));
QVERIFY( j );
VcsJob* j = m_plugin->commit(QString("Test commit"), KUrl::List(gitTest_BaseDir));
QVERIFY(j);
// try to start the job
QVERIFY( j->exec() );
QVERIFY(j->exec());
QVERIFY(j->status() == KDevelop::VcsJob::JobSucceeded);
//test git-status exitCode one more time.
j = m_proxy->status(gitTest_BaseDir, KUrl::List(), 0, 0);
QVERIFY( j );
QVERIFY(!j->exec() );
j = m_plugin->status(KUrl::List(gitTest_BaseDir));
QVERIFY(j);
QVERIFY(j->exec());
QVERIFY(j->status() == KDevelop::VcsJob::JobSucceeded);
//since we commited the file to the "pure" repository, .git/refs/heads/master should exist
//TODO: maybe other method should be used
QString headRefName(gitRepo + "/refs/heads/master");
QVERIFY( QFileInfo(headRefName).exists() );
QVERIFY(QFileInfo(headRefName).exists());
//Test the results of the "git add"
DVCSjob* jobLs = new DVCSjob(0);
DVcsJob* jobLs = new DVcsJob(0);
jobLs->clear();
jobLs->setDirectory(gitTest_BaseDir);
*jobLs<<"git"<<"ls-tree"<<"--name-only"<<"-r"<<"HEAD";
*jobLs << "git" << "ls-tree" << "--name-only" << "-r" << "HEAD";
if (jobLs) {
QVERIFY(jobLs->exec() );
QVERIFY(jobLs->exec());
QVERIFY(jobLs->status() == KDevelop::VcsJob::JobSucceeded);
QStringList files = jobLs->output().split("\n");
......@@ -235,49 +244,58 @@ void GitInitTest::commitFiles()
}
QString firstCommit;
QFile headRef(headRefName);
if(headRef.open(QIODevice::ReadOnly)) {
QTextStream output( &headRef );
output>>firstCommit;
if (headRef.open(QIODevice::ReadOnly)) {
QTextStream output(&headRef);
output >> firstCommit;
}
headRef.flush();
headRef.close();
QVERIFY(firstCommit!="");
QVERIFY(firstCommit != "");
kDebug() << "Committing one more time";
//let's try to change the file and test "git commit -a"
QFile f(gitTest_BaseDir + gitTest_FileName);
if(f.open(QIODevice::WriteOnly)) {
QTextStream input( &f );
if (f.open(QIODevice::WriteOnly)) {
QTextStream input(&f);
input << "Just another HELLO WORLD";
}
f.flush();
//add changes
j = m_proxy->add(gitTest_BaseDir, KUrl::List(QStringList(gitTest_FileName)));
QVERIFY( j );
j = m_plugin->add(KUrl::List(QStringList(gitTest_BaseDir + gitTest_FileName)));
QVERIFY(j);
// try to start the job
QVERIFY( j->exec() );
QVERIFY(j->exec());
QVERIFY(j->status() == KDevelop::VcsJob::JobSucceeded);
j = m_proxy->commit(gitTest_BaseDir, QString("KDevelop's Test commit2"));
QVERIFY( j );
j = m_plugin->commit(QString("KDevelop's Test commit2"), KUrl::List(gitTest_BaseDir));
QVERIFY(j);
// try to start the job
QVERIFY( j->exec() );
QVERIFY(j->exec());
QVERIFY(j->status() == KDevelop::VcsJob::JobSucceeded);