diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-15 17:32:48 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-15 17:32:48 +0000 |
commit | e2f541c98dfa4081fa3ab3d28f08ea2309281884 (patch) | |
tree | cb721a55bc88753ddeb9754dc98ef45e2850ce30 /src/svnqt | |
download | tdesvn-e2f541c98dfa4081fa3ab3d28f08ea2309281884.tar.gz tdesvn-e2f541c98dfa4081fa3ab3d28f08ea2309281884.zip |
Added KDE3 version of kdesvn
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kdesvn@1103685 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/svnqt')
103 files changed, 18553 insertions, 0 deletions
diff --git a/src/svnqt/CMakeLists.txt b/src/svnqt/CMakeLists.txt new file mode 100644 index 0000000..bf50a6f --- /dev/null +++ b/src/svnqt/CMakeLists.txt @@ -0,0 +1,205 @@ +SET(SOURCES + apr.cpp + client_annotate.cpp + client_cat.cpp + client.cpp + client_diff.cpp + client_ls.cpp + client_modify.cpp + client_property.cpp + client_status.cpp + context.cpp + datetime.cpp + dirent.cpp + entry.cpp + exception.cpp + log_entry.cpp + path.cpp + pool.cpp + revision.cpp + status.cpp + targets.cpp + url.cpp + version_check.cpp + wc.cpp + lock_entry.cpp + client_lock.cpp + info_entry.cpp + client_impl.cpp + contextdata.cpp + commititem.cpp + repository.cpp + repositorydata.cpp + repositorylistener.cpp + svnstream.cpp + diff_data.cpp + svnfilestream.cpp + stringarray.cpp + diffoptions.cpp + conflictdescription.cpp + conflictresult.cpp + client_merge.cpp + cache/LogCache.cpp + cache/ReposLog.cpp + cache/DatabaseException.hpp + cache/DatabaseException.cpp + ) + +IF (NOT QT4_FOUND) + IF (SQLITE_FOUND) + MESSAGE(STATUS "Build own sqlite3 database modul") + SET(SOURCES + ${SOURCES} + cache/sqlite3/qsqlcachedresult.cpp + cache/sqlite3/qsql_sqlite3.cpp + cache/sqlite3/qsqlcachedresult.h + cache/sqlite3/qsql_sqlite3.h + ) + ELSE (SQLITE_FOUND) + MESSAGE(SEND_ERROR "The QT3 version requires sqlite3 but could not found") + ENDIF (SQLITE_FOUND) +ELSE (NOT QT4_FOUND) + MESSAGE(STATUS "Build with QT4.") + ADD_DEFINITIONS(-DNO_SQLITE3) +ENDIF (NOT QT4_FOUND) + +SET(CACHEINST_HEADERS + cache/LogCache.hpp + cache/ReposLog.hpp + cache/DatabaseException.hpp +) + +SET(INST_HEADERS + annotate_line.hpp + apr.hpp + check.hpp + client.hpp + commititem.hpp + context.hpp + context_listener.hpp + datetime.hpp + dirent.hpp + entry.hpp + exception.hpp + info_entry.hpp + lock_entry.hpp + log_entry.hpp + path.hpp + pool.hpp + repository.hpp + repositorylistener.hpp + revision.hpp + smart_pointer.hpp + shared_pointer.hpp + status.hpp + svnfilestream.hpp + svnstream.hpp + svnqttypes.hpp + targets.hpp + url.hpp + version_check.hpp + wc.hpp + stringarray.hpp + diffoptions.hpp + conflictdescription.hpp + conflictresult.hpp + ) + +FILE(GLOB svnhdr RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.hpp") +SET(svnhdr ${svnhdr} ${CACHE_INST_HEADERS}) + +IF(QT4_FOUND) + MESSAGE(STATUS "Qt: ${QT_LIBRARY_DIR}") + MESSAGE(STATUS "Qt: ${QT_QTCORE_LIBRARY}") + SET(TOUTF8 "toUtf8") + SET(FROMUTF8 "fromUtf8") + SET(QLIST "QList") + SET(TOASCII "toAscii") + SET(HOMEDIR "homePath") + SET(svnqt-name svnqt-qt4) + SET(QDATABASE "QSqlDatabase") + SET(QLONG "qlonglong") +ELSE(QT4_FOUND) + IF(QT_FOUND) + SET(TOUTF8 "utf8") + SET(FROMUTF8 "fromUtf8") + SET(QLIST "QValueList") + SET(TOASCII "latin1") + SET(HOMEDIR "homeDirPath") + SET(QDATABASE "QSqlDatabase*") + SET(QLONG "Q_LLONG") + ENDIF(QT_FOUND) + SET(svnqt-name svnqt) +ENDIF(QT4_FOUND) + +IF (HAVE_GCC_VISIBILITY) + SET(_SVNQT_EXPORT "__attribute__ ((visibility(\"default\")))") + SET(_SVNQT_NOEXPORT "__attribute__ ((visibility(\"hidden\")))") +ENDIF (HAVE_GCC_VISIBILITY) +IF (WIN32) + SET(_SVNQT_EXPORT "__declspec(dllexport)") +ENDIF (WIN32) + +CONFIGURE_FILE( + "${CMAKE_CURRENT_SOURCE_DIR}/svnqt_defines.hpp.in" + "${CMAKE_CURRENT_BINARY_DIR}/svnqt_defines.hpp" + IMMEDIATE + @ONLY) + +SET(INST_HEADERS ${INST_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/svnqt_defines.hpp) +INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) + +ADD_LIBRARY(${svnqt-name} SHARED ${SOURCES} ${svnhdr}) +IF(WIN32) + ADD_DEFINITIONS(-D_USE_32BIT_TIME_T) +ELSE(WIN32) + SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib${LIB_SUFFIX}) + SET_TARGET_PROPERTIES(${svnqt-name} + PROPERTIES + COMPILE_FLAGS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}) +ENDIF(WIN32) + +SET(LIB_MAJOR 4) +SET(LIB_MINOR 2) +SET(LIB_RELEASE 2) + +SET(_soversion ${LIB_MAJOR}.${LIB_MINOR}.${LIB_RELEASE}) + +SET_TARGET_PROPERTIES(${svnqt-name} PROPERTIES + SOVERSION ${LIB_MAJOR} + VERSION ${_soversion}) + +SET(ALL_LINKFLAGS ${APR_EXTRA_LIBFLAGS}) +SET(ALL_LINKFLAGS "${ALL_LINKFLAGS} ${APU_EXTRA_LIBFLAGS}") +SET_TARGET_PROPERTIES(${svnqt-name} PROPERTIES LINK_FLAGS "${ALL_LINKFLAGS} ${LINK_NO_UNDEFINED}") +TARGET_LINK_LIBRARIES(${svnqt-name} ${QT_LIBRARIES} ${SUBVERSION_ALL_LIBS}) + +IF (SQLITE_FOUND AND NOT QT4_FOUND) + TARGET_LINK_LIBRARIES(${svnqt-name} ${SQLITE_LIBRARIES}) + INCLUDE_DIRECTORIES(SQLITE_INCLUDE_DIR) +ELSE (SQLITE_FOUND AND NOT QT4_FOUND) + TARGET_LINK_LIBRARIES(${svnqt-name} ${QT_QTSQL_LIBRARY}) +ENDIF (SQLITE_FOUND AND NOT QT4_FOUND) + +IF (WIN32) + TARGET_LINK_LIBRARIES( ${svnqt-name} wsock32.lib ) +ENDIF (WIN32) + +# Just a small linking test +IF (BUILD_TESTS) + ADD_EXECUTABLE(testlink testmain.cpp) + TARGET_LINK_LIBRARIES(testlink ${svnqt-name}) +ENDIF (BUILD_TESTS) + +# install rules +# in win32 we don't install it +IF(NOT WIN32) + INSTALL(TARGETS ${svnqt-name} DESTINATION ${LIB_INSTALL_DIR}) + INSTALL(FILES ${INST_HEADERS} DESTINATION include/${svnqt-name}) + INSTALL(FILES ${CACHEINST_HEADERS} DESTINATION include/${svnqt-name}/cache) +ENDIF(NOT WIN32) + +IF (BUILD_TESTS) + ADD_SUBDIRECTORY(tests) + ADD_SUBDIRECTORY(cache/test) +ENDIF (BUILD_TESTS) diff --git a/src/svnqt/annotate_line.hpp b/src/svnqt/annotate_line.hpp new file mode 100644 index 0000000..c8a0a6f --- /dev/null +++ b/src/svnqt/annotate_line.hpp @@ -0,0 +1,159 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ +#ifndef _SVNCPP_ANNOTATE_LINE_HPP_ +#define _SVNCPP_ANNOTATE_LINE_HPP_ + +#include "svnqt/svnqt_defines.hpp" + +#include <qstring.h> +#include <qdatetime.h> + +namespace svn +{ + /** + * This class holds the data for one line in an annotation + */ + class AnnotateLine + { + public: + AnnotateLine (QLONG line_no, + QLONG revision, + const char *author, + const char *date, + const char *line) + : m_line_no (line_no), m_revision (revision), + m_date( (date&&strlen(date))?QDateTime::fromString(QString::FROMUTF8(date),Qt::ISODate):QDateTime()), + m_line(line?line:""),m_author(author?author:""), + m_merge_revision(-1), + m_merge_date(QDateTime()), + m_merge_author(""),m_merge_path("") + + { + } + + AnnotateLine (QLONG line_no, + QLONG revision, + const char *author, + const char *date, + const char *line, + QLONG merge_revision, + const char *merge_author, + const char *merge_date, + const char *merge_path + ) + : m_line_no (line_no), m_revision (revision), + m_date( (date&&strlen(date))?QDateTime::fromString(QString::FROMUTF8(date),Qt::ISODate):QDateTime()), + m_line(line?line:""),m_author(author?author:""), + m_merge_revision(merge_revision), + m_merge_date( (merge_date&&strlen(merge_date))?QDateTime::fromString(QString::FROMUTF8(merge_date),Qt::ISODate):QDateTime()), + m_merge_author(merge_author?merge_author:""),m_merge_path(merge_path?merge_path:"") + { + } + + AnnotateLine ( const AnnotateLine &other) + : m_line_no (other.m_line_no), m_revision (other.m_revision), m_date (other.m_date), + m_line (other.m_line), m_author (other.m_author) + { + } + AnnotateLine() + : m_line_no(0),m_revision(-1),m_date(), + m_line(), m_author() + { + } + + /** + * destructor + */ + virtual ~AnnotateLine () + { + } + + QLONG + lineNumber () const + { + return m_line_no; + } + QLONG + revision () const + { + return m_revision; + } + + + const QByteArray & + author () const + { + return m_author; + } + + + const QDateTime & + date () const + { + return m_date; + } + + + const QByteArray & + line () const + { + return m_line; + } + + protected: + QLONG m_line_no; + QLONG m_revision; + QDateTime m_date; +#if QT_VERSION < 0x040000 + QCString m_line; + QCString m_author; +#else + QByteArray m_line; + QByteArray m_author; +#endif + + QLONG m_merge_revision; + QDateTime m_merge_date; +#if QT_VERSION < 0x040000 + QCString m_merge_author; + QCString m_merge_path; +#else + QByteArray m_merge_author; + QByteArray m_merge_path; +#endif + }; +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/apr.cpp b/src/svnqt/apr.cpp new file mode 100644 index 0000000..ca531a0 --- /dev/null +++ b/src/svnqt/apr.cpp @@ -0,0 +1,52 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +// apr +#include "apr_general.h" + +// svncpp +#include "apr.hpp" + + +/** + * SvnCpp namespace. + */ +namespace svn +{ + Apr::Apr () + { + apr_initialize (); + } + + Apr::~Apr () + { + apr_terminate (); + } +} diff --git a/src/svnqt/apr.hpp b/src/svnqt/apr.hpp new file mode 100644 index 0000000..bb6655a --- /dev/null +++ b/src/svnqt/apr.hpp @@ -0,0 +1,69 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_APR_H_ +#define _SVNCPP_APR_H_ + +namespace svn +{ + + /** + * APR class. Include this class in your application for apr + * support. + */ + class Apr + { + public: + /** + * Default constructor. Initializes APR + */ + Apr (); + + /** + * Destructor. Terminates APR + */ + ~Apr (); + + private: + /** Disallow copy constructor */ + Apr (const Apr &); + + /** Disallow assignment operator */ + Apr & + operator = (const Apr &); + }; +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/cache/DatabaseException.cpp b/src/svnqt/cache/DatabaseException.cpp new file mode 100644 index 0000000..85812ab --- /dev/null +++ b/src/svnqt/cache/DatabaseException.cpp @@ -0,0 +1,12 @@ +#include "DatabaseException.hpp" + +/*! + \fn svn::cache::DatabaseException::DatabaseException(const QString&msg,int aNumber)throw() + */ +svn::cache::DatabaseException::DatabaseException(const QString&msg,int aNumber)throw() + : Exception(msg),m_number(aNumber) +{ + if (aNumber>-1) { + setMessage(QString("(Code %1) %2").arg(aNumber).arg(msg)); + } +} diff --git a/src/svnqt/cache/DatabaseException.hpp b/src/svnqt/cache/DatabaseException.hpp new file mode 100644 index 0000000..85e5ce4 --- /dev/null +++ b/src/svnqt/cache/DatabaseException.hpp @@ -0,0 +1,35 @@ +#ifndef _DATABASE_EXCEPTION_HPP +#define _DATABASE_EXCEPTION_HPP + +#include "svnqt/exception.hpp" + +namespace svn +{ +namespace cache +{ + +class SVNQT_EXPORT DatabaseException:public svn::Exception +{ + private: + DatabaseException()throw(); + int m_number; + + public: + DatabaseException(const QString&msg)throw() + : Exception(msg),m_number(-1) + {} + + DatabaseException(const DatabaseException&src)throw() + : Exception(src.msg()),m_number(src.number()) + {} + DatabaseException(const QString&msg,int aNumber)throw(); + virtual ~DatabaseException()throw(){} + int number() const + { + return m_number; + } +}; + +} +} +#endif diff --git a/src/svnqt/cache/LogCache.cpp b/src/svnqt/cache/LogCache.cpp new file mode 100644 index 0000000..6356c6f --- /dev/null +++ b/src/svnqt/cache/LogCache.cpp @@ -0,0 +1,468 @@ +#include "LogCache.hpp" + +#include <qdir.h> +#include <qsql.h> +#include <qsqldatabase.h> +#if QT_VERSION < 0x040000 +#include <qthreadstorage.h> +#else +#include <QMutex> +#include <QThreadStorage> +#include <QSqlError> +#include <QSqlQuery> +#include <QVariant> +#endif +#include <qmap.h> + +#include "svnqt/path.hpp" +#include "svnqt/cache/DatabaseException.hpp" + +#ifndef NO_SQLITE3 +#include "sqlite3/qsql_sqlite3.h" +#define SQLTYPE "QSQLITE3" +#else +#define SQLTYPE "QSQLITE" +#endif + +#define SQLMAIN "logmain-logcache" +#define SQLMAINTABLE "logdb" + +namespace svn { +namespace cache { + +LogCache* LogCache::mSelf = 0; + +class ThreadDBStore +{ +public: + ThreadDBStore(){ +#if QT_VERSION < 0x040000 + m_DB=0; +#else + m_DB=QSqlDatabase(); +#endif + } + ~ThreadDBStore(){ +#if QT_VERSION < 0x040000 + m_DB=0; +#else + m_DB=QSqlDatabase(); +#endif + QSqlDatabase::removeDatabase(key); + QMap<QString,QString>::Iterator it; + for (it=reposCacheNames.begin();it!=reposCacheNames.end();++it) { +#if QT_VERSION < 0x040000 + QSqlDatabase::removeDatabase(it.data()); +#else + QSqlDatabase::removeDatabase(it.value()); +#endif + } + } + + QDataBase m_DB; + QString key; + QMap<QString,QString> reposCacheNames; +}; + +class LogCacheData +{ + +protected: + QMutex m_singleDbMutex; + +public: + LogCacheData(){} + ~LogCacheData(){ + if (m_mainDB.hasLocalData()) { + m_mainDB.setLocalData(0L); + } + } + + bool checkReposDb(QDataBase aDb) + { +#if QT_VERSION < 0x040000 + if (!aDb) { + return false; + } + if (!aDb->open()) { + return false; + } +#else + if (!aDb.open()) { + return false; + } +#endif + + QSqlQuery _q(QString::null, aDb); +#if QT_VERSION < 0x040000 + QStringList list = aDb->tables(); +#else + QStringList list = aDb.tables(); +#endif + +#if QT_VERSION < 0x040000 + if (list.find("logentries")==list.end()) { + aDb->transaction(); +#else + if (list.indexOf("logentries")==-1) { + aDb.transaction(); +#endif + _q.exec("CREATE TABLE \"logentries\" (\"revision\" INTEGER UNIQUE,\"date\" INTEGER,\"author\" TEXT, \"message\" TEXT)"); +#if QT_VERSION < 0x040000 + aDb->commit(); +#else + aDb.commit(); +#endif + } +#if QT_VERSION < 0x040000 + if (list.find("changeditems")==list.end()) { + aDb->transaction(); +#else + if (list.indexOf("changeditems")==-1) { + aDb.transaction(); +#endif + _q.exec("CREATE TABLE \"changeditems\" (\"revision\" INTEGER,\"changeditem\" TEXT,\"action\" TEXT,\"copyfrom\" TEXT,\"copyfromrev\" INTEGER, PRIMARY KEY(revision,changeditem,action))"); +#if QT_VERSION < 0x040000 + aDb->commit(); +#else + aDb.commit(); +#endif + } +#if QT_VERSION < 0x040000 + list = aDb->tables(); + if (list.find("logentries")==list.end() || list.find("changeditems")==list.end()) { +#else + list = aDb.tables(); + if (list.indexOf("logentries")==-1 || list.indexOf("changeditems")==-1) { +#endif + return false; + } + return true; + } + + QString createReposDB(const svn::Path&reposroot) { + QMutexLocker locker( &m_singleDbMutex ); + + QDataBase _mdb = getMainDB(); + + QSqlQuery query1(QString::null,_mdb); + QString q("insert into "+QString(SQLMAINTABLE)+" (reposroot) VALUES('"+reposroot+"')"); +#if QT_VERSION < 0x040000 + _mdb->transaction(); +#else + _mdb.transaction(); +#endif + + query1.exec(q); +#if QT_VERSION < 0x040000 + _mdb->commit(); +#else + _mdb.commit(); +#endif + QSqlQuery query(QString::null,_mdb); + query.prepare(s_reposSelect); + query.bindValue(0,reposroot.native()); + query.exec(); + QString db; +#if QT_VERSION < 0x040000 + if (query.lastError().type()==QSqlError::None && query.next()) { +#else + if (query.lastError().type()==QSqlError::NoError && query.next()) { +#endif + db = query.value(0).toString(); + } + else { + qDebug("Error select_01: %s (%s)",query.lastError().text().TOUTF8().data(), + query.lastQuery().TOUTF8().data()); + } + if (!db.isEmpty()) { + QString fulldb = m_BasePath+"/"+db+".db"; + QDataBase _db = QSqlDatabase::addDatabase(SQLTYPE,"tmpdb"); +#if QT_VERSION < 0x040000 + _db->setDatabaseName(fulldb); +#else + _db.setDatabaseName(fulldb); +#endif + if (!checkReposDb(_db)) { + } + QSqlDatabase::removeDatabase("tmpdb"); + } + return db; + } + + QDataBase getReposDB(const svn::Path&reposroot) { +#if QT_VERSION < 0x040000 + if (!getMainDB()) { + return 0; +#else + if (!getMainDB().isValid()) { + return QDataBase(); +#endif + } + bool checkDone = false; + // make sure path is correct eg. without traling slashes. + QString dbFile; + QSqlQuery c(QString::null,getMainDB()); + c.prepare(s_reposSelect); + c.bindValue(0,reposroot.native()); + c.exec(); + +#if QT_VERSION < 0x040000 + //qDebug("Check for path: "+reposroot.native()); +#endif + + // only the first one + if ( c.next() ) { +#if QT_VERSION < 0x040000 +/* qDebug( c.value(0).toString() + ": " + + c.value(0).toString() );*/ +#endif + dbFile = c.value(0).toString(); + } + if (dbFile.isEmpty()) { + dbFile = createReposDB(reposroot); + if (dbFile.isEmpty()) { +#if QT_VERSION < 0x040000 + return 0; +#else + return QSqlDatabase(); +#endif + } + checkDone=true; + } + if (m_mainDB.localData()->reposCacheNames.find(dbFile)!=m_mainDB.localData()->reposCacheNames.end()) { + return QSqlDatabase::database(m_mainDB.localData()->reposCacheNames[dbFile]); + } + int i = 0; + QString _key = dbFile; + while (QSqlDatabase::contains(_key)) { + _key = QString("%1-%2").arg(dbFile).arg(i++); + } +// qDebug("The repository key is now: %s",_key.TOUTF8().data()); + QDataBase _db = QSqlDatabase::addDatabase(SQLTYPE,_key); +#if QT_VERSION < 0x040000 + if (!_db) { + return 0; + } +#endif + QString fulldb = m_BasePath+"/"+dbFile+".db"; +#if QT_VERSION < 0x040000 + _db->setDatabaseName(fulldb); +#else + _db.setDatabaseName(fulldb); +#endif +// qDebug("try database open %s",fulldb.TOUTF8().data()); + if (!checkReposDb(_db)) { + qDebug("no DB opened"); +#if QT_VERSION < 0x040000 + _db = 0; +#else + _db = QSqlDatabase(); +#endif + } else { + qDebug("Insert into map"); + m_mainDB.localData()->reposCacheNames[dbFile]=_key; + } + return _db; + } + + QDataBase getMainDB()const + { + if (!m_mainDB.hasLocalData()) { + unsigned i=0; + QString _key = SQLMAIN; + while (QSqlDatabase::contains(_key)) { + _key.sprintf("%s-%i",SQLMAIN,i++); + } + qDebug("The key is now: %s",_key.TOUTF8().data()); + + QDataBase db = QSqlDatabase::addDatabase(SQLTYPE,_key); +#if QT_VERSION < 0x040000 + db->setDatabaseName(m_BasePath+"/maindb.db"); + if (!db->open()) { +#else + db.setDatabaseName(m_BasePath+"/maindb.db"); + if (!db.open()) { +#endif +#if QT_VERSION < 0x040000 + qWarning("Failed to open main database: " + db->lastError().text()); +#endif + } else { + m_mainDB.setLocalData(new ThreadDBStore); + m_mainDB.localData()->key = _key; + m_mainDB.localData()->m_DB = db; + } + } + if (m_mainDB.hasLocalData()) { + return m_mainDB.localData()->m_DB; + } else { +#if QT_VERSION < 0x040000 + return 0; +#else + return QSqlDatabase(); +#endif + } + } + QString m_BasePath; + + mutable QThreadStorage<ThreadDBStore*> m_mainDB; + + static const QString s_reposSelect; +}; + + +QString LogCache::s_CACHE_FOLDER="logcache"; +const QString LogCacheData::s_reposSelect=QString("SELECT id from ")+QString(SQLMAINTABLE)+QString(" where reposroot=? ORDER by id DESC"); + +/*! + \fn svn::cache::LogCache::LogCache() + */ +LogCache::LogCache() +{ + m_BasePath = QDir::HOMEDIR()+"/.svnqt"; + setupCachePath(); +} + +LogCache::LogCache(const QString&aBasePath) +{ + if (mSelf) { + delete mSelf; + } + mSelf=this; + if (aBasePath.isEmpty()) { + m_BasePath=QDir::HOMEDIR()+"/.svnqt"; + } else { + m_BasePath=aBasePath; + } + setupCachePath(); +} + + +LogCache::~LogCache() +{ +} + +/*! + \fn svn::cache::LogCache::setupCachePath() + */ +void LogCache::setupCachePath() +{ + m_CacheData = new LogCacheData; + m_CacheData->m_BasePath=m_BasePath; + QDir d; + if (!d.exists(m_BasePath)) { + d.mkdir(m_BasePath); + } + m_BasePath=m_BasePath+"/"+s_CACHE_FOLDER; + if (!d.exists(m_BasePath)) { + d.mkdir(m_BasePath); + } + m_CacheData->m_BasePath=m_BasePath; + if (d.exists(m_BasePath)) { + setupMainDb(); + } +} + +void LogCache::setupMainDb() +{ +#ifndef NO_SQLITE3 + if (!QSqlDatabase::isDriverAvailable(SQLTYPE)) { + QSqlDatabase::registerSqlDriver(SQLTYPE,new QSqlDriverCreator<QSQLite3Driver>); + } +#endif + QDataBase mainDB = m_CacheData->getMainDB(); +#if QT_VERSION < 0x040000 + if (!mainDB || !mainDB->open()) { + qWarning("Failed to open main database: " + (mainDB?mainDB->lastError().text():"No database object.")); +#else + if (!mainDB.isValid()) { + qWarning("Failed to open main database."); +#endif + } else { + QSqlQuery q(QString::null, mainDB); +#if QT_VERSION < 0x040000 + mainDB->transaction(); +#else + mainDB.transaction(); +#endif + if (!q.exec("CREATE TABLE IF NOT EXISTS \""+QString(SQLMAINTABLE)+"\" (\"reposroot\" TEXT,\"id\" INTEGER PRIMARY KEY NOT NULL);")) { +#if QT_VERSION < 0x040000 + qWarning("Failed create main database: " + mainDB->lastError().text()); +#endif + } +#if QT_VERSION < 0x040000 + mainDB->commit(); +#else + mainDB.commit(); +#endif + } +} + +} +} + + +/*! + \fn svn::cache::LogCache::self() + */ +svn::cache::LogCache* svn::cache::LogCache::self() +{ + if (!mSelf) { + mSelf=new LogCache(); + } + return mSelf; +} + + +/*! + \fn svn::cache::LogCache::reposDb() + */ +QDataBase svn::cache::LogCache::reposDb(const QString&aRepository) +{ +// qDebug("reposDB"); + return m_CacheData->getReposDB(aRepository); +} + + +/*! + \fn svn::cache::LogCache::cachedRepositories()const + */ +QStringList svn::cache::LogCache::cachedRepositories()const +{ + static QString s_q(QString("select \"reposroot\" from ")+QString(SQLMAINTABLE)+QString("order by reposroot")); + QDataBase mainDB = m_CacheData->getMainDB(); + QStringList _res; +#if QT_VERSION < 0x040000 + if (!mainDB || !mainDB->open()) { +#else + if (!mainDB.isValid()) { +#endif + qWarning("Failed to open main database."); + return _res; + } + QSqlQuery cur(QString::null,mainDB); + cur.prepare(s_q); + if (!cur.exec()) { + qDebug(cur.lastError().text().TOUTF8().data()); + throw svn::cache::DatabaseException(QString("Could not retrieve values: ")+cur.lastError().text()); + return _res; + } + while (cur.next()) { + _res.append(cur.value(0).toString()); + } + + return _res; +} + +bool svn::cache::LogCache::valid()const +{ + QDataBase mainDB = m_CacheData->getMainDB(); +#if QT_VERSION < 0x040000 + if (!mainDB || !mainDB->open()) { +#else + if (!mainDB.isValid()) { +#endif + return false; + } + return true; +} diff --git a/src/svnqt/cache/LogCache.hpp b/src/svnqt/cache/LogCache.hpp new file mode 100644 index 0000000..9e76697 --- /dev/null +++ b/src/svnqt/cache/LogCache.hpp @@ -0,0 +1,41 @@ +#ifndef _LOG_CACHE_HPP +#define _LOG_CACHE_HPP + +#include <qstring.h> +#include <qdir.h> + +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/shared_pointer.hpp" + +namespace svn { + namespace cache { + + class LogCacheData; + + class SVNQT_EXPORT LogCache + { + private: + svn::SharedPointer<LogCacheData> m_CacheData; + + protected: + LogCache(); + static LogCache* mSelf; + QString m_BasePath; + static QString s_CACHE_FOLDER; + void setupCachePath(); + void setupMainDb(); + + public: + ///! should used for testing only! + LogCache(const QString&aBasePath); + virtual ~LogCache(); + static LogCache* self(); + QDataBase reposDb(const QString&aRepository); + QStringList cachedRepositories()const; + + bool valid()const; + }; + } +} + +#endif diff --git a/src/svnqt/cache/ReposLog.cpp b/src/svnqt/cache/ReposLog.cpp new file mode 100644 index 0000000..89be2d0 --- /dev/null +++ b/src/svnqt/cache/ReposLog.cpp @@ -0,0 +1,535 @@ +#include "ReposLog.hpp" + +#include "LogCache.hpp" +#include "svnqt/info_entry.hpp" +#include "svnqt/svnqttypes.hpp" +#include "svnqt/client.hpp" +#include "svnqt/context_listener.hpp" +#include "svnqt/cache/DatabaseException.hpp" + +#include <qsqldatabase.h> + +#if QT_VERSION < 0x040000 +#else +#include <QSqlError> +#include <QSqlQuery> +#include <QVariant> +#define Q_LLONG qlonglong +#endif + +/*! + \fn svn::cache::ReposLog::ReposLog(svn::Client*aClient,const QString&) + */ +svn::cache::ReposLog::ReposLog(svn::Client*aClient,const QString&aRepository) + :m_Client(), +#if QT_VERSION < 0x040000 + m_Database(0), +#else + m_Database(), +#endif + m_ReposRoot(aRepository),m_latestHead(svn::Revision::UNDEFINED) +{ + m_Client=aClient; + ContextP ctx = m_Client->getContext(); + if (!aRepository.isEmpty()) { + m_Database = LogCache::self()->reposDb(aRepository); + } +} + + +/*! + \fn svn::cache::ReposLog::latestHeadRev() + */ +svn::Revision svn::cache::ReposLog::latestHeadRev() +{ + if (!m_Client||m_ReposRoot.isEmpty()) { + return svn::Revision::UNDEFINED; + } +#if QT_VERSION < 0x040000 + if (!m_Database) { +#else + if (!m_Database.isValid()) { +#endif + m_Database = LogCache::self()->reposDb(m_ReposRoot); +#if QT_VERSION < 0x040000 + if (!m_Database) { +#else + if (!m_Database.isValid()) { +#endif + return svn::Revision::UNDEFINED; + } + } + /// no catch - exception has go trough... + qDebug("Getting headrev"); + svn::InfoEntries e = m_Client->info(m_ReposRoot,svn::DepthEmpty,svn::Revision::HEAD,svn::Revision::HEAD); + if (e.count()<1||e[0].reposRoot().isEmpty()) { + return svn::Revision::UNDEFINED; + } + qDebug("Getting headrev done"); + return e[0].revision(); +} + + +/*! + \fn svn::cache::ReposLog::latestCachedRev() + */ +svn::Revision svn::cache::ReposLog::latestCachedRev() +{ + if (m_ReposRoot.isEmpty()) { + return svn::Revision::UNDEFINED; + } +#if QT_VERSION < 0x040000 + if (!m_Database) { +#else + if (!m_Database.isValid()) { +#endif + m_Database = LogCache::self()->reposDb(m_ReposRoot); +#if QT_VERSION < 0x040000 + if (!m_Database) { +#else + if (!m_Database.isValid()) { +#endif + return svn::Revision::UNDEFINED; + } + } + QString q("select revision from 'logentries' order by revision DESC limit 1"); + QSqlQuery _q(QString::null, m_Database); + if (!_q.exec(q)) { + qDebug(_q.lastError().text().TOUTF8().data()); + return svn::Revision::UNDEFINED; + } + int _r; + if (_q.isActive() && _q.next()) { + //qDebug("Sel result: %s",_q.value(0).toString().TOUTF8().data()); + _r = _q.value(0).toInt(); + } else { + qDebug(_q.lastError().text().TOUTF8().data()); + return svn::Revision::UNDEFINED; + } + return _r; +} + +bool svn::cache::ReposLog::checkFill(svn::Revision&start,svn::Revision&end,bool checkHead) +{ +#if QT_VERSION < 0x040000 + if (!m_Database) { +#else + if (!m_Database.isValid()) { +#endif + m_Database = LogCache::self()->reposDb(m_ReposRoot); +#if QT_VERSION < 0x040000 + if (!m_Database) { +#else + if (!m_Database.isValid()) { +#endif + return false; + } + } + ContextP cp = m_Client->getContext(); + long long icount=0; + + svn::Revision _latest=latestCachedRev(); +// qDebug("Latest cached rev: %i",_latest.revnum()); +// qDebug("End revision is: %s",end.toString().TOUTF8().data()); + + if (checkHead && _latest.revnum()>=latestHeadRev().revnum()) { + return true; + } + + start=date2numberRev(start); + end=date2numberRev(end); + + // both should now one of START, HEAD or NUMBER + if (start==svn::Revision::HEAD || (end==svn::Revision::NUMBER && start==svn::Revision::NUMBER && start.revnum()>end.revnum())) { + svn::Revision tmp = start; + start = end; + end = tmp; + } + svn::Revision _rstart=_latest.revnum()+1; + svn::Revision _rend = end; + if (_rend==svn::Revision::UNDEFINED) { +// qDebug("Setting end to Head"); + _rend=svn::Revision::HEAD; + } + // no catch - exception should go outside. + if (_rstart==0){ + _rstart = 1; + } +// qDebug("Getting log %s -> %s",_rstart.toString().TOUTF8().data(),_rend.toString().TOUTF8().data()); + if (_rend==svn::Revision::HEAD) { + _rend=latestHeadRev(); + } + + if (_rend==svn::Revision::HEAD||_rend.revnum()>_latest.revnum()) { + LogEntriesMap _internal; +// qDebug("Retrieving from network."); + if (!m_Client->log(m_ReposRoot,_rstart,_rend,_internal,svn::Revision::UNDEFINED,true,false)) { + return false; + } + LogEntriesMap::ConstIterator it=_internal.begin(); + + for (;it!=_internal.end();++it) { + _insertLogEntry((*it)); + if (cp && cp->getListener()) { + //cp->getListener()->contextProgress(++icount,_internal.size()); + if (cp->getListener()->contextCancel()) { + throw DatabaseException(QString("Could not retrieve values: User cancel.")); + } + } + } + } + return true; +} + +bool svn::cache::ReposLog::fillCache(const svn::Revision&_end) +{ + svn::Revision end = _end; + svn::Revision start = latestCachedRev().revnum()+1; + return checkFill(start,end,false); +} + +/*! + \fn svn::cache::ReposLog::simpleLog(const svn::Revision&start,const svn::Revision&end,LogEntriesMap&target) + */ +bool svn::cache::ReposLog::simpleLog(LogEntriesMap&target,const svn::Revision&_start,const svn::Revision&_end,bool noNetwork) +{ + if (!m_Client||m_ReposRoot.isEmpty()) { + return false; + } + target.clear(); + ContextP cp = m_Client->getContext(); + + svn::Revision end = _end; + svn::Revision start = _start; + if (!noNetwork) { + if (!checkFill(start,end,true)) { + return false; + } + } else { + end=date2numberRev(end,noNetwork); + start=date2numberRev(start,noNetwork); + } + + if (end==svn::Revision::HEAD) { + end = latestCachedRev(); + } + if (start==svn::Revision::HEAD) { + start=latestCachedRev(); + } + static QString sCount("select count(*) from logentries where revision<=? and revision>=?"); + static QString sEntry("select revision,author,date,message from logentries where revision<=? and revision>=?"); + static QString sItems("select changeditem,action,copyfrom,copyfromrev from changeditems where revision=?"); + + QSqlQuery bcount(QString::null,m_Database); + bcount.prepare(sCount); + + QSqlQuery bcur(QString::null,m_Database); + bcur.prepare(sEntry); + + QSqlQuery cur(QString::null,m_Database); + cur.prepare(sItems); + + bcount.bindValue(0,Q_LLONG(end.revnum())); + bcount.bindValue(1,Q_LLONG(start.revnum())); + if (!bcount.exec()) { + qDebug(bcount.lastError().text().TOUTF8().data()); + throw svn::cache::DatabaseException(QString("Could not retrieve count: ")+bcount.lastError().text()); + return false; + } + bcount.next(); + if (bcount.value(0).toLongLong()<1) { + // we didn't found logs with this parameters + return false; + } + + bcur.bindValue(0,Q_LLONG(end.revnum())); + bcur.bindValue(1,Q_LLONG(start.revnum())); + + if (!bcur.exec()) { + qDebug(bcur.lastError().text().TOUTF8().data()); + throw svn::cache::DatabaseException(QString("Could not retrieve values: ")+bcur.lastError().text()); + return false; + } + Q_LLONG revision; + while(bcur.next()) { + revision = bcur.value(0).toLongLong(); + cur.bindValue(0,revision); + if (!cur.exec()) { + qDebug(cur.lastError().text().TOUTF8().data()); + throw svn::cache::DatabaseException(QString("Could not retrieve values: ")+cur.lastError().text() + ,cur.lastError().number()); + return false; + } + target[revision].revision=revision; + target[revision].author=bcur.value(1).toString(); + target[revision].date=bcur.value(2).toLongLong(); + target[revision].message=bcur.value(3).toString(); + while(cur.next()) { + LogChangePathEntry lcp; + QString ac = cur.value(1).toString(); +#if QT_VERSION < 0x040000 + lcp.action=ac[0].latin1(); +#else + lcp.action=ac[0].toLatin1(); +#endif + lcp.copyFromPath=cur.value(2).toString(); + lcp.path= cur.value(0).toString(); + lcp.copyFromRevision=cur.value(3).toLongLong(); + target[revision].changedPaths.push_back(lcp); + } + if (cp && cp->getListener()) { + if (cp->getListener()->contextCancel()) { + throw svn::cache::DatabaseException(QString("Could not retrieve values: User cancel.")); + return false; + } + } + } + return true; +} + + +/*! + \fn svn::cache::ReposLog::date2numberRev(const svn::Revision&) + */ +svn::Revision svn::cache::ReposLog::date2numberRev(const svn::Revision&aRev,bool noNetwork) +{ + if (aRev!=svn::Revision::DATE) { + return aRev; + } +#if QT_VERSION < 0x040000 + if (!m_Database) { +#else + if (!m_Database.isValid()) { +#endif + return svn::Revision::UNDEFINED; + } + static QString _q("select revision from logentries where date<? order by revision desc"); + QSqlQuery query("select revision,date from logentries order by revision desc limit 1",m_Database); + +#if QT_VERSION < 0x040000 + if (query.lastError().type()!=QSqlError::None) { +#else + if (query.lastError().type()!=QSqlError::NoError) { +#endif + qDebug(query.lastError().text().TOUTF8().data()); + } + bool must_remote=!noNetwork; + if (query.next()) { + if (query.value(1).toLongLong()>=aRev.date()) { + must_remote=false; + } + } + if (must_remote) { + svn::InfoEntries e = (m_Client->info(m_ReposRoot,svn::DepthEmpty,aRev,aRev));; + if (e.count()<1||e[0].reposRoot().isEmpty()) { + return aRev; + } + return e[0].revision(); + } + query.prepare(_q); + query.bindValue(0,Q_LLONG(aRev.date())); + query.exec(); +#if QT_VERSION < 0x040000 + if (query.lastError().type()!=QSqlError::None) { +#else + if (query.lastError().type()!=QSqlError::NoError) { +#endif + qDebug(query.lastError().text().TOUTF8().data()); + } + if (query.next()) { + return query.value(0).toInt(); + } + // not found... + if (noNetwork) { + return svn::Revision::UNDEFINED; + } + svn::InfoEntries e = (m_Client->info(m_ReposRoot,svn::DepthEmpty,svn::Revision::HEAD,svn::Revision::HEAD));; + if (e.count()<1||e[0].reposRoot().isEmpty()) { + return svn::Revision::UNDEFINED; + } + return e[0].revision(); +} + + +/*! + \fn svn::cache::ReposLog::insertLogEntry(const svn::LogEntry&) + */ +bool svn::cache::ReposLog::_insertLogEntry(const svn::LogEntry&aEntry) +{ + QSqlRecord *buffer; + +#if QT_VERSION < 0x040000 + m_Database->transaction(); + Q_LLONG j = aEntry.revision; +#else + m_Database.transaction(); + qlonglong j = aEntry.revision; +#endif + static QString qEntry("insert into logentries (revision,date,author,message) values (?,?,?,?)"); + static QString qPathes("insert into changeditems (revision,changeditem,action,copyfrom,copyfromrev) values (?,?,?,?,?)"); + QSqlQuery _q(QString::null,m_Database); + _q.prepare(qEntry); + _q.bindValue(0,j); + _q.bindValue(1,aEntry.date); + _q.bindValue(2,aEntry.author); + _q.bindValue(3,aEntry.message); + if (!_q.exec()) { +#if QT_VERSION < 0x040000 + m_Database->rollback(); +#else + m_Database.rollback(); +#endif + qDebug("Could not insert values: %s",_q.lastError().text().TOUTF8().data()); + qDebug(_q.lastQuery().TOUTF8().data()); + throw svn::cache::DatabaseException(QString("Could not insert values: ")+_q.lastError().text(),_q.lastError().number()); + } + _q.prepare(qPathes); + svn::LogChangePathEntries::ConstIterator cpit = aEntry.changedPaths.begin(); + for (;cpit!=aEntry.changedPaths.end();++cpit){ + _q.bindValue(0,j); + _q.bindValue(1,(*cpit).path); + _q.bindValue(2,QString(QChar((*cpit).action))); + _q.bindValue(3,(*cpit).copyFromPath); + _q.bindValue(4,Q_LLONG((*cpit).copyFromRevision)); + if (!_q.exec()) { +#if QT_VERSION < 0x040000 + m_Database->rollback(); +#else + m_Database.rollback(); +#endif + qDebug("Could not insert values: %s",_q.lastError().text().TOUTF8().data()); + qDebug(_q.lastQuery().TOUTF8().data()); + throw svn::cache::DatabaseException(QString("Could not insert values: ")+_q.lastError().text(),_q.lastError().number()); + } + } +#if QT_VERSION < 0x040000 + m_Database->commit(); +#else + m_Database.commit(); +#endif + return true; +} + +bool svn::cache::ReposLog::insertLogEntry(const svn::LogEntry&aEntry) +{ + return _insertLogEntry(aEntry); +} + + +/*! + \fn svn::cache::ReposLog::log(const svn::Path&,const svn::Revision&start, const svn::Revision&end,const svn::Revision&peg,svn::LogEntriesMap&target, bool strictNodeHistory,int limit)) + */ +bool svn::cache::ReposLog::log(const svn::Path&what,const svn::Revision&_start, const svn::Revision&_end,const svn::Revision&_peg,svn::LogEntriesMap&target, bool strictNodeHistory,int limit) +{ + static QString s_q("select logentries.revision,logentries.author,logentries.date,logentries.message from logentries where logentries.revision in (select changeditems.revision from changeditems where (changeditems.changeditem='%1' or changeditems.changeditem GLOB '%2/*') %3 GROUP BY changeditems.revision) ORDER BY logentries.revision DESC"); + + static QString s_e("select changeditem,action,copyfrom,copyfromrev from changeditems where changeditems.revision='%1'"); + + svn::Revision peg = date2numberRev(_peg,true); + svn::Revision end = date2numberRev(_end,true); + svn::Revision start = date2numberRev(_start,true); + QString query_string = QString(s_q).arg(what.native()).arg(what.native()).arg((peg==svn::Revision::UNDEFINED?"":QString(" AND revision<=%1").arg(peg.revnum()))); + if (peg==svn::Revision::UNDEFINED) { + peg = latestCachedRev(); + } + if (!itemExists(peg,what)) { + throw svn::cache::DatabaseException(QString("Entry '%1' does not exists at revision %2").arg(what.native()).arg(peg.toString())); + } + if (limit>0) { + query_string+=QString(" LIMIT %1").arg(limit); + } + QSqlQuery _q(QString::null,m_Database); + QSqlQuery _q2(QString::null,m_Database); + _q.prepare(query_string); + if (!_q.exec()) { + qDebug("Could not select values: %s",_q.lastError().text().TOUTF8().data()); + qDebug(_q.lastQuery().TOUTF8().data()); + throw svn::cache::DatabaseException(QString("Could not select values: ")+_q.lastError().text(),_q.lastError().number()); + } + while(_q.next()) { + Q_LLONG revision = _q.value(0).toLongLong(); + target[revision].revision=revision; + target[revision].author=_q.value(1).toString(); + target[revision].date=_q.value(2).toLongLong(); + target[revision].message=_q.value(3).toString(); + query_string=s_e.arg(revision); + _q2.prepare(query_string); + if (!_q2.exec()) { + qDebug("Could not select values: %s",_q2.lastError().text().TOUTF8().data()); + } else { + while (_q2.next()) { +#if QT_VERSION < 0x040000 + target[revision].changedPaths.push_back ( + LogChangePathEntry (_q2.value(0).toString(), + _q2.value(1).toString()[0], + _q2.value(2).toString(), + _q2.value(3).toLongLong() + ) + ); +#else + target[revision].changedPaths.push_back ( + LogChangePathEntry (_q2.value(0).toString(), + _q2.value(1).toChar().toLatin1(), + _q2.value(2).toString(), + _q2.value(3).toLongLong() + ) + ); +#endif + } + } + + } + return true; +} + + +/*! + \fn svn::cache::ReposLog::itemExists(const svn::Revision&,const QString&) + */ +bool svn::cache::ReposLog::itemExists(const svn::Revision&peg,const svn::Path&path) +{ + /// @todo this moment I have no idea how to check real with all moves and deletes of parent folders without a hell of sql statements so we make it quite simple: it exists if we found it. + + +#if 0 + static QString _s1("select revision from changeditems where changeditem='%1' and action='A' and revision<=%2 order by revision desc limit 1"); + QSqlQuery _q(QString::null,m_Database); + QString query_string=QString(_s1).arg(path.native()).arg(peg.revnum()); + if (!_q.exec(query_string)) { + qDebug("Could not select values: %s",_q.lastError().text().TOUTF8().data()); + qDebug(_q.lastQuery().TOUTF8().data()); + throw svn::cache::DatabaseException(QString("Could not select values: ")+_q.lastError().text(),_q.lastError().number()); + } + qDebug(_q.lastQuery().TOUTF8().data()); + + + svn::Path _p = path; + static QString _s2("select revision from changeditem where changeditem in (%1) and action='D' and revision>%2 and revision<=%3 order by revision desc limit 1"); + QStringList p_list; + while (_p.length()>0) { + p_list.append(QString("'%1'").arg(_p.native())); + _p.removeLast(); + } + query_string=QString(_s2).arg(p_list.join(",")).arg(); +#endif + return true; +} + +bool svn::cache::ReposLog::isValid()const +{ +#if QT_VERSION < 0x040000 + if (!m_Database) { +#else + if (!m_Database.isValid()) { +#endif + m_Database = LogCache::self()->reposDb(m_ReposRoot); +#if QT_VERSION < 0x040000 + if (!m_Database) { +#else + if (!m_Database.isValid()) { +#endif + return false; + } + } + return true; +} diff --git a/src/svnqt/cache/ReposLog.hpp b/src/svnqt/cache/ReposLog.hpp new file mode 100644 index 0000000..e81a5c9 --- /dev/null +++ b/src/svnqt/cache/ReposLog.hpp @@ -0,0 +1,70 @@ +#ifndef _REPOS_LOG_HPP +#define _REPOS_LOG_HPP + +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/svnqttypes.hpp" +#include "svnqt/revision.hpp" + +#include <qsqldatabase.h> +#include <qstring.h> + +namespace svn +{ + +class Client; + +namespace cache +{ + +class SVNQT_EXPORT ReposLog +{ +protected: + svn::Client*m_Client; + mutable QDataBase m_Database; + QString m_ReposRoot; + svn::Revision m_latestHead; + //! internal insert. + bool _insertLogEntry(const svn::LogEntry&); + bool checkFill(svn::Revision&_start,svn::Revision&_end,bool checkHead); + +public: + ReposLog(svn::Client*aClient,const QString&aRepository=QString::null); + + QString ReposRoot() const + { + return m_ReposRoot; + } + + QDataBase Database() const + { + return m_Database; + } + //! search for latest head revision on network for assigned repository + svn::Revision latestHeadRev(); + //! return lates revision in cache + svn::Revision latestCachedRev(); + //! simple retrieves logentries + /*! + * This method acts on network, too for checking if there are new entries on server. + * + * @param target where to store the result + * @param start revision to start for search + * @param end revision to end for search + * @param noNetwork if yes, no check on network for newer revisions will made + * @return true if entries found and no error, if no entries found false + * @exception svn::DatabaseException in case of errors + */ + bool simpleLog(LogEntriesMap&target,const svn::Revision&start,const svn::Revision&end,bool noNetwork=false); + svn::Revision date2numberRev(const svn::Revision&,bool noNetwork=false); + bool fillCache(const svn::Revision&end); + bool insertLogEntry(const svn::LogEntry&); + bool log(const svn::Path&,const svn::Revision&start, const svn::Revision&end,const svn::Revision&peg,svn::LogEntriesMap&target, bool strictNodeHistory,int limit); + bool itemExists(const svn::Revision&,const svn::Path&); + + bool isValid()const; +}; + +} +} + +#endif diff --git a/src/svnqt/cache/sqlite3/README b/src/svnqt/cache/sqlite3/README new file mode 100644 index 0000000..e2f7914 --- /dev/null +++ b/src/svnqt/cache/sqlite3/README @@ -0,0 +1,32 @@ +With this driver you can access the files created by sqlite3 through +the standard Qt sql module. The driver name is QSQLITE3. + +Although there are many other solutions to access such DB files, I think +that using this driver has some advantages: + +--> You use the standard Qt interface so you can reuse exinting code or + switch to or from other DB types quite easily. + +--> Soft transition to Qt 4: Qt 4 supports sqlite3, you can prepare your + application now. + +--> The source of this driver is smaller than any other, you can incorporate + it on your application with little overhead and without requiring external + libraries. + + +Developer note: + +The driver is a merge between the QSQLITE driver in Qt 3 and in Qt 4 beta 1, with +small tweaks, so I think is quite stable and usable. +Please report success or failure, thanks + +To compile + +qmake +make +cp sqldrivers/libqsqlite3.so $QTDIR/plugins/sqldrivers (probably as root) + +use it as any other Qt sql driver. + +Have fun, Stefano !!!
\ No newline at end of file diff --git a/src/svnqt/cache/sqlite3/qsql_sqlite3.cpp b/src/svnqt/cache/sqlite3/qsql_sqlite3.cpp new file mode 100644 index 0000000..93010c1 --- /dev/null +++ b/src/svnqt/cache/sqlite3/qsql_sqlite3.cpp @@ -0,0 +1,485 @@ +/**************************************************************************** +** +** Implementation of SQLite driver classes. +** +** Copyright (C) 1992-2003 Trolltech AS. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** EDITIONS: FREE, ENTERPRISE +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include "qsql_sqlite3.h" + +#include <qdatetime.h> +#include <qvaluevector.h> +#include <qregexp.h> +#include <qfile.h> +#include <sqlite3.h> + +#if (QT_VERSION-0 < 0x030200) +# include <qvector.h> +# if !defined Q_WS_WIN32 +# include <unistd.h> +# endif +#else +# include <qptrvector.h> +# if !defined Q_WS_WIN32 +# include <unistd.h> +# endif +#endif + +typedef struct sqlite3_stmt sqlite3_stmt; + +#define QSQLITE3_DRIVER_NAME "QSQLITE3" + +static QVariant::Type qSqliteType(int tp) +{ + switch (tp) { + case SQLITE_INTEGER: + return QVariant::Int; + case SQLITE_FLOAT: + return QVariant::Double; + case SQLITE_BLOB: + return QVariant::ByteArray; + case SQLITE_TEXT: + default: + return QVariant::String; + } +} + +static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::Type type, + int errorCode = -1) +{ + return QSqlError(descr, + QString::fromUtf8(sqlite3_errmsg(access)), + type, errorCode); +} + +class QSQLite3DriverPrivate +{ +public: + QSQLite3DriverPrivate(); + sqlite3 *access; + bool utf8; +}; + +QSQLite3DriverPrivate::QSQLite3DriverPrivate() : access(0) +{ + utf8 = true; +} + +class QSQLite3ResultPrivate +{ +public: + QSQLite3ResultPrivate(QSQLite3Result *res); + void cleanup(); + bool fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch); + bool isSelect(); + // initializes the recordInfo and the cache + void initColumns(); + void finalize(); + + QSQLite3Result* q; + sqlite3 *access; + + sqlite3_stmt *stmt; + + uint skippedStatus: 1; // the status of the fetchNext() that's skipped + uint skipRow: 1; // skip the next fetchNext()? + uint utf8: 1; + QSqlRecord rInf; +}; + +static const uint initial_cache_size = 128; + +QSQLite3ResultPrivate::QSQLite3ResultPrivate(QSQLite3Result* res) : q(res), access(0), + stmt(0), skippedStatus(false), skipRow(false), utf8(false) +{ +} + +void QSQLite3ResultPrivate::cleanup() +{ + finalize(); + rInf.clear(); + skippedStatus = false; + skipRow = false; + q->setAt(QSql::BeforeFirst); + q->setActive(false); + q->cleanup(); +} + +void QSQLite3ResultPrivate::finalize() +{ + if (!stmt) + return; + + sqlite3_finalize(stmt); + stmt = 0; +} + +// called on first fetch +void QSQLite3ResultPrivate::initColumns() +{ + rInf.clear(); + + int nCols = sqlite3_column_count(stmt); + if (nCols <= 0) + return; + + q->init(nCols); + + for (int i = 0; i < nCols; ++i) { + QString colName = QString::fromUtf8(sqlite3_column_name(stmt, i)); + + int dotIdx = colName.findRev('.'); + rInf.append(QSqlField(colName.mid(dotIdx == -1 ? 0 : dotIdx + 1), + qSqliteType(sqlite3_column_type(stmt, i)))); + } +} + +bool QSQLite3ResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch) +{ + int res; + unsigned int i; + + if (skipRow) { + // already fetched + Q_ASSERT(!initialFetch); + skipRow = false; + return skippedStatus; + } + skipRow = initialFetch; + + if (!stmt) + return false; + + // keep trying while busy, wish I could implement this better. + while ((res = sqlite3_step(stmt)) == SQLITE_BUSY) { + // sleep instead requesting result again immidiately. +#if defined Q_OS_WIN + Sleep(1000); +#else + sleep(1); +#endif + } + + switch(res) { + case SQLITE_ROW: + // check to see if should fill out columns + if (rInf.isEmpty()) + // must be first call. + initColumns(); + if (idx < 0 && !initialFetch) + return true; + for (i = 0; i < rInf.count(); ++i) + // todo - handle other types + values[i + idx] = QString::fromUtf8((char *)(sqlite3_column_text(stmt, i))); + // values[i + idx] = utf8 ? QString::fromUtf8(fvals[i]) : QString::fromAscii(fvals[i]); + return true; + case SQLITE_DONE: + if (rInf.isEmpty()) + // must be first call. + initColumns(); + q->setAt(QSql::AfterLast); + return false; + case SQLITE_ERROR: + case SQLITE_MISUSE: + default: + // something wrong, don't get col info, but still return false + q->setLastError(qMakeError(access, "Unable to fetch row", QSqlError::Connection, res)); + finalize(); + q->setAt(QSql::AfterLast); + return false; + } + return false; +} + +QSQLite3Result::QSQLite3Result(const QSQLite3Driver* db) + : QSqlCachedResult(db) +{ + d = new QSQLite3ResultPrivate(this); + d->access = db->d->access; +} + +QSQLite3Result::~QSQLite3Result() +{ + d->cleanup(); + delete d; +} + +/* + Execute \a query. +*/ +bool QSQLite3Result::reset (const QString &query) +{ + // this is where we build a query. + if (!driver() || !driver()->isOpen() || driver()->isOpenError()) + return false; + + d->cleanup(); + + setSelect(false); + + int res = sqlite3_prepare(d->access, query.utf8().data(), (query.length() + 1) * sizeof(QChar), + &d->stmt, 0); + + if (res != SQLITE_OK) { + setLastError(qMakeError(d->access, "Unable to execute statement", QSqlError::Statement, res)); + d->finalize(); + return false; + } + + d->skippedStatus = d->fetchNext(cache(), 0, true); + + setSelect(!d->rInf.isEmpty()); + setActive(true); + return true; +} + +bool QSQLite3Result::gotoNext(QSqlCachedResult::ValueCache& row, int idx) +{ + return d->fetchNext(row, idx, false); +} + +int QSQLite3Result::size() +{ + return -1; +} + +int QSQLite3Result::numRowsAffected() +{ + return sqlite3_changes(d->access); +} + +///////////////////////////////////////////////////////// + +QSQLite3Driver::QSQLite3Driver(QObject * parent, const char *name) + : QSqlDriver(parent, name) +{ + d = new QSQLite3DriverPrivate(); +} + +QSQLite3Driver::QSQLite3Driver(sqlite3 *connection, QObject *parent, const char *name) + : QSqlDriver(parent, name) +{ + d = new QSQLite3DriverPrivate(); + d->access = connection; + setOpen(true); + setOpenError(false); +} + + +QSQLite3Driver::~QSQLite3Driver() +{ + delete d; +} + +bool QSQLite3Driver::hasFeature(DriverFeature f) const +{ + switch (f) { + case Transactions: + case Unicode: + case BLOB: + return true; + default: + break; + } + return false; +} + +/* + SQLite dbs have no user name, passwords, hosts or ports. + just file names. +*/ +bool QSQLite3Driver::open(const QString & db, const QString &, const QString &, const QString &, int, const QString &) +{ + if (isOpen()) + close(); + + if (db.isEmpty()) + return false; + + if (sqlite3_open(QFile::encodeName(db), &d->access) == SQLITE_OK) { + setOpen(true); + setOpenError(false); + return true; + } else { + setLastError(qMakeError(d->access, "Error opening database", + QSqlError::Connection)); + setOpenError(true); + return false; + } +} + +void QSQLite3Driver::close() +{ + if (isOpen()) { + if (sqlite3_close(d->access) != SQLITE_OK) + setLastError(qMakeError(d->access, "Error closing database", + QSqlError::Connection)); + d->access = 0; + setOpen(false); + setOpenError(false); + } +} + +QSqlQuery QSQLite3Driver::createQuery() const +{ + return QSqlQuery(new QSQLite3Result(this)); +} + +bool QSQLite3Driver::beginTransaction() +{ + if (!isOpen() || isOpenError()) + return false; + + QSqlQuery q(createQuery()); + if (!q.exec("BEGIN")) { + setLastError(QSqlError("Unable to begin transaction", + q.lastError().databaseText(), QSqlError::Transaction)); + return false; + } + + return true; +} + +bool QSQLite3Driver::commitTransaction() +{ + if (!isOpen() || isOpenError()) + return false; + + QSqlQuery q(createQuery()); + if (!q.exec("COMMIT")) { + setLastError(QSqlError("Unable to begin transaction", + q.lastError().databaseText(), QSqlError::Transaction)); + return false; + } + + return true; +} + +bool QSQLite3Driver::rollbackTransaction() +{ + if (!isOpen() || isOpenError()) + return false; + + QSqlQuery q(createQuery()); + if (!q.exec("ROLLBACK")) { + setLastError(QSqlError("Unable to begin transaction", + q.lastError().databaseText(), QSqlError::Transaction)); + return false; + } + + return true; +} + +QStringList QSQLite3Driver::tables(const QString &typeName) const +{ + QStringList res; + if (!isOpen()) + return res; + int type = typeName.toInt(); + + QSqlQuery q = createQuery(); + q.setForwardOnly(TRUE); +#if (QT_VERSION-0 >= 0x030200) + if ((type & (int)QSql::Tables) && (type & (int)QSql::Views)) + q.exec("SELECT name FROM sqlite_master WHERE type='table' OR type='view'"); + else if (typeName.isEmpty() || (type & (int)QSql::Tables)) + q.exec("SELECT name FROM sqlite_master WHERE type='table'"); + else if (type & (int)QSql::Views) + q.exec("SELECT name FROM sqlite_master WHERE type='view'"); +#else + q.exec("SELECT name FROM sqlite_master WHERE type='table' OR type='view'"); +#endif + + + if (q.isActive()) { + while(q.next()) + res.append(q.value(0).toString()); + } + +#if (QT_VERSION-0 >= 0x030200) + if (type & (int)QSql::SystemTables) { + // there are no internal tables beside this one: + res.append("sqlite_master"); + } +#endif + + return res; +} + +QSqlIndex QSQLite3Driver::primaryIndex(const QString &tblname) const +{ + QSqlRecordInfo rec(recordInfo(tblname)); // expensive :( + + if (!isOpen()) + return QSqlIndex(); + + QSqlQuery q = createQuery(); + q.setForwardOnly(TRUE); + // finrst find a UNIQUE INDEX + q.exec("PRAGMA index_list('" + tblname + "');"); + QString indexname; + while(q.next()) { + if (q.value(2).toInt()==1) { + indexname = q.value(1).toString(); + break; + } + } + if (indexname.isEmpty()) + return QSqlIndex(); + + q.exec("PRAGMA index_info('" + indexname + "');"); + + QSqlIndex index(indexname); + while(q.next()) { + QString name = q.value(2).toString(); + QSqlVariant::Type type = QSqlVariant::Invalid; + if (rec.contains(name)) + type = rec.find(name).type(); + index.append(QSqlField(name, type)); + } + return index; +} + +QSqlRecordInfo QSQLite3Driver::recordInfo(const QString &tbl) const +{ + if (!isOpen()) + return QSqlRecordInfo(); + + QSqlQuery q = createQuery(); + q.setForwardOnly(TRUE); + q.exec("SELECT * FROM " + tbl + " LIMIT 1"); + return recordInfo(q); +} + +QSqlRecord QSQLite3Driver::record(const QString &tblname) const +{ + if (!isOpen()) + return QSqlRecord(); + + return recordInfo(tblname).toRecord(); +} + +QSqlRecord QSQLite3Driver::record(const QSqlQuery& query) const +{ + if (query.isActive() && query.driver() == this) { + QSQLite3Result* result = (QSQLite3Result*)query.result(); + return result->d->rInf; + } + return QSqlRecord(); +} + +QSqlRecordInfo QSQLite3Driver::recordInfo(const QSqlQuery& query) const +{ + if (query.isActive() && query.driver() == this) { + QSQLite3Result* result = (QSQLite3Result*)query.result(); + return QSqlRecordInfo(result->d->rInf); + } + return QSqlRecordInfo(); +} diff --git a/src/svnqt/cache/sqlite3/qsql_sqlite3.h b/src/svnqt/cache/sqlite3/qsql_sqlite3.h new file mode 100644 index 0000000..f89c038 --- /dev/null +++ b/src/svnqt/cache/sqlite3/qsql_sqlite3.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Definition of SQLite driver classes. +** +** Copyright (C) 1992-2003 Trolltech AS. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** EDITIONS: FREE, ENTERPRISE +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef QSQL_SQLITE3_H +#define QSQL_SQLITE3_H + +#include <qsqldriver.h> +#include <qsqlresult.h> +#include <qsqlrecord.h> +#include <qsqlindex.h> +#include "qsqlcachedresult.h" + +#if (QT_VERSION-0 >= 0x030200) +typedef QVariant QSqlVariant; +#endif + +#if defined (Q_OS_WIN32) +# include <qt_windows.h> +#endif + +class QSQLite3DriverPrivate; +class QSQLite3ResultPrivate; +class QSQLite3Driver; +struct sqlite3; + +class QSQLite3Result : public QSqlCachedResult +{ + friend class QSQLite3Driver; + friend class QSQLite3ResultPrivate; +public: + QSQLite3Result(const QSQLite3Driver* db); + ~QSQLite3Result(); + +protected: + bool gotoNext(QSqlCachedResult::ValueCache& row, int idx); + bool reset (const QString& query); + int size(); + int numRowsAffected(); + +private: + QSQLite3ResultPrivate* d; +}; + +class QSQLite3Driver : public QSqlDriver +{ + friend class QSQLite3Result; +public: + QSQLite3Driver(QObject *parent = 0, const char *name = 0); + QSQLite3Driver(sqlite3 *connection, QObject *parent = 0, const char *name = 0); + ~QSQLite3Driver(); + bool hasFeature(DriverFeature f) const; + bool open(const QString & db, + const QString & user, + const QString & password, + const QString & host, + int port, + const QString & connOpts); + bool open( const QString & db, + const QString & user, + const QString & password, + const QString & host, + int port ) { return open (db, user, password, host, port, QString()); } + void close(); + QSqlQuery createQuery() const; + bool beginTransaction(); + bool commitTransaction(); + bool rollbackTransaction(); + QStringList tables(const QString &user) const; + + QSqlRecord record(const QString& tablename) const; + QSqlRecordInfo recordInfo(const QString& tablename) const; + QSqlIndex primaryIndex(const QString &table) const; + QSqlRecord record(const QSqlQuery& query) const; + QSqlRecordInfo recordInfo(const QSqlQuery& query) const; + +private: + QSQLite3DriverPrivate* d; +}; +#endif diff --git a/src/svnqt/cache/sqlite3/qsqlcachedresult.cpp b/src/svnqt/cache/sqlite3/qsqlcachedresult.cpp new file mode 100644 index 0000000..8a23183 --- /dev/null +++ b/src/svnqt/cache/sqlite3/qsqlcachedresult.cpp @@ -0,0 +1,260 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2005 Trolltech AS. All rights reserved. +** +** This file is part of the sql module of the Qt Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include "qsqlcachedresult.h" + +#include <qvariant.h> +#include <qdatetime.h> +#include <qvaluevector.h> + +static const uint initial_cache_size = 128; + +class QSqlCachedResultPrivate +{ +public: + QSqlCachedResultPrivate(); + bool canSeek(int i) const; + inline int cacheCount() const; + void init(int count, bool fo); + void cleanup(); + int nextIndex(); + void revertLast(); + + QSqlCachedResult::ValueCache cache; + int rowCacheEnd; + int colCount; + bool forwardOnly; +}; + +QSqlCachedResultPrivate::QSqlCachedResultPrivate(): + rowCacheEnd(0), colCount(0), forwardOnly(false) +{ +} + +void QSqlCachedResultPrivate::cleanup() +{ + cache.clear(); + forwardOnly = false; + colCount = 0; + rowCacheEnd = 0; +} + +void QSqlCachedResultPrivate::init(int count, bool fo) +{ + Q_ASSERT(count); + cleanup(); + forwardOnly = fo; + colCount = count; + if (fo) { + cache.resize(count); + rowCacheEnd = count; + } else { + cache.resize(initial_cache_size * count); + } +} + +int QSqlCachedResultPrivate::nextIndex() +{ + if (forwardOnly) + return 0; + int newIdx = rowCacheEnd; + if (rowCacheEnd == (int)cache.size()) + cache.resize(cache.size() * 2); +/* if (newIdx + colCount > cache.size()){ + if(cache.size() * 2 < cache.size() + 10000) + cache.resize(cache.size() * 2); + else + cache.resize(cache.size() + 10000); + }*/ + rowCacheEnd += colCount; + + return newIdx; +} + +bool QSqlCachedResultPrivate::canSeek(int i) const +{ + if (forwardOnly || i < 0) + return false; + return rowCacheEnd >= (i + 1) * colCount; +} + +void QSqlCachedResultPrivate::revertLast() +{ + if (forwardOnly) + return; + rowCacheEnd -= colCount; +} + +inline int QSqlCachedResultPrivate::cacheCount() const +{ + Q_ASSERT(!forwardOnly); + Q_ASSERT(colCount); + return rowCacheEnd / colCount; +} + +////////////// + +QSqlCachedResult::QSqlCachedResult(const QSqlDriver * db): QSqlResult (db) +{ + d = new QSqlCachedResultPrivate(); +} + +QSqlCachedResult::~QSqlCachedResult() +{ + delete d; +} + +void QSqlCachedResult::init(int colCount) +{ + d->init(colCount, isForwardOnly()); +} + +bool QSqlCachedResult::fetch(int i) +{ + if ((!isActive()) || (i < 0)) + return false; + if (at() == i) + return true; + if (d->forwardOnly) { + // speed hack - do not copy values if not needed + if (at() > i || at() == QSql::AfterLast) + return false; + while(at() < i - 1) { + if (!gotoNext(d->cache, -1)) + return false; + setAt(at() + 1); + } + if (!gotoNext(d->cache, 0)) + return false; + setAt(at() + 1); + return true; + } + if (d->canSeek(i)) { + setAt(i); + return true; + } + if (d->rowCacheEnd > 0) + setAt(d->cacheCount()-1); + while (at() < i) { + if (!cacheNext()) + return false; + } + return true; +} + +bool QSqlCachedResult::fetchNext() +{ + if (d->canSeek(at() + 1)) { + setAt(at() + 1); + return true; + } + return cacheNext(); +} + +bool QSqlCachedResult::fetchPrevious() +{ + return fetch(at() - 1); +} + +bool QSqlCachedResult::fetchFirst() +{ + if (d->forwardOnly && at() != QSql::BeforeFirst) { + return false; + } + if (d->canSeek(0)) { + setAt(0); + return true; + } + return cacheNext(); +} + +bool QSqlCachedResult::fetchLast() +{ + if (at() == QSql::AfterLast) { + if (d->forwardOnly) + return false; + else + return fetch(d->cacheCount() - 1); + } + + int i = at(); + while (fetchNext()) + ++i; /* brute force */ + if (d->forwardOnly && at() == QSql::AfterLast) { + setAt(i); + return true; + } else { + return fetch(i); + } +} + +QVariant QSqlCachedResult::data(int i) +{ + int idx = d->forwardOnly ? i : at() * d->colCount + i; + if (i >= d->colCount || i < 0 || at() < 0 || idx >= d->rowCacheEnd) + return QVariant(); + + return d->cache.at(idx); +} + +bool QSqlCachedResult::isNull(int i) +{ + int idx = d->forwardOnly ? i : at() * d->colCount + i; + if (i > d->colCount || i < 0 || at() < 0 || idx >= d->rowCacheEnd) + return true; + + return d->cache.at(idx).isNull(); +} + +void QSqlCachedResult::cleanup() +{ + setAt(QSql::BeforeFirst); + setActive(false); + d->cleanup(); +} + +bool QSqlCachedResult::cacheNext() +{ + if (!gotoNext(d->cache, d->nextIndex())) { + d->revertLast(); + return false; + } + setAt(at() + 1); + return true; +} + +int QSqlCachedResult::colCount() const +{ + return d->colCount; +} + +QSqlCachedResult::ValueCache &QSqlCachedResult::cache() +{ + return d->cache; +} + diff --git a/src/svnqt/cache/sqlite3/qsqlcachedresult.h b/src/svnqt/cache/sqlite3/qsqlcachedresult.h new file mode 100644 index 0000000..fa8924f --- /dev/null +++ b/src/svnqt/cache/sqlite3/qsqlcachedresult.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2005 Trolltech AS. All rights reserved. +** +** This file is part of the sql module of the Qt Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef QSQLCACHEDRESULT_P_H +#define QSQLCACHEDRESULT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qsqlresult.h> + +class QVariant; +template <typename T> class QValueVector; + +class QSqlCachedResultPrivate; + +class QM_EXPORT_SQL QSqlCachedResult: public QSqlResult +{ +public: + virtual ~QSqlCachedResult(); + + typedef QValueVector<QVariant> ValueCache; + +protected: + QSqlCachedResult(const QSqlDriver * db); + + void init(int colCount); + void cleanup(); + + virtual bool gotoNext(ValueCache &values, int index) = 0; + + QVariant data(int i); + bool isNull(int i); + bool fetch(int i); + bool fetchNext(); + bool fetchPrevious(); + bool fetchFirst(); + bool fetchLast(); + + int colCount() const; + ValueCache &cache(); + +private: + bool cacheNext(); + QSqlCachedResultPrivate *d; +}; + +#endif // QSQLCACHEDRESULT_P_H diff --git a/src/svnqt/cache/test/CMakeLists.txt b/src/svnqt/cache/test/CMakeLists.txt new file mode 100644 index 0000000..ecc6130 --- /dev/null +++ b/src/svnqt/cache/test/CMakeLists.txt @@ -0,0 +1,19 @@ +SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + +MACRO(BUILD_TEST tname) + SET(${tname}-src ${tname}.cpp) + IF (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${tname}.h) + SET(${tname}-src ${${tname}-src} ${tname}.h) + ENDIF (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${tname}.h) + ADD_EXECUTABLE(${tname} ${${tname}-src}) + TARGET_LINK_LIBRARIES(${tname} ${svnqt-name} ${QT_LIBRARIES}) + ADD_TEST(${tname} ${CMAKE_CURRENT_BINARY_DIR}/${tname}) +ENDMACRO(BUILD_TEST) + +IF (BUILD_TESTS) + CONFIGURE_FILE( + ${CMAKE_CURRENT_SOURCE_DIR}/testconfig.h.in + ${CMAKE_CURRENT_BINARY_DIR}/testconfig.h + ) + BUILD_TEST(sqlite) +ENDIF(BUILD_TESTS) diff --git a/src/svnqt/cache/test/sqlite.cpp b/src/svnqt/cache/test/sqlite.cpp new file mode 100644 index 0000000..4f14b2d --- /dev/null +++ b/src/svnqt/cache/test/sqlite.cpp @@ -0,0 +1,111 @@ +#include <qsql.h> +#include <qsqldatabase.h> +#include <qstringlist.h> +#include <iostream> +#include <qapplication.h> +#include <qtextstream.h> + +#include "svnqt/client.hpp" +#include "svnqt/svnqttypes.hpp" +#include "svnqt/log_entry.hpp" + +#include "svnqt/cache/LogCache.hpp" +#include "svnqt/cache/ReposLog.hpp" +#include "svnqt/cache/test/testconfig.h" +#include "svnqt/cache/DatabaseException.hpp" + +#if QT_VERSION < 0x040000 +#else +#include <QSqlQuery> +#include <QSqlError> +#endif + +int main(int argc,char**argv) +{ + QApplication app(argc,argv); + + svn::ContextP m_CurrentContext; + svn::Client* m_Svnclient; + m_Svnclient=svn::Client::getobject(0,0); + m_CurrentContext = new svn::Context(); + + m_Svnclient->setContext(m_CurrentContext); + + QStringList list; + QStringList::Iterator it; + // goes into "self" of logcache + new svn::cache::LogCache(TESTDBPATH); + list = QSqlDatabase::drivers(); + it = list.begin(); + while( it != list.end() ) { + std::cout << (*it).TOUTF8().data() << std::endl; + ++it; + } + svn::cache::ReposLog rl(m_Svnclient,"http://www.alwins-world.de/repos/kdesvn"); + QDataBase db = rl.Database(); +#if QT_VERSION < 0x040000 + if (!db) { +#else + if (!db.isValid()) { +#endif + std::cerr << "No database object."<<std::endl; + exit(-1); + } +#if QT_VERSION < 0x040000 + list = db->tables(); +#else + list = db.tables(); +#endif + it = list.begin(); + while( it != list.end() ) { + std::cout << ( *it ).TOUTF8().data() << std::endl; + ++it; + } + svn::LogEntriesMap lm; + try { + rl.simpleLog(lm,100,svn::Revision::HEAD); + } + catch (const svn::cache::DatabaseException&cl) + { + std::cerr << cl.msg().TOUTF8().data() <<std::endl; + } + catch (const svn::Exception&ce) + { + std::cerr << "Exception: " << ce.msg().TOUTF8().data() <<std::endl; + } + svn::LogEntriesMap::ConstIterator lit = lm.begin(); + std::cout<<"Count: "<<lm.count()<<std::endl; + + svn::Revision r("{2006-09-27}"); + std::cout << r.toString().TOUTF8().data() << " -> " << rl.date2numberRev(r).toString().TOUTF8().data()<<std::endl; + r = svn::Revision::HEAD; + std::cout << rl.date2numberRev(r).toString().TOUTF8().data()<<std::endl; + try { + rl.insertLogEntry(lm[100]); + } + catch (const svn::cache::DatabaseException&cl) + { + std::cerr << cl.msg().TOUTF8().data() << std::endl; + } + QSqlQuery q("insert into logentries(revision,date,author,message) values ('100','1122591406','alwin','copy and moving works now in basic form')",db); + q.exec(); + std::cerr << "\n" << q.lastError().text().TOUTF8().data()<<std::endl; + +#if QT_VERSION < 0x040000 +#else + db=QSqlDatabase(); +#endif + try { + rl.log("/trunk/src/svnqt",1,1000,svn::Revision::UNDEFINED,lm,false,-1); + } + catch (const svn::cache::DatabaseException&cl) + { + std::cerr << cl.msg().TOUTF8().data() <<std::endl; + } + catch (const svn::Exception&ce) + { + std::cerr << "Exception: " << ce.msg().TOUTF8().data() <<std::endl; + } + std::cout<<"Count: "<<lm.count()<<std::endl; + return 0; +} diff --git a/src/svnqt/cache/test/testconfig.h.in b/src/svnqt/cache/test/testconfig.h.in new file mode 100644 index 0000000..865ac6e --- /dev/null +++ b/src/svnqt/cache/test/testconfig.h.in @@ -0,0 +1,8 @@ +#ifndef __TEST_CONFIG_H +#define __TEST_CONFIG_H + +#define TESTREPOPATH "@CMAKE_CURRENT_BINARY_DIR@/repo" +#define TESTCOPATH "@CMAKE_CURRENT_BINARY_DIR@/co" +#define TESTDBPATH "@CMAKE_CURRENT_BINARY_DIR@/db" + +#endif diff --git a/src/svnqt/check.hpp b/src/svnqt/check.hpp new file mode 100644 index 0000000..0c6a340 --- /dev/null +++ b/src/svnqt/check.hpp @@ -0,0 +1,50 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_CHECK_HPP_ +#define _SVNCPP_CHECK_HPP_ + +// subversion api +#include "svn_version.h" + +/** + * Check if the current version of the subversion + * API is at least major.minor + */ +#define CHECK_SVN_VERSION (major,minor) \ + (SVN_VER_MAJOR > (major) || \ + (SVN_VER_MAJOR == (major) && SVN_VER_MINOR > (minor)) + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/client.cpp b/src/svnqt/client.cpp new file mode 100644 index 0000000..d78c416 --- /dev/null +++ b/src/svnqt/client.cpp @@ -0,0 +1,104 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ +#if defined( _MSC_VER) && _MSC_VER <= 1550 +#pragma warning( disable: 4786 )// debug symbol truncated +#endif + +// svncpp +#include "svnqt/client.hpp" +#include "svnqt/client_impl.hpp" +#include "svnqt/svnqt_defines.hpp" + +#include "svn_opt.h" + +#include <svn_cmdline.h> + +#include <qstringlist.h> +#include <qdir.h> + +namespace svn +{ + //! this namespace contains only internal stuff not for public use + namespace internal { + //! small helper class + /*! + There will be an static instance created for calling the constructor at program load. + */ + class SvnInit + { + public: + //! constructor calling initialize functions + SvnInit(); + ~SvnInit(){}; + }; + + SvnInit::SvnInit() { + svn_cmdline_init("svnqt",0); + qDebug("svn_cmdline_init done"); + QString BasePath=QDir::HOMEDIR(); + QDir d; + if (!d.exists(BasePath)) { + d.mkdir(BasePath); + } + BasePath=BasePath+"/"+".svnqt"; + if (!d.exists(BasePath)) { + d.mkdir(BasePath); + } + + } + } + + Client::Client() + { + } + + Client::~Client () + { + } + + Client*Client::getobject(ContextP context,int subtype) + { + static internal::SvnInit sInit; + switch(subtype) { + case 0: + return new Client_impl(context); + break; + default: + break; + } + return 0L; + } +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/client.hpp b/src/svnqt/client.hpp new file mode 100644 index 0000000..622c0be --- /dev/null +++ b/src/svnqt/client.hpp @@ -0,0 +1,882 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_CLIENT_H_ +#define _SVNCPP_CLIENT_H_ + +// Ignore MSVC 6 compiler warning: debug symbol truncated +#if defined (_MSC_VER) && _MSC_VER <= 1200 +#pragma warning (disable: 4786) +#endif + +// Ignore MSVC 7, 2005 & 2008 compiler warning: C++ exception specification +#if defined (_MSC_VER) && _MSC_VER > 1200 && _MSC_VER <= 1550 +#pragma warning (disable: 4290) +#endif + +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/svnqttypes.hpp" +#include "svnqt/svnstream.hpp" + +// qt +#include <qglobal.h> + +#if QT_VERSION < 0x040000 + #include <qstring.h> + #include <qpair.h> + #include <qvaluelist.h> + #include <qmap.h> +#else + #include <QtCore> +#endif + +// svnqt +#include "svnqt/context.hpp" +#include "svnqt/exception.hpp" +#include "svnqt/path.hpp" +#include "svnqt/entry.hpp" +#include "svnqt/revision.hpp" +#include "svnqt/log_entry.hpp" +#include "svnqt/info_entry.hpp" +#include "svnqt/annotate_line.hpp" +#include "svnqt/stringarray.hpp" +#include "svnqt/diffoptions.hpp" +#include "svnqt/conflictresult.hpp" + +class QStringList; + +namespace svn +{ + /** Subversion client API. + * + * Never use an object of this as global static! This will make problems with subversion + * initialize. + */ + class SVNQT_EXPORT Client + { + public: + + /** + * Initializes the primary memory pool. + */ + Client(); + + virtual ~Client (); + + + /** + * @return returns the Client context + */ + virtual const ContextP + getContext () const = 0; + + /** + * sets the client context + * you have to make sure the old context + * is de-allocated + * + * @param context new context to use + */ + virtual void + setContext (ContextP context) = 0; + + /** + * get a real instance. Result must cleaned with delete. + * \param context The context to use + * \param subtype the wanted implementation - this moment only 0 allowed. + * \return an instance of client or 0L if error. + */ + static Client*getobject(ContextP context,int subtype=0); + + /** + * Enumerates all files/dirs at a given path. + * + * Throws an exception if an error occurs + * + * @param path Path to explore. + * @param descend Recurse into subdirectories if existant. + * @param get_all Return all entries, not just the interesting ones. + * @param update Query the repository for updates. + * @param no_ignore Disregard default and svn:ignore property ignores. + * @param hide_externals don't recurse into external definitions + * @param revision list specific revision when browsing remote, on working copies parameter will ignored + * @param detailed_remote if on remote listing detailed item info should get if possible + * that may slow so should configureable in frontends! + * @return vector with Status entries. + */ + virtual StatusEntries + status (const Path& path, + Depth depth=DepthImmediates, + bool get_all = true, + bool update = false, + bool no_ignore = false, + const Revision revision = svn::Revision::HEAD, + bool detailed_remote = false, + bool hide_externals = false, + const StringArray & changelists=StringArray() ) throw (ClientException) = 0; + + /** + * Returns the status of a single file in the path. + * + * Throws an exception if an error occurs + * + * @param path File to gather status. + * @param update if check against repository if new updates are there (for WC only) + * @param revision list specific revision when browsing remote, on working copies parameter will ignored + * @return a Status with Statis.isVersioned = FALSE + */ + virtual StatusPtr + singleStatus (const Path& path,bool update=false,const Revision revision = svn::Revision::HEAD) throw (ClientException)=0; + + /** + * Executes a revision checkout. + * @param moduleName name of the module to checkout. + * @param destPath destination directory for checkout. + * @param revision the revision number to checkout. If the number is -1 + * then it will checkout the latest revision. + * @param peg Revision to look up + * @param recurse whether you want it to checkout files recursively. + * @param ignore_externals if true don't process externals definitions. + * @exception ClientException + */ + virtual svn_revnum_t + checkout (const Path& moduleName, const Path & destPath, + const Revision & revision, + const Revision & peg = Revision::UNDEFINED, + svn::Depth depth=DepthInfinity, + bool ignore_externals=false, + bool overwrite=false + ) throw (ClientException) = 0; + + /** + * relocate wc @a from to @a to + * @exception ClientException + */ + virtual void + relocate (const Path & path, const QString &from_url, + const QString &to_url, bool recurse) throw (ClientException)=0; + + /** + * Sets a single file for deletion. + * @exception ClientException + */ + virtual svn::Revision + remove (const Path & path, bool force, + bool keep_local = true, + const PropertiesMap&revProps = PropertiesMap()) throw (ClientException)=0; + + /** + * Sets files for deletion. + * + * @param targets targets to delete + * @param force force if files are locally modified + * @exception ClientException + */ + virtual svn::Revision + remove (const Targets & targets, + bool force, + bool keep_local=true, + const PropertiesMap&revProps=PropertiesMap()) throw (ClientException) = 0; + + /** + * Reverts a couple of files to a pristiner state. + * @exception ClientException + */ + virtual void + revert (const Targets & targets, + Depth depth, + const StringArray&changelist=StringArray() + ) throw (ClientException)=0; + + + /** + * Adds a file to the repository. + * @param path the path to add + * @param depth if @a path is a folder add items recursive depending on value if it. + * @param force if true, do not error on already-versioned items. + * @param no_ignore if false don't add files or directories that match ignore patterns. When build against svn 1.2 always false + * @param add_parents if true, go up to the next versioned folder and add all between path and this folder. + * @exception ClientException + */ + virtual void + add (const Path & path, svn::Depth depth,bool force=false, bool no_ignore=false, bool add_parents = true) throw (ClientException)=0; + + /** + * Updates the file or directory. + * @param path targets. + * @param revision the revision number to checkout. + * Revision::HEAD will checkout the + * latest revision. + * @param depth Depthness for operation + * @param ignore_externals ignore externals + * @param allow_unversioned will operation not fail if there are unversioned items in tree with same name. + * @exception ClientException + */ + virtual Revisions + update (const Targets & path, const Revision & revision, + Depth depth,bool ignore_externals,bool allow_unversioned, + bool sticky_depth) throw (ClientException) = 0; + + /** + * Retrieves the contents for a specific @a revision of + * a @a path at @a peg_revision + * + * @param path path of file or directory + * @param peg_revision revision to base the URL + * @param revision revision to retrieve + * @return contents of the file + */ + virtual QByteArray + cat (const Path & path, + const Revision & revision, + const Revision & peg_revision=svn_opt_revision_unspecified) throw (ClientException)=0; + /** + * Retrieves the contents for a specific @a revision of + * a @a path at @a peg_revision + * + * @param buffer Stream to store content direct + * @param path path of file or directory + * @param peg_revision revision to base the URL + * @param revision revision to retrieve + * @exception ClientException + */ + virtual void + cat(svn::stream::SvnStream&buffer, + const Path & path, + const Revision & revision, + const Revision & peg_revision) throw (ClientException)=0; + /** + * Retrieves the contents for a specific @a revision of + * a @a path at @a peg_revision + * + * @param path path of file or directory + * @param target new (local) name + * @param peg_revision revision to base the URL + * @param revision revision to retrieve + * @param peg_revision Revision to look at + */ + virtual void + get (const Path & path, + const QString & target, + const Revision & revision, + const Revision & peg_revision=svn_opt_revision_unspecified) throw (ClientException)=0; + + /** + * Retrieves the contents for a specific @a revision of + * a @a path and stores the result in @a target + * + * @param target the container where to store the result + * @param path path of file or directory + * @param revisionStart revision to retrieve + * @param revisionEnd revision to retrieve + * @param peg indicates in which revision path is valid + */ + virtual void + annotate (AnnotatedFile&target, + const Path & path, + const Revision & revisionStart, + const Revision & revisionEnd, + const Revision & peg = Revision::UNDEFINED, + const DiffOptions&diffoptions = DiffOptions(), + bool ignore_mimetypes = false, + bool include_merged_revisions = false + ) throw (ClientException)=0; + + /** + * Commits changes to the repository. This usually requires + * authentication, see Auth. + * @return Returns revision transferred or svn::Revision::UNDEFINED if the revision number is invalid. + * @param targets files to commit. + * @param message log message. + * @param depth whether the operation should be done recursively. + * @param keep_locks if false unlock items in paths + * @param changelist + * @param keep_changelist + * @exception ClientException + */ + virtual svn::Revision + commit (const Targets & targets, + const QString& message, + svn::Depth depth,bool keep_locks=true, + const svn::StringArray&contents=svn::StringArray(), + const PropertiesMap&revProps=PropertiesMap(), + bool keep_changelist=false + ) throw (ClientException)=0; + + /** + * Copies a versioned file with the history preserved. + * @exception ClientException + */ + virtual svn::Revision + copy (const Path & srcPath, + const Revision & srcRevision, + const Path & destPath) throw (ClientException)=0; + /** + * Copies a versioned file with the history preserved. + * @since subversion 1.5 api + * @see svn_client_copy4 + * @exception ClientException + */ + virtual svn::Revision + copy (const Targets & srcPath, + const Revision & srcRevision, + const Revision & pegRevision, + const Path & destPath, + bool asChild=false,bool makeParent=false,const PropertiesMap&revProps=PropertiesMap()) throw (ClientException)=0; + + /** + * Moves or renames a file. + * @exception ClientException + */ + virtual svn::Revision + move (const Path & srcPath, + const Path & destPath, + bool force) throw (ClientException)=0; + /** + * Moves or renames a file. + * @exception ClientException + */ + virtual svn::Revision + move (const Targets & srcPath, + const Path & destPath, + bool force,bool asChild,bool makeParent,const PropertiesMap&revProps=PropertiesMap()) throw (ClientException)=0; + + /** + * Creates a directory directly in a repository or creates a + * directory on disk and schedules it for addition. If <i>path</i> + * is a URL then authentication is usually required, see Auth and + * the callback asks for a logmessage. With subversion 1.4 the target + * must not exist (\sa svn_client_move4) + * + * @param path + * @param message log message. if it is QString::null asks when working on repository + * @param makeParent create parent folders if not existant (only when build with svn 1.5 or above) + * @exception ClientException + */ + virtual svn::Revision + mkdir (const Path & path, + const QString& message, + bool makeParent=true, + const PropertiesMap&revProps=PropertiesMap() + ) throw (ClientException)=0; + /** + * Creates a directory directly in a repository or creates a + * directory on disk and schedules it for addition. If <i>path</i> + * is a URL then authentication is usually required, see Auth and + * the callback asks for a logmessage. + * + * @param targets encoded pathes to create + * @param message log message. if it is QString::null asks when working on repository + * @param makeParent create parent folders if not existant (only when build with svn 1.5 or above) + * @exception ClientException + */ + virtual svn::Revision + mkdir (const Targets & targets, + const QString& message, + bool makeParent=true, + const PropertiesMap&revProps=PropertiesMap() + ) throw (ClientException)=0; + + /** + * Recursively cleans up a local directory, finishing any + * incomplete operations, removing lockfiles, etc. + * @param path a local directory. + * @exception ClientException + */ + virtual void + cleanup (const Path & path) throw (ClientException)=0; + + /** + * Removes the 'conflicted' state on a file. + * @exception ClientException + */ + virtual void resolve (const Path & path,Depth depth,const ConflictResult&resolution=ConflictResult()) throw (ClientException)=0; + + /** + * Exports the contents of either a subversion repository into a + * 'clean' directory (meaning a directory with no administrative + * directories). + * @exception ClientException + * @param srcPath source path + * @param destPath a destination path that must not already exist. + * @param revision revision to use for the export + * @param peg the revision where the path is first looked up when exporting from a repository. + * @param overwrite overwrite existing files + * @param native_eol Either "LF", "CR" or "CRLF" or NULL. + * @param ignore_externals don't process externals definitions as part of this operation. + * @param recurse if true, export recursively.<br> + Otherwise, export just the directory represented by from and its immediate non-directory children. + */ + virtual svn_revnum_t + doExport (const Path & srcPath, + const Path & destPath, + const Revision & revision, + const Revision & peg = Revision::UNDEFINED, + bool overwrite=false, + const QString&native_eol=QString::null, + bool ignore_externals = false, + svn::Depth depth=svn::DepthInfinity + ) throw (ClientException)=0; + + /** + * Update local copy to mirror a new url. This excapsulates the + * svn_client_switch() client method. + * @exception ClientException + */ + virtual svn_revnum_t + doSwitch ( + const Path & path, const QString& url, + const Revision & revision, + Depth depth, + const Revision & peg=Revision::UNDEFINED, + bool sticky_depth = true, + bool ignore_externals=false, + bool allow_unversioned=false + ) throw (ClientException)=0; + + /** + * Import file or directory PATH into repository directory URL at + * head. This usually requires authentication, see Auth. + * @param path path to import + * @param url + * @param message log message. + * @param depth kind of recurse operation + * @param no_ignore if false, don't add items matching global ignore pattern (@since subversion 1.3) + * @param no_unknown_nodetype if true ignore files type not known like pipes or device files (@since subversion 1.5) + * @exception ClientException + */ + virtual svn::Revision + import (const Path & path, const QString& url, + const QString& message, + svn::Depth depth, + bool no_ignore,bool no_unknown_nodetype, + const PropertiesMap&revProps=PropertiesMap()) throw (ClientException)=0; + + /** + * Merge changes from two paths into a new local path. + * @exception ClientException + */ + virtual void + merge (const Path & path1, const Revision & revision1, + const Path & path2, const Revision & revision2, + const Path & localPath, bool force, + Depth depth, + bool notice_ancestry=false, + bool dry_run=false, + bool record_only=false, + const StringArray&merge_options=StringArray() + ) throw (ClientException)=0; + + virtual void + merge_peg(const Path&src, + const RevisionRanges&ranges, + const Revision&peg, + const Path&targetWc, + Depth depth, + bool notice_ancestry=false, + bool dry_run=false, + bool force=false, + bool record_only=false, + const StringArray&merge_options=StringArray() + ) throw (ClientException)=0; + + virtual void + merge_peg(const Path&src, + const RevisionRange&range, + const Revision&peg, + const Path&targetWc, + Depth depth, + bool notice_ancestry=false, + bool dry_run=false, + bool force=false, + const StringArray&merge_options=StringArray() + ) throw (ClientException)=0; + + /** + * Retrieve information for the given path + * remote or local. + * + * @param path path for info + * @param rec recursive (if dir) + * @param rev for which revision + * @param peg_revision peg revision + * @return InfoEntries + */ + virtual InfoEntries + info (const Path &path, + Depth depth, + const Revision & rev, + const Revision & peg_revision=svn_opt_revision_unspecified, + const StringArray&changelists=StringArray() + ) throw (ClientException)=0; + + /** + * Retrieve log information for the given path + * Loads the log messages result set. The first + * entry is the youngest revision. + * + * You can use the constants Revision::START and + * Revision::HEAD + * + * @param path + * @param revisionStart + * @param revisionEnd + * @param discoverChangedPaths + * @param strictNodeHistory + * @param limit the maximum log entries count. + * @return a vector with log entries + */ + virtual LogEntriesPtr + log (const Path& path, + const Revision & revisionStart, + const Revision & revisionEnd, + const Revision & revisionPeg, + bool discoverChangedPaths=false, + bool strictNodeHistory=true,int limit = 0, + bool include_merged_revisions = false, + const StringArray&revprops=StringArray() + ) throw (ClientException)=0; + + /** + * Retrieve log information for the given path + * Loads the log messages result set. Result will stored + * in a map where the key is the revision number + * + * You can use the constants Revision::START and + * Revision::HEAD + * + * @param path Path to make a log for + * @param revisionStart + * @param revisionEnd + * @param target the logmap where to store the entries + * @param discoverChangedPaths + * @param strictNodeHistory + * @param limit (ignored when subversion 1.1 API) + * @return true if success + */ + virtual bool + log (const Path& path, const Revision & revisionStart, + const Revision & revisionEnd, + LogEntriesMap&target, + const Revision & revisionPeg=Revision::UNDEFINED, + bool discoverChangedPaths=false, + bool strictNodeHistory=true,int limit = 0, + bool include_merged_revisions = false, + const StringArray&revprops=StringArray() + ) throw (ClientException)=0; + + /** + * Produce diff output which describes the delta between + * @a path/@a revision1 and @a path/@a revision2. @a path + * can be either a working-copy path or a URL. + * + * A ClientException will be thrown if either @a revision1 or + * @a revision2 has an `unspecified' or unrecognized `kind'. + * + * @param tmpPath prefix for a temporary directory needed by diff. + * Filenames will have ".tmp" and similar added to this prefix in + * order to ensure uniqueness. + * @param path path of the file. + * @param revision1 one of the revisions to check. + * @param revision2 the other revision. + * @param recurse whether the operation should be done recursively. + * @param ignoreAncestry whether the files will be checked for + * relatedness. + * @param noDiffDeleted if true, no diff output will be generated on deleted files. + * @param ignore_contenttype if true generate diff even the items are marked as binaries + * @param extra extra options for diff ("-b", "-w","--ignore-eol-style") + * @return delta between the files + * @exception ClientException + */ + virtual QByteArray + diff_peg(const Path & tmpPath, const Path & path,const Path&relativeTo, + const Revision & revision1, const Revision & revision2, const Revision& peg_revision, + Depth depth, bool ignoreAncestry, + bool noDiffDeleted,bool ignore_contenttype, + const StringArray&extra, + const StringArray&changelists + ) throw (ClientException)=0; + + /** + * Same as other diff but extra options always set to empty list. + */ + virtual QByteArray + diff_peg (const Path & tmpPath, const Path & path,const Path&relativeTo, + const Revision & revision1, const Revision & revision2, const Revision& peg_revision, + Depth depth, bool ignoreAncestry, + bool noDiffDeleted,bool ignore_contenttype) throw (ClientException)=0; + + /** + * Produce diff output which describes the delta between + * @a path1/@a revision1 and @a path2/@a revision2. @a path2 + * can be either a working-copy path or a URL. + * + * A ClientException will be thrown if either @a revision1 or + * @a revision2 has an `unspecified' or unrecognized `kind'. + * + * @param tmpPath prefix for a temporary directory needed by diff. + * Filenames will have ".tmp" and similar added to this prefix in + * order to ensure uniqueness. + * @param path1 first file or folder to diff. + * @param path2 second file or folder to diff. + * @param revision1 one of the revisions to check (path1). + * @param revision2 the other revision (path2). + * @param recurse whether the operation should be done recursively. + * @param ignoreAncestry whether the files will be checked for + * relatedness. + * @param noDiffDeleted if true, no diff output will be generated on deleted files. + * @param ignore_contenttype if true generate diff even the items are marked as binaries + * @param extra extra options for diff ("-b", "-w","--ignore-eol-style") + * @return delta between the files + * @exception ClientException + */ + virtual QByteArray + diff (const Path & tmpPath, const Path & path1,const Path & path2,const Path&relativeTo, + const Revision & revision1, const Revision & revision2, + Depth depth, bool ignoreAncestry, + bool noDiffDeleted,bool ignore_contenttype, + const StringArray&extra, + const StringArray&changelists + ) throw (ClientException)=0; + + /** + * Same as other diff but extra options and changelists always set to empty list. + */ + virtual QByteArray + diff (const Path & tmpPath, const Path & path1,const Path & path2,const Path&relativeTo, + const Revision & revision1, const Revision & revision2, + Depth depth, bool ignoreAncestry, + bool noDiffDeleted,bool ignore_contenttype) throw (ClientException)=0; + + /** + * lists entries in @a pathOrUrl no matter whether local or + * repository + * + * If checking for locks is activated, it lists the locks inside repository, not locks inside + * working copy! + * @param pathOrUrl + * @param revision + * @param peg at wich revision path exists + * @param depth @sa depth + * @param retrieve_locks check for REPOSITORY locks while listing. + * @return a vector of directory entries, each with + * a relative path (only filename). In subversion >= 1.4 an entry without a name is returned, too. This + * is the searched directory (done in subversion itself) + */ + virtual DirEntries + list (const Path& pathOrUrl, + const Revision& revision, + const Revision& peg, + svn::Depth depth,bool retrieve_locks) throw (ClientException)=0; + + /** + * lists properties in @a path no matter whether local or + * repository + * + * @param path + * @param revision + * @param peg most case should set to @a revision + * @param recurse + * @return PropertiesList + */ + virtual PathPropertiesMapListPtr + proplist(const Path &path, + const Revision &revision, + const Revision &peg, + Depth depth=DepthEmpty, + const StringArray&changelists=StringArray() + )=0; + + /** + * lists one property in @a path no matter whether local or + * repository + * + * @param propName + * @param path + * @param revision + * @param peg most case should set to @a revision + * @param recurse + * @return PathPropertiesMapList and revision where the properties are taken from (svn 1.5) or undefined revision (prior 1.5) + */ + virtual QPair<QLONG,PathPropertiesMapList> + propget(const QString& propName, + const Path &path, + const Revision &revision, + const Revision &peg, + Depth depth = svn::DepthEmpty, + const StringArray&changelists=StringArray()) = 0; + + /** + * set property in @a path no matter whether local or + * repository + * + * @param path + * @param revision + * @param propName + * @param propValue + * @param recurse + * @param skip_checks if true skip validity checks + * @return PropertiesList + */ + virtual void + propset(const QString& propName, + const QString& propValue, + const Path &path, + Depth depth=DepthEmpty, + bool skip_checks=false, + const Revision&base_revision=Revision::UNDEFINED, + const StringArray&changelists=StringArray(), + const PropertiesMap&revProps=PropertiesMap() + ) = 0; + + /** + * delete property in @a path no matter whether local or + * repository + * + * @param propName + * @param path + * @param revision + * @param recurse + */ + virtual void + propdel(const QString& propName, + const Path &path, + Depth depth=DepthEmpty, + bool skip_check=false, + const Revision&base_revision=Revision::UNDEFINED, + const StringArray&changelists=StringArray())=0; + + + /** + * lists revision properties in @a path no matter whether local or + * repository + * + * @param path + * @param revision + * @return PropertiesList + */ + virtual QPair<QLONG,PropertiesMap> + revproplist(const Path &path, + const Revision &revision)=0; + + /** + * lists one revision property in @a path no matter whether local or + * repository + * + * @param propName + * @param path + * @param revision + * @return PropertiesList + */ + virtual QPair<QLONG,QString> + revpropget(const QString& propName, + const Path &path, + const Revision &revision)=0; + + /** + * set revision property in @a path no matter whether local or + * repository + * + * @param propName + * @param propValue + * @param path + * @param revision + * @param force + * @return Revision + */ + virtual QLONG + revpropset(const QString& propName, + const QString& propValue, + const Path &path, + const Revision &revision, + bool force=false)=0; + + /** + * delete revision property in @a path no matter whether local or + * repository + * + * @param propName + * @param path + * @param revision + * @param force + * @return Revision + */ + virtual QLONG + revpropdel(const QString& propName, + const Path &path, + const Revision &revision, + bool force=false) = 0; + + /** + * lock files in repository or working copy + * @param targets items to be locked + * @param message if non null stored with each lock in repository + * @param steal_lock if true locks in wc will stolen. + * @since subversion 1.2 + */ + virtual void + lock (const Targets & targets, + const QString& message, + bool steal_lock) throw (ClientException)=0; + /** + * unlock files in repository or working copy + * @param targets items to unlock + * @param break_lock ignore any errors + */ + virtual void + unlock (const Targets&targets, + bool break_lock) throw (ClientException)=0; + + virtual void + url2Revision(const QString&revstring, + Revision&start,Revision&end)=0; + virtual void + url2Revision(const QString&revstring, + Revision&start)=0; + + private: + /** + * disallow assignment operator + */ + Client & operator= (const Client &); + /** + * disallow copy constructor + */ + Client (const Client &); + }; + +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/client_annotate.cpp b/src/svnqt/client_annotate.cpp new file mode 100644 index 0000000..96bc92c --- /dev/null +++ b/src/svnqt/client_annotate.cpp @@ -0,0 +1,142 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ +#if defined( _MSC_VER) && _MSC_VER <= 1200 +#pragma warning( disable: 4786 )// debug symbol truncated +#endif +// svncpp +#include "svnqt/client_impl.hpp" +#include "svnqt/svnqt_defines.hpp" + +// Subversion api +#include "svn_client.h" + + + +namespace svn +{ +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + static svn_error_t * + annotateReceiver(void *baton, + apr_int64_t line_no, + svn_revnum_t revision, + const char *author, + const char *date, + svn_revnum_t merge_revision, + const char *merge_author, + const char *merge_date, + const char *merge_path, + const char *line, + apr_pool_t *) + { + AnnotatedFile * entries = (AnnotatedFile *) baton; + entries->push_back (AnnotateLine(line_no, revision,author, + date,line,merge_revision, + merge_author,merge_date,merge_path)); + return NULL; + } +#else + static svn_error_t * + annotateReceiver(void *baton, + apr_int64_t line_no, + svn_revnum_t revision, + const char *author, + const char *date, + const char *line, + apr_pool_t *) + { + AnnotatedFile * entries = (AnnotatedFile *) baton; + entries->push_back ( + AnnotateLine (line_no, revision, + author?author:"", + date?date:"", + line?line:"")); + + return NULL; + } +#endif + + void + Client_impl::annotate (AnnotatedFile&target,const Path & path, + const Revision & revisionStart, + const Revision & revisionEnd, + const Revision & peg, + const DiffOptions&diffoptions, + bool ignore_mimetypes, + bool include_merged_revisions + ) throw (ClientException) + { + Pool pool; + svn_error_t *error; +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + error = svn_client_blame4( + path.path().TOUTF8(), + peg.revision(), + revisionStart.revision (), + revisionEnd.revision (), + diffoptions.options(pool), + ignore_mimetypes, + include_merged_revisions, + annotateReceiver, + &target, + *m_context, // client ctx + pool); +#elif ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 4)) || (SVN_VER_MAJOR > 1) + Q_UNUSED(include_merged_revisions); + error = svn_client_blame3( + path.path().TOUTF8(), + peg.revision(), + revisionStart.revision (), + revisionEnd.revision (), + diffoptions.options(pool), + ignore_mimetypes, + annotateReceiver, + &target, + *m_context, // client ctx + pool); +#else + Q_UNUSED(include_merged_revisions); + Q_UNUSED(ignore_mimetypes); + Q_UNUSED(diffoptions); + error = svn_client_blame2( + path.path().TOUTF8(), + peg.revision(), + revisionStart.revision (), + revisionEnd.revision (), + annotateReceiver, + &target, + *m_context, // client ctx + pool); +#endif + if (error != NULL) + { + throw ClientException (error); + } + } +} diff --git a/src/svnqt/client_cat.cpp b/src/svnqt/client_cat.cpp new file mode 100644 index 0000000..fb03f46 --- /dev/null +++ b/src/svnqt/client_cat.cpp @@ -0,0 +1,105 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ +#if defined( _MSC_VER) && _MSC_VER <= 1200 +#pragma warning( disable: 4786 )// debug symbol truncated +#endif +// svncpp +#include "client_impl.hpp" + +// Subversion api +#include "svn_client.h" +//#include "svn_io.h" + +#include "svnqt/exception.hpp" +#include "svnqt/pool.hpp" +#include "svnqt/status.hpp" +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/svnstream.hpp" +#include "svnqt/svnfilestream.hpp" + +namespace svn +{ + QByteArray + Client_impl::cat(const Path & path, + const Revision & revision, + const Revision & peg_revision) throw (ClientException) + { + svn::stream::SvnByteStream buffer(*m_context); + svn_error_t * error = internal_cat(path,revision,peg_revision,buffer); + if (error != 0) + throw ClientException (error); + + return buffer.content(); + } + + void + Client_impl::cat(svn::stream::SvnStream&buffer, + const Path & path, + const Revision & revision, + const Revision & peg_revision) throw (ClientException) + { + svn_error_t * error = internal_cat(path,revision,peg_revision,buffer); + if (error != 0) + throw ClientException (error); + } + + void + Client_impl::get (const Path & path, + const QString & target, + const Revision & revision, + const Revision & peg_revision) throw (ClientException) + { + svn::stream::SvnFileOStream buffer(target,*m_context); + svn_error_t * error = internal_cat(path,revision,peg_revision,buffer); + if (error != 0) + throw ClientException (error); + } + + svn_error_t * Client_impl::internal_cat(const Path & path, + const Revision & revision, + const Revision & peg_revision, + svn::stream::SvnStream&buffer) + { + Pool pool; + return svn_client_cat2 (buffer, + path.path().TOUTF8(), + peg_revision.revision (), + revision.revision (), + *m_context, + pool); + } + +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/client_diff.cpp b/src/svnqt/client_diff.cpp new file mode 100644 index 0000000..4074fa2 --- /dev/null +++ b/src/svnqt/client_diff.cpp @@ -0,0 +1,184 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ +#if defined( _MSC_VER) && _MSC_VER <= 1200 +#pragma warning( disable: 4786 )// debug symbol truncated +#endif +// svncpp +#include "svnqt/client_impl.hpp" + +// Subversion api +#include "svn_client.h" +#include "svn_path.h" + +#include "svnqt/exception.hpp" +#include "svnqt/pool.hpp" +#include "svnqt/status.hpp" +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/helper.hpp" +#include "diff_data.hpp" + +#include <qfile.h> +#include <qstringlist.h> + +#include <apr_xlate.h> + +namespace svn +{ + QByteArray + Client_impl::diff_peg (const Path & tmpPath, const Path & path,const Path&relativeTo, + const Revision & revision1, const Revision & revision2, const Revision& peg_revision, + Depth depth, const bool ignoreAncestry, + const bool noDiffDeleted,const bool ignore_contenttype) throw (ClientException) + { + return diff_peg(tmpPath,path,relativeTo, + revision1,revision2,peg_revision, + depth,ignoreAncestry,noDiffDeleted,ignore_contenttype, + StringArray(),StringArray()); + } + + QByteArray + Client_impl::diff_peg (const Path & tmpPath, const Path & path,const Path&relativeTo, + const Revision & revision1, const Revision & revision2, const Revision& peg_revision, + Depth depth, const bool ignoreAncestry, + const bool noDiffDeleted,const bool ignore_contenttype, + const StringArray&extra,const StringArray&changelists) throw (ClientException) + { + Pool pool; + svn_error_t * error; + const apr_array_header_t * options; + + // svn_client_diff needs an options array, even if it is empty + options = extra.array(pool); + DiffData ddata(tmpPath,path,revision1,path,revision2); + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + qDebug("pegged diff4 call"); + error = svn_client_diff_peg4( + options, + path.cstr(), + peg_revision,ddata.r1().revision(),ddata.r2().revision(), + relativeTo.length()>0?relativeTo.cstr():QByteArray(0), + internal::DepthToSvn(depth), + ignoreAncestry,noDiffDeleted,ignore_contenttype, + APR_LOCALE_CHARSET, + ddata.outFile(),ddata.errFile(), + changelists.array(pool), + *m_context, + pool + ); +#else + Q_UNUSED(relativeTo); + Q_UNUSED(changelists); + bool recurse = depth==DepthInfinity; + error = svn_client_diff_peg3( + options, + path.cstr(), + peg_revision,ddata.r1().revision(),ddata.r2().revision(), + recurse?1:0,ignoreAncestry,noDiffDeleted,ignore_contenttype, + APR_LOCALE_CHARSET, + ddata.outFile(),ddata.errFile(), + *m_context, + pool + ); +#endif + if (error != NULL) + { + throw ClientException (error); + } + return ddata.content(); + } + + QByteArray + Client_impl::diff (const Path & tmpPath, const Path & path1,const Path&path2,const Path&relativeTo, + const Revision & revision1, const Revision & revision2, + Depth depth, const bool ignoreAncestry, + const bool noDiffDeleted,const bool ignore_contenttype) throw (ClientException) + { + return diff(tmpPath,path1,path2,relativeTo, + revision1,revision2, + depth,ignoreAncestry,noDiffDeleted,ignore_contenttype, + StringArray(),StringArray()); + } + + QByteArray + Client_impl::diff (const Path & tmpPath, const Path & path1,const Path&path2,const Path&relativeTo, + const Revision & revision1, const Revision & revision2, + Depth depth, const bool ignoreAncestry, + const bool noDiffDeleted,const bool ignore_contenttype, + const StringArray&extra,const StringArray&changelists) throw (ClientException) + { + + Pool pool; + svn_error_t * error; + const apr_array_header_t * options; + + // svn_client_diff needs an options array, even if it is empty + options = extra.array(pool); + DiffData ddata(tmpPath,path1,revision1,path2,revision2); + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + error = svn_client_diff4(options, + path1.cstr (), ddata.r1().revision (), + path2.cstr (), ddata.r2().revision (), + relativeTo.length()>0?relativeTo.cstr():QByteArray(0), + internal::DepthToSvn(depth), ignoreAncestry, noDiffDeleted, ignore_contenttype, + APR_LOCALE_CHARSET, + ddata.outFile(),ddata.errFile(), + changelists.array(pool), + *m_context, + pool); +#else + Q_UNUSED(changelists); + Q_UNUSED(relativeTo); + bool recurse = depth==DepthInfinity; + // run diff + error = svn_client_diff3 (options, + path1.cstr (), ddata.r1().revision (), + path2.cstr (), ddata.r2().revision (), + recurse?1:0, ignoreAncestry, noDiffDeleted, ignore_contenttype, + APR_LOCALE_CHARSET, + ddata.outFile(),ddata.errFile(), + *m_context, + pool); +#endif + if (error != NULL) + { + throw ClientException (error); + } + return ddata.content(); + + } +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/client_impl.cpp b/src/svnqt/client_impl.cpp new file mode 100644 index 0000000..74c2850 --- /dev/null +++ b/src/svnqt/client_impl.cpp @@ -0,0 +1,123 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ +#if defined( _MSC_VER) && _MSC_VER <= 1200 +#pragma warning( disable: 4786 )// debug symbol truncated +#endif + +// svncpp +#include "svnqt/client_impl.hpp" +#include "svn_opt.h" +#include "svnqt/svnqt_defines.hpp" + +#include <qmap.h> +#include <qstringlist.h> +namespace svn +{ + + Client_impl::Client_impl (ContextP context) + : Client() + { + setContext (context); + } + + Client_impl::~Client_impl () + { + } + + const ContextP + Client_impl::getContext () const + { + return m_context; + } + + void + Client_impl::setContext (ContextP context) + { + m_context = context; + } + + + void + Client_impl::url2Revision(const QString&revstring, + Revision&start,Revision&end) + { + Pool pool; + int n = svn_opt_parse_revision(start,end,revstring.TOUTF8(),pool); + + if (n<0) { + start = Revision::UNDEFINED; + end = Revision::UNDEFINED; + } + } + + void Client_impl::url2Revision(const QString&revstring,Revision&start) + { + if (revstring=="WORKING") { + start = Revision::WORKING; + } else if (revstring=="BASE"){ + start = Revision::BASE; + } else if (revstring=="START"){ + start = Revision::START; + } else { + Revision end; + url2Revision(revstring,start,end); + } + } + + apr_hash_t * Client_impl::map2hash(const PropertiesMap&aMap,const Pool&pool) + { + if (aMap.count()==0) { + return 0; + } + apr_hash_t * hash = apr_hash_make(pool); + PropertiesMap::ConstIterator it; + const char*propval; + const char*propname; + QByteArray s,n; + for (it=aMap.begin();it!=aMap.end();++it) { +#if QT_VERSION < 0x040000 + s=it.data().TOUTF8(); +#else + s=it.value().TOUTF8(); +#endif + n=it.key().TOUTF8(); + propval=apr_pstrndup(pool,s,s.size()); + propname=apr_pstrndup(pool,n,n.size()); + apr_hash_set(hash,propname,APR_HASH_KEY_STRING,propval); + } + return hash; + } +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/client_impl.hpp b/src/svnqt/client_impl.hpp new file mode 100644 index 0000000..4c3b363 --- /dev/null +++ b/src/svnqt/client_impl.hpp @@ -0,0 +1,881 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_CLIENT_IMPL_H_ +#define _SVNCPP_CLIENT_IMPL_H_ + +#include "svnqt/client.hpp" +#include "svnqt/svnqt_defines.hpp" + +// Ignore MSVC 6 compiler warning: debug symbol truncated +#if defined (_MSC_VER) && _MSC_VER <= 1200 +#pragma warning (disable: 4786) +#endif + +// Ignore MSVC 7, 2005 & 2008 compiler warning: C++ exception specification +#if defined (_MSC_VER) && _MSC_VER > 1200 && _MSC_VER <= 1550 +#pragma warning (disable: 4290) +#endif + +class QStringList; + +namespace svn +{ + namespace stream { + class SvnStream; + } + + /** + * Subversion client API. + */ + class SVNQT_NOEXPORT Client_impl:public Client + { + public: + /** + * Initializes the primary memory pool. + */ + Client_impl(ContextP context); + + virtual ~Client_impl(); + + /** + * @return returns the Client context + */ + virtual const ContextP + getContext () const; + + /** + * sets the client context + * you have to make sure the old context + * is de-allocated + * + * @param context new context to use + */ + virtual void + setContext (ContextP context); + + + /** + * Enumerates all files/dirs at a given path. + * + * Throws an exception if an error occurs + * + * @param path Path to explore. + * @param descend Recurse into subdirectories if existant. + * @param get_all Return all entries, not just the interesting ones. + * @param update Query the repository for updates. + * @param no_ignore Disregard default and svn:ignore property ignores. + * @param hide_externals don't recurse into external definitions + * @param revision list specific revision when browsing remote, on working copies parameter will ignored + * @param detailed_remote if on remote listing detailed item info should get if possible + * that may slow so should configureable in frontends! + * @return vector with Status entries. + */ + virtual StatusEntries + status (const Path& path, + Depth depth=DepthEmpty, + bool get_all = true, + bool update = false, + bool no_ignore = false, + const Revision revision = svn::Revision::HEAD, + bool detailed_remote = false, + bool hide_externals = false, + const StringArray & changelists=StringArray()) throw (ClientException); + + /** + * Returns the status of a single file in the path. + * + * Throws an exception if an error occurs + * + * @param path File to gather status. + * @param update if check against repository if new updates are there (for WC only) + * @param revision list specific revision when browsing remote, on working copies parameter will ignored + * @return a Status with Statis.isVersioned = FALSE + */ + virtual StatusPtr + singleStatus (const Path& path,bool update=false,const Revision revision = svn::Revision::HEAD) throw (ClientException); + + /** + * Executes a revision checkout. + * @param moduleName name of the module to checkout. + * @param destPath destination directory for checkout. + * @param revision the revision number to checkout. If the number is -1 + * then it will checkout the latest revision. + * @param peg Revision to look up + * @param recurse whether you want it to checkout files recursively. + * @param ignore_externals if true don't process externals definitions. + * @exception ClientException + */ + virtual svn_revnum_t + checkout (const Path& moduleName, const Path & destPath, + const Revision & revision, + const Revision & peg = Revision::UNDEFINED, + svn::Depth depth=DepthInfinity, + bool ignore_externals=false, + bool overwrite=false + ) throw (ClientException); + + /** + * relocate wc @a from to @a to + * @exception ClientException + */ + virtual void + relocate (const Path & path, const QString &from_url, + const QString &to_url, bool recurse) throw (ClientException); + + /** + * Sets a single file for deletion. + * @exception ClientException + */ + virtual svn::Revision + remove (const Path & path, bool force, + bool keep_local = true, + const PropertiesMap&revProps = PropertiesMap()) throw (ClientException); + + /** + * Sets files for deletion. + * + * @param targets targets to delete + * @param force force if files are locally modified + * @exception ClientException + */ + virtual svn::Revision + remove (const Targets & targets, + bool force, + bool keep_local = true, + const PropertiesMap&revProps = PropertiesMap()) throw (ClientException); + + /** + * Reverts a couple of files to a pristiner state. + * @exception ClientException + */ + virtual void + revert (const Targets & targets, + Depth depth, + const StringArray&changelist=StringArray() + ) throw (ClientException); + + + /** + * Adds a file to the repository. + * @param path the path to add + * @param depth if @a path is a folder add items recursive depending on value if it. Pre-subversion 1.5 DepthInfinity is mapped to recursive, all other to not-recursive. + * @param force if true, do not error on already-versioned items. + * @param no_ignore if false don't add files or directories that match ignore patterns. + * @param add_parents if true, go up to the next versioned folder and add all between path and this folder. Used only with subversion 1.5 or newer + * @exception ClientException + * @sa svn::Depth + */ + virtual void add (const Path & path, svn::Depth depth,bool force=false, bool no_ignore=false, bool add_parents = true) throw (ClientException); + + /** + * Updates the file or directory. + * @param path targets. + * @param revision the revision number to checkout. + * Revision::HEAD will checkout the + * latest revision. + * @param depth Depthness for operation + * @param ignore_externals ignore externals + * @param allow_unversioned will operation not fail if there are unversioned items in tree with same name. + * @exception ClientException + */ + virtual Revisions + update (const Targets & path, const Revision & revision, + Depth depth,bool ignore_externals,bool allow_unversioned, + bool sticky_depth) throw (ClientException); + + /** + * Retrieves the contents for a specific @a revision of + * a @a path at @a peg_revision + * + * @param path path of file or directory + * @param peg_revision revision to base the URL + * @param revision revision to retrieve + * @param peg_revision Revision to look at + * @return contents of the file + */ + virtual QByteArray + cat (const Path & path, + const Revision & revision, + const Revision & peg_revision=svn_opt_revision_unspecified) throw (ClientException); + /** + * Retrieves the contents for a specific @a revision of + * a @a path at @a peg_revision + * + * @param buffer Stream to store content direct + * @param path path of file or directory + * @param peg_revision revision to base the URL + * @param revision revision to retrieve + * @exception ClientException + */ + virtual void + cat(svn::stream::SvnStream&buffer, + const Path & path, + const Revision & revision, + const Revision & peg_revision) throw (ClientException); + + /** + * Retrieves the contents for a specific @a revision of + * a @a path at @a peg_revision + * + * @param path path of file or directory + * @param target new (local) name + * @param peg_revision revision to base the URL + * @param revision revision to retrieve + * @param peg_revision Revision to look at + */ + virtual void + get (const Path & path, + const QString & target, + const Revision & revision, + const Revision & peg_revision=svn_opt_revision_unspecified) throw (ClientException); + + /** + * Retrieves the contents for a specific @a revision of + * a @a path and stores the result in @a target + * + * @param target the container where to store the result + * @param path path of file or directory + * @param revisionStart revision to retrieve + * @param revisionEnd revision to retrieve + * @param peg indicates in which revision path is valid + */ + virtual void + annotate (AnnotatedFile&target, + const Path & path, + const Revision & revisionStart, + const Revision & revisionEnd, + const Revision & peg = Revision::UNDEFINED, + const DiffOptions&diffoptions = DiffOptions(), + bool ignore_mimetypes = false, + bool include_merged_revisions = false + ) throw (ClientException); + + /** + * Commits changes to the repository. This usually requires + * authentication, see Auth. + * @return Returns revision transferred or svn::Revision::UNDEFINED if the revision number is invalid. + * @param targets files to commit. + * @param message log message. + * @param depth whether the operation should be done recursively. + * @param keep_locks if false unlock items in paths + * @param changelist + * @param keep_changelist + * @exception ClientException + */ + virtual svn::Revision + commit (const Targets & targets, + const QString& message, + svn::Depth depth,bool keep_locks=true, + const svn::StringArray&changelist=svn::StringArray(), + const PropertiesMap&revProps=PropertiesMap(), + bool keep_changelist=false + ) throw (ClientException); + + /** + * Copies a versioned file with the history preserved. + * @exception ClientException + */ + virtual svn::Revision + copy (const Path & srcPath, + const Revision & srcRevision, + const Path & destPath) throw (ClientException); + /** + * Copies a versioned file with the history preserved. + * @since subversion 1.5 api + * @see svn_client_copy4 + * @exception ClientException + */ + virtual svn::Revision + copy (const Targets & srcPath, + const Revision & srcRevision, + const Revision & pegRevision, + const Path & destPath, + bool asChild=false,bool makeParent=false,const PropertiesMap&revProps=PropertiesMap()) throw (ClientException); + + /** + * Moves or renames a file. + * @exception ClientException + */ + virtual svn::Revision + move (const Path & srcPath, + const Path & destPath, + bool force) throw (ClientException); + + /** + * Moves or renames a file. + * @exception ClientException + */ + virtual svn::Revision + move (const Targets & srcPath, + const Path & destPath, + bool force,bool asChild,bool makeParent,const PropertiesMap&revProps=PropertiesMap()) throw (ClientException); + + /** + * Creates a directory directly in a repository or creates a + * directory on disk and schedules it for addition. If <i>path</i> + * is a URL then authentication is usually required, see Auth and + * the callback asks for a logmessage. + * + * @param path + * @param message log message. if it is QString::null asks when working on repository + * @exception ClientException + */ + virtual svn::Revision + mkdir (const Path & path, + const QString& message, + bool makeParent=true, + const PropertiesMap&revProps=PropertiesMap() + ) throw (ClientException); + /** + * Creates a directory directly in a repository or creates a + * directory on disk and schedules it for addition. If <i>path</i> + * is a URL then authentication is usually required, see Auth and + * the callback asks for a logmessage. + * + * @param targets encoded pathes to create + * @param message log message. if it is QString::null asks when working on repository + * @exception ClientException + */ + virtual svn::Revision + mkdir (const Targets & targets, + const QString& message, + bool makeParent=true, + const PropertiesMap&revProps=PropertiesMap() + ) throw (ClientException); + + /** + * Recursively cleans up a local directory, finishing any + * incomplete operations, removing lockfiles, etc. + * @param path a local directory. + * @exception ClientException + */ + virtual void + cleanup (const Path & path) throw (ClientException); + + /** + * Removes the 'conflicted' state on a file. + * @exception ClientException + */ + virtual void resolve (const Path & path,Depth depth,const ConflictResult&resolution=ConflictResult()) throw (ClientException); + + /** + * Exports the contents of either a subversion repository into a + * 'clean' directory (meaning a directory with no administrative + * directories). + * @exception ClientException + * @param srcPath source path + * @param destPath a destination path that must not already exist. + * @param revision revision to use for the export + * @param peg the revision where the path is first looked up when exporting from a repository. + * @param overwrite overwrite existing files + * @param native_eol Either "LF", "CR" or "CRLF" or NULL. + * @param ignore_externals don't process externals definitions as part of this operation. + * @param recurse if true, export recursively. Otherwise, export just the directory represented by from and its immediate non-directory children. + */ + virtual svn_revnum_t + doExport (const Path & srcPath, + const Path & destPath, + const Revision & revision, + const Revision & peg = Revision::UNDEFINED, + bool overwrite=false, + const QString&native_eol=QString::null, + bool ignore_externals = false, + svn::Depth depth=svn::DepthInfinity + ) throw (ClientException); + + /** + * Update local copy to mirror a new url. This excapsulates the + * svn_client_switch() client method. + * @exception ClientException + */ + virtual svn_revnum_t + doSwitch ( + const Path & path, const QString& url, + const Revision & revision, + Depth depth, + const Revision & peg=Revision::UNDEFINED, + bool sticky_depth = true, + bool ignore_externals=false, + bool allow_unversioned=false + ) throw (ClientException); + + /** + * Import file or directory PATH into repository directory URL at + * head. This usually requires authentication, see Auth. + * @param path path to import + * @param url + * @param message log message. + * @param depth kind of recurse operation + * @param no_ignore if false, don't add items matching global ignore pattern + * @param no_unknown_nodetype if true ignore files type not known like pipes or device files + * @exception ClientException + */ + virtual svn::Revision + import (const Path & path, const QString& url, + const QString& message, + svn::Depth depth, + bool no_ignore,bool no_unknown_nodetype, + const PropertiesMap&revProps=PropertiesMap()) throw (ClientException); + + /** + * Merge changes from two paths into a new local path. + * @exception ClientException + */ + virtual void + merge (const Path & path1, const Revision & revision1, + const Path & path2, const Revision & revision2, + const Path & localPath, bool force, + Depth depth, + bool notice_ancestry=false, + bool dry_run=false, + bool record_only=false, + const StringArray&merge_options=StringArray() + ) throw (ClientException); + + virtual void + merge_peg(const Path&src, + const RevisionRanges&ranges, + const Revision&peg, + const Path&targetWc, + Depth depth, + bool notice_ancestry=false, + bool dry_run=false, + bool force=false, + bool record_only=false, + const StringArray&merge_options=StringArray() + ) throw (ClientException); + + virtual void + merge_peg(const Path&src, + const RevisionRange&range, + const Revision&peg, + const Path&targetWc, + Depth depth, + bool notice_ancestry, + bool dry_run, + bool force, + const StringArray&merge_options + ) throw (ClientException); + + /** + * Retrieve information for the given path + * remote or local. Only gives with subversion 1.2 + * usefull results + * + * @param path path for info + * @param rec recursive (if dir) + * @param rev for which revision + * @param peg_revision peg revision + * @return InfoEntries + * @since subversion 1.2 + */ + virtual InfoEntries + info(const Path &path, + Depth depth, + const Revision & rev, + const Revision & peg_revision=svn_opt_revision_unspecified, + const StringArray&changelists=StringArray() + ) throw (ClientException); + /** + * Retrieve log information for the given path + * Loads the log messages result set. The first + * entry is the youngest revision. + * + * You can use the constants Revision::START and + * Revision::HEAD + * + * @param path + * @param revisionStart Start revision. + * @param revisionEnd End revision + * @param revisionPeg Revision where path is valid. + * @param discoverChangedPaths Should changed pathes transferred + * @param strictNodeHistory + * @param limit the maximum log entries count. + * @param include_merged_revisions log information for revisions which have been merged to targets will also be returned. (subversion 1.5) + * @return a vector with log entries + */ + virtual LogEntriesPtr + log (const Path& path, const Revision & revisionStart, + const Revision & revisionEnd, + const Revision & revisionPeg, + bool discoverChangedPaths=false, + bool strictNodeHistory=true,int limit=0, + bool include_merged_revisions = false, + const StringArray&revprops=StringArray() + ) throw (ClientException); + /** + * Retrieve log information for the given path + * Loads the log messages result set. Result will stored + * in a map where the key is the revision number + * + * You can use the constants Revision::START and + * Revision::HEAD + * + * @param path + * @param revisionStart + * @param revisionEnd + * @param revisionPeg Revision where path is valid. + * @param target the logmap where to store the entries + * @param discoverChangedPaths + * @param strictNodeHistory + * @param limit (ignored when subversion 1.1 API) + * @return true if success + */ + virtual bool + log (const Path& path, const Revision & revisionStart, + const Revision & revisionEnd, + LogEntriesMap&target, + const Revision & revisionPeg, + bool discoverChangedPaths, + bool strictNodeHistory,int limit, + bool include_merged_revisions = false, + const StringArray&revprops=StringArray() + ) throw (ClientException); + + /** + * Produce diff output which describes the delta between + * @a path/@a revision1 and @a path/@a revision2. @a path + * can be either a working-copy path or a URL. + * + * A ClientException will be thrown if either @a revision1 or + * @a revision2 has an `unspecified' or unrecognized `kind'. + * + * @param tmpPath prefix for a temporary directory needed by diff. + * Filenames will have ".tmp" and similar added to this prefix in + * order to ensure uniqueness. + * @param path path of the file. + * @param revision1 one of the revisions to check. + * @param revision2 the other revision. + * @param recurse whether the operation should be done recursively. + * @param ignoreAncestry whether the files will be checked for + * relatedness. + * @param noDiffDeleted if true, no diff output will be generated on deleted files. + * @param ignore_contenttype if true generate diff even the items are marked as binaries + * @param extra extra options for diff ("-b", "-w","--ignore-eol-style") + * @return delta between the files + * @exception ClientException + */ + virtual QByteArray + diff_peg (const Path & tmpPath, const Path & path,const Path&relativeTo, + const Revision & revision1, const Revision & revision2, const Revision& peg_revision, + Depth depth, bool ignoreAncestry, + bool noDiffDeleted,bool ignore_contenttype, + const StringArray&extra, + const StringArray&changelists + ) + throw (ClientException); + + /** + * Same as other diff but extra options and changelists always set to empty list. + */ + virtual QByteArray + diff_peg (const Path & tmpPath, const Path & path,const Path&relativeTo, + const Revision & revision1, const Revision & revision2, const Revision& peg_revision, + Depth depth, bool ignoreAncestry, + bool noDiffDeleted,bool ignore_contenttype) + throw (ClientException); + + /** + * Produce diff output which describes the delta between + * @a path1/@a revision1 and @a path2/@a revision2. @a path2 + * can be either a working-copy path or a URL. + * + * A ClientException will be thrown if either @a revision1 or + * @a revision2 has an `unspecified' or unrecognized `kind'. + * + * @param tmpPath prefix for a temporary directory needed by diff. + * Filenames will have ".tmp" and similar added to this prefix in + * order to ensure uniqueness. + * @param path1 first file or folder to diff. + * @param path2 second file or folder to diff. + * @param revision1 one of the revisions to check (path1). + * @param revision2 the other revision (path2). + * @param recurse whether the operation should be done recursively. + * @param ignoreAncestry whether the files will be checked for + * relatedness. + * @param noDiffDeleted if true, no diff output will be generated on deleted files. + * @param ignore_contenttype if true generate diff even the items are marked as binaries + * @param extra extra options for diff ("-b", "-w","--ignore-eol-style") + * @return delta between the files + * @exception ClientException + */ + virtual QByteArray + diff (const Path & tmpPath, const Path & path1,const Path & path2,const Path&relativeTo, + const Revision & revision1, const Revision & revision2, + Depth depth, bool ignoreAncestry, + bool noDiffDeleted,bool ignore_contenttype, + const StringArray&extra, + const StringArray&changelists + ) + throw (ClientException); + + /** + * Same as other diff but extra options always set to empty list. + */ + virtual QByteArray + diff (const Path & tmpPath, const Path & path1,const Path & path2,const Path&relativeTo, + const Revision & revision1, const Revision & revision2, + Depth depth, bool ignoreAncestry, + bool noDiffDeleted,bool ignore_contenttype) + throw (ClientException); + + /** + * lists entries in @a pathOrUrl no matter whether local or + * repository + * + * @param pathOrUrl + * @param revision + * @param peg at wich revision path exists + * @param depth @sa svn::Depth + * @param retrieve_locks check for REPOSITORY locks while listing + * @return a vector of directory entries, each with + * a relative path (only filename) + */ + virtual DirEntries + list (const Path& pathOrUrl, + const Revision& revision, + const Revision& peg, + svn::Depth depth,bool retrieve_locks) throw (ClientException); + + /** + * lists properties in @a path no matter whether local or + * repository + * + * @param path + * @param revision + * @param peg most case should set to @a revision + * @param recurse + * @return PropertiesList + */ + virtual PathPropertiesMapListPtr + proplist(const Path &path, + const Revision &revision, + const Revision &peg, + Depth depth=DepthEmpty, + const StringArray&changelists=StringArray()); + + /** + * lists one property in @a path no matter whether local or + * repository + * + * @param propName + * @param path + * @param revision + * @param peg most case should set to @a revision + * @param recurse + * @return PathPropertiesMapList + */ + virtual QPair<QLONG,PathPropertiesMapList> + propget(const QString& propName, + const Path &path, + const Revision &revision, + const Revision &peg, + Depth depth = svn::DepthEmpty, + const StringArray&changelists=StringArray()); + + /** + * set property in @a path no matter whether local or + * repository + * + * @param path + * @param propName + * @param propValue + * @param recurse + * @param skip_check if true skip validity checks + * @return PropertiesList + */ + virtual void + propset(const QString& propName, + const QString& propValue, + const Path &path, + Depth depth=DepthEmpty, + bool skip_check=false, + const Revision&base_revision=Revision::UNDEFINED, + const StringArray&changelists=StringArray(), + const PropertiesMap&revProps=PropertiesMap() + ); + + /** + * delete property in @a path no matter whether local or + * repository + * + * @param propName + * @param path + * @param revision + * @param recurse + */ + virtual void + propdel(const QString& propName, + const Path &path, + Depth depth=DepthEmpty, + bool skip_check=false, + const Revision&base_revision=Revision::UNDEFINED, + const StringArray&changelists=StringArray()); + + + /** + * lists revision properties in @a path no matter whether local or + * repository + * + * @param path + * @param revision + * @return PropertiesList + */ + virtual QPair<QLONG,PropertiesMap> + revproplist(const Path &path, + const Revision &revision); + + /** + * lists one revision property in @a path no matter whether local or + * repository + * + * @param propName + * @param path + * @param revision + * @return PropertiesList + */ + QPair<QLONG,QString> + revpropget(const QString& propName, + const Path &path, + const Revision &revision); + + /** + * set revision property in @a path no matter whether local or + * repository + * + * @param propName + * @param propValue + * @param path + * @param revision + * @param force + * @return Revision + */ + virtual QLONG + revpropset(const QString& propName, + const QString& propValue, + const Path &path, + const Revision &revision, + bool force=false); + + /** + * delete revision property in @a path no matter whether local or + * repository + * + * @param propName + * @param path + * @param revision + * @param force + * @return Revision + */ + virtual QLONG + revpropdel(const QString& propName, + const Path &path, + const Revision &revision, + bool force=false); + + /** + * lock files in repository or working copy + * @param targets items to be locked + * @param message if non null stored with each lock in repository + * @param steal_lock if true locks in wc will stolen. + * @since subversion 1.2 + */ + virtual void + lock (const Targets & targets, + const QString& message, + bool steal_lock) throw (ClientException); + /** + * unlock files in repository or working copy + * @param targets items to unlock + * @param break_lock ignore any errors + */ + virtual void + unlock (const Targets&targets, + bool break_lock) throw (ClientException); + + virtual void + url2Revision(const QString&revstring, + Revision&start,Revision&end); + virtual void + url2Revision(const QString&revstring, + Revision&start); + + struct sBaton { + Context*m_context; + void*m_data; + void*m_revstack; + }; + + struct propBaton { + Context*m_context; + PathPropertiesMapList*resultlist; + }; + + private: + ContextP m_context; + + /** + * disallow assignment operator + */ + Client_impl & operator= (const Client &); + + /** + * disallow copy constructor + */ + Client_impl (const Client &); + + DirEntries + list_simple(const Path& pathOrUrl, + const Revision& revision, + const Revision& peg, + bool recurse) throw (ClientException); + DirEntries + list_locks(const Path& pathOrUrl, + const Revision& revision, + const Revision& peg, + bool recurse) throw (ClientException); + + svn_error_t * internal_cat(const Path & path, + const Revision & revision, + const Revision & peg_revision, + svn::stream::SvnStream&); + + apr_hash_t * map2hash(const PropertiesMap&,const Pool&); + }; + +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/client_lock.cpp b/src/svnqt/client_lock.cpp new file mode 100644 index 0000000..b70223d --- /dev/null +++ b/src/svnqt/client_lock.cpp @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +// svncpp +#include "client_impl.hpp" + +// subversion api +#include "svn_client.h" + +#include "svnqt/exception.hpp" +#include "svnqt/pool.hpp" +#include "svnqt/targets.hpp" +#include "svnqt/svnqt_defines.hpp" + +namespace svn +{ + + void + Client_impl::lock (const Targets & targets, + const QString& message, + bool steal_lock) throw (ClientException) + { + Pool pool; + svn_error_t * error = + svn_client_lock(const_cast<apr_array_header_t*> (targets.array (pool)), + message.TOUTF8(), + steal_lock, + *m_context, + pool); + if(error != NULL) + throw ClientException (error); + } + + void + Client_impl::unlock (const Targets&targets, + bool break_lock) throw (ClientException) + { + Pool pool; + svn_error_t * error = + svn_client_unlock(const_cast<apr_array_header_t*> (targets.array (pool)), + break_lock, + *m_context, + pool); + if(error != NULL) + throw ClientException (error); + } +} diff --git a/src/svnqt/client_ls.cpp b/src/svnqt/client_ls.cpp new file mode 100644 index 0000000..897a4d8 --- /dev/null +++ b/src/svnqt/client_ls.cpp @@ -0,0 +1,237 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ +#if defined( _MSC_VER) && _MSC_VER <= 1200 +#pragma warning( disable: 4786 )// debug symbol truncated +#endif + + +// svncpp +#include "svnqt/client_impl.hpp" + +// subversion api +#include "svn_client.h" +#include "svn_path.h" +#include "svn_sorts.h" +//#include "svn_utf.h" + +#include "svnqt/dirent.hpp" +#include "svnqt/exception.hpp" +#include "svnqt/svnqt_defines.hpp" + +#include "svnqt/helper.hpp" + +static int +compare_items_as_paths (const svn_sort__item_t *a, const svn_sort__item_t *b) +{ + return svn_path_compare_paths ((const char *)a->key, (const char *)b->key); +} + +namespace svn +{ + + DirEntries + Client_impl::list_simple(const Path& _p, + const Revision& revision, + const Revision& peg, + bool recurse) throw (ClientException) + { + Pool pool; + + apr_hash_t * hash; + /* don't want the lock hashs, so we simply use ls2 on svn 1.3, too. + * there is that method a cast to ls3 with lock_hash == 0 + */ + svn_error_t * error = + svn_client_ls2 (&hash, + _p.cstr(), + peg.revision(), + revision.revision(), + recurse, + *m_context, + pool); + + if (error != 0) + throw ClientException (error); + + apr_array_header_t * + array = svn_sort__hash ( + hash, compare_items_as_paths, pool); + + DirEntries entries; + + for (int i = 0; i < array->nelts; ++i) + { + const char *entryname; + svn_dirent_t *dirent; + svn_sort__item_t *item; + + item = &APR_ARRAY_IDX (array, i, svn_sort__item_t); + + entryname = static_cast<const char *>(item->key); + + dirent = static_cast<svn_dirent_t *> + (apr_hash_get (hash, entryname, item->klen)); + + entries.push_back (new DirEntry(QString::FROMUTF8(entryname), dirent)); + } + + return entries; + } + + DirEntries + Client_impl::list_locks(const Path& pathOrUrl, + const Revision& revision, + const Revision& peg, + bool recurse) throw (ClientException) + { + Pool pool; + + apr_hash_t * hash; + apr_hash_t * lock_hash; + + svn_error_t * error = + svn_client_ls3 (&hash, + &lock_hash, + pathOrUrl.cstr(), + peg, + revision, + recurse, + *m_context, + pool); + + if (error != 0) + throw ClientException (error); + + apr_array_header_t * + array = svn_sort__hash ( + hash, compare_items_as_paths, pool); + + DirEntries entries; + + for (int i = 0; i < array->nelts; ++i) + { + const char *entryname; + svn_dirent_t *dirent; + svn_lock_t * lockent; + svn_sort__item_t *item; + + item = &APR_ARRAY_IDX (array, i, svn_sort__item_t); + + entryname = static_cast<const char *>(item->key); + + dirent = static_cast<svn_dirent_t *> + (apr_hash_get (hash, entryname, item->klen)); + lockent = static_cast<svn_lock_t *> + (apr_hash_get(lock_hash,entryname,item->klen)); + entries.push_back (new DirEntry(QString::FROMUTF8(entryname), dirent,lockent)); + } + + return entries; + } + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 4)) || (SVN_VER_MAJOR > 1) + static svn_error_t * s_list_func + (void * baton,const char*path,const svn_dirent_t*dirent,const svn_lock_t*lock,const char* abs_path,apr_pool_t*) + { + Q_UNUSED(abs_path); + if (!baton || !path || !dirent) { + return 0; + } + /* check every loop for cancel of operation */ + Client_impl::sBaton * l_baton = (Client_impl::sBaton*)baton; + Context*l_context = l_baton->m_context; + DirEntries*entries = static_cast<DirEntries*>(l_baton->m_data); + svn_client_ctx_t*ctx = l_context->ctx(); + if (ctx&&ctx->cancel_func) { + SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); + } + entries->push_back(new DirEntry(QString::FROMUTF8(path),dirent,lock)); + return 0; + } +#endif + + DirEntries + Client_impl::list(const Path& pathOrUrl, + const Revision& revision, + const Revision& peg, + Depth depth,bool retrieve_locks) throw (ClientException) + { + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 4)) || (SVN_VER_MAJOR > 1) + sBaton _baton; + Pool pool; + DirEntries entries; + _baton.m_data = &entries; + _baton.m_context=m_context; +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + svn_error_t * error = svn_client_list2(pathOrUrl.cstr(), + peg, + revision, + svn::internal::DepthToSvn(depth), + SVN_DIRENT_ALL, + retrieve_locks, + s_list_func, + &_baton, + *m_context, + pool + ); +#else + bool recurse = depth==DepthInfinity; + svn_error_t * error = svn_client_list(pathOrUrl.cstr(), + peg, + revision, + recurse, + SVN_DIRENT_ALL, + retrieve_locks, + s_list_func, + &_baton, + *m_context, + pool + ); +#endif + if (error != 0) { + throw ClientException (error); + } + return entries; +#else + if (!retrieve_locks) { + return list_simple(pathOrUrl,revision,peg,depth==DepthInfinity); + } else { + return list_locks(pathOrUrl,revision,peg,depth==DepthInfinity); + } +#endif + } +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/client_merge.cpp b/src/svnqt/client_merge.cpp new file mode 100644 index 0000000..0d84cc2 --- /dev/null +++ b/src/svnqt/client_merge.cpp @@ -0,0 +1,180 @@ +#include "svnqt/client_impl.hpp" + +// subversion api +#include "svn_client.h" + +#include "svnqt/exception.hpp" +#include "svnqt/pool.hpp" +#include "svnqt/targets.hpp" +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/stringarray.hpp" + +#include "svnqt/helper.hpp" + +namespace svn +{ +void Client_impl::merge (const Path & path1, const Revision & revision1, + const Path & path2, const Revision & revision2, + const Path & localPath, + bool force, + Depth depth, + bool notice_ancestry, + bool dry_run, + bool record_only, + const StringArray&merge_options + ) throw (ClientException) +{ + Pool pool; + svn_error_t * error = 0; +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + error = svn_client_merge3(path1.cstr (), + revision1.revision (), + path2.cstr (), + revision2.revision (), + localPath.cstr (), + internal::DepthToSvn(depth), + !notice_ancestry, + force, + record_only, + dry_run, + merge_options.array(pool), + *m_context, + pool); +#else + bool recurse = depth==DepthInfinity; + Q_UNUSED(record_only); +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 4)) + error = svn_client_merge2(path1.cstr (), + revision1.revision (), + path2.cstr (), + revision2.revision (), + localPath.cstr (), + recurse, + !notice_ancestry, + force, + dry_run, + merge_options.array(pool), + *m_context, + pool); +#else + Q_UNUSED(merge_options); + error = svn_client_merge(path1.cstr (), + revision1.revision (), + path2.cstr (), + revision2.revision (), + localPath.cstr (), + recurse, + !notice_ancestry, + force, + dry_run, + *m_context, + pool); +#endif +#endif + + if(error != 0) { + throw ClientException (error); + } + } + + void Client_impl::merge_peg(const Path&src, + const RevisionRanges&ranges, + const Revision&peg, + const Path&targetWc, + Depth depth, + bool notice_ancestry, + bool dry_run, + bool force, + bool record_only, + const StringArray&merge_options + ) throw (ClientException) + { +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + Pool pool; + internal::RevisionRangesToHash _rhash(ranges); + + svn_error_t*error; + + error = svn_client_merge_peg3( + src.cstr(), + _rhash.array(pool), + peg, + targetWc.cstr(), + internal::DepthToSvn(depth), + !notice_ancestry, + force, + record_only, + dry_run, + merge_options.array(pool), + *m_context, + pool + ); + if(error != 0) { + throw ClientException (error); + } +#else + Q_UNUSED(record_only); + for (unsigned long i=0;i<ranges.count();++i) { + merge_peg(src,ranges[i],peg,targetWc,depth,notice_ancestry,dry_run,force,merge_options); + } +#endif + } + + void Client_impl::merge_peg(const Path&src, + const RevisionRange&range, + const Revision&peg, + const Path&targetWc, + Depth depth, + bool notice_ancestry, + bool dry_run, + bool force, + const StringArray&merge_options + ) throw (ClientException) + { +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + RevisionRanges ranges; + ranges.append(range); + merge_peg(src,ranges,peg,targetWc,depth,notice_ancestry,dry_run,force,false,merge_options); +#else + Pool pool; + bool recurse=depth==DepthInfinity; + svn_error_t*error; + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 4)) || (SVN_VER_MAJOR > 1) + error = svn_client_merge_peg2( + src.cstr(), + range.first, + range.second, + peg.revision(), + targetWc.cstr(), + recurse, + !notice_ancestry, + force, + dry_run, + merge_options.array(pool), + *m_context, + pool + ); +#else + Q_UNUSED(merge_options); + error = svn_client_merge_peg( + src.cstr(), + range.first, + range.second, + peg.revision(), + targetWc.cstr(), + recurse, + !notice_ancestry, + force, + dry_run, + *m_context, + pool + ); +#endif + if(error != 0) { + throw ClientException (error); + } +#endif + } + +} diff --git a/src/svnqt/client_modify.cpp b/src/svnqt/client_modify.cpp new file mode 100644 index 0000000..352760b --- /dev/null +++ b/src/svnqt/client_modify.cpp @@ -0,0 +1,722 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ +#if defined( _MSC_VER) && _MSC_VER <= 1200 +#pragma warning( disable: 4786 )// debug symbol truncated +#endif +// svncpp +#include "svnqt/client_impl.hpp" + +// subversion api +#include "svn_client.h" + +#include "svnqt/exception.hpp" +#include "svnqt/pool.hpp" +#include "svnqt/targets.hpp" +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/stringarray.hpp" + +#include "svnqt/helper.hpp" + +namespace svn +{ + svn_revnum_t + Client_impl::checkout (const Path& url, const Path & destPath, + const Revision & revision, + const Revision & peg, + svn::Depth depth, + bool ignore_externals, + bool overwrite + ) throw (ClientException) + { + Pool subPool; + svn_revnum_t revnum = 0; + Path up(url); + svn_error_t * error = 0; +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + error = svn_client_checkout3(&revnum, + up.cstr(), + destPath.cstr(), + peg.revision(), + revision.revision (), + internal::DepthToSvn(depth), + ignore_externals, + overwrite, + *m_context, + subPool); +#else + bool recurse = depth==DepthInfinity; + Q_UNUSED(overwrite); + error = svn_client_checkout2(&revnum, + up.cstr(), + destPath.cstr(), + peg.revision(), + revision.revision (), + recurse, + ignore_externals, + *m_context, + subPool); +#endif + if(error != NULL) + throw ClientException (error); + return revnum; + } + + Revision Client_impl::remove (const Path & path,bool force, + bool keep_local, + const PropertiesMap&revProps) throw (ClientException) + { + Targets targets (path.path()); + return remove(targets,force,keep_local,revProps); + } + + Revision + Client_impl::remove (const Targets & targets, + bool force, + bool keep_local, + const PropertiesMap&revProps + ) throw (ClientException) + { + Pool pool; + + svn_commit_info_t *commit_info = 0; + + svn_error_t * error = +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + svn_client_delete3( + &commit_info, + targets.array(pool), + force, + keep_local, + map2hash(revProps,pool), + *m_context, + pool + ); +#else + svn_client_delete2 + (&commit_info, + const_cast<apr_array_header_t*> (targets.array (pool)), + force, + *m_context, + pool); + Q_UNUSED(keep_local); + Q_UNUSED(revProps); +#endif + if(error != 0) { + throw ClientException (error); + } + if (commit_info) { + return commit_info->revision; + } + return Revision::UNDEFINED; + } + + void + Client_impl::revert (const Targets & targets, + Depth depth, + const StringArray&changelist + ) throw (ClientException) + { + Pool pool; + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + svn_error_t * error = + svn_client_revert2 ((targets.array (pool)), + internal::DepthToSvn(depth), + changelist.array(pool), + *m_context, + pool); + +#else + bool recurse = depth==DepthInfinity; + Q_UNUSED(changelist); + svn_error_t * error = + svn_client_revert ((targets.array (pool)), + recurse, + *m_context, + pool); +#endif + if(error != NULL) { + throw ClientException (error); + } + } + + void + Client_impl::add (const Path & path, + svn::Depth depth,bool force, bool no_ignore, bool add_parents) throw (ClientException) + { + Pool pool; +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + svn_error_t * error = + svn_client_add4(path.cstr (), + internal::DepthToSvn(depth), + force, + no_ignore, + add_parents, + *m_context, + pool); +#else + Q_UNUSED(add_parents); + svn_error_t * error = + svn_client_add3 (path.cstr (), + depth==DepthInfinity, + force, + no_ignore, + *m_context, + pool); +#endif + if(error != NULL) + throw ClientException (error); + } + + Revisions + Client_impl::update (const Targets & path, + const Revision & revision, + Depth depth, + bool ignore_externals, + bool allow_unversioned, + bool sticky_depth + ) throw (ClientException) + { + Pool pool; + Revisions resulting; + svn_error_t * error; + + apr_pool_t *apr_pool = pool.pool(); + apr_array_header_t *apr_revisions = apr_array_make (apr_pool, + path.size(), + sizeof (svn_revnum_t)); + if (depth==DepthUnknown) { + depth=DepthInfinity; + } +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + error = svn_client_update3(&apr_revisions,path.array(pool),revision,internal::DepthToSvn(depth),sticky_depth,ignore_externals,allow_unversioned,*m_context,pool); +#else + bool recurse = depth==DepthInfinity; + Q_UNUSED(sticky_depth); + Q_UNUSED(allow_unversioned); + error = svn_client_update2(&apr_revisions,path.array(pool),revision,recurse,ignore_externals,*m_context,pool); +#endif + if (error!=NULL) { + throw ClientException(error); + } + for (int i = 0; i < apr_revisions->nelts; ++i) + { + svn_revnum_t * _rev = + &APR_ARRAY_IDX (apr_revisions, i, svn_revnum_t); + + resulting.push_back((*_rev)); + } + return resulting; + } + + svn::Revision + Client_impl::commit (const Targets & targets, const QString& message, + svn::Depth depth,bool keep_locks, + const svn::StringArray&changelist, + const PropertiesMap&revProps, + bool keep_changelist) throw (ClientException) + { + Pool pool; + + m_context->setLogMessage (message); + svn_commit_info_t *commit_info = NULL; + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + svn_error_t * error = + svn_client_commit4 ( + &commit_info, + targets.array (pool), + internal::DepthToSvn(depth), + keep_locks, + keep_changelist, + changelist.array(pool), + map2hash(revProps,pool), + *m_context, + pool); +#else + Q_UNUSED(changelist); + Q_UNUSED(keep_changelist); + Q_UNUSED(revProps); + bool recurse = depth==DepthInfinity; + + svn_error_t * error = + svn_client_commit3 + (&commit_info, + targets.array (pool), + recurse, + keep_locks, + *m_context, + pool); +#endif + if (error != NULL) { + throw ClientException (error); + } + + if (commit_info && SVN_IS_VALID_REVNUM (commit_info->revision)) + return (commit_info->revision); + + return svn::Revision::UNDEFINED; + } + + Revision + Client_impl::copy(const Targets & srcPaths, + const Revision & srcRevision, + const Revision &pegRevision, + const Path & destPath, + bool asChild,bool makeParent, + const PropertiesMap&revProps + ) throw (ClientException) + { + if (srcPaths.size()<1) + { + throw ClientException("Wrong size of sources."); + } +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + Pool pool; + svn_commit_info_t *commit_info = 0L; + apr_array_header_t * sources = apr_array_make(pool,srcPaths.size(),sizeof(svn_client_copy_source_t *)); + for (size_t j=0;j<srcPaths.size();++j) + { + svn_client_copy_source_t* source = (svn_client_copy_source_t*)apr_palloc(pool, sizeof(svn_client_copy_source_t)); + source->path = apr_pstrdup(pool,srcPaths[j].path().TOUTF8()); + source->revision=srcRevision.revision(); + source->peg_revision=pegRevision.revision(); + APR_ARRAY_PUSH(sources, svn_client_copy_source_t *) = source; + } + svn_error_t * error = + svn_client_copy4(&commit_info, + sources, + destPath.cstr(), + asChild,makeParent,map2hash(revProps,pool),*m_context,pool); + if (error!=0){ + throw ClientException (error); + } + if (commit_info) { + return commit_info->revision; + } + return Revision::UNDEFINED; +#else + Q_UNUSED(asChild); + Q_UNUSED(makeParent); + Q_UNUSED(revProps); + Q_UNUSED(pegRevision); + Revision rev; + if (srcPaths.size()>1 && !asChild) + { + throw ClientException("Multiple sources not allowed"); + } + + Path _dest; + QString base,dir; + for (size_t j=0;j<srcPaths.size();++j) + { + _dest=destPath; + if (asChild) { + srcPaths[j].split(dir,base); + _dest.addComponent(base); + } + rev = copy(srcPaths[j],srcRevision,_dest); + } + return rev; +#endif + } + + Revision + Client_impl::copy (const Path & srcPath, + const Revision & srcRevision, + const Path & destPath) throw (ClientException) + { +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + return copy(srcPath,srcRevision,srcRevision,destPath,true,false); +#else + Pool pool; + svn_commit_info_t *commit_info = NULL; + svn_error_t * error = + svn_client_copy2 + (&commit_info, + srcPath.cstr (), + srcRevision.revision (), + destPath.cstr (), + *m_context, + pool); + + if(error != 0) { + throw ClientException (error); + } + if (commit_info) { + return commit_info->revision; + } + return Revision::UNDEFINED; +#endif + } + + svn::Revision Client_impl::move (const Path & srcPath, + const Path & destPath, + bool force) throw (ClientException) + { + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + return move(srcPath,destPath,force,false,false,PropertiesMap()); +#else + Pool pool; + svn_commit_info_t *commit_info = 0; + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 4)) + svn_error_t * error = svn_client_move4 +#else + svn_error_t * error = svn_client_move3 +#endif + (&commit_info, + srcPath.cstr (), + destPath.cstr (), + force, + *m_context, + pool); + + if(error != 0) { + throw ClientException (error); + } + if (commit_info) { + return commit_info->revision; + } + return Revision::UNDEFINED; +#endif + } + + svn::Revision Client_impl::move ( + const Targets & srcPaths, + const Path & destPath, + bool force, + bool asChild, + bool makeParent, + const PropertiesMap&revProps) throw (ClientException) + { +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + Pool pool; + svn_commit_info_t *commit_info = 0; + svn_error_t * error = svn_client_move5( + &commit_info, + srcPaths.array(pool), + destPath.cstr(), + force, + asChild, + makeParent, + map2hash(revProps,pool), + *m_context, + pool + ); + if (error!=0) { + throw ClientException (error); + } + if (commit_info) { + return commit_info->revision; + } + return Revision::UNDEFINED; +#else + Q_UNUSED(makeParent); + Q_UNUSED(revProps); + Revision rev; + if (srcPaths.size()>1 && !asChild) + { + throw ClientException("Multiple sources not allowed"); + } + QString base,dir; + Path _dest; + for (size_t j=0;j<srcPaths.size();++j) + { + _dest=destPath; + if (asChild) { + srcPaths[j].split(dir,base); + _dest.addComponent(base); + } + rev = move(srcPaths[j],_dest,force); + } + return rev; +#endif + } + + svn::Revision + Client_impl::mkdir (const Path & path, + const QString& message, + bool makeParent, + const PropertiesMap&revProps + ) throw (ClientException) + { + Targets targets(path.path()); + return mkdir(targets,message,makeParent,revProps); + } + + svn::Revision + Client_impl::mkdir (const Targets & targets, + const QString&msg, + bool makeParent, + const PropertiesMap&revProps + ) throw (ClientException) + { + Pool pool; + m_context->setLogMessage(msg); + + svn_commit_info_t *commit_info = NULL; + + svn_error_t * error = 0; + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + error = svn_client_mkdir3 + (&commit_info, + const_cast<apr_array_header_t*>(targets.array (pool)), + makeParent, + map2hash(revProps,pool), + *m_context, pool); +#else + Q_UNUSED(makeParent); + Q_UNUSED(revProps); + error = svn_client_mkdir2 + (&commit_info, + const_cast<apr_array_header_t*>(targets.array (pool)), + *m_context, pool); +#endif + + /* important! otherwise next op on repository uses that logmessage again! */ + m_context->setLogMessage(QString::null); + + if(error != NULL) + throw ClientException (error); + if (commit_info) { + return commit_info->revision; + } + return Revision::UNDEFINED; + } + + void + Client_impl::cleanup (const Path & path) throw (ClientException) + { + Pool subPool; + apr_pool_t * apr_pool = subPool.pool (); + + svn_error_t * error = + svn_client_cleanup (path.cstr (), *m_context, apr_pool); + + if(error != NULL) + throw ClientException (error); + } + + void Client_impl::resolve(const Path & path,Depth depth,const ConflictResult&resolution) throw (ClientException) + { + Pool pool; +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + const svn_wc_conflict_result_t*aResult=resolution.result(pool); + svn_error_t*error=svn_client_resolve(path.cstr(),internal::DepthToSvn(depth),aResult->choice,*m_context,pool); + +#else + Q_UNUSED(resolution); + bool recurse=depth==DepthInfinity; + svn_error_t * error = + svn_client_resolved (path.cstr (), + recurse, + *m_context, + pool); +#endif + if(error != NULL) { + throw ClientException (error); + } + } + + svn_revnum_t + Client_impl::doExport (const Path & srcPath, + const Path & destPath, + const Revision & revision, + const Revision & peg, + bool overwrite, + const QString&native_eol, + bool ignore_externals, + svn::Depth depth) throw (ClientException) + { + Pool pool; + svn_revnum_t revnum = 0; + const char*_neol; + if (native_eol==QString::null) { + _neol = (const char*)0; + } else { + _neol = native_eol.TOUTF8(); + } +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + svn_error_t * error = + svn_client_export4(&revnum, + srcPath.cstr(), + destPath.cstr(), + peg.revision(), + revision.revision(), + overwrite, + ignore_externals, + internal::DepthToSvn(depth), + _neol, + *m_context, + pool); +#else + bool recurse = depth==svn::DepthInfinity; + svn_error_t * error = + svn_client_export3(&revnum, + srcPath.cstr(), + destPath.cstr(), + peg.revision(), + revision.revision(), + overwrite, + ignore_externals, + recurse, + _neol, + *m_context, + pool); +#endif + if(error != NULL) + throw ClientException (error); + return revnum; + } + + svn_revnum_t + Client_impl::doSwitch ( + const Path & path, const QString& url, + const Revision & revision, + Depth depth, + const Revision & peg, + bool sticky_depth, + bool ignore_externals, + bool allow_unversioned + ) throw (ClientException) + { + Pool pool; + svn_revnum_t revnum = 0; + svn_error_t * error = 0; + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + error = svn_client_switch2( + &revnum, + path.cstr(), + url.TOUTF8(), + peg.revision(), + revision.revision(), + internal::DepthToSvn(depth), + sticky_depth, + ignore_externals, + allow_unversioned, + *m_context, + pool + ); +#else + bool recurse = depth==DepthInfinity; + Q_UNUSED(peg); + Q_UNUSED(sticky_depth); + Q_UNUSED(ignore_externals); + Q_UNUSED(allow_unversioned); + error = svn_client_switch (&revnum, + path.cstr(), + url.TOUTF8(), + revision.revision (), + recurse, + *m_context, + pool); +#endif + if(error != NULL) { + throw ClientException (error); + } + return revnum; + } + + Revision + Client_impl::import (const Path & path, + const QString& url, + const QString& message, + svn::Depth depth, + bool no_ignore,bool no_unknown_nodetype, + const PropertiesMap&revProps + ) throw (ClientException) + + { + svn_commit_info_t *commit_info = NULL; + Pool pool; + + m_context->setLogMessage (message); +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + svn_error_t * error = + svn_client_import3(&commit_info,path.cstr (),url.TOUTF8(), + internal::DepthToSvn(depth),no_ignore,no_unknown_nodetype, + map2hash(revProps,pool), + *m_context,pool); +#else + bool recurse = depth==DepthInfinity; + Q_UNUSED(revProps); + Q_UNUSED(no_unknown_nodetype); + + svn_error_t * error = + svn_client_import2(&commit_info, + path.cstr (), + url.TOUTF8(), + !recurse, + no_ignore, + *m_context, + pool); +#endif + /* important! otherwise next op on repository uses that logmessage again! */ + m_context->setLogMessage(QString::null); + + if(error != 0) { + throw ClientException (error); + } + if (commit_info) { + return commit_info->revision; + } + return Revision::UNDEFINED; + } + + void + Client_impl::relocate (const Path & path, + const QString& from_url, + const QString& to_url, + bool recurse) throw (ClientException) + { + Pool pool; + svn_error_t * error = + svn_client_relocate (path.cstr (), + from_url.TOUTF8(), + to_url.TOUTF8(), + recurse, + *m_context, + pool); + + if(error != NULL) + throw ClientException (error); + } + +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/client_property.cpp b/src/svnqt/client_property.cpp new file mode 100644 index 0000000..6438ff6 --- /dev/null +++ b/src/svnqt/client_property.cpp @@ -0,0 +1,450 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ +#if defined( _MSC_VER) && _MSC_VER <= 1200 +#pragma warning( disable: 4786 )// debug symbol truncated +#endif +// svncpp +#include "svnqt/client_impl.hpp" + +// subversion api +#include "svn_client.h" +//#include "svn_utf.h" + +#include "svnqt/path.hpp" +#include "svnqt/exception.hpp" +#include "svnqt/pool.hpp" +#include "svnqt/revision.hpp" +#include "svnqt/svnqt_defines.hpp" + +#include "svnqt/helper.hpp" + + +namespace svn +{ + + static svn_error_t* ProplistReceiver(void*baton,const char*path,apr_hash_t*prop_hash,apr_pool_t*pool) + { + Client_impl::propBaton*_baton=(Client_impl::propBaton*)baton; + PropertiesMap prop_map; + PathPropertiesMapList*mapList = (PathPropertiesMapList*)_baton->resultlist; + + Context*l_context = _baton->m_context; + svn_client_ctx_t*ctx = l_context->ctx(); + if (ctx&&ctx->cancel_func) { + SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); + } + + apr_hash_index_t *hi; + for (hi = apr_hash_first (pool, prop_hash); hi; + hi = apr_hash_next (hi)) + { + const void *key; + void *val; + + apr_hash_this (hi, &key, NULL, &val); + prop_map[ QString::FROMUTF8( (const char *)key ) ] = + QString::FROMUTF8( ((const svn_string_t *)val)->data ); + } + mapList->push_back(PathPropertiesMapEntry(QString::FROMUTF8(path), prop_map )); + return 0; + } + + PathPropertiesMapListPtr + Client_impl::proplist(const Path &path, + const Revision &revision, + const Revision &peg, + Depth depth, + const StringArray&changelists) + { + Pool pool; + + PathPropertiesMapListPtr path_prop_map_list = PathPropertiesMapListPtr(new PathPropertiesMapList); + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + propBaton baton; + baton.m_context=m_context; + baton.resultlist=path_prop_map_list; + svn_error_t * error = + svn_client_proplist3( + path.cstr (), + peg.revision(), + revision.revision (), + internal::DepthToSvn(depth), + changelists.array(pool), + ProplistReceiver, + &baton, + *m_context, + pool); +#else + Q_UNUSED(changelists); + Q_UNUSED(ProplistReceiver); + bool recurse=depth==DepthInfinity; + apr_array_header_t * props; + svn_error_t * error = + svn_client_proplist2(&props, + path.cstr (), + peg.revision(), + revision.revision (), + recurse, + *m_context, + pool); + +#endif + if(error != NULL) + { + throw ClientException (error); + } + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR < 5)) + for (int j = 0; j < props->nelts; ++j) + { + svn_client_proplist_item_t *item = + ((svn_client_proplist_item_t **)props->elts)[j]; + + PropertiesMap prop_map; + + apr_hash_index_t *hi; + for (hi = apr_hash_first (pool, item->prop_hash); hi; + hi = apr_hash_next (hi)) + { + const void *key; + void *val; + + apr_hash_this (hi, &key, NULL, &val); + prop_map[ QString::FROMUTF8( (const char *)key ) ] = + QString::FROMUTF8( ((const svn_string_t *)val)->data ); + } + + path_prop_map_list->push_back( PathPropertiesMapEntry( QString::FROMUTF8(item->node_name->data), prop_map ) ); + } +#endif + return path_prop_map_list; + } + + QPair<QLONG,PathPropertiesMapList> + Client_impl::propget(const QString& propName, + const Path &path, + const Revision &revision, + const Revision &peg, + Depth depth, + const StringArray&changelists + ) + { + Pool pool; + + apr_hash_t *props; + svn_revnum_t actual = svn_revnum_t(-1); +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + svn_error_t * error = svn_client_propget3(&props, + propName.TOUTF8(), + path.cstr (), + peg.revision(), + revision.revision (), + &actual, + internal::DepthToSvn(depth), + changelists.array(pool), + *m_context, + pool + ); +#else + bool recurse=depth==DepthInfinity; + Q_UNUSED(changelists); + svn_error_t * error = + svn_client_propget2(&props, + propName.TOUTF8(), + path.cstr (), + peg.revision(), + revision.revision (), + recurse, + *m_context, + pool); +#endif + + if(error != NULL) + { + throw ClientException (error); + } + + PathPropertiesMapList path_prop_map_list; + + + apr_hash_index_t *hi; + for (hi = apr_hash_first (pool, props); hi; + hi = apr_hash_next (hi)) + { + PropertiesMap prop_map; + + const void *key; + void *val; + + apr_hash_this (hi, &key, NULL, &val); + prop_map[propName] = QString::FROMUTF8( ((const svn_string_t *)val)->data ); + path_prop_map_list.push_back( PathPropertiesMapEntry(QString::FROMUTF8((const char *)key), prop_map ) ); + } + + return QPair<QLONG,PathPropertiesMapList>(actual,path_prop_map_list); + } + + void + Client_impl::propset(const QString& propName, + const QString& propValue, + const Path &path, + Depth depth, + bool skip_checks, + const Revision&base_revision, + const StringArray&changelists, + const PropertiesMap&revProps + ) + { + Pool pool; + const svn_string_t * propval; + + if (propValue.isNull()) { + propval=0; + } else { + propval = svn_string_create (propValue.TOUTF8(),pool); + } + + svn_error_t * error = 0; +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + svn_commit_info_t * commit_info; + svn_client_propset3( + &commit_info, + propName.TOUTF8(), + propval, path.cstr(), + internal::DepthToSvn(depth),skip_checks, + base_revision, + changelists.array(pool), + map2hash(revProps,pool), + *m_context, pool); + +#else + Q_UNUSED(changelists); + Q_UNUSED(base_revision); + Q_UNUSED(revProps); + bool recurse = depth==DepthInfinity; + svn_client_propset2( + propName.TOUTF8(), + propval, path.cstr(), + recurse,skip_checks, *m_context, pool); +#endif + if(error != NULL) { + throw ClientException (error); + } + } + + void + Client_impl::propdel(const QString& propName, + const Path &path, + Depth depth, + bool skip_checks, + const Revision&base_revision, + const StringArray&changelists) + { + propset(propName,QString::null,path,depth,skip_checks,base_revision,changelists); + } + +//-------------------------------------------------------------------------------- +// +// revprop functions +// +//-------------------------------------------------------------------------------- + /** + * lists revision properties in @a path no matter whether local or + * repository + * + * @param path + * @param revision + * @param recurse + * @return PropertiesList + */ + QPair<QLONG,PropertiesMap> + Client_impl::revproplist(const Path &path, + const Revision &revision) + { + Pool pool; + + apr_hash_t * props; + svn_revnum_t revnum; + svn_error_t * error = + svn_client_revprop_list (&props, + path.cstr (), + revision.revision (), + &revnum, + *m_context, + pool); + if(error != NULL) + { + throw ClientException (error); + } + + PropertiesMap prop_map; + + apr_hash_index_t *hi; + for (hi = apr_hash_first (pool, props); hi; + hi = apr_hash_next (hi)) + { + const void *key; + void *val; + + apr_hash_this (hi, &key, NULL, &val); + prop_map[ QString::FROMUTF8( (const char *)key ) ] = QString::FROMUTF8( ((const svn_string_t *)val)->data ); + } + + return QPair<QLONG,PropertiesMap>( revnum, prop_map ); + } + + /** + * lists one revision property in @a path no matter whether local or + * repository + * + * @param path + * @param revision + * @param recurse + * @return PropertiesList + */ + + QPair<QLONG,QString> + Client_impl::revpropget(const QString& propName, + const Path &path, + const Revision &revision) + { + Pool pool; + + svn_string_t *propval; + svn_revnum_t revnum; + svn_error_t * error = + svn_client_revprop_get ( + propName.TOUTF8(), + &propval, + path.cstr (), + revision.revision (), + &revnum, + *m_context, + pool); + if(error != NULL) + { + throw ClientException (error); + } + + // if the property does not exist NULL is returned + if( propval == NULL ) + return QPair<QLONG,QString>( 0, QString() ); + + return QPair<QLONG,QString>( revnum, QString::FROMUTF8(propval->data) ); + } + + /** + * set property in @a path no matter whether local or + * repository + * + * @param path + * @param revision + * @param propName + * @param propValue + * @param recurse + * @param revprop + * @return PropertiesList + */ + QLONG + Client_impl::revpropset(const QString& propName, + const QString& propValue, + const Path &path, + const Revision &revision, + bool force) + { + Pool pool; + + const svn_string_t * propval + = svn_string_create ( + propValue.TOUTF8(), + pool); + + svn_revnum_t revnum; + svn_error_t * error = + svn_client_revprop_set ( + propName.TOUTF8(), + propval, + path.cstr (), + revision.revision (), + &revnum, + force, + *m_context, + pool); + if(error != NULL) + throw ClientException (error); + + return revnum; + } + + /** + * delete property in @a path no matter whether local or + * repository + * + * @param path + * @param revision + * @param propName + * @param propValue + * @param recurse + * @param revprop + * @return PropertiesList + */ + QLONG + Client_impl::revpropdel(const QString& propName, + const Path &path, + const Revision &revision, + bool force) + { + Pool pool; + + svn_revnum_t revnum; + svn_error_t * error = + svn_client_revprop_set ( + propName.TOUTF8(), + 0, // value = NULL + path.cstr (), + revision.revision (), + &revnum, + force, + *m_context, + pool); + if(error != NULL) + throw ClientException (error); + + return revnum; + } + +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/client_status.cpp b/src/svnqt/client_status.cpp new file mode 100644 index 0000000..17f51e6 --- /dev/null +++ b/src/svnqt/client_status.cpp @@ -0,0 +1,736 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2008 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ +#if defined( _MSC_VER) && _MSC_VER <= 1200 +#pragma warning( disable: 4786 )// debug symbol truncated +#endif + + +// svncpp +#include "svnqt/client_impl.hpp" +#include "svnqt/helper.hpp" + +// Subversion api +#include "svn_client.h" +#include "svn_sorts.h" +#include "svn_path.h" +//#include "svn_utf.h" + +#include "svnqt/dirent.hpp" +#include "svnqt/exception.hpp" +#include "svnqt/pool.hpp" +#include "svnqt/status.hpp" +#include "svnqt/targets.hpp" +#include "svnqt/info_entry.hpp" +#include "svnqt/url.hpp" +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/context_listener.hpp" + +namespace svn +{ + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + static svn_error_t * + logReceiver2( + void*baton, + svn_log_entry_t *log_entry, + apr_pool_t * pool + ) + { + Client_impl::sBaton * l_baton = (Client_impl::sBaton*)baton; + LogEntries * entries = + (LogEntries *) l_baton->m_data; + QLIST<QLONG>*rstack= + (QLIST<QLONG>*)l_baton->m_revstack; + Context*l_context = l_baton->m_context; + svn_client_ctx_t*ctx = l_context->ctx(); + if (ctx&&ctx->cancel_func) { + SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); + } + if (! SVN_IS_VALID_REVNUM(log_entry->revision)) + { + if (rstack&&rstack->size()>0) { + rstack->pop_front(); + } + return SVN_NO_ERROR; + } + entries->insert (entries->begin (), LogEntry (log_entry)); + if (rstack) { + entries->first().m_MergedInRevisions=(*rstack); + if (log_entry->has_children) { + rstack->push_front(log_entry->revision); + } + } + return SVN_NO_ERROR; + } +#else + static svn_error_t * + logReceiver ( + void *baton, + apr_hash_t * changedPaths, + svn_revnum_t rev, + const char *author, + const char *date, + const char *msg, + apr_pool_t * pool + ) + { + Client_impl::sBaton * l_baton = (Client_impl::sBaton*)baton; + LogEntries * entries = + (LogEntries *) l_baton->m_data; + + /* check every loop for cancel of operation */ + Context*l_context = l_baton->m_context; + svn_client_ctx_t*ctx = l_context->ctx(); + if (ctx&&ctx->cancel_func) { + SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); + } + entries->insert (entries->begin (), LogEntry (rev, author, date, msg)); + if (changedPaths != NULL) + { + LogEntry &entry = entries->front (); + + for (apr_hash_index_t *hi = apr_hash_first (pool, changedPaths); + hi != NULL; + hi = apr_hash_next (hi)) + { + const void *pv; + void *val; + apr_hash_this (hi, &pv, NULL, &val); + + svn_log_changed_path_t *log_item = reinterpret_cast<svn_log_changed_path_t *> (val); + const char* path = reinterpret_cast<const char*>(pv); + + entry.changedPaths.push_back ( + LogChangePathEntry (path, + log_item->action, + log_item->copyfrom_path, + log_item->copyfrom_rev) ); + + } + } + + return SVN_NO_ERROR; + } +#endif + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + static svn_error_t * + logMapReceiver2( + void*baton, + svn_log_entry_t *log_entry, + apr_pool_t * pool + ) + { + Client_impl::sBaton * l_baton = (Client_impl::sBaton*)baton; + LogEntriesMap * entries = + (LogEntriesMap *) l_baton->m_data; + Context*l_context = l_baton->m_context; + QLIST<QLONG>*rstack= + (QLIST<QLONG>*)l_baton->m_revstack; + svn_client_ctx_t*ctx = l_context->ctx(); + if (ctx&&ctx->cancel_func) { + SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); + } + if (! SVN_IS_VALID_REVNUM(log_entry->revision)) + { + if (rstack&&rstack->size()>0) { + rstack->pop_front(); + } + return SVN_NO_ERROR; + } + (*entries)[log_entry->revision]=LogEntry (log_entry); + /// @TODO insert it into last logentry + if (rstack) { + (*entries)[log_entry->revision].m_MergedInRevisions=(*rstack); + if (log_entry->has_children) { + rstack->push_front(log_entry->revision); + } + } + return SVN_NO_ERROR; + } +#else + static svn_error_t * + logMapReceiver (void *baton, + apr_hash_t * changedPaths, + svn_revnum_t rev, + const char *author, + const char *date, + const char *msg, + apr_pool_t * pool + ) + { + Client_impl::sBaton * l_baton = (Client_impl::sBaton*)baton; + LogEntriesMap * entries = + (LogEntriesMap *) l_baton->m_data; + + /* check every loop for cancel of operation */ + Context*l_context = l_baton->m_context; + svn_client_ctx_t*ctx = l_context->ctx(); + if (ctx&&ctx->cancel_func) { + SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); + } + (*entries)[rev]=LogEntry(rev, author, date, msg); + if (changedPaths != NULL) + { + LogEntry &entry = (*entries)[rev]; + + for (apr_hash_index_t *hi = apr_hash_first (pool, changedPaths); + hi != NULL; + hi = apr_hash_next (hi)) + { + const void *pv; + void *val; + apr_hash_this (hi, &pv, NULL, &val); + + svn_log_changed_path_t *log_item = reinterpret_cast<svn_log_changed_path_t *> (val); + const char* path = reinterpret_cast<const char*>(pv); + + entry.changedPaths.push_back ( + LogChangePathEntry (path, + log_item->action, + log_item->copyfrom_path, + log_item->copyfrom_rev) ); + + } + } + + return NULL; + } +#endif + + struct StatusEntriesBaton { + apr_pool_t* pool; + apr_hash_t* hash; + Context*m_Context; + StatusEntriesBaton() { + pool = 0; + hash = 0; + m_Context = 0; + } + }; + + static svn_error_t * InfoEntryFunc(void*baton, + const char*path, + const svn_info_t*info, + apr_pool_t *) + { + StatusEntriesBaton* seb = (StatusEntriesBaton*)baton; + if (seb->m_Context) { + /* check every loop for cancel of operation */ + Context*l_context = seb->m_Context; + svn_client_ctx_t*ctx = l_context->ctx(); + if (ctx&&ctx->cancel_func) { + SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); + } + } + path = apr_pstrdup (seb->pool, path); + InfoEntry*e = new InfoEntry(info,path); + apr_hash_set (seb->hash, path, APR_HASH_KEY_STRING, e); + return NULL; + } + + static void StatusEntriesFunc (void *baton, + const char *path, + svn_wc_status2_t *status) + { + svn_wc_status2_t* stat; + StatusEntriesBaton* seb = (StatusEntriesBaton*)baton; + + path = apr_pstrdup (seb->pool, path); + stat = svn_wc_dup_status2 (status, seb->pool); + apr_hash_set (seb->hash, path, APR_HASH_KEY_STRING, stat); + } + + static StatusEntries + localStatus (const Path& path, + Depth depth, + const bool get_all, + const bool update, + const bool no_ignore, + const bool hide_externals, + const StringArray & changelists, + Context * context) + { + svn_error_t *error; + StatusEntries entries; + apr_hash_t *status_hash; + svn_revnum_t revnum; + Revision rev (Revision::HEAD); + Pool pool; + StatusEntriesBaton baton; + + status_hash = apr_hash_make (pool); + baton.hash = status_hash; + baton.pool = pool; +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + error = svn_client_status3 ( + &revnum, // revnum + path.path().TOUTF8(), // path + rev, + StatusEntriesFunc, // status func + &baton, // status baton + internal::DepthToSvn(depth), // see svn::Depth + get_all, // get all not only interesting + update, // check for updates + no_ignore, // hide ignored files or not + hide_externals, // hide external + changelists.array(pool), + *context, //client ctx + pool); +#else + Q_UNUSED(changelists); + error = svn_client_status2 ( + &revnum, // revnum + path.path().TOUTF8(), // path + rev, + StatusEntriesFunc, // status func + &baton, // status baton + (depth==DepthInfinity), //recurse + get_all, // get all not only interesting + update, // check for updates + no_ignore, // hide ignored files or not + hide_externals, // hide external + *context, //client ctx + pool); +#endif + + if (error!=NULL) + { + throw ClientException (error); + } + + apr_array_header_t *statusarray = + svn_sort__hash (status_hash, svn_sort_compare_items_as_paths, + pool); + int i; + + /* Loop over array, printing each name/status-structure */ + for (i = 0; i < statusarray->nelts; ++i) + { + const svn_sort__item_t *item; + const char *filePath; + svn_wc_status2_t *status = NULL; + + item = &APR_ARRAY_IDX (statusarray, i, const svn_sort__item_t); + status = (svn_wc_status2_t *) item->value; + + filePath = (const char *) item->key; + entries.push_back (StatusPtr(new Status(filePath, status))); + } + return entries; + } + + static StatusPtr + dirEntryToStatus (const Path& path, DirEntryPtr dirEntry) + { + QString url = path.path(); + url += QString::FROMUTF8("/"); + url += dirEntry->name(); + return StatusPtr(new Status (url, dirEntry)); + } + + static StatusPtr + infoEntryToStatus(const Path&,const InfoEntry&infoEntry) + { + return StatusPtr(new Status(infoEntry.url(),infoEntry)); + } + + static StatusEntries + remoteStatus (Client * client, + const Path& path, + Depth depth, + const bool , + const bool , + const bool , + const Revision revision, + Context * , + bool detailed_remote) + { + DirEntries dirEntries = client->list(path, revision, revision, depth,detailed_remote); + DirEntries::const_iterator it; + + StatusEntries entries; + QString url = path.path(); + url+=QString::FROMUTF8("/"); + + for (it = dirEntries.begin (); it != dirEntries.end (); it++) + { + DirEntryPtr dirEntry = *it; + if (dirEntry->name().isEmpty()) + continue; + entries.push_back(dirEntryToStatus (path, dirEntry)); + } + return entries; + } + + StatusEntries + Client_impl::status (const Path& path, + Depth depth, + const bool get_all, + const bool update, + const bool no_ignore, + const Revision revision, + bool detailed_remote, + const bool hide_externals, + const StringArray & changelists) throw (ClientException) + { + if (Url::isValid (path.path())) { + return remoteStatus (this, path, depth, get_all, update, + no_ignore,revision,m_context,detailed_remote); + } else { + return localStatus (path, depth, get_all, update, + no_ignore, hide_externals,changelists, m_context); + } + } + + static StatusPtr + localSingleStatus (const Path& path, Context * context,bool update=false) + { + svn_error_t *error; + apr_hash_t *status_hash; + Pool pool; + StatusEntriesBaton baton; + svn_revnum_t revnum; + Revision rev (Revision::HEAD); + + status_hash = apr_hash_make( pool ); + baton.hash = status_hash; + baton.pool = pool; + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + error = svn_client_status3 ( + &revnum, // revnum + path.path().TOUTF8(), // path + rev, + StatusEntriesFunc, // status func + &baton, // status baton + svn_depth_empty, // not recurse + true, // get all not only interesting + update, // check for updates + false, // hide ignored files or not + false, // hide external + 0, + *context, //client ctx + pool); +#else + error = svn_client_status2 ( + &revnum, // revnum + path.path().TOUTF8(), // path + rev, + StatusEntriesFunc, // status func + &baton, // status baton + false, + true, + update, + false, + false, + *context, //client ctx + pool); +#endif + if (error != NULL) + { + throw ClientException (error); + } + + apr_array_header_t *statusarray = + svn_sort__hash (status_hash, svn_sort_compare_items_as_paths, + pool); + const svn_sort__item_t *item; + const char *filePath; + svn_wc_status2_t *status = NULL; + + item = &APR_ARRAY_IDX (statusarray, 0, const svn_sort__item_t); + status = (svn_wc_status2_t *) item->value; + filePath = (const char *) item->key; + + return StatusPtr(new Status (filePath, status)); + }; + + static StatusPtr + remoteSingleStatus (Client * client, const Path& path,const Revision revision, Context * ) + { + InfoEntries infoEntries = client->info(path,DepthEmpty,revision,Revision(Revision::UNDEFINED)); + if (infoEntries.size () == 0) + return StatusPtr(new Status()); + else + return infoEntryToStatus (path, infoEntries [0]); + } + + StatusPtr + Client_impl::singleStatus (const Path& path,bool update,const Revision revision) throw (ClientException) + { + if (Url::isValid (path.path())) + return remoteSingleStatus (this, path,revision, m_context); + else + return localSingleStatus (path, m_context,update); + } + + bool + Client_impl::log (const Path& path, const Revision & revisionStart, + const Revision & revisionEnd, + LogEntriesMap&log_target, + const Revision & revisionPeg, + bool discoverChangedPaths, + bool strictNodeHistory,int limit, + bool include_merged_revisions, + const StringArray&revprops + ) throw (ClientException) + { + Targets target(path); + Pool pool; + sBaton l_baton; + QLIST<QLONG> revstack; + l_baton.m_context=m_context; + l_baton.m_data = &log_target; + l_baton.m_revstack = &revstack; + svn_error_t *error; + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + error = svn_client_log4 ( + target.array (pool), + revisionPeg.revision(), + revisionStart.revision (), + revisionEnd.revision (), + limit, + discoverChangedPaths ? 1 : 0, + strictNodeHistory ? 1 : 0, + include_merged_revisions?1:0, + revprops.array(pool), + logMapReceiver2, + &l_baton, + *m_context, // client ctx + pool); +#elif ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 4)) || (SVN_VER_MAJOR > 1) + Q_UNUSED(include_merged_revisions); + Q_UNUSED(revprops); + + error = svn_client_log3 ( + target.array (pool), + revisionPeg.revision(), + revisionStart.revision (), + revisionEnd.revision (), + limit, + discoverChangedPaths ? 1 : 0, + strictNodeHistory ? 1 : 0, + logMapReceiver, + &l_baton, + *m_context, // client ctx + pool); +#else + Q_UNUSED(include_merged_revisions); + Q_UNUSED(revprops); + Q_UNUSED(revisionPeg); + + error = svn_client_log2 ( + target.array (pool), + revisionStart.revision (), + revisionEnd.revision (), + limit, + discoverChangedPaths ? 1 : 0, + strictNodeHistory ? 1 : 0, + logMapReceiver, + &l_baton, + *m_context, // client ctx + pool); +#endif + if (error != NULL) + { + throw ClientException (error); + } + return true; + } + + LogEntriesPtr + Client_impl::log (const Path& path, const Revision & revisionStart, + const Revision & revisionEnd, const Revision & revisionPeg, + bool discoverChangedPaths, + bool strictNodeHistory,int limit, + bool include_merged_revisions, + const StringArray&revprops + ) throw (ClientException) + { + Targets target(path); + Pool pool; + LogEntriesPtr entries = LogEntriesPtr(new LogEntries ()); + QLIST<QLONG> revstack; + sBaton l_baton; + l_baton.m_context=m_context; + l_baton.m_data = entries; + l_baton.m_revstack = &revstack; + + svn_error_t *error; +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + error = svn_client_log4 ( + target.array (pool), + revisionPeg.revision(), + revisionStart.revision (), + revisionEnd.revision (), + limit, + discoverChangedPaths ? 1 : 0, + strictNodeHistory ? 1 : 0, + include_merged_revisions?1:0, + revprops.array(pool), + logReceiver2, + &l_baton, + *m_context, // client ctx + pool); +#elif ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 4)) || (SVN_VER_MAJOR > 1) + Q_UNUSED(include_merged_revisions); + Q_UNUSED(revprops); + + error = svn_client_log3 ( + target.array (pool), + revisionPeg.revision(), + revisionStart.revision (), + revisionEnd.revision (), + limit, + discoverChangedPaths ? 1 : 0, + strictNodeHistory ? 1 : 0, + logReceiver, + &l_baton, + *m_context, // client ctx + pool); +#else + Q_UNUSED(include_merged_revisions); + Q_UNUSED(revprops); + Q_UNUSED(revisionPeg); + + error = svn_client_log2 ( + target.array (pool), + revisionStart.revision (), + revisionEnd.revision (), + limit, + discoverChangedPaths ? 1 : 0, + strictNodeHistory ? 1 : 0, + logReceiver, + &l_baton, + *m_context, // client ctx + pool); +#endif + if (error != NULL) + { + throw ClientException (error); + } + + return entries; + } + + InfoEntries + Client_impl::info(const Path& _p, + Depth depth, + const Revision & rev, + const Revision & peg_revision, + const StringArray&changelists + ) throw (ClientException) + { + + InfoEntries ientries; + Pool pool; + svn_error_t *error = NULL; + StatusEntriesBaton baton; + apr_hash_t *status_hash; + + status_hash = apr_hash_make (pool); + baton.hash = status_hash; + baton.pool = pool; + baton.m_Context=m_context; + svn_opt_revision_t pegr; + const char *truepath = 0; + bool internal_peg = false; + QByteArray _buf = _p.cstr(); + + error = svn_opt_parse_path(&pegr, &truepath, + _buf, + pool); + if (error != NULL) + throw ClientException (error); + + if (peg_revision.kind() == svn_opt_revision_unspecified) { + if ((svn_path_is_url (_p.cstr())) && (pegr.kind == svn_opt_revision_unspecified)) { + pegr.kind = svn_opt_revision_head; + internal_peg=true; + } + } + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + error = + svn_client_info2(truepath, + internal_peg?&pegr:peg_revision.revision(), + rev.revision (), + &InfoEntryFunc, + &baton, + internal::DepthToSvn(depth), + changelists.array(pool), + *m_context, //client ctx + pool); +#else + bool rec = depth==DepthInfinity; + Q_UNUSED(changelists); + error = + svn_client_info(truepath, + internal_peg?&pegr:peg_revision.revision(), + rev.revision (), + &InfoEntryFunc, + &baton, + rec, + *m_context, //client ctx + pool); +#endif + + if (error != NULL) + throw ClientException (error); + + apr_array_header_t *statusarray = + svn_sort__hash (status_hash, svn_sort_compare_items_as_paths, + pool); + int i; + + /* Loop over array, printing each name/status-structure */ + for (i=0; i< statusarray->nelts; ++i) + { + const svn_sort__item_t *item; + InfoEntry*e = NULL; + item = &APR_ARRAY_IDX (statusarray, i, const svn_sort__item_t); + e = (InfoEntry *) item->value; + ientries.push_back(*e); + delete e; + } + if (error != NULL) + throw ClientException (error); + return ientries; + } + +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/cmakemodules/FindSqlite.cmake b/src/svnqt/cmakemodules/FindSqlite.cmake new file mode 100644 index 0000000..3c50d33 --- /dev/null +++ b/src/svnqt/cmakemodules/FindSqlite.cmake @@ -0,0 +1,32 @@ +IF (SQLITE_INCLUDE_DIR AND SQLITE_LIBRARIES) + SET(SQLITE_FOUND TRUE) +ELSE (SQLITE_INCLUDE_DIR AND SQLITE_LIBRARIES) + INCLUDE(UsePkgConfig) + PKGCONFIG(sqlite3 _sqliteincdir _sqlitelibdir _sqlitelinkflags _sqlitecflags) + + FIND_PATH(SQLITE_INCLUDE_DIR sqlite3.h + ${_sqliteincdir} + /usr/include + /usr/local/include + ) + FIND_LIBRARY(SQLITE_LIBRARIES NAMES sqlite3 + PATHS + ${_sqlitelibdir} + /usr/lib + /usr/local/lib + ) + + IF (SQLITE_INCLUDE_DIR AND SQLITE_LIBRARIES) + SET(SQLITE_FOUND TRUE) + ENDIF (SQLITE_INCLUDE_DIR AND SQLITE_LIBRARIES) + + IF (SQLITE_FOUND) + MESSAGE(STATUS "Found sqlite3: ${SQLITE_LIBRARIES}") + ELSE (SQLITE_FOUND) + MESSAGE(STATUS "Could not find sqlite3") + ADD_DEFINITIONS(-DNO_SQLITE3) + ENDIF (SQLITE_FOUND) + + MARK_AS_ADVANCED(SQLITE_LIBRARIES SQLITE_INCLUDE_DIR) + +ENDIF (SQLITE_INCLUDE_DIR AND SQLITE_LIBRARIES) diff --git a/src/svnqt/cmakemodules/FindSubversion.cmake b/src/svnqt/cmakemodules/FindSubversion.cmake new file mode 100644 index 0000000..358ee3a --- /dev/null +++ b/src/svnqt/cmakemodules/FindSubversion.cmake @@ -0,0 +1,352 @@ +SET(SUBVERSIONFOUND) +SET(SUBVERSION_ALL_LIBS) + +INCLUDE (CheckIncludeFiles) + +#search libraries for UNIX +IF (UNIX) + + MACRO(FIND_SUB_LIB targetvar libname) + IF (SUBVERSION_INSTALL_PATH) + FIND_LIBRARY(${targetvar} ${libname} + PATHS + ${SUBVERSION_INSTALL_PATH}/lib + NO_DEFAULT_PATH + ) + ENDIF(SUBVERSION_INSTALL_PATH) + FIND_LIBRARY(${targetvar} ${libname} + PATHS + /usr/lib + /usr/local/lib + ) + ENDMACRO(FIND_SUB_LIB) + + IF (SUBVERSION_INSTALL_PATH) + FIND_PATH(SUBVERSION_INCLUDE_DIR svn_client.h + PATHS + ${SUBVERSION_INSTALL_PATH}/include/subversion-1 + NO_DEFAULT_PATH + ) + ENDIF (SUBVERSION_INSTALL_PATH) + FIND_PATH(SUBVERSION_INCLUDE_DIR svn_client.h + /usr/include/subversion-1 + /usr/local/include/subversion-1) + + FIND_SUB_LIB(SUBVERSION_CLIENTLIB svn_client-1) + FIND_SUB_LIB(SUBVERSION_REPOSITORYLIB svn_repos-1) + FIND_SUB_LIB(SUBVERSION_WCLIB svn_wc-1) + FIND_SUB_LIB(SUBVERSION_FSLIB svn_fs-1) + FIND_SUB_LIB(SUBVERSION_SUBRLIB svn_subr-1) + FIND_SUB_LIB(SUBVERSION_RALIB svn_ra-1) + FIND_SUB_LIB(SUBVERSION_DIFFLIB svn_diff-1) + + FIND_PROGRAM(APR_CONFIG NAMES apr-config apr-1-config + PATHS + /usr/local/apr/bin + ) + + FIND_PROGRAM(APU_CONFIG NAMES apu-config apu-1-config + PATHS + /usr/local/apr/bin + ) + + if(NOT APR_CONFIG) + MESSAGE(SEND_ERROR "Error: no apr-config found") + endif(NOT APR_CONFIG) + + if(NOT APU_CONFIG) + MESSAGE(SEND_ERROR "Error: no apu-config found") + endif(NOT APU_CONFIG) + + EXEC_PROGRAM(${APR_CONFIG} ARGS "--includedir" OUTPUT_VARIABLE APR_INCLUDE_DIR) + EXEC_PROGRAM(${APU_CONFIG} ARGS "--includedir" OUTPUT_VARIABLE APU_INCLUDE_DIR) + + EXEC_PROGRAM(${APR_CONFIG} ARGS "--cppflags" OUTPUT_VARIABLE APR_CPP_FLAGS) + EXEC_PROGRAM(${APU_CONFIG} ARGS "--cppflags" OUTPUT_VARIABLE APU_CPP_FLAGS) + + EXEC_PROGRAM(${APR_CONFIG} ARGS "--ldflags --libs --link-ld" OUTPUT_VARIABLE APR_EXTRA_LIBFLAGS) + EXEC_PROGRAM(${APU_CONFIG} ARGS "--ldflags --libs --link-ld" OUTPUT_VARIABLE APU_EXTRA_LIBFLAGS) + + CHECK_INCLUDE_FILES(execinfo.h HAS_BACKTRACE_H) + +ENDIF (UNIX) + +#search libaries for Windows +IF (WIN32) + + # search for pathes + FIND_PATH (SUBVERSION_BIN_DIR svn.exe + "$ENV{ProgramFiles}/Subversion/bin" + ) + + FIND_PATH (SUBVERSION_INCLUDE_DIR svn_client.h + "$ENV{ProgramFiles}/Subversion/include" + ) + + FIND_PATH(APR_INCLUDE_DIR apr.h + "$ENV{ProgramFiles}/Subversion/include/apr" + ) + + FIND_PATH(APU_INCLUDE_DIR apu.h + "$ENV{ProgramFiles}/Subversion/include/apr-util" + ) + + # search for libraries + FIND_LIBRARY(APR_LIB libapr + "$ENV{ProgramFiles}/Subversion/lib/apr" + ) + + FIND_LIBRARY(APRICONV_LIB libapriconv + "$ENV{ProgramFiles}/Subversion/lib/apr-iconv" + ) + + FIND_LIBRARY(APU_LIB libaprutil + "$ENV{ProgramFiles}/Subversion/lib/apr-util" + ) + + FIND_LIBRARY(APU_XMLLIB xml + "$ENV{ProgramFiles}/Subversion/lib/apr-util" + ) + + FIND_LIBRARY(NEON_LIB libneon + "$ENV{ProgramFiles}/Subversion/lib/neon" + ) + + FIND_LIBRARY(NEON_ZLIBSTATLIB zlibstat + "$ENV{ProgramFiles}/Subversion/lib/neon" + ) + + FIND_LIBRARY(INTL3LIB intl3_svn + "$ENV{ProgramFiles}/Subversion/lib" + ) + + FIND_LIBRARY(DB44_LIB libdb44 + "$ENV{ProgramFiles}/Subversion/lib" + ) + + FIND_LIBRARY(SUBVERSION_CLIENTLIB libsvn_client-1 + "$ENV{ProgramFiles}/Subversion/lib" + ) + + FIND_LIBRARY(SUBVERSION_DELTALIB libsvn_delta-1 + "$ENV{ProgramFiles}/Subversion/lib" + ) + + FIND_LIBRARY(SUBVERSION_DIFFLIB libsvn_diff-1 + "$ENV{ProgramFiles}/Subversion/lib" + ) + + FIND_LIBRARY(SUBVERSION_FSBASELIB libsvn_fs_base-1 + "$ENV{ProgramFiles}/Subversion/lib" + ) + + FIND_LIBRARY(SUBVERSION_FSFSLIB libsvn_fs_fs-1 + "$ENV{ProgramFiles}/Subversion/lib" + ) + + FIND_LIBRARY(SUBVERSION_FSUTILLIB libsvn_fs_util-1 + "$ENV{ProgramFiles}/Subversion/lib" + ) + + FIND_LIBRARY(SUBVERSION_FSLIB libsvn_fs-1 + "$ENV{ProgramFiles}/Subversion/lib" + ) + + FIND_LIBRARY(SUBVERSION_RALOCALLIB libsvn_ra_local-1 + "$ENV{ProgramFiles}/Subversion/lib" + ) + + FIND_LIBRARY(SUBVERSION_RANEONLIB libsvn_ra_neon-1 + "$ENV{ProgramFiles}/Subversion/lib" + ) + + FIND_LIBRARY(SUBVERSION_RASVNLIB libsvn_ra_svn-1 + "$ENV{ProgramFiles}/Subversion/lib" + ) + + FIND_LIBRARY(SUBVERSION_RALIB libsvn_ra-1 + "$ENV{ProgramFiles}/Subversion/lib" + ) + + FIND_LIBRARY(SUBVERSION_REPOSITORYLIB libsvn_repos-1 + "$ENV{ProgramFiles}/Subversion/lib" + ) + + FIND_LIBRARY(SUBVERSION_SUBRLIB libsvn_subr-1 + "$ENV{ProgramFiles}/Subversion/lib" + ) + + FIND_LIBRARY(SUBVERSION_WCLIB libsvn_wc-1 + "$ENV{ProgramFiles}/Subversion/lib" + ) + + SET(APR_EXTRA_LIBFLAGS ) + SET(APU_EXTRA_LIBFLAGS ) + + + # check found libraries + if (NOT APR_LIB) + MESSAGE(SEND_ERROR "No apr lib found!") + ELSE (NOT APR_LIB) + MESSAGE(STATUS "Found apr lib: ${APR_LIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${APR_LIB}) + endif(NOT APR_LIB) + + if (NOT APRICONV_LIB) + MESSAGE(SEND_ERROR "No apriconv lib found!") + ELSE (NOT APRICONV_LIB) + MESSAGE(STATUS "Found apriconv lib: ${APRICONV_LIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${APRICONV_LIB}) + endif(NOT APRICONV_LIB) + + if (NOT APU_LIB) + MESSAGE(SEND_ERROR "No aprutil lib found!") + ELSE (NOT APU_LIB) + MESSAGE(STATUS "Found aprutil lib: ${APU_LIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${APU_LIB}) + endif(NOT APU_LIB) + + if (NOT APU_XMLLIB) + MESSAGE(SEND_ERROR "No xml lib found!") + ELSE (NOT APU_XMLLIB) + MESSAGE(STATUS "Found xml lib: ${APU_XMLLIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${APU_XMLLIB}) + endif(NOT APU_XMLLIB) + + if (NOT NEON_LIB) + MESSAGE(SEND_ERROR "No neon lib found!") + ELSE (NOT NEON_LIB) + MESSAGE(STATUS "Found neon lib: ${NEON_LIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${NEON_LIB}) + endif(NOT NEON_LIB) + + if (NOT NEON_ZLIBSTATLIB) + MESSAGE(SEND_ERROR "No zlibstat lib found!") + ELSE (NOT APRICONV_LIB) + MESSAGE(STATUS "Found zlibstat lib: ${NEON_ZLIBSTATLIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${NEON_ZLIBSTATLIB}) + endif(NOT NEON_ZLIBSTATLIB) + + if (NOT INTL3LIB) + MESSAGE(SEND_ERROR "No intl3 lib found!") + ELSE (NOT INTL3LIB) + MESSAGE(STATUS "Found intl3 lib: ${INTL3LIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${INTL3LIB}) + endif(NOT INTL3LIB) + + if (NOT DB44_LIB) + MESSAGE(SEND_ERROR "No db44 lib found!") + ELSE (NOT DB44_LIB) + MESSAGE(STATUS "Found db44 lib: ${DB44_LIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${DB44_LIB}) + endif(NOT DB44_LIB) + + if (NOT SUBVERSION_DELTALIB) + MESSAGE(SEND_ERROR "No subversion delta lib found!") + ELSE (NOT SUBVERSION_DELTALIB) + MESSAGE(STATUS "Found subversion delta lib: ${SUBVERSION_DELTALIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${SUBVERSION_DELTALIB}) + endif(NOT SUBVERSION_DELTALIB) + + if (NOT SUBVERSION_FSBASELIB) + MESSAGE(SEND_ERROR "No subversion fs base lib found!") + ELSE (NOT SUBVERSION_FSBASELIB) + MESSAGE(STATUS "Found subversion fs base lib: ${SUBVERSION_FSBASELIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${SUBVERSION_FSBASELIB}) + endif(NOT SUBVERSION_FSBASELIB) + + if (NOT SUBVERSION_FSFSLIB) + MESSAGE(SEND_ERROR "No subversion fs fs lib found!") + ELSE (NOT SUBVERSION_FSFSLIB) + MESSAGE(STATUS "Found subversion fs fs lib: ${SUBVERSION_FSFSLIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${SUBVERSION_FSFSLIB}) + endif(NOT SUBVERSION_FSFSLIB) + + if (NOT SUBVERSION_FSUTILLIB) + MESSAGE(SEND_ERROR "No subversion fs util lib found!") + ELSE (NOT SUBVERSION_FSUTILLIB) + MESSAGE(STATUS "Found subversion fs util lib: ${SUBVERSION_FSUTILLIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${SUBVERSION_FSUTILLIB}) + endif(NOT SUBVERSION_FSUTILLIB) + + if (NOT SUBVERSION_RALOCALLIB) + MESSAGE(SEND_ERROR "No subversion ra local lib found!") + ELSE (NOT SUBVERSION_RALOCALLIB) + MESSAGE(STATUS "Found subversion ra local lib: ${SUBVERSION_RALOCALLIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${SUBVERSION_RALOCALLIB}) + endif(NOT SUBVERSION_RALOCALLIB) + + if (NOT SUBVERSION_RANEONLIB) + MESSAGE(SEND_ERROR "No subversion ra neon lib found!") + ELSE (NOT SUBVERSION_RANEONLIB) + MESSAGE(STATUS "Found subversion ra neon lib: ${SUBVERSION_RANEONLIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${SUBVERSION_RANEONLIB}) + endif(NOT SUBVERSION_RANEONLIB) + + if (NOT SUBVERSION_RASVNLIB) + MESSAGE(SEND_ERROR "No subversion ra svn lib found!") + ELSE (NOT SUBVERSION_RASVNLIB) + MESSAGE(STATUS "Found subversion ra svn lib: ${SUBVERSION_RASVNLIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${SUBVERSION_RASVNLIB}) + endif(NOT SUBVERSION_RASVNLIB) + +ENDIF (WIN32) + + +IF(NOT SUBVERSION_INCLUDE_DIR) + MESSAGE(SEND_ERROR "No subversion includes found!") +ELSE(NOT SUBVERSION_INCLUDE_DIR) + MESSAGE(STATUS "Found subversion include: ${SUBVERSION_INCLUDE_DIR}") +ENDIF(NOT SUBVERSION_INCLUDE_DIR) + +if (NOT SUBVERSION_CLIENTLIB) + MESSAGE(SEND_ERROR "No subversion client libs found!") +ELSE (NOT SUBVERSION_CLIENTLIB) + MESSAGE(STATUS "Found subversion client lib: ${SUBVERSION_CLIENTLIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${SUBVERSION_CLIENTLIB}) +endif(NOT SUBVERSION_CLIENTLIB) + +if (NOT SUBVERSION_DIFFLIB) + MESSAGE(SEND_ERROR "No subversion diff lib found!") +ELSE (NOT SUBVERSION_DIFFLIB) + MESSAGE(STATUS "Found subversion diff lib: ${SUBVERSION_DIFFLIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${SUBVERSION_DIFFLIB}) +endif(NOT SUBVERSION_DIFFLIB) + +if (NOT SUBVERSION_FSLIB) + MESSAGE(SEND_ERROR "No subversion fs lib found!") +ELSE (NOT SUBVERSION_FSLIB) + MESSAGE(STATUS "Found subversion fs lib: ${SUBVERSION_FSLIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${SUBVERSION_FSLIB}) +endif(NOT SUBVERSION_FSLIB) + +if (NOT SUBVERSION_RALIB) + MESSAGE(SEND_ERROR "No subversion ra lib found!") +ELSE (NOT SUBVERSION_RALIB) + MESSAGE(STATUS "Found subversion ra lib: ${SUBVERSION_RALIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${SUBVERSION_RALIB}) +endif(NOT SUBVERSION_RALIB) + +if (NOT SUBVERSION_REPOSITORYLIB) + MESSAGE(SEND_ERROR "No subversion repository lib found!") +ELSE (NOT SUBVERSION_REPOSITORYLIB) + MESSAGE(STATUS "Found subversion repository lib: ${SUBVERSION_REPOSITORYLIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${SUBVERSION_REPOSITORYLIB}) +endif(NOT SUBVERSION_REPOSITORYLIB) + +if (NOT SUBVERSION_SUBRLIB) + MESSAGE(SEND_ERROR "No subversion subr lib found!") +ELSE (NOT SUBVERSION_SUBRLIB) + MESSAGE(STATUS "Found subversion subr lib: ${SUBVERSION_SUBRLIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${SUBVERSION_SUBRLIB}) +endif(NOT SUBVERSION_SUBRLIB) + +if (NOT SUBVERSION_WCLIB) + MESSAGE(SEND_ERROR "No subversion wc lib found!") +ELSE (NOT SUBVERSION_WCLIB) + MESSAGE(STATUS "Found subversion wc lib: ${SUBVERSION_WCLIB}") + SET(SUBVERSION_ALL_LIBS ${SUBVERSION_ALL_LIBS} ${SUBVERSION_WCLIB}) +endif(NOT SUBVERSION_WCLIB) + + +SET(SUBVERSIONFOUND true) diff --git a/src/svnqt/commititem.cpp b/src/svnqt/commititem.cpp new file mode 100644 index 0000000..2d97e6c --- /dev/null +++ b/src/svnqt/commititem.cpp @@ -0,0 +1,167 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#include "commititem.hpp" + +#include <svn_client.h> +#include <svn_props.h> + +namespace svn { + +CommitItem::CommitItem(const svn_client_commit_item_t*_item) +{ + init(); + if (_item) { + m_Path = QString::FROMUTF8(_item->path); + m_Kind = _item->kind; + m_Url = QString::FROMUTF8(_item->url); + if (_item->state_flags & SVN_CLIENT_COMMIT_ITEM_IS_COPY) { + m_CopyFromRevision = _item->revision; + } else { + m_Revision = _item->revision; + } + m_CopyFromUrl = QString::FROMUTF8(_item->copyfrom_url); + m_State = _item->state_flags; + convertprop(_item->wcprop_changes); + } +} + +CommitItem::CommitItem(const svn_client_commit_item2_t*_item) +{ + init(); + + if (_item) { + m_Path = QString::FROMUTF8(_item->path); + m_Kind = _item->kind; + m_Url = QString::FROMUTF8(_item->url); + m_Revision = _item->revision; + m_CopyFromRevision = _item->copyfrom_rev; + m_CopyFromUrl = QString::FROMUTF8(_item->copyfrom_url); + m_State = _item->state_flags; + convertprop(_item->wcprop_changes); + } +} + +CommitItem::CommitItem(const svn_client_commit_item3_t*_item) +{ + init(); + + if (_item) { +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + m_Path = QString::FROMUTF8(_item->path); + m_Kind = _item->kind; + m_Url = QString::FROMUTF8(_item->url); + m_Revision = _item->revision; + m_CopyFromRevision = _item->copyfrom_rev; + m_CopyFromUrl = QString::FROMUTF8(_item->copyfrom_url); + m_State = _item->state_flags; + convertprop(_item->incoming_prop_changes); + if (_item->outgoing_prop_changes) + { + convertprop(_item->outgoing_prop_changes); + } +#endif + } +} + +void CommitItem::convertprop(apr_array_header_t * list) +{ + if (!list) { + m_CommitProperties.clear(); + return; + } + for (int j = 0; j < list->nelts; ++j) { + svn_prop_t * item = ((svn_prop_t **)list->elts)[j]; + if (!item) continue; + m_CommitProperties[QString::FROMUTF8(item->name)]=QString::FROMUTF8(item->value->data,item->value->len); + } +} + +void CommitItem::init() +{ + m_Path=m_Url=m_CopyFromUrl = QString::null; + m_Kind = svn_node_unknown; + m_Revision=m_CopyFromRevision = -1; + m_State = 0; + m_CommitProperties.clear(); +} + +CommitItem::~CommitItem() +{ +} + +const QString& CommitItem::path()const +{ + return m_Path; +} + +const QString& CommitItem::url()const +{ + return m_Url; +} + +const QString& CommitItem::copyfromurl()const +{ + return m_CopyFromUrl; +} + +const PropertiesMap& CommitItem::properties()const +{ + return m_CommitProperties; +} + +svn_revnum_t CommitItem::revision()const +{ + return m_Revision; +} + +svn_revnum_t CommitItem::copyfromrevision()const +{ + return m_CopyFromRevision; +} + +svn_node_kind_t CommitItem::kind()const +{ + return m_Kind; +} + +apr_byte_t CommitItem::state()const +{ + return m_State; +} + +char CommitItem::actionType()const +{ + char r=0; + if (m_State & SVN_CLIENT_COMMIT_ITEM_IS_COPY) { + r = 'C'; + } else if (m_State & SVN_CLIENT_COMMIT_ITEM_ADD){ + r = 'A'; + } else if (m_State & SVN_CLIENT_COMMIT_ITEM_DELETE){ + r = 'D'; + } else if (m_State & SVN_CLIENT_COMMIT_ITEM_PROP_MODS || + m_State & SVN_CLIENT_COMMIT_ITEM_TEXT_MODS){ + r = 'M'; + } else if (m_State & SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN){ + r = 'L'; + } + return r; +} + +} diff --git a/src/svnqt/commititem.hpp b/src/svnqt/commititem.hpp new file mode 100644 index 0000000..fc12def --- /dev/null +++ b/src/svnqt/commititem.hpp @@ -0,0 +1,101 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef SVNCOMMITITEM_H +#define SVNCOMMITITEM_H + +#include "client.hpp" + +#include <svn_types.h> +#include <apr.h> + +// forward declarations +struct svn_client_commit_item_t; +// only used if build against svn 1.3 api +struct svn_client_commit_item2_t; +// only used if build against svn 1.5 api +struct svn_client_commit_item3_t; + +namespace svn { + +/** + @author Rajko Albrecht <ral@alwins-world.de> +*/ +class SVNQT_EXPORT CommitItem{ + +private: + void init(); + void convertprop(apr_array_header_t *); + +protected: + PropertiesMap m_CommitProperties; + QString m_Path,m_Url,m_CopyFromUrl; + svn_node_kind_t m_Kind; + svn_revnum_t m_Revision,m_CopyFromRevision; + apr_byte_t m_State; + +public: + //! constructor + CommitItem(const svn_client_commit_item_t*aSource=0); + //! constructor + /*! + * This one will only do something if build against subversion 1.3 + */ + CommitItem(const svn_client_commit_item2_t*); + /*! + * This one will only do something if build against subversion 1.5 + */ + CommitItem(const svn_client_commit_item3_t*); + //! Destructor + /*! + * Not virtual 'cause no child class is needed + */ + ~CommitItem(); + + const QString& path()const; + const QString& url()const; + const QString& copyfromurl()const; + const PropertiesMap& properties()const; + svn_revnum_t revision()const; + svn_revnum_t copyfromrevision()const; + svn_node_kind_t kind()const; + apr_byte_t state()const; + //! Kind of action + /*! + * \return Char for type of action or 0 if unknown. Currently known is + * <UL> + * <LI>A - add</LI> + * <LI>C - copy</LI> + * <LI>D - deletion</LI> + * <LI>M - Modify (content or property)</LI> + * <LI>R - replaced</LI> + * <LI>L - (un-)lock</LI> + * </UL> + */ + char actionType()const; +}; + +#if QT_VERSION < 0x040000 + typedef QValueList<CommitItem> CommitItemList; +#else + typedef QList<CommitItem> CommitItemList; +#endif +} + +#endif diff --git a/src/svnqt/conflictdescription.cpp b/src/svnqt/conflictdescription.cpp new file mode 100644 index 0000000..bbf059a --- /dev/null +++ b/src/svnqt/conflictdescription.cpp @@ -0,0 +1,185 @@ +/*************************************************************************** + * Copyright (C) 2008 by Rajko Albrecht ral@alwins-world.de * + * http://kdesvn.alwins-world.de/ * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#include "conflictdescription.hpp" +#include "svnqt_defines.hpp" + +#include <svn_wc.h> + +namespace svn { + +ConflictDescription::ConflictDescription() + :m_pool() +{ + init(); +} + + +ConflictDescription::~ConflictDescription() +{ +} + +ConflictDescription::ConflictDescription(const svn_wc_conflict_description_t*conflict) + :m_pool() +{ + init(); +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + if (!conflict) { + return; + } + m_baseFile=QString::FROMUTF8(conflict->base_file); + m_mergedFile=QString::FROMUTF8(conflict->merged_file); + m_mimeType=QString::FROMUTF8(conflict->mime_type); + m_myFile=QString::FROMUTF8(conflict->my_file); + m_Path=QString::FROMUTF8(conflict->path); + m_propertyName=QString::FROMUTF8(conflict->property_name); + m_theirFile=QString::FROMUTF8(conflict->their_file); + switch(conflict->action) { + case svn_wc_conflict_action_edit: + m_action=ConflictEdit; + break; + case svn_wc_conflict_action_add: + m_action=ConflictAdd; + break; + case svn_wc_conflict_action_delete: + m_action=ConflictDelete; + break; + } + switch (conflict->kind) { + case svn_wc_conflict_kind_text: + m_Type=ConflictText; + break; + case svn_wc_conflict_kind_property: + m_Type=ConflictProperty; + break; + } + m_nodeKind=conflict->node_kind; + m_binary=conflict->is_binary; + switch (conflict->reason) { + case svn_wc_conflict_reason_edited: + m_reason=ReasonEdited; + break; + case svn_wc_conflict_reason_obstructed: + m_reason=ReasonObstructed; + break; + case svn_wc_conflict_reason_deleted: + m_reason=ReasonDeleted; + break; + case svn_wc_conflict_reason_missing: + m_reason=ReasonMissing; + break; + case svn_wc_conflict_reason_unversioned: + m_reason=ReasonUnversioned; + break; + } +#else + Q_UNUSED(conflict); +#endif +} + +ConflictDescription::ConflictDescription(const ConflictDescription&) + :m_pool() +{ +} + +} + +svn::ConflictDescription::ConflictAction svn::ConflictDescription::action() const +{ + return m_action; +} + +const QString&svn::ConflictDescription::baseFile() const +{ + return m_baseFile; +} + + +/*! + \fn svn::ConflictDescription::init() + */ +void svn::ConflictDescription::init() +{ + m_baseFile=m_Path=m_mergedFile=m_propertyName=m_theirFile=m_myFile=m_mimeType=QString::null; + m_action=ConflictEdit; + m_Type=ConflictText; + m_reason=ReasonEdited; + m_binary=false; + m_nodeKind = svn_node_unknown; +} + + +bool svn::ConflictDescription::binary() const +{ + return m_binary; +} + + +const QString& svn::ConflictDescription::mergedFile() const +{ + return m_mergedFile; +} + + +const QString& svn::ConflictDescription::mimeType() const +{ + return m_mimeType; +} + + +const QString& svn::ConflictDescription::myFile() const +{ + return m_myFile; +} + + +svn_node_kind_t svn::ConflictDescription::nodeKind() const +{ + return m_nodeKind; +} + + +const QString& svn::ConflictDescription::Path() const +{ + return m_Path; +} + + +const QString& svn::ConflictDescription::propertyName() const +{ + return m_propertyName; +} + + +svn::ConflictDescription::ConflictReason svn::ConflictDescription::reason() const +{ + return m_reason; +} + + +const QString& svn::ConflictDescription::theirFile() const +{ + return m_theirFile; +} + + +svn::ConflictDescription::ConflictType svn::ConflictDescription::Type() const +{ + return m_Type; +} diff --git a/src/svnqt/conflictdescription.hpp b/src/svnqt/conflictdescription.hpp new file mode 100644 index 0000000..3f72562 --- /dev/null +++ b/src/svnqt/conflictdescription.hpp @@ -0,0 +1,96 @@ +/*************************************************************************** + * Copyright (C) 2008 by Rajko Albrecht ral@alwins-world.de * + * http://kdesvn.alwins-world.de/ * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef SVNCONFLICTDESCRIPTION_H +#define SVNCONFLICTDESCRIPTION_H + +struct svn_wc_conflict_description_t; + +#include "svnqt/pool.hpp" +#include "svnqt/svnqt_defines.hpp" +#include <svn_types.h> + +#include <qstring.h> + +namespace svn { + +/** Wrapper for svn_wc_conflict_description_t + * does nothing when build against subversion prior 1.5 + * @since subversion 1.5 + * @author Rajko Albrecht +*/ +class SVNQT_EXPORT ConflictDescription +{ +public: + enum ConflictType { + ConflictText, + ConflictProperty + }; + enum ConflictReason { + ReasonEdited, + ReasonObstructed, + ReasonDeleted, + ReasonMissing, + ReasonUnversioned + }; + enum ConflictAction { + ConflictEdit, + ConflictAdd, + ConflictDelete + }; + ConflictDescription(); + ConflictDescription(const svn_wc_conflict_description_t*); + ~ConflictDescription(); + + ConflictAction action() const; + ConflictType Type() const; + ConflictReason reason() const; + svn_node_kind_t nodeKind() const; + bool binary() const; + const QString& baseFile() const; + const QString& theirFile() const; + const QString& propertyName() const; + const QString& Path() const; + const QString& myFile() const; + const QString& mimeType() const; + const QString& mergedFile() const; + +protected: + //! don't use it. + ConflictDescription(const ConflictDescription&); + void init(); +protected: + Pool m_pool; + bool m_binary; + ConflictAction m_action; + ConflictType m_Type; + ConflictReason m_reason; + QString m_baseFile; + QString m_mergedFile; + QString m_mimeType; + QString m_myFile; + QString m_Path; + QString m_propertyName; + QString m_theirFile; + svn_node_kind_t m_nodeKind; +}; + +} + +#endif diff --git a/src/svnqt/conflictresult.cpp b/src/svnqt/conflictresult.cpp new file mode 100644 index 0000000..0465e33 --- /dev/null +++ b/src/svnqt/conflictresult.cpp @@ -0,0 +1,131 @@ +/*************************************************************************** + * Copyright (C) 2007 by Rajko Albrecht ral@alwins-world.de * + * http://kdesvn.alwins-world.de/ * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "conflictresult.hpp" + +#include "svnqt_defines.hpp" + +#include <svn_wc.h> + +namespace svn +{ + ConflictResult::ConflictResult() + :m_choice(ChooseMerged),m_MergedFile(QString::null) + { + } + + ConflictResult::ConflictResult(const svn_wc_conflict_result_t*aResult) + { + if (!aResult){ + return; + } +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + switch (aResult->choice){ + case svn_wc_conflict_choose_base: + m_choice=ChooseBase; + break; + case svn_wc_conflict_choose_theirs_full: + m_choice=ChooseTheirsFull; + break; + case svn_wc_conflict_choose_mine_full: + m_choice=ChooseMineFull; + break; + case svn_wc_conflict_choose_theirs_conflict: + m_choice=ChooseTheirsConflict; + break; + case svn_wc_conflict_choose_mine_conflict: + m_choice=ChooseMineConflict; + break; + case svn_wc_conflict_choose_merged: + m_choice=ChooseMerged; + break; + case svn_wc_conflict_choose_postpone: + default: + m_choice=ChoosePostpone; + break; + } + if (aResult->merged_file) { + m_MergedFile=QString::FROMUTF8(aResult->merged_file); + } else { + m_MergedFile=QString::null; + } +#else + Q_UNUSED(aResult); +#endif + } + + void ConflictResult::setMergedFile(const QString&aMergedfile) { + m_MergedFile=aMergedfile; + } + + void ConflictResult::setChoice(ConflictChoice aValue) + { + m_choice=aValue; + } + + void ConflictResult::assignResult(svn_wc_conflict_result_t**aResult,const Pool&pool)const + { +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + svn_wc_conflict_choice_t _choice; + switch (choice()) { + case ConflictResult::ChooseBase: + _choice=svn_wc_conflict_choose_base; + break; + case ConflictResult::ChooseTheirsFull: + _choice=svn_wc_conflict_choose_theirs_full; + break; + case ConflictResult::ChooseMineFull: + _choice=svn_wc_conflict_choose_mine_full; + break; + case ConflictResult::ChooseTheirsConflict: + _choice=svn_wc_conflict_choose_theirs_conflict; + break; + case ConflictResult::ChooseMineConflict: + _choice=svn_wc_conflict_choose_mine_conflict; + break; + case ConflictResult::ChooseMerged: + _choice=svn_wc_conflict_choose_merged; + break; + case ConflictResult::ChoosePostpone: + default: + _choice=svn_wc_conflict_choose_postpone; + break; + + } + const char* _merged_file = mergedFile().isNull()?0:apr_pstrdup (pool,mergedFile().TOUTF8()); + if ((*aResult)==0) { + (*aResult) = svn_wc_create_conflict_result(_choice,_merged_file,pool); + } else { + (*aResult)->choice=_choice; + (*aResult)->merged_file=_merged_file; + } +#else + Q_UNUSED(aResult); + Q_UNUSED(pool); +#endif + } + + const svn_wc_conflict_result_t*ConflictResult::result(const Pool&pool)const + { + svn_wc_conflict_result_t*result=0; + assignResult(&result,pool); + return result; + } +} diff --git a/src/svnqt/conflictresult.hpp b/src/svnqt/conflictresult.hpp new file mode 100644 index 0000000..0dfb426 --- /dev/null +++ b/src/svnqt/conflictresult.hpp @@ -0,0 +1,78 @@ +/*************************************************************************** + * Copyright (C) 2007 by Rajko Albrecht ral@alwins-world.de * + * http://kdesvn.alwins-world.de/ * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef _CONFLICT_RESULT_HPP +#define _CONFLICT_RESULT_HPP + +struct svn_wc_conflict_result_t; + +#include "svnqt/pool.hpp" +#include "svnqt/svnqt_defines.hpp" +#include <svn_types.h> + +#include <qstring.h> + +namespace svn { + +class SVNQT_EXPORT ConflictResult +{ + public: + enum ConflictChoice { + //! let user make a call to resolve + ChoosePostpone, + ChooseBase, + ChooseTheirsFull, + ChooseMineFull, + ChooseTheirsConflict, + ChooseMineConflict, + ChooseMerged + }; + ConflictResult(); + //! Copy constructor + /*! only usefull wenn build with subversion 1.5 or newer + */ + ConflictResult(const svn_wc_conflict_result_t*); + + const QString& mergedFile()const + { + return m_MergedFile; + } + void setMergedFile(const QString&aMergedfile); + + ConflictChoice choice()const + { + return m_choice; + } + void setChoice(ConflictChoice aValue); + + const svn_wc_conflict_result_t*result(const Pool&pool)const; + void assignResult(svn_wc_conflict_result_t**aResult,const Pool&pool)const; + + protected: + ConflictChoice m_choice; + //! Merged file + /*! will only used if m_choice is ChooseMerged + */ + QString m_MergedFile; +}; + +} + +#endif diff --git a/src/svnqt/context.cpp b/src/svnqt/context.cpp new file mode 100644 index 0000000..56f35c0 --- /dev/null +++ b/src/svnqt/context.cpp @@ -0,0 +1,136 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +// Apache Portable Runtime +#include "apr_xlate.h" + +// Subversion api +#include "svn_auth.h" +#include "svn_config.h" +#include "svn_subst.h" +//#include "svn_utf.h" + +// svncpp +#include "apr.hpp" +#include "context.hpp" +#include "context_listener.hpp" +#include "contextdata.hpp" + +namespace svn +{ + Context::Context (const QString &configDir) + : ref_count() + { + m = new ContextData (configDir); + } + + Context::Context (const Context & src) + : ref_count() + { + m = new ContextData (src.m->configDir()); + setLogin (src.getUsername (), src.getPassword ()); + } + + Context::~Context () + { + delete m; + } + + void + Context::setAuthCache (bool value) + { + m->setAuthCache (value); + } + + void + Context::setLogin (const QString& username, const QString& password) + { + m->setLogin (username, password); + } + + Context::operator svn_client_ctx_t * () + { + return m->ctx(); + } + + svn_client_ctx_t * + Context::ctx () + { + return m->ctx(); + } + + void + Context::setLogMessage (const QString& msg) + { + m->setLogMessage (msg); + } + + const QString& + Context::getUsername () const + { + return m->getUsername (); + } + + const QString& + Context::getPassword () const + { + return m->getPassword (); + } + + const QString& + Context::getLogMessage () const + { + return m->getLogMessage (); + } + + void + Context::setListener (ContextListener * listener) + { + m->setListener(listener); + } + + ContextListener * + Context::getListener () const + { + return m->getListener(); + } + + void + Context::reset () + { + m->reset(); + } +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/context.hpp b/src/svnqt/context.hpp new file mode 100644 index 0000000..b45cb1c --- /dev/null +++ b/src/svnqt/context.hpp @@ -0,0 +1,176 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_CONTEXT_HPP_ +#define _SVNCPP_CONTEXT_HPP_ + +#include "svnqt/svnqt_defines.hpp" + +// qt +#include <qstring.h> + +// Subversion api +#include "svn_client.h" + +// svncpp +#include "svnqt/pool.hpp" +#include "svnqt/smart_pointer.hpp" + + +namespace svn +{ + // forward declarations + class ContextListener; + class ContextData; + + /** + * This class will hold the client context + * and replace the old notification and baton + * stuff + */ + class SVNQT_EXPORT Context:public ref_count + { + public: + /** + * default constructor + * + * @param configDir location where the + * subversion api stores its + * configuration + */ + Context (const QString & configDir=QString::null); + + /** + * copy constructor + * + * @param src + */ + Context (const Context &src); + + /** + * destructor + */ + virtual ~Context (); + + /** + * enable/disable authentication caching + * + * @param value true=enable/false=disable + */ + void setAuthCache (bool value); + + /** + * set username/password for authentication + */ + void setLogin (const QString& username, const QString& password); + + /** + * operator to get svn_client_ctx object + */ + operator svn_client_ctx_t * (); + + /** + * return the svn_client_ctx object + */ + svn_client_ctx_t * ctx (); + + /** + * this will be called at the beginning of an action. + * the log message will be reset. + */ + void reset (); + + /** + * set log message + * + * @param msg + */ + void setLogMessage (const QString& msg); + + /** + * get log message + * + * @return log message + */ + const QString& + getLogMessage () const; + + /** + * get username + * + * @return username + */ + const QString& + getUsername () const; + + /** + * get password + * + * @return password + */ + const QString& + getPassword () const; + + /** + * set the listener for the context. The listener will be + * called to poll authentication information and other + * information like this + * + * @param listener + */ + void + setListener (ContextListener * listener); + + /** + * get the listener + * + * @return the listener + */ + ContextListener * + getListener () const; + + private: + ContextData * m; + + /** + * disable assignment operator + */ + Context & operator = (const Context &); + }; + + typedef svn::smart_pointer<svn::Context> ContextP; +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/context_listener.hpp b/src/svnqt/context_listener.hpp new file mode 100644 index 0000000..8383724 --- /dev/null +++ b/src/svnqt/context_listener.hpp @@ -0,0 +1,271 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_CONTEXT_LISTENER_HPP_ +#define _SVNCPP_CONTEXT_LISTENER_HPP_ + +// svncpp +#include "svnqt/pool.hpp" +#include "svnqt/commititem.hpp" +#include "svnqt/svnqt_defines.hpp" +// qt +#include <qstring.h> +// Subversion api +#include <svn_client.h> + + +namespace svn +{ + class ConflictResult; + class ConflictDescription; + /** + * This is the interface that is used by @a Context + * for callbacks. + * To use this you will have to inherit from this + * interface and overwrite the virtual methods. + */ + class SVNQT_EXPORT ContextListener + { + public: + /** + * empty destructor avoids a lot of compiler warnings + */ + virtual ~ContextListener(){} + /** + * this method will be called to retrieve + * authentication information. This will called until valid information were + * inserted or it returns false. + * + * @param username username set as default by subversion + * @param realm in which username/password will be used + * @param password target storage for password + * @param maySave in/out set false to not save + * @return continue action? + * @retval true continue + */ + virtual bool + contextGetLogin (const QString & realm, + QString & username, + QString & password, + bool & maySave) = 0; + /** + * this method will be called to retrieve + * authentication information stored not by subversion. This + * will only called once! + * + * @param username username set as default by subversion + * @param realm in which username/password will be used + * @param password target storage for password + * @return continue action? should only in case of emergency return false. + * @retval true continue + */ + virtual bool + contextGetSavedLogin(const QString & realm, + QString & username, + QString & password) = 0; + /** + * this method will be called to retrieve + * authentication information stored not persistent. This + * will only called once! + * + * @param username username set as default by subversion + * @param realm in which username/password will be used + * @param password target storage for password + * @return continue action? should only in case of emergency return false. + * @retval true continue + */ + virtual bool + contextGetCachedLogin(const QString & realm, + QString & username, + QString & password) = 0; + + /** + * this method will be called to notify about + * the progress of an ongoing action + * + * @param path + * @param action + * @param kind + * @param mime_type + * @param content_state + * @param prop_state + * @param revision + */ + virtual void + contextNotify (const char *path, + svn_wc_notify_action_t action, + svn_node_kind_t kind, + const char *mime_type, + svn_wc_notify_state_t content_state, + svn_wc_notify_state_t prop_state, + svn_revnum_t revision) = 0; + /** + * this method will be called to notify about + * the progress of an ongoing action + * + * @param action the action got notified about + * @since subversion 1.2 + */ + virtual void + contextNotify (const svn_wc_notify_t *action) = 0; + /** + * this method will be called periodically to allow + * the app to cancel long running operations + * + * @return cancel action? + * @retval true cancel + */ + virtual bool + contextCancel() = 0; + + /** + * this method will be called to retrieve + * a log message + * + * WORKAROUND FOR apr_xlate PROBLEM: + * STRINGS ALREADY HAVE TO BE UTF8!!! + * + * @param msg log message + * @return continue action? + * @retval true continue + */ + virtual bool + contextGetLogMessage (QString & msg,const CommitItemList&) = 0; + + typedef enum + { + DONT_ACCEPT = 0, + ACCEPT_TEMPORARILY, + ACCEPT_PERMANENTLY + } SslServerTrustAnswer; + + + /** + * @see contextSslServerTrust + * @see svn_auth_cred_ssl_server_trust_t + */ + struct SslServerTrustData + { + public: + /** bit coded failures */ + const apr_uint32_t failures; + + /** certificate information */ + QString hostname; + QString fingerprint; + QString validFrom; + QString validUntil; + QString issuerDName; + QString realm; + bool maySave; + + SslServerTrustData (const apr_uint32_t failures_) + : failures (failures_), hostname (""), fingerprint (""), + validFrom (""), validUntil (""), issuerDName (""), + realm (""), maySave (true) + { + } + }; + + + /** + * this method is called if there is ssl server + * information, that has to be confirmed by the user + * + * @param data + * @param acceptedFailures + * @return @a SslServerTrustAnswer + */ + virtual SslServerTrustAnswer + contextSslServerTrustPrompt (const SslServerTrustData & data, + apr_uint32_t & acceptedFailures) = 0; + + /** + * this method is called to retrieve client side + * information + */ + virtual bool + contextSslClientCertPrompt (QString & certFile) = 0; + + /** + * this method is called to retrieve the password + * for the client certificate + * + * @param password + * @param realm + * @param maySave + */ + virtual bool + contextSslClientCertPwPrompt (QString & password, + const QString & realm, + bool & maySave) = 0; + /** + * this method is called to retrieve the password + * for the client certificate from a local storage or such. it will called only once. + * + * @param password + * @param realm + */ + virtual bool + contextLoadSslClientCertPw(QString&password,const QString&realm)=0; + + virtual void + contextProgress(long long int current, long long int max) = 0; + + /** + * try to translate a text. In current implementation does + * nothing than returning the origin but may used to get an + * application specific translation. + * @param what text to translate + * @return translated text or origin. + */ + virtual QString translate(const QString&what){return what;} + + /** Callback for svn_wc_conflict_resolver_func_t in subversion 1.5 + * This method is only useful when build with subverion 1.5 or above. The default implementation sets + * result to ConflictResult::ChoosePostpone. Then conflicts while merge, update and switch results in an + * item with "conflict" status set. + * + * @param result The result where to store + * @param description description of conflict. + * @return true if result may used and operaion should continue. + * @sa svn_wc_conflict_description_t, svn_wc_conflict_result_t + * @since subversion 1.5 + */ + virtual bool contextConflictResolve(ConflictResult&result,const ConflictDescription&description); + }; +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/contextdata.cpp b/src/svnqt/contextdata.cpp new file mode 100644 index 0000000..b4c2ea4 --- /dev/null +++ b/src/svnqt/contextdata.cpp @@ -0,0 +1,782 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + + +#include "contextdata.hpp" +#include "context_listener.hpp" +#include "conflictresult.hpp" +#include "conflictdescription.hpp" + +#include <svn_config.h> +#include <svn_wc.h> + +namespace svn { + +ContextData::ContextData(const QString & configDir_) + : listener (0), logIsSet (false), + m_promptCounter (0), m_ConfigDir(configDir_) +{ + const char * c_configDir = 0; + if( m_ConfigDir.length () > 0 ) + { + c_configDir = m_ConfigDir.TOUTF8(); + } + + // make sure the configuration directory exists + svn_config_ensure (c_configDir, pool); + + // intialize authentication providers + // * simple + // * username + // * simple pw cache of frontend app + // * simple pw storage + // * simple prompt + // * ssl server trust file + // * ssl server trust prompt + // * ssl client cert pw file + // * ssl client cert pw load + // * ssl client cert pw prompt + // * ssl client cert file + // =================== + // 11 providers (+1 for windowsvariant) + + apr_array_header_t *providers = +#if defined(WIN32) && (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4) + apr_array_make (pool, 12, sizeof (svn_auth_provider_object_t *)); +#else + apr_array_make (pool, 11, sizeof (svn_auth_provider_object_t *)); +#endif + svn_auth_provider_object_t *provider; + +#if defined(WIN32) && (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4) + svn_auth_get_windows_simple_provider (&provider, pool); + APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider; +#endif + +#if (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4) + svn_auth_get_simple_provider +#else + svn_client_get_simple_provider +#endif + (&provider, pool); + *(svn_auth_provider_object_t **)apr_array_push (providers) = provider; + +#if (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4) + svn_auth_get_username_provider +#else + svn_client_get_username_provider +#endif + (&provider,pool); + *(svn_auth_provider_object_t **)apr_array_push (providers) = provider; + +#if (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4) + svn_auth_get_simple_prompt_provider +#else + svn_client_get_simple_prompt_provider +#endif + (&provider,onCachedPrompt,this,0,pool); + *(svn_auth_provider_object_t **)apr_array_push (providers) = provider; + +#if (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4) + svn_auth_get_simple_prompt_provider +#else + svn_client_get_simple_prompt_provider +#endif + (&provider,onSavedPrompt,this,0,pool); + *(svn_auth_provider_object_t **)apr_array_push (providers) = provider; + +#if (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4) + svn_auth_get_simple_prompt_provider +#else + svn_client_get_simple_prompt_provider +#endif + /* not very nice. should be infinite... */ + (&provider,onSimplePrompt,this,100000000,pool); + *(svn_auth_provider_object_t **)apr_array_push (providers) = provider; + + // add ssl providers + + // file first then prompt providers +#if (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4) + svn_auth_get_ssl_server_trust_file_provider +#else + svn_client_get_ssl_server_trust_file_provider +#endif + (&provider, pool); + *(svn_auth_provider_object_t **)apr_array_push (providers) = provider; + +#if (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4) + svn_auth_get_ssl_client_cert_file_provider +#else + svn_client_get_ssl_client_cert_file_provider +#endif + (&provider, pool); + *(svn_auth_provider_object_t **)apr_array_push (providers) = provider; + +#if (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4) + svn_auth_get_ssl_client_cert_pw_file_provider +#else + svn_client_get_ssl_client_cert_pw_file_provider +#endif + (&provider, pool); + *(svn_auth_provider_object_t **)apr_array_push (providers) = provider; + +#if (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4) + svn_auth_get_ssl_server_trust_prompt_provider +#else + svn_client_get_ssl_server_trust_prompt_provider +#endif + (&provider, onSslServerTrustPrompt, this, pool); + *(svn_auth_provider_object_t **)apr_array_push (providers) = provider; + + // first try load from extra storage +#if (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4) + svn_auth_get_ssl_client_cert_pw_prompt_provider +#else + svn_client_get_ssl_client_cert_pw_prompt_provider +#endif + (&provider, onFirstSslClientCertPw, this, 0, pool); + *(svn_auth_provider_object_t **)apr_array_push (providers) = provider; + + // plugged in 3 as the retry limit - what is a good limit? +#if (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4) + svn_auth_get_ssl_client_cert_pw_prompt_provider +#else + svn_client_get_ssl_client_cert_pw_prompt_provider +#endif + (&provider, onSslClientCertPwPrompt, this, 3, pool); + *(svn_auth_provider_object_t **)apr_array_push (providers) = provider; + + svn_auth_baton_t *ab; + svn_auth_open (&ab, providers, pool); + + // initialize ctx structure + svn_client_create_context(&m_ctx,pool); + + // get the config based on the configDir passed in + svn_config_get_config ( &(m_ctx->config), c_configDir, pool); + + // tell the auth functions where the config is + if (c_configDir) { + svn_auth_set_parameter(ab, SVN_AUTH_PARAM_CONFIG_DIR, + c_configDir); + } + + m_ctx->auth_baton = ab; + m_ctx->notify_func = onNotify; + m_ctx->notify_baton = this; + m_ctx->cancel_func = onCancel; + m_ctx->cancel_baton = this; + m_ctx->notify_func2 = onNotify2; + m_ctx->notify_baton2 = this; + + m_ctx->log_msg_func = onLogMsg; + m_ctx->log_msg_baton = this; + // subversion 1.3 functions + m_ctx->log_msg_func2 = onLogMsg2; + m_ctx->log_msg_baton2 = this; + + m_ctx->progress_func = onProgress; + m_ctx->progress_baton = this; + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5) || (SVN_VER_MAJOR > 2)) + m_ctx->log_msg_func3 = onLogMsg3; + m_ctx->log_msg_baton3 = this; + + m_ctx->conflict_func = onWcConflictResolver; + m_ctx->conflict_baton = this; + + m_ctx->client_name = "SvnQt wrapper client"; + initMimeTypes(); +#endif +} + + +ContextData::~ContextData() +{ +} + + +const QString&ContextData::getLogMessage () const +{ + return logMessage; +} + +bool ContextData::retrieveLogMessage (QString & msg,const CommitItemList&_itemlist) +{ + bool ok = false; + if (listener) { + ok = listener->contextGetLogMessage (logMessage,_itemlist); + if (ok) + msg = logMessage; + else + logIsSet = false; + } + return ok; +} + +void ContextData::notify(const char *path, + svn_wc_notify_action_t action, + svn_node_kind_t kind, + const char *mime_type, + svn_wc_notify_state_t content_state, + svn_wc_notify_state_t prop_state, + svn_revnum_t revision) +{ + if (listener != 0) { + listener->contextNotify (path, action, kind, mime_type, + content_state, prop_state, revision); + } +} + +void ContextData::notify (const svn_wc_notify_t *action) +{ + if (listener != 0) { + listener->contextNotify(action); + } +} + +bool ContextData::cancel() +{ + if (listener != 0) { + return listener->contextCancel (); + } else { + // don't cancel if no listener + return false; + } +} +const QString& ContextData::getUsername () const +{ + return username; +} + +const QString& ContextData::getPassword() const +{ + return password; +} + +bool ContextData::retrieveLogin (const char * username_, + const char * realm, + bool &may_save) +{ + bool ok; + + if (listener == 0) + return false; + + username = QString::FROMUTF8(username_); + ok = listener->contextGetLogin(QString::FROMUTF8(realm),username, password, may_save); + + return ok; +} + +bool ContextData::retrieveSavedLogin (const char * username_, + const char * realm, + bool & may_save) +{ + bool ok; + may_save = false; + + if (listener == 0) + return false; + + username = QString::FROMUTF8(username_); + ok = listener->contextGetSavedLogin(QString::FROMUTF8(realm),username, password); + return ok; +} + +bool ContextData::retrieveCachedLogin (const char * username_, + const char * realm, + bool & may_save) +{ + bool ok; + may_save = false; + + if (listener == 0) + return false; + + username = QString::FROMUTF8(username_); + ok = listener->contextGetCachedLogin(QString::FROMUTF8(realm),username, password); + return ok; +} + +svn_client_ctx_t *ContextData::ctx() +{ + return m_ctx; +} + +const QString&ContextData::configDir()const +{ + return m_ConfigDir; +} + +svn_error_t * +ContextData::getContextData (void * baton, ContextData ** data) +{ + if (baton == NULL) + return svn_error_create (SVN_ERR_CANCELLED, NULL, + "invalid baton"); + + ContextData * data_ = static_cast <ContextData*>(baton); + + if (data_->listener == 0) + return svn_error_create (SVN_ERR_CANCELLED, NULL, + "invalid listener"); + + *data = data_; + return SVN_NO_ERROR; +} + +void ContextData::setAuthCache(bool value) +{ + void *param = 0; + if (!value) { + param = (void *)"1"; + } + svn_auth_set_parameter (m_ctx->auth_baton, + SVN_AUTH_PARAM_NO_AUTH_CACHE,param); +} + +void ContextData::setLogin(const QString& usr, const QString& pwd) +{ + username = usr; + password = pwd; + svn_auth_baton_t * ab = m_ctx->auth_baton; + svn_auth_set_parameter (ab, SVN_AUTH_PARAM_DEFAULT_USERNAME, username.TOUTF8()); + svn_auth_set_parameter (ab, SVN_AUTH_PARAM_DEFAULT_PASSWORD, password.TOUTF8()); +} + +void ContextData::setLogMessage (const QString& msg) +{ + logMessage = msg; + if (msg.isNull()) { + logIsSet = false; + } else { + logIsSet = true; + } +} + +svn_error_t *ContextData::onLogMsg (const char **log_msg, + const char **tmp_file, + apr_array_header_t * commit_items, + void *baton, + apr_pool_t * pool) +{ + ContextData * data = 0; + SVN_ERR (getContextData (baton, &data)); + + QString msg; + if (data->logIsSet) { + msg = data->getLogMessage (); + } else { + CommitItemList _items; + for (int j = 0; j < commit_items->nelts; ++j) { + svn_client_commit_item_t*item = ((svn_client_commit_item_t **)commit_items->elts)[j]; + _items.push_back(CommitItem(item)); + } + if (!data->retrieveLogMessage (msg,_items)) { + return data->generate_cancel_error(); + } + } + + *log_msg = apr_pstrdup (pool,msg.TOUTF8()); + *tmp_file = NULL; + return SVN_NO_ERROR; +} + +svn_error_t *ContextData::onLogMsg2 (const char **log_msg, + const char **tmp_file, + const apr_array_header_t * commit_items, + void *baton, + apr_pool_t * pool) +{ + ContextData * data = 0; + SVN_ERR (getContextData (baton, &data)); + + QString msg; + if (data->logIsSet) { + msg = data->getLogMessage (); + } else { + CommitItemList _items; + for (int j = 0; j < commit_items->nelts; ++j) { + svn_client_commit_item2_t*item = ((svn_client_commit_item2_t **)commit_items->elts)[j]; + _items.push_back(CommitItem(item)); + } + + if (!data->retrieveLogMessage (msg,_items)) { + return data->generate_cancel_error(); + } + } + + *log_msg = apr_pstrdup (pool,msg.TOUTF8()); + *tmp_file = NULL; + return SVN_NO_ERROR; +} + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5) || (SVN_VER_MAJOR > 2)) +svn_error_t *ContextData::onLogMsg3 (const char **log_msg, + const char **tmp_file, + const apr_array_header_t * commit_items, + void *baton, + apr_pool_t * pool) +{ + ContextData * data = 0; + SVN_ERR (getContextData (baton, &data)); + + QString msg; + if (data->logIsSet) { + msg = data->getLogMessage (); + } else { + CommitItemList _items; + for (int j = 0; j < commit_items->nelts; ++j) { + svn_client_commit_item3_t*item = ((svn_client_commit_item3_t **)commit_items->elts)[j]; + _items.push_back(CommitItem(item)); + } + + if (!data->retrieveLogMessage (msg,_items)) { + return data->generate_cancel_error(); + } + } + + *log_msg = apr_pstrdup (pool,msg.TOUTF8()); + *tmp_file = NULL; + return SVN_NO_ERROR; +} +#endif + +void ContextData::onNotify (void * baton, + const char *path, + svn_wc_notify_action_t action, + svn_node_kind_t kind, + const char *mime_type, + svn_wc_notify_state_t content_state, + svn_wc_notify_state_t prop_state, + svn_revnum_t revision) +{ + if (baton == 0) + return; + ContextData * data = static_cast <ContextData *> (baton); + data->notify (path, action, kind, mime_type, content_state, + prop_state, revision); +} + +void ContextData::onNotify2(void*baton,const svn_wc_notify_t *action,apr_pool_t */*tpool*/) +{ + if (!baton) return; + ContextData * data = static_cast <ContextData *> (baton); + data->notify (action); +} + +svn_error_t * ContextData::onCancel (void * baton) +{ + if (baton == 0) return SVN_NO_ERROR; + ContextData * data = static_cast <ContextData *> (baton); + if( data->cancel () ) + return data->generate_cancel_error(); + else + return SVN_NO_ERROR; +} + +svn_error_t *ContextData::onCachedPrompt(svn_auth_cred_simple_t **cred, + void *baton, + const char *realm, + const char *username, + svn_boolean_t _may_save, + apr_pool_t *pool) +{ + ContextData * data = 0; + SVN_ERR (getContextData (baton, &data)); + bool may_save = _may_save != 0; + if (!data->retrieveCachedLogin (username, realm, may_save )) + return SVN_NO_ERROR; + svn_auth_cred_simple_t* lcred = (svn_auth_cred_simple_t*) + apr_palloc (pool, sizeof (svn_auth_cred_simple_t)); + QByteArray l; + l = data->getPassword().TOUTF8(); + lcred->password = apr_pstrndup (pool,l,l.size()); + l = data->getUsername().TOUTF8(); + lcred->username = apr_pstrndup (pool,l,l.size()); + + // tell svn if the credentials need to be saved + lcred->may_save = may_save; + *cred = lcred; + + return SVN_NO_ERROR; +} + +svn_error_t *ContextData::onSavedPrompt(svn_auth_cred_simple_t **cred, + void *baton, + const char *realm, + const char *username, + svn_boolean_t _may_save, + apr_pool_t *pool) +{ + ContextData * data = 0; + SVN_ERR (getContextData (baton, &data)); + bool may_save = _may_save != 0; + if (!data->retrieveSavedLogin (username, realm, may_save )) + return SVN_NO_ERROR; + svn_auth_cred_simple_t* lcred = (svn_auth_cred_simple_t*) + apr_palloc (pool, sizeof (svn_auth_cred_simple_t)); + QByteArray l; + l = data->getPassword().TOUTF8(); + lcred->password = apr_pstrndup (pool,l,l.size()); + l = data->getUsername().TOUTF8(); + lcred->username = apr_pstrndup (pool,l,l.size()); + + // tell svn if the credentials need to be saved + lcred->may_save = may_save; + *cred = lcred; + + return SVN_NO_ERROR; +} + +svn_error_t *ContextData::onSimplePrompt (svn_auth_cred_simple_t **cred, + void *baton, + const char *realm, + const char *username, + svn_boolean_t _may_save, + apr_pool_t *pool) +{ + ContextData * data = 0; + SVN_ERR (getContextData (baton, &data)); + bool may_save = _may_save != 0; + if (!data->retrieveLogin (username, realm, may_save )) + return data->generate_cancel_error(); + + svn_auth_cred_simple_t* lcred = (svn_auth_cred_simple_t*) + apr_palloc (pool, sizeof (svn_auth_cred_simple_t)); + QByteArray l; + l = data->getPassword().TOUTF8(); + lcred->password = apr_pstrndup (pool,l,l.size()); + l = data->getUsername().TOUTF8(); + lcred->username = apr_pstrndup (pool,l,l.size()); + + // tell svn if the credentials need to be saved + lcred->may_save = may_save; + *cred = lcred; + + return SVN_NO_ERROR; +} + +svn_error_t * ContextData::onSslServerTrustPrompt (svn_auth_cred_ssl_server_trust_t **cred, + void *baton, + const char *realm, + apr_uint32_t failures, + const svn_auth_ssl_server_cert_info_t *info, + svn_boolean_t may_save, + apr_pool_t *pool) +{ + ContextData * data = 0; + SVN_ERR (getContextData (baton, &data)); + + ContextListener::SslServerTrustData trustData (failures); + if (realm != NULL) + trustData.realm = realm; + trustData.hostname = info->hostname; + trustData.fingerprint = info->fingerprint; + trustData.validFrom = info->valid_from; + trustData.validUntil = info->valid_until; + trustData.issuerDName = info->issuer_dname; + trustData.maySave = may_save != 0; + + apr_uint32_t acceptedFailures = failures; + ContextListener::SslServerTrustAnswer answer = + data->listener->contextSslServerTrustPrompt ( + trustData, acceptedFailures ); + + if(answer == ContextListener::DONT_ACCEPT) { + *cred = 0L; + } else + { + svn_auth_cred_ssl_server_trust_t *cred_ = + (svn_auth_cred_ssl_server_trust_t*) + apr_palloc (pool, sizeof (svn_auth_cred_ssl_server_trust_t)); + + cred_->accepted_failures = failures; + if (answer == ContextListener::ACCEPT_PERMANENTLY) + { + cred_->may_save = true; + } else { + cred_->may_save = false; + } + *cred = cred_; + } + + return SVN_NO_ERROR; +} + +svn_error_t * ContextData::onSslClientCertPrompt (svn_auth_cred_ssl_client_cert_t **cred, + void *baton, + apr_pool_t *pool) +{ + ContextData * data = 0; + SVN_ERR (getContextData (baton, &data)); + + QString certFile; + if (!data->listener->contextSslClientCertPrompt (certFile)) + return data->generate_cancel_error(); + + svn_auth_cred_ssl_client_cert_t *cred_ = + (svn_auth_cred_ssl_client_cert_t*) + apr_palloc (pool, sizeof (svn_auth_cred_ssl_client_cert_t)); + + cred_->cert_file = certFile.TOUTF8(); + + *cred = cred_; + return SVN_NO_ERROR; +} + +svn_error_t *ContextData::onFirstSslClientCertPw ( + svn_auth_cred_ssl_client_cert_pw_t **cred, + void *baton, + const char *realm, + svn_boolean_t maySave, + apr_pool_t *pool) +{ + ContextData * data = 0; + SVN_ERR (getContextData (baton, &data)); + + QString password; + bool may_save = maySave != 0; + if (!data->listener->contextLoadSslClientCertPw(password, QString::FROMUTF8(realm))) + return SVN_NO_ERROR; + + svn_auth_cred_ssl_client_cert_pw_t *cred_ = + (svn_auth_cred_ssl_client_cert_pw_t *) + apr_palloc (pool, sizeof (svn_auth_cred_ssl_client_cert_pw_t)); + + cred_->password = password.TOUTF8(); + cred_->may_save = may_save; + *cred = cred_; + + return SVN_NO_ERROR; +} + +svn_error_t * ContextData::onSslClientCertPwPrompt( + svn_auth_cred_ssl_client_cert_pw_t **cred, + void *baton, + const char *realm, + svn_boolean_t maySave, + apr_pool_t *pool) +{ + ContextData * data = 0; + SVN_ERR (getContextData (baton, &data)); + + QString password; + bool may_save = maySave != 0; + if (!data->listener->contextSslClientCertPwPrompt (password, QString::FROMUTF8(realm), may_save)) + return data->generate_cancel_error(); + + svn_auth_cred_ssl_client_cert_pw_t *cred_ = + (svn_auth_cred_ssl_client_cert_pw_t *) + apr_palloc (pool, sizeof (svn_auth_cred_ssl_client_cert_pw_t)); + + cred_->password = password.TOUTF8(); + cred_->may_save = may_save; + *cred = cred_; + + return SVN_NO_ERROR; +} + +void ContextData::setListener(ContextListener * _listener) +{ + listener = _listener; +} + +ContextListener * ContextData::getListener() const +{ + return listener; +} + +void ContextData::reset() +{ + m_promptCounter = 0; + logIsSet = false; +} + +svn_error_t * ContextData::generate_cancel_error() +{ + return svn_error_create (SVN_ERR_CANCELLED, 0, listener->translate(QString::FROMUTF8("Cancelled by user.")).TOUTF8()); +} + +void ContextData::onProgress(apr_off_t progress, apr_off_t total, void*baton, apr_pool_t*) +{ + ContextData * data = 0; + if (getContextData (baton, &data)!=SVN_NO_ERROR) + { + return; + } + data->getListener()->contextProgress(progress,total); +} + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5) || (SVN_VER_MAJOR > 2)) +void ContextData::initMimeTypes() +{ + // code take from subversion 1.5 commandline client + const char *mimetypes_file; + svn_error_t * err = 0L; + svn_config_t * cfg = (svn_config_t *)apr_hash_get(m_ctx->config, SVN_CONFIG_CATEGORY_CONFIG, + APR_HASH_KEY_STRING); + + svn_config_get(cfg, &mimetypes_file, + SVN_CONFIG_SECTION_MISCELLANY, + SVN_CONFIG_OPTION_MIMETYPES_FILE, false); + if (mimetypes_file && *mimetypes_file) { + if ((err = svn_io_parse_mimetypes_file(&(m_ctx->mimetypes_map), + mimetypes_file, pool))) { + svn_handle_error2(err, stderr, false, "svn: "); + } + } +} +#endif + +svn_error_t* ContextData::onWcConflictResolver(svn_wc_conflict_result_t**result,const svn_wc_conflict_description_t *description, void *baton, apr_pool_t *pool) +{ +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5) || (SVN_VER_MAJOR > 2)) + ContextData * data = 0; + SVN_ERR (getContextData (baton, &data)); + ConflictResult cresult; + if (!data->getListener()->contextConflictResolve(cresult,description)) { + return data->generate_cancel_error(); + } + cresult.assignResult(result,pool); + return SVN_NO_ERROR; +#else + Q_UNUSED(result); + Q_UNUSED(description); + Q_UNUSED(baton); + Q_UNUSED(pool); + return svn_error_create (SVN_ERR_CANCELLED, NULL,"invalid subversion version."); +#endif +} + +bool ContextListener::contextConflictResolve(ConflictResult&result,const ConflictDescription&description) +{ + Q_UNUSED(description); +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5) || (SVN_VER_MAJOR > 2)) + result.setChoice(ConflictResult::ChoosePostpone); +#else + Q_UNUSED(result); +#endif + return true; +} + +} diff --git a/src/svnqt/contextdata.hpp b/src/svnqt/contextdata.hpp new file mode 100644 index 0000000..7c03f0a --- /dev/null +++ b/src/svnqt/contextdata.hpp @@ -0,0 +1,338 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef SVNCONTEXTDATA_HPP +#define SVNCONTEXTDATA_HPP + +#include "svnqt/pool.hpp" +#include "svnqt/apr.hpp" +#include "svnqt/commititem.hpp" +#include "svnqt/svnqt_defines.hpp" + +#include <svn_client.h> +#if (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4) +#include <svn_auth.h> +#endif +#include <qstring.h> + +struct svn_wc_conflict_result_t; +struct svn_wc_conflict_description_t; + +namespace svn { + + class ContextListener; +/** + @author Rajko Albrecht <ral@alwins-world.de> +*/ + +class SVNQT_NOEXPORT ContextData{ +public: + ContextData(const QString & configDir_); + ~ContextData(); + + // data methods + svn_client_ctx_t*ctx(); + const QString&configDir()const; + void setListener (ContextListener * listener); + ContextListener * getListener () const; + void reset(); + + // svn methods + void setAuthCache(bool value); + /** @see Context::setLogin */ + void setLogin (const QString& usr, const QString& pwd); + /** @see Context::setLogMessage */ + void setLogMessage (const QString& msg); + const QString&getLogMessage ()const; + /** + * if the @a listener is set, use it to retrieve the log + * message using ContextListener::contextGetLogMessage. + * This return values is given back, then. + * + * if the @a listener is not set the its checked whether + * the log message has been set using @a setLogMessage + * yet. If not, return false otherwise true + * + * @param msg log message + * @retval false cancel + */ + bool retrieveLogMessage (QString & msg,const CommitItemList&); + + /** + * if the @a listener is set call the method + * @a contextNotify + */ + void notify (const char *path, + svn_wc_notify_action_t action, + svn_node_kind_t kind, + const char *mime_type, + svn_wc_notify_state_t content_state, + svn_wc_notify_state_t prop_state, + svn_revnum_t revision); + void notify (const svn_wc_notify_t *action); + /** + * if the @a listener is set call the method + * @a contextCancel + */ + bool cancel(); + const QString& getUsername () const; + const QString& getPassword () const; + + /** + * if the @a listener is set and no password has been + * set yet, use it to retrieve login and password using + * ContextListener::contextGetLogin. + * + * if the @a listener is not set, check if setLogin + * has been called yet. + * + * @return continue? + * @retval false cancel + */ + bool + retrieveLogin (const char * username_, + const char * realm, + bool &may_save); + /** + * if the @a listener is set and no password has been + * set yet, use it to retrieve login and password using + * ContextListener::contextGetSavedLogin. + * + * if the @a listener is not set, check if setLogin + * has been called yet. + * + * @return continue? + * @retval false cancel + */ + bool + retrieveSavedLogin(const char * username_, + const char * realm, + bool &may_save); + /** + * if the @a listener is set and no password has been + * set yet, use it to retrieve login and password using + * ContextListener::contextGetCachedLogin. + * + * if the @a listener is not set, check if setLogin + * has been called yet. + * + * @return continue? + * @retval false cancel + */ + bool + retrieveCachedLogin(const char * username_, + const char * realm, + bool &may_save); + +protected: + // static methods + /** + * the @a baton is interpreted as ContextData * + * Several checks are performed on the baton: + * - baton == 0? + * - baton->Data + * - listener set? + * + * @param baton + * @param data returned data if everything is OK + * @retval SVN_NO_ERROR if everything is fine + * @retval SVN_ERR_CANCELLED on invalid values + */ + static svn_error_t * + getContextData (void * baton, ContextData ** data); + + /** + * this function gets called by the subversion api function + * when a log message is needed. This is the case on a commit + * for example + */ + static svn_error_t * + onLogMsg (const char **log_msg, + const char **tmp_file, + apr_array_header_t * commit_items, + void *baton, + apr_pool_t * pool); + + /** + * this function gets called by the subversion api function + * when a log message is needed. This is the case on a commit + * for example + */ + static svn_error_t * + onLogMsg2 (const char **log_msg, + const char **tmp_file, + const apr_array_header_t * commit_items, + void *baton, + apr_pool_t * pool); + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5) || (SVN_VER_MAJOR > 2)) + /** + * this function gets called by the subversion api function + * when a log message is needed. This is the case on a commit + * for example + */ + static svn_error_t * + onLogMsg3 (const char **log_msg, + const char **tmp_file, + const apr_array_header_t * commit_items, + void *baton, + apr_pool_t * pool); +#endif + + /** + * this is the callback function for the subversion + * api functions to signal the progress of an action + */ + static void + onNotify (void * baton, + const char *path, + svn_wc_notify_action_t action, + svn_node_kind_t kind, + const char *mime_type, + svn_wc_notify_state_t content_state, + svn_wc_notify_state_t prop_state, + svn_revnum_t revision); + /** + * this is the callback function for the subversion 1.2 + * api functions to signal the progress of an action + * + * @todo right now we forward only to @a onNotify, + * but maybe we should a notify2 to the listener + * @since subversion 1.2 + */ + static void + onNotify2(void*baton,const svn_wc_notify_t *action,apr_pool_t */*tpool*/); + /** + * this is the callback function for the subversion + * api functions to signal the progress of an action + * @param baton pointer to a ContextData instance + */ + static svn_error_t * onCancel (void * baton); + + /** + * @see svn_auth_simple_prompt_func_t + * this method is an alternate and called ONEs before onSimplePrompt. + * So we can try load password from other source. + */ + static svn_error_t * + onCachedPrompt(svn_auth_cred_simple_t **cred, + void *baton, + const char *realm, + const char *username, + svn_boolean_t _may_save, + apr_pool_t *pool); + + /** + * @see svn_auth_simple_prompt_func_t + * this method is an alternate and called ONEs before onSimplePrompt. + * So we can try load password from other source. + */ + static svn_error_t * + onSavedPrompt(svn_auth_cred_simple_t **cred, + void *baton, + const char *realm, + const char *username, + svn_boolean_t _may_save, + apr_pool_t *pool); + /** + * @see svn_auth_simple_prompt_func_t + */ + static svn_error_t * + onSimplePrompt (svn_auth_cred_simple_t **cred, + void *baton, + const char *realm, + const char *username, + svn_boolean_t _may_save, + apr_pool_t *pool); + /** + * @see svn_auth_ssl_server_trust_prompt_func_t + */ + static svn_error_t * + onSslServerTrustPrompt (svn_auth_cred_ssl_server_trust_t **cred, + void *baton, + const char *realm, + apr_uint32_t failures, + const svn_auth_ssl_server_cert_info_t *info, + svn_boolean_t may_save, + apr_pool_t *pool); + static svn_error_t * + onSslClientCertPrompt (svn_auth_cred_ssl_client_cert_t **cred, + void *baton, + apr_pool_t *pool); + /** + * @see svn_auth_ssl_client_cert_pw_prompt_func_t + */ + static svn_error_t * + onFirstSslClientCertPw ( + svn_auth_cred_ssl_client_cert_pw_t **cred, + void *baton, + const char *realm, + svn_boolean_t maySave, + apr_pool_t *pool); + + /** + * @see svn_auth_ssl_client_cert_pw_prompt_func_t + */ + static svn_error_t * + onSslClientCertPwPrompt ( + svn_auth_cred_ssl_client_cert_pw_t **cred, + void *baton, + const char *realm, + svn_boolean_t maySave, + apr_pool_t *pool); + + /** + * @see svn_client_ctx_t::progress_func + */ + static void onProgress(apr_off_t progress, apr_off_t total, void *baton, apr_pool_t *pool); + + /** + * @see svn_wc_conflict_resolver_func_t + * @since subversion 1.5 + */ + static svn_error_t* onWcConflictResolver(svn_wc_conflict_result_t**result,const svn_wc_conflict_description_t *description, void *baton, apr_pool_t *pool); + + // extra methods + svn_error_t * + generate_cancel_error(); + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5) || (SVN_VER_MAJOR > 2)) + /** read in mimetypes map + * @since subversion 1.5 + */ + void initMimeTypes(); +#endif +protected: + Apr apr; + + ContextListener * listener; + bool logIsSet; + int m_promptCounter; + Pool pool; + svn_client_ctx_t*m_ctx; + QString username; + QString password; + QString logMessage; + QString m_ConfigDir; + +}; + +} + +#endif diff --git a/src/svnqt/datetime.cpp b/src/svnqt/datetime.cpp new file mode 100644 index 0000000..496a04b --- /dev/null +++ b/src/svnqt/datetime.cpp @@ -0,0 +1,170 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +// apr +#include "apr_date.h" + +// svncpp +#include "datetime.hpp" + + +namespace svn +{ + DateTime::DateTime () + : m_time() + { + } + + DateTime::DateTime (const apr_time_t time) + : m_time() + { + setAprTime(time); + } + + DateTime::DateTime(const QDateTime&dt) + : m_time(dt) + { + } + + DateTime::DateTime (const DateTime & dateTime) + : m_time(dateTime.m_time) + { + } + + const DateTime & + DateTime::operator =(const DateTime & dateTime) + { + m_time = dateTime.m_time; + return *this; + } + + bool DateTime::operator<(const DateTime&dateTime)const + { + return m_time<dateTime.m_time; + } + + bool DateTime::operator>(const DateTime&dateTime)const + { + return dateTime<*this; + } + + bool DateTime::operator!=(const DateTime&dateTime)const + { + return *this<dateTime||dateTime<*this; + } + bool DateTime::operator==(const DateTime&dateTime)const + { + return !(*this!=dateTime); + } + + bool + DateTime::operator ==(const DateTime & dateTime) + { + return m_time == dateTime.m_time; + } + + bool + DateTime::operator !=(const DateTime & dateTime) + { + return m_time != dateTime.m_time; + } + bool + DateTime::operator<=(const DateTime&dateTime)const + { + return *this==dateTime||*this<dateTime; + } + bool + DateTime::operator>=(const DateTime&dateTime)const + { + return *this==dateTime||*this>dateTime; + } + + bool + DateTime::IsValid () const + { + return m_time.isValid(); + } + + apr_time_t + DateTime::GetAPRTimeT () const + { + apr_time_t aTime; + apr_time_ansi_put(&aTime,m_time.toTime_t()); + return aTime; + } + + bool + DateTime::SetRFC822Date (const char* date) + { + apr_time_t aTime = apr_date_parse_rfc(date); + setAprTime(aTime); + return IsValid(); + } + + DateTime::operator const QDateTime&()const + { + return m_time; + } + + const QDateTime&DateTime::toQDateTime()const + { + return *this; + } + + void DateTime::setAprTime(apr_time_t aTime) + { +#if QT_VERSION < 0x040000 + if (aTime<0)m_time.setTime_t(0,Qt::LocalTime); + else m_time.setTime_t(aTime/(1000*1000),Qt::LocalTime); +#else + m_time.setTimeSpec(Qt::LocalTime); + if (aTime<0)m_time.setTime_t(0); + else m_time.setTime_t(aTime/(1000*1000)); +#endif + } + + QString DateTime::toString(const QString&format)const + { + return m_time.toString(format); + } +} + +/*! + \fn svn::DateTime::toTime_t() + */ +unsigned int svn::DateTime::toTime_t()const +{ + return m_time.toTime_t(); +} + +void svn::DateTime::setTime_t(unsigned int sec) +{ + m_time.setTime_t(sec); +} diff --git a/src/svnqt/datetime.hpp b/src/svnqt/datetime.hpp new file mode 100644 index 0000000..06fedb4 --- /dev/null +++ b/src/svnqt/datetime.hpp @@ -0,0 +1,166 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_DATETIME_HPP_ +#define _SVNCPP_DATETIME_HPP_ + +#include "svnqt/svnqt_defines.hpp" + +#include <qdatetime.h> + +// subversion api +#include "svn_types.h" + + +namespace svn +{ + /** + * Class that encapsulates apr_time_t. + * + * @see apr_time_t + */ + class SVNQT_EXPORT DateTime + { + private: + QDateTime m_time; + + public: + + /** + * Default Constructor + */ + DateTime (); + + /** + * Constructor + * + * @param time number of microseconds since 00:00:00 january 1, 1970 UTC + */ + DateTime (const apr_time_t time); + + /** + * Constructor + * + * @param dt QDateTime class + */ + DateTime(const QDateTime&dt); + + /** + * Copy constructor + * + * @param dateTime Source + */ + DateTime (const DateTime & dateTime); + + /** + * @param dateTime Source + */ + const DateTime & + operator =(const DateTime & dateTime); + + /** + * @param dateTime Comparator + */ + bool + operator ==(const DateTime & dateTime); + /** + * @param dateTime Comparator + */ + bool + operator !=(const DateTime & dateTime); + + bool + operator<(const DateTime&dateTime)const; + bool + operator>(const DateTime&dateTime)const; + bool + operator!=(const DateTime&dateTime)const; + bool + operator==(const DateTime&dateTime)const; + bool + operator<=(const DateTime&dateTime)const; + bool + operator>=(const DateTime&dateTime)const; + + + /** + * @return Is a valid (non-zero) date + */ + bool + IsValid () const; + + /** + * @return APR apr_time_t + */ + apr_time_t + GetAPRTimeT () const; + + /** + * @return QDateTime object + */ + operator const QDateTime&()const; + + /** + * @return QDateTime object + */ + const QDateTime&toQDateTime()const; + + /** + * @param format format string + * @return formatted string + * @see QDateTime::toString + */ + QString toString(const QString&format)const; + + /** + * Set from date string of the form below, using apr_date_parse_rfc + * + * <PRE> + * Sun, 06 Nov 1994 08:49:37 GMT + * </PRE> + * + * @see apr_date_parse_rfc + * @return Successfully parsed + */ + bool + SetRFC822Date (const char* date); + + void setAprTime(apr_time_t aTime); + unsigned int toTime_t()const; + void setTime_t(unsigned int sec); + }; +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/diff_data.cpp b/src/svnqt/diff_data.cpp new file mode 100644 index 0000000..a5f66f9 --- /dev/null +++ b/src/svnqt/diff_data.cpp @@ -0,0 +1,145 @@ +/*************************************************************************** + * Copyright (C) 2008 by Rajko Albrecht ral@alwins-world.de * + * http://kdesvn.alwins-world.de/ * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#include "diff_data.hpp" +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/exception.hpp" + +#include <qfile.h> + +#include <svn_version.h> +#include <svn_io.h> +#include <svn_path.h> + +namespace svn +{ + DiffData::DiffData(const Path&aTmpPath,const Path&_p1,const Revision&_r1,const Path&_p2,const Revision&_r2) + :m_Pool(),m_tmpPath(aTmpPath), + m_outFile(0),m_errFile(0),m_outFileName(0),m_errFileName(0), + m_p1(_p1),m_p2(_p2),m_r1(_r1),m_r2(_r2), + m_working_copy_present(false),m_url_is_present(false) + { + init(); + } + + void DiffData::init() + { + svn_error_t * error; +#if (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4) + error = svn_io_open_unique_file2(&m_outFile, &m_outFileName, + m_tmpPath.path().TOUTF8(), + ".tmp", + svn_io_file_del_on_pool_cleanup, m_Pool); +#else + error = svn_io_open_unique_file (&m_outFile, &m_outFileName, + m_tmpPath.path().TOUTF8(), + ".tmp", + FALSE, m_Pool); +#endif + if (error!=0) { + clean(); + throw ClientException (error); + } +#if (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4) + error = svn_io_open_unique_file2(&m_errFile, &m_errFileName, + m_tmpPath.path().TOUTF8(), + ".tmp", + svn_io_file_del_on_pool_cleanup, m_Pool); +#else + error = svn_io_open_unique_file (&m_errFile, &m_errFileName, + m_tmpPath.path().TOUTF8(), + ".tmp", + FALSE, m_Pool); +#endif + if (error!=0) { + clean(); + throw ClientException (error); + } + if (svn_path_is_url(m_p1.cstr())) { + m_url_is_present = true; + } else { + m_working_copy_present = true; + } + if (svn_path_is_url(m_p2.cstr())) { + m_url_is_present = true; + } else { + m_working_copy_present = true; + } + + if (m_r1.revision()->kind==svn_opt_revision_unspecified && m_working_copy_present) { + m_r1 = svn_opt_revision_base; + } + if (m_r2.revision()->kind==svn_opt_revision_unspecified) { + m_r2 = m_working_copy_present?svn_opt_revision_working : svn_opt_revision_head; + } + } + + DiffData::~DiffData() + { + clean(); + } + + void DiffData::clean() + { + close(); +#if !((SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 4)) + if (m_outFileName != 0) { + svn_error_clear (svn_io_remove_file (m_outFileName, m_Pool)); + m_outFileName=0; + } + if (m_errFileName != 0) { + svn_error_clear (svn_io_remove_file (m_errFileName, m_Pool)); + m_errFileName=0; + } +#endif + } + + void DiffData::close() + { + if (m_outFile != 0) { + svn_io_file_close(m_outFile,m_Pool); + m_outFile=0; + } + if (m_errFile != 0) { + svn_io_file_close(m_errFile,m_Pool); + m_errFile=0; + } + } + + QByteArray DiffData::content() + { + if (!m_outFileName) { + return QByteArray(); + } + close(); + QFile fi(m_outFileName); +#if QT_VERSION < 0x040000 + if (!fi.open(IO_ReadOnly|IO_Raw)) { + throw ClientException(QString("%1 '%2'").arg(fi.errorString()).arg(m_outFileName)); +#else + if (!fi.open(QIODevice::ReadOnly)) { + throw ClientException(QString("%1 '%2'").arg(fi.errorString()).arg(m_outFileName).toLatin1().constData()); +#endif + } + + QByteArray res = fi.readAll(); + fi.close(); + return res; + } +} diff --git a/src/svnqt/diff_data.hpp b/src/svnqt/diff_data.hpp new file mode 100644 index 0000000..c92c8ac --- /dev/null +++ b/src/svnqt/diff_data.hpp @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (C) 2008 by Rajko Albrecht ral@alwins-world.de * + * http://kdesvn.alwins-world.de/ * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef __DIFF_DATA +#define __DIFF_DATA + +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/pool.hpp" +#include "path.hpp" +#include "revision.hpp" + +#include <qglobal.h> + +#if QT_VERSION < 0x040000 + #include <qstring.h> +#else + #include <QtCore> +#endif + +struct apr_file_t; + +namespace svn +{ + class Path; + + class SVNQT_NOEXPORT DiffData + { + protected: + Pool m_Pool; + Path m_tmpPath; + apr_file_t*m_outFile; + apr_file_t*m_errFile; + const char*m_outFileName; + const char*m_errFileName; + + Path m_p1,m_p2; + Revision m_r1,m_r2; + + bool m_working_copy_present,m_url_is_present; + + void init(); + void clean(); + void close(); + + public: + DiffData(const Path&aTmpPath,const Path&,const Revision&,const Path&,const Revision&); + virtual ~DiffData(); + + apr_file_t*outFile(){return m_outFile;} + apr_file_t*errFile(){return m_errFile;} + const Revision& r1()const{return m_r1;} + const Revision& r2()const{return m_r2;} + + QByteArray content(); + }; +} + +#endif diff --git a/src/svnqt/diffoptions.cpp b/src/svnqt/diffoptions.cpp new file mode 100644 index 0000000..7ada9c8 --- /dev/null +++ b/src/svnqt/diffoptions.cpp @@ -0,0 +1,144 @@ +/*************************************************************************** + * Copyright (C) 2007 by Rajko Albrecht ral@alwins-world.de * + * http://kdesvn.alwins-world.de/ * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "diffoptions.hpp" +#include "stringarray.hpp" +#include "pool.hpp" + +#include <svn_diff.h> + +namespace svn +{ + struct DiffOptionsData + { + DiffOptions::IgnoreSpace _ignorespace; + bool _ignoreeol; + bool _showc; + + DiffOptionsData() + { + _ignorespace=DiffOptions::IgnoreSpaceNone; + _ignoreeol = _showc = false; + } + }; + + DiffOptions::DiffOptions() + :m_data(new DiffOptionsData()) + { + } + + void DiffOptions::init(const svn_diff_file_options_t*_diffopts) + { +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 4)) || (SVN_VER_MAJOR > 1) + m_data->_ignoreeol = _diffopts->ignore_eol_style; + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + m_data->_showc = _diffopts->show_c_function; +#else + m_data->_showc = false; +#endif + switch (_diffopts->ignore_space) { + case svn_diff_file_ignore_space_change: + m_data->_ignorespace = IgnoreSpaceChange; + break; + case svn_diff_file_ignore_space_all: + m_data->_ignorespace = IgnoreSpaceAll; + break; + case svn_diff_file_ignore_space_none: + default: + m_data->_ignorespace = IgnoreSpaceNone; + break; + } +#else + Q_UNUSED(_diffopts); +#endif + } + + DiffOptions::DiffOptions(const QStringList&options) + :m_data(new DiffOptionsData()) + { +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 4)) || (SVN_VER_MAJOR > 1) + Pool pool; + StringArray _ar(options); + svn_diff_file_options_t * _diffopts = svn_diff_file_options_create(pool); + if (_diffopts) { + svn_error_t*error = svn_diff_file_options_parse(_diffopts,_ar.array(pool),pool); + if (error==0) { + init(_diffopts); + } + } +#else + Q_UNUSED(options) +#endif + } + + DiffOptions::DiffOptions(const svn_diff_file_options_t*options) + :m_data(new DiffOptionsData()) + { +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 4)) || (SVN_VER_MAJOR > 1) + if (options) { + init(options); + } +#else + Q_UNUSED(options) +#endif + } + + svn_diff_file_options_t*DiffOptions::options(const Pool&pool)const + { +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 4)) || (SVN_VER_MAJOR > 1) + svn_diff_file_options_t * _diffopts = svn_diff_file_options_create(pool); + _diffopts->ignore_eol_style = m_data->_ignoreeol; +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + _diffopts->show_c_function = m_data->_showc; +#endif + switch (m_data->_ignorespace) { + case IgnoreSpaceChange: + _diffopts->ignore_space=svn_diff_file_ignore_space_change; + break; + case IgnoreSpaceAll: + _diffopts->ignore_space=svn_diff_file_ignore_space_all; + break; + case IgnoreSpaceNone: + default: + _diffopts->ignore_space=svn_diff_file_ignore_space_none; + break; + } + return _diffopts; +#else + Q_UNUSED(pool); + return 0; +#endif + } + + DiffOptions::DiffOptions(const DiffOptions&old) + :m_data(new DiffOptionsData()) + { + m_data->_showc = old.m_data->_showc; + m_data->_ignorespace=old.m_data->_ignorespace; + m_data->_ignoreeol=old.m_data->_ignoreeol; + } + + DiffOptions::~DiffOptions() + { + delete m_data; + m_data=0; + } +} diff --git a/src/svnqt/diffoptions.hpp b/src/svnqt/diffoptions.hpp new file mode 100644 index 0000000..5509821 --- /dev/null +++ b/src/svnqt/diffoptions.hpp @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2007 by Rajko Albrecht ral@alwins-world.de * + * http://kdesvn.alwins-world.de/ * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef _DIFF_OPTIONS_HPP +#define _DIFF_OPTIONS_HPP + +#include "svnqt/svnqt_defines.hpp" + +namespace svn { + class Pool; + struct DiffOptionsData; +} + +struct svn_diff_file_options_t; +class QStringList; + +namespace svn +{ + /** c++ wrapper for svn_diffoptions_t + * + * This is needed until svnqt stops support for subversion prior 1.4 + */ + class SVNQT_EXPORT DiffOptions + { + public: + enum IgnoreSpace { + IgnoreSpaceNone, + IgnoreSpaceChange, + IgnoreSpaceAll + }; + protected: + DiffOptionsData* m_data; + void init(const svn_diff_file_options_t*options); + + public: + DiffOptions(); + /** Initialize options with values depending on options. + * Supported types are: + * - --ignore-space-change, -b + * - --ignore-all-space, -w + * - --ignore-eol-style + * - --unified, -u (for compatibility, does nothing). + * @sa svn_diff_file_options_parse + */ + DiffOptions(const QStringList&options); + + /** Initialize options with values depending on options. + * Only if build against subversion 1.4 or newer. + */ + DiffOptions(const svn_diff_file_options_t*options); + + /** copy operator + */ + DiffOptions(const DiffOptions&old); + + ~DiffOptions(); + + svn_diff_file_options_t*options(const Pool&pool)const; + }; +} + +#endif diff --git a/src/svnqt/dirent.cpp b/src/svnqt/dirent.cpp new file mode 100644 index 0000000..480546f --- /dev/null +++ b/src/svnqt/dirent.cpp @@ -0,0 +1,186 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +// svncpp +#include "svnqt/dirent.hpp" +#include "svnqt/lock_entry.hpp" +#include "svnqt/svnqt_defines.hpp" + +#include <qstring.h> + +namespace svn +{ + class SVNQT_NOEXPORT DirEntry_Data + { + public: + QString name; + svn_node_kind_t kind; + QLONG size; + bool hasProps; + svn_revnum_t createdRev; + DateTime time; + QString lastAuthor; + LockEntry m_Lock; + + DirEntry_Data () + : kind (svn_node_unknown), size (0), hasProps(false), + createdRev (0), time (0), m_Lock() + { + } + + DirEntry_Data (const QString& _name, const svn_dirent_t * dirEntry) + : name (_name), kind (dirEntry->kind), size (dirEntry->size), + hasProps (dirEntry->has_props != 0), + createdRev (dirEntry->created_rev), time (dirEntry->time), m_Lock() + { + lastAuthor = dirEntry->last_author == 0 ? QString::fromLatin1("") : QString::FROMUTF8(dirEntry->last_author); + } + + DirEntry_Data (const DirEntry & src) + { + init (src); + } + + void + init (const DirEntry & src) + { + name = src.name (); + kind = src.kind (); + size = src.size (); + hasProps = src.hasProps (); + createdRev = src.createdRev (); + time = src.time (); + lastAuthor = src.lastAuthor (); + m_Lock = src.lockEntry(); + } + }; + + DirEntry::DirEntry () + : m (new DirEntry_Data ()) + { + } + + DirEntry::DirEntry (const QString& name, const svn_dirent_t * dirEntry) + : m (new DirEntry_Data (name, dirEntry)) + { + } + + DirEntry::DirEntry (const QString& name, const svn_dirent_t * dirEntry,const svn_lock_t*lockEntry) + : m (new DirEntry_Data (name, dirEntry)) + { + setLock(lockEntry); + } + + DirEntry::DirEntry (const QString& name, const svn_dirent_t * dirEntry,const LockEntry&lockEntry) + : m (new DirEntry_Data (name, dirEntry)) + { + m->m_Lock = lockEntry; + } + + DirEntry::DirEntry (const DirEntry & src) + : m (new DirEntry_Data (src)) + { + } + + DirEntry::~DirEntry () + { + delete m; + } + + svn_node_kind_t + DirEntry::kind () const + { + return m->kind; + } + + QLONG + DirEntry::size () const + { + return m->size; + } + + bool + DirEntry::hasProps () const + { + return m->hasProps; + } + + svn_revnum_t + DirEntry::createdRev () const + { + return m->createdRev; + } + + const DateTime& + DirEntry::time () const + { + return m->time; + } + + const QString& + DirEntry::lastAuthor () const + { + return m->lastAuthor; + } + + const QString& + DirEntry::name () const + { + return m->name; + } + + const LockEntry& + DirEntry::lockEntry() const + { + return m->m_Lock; + } + + void + DirEntry::setLock(const svn_lock_t*_l) + { + m->m_Lock.init(_l); + } + + DirEntry & + DirEntry::operator= (const DirEntry & dirEntry) + { + if (this == &dirEntry) + return *this; + + m->init (dirEntry); + return *this; + } +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/dirent.hpp b/src/svnqt/dirent.hpp new file mode 100644 index 0000000..9b7c3e2 --- /dev/null +++ b/src/svnqt/dirent.hpp @@ -0,0 +1,131 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_DIRENT_HPP_ +#define _SVNCPP_DIRENT_HPP_ + +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/lock_entry.hpp" +#include "svnqt/datetime.hpp" + +// subversion api +#include "svn_client.h" + +#include <qstring.h> + +namespace svn +{ + class DirEntry_Data; + + class SVNQT_EXPORT DirEntry + { + public: + /** + * default constructor + */ + DirEntry (); + + /** + * constructor for existing @a svn_dirent_t entries + */ + DirEntry (const QString& name, const svn_dirent_t * dirEntry); + /** + * constructor for existing @a svn_dirent_t entries + */ + DirEntry (const QString& name, const svn_dirent_t * dirEntry,const svn_lock_t*lockEntry); + + DirEntry (const QString& name, const svn_dirent_t * dirEntry,const LockEntry&lockEntry); + /** + * copy constructor + */ + DirEntry (const DirEntry & src); + + /** + * destructor + */ + ~DirEntry (); + + /** + * assignment operator + */ + DirEntry & + operator = (const DirEntry &); + + const QString& + name () const; + + svn_node_kind_t + kind () const; + + QLONG + size () const; + + bool + hasProps () const; + + svn_revnum_t + createdRev () const; + + const DateTime& + time () const; + + const QString& + lastAuthor () const; + + //! The assigned lock entry + /*! + * returns the assigned lock entry if set + * \return a valid or an empty lock + */ + const LockEntry& + lockEntry() const; + + //! initialize and convert the internal lock entry + /*! + * This method should not needed to call outside the lib, it may just used + * inside svn::Client::ls. + * \param aLock the subversion lock description to convert. + */ + void + setLock(const svn_lock_t*aLock); + + + private: + DirEntry_Data * m; + + }; +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/entry.cpp b/src/svnqt/entry.cpp new file mode 100644 index 0000000..27c14cf --- /dev/null +++ b/src/svnqt/entry.cpp @@ -0,0 +1,394 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +// svncpp +#include "entry.hpp" + +namespace svn +{ + class SVNQT_NOEXPORT Entry_private + { + protected: + void init_clean(); + public: + Entry_private(); + Entry_private(const Entry_private&src); + virtual ~Entry_private(); + + bool m_valid; + LockEntry m_Lock; + + QString _name,_url,_repos,_uuid,_copyfrom_url,_conflict_old,_conflict_new,_conflict_wrk,_prejfile,_checksum,_cmt_author; + bool _copied,_deleted,_absent,_incomplete; + svn_revnum_t _revision,_copyfrom_rev,_cmt_rev; + svn_node_kind_t _kind; + svn_wc_schedule_t _schedule; + DateTime _text_time,_prop_time,_cmt_date; + + /** + * initializes the members + */ + void + init (const svn_wc_entry_t * src); + void + init(const Entry_private&src); + void + init(const QString&url,const DirEntryPtr&src); + void + init(const QString&url,const InfoEntry&src); + }; + + void Entry_private::init_clean() + { + _name = _url = _repos = _uuid = _copyfrom_url = _conflict_old = _conflict_new = _conflict_wrk + = _prejfile = _checksum = _cmt_author = QString::null; + _revision = _copyfrom_rev = _cmt_rev = -1; + _kind = svn_node_unknown; + _schedule = svn_wc_schedule_normal; + _text_time = _prop_time = _cmt_date = 0; + _copied = _deleted = _absent = _incomplete = false; + } + + Entry_private::Entry_private() + : m_valid (false),m_Lock() + { + init_clean(); + } + + Entry_private::Entry_private(const Entry_private&src) + : m_valid (false),m_Lock() + { + init_clean(); + init(src); + } + + Entry_private::~Entry_private() + { + } + + void + Entry_private::init (const svn_wc_entry_t * src) + { + if (src) { + // copy & convert the contents of src + _name = QString::FROMUTF8(src->name); + _revision = src->revision; + _url = QString::FROMUTF8(src->url); + _repos = QString::FROMUTF8(src->repos); + _uuid = QString::FROMUTF8(src->uuid); + _kind = src->kind; + _schedule = src->schedule; + _copied = src->copied!=0; + _deleted = src->deleted!=0; + _absent = src->absent!=0; + _incomplete = src->incomplete!=0; + _copyfrom_url=QString::FROMUTF8(src->copyfrom_url); + _copyfrom_rev = src->copyfrom_rev; + _conflict_old = QString::FROMUTF8(src->conflict_old); + _conflict_new = QString::FROMUTF8(src->conflict_new); + _conflict_wrk = QString::FROMUTF8(src->conflict_wrk); + _prejfile = QString::FROMUTF8(src->prejfile); + _text_time = src->text_time; + _prop_time = src->prop_time; + _checksum = QString::FROMUTF8(src->checksum); + _cmt_rev = src->cmt_rev; + _cmt_date = src->cmt_date; + _cmt_author = QString::FROMUTF8(src->cmt_author); + m_Lock.init(src); + m_valid = true; + } else { + m_valid = false; + m_Lock=LockEntry(); + _name= + _url=_repos=_uuid=_copyfrom_url=_conflict_old=_conflict_new=_conflict_wrk=_prejfile=_checksum=_cmt_author= QString::null; + _copied=_deleted=_absent=_incomplete = false; + _kind = svn_node_unknown; + _schedule=svn_wc_schedule_normal; + _text_time=_prop_time=_cmt_date=0; + } + } + void + Entry_private::init(const Entry_private&src) + { + _name=src._name; + _url=src._url; + _repos=src._repos; + _uuid=src._uuid; + _copyfrom_url=src._copyfrom_url; + _conflict_old=src._conflict_old; + _conflict_new=src._conflict_new; + _conflict_wrk=src._conflict_wrk; + _prejfile=src._prejfile; + _checksum=src._checksum; + _cmt_author=src._cmt_author; + _copied=src._copied; + _deleted=src._deleted; + _absent=src._absent; + _incomplete=src._incomplete; + _revision=src._revision; + _copyfrom_rev=src._copyfrom_rev; + _cmt_rev=src._cmt_rev; + _kind=src._kind; + _schedule=src._schedule; + _text_time=src._text_time; + _prop_time=src._prop_time; + _cmt_date=src._cmt_date; + _kind = src._kind; + m_Lock=src.m_Lock; + m_valid=src.m_valid; + } + + void Entry_private::init(const QString&url,const DirEntryPtr&dirEntry) + { + init(0); + _url = url; + if (dirEntry) { + _name=dirEntry->name(); + _revision = dirEntry->createdRev(); + _kind = dirEntry->kind(); + _schedule = svn_wc_schedule_normal; + _text_time = dirEntry->time (); + _prop_time = dirEntry->time (); + _cmt_rev = dirEntry->createdRev (); + _cmt_date = dirEntry->time (); + _cmt_author = dirEntry->lastAuthor (); + m_Lock=dirEntry->lockEntry(); + m_valid = true; + } + } + + void Entry_private::init(const QString&url,const InfoEntry&src) + { + init(0); + _name = src.Name(); + _url = url; + _revision = src.revision(); + _kind = src.kind (); + _schedule = svn_wc_schedule_normal; + _text_time = src.textTime (); + _prop_time = src.propTime (); + _cmt_rev = src.cmtRev (); + _cmt_date = src.cmtDate(); + _cmt_author = src.cmtAuthor(); + m_Lock=src.lockEntry(); + m_valid = true; + } + + Entry::Entry (const svn_wc_entry_t * src) + : m_Data(new Entry_private()) + { + m_Data->init (src); + } + + Entry::Entry (const Entry & src) + : m_Data(new Entry_private()) + { + if (src.m_Data) { + m_Data->init(*(src.m_Data)); + } else { + m_Data->init(0); + } + } + + Entry::Entry (const QString&url,const DirEntryPtr&src) + : m_Data(new Entry_private()) + { + m_Data->init(url,src); + } + + Entry::Entry (const QString&url,const InfoEntry&src) + : m_Data(new Entry_private()) + { + m_Data->init(url,src); + } + + Entry::~Entry () + { + delete m_Data; + } + + Entry & + Entry::operator = (const Entry & src) + { + if (this == &src) + return *this; + if (src.m_Data) { + m_Data->init(*(src.m_Data)); + } else { + m_Data->init(0); + } + return *this; + } + + const LockEntry& + Entry::lockEntry()const + { + return m_Data->m_Lock; + } + + const QString& + Entry::cmtAuthor () const + { + return m_Data->_cmt_author; + } + + const DateTime& + Entry::cmtDate () const + { + return m_Data->_cmt_date; + } + + svn_revnum_t + Entry::cmtRev () const + { + return m_Data->_cmt_rev; + } + const QString& + Entry::checksum () const + { + return m_Data->_checksum; + } + + const DateTime& + Entry::propTime () const + { + return m_Data->_prop_time; + } + + const DateTime& + Entry::textTime () const + { + return m_Data->_text_time; + } + const QString& + Entry::prejfile () const + { + return m_Data->_prejfile; + } + const QString& + Entry::conflictWrk () const + { + return m_Data->_conflict_wrk; + } + + const QString& + Entry::conflictNew () const + { + return m_Data->_conflict_new; + } + const QString& + Entry::conflictOld () const + { + return m_Data->_conflict_old; + } + svn_revnum_t + Entry::copyfromRev () const + { + return m_Data->_copyfrom_rev; + } + const QString& + Entry::copyfromUrl () const + { + return m_Data->_copyfrom_url; + } + + bool + Entry::isAbsent () const + { + return m_Data->_absent; + } + bool + Entry::isDeleted () const + { + return m_Data->_deleted != 0; + } + bool + Entry::isCopied () const + { + return m_Data->_copied != 0; + } + svn_wc_schedule_t + Entry::schedule () const + { + return m_Data->_schedule; + } + svn_node_kind_t + Entry::kind () const + { + return m_Data->_kind; + } + const QString& + Entry::uuid () const + { + return m_Data->_uuid; + } + const QString& + Entry::repos () const + { + return m_Data->_repos; + } + const QString& + Entry::url () const + { + return m_Data->_url; + } + svn_revnum_t + Entry::revision () const + { + return m_Data->_revision; + } + const QString& + Entry::name () const + { + return m_Data->_name; + } + + bool Entry::isValid () const + { + return m_Data->m_valid; + } +} + +/*! + \fn svn::Entry::isDir() + */ +bool svn::Entry::isDir() const +{ + return kind()==svn_node_dir; +} + + +/*! + \fn svn::Entry::isFile() + */ +bool svn::Entry::isFile() const +{ + return kind()==svn_node_file; +} diff --git a/src/svnqt/entry.hpp b/src/svnqt/entry.hpp new file mode 100644 index 0000000..0043622 --- /dev/null +++ b/src/svnqt/entry.hpp @@ -0,0 +1,245 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ +#ifndef _SVNCPP_ENTRY_HPP_ +#define _SVNCPP_ENTRY_HPP_ + +// svncpp +#include "svnqt/pool.hpp" +#include "svnqt/lock_entry.hpp" +#include "svnqt/dirent.hpp" +#include "svnqt/info_entry.hpp" +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/svnqttypes.hpp" + +// subversion api +#include "svn_wc.h" + + +#include <qstring.h> + +namespace svn +{ + class Entry_private; + /** + * C++ API for Subversion. + * This class wraps around @a svn_wc_entry_t. + */ + class SVNQT_EXPORT Entry + { + public: + /** + * default constructor. if @a src is set, + * copy its contents. + * + * If @a src is not set (=0) this will be + * a non-versioned entry. This can be checked + * later with @a isValid (). + * + * @param src another entry to copy from + */ + Entry (const svn_wc_entry_t * src = 0); + + /** + * copy constructor + */ + Entry (const Entry & src); + + /** + * converting constructr + */ + Entry (const QString&url,const DirEntryPtr&src); + /** + * converting constructr + */ + Entry (const QString&url,const InfoEntry&src); + + /** + * destructor + */ + virtual ~Entry (); + + /** + * returns whether this is a valid=versioned + * entry. + * + * @return is entry valid + * @retval true valid entry + * @retval false invalid or unversioned entry + */ + bool isValid () const; + /** + * @return entry's name + */ + const QString& + name () const; + /** + * @return base revision + */ + svn_revnum_t + revision () const; + /** + * @return url in repository + */ + const QString& + url () const; + + /** + * @return canonical repository url + */ + const QString& + repos () const; + /** + * @return repository uuid + */ + const QString& + uuid () const; + /** + * @return node kind (file, dir, ...) + */ + svn_node_kind_t + kind () const; + /** + * @return scheduling (add, delete, replace) + */ + svn_wc_schedule_t + schedule () const; + /** + * @return TRUE if copied + */ + bool + isCopied () const; + /** + * @return true if deleted + */ + bool + isDeleted () const; + /** + * @return true if deleted + */ + bool + isAbsent () const; + /** + * @return copyfrom location + */ + const QString& + copyfromUrl () const; + /** + * @return copyfrom revision + */ + svn_revnum_t + copyfromRev () const; + /** + * @return old version of conflicted file + */ + const QString& + conflictOld () const; + /** + * @return new version of conflicted file + */ + const QString& + conflictNew () const; + /** + * @return working version of conflicted file + */ + const QString& + conflictWrk () const; + /** + * @return property reject file + */ + const QString& + prejfile () const; + /** + * @return last up-to-date time for text contents + * @retval 0 no information available + */ + const DateTime& + textTime () const; + /** + * @return last up-to-date time for properties + * @retval 0 no information available + */ + const DateTime& + propTime()const; + + /** + * @return base64 encoded checksum + * @retval NULL for backwards compatibility + */ + const QString& + checksum () const; + + /** + * @return last revision this was changed + */ + svn_revnum_t + cmtRev () const; + + /** + * @return last date this was changed + */ + const DateTime& + cmtDate () const; + + /** + * @return last commit author of this file + */ + const QString& + cmtAuthor () const; + + /** + * @return lock for that entry + * @since subversion 1.2 + */ + const LockEntry& + lockEntry()const; + + /** + * @return true if entry is marked as dir + */ + bool isDir()const; + /** + * assignment operator + */ + Entry & + operator = (const Entry &); + bool isFile()const; + + private: + Entry_private*m_Data; + }; + +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/exception.cpp b/src/svnqt/exception.cpp new file mode 100644 index 0000000..67bcb60 --- /dev/null +++ b/src/svnqt/exception.cpp @@ -0,0 +1,224 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + + +// svncpp +#include "exception.hpp" +#include "svnqt/svnqt_defines.hpp" + +#include <qstring.h> + +#ifdef HAS_BACKTRACE_H +#include <execinfo.h> +#include <qstringlist.h> +#define SVNQT_BACKTRACE_LENGTH 20 +#endif + +namespace svn +{ + + struct Exception::Data + { + private: + public: + QString message; + apr_status_t apr_err; + + Data (const char * msg) + : message(QString::FROMUTF8(msg)),apr_err(0) + { + } + + Data (const QString& msg) + : message(msg),apr_err(0) + { + } + + + Data (const Data& other) + : message(other.message), apr_err(other.apr_err) + { + } + }; + + Exception::Exception (const char * message) throw () + { + m = new Data (message); + } + + Exception::Exception (const QString& message) throw () + { + m = new Data (message); + } + + Exception::Exception (const Exception & other) throw () + { + m = new Data (*other.m); + } + + Exception::~Exception () throw () + { + delete m; + } + + apr_status_t + Exception::apr_err () const + { + return m->apr_err; + } + + const QString& + Exception::msg () const + { + return m->message; + } + + void Exception::setMessage(const QString&aMsg) + { + m->message=aMsg; + } + + QString Exception::error2msg(svn_error_t*error) + { + QString message = ""; + if (error==0) { + return message; + } + svn_error_t * next = error->child; + if (error->message) + message = QString::FROMUTF8(error->message); + else + { + message = "Unknown error!\n"; + if (error->file) + { + message += QString::FROMUTF8("In file "); + message += QString::FROMUTF8(error->file); + message += QString(" Line %1").arg(error->line); + } + } + while (next != NULL && next->message != NULL) + { + message = message + "\n" + QString::FROMUTF8(next->message); + + next = next->child; + } + + return message; + + } + + ClientException::ClientException (const char*msg) throw () + : Exception (msg) + { + } + + ClientException::ClientException (const QString&msg) throw () + : Exception (msg) + { + } + + ClientException::ClientException (svn_error_t * error) throw () + : Exception ("") + { + init(); + if (error == 0) + return; + + m->apr_err = error->apr_err; + m->message += error2msg(error); + svn_error_clear (error); + } + + ClientException::ClientException (apr_status_t status) throw () + : Exception ("") + { + init(); + m->apr_err = status; + } + + + ClientException::~ClientException () throw () + { + } + + ClientException::ClientException (const ClientException & src) throw () + : Exception (src.msg()) + { + m->apr_err = src.apr_err(); + } + + void ClientException::init() + { +#ifdef USEBACKTRACE + if (m_backTraceConstr.length()==0) { + m_backTraceConstr = getBackTrace(); + m->message=m_backTraceConstr; + } +#else + m_backTraceConstr=""; +#endif + } + + QString ClientException::getBackTrace() + { + QString Result; + qDebug("getBackTrace"); +#ifdef HAS_BACKTRACE_H + qDebug("Generating backtrace"); + void *array[SVNQT_BACKTRACE_LENGTH]; + size_t size; + size_t i; + + size = backtrace (array, SVNQT_BACKTRACE_LENGTH); + if (!size) { + return Result; + } + + char ** strings = backtrace_symbols (array, size); + + QStringList r; + for (i = 0; i < size; ++i) { + r.push_back(QString::number(i) + + QString::FROMUTF8(": ") + + QString::FROMUTF8(strings[i])); + } + Result = QString::FROMUTF8("[\n")+r.join("\n")+QString::FROMUTF8("]\n"); + free (strings); +#endif + return Result; + } + +} +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/exception.hpp b/src/svnqt/exception.hpp new file mode 100644 index 0000000..b83269f --- /dev/null +++ b/src/svnqt/exception.hpp @@ -0,0 +1,138 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_EXCEPTION_H_ +#define _SVNCPP_EXCEPTION_H_ + +#include "svnqt/svnqt_defines.hpp" +// subversion api +#include "svn_client.h" +#include <qstring.h> + +namespace svn +{ + + /** + * Generic exception class. + */ + class SVNQT_EXPORT Exception + { + public: + /** + * Constructor. Assigns the exception reason. + */ + Exception (const char * message) throw (); + Exception (const QString&message) throw(); + + virtual ~Exception () throw (); + + /** + * @return the exception message. + */ + virtual const QString& msg() const; + + /** + * @return the outermost error code. + */ + apr_status_t apr_err () const; + + static QString error2msg(svn_error_t*error); + + protected: + struct Data; + Data * m; + void setMessage(const QString&); + + private: + + Exception (const Exception &) throw (); + + Exception () throw (); + + Exception & operator = (const Exception &); + + }; + + /** + * Subversion client exception class. + */ + class SVNQT_EXPORT ClientException : public Exception + { + public: + /** + * Constructor. Sets the error template and an optional message. + * @param error the error to display. This will get cleared inside with svn_error_clear + * so it isn't usable after that! + */ + ClientException (svn_error_t * error) throw (); + + + /** + * Constructor that takes only an apr errorcode + */ + ClientException (apr_status_t status) throw (); + + /** + * Constructor + */ + ClientException (const char*msg) throw (); + + /** + * Constructor + */ + ClientException (const QString&message) throw(); + + /** + * Copy constructor + */ + ClientException (const ClientException & src) throw (); + + virtual ~ClientException () throw (); + + private: + ClientException () throw (); + + ClientException & operator = (ClientException &); + static QString getBackTrace(); + + void init(); + /// backtrace from constructor; + QString m_backTraceConstr; + + }; + +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/helper.hpp b/src/svnqt/helper.hpp new file mode 100644 index 0000000..fca54d1 --- /dev/null +++ b/src/svnqt/helper.hpp @@ -0,0 +1,98 @@ + +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef __HELPER_HPP +#define __HELPER_HPP + +#include "svnqttypes.hpp" +#include "revision.hpp" +#include <svn_types.h> + +#include <iostream> + +namespace svn +{ + namespace internal + { + class DepthToSvn + { +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + protected: + svn_depth_t _value; + public: + DepthToSvn(const svn::Depth&val):_value(svn_depth_unknown) + { + switch (val) { + case DepthUnknown: + _value = svn_depth_unknown; + break; + case DepthExclude: + _value = svn_depth_exclude; + break; + case DepthEmpty: + _value = svn_depth_empty; + break; + case DepthFiles: + _value = svn_depth_files; + break; + case DepthImmediates: + _value = svn_depth_immediates; + break; + case DepthInfinity: + default: + _value = svn_depth_infinity; + break; + } + } + + operator svn_depth_t () + { + return _value; + } +#endif + }; + + class RevisionRangesToHash + { +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + protected: + RevisionRanges m_ranges; + public: + RevisionRangesToHash(const RevisionRanges&_input):m_ranges(_input){} + + apr_array_header_t*array(const Pool&pool) + { + apr_array_header_t*ranges=apr_array_make(pool,m_ranges.size(),sizeof(svn_opt_revision_range_t *)); + svn_opt_revision_range_t *range; + + for (unsigned long j=0;j<m_ranges.count();++j) + { + range = (svn_opt_revision_range_t *)apr_palloc(pool, sizeof(*range)); + range->start= *m_ranges[j].first.revision(); + range->end = *m_ranges[j].second.revision(); + APR_ARRAY_PUSH(ranges,svn_opt_revision_range_t *) = range; + } + return ranges; + } +#endif + }; + } +} +#endif diff --git a/src/svnqt/info_entry.cpp b/src/svnqt/info_entry.cpp new file mode 100644 index 0000000..72d714a --- /dev/null +++ b/src/svnqt/info_entry.cpp @@ -0,0 +1,311 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#include "svnqt/info_entry.hpp" +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/pool.hpp" +#include <svn_client.h> +#include <svn_path.h> + +namespace svn +{ + + InfoEntry::InfoEntry() + { + init(); + } + + InfoEntry::InfoEntry(const svn_info_t*info,const char*path) + { + init(info,path); + } + + InfoEntry::InfoEntry(const svn_info_t*info,const QString&path) + { + init(info,path); + } + + InfoEntry::~InfoEntry() + { + } + + DateTime InfoEntry::cmtDate()const + { + return m_last_changed_date; + } + DateTime InfoEntry::textTime()const + { + return m_text_time; + } + DateTime InfoEntry::propTime()const + { + return m_prop_time; + } + bool InfoEntry::hasWc()const + { + return m_hasWc; + } + const LockEntry&InfoEntry::lockEntry()const + { + return m_Lock; + } + const QString&InfoEntry::cmtAuthor () const + { + return m_last_author; + } + const QString&InfoEntry::Name()const + { + return m_name; + } + const QString& InfoEntry::checksum()const + { + return m_checksum; + } + const QString& InfoEntry::conflictNew()const + { + return m_conflict_new; + } + const QString& InfoEntry::conflictOld()const + { + return m_conflict_old; + } + const QString& InfoEntry::conflictWrk()const + { + return m_conflict_wrk; + } + const QString& InfoEntry::copyfromUrl()const + { + return m_copyfrom_url; + } + const QString& InfoEntry::prejfile()const + { + return m_prejfile; + } + const QString& InfoEntry::reposRoot()const + { + return m_repos_root; + } + const QString& InfoEntry::url()const + { + return m_url; + } + const QString& InfoEntry::uuid()const + { + return m_UUID; + } + svn_node_kind_t InfoEntry::kind()const + { + return m_kind; + } + const Revision& InfoEntry::cmtRev()const + { + return m_last_changed_rev; + } + const Revision& InfoEntry::copyfromRev()const + { + return m_copy_from_rev; + } + const Revision& InfoEntry::revision()const + { + return m_revision; + } + svn_wc_schedule_t InfoEntry::Schedule()const + { + return m_schedule; + } + const QString&InfoEntry::prettyUrl()const + { + return m_pUrl; + } + bool InfoEntry::isDir()const + { + return kind()==svn_node_dir; + } + const QByteArray&InfoEntry::changeList()const + { + return m_changeList; + } + QLONG InfoEntry::size()const + { + return m_size; + } + QLONG InfoEntry::working_size()const + { + return m_working_size; + } + svn::Depth InfoEntry::depth()const + { + return m_depth; + } +} + +/*! + \fn svn::InfoEntry::init() + */ +void svn::InfoEntry::init() +{ + m_name = ""; + m_last_changed_date=0; + m_text_time = 0; + m_prop_time = 0; + m_hasWc = false; + m_Lock = LockEntry(); + m_checksum = ""; + m_conflict_new = ""; + m_conflict_old = ""; + m_conflict_wrk = ""; + m_copyfrom_url = ""; + m_last_author = ""; + m_prejfile = ""; + m_repos_root = ""; + m_url = ""; + m_pUrl = ""; + m_UUID = ""; + m_kind = svn_node_none; + m_copy_from_rev = SVN_INVALID_REVNUM; + m_last_changed_rev = SVN_INVALID_REVNUM; + m_revision = SVN_INVALID_REVNUM; + m_schedule = svn_wc_schedule_normal; + + m_size = m_working_size = SVNQT_SIZE_UNKNOWN; + m_changeList=QByteArray(); + m_depth = DepthUnknown; +} + +void svn::InfoEntry::init(const svn_info_t*item,const char*path) +{ + init(item,QString::FROMUTF8(path)); +} + +/*! + \fn svn::InfoEntry::init(const svn_info_t*) + */ +void svn::InfoEntry::init(const svn_info_t*item,const QString&path) +{ + if (!item) { + init(); + return; + } + m_name = path; + m_last_changed_date=item->last_changed_date; + m_text_time = item->text_time; + m_prop_time = item->prop_time; + if (item->lock) { + m_Lock.init(item->lock); + } else { + m_Lock = LockEntry(); + } + m_checksum = QString::FROMUTF8(item->checksum); + m_conflict_new = QString::FROMUTF8(item->conflict_new); + m_conflict_old = QString::FROMUTF8(item->conflict_old); + m_conflict_wrk = QString::FROMUTF8(item->conflict_wrk); + m_copyfrom_url = QString::FROMUTF8(item->copyfrom_url); + m_last_author = QString::FROMUTF8(item->last_changed_author); + m_prejfile = QString::FROMUTF8(item->prejfile); + m_repos_root = QString::FROMUTF8(item->repos_root_URL); + m_url = QString::FROMUTF8(item->URL); + m_pUrl = prettyUrl(item->URL); + m_UUID = QString::FROMUTF8(item->repos_UUID); + m_kind = item->kind; + m_copy_from_rev = item->copyfrom_rev; + m_last_changed_rev = item->last_changed_rev; + m_revision = item->rev; + m_hasWc = item->has_wc_info; + m_schedule = item->schedule; + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + m_size = item->size!=SVN_INFO_SIZE_UNKNOWN?QLONG(item->size):SVNQT_SIZE_UNKNOWN; + m_working_size = item->working_size!=SVN_INFO_SIZE_UNKNOWN?QLONG(item->working_size):SVNQT_SIZE_UNKNOWN; + if (item->changelist) { +#if QT_VERSION < 0x040000 + m_changeList = QByteArray(QCString(item->changelist,strlen(item->changelist))); +#else + m_changeList = QByteArray(item->changelist,strlen(item->changelist)); +#endif + } else { + m_changeList=QByteArray(); + } + + switch (item->depth) { + case svn_depth_exclude: + m_depth=DepthExclude; + break; + case svn_depth_empty: + m_depth=DepthEmpty; + break; + case svn_depth_files: + m_depth=DepthFiles; + break; + case svn_depth_immediates: + m_depth=DepthImmediates; + break; + case svn_depth_infinity: + m_depth=DepthInfinity; + break; + case svn_depth_unknown: + default: + m_depth=DepthUnknown; + break; + } +#else + m_size = SVNQT_SIZE_UNKNOWN; + m_working_size = SVNQT_SIZE_UNKNOWN; + m_changeList=QByteArray(); + m_depth = DepthUnknown; +#endif +} + +QString svn::InfoEntry::prettyUrl(const char*_url)const +{ + if (_url) { + Pool pool; + _url = svn_path_uri_decode(_url,pool); + return QString::FROMUTF8(_url); + } + return QString::FROMUTF8(""); +} + +svn::InfoEntry::InfoEntry(const InfoEntry&other) +{ + m_name = other.m_name; + m_last_changed_date=other.m_last_changed_date; + m_text_time = other.m_text_time; + m_prop_time = other.m_prop_time; + m_Lock = other.m_Lock; + m_checksum = other.m_checksum; + m_conflict_new = other.m_conflict_new; + m_conflict_old = other.m_conflict_old; + m_conflict_wrk = other.m_conflict_wrk; + m_copyfrom_url = other.m_copyfrom_url; + m_last_author = other.m_last_author; + m_prejfile = other.m_prejfile; + m_repos_root = other.m_repos_root; + m_url = other.m_url; + m_pUrl = other.m_pUrl; + m_UUID = other.m_UUID; + m_kind = other.m_kind; + m_copy_from_rev = other.m_copy_from_rev; + m_last_changed_rev = other.m_last_changed_rev; + m_revision = other.m_revision; + m_hasWc = other.m_hasWc; + m_schedule = other.m_schedule; + m_size = other.m_size; + m_working_size = other.m_working_size; + +} diff --git a/src/svnqt/info_entry.hpp b/src/svnqt/info_entry.hpp new file mode 100644 index 0000000..91de95c --- /dev/null +++ b/src/svnqt/info_entry.hpp @@ -0,0 +1,118 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef __INFO_ENTRY_H +#define __INFO_ENTRY_H + +#include <svnqt/lock_entry.hpp> +#include <svnqt/datetime.hpp> +#include <svnqt/revision.hpp> +#include <svnqt/svnqttypes.hpp> + +#include <qstring.h> + +struct svn_info_t; + +namespace svn { + class SVNQT_EXPORT InfoEntry + { +public: + InfoEntry(); + InfoEntry(const svn_info_t*,const char*path); + InfoEntry(const svn_info_t*,const QString&path); + InfoEntry(const InfoEntry&); + ~InfoEntry(); + + void init(const svn_info_t*,const char*path); + void init(const svn_info_t*,const QString&path); + + DateTime cmtDate()const; + DateTime textTime()const; + DateTime propTime()const; + bool hasWc()const; + /** + * @return lock for that entry + * @since subversion 1.2 + */ + const LockEntry&lockEntry()const; + /** + * @return last commit author of this file + */ + const QString&cmtAuthor () const; + const QString&Name()const; + + const QString& checksum()const; + const QString& conflictNew()const; + const QString& conflictOld()const; + const QString& conflictWrk()const; + const QString& copyfromUrl()const; + const QString& prejfile()const; + const QString& reposRoot()const; + const QString& url()const; + const QString& uuid()const; + svn_node_kind_t kind()const; + const Revision& cmtRev()const; + const Revision& copyfromRev()const; + const Revision& revision()const; + svn_wc_schedule_t Schedule()const; + + QLONG size()const; + QLONG working_size()const; + const QByteArray&changeList()const; + svn::Depth depth()const; + + const QString&prettyUrl()const; + + bool isDir()const; + QString prettyUrl(const char*)const; + +protected: + DateTime m_last_changed_date; + DateTime m_text_time; + DateTime m_prop_time; + bool m_hasWc; + LockEntry m_Lock; + QString m_name; + QString m_checksum; + QString m_conflict_new; + QString m_conflict_old; + QString m_conflict_wrk; + QString m_copyfrom_url; + QString m_last_author; + QString m_prejfile; + QString m_repos_root; + QString m_url; + QString m_pUrl; + QString m_UUID; + svn_node_kind_t m_kind; + Revision m_copy_from_rev; + Revision m_last_changed_rev; + Revision m_revision; + svn_wc_schedule_t m_schedule; + + QLONG m_size; + QLONG m_working_size; + QByteArray m_changeList; + svn::Depth m_depth; + +protected: + void init(); + }; +} +#endif diff --git a/src/svnqt/lock_entry.cpp b/src/svnqt/lock_entry.cpp new file mode 100644 index 0000000..cf7ffe1 --- /dev/null +++ b/src/svnqt/lock_entry.cpp @@ -0,0 +1,141 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +// svncpp +#include "lock_entry.hpp" +#include "pool.hpp" + +// subversion api +#include "svn_time.h" +#include "svn_version.h" + + +namespace svn +{ + LockEntry::LockEntry () + : date(0),exp(0),owner(""),comment(""),token(""),locked(false) + { + } + + LockEntry::LockEntry ( + const apr_time_t lock_time, + const apr_time_t expiration_time, + const char * lock_owner, + const char * lock_comment, + const char * lock_token) + : date(lock_time),exp(expiration_time), + owner(lock_owner?QString::FROMUTF8(lock_owner):""), + comment(lock_comment?QString::FROMUTF8(lock_comment):""), + token(lock_token?QString::FROMUTF8(lock_token):""), + locked(lock_token?true:false) + { + } + const QString&LockEntry::Comment()const + { + return comment; + } + const QString&LockEntry::Owner()const + { + return owner; + } + const QString&LockEntry::Token()const + { + return token; + } + const DateTime&LockEntry::Date()const + { + return date; + } + const DateTime&LockEntry::Expiration()const + { + return exp; + } + bool LockEntry::Locked()const + { + return locked; + } + void LockEntry::init(const svn_wc_entry_t * src) + { + if (src) { + date = src->lock_creation_date; + locked = src->lock_token?true:false; + token = (src->lock_token?QString::FROMUTF8(src->lock_token):""); + comment = (src->lock_comment?QString::FROMUTF8(src->lock_comment):""); + owner = (src->lock_owner?QString::FROMUTF8(src->lock_owner):""); + } else { + date = 0; + owner = ""; + comment = ""; + token = ""; + locked = false; + } + exp = 0; + } + + void LockEntry::init(const svn_lock_t* src) + { + if (src) { + date = src->creation_date; + locked = src->token?true:false; + token = (src->token?QString::FROMUTF8(src->token):""); + comment = (src->comment?QString::FROMUTF8(src->comment):""); + owner = (src->owner?QString::FROMUTF8(src->owner):""); + } else { + date = 0; + exp = 0; + owner = ""; + comment = ""; + token = ""; + locked = false; + } + + } + + void LockEntry::init( + const apr_time_t lock_time, + const apr_time_t expiration_time, + const char * lock_owner, + const char * lock_comment, + const char * lock_token) + { + date = lock_time; + exp = expiration_time; + locked = lock_token?true:false; + token = lock_token?QString::FROMUTF8(lock_token):""; + owner = lock_owner?QString::FROMUTF8(lock_owner):""; + comment = lock_comment?QString::FROMUTF8(lock_comment):""; + } +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/lock_entry.hpp b/src/svnqt/lock_entry.hpp new file mode 100644 index 0000000..eec3d1f --- /dev/null +++ b/src/svnqt/lock_entry.hpp @@ -0,0 +1,90 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_LOCK_ENTRY_H_ +#define _SVNCPP_LOCK_ENTRY_H_ + +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/datetime.hpp" + +#include <qstring.h> + +// apr +#include "apr_time.h" + +// subversion api +#include "svn_types.h" +#include "svn_wc.h" + +namespace svn +{ + class SVNQT_EXPORT LockEntry + { + public: + LockEntry (); + + LockEntry (const apr_time_t lock_time, + const apr_time_t expiration_time, + const char * lock_owner, + const char * lock_comment, + const char * lock_token); + + void init(const svn_wc_entry_t * src); + + void init(const apr_time_t lock_time, + const apr_time_t expiration_time, + const char * lock_owner, + const char * lock_comment, + const char * lock_token); + void init(const svn_lock_t*); + const QString&Comment()const; + const QString&Owner()const; + const QString&Token()const; + const DateTime&Date()const; + const DateTime&Expiration()const; + bool Locked()const; + + protected: + DateTime date; + DateTime exp; + QString owner; + QString comment; + QString token; + bool locked; + }; +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ + diff --git a/src/svnqt/log_entry.cpp b/src/svnqt/log_entry.cpp new file mode 100644 index 0000000..fdd28e8 --- /dev/null +++ b/src/svnqt/log_entry.cpp @@ -0,0 +1,190 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ +// svncpp +#include "log_entry.hpp" +#include "pool.hpp" + +// subversion api +#include "svn_time.h" +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) +#include "svn_compat.h" +#endif + + +namespace svn +{ + LogChangePathEntry::LogChangePathEntry ( + const char *path_, + char action_, + const char *copyFromPath_, + const svn_revnum_t copyFromRevision_) + : path(QString::FROMUTF8(path_)), action(action_), + copyFromPath (QString::FROMUTF8(copyFromPath_)), + copyFromRevision (copyFromRevision_) + { + } + + LogChangePathEntry::LogChangePathEntry (const QString &path_, + char action_, + const QString ©FromPath_, + const svn_revnum_t copyFromRevision_) + : path(path_), + action(action_), + copyFromPath(copyFromPath_), + copyToPath(QString::null), + copyFromRevision(copyFromRevision_), + copyToRevision(-1) + { + } + + LogChangePathEntry::LogChangePathEntry() + : path(QString::null),action(0),copyFromPath(QString::null),copyToPath(QString::null), + copyFromRevision(-1),copyToRevision(-1) + { + } + + LogChangePathEntry::LogChangePathEntry (const QString &path_, + char action_, + const QString ©FromPath_, + const svn_revnum_t copyFromRevision_, + const QString ©ToPath_, + const svn_revnum_t copyToRevision_) + : path(path_),action(action_),copyFromPath(copyFromPath_),copyToPath(copyToPath_), + copyFromRevision(copyFromRevision_),copyToRevision(copyToRevision_) + { + } + + LogEntry::LogEntry () + : revision(-1),date(0),author(""),message("") + { + } + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + LogEntry::LogEntry(svn_log_entry_t*log_entry) + : revision(-1),date(0),author(""),message("") + { + Pool pool; + const char *author_; + const char *date_; + const char *message_; + svn_compat_log_revprops_out(&author_, &date_, &message_, log_entry->revprops); + + author = author_ == 0 ? QString::fromLatin1("") : QString::FROMUTF8(author_); + message = message_ == 0 ? QString::fromLatin1("") : QString::FROMUTF8(message_); + setDate(date_); + revision = log_entry->revision; + if (log_entry->changed_paths) { + for (apr_hash_index_t *hi = apr_hash_first (pool, log_entry->changed_paths); + hi != NULL; + hi = apr_hash_next (hi)) + { + const void *pv; + void *val; + apr_hash_this (hi, &pv, NULL, &val); + svn_log_changed_path_t *log_item = reinterpret_cast<svn_log_changed_path_t *> (val); + const char* path = reinterpret_cast<const char*>(pv); + changedPaths.push_back (LogChangePathEntry (path,log_item->action,log_item->copyfrom_path,log_item->copyfrom_rev) ); + } + } + } +#endif + + LogEntry::LogEntry ( + const svn_revnum_t revision_, + const char * author_, + const char * date_, + const char * message_) + { + setDate(date_); + + revision = revision_; + author = author_ == 0 ? QString::fromLatin1("") : QString::FROMUTF8(author_); + message = message_ == 0 ? QString::fromLatin1("") : QString::FROMUTF8(message_); + } + + void LogEntry::setDate(const char*date_) + { + apr_time_t date__ = 0; + if (date_ != 0) + { + Pool pool; + + if (svn_time_from_cstring (&date__, date_, pool) != 0) + date__ = 0; + } + date = date__; + } +} + + +SVNQT_EXPORT QDataStream& operator<<(QDataStream&s,const svn::LogEntry&r) +{ + s << r.revision + << r.author + << r.message + << r.changedPaths + << r.date; + return s; +} + +SVNQT_EXPORT QDataStream& operator<<(QDataStream&s,const svn::LogChangePathEntry&r) +{ + short ac = r.action; + s << r.path + << ac + << r.copyFromPath + << r.copyFromRevision + << r.copyToPath + << r.copyToRevision; + return s; +} + +SVNQT_EXPORT QDataStream& operator>>(QDataStream&s,svn::LogEntry&r) +{ + s >> r.revision + >> r.author + >> r.message + >> r.changedPaths + >> r.date; + return s; +} + +SVNQT_EXPORT QDataStream& operator>>(QDataStream&s,svn::LogChangePathEntry&r) +{ + short ac; + s >> r.path + >> ac + >> r.copyFromPath + >> r.copyFromRevision + >> r.copyToPath + >> r.copyToRevision; + r.action = ac; + return s; +} diff --git a/src/svnqt/log_entry.hpp b/src/svnqt/log_entry.hpp new file mode 100644 index 0000000..cc33f60 --- /dev/null +++ b/src/svnqt/log_entry.hpp @@ -0,0 +1,137 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_LOG_ENTRY_H_ +#define _SVNCPP_LOG_ENTRY_H_ + +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/datetime.hpp" + +//Qt +#include <qglobal.h> + +#if QT_VERSION < 0x040000 + +#include <qglobal.h> +#include <qstring.h> +#include <qvaluelist.h> +#include <qmap.h> + +#else + +#include <QtCore> + +#endif + +// apr +#include "apr_time.h" + +// subversion api +#include "svn_types.h" +#include "svn_version.h" + +namespace svn +{ + + class SVNQT_EXPORT LogChangePathEntry + { + public: + LogChangePathEntry (const char *path_, + char action_, + const char *copyFromPath_, + const svn_revnum_t copyFromRevision_); + + LogChangePathEntry (const QString &path_, + char action_, + const QString ©FromPath_, + const svn_revnum_t copyFromRevision_); + + LogChangePathEntry (const QString &path_, + char action_, + const QString ©FromPath_, + const svn_revnum_t copyFromRevision_, + const QString ©ToPath_, + const svn_revnum_t copyToRevision_); + + LogChangePathEntry(); + + QString path; + char action; + QString copyFromPath; + //! future use or useful in backends + QString copyToPath; + + QLONG copyFromRevision; + //! future use or useful in backends + QLONG copyToRevision; + }; + +#if QT_VERSION < 0x040000 + typedef QValueList<LogChangePathEntry> LogChangePathEntries; +#else + typedef QList<LogChangePathEntry> LogChangePathEntries; +#endif + + class SVNQT_EXPORT LogEntry + { + public: + LogEntry (); + + LogEntry (const svn_revnum_t revision, + const char * author, + const char * date, + const char * message); +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5)) || (SVN_VER_MAJOR > 1) + LogEntry(svn_log_entry_t*); +#endif + void setDate(const char*date); + + //! if -1 the entry is a fake entry and not real usable! + QLONG revision; + QLONG date; + QString author; + QString message; + LogChangePathEntries changedPaths; + QLIST<QLONG> m_MergedInRevisions; + }; +} + +SVNQT_EXPORT QDataStream &operator<<(QDataStream&s,const svn::LogEntry&r); +SVNQT_EXPORT QDataStream &operator<<(QDataStream&s,const svn::LogChangePathEntry&r); + +SVNQT_EXPORT QDataStream &operator>>(QDataStream&s,svn::LogEntry&r); +SVNQT_EXPORT QDataStream &operator>>(QDataStream&s,svn::LogChangePathEntry&r); + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/path.cpp b/src/svnqt/path.cpp new file mode 100644 index 0000000..676c151 --- /dev/null +++ b/src/svnqt/path.cpp @@ -0,0 +1,290 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + + +// subversion api +#include "svn_path.h" + +// apr api +#include "apr_file_io.h" + +// svncpp +#include "svnqt/path.hpp" +#include "svnqt/pool.hpp" +#include "svnqt/url.hpp" +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/revision.hpp" +#include "svnqt/exception.hpp" + +#include <qurl.h> + +namespace svn +{ + Path::Path (const char * path) + { + init(QString::FROMUTF8(path)); + } + + Path::Path (const QString & path) + { + init (path); + } + + Path::Path (const Path & path) + : m_path(path.m_path) + { + } + + void + Path::init (const QString& path) + { + Pool pool; + + if (path.isEmpty()) { + m_path = ""; + } else { + const char * int_path = svn_path_internal_style (path.TOUTF8(), pool.pool () ); + if (Url::isValid(path) ) { + if (!svn_path_is_uri_safe(int_path)) { + int_path = svn_path_uri_encode(int_path,pool); + } + } + m_path = QString::FROMUTF8(int_path); +#if QT_VERSION < 0x040000 + if (Url::isValid(path) && m_path.find("@")!=-1 ) { +#else + if (Url::isValid(path) && m_path.indexOf("@")!=-1 ) { +#endif + /// @todo make sure that "@" is never used as revision paramter + QUrl uri = m_path; + m_path = uri.path(); + m_path.replace("@","%40"); +#if QT_VERSION < 0x040000 + m_path = uri.protocol()+"://"+(uri.hasUser()?uri.user()+(uri.hasPassword()?":"+uri.password():"")+"@":"") + +uri.host()+m_path; +#else + m_path = uri.scheme()+"://"+uri.authority()+m_path; +#endif + if (m_path.endsWith("/")) { + int_path = svn_path_internal_style (path.TOUTF8(), pool.pool () ); + m_path = QString::FROMUTF8(int_path); + } + } + } + } + + bool Path::isUrl()const + { + return Url::isValid(m_path); + } + + const QString & + Path::path () const + { + return m_path; + } + + Path::operator const QString&()const + { + return m_path; + } + + QString Path::prettyPath()const + { + if (!Url::isValid(m_path)) { + return m_path; + } + Pool pool; + const char * int_path = svn_path_uri_decode(m_path.TOUTF8(), pool.pool () ); + QString _p = QString::FROMUTF8(int_path); + _p.replace("%40","@"); + return _p; + } + + const QByteArray + Path::cstr() const + { + return m_path.TOUTF8(); + } + + Path& + Path::operator=(const Path & path) + { + if (this == &path) + return *this; + m_path = path.path(); + return *this; + } + + bool + Path::isset () const + { + return m_path.length () > 0; + } + + void + Path::addComponent (const QString& component) + { + Pool pool; + + if (Url::isValid (m_path)) + { + const char * newPath = + svn_path_url_add_component (m_path.TOUTF8(), component.TOUTF8(), pool); + m_path = QString::FROMUTF8(newPath); + } + else + { + svn_stringbuf_t * pathStringbuf = + svn_stringbuf_create (m_path.TOUTF8(), pool); + + svn_path_add_component (pathStringbuf, + component.TOUTF8()); + + m_path = QString::FROMUTF8(pathStringbuf->data); + } + } + + + void + Path::addComponent (const char* component) + { + addComponent (QString::FROMUTF8(component)); + } + + + void + Path::removeLast() + { + Pool pool; + if (m_path.length()<=1) { + m_path=QString::FROMUTF8(""); + } + svn_stringbuf_t*pathStringbuf= + svn_stringbuf_create (m_path.TOUTF8(), pool); + svn_path_remove_component(pathStringbuf); + m_path = QString::FROMUTF8(pathStringbuf->data); + } + + void + Path::split (QString & dirpath, QString & basename) const + { + Pool pool; + + const char * cdirpath; + const char * cbasename; + + svn_path_split (prettyPath().TOUTF8(), &cdirpath, &cbasename, pool); + dirpath = QString::FROMUTF8(cdirpath); + basename = QString::FROMUTF8(cbasename); + } + + + void + Path::split (QString & dir, QString & filename, QString & ext) const + { + QString basename; + + // first split path into dir and filename+ext + split (dir, basename); + + // next search for last . +#if QT_VERSION < 0x040000 + int pos = basename.findRev(QChar('.')); +#else + int pos = basename.lastIndexOf(QChar('.')); +#endif + + if (pos == -1) + { + filename = basename; + ext = QString::fromLatin1(""); + } + else + { + filename = basename.left(pos); + ext = basename.mid(pos+1); + } + } + + Path + Path::getTempDir () + { + const char * tempdir = 0; + Pool pool; + + if (apr_temp_dir_get (&tempdir, pool) != APR_SUCCESS) + { + tempdir = 0; + } + + return tempdir; + } + + void + Path::parsePeg(const QString&pathorurl,Path&_path,svn::Revision&_peg) + { + const char *truepath = 0; + svn_opt_revision_t pegr; + svn_error_t *error = 0; + QByteArray _buf = pathorurl.TOUTF8(); + + Pool pool; + error = svn_opt_parse_path(&pegr, &truepath,_buf,pool); + if (error != 0) { + throw ClientException (error); + } + qDebug("Path: %s",truepath); + _peg = svn::Revision(&pegr); + _path=Path(truepath); + } + + unsigned int + Path::length () const + { + return m_path.length (); + } + + + QString + Path::native () const + { + Pool pool; + + return QString::FROMUTF8(svn_path_local_style (m_path.TOUTF8(), pool)); + } + +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/path.hpp b/src/svnqt/path.hpp new file mode 100644 index 0000000..0d92fc2 --- /dev/null +++ b/src/svnqt/path.hpp @@ -0,0 +1,200 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_PATH_HPP_ +#define _SVNCPP_PATH_HPP_ + +#include <qstring.h> +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/svnqttypes.hpp" + +namespace svn +{ + /** + * Encapsulation for Subversion Path handling + */ + class SVNQT_EXPORT Path + { + private: + QString m_path; + + /** + * initialize the class + * + * @param path Path string - when url this should NOT hold revision as @ parameter!!!!! (will filtered out) + */ + void init (const QString& path); + + public: + /** + * Constructor that takes a string as parameter. + * The string is converted to subversion internal + * representation. The string is copied. + * + * @param path Path string - when url this should NOT hold revision as @ parameter!!!!! (will filtered out) + */ + Path (const QString & path = QString::null); + + /** + * Constructor + * + * @see Path::Path (const QString &) + * @param path Path string - when url this should NOT hold revision as @ parameter!!!!! (will filtered out) + */ + Path (const char * path); + + /** + * Copy constructor + * + * @param path Path to be copied + */ + Path (const Path & path); + + /** + * Assignment operator + */ + Path& operator=(const Path&); + + /** + * @return Path string + */ + const QString & + path () const; + + /** + * @return Path string + */ + operator const QString&()const; + + /** + * @return Path as pretty url + */ + QString prettyPath()const; + + /** + * @return Path string as c string + */ + const QByteArray cstr() const; + + /** + * check whether a path is set. Right now + * this checks only if the string is non- + * empty. + * + * @return true if there is a path set + */ + bool + isset() const; + + + /** + * adds a new URL component to the path + * + * @param component new component to add + */ + void + addComponent (const char * component); + + + /** + * adds a new URL component to the path + * + * @param component new component to add + */ + void + addComponent (const QString & component); + + /** Reduce path to its parent folder. + * If the path length is 1 (eg., only "/") it will cleared so + * path length will get zero. + * @sa svn_path_remove_component + */ + void + removeLast(); + + + /** + * split path in its components + * + * @param dirpath directory/path component + * @param basename filename + */ + void + split (QString & dirpath, QString & basename) const; + + + /** + * split path in its components including + * file extension + * + * @param dir directory component + * @param filename filename + * @param ext extension (including leading dot ".") + */ + void + split (QString & dir, QString & filename, QString & ext) const; + + + /** + * returns the temporary directory + */ + static Path + getTempDir (); + + /** Parse a string for a peg revision + * @param pathorurl url to parse + * @param _path target to store the cleaned url + * @param _peg target where to store the peg url. + * @throw svn::ClientException on errors + */ + static void + parsePeg(const QString&pathorurl,Path&_path,svn::Revision&_peg); + + + /** return the length of the path-string */ + unsigned int + length () const; + + + /** returns the path with native separators */ + QString + native () const; + + /** returns if the path is a valid url, eg. points to a remote */ + bool isUrl()const; + }; +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/pool.cpp b/src/svnqt/pool.cpp new file mode 100644 index 0000000..34ef947 --- /dev/null +++ b/src/svnqt/pool.cpp @@ -0,0 +1,94 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +// svncpp +#include "pool.hpp" + + +namespace svn +{ + bool Pool::s_initialized = false; + + apr_pool_t * + Pool::pool_create (apr_pool_t * parent) + { + if (!s_initialized) { + apr_pool_initialize(); + s_initialized=true; + } + return svn_pool_create (parent); + } + + Pool::Pool (apr_pool_t * parent) + : m_parent (parent), m_pool (pool_create (parent)) + { + } + + Pool::~Pool () + { + if(m_pool) + { + svn_pool_destroy (m_pool); + } + } + + apr_pool_t * + Pool::pool () const + { + return m_pool; + } + + void + Pool::renew () + { + if (m_pool) + { + svn_pool_destroy (m_pool); + } + m_pool = pool_create (m_parent); + } + +//TODO +// apr_pool_t * +// Pool::operator=(const Pool & pool) +// { +// return +// if (this == &path) +// return *this; +// m_path = path.c_str(); +// return *this; +// } +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/pool.hpp b/src/svnqt/pool.hpp new file mode 100644 index 0000000..accdd75 --- /dev/null +++ b/src/svnqt/pool.hpp @@ -0,0 +1,92 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_POOL_H_ +#define _SVNCPP_POOL_H_ + +// subversion api +#include "svn_pools.h" + + +namespace svn +{ + /** + * Class for encapsulation of apr/subversion pools + */ + class Pool + { + public: + /** + * creates a subpool new pool to an existing pool + * + * @param parent NULL -> global pool + */ + Pool (apr_pool_t * parent = (apr_pool_t *)0); + + virtual ~ Pool (); + + /** + * @return apr handle to the pool + */ + apr_pool_t * + pool () const; + + /** + * operator to return apr handle to the pool + */ + operator apr_pool_t * () const + { + return m_pool; + } + + /** + * release pool and create a new one + */ + void renew (); + private: + apr_pool_t * m_parent; + apr_pool_t * m_pool; + + Pool& operator=(const Pool&); + + Pool (const Pool &); + + static bool s_initialized; + static apr_pool_t * pool_create (apr_pool_t * parent); + }; +} + +#endif + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/repository.cpp b/src/svnqt/repository.cpp new file mode 100644 index 0000000..2a3dd0e --- /dev/null +++ b/src/svnqt/repository.cpp @@ -0,0 +1,104 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#include "repository.hpp" +#include "repositorydata.hpp" + +namespace svn { + +namespace repository { + +Repository::Repository(svn::repository::RepositoryListener*aListener) +{ + m_Data=new RepositoryData(aListener); +} + + +Repository::~Repository() +{ + delete m_Data; +} + + +/*! + \fn svn::Repository::Open(const QString&) + */ +void Repository::Open(const QString&name) throw (ClientException) +{ + svn_error_t * error = m_Data->Open(name); + if (error!=0) { + throw ClientException (error); + } +} + +void Repository::CreateOpen(const QString&path, const QString&fstype, bool _bdbnosync, bool _bdbautologremove, bool _pre_1_4_compat, bool _pre_1_5_compat) throw (ClientException) +{ + svn_error_t * error = m_Data->CreateOpen(path,fstype,_bdbnosync,_bdbautologremove,_pre_1_4_compat,_pre_1_5_compat); + if (error!=0) { + throw ClientException (error); + } +} + + +/*! + \fn svn::Repository::dump(const QString&output,const svn::Revision&start,const svn::Revision&end, bool incremental, bool use_deltas)throw (ClientException) + */ +void Repository::dump(const QString&output,const svn::Revision&start,const svn::Revision&end, bool incremental, bool use_deltas)throw (ClientException) +{ + svn_error_t * error = m_Data->dump(output,start,end,incremental,use_deltas); + if (error!=0) { + throw ClientException (error); + } +} + +void Repository::loaddump(const QString&dump,LOAD_UUID uuida, const QString&parentFolder, bool usePre, bool usePost)throw (ClientException) +{ + svn_repos_load_uuid uuid_action; + switch (uuida) { + case UUID_IGNORE_ACTION: + uuid_action=svn_repos_load_uuid_ignore; + break; + case UUID_FORCE_ACTION: + uuid_action=svn_repos_load_uuid_force ; + break; + case UUID_DEFAULT_ACTION: + default: + uuid_action=svn_repos_load_uuid_default; + break; + } + svn_error_t * error = m_Data->loaddump(dump,uuid_action,parentFolder,usePre,usePost); + if (error!=0) { + throw ClientException (error); + } +} + +/*! + \fn svn::Repository::hotcopy(const QString&src,const QString&dest,bool cleanlogs) + */ +void Repository::hotcopy(const QString&src,const QString&dest,bool cleanlogs)throw (ClientException) +{ + svn_error_t * error = RepositoryData::hotcopy(src,dest,cleanlogs); + if (error!=0) { + throw ClientException (error); + } +} + +} // namespace repository + +} // namespace svn diff --git a/src/svnqt/repository.hpp b/src/svnqt/repository.hpp new file mode 100644 index 0000000..e4ea5eb --- /dev/null +++ b/src/svnqt/repository.hpp @@ -0,0 +1,119 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef SVNREPOSITORY_H +#define SVNREPOSITORY_H + +// Ignore MSVC 7, 2005 & 2008 compiler warning: C++ exception specification +#if defined (_MSC_VER) && _MSC_VER > 1200 && _MSC_VER <= 1550 +#pragma warning (disable: 4290) +#endif + +#include "svnqt/exception.hpp" +#include "svnqt/revision.hpp" +#include "svnqt/svnqt_defines.hpp" + +#include <qstring.h> + +namespace svn { + +namespace repository { + +class RepositoryData; +class RepositoryListener; + +//! wrapper class for subversions administrative repository functions +/*! + \author Rajko Albrecht <ral@alwins-world.de> +*/ +class SVNQT_EXPORT Repository{ +public: + enum LOAD_UUID { + UUID_DEFAULT_ACTION = 0, + UUID_IGNORE_ACTION = 1, + UUID_FORCE_ACTION = 2 + }; + //! constructor + /*! + * \param aListener callback object, the object will NOT take the ownership. + */ + Repository(svn::repository::RepositoryListener*aListener); + //! destructor + virtual ~Repository(); + + //! open a local repository path for maintainance + /*! + Assigns a repository with that object. If a path was opened before it will closed. + \param path Path to a local repository, must not be an url + \exception ClientException will be thrown in case of an error + */ + void Open(const QString&path) throw (ClientException); + //! Creates and open a new repository + /*! + * Creates a new repository in path with type fstype. If create succeeded open and assigns with the object. + * If a repository was opened before it will closed. + * \param path the path where to create the new repository. Must not be an url. + * \param fstype type of repository ("fsfs" or "bdb"). If wrong is set fsfs is the default. + * \param _bdbnosync disable fsync at transaction commit [Berkeley DB] + * \param _bdbautologremove enable automatic log file removal [Berkeley DB] + * \param _pre_1_4_compat Create repository compatibel to version earlier than 1.4 (only used with subversion 1.4) + */ + void CreateOpen(const QString&path, const QString&fstype, bool _bdbnosync = false, + bool _bdbautologremove = true, bool _pre_1_4_compat=false, bool _pre_1_5_compat=false) throw (ClientException); + //! dump content of repository to a file + /*! + The repository must opend before. Progress message go trough the assigned svn::repository::RepositoryListener object. + The revision parameter must be numbers, no constant values like svn::Revision::HEAD. + \param output where to output the content + \param start Begin on revision. If revision == -1 than start with first entry. + \param end End with revision. If revision == -1 than end with current head. + \param incremental dump incrementally + \param use_deltas use deltas in dump output + \exception ClientException will be thrown in case of an error + */ + void dump(const QString&output,const svn::Revision&start,const svn::Revision&end, bool incremental, bool use_deltas)throw (ClientException); + //! load a dump into repository + /*! + The repository must opened before. Progress message go trough the assigned svn::repository::RepositoryListener object. + \param dump Dumpfile to load + \param uuida what to do with UUIDs + \param parentFolder put content of dumpstream within folder in repository, if empty put into root-folder. + \param usePre use pre-commit-hook + \param usePost use post-commit-hook + \exception ClientException will be thrown in case of an error + */ + void loaddump(const QString&dump,LOAD_UUID uuida, const QString&parentFolder, bool usePre, bool usePost)throw (ClientException); + //! copy a repository to a new location + /*! + \param src the repository path to copy + \param dest where to copy + \param cleanlogs remove redundand log files from source + \exception ClientException will be thrown in case of an error + */ + static void hotcopy(const QString&src,const QString&dest,bool cleanlogs)throw (ClientException); + +private: + RepositoryData*m_Data; +}; + +} + +} + +#endif diff --git a/src/svnqt/repositorydata.cpp b/src/svnqt/repositorydata.cpp new file mode 100644 index 0000000..2ab9c5d --- /dev/null +++ b/src/svnqt/repositorydata.cpp @@ -0,0 +1,250 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#include "svnqt/repositorydata.hpp" +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/exception.hpp" +#include "svnqt/repositorylistener.hpp" +#include "svnqt/svnfilestream.hpp" + +#include <svn_fs.h> +#include <svn_path.h> +#include <svn_config.h> + +namespace svn { + +namespace repository { + +class RepoOutStream:public stream::SvnStream +{ +public: + RepoOutStream(RepositoryData*); + virtual ~RepoOutStream(){} + + virtual bool isOk()const{return true;} + virtual long write(const char*data,const unsigned long max); + +protected: + RepositoryData*m_Back; +}; + +RepoOutStream::RepoOutStream(RepositoryData*aBack) + : SvnStream(false,true) +{ + m_Back = aBack; +} + +long RepoOutStream::write(const char*data,const unsigned long max) +{ + if (m_Back) { + QString msg = QString::FROMUTF8(data,max); + m_Back->reposFsWarning(msg); + } + return max; +} + +RepositoryData::RepositoryData(RepositoryListener*aListener) +{ + m_Repository = 0; + m_Listener = aListener; +} + + +RepositoryData::~RepositoryData() +{ +} + +void RepositoryData::warning_func(void *baton, svn_error_t *err) +{ + RepositoryData*_r = (RepositoryData*)baton; + + if (_r) { + QString msg = svn::Exception::error2msg(err); + svn_error_clear(err); + _r->reposFsWarning(msg); + } +} + +void RepositoryData::reposFsWarning(const QString&msg) +{ + if (m_Listener) { + m_Listener->sendWarning(msg); + } +} + +svn_error_t*RepositoryData::cancel_func(void*baton) +{ + RepositoryListener*m_L = (RepositoryListener*)baton; + if (m_L && m_L->isCanceld()) { + return svn_error_create (SVN_ERR_CANCELLED, 0, QString::FROMUTF8("Cancelled by user.").TOUTF8()); + } + return SVN_NO_ERROR; +} + +/*! + \fn svn::RepositoryData::close() + */ +void RepositoryData::Close() +{ + m_Pool.renew(); + m_Repository = 0; +} + + +/*! + \fn svn::RepositoryData::Open(const QString&) + */ +svn_error_t * RepositoryData::Open(const QString&path) +{ + Close(); + svn_error_t * error = svn_repos_open(&m_Repository,path.TOUTF8(),m_Pool); + if (error!=0L) { + m_Repository=0; + return error; + } + svn_fs_set_warning_func(svn_repos_fs(m_Repository), RepositoryData::warning_func, this); + return SVN_NO_ERROR; +} + + +/*! + \fn svn::RepositoryData::CreateOpen(const QString&path, const QString&fstype, bool _bdbnosync = false, bool _bdbautologremove = true, bool nosvn1diff=false) + */ +svn_error_t * RepositoryData::CreateOpen(const QString&path, const QString&fstype, bool _bdbnosync, + bool _bdbautologremove, + bool _pre_1_4_compat, + bool _pre_1_5_compat) +{ + Close(); + const char* _type; +#if QT_VERSION < 0x040000 + if (fstype.lower()=="bdb") { +#else + if (fstype.toLower()=="bdb") { +#endif + _type="bdb"; + } else { + _type="fsfs"; + } + apr_hash_t *config; + apr_hash_t *fs_config = apr_hash_make(m_Pool); + + apr_hash_set(fs_config, SVN_FS_CONFIG_BDB_TXN_NOSYNC, + APR_HASH_KEY_STRING, + (_bdbnosync ? "1" : "0")); + apr_hash_set(fs_config, SVN_FS_CONFIG_BDB_LOG_AUTOREMOVE, + APR_HASH_KEY_STRING, + (_bdbautologremove ? "1" : "0")); + apr_hash_set(fs_config, SVN_FS_CONFIG_FS_TYPE, + APR_HASH_KEY_STRING, + _type); + +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 4) || SVN_VER_MAJOR>1) + if (_pre_1_4_compat) { + qDebug("Pre 14"); + apr_hash_set(fs_config, SVN_FS_CONFIG_PRE_1_4_COMPATIBLE, + APR_HASH_KEY_STRING,"1"); + } +#else + Q_UNUSED(_pre_1_4_compat); +#endif +#if ((SVN_VER_MAJOR == 1) && (SVN_VER_MINOR >= 5) || SVN_VER_MAJOR>1) + if (_pre_1_5_compat) { + qDebug("Pre 15"); + apr_hash_set(fs_config, SVN_FS_CONFIG_PRE_1_5_COMPATIBLE, + APR_HASH_KEY_STRING,"1"); + } +#else + Q_UNUSED(_pre_1_5_compat); +#endif + /// @todo config as extra paramter? Meanwhile default config only + /// (see svn::ContextData) + SVN_ERR(svn_config_get_config(&config, 0, m_Pool)); + const char*repository_path = apr_pstrdup (m_Pool,path.TOUTF8()); + + repository_path = svn_path_internal_style(repository_path, m_Pool); + + if (svn_path_is_url(repository_path)) { + return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + "'%s' is an URL when it should be a path",repository_path); + } + SVN_ERR(svn_repos_create(&m_Repository, repository_path, + NULL, NULL,config, fs_config,m_Pool)); + + svn_fs_set_warning_func(svn_repos_fs(m_Repository), RepositoryData::warning_func, this); + + return SVN_NO_ERROR; +} + + +/*! + \fn svn::RepositoryData::dump(const QString&output,const svn::Revision&start,const svn::Revision&end, bool incremental, bool use_deltas) + */ +svn_error_t* RepositoryData::dump(const QString&output,const svn::Revision&start,const svn::Revision&end, bool incremental, bool use_deltas) +{ + if (!m_Repository) { + return svn_error_create(SVN_ERR_CANCELLED,0,"No repository selected."); + } + Pool pool; + svn::stream::SvnFileOStream out(output); + RepoOutStream backstream(this); + svn_revnum_t _s,_e; + _s = start.revnum(); + _e = end.revnum(); + SVN_ERR(svn_repos_dump_fs2(m_Repository,out,backstream,_s,_e,incremental,use_deltas, + RepositoryData::cancel_func,m_Listener,pool)); + + return SVN_NO_ERROR; +} + +svn_error_t* RepositoryData::loaddump(const QString&dump,svn_repos_load_uuid uuida, const QString&parentFolder, bool usePre, bool usePost) +{ + if (!m_Repository) { + return svn_error_create(SVN_ERR_CANCELLED,0,"No repository selected."); + } + svn::stream::SvnFileIStream infile(dump); + RepoOutStream backstream(this); + Pool pool; + const char*src_path = apr_pstrdup (pool,dump.TOUTF8()); + const char*dest_path; + if (parentFolder.isEmpty()) { + dest_path=0; + } else { + dest_path=apr_pstrdup (pool,parentFolder.TOUTF8()); + } + + src_path = svn_path_internal_style(src_path, pool); + SVN_ERR(svn_repos_load_fs2(m_Repository,infile,backstream,uuida,dest_path,usePre?1:0,usePost?1:0,RepositoryData::cancel_func,m_Listener,pool)); + return SVN_NO_ERROR; +} + +svn_error_t* RepositoryData::hotcopy(const QString&src,const QString&dest,bool cleanlogs) +{ + Pool pool; + const char*src_path = apr_pstrdup (pool,src.TOUTF8()); + const char*dest_path = apr_pstrdup (pool,dest.TOUTF8()); + src_path = svn_path_internal_style(src_path, pool); + dest_path = svn_path_internal_style(dest_path, pool); + SVN_ERR(svn_repos_hotcopy(src_path,dest_path,cleanlogs?1:0,pool)); + return SVN_NO_ERROR; +} + +} + +} diff --git a/src/svnqt/repositorydata.hpp b/src/svnqt/repositorydata.hpp new file mode 100644 index 0000000..9884b70 --- /dev/null +++ b/src/svnqt/repositorydata.hpp @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef SVNREPOSITORYDATA_H +#define SVNREPOSITORYDATA_H + +#include "svnqt/pool.hpp" +#include "svnqt/revision.hpp" +#include "svnqt/apr.hpp" +#include "svnqt/svnqt_defines.hpp" + +#include <qstring.h> + +#include <svn_repos.h> +#include <svn_error.h> + +namespace svn { + +namespace repository { + +class Repository; +class RepositoryListener; +/** + @author Rajko Albrecht <ral@alwins-world.de> +*/ +class SVNQT_NOEXPORT RepositoryData{ + friend class Repository; + +public: + RepositoryData(RepositoryListener*); + + virtual ~RepositoryData(); + void Close(); + svn_error_t * Open(const QString&); + svn_error_t * CreateOpen(const QString&path, const QString&fstype, bool _bdbnosync = false, + bool _bdbautologremove = true, bool _pre_1_4_compat=false, bool _pre_1_5_compat=false); + + void reposFsWarning(const QString&msg); + svn_error_t* dump(const QString&output,const svn::Revision&start,const svn::Revision&end, bool incremental, bool use_deltas); + svn_error_t* loaddump(const QString&dump,svn_repos_load_uuid uuida, const QString&parentFolder, bool usePre, bool usePost); + static svn_error_t* hotcopy(const QString&src,const QString&dest,bool cleanlogs); + +protected: + Pool m_Pool; + svn_repos_t*m_Repository; + RepositoryListener*m_Listener; + +private: + static void warning_func(void *baton, svn_error_t *err); + static svn_error_t*cancel_func(void*baton); +}; + +} + +} + +#endif diff --git a/src/svnqt/repositorylistener.cpp b/src/svnqt/repositorylistener.cpp new file mode 100644 index 0000000..9c809a8 --- /dev/null +++ b/src/svnqt/repositorylistener.cpp @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#include "repositorylistener.hpp" + +namespace svn { + +namespace repository { + +RepositoryListener::RepositoryListener() +{ +} + + +RepositoryListener::~RepositoryListener() +{ +} + +} + +} diff --git a/src/svnqt/repositorylistener.hpp b/src/svnqt/repositorylistener.hpp new file mode 100644 index 0000000..15d650d --- /dev/null +++ b/src/svnqt/repositorylistener.hpp @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef REPOSITORYLISTENER_HPP +#define REPOSITORYLISTENER_HPP + +/** + @author Rajko Albrecht <ral@alwins-world.de> +*/ + +#include "svnqt/svnqt_defines.hpp" +#include <qstring.h> + +namespace svn { + +namespace repository { + +//! class for callbacks on repository operations +class SVNQT_EXPORT RepositoryListener{ + +public: + //! constructor + RepositoryListener(); + //! destructor + virtual ~RepositoryListener(); + + //! sends a warning or informative message + virtual void sendWarning(const QString&)=0; + //! sends an error message + virtual void sendError(const QString&)=0; + //! check if running operation should cancelled + virtual bool isCanceld() =0; + +}; + +} + +} + +#endif diff --git a/src/svnqt/revision.cpp b/src/svnqt/revision.cpp new file mode 100644 index 0000000..a89fae1 --- /dev/null +++ b/src/svnqt/revision.cpp @@ -0,0 +1,299 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + + +// svncpp +#include "revision.hpp" +#include "pool.hpp" + +// qt +#include "qdatetime.h" + +namespace svn +{ + const svn_opt_revision_kind Revision::START = svn_opt_revision_number; + const svn_opt_revision_kind Revision::BASE = svn_opt_revision_base; + const svn_opt_revision_kind Revision::HEAD = svn_opt_revision_head; + const svn_opt_revision_kind Revision::WORKING = svn_opt_revision_working; + const svn_opt_revision_kind Revision::UNDEFINED = svn_opt_revision_unspecified; + const svn_opt_revision_kind Revision::PREV = svn_opt_revision_previous; + + const svn_opt_revision_kind Revision::DATE = svn_opt_revision_date; + const svn_opt_revision_kind Revision::NUMBER = Revision::START; + + + Revision::Revision (const svn_opt_revision_t * revision) + { + init (revision); + } + + Revision::Revision (const svn_revnum_t revnum) + { + if (revnum<0) { + m_revision.kind = svn_opt_revision_unspecified; + m_revision.value.number = 0; + } else { + m_revision.kind = svn_opt_revision_number; + m_revision.value.number = revnum; + } + } + + Revision::Revision (const svn_opt_revision_kind kind) + { + m_revision.kind = kind; + m_revision.value.number = 0; + } + + Revision::Revision (const int revnum, const QString&revstring) + { + m_revision.kind = svn_opt_revision_unspecified; + + if (revnum > -1) { + m_revision.kind = svn_opt_revision_number; + m_revision.value.number = revnum; + } else { + assign(revstring); + } + } + + Revision::Revision (const QString&revstring) + { + assign(revstring); + } + + void + Revision::assign(const QString&revstring) + { + m_revision.kind = svn_opt_revision_unspecified; + if (revstring.isEmpty()) { + return; + } + if (revstring=="WORKING") { + m_revision.kind = WORKING; + } else if (revstring=="BASE") { + m_revision.kind = BASE; + } else if (revstring=="START"){ + m_revision.kind = Revision::START; + m_revision.value.number = 0; + } else if (revstring=="PREV"){ + m_revision.kind = Revision::PREV; + } else if (!revstring.isNull()) { + Pool pool; + svn_opt_revision_t endrev; + svn_opt_parse_revision(&m_revision,&endrev,revstring.TOUTF8(),pool); + } + } + + void + Revision::assign(const QDateTime&dateTime) + { + m_revision.kind = svn_opt_revision_date; + DateTime dt(dateTime); + m_revision.value.date = dt.GetAPRTimeT(); + } + + Revision& Revision::operator=(const QString&what) + { + assign(what); + return *this; + } + + Revision::Revision (const DateTime dateTime) + { + m_revision.kind = svn_opt_revision_date; + m_revision.value.date = dateTime.GetAPRTimeT(); + } + + Revision::Revision (const QDateTime&dateTime) + { + assign(dateTime); + } + + Revision::Revision (const Revision & revision) + { + init (revision.revision ()); + } + + void + Revision::init (const svn_opt_revision_t * revision) + { + if( !revision ) + { + m_revision.kind = svn_opt_revision_unspecified; + } + else + { + m_revision.kind = revision->kind; + + // m_revision.value is a union so we are not + // allowed to set number if we want to use date + // and vice versa + + switch( revision->kind ) + { + case svn_opt_revision_number: + m_revision.value.number = revision->value.number; + break; + + case svn_opt_revision_date: + m_revision.value.date = revision->value.date; + break; + + default: + m_revision.value.number = 0; + } + } + } + + Revision::operator QString ()const + { + return toString(); + } + + QString Revision::toString()const + { + QString value; + QDateTime result; + switch (m_revision.kind) { + case svn_opt_revision_number: + value.sprintf("%li",m_revision.value.number); + break; + case svn_opt_revision_date: + value = DateTime(m_revision.value.date).toString("{yyyy-MM-dd}"); + break; + case svn_opt_revision_base: + value = "BASE"; + break; + case svn_opt_revision_head: + value = "HEAD"; + break; + case svn_opt_revision_working: + value = "WORKING"; + break; + case svn_opt_revision_previous: + value="PREVIOUS"; + break; + case svn_opt_revision_unspecified: + default: + value="-1"; + break; + } + return value; + } + + const svn_opt_revision_t * + Revision::revision () const + { + return &m_revision; + } + + svn_revnum_t + Revision::revnum () const + { + if (m_revision.kind==svn_opt_revision_number) { + return m_revision.value.number; + } + return SVN_INVALID_REVNUM; + } + + apr_time_t + Revision::date () const + { + return m_revision.value.date; + } + + svn_opt_revision_kind + Revision::kind () const + { + return m_revision.kind; + } + + bool Revision::operator==(const Revision&r)const + { + if (r.kind()!=kind()) { + return false; + } + if (m_revision.kind == svn_opt_revision_number) { + return revnum()==r.revnum(); + } else if (m_revision.kind == svn_opt_revision_date) { + return date()==r.date(); + } + return true; + } + + bool Revision::operator==(int value)const + { + if (m_revision.kind!=svn_opt_revision_number || value!=revnum()) { + return false; + } + return true; + } + + bool Revision::operator!=(const svn_opt_revision_kind t)const + { + return kind()!=t; + } + bool Revision::operator==(const svn_opt_revision_kind t)const + { + return kind()==t; + } + + bool Revision::operator!()const + { + return kind()==UNDEFINED; + } + + bool Revision::operator!() + { + return kind()==UNDEFINED; + } + + Revision::operator bool()const + { + return kind()!=UNDEFINED; + } + + Revision::operator bool() + { + return kind()!=UNDEFINED; + } + + bool Revision::isRemote()const + { + return kind()!=UNDEFINED && kind()!=BASE && kind()!=WORKING; + } + +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/revision.hpp b/src/svnqt/revision.hpp new file mode 100644 index 0000000..371b1a1 --- /dev/null +++ b/src/svnqt/revision.hpp @@ -0,0 +1,222 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_REVISION_HPP_ +#define _SVNCPP_REVISION_HPP_ + +// svncpp +#include <svnqt/datetime.hpp> +#include <svnqt/svnqt_defines.hpp> + +// qt +#include <qglobal.h> +#if QT_VERSION < 0x040000 + #include <qstring.h> + #include <qtextstream.h> +#else + #include <QtCore> +#endif + +// subversion api +#include "svn_types.h" +#include "svn_opt.h" + +namespace svn +{ + /** + * Class that encapsulates svn_opt_revnum_t. + * + * @see svn_opt_revnum_t + */ + class SVNQT_EXPORT Revision + { + private: + svn_opt_revision_t m_revision; + + void + init (const svn_opt_revision_t * revision); + + void + assign(const QString&); + + void + assign(const QDateTime&); + + public: + static const svn_opt_revision_kind START; + static const svn_opt_revision_kind BASE; + static const svn_opt_revision_kind HEAD; + static const svn_opt_revision_kind WORKING; + static const svn_opt_revision_kind UNDEFINED; + static const svn_opt_revision_kind PREV; + + static const svn_opt_revision_kind DATE; + static const svn_opt_revision_kind NUMBER; + + /** + * Constructor + * + * @param revision revision information + */ + Revision (const svn_opt_revision_t * revision); + + /** + * Constructor + * + * @param revnum revision number + */ + Revision (const svn_revnum_t revnum); + + /** + * Constructor + * @param revnum a revision number + * @param revstring a revision string + * + * The revision string MUST uppercase, it may some of "HEAD", "BASE", "WORKING", "COMMITED", "PREV", + * or a date in form {YYYY-MM-DD}. + */ + Revision (const int revnum, const QString&revstring); + + /** + * Constructor + * @param revstring a revision string + * + * The revision string MUST uppercase, it may some of "HEAD", "BASE", "WORKING", "COMMITED", "PREV", + * or a date in form {YYYY-MM-DD}. + */ + Revision (const QString&revstring); + + /** + * Constructor + * + * @param kind + */ + Revision (const svn_opt_revision_kind kind = svn_opt_revision_unspecified); + + /** + * Constructor + * + * @param dateTime DateTime wrapper for apr_time_t + * @todo change it to referenced parameter (requires interface upgrade of lib) + */ + Revision (const DateTime dateTime); + /** + * Constructor + * + * @param dateTime QDateTime type + */ + Revision (const QDateTime&dateTime); + + /** + * Copy constructor + * + * @param revision Source + */ + Revision (const Revision & revision); + + /** + * @return revision information + */ + const svn_opt_revision_t * + revision () const; + + /** + * @see revision (). Same function + * but with operator overloading + */ + operator svn_opt_revision_t * () + { + return &m_revision; + } + + /** + * @see revision (). Same function + * but with operator overloading + */ + operator const svn_opt_revision_t*()const + { + return &m_revision; + } + + /** + * @return revision numver + */ + svn_revnum_t + revnum () const; + + /** + * @return revision kind + */ + svn_opt_revision_kind + kind () const; + + operator QString ()const; + QString toString()const; + + bool isRemote()const; + + /** + * @return date + */ + apr_time_t + date () const; + + bool operator==(const Revision&)const; + bool operator!=(const svn_opt_revision_kind)const; + bool operator==(const svn_opt_revision_kind)const; + bool operator==(int)const; + + bool operator!()const; + bool operator!(); + operator bool()const; + operator bool(); + + /** + * assignment operator + * @param what a simple revision string (not s:e but s) + * @return object itself + */ + Revision& operator=(const QString&what); + + }; +} + +inline QTextStream& operator<<(QTextStream&s,svn::Revision&r) +{ + s << r.toString(); + return s; +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/shared_pointer.hpp b/src/svnqt/shared_pointer.hpp new file mode 100644 index 0000000..cd1587e --- /dev/null +++ b/src/svnqt/shared_pointer.hpp @@ -0,0 +1,193 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef SVNQT_SHARED_POINTER_HPP +#define SVNQT_SHARED_POINTER_HPP + +#include "svnqt/smart_pointer.hpp" + +/*! + * \file shared_pointer.hpp + * \brief shared pointer adapter + * \sa smart_pointer.hpp + */ + +namespace svn +{ + +template<class T> class SharedPointer; + +/*! + * Data container for svn::SharedPointer + */ +template<class T> class SharedPointerData:public ref_count +{ + friend class SharedPointer<T>; +protected: + //! The protected pointer + T*data; +public: + //! Constructor + /*! + * Take ownership of pointer dt + * \param dt the data to wrap + **/ + SharedPointerData(T*dt){ + data = dt; + } + //! Destructor + /*! + * Release content data + */ + ~SharedPointerData() { + delete data; + } +}; + +//! Shared pointer adapater +/*! + * Implements a thread safe reference counter around any pointer. + * This class takes ownership of data, eg., last reference will delete + * the data it inspects. + */ +template<class T> class SharedPointer +{ + typedef SharedPointerData<T> Data; + Data*data; + + //! count down reference of data and release if it was the last share + void unref(){ + if (data) { + data->Decr(); + if (!data->Shared()) { + delete data; + } + data = 0; + } + } +public: + //! empty constructor + SharedPointer():data(0){} + //! copy constructor + /*! + * \param p Data to increase reference for + */ + SharedPointer(const SharedPointer<T>& p) + { + if ( (data = p.data) ) data->Incr(); + } + //! assignment constructor + /*! + * Take ownership of data pointer t + * \param t data pointer to store inside + */ + SharedPointer(T*t) + { + data = new Data(t);data->Incr(); + } + //! destructor + /*! + * decrease reference, if reference == 0 release data + */ + ~SharedPointer() + { + unref(); + } + + //! assignment operator + /*! + * \param p Data to increase reference for + */ + SharedPointer<T> &operator=(const SharedPointer<T>&p) + { + // we always have a reference to the data + if (data==p.data) return *this; + unref(); + if ((data=p.data)) data->Incr(); + return *this; + } + //! assignment operator + /*! + * \param p Data to increase reference for + */ + SharedPointer<T> &operator=(T*p) + { + if (data && data->data==p) { + return *this; + } + unref(); + data = new Data(p); + data->Incr(); + return *this; + } + + //! access operator + /*! + * Use this operator with care! + * \return pointer to wrapped data + */ + operator T*()const {return data->data;} + //! access operator + /*! + * \return reference to wrapped data + */ + T& operator*() {return *data->data;} + //! access operator + /*! + * \return const reference to wrapped data + */ + const T& operator*()const{return *data->data;} + //! access operator + /*! + * \return pointer to wrapped data + */ + T*operator->() {return data->data;} + //! access operator + /*! + * \return const pointer to wrapped data + */ + const T*operator->()const{return data->data;} + + //! Bool operator + /*! + * \return true if content set and not a null-pointer, otherwise false + */ + operator bool () const { return (data != 0 && data->data != 0); } + //! Bool operator + /*! + * \return true if content set and not a null-pointer, otherwise false + */ + operator bool () { return ( data != 0 && data->data != 0 );} + + //! Negation operator + /*! + * \return true if content not set or a null-pointer, otherwise false + */ + bool operator! () const { return (data == 0 || data->data == 0); } + //! Negation operator + /*! + * \return true if content not set or a null-pointer, otherwise false + */ + bool operator! () { return (data == 0 || data->data == 0); } +}; + +} + +#endif diff --git a/src/svnqt/smart_pointer.hpp b/src/svnqt/smart_pointer.hpp new file mode 100644 index 0000000..2790df5 --- /dev/null +++ b/src/svnqt/smart_pointer.hpp @@ -0,0 +1,146 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef _smart_pointer_hpp +#define _smart_pointer_hpp + +#if defined QT_THREAD_SUPPORT +#include "qmutex.h" +#endif + +#include "svnqt/svnqt_defines.hpp" + +/*! + * \file smart_pointer.h + * \brief smart pointer and reference counter + * \author Rajko Albrecht + * + */ + +namespace svn +{ + +//! simple reference counter class +class ref_count { +protected: + //! reference count member + long m_RefCount; +#ifdef QT_THREAD_SUPPORT + QMutex m_RefcountMutex; +#endif +public: + //! first reference must be added after "new" via Pointer() + ref_count() : m_RefCount(0) +#ifdef QT_THREAD_SUPPORT + ,m_RefcountMutex() +#endif + {} + virtual ~ref_count() {} + //! add a reference + void Incr() { +#ifdef QT_THREAD_SUPPORT + QMutexLocker a(&m_RefcountMutex); +#endif + ++m_RefCount; + } + //! delete a reference + bool Decr() { +#ifdef QT_THREAD_SUPPORT + QMutexLocker a(&m_RefcountMutex); +#endif + --m_RefCount; + return Shared(); + } + //! is it referenced + bool Shared() { return (m_RefCount > 0); } +}; + +//! reference counting wrapper class +template<class T> class smart_pointer { + //! pointer to object + /*! + * this object must contain Incr(), Decr() and Shared() + * methode as public members. The best way is, that it will be a child + * class of RefCount + */ + T *ptr; +public: + //! standart constructor + smart_pointer() { ptr = 0; } + //! standart destructor + /*! + * release the reference, if it were the last reference, destroys + * ptr + */ + ~smart_pointer() + { + if (ptr && !ptr->Decr()) { + delete ptr; + } + } + //! construction + smart_pointer(T* t) { if ( (ptr = t) ) ptr->Incr(); } + //! Pointer copy + smart_pointer(const smart_pointer<T>& p) + { if ( (ptr = p.ptr) ) ptr->Incr(); } + //! pointer copy by assignment + smart_pointer<T>& operator= (const smart_pointer<T>& p) + { + // already same: nothing to do + if (ptr == p.ptr) return *this; + // decouple reference + if ( ptr && !ptr->Decr()) delete ptr; + // establish new reference + if ( (ptr = p.ptr) ) ptr->Incr(); + return *this; + } + smart_pointer<T>& operator= (T*p) + { + if (ptr==p)return *this; + if (ptr && !ptr->Decr()) delete ptr; + if ( (ptr=p) ) ptr->Incr(); + return *this; + } + + //! cast to conventional pointer + operator T* () const { return ptr; } + + //! deref: fails for 0 pointer + T& operator* () {return *ptr; } + //! deref: fails for 0 pointer + const T& operator* ()const {return *ptr; } + + //! deref with method call + T* operator-> () {return ptr; } + //! deref with const method call + const T* operator-> ()const {return ptr; } + + //! supports "if (pointer)" + operator bool () const { return (ptr != 0); } + //! "if (pointer)" as non const + operator bool () { return ptr != 0;} + + //! support if (!pointer)" + bool operator! () const { return (ptr == 0); } + //! support if (!pointer)" as non const + bool operator! () { return (ptr == 0); } +}; + +} // namespace svn +#endif diff --git a/src/svnqt/status.cpp b/src/svnqt/status.cpp new file mode 100644 index 0000000..15a4af0 --- /dev/null +++ b/src/svnqt/status.cpp @@ -0,0 +1,319 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +// svncpp +#include "status.hpp" +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/path.hpp" +#include "svnqt/url.hpp" + +#include "svn_path.h" + +namespace svn +{ + class SVNQT_NOEXPORT Status_private + { + public: + Status_private(); + virtual ~Status_private(); + /** + * Initialize structures + * + * @param path + * @param status if NULL isVersioned will be false + */ + void + init (const QString&path, const svn_wc_status2_t * status); + void + init (const QString&path,const Status_private&src); + void + init(const QString&url,const DirEntryPtr&src); + void + init(const QString&url,const InfoEntry&src); + + void setPath(const QString&); + + QString m_Path; + bool m_isVersioned; + bool m_hasReal; + LockEntry m_Lock; + Entry m_entry; + + svn_wc_status_kind _text_status,_prop_status,_repos_text_status,_repos_prop_status; + bool _copied,_switched; + }; + + Status_private::Status_private() + :m_Path(),m_isVersioned(false),m_hasReal(false) + { + } + + Status_private::~ Status_private() + { + } + + void Status_private::setPath(const QString&aPath) + { + Pool pool; + if (!Url::isValid(aPath)) { + m_Path = aPath; + } else { + const char * int_path = svn_path_uri_decode(aPath.TOUTF8(), pool.pool () ); + m_Path = QString::FROMUTF8(int_path); + } + } + + void Status_private::init (const QString&path, const svn_wc_status2_t * status) + { + setPath(path); + if (!status) + { + m_isVersioned = false; + m_hasReal = false; + m_entry=Entry(); + m_Lock = LockEntry(); + } + else + { + m_isVersioned = status->text_status > svn_wc_status_unversioned||status->repos_text_status>svn_wc_status_unversioned; + m_hasReal = m_isVersioned && + status->text_status!=svn_wc_status_ignored; + // now duplicate the contents + if (status->entry) + { + m_entry = Entry(status->entry); + } else { + m_entry=Entry(); + } + _text_status = status->text_status; + _prop_status = status->prop_status; + _copied = status->copied!=0; + _switched = status->switched!=0; + _repos_text_status = status->repos_text_status; + _repos_prop_status = status->repos_prop_status; + if (status->repos_lock) { + m_Lock.init(status->repos_lock->creation_date, + status->repos_lock->expiration_date, + status->repos_lock->owner, + status->repos_lock->comment, + status->repos_lock->token); + } else { + m_Lock=LockEntry(); + } + } + } + + void + Status_private::init (const QString&path,const Status_private&src) + { + setPath(path); + m_Lock=src.m_Lock; + m_entry=src.m_entry; + m_isVersioned=src.m_isVersioned; + m_hasReal=src.m_hasReal; + _text_status=src._text_status; + _prop_status=src._prop_status; + _repos_text_status=src._repos_text_status; + _repos_prop_status=src._repos_prop_status; + _copied=src._copied; + _switched=src._switched; + } + + void Status_private::init(const QString&url,const DirEntryPtr&src) + { + m_entry=Entry(url,src); + setPath(url); + _text_status = svn_wc_status_normal; + _prop_status = svn_wc_status_normal; + if (src) { + m_Lock=src->lockEntry(); + m_isVersioned=true; + m_hasReal=true; + } + _switched = false; + _repos_text_status = svn_wc_status_normal; + _repos_prop_status = svn_wc_status_normal; + } + + void Status_private::init(const QString&url,const InfoEntry&src) + { + m_entry=Entry(url,src); + setPath(url); + m_Lock=src.lockEntry(); + _text_status = svn_wc_status_normal; + _prop_status = svn_wc_status_normal; + _repos_text_status = svn_wc_status_normal; + _repos_prop_status = svn_wc_status_normal; + m_isVersioned=true; + m_hasReal=true; + } + + Status::Status (const Status & src) + : m_Data(new Status_private()) + { + if( &src != this ) + { + if (src.m_Data) { + m_Data->init (src.m_Data->m_Path, *(src.m_Data)); + } else { + m_Data->init(src.m_Data->m_Path,0); + } + } + } + + Status::Status (const QString&path, svn_wc_status2_t * status) + : m_Data(new Status_private()) + { + m_Data->init(path, status); + } + + Status::Status (const char*path, svn_wc_status2_t * status) + : m_Data(new Status_private()) + { + m_Data->init(QString::FROMUTF8(path),status); + } + + Status::Status(const QString&url,const DirEntryPtr&src) + : m_Data(new Status_private()) + { + m_Data->init(url,src); + } + + Status::Status(const QString&url,const InfoEntry&src) + : m_Data(new Status_private()) + { + m_Data->init(url,src); + } + + Status::~Status () + { + delete m_Data; + } + + Status & + Status::operator=(const Status & status) + { + if (this == &status) + return *this; + if (status.m_Data) { + m_Data->init (status.m_Data->m_Path, *(status.m_Data)); + } else { + m_Data->init(status.m_Data->m_Path,0); + } + return *this; + } + + const LockEntry& + Status::lockEntry () const + { + return m_Data->m_Lock; + } + svn_wc_status_kind + Status::reposPropStatus () const + { + return m_Data->_repos_prop_status; + } + svn_wc_status_kind + Status::reposTextStatus () const + { + return m_Data->_repos_text_status; + } + bool + Status::isSwitched () const + { + return m_Data->_switched != 0; + } + bool + Status::isCopied () const + { + return m_Data->_copied; + } + + bool + Status::isLocked () const + { + return m_Data->m_Lock.Locked(); + } + + bool + Status::isModified()const + { + return textStatus()==svn_wc_status_modified||propStatus()==svn_wc_status_modified + ||textStatus ()==svn_wc_status_replaced; + } + + bool + Status::isRealVersioned()const + { + return m_Data->m_hasReal; + } + + bool + Status::isVersioned () const + { + return m_Data->m_isVersioned; + } + + svn_wc_status_kind + Status::propStatus () const + { + return m_Data->_prop_status; + } + + svn_wc_status_kind + Status::textStatus () const + { + return m_Data->_text_status; + } + + const Entry& + Status::entry () const + { + return m_Data->m_entry; + } + + const QString& + Status::path () const + { + return m_Data->m_Path; + } + + bool + Status::validReposStatus()const + { + return reposTextStatus()!=svn_wc_status_none||reposPropStatus()!=svn_wc_status_none; + } + + bool + Status::validLocalStatus()const + { + return textStatus()!=svn_wc_status_none||propStatus()!=svn_wc_status_none; + } +} diff --git a/src/svnqt/status.hpp b/src/svnqt/status.hpp new file mode 100644 index 0000000..ec0f436 --- /dev/null +++ b/src/svnqt/status.hpp @@ -0,0 +1,187 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ +#ifndef _SVNCPP_STATUS_HPP_ +#define _SVNCPP_STATUS_HPP_ + +// subversion api +#include "svn_wc.h" + +// svncpp +#include "svnqt/svnqttypes.hpp" +#include "svnqt/entry.hpp" +#include "svnqt/pool.hpp" +#include "svnqt/lock_entry.hpp" +#include "svnqt/dirent.hpp" +#include "svnqt/info_entry.hpp" +#include "svnqt/svnqt_defines.hpp" + +namespace svn +{ + /** + * Subversion status API. This class wraps around + * @a svn_wc_status_t. + * + * @see svn_wc.hpp + * @see svn_wc_status_t + */ + class Status_private; + + class SVNQT_EXPORT Status + { + public: + /** + * copy constructor + */ + Status (const Status & src); + + /** + * default constructor + * + * @param path path for this status entry + * @param status status entry + */ + Status (const QString&path=QString::null, svn_wc_status2_t * status = NULL); + /** + * default constructor + * + * @param path path for this status entry + * @param status status entry + */ + Status (const char*path, svn_wc_status2_t * status = NULL); + /** + * converting constructor + */ + Status(const QString&path,const DirEntryPtr&src); + /** + * converting constructor + */ + Status(const QString&path,const InfoEntry&src); + + /** + * destructor + */ + virtual ~Status (); + + /** + * @return path of status entry + */ + const QString& + path () const; + + /** + * @return entry for this path + * @retval entry.isValid () = false item is not versioned + */ + const Entry& + entry () const; + /** + * @return file status property enum of the "textual" component. + */ + svn_wc_status_kind + textStatus () const; + + /** + * @return file status property enum of the "property" component. + */ + svn_wc_status_kind + propStatus () const; + + /** + * @retval TRUE if under version control + */ + bool + isVersioned () const; + + /** + * @retval TRUE if under version control and not ignored + */ + bool + isRealVersioned()const; + + /** + * @retval TRUE if under version control and local modified + */ + bool + isModified()const; + + /** + * @retval TRUE if locked + */ + bool + isLocked () const; + + /** + * @retval TRUE if copied + */ + bool + isCopied () const; + + /** + * @retval TRUE if switched + */ + bool + isSwitched () const; + /** + * @return the entry's text status in the repository + */ + svn_wc_status_kind + reposTextStatus () const; + /** + * @return the entry's prop status in the repository + */ + svn_wc_status_kind + reposPropStatus () const; + + const LockEntry& + lockEntry () const; + + bool + validReposStatus()const; + + bool + validLocalStatus()const; + + + /** + * assignment operator + */ + Status & + operator = (const Status &); + private: + Status_private*m_Data; + }; +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/stringarray.cpp b/src/svnqt/stringarray.cpp new file mode 100644 index 0000000..bdac55b --- /dev/null +++ b/src/svnqt/stringarray.cpp @@ -0,0 +1,121 @@ +/*************************************************************************** + * Copyright (C) 2006-2008 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "svnqt/stringarray.hpp" +#include "svnqt/pool.hpp" + +#include <svn_types.h> +// apr api +#include <apr_pools.h> +#include <apr_strings.h> + +/*! + \fn svn::StringArray::StringArray() + */ + svn::StringArray::StringArray() + :m_content() +{ + setNull(true); +} + + +/*! + \fn svn::StringArray::StringArray(const QStringList&) + */ +svn::StringArray::StringArray(const QStringList&aList) + :m_content(aList) +{ + setNull(false); +} + +/*! + \fn svn::StringArray::StringArray(const apr_array_header_t * apr_targets) + */ +svn::StringArray::StringArray(const apr_array_header_t * apr_targets) + :m_content() +{ + int i; + for (i = 0; i < apr_targets->nelts; i++) + { + const char ** target = + &APR_ARRAY_IDX (apr_targets, i, const char *); + + m_content.push_back (QString::FROMUTF8(*target)); + } +} + + +/*! + \fn svn::StringArray::size()const + */ +size_t svn::StringArray::size()const +{ + if (isNull()) { + return 0; + } + return m_content.size (); +} + + +/*! + \fn svn::StringArray::operator[](size_t which) + */ +const QString& svn::StringArray::operator[](size_t which) +{ + return m_content[which]; +} + + +/*! + \fn svn::StringArray::array (const Pool & pool) const + */ +apr_array_header_t * svn::StringArray::array (const Pool & pool) const +{ + if (isNull()) { + return 0; + } + QStringList::const_iterator it; + + apr_pool_t *apr_pool = pool.pool (); + apr_array_header_t *apr_targets = + apr_array_make (apr_pool,m_content.size(),sizeof (const char *)); + + for (it = m_content.begin (); it != m_content.end (); it++) + { + QByteArray s = (*it).TOUTF8(); + char * t2 = apr_pstrndup (apr_pool,s,s.size()); + + (*((const char **) apr_array_push (apr_targets))) = t2; + } + return apr_targets; +} + +bool svn::StringArray::isNull()const +{ + return m_isNull; +} + +void svn::StringArray::setNull(bool _n) +{ + if (_n) { + m_content.clear(); + } + m_isNull = _n; +} diff --git a/src/svnqt/stringarray.hpp b/src/svnqt/stringarray.hpp new file mode 100644 index 0000000..285f500 --- /dev/null +++ b/src/svnqt/stringarray.hpp @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (C) 2006-2008 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef _STRING_ARRAY_HPP +#define _STRING_ARRAY_HPP + +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/svnqttypes.hpp" + +#include <qglobal.h> +#if QT_VERSION < 0x040000 +#include <qstringlist.h> +#else +#include <QtCore> +#include <QStringList> +#endif + +// apr api +#include "apr_tables.h" + +namespace svn +{ + // forward declarations + class Pool; + + /** Handle array of const char * in a c++ like way */ + class SVNQT_EXPORT StringArray + { + protected: + QStringList m_content; + bool m_isNull; + + public: + StringArray(); + StringArray(const QStringList&); + StringArray(const apr_array_header_t * apr_targets); + size_t size()const; + const QString& operator[](size_t which); + /** + * Returns an apr array containing char*. + * + * @param pool Pool used for conversion + */ + apr_array_header_t * array (const Pool & pool) const; + /** content of array + * @return const reference to data, may used for searches. + */ + const QStringList& data() const {return m_content;} + + /** if array should return 0 instead of empty array */ + bool isNull()const; + void setNull(bool _n); + }; +} + +#endif diff --git a/src/svnqt/svnfilestream.cpp b/src/svnqt/svnfilestream.cpp new file mode 100644 index 0000000..2803ef4 --- /dev/null +++ b/src/svnqt/svnfilestream.cpp @@ -0,0 +1,134 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#include "svnfilestream.hpp" + +#include <qfile.h> + +namespace svn { + +namespace stream { + +#if QT_VERSION < 0x040000 +typedef int openmode; +#define READONLY IO_ReadOnly +#define WRITEONLY IO_WriteOnly +#else +typedef QIODevice::OpenMode openmode; +#define READONLY QIODevice::ReadOnly +#define WRITEONLY QIODevice::WriteOnly +#endif + +class SVNQT_NOEXPORT SvnFileStream_private +{ +public: + SvnFileStream_private(const QString&fn,openmode mode); + virtual ~SvnFileStream_private(); + + QString m_FileName; + QFile m_File; +}; + +SvnFileStream_private::SvnFileStream_private(const QString&fn,openmode mode) + : m_FileName(fn),m_File(fn) +{ + m_File.open(mode); +} + +SvnFileStream_private::~SvnFileStream_private() +{ +} + +SvnFileOStream::SvnFileOStream(const QString&fn,svn_client_ctx_t*ctx) + :SvnStream(false,true,ctx) +{ + m_FileData = new SvnFileStream_private(fn,WRITEONLY); + if (!m_FileData->m_File.isOpen()) { + setError(m_FileData->m_File.errorString()); + } +} + + +SvnFileOStream::~SvnFileOStream() +{ + delete m_FileData; +} + + +bool SvnFileOStream::isOk() const +{ + return m_FileData->m_File.isOpen(); +} + +long SvnFileOStream::write(const char* data, const unsigned long max) +{ + if (!m_FileData->m_File.isOpen()) { + return -1; + } +#if QT_VERSION < 0x040000 + long res = m_FileData->m_File.writeBlock(data,max); +#else + long res = m_FileData->m_File.write(data,max); +#endif + if (res<0) { + setError(m_FileData->m_File.errorString()); + } + return res; +} + +SvnFileIStream::SvnFileIStream(const QString&fn,svn_client_ctx_t*ctx) + :SvnStream(true,false,ctx) +{ + m_FileData = new SvnFileStream_private(fn,READONLY); + if (!m_FileData->m_File.isOpen()) { + setError(m_FileData->m_File.errorString()); + } +} + + +SvnFileIStream::~SvnFileIStream() +{ + delete m_FileData; +} + + +bool SvnFileIStream::isOk() const +{ + return m_FileData->m_File.isOpen(); +} + +long SvnFileIStream::read(char* data, const unsigned long max) +{ + if (!m_FileData->m_File.isOpen()) { + return -1; + } +#if QT_VERSION < 0x040000 + long res = m_FileData->m_File.readBlock(data,max); +#else + long res = m_FileData->m_File.read(data,max); +#endif + if (res<0) { + setError(m_FileData->m_File.errorString()); + } + return res; +} + +} + +} diff --git a/src/svnqt/svnfilestream.hpp b/src/svnqt/svnfilestream.hpp new file mode 100644 index 0000000..d64e1cc --- /dev/null +++ b/src/svnqt/svnfilestream.hpp @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef SVN_STREAMSVNFILESTREAM_HPP +#define SVN_STREAMSVNFILESTREAM_HPP + +#include "svnstream.hpp" + +namespace svn { + +namespace stream { + +class SvnFileStream_private; + +/** + @author Rajko Albrecht <ral@alwins-world.de> + @short Writeonly filestream +*/ +class SVNQT_EXPORT SvnFileOStream : public SvnStream +{ +public: + SvnFileOStream(const QString&fn,svn_client_ctx_t*ctx=0); + + virtual ~SvnFileOStream(); + + virtual bool isOk() const; + virtual long write(const char* data, const unsigned long max); +private: + SvnFileStream_private*m_FileData; +}; + +/** + @author Rajko Albrecht <ral@alwins-world.de> + @short Readonly filestream +*/ +class SVNQT_EXPORT SvnFileIStream : public SvnStream +{ +public: + SvnFileIStream(const QString&fn,svn_client_ctx_t*ctx=0); + + virtual ~SvnFileIStream(); + virtual bool isOk() const; + virtual long read(char* data, const unsigned long max); + +private: + SvnFileStream_private*m_FileData; +}; + +} + +} + +#endif diff --git a/src/svnqt/svnqt_defines.hpp.in b/src/svnqt/svnqt_defines.hpp.in new file mode 100644 index 0000000..6281d42 --- /dev/null +++ b/src/svnqt/svnqt_defines.hpp.in @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef _SVNQT_DEFINES_H +#define _SVNQT_DEFINES_H + +/* defines if we setup against a compiler with working "-fvisibility=hidden" */ +#define SVNQT_EXPORT @_SVNQT_EXPORT@ +#define SVNQT_NOEXPORT @_SVNQT_NOEXPORT@ + +/* cmake trick: so we make sure that the define in installs + is always set as in library used at build time + */ +#define TOUTF8 @TOUTF8@ +#define FROMUTF8 @FROMUTF8@ +#define QLIST @QLIST@ +#define TOASCII @TOASCII@ +#define HOMEDIR @HOMEDIR@ +#define QLONG @QLONG@ + +#define SVNQT_SIZE_UNKNOWN QLONG(-1) + +/* the difference between qt3 and qt4 is too much... :( */ +class QSqlDatabase; +typedef @QDATABASE@ QDataBase; +#endif diff --git a/src/svnqt/svnqttypes.hpp b/src/svnqt/svnqttypes.hpp new file mode 100644 index 0000000..b3c6381 --- /dev/null +++ b/src/svnqt/svnqttypes.hpp @@ -0,0 +1,104 @@ +/*************************************************************************** + * Copyright (C) 2007 by Rajko Albrecht ral@alwins-world.de * + * http://kdesvn.alwins-world.de/ * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef _SVNQT_TYPES_HPP +#define _SVNQT_TYPES_HPP + +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/shared_pointer.hpp" + +// qt +#include <qglobal.h> + +#if QT_VERSION < 0x040000 + #include <qstring.h> + #include <qpair.h> + #include <qvaluelist.h> + #include <qmap.h> +#else + #include <QtCore> +#endif + +namespace svn +{ + // forward declarations + class AnnotateLine; + class Context; + class DirEntry; + class InfoEntry; + class LogEntry; + class Revision; + class Status; + class Targets; + class Path; + class StringArray; + + typedef QLIST<AnnotateLine> AnnotatedFile; + + typedef SharedPointer<DirEntry> DirEntryPtr; + typedef QLIST<DirEntryPtr> DirEntries; + typedef QLIST<InfoEntry> InfoEntries; + /// simple list of log entries + typedef QLIST<LogEntry> LogEntries; + /// shared_pointer for LogEntriesMap + typedef SharedPointer<LogEntries> LogEntriesPtr; + + /// map of logentries - key is revision + typedef QMap<long,LogEntry> LogEntriesMap; + /// shared_pointer for LogEntriesMap + typedef SharedPointer<LogEntriesMap> LogEntriesMapPtr; + + typedef SharedPointer<Status> StatusPtr; + typedef QLIST<StatusPtr> StatusEntries; + typedef QLIST<Revision> Revisions; + + /** Range of Revision */ + typedef QPair<Revision,Revision> RevisionRange; + /** list of revision ranges */ + typedef QLIST<RevisionRange> RevisionRanges; + + /// map of property names to values + typedef QMap<QString,QString> PropertiesMap; + /// pair of path, PropertiesMap + typedef QPair<QString, PropertiesMap> PathPropertiesMapEntry; + /// vector of path, Properties pairs + typedef QLIST<PathPropertiesMapEntry> PathPropertiesMapList; + /// shared pointer for properties + typedef SharedPointer<PathPropertiesMapList> PathPropertiesMapListPtr; + + typedef QLIST<Path> Pathes; + + //! Mapper enum for svn_depth_t + /*! + * Until subversion prior 1.5 is supported by this lib we must hide the svn_depth_t enum from interface. + * \since subversion 1.5 / svnqt 1.0 + * \sa svn_depth_t + */ + enum Depth { + DepthUnknown, + DepthExclude, + DepthEmpty, + DepthFiles, + DepthImmediates, + DepthInfinity + }; +} + +#endif diff --git a/src/svnqt/svnstream.cpp b/src/svnqt/svnstream.cpp new file mode 100644 index 0000000..e3b6014 --- /dev/null +++ b/src/svnqt/svnstream.cpp @@ -0,0 +1,263 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#include "svnqt/svnstream.hpp" +#include "svnqt/pool.hpp" +#include "svnqt/apr.hpp" + +// Subversion api +#include "svn_client.h" + +#include <qbuffer.h> +#include <qdatetime.h> +#include <qfile.h> + +#define MAX_TIME 300 + +namespace svn { + +namespace stream { +class SVNQT_NOEXPORT SvnStream_private +{ +public: + SvnStream_private(){m_Stream=0;m_LastError="";_context=0;cancel_timeout.start();} + ~SvnStream_private(){qDebug("Time elapsed: %i ",cancel_timeout.elapsed());} + + static svn_error_t * stream_write(void*baton,const char*data,apr_size_t*len); + static svn_error_t * stream_read(void*baton,char*data,apr_size_t*len); + + Pool m_Pool; + svn_stream_t * m_Stream; + QString m_LastError; + + svn_client_ctx_t* _context; + QTime cancel_timeout; +}; + +svn_error_t * SvnStream_private::stream_read(void*baton,char*data,apr_size_t*len) +{ + SvnStream*b = (SvnStream*)baton; + svn_client_ctx_t*ctx = b->context(); + + if (ctx&&ctx->cancel_func) { + SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); + } + + long res = b->isOk()?b->read(data,*len):-1; + + if (res<0) { + *len = 0; + return svn_error_create(SVN_ERR_MALFORMED_FILE,0L,b->lastError().TOUTF8()); + } + *len = res; + return SVN_NO_ERROR; +} + +svn_error_t * SvnStream_private::stream_write(void*baton,const char*data,apr_size_t*len) +{ + SvnStream*b = (SvnStream*)baton; + svn_client_ctx_t*ctx = b->context(); + + if (ctx&&ctx->cancel_func&&b->cancelElapsed()>50) { + qDebug("Check cancel"); + SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); + b->cancelTimeReset(); + } + + long res = b->isOk()?b->write(data,*len):-1; + if (res<0) { + *len = 0; + return svn_error_create(SVN_ERR_MALFORMED_FILE,0L,b->lastError().TOUTF8()); + } + *len = res; + return SVN_NO_ERROR; +} + +SvnStream::SvnStream(bool read, bool write,svn_client_ctx_t * ctx) +{ + m_Data = new SvnStream_private; + m_Data->m_Stream = svn_stream_create(this,m_Data->m_Pool); + m_Data->_context = ctx; + if (read) { + svn_stream_set_read(m_Data->m_Stream,SvnStream_private::stream_read); + } + if (write) { + svn_stream_set_write(m_Data->m_Stream,SvnStream_private::stream_write); + } +} + +SvnStream::SvnStream() +{ +} + +SvnStream::~SvnStream() +{ + delete m_Data; +} + +int SvnStream::cancelElapsed()const +{ + return m_Data->cancel_timeout.elapsed(); +} + +void SvnStream::cancelTimeReset() +{ + m_Data->cancel_timeout.restart(); +} + +SvnStream::operator svn_stream_t* ()const +{ + return m_Data->m_Stream; +} + +svn_client_ctx_t * SvnStream::context() +{ + return m_Data->_context; +} + +long SvnStream::write(const char*,const unsigned long) +{ + m_Data->m_LastError = "Write not supported with that stream"; + return -1; +} + +long SvnStream::read(char*,const unsigned long ) +{ + m_Data->m_LastError = "Read not supported with that stream"; + return -1; +} + +const QString&SvnStream::lastError()const +{ + return m_Data->m_LastError; +} + +void SvnStream::setError(const QString&aError)const +{ + m_Data->m_LastError = aError; +} + +#if QT_VERSION < 0x040000 +void SvnStream::setError(int ioError)const +{ + switch (ioError) { + case IO_Ok: + setError("Operation was successfull."); + break; + case IO_ReadError: + setError("Could not read from device"); + break; + case IO_WriteError: + setError("Could not write to device"); + break; + case IO_FatalError: + setError("A fatal unrecoverable error occurred."); + break; + case IO_OpenError: + setError("Could not open device or stream."); + break; + case IO_AbortError: + setError("The operation was unexpectedly aborted."); + break; + case IO_TimeOutError: + setError("The operation timed out."); + break; + case IO_UnspecifiedError: + setError("An unspecified error happened on close."); + break; + default: + setError("Unknown error happend."); + break; + } +} +#endif + +class SvnByteStream_private { +public: + SvnByteStream_private(); + virtual ~SvnByteStream_private(){} + + QByteArray m_Content; + QBuffer mBuf; +}; + +#if QT_VERSION < 0x040000 +SvnByteStream_private::SvnByteStream_private() + :mBuf(m_Content) +{ + mBuf.open(IO_WriteOnly); +} +#else +SvnByteStream_private::SvnByteStream_private() + :mBuf(&m_Content, 0) +{ + mBuf.open(QFile::WriteOnly); +} +#endif + +/* ByteStream implementation start */ +SvnByteStream::SvnByteStream(svn_client_ctx_t * ctx) + : SvnStream(false,true,ctx) +{ + m_ByteData = new SvnByteStream_private; + if (!m_ByteData->mBuf.isOpen()) { +#if QT_VERSION < 0x040000 + setError(m_ByteData->mBuf.status()); +#else + setError(m_ByteData->mBuf.errorString()); +#endif + } +} + +SvnByteStream::~SvnByteStream() +{ + delete m_ByteData; +} + +long SvnByteStream::write(const char*aData,const unsigned long max) +{ +#if QT_VERSION < 0x040000 + long i = m_ByteData->mBuf.writeBlock(aData,max); + if (i<0) { + setError(m_ByteData->mBuf.status()); + } +#else + long i = m_ByteData->mBuf.write(aData,max); + if (i<0) { + setError(m_ByteData->mBuf.errorString()); + } +#endif + return i; +} + +QByteArray SvnByteStream::content()const +{ + return m_ByteData->mBuf.buffer(); +} + +bool SvnByteStream::isOk()const +{ + return m_ByteData->mBuf.isOpen(); +} + +/* ByteStream implementation end */ + +} // namespace stream + +} // namespace svn diff --git a/src/svnqt/svnstream.hpp b/src/svnqt/svnstream.hpp new file mode 100644 index 0000000..89276c8 --- /dev/null +++ b/src/svnqt/svnstream.hpp @@ -0,0 +1,164 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef SVNSVNSTREAM_HPP +#define SVNSVNSTREAM_HPP + +#include "svnqt/svnqt_defines.hpp" + +#include <qstring.h> + +#include <svn_io.h> +struct svn_client_ctx_t; + +namespace svn { + +namespace stream { +class SvnStream_private; + +/** + @author Rajko Albrecht <ral@alwins-world.de> + @short wrapper class around the svn_stream_t structure +*/ +class SVNQT_EXPORT SvnStream{ + friend class SvnStream_private; +public: + //! Constructor + /*! + * Setup a svn_stream_t and holds a required pool. The stream will freed + * when deleting this object. + * \param readit set readable + * \param writeit set writable + * \param ctx a client context for calls to cancel_func inside. you should this only set with functions not using it itself + * like svn_client_cat2: + */ + SvnStream(bool readit, bool writeit, svn_client_ctx_t * ctx = 0); + //! frees all structures and releases memory pool. + virtual ~SvnStream(); + + //! operator returning transparent a svn_stream_t structure + /*! + \return a svn_stream_t structure for use with subversion api. + */ + operator svn_stream_t* ()const; + + //! write operation + /*! + Write data FROM subversion to the class behind. Eg., data comes from + subversion-api and this method has to do something with it (printing on a window, writing to a file) + This implementation always returns -1 (eg, error), must reimplemented for real usage. + \param data the data to written + \param max maximum data to write + \return should return the amount of data real written, in case of error must return -1 + \sa setError(int ioError), setError(const QString&error), read(char*data,const unsigned long max) + */ + virtual long write(const char*data,const unsigned long max); + //! read operation + /*! implements the wrapper for svn_stream_read, eg. data are read FROM class (eg, file, string or whatever) + into subversion-api. This implementation always returns -1 (eg, error), must reimplemented for real usage. + \param data target array where to store the read + \param max maximum byte count to read + \return amount of data read or -1 in case of error + \sa setError(int ioError), setError(const QString&error), write(const char*data,const unsigned long max) + */ + virtual long read(char*data,const unsigned long max); + + //! returns the error set + /*! + \return a human readable message about the reason the last operation failed. + */ + virtual const QString& lastError()const; + //! is that stream usable + /*! + Gives information about if the stream object is usable. May if the file is real open or such. + \return true if stream is usable, false if not. + */ + virtual bool isOk()const = 0; + + svn_client_ctx_t * context(); + +protected: + //! set a human readable errormessage + /*! + This message may printed to the user and will checked if one of the stream-operations failed. So should set from + write and/or read if them will return -1 (for error) + \param error the errormessage assigned. + */ + virtual void setError(const QString&error)const; + //! set the internal error + /*! \param ioError error code from QIODevide::status + */ +#if QT_VERSION < 0x040000 + virtual void setError(int ioError)const; +#endif + +protected: + int cancelElapsed()const; + void cancelTimeReset(); + +private: + SvnStream_private*m_Data; + /* disable default contructor */ + SvnStream(); +}; + +class SvnByteStream_private; + +//! a class let subversion print into a QByteArray +class SVNQT_EXPORT SvnByteStream:public SvnStream +{ +public: + //! constructor + /*! + creates internal buffer + * \param ctx a client context for calls to cancel_func inside. you should this only set with functions not using it itself + * like svn_client_cat2: + */ + SvnByteStream(svn_client_ctx_t * ctx = 0); + //! release internal buffer + virtual ~SvnByteStream(); + //! fill internal buffer with data + /*! + stores the data written into the internal buffer. + \param data data to store + \param max length of data to store + \return data real stored or -1 if error. + */ + virtual long write(const char*data,const unsigned long max); + + //! return the data stored + /*! + \return the internal stored data + */ + QByteArray content()const; + //! checks if the buffer is usable. + /*! + * \return true if data may written, false if not, in that case a errormessage will set. + */ + virtual bool isOk()const; + +private: + SvnByteStream_private*m_ByteData; +}; + +} // namespace stream + +} // namespace svn + +#endif diff --git a/src/svnqt/targets.cpp b/src/svnqt/targets.cpp new file mode 100644 index 0000000..6e2fced --- /dev/null +++ b/src/svnqt/targets.cpp @@ -0,0 +1,170 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +// subversion api +#include "svn_types.h" + +// apr api +#include "apr_pools.h" +#include "apr_strings.h" + +// svncpp +#include "svnqt/targets.hpp" +#include "svnqt/path.hpp" +#include "svnqt/pool.hpp" +#include "svnqt/svnqt_defines.hpp" + +#include <qstringlist.h> + +namespace svn +{ + Targets::Targets (const Pathes & targets) + { + m_targets = targets; + } + + Targets::Targets(const QStringList&targets) + { + m_targets.clear(); + for (unsigned int i = 0; i < targets.size();++i) { + if (targets[i].isEmpty()) { + m_targets.push_back(""); + } else { + m_targets.push_back(targets[i]); + } + } + } + + Targets::Targets (const apr_array_header_t * apr_targets) + { + int i; + + m_targets.clear (); + //m_targets.reserve (apr_targets->nelts); + + for (i = 0; i < apr_targets->nelts; i++) + { + const char ** target = + &APR_ARRAY_IDX (apr_targets, i, const char *); + + m_targets.push_back (Path (*target)); + } + } + + Targets::Targets (const Targets & targets) + { + m_targets = targets.targets (); + } + + Targets::Targets (const QString& target) + { + if (!target.isEmpty()) { + m_targets.push_back(target); + } + } + + Targets::Targets (const Path& target) + { + if (!target.cstr().isEmpty()) { + m_targets.push_back(target); + } + } + + Targets::Targets (const char* target) + { + if (target) { + m_targets.push_back(QString::FROMUTF8(target)); + } + } + + Targets::~Targets () + { + } + + apr_array_header_t * + Targets::array (const Pool & pool) const + { + Pathes::const_iterator it; + + apr_pool_t *apr_pool = pool.pool (); + apr_array_header_t *apr_targets = + apr_array_make (apr_pool, + m_targets.size(), + sizeof (const char *)); + + for (it = m_targets.begin (); it != m_targets.end (); it++) + { + QByteArray s = (*it).path().TOUTF8(); + + char * t2 = + apr_pstrndup (apr_pool,s,s.size()); + + (*((const char **) apr_array_push (apr_targets))) = t2; + } + + return apr_targets; + } + + const Pathes & + Targets::targets () const + { + return m_targets; + } + + size_t + Targets::size () const + { + return m_targets.size (); + } + + const Path& Targets::operator [](size_t which)const + { + return m_targets[which]; + } + + const Path + Targets::target (unsigned int which) const + { + if (m_targets.size () > which) + { + return m_targets[which]; + } + else + { + return Path(); + } + } +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/targets.hpp b/src/svnqt/targets.hpp new file mode 100644 index 0000000..06cef77 --- /dev/null +++ b/src/svnqt/targets.hpp @@ -0,0 +1,168 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_TARGETS_HPP_ +#define _SVNCPP_TARGETS_HPP_ + +#include "svnqt/svnqt_defines.hpp" +#include "svnqt/svnqttypes.hpp" + +#include <qglobal.h> +#if QT_VERSION < 0x040000 +#include <qvaluelist.h> +#else +#include <QtCore> +#endif + +// apr api +#include "apr_tables.h" + +class QStringList; + +namespace svn +{ + // forward declarations + class Pool; + + /** + * Encapsulation for Subversion target arrays handling + */ + class SVNQT_EXPORT Targets + { + public: + /** + * Constructor + * + * @param targets vector of paths + */ + Targets (const Pathes & targets); + + /** + * Constructor + * @param path a single paths + */ + Targets (const Path & targets); + + /** + * Constructor from an APR array containing + * char *. + * + * @param targets APR array header + */ + Targets (const apr_array_header_t * targets); + + /** + * Constructor. Initializes list with just + * one entry + * + * @param target + */ + Targets (const QString& target = QString::null); + /** + * Constructor. Initializes list with just + * one entry + * + * @param target + */ + Targets (const char * target); + /** + * Constructor. Convert stringlist into target list. + * @param targets + */ + Targets(const QStringList&targets); + + /** + * Copy Constructor + * + * @param targets Source + */ + Targets (const Targets & targets); + + /** + * Destructor + */ + virtual ~Targets (); + + /** + * Returns an apr array containing + * char *. + * + * @param pool Pool used for conversion + */ + apr_array_header_t * + array (const Pool & pool) const; + + /** + * Returns a vector of paths + * + * @return vector of paths + */ + const Pathes & + targets() const; + + /** + * @return the number of targets + */ + size_t size () const; + + /** + * operator to return the vector + * + * @return vector with targets + */ + operator const Pathes & () const + { + return m_targets; + } + + const Path& operator [](size_t which)const; + /** + * returns one single target. + * the first in the vector, if no parameter given if there are more + * than one. if there is no target or parameter > then stored pathes returns + * an empty path + * \param which which item we want + * @return single path + */ + const Path + target(unsigned int which = 0) const; + + + private: + Pathes m_targets; + }; +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/testmain.cpp b/src/svnqt/testmain.cpp new file mode 100644 index 0000000..13ae286 --- /dev/null +++ b/src/svnqt/testmain.cpp @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#include "client.hpp" +#include "repository.hpp" +#include "context.hpp" +#include "datetime.hpp" + +#include <qdatastream.h> + +int main(int,char**) +{ + svn::Client::getobject(0,0); + svn::repository::Repository rep(0L); + svn::ContextP myContext = new svn::Context(); + + QByteArray tout; +#if QT_VERSION < 0x040000 + QDataStream out(tout,IO_WriteOnly); +#endif + svn::Client*m_Svnclient = svn::Client::getobject(0,0); + svn::ContextP m_CurrentContext = new svn::Context(); + m_Svnclient->setContext(m_CurrentContext); + bool gotit = true; + svn::LogEntriesMap m_OldHistory; + + try { + m_Svnclient->log("http://www.alwins-world.de/repos/kdesvn/trunk",svn::Revision::HEAD,20,m_OldHistory,svn::Revision::UNDEFINED,true,false,0); + } catch (svn::ClientException ce) { + gotit = false; + } +#if QT_VERSION < 0x040000 + if (gotit) { + out << m_OldHistory; + svn::LogEntriesMap m_NewHistory; + QDataStream inp(tout,IO_ReadOnly); + inp >> m_NewHistory; + + svn::LogEntriesMap::Iterator it; + for (it=m_NewHistory.begin();it!=m_NewHistory.end();++it) { + qDebug("%lu %s %s",it.key(),it.data().author.ascii(),it.data().message.ascii()); + } + } +#endif + return 1; +} diff --git a/src/svnqt/tests/CMakeLists.txt b/src/svnqt/tests/CMakeLists.txt new file mode 100644 index 0000000..8aef2d5 --- /dev/null +++ b/src/svnqt/tests/CMakeLists.txt @@ -0,0 +1,23 @@ +SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + +MACRO(BUILD_TEST tname) + SET(${tname}-src ${tname}.cpp) + IF (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${tname}.h) + SET(${tname}-src ${${tname}-src} ${tname}.h) + ENDIF (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${tname}.h) + ADD_EXECUTABLE(${tname} ${${tname}-src}) + TARGET_LINK_LIBRARIES(${tname} ${svnqt-name} ${QT_LIBRARIES}) + ADD_TEST(${tname} ${CMAKE_CURRENT_BINARY_DIR}/${tname}) +ENDMACRO(BUILD_TEST) + +IF (BUILD_TESTS) + CONFIGURE_FILE( + ${CMAKE_CURRENT_SOURCE_DIR}/testconfig.h.in + ${CMAKE_CURRENT_BINARY_DIR}/testconfig.h + ) + ADD_TEST(rmrepo "/bin/rm" "-rvf" "${CMAKE_CURRENT_BINARY_DIR}/repo") + ADD_TEST(rmco "/bin/rm" "-rvf" "${CMAKE_CURRENT_BINARY_DIR}/co") + BUILD_TEST(crepo) + BUILD_TEST(lsdir) + BUILD_TEST(ckpath) +ENDIF(BUILD_TESTS) diff --git a/src/svnqt/tests/ckpath.cpp b/src/svnqt/tests/ckpath.cpp new file mode 100644 index 0000000..ca4fe3e --- /dev/null +++ b/src/svnqt/tests/ckpath.cpp @@ -0,0 +1,24 @@ +#include "src/svnqt/path.hpp" +#include <iostream> + +int main(int,char**) +{ + svn::Path pa("/test/foo/bar/"); + if (pa.path()!=QString("/test/foo/bar")) { + std::cout << "No cleanup of components" << std::endl; + return -1; + } + pa.removeLast(); + if (pa.path()!=QString("/test/foo")) { + std::cout<<"removeLast didn't work." << std::endl; + return -1; + } + unsigned j = 0; + while (pa.length()>0) { + std::cout << pa.path() << std::endl; + pa.removeLast(); + ++j; + } + return 0; +} + diff --git a/src/svnqt/tests/crepo.cpp b/src/svnqt/tests/crepo.cpp new file mode 100644 index 0000000..604e4e9 --- /dev/null +++ b/src/svnqt/tests/crepo.cpp @@ -0,0 +1,63 @@ +#include "src/svnqt/client.hpp" +#include "src/svnqt/tests/testconfig.h" +#include "src/svnqt/repository.hpp" +#include "src/svnqt/repositorylistener.hpp" +#include "src/svnqt/targets.hpp" + +#include "testlistener.h" + +#include <iostream> +#include <unistd.h> +#include <qstringlist.h> + +class Listener:public svn::repository::RepositoryListener +{ + public: + Listener(){} + virtual ~Listener(){} + virtual void sendWarning(const QString&msg) + { + std::cout << msg << std::endl; + } + virtual void sendError(const QString&msg) + { + std::cout << msg << std::endl; + } + virtual bool isCanceld(){return false;} +}; + +int main(int,char**) +{ + QString p = TESTREPOPATH; + Listener ls; + svn::repository::Repository rp(&ls); + try { + rp.CreateOpen(p,"fsfs"); + } catch (svn::ClientException e) { + QString ex = e.msg(); + std::cout << ex.TOUTF8() << std::endl; + return -1; + } + + svn::ContextP m_CurrentContext; + svn::Client* m_Svnclient; + m_Svnclient=svn::Client::getobject(0,0); + TestListener tl; + m_CurrentContext = new svn::Context(); + m_CurrentContext->setListener(&tl); + p = "file://"+p; + + m_Svnclient->setContext(m_CurrentContext); + QStringList s; s.append(p+"/trunk"); s.append(p+"/branches"); s.append(p+"/tags"); + + try { + m_Svnclient->mkdir(svn::Targets(s),"Test mkdir"); + m_Svnclient->checkout(p,TESTCOPATH,svn::Revision::HEAD,svn::Revision::HEAD,svn::DepthInfinity,false); + } catch (svn::ClientException e) { + QString ex = e.msg(); + std::cout << ex.TOUTF8() << std::endl; + return -1; + } + + return 0; +} diff --git a/src/svnqt/tests/lsdir.cpp b/src/svnqt/tests/lsdir.cpp new file mode 100644 index 0000000..c458f31 --- /dev/null +++ b/src/svnqt/tests/lsdir.cpp @@ -0,0 +1,78 @@ + +#include "src/svnqt/client.hpp" +#include "src/svnqt/tests/testconfig.h" +#include "src/svnqt/status.hpp" +#include "src/svnqt/svnqttypes.hpp" +#include <iostream> + +int main(int,char**) +{ + svn::ContextP m_CurrentContext; + svn::Client* m_Svnclient; + m_Svnclient=svn::Client::getobject(0,0); + m_CurrentContext = new svn::Context(); + + m_Svnclient->setContext(m_CurrentContext); + svn::DirEntries dlist; + + QString p = QString("file://%1").arg(TESTREPOPATH); + QString l = QString("%1").arg(TESTCOPATH); + + try { + dlist = m_Svnclient->list(svn::Path(p),svn::Revision::HEAD,svn::Revision::HEAD,svn::DepthInfinity,true); + } catch (svn::ClientException e) { + QString ex = e.msg(); + std::cout << ex.TOUTF8() << std::endl; + return -1; + } + std::cout << "List 1 "<<dlist.size()<<std::endl; + for (unsigned int i=0; i < dlist.size();++i) { + QDateTime dt = svn::DateTime(dlist[i]->time()); + std::cout << dlist[i]->name() << " " + << dlist[i]->lastAuthor() << " " + << dlist[i]->size() << " " + << dt.toTime_t() << std::endl; + } + try { + dlist = m_Svnclient->list(svn::Path(p),svn::Revision::HEAD,svn::Revision::HEAD,svn::DepthImmediates,false); + } catch (svn::ClientException e) { + QString ex = e.msg(); + std::cout << ex.TOUTF8() << std::endl; + return -1; + } + std::cout << "================"<<std::endl; + std::cout << "List 2 "<<dlist.size()<<std::endl; + for (unsigned int i=0; i < dlist.size();++i) { + QDateTime dt = svn::DateTime(dlist[i]->time()); + std::cout << dlist[i]->name() << " " + << dlist[i]->lastAuthor() << " " + << dlist[i]->size() << " " + << dt.toTime_t() << std::endl; + } + std::cout << "================"<<std::endl; + svn::StatusEntries slist; + try { + slist = m_Svnclient->status(svn::Path(p),svn::DepthInfinity,true,true,true,svn::Revision::HEAD,true,false); + } catch (svn::ClientException e) { + QString ex = e.msg(); + std::cout << ex.TOUTF8() << std::endl; + return -1; + } + for (unsigned int i=0; i < slist.size();++i) { + std::cout << slist[i]->path()<< std::endl; + } + std::cout << "================"<<std::endl; + std::cout << "Second status:"<<std::endl; + try { + slist = m_Svnclient->status(svn::Path(l),svn::DepthInfinity,true,true,true,svn::Revision::WORKING,true,false); + } catch (svn::ClientException e) { + QString ex = e.msg(); + std::cout << ex.TOUTF8() << std::endl; + return -1; + } + for (unsigned int i=0; i < slist.size();++i) { + std::cout << slist[i]->path()<< std::endl; + } + + return 0; +} diff --git a/src/svnqt/tests/testconfig.h.in b/src/svnqt/tests/testconfig.h.in new file mode 100644 index 0000000..5ffff3e --- /dev/null +++ b/src/svnqt/tests/testconfig.h.in @@ -0,0 +1,7 @@ +#ifndef __TEST_CONFIG_H +#define __TEST_CONFIG_H + +#define TESTREPOPATH "@CMAKE_CURRENT_BINARY_DIR@/repo" +#define TESTCOPATH "@CMAKE_CURRENT_BINARY_DIR@/co" + +#endif diff --git a/src/svnqt/tests/testlistener.h b/src/svnqt/tests/testlistener.h new file mode 100644 index 0000000..0c38a43 --- /dev/null +++ b/src/svnqt/tests/testlistener.h @@ -0,0 +1,37 @@ +#ifndef _TESTLISTENER_ +#define _TESTLISTENER_ + +#include "src/svnqt/context_listener.hpp" + +class TestListener:public svn::ContextListener +{ + public: + TestListener(){} + virtual ~TestListener(){} + + virtual void contextProgress(long long int current, long long int max){}; + virtual bool contextSslClientCertPwPrompt (QString &,const QString &, bool &){return false;} + virtual bool contextLoadSslClientCertPw(QString&,const QString&){return false;} + virtual bool contextSslClientCertPrompt (QString &){return false;} + virtual svn::ContextListener::SslServerTrustAnswer + contextSslServerTrustPrompt (const SslServerTrustData &, + apr_uint32_t & ){return svn::ContextListener::SslServerTrustAnswer();} + virtual bool contextGetLogMessage (QString &,const svn::CommitItemList&){return false;} + virtual bool contextCancel(){return false;} + virtual void contextNotify (const svn_wc_notify_t *){} + virtual void contextNotify (const char *,svn_wc_notify_action_t, + svn_node_kind_t, + const char *, + svn_wc_notify_state_t, + svn_wc_notify_state_t, + svn_revnum_t){} + virtual bool contextGetSavedLogin (const QString & realm,QString & username,QString & password){return false;} + virtual bool contextGetCachedLogin (const QString & realm,QString & username,QString & password){return false;} + virtual bool contextGetLogin (const QString & realm, + QString & username, + QString & password, + bool & maySave){maySave=false;return false;} + +}; + +#endif diff --git a/src/svnqt/url.cpp b/src/svnqt/url.cpp new file mode 100644 index 0000000..185f582 --- /dev/null +++ b/src/svnqt/url.cpp @@ -0,0 +1,209 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ +#if defined( _MSC_VER) && _MSC_VER <= 1200 +#pragma warning( disable: 4786 )// debug symbol truncated +#endif + + +// svncpp +#include "pool.hpp" +#include "url.hpp" + +#include <qglobal.h> +#if QT_VERSION < 0x040000 +#include <qvaluelist.h> +#else +#include <QtCore> +#endif + +// subversion api +#include "svn_ra.h" + +namespace svn +{ + static const char * + VALID_SCHEMAS [] = + { + "http","https","file", + "svn","svn+ssh","svn+http","svn+https","svn+file", + "ksvn","ksvn+ssh","ksvn+http","ksvn+https","ksvn+file","ksvn", + 0 + }; + + static bool mSchemasInitialized = false; +#if QT_VERSION < 0x040000 + QValueList<QString> mSchemas; +#else + QList<QString> mSchemas; +#endif + + Url::Url () {} + + Url::~Url () {} + + bool Url::isLocal(const QString& url) + { +#if QT_VERSION < 0x040000 + bool cs = false; +#else + Qt::CaseSensitivity cs=Qt::CaseInsensitive; +#endif + if ( + url.startsWith("file://",cs) || + url.startsWith("/") || + url.startsWith("svn+file://",cs) || + url.startsWith("ksvn+file://",cs) ) + { + return true; + } + return false; + } + + bool Url::isValid (const QString& url) + { + QString urlTest(url); + unsigned int index = 0; + while (VALID_SCHEMAS[index]!=0) + { + QString schema = QString::FROMUTF8(VALID_SCHEMAS[index]); + QString urlComp = urlTest.mid(0, schema.length()); + + if (schema == urlComp) + { + return true; + } + ++index; + } + + return false; + } + + QString + Url::transformProtokoll(const QString&prot) + { +#if QT_VERSION < 0x040000 + QString _prot = prot.lower(); +#else + QString _prot = prot.toLower(); +#endif + if (QString::compare(_prot,"svn+http")==0|| + QString::compare(_prot,"ksvn+http")==0) { + return QString("http"); + } else if (QString::compare(_prot,"svn+https")==0|| + QString::compare(_prot,"ksvn+https")==0) { + return QString("https"); + }else if (QString::compare(_prot,"svn+file")==0|| + QString::compare(_prot,"ksvn+file")==0) { + return QString("file"); + } else if (QString::compare(_prot,"ksvn+ssh")==0) { + return QString("svn+ssh"); + } else if (QString::compare(_prot,"ksvn")==0) { + return QString("svn"); + } + return _prot; + } + + + /** + * the implementation of the function that pull the supported + * url schemas out of the ra layer it rather dirty now since + * we are lacking a higher level of abstraction + */ +#if QT_VERSION < 0x040000 + QValueList<QString> +#else + QList<QString> +#endif + Url::supportedSchemas () + { + if (mSchemasInitialized) + return mSchemas; + + mSchemasInitialized = true; + Pool pool; + void * ra_baton; + + svn_error_t * error = + svn_ra_init_ra_libs (&ra_baton, pool); + if (error) + return mSchemas; + + svn_stringbuf_t *descr; + error = + svn_ra_print_ra_libraries (&descr, ra_baton, pool); + if (error) + return mSchemas; + + // schemas are in the following form: + // <schema>:<whitespace><description>\n... + // find the f�st : + QString descriptions (descr->data); + int pos=0; + const int not_found = -1; + do + { + const QString tokenStart ("handles '"); + const QString tokenEnd ("' schem"); +#if QT_VERSION < 0x040000 + pos = descriptions.find (tokenStart, pos); +#else + pos = descriptions.indexOf( tokenStart, pos ); +#endif + if (pos == not_found) + break; + + pos += tokenStart.length (); + +#if QT_VERSION < 0x040000 + int posEnd = descriptions.find (tokenEnd, pos); +#else + int posEnd = descriptions.indexOf( tokenEnd, pos ); +#endif + if (posEnd == not_found) + break; + + // found + QString schema (descriptions.mid(pos, posEnd-pos) + ":"); + mSchemas.push_back (schema); + + // forward to the next newline + pos = posEnd + tokenEnd.length (); + } + while (pos != not_found); + + return mSchemas; + } +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/url.hpp b/src/svnqt/url.hpp new file mode 100644 index 0000000..795d4c8 --- /dev/null +++ b/src/svnqt/url.hpp @@ -0,0 +1,104 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_URL_H_ +#define _SVNCPP_URL_H_ + +#include "svnqt/svnqt_defines.hpp" + +// qt +#include <qglobal.h> +#if QT_VERSION < 0x040000 + +#include <qstring.h> +#include <qvaluelist.h> + +#else + +#include <QtCore> + +#endif + + +namespace svn +{ + class SVNQT_EXPORT Url + { + public: + /** Constructor */ + Url (); + + /** Destructor */ + virtual ~Url (); + + /** + * Checks if @a url is valid + * + * Example of a valid URL: + * http://svn.collab.net/repos/svn + * Example of an invalid URL: + * /home/foo/bar + */ + static bool + isValid (const QString& url); + + /** + * Checks if @a url points to a local filesystem. + * + * @return true if url is accessed local without network. + */ + static bool + isLocal(const QString& url); + + static QString + transformProtokoll(const QString&); + + /** + * returns a vector with url schemas that are + * supported by svn + * + * @return vector with entries like "file:", "http:" + */ +#if QT_VERSION < 0x040000 + static QValueList<QString> +#else + static QList<QString> +#endif + supportedSchemas (); + }; +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ + diff --git a/src/svnqt/version_check.cpp b/src/svnqt/version_check.cpp new file mode 100644 index 0000000..02f6b10 --- /dev/null +++ b/src/svnqt/version_check.cpp @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#include "version_check.hpp" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <svn_version.h> +#include <svn_client.h> + +#include <qstring.h> + +namespace svn { + static const svn_version_t Linkedtag = { + SVN_VER_MAJOR, + SVN_VER_MINOR, + SVN_VER_PATCH, + SVN_VER_NUMTAG + }; + + static QString curr_version_string; + + bool Version::client_version_compatible() + { + return svn_ver_compatible(svn_client_version(),&Linkedtag); + } + + const QString Version::linked_version() + { + return QString( SVN_VERSION ); + } + + const QString Version::running_version() + { + if (curr_version_string.length()==0) { + curr_version_string = + QString("%1.%2.%3.%4").arg(svn_client_version()->major).arg(svn_client_version()->minor) + .arg(svn_client_version()->patch).arg(svn_client_version()->tag); + } + return curr_version_string; + } + + int Version::version_major() + { + return svn_client_version()->major; + } + + int Version::version_minor() + { + return svn_client_version()->minor; + } +} diff --git a/src/svnqt/version_check.hpp b/src/svnqt/version_check.hpp new file mode 100644 index 0000000..2398645 --- /dev/null +++ b/src/svnqt/version_check.hpp @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 by Rajko Albrecht * + * ral@alwins-world.de * + * * + * 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. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef __VERSION_CHECK_HPP +#define __VERSION_CHECK_HPP + +#include "svnqt/svnqt_defines.hpp" + +class QString; + +namespace svn { + class SVNQT_EXPORT Version { + + public: + Version(){} + ~Version(){} + + static bool client_version_compatible(); + static const QString linked_version(); + static const QString running_version(); + + static int version_major(); + static int version_minor(); + }; +} + +#endif diff --git a/src/svnqt/wc.cpp b/src/svnqt/wc.cpp new file mode 100644 index 0000000..bcfe139 --- /dev/null +++ b/src/svnqt/wc.cpp @@ -0,0 +1,129 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +// subversion api +#include "svn_wc.h" + +// svncpp +#include "exception.hpp" +#include "path.hpp" +#include "pool.hpp" +#include "wc.hpp" + +namespace svn +{ + const char * Wc::ADM_DIR_NAME = SVN_WC_ADM_DIR_NAME; + + bool + Wc::checkWc (const QString& dir) + { + Pool pool; + Path path (dir); + int wc; + + svn_error_t * error = svn_wc_check_wc ( + path.path().TOUTF8(), + &wc, pool); + + if ((error != NULL) || (wc == 0)) + { + return false; + } + + return true; + } + + void + Wc::ensureAdm (const QString& dir, const QString& uuid, + const QString& url, const Revision & revision) throw (ClientException) + { + Pool pool; + Path dirPath (dir); + Path urlPath (url); + + svn_error_t * error = + svn_wc_ensure_adm ( + dirPath.path().TOUTF8(), // path + uuid.TOUTF8(), // UUID + urlPath.path().TOUTF8(), // url + revision.revnum (), // revision + pool); + if(error != NULL) + throw ClientException (error); + } + + const svn_wc_entry_t *Wc::getEntry( const QString &path ) throw ( ClientException ) + { + Pool pool; + Path itemPath(path); + svn_error_t * error = 0; + svn_wc_adm_access_t *adm_access; + const svn_wc_entry_t *entry; + error = svn_wc_adm_probe_open2(&adm_access,0,itemPath.path().TOUTF8(),FALSE,0,pool); + if (error!=0) { + throw ClientException(error); + } + error = svn_wc_entry(&entry,itemPath.path().TOUTF8(),adm_access,FALSE,pool); + if (error!=0) { + throw ClientException(error); + } + error = svn_wc_adm_close(adm_access); + if (error!=0) { + throw ClientException(error); + } + return entry; + } + + QString Wc::getUrl(const QString&path) throw (ClientException) + { + QString result = ""; + const svn_wc_entry_t *entry; + entry = getEntry( path ); + result = entry?QString::FROMUTF8(entry->url):""; + + return result; + } + + QString Wc::getRepos(const QString&path) throw (ClientException) + { + QString result = ""; + const svn_wc_entry_t *entry; + entry = getEntry( path ); + result = entry ? QString::FROMUTF8(entry->repos) : QString::fromLatin1(""); + + return result; + } +} + +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ diff --git a/src/svnqt/wc.hpp b/src/svnqt/wc.hpp new file mode 100644 index 0000000..b8769f8 --- /dev/null +++ b/src/svnqt/wc.hpp @@ -0,0 +1,96 @@ +/* + * Port for usage with qt-framework and development for kdesvn + * (C) 2005-2007 by Rajko Albrecht + * http://kdesvn.alwins-world.de + */ +/* + * ==================================================================== + * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library (in the file LGPL.txt); if not, + * write to the Free Software Foundation, Inc., 51 Franklin St, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://rapidsvn.tigris.org/. + * ==================================================================== + */ + +#ifndef _SVNCPP_WC_HPP_ +#define _SVNCPP_WC_HPP_ + +// Ignore MSVC 7, 2005 & 2008 compiler warning: C++ exception specification +#if defined (_MSC_VER) && _MSC_VER > 1200 && _MSC_VER <= 1550 +#pragma warning (disable: 4290) +#endif + +// svncpp +#include "svnqt/exception.hpp" +#include "svnqt/revision.hpp" +#include "svnqt/svnqt_defines.hpp" + +#include <qstring.h> + +namespace svn +{ + /** + * Class that deals with a working copy + */ + class SVNQT_EXPORT Wc + { + public: + /** + * check if Path is a valid working directory + * + * @param dir path to a directory + * @return true=valid working copy + */ + static bool + checkWc (const QString& dir); + + /** + * ensure that an administrative area exists for @a dir, so that @a dir + * is a working copy subdir based on @a url at @a revision. + * + * @param dir path to a directory + * @param uuid + * @param url corresponding url + * @param revision expected working copy revision + */ + static void + ensureAdm (const QString& dir, const QString& uuid, + const QString& url, const Revision & revision) throw (ClientException); + + /** + * retrieve the url of a given working copy item + * @param path the working copy item to check + * @return the repository url of @a path + */ + static QString getUrl(const QString&path) throw (ClientException); + static QString getRepos(const QString&path) throw (ClientException); + static const char * ADM_DIR_NAME; + + private: + static const svn_wc_entry_t *getEntry( const QString &path ) throw ( ClientException ); + + }; +} + +#endif +/* ----------------------------------------------------------------- + * local variables: + * eval: (load-file "../../rapidsvn-dev.el") + * end: + */ |