summaryrefslogtreecommitdiffstats
path: root/cervisia/cvsservice/cvsservice.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cervisia/cvsservice/cvsservice.cpp')
-rw-r--r--cervisia/cvsservice/cvsservice.cpp1008
1 files changed, 1008 insertions, 0 deletions
diff --git a/cervisia/cvsservice/cvsservice.cpp b/cervisia/cvsservice/cvsservice.cpp
new file mode 100644
index 00000000..a5f02e20
--- /dev/null
+++ b/cervisia/cvsservice/cvsservice.cpp
@@ -0,0 +1,1008 @@
+/*
+ * Copyright (c) 2002-2004 Christian Loose <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "cvsservice.h"
+
+#include <qintdict.h>
+#include <qstring.h>
+
+#include <dcopref.h>
+#include <dcopclient.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+
+#include "cvsjob.h"
+#include "cvsloginjob.h"
+#include "cvsserviceutils.h"
+#include "repository.h"
+#include "sshagent.h"
+
+
+static const char SINGLE_JOB_ID[] = "NonConcurrentJob";
+static const char REDIRECT_STDERR[] = "2>&1";
+
+enum WatchEvents { None=0, All=1, Commits=2, Edits=4, Unedits=8 };
+
+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
+ QIntDict<CvsLoginJob> loginJobs;
+ unsigned lastJobId;
+
+ QCString appId; // cache the DCOP clients app id
+
+ Repository* repository;
+
+ CvsJob* createCvsJob();
+ DCOPRef setupNonConcurrentJob(Repository* repo = 0);
+
+ bool hasWorkingCopy();
+ bool hasRunningJob();
+};
+
+
+CvsService::CvsService()
+ : DCOPObject("CvsService")
+ , d(new Private)
+{
+ 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);
+ d->loginJobs.setAutoDelete(true);
+
+ KConfig* config = kapp->config();
+ KConfigGroupSaver cs(config, "General");
+ if( config->readBoolEntry("UseSshAgent", false) )
+ {
+ // use the existing or start a new ssh-agent
+ SshAgent ssh;
+ // TODO CL do we need the return value?
+ //bool res = ssh.querySshAgent();
+ ssh.querySshAgent();
+ }
+}
+
+
+CvsService::~CvsService()
+{
+ // kill the ssh-agent (when we started it)
+ SshAgent ssh;
+ ssh.killSshAgent();
+
+ d->cvsJobs.clear();
+ d->loginJobs.clear();
+ delete d;
+}
+
+
+DCOPRef CvsService::add(const QStringList& files, bool isBinary)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs add [-kb] [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "add";
+
+ if( isBinary )
+ *d->singleCvsJob << "-kb";
+
+ *d->singleCvsJob << CvsServiceUtils::joinFileList(files) << REDIRECT_STDERR;
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::addWatch(const QStringList& files, int events)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "watch add";
+
+ if( events != All )
+ {
+ if( events & Commits )
+ *d->singleCvsJob << "-a commit";
+ if( events & Edits )
+ *d->singleCvsJob << "-a edit";
+ if( events & Unedits )
+ *d->singleCvsJob << "-a unedit";
+ }
+
+ *d->singleCvsJob << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::annotate(const QString& fileName, const QString& revision)
+{
+ if( !d->hasWorkingCopy() )
+ return DCOPRef();
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // (cvs log [FILE] && cvs annotate [-r rev] [FILE])
+ QString quotedName = KProcess::quote(fileName);
+ QString cvsClient = d->repository->cvsClient();
+
+ *job << "(" << cvsClient << "log" << quotedName << "&&"
+ << cvsClient << "annotate";
+
+ if( !revision.isEmpty() )
+ *job << "-r" << revision;
+
+ // *Hack*
+ // because the string "Annotations for blabla" is
+ // printed to stderr even with option -Q.
+ *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->hasRunningJob() )
+ return DCOPRef();
+
+ Repository repo(repository);
+
+ // assemble the command line
+ // cd [DIRECTORY] && cvs -d [REPOSITORY] checkout [-r tag] [-P] [MODULE]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << "cd" << KProcess::quote(workingDir) << "&&"
+ << repo.cvsClient()
+ << "-d" << repository
+ << "checkout";
+
+ if( !tag.isEmpty() )
+ *d->singleCvsJob << "-r" << tag;
+
+ if( pruneDirs )
+ *d->singleCvsJob << "-P";
+
+ *d->singleCvsJob << module;
+
+ return d->setupNonConcurrentJob(&repo);
+}
+
+
+DCOPRef CvsService::checkout(const QString& workingDir, const QString& repository,
+ const QString& module, const QString& tag,
+ bool pruneDirs, const QString& alias, bool exportOnly)
+{
+ if( d->hasRunningJob() )
+ return DCOPRef();
+
+ Repository repo(repository);
+
+ // assemble the command line
+ // cd [DIRECTORY] && cvs -d [REPOSITORY] co [-r tag] [-P] [-d alias] [MODULE]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << "cd" << KProcess::quote(workingDir) << "&&"
+ << repo.cvsClient()
+ << "-d" << repository;
+ if( exportOnly)
+ *d->singleCvsJob << "export";
+ else
+ *d->singleCvsJob << "checkout";
+
+ if( !tag.isEmpty() )
+ *d->singleCvsJob << "-r" << tag;
+
+ if( pruneDirs && !exportOnly )
+ *d->singleCvsJob << "-P";
+
+ if( !alias.isEmpty() )
+ *d->singleCvsJob << "-d" << alias;
+
+ *d->singleCvsJob << module;
+
+ return d->setupNonConcurrentJob(&repo);
+}
+
+DCOPRef CvsService::checkout(const QString& workingDir, const QString& repository,
+ const QString& module, const QString& tag,
+ bool pruneDirs, const QString& alias, bool exportOnly,
+ bool recursive)
+{
+ if( d->hasRunningJob() )
+ return DCOPRef();
+
+ Repository repo(repository);
+
+ // assemble the command line
+ // cd [DIRECTORY] && cvs -d [REPOSITORY] co [-r tag] [-P] [-d alias] [MODULE]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << "cd" << KProcess::quote(workingDir) << "&&"
+ << repo.cvsClient()
+ << "-d" << repository;
+ if( exportOnly)
+ *d->singleCvsJob << "export";
+ else
+ *d->singleCvsJob << "checkout";
+
+ if( !tag.isEmpty() )
+ *d->singleCvsJob << "-r" << tag;
+
+ if( pruneDirs && !exportOnly )
+ *d->singleCvsJob << "-P";
+
+ if( !alias.isEmpty() )
+ *d->singleCvsJob << "-d" << alias;
+
+ if( ! recursive )
+ *d->singleCvsJob << "-l";
+
+ *d->singleCvsJob << module;
+
+ return d->setupNonConcurrentJob(&repo);
+}
+
+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::createRepository(const QString& repository)
+{
+ if( d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs -d [REPOSITORY] init
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << "mkdir -p" << KProcess::quote(repository) << "&&"
+ << d->repository->cvsClient()
+ << "-d" << KProcess::quote(repository)
+ << "init";
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::createTag(const QStringList& files, const QString& tag,
+ bool branch, bool force)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs tag [-b] [-F] [TAG] [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "tag";
+
+ if( branch )
+ *d->singleCvsJob << "-b";
+
+ if( force )
+ *d->singleCvsJob << "-F";
+
+ *d->singleCvsJob << KProcess::quote(tag)
+ << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::deleteTag(const QStringList& files, const QString& tag,
+ bool branch, bool force)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs tag -d [-b] [-F] [TAG] [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "tag" << "-d";
+
+ if( branch )
+ *d->singleCvsJob << "-b";
+
+ if( force )
+ *d->singleCvsJob << "-F";
+
+ *d->singleCvsJob << KProcess::quote(tag)
+ << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::downloadCvsIgnoreFile(const QString& repository,
+ const QString& outputFile)
+{
+ Repository repo(repository);
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // cvs -d [REPOSITORY] -q checkout -p CVSROOT/cvsignore > [OUTPUTFILE]
+ *job << repo.cvsClient() << "-d" << repository
+ << "-q checkout -p CVSROOT/cvsignore >"
+ << KProcess::quote(outputFile);
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::downloadRevision(const QString& fileName,
+ const QString& revision,
+ const QString& outputFile)
+{
+ if( !d->hasWorkingCopy() )
+ return DCOPRef();
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // cvs update -p -r [REV] [FILE] > [OUTPUTFILE]
+ *job << d->repository->cvsClient() << "update -p";
+
+ if( !revision.isEmpty() )
+ *job << "-r" << KProcess::quote(revision);
+
+ *job << KProcess::quote(fileName) << ">" << KProcess::quote(outputFile);
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::downloadRevision(const QString& fileName,
+ const QString& revA,
+ const QString& outputFileA,
+ const QString& revB,
+ const QString& outputFileB)
+{
+ if( !d->hasWorkingCopy() )
+ return DCOPRef();
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // cvs update -p -r [REVA] [FILE] > [OUTPUTFILEA] ;
+ // cvs update -p -r [REVB] [FILE] > [OUTPUTFILEB]
+ *job << d->repository->cvsClient() << "update -p"
+ << "-r" << KProcess::quote(revA)
+ << KProcess::quote(fileName) << ">" << KProcess::quote(outputFileA)
+ << ";" << d->repository->cvsClient() << "update -p"
+ << "-r" << KProcess::quote(revB)
+ << KProcess::quote(fileName) << ">" << KProcess::quote(outputFileB);
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::diff(const QString& fileName, const QString& revA,
+ const QString& revB, const QString& diffOptions,
+ unsigned contextLines)
+{
+ // cvs diff [DIFFOPTIONS] -U CONTEXTLINES [-r REVA] {-r REVB] [FILE]
+ QString format = "-U" + QString::number(contextLines);
+ return diff(fileName, revA, revB, diffOptions, format);
+}
+
+
+DCOPRef CvsService::diff(const QString& fileName, const QString& revA,
+ const QString& revB, const QString& diffOptions,
+ const QString& format)
+{
+ if( !d->hasWorkingCopy() )
+ return DCOPRef();
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // cvs diff [DIFFOPTIONS] [FORMAT] [-r REVA] {-r REVB] [FILE]
+ *job << d->repository->cvsClient() << "diff" << diffOptions
+ << format;
+
+ if( !revA.isEmpty() )
+ *job << "-r" << KProcess::quote(revA);
+
+ if( !revB.isEmpty() )
+ *job << "-r" << KProcess::quote(revB);
+
+ *job << KProcess::quote(fileName);
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::edit(const QStringList& files)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs edit [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "edit"
+ << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::editors(const QStringList& files)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs editors [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "editors"
+ << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::history()
+{
+ if( !d->hasWorkingCopy() )
+ return DCOPRef();
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // cvs history -e -a
+ *job << d->repository->cvsClient() << "history -e -a";
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::import(const QString& workingDir, const QString& repository,
+ const QString& module, const QString& ignoreList,
+ const QString& comment, const QString& vendorTag,
+ const QString& releaseTag, bool importAsBinary)
+{
+ if( d->hasRunningJob() )
+ return DCOPRef();
+
+ Repository repo(repository);
+
+ // assemble the command line
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << "cd" << KProcess::quote(workingDir) << "&&"
+ << repo.cvsClient()
+ << "-d" << repository
+ << "import";
+
+ if( importAsBinary )
+ *d->singleCvsJob << "-kb";
+
+ const QString ignore = ignoreList.stripWhiteSpace();
+ if( !ignore.isEmpty() )
+ *d->singleCvsJob << "-I" << KProcess::quote(ignore);
+
+ QString logMessage = comment.stripWhiteSpace();
+ logMessage.prepend("\"");
+ logMessage.append("\"");
+ *d->singleCvsJob << "-m" << logMessage;
+
+ *d->singleCvsJob << module << vendorTag << releaseTag;
+
+ return d->setupNonConcurrentJob(&repo);
+}
+
+
+DCOPRef CvsService::import(const QString& workingDir, const QString& repository,
+ const QString& module, const QString& ignoreList,
+ const QString& comment, const QString& vendorTag,
+ const QString& releaseTag, bool importAsBinary,
+ bool useModificationTime)
+{
+ if( d->hasRunningJob() )
+ return DCOPRef();
+
+ Repository repo(repository);
+
+ // assemble the command line
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << "cd" << KProcess::quote(workingDir) << "&&"
+ << repo.cvsClient()
+ << "-d" << repository
+ << "import";
+
+ if( importAsBinary )
+ *d->singleCvsJob << "-kb";
+
+ if( useModificationTime )
+ *d->singleCvsJob << "-d";
+
+ const QString ignore = ignoreList.stripWhiteSpace();
+ if( !ignore.isEmpty() )
+ *d->singleCvsJob << "-I" << KProcess::quote(ignore);
+
+ QString logMessage = comment.stripWhiteSpace();
+ logMessage.prepend("\"");
+ logMessage.append("\"");
+ *d->singleCvsJob << "-m" << logMessage;
+
+ *d->singleCvsJob << module << vendorTag << releaseTag;
+
+ return d->setupNonConcurrentJob(&repo);
+}
+
+
+DCOPRef CvsService::lock(const QStringList& files)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs admin -l [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "admin -l"
+ << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::log(const QString& fileName)
+{
+ if( !d->hasWorkingCopy() )
+ return DCOPRef();
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // cvs log [FILE]
+ *job << d->repository->cvsClient() << "log" << KProcess::quote(fileName);
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::login(const QString& repository)
+{
+ if( repository.isEmpty() )
+ return DCOPRef();
+
+ Repository repo(repository);
+
+ // create a cvs job
+ ++(d->lastJobId);
+
+ CvsLoginJob* job = new CvsLoginJob(d->lastJobId);
+ d->loginJobs.insert(d->lastJobId, job);
+
+ // TODO: CVS_SERVER doesn't work ATM
+// job->setServer(repo.server());
+
+ // assemble the command line
+ // cvs -d [REPOSITORY] login
+ job->setCvsClient(repo.clientOnly().local8Bit());
+ job->setRepository(repository.local8Bit());
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::logout(const QString& repository)
+{
+ if( repository.isEmpty() )
+ return DCOPRef();
+
+ Repository repo(repository);
+
+ // create a cvs job
+ ++(d->lastJobId);
+
+ CvsJob* job = new CvsJob(d->lastJobId);
+ d->cvsJobs.insert(d->lastJobId, job);
+
+ job->setRSH(repo.rsh());
+ job->setServer(repo.server());
+ job->setDirectory(repo.workingCopy());
+
+ // assemble the command line
+ // cvs -d [REPOSITORY] logout
+ *job << repo.cvsClient() << "-d" << repository << "logout";
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::makePatch()
+{
+ return makePatch("", "-u");
+}
+
+
+DCOPRef CvsService::makePatch(const QString& diffOptions, const QString& format)
+{
+ if( !d->hasWorkingCopy() )
+ return DCOPRef();
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // cvs diff [DIFFOPTIONS] [FORMAT] -R 2>/dev/null
+ *job << d->repository->cvsClient() << "diff" << diffOptions << format << "-R"
+ << "2>/dev/null";
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::moduleList(const QString& repository)
+{
+ Repository repo(repository);
+
+ // create a cvs job
+ ++(d->lastJobId);
+
+ CvsJob* job = new CvsJob(d->lastJobId);
+ d->cvsJobs.insert(d->lastJobId, job);
+
+ job->setRSH(repo.rsh());
+ job->setServer(repo.server());
+ job->setDirectory(repo.workingCopy());
+
+ // assemble the command line
+ // cvs -d [REPOSITORY] checkout -c
+ *job << repo.cvsClient() << "-d" << repository << "checkout -c";
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::remove(const QStringList& files, bool recursive)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs remove -f [-l] [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "remove -f";
+
+ if( !recursive )
+ *d->singleCvsJob << "-l";
+
+ *d->singleCvsJob << CvsServiceUtils::joinFileList(files) << REDIRECT_STDERR;
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::removeWatch(const QStringList& files, int events)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "watch remove";
+
+ if( events != All )
+ {
+ if( events & Commits )
+ *d->singleCvsJob << "-a commit";
+ if( events & Edits )
+ *d->singleCvsJob << "-a edit";
+ if( events & Unedits )
+ *d->singleCvsJob << "-a unedit";
+ }
+
+ *d->singleCvsJob << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::rlog(const QString& repository, const QString& module,
+ bool recursive)
+{
+ Repository repo(repository);
+
+ // create a cvs job
+ ++(d->lastJobId);
+
+ CvsJob* job = new CvsJob(d->lastJobId);
+ d->cvsJobs.insert(d->lastJobId, job);
+
+ job->setRSH(repo.rsh());
+ job->setServer(repo.server());
+
+ // assemble the command line
+ // cvs -d [REPOSITORY] rlog [-l] [MODULE]
+ *job << repo.cvsClient() << "-d" << repository << "rlog";
+
+ if( !recursive )
+ *job << "-l";
+
+ *job << module;
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::simulateUpdate(const QStringList& files, bool recursive,
+ bool createDirs, bool pruneDirs)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs -n update [-l] [-d] [-P] [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "-n -q update";
+
+ if( !recursive )
+ *d->singleCvsJob << "-l";
+
+ if( createDirs )
+ *d->singleCvsJob << "-d";
+
+ if( pruneDirs )
+ *d->singleCvsJob << "-P";
+
+ *d->singleCvsJob << CvsServiceUtils::joinFileList(files) << REDIRECT_STDERR;
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::status(const QStringList& files, bool recursive, bool tagInfo)
+{
+ if( !d->hasWorkingCopy() )
+ return DCOPRef();
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // cvs status [-l] [-v] [FILES]
+ *job << d->repository->cvsClient() << "status";
+
+ if( !recursive )
+ *job << "-l";
+
+ if( tagInfo )
+ *job << "-v";
+
+ *job << CvsServiceUtils::joinFileList(files);
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::unedit(const QStringList& files)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // echo y | cvs unedit [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << "echo y |"
+ << d->repository->cvsClient() << "unedit"
+ << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::unlock(const QStringList& files)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs admin -u [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "admin -u"
+ << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::update(const QStringList& files, bool recursive,
+ bool createDirs, bool pruneDirs, const QString& extraOpt)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs update [-l] [-d] [-P] [EXTRAOPTIONS] [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "-q update";
+
+ if( !recursive )
+ *d->singleCvsJob << "-l";
+
+ if( createDirs )
+ *d->singleCvsJob << "-d";
+
+ if( pruneDirs )
+ *d->singleCvsJob << "-P";
+
+ *d->singleCvsJob << extraOpt << CvsServiceUtils::joinFileList(files)
+ << REDIRECT_STDERR;
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::watchers(const QStringList& files)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs watchers [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "watchers"
+ << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+void CvsService::quit()
+{
+ kapp->quit();
+}
+
+
+CvsJob* CvsService::Private::createCvsJob()
+{
+ ++lastJobId;
+
+ // create a cvs job
+ CvsJob* job = new CvsJob(lastJobId);
+ cvsJobs.insert(lastJobId, job);
+
+ job->setRSH(repository->rsh());
+ job->setServer(repository->server());
+ job->setDirectory(repository->workingCopy());
+
+ return job;
+}
+
+
+DCOPRef CvsService::Private::setupNonConcurrentJob(Repository* repo)
+{
+ // no explicit repository provided?
+ if( !repo )
+ repo = repository;
+
+ singleCvsJob->setRSH(repo->rsh());
+ singleCvsJob->setServer(repo->server());
+ singleCvsJob->setDirectory(repo->workingCopy());
+
+ return singleJobRef;
+}
+
+
+bool CvsService::Private::hasWorkingCopy()
+{
+ if( repository->workingCopy().isEmpty() )
+ {
+ KMessageBox::sorry(0, i18n("You have to set a local working copy "
+ "directory before you can use this function!"));
+ return false;
+ }
+
+ return true;
+}
+
+
+bool CvsService::Private::hasRunningJob()
+{
+ bool result = singleCvsJob->isRunning();
+
+ if( result )
+ KMessageBox::sorry(0, i18n("There is already a job running"));
+
+ return result;
+}