Commit 9c065532 authored by Christian Loose's avatar Christian Loose

* moved some reponsibilities from CvsService to Repository

   (setWorkingCopy(), KDirWatch for cvsservicerc, etc...)
* removed a lot of code duplication in CvsService's methods
* added new add() and commit() method to CvsService
   TODO: need documentation!
* Methods with a file list parameter now take QStringList instead of
   QString. So the caller doesn't have to worry about proper quoting.

svn path=/trunk/kdesdk/cervisia/; revision=199939
parent 84177c18
/*
* Copyright (c) 2002 Christian Loose <christian.loose@hamburg.de>
* Copyright (c) 2002-2003 Christian Loose <christian.loose@hamburg.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
......@@ -20,40 +20,48 @@
#include "cvsservice.h"
#include <qdir.h>
#include <qintdict.h>
#include <qstring.h>
#include <dcopref.h>
#include <dcopclient.h>
#include <kapplication.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kdirwatch.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kprocess.h>
#include <kstandarddirs.h>
#include "cvsjob.h"
#include "cvsserviceutils.h"
#include "repository.h"
static const char* SINGLE_JOB_ID = "NonConcurrentJob";
static const char* SINGLE_JOB_ID = "NonConcurrentJob";
static const char* REDIRECT_STDERR = "2>&1";
struct CvsService::Private
{
Private() : singleCvsJob(0), lastJobId(0), repository(0) {}
~Private()
{
delete repository;
delete singleCvsJob;
}
CvsJob* singleCvsJob; // non-concurrent cvs job, like update or commit
DCOPRef singleJobRef; // DCOP reference to non-concurrent cvs job
QIntDict<CvsJob> cvsJobs; // concurrent cvs jobs, like diff or annotate
unsigned lastJobId;
QCString appId; // cache the DCOP clients app id
QString configFile; // name of config file (including path)
QString workingCopy;
Repository* repository;
CvsJob* createCvsJob();
DCOPRef setupNonConcurrentJob();
bool hasWorkingCopy();
bool hasRunningJob();
};
......@@ -61,85 +69,56 @@ CvsService::CvsService()
: DCOPObject("CvsService")
, d(new Private)
{
// initialize private data
d->lastJobId = 0;
d->repository = 0;
d->appId = kapp->dcopClient()->appId();
// create non-concurrent cvs job
d->singleCvsJob = new CvsJob(SINGLE_JOB_ID);
d->singleJobRef.setRef(d->appId, d->singleCvsJob->objId());
// create repository manager
d->repository = new Repository();
d->cvsJobs.setAutoDelete(true);
// other cvsservice instances might change the configuration file
// so we watch it for changes
d->configFile = locate("config", "cvsservicerc");
kdDebug() << d->configFile << endl;
KDirWatch* fileWatcher = new KDirWatch(this);
connect(fileWatcher, SIGNAL(dirty(const QString&)),
this, SLOT(slotConfigDirty(const QString&)));
fileWatcher->addFile(d->configFile);
}
CvsService::~CvsService()
{
d->cvsJobs.clear();
delete d->singleCvsJob;
delete d->repository;
delete d;
}
bool CvsService::setWorkingCopy(const QString& dirName)
DCOPRef CvsService::add(const QStringList& files, bool isBinary)
{
const QFileInfo fi(dirName);
QString path = fi.absFilePath();
if( !d->hasWorkingCopy() || d->hasRunningJob() )
return DCOPRef();
// assemble the command line
// cvs add [-kb] [FILES]
d->singleCvsJob->clearCvsCommand();
// is this really a cvs-controlled directory?
const QFileInfo cvsDirInfo(path + "/CVS");
if( !cvsDirInfo.exists() || !cvsDirInfo.isDir() )
return false;
// delete old data
delete d->repository;
d->repository = 0;
d->workingCopy = path;
d->repository = new Repository(path);
*d->singleCvsJob << d->repository->cvsClient() << "add";
QDir::setCurrent(path);
if( isBinary )
*d->singleCvsJob << "-kb";
return true;
}
QString CvsService::workingCopy() const
{
return d->workingCopy;
}
QString CvsService::repository() const
{
if( d->repository )
return d->repository->location();
else
return QString::null;
*d->singleCvsJob << CvsServiceUtils::joinFileList(files) << REDIRECT_STDERR;
return d->setupNonConcurrentJob();
}
DCOPRef CvsService::annotate(const QString& fileName, const QString& revision)
{
if( !d->repository )
{
KMessageBox::sorry(0, i18n("You have to set a local working copy "
"directory before you can use this function!"));
if( !d->hasWorkingCopy() )
return DCOPRef();
}
// create a cvs job
CvsJob* job = d->createCvsJob();
// Assemble the command line
// assemble the command line
// (cvs log [FILE] && cvs annotate [-r rev] [FILE])
QString quotedName = KProcess::quote(fileName);
QString cvsClient = d->repository->cvsClient();
......@@ -152,26 +131,72 @@ DCOPRef CvsService::annotate(const QString& fileName, const QString& revision)
// *Hack*
// because the string "Annotations for blabla" is
// printed to stderr even with option -Q.
*job << quotedName << ") 2>&1";
*job << quotedName << ")" << REDIRECT_STDERR;
// return a DCOP reference to the cvs job
return DCOPRef(d->appId, job->objId());
}
DCOPRef CvsService::checkout(const QString& workingDir, const QString& repository,
const QString& module, const QString& tag, bool pruneDirs)
{
if( !d->hasWorkingCopy() || d->hasRunningJob() )
return DCOPRef();
// assemble the command line
// cd [DIRECTORY] && cvs -d [REPOSITORY] checkout [-r tag] [-P] [MODULE]
d->singleCvsJob->clearCvsCommand();
*d->singleCvsJob << "cd" << workingDir << "&&"
<< d->repository->cvsClient()
<< "-d" << repository
<< "checkout";
if( !tag.isEmpty() )
*d->singleCvsJob << "-r" << tag;
if( pruneDirs )
*d->singleCvsJob << "-P";
*d->singleCvsJob << module;
return d->setupNonConcurrentJob();
}
DCOPRef CvsService::commit(const QStringList& files, const QString& commitMessage,
bool recursive)
{
if( !d->hasWorkingCopy() || d->hasRunningJob() )
return DCOPRef();
// assemble the command line
// cvs commit [-l] [-m MESSAGE] [FILES]
d->singleCvsJob->clearCvsCommand();
*d->singleCvsJob << d->repository->cvsClient() << "commit";
if( !recursive )
*d->singleCvsJob << "-l";
*d->singleCvsJob << "-m" << KProcess::quote(commitMessage)
<< CvsServiceUtils::joinFileList(files) << REDIRECT_STDERR;
return d->setupNonConcurrentJob();
}
DCOPRef CvsService::log(const QString& fileName)
{
if( !d->repository )
{
KMessageBox::sorry(0, i18n("You have to set a local working copy "
"directory before you can use this function!"));
if( !d->hasWorkingCopy() )
return DCOPRef();
}
// create a cvs job
CvsJob* job = d->createCvsJob();
// Assemble the command line
// assemble the command line
// cvs log [FILE]
*job << d->repository->cvsClient() << "log" << KProcess::quote(fileName);
// return a DCOP reference to the cvs job
......@@ -179,22 +204,13 @@ DCOPRef CvsService::log(const QString& fileName)
}
DCOPRef CvsService::status(const QString& files, bool recursive)
DCOPRef CvsService::status(const QStringList& files, bool recursive)
{
if( !d->repository )
{
KMessageBox::sorry(0, i18n("You have to set a local working copy "
"directory before you can use this function!"));
if( !d->hasWorkingCopy() || d->hasRunningJob() )
return DCOPRef();
}
if( d->singleCvsJob->isRunning() )
{
KMessageBox::sorry(0, i18n("There is already a job running"));
return DCOPRef();
}
// Assemble the command line
// assemble the command line
// cvs -n update [-l] [FILES]
d->singleCvsJob->clearCvsCommand();
*d->singleCvsJob << d->repository->cvsClient() << "-n update";
......@@ -202,29 +218,22 @@ DCOPRef CvsService::status(const QString& files, bool recursive)
if( !recursive )
*d->singleCvsJob << "-l";
*d->singleCvsJob << files << "2>&1";
d->singleCvsJob->setRSH(d->repository->rsh());
d->singleCvsJob->setServer(d->repository->server());
d->singleCvsJob->setDirectory(d->workingCopy);
*d->singleCvsJob << CvsServiceUtils::joinFileList(files) << REDIRECT_STDERR;
return DCOPRef(d->appId, d->singleCvsJob->objId());
return d->setupNonConcurrentJob();
}
DCOPRef CvsService::status(const QString& files, bool recursive, bool tagInfo)
DCOPRef CvsService::status(const QStringList& files, bool recursive, bool tagInfo)
{
if( !d->repository )
{
KMessageBox::sorry(0, i18n("You have to set a local working copy "
"directory before you can use this function!"));
if( !d->hasWorkingCopy() )
return DCOPRef();
}
// create a cvs job
CvsJob* job = d->createCvsJob();
// Assemble the command line
// assemble the command line
// cvs status [-l] [-v] [FILES]
*job << d->repository->cvsClient() << "status";
if( !recursive )
......@@ -233,30 +242,21 @@ DCOPRef CvsService::status(const QString& files, bool recursive, bool tagInfo)
if( tagInfo )
*job << "-v";
*job << files;
*job << CvsServiceUtils::joinFileList(files);
// return a DCOP reference to the cvs job
return DCOPRef(d->appId, job->objId());
}
DCOPRef CvsService::update(const QString& files, bool recursive,
DCOPRef CvsService::update(const QStringList& files, bool recursive,
bool createDirs, bool pruneDirs, const QString& extraOpt)
{
if( !d->repository )
{
KMessageBox::sorry(0, i18n("You have to set a local working copy "
"directory before you can use this function!"));
if( !d->hasWorkingCopy() || d->hasRunningJob() )
return DCOPRef();
}
if( d->singleCvsJob->isRunning() )
{
KMessageBox::sorry(0, i18n("There is already a job running"));
return DCOPRef();
}
// Assemble the command line
// assemble the command line
// cvs update [-l] [-d] [-P] [EXTRAOPTIONS] [FILES]
d->singleCvsJob->clearCvsCommand();
*d->singleCvsJob << d->repository->cvsClient() << "update";
......@@ -270,86 +270,64 @@ DCOPRef CvsService::update(const QString& files, bool recursive,
if( pruneDirs )
*d->singleCvsJob << "-P";
*d->singleCvsJob << extraOpt << files << "2>&1";
d->singleCvsJob->setRSH(d->repository->rsh());
d->singleCvsJob->setServer(d->repository->server());
d->singleCvsJob->setDirectory(d->workingCopy);
*d->singleCvsJob << extraOpt << CvsServiceUtils::joinFileList(files)
<< REDIRECT_STDERR;
return DCOPRef(d->appId, d->singleCvsJob->objId());
return d->setupNonConcurrentJob();
}
DCOPRef CvsService::checkout(const QString& workingDir, const QString& repository,
const QString& module, const QString& tag, bool pruneDirs)
void CvsService::quit()
{
if( !d->repository )
{
KMessageBox::sorry(0, i18n("You have to set a local working copy "
"directory before you can use this function!"));
return DCOPRef();
}
kapp->quit();
}
if( d->singleCvsJob->isRunning() )
{
KMessageBox::sorry(0, i18n("There is already a job running"));
return DCOPRef();
}
// Assemble the command line
d->singleCvsJob->clearCvsCommand();
*d->singleCvsJob << "cd" << workingDir << "&&"
<< d->repository->cvsClient()
<< "-d" << repository
<< "checkout";
if( !tag.isEmpty() )
*d->singleCvsJob << "-r" << tag;
if( pruneDirs )
*d->singleCvsJob << "-P";
CvsJob* CvsService::Private::createCvsJob()
{
++lastJobId;
*d->singleCvsJob << module;
// create a cvs job
CvsJob* job = new CvsJob(lastJobId);
cvsJobs.insert(lastJobId, job);
d->singleCvsJob->setRSH(d->repository->rsh());
d->singleCvsJob->setServer(d->repository->server());
d->singleCvsJob->setDirectory(d->workingCopy);
job->setRSH(repository->rsh());
job->setServer(repository->server());
job->setDirectory(repository->workingCopy());
return DCOPRef(d->appId, d->singleCvsJob->objId());
return job;
}
void CvsService::quit()
DCOPRef CvsService::Private::setupNonConcurrentJob()
{
kapp->quit();
singleCvsJob->setRSH(repository->rsh());
singleCvsJob->setServer(repository->server());
singleCvsJob->setDirectory(repository->workingCopy());
return singleJobRef;
}
void CvsService::slotConfigDirty(const QString& fileName)
bool CvsService::Private::hasWorkingCopy()
{
if( d->repository && fileName == d->configFile )
if( repository->workingCopy().isEmpty() )
{
// reread the configuration data from disk
kapp->config()->reparseConfiguration();
d->repository->updateConfig();
KMessageBox::sorry(0, i18n("You have to set a local working copy "
"directory before you can use this function!"));
return false;
}
return true;
}
CvsJob* CvsService::Private::createCvsJob()
bool CvsService::Private::hasRunningJob()
{
++lastJobId;
// create a cvs job
CvsJob* job = new CvsJob(lastJobId);
cvsJobs.insert(lastJobId, job);
job->setRSH(repository->rsh());
job->setServer(repository->server());
job->setDirectory(workingCopy);
return job;
bool result = singleCvsJob->isRunning();
if( result )
KMessageBox::sorry(0, i18n("There is already a job running"));
return result;
}
#include "cvsservice.moc"
/*
* Copyright (c) 2002 Christian Loose <christian.loose@hamburg.de>
* Copyright (c) 2002-2003 Christian Loose <christian.loose@hamburg.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
......@@ -21,17 +21,16 @@
#ifndef CVSSERVICE_H
#define CVSSERVICE_H
#include <qobject.h>
#include <qstringlist.h>
#include <dcopref.h>
#include <dcopobject.h>
class QString;
class CvsService : public QObject, public DCOPObject
class CvsService : public DCOPObject
{
K_DCOP
Q_OBJECT
public:
CvsService();
......@@ -39,25 +38,8 @@ public:
k_dcop:
/**
* Changes the working copy and the corresponding cvs repository.
*
* @param dirName path to the local working copy directory.
*/
bool setWorkingCopy(const QString& dirName);
/**
* Path to the current working copy.
*
* @return The working copy directory. Can be null if not set.
*/
QString workingCopy() const;
/**
* Path to the current cvs repository.
*
* @return The cvs repository. Can be null if not set.
*/
QString repository() const;
DCOPRef add(const QStringList& files, bool isBinary);
/**
* Shows information on who last modified each line of a file and when.
......@@ -70,6 +52,26 @@ k_dcop:
*/
DCOPRef annotate(const QString& fileName, const QString& revision);
/**
* Checks out a module from the repository into a working copy.
*
* @param workingDir
* @param repository
* @param module
* @param tag
* @param pruneDirs remove empty directories from the working copy.
*
* @return A DCOP reference to the cvs job or in case of failure a
* null reference.
*/
DCOPRef checkout(const QString& workingDir, const QString& repository,
const QString& module, const QString& tag, bool pruneDirs);
/**
*/
DCOPRef commit(const QStringList& files, const QString& commitMessage,
bool recursive);
/**
* Shows log messages for a file.
*
......@@ -90,7 +92,7 @@ k_dcop:
* @return A DCOP reference to the cvs job or in case of failure a
* null reference.
*/
DCOPRef status(const QString& files, bool recursive);
DCOPRef status(const QStringList& files, bool recursive);
/**
* Shows the status of the files in the working copy.
......@@ -102,7 +104,7 @@ k_dcop:
* @return A DCOP reference to the cvs job or in case of failure a
* null reference.
*/
DCOPRef status(const QString& files, bool recursive, bool tagInfo);
DCOPRef status(const QStringList& files, bool recursive, bool tagInfo);
/**
* Merges changes from the repository into the files of the
......@@ -118,32 +120,14 @@ k_dcop:
* @return A DCOP reference to the cvs job or in case of failure a
* null reference.
*/
DCOPRef update(const QString& files, bool recursive, bool createDirs,
DCOPRef update(const QStringList& files, bool recursive, bool createDirs,
bool pruneDirs, const QString& extraOpt);
/**
* Checks out a module from the repository into a working copy.
*
* @param workingDir
* @param repository
* @param module
* @param tag
* @param pruneDirs remove empty directories from the working copy.
*
* @return A DCOP reference to the cvs job or in case of failure a
* null reference.
*/
DCOPRef checkout(const QString& workingDir, const QString& repository,
const QString& module, const QString& tag, bool pruneDirs);
/**
* Quits the DCOP service.
*/
void quit();
private slots:
void slotConfigDirty(const QString& fileName);
private:
struct Private;
Private* d;
......
/*
* Copyright (c) 2002 Christian Loose <christian.loose@hamburg.de>
* Copyright (c) 2002-2003 Christian Loose <christian.loose@hamburg.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
......@@ -20,60 +20,100 @@
#include "repository.h"
#include <qdir.h>
#include <qfile.h>
#include <qstring.h>
#include <kapplication.h>
#include <kconfig.h>
#include <kdirwatch.h>
#include <kstandarddirs.h>
struct Repository::Private
{
QString client;
QString location;
QString rsh;
QString server;