diff --git a/CMakeLists.txt b/CMakeLists.txt index 36bd796..014102e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,8 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} ) +#ADD_DEFINITIONS(-DGW_NO_DEPRECATION) + ADD_SUBDIRECTORY(libGitWrap) ADD_SUBDIRECTORY(testGitWrap) diff --git a/libGitWrap/Base.cpp b/libGitWrap/Base.cpp index 59bbbf3..1f5a96a 100644 --- a/libGitWrap/Base.cpp +++ b/libGitWrap/Base.cpp @@ -17,9 +17,11 @@ * */ -#include "Base.hpp" +#include "libGitWrap/Base.hpp" +#include "libGitWrap/Object.hpp" -#include "Private/BasePrivate.hpp" +#include "libGitWrap/Private/BasePrivate.hpp" +#include "libGitWrap/Private/ObjectPrivate.hpp" namespace Git { @@ -35,9 +37,65 @@ namespace Git { } - const git_oid* BasePrivate::sha(const ObjectId& id) + git_object* BasePrivate::objectOf(const Object& o) { - return reinterpret_cast(id.raw()); + Object::Private* op = dataOf(o); + + if (!op) { + return NULL; + } + + return op->o(); + } + + /** + * @internal + * @brief Static private validity checker + * + * This is a private validity checker. It is used from the GW_D macro. Implementing it as a + * private static method, allows a lot of code reduction (resulting in isValid() being in + * the CPU cache and thus much less cache misses on code that uses GitWrap a lot). + * + * Also, this allows us to transparently delegate to the virtual method isValidObject(), + * which gives the object itself an opportunitiy to tell whether it is valid or not and also + * set a custom result. + * + * This is esp. useful since Reference objects can become invalid (when destroy() is used) + * and we cannot warrant that this will be checked in all methods of Reference derivates. + * + * @param[in,out] r A Result that will be set to invalid if @a d is `NULL` and can be + * set to anything, if @a d is not `NULL`. + * + * @param[in] d The BasePrivate to check. + * + * @return `true`, if this object can be treated as vaild. + * + */ + bool BasePrivate::isValid(Result& r, const BasePrivate* d) + { + if (Q_LIKELY(d)) { + return d->isValidObject(r); + } + r.setInvalidObject(); + return false; + } + + /** + * @internal + * @brief Check for validity + * + * @param[in,out] r A Result that can be used to tell the user about any problems with + * the object at hand. + * + * @return `true`, if this object is valid - `false` otherwise. Note, that by + * convention, the object is invalid if the Result @a r contains an error + * on input, thus this method should `return r;` whenever it wants to + * return `true` actually. + * + */ + bool BasePrivate::isValidObject(Result& r) const + { + return r; } } @@ -46,8 +104,8 @@ namespace Git { } - Base::Base(Internal::BasePrivate &_d) - : mData(&_d) + Base::Base(const PrivatePtr& _d) + : mData(_d) { } @@ -71,6 +129,11 @@ namespace Git return mData == other.mData; } + bool Base::operator!=(const Base& other) const + { + return mData != other.mData; + } + bool Base::isValid() const { return mData; diff --git a/libGitWrap/Base.hpp b/libGitWrap/Base.hpp index 10ff8c1..df984ff 100644 --- a/libGitWrap/Base.hpp +++ b/libGitWrap/Base.hpp @@ -46,12 +46,25 @@ namespace Git Base(const Base& other); virtual ~Base(); Base& operator=(const Base& other); - bool isValid() const; bool operator==(const Base& other) const; + bool operator!=(const Base& other) const; + + public: + bool isValid() const; + + protected: + typedef QExplicitlySharedDataPointer PrivatePtr; + Base(const PrivatePtr& _d); + PrivatePtr mData; protected: - Base(Internal::BasePrivate& _d); - QExplicitlySharedDataPointer mData; + inline void ensureThisIsNotConst() + { + // This method is invoked from the GW_D macro. Its only purpose is to error out at + // compile time, if we casted from a const outer object. This is actually neccessary + // because QExplicitlySharedDataPointer seems to give a shit about const + // correctness. + } }; } diff --git a/libGitWrap/Blob.cpp b/libGitWrap/Blob.cpp new file mode 100644 index 0000000..fec4b4d --- /dev/null +++ b/libGitWrap/Blob.cpp @@ -0,0 +1,54 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 Sascha Cunz + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#include "libGitWrap/Blob.hpp" + +#include "libGitWrap/Private/GitWrapPrivate.hpp" +#include "libGitWrap/Private/BlobPrivate.hpp" + +namespace Git +{ + + namespace Internal { + + BlobPrivate::BlobPrivate(const RepositoryPrivate::Ptr& repo, git_blob* o) + : ObjectPrivate(repo, reinterpret_cast(o)) + { + Q_ASSERT(o); + } + + BlobPrivate::BlobPrivate(const RepositoryPrivate::Ptr& repo, git_object* o) + : ObjectPrivate(repo, o) + { + Q_ASSERT(o); + Q_ASSERT(git_object_type(o) == GIT_OBJ_BLOB); + } + + git_otype BlobPrivate::otype() const + { + return GIT_OBJ_BLOB; + } + + ObjectType BlobPrivate::objectType() const + { + return otBlob; + } + + } + + GW_PRIVATE_IMPL(Blob, Object) + +} diff --git a/libGitWrap/ObjectBlob.cpp b/libGitWrap/Blob.hpp similarity index 54% rename from libGitWrap/ObjectBlob.cpp rename to libGitWrap/Blob.hpp index 13d9faf..04a50ee 100644 --- a/libGitWrap/ObjectBlob.cpp +++ b/libGitWrap/Blob.hpp @@ -14,28 +14,43 @@ * */ -#include "ObjectBlob.hpp" +#ifndef GIT_OBJECT_BLOB_H +#define GIT_OBJECT_BLOB_H -#include "Private/GitWrapPrivate.hpp" +#include "libGitWrap/GitWrap.hpp" +#include "libGitWrap/ObjectId.hpp" +#include "libGitWrap/Object.hpp" namespace Git { - ObjectBlob::ObjectBlob() + namespace Internal { + + class BlobPrivate; + } - ObjectBlob::ObjectBlob(Internal::ObjectPrivate& _d) - : Object(_d) + /** + * @ingroup GitWrap + * @brief Provides access to git BLOB (Binary Large Object) objects + * + */ + class GITWRAP_API Blob : public Object { - Result r; - Q_UNUSED( r ); - Q_ASSERT( type(r) == otBlob ); - } + public: + GW_PRIVATE_DECL(Blob, Object, public); + enum { ObjectTypeId = otBlob }; + }; - ObjectBlob::ObjectBlob(const ObjectBlob& o) - : Object(o) + template<> + inline Blob Object::as() const { + return asBlob(); } } + +Q_DECLARE_METATYPE(Git::Blob) + +#endif diff --git a/libGitWrap/BranchRef.cpp b/libGitWrap/BranchRef.cpp new file mode 100644 index 0000000..906df20 --- /dev/null +++ b/libGitWrap/BranchRef.cpp @@ -0,0 +1,55 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 The MacGitver-Developers + * + * (C) Sascha Cunz + * (C) Nils Fenner + * (C) Cunz RaD Ltd. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#include "libGitWrap/BranchRef.hpp" +#include "libGitWrap/Private/BranchRefPrivate.hpp" + +namespace Git +{ + + namespace Internal + { + + BranchRefPrivate::BranchRefPrivate(const RepositoryPrivate::Ptr& repo, + git_reference* reference) + : ReferencePrivate(repo, reference) + { + #ifdef QT_DEBUG + // We want this constructor to analyze only for the assert... + ensureAnalyzed(); + Q_ASSERT(isBranch); + #endif + } + + BranchRefPrivate::BranchRefPrivate(git_reference* reference, const RefNamePrivate* refName) + : ReferencePrivate(reference, refName) + { + } + + ReferenceKinds BranchRefPrivate::kind() const + { + return BranchReference; + } + + } + + GW_PRIVATE_IMPL(BranchRef, Reference) + +} diff --git a/libGitWrap/BranchRef.hpp b/libGitWrap/BranchRef.hpp new file mode 100644 index 0000000..50fabde --- /dev/null +++ b/libGitWrap/BranchRef.hpp @@ -0,0 +1,53 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 The MacGitver-Developers + * + * (C) Sascha Cunz + * (C) Nils Fenner + * (C) Cunz RaD Ltd. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GITWRAP_BRANCH_REF_HPP +#define GITWRAP_BRANCH_REF_HPP +#pragma once + +#include "libGitWrap/Reference.hpp" + +namespace Git +{ + + namespace Internal + { + + class BranchRefPrivate; + + } + + class GITWRAP_API BranchRef : public Reference + { + GW_PRIVATE_DECL(BranchRef, Reference, public) + + public: + }; + + template<> + inline BranchRef Reference::as() const { + return asBranch(); + } + +} + +Q_DECLARE_METATYPE(Git::BranchRef) + +#endif diff --git a/libGitWrap/CMakeLists.txt b/libGitWrap/CMakeLists.txt index 24a55d4..cd0c185 100644 --- a/libGitWrap/CMakeLists.txt +++ b/libGitWrap/CMakeLists.txt @@ -117,93 +117,122 @@ ADD_DEFINITIONS( -D_FILE_OFFSET_BITS=64 -DGIT_THREADS ) SET( SRC_FILES Base.cpp - RepoObject.cpp - Config.cpp + Blob.cpp + BranchRef.cpp ChangeListConsumer.cpp - CloneOperation.cpp + Commit.cpp + Config.cpp DiffList.cpp GitWrap.cpp - IFetchEvents.cpp Index.cpp - IndexEntry.cpp IndexConflict.cpp IndexConflicts.cpp + IndexEntry.cpp + NoteRef.cpp Object.cpp - ObjectBlob.cpp - ObjectCommit.cpp ObjectId.cpp - ObjectTag.cpp - ObjectTree.cpp PatchConsumer.cpp RefName.cpp RefSpec.cpp Reference.cpp Remote.cpp + RepoObject.cpp Repository.cpp Result.cpp RevisionWalker.cpp Signature.cpp Submodule.cpp + Tag.cpp + TagRef.cpp + Tree.cpp TreeBuilder.cpp TreeEntry.cpp - Private/FetchCallbacks.cpp - Private/WorkerThread.cpp + Operations/BaseOperation.cpp + Operations/CheckoutOperation.cpp + Operations/CloneOperation.cpp + Operations/IFetchEvents.cpp + + Operations/Private/FetchCallbacks.cpp + Operations/Private/WorkerThread.cpp ) SET( PUB_HDR_FILES Base.hpp - RepoObject.hpp - Result.hpp - Config.hpp + Blob.hpp + BranchRef.hpp ChangeListConsumer.hpp - CloneOperation.hpp + Commit.hpp + Config.hpp DiffList.hpp + FileInfo.hpp GitWrap.hpp - IFetchEvents.hpp Index.hpp - IndexEntry.hpp IndexConflict.hpp IndexConflicts.hpp + IndexEntry.hpp + NoteRef.hpp Object.hpp ObjectBlob.hpp ObjectCommit.hpp ObjectId.hpp ObjectTag.hpp ObjectTree.hpp - RefSpec.hpp RefName.hpp + RefSpec.hpp Reference.hpp Remote.hpp + RepoObject.hpp Repository.hpp + Result.hpp RevisionWalker.hpp Signature.hpp Submodule.hpp + Tag.hpp + TagRef.hpp + Tree.hpp TreeBuilder.hpp TreeEntry.hpp + + Operations/BaseOperation.hpp + Operations/CheckoutOperation.hpp + Operations/CloneOperation.hpp + Operations/IFetchEvents.hpp ) SET( PRI_HDR_FILES - Private/GitWrapPrivate.hpp Private/BasePrivate.hpp + Private/BlobPrivate.hpp + Private/BranchRefPrivate.hpp + Private/CommitPrivate.hpp Private/ConfigPrivate.hpp - Private/CloneOperationPrivate.hpp Private/DiffListPrivate.hpp - Private/FetchCallbacks.hpp - Private/IndexPrivate.hpp - Private/IndexEntryPrivate.hpp + Private/GitWrapPrivate.hpp Private/IndexConflictPrivate.hpp + Private/IndexEntryPrivate.hpp + Private/IndexPrivate.hpp Private/ObjectPrivate.hpp + Private/NoteRefPrivate.hpp Private/ReferencePrivate.hpp + Private/RefNamePrivate.hpp Private/RemotePrivate.hpp Private/RepoObjectPrivate.hpp Private/RepositoryPrivate.hpp Private/RevisionWalkerPrivate.hpp + Private/SubmodulePrivate.hpp + Private/TagPrivate.hpp + Private/TagRefPrivate.hpp Private/TreeBuilderPrivate.hpp Private/TreeEntryPrivate.hpp - Private/WorkerThread.hpp + Private/TreePrivate.hpp + + Operations/Private/BaseOperationPrivate.hpp + Operations/Private/CheckoutOperationPrivate.hpp + Operations/Private/CloneOperationPrivate.hpp + Operations/Private/FetchCallbacks.hpp + Operations/Private/WorkerThread.hpp ) SET( HDR_FILES ${PRI_HDR_FILES} ${PUB_HDR_FILES} ) diff --git a/libGitWrap/ChangeListConsumer.cpp b/libGitWrap/ChangeListConsumer.cpp index 07d0167..a3cf4be 100644 --- a/libGitWrap/ChangeListConsumer.cpp +++ b/libGitWrap/ChangeListConsumer.cpp @@ -14,7 +14,7 @@ * */ -#include "ChangeListConsumer.hpp" +#include "libGitWrap/ChangeListConsumer.hpp" namespace Git { diff --git a/libGitWrap/ChangeListConsumer.hpp b/libGitWrap/ChangeListConsumer.hpp index 93b1bfc..a3fbb9f 100644 --- a/libGitWrap/ChangeListConsumer.hpp +++ b/libGitWrap/ChangeListConsumer.hpp @@ -17,7 +17,7 @@ #ifndef GIT_CHANGELIST_CONSUMER_H #define GIT_CHANGELIST_CONSUMER_H -#include "GitWrap.hpp" +#include "libGitWrap/GitWrap.hpp" namespace Git { diff --git a/libGitWrap/Commit.cpp b/libGitWrap/Commit.cpp new file mode 100644 index 0000000..e18dc86 --- /dev/null +++ b/libGitWrap/Commit.cpp @@ -0,0 +1,342 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 Sascha Cunz + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#include "libGitWrap/Commit.hpp" +#include "libGitWrap/Tree.hpp" +#include "libGitWrap/Reference.hpp" +#include "libGitWrap/Repository.hpp" + +#include "libGitWrap/Private/GitWrapPrivate.hpp" +#include "libGitWrap/Private/ObjectPrivate.hpp" +#include "libGitWrap/Private/RepositoryPrivate.hpp" +#include "libGitWrap/Private/ReferencePrivate.hpp" +#include "libGitWrap/Private/CommitPrivate.hpp" +#include "libGitWrap/Private/TreePrivate.hpp" +#include "libGitWrap/Private/DiffListPrivate.hpp" + +namespace Git +{ + + namespace Internal { + + CommitPrivate::CommitPrivate(const RepositoryPrivate::Ptr& repo, git_commit *o) + : ObjectPrivate(repo, reinterpret_cast(o)) + { + Q_ASSERT(o); + } + + CommitPrivate::CommitPrivate(const RepositoryPrivate::Ptr& repo, git_object *o) + : ObjectPrivate(repo, o) + { + Q_ASSERT(o); + Q_ASSERT(git_object_type(o) == GIT_OBJ_TREE); + } + + git_otype CommitPrivate::otype() const + { + return GIT_OBJ_TREE; + } + + ObjectType CommitPrivate::objectType() const + { + return otCommit; + } + + } + + GW_PRIVATE_IMPL(Commit, Object) + + Tree Commit::tree( Result& result ) const + { + GW_CD_CHECKED(Commit, Tree(), result); + git_tree* tree = NULL; + + result = git_commit_tree(&tree, d->o()); + if(!result) { + return Tree(); + } + + return Tree::PrivatePtr(new Tree::Private(d->repo(), tree)); + } + + ObjectId Commit::treeId( Result& result ) const + { + GW_CD_CHECKED(Commit, ObjectId(), result); + return Private::oid2sha(git_commit_tree_id(d->o())); + } + + ObjectIdList Commit::parentCommitIds( Result& result ) const + { + GW_CD_CHECKED(Commit, ObjectIdList(), result); + const git_commit* commit = d->o(); + ObjectIdList ids; + + for (unsigned int i = 0; i < numParentCommits(); i++) { + ids << Private::oid2sha(git_commit_parent_id(commit, i)); + } + + return ids; + } + + Commit Commit::parentCommit(Result& result, unsigned int index) const + { + GW_CD_CHECKED(Commit, Commit(), result); + git_commit* gitparent = NULL; + + result = git_commit_parent(&gitparent, d->o(), index); + if (!result) { + return Commit(); + } + + return PrivatePtr(new Private(d->repo(), gitparent)); + } + + ObjectId Commit::parentCommitId(Result& result, unsigned int index) const + { + GW_CD_CHECKED(Commit, ObjectId(), result) + + if(numParentCommits() > index) { + const git_oid* oid = git_commit_parent_id(d->o(), index); + if (oid) { + return Private::oid2sha(oid); + } + } + + return ObjectId(); + } + + CommitList Commit::parentCommits( Result& result ) const + { + GW_CD_CHECKED(Commit, CommitList(), result) + CommitList objs; + + for( unsigned int i = 0; i < numParentCommits(); i++ ) + { + git_commit* parent = NULL; + + result = git_commit_parent(&parent, d->o(), i); + if (!result) { + return CommitList(); + } + + objs.append(PrivatePtr(new Private(d->repo(), parent))); + } + + return objs; + } + + unsigned int Commit::numParentCommits() const + { + GW_CD(Commit); + if (!d) { + return 0; + } + + return git_commit_parentcount(d->o()); + } + + bool Commit::isParentOf(Result& result, const Git::Commit& child) const + { + CommitList parents = child.parentCommits( result ); + + for (int i = 0; result && i < parents.count(); i++) { + if (isEqual(result, parents[i])) { + return true; + } + } + + return false; + } + + bool Commit::isChildOf(Result& result, const Git::Commit& parent) const + { + CommitList children = parentCommits( result ); + + for (int i = 0; result && i < children.count(); i++) { + if (parent.isEqual(result, children[i])) { + return true; + } + } + + return false; + } + + bool Commit::isEqual(Result& result, const Git::Commit& commit) const + { + return result && id() == commit.id(); + } + + Signature Commit::author( Result& result ) const + { + return author(); + } + + Signature Commit::committer( Result& result ) const + { + return committer(); + } + + QString Commit::message( Result& result ) const + { + return message(); + } + + QString Commit::shortMessage( Result& result ) const + { + return shortMessage(); + } + + Signature Commit::author() const + { + GW_CD(Commit); + if (!d) { + return Signature(); + } + return Internal::git2Signature(git_commit_author(d->o())); + } + + Signature Commit::committer() const + { + GW_CD(Commit); + if (!d) { + return Signature(); + } + return Internal::git2Signature(git_commit_committer(d->o())); + } + + QString Commit::message() const + { + GW_CD(Commit); + if (!d) { + return QString(); + } + + const char* msg = git_commit_message(d->o()); + int len = int( strlen( msg ) ); + + if (len && msg[len - 1] == '\n') { + len--; + } + + return QString::fromUtf8(msg, len); + } + + QString Commit::shortMessage() const + { + GW_CD(Commit); + if (!d) { + return QString(); + } + + const char* msg = git_commit_message(d->o()); + + int len = 0; + while (msg[len] && msg[len] != '\n') { + len++; + } + + return QString::fromUtf8(msg, len); + } + + /** + * @brief Checkout this commit. + * + * @param[in,out] result A Result object; see @ref GitWrapErrorHandling + * + * @param[in] force If @c true, files will be overwritten. If @c false (the default), + * the operation is canceled in case of any problem. + * + * @param[in] updateHEAD If @c true, Commit::updateHEAD() is called after a + * successful checkout. If @c false (the default), updateHEAD is + * not called. + * + * @param[in] paths Inclusive filters to the tree to checkout. If empty (the default), + * the whole tree is checked out. + * + */ + void Commit::checkout(Result &result, bool force, bool updateHEAD, + const QStringList &paths) const + { + GW_CD_CHECKED_VOID(Commit, result); + + tree(result).checkout(result, force, paths); + + if (result && updateHEAD) { + setAsDetachedHEAD(result); + } + } + + Reference Commit::createBranch(Result& result, const QString& name, bool force) const + { + GW_CD_CHECKED(Commit, Reference(), result); + + git_reference* ref = NULL; + result = git_branch_create(&ref, d->repo()->mRepo, name.toUtf8().constData(), d->o(), force); + + if (!result) { + return Reference(); + } + + return Reference::PrivatePtr(new Reference::Private(d->repo(), ref)); + } + + DiffList Commit::diffFromParent(Result& result, unsigned int index) + { + GW_CD_CHECKED(Commit, DiffList(), result) + + Commit parentObjCommit = parentCommit( result, index ); + Tree parentObjTree = parentObjCommit.tree( result ); + + return parentObjTree.diffToTree( result, tree( result ) ); + } + + DiffList Commit::diffFromAllParents( Result& result ) + { + GW_CD_CHECKED(Commit, DiffList(), result) + + if (numParentCommits() == 0) { + return DiffList(); + } + + DiffList dl = diffFromParent( result, 0 ); + for (unsigned int i = 1; i < numParentCommits(); i++) { + DiffList dl2 = diffFromParent( result, i ); + dl2.mergeOnto( result, dl ); + } + + return dl; + } + + void Commit::setAsDetachedHEAD(Result& result) const + { + GW_CD_CHECKED_VOID(Commit, result); + repository().setDetachedHEAD(result, *this); + } + +} + +/** + * @ingroup GitWrap + * @brief Debug-Stream support for Git::Commit + * @param[in] debug The Debug-Stream to output into + * @param[in] commit The commit object to output + * @return The Debug-Stream + */ +QDebug operator<<( QDebug debug, const Git::Commit& commit ) +{ + return debug << "Commit(id=" << commit.id() << ";author=" << commit.author() << ")"; +} + diff --git a/libGitWrap/Commit.hpp b/libGitWrap/Commit.hpp new file mode 100644 index 0000000..9bf0455 --- /dev/null +++ b/libGitWrap/Commit.hpp @@ -0,0 +1,104 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 Sascha Cunz + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GIT_OBJECT_COMMIT_H +#define GIT_OBJECT_COMMIT_H + +#include "libGitWrap/GitWrap.hpp" +#include "libGitWrap/ObjectId.hpp" +#include "libGitWrap/Object.hpp" +#include "libGitWrap/Signature.hpp" +#include "libGitWrap/DiffList.hpp" +#include "libGitWrap/Result.hpp" + +namespace Git +{ + + namespace Internal + { + class CommitPrivate; + } + + /** + * @ingroup GitWrap + * @brief Represents a git commit object. + * + */ + class GITWRAP_API Commit : public Object + { + GW_PRIVATE_DECL(Commit, Object, public); + public: + enum { ObjectTypeId = otCommit }; + + public: + Tree tree( Result& result ) const; + ObjectId treeId( Result& result ) const; + + ObjectIdList parentCommitIds( Result& result ) const; + CommitList parentCommits( Result& result ) const; + Commit parentCommit( Result& result, unsigned int index ) const; + ObjectId parentCommitId( Result& result, unsigned int index ) const; + unsigned int numParentCommits() const; + + bool isParentOf( Result& result, const Git::Commit& child ) const; + bool isChildOf( Result& result, const Git::Commit& parent ) const; + bool isEqual( Result& result, const Git::Commit& commit ) const; + + GW_DEPRECATED Signature author( Result& result ) const; + GW_DEPRECATED Signature committer( Result& result ) const; + GW_DEPRECATED QString message( Result& result ) const; + GW_DEPRECATED QString shortMessage( Result& result ) const; + + Signature author() const; + Signature committer() const; + + QString message() const; + QString shortMessage() const; + + void checkout( Result &result, + bool force = false, + bool updateHEAD = true, + const QStringList &paths = QStringList() ) const; + Reference createBranch( Result& result, const QString& name, bool force ) const; + + DiffList diffFromParent( Result& result, unsigned int index ); + DiffList diffFromAllParents( Result& result ); + + void setAsDetachedHEAD(Result& result) const; + }; + + template<> + inline Commit Object::as() const + { + return asCommit(); + } + + /** + * @ingroup GitWrap + * @brief qHash() for Git::Commit + */ + inline uint qHash(const Commit& c) + { + return qHash(c.id()); + } + +} + +GITWRAP_API QDebug operator<<( QDebug debug, const Git::Commit& commit ); + +Q_DECLARE_METATYPE(Git::Commit) + +#endif diff --git a/libGitWrap/Config.cpp b/libGitWrap/Config.cpp index ff6c1c7..b4172fc 100644 --- a/libGitWrap/Config.cpp +++ b/libGitWrap/Config.cpp @@ -17,9 +17,9 @@ * */ -#include "Config.hpp" +#include "libGitWrap/Config.hpp" -#include "Private/ConfigPrivate.hpp" +#include "libGitWrap/Private/ConfigPrivate.hpp" namespace Git { @@ -39,14 +39,7 @@ namespace Git } - Config::Config() - { - } - - Config::Config(Internal::ConfigPrivate& _d) - : Base(_d) - { - } + GW_PRIVATE_IMPL(Config, Base) QString Config::globalFilePath() { @@ -93,7 +86,7 @@ namespace Git return Config(); } - return *new Internal::ConfigPrivate(cfg); + return PrivatePtr(new Private(cfg)); } Config Config::user() @@ -113,7 +106,7 @@ namespace Git return Config(); } - return *new Internal::ConfigPrivate(cfg); + return PrivatePtr(new Private(cfg)); } Config Config::file( const QString& fileName ) @@ -127,7 +120,7 @@ namespace Git return Config(); } - return *new Internal::ConfigPrivate(cfg); + return PrivatePtr(new Private(cfg)); } Config Config::create() @@ -140,7 +133,7 @@ namespace Git return Config(); } - return *new Internal::ConfigPrivate(cfg); + return PrivatePtr(new Private(cfg)); } bool Config::addFile(const QString& fileName, int priority) @@ -169,9 +162,9 @@ namespace Git return 0; } - ConfigValues Config::values() + ConfigValues Config::values() const { - GW_D(Config); + GW_CD(Config); ConfigValues values; git_config_foreach( d->mCfg, &read_config_cb, (void*) &values ); return values; diff --git a/libGitWrap/Config.hpp b/libGitWrap/Config.hpp index 01979b4..3cfe3a2 100644 --- a/libGitWrap/Config.hpp +++ b/libGitWrap/Config.hpp @@ -20,7 +20,7 @@ #ifndef GITWRAP_CONFIG_H #define GITWRAP_CONFIG_H -#include "Base.hpp" +#include "libGitWrap/Base.hpp" namespace Git { @@ -39,14 +39,12 @@ namespace Git */ class GITWRAP_API Config : public Base { - public: - Config(); - Config(Internal::ConfigPrivate& _d); + GW_PRIVATE_DECL(Config, Base, public) public: bool addFile( const QString& fileName, int priority ); - ConfigValues values(); + ConfigValues values() const; public: static QString globalFilePath(); @@ -59,6 +57,6 @@ namespace Git } -Q_DECLARE_METATYPE( Git::Config ) +Q_DECLARE_METATYPE(Git::Config) #endif diff --git a/libGitWrap/DiffList.cpp b/libGitWrap/DiffList.cpp index 97784d2..cc12073 100644 --- a/libGitWrap/DiffList.cpp +++ b/libGitWrap/DiffList.cpp @@ -14,14 +14,14 @@ * */ -#include "ChangeListConsumer.hpp" -#include "PatchConsumer.hpp" -#include "DiffList.hpp" -#include "Repository.hpp" +#include "libGitWrap/ChangeListConsumer.hpp" +#include "libGitWrap/PatchConsumer.hpp" +#include "libGitWrap/DiffList.hpp" +#include "libGitWrap/Repository.hpp" -#include "Private/GitWrapPrivate.hpp" -#include "Private/DiffListPrivate.hpp" -#include "Private/RepositoryPrivate.hpp" +#include "libGitWrap/Private/GitWrapPrivate.hpp" +#include "libGitWrap/Private/DiffListPrivate.hpp" +#include "libGitWrap/Private/RepositoryPrivate.hpp" namespace Git { @@ -52,7 +52,7 @@ namespace Git return mChanges; } - DiffListPrivate::DiffListPrivate(RepositoryPrivate* repo, git_diff_list* difflist) + DiffListPrivate::DiffListPrivate(const RepositoryPrivate::Ptr& repo, git_diff_list* difflist) : RepoObjectPrivate(repo) , mDiffList(difflist) { @@ -179,29 +179,7 @@ namespace Git } - DiffList::DiffList() - { - } - - DiffList::DiffList(Internal::DiffListPrivate& _d) - : RepoObject(_d) - { - } - - DiffList::DiffList(const DiffList& o) - : RepoObject(o) - { - } - - DiffList::~DiffList() - { - } - - DiffList& DiffList::operator=( const DiffList& other ) - { - RepoObject::operator=(other); - return *this; - } + GW_PRIVATE_IMPL(DiffList, RepoObject) bool DiffList::mergeOnto(Result& result, DiffList onto) const { diff --git a/libGitWrap/DiffList.hpp b/libGitWrap/DiffList.hpp index ce72409..f2496ca 100644 --- a/libGitWrap/DiffList.hpp +++ b/libGitWrap/DiffList.hpp @@ -34,19 +34,7 @@ namespace Git */ class GITWRAP_API DiffList : public RepoObject { - public: - typedef Internal::DiffListPrivate Private; - - public: - explicit DiffList(Internal::DiffListPrivate& _d); - - public: - DiffList(const DiffList& other); - DiffList(); - ~DiffList(); - - public: - DiffList& operator=( const DiffList& other ); + GW_PRIVATE_DECL(DiffList, RepoObject, public); public: bool mergeOnto( Result& result, DiffList other ) const; @@ -62,6 +50,6 @@ namespace Git } -Q_DECLARE_METATYPE( Git::DiffList ) +Q_DECLARE_METATYPE(Git::DiffList) #endif diff --git a/libGitWrap/FileInfo.hpp b/libGitWrap/FileInfo.hpp new file mode 100644 index 0000000..4095809 --- /dev/null +++ b/libGitWrap/FileInfo.hpp @@ -0,0 +1,81 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 Sascha Cunz + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GW_FILEINFO_HPP +#define GW_FILEINFO_HPP +#pragma once + +#include + +#include "libGitWrap/ObjectId.hpp" + +namespace Git +{ + + class GITWRAP_API FileInfo + { + public: + FileInfo(const QString& _fileName, ObjectId _sha1, qint64 _size, FileModes _mode, + bool _binary, bool _shaKnown) + : mSize(_size) + , mSHA1(_sha1) + , mFileName(_fileName) + , mFileMode(_mode) + , mIsBinary(_binary) + , mIsSHAKnown(_shaKnown) + , mIsValid(true) + {} + + FileInfo() + : mSize(0), mFileMode(UnkownAttr), mIsBinary(false), mIsSHAKnown(false), mIsValid(false) + {} + + ~FileInfo() + {} + + FileInfo(const FileInfo& other) + : mSize(other.mSize) + , mSHA1(other.mSHA1) + , mFileName(other.mFileName) + , mFileMode(other.mFileMode) + , mIsBinary(other.mIsBinary) + , mIsSHAKnown(other.mIsSHAKnown) + , mIsValid(other.mIsValid) + { + } + + public: + bool isValid() const { return mIsValid; } + bool isBinary() const { return mIsBinary; } + bool isSHAKnwon() const { return mIsSHAKnown; } + qint64 size() const { return mSize; } + QString fileName() const { return mFileName; } + FileModes fileMode() const { return mFileMode; } + ObjectId sha() const { return mSHA1; } + + private: + qint64 mSize; + ObjectId mSHA1; + QString mFileName; + FileModes mFileMode; + bool mIsBinary : 1; + bool mIsSHAKnown : 1; + bool mIsValid : 1; + }; + +} + +#endif diff --git a/libGitWrap/GitWrap.cpp b/libGitWrap/GitWrap.cpp index 911dcbc..f07f8f3 100644 --- a/libGitWrap/GitWrap.cpp +++ b/libGitWrap/GitWrap.cpp @@ -14,10 +14,11 @@ * */ -#include "Index.hpp" -#include "Repository.hpp" +#include "libGitWrap/Index.hpp" +#include "libGitWrap/Repository.hpp" +#include "libGitWrap/FileInfo.hpp" -#include "Private/GitWrapPrivate.hpp" +#include "libGitWrap/Private/GitWrapPrivate.hpp" namespace Git { @@ -46,12 +47,22 @@ namespace Git return sl; } + //-- StrArrayWrapper -------------------------------------------------------------------- >8 + StrArrayWrapper::StrArrayWrapper() { + Q_ASSERT(false); } StrArrayWrapper::StrArrayWrapper( const StrArrayWrapper & ) { + Q_ASSERT(false); + } + + StrArrayWrapper& StrArrayWrapper::operator=(const StrArrayWrapper&) + { + Q_ASSERT(false); + return *this; } StrArrayWrapper::StrArrayWrapper(const QStringList& sl) @@ -82,6 +93,46 @@ namespace Git return &a; } + //-- StrArray --------------------------------------------------------------------------- >8 + + StrArray& StrArray::operator=(const StrArray&) + { + Q_ASSERT(false); + return *this; + } + + StrArray::StrArray(git_strarray& _a, const QStringList& sl) + : a(_a) + , internalCopy(sl) + { + a.count = internalCopy.count(); + a.strings = new char *[a.count]; + + for(int i=0; i < internalCopy.count(); ++i ) + { + a.strings[i] = internalCopy[i].toUtf8().data(); + } + } + + StrArray::~StrArray() + { + delete[] a.strings; + } + + FileInfo mkFileInfo(const git_diff_file* df) + { + if (!df) { + return FileInfo(); + } + + QString path; + if (df->path) { + path = QString::fromUtf8(df->path); + } + return FileInfo(path, ObjectId::fromRaw(df->oid.id), df->size, FileModes(df->mode), + false, (df->flags & GIT_DIFF_FLAG_VALID_OID) != 0); + } + } GitWrap::GitWrap() diff --git a/libGitWrap/GitWrap.hpp b/libGitWrap/GitWrap.hpp index e3c28aa..0344dfe 100644 --- a/libGitWrap/GitWrap.hpp +++ b/libGitWrap/GitWrap.hpp @@ -34,29 +34,15 @@ # define GITWRAP_API Q_DECL_IMPORT #endif +#ifndef GW_NO_DEPRECATION +# define GW_DEPRECATED Q_DECL_DEPRECATED +#else +# define GW_DEPRECATED +#endif + namespace Git { - enum ObjectType - { - otTree, - otCommit, - otBlob, - otTag, - - otAny = -1 - }; - - enum TreeEntryAttributes - { - UnkownAttr = 0, - TreeAttr = 0040000, - FileAttr = 0100644, - FileExecutableAttr = 0100755, - GitLinkAttr = 0120000, - SubmoduleAttr = 0160000 - }; - class ChangeListConsumer; class DiffList; class Index; @@ -64,11 +50,14 @@ namespace Git class IndexConflicts; class IndexEntry; class Object; - class ObjectBlob; - class ObjectCommit; class ObjectId; - class ObjectTag; - class ObjectTree; + class Blob; + class BranchRef; + class Commit; + class NoteRef; + class Tag; + class TagRef; + class Tree; class PatchConsumer; class RefName; class RefSpec; @@ -86,7 +75,9 @@ namespace Git typedef QVector< Reference > ReferenceList; typedef QVector< Remote > RemoteList; typedef QVector< Submodule > SubmoduleList; - typedef QVector< ObjectCommit > ObjectCommitList; + typedef QVector< Commit > CommitList; + + typedef GW_DEPRECATED CommitList ObjectCommitList; /** * @enum Status @@ -220,7 +211,74 @@ namespace Git }; Q_DECLARE_FLAGS ( StatusFlags, Status ) - typedef QHash< QString, StatusFlags > StatusHash; + enum ObjectType + { + otTree, + otCommit, + otBlob, + otTag, + + otAny = -1 + }; + + enum FileModes + { + UnkownAttr = 0, + TreeAttr = 0040000, + FileAttr = 0100644, + FileExecutableAttr = 0100755, + GitLinkAttr = 0120000, + SubmoduleAttr = 0160000 + }; + + enum ReferenceTypes + { + ReferenceDirect, + ReferenceSymbolic, + + ReferenceInvalid = -1 + }; + + enum ReferenceKinds + { + BranchReference, + TagReference, + NoteReference, + + UnknownReference + }; + + enum CheckoutMode + { + CheckoutDryRun, + CheckoutSafe, + CheckoutSafeCreate, + CheckoutForce + }; + + enum CheckoutOption + { + CheckoutUpdateHEAD = (1UL << 0), + CheckoutAllowDetachHEAD = (1UL << 1), + CheckoutForceDetachHEAD = (1UL << 2), + CheckoutCreateLocalBranch = (1UL << 3), + + /* these are LG2 flags: */ + CheckoutAllowConflicts = (1UL << 8), + CheckoutRemoveUntracked = (1UL << 9), + CheckoutRemoveIgnored = (1UL << 10), + CheckoutNoRefresh = (1UL << 11), + CheckoutUpdateOnly = (1UL << 12), + CheckoutDontUpdateIndex = (1UL << 13), + CheckoutDisablePathSpecMatch = (1UL << 14), + CheckoutSkipLockedDirectories = (1UL << 15), + + CheckoutNone = 0 + }; + + typedef QFlags CheckoutOptions; + + typedef QHash StatusHash; class Result; @@ -236,4 +294,52 @@ namespace Git } +// Note, that macros like these are also a good way to hide the nasty administrative stuff from +// Doxygen, later... + +#define GW_PRIVATE_DECL_EX(SHARE, CLASS, BASE, SCOPE) \ + public: \ + typedef Internal::SHARE##Private Private; \ + typedef QExplicitlySharedDataPointer PrivatePtr; \ + \ + SCOPE: \ + CLASS() \ + : BASE() \ + {} \ + \ + CLASS(Private* _d); \ + CLASS(const PrivatePtr& _d); \ + \ + CLASS(const CLASS& other) \ + : BASE(other) \ + {} \ + \ + CLASS& operator=(const CLASS& other) \ + { return static_cast(BASE::operator=(other)); } \ + \ + bool operator==(const CLASS& other) const \ + { return BASE::operator==(other); } \ + \ + bool operator!=(const CLASS& other) const \ + { return BASE::operator!=(other); } \ + \ + bool operator!() const \ + { return !isValid(); } \ + \ + public: \ + ~CLASS() \ + {} + +#define GW_PRIVATE_IMPL(CLASS, BASE) \ + CLASS::CLASS(Private* _d) \ + : BASE(PrivatePtr(_d)) \ + {} \ + \ + CLASS::CLASS(const PrivatePtr& _d) \ + : BASE(_d) \ + {} + +#define GW_PRIVATE_DECL(CLASS, BASE, SCOPE) \ + GW_PRIVATE_DECL_EX(CLASS, CLASS, BASE, SCOPE) + #endif diff --git a/libGitWrap/Index.cpp b/libGitWrap/Index.cpp index 34812b2..bae4a0c 100644 --- a/libGitWrap/Index.cpp +++ b/libGitWrap/Index.cpp @@ -16,18 +16,19 @@ * */ -#include "Index.hpp" -#include "IndexEntry.hpp" -#include "IndexConflict.hpp" -#include "IndexConflicts.hpp" -#include "Repository.hpp" -#include "ObjectTree.hpp" - -#include "Private/IndexPrivate.hpp" -#include "Private/IndexEntryPrivate.hpp" -#include "Private/IndexConflictPrivate.hpp" -#include "Private/RepositoryPrivate.hpp" -#include "Private/ObjectPrivate.hpp" +#include "libGitWrap/Index.hpp" +#include "libGitWrap/IndexEntry.hpp" +#include "libGitWrap/IndexConflict.hpp" +#include "libGitWrap/IndexConflicts.hpp" +#include "libGitWrap/Repository.hpp" +#include "libGitWrap/Tree.hpp" + +#include "libGitWrap/Private/IndexPrivate.hpp" +#include "libGitWrap/Private/IndexEntryPrivate.hpp" +#include "libGitWrap/Private/IndexConflictPrivate.hpp" +#include "libGitWrap/Private/RepositoryPrivate.hpp" +#include "libGitWrap/Private/ObjectPrivate.hpp" +#include "libGitWrap/Private/TreePrivate.hpp" namespace Git { @@ -35,7 +36,7 @@ namespace Git namespace Internal { - IndexPrivate::IndexPrivate(RepositoryPrivate *repo, git_index* index) + IndexPrivate::IndexPrivate(const RepositoryPrivate::Ptr& repo, git_index* index) : RepoObjectPrivate(repo) , index(index) , conflictsLoaded(false) @@ -108,108 +109,59 @@ namespace Git * Index i; * i.readTree(result, rootTree); * // modify i... - * ObjectTree newRoot = i.writeTreeTo(result, repository); + * Tree newRoot = i.writeTreeTo(result, repository); * @endcode * */ + GW_PRIVATE_IMPL(Index, RepoObject) /** - * @brief Constructor + * @brief Create an in-memory index * - * @param[in] create If `true`, an _in-memory_ Index will be created. An in-memory index - * can be used to perform index operations, but cannot be written to - * disc. - * If `false` (the default), an invalid Index object will be - * constructed, which is equal to a default constructed object. + * @return The created _in-memory_ Index. + * + * An in-memory index can be used to perform index operations, but cannot be written to disc. * */ - Index::Index( bool create ) + Index Index::createInMemory() { - if( create ) - { - git_index* index = NULL; + git_index* index = NULL; - // We can't do anything with a potential error; anyway: it can only error out in - // Out-Of-Memory case. - git_index_new(&index); + // We can't do anything with a potential error; anyway: it can only error out in + // Out-Of-Memory case. + git_index_new(&index); - mData = new Internal::IndexPrivate(NULL, index); - } + return PrivatePtr(new Private(Repository::PrivatePtr(), index)); } /** - * @brief Constructor + * @brief Open an existing on disc index + * + * @param[in,out] result A Result object; see @ref GitWrapErrorHandling * * @param[in] path Path to read an index from. * - * @param[in,out] result A Result object; see @ref GitWrapErrorHandling + * @return The loaded index or an invalid Index object if anything went wrong. * * Creates a so called _bare_ index. A bare index is loaded from disc (from the @a path file) * and can be stored back there. It is _not_ associated with any repository. * */ - Index::Index(Result& result, const QString& path) + Index Index::openPath(Result& result, const QString& path) { - if(!result) { - // Simply keep ourselves invalid, as we cannot report - return; + if (!result) { + return Index(); } git_index* index = NULL; - result = git_index_open( &index, path.toUtf8().constData() ); + if (!result) { - // Simply keep ourselves invalid, as we cannot report - return; + return Index(); } - mData = new Internal::IndexPrivate( NULL, index ); - } - - /** - * @internal - * @brief Constructor - * - * @param[in] _d Internal data pointer to use for construction. - * - */ - Index::Index(Internal::IndexPrivate& _d) - : RepoObject( _d ) - { - } - - /** - * @brief Constructor (Copy) - * - * @param[in] o The Index object to create a copy of. - * - */ - Index::Index(const Index& o) - : RepoObject(o) - { - } - - /** - * @brief Destructor - * - * Does nothing. - */ - Index::~Index() - { - } - - /** - * @brief Assignment operator - * - * @param[in] other The Index object to assign to @c this - * - * @return A reference to @c this. - */ - Index& Index::operator=( const Index& other ) - { - RepoObject::operator=(other); - return *this; + return PrivatePtr(new Private(Repository::PrivatePtr(), index)); } /** @@ -221,7 +173,7 @@ namespace Git bool Index::isBare() const { GW_CD(Index); - return d->repo() == NULL; + return d->repo().data() == NULL; } /** @@ -265,7 +217,7 @@ namespace Git result.setError(GIT_ENOTFOUND); } - return IndexEntry(*new Internal::IndexEntryPrivate(entry)); + return IndexEntry::PrivatePtr(new IndexEntry::Private(entry)); } /** @@ -296,7 +248,7 @@ namespace Git result.setError(GIT_ENOTFOUND); } - return IndexEntry(*new Internal::IndexEntryPrivate(entry)); + return IndexEntry::PrivatePtr(new IndexEntry::Private(entry)); } /** @@ -463,18 +415,11 @@ namespace Git void Index::checkoutFiles(Result &result, const QStringList &paths) { GW_D_CHECKED_VOID(Index, result) - git_checkout_opts options = GIT_CHECKOUT_OPTS_INIT; options.checkout_strategy = GIT_CHECKOUT_FORCE; + Internal::StrArray(options.paths, paths); - // TODO don't copy, just map paths here - result = git_strarray_copy( &options.paths, Internal::StrArrayWrapper( paths ) ); - if ( !result ) - return; - - result = git_checkout_index( d->repo()->mRepo, d->index, &options ); - - git_strarray_free(&options.paths); + result = git_checkout_index(d->repo()->mRepo, d->index, &options); } /** @@ -533,7 +478,7 @@ namespace Git * * The index is cleared and recursively populated with all tree entries contained in @a tree. */ - void Index::readTree(Result& result, ObjectTree& tree) + void Index::readTree(Result& result, Tree& tree) { GW_D_CHECKED_VOID(Index, result); @@ -542,10 +487,8 @@ namespace Git return; } - Internal::ObjectPrivate* op = Internal::BasePrivate::dataOf(tree); - const git_tree* treeobj = (const git_tree*) op->mObj; - - result = git_index_read_tree(d->index, treeobj); + Tree::Private* tp = Private::dataOf(tree); + result = git_index_read_tree(d->index, tp->o()); if (result) { d->clearKnownConflicts(); @@ -557,8 +500,7 @@ namespace Git * * @param[in,out] result A Result object; see @ref GitWrapErrorHandling * - * @return The root tree as ObjectTree on success; an invalid ObjectTree in case of any - * failure. + * @return The root tree as Tree on success; an invalid Tree in case of any failure. * * The Index object must not be bare (isBare() must return @c false) and be associated to a * repository. It must also not contain any conflict entries (hasConflicts() must return @@ -571,14 +513,14 @@ namespace Git * tree objects. * */ - ObjectTree Index::writeTree(Result& result) + Tree Index::writeTree(Result& result) { - GW_D_CHECKED(Index, ObjectTree(), result) + GW_D_CHECKED(Index, Tree(), result) git_oid treeGitOid; result = git_index_write_tree(&treeGitOid, d->index); if (!result) { - return ObjectTree(); + return Tree(); } return repository().lookupTree(result, ObjectId::fromRaw(treeGitOid.id)); @@ -591,8 +533,7 @@ namespace Git * * @param[in] repo The repository to store objects into * - * @return The root tree as ObjectTree on success; an invalid ObjectTree in case of any - * failure. + * @return The root tree as Tree on success; an invalid Tree in case of any failure. * * The Index must not contain any conflict entries (hasConflicts() must return @c false). * @@ -600,20 +541,20 @@ namespace Git * as tree objects. * */ - ObjectTree Index::writeTreeTo(Result& result, Repository& repo) + Tree Index::writeTreeTo(Result& result, Repository& repo) { - GW_D_CHECKED(Index, ObjectTree(), result) + GW_D_CHECKED(Index, Tree(), result) if (!repo.isValid()) { result.setInvalidObject(); - return ObjectTree(); + return Tree(); } git_oid treeGitOid; Repository::Private* rp = Private::dataOf(repo); result = git_index_write_tree_to(&treeGitOid, d->index, rp->mRepo); if (!result) { - return ObjectTree(); + return Tree(); } return repo.lookupTree(result, ObjectId::fromRaw(treeGitOid.id)); @@ -627,8 +568,8 @@ namespace Git */ IndexConflicts Index::conflicts() const { - GW_D(Index); - return IndexConflicts(*d); + GW_CD_EX(Index); + return d; } /** @@ -640,7 +581,7 @@ namespace Git */ bool Index::hasConflicts() const { - GW_D(Index); + GW_CD(Index); return d && git_index_has_conflicts(d->index); } diff --git a/libGitWrap/Index.hpp b/libGitWrap/Index.hpp index 0d69563..bba92df 100644 --- a/libGitWrap/Index.hpp +++ b/libGitWrap/Index.hpp @@ -31,8 +31,7 @@ namespace Git class GITWRAP_API Index : public RepoObject { - public: - explicit Index(Internal::IndexPrivate& _d); + GW_PRIVATE_DECL(Index, RepoObject, public); public: enum Stages { @@ -43,13 +42,8 @@ namespace Git }; public: - Index( bool create = false ); - Index( Result& result, const QString& path ); - Index( const Index& other ); - ~Index(); - - public: - Index& operator=( const Index& other ); + static Index createInMemory(); + static Index openPath(Result& result, const QString& path); public: bool isBare() const; @@ -57,9 +51,9 @@ namespace Git void read(Result& result); void write(Result& result); void clear(); - void readTree(Result& result, ObjectTree& tree); - ObjectTree writeTree(Result& result); - ObjectTree writeTreeTo(Result& result, Repository& repo); + void readTree(Result& result, Tree& tree); + Tree writeTree(Result& result); + Tree writeTreeTo(Result& result, Repository& repo); // Methods to access and change entries int count( Result& result ) const; diff --git a/libGitWrap/IndexConflict.cpp b/libGitWrap/IndexConflict.cpp index 65bd0ce..96e0b8d 100644 --- a/libGitWrap/IndexConflict.cpp +++ b/libGitWrap/IndexConflict.cpp @@ -30,9 +30,9 @@ namespace Git IndexConflictPrivate::IndexConflictPrivate(const git_index_entry *_from, const git_index_entry *_ours, const git_index_entry *_theirs) - : from (*new IndexEntryPrivate(_from)) - , ours (*new IndexEntryPrivate(_ours)) - , theirs(*new IndexEntryPrivate(_theirs)) + : from (IndexEntry::PrivatePtr(new IndexEntryPrivate(_from))) + , ours (IndexEntry::PrivatePtr(new IndexEntryPrivate(_ours))) + , theirs(IndexEntry::PrivatePtr(new IndexEntryPrivate(_theirs))) { } @@ -51,25 +51,13 @@ namespace Git } - IndexConflict::IndexConflict() - { - } - - IndexConflict::IndexConflict(Internal::IndexConflictPrivate& _d) - : Base(_d) - { - } - - IndexConflict::IndexConflict(const IndexEntry& from, - const IndexEntry& ours, - const IndexEntry& theirs) - : Base(*new Internal::IndexConflictPrivate(from, ours, theirs)) - { - } + GW_PRIVATE_IMPL(IndexConflict, Base) - IndexConflict::IndexConflict(const IndexConflict& other) - : Base(other) + IndexConflict IndexConflict::create(const IndexEntry& from, + const IndexEntry& ours, + const IndexEntry& theirs) { + return PrivatePtr(new Private(from, ours, theirs)); } IndexEntry IndexConflict::from() const diff --git a/libGitWrap/IndexConflict.hpp b/libGitWrap/IndexConflict.hpp index 6928a58..c2184ad 100644 --- a/libGitWrap/IndexConflict.hpp +++ b/libGitWrap/IndexConflict.hpp @@ -1,52 +1,51 @@ -/* - * libGitWrap - A Qt wrapper library for libgit2 - * Copyright (C) 2012-2013 The MacGitver-Developers - * - * (C) Sascha Cunz - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License (Version 2) as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if - * not, see . - * - */ - -#ifndef GIT_INDEX_CONFLICT_HPP -#define GIT_INDEX_CONFLICT_HPP - -#include "libGitWrap/Base.hpp" - -namespace Git -{ - - namespace Internal - { - - class IndexConflictPrivate; - - } - - class IndexConflict : public Base - { - public: - explicit IndexConflict(Internal::IndexConflictPrivate& _d); - - public: - IndexConflict(); - IndexConflict(const IndexConflict& other); - IndexConflict(const IndexEntry& from, const IndexEntry& ours, const IndexEntry& theirs); - - public: - IndexEntry from() const; - IndexEntry ours() const; - IndexEntry theirs() const; - }; - -} - -#endif +/* + * libGitWrap - A Qt wrapper library for libgit2 + * Copyright (C) 2012-2013 The MacGitver-Developers + * + * (C) Sascha Cunz + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GIT_INDEX_CONFLICT_HPP +#define GIT_INDEX_CONFLICT_HPP + +#include "libGitWrap/Base.hpp" + +namespace Git +{ + + namespace Internal + { + + class IndexConflictPrivate; + + } + + class IndexConflict : public Base + { + GW_PRIVATE_DECL(IndexConflict, Base, public) + + public: + static IndexConflict create(const IndexEntry& from, + const IndexEntry& ours, + const IndexEntry& theirs); + + public: + IndexEntry from() const; + IndexEntry ours() const; + IndexEntry theirs() const; + }; + +} + +#endif diff --git a/libGitWrap/IndexConflicts.cpp b/libGitWrap/IndexConflicts.cpp index 91969a0..d7c662d 100644 --- a/libGitWrap/IndexConflicts.cpp +++ b/libGitWrap/IndexConflicts.cpp @@ -16,41 +16,23 @@ * */ -#include "IndexConflict.hpp" -#include "IndexConflicts.hpp" -#include "Index.hpp" +#include "libGitWrap/IndexConflict.hpp" +#include "libGitWrap/IndexConflicts.hpp" +#include "libGitWrap/Index.hpp" -#include "Private/IndexPrivate.hpp" -#include "Private/IndexEntryPrivate.hpp" -#include "Private/IndexConflictPrivate.hpp" +#include "libGitWrap/Private/IndexPrivate.hpp" +#include "libGitWrap/Private/IndexEntryPrivate.hpp" +#include "libGitWrap/Private/IndexConflictPrivate.hpp" namespace Git { - IndexConflicts::IndexConflicts(Internal::IndexPrivate& _d) - : Base(_d) - { - } - - IndexConflicts::IndexConflicts(const IndexConflicts& other) - : Base(other) - { - } - - IndexConflicts::~IndexConflicts() - { - } - - IndexConflicts& IndexConflicts::operator=(const IndexConflicts& other) - { - Base::operator =(other); - return * this; - } + GW_PRIVATE_IMPL(IndexConflicts, RepoObject) Index IndexConflicts::index() const { - GW_D(Index); - return Index(*d); + GW_CD_EX(Index); + return d; } void IndexConflicts::refresh() diff --git a/libGitWrap/IndexConflicts.hpp b/libGitWrap/IndexConflicts.hpp index 457b00d..ceacf3d 100644 --- a/libGitWrap/IndexConflicts.hpp +++ b/libGitWrap/IndexConflicts.hpp @@ -19,7 +19,7 @@ #ifndef GIT_INDEX_CONFLICTS_HPP #define GIT_INDEX_CONFLICTS_HPP -#include "libGitWrap/Base.hpp" +#include "libGitWrap/Index.hpp" namespace Git { @@ -29,17 +29,9 @@ namespace Git class IndexPrivate; } - class IndexConflicts : public Base + class IndexConflicts : public RepoObject { - public: - typedef Internal::IndexPrivate Private; - - public: - explicit IndexConflicts(Internal::IndexPrivate& _d); - IndexConflicts(const IndexConflicts& other); - ~IndexConflicts(); - - IndexConflicts& operator=(const IndexConflicts& other); + GW_PRIVATE_DECL_EX(Index, IndexConflicts, RepoObject, public) public: Index index() const; diff --git a/libGitWrap/IndexEntry.cpp b/libGitWrap/IndexEntry.cpp index 1178f8f..bf259a5 100644 --- a/libGitWrap/IndexEntry.cpp +++ b/libGitWrap/IndexEntry.cpp @@ -16,10 +16,10 @@ * */ -#include "IndexEntry.hpp" -#include "ObjectId.hpp" +#include "libGitWrap/IndexEntry.hpp" +#include "libGitWrap/ObjectId.hpp" -#include "Private/IndexEntryPrivate.hpp" +#include "libGitWrap/Private/IndexEntryPrivate.hpp" namespace Git { @@ -48,29 +48,7 @@ namespace Git * An IndexEntry object is a very short lived data container for an index' entry. */ - IndexEntry::IndexEntry() - { - } - - IndexEntry::IndexEntry(const IndexEntry& other) - : Base(other) - { - } - - IndexEntry::IndexEntry(Internal::IndexEntryPrivate& _d) - : Base(_d) - { - } - - IndexEntry::~IndexEntry() - { - } - - IndexEntry &IndexEntry::operator =(const IndexEntry &other) - { - Base::operator=(other); - return *this; - } + GW_PRIVATE_IMPL(IndexEntry, Base) QString IndexEntry::path() const { diff --git a/libGitWrap/IndexEntry.hpp b/libGitWrap/IndexEntry.hpp index 51194c9..b3bf826 100644 --- a/libGitWrap/IndexEntry.hpp +++ b/libGitWrap/IndexEntry.hpp @@ -31,16 +31,7 @@ namespace Git class GITWRAP_API IndexEntry : public Base { - public: - typedef Internal::IndexEntryPrivate Private; - - public: - IndexEntry(); - IndexEntry(const IndexEntry &other); - IndexEntry(Internal::IndexEntryPrivate& _d); - ~IndexEntry(); - - IndexEntry& operator=( const IndexEntry& other ); + GW_PRIVATE_DECL(IndexEntry, Base, public) public: QString path() const; diff --git a/libGitWrap/NoteRef.cpp b/libGitWrap/NoteRef.cpp new file mode 100644 index 0000000..71aa4c5 --- /dev/null +++ b/libGitWrap/NoteRef.cpp @@ -0,0 +1,55 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 The MacGitver-Developers + * + * (C) Sascha Cunz + * (C) Nils Fenner + * (C) Cunz RaD Ltd. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#include "libGitWrap/NoteRef.hpp" +#include "libGitWrap/Private/NoteRefPrivate.hpp" + +namespace Git +{ + + namespace Internal + { + + NoteRefPrivate::NoteRefPrivate(const RepositoryPrivate::Ptr& repo, + git_reference* reference) + : ReferencePrivate(repo, reference) + { + #ifdef QT_DEBUG + // We want this constructor to analyze only for the assert... + ensureAnalyzed(); + Q_ASSERT(isNote); + #endif + } + + NoteRefPrivate::NoteRefPrivate(git_reference* reference, const RefNamePrivate* refName) + : ReferencePrivate(reference, refName) + { + } + + ReferenceKinds NoteRefPrivate::kind() const + { + return NoteReference; + } + + } + + GW_PRIVATE_IMPL(NoteRef, Reference) + +} diff --git a/libGitWrap/NoteRef.hpp b/libGitWrap/NoteRef.hpp new file mode 100644 index 0000000..48d33dd --- /dev/null +++ b/libGitWrap/NoteRef.hpp @@ -0,0 +1,52 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 The MacGitver-Developers + * + * (C) Sascha Cunz + * (C) Nils Fenner + * (C) Cunz RaD Ltd. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GITWRAP_NOTE_REF_HPP +#define GITWRAP_NOTE_REF_HPP + +#include "libGitWrap/Reference.hpp" + +namespace Git +{ + + namespace Internal + { + + class NoteRefPrivate; + + } + + class GITWRAP_API NoteRef : public Reference + { + GW_PRIVATE_DECL(NoteRef, Reference, public) + + public: + }; + + template<> + inline NoteRef Reference::as() const { + return asNote(); + } + +} + +Q_DECLARE_METATYPE(Git::NoteRef) + +#endif diff --git a/libGitWrap/Object.cpp b/libGitWrap/Object.cpp index 76e433b..05ec006 100644 --- a/libGitWrap/Object.cpp +++ b/libGitWrap/Object.cpp @@ -16,14 +16,17 @@ #include "libGitWrap/ObjectId.hpp" #include "libGitWrap/Object.hpp" -#include "libGitWrap/ObjectTree.hpp" -#include "libGitWrap/ObjectTag.hpp" -#include "libGitWrap/ObjectCommit.hpp" -#include "libGitWrap/ObjectBlob.hpp" +#include "libGitWrap/Tree.hpp" +#include "libGitWrap/Tag.hpp" +#include "libGitWrap/Commit.hpp" +#include "libGitWrap/Blob.hpp" #include "libGitWrap/Repository.hpp" #include "libGitWrap/Private/GitWrapPrivate.hpp" -#include "libGitWrap/Private/ObjectPrivate.hpp" +#include "libGitWrap/Private/CommitPrivate.hpp" +#include "libGitWrap/Private/TreePrivate.hpp" +#include "libGitWrap/Private/TagPrivate.hpp" +#include "libGitWrap/Private/BlobPrivate.hpp" namespace Git { @@ -31,7 +34,7 @@ namespace Git namespace Internal { - ObjectPrivate::ObjectPrivate(RepositoryPrivate* repo, git_object* o) + ObjectPrivate::ObjectPrivate(const RepositoryPrivate::Ptr& repo, git_object* o) : RepoObjectPrivate(repo) , mObj(o) { @@ -43,36 +46,25 @@ namespace Git git_object_free(mObj); } - } - - Object::Object(Internal::ObjectPrivate& _d) - : RepoObject(_d) - { - } - - Object::Object(const Object& other) - : RepoObject(other) - { - } + Object::PrivatePtr ObjectPrivate::create(const RepositoryPrivate::Ptr& repo, git_object* o) + { + Q_ASSERT(o); + ObjectPrivate* op = NULL; - Object::Object() - { - } + switch (git_object_type(o)) { + case GIT_OBJ_TAG: op = new TagPrivate( repo, reinterpret_cast(o)); break; + case GIT_OBJ_COMMIT: op = new CommitPrivate(repo, reinterpret_cast(o)); break; + case GIT_OBJ_BLOB: op = new TreePrivate( repo, reinterpret_cast(o)); break; + case GIT_OBJ_TREE: op = new BlobPrivate( repo, reinterpret_cast(o)); break; + default: break; + } - Object::~Object() - { - } + return Object::PrivatePtr(op); + } - Object& Object::operator=( const Object& other ) - { - RepoObject::operator =(other); - return * this; } - bool Object::operator==( const Object& other ) const - { - return RepoObject::operator==(other); - } + GW_PRIVATE_IMPL(Object, RepoObject) ObjectType Object::type(Result& result) const { @@ -90,71 +82,87 @@ namespace Git ObjectId Object::id(Result& result) const { - GW_CD_CHECKED(Object, ObjectId(), result) + return id(); + } - const git_oid* oid = git_object_id( d->mObj ); - return ObjectId::fromRaw( oid->id ); + ObjectId Object::id() const + { + GW_CD(Object); + if (!d) { + return ObjectId(); + } + + return Private::oid2sha(git_object_id(d->mObj)); } - ObjectTree Object::asTree( Result& result ) + Tree Object::asTree() const { - ObjectTree o; - if (isTree(result)) { - GW_D(Object); - o = ObjectTree(*d); + Tree o; + if (isTree()) { + GW_CD_EX(Tree); + o = Tree(d); } return o; } - ObjectCommit Object::asCommit(Result& result) + Commit Object::asCommit() const { - ObjectCommit o; - if (isCommit(result)) { - GW_D(Object); - o = ObjectCommit(*d); + Commit o; + if (isCommit()) { + GW_CD_EX(Commit); + o = Commit(d); } return o; } - ObjectBlob Object::asBlob(Result& result) + Blob Object::asBlob() const { - ObjectBlob o; - if (isBlob(result)) { - GW_D(Object); - o = ObjectBlob(*d); + Blob o; + if (isBlob()) { + GW_CD_EX(Blob); + o = Blob(d); } return o; } - ObjectTag Object::asTag(Result& result) + Tag Object::asTag() const { - ObjectTag o; - if (isTag(result)) { - GW_D(Object); - o = ObjectTag(*d); + Tag o; + if (isTag()) { + GW_CD_EX(Tag); + o = Tag(d); } return o; } - bool Object::isTree(Result& result) const + bool Object::isTree() const { - return type(result) == otTree; + GW_CD(Object); + return d && d->objectType() == otTree; } - bool Object::isTag(Result& result) const + bool Object::isTag() const { - return type(result) == otTag; + GW_CD(Object); + return d && d->objectType() == otTag; } - bool Object::isCommit(Result& result) const + bool Object::isCommit() const { - return type(result) == otCommit; + GW_CD(Object); + return d && d->objectType() == otCommit; } - bool Object::isBlob(Result& result) const + bool Object::isBlob() const { - return type(result) == otBlob; + GW_CD(Object); + return d && d->objectType() == otBlob; } + Tree Object::asTree (Result& result) const { return asTree(); } + Commit Object::asCommit(Result& result) const { return asCommit(); } + Blob Object::asBlob (Result& result) const { return asBlob(); } + Tag Object::asTag (Result& result) const { return asTag(); } + } diff --git a/libGitWrap/Object.hpp b/libGitWrap/Object.hpp index 72d7e41..b07d9da 100644 --- a/libGitWrap/Object.hpp +++ b/libGitWrap/Object.hpp @@ -37,18 +37,9 @@ namespace Git */ class GITWRAP_API Object : public RepoObject { - public: - typedef Internal::ObjectPrivate Private; - - public: - Object(Internal::ObjectPrivate& _d); - Object(const Object& other); - Object(); - ~Object(); + GW_PRIVATE_DECL(Object, RepoObject, public); public: - Object& operator=( const Object& other ); - bool operator==( const Object& other ) const; /** * @return the object's type @@ -58,67 +49,88 @@ namespace Git /** * @return the object's id (OID) */ - ObjectId id( Result& result ) const; + ObjectId id() const; + + GW_DEPRECATED ObjectId id( Result& result ) const; /** * @brief Converts a generic object into a Git tree object. * - * @return the valid or invalid converted ObjectTree + * @return the valid or invalid converted Tree * * @see isValid() */ - ObjectTree asTree( Result& result ); + Tree asTree() const; /** * @brief Converts a generic object into a Git commit object. * - * @return the valid or invalid converted ObjectCommit + * @return the valid or invalid converted Commit * * @see isValid() */ - ObjectCommit asCommit( Result& result ); + Commit asCommit() const; /** * @brief Converts a generic object into a Git BLOB object. * - * @return the valid or invalid converted ObjectBlob + * @return the valid or invalid converted Blob * * @see isValid() */ - ObjectBlob asBlob( Result& result ); + Blob asBlob() const; /** * @brief Converts a generic object into a Git tag object. * - * @return the valid or invalid converted ObjectTag + * @return the valid or invalid converted Tag * * @see isValid() */ - ObjectTag asTag( Result& result ); + Tag asTag() const; + + // This method has no general implementation. There are four implementations that are all + // located in the reimplementation headers of this class (i.e. Tag.hpp) + template< class T > + T as() const; /** - * @brief Checks, if this is a ObjectTree object. + * @brief Checks, if this is a Tree object. * @return true or false */ - bool isTree( Result& result ) const; + bool isTree() const; /** - * @brief Checks, if this is a ObjectTree object. + * @brief Checks, if this is a Tag object. * @return true or false */ - bool isTag( Result& result ) const; + bool isTag() const; /** - * @brief Checks, if this is a ObjectTree object. + * @brief Checks, if this is a Commit object. * @return true or false */ - bool isCommit( Result& result ) const; + bool isCommit() const; /** - * @brief Checks, if this is a ObjectTree object. + * @brief Checks, if this is a Blob object. * @return true or false */ - bool isBlob( Result& result ) const; + bool isBlob() const; + + GW_DEPRECATED bool isTree (Result& result) const { return isTree(); } + GW_DEPRECATED bool isTag (Result& result) const { return isTag(); } + GW_DEPRECATED bool isCommit (Result& result) const { return isCommit(); } + GW_DEPRECATED bool isBlob (Result& result) const { return isBlob(); } + + GW_DEPRECATED Tree asTree (Result& result) const; + GW_DEPRECATED Commit asCommit(Result& result) const; + GW_DEPRECATED Blob asBlob (Result& result) const; + GW_DEPRECATED Tag asTag (Result& result) const; + + template< class T > + GW_DEPRECATED T as(Result& result) const { return as(); } + }; } diff --git a/libGitWrap/ObjectBlob.hpp b/libGitWrap/ObjectBlob.hpp index 95297e8..d869d5d 100644 --- a/libGitWrap/ObjectBlob.hpp +++ b/libGitWrap/ObjectBlob.hpp @@ -1,44 +1,6 @@ -/* - * MacGitver - * Copyright (C) 2012-2013 Sascha Cunz - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License (Version 2) as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if - * not, see . - * - */ - -#ifndef GIT_OBJECT_BLOB_H -#define GIT_OBJECT_BLOB_H - -#include "GitWrap.hpp" -#include "ObjectId.hpp" -#include "Object.hpp" +#include "libGitWrap/Blob.hpp" namespace Git { - - /** - * @ingroup GitWrap - * @brief Provides access to git BLOB (Binary Large Object) objects - * - */ - class GITWRAP_API ObjectBlob : public Object - { - public: - ObjectBlob(); - ObjectBlob(Internal::ObjectPrivate& _d); - ObjectBlob(const ObjectBlob& o); - }; - + typedef GW_DEPRECATED Blob ObjectBlob; } - -Q_DECLARE_METATYPE( Git::ObjectBlob ) - -#endif diff --git a/libGitWrap/ObjectCommit.cpp b/libGitWrap/ObjectCommit.cpp deleted file mode 100644 index d449ae8..0000000 --- a/libGitWrap/ObjectCommit.cpp +++ /dev/null @@ -1,347 +0,0 @@ -/* - * MacGitver - * Copyright (C) 2012-2013 Sascha Cunz - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License (Version 2) as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if - * not, see . - * - */ - -#include "ObjectCommit.hpp" -#include "ObjectTree.hpp" -#include "Reference.hpp" - -#include "Private/GitWrapPrivate.hpp" -#include "Private/ObjectPrivate.hpp" -#include "Private/RepositoryPrivate.hpp" -#include "Private/ReferencePrivate.hpp" - -namespace Git -{ - - ObjectCommit::ObjectCommit() - { - } - - ObjectCommit::ObjectCommit(Internal::ObjectPrivate& _d) - : Object(_d) - { - Result r; - if( ( type( r ) != otCommit ) || !r ) - { - mData = NULL; - } - } - - ObjectCommit::ObjectCommit( const ObjectCommit& o ) - : Object( o ) - { - } - - ObjectTree ObjectCommit::tree( Result& result ) - { - GW_D_CHECKED(Object, ObjectTree(), result) - - git_commit* commit = (git_commit*) d->mObj; - git_tree* tree = 0; - - result = git_commit_tree( &tree, commit ); - if( !result ) - { - return ObjectTree(); - } - - return *new Internal::ObjectPrivate( d->repo(), (git_object*) tree ); - } - - ObjectId ObjectCommit::treeId( Result& result ) - { - GW_D_CHECKED(Object, ObjectId(), result) - - git_commit* commit = (git_commit*) d->mObj; - return ObjectId::fromRaw(git_commit_tree_id( commit )->id); - } - - ObjectIdList ObjectCommit::parentCommitIds( Result& result ) const - { - GW_CD_CHECKED(Object, ObjectIdList(), result) - ObjectIdList ids; - - git_commit* commit = (git_commit*) d->mObj; - - for( unsigned int i = 0; i < numParentCommits(); i++ ) - { - ObjectId id = ObjectId::fromRaw( git_commit_parent_id( commit, i )->id ); - ids.append( id ); - } - - return ids; - } - - ObjectCommit ObjectCommit::parentCommit(Result& result, unsigned int index) const - { - GW_D_CHECKED(Object, ObjectCommit(), result) - - git_commit* commit = (git_commit*) d->mObj; - git_commit* gitparent = NULL; - - result = git_commit_parent( &gitparent, commit, index ); - if( !result ) - { - return ObjectCommit(); - } - - return *new Internal::ObjectPrivate( d->repo(), (git_object*) gitparent ); - } - - ObjectId ObjectCommit::parentCommitId(Result& result, unsigned int index) const - { - GW_CD_CHECKED(Object, ObjectId(), result) - - if( numParentCommits() > index ) - { - git_commit* commit = (git_commit*) d->mObj; - - const git_oid* oid = git_commit_parent_id( commit, index ); - if( oid ) - { - return ObjectId::fromRaw( oid->id ); - } - } - - return ObjectId(); - } - - ObjectCommitList ObjectCommit::parentCommits( Result& result ) const - { - GW_CD_CHECKED(Object, ObjectCommitList(), result) - ObjectCommitList objs; - - git_commit* commit = (git_commit*) d->mObj; - - for( unsigned int i = 0; i < numParentCommits(); i++ ) - { - git_commit* parent = NULL; - - result = git_commit_parent( &parent, commit, i ); - if( !result ) - { - return ObjectCommitList(); - } - - objs.append(*new Internal::ObjectPrivate(d->repo(), (git_object*) parent)); - } - - return objs; - } - - unsigned int ObjectCommit::numParentCommits() const - { - GW_D(Object); - if (!d) { - return 0; - } - - git_commit* commit = (git_commit*) d->mObj; - return git_commit_parentcount( commit ); - } - - bool ObjectCommit::isParentOf(Result& result, const Git::ObjectCommit& child) const - { - QVector< Git::ObjectCommit > parents = child.parentCommits( result ); - - for (int i = 0; result && i < parents.count(); i++) { - if (isEqual(result, parents[i])) { - return true; - } - } - - return false; - } - - bool ObjectCommit::isChildOf(Result& result, const Git::ObjectCommit& parent) const - { - QVector< Git::ObjectCommit > children = parentCommits( result ); - - for (int i = 0; result && i < children.count(); i++) { - if (parent.isEqual(result, children[i])) { - return true; - } - } - - return false; - } - - bool ObjectCommit::isEqual(Result& result, const Git::ObjectCommit& commit) const - { - return id(result) == commit.id(result) && result; - } - - Signature ObjectCommit::author( Result& result ) const - { - GW_CD_CHECKED(Object, Signature(), result) - - git_commit* commit = (git_commit*) d->mObj; - const git_signature* sig = git_commit_author( commit ); - - return Internal::git2Signature( sig ); - } - - Signature ObjectCommit::committer( Result& result ) const - { - GW_CD_CHECKED(Object, Signature(), result) - - git_commit* commit = (git_commit*) d->mObj; - const git_signature* sig = git_commit_committer( commit ); - - return Internal::git2Signature( sig ); - } - - QString ObjectCommit::message( Result& result ) const - { - GW_CD_CHECKED(Object, QString(), result) - - git_commit* commit = (git_commit*) d->mObj; - const char* msg = git_commit_message( commit ); - int len = int( strlen( msg ) ); - - if( len && msg[ len - 1 ] == '\n' ) - { - len--; - } - - return QString::fromUtf8( msg, len ); - } - - QString ObjectCommit::shortMessage( Result& result ) const - { - GW_CD_CHECKED(Object, QString(), result) - - git_commit* commit = (git_commit*) d->mObj; - const char* msg = git_commit_message( commit ); - - int len = 0; - while( msg[ len ] && msg[ len ] != '\n' ) - { - len++; - } - - return QString::fromUtf8( msg, len ); - } - - /** - * @brief Checkout this commit. - * - * @param[in,out] result A Result object; see @ref GitWrapErrorHandling - * - * @param[in] force If @c true, files will be overwritten. If @c false (the default), - * the operation is canceled in case of any problem. - * - * @param[in] updateHEAD If @c true, ObjectCommit::updateHEAD() is called after a - * successful checkout. If @c false (the default), updateHEAD is - * not called. - * - * @param[in] paths Inclusive filters to the tree to checkout. If empty (the default), - * the whole tree is checked out. - * - */ - void ObjectCommit::checkout(Result &result, bool force, bool updateHEAD, - const QStringList &paths) const - { - GW_CD_CHECKED_VOID(Object, result) - - git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; - opts.checkout_strategy = force ? GIT_CHECKOUT_FORCE : GIT_CHECKOUT_SAFE; - if ( !paths.isEmpty() ) - { - // TODO: don't copy, just map paths here - result = git_strarray_copy( &opts.paths, Internal::StrArrayWrapper( paths ) ); - if ( !result ) return; - } - - result = git_checkout_tree( d->repo()->mRepo, d->mObj, &opts ); - if (updateHEAD) { - this->updateHEAD(result); - } - } - - Reference ObjectCommit::createBranch(Result& result, const QString& name, bool force) const - { - GW_CD_CHECKED(Object, Reference(), result) - - git_reference* ref = NULL; - result = git_branch_create( &ref, d->repo()->mRepo, name.toUtf8().constData(), - (const git_commit*) d->mObj, force ); - if( !result ) - { - return Reference(); - } - - return Reference( *new Internal::ReferencePrivate( d->repo(), ref ) ); - } - - DiffList ObjectCommit::diffFromParent(Result& result, unsigned int index) - { - GW_CD_CHECKED(Object, DiffList(), result) - - ObjectCommit parentObjCommit = parentCommit( result, index ); - ObjectTree parentObjTree = parentObjCommit.tree( result ); - - return parentObjTree.diffToTree( result, tree( result ) ); - } - - DiffList ObjectCommit::diffFromAllParents( Result& result ) - { - GW_CD_CHECKED(Object, DiffList(), result) - - if( numParentCommits() == 0 ) - { - return DiffList(); - } - - DiffList dl = diffFromParent( result, 0 ); - for( unsigned int i = 1; i < numParentCommits(); i++ ) - { - DiffList dl2 = diffFromParent( result, i ); - dl2.mergeOnto( result, dl ); - } - - return dl; - } - - /** - * @brief Set the HEAD ref to point (detached) to this commit. - * - * @param[in,out] result A Result object; see @ref GitWrapErrorHandling - * - */ - void ObjectCommit::updateHEAD(Result &result) const - { - GW_CD_CHECKED_VOID(Object, result) - - result = git_repository_set_head_detached( d->repo()->mRepo - , git_object_id( d->mObj ) ); - } - -} - -/** - * @ingroup GitWrap - * @brief Debug-Stream support of Git::ObjectCommit - * @param[in] debug The Debug-Stream to output into - * @param[in] commit The commit object to output - * @return The Debug-Stream - */ -QDebug operator<<( QDebug debug, const Git::ObjectCommit& commit ) -{ - Git::Result r; - return debug << "Commit(id=" << commit.id( r ) << ";author=" << commit.author( r ) << ")"; -} - diff --git a/libGitWrap/ObjectCommit.hpp b/libGitWrap/ObjectCommit.hpp index b2c1a48..e13c8fb 100644 --- a/libGitWrap/ObjectCommit.hpp +++ b/libGitWrap/ObjectCommit.hpp @@ -1,101 +1,6 @@ -/* - * MacGitver - * Copyright (C) 2012-2013 Sascha Cunz - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License (Version 2) as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if - * not, see . - * - */ - -#ifndef GIT_OBJECT_COMMIT_H -#define GIT_OBJECT_COMMIT_H - -#include "libGitWrap/GitWrap.hpp" -#include "libGitWrap/ObjectId.hpp" -#include "libGitWrap/Object.hpp" -#include "libGitWrap/Signature.hpp" -#include "libGitWrap/DiffList.hpp" -#include "libGitWrap/Result.hpp" +#include "libGitWrap/Commit.hpp" namespace Git { - - /** - * @ingroup GitWrap - * @brief Represents a git commit object. - * - */ - class GITWRAP_API ObjectCommit : public Object - { - public: - ObjectCommit(); - ObjectCommit(Internal::ObjectPrivate& _d); - ObjectCommit(const ObjectCommit& o); - - public: - bool operator==( const Git::ObjectCommit& commit ) const - { - Result r; - return isEqual( r, commit ) && r; - } - - bool operator!=( const Git::ObjectCommit& commit ) const - { - Result r; - return !isEqual( r, commit ) && r; - } - - public: - ObjectTree tree( Result& result ); - ObjectId treeId( Result& result ); - - ObjectIdList parentCommitIds( Result& result ) const; - ObjectCommitList parentCommits( Result& result ) const; - ObjectCommit parentCommit( Result& result, unsigned int index ) const; - ObjectId parentCommitId( Result& result, unsigned int index ) const; - unsigned int numParentCommits() const; - - bool isParentOf( Result& result, const Git::ObjectCommit& child ) const; - bool isChildOf( Result& result, const Git::ObjectCommit& parent ) const; - bool isEqual( Result& result, const Git::ObjectCommit& commit ) const; - - Signature author( Result& result ) const; - Signature committer( Result& result ) const; - - QString message( Result& result ) const; - QString shortMessage( Result& result ) const; - - void checkout( Result &result, - bool force = false, - bool updateHEAD = true, - const QStringList &paths = QStringList() ) const; - Reference createBranch( Result& result, const QString& name, bool force ) const; - - DiffList diffFromParent( Result& result, unsigned int index ); - DiffList diffFromAllParents( Result& result ); - - void updateHEAD(Result &result) const; - }; - - /** - * @ingroup GitWrap - * @brief qHash() for Git::ObjectCommit - */ - inline uint qHash( const ObjectCommit& c ) - { - Result r; - return qHash( c.id( r ) ); - } - + typedef GW_DEPRECATED Commit ObjectCommit; } - -GITWRAP_API QDebug operator<<( QDebug debug, const Git::ObjectCommit& commit ); - -#endif diff --git a/libGitWrap/ObjectId.cpp b/libGitWrap/ObjectId.cpp index 1019791..263230e 100644 --- a/libGitWrap/ObjectId.cpp +++ b/libGitWrap/ObjectId.cpp @@ -14,9 +14,9 @@ * */ -#include "ObjectId.hpp" +#include "libGitWrap/ObjectId.hpp" -#include "Private/GitWrapPrivate.hpp" +#include "libGitWrap/Private/GitWrapPrivate.hpp" namespace Git { diff --git a/libGitWrap/ObjectId.hpp b/libGitWrap/ObjectId.hpp index f0f9ea0..d8c2102 100644 --- a/libGitWrap/ObjectId.hpp +++ b/libGitWrap/ObjectId.hpp @@ -17,7 +17,7 @@ #ifndef GIT_OBJECT_ID_H #define GIT_OBJECT_ID_H -#include "GitWrap.hpp" +#include "libGitWrap/GitWrap.hpp" namespace Git { diff --git a/libGitWrap/ObjectTag.hpp b/libGitWrap/ObjectTag.hpp index 498a2f9..50cb90c 100644 --- a/libGitWrap/ObjectTag.hpp +++ b/libGitWrap/ObjectTag.hpp @@ -1,44 +1,6 @@ -/* - * MacGitver - * Copyright (C) 2012-2013 Sascha Cunz - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License (Version 2) as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if - * not, see . - * - */ - -#ifndef GIT_OBJECT_TAG_H -#define GIT_OBJECT_TAG_H - -#include "GitWrap.hpp" -#include "ObjectId.hpp" -#include "Object.hpp" +#include "libGitWrap/Tag.hpp" namespace Git { - - /** - * @ingroup GitWrap - * @brief Represents a git tag reference. - * - */ - class GITWRAP_API ObjectTag : public Object - { - public: - ObjectTag(); - ObjectTag(Internal::ObjectPrivate& _d); - ObjectTag(const ObjectTag& o); - }; - + typedef GW_DEPRECATED Tag ObjectTag; } - -Q_DECLARE_METATYPE( Git::ObjectTag ) - -#endif diff --git a/libGitWrap/ObjectTree.cpp b/libGitWrap/ObjectTree.cpp deleted file mode 100644 index f3922b1..0000000 --- a/libGitWrap/ObjectTree.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* - * MacGitver - * Copyright (C) 2012-2013 Sascha Cunz - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License (Version 2) as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if - * not, see . - * - */ - -#include "DiffList.hpp" -#include "ObjectTree.hpp" - -#include "Private/GitWrapPrivate.hpp" -#include "Private/DiffListPrivate.hpp" -#include "Private/ObjectPrivate.hpp" -#include "Private/RepositoryPrivate.hpp" -#include "Private/TreeEntryPrivate.hpp" - -namespace Git -{ - - ObjectTree::ObjectTree() - { - } - - ObjectTree::ObjectTree(Internal::ObjectPrivate& _d) - : Object( _d ) - { - Result r; - if( ( type( r ) != otTree ) || !r ) - { - mData = NULL; - } - } - - ObjectTree::ObjectTree( const ObjectTree& o ) - : Object( o ) - { - } - - ObjectTree ObjectTree::subPath(Result& result , const QString& pathName) const - { - GW_CD_CHECKED(Object, ObjectTree(), result) - - git_tree* d2 = (git_tree*) d->mObj; - - const git_tree_entry* entry = git_tree_entry_byname( d2, pathName.toUtf8().constData() ); - if( !entry ) - { - return ObjectTree(); - } - - git_object* subObject = 0; - result = git_tree_entry_to_object( &subObject, d->repo()->mRepo, entry ); - if( !result ) - { - return ObjectTree(); - } - - if( git_object_type( subObject ) != GIT_OBJ_TREE ) - { - git_object_free( subObject ); - return ObjectTree(); - } - - return *new Internal::ObjectPrivate( d->repo(), subObject ); - } - - DiffList ObjectTree::diffToTree(Result& result , ObjectTree newTree) - { - GW_CD_CHECKED(Object, DiffList(), result) - - git_tree* gitTree = (git_tree*) d->mObj; - Object::Private* op = Base::Private::dataOf(newTree); - git_tree* gitNewTree = (git_tree*) op->mObj; - - git_diff_list* diffList = NULL; - result = git_diff_tree_to_tree( &diffList, d->repo()->mRepo, gitTree, gitNewTree, NULL ); - if( !result ) - { - return DiffList(); - } - - return DiffList(*new Internal::DiffListPrivate(d->repo(), diffList)); - } - - DiffList ObjectTree::diffToIndex( Result& result ) - { - GW_CD_CHECKED(Object, DiffList(), result) - - git_tree* gitTree = (git_tree*) d->mObj; - - git_diff_list* diffList = NULL; - - result = git_diff_tree_to_index( &diffList, d->repo()->mRepo, gitTree, NULL, NULL ); - if( !result ) - { - return DiffList(); - } - - return DiffList(*new Internal::DiffListPrivate(d->repo(), diffList)); - } - - DiffList ObjectTree::diffToWorkingDir( Result& result ) - { - GW_CD_CHECKED(Object, DiffList(), result) - - git_tree* gitTree = (git_tree*) d->mObj; - - git_diff_list* diffList = NULL; - result = git_diff_tree_to_workdir( &diffList, d->repo()->mRepo, gitTree, NULL ); - if( !result ) - { - return DiffList(); - } - - return DiffList(*new Internal::DiffListPrivate(d->repo(), diffList)); - } - - size_t ObjectTree::entryCount() const - { - GW_D(Object); - - if(!d) { - return 0; - } - - git_tree* gitTree = (git_tree*) d->mObj; - return git_tree_entrycount( gitTree ); - } - - TreeEntry ObjectTree::entryAt( size_t index ) const - { - GW_D(Object); - - if(!d) { - return TreeEntry(); - } - - git_tree* gitTree = (git_tree*) d->mObj; - - const git_tree_entry* entry = git_tree_entry_byindex( gitTree, index ); - return *new Internal::TreeEntryPrivate( entry ); - } - - TreeEntry ObjectTree::entry( const QString& fileName ) const - { - GW_D(Object); - - if(!d) { - return TreeEntry(); - } - - git_tree* gitTree = (git_tree*) d->mObj; - - const git_tree_entry* entry = git_tree_entry_byname( gitTree, - fileName.toUtf8().constData() ); - return *new Internal::TreeEntryPrivate( entry ); - } - -} diff --git a/libGitWrap/ObjectTree.hpp b/libGitWrap/ObjectTree.hpp index fb2551a..61b26e0 100644 --- a/libGitWrap/ObjectTree.hpp +++ b/libGitWrap/ObjectTree.hpp @@ -1,67 +1,6 @@ -/* - * MacGitver - * Copyright (C) 2012-2013 Sascha Cunz - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License (Version 2) as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; if - * not, see . - * - */ - -#ifndef GIT_OBJECT_TREE_H -#define GIT_OBJECT_TREE_H - -#include "GitWrap.hpp" -#include "ObjectId.hpp" -#include "Object.hpp" -#include "TreeEntry.hpp" +#include "libGitWrap/Tree.hpp" namespace Git { - - /** - * @ingroup GitWrap - * @brief Represents a git tree object - * - */ - class GITWRAP_API ObjectTree : public Object - { - public: - ObjectTree(); - ObjectTree(Internal::ObjectPrivate& _d); - ObjectTree(const ObjectTree& o); - - public: - ObjectTree subPath( Result& result, const QString& pathName ) const; - - DiffList diffToTree( Result& result, ObjectTree newTree ); - DiffList diffToIndex( Result& result ); - DiffList diffToWorkingDir( Result& result ); - - size_t entryCount() const; - TreeEntry entryAt( size_t index ) const; - TreeEntry entry( const QString& fileName ) const; - - public: - inline TreeEntry operator[]( size_t index ) const - { - return entryAt( index ); - } - - inline TreeEntry operator[]( const QString& fileName ) const - { - return entry( fileName ); - } - }; - + typedef GW_DEPRECATED Tree ObjectTree; } - -Q_DECLARE_METATYPE( Git::ObjectTree ) - -#endif diff --git a/libGitWrap/Operations/BaseOperation.cpp b/libGitWrap/Operations/BaseOperation.cpp new file mode 100644 index 0000000..1a74d46 --- /dev/null +++ b/libGitWrap/Operations/BaseOperation.cpp @@ -0,0 +1,95 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 Sascha Cunz + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#include "libGitWrap/Operations/BaseOperation.hpp" + +#include "libGitWrap/Operations/Private/BaseOperationPrivate.hpp" + +namespace Git +{ + + namespace Internal + { + + BaseOperationPrivate::BaseOperationPrivate(BaseOperation* owner) + : mOwner( owner ) + { + mBackgroundMode = false; + mThread = NULL; + } + + BaseOperationPrivate::~BaseOperationPrivate() + { + } + + } + + BaseOperation::BaseOperation(Private& _d, QObject* parent) + : mData(&_d) + { + } + + BaseOperation::~BaseOperation() + { + } + + void BaseOperation::setBackgroundMode( bool backgroundMode ) + { + mData->mBackgroundMode = backgroundMode; + } + + bool BaseOperation::backgroundMode() const + { + return mData->mBackgroundMode; + } + + Result BaseOperation::execute() + { + if (mData->mBackgroundMode) { + Q_ASSERT(!mData->mThread); + + mData->mThread = new Internal::WorkerThread(this, mData); + + connect(mData->mThread, SIGNAL(finished()), this, SLOT(workerFinished())); + + mData->mThread->start(); + return Result(); + } + else + { + mData->run(); + return mData->mResult; + } + } + + bool BaseOperation::isRunning() const + { + return mData->mThread; + } + + void BaseOperation::workerFinished() + { + delete mData->mThread; + mData->mThread = NULL; + emit finished(); + } + + Result BaseOperation::result() const + { + return mData->mResult; + } + +} diff --git a/libGitWrap/Operations/BaseOperation.hpp b/libGitWrap/Operations/BaseOperation.hpp new file mode 100644 index 0000000..50d22c6 --- /dev/null +++ b/libGitWrap/Operations/BaseOperation.hpp @@ -0,0 +1,77 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 Sascha Cunz + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GITWRAP_BASE_OPERATION_HPP +#define GITWRAP_BASE_OPERATION_HPP + +#include + +#include "libGitWrap/GitWrap.hpp" + +namespace Git +{ + + class Result; + + namespace Internal + { + + class BaseOperationPrivate; + } + + class GITWRAP_API BaseOperation : public QObject + { + Q_OBJECT + public: + typedef Internal::BaseOperationPrivate Private; + + public: + BaseOperation(Private& _d, QObject* parent = 0); + ~BaseOperation(); + + public: + Result execute(); + + public slots: + void setBackgroundMode(bool backgroundMode); + + public: + bool backgroundMode() const; + bool isRunning() const; + Result result() const; + + signals: + void finished(); + + private slots: + void workerFinished(); + + protected: + QExplicitlySharedDataPointer mData; + + protected: + inline void ensureThisIsNotConst() + { + // This method is invoked from the GW_D macro. Its only purpose is to error out at + // compile time, if we casted from a const outer object. This is actually neccessary + // because QExplicitlySharedDataPointer seems to give a shit about const + // correctness. + } + }; + +} + +#endif diff --git a/libGitWrap/Operations/CheckoutOperation.cpp b/libGitWrap/Operations/CheckoutOperation.cpp new file mode 100644 index 0000000..010f2e6 --- /dev/null +++ b/libGitWrap/Operations/CheckoutOperation.cpp @@ -0,0 +1,508 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 Sascha Cunz + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#include "libGitWrap/Repository.hpp" +#include "libGitWrap/Index.hpp" + +#include "libGitWrap/Private/TreePrivate.hpp" +#include "libGitWrap/Private/RepositoryPrivate.hpp" +#include "libGitWrap/Private/IndexPrivate.hpp" + +#include "libGitWrap/Operations/CheckoutOperation.hpp" + +#include "libGitWrap/Operations/Private/CheckoutOperationPrivate.hpp" + +namespace Git +{ + + namespace Internal + { + + static void checkoutProgress(const char* path, size_t completed_steps, size_t total_steps, + void* payload) + { + CheckoutBaseOperationPrivate* d = + reinterpret_cast(payload); + Q_ASSERT(d); + + QString pathName = QString::fromUtf8(path); + + d->emitProgress(pathName, completed_steps, total_steps); + } + + static int checkoutNotify(git_checkout_notify_t why, const char* path, + const git_diff_file* baseline, const git_diff_file* target, + const git_diff_file* workdir, void* payload) + { + CheckoutBaseOperationPrivate* d = + reinterpret_cast(payload); + Q_ASSERT(d); + + d->emitFile(why, path, baseline, target, workdir); + + return d->mCancel ? -1 : 0; + } + + // -- CheckoutBaseOperationPrivate ------------------------------------------------------ >8 + + CheckoutBaseOperationPrivate::CheckoutBaseOperationPrivate(CheckoutBaseOperation* owner) + : BaseOperationPrivate(owner) + , mMode(CheckoutDryRun) + { + } + + CheckoutBaseOperationPrivate::~CheckoutBaseOperationPrivate() + { + } + + void CheckoutBaseOperationPrivate::emitProgress(const QString& pathName, quint32 completed, + quint32 total) + { + GW_OP_OWNER(CheckoutBaseOperation); + owner->progress(owner, pathName, completed, total); + } + + + void CheckoutBaseOperationPrivate::emitFile(git_checkout_notify_t why, const char *path, + const git_diff_file *baseline, + const git_diff_file *target, + const git_diff_file *workdir) + { + GW_OP_OWNER(CheckoutBaseOperation); + QString pathName = QString::fromUtf8(path); + + FileInfo fiBaseLine = mkFileInfo(baseline); + FileInfo fiTarget = mkFileInfo(target); + FileInfo fiWorkDir = mkFileInfo(workdir); + + switch (why) { + case GIT_CHECKOUT_NOTIFY_CONFLICT: + owner->conflict(owner, pathName, fiBaseLine, fiTarget, fiWorkDir); + break; + + case GIT_CHECKOUT_NOTIFY_DIRTY: + owner->dirty(owner, pathName, fiBaseLine, fiTarget, fiWorkDir); + break; + + case GIT_CHECKOUT_NOTIFY_UPDATED: + owner->updated(owner, pathName, fiBaseLine, fiTarget, fiWorkDir); + break; + + case GIT_CHECKOUT_NOTIFY_UNTRACKED: + owner->untracked(owner, pathName, fiBaseLine, fiTarget, fiWorkDir); + break; + + case GIT_CHECKOUT_NOTIFY_IGNORED: + owner->ignored(owner, pathName, fiBaseLine, fiTarget, fiWorkDir); + break; + + default: + break; + } + } + + void CheckoutBaseOperationPrivate::prepare() + { + git_checkout_opts o = GIT_CHECKOUT_OPTS_INIT; + memcpy(&mOpts, &o, sizeof(o)); + + if (mPaths.count()) { + mOpts.paths.count = mPaths.count(); + mOpts.paths.strings = new char *[mOpts.paths.count]; + for (int i=0; i < mPaths.count(); ++i) { + mOpts.paths.strings[i] = mPaths[i].toUtf8().data(); + } + } + + if (!mPath.isEmpty()) { + mOpts.target_directory = mPath.toUtf8().constData(); + } + + switch (mMode) { + default: + case CheckoutDryRun: /* this is the default */ break; + case CheckoutSafe: mOpts.checkout_strategy |= GIT_CHECKOUT_SAFE; break; + case CheckoutSafeCreate: mOpts.checkout_strategy |= GIT_CHECKOUT_SAFE_CREATE; break; + case CheckoutForce: mOpts.checkout_strategy |= GIT_CHECKOUT_FORCE; break; + } + + static const int flags[] = { + CheckoutAllowConflicts, GIT_CHECKOUT_ALLOW_CONFLICTS, + CheckoutRemoveUntracked, GIT_CHECKOUT_REMOVE_UNTRACKED, + CheckoutRemoveIgnored, GIT_CHECKOUT_REMOVE_IGNORED, + CheckoutNoRefresh, GIT_CHECKOUT_NO_REFRESH, + CheckoutUpdateOnly, GIT_CHECKOUT_UPDATE_ONLY, + CheckoutDontUpdateIndex, GIT_CHECKOUT_DONT_UPDATE_INDEX, + CheckoutDisablePathSpecMatch, GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH, + CheckoutSkipLockedDirectories, GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES, + CheckoutNone + }; + + int i = 0; + while (flags[i] != CheckoutNone) { + if (mOptions.testFlag(CheckoutOption(flags[i++]))) { + mOpts.checkout_strategy |= flags[i]; + } + i++; + } + + if (mBaseline.isValid()) { + TreePrivate* tp = BasePrivate::dataOf(mBaseline); + mOpts.baseline = tp->o(); + } + + mOpts.progress_payload = this; + mOpts.progress_cb = &checkoutProgress; + mOpts.notify_payload = this; + mOpts.notify_cb = &checkoutNotify; + mOpts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL; + } + + void CheckoutBaseOperationPrivate::unprepare() + { + delete[] mOpts.paths.strings; + } + + // -- CheckoutIndexOperationPrivate ----------------------------------------------------- >8 + + CheckoutIndexOperationPrivate::CheckoutIndexOperationPrivate(CheckoutIndexOperation *owner) + : CheckoutBaseOperationPrivate(owner) + { + } + + void CheckoutIndexOperationPrivate::run() + { + git_repository* grepo = NULL; + git_index* gindex = NULL; + + prepare(); + + if (mRepository.isValid()) { + Repository::Private* rp = BasePrivate::dataOf(mRepository); + grepo = rp->mRepo; + } + + if (mIndex.isValid()) { + Index::Private* ip = BasePrivate::dataOf(mIndex); + gindex = ip->index; + } + + mResult = git_checkout_index(grepo, gindex, &mOpts); + + unprepare(); + } + + // -- CheckoutTreeOperationPrivate ------------------------------------------------------ >8 + + CheckoutTreeOperationPrivate::CheckoutTreeOperationPrivate(CheckoutTreeOperation *owner) + : CheckoutBaseOperationPrivate(owner) + { + } + + void CheckoutTreeOperationPrivate::run() + { + git_repository* grepo = NULL; + const git_object* gtree = NULL; + + prepare(); + + if (mRepository.isValid()) { + Repository::Private* rp = BasePrivate::dataOf(mRepository); + grepo = rp->mRepo; + } + + if (mTree.isValid()) { + Tree::Private* tp = BasePrivate::dataOf(mTree); + gtree = tp->mObj; + } + + if (gtree) { + mResult = git_checkout_tree(grepo, gtree, &mOpts); + } + else { + mResult = git_checkout_head(grepo, &mOpts); + } + + unprepare(); + } + + // -- CheckoutBranchOperationPrivate ---------------------------------------------------- >8 + + CheckoutBranchOperationPrivate::CheckoutBranchOperationPrivate( + CheckoutBranchOperation *owner) + : CheckoutBaseOperationPrivate(owner) + { + } + + void CheckoutBranchOperationPrivate::run() + { + git_repository* grepo = NULL; + const git_object* gtree = NULL; + + prepare(); + + if (mRepository.isValid()) { + Repository::Private* rp = BasePrivate::dataOf(mRepository); + grepo = rp->mRepo; + } + + /* + if (mTree.isValid()) { + Tree::Private* tp = BasePrivate::dataOf(mTree); + gtree = tp->mObj; + } + + if (gtree) { + mResult = git_checkout_tree(grepo, gtree, &mOpts); + } + else { + mResult = git_checkout_head(grepo, &mOpts); + } + */ + + unprepare(); + } + + } + + // -- CheckoutBaseOperation ----------------------------------------------------------------- >8 + + CheckoutBaseOperation::CheckoutBaseOperation(Private& _d, QObject* parent) + : BaseOperation(_d, parent) + { + } + + CheckoutBaseOperation::~CheckoutBaseOperation() + { + } + + void CheckoutBaseOperation::setRepository(const Repository& repo) + { + GW_D(CheckoutBaseOperation); + Q_ASSERT(!isRunning()); + d->mRepository = repo; + } + + void CheckoutBaseOperation::setMode(CheckoutMode mode) + { + GW_D(CheckoutBaseOperation); + Q_ASSERT(!isRunning()); + d->mMode = mode; + } + + void CheckoutBaseOperation::setOptions(CheckoutOptions opts) + { + GW_D(CheckoutBaseOperation); + Q_ASSERT(!isRunning()); + d->mOptions = opts; + } + + void CheckoutBaseOperation::setTargetDirectory(const QString& path) + { + GW_D(CheckoutBaseOperation); + Q_ASSERT(!isRunning()); + d->mPath = path; + } + + void CheckoutBaseOperation::setCheckoutPaths(const QStringList& paths) + { + GW_D(CheckoutBaseOperation); + Q_ASSERT(!isRunning()); + d->mPaths = paths; + } + + void CheckoutBaseOperation::setBaseline(const Tree& baseline) + { + GW_D(CheckoutBaseOperation); + Q_ASSERT(!isRunning()); + d->mBaseline = baseline; + } + + Repository CheckoutBaseOperation::repository() const + { + GW_CD(CheckoutBaseOperation); + return d->mRepository; + } + + CheckoutMode CheckoutBaseOperation::mode() const + { + GW_CD(CheckoutBaseOperation); + return d->mMode; + } + + CheckoutOptions CheckoutBaseOperation::options() const + { + GW_CD(CheckoutBaseOperation); + return d->mOptions; + } + + QString CheckoutBaseOperation::targetDirectory() const + { + GW_CD(CheckoutBaseOperation); + return d->mPath; + } + + QStringList CheckoutBaseOperation::checkoutPaths() const + { + GW_CD(CheckoutBaseOperation); + return d->mPaths; + } + + Tree CheckoutBaseOperation::baseline() const + { + GW_CD(CheckoutBaseOperation); + return d->mBaseline; + } + + void CheckoutBaseOperation::setCancel(bool cancel) + { + GW_D(CheckoutBaseOperation); + Q_ASSERT(isRunning()); + d->mCancel = cancel; + } + + // -- CheckoutIndexOperation ---------------------------------------------------------------- >8 + + CheckoutIndexOperation::CheckoutIndexOperation(QObject* parent) + : CheckoutBaseOperation(*new Private(this), parent) + { + } + + CheckoutIndexOperation::CheckoutIndexOperation(const Index& index, QObject* parent) + : CheckoutBaseOperation(*new Private(this), parent) + { + setRepository(index.repository()); + setIndex(index); + } + + CheckoutIndexOperation::CheckoutIndexOperation(const Repository& repo, QObject* parent) + : CheckoutBaseOperation(*new Private(this), parent) + { + setRepository(repo); + } + + void CheckoutIndexOperation::setIndex(const Index& index) + { + GW_D(CheckoutIndexOperation); + Q_ASSERT(!isRunning()); + d->mIndex = index; + } + + // -- CheckoutTreeOperation ----------------------------------------------------------------- >8 + + CheckoutTreeOperation::CheckoutTreeOperation(QObject* parent) + : CheckoutBaseOperation(*new Private(this), parent) + { + } + + CheckoutTreeOperation::CheckoutTreeOperation(const Tree& tree, QObject* parent) + : CheckoutBaseOperation(*new Private(this), parent) + { + setRepository(tree.repository()); + setTree(tree); + } + + CheckoutTreeOperation::CheckoutTreeOperation(const Repository& repo, QObject* parent) + : CheckoutBaseOperation(*new Private(this), parent) + { + setRepository(repo); + } + + void CheckoutTreeOperation::setTree(const Tree& tree) + { + GW_D(CheckoutTreeOperation); + Q_ASSERT(!isRunning()); + d->mTree = tree; + } + + Tree CheckoutTreeOperation::tree() const + { + GW_CD(CheckoutTreeOperation); + return d->mTree; + } + + // -- CheckoutBranchOperation --------------------------------------------------------------- >8 + + CheckoutBranchOperation::CheckoutBranchOperation(QObject* parent) + : CheckoutBaseOperation(*new Private(this), parent) + { + } + + CheckoutBranchOperation::CheckoutBranchOperation(const BranchRef& branch, QObject* parent) + : CheckoutBaseOperation(*new Private(this), parent) + { + setRepository(branch.repository()); + setBranch(branch); + } + + CheckoutBranchOperation::CheckoutBranchOperation(const Repository& repo, QObject* parent) + : CheckoutBaseOperation(*new Private(this), parent) + { + setRepository(repo); + } + + CheckoutBranchOperation::CheckoutBranchOperation(const Repository& repo, + const QString& branchName, + QObject* parent) + : CheckoutBaseOperation(*new Private(this), parent) + { + setRepository(repo); + setBranch(branchName); + } + + bool CheckoutBranchOperation::setBranch(const QString& branchName) + { + Q_ASSERT(!isRunning()); + + if (!repository().isValid()) { + return false; + } + + GW_D(CheckoutBranchOperation); + if (!d) { + return false; + } + + Result res; + d->branch = repository().branchRef(res, branchName); + return res && d->branch.isValid(); + } + + bool CheckoutBranchOperation::setBranch(const BranchRef& branch) + { + Q_ASSERT(!isRunning()); + GW_D(CheckoutBranchOperation); + + if (!d) { + return false; + } + + if (branch.repository() != repository()) { + return false; + } + + d->branch = branch; + return true; + } + + BranchRef CheckoutBranchOperation::branch() const + { + GW_CD(CheckoutBranchOperation); + return d ? d->branch : BranchRef(); + } + +} + diff --git a/libGitWrap/Operations/CheckoutOperation.hpp b/libGitWrap/Operations/CheckoutOperation.hpp new file mode 100644 index 0000000..2c0189e --- /dev/null +++ b/libGitWrap/Operations/CheckoutOperation.hpp @@ -0,0 +1,158 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 Sascha Cunz + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GITWRAP_CHECKOUT_OPERATION_HPP +#define GITWRAP_CHECKOUT_OPERATION_HPP +#pragma once + +#include "libGitWrap/Operations/BaseOperation.hpp" +#include "libGitWrap/FileInfo.hpp" // Required for moc, only + +namespace Git +{ + + class Result; + + namespace Internal + { + + class CheckoutBaseOperationPrivate; + class CheckoutIndexOperationPrivate; + class CheckoutTreeOperationPrivate; + class CheckoutBranchOperationPrivate; + + } + + class GITWRAP_API CheckoutBaseOperation : public BaseOperation + { + Q_OBJECT + #if QT_VERSION < 0x050000 + friend class Internal::CheckoutBaseOperationPrivate; + #endif + public: + typedef Internal::CheckoutBaseOperationPrivate Private; + + protected: + CheckoutBaseOperation(Private& _d, QObject* parent = 0); + public: + ~CheckoutBaseOperation(); + + public: + void setRepository(const Repository& repo); + void setMode(CheckoutMode mode); + void setOptions(CheckoutOptions opts); + void setTargetDirectory(const QString& path); + void setCheckoutPaths(const QStringList& paths); + void setBaseline(const Tree& baseline); + + void setCancel(bool cancel); + + public: + Repository repository() const; + CheckoutMode mode() const; + CheckoutOptions options() const; + QString targetDirectory() const; + QStringList checkoutPaths() const; + Tree baseline() const; + + signals: + void conflict (const CheckoutBaseOperation* opertation, + const QString& path, + const FileInfo& baseline, + const FileInfo& target, + const FileInfo& workTree); + + void dirty (const CheckoutBaseOperation* opertation, + const QString& path, + const FileInfo& baseline, + const FileInfo& target, + const FileInfo& workTree); + + void updated (const CheckoutBaseOperation* opertation, + const QString& path, + const FileInfo& baseline, + const FileInfo& target, + const FileInfo& workTree); + + void untracked (const CheckoutBaseOperation* opertation, + const QString& path, + const FileInfo& baseline, + const FileInfo& target, + const FileInfo& workTree); + + void ignored (const CheckoutBaseOperation* opertation, + const QString& path, + const FileInfo& baseline, + const FileInfo& target, + const FileInfo& workTree); + + void progress (const CheckoutBaseOperation* opertation, + const QString& path, + quint32 completedSteps, + quint32 totalSteps); + }; + + class CheckoutIndexOperation : public CheckoutBaseOperation + { + public: + typedef Internal::CheckoutIndexOperationPrivate Private; + + public: + CheckoutIndexOperation(QObject* parent = 0); + CheckoutIndexOperation(const Repository& repo, QObject* parent = 0); + CheckoutIndexOperation(const Index& index, QObject* parent = 0); + + public: + void setIndex(const Index& index); + Index index() const; + }; + + class CheckoutTreeOperation : public CheckoutBaseOperation + { + public: + typedef Internal::CheckoutTreeOperationPrivate Private; + + public: + CheckoutTreeOperation(QObject* parent = 0); + CheckoutTreeOperation(const Repository& repo, QObject* parent = 0); + CheckoutTreeOperation(const Tree& tree, QObject* parent = 0); + + public: + void setTree(const Tree& tree); + Tree tree() const; + }; + + class CheckoutBranchOperation : public CheckoutBaseOperation + { + public: + typedef Internal::CheckoutBranchOperationPrivate Private; + + public: + CheckoutBranchOperation(QObject* parent = 0); + CheckoutBranchOperation(const BranchRef& branch, QObject* parent = 0); + CheckoutBranchOperation(const Repository& repo, QObject* parent = 0); + CheckoutBranchOperation(const Repository& repo, const QString& branchName, + QObject* parent = 0); + + public: + bool setBranch(const QString& branchName); + bool setBranch(const BranchRef& branch); + BranchRef branch() const; + }; + +} + +#endif diff --git a/libGitWrap/CloneOperation.cpp b/libGitWrap/Operations/CloneOperation.cpp similarity index 59% rename from libGitWrap/CloneOperation.cpp rename to libGitWrap/Operations/CloneOperation.cpp index fe5975c..c4e4bb9 100644 --- a/libGitWrap/CloneOperation.cpp +++ b/libGitWrap/Operations/CloneOperation.cpp @@ -14,10 +14,10 @@ * */ -#include "CloneOperation.hpp" +#include "libGitWrap/Operations/CloneOperation.hpp" -#include "Private/CloneOperationPrivate.hpp" -#include "Private/FetchCallbacks.hpp" +#include "libGitWrap/Operations/Private/CloneOperationPrivate.hpp" +#include "libGitWrap/Operations/Private/FetchCallbacks.hpp" namespace Git { @@ -25,29 +25,26 @@ namespace Git namespace Internal { - CloneOperationPrivate::CloneOperationPrivate( CloneOperation* owner ) - : mOwner( owner ) + CloneOperationPrivate::CloneOperationPrivate(CloneOperation* owner) + : BaseOperationPrivate(owner) { - mBackgroundMode = false; - mThread = NULL; - git_clone_options opts = GIT_CLONE_OPTIONS_INIT; - memcpy( &mGitCloneOptions, &opts, sizeof( opts ) ); + memcpy(&mGitCloneOptions, &opts, sizeof(opts)); git_remote_callbacks rcb = GIT_REMOTE_CALLBACKS_INIT; - memcpy( &mRemoteCallbacks, &rcb, sizeof( rcb ) ); + memcpy(&mRemoteCallbacks, &rcb, sizeof(rcb)); mRemoteCallbacks.completion = &FetchCallbacks::remoteComplete; mRemoteCallbacks.progress = &FetchCallbacks::remoteProgress; mRemoteCallbacks.update_tips = &FetchCallbacks::remoteUpdateTips; - mRemoteCallbacks.payload = static_cast< IFetchEvents* >( mOwner ); + mRemoteCallbacks.payload = static_cast< IFetchEvents* >(owner); mGitCloneOptions.remote_callbacks = &mRemoteCallbacks; mGitCloneOptions.fetch_progress_cb = &FetchCallbacks::fetchProgress; - mGitCloneOptions.fetch_progress_payload = static_cast< IFetchEvents* >( mOwner ); + mGitCloneOptions.fetch_progress_payload = static_cast< IFetchEvents* >(owner); mGitCloneOptions.cred_acquire_cb = &FetchCallbacks::credAccquire; - mGitCloneOptions.cred_acquire_payload = static_cast< IFetchEvents* >( mOwner ); + mGitCloneOptions.cred_acquire_payload = static_cast< IFetchEvents* >(owner); } CloneOperationPrivate::~CloneOperationPrivate() @@ -57,147 +54,128 @@ namespace Git void CloneOperationPrivate::run() { git_repository* repo = NULL; - mResult = git_clone( &repo, - mUrl.toUtf8().constData(), - mPath.toUtf8().constData(), - &mGitCloneOptions ); + mResult = git_clone(&repo, + mUrl.toUtf8().constData(), + mPath.toUtf8().constData(), + &mGitCloneOptions ); - if( mResult && repo ) - { + if(mResult && repo) { git_repository_free( repo ); } } } - CloneOperation::CloneOperation( QObject* parent ) - : QObject( parent ) + CloneOperation::CloneOperation(QObject* parent) + : BaseOperation(*new Private(this), parent) { - d = new Internal::CloneOperationPrivate( this ); } CloneOperation::~CloneOperation() { - delete d; } - void CloneOperation::setUrl( const QString& url ) + void CloneOperation::setUrl(const QString& url) { + GW_D(CloneOperation); + Q_ASSERT(!isRunning()); d->mUrl = url; } void CloneOperation::setPath( const QString& path ) { + GW_D(CloneOperation); + Q_ASSERT(!isRunning()); d->mPath = path; } - void CloneOperation::setBare( bool bare ) + void CloneOperation::setBare(bool bare) { + GW_D(CloneOperation); + Q_ASSERT(!isRunning()); d->mGitCloneOptions.bare = bare ? 1 : 0; } - void CloneOperation::setRemoteName( const QByteArray& remoteName ) + void CloneOperation::setRemoteName(const QByteArray& remoteName) { + GW_D(CloneOperation); + Q_ASSERT(!isRunning()); d->mRemoteName = remoteName; d->mGitCloneOptions.remote_name = remoteName.isEmpty() ? NULL : remoteName.constData(); } - void CloneOperation::setFetchSpec( const QByteArray& fetchSpec ) + void CloneOperation::setRemoteName(const QString& remoteName) + { + GW_D(CloneOperation); + Q_ASSERT(!isRunning()); + d->mRemoteName = remoteName.toUtf8(); + d->mGitCloneOptions.remote_name = remoteName.isEmpty() ? NULL : d->mRemoteName.constData(); + } + + void CloneOperation::setFetchSpec(const QByteArray& fetchSpec) { + GW_D(CloneOperation); + Q_ASSERT(!isRunning()); d->mFetchSpec = fetchSpec; d->mGitCloneOptions.fetch_spec = fetchSpec.isEmpty() ? NULL : fetchSpec.constData(); } - void CloneOperation::setPushSpec( const QByteArray& pushSpec ) + void CloneOperation::setPushSpec(const QByteArray& pushSpec) { + GW_D(CloneOperation); + Q_ASSERT(!isRunning()); d->mPushSpec = pushSpec; d->mGitCloneOptions.push_spec = pushSpec.isEmpty() ? NULL : pushSpec.constData(); } - void CloneOperation::setPushUrl( const QByteArray& pushUrl ) + void CloneOperation::setPushUrl(const QByteArray& pushUrl) { + GW_D(CloneOperation); + Q_ASSERT(!isRunning()); d->mPushUrl = pushUrl; d->mGitCloneOptions.pushurl = pushUrl.isEmpty() ? NULL : pushUrl.constData(); } QString CloneOperation::url() const { + GW_CD(CloneOperation); return d->mUrl; } QString CloneOperation::path() const { + GW_CD(CloneOperation); return d->mPath; } bool CloneOperation::bare() const { + GW_CD(CloneOperation); return d->mGitCloneOptions.bare != 0; } QByteArray CloneOperation::remoteName() const { + GW_CD(CloneOperation); return d->mRemoteName; } QByteArray CloneOperation::fetchSpec() const { + GW_CD(CloneOperation); return d->mFetchSpec; } QByteArray CloneOperation::pushSpec() const { + GW_CD(CloneOperation); return d->mPushSpec; } QByteArray CloneOperation::pushUrl() const { + GW_CD(CloneOperation); return d->mPushUrl; } - void CloneOperation::setBackgroundMode( bool backgroundMode ) - { - d->mBackgroundMode = backgroundMode; - } - - bool CloneOperation::backgroundMode() const - { - return d->mBackgroundMode; - } - - Result CloneOperation::execute() - { - if( d->mBackgroundMode ) - { - Q_ASSERT( !d->mThread ); - d->mThread = new Internal::WorkerThread( this, d ); - connect( d->mThread, SIGNAL(finished()), - this, SLOT(workerFinished()) ); - d->mThread->start(); - return Result(); - } - else - { - d->run(); - return d->mResult; - } - } - - bool CloneOperation::isRunning() const - { - return d->mThread; - } - - void CloneOperation::workerFinished() - { - delete d->mThread; - d->mThread = NULL; - emit finished(); - } - - Result CloneOperation::result() const - { - return d->mResult; - } - } diff --git a/libGitWrap/CloneOperation.hpp b/libGitWrap/Operations/CloneOperation.hpp similarity index 70% rename from libGitWrap/CloneOperation.hpp rename to libGitWrap/Operations/CloneOperation.hpp index 5ad3228..b3e38b1 100644 --- a/libGitWrap/CloneOperation.hpp +++ b/libGitWrap/Operations/CloneOperation.hpp @@ -17,7 +17,8 @@ #ifndef GITWRAP_CLONE_OPERATION_HPP #define GITWRAP_CLONE_OPERATION_HPP -#include "IFetchEvents.hpp" +#include "libGitWrap/Operations/IFetchEvents.hpp" +#include "libGitWrap/Operations/BaseOperation.hpp" namespace Git { @@ -30,40 +31,36 @@ namespace Git class CloneOperationPrivate; } - class GITWRAP_API CloneOperation : public QObject, public IFetchEvents + class GITWRAP_API CloneOperation : public BaseOperation, public IFetchEvents { Q_OBJECT public: - CloneOperation( QObject* parent = 0 ); - ~CloneOperation(); + typedef Internal::CloneOperationPrivate Private; public: - Result execute(); + CloneOperation( QObject* parent = 0 ); + ~CloneOperation(); public slots: - void setBackgroundMode( bool backgroundMode ); - void setUrl( const QString& url ); - void setPath( const QString& path ); - void setBare( bool bare ); - void setRemoteName( const QByteArray& remoteName ); - void setFetchSpec( const QByteArray& fetchSpec ); - void setPushSpec( const QByteArray& pushSpec ); - void setPushUrl( const QByteArray& pushUrl ); + void setUrl(const QString& url); + void setPath(const QString& path); + void setBare(bool bare); + void setRemoteName(const QString& remoteName); + void setRemoteName(const QByteArray& remoteName); + void setFetchSpec(const QByteArray& fetchSpec); + void setPushSpec(const QByteArray& pushSpec); + void setPushUrl(const QByteArray& pushUrl); public: QString url() const; QString path() const; bool bare() const; - bool backgroundMode() const; - bool isRunning() const; QByteArray remoteName() const; QByteArray fetchSpec() const; QByteArray pushSpec() const; QByteArray pushUrl() const; - Result result() const; - signals: void askCredentials( CredentialRequest& request ); void transportProgress( quint32 totalObjects, @@ -77,13 +74,6 @@ namespace Git void updateTip( const QString& branchName, const Git::ObjectId& from, const Git::ObjectId& to ); - void finished(); - - private slots: - void workerFinished(); - - private: - Internal::CloneOperationPrivate* d; }; } diff --git a/libGitWrap/IFetchEvents.cpp b/libGitWrap/Operations/IFetchEvents.cpp similarity index 93% rename from libGitWrap/IFetchEvents.cpp rename to libGitWrap/Operations/IFetchEvents.cpp index cf07ee0..7fe779d 100644 --- a/libGitWrap/IFetchEvents.cpp +++ b/libGitWrap/Operations/IFetchEvents.cpp @@ -14,7 +14,7 @@ * */ -#include "IFetchEvents.hpp" +#include "libGitWrap/Operations/IFetchEvents.hpp" namespace Git { diff --git a/libGitWrap/IFetchEvents.hpp b/libGitWrap/Operations/IFetchEvents.hpp similarity index 95% rename from libGitWrap/IFetchEvents.hpp rename to libGitWrap/Operations/IFetchEvents.hpp index fd05b2f..c19b052 100644 --- a/libGitWrap/IFetchEvents.hpp +++ b/libGitWrap/Operations/IFetchEvents.hpp @@ -17,8 +17,8 @@ #ifndef GITWRAP_IFETCH_EVENTS_HPP #define GITWRAP_IFETCH_EVENTS_HPP -#include "GitWrap.hpp" -#include "ObjectId.hpp" +#include "libGitWrap/GitWrap.hpp" +#include "libGitWrap/ObjectId.hpp" namespace Git { diff --git a/libGitWrap/Operations/Private/BaseOperationPrivate.hpp b/libGitWrap/Operations/Private/BaseOperationPrivate.hpp new file mode 100644 index 0000000..b94e47e --- /dev/null +++ b/libGitWrap/Operations/Private/BaseOperationPrivate.hpp @@ -0,0 +1,61 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 Sascha Cunz + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GITWRAP_OPS_BASEOP_PRIVATE_HPP +#define GITWRAP_OPS_BASEOP_PRIVATE_HPP +#pragma once + +#include "libGitWrap/Result.hpp" + +#include "libGitWrap/Private/GitWrapPrivate.hpp" + +#include "libGitWrap/Operations/Private/WorkerThread.hpp" + +namespace Git +{ + + class BaseOperation; + + namespace Internal + { + + /** + * @internal + * @ingroup GitWrap + * + */ + class BaseOperationPrivate : public Worker + { + public: + BaseOperationPrivate(BaseOperation* owner); + ~BaseOperationPrivate(); + + public: + BaseOperation* mOwner; + bool mBackgroundMode; + + Result mResult; + WorkerThread* mThread; + }; + + } + +} + +#define GW_OP_OWNER(CLS) \ + CLS* owner = static_cast(mOwner) + +#endif diff --git a/libGitWrap/Operations/Private/CheckoutOperationPrivate.hpp b/libGitWrap/Operations/Private/CheckoutOperationPrivate.hpp new file mode 100644 index 0000000..6080ffc --- /dev/null +++ b/libGitWrap/Operations/Private/CheckoutOperationPrivate.hpp @@ -0,0 +1,102 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 Sascha Cunz + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#include "libGitWrap/Result.hpp" +#include "libGitWrap/Tree.hpp" +#include "libGitWrap/Repository.hpp" +#include "libGitWrap/Index.hpp" +#include "libGitWrap/BranchRef.hpp" + +#include "libGitWrap/Private/GitWrapPrivate.hpp" + +#include "libGitWrap/Operations/Private/BaseOperationPrivate.hpp" + +namespace Git +{ + + class CheckoutBaseOperation; + class CheckoutIndexOperation; + class CheckoutTreeOperation; + + namespace Internal + { + + class CheckoutBaseOperationPrivate : public BaseOperationPrivate + { + public: + CheckoutBaseOperationPrivate(CheckoutBaseOperation* owner); + ~CheckoutBaseOperationPrivate(); + + public: + void prepare(); + void unprepare(); + + public: + void emitFile(git_checkout_notify_t why, const char *path, + const git_diff_file *baseline, const git_diff_file *target, + const git_diff_file *workdir); + void emitProgress(const QString& pathName, quint32 completed, quint32 total); + + public: + Repository mRepository; + CheckoutOptions mOptions; + CheckoutMode mMode; + QStringList mPaths; + QString mPath; + Tree mBaseline; + git_checkout_opts mOpts; + bool mCancel; + }; + + class CheckoutIndexOperationPrivate : public CheckoutBaseOperationPrivate + { + public: + CheckoutIndexOperationPrivate(CheckoutIndexOperation* owner); + + public: + void run(); + + public: + Index mIndex; + }; + + class CheckoutTreeOperationPrivate : public CheckoutBaseOperationPrivate + { + public: + CheckoutTreeOperationPrivate(CheckoutTreeOperation* owner); + + public: + void run(); + + public: + Tree mTree; + }; + + class CheckoutBranchOperationPrivate : public CheckoutBaseOperationPrivate + { + public: + CheckoutBranchOperationPrivate(CheckoutBranchOperation* owner); + + public: + void run(); + + public: + BranchRef branch; + }; + + } + +} diff --git a/libGitWrap/Private/CloneOperationPrivate.hpp b/libGitWrap/Operations/Private/CloneOperationPrivate.hpp similarity index 78% rename from libGitWrap/Private/CloneOperationPrivate.hpp rename to libGitWrap/Operations/Private/CloneOperationPrivate.hpp index 2f83fa4..008f391 100644 --- a/libGitWrap/Private/CloneOperationPrivate.hpp +++ b/libGitWrap/Operations/Private/CloneOperationPrivate.hpp @@ -14,9 +14,11 @@ * */ -#include "GitWrapPrivate.hpp" -#include "Result.hpp" -#include "WorkerThread.hpp" +#include "libGitWrap/Result.hpp" + +#include "libGitWrap/Private/GitWrapPrivate.hpp" + +#include "libGitWrap/Operations/Private/BaseOperationPrivate.hpp" namespace Git { @@ -31,10 +33,10 @@ namespace Git * @ingroup GitWrap * */ - class CloneOperationPrivate : public Worker + class CloneOperationPrivate : public BaseOperationPrivate { public: - CloneOperationPrivate( CloneOperation* owner ); + CloneOperationPrivate(CloneOperation* owner); ~CloneOperationPrivate(); public: @@ -44,9 +46,6 @@ namespace Git QString mUrl; QString mPath; - CloneOperation* mOwner; - bool mBackgroundMode; - QByteArray mRemoteName; QByteArray mFetchSpec; QByteArray mPushSpec; @@ -54,9 +53,6 @@ namespace Git git_clone_options mGitCloneOptions; git_remote_callbacks mRemoteCallbacks; - - Result mResult; - WorkerThread* mThread; }; } diff --git a/libGitWrap/Private/FetchCallbacks.cpp b/libGitWrap/Operations/Private/FetchCallbacks.cpp similarity index 97% rename from libGitWrap/Private/FetchCallbacks.cpp rename to libGitWrap/Operations/Private/FetchCallbacks.cpp index 4fbc6b5..9285345 100644 --- a/libGitWrap/Private/FetchCallbacks.cpp +++ b/libGitWrap/Operations/Private/FetchCallbacks.cpp @@ -14,8 +14,9 @@ * */ -#include "IFetchEvents.hpp" -#include "FetchCallbacks.hpp" +#include "libGitWrap/Operations/IFetchEvents.hpp" + +#include "libGitWrap/Operations/Private/FetchCallbacks.hpp" #if 0 #define debugEvents qDebug diff --git a/libGitWrap/Private/FetchCallbacks.hpp b/libGitWrap/Operations/Private/FetchCallbacks.hpp similarity index 96% rename from libGitWrap/Private/FetchCallbacks.hpp rename to libGitWrap/Operations/Private/FetchCallbacks.hpp index bb9dec8..341b951 100644 --- a/libGitWrap/Private/FetchCallbacks.hpp +++ b/libGitWrap/Operations/Private/FetchCallbacks.hpp @@ -17,7 +17,7 @@ #ifndef GITWRAP_FETCH_CALLBACKS_HPP #define GITWRAP_FETCH_CALLBACKS_HPP -#include "GitWrapPrivate.hpp" +#include "libGitWrap/Private/GitWrapPrivate.hpp" namespace Git { diff --git a/libGitWrap/Private/WorkerThread.cpp b/libGitWrap/Operations/Private/WorkerThread.cpp similarity index 79% rename from libGitWrap/Private/WorkerThread.cpp rename to libGitWrap/Operations/Private/WorkerThread.cpp index d23e9a5..e1c4f59 100644 --- a/libGitWrap/Private/WorkerThread.cpp +++ b/libGitWrap/Operations/Private/WorkerThread.cpp @@ -14,7 +14,7 @@ * */ -#include "WorkerThread.hpp" +#include "libGitWrap/Operations/Private/WorkerThread.hpp" namespace Git { @@ -26,15 +26,15 @@ namespace Git { } - WorkerThread::WorkerThread( QObject* parent, Worker* worker ) - : QThread( parent ) - , mWorker( worker ) + WorkerThread::WorkerThread(QObject* parent, const Worker::Ptr& worker) + : QThread(parent) + , mWorker(worker) { } void WorkerThread::run() { - Q_ASSERT( mWorker ); + Q_ASSERT(mWorker); mWorker->run(); } diff --git a/libGitWrap/Private/WorkerThread.hpp b/libGitWrap/Operations/Private/WorkerThread.hpp similarity index 81% rename from libGitWrap/Private/WorkerThread.hpp rename to libGitWrap/Operations/Private/WorkerThread.hpp index 31b8b30..c1d00b9 100644 --- a/libGitWrap/Private/WorkerThread.hpp +++ b/libGitWrap/Operations/Private/WorkerThread.hpp @@ -17,6 +17,7 @@ #ifndef GITWRAP_WORKER_THREAD_HPP #define GITWRAP_WORKER_THREAD_HPP +#include #include namespace Git @@ -25,8 +26,10 @@ namespace Git namespace Internal { - class Worker + class Worker : public QSharedData { + public: + typedef QExplicitlySharedDataPointer Ptr; public: virtual ~Worker(); @@ -38,13 +41,13 @@ namespace Git { Q_OBJECT public: - WorkerThread( QObject* parent, Worker* worker ); + WorkerThread(QObject* parent, const Worker::Ptr& worker); public: void run(); private: - Worker* mWorker; + Worker::Ptr mWorker; }; } diff --git a/libGitWrap/PatchConsumer.cpp b/libGitWrap/PatchConsumer.cpp index 32899b0..11e2f57 100644 --- a/libGitWrap/PatchConsumer.cpp +++ b/libGitWrap/PatchConsumer.cpp @@ -14,7 +14,7 @@ * */ -#include "PatchConsumer.hpp" +#include "libGitWrap/PatchConsumer.hpp" namespace Git { diff --git a/libGitWrap/PatchConsumer.hpp b/libGitWrap/PatchConsumer.hpp index 40f31bc..03d529d 100644 --- a/libGitWrap/PatchConsumer.hpp +++ b/libGitWrap/PatchConsumer.hpp @@ -17,8 +17,8 @@ #ifndef GITWRAP_PATCH_CONSUMER_H #define GITWRAP_PATCH_CONSUMER_H -#include "GitWrap.hpp" -#include "ChangeListConsumer.hpp" +#include "libGitWrap/GitWrap.hpp" +#include "libGitWrap/ChangeListConsumer.hpp" namespace Git { diff --git a/libGitWrap/Private/BasePrivate.hpp b/libGitWrap/Private/BasePrivate.hpp index a4bf7c1..ff46eea 100644 --- a/libGitWrap/Private/BasePrivate.hpp +++ b/libGitWrap/Private/BasePrivate.hpp @@ -19,11 +19,13 @@ #include -#include "GitWrapPrivate.hpp" +#include "libGitWrap/Private/GitWrapPrivate.hpp" namespace Git { + class Object; + namespace Internal { @@ -39,6 +41,10 @@ namespace Git BasePrivate(); virtual ~BasePrivate(); + public: + static bool isValid(Result& r, const BasePrivate* d); + virtual bool isValidObject(Result& r) const; + public: template< class T> static typename T::Private* dataOf(T* o) @@ -52,41 +58,23 @@ namespace Git return static_cast(o.mData.data()); } - static const git_oid* sha(const ObjectId& id); + static inline const git_oid* sha(const ObjectId& id) + { + return reinterpret_cast(id.raw()); + } + + static inline ObjectId oid2sha(const git_oid* oid) + { + return ObjectId::fromRaw(oid->id); + } + + static git_object* objectOf(const Object& o); + }; } } -#define GW_D(CLASS) \ - Internal::CLASS##Private* d = \ - static_cast(mData.data()) - -#define GW_CD(CLASS) \ - const Internal::CLASS##Private* d = \ - static_cast(mData.data()) - -#define GW_D_CHECKED(CLASS, returns, result) \ - GW_D(CLASS); \ - if (!result) { return returns; } \ - if (!d) { result.setInvalidObject(); return returns; } - -#define GW_CD_CHECKED(CLASS, returns, result) \ - GW_CD(CLASS); \ - if (!result) { return returns; } \ - if (!d) { result.setInvalidObject(); return returns; } - -// Wherever we have to use one of those two, we've made bad API design! -#define GW_D_CHECKED_VOID(CLASS, result) \ - GW_D(CLASS); \ - if (!result) { return; } \ - if (!d) { result.setInvalidObject(); return; } - -#define GW_CD_CHECKED_VOID(CLASS, result) \ - GW_CD(CLASS); \ - if (!result) { return; } \ - if (!d) { result.setInvalidObject(); return; } - #endif diff --git a/libGitWrap/Private/BlobPrivate.hpp b/libGitWrap/Private/BlobPrivate.hpp new file mode 100644 index 0000000..14f2c4b --- /dev/null +++ b/libGitWrap/Private/BlobPrivate.hpp @@ -0,0 +1,50 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 The MacGitver-Developers + * + * (C) Sascha Cunz + * (C) Cunz RaD Ltd. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GITWRAP_BLOB_PRIVATE_HPP +#define GITWRAP_BLOB_PRIVATE_HPP +#pragma once + +#include "libGitWrap/Private/ObjectPrivate.hpp" + +namespace Git +{ + + namespace Internal + { + + class BlobPrivate : public ObjectPrivate + { + public: + BlobPrivate(const RepositoryPrivate::Ptr& repo, git_object* o); + BlobPrivate(const RepositoryPrivate::Ptr& repo, git_blob* o); + + public: + git_blob* o() { return reinterpret_cast(mObj); } + const git_blob* o() const { return reinterpret_cast(mObj); } + + git_otype otype() const; + ObjectType objectType() const; + }; + + } + +} + +#endif diff --git a/libGitWrap/Private/BranchRefPrivate.hpp b/libGitWrap/Private/BranchRefPrivate.hpp new file mode 100644 index 0000000..5f068d2 --- /dev/null +++ b/libGitWrap/Private/BranchRefPrivate.hpp @@ -0,0 +1,47 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 The MacGitver-Developers + * + * (C) Sascha Cunz + * (C) Nils Fenner + * (C) Cunz RaD Ltd. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GITWRAP_BRANCH_REF_PRIVATE_HPP +#define GITWRAP_BRANCH_REF_PRIVATE_HPP +#pragma once + +#include "libGitWrap/Private/ReferencePrivate.hpp" + +namespace Git +{ + + namespace Internal + { + + class BranchRefPrivate : public ReferencePrivate + { + public: + BranchRefPrivate(const RepositoryPrivate::Ptr& repo, git_reference* reference); + BranchRefPrivate(git_reference* reference, const RefNamePrivate* refName); + + public: + ReferenceKinds kind() const; + }; + + } + +} + +#endif diff --git a/libGitWrap/Private/CommitPrivate.hpp b/libGitWrap/Private/CommitPrivate.hpp new file mode 100644 index 0000000..ebdf4e2 --- /dev/null +++ b/libGitWrap/Private/CommitPrivate.hpp @@ -0,0 +1,50 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 The MacGitver-Developers + * + * (C) Sascha Cunz + * (C) Cunz RaD Ltd. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GITWRAP_COMMIT_PRIVATE_HPP +#define GITWRAP_COMMIT_PRIVATE_HPP +#pragma once + +#include "libGitWrap/Private/ObjectPrivate.hpp" + +namespace Git +{ + + namespace Internal + { + + class CommitPrivate : public ObjectPrivate + { + public: + CommitPrivate(const RepositoryPrivate::Ptr& repo, git_object* o); + CommitPrivate(const RepositoryPrivate::Ptr& repo, git_commit* o); + + public: + git_commit* o() { return reinterpret_cast(mObj); } + const git_commit* o() const { return reinterpret_cast(mObj); } + + git_otype otype() const; + ObjectType objectType() const; + }; + + } + +} + +#endif diff --git a/libGitWrap/Private/DiffListPrivate.hpp b/libGitWrap/Private/DiffListPrivate.hpp index f8b313b..e7476ab 100644 --- a/libGitWrap/Private/DiffListPrivate.hpp +++ b/libGitWrap/Private/DiffListPrivate.hpp @@ -35,7 +35,7 @@ namespace Git class DiffListPrivate : public RepoObjectPrivate { public: - DiffListPrivate(RepositoryPrivate* repo, git_diff_list* difflist); + DiffListPrivate(const RepositoryPrivate::Ptr& repo, git_diff_list* difflist); ~DiffListPrivate(); public: diff --git a/libGitWrap/Private/GitWrapPrivate.hpp b/libGitWrap/Private/GitWrapPrivate.hpp index debd88c..b9bf6d1 100644 --- a/libGitWrap/Private/GitWrapPrivate.hpp +++ b/libGitWrap/Private/GitWrapPrivate.hpp @@ -22,13 +22,14 @@ #include "git2.h" -#include "GitWrap.hpp" -#include "Result.hpp" -#include "ObjectId.hpp" +#include "libGitWrap/GitWrap.hpp" +#include "libGitWrap/Result.hpp" +#include "libGitWrap/ObjectId.hpp" namespace Git { + class FileInfo; class Signature; class RefSpec; @@ -44,6 +45,7 @@ namespace Git git_signature* signature2git( Result& result, const Signature& sig ); RefSpec mkRefSpec( const git_refspec* refspec ); QStringList slFromStrArray( git_strarray* arry ); + FileInfo mkFileInfo(const git_diff_file* df); /** * @internal @@ -52,9 +54,6 @@ namespace Git */ class StrArrayWrapper { - git_strarray a; - QStringList internalCopy; - public: StrArrayWrapper(const QStringList& sl); ~StrArrayWrapper(); @@ -65,6 +64,26 @@ namespace Git private: StrArrayWrapper(); StrArrayWrapper(const StrArrayWrapper&); + StrArrayWrapper& operator=(const StrArrayWrapper&); + + private: + git_strarray a; + QStringList internalCopy; + }; + + class StrArray + { + public: + StrArray(git_strarray& _a, const QStringList& sl); + ~StrArray(); + + private: + /* Cannot privatize Copy+Default ctor because of the member-by-reference */ + StrArray& operator=(const StrArray&); + + private: + git_strarray& a; + QStringList internalCopy; }; /** @@ -74,7 +93,7 @@ namespace Git * @param[in] attr GitWrap's TreeEntryAttributes * @return LibGit2's git_filemode_t */ - static inline git_filemode_t teattr2filemode( TreeEntryAttributes attr ) + static inline git_filemode_t teattr2filemode( FileModes attr ) { switch( attr ) { @@ -97,16 +116,37 @@ namespace Git * @param[in] otype LibGit2's object type * @return LibGitWrap's object type */ - static inline ObjectType gitotype2ObjectType( git_otype otype ) + static inline ObjectType gitotype2ObjectType(git_otype otype) { - switch( otype ) - { + switch (otype) { + default: Q_ASSERT(false); + case GIT_OBJ_ANY: return otAny; case GIT_OBJ_BLOB: return otBlob; case GIT_OBJ_COMMIT: return otCommit; case GIT_OBJ_TREE: return otTree; case GIT_OBJ_TAG: return otTag; - default: Q_ASSERT( false ); - return otAny; + } + } + + /** + * @internal + * @ingroup GitWrap + * @brief Convert ObjectType to GIT_OBJ_xxx constant + * + * @param[in] ot The ObjectType to convert + * + * @return The GIT_OBJ_xxx constant + * + */ + static inline git_otype objectType2gitotype(ObjectType ot) + { + switch (ot) { + default: Q_ASSERT(false); + case otAny: return GIT_OBJ_ANY; + case otBlob: return GIT_OBJ_BLOB; + case otCommit: return GIT_OBJ_COMMIT; + case otTree: return GIT_OBJ_TREE; + case otTag: return GIT_OBJ_TAG; } } @@ -169,4 +209,56 @@ namespace Git } +#define GW__CHECK(returns, result) \ + if (!Private::isValid(result, d)) { return returns; } + +#define GW__CHECK_VOID(result) \ + if (!Private::isValid(result, d)) { return; } + + +#define GW__EX_CHECK(returns, result) \ + if (!Private::isValid(result, d.constData())) { return returns; } + +#define GW__EX_CHECK_VOID(result) \ + if (!Private::isValid(result, d.constData())) { return; } + +#define GW_D(CLASS) \ + Private* d = static_cast(mData.data()); \ + ensureThisIsNotConst() + +#define GW_D_EX(CLASS) \ + PrivatePtr d(static_cast(mData.data())); \ + ensureThisIsNotConst() + +#define GW_CD(CLASS) \ + const Private* d = static_cast(mData.constData()) + +#define GW_CD_EX(CLASS) \ + const PrivatePtr d(static_cast(mData.data())) + +#define GW_CD_EX_CHECKED(CLASS, returns, result) \ + GW_CD_EX(CLASS); \ + GW__EX_CHECK(returns, result) + +#define GW_D_CHECKED(CLASS, returns, result) \ + GW_D(CLASS); \ + GW__CHECK(returns, result) + +#define GW_D_EX_CHECKED(CLASS, returns, result) \ + GW_D_EX(CLASS); \ + GW__EX_CHECK(returns, result) + +#define GW_CD_CHECKED(CLASS, returns, result) \ + GW_CD(CLASS); \ + GW__CHECK(returns, result) + +// Wherever we have to use one of those two, we've made bad API design! +#define GW_D_CHECKED_VOID(CLASS, result) \ + GW_D(CLASS); \ + GW__CHECK_VOID(result) + +#define GW_CD_CHECKED_VOID(CLASS, result) \ + GW_CD(CLASS); \ + GW__CHECK_VOID(result) + #endif diff --git a/libGitWrap/Private/IndexPrivate.hpp b/libGitWrap/Private/IndexPrivate.hpp index 1b99cb7..9844a86 100644 --- a/libGitWrap/Private/IndexPrivate.hpp +++ b/libGitWrap/Private/IndexPrivate.hpp @@ -19,7 +19,7 @@ #ifndef GIT_INDEX_PRIVATE_H #define GIT_INDEX_PRIVATE_H -#include "IndexConflict.hpp" +#include "libGitWrap/IndexConflict.hpp" #include "libGitWrap/Private/GitWrapPrivate.hpp" #include "libGitWrap/Private/RepoObjectPrivate.hpp" @@ -39,7 +39,7 @@ namespace Git class IndexPrivate : public RepoObjectPrivate { public: - IndexPrivate(RepositoryPrivate* repo, git_index* index); + IndexPrivate(const RepositoryPrivate::Ptr& repo, git_index* index); ~IndexPrivate(); public: diff --git a/libGitWrap/Private/NoteRefPrivate.hpp b/libGitWrap/Private/NoteRefPrivate.hpp new file mode 100644 index 0000000..6cb091e --- /dev/null +++ b/libGitWrap/Private/NoteRefPrivate.hpp @@ -0,0 +1,47 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 The MacGitver-Developers + * + * (C) Sascha Cunz + * (C) Nils Fenner + * (C) Cunz RaD Ltd. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GITWRAP_NOTE_REF_PRIVATE_HPP +#define GITWRAP_NOTE_REF_PRIVATE_HPP +#pragma once + +#include "libGitWrap/Private/ReferencePrivate.hpp" + +namespace Git +{ + + namespace Internal + { + + class NoteRefPrivate : public ReferencePrivate + { + public: + NoteRefPrivate(const RepositoryPrivate::Ptr& repo, git_reference* reference); + NoteRefPrivate(git_reference* reference, const RefNamePrivate* refName); + + public: + ReferenceKinds kind() const; + }; + + } + +} + +#endif diff --git a/libGitWrap/Private/ObjectPrivate.hpp b/libGitWrap/Private/ObjectPrivate.hpp index 96d8766..1ffc208 100644 --- a/libGitWrap/Private/ObjectPrivate.hpp +++ b/libGitWrap/Private/ObjectPrivate.hpp @@ -32,10 +32,22 @@ namespace Git */ class ObjectPrivate : public RepoObjectPrivate { + protected: + ObjectPrivate(const RepositoryPrivate::Ptr& repo, git_object* o); + public: - ObjectPrivate(RepositoryPrivate* repo, git_object* o); ~ObjectPrivate(); + git_object* o() { return mObj; } + const git_object* o() const { return mObj; } + + public: + static Object::PrivatePtr create(const RepositoryPrivate::Ptr& repo, git_object* o); + + public: + virtual git_otype otype() const = 0; + virtual ObjectType objectType() const = 0; + public: git_object* mObj; }; diff --git a/libGitWrap/Private/RefNamePrivate.hpp b/libGitWrap/Private/RefNamePrivate.hpp new file mode 100644 index 0000000..c1ba712 --- /dev/null +++ b/libGitWrap/Private/RefNamePrivate.hpp @@ -0,0 +1,134 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 The MacGitver-Developers + * + * (C) Sascha Cunz + * (C) Cunz RaD Ltd. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GIT_REF_NAME_PRIVATE_HPP +#define GIT_REF_NAME_PRIVATE_HPP +#pragma once + +#include +#include + +#include "libGitWrap/Private/RepoObjectPrivate.hpp" + +namespace Git +{ + + namespace Internal + { + + class ReferencePrivate; + + struct CustomMatches + { + public: + CustomMatches() + : id(-1) + , payload(NULL) + { + } + + CustomMatches(const QRegExp& _re, int _id, void* _payload) + : id(_id) + , regExp(_re) + , payload(_payload) + { + } + + public: + int id; + QRegExp regExp; + void* payload; + }; + + class RefNameMatches + { + public: + static RefNameMatches& self(); + + public: + const QRegExp reNamespaces; + const QRegExp reRemote; + const QRegExp reScopes; + QVector customMatches; + int nextId; + + private: + static RefNameMatches* sSelf; + RefNameMatches(); + }; + + class RefNamePrivate : public RepoObjectPrivate + { + protected: + RefNamePrivate(const RefNamePrivate* refName); + public: + RefNamePrivate(RepositoryPrivate* repo); + RefNamePrivate(RepositoryPrivate* repo, const QString& name); + + public: + RefNamePrivate(); + + public: + bool isAnalyzed : 1; + + bool isStage : 1; + bool isBranch : 1; + bool isTag : 1; + bool isNote : 1; + bool isHead : 1; + bool isMergeHead : 1; + bool isCommitNote : 1; + bool isPecuiliar : 1; + + QString fqrn; + + QString remote; + QString name; + QStringList scopes; + QStringList namespaces; + QVector customMatches; + + public: + static ReferencePrivate* createRefObject(Repository::Private *repo, + const QString& name, git_reference* lgo); + + public: + virtual bool isRealReference() const; + void ensureAnalyzed(); + void analyze(); + + ReferencePrivate* cloned(git_reference* lgo); + + private: + template + typename T::Private* cloneAs(git_reference* lgo) const + { + return new typename T::Private(lgo, this); + } + + private: + void scopeTest(QString sub); + bool analyzeCustom(); + }; + + } + +} + +#endif diff --git a/libGitWrap/Private/ReferencePrivate.hpp b/libGitWrap/Private/ReferencePrivate.hpp index 9595c2d..e0ce27a 100644 --- a/libGitWrap/Private/ReferencePrivate.hpp +++ b/libGitWrap/Private/ReferencePrivate.hpp @@ -14,10 +14,11 @@ * */ -#ifndef GIT_REFERENCE_PRIVATE_H -#define GIT_REFERENCE_PRIVATE_H +#ifndef GIT_REFERENCE_PRIVATE_HPP +#define GIT_REFERENCE_PRIVATE_HPP +#pragma once -#include "libGitWrap/Private/RepoObjectPrivate.hpp" +#include "libGitWrap/Private/RefNamePrivate.hpp" namespace Git { @@ -31,14 +32,30 @@ namespace Git * @brief The ReferencePrivate class * */ - class ReferencePrivate : public RepoObjectPrivate + class ReferencePrivate : public RefNamePrivate { public: - ReferencePrivate(RepositoryPrivate* repo, git_reference* ref); + ReferencePrivate(git_reference* ref, const RefNamePrivate* refName); + public: + ReferencePrivate(const RepositoryPrivate::Ptr& repo, + const QString& name, + git_reference* ref); + ReferencePrivate(const RepositoryPrivate::Ptr& repo, git_reference* ref); ~ReferencePrivate(); public: - git_reference* mRef; + bool isRealReference() const; + + public: + bool isValidObject(Result &r) const; + + public: + virtual ReferenceKinds kind() const; + virtual CheckoutBaseOperation* checkoutOperation(Result& result) const; + + public: + bool wasDeleted; + git_reference* reference; }; } diff --git a/libGitWrap/Private/RemotePrivate.hpp b/libGitWrap/Private/RemotePrivate.hpp index 1f94e63..374a9ef 100644 --- a/libGitWrap/Private/RemotePrivate.hpp +++ b/libGitWrap/Private/RemotePrivate.hpp @@ -35,7 +35,7 @@ namespace Git class RemotePrivate : public RepoObjectPrivate { public: - RemotePrivate(RepositoryPrivate* repo, git_remote* remote); + RemotePrivate(Repository::Private* repo, git_remote* remote); ~RemotePrivate(); public: diff --git a/libGitWrap/Private/RepoObjectPrivate.hpp b/libGitWrap/Private/RepoObjectPrivate.hpp index 7a7b31a..b9eeee4 100644 --- a/libGitWrap/Private/RepoObjectPrivate.hpp +++ b/libGitWrap/Private/RepoObjectPrivate.hpp @@ -35,11 +35,13 @@ namespace Git */ class RepoObjectPrivate : public BasePrivate { - public: + protected: + RepoObjectPrivate(); + RepoObjectPrivate(const RepositoryPrivate::Ptr& repo); RepoObjectPrivate(RepositoryPrivate* repo); public: - RepositoryPrivate* repo() const; + RepositoryPrivate::Ptr repo() const; protected: RepositoryPrivate::Ptr mRepo; diff --git a/libGitWrap/Private/RepositoryPrivate.hpp b/libGitWrap/Private/RepositoryPrivate.hpp index ab38cff..9cc5696 100644 --- a/libGitWrap/Private/RepositoryPrivate.hpp +++ b/libGitWrap/Private/RepositoryPrivate.hpp @@ -19,6 +19,7 @@ #include "libGitWrap/Private/GitWrapPrivate.hpp" #include "libGitWrap/Private/BasePrivate.hpp" +#include "libGitWrap/Submodule.hpp" namespace Git { @@ -45,6 +46,7 @@ namespace Git public: git_repository* mRepo; IndexPrivate* mIndex; + Submodule openedFrom; }; } diff --git a/libGitWrap/Private/SubmodulePrivate.hpp b/libGitWrap/Private/SubmodulePrivate.hpp new file mode 100644 index 0000000..08d55a1 --- /dev/null +++ b/libGitWrap/Private/SubmodulePrivate.hpp @@ -0,0 +1,50 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 The MacGitver-Developers + * + * (C) Sascha Cunz + * (C) Cunz RaD Ltd. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GITWRAP_SUBMODULE_PRIVATE_HPP +#define GITWRAP_SUBMODULE_PRIVATE_HPP +#pragma once + +#include "libGitWrap/Private/RepoObjectPrivate.hpp" + +namespace Git +{ + + namespace Internal + { + + class SubmodulePrivate : public RepoObjectPrivate + { + public: + SubmodulePrivate(const Repository::PrivatePtr& repo, const QString& name); + + public: + git_submodule* getSM( Result& rc ) const; + bool open(Result& result); + + public: + QString mName; + RepositoryPrivate* mSubRepo; + }; + + } + +} + +#endif diff --git a/libGitWrap/Private/TagPrivate.hpp b/libGitWrap/Private/TagPrivate.hpp new file mode 100644 index 0000000..d8dbc0a --- /dev/null +++ b/libGitWrap/Private/TagPrivate.hpp @@ -0,0 +1,50 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 The MacGitver-Developers + * + * (C) Sascha Cunz + * (C) Cunz RaD Ltd. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GITWRAP_TAG_PRIVATE_HPP +#define GITWRAP_TAG_PRIVATE_HPP +#pragma once + +#include "libGitWrap/Private/ObjectPrivate.hpp" + +namespace Git +{ + + namespace Internal + { + + class TagPrivate : public ObjectPrivate + { + public: + TagPrivate(const RepositoryPrivate::Ptr& repo, git_object* o); + TagPrivate(const RepositoryPrivate::Ptr& repo, git_tag* o); + + public: + git_tag* o() { return reinterpret_cast(mObj); } + const git_tag* o() const { return reinterpret_cast(mObj); } + + git_otype otype() const; + ObjectType objectType() const; + }; + + } + +} + +#endif diff --git a/libGitWrap/Private/TagRefPrivate.hpp b/libGitWrap/Private/TagRefPrivate.hpp new file mode 100644 index 0000000..04c3f59 --- /dev/null +++ b/libGitWrap/Private/TagRefPrivate.hpp @@ -0,0 +1,47 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 The MacGitver-Developers + * + * (C) Sascha Cunz + * (C) Nils Fenner + * (C) Cunz RaD Ltd. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GITWRAP_TAG_REF_PRIVATE_HPP +#define GITWRAP_TAG_REF_PRIVATE_HPP +#pragma once + +#include "libGitWrap/Private/ReferencePrivate.hpp" + +namespace Git +{ + + namespace Internal + { + + class TagRefPrivate : public ReferencePrivate + { + public: + TagRefPrivate(const RepositoryPrivate::Ptr& repo, git_reference* reference); + TagRefPrivate(git_reference* reference, const RefNamePrivate* refName); + + public: + ReferenceKinds kind() const; + }; + + } + +} + +#endif diff --git a/libGitWrap/Private/TreeBuilderPrivate.hpp b/libGitWrap/Private/TreeBuilderPrivate.hpp index 63bdbe4..d8256d4 100644 --- a/libGitWrap/Private/TreeBuilderPrivate.hpp +++ b/libGitWrap/Private/TreeBuilderPrivate.hpp @@ -34,7 +34,7 @@ namespace Git class TreeBuilderPrivate : public RepoObjectPrivate { public: - TreeBuilderPrivate(RepositoryPrivate* repo, git_treebuilder* builder); + TreeBuilderPrivate(const RepositoryPrivate::Ptr& repo, git_treebuilder* builder); ~TreeBuilderPrivate(); public: diff --git a/libGitWrap/Private/TreePrivate.hpp b/libGitWrap/Private/TreePrivate.hpp new file mode 100644 index 0000000..5d03c12 --- /dev/null +++ b/libGitWrap/Private/TreePrivate.hpp @@ -0,0 +1,50 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 The MacGitver-Developers + * + * (C) Sascha Cunz + * (C) Cunz RaD Ltd. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GITWRAP_TREE_PRIVATE_HPP +#define GITWRAP_TREE_PRIVATE_HPP +#pragma once + +#include "libGitWrap/Private/ObjectPrivate.hpp" + +namespace Git +{ + + namespace Internal + { + + class TreePrivate : public ObjectPrivate + { + public: + TreePrivate(const RepositoryPrivate::Ptr& repo, git_object* o); + TreePrivate(const RepositoryPrivate::Ptr& repo, git_tree* o); + + public: + git_tree* o() { return reinterpret_cast(mObj); } + const git_tree* o() const { return reinterpret_cast(mObj); } + + git_otype otype() const; + ObjectType objectType() const; + }; + + } + +} + +#endif diff --git a/libGitWrap/RefName.cpp b/libGitWrap/RefName.cpp index 90099a7..0e1f4ee 100644 --- a/libGitWrap/RefName.cpp +++ b/libGitWrap/RefName.cpp @@ -21,8 +21,17 @@ #include #include "libGitWrap/RefName.hpp" +#include "libGitWrap/Reference.hpp" +#include "libGitWrap/TagRef.hpp" +#include "libGitWrap/BranchRef.hpp" +#include "libGitWrap/NoteRef.hpp" #include "libGitWrap/Private/BasePrivate.hpp" +#include "libGitWrap/Private/RefNamePrivate.hpp" +#include "libGitWrap/Private/ReferencePrivate.hpp" +#include "libGitWrap/Private/TagRefPrivate.hpp" +#include "libGitWrap/Private/BranchRefPrivate.hpp" +#include "libGitWrap/Private/NoteRefPrivate.hpp" #include "libGitWrap/Private/GitWrapPrivate.hpp" namespace Git @@ -196,52 +205,6 @@ namespace Git namespace Internal { - struct CustomMatches - { - public: - CustomMatches() - : id(-1) - , payload(NULL) - { - }/* - - CustomMatches(const CustomMatches& o) - : id(o.id) - , regExp(o.regExp) - , payload(o.payload) - { - }*/ - - CustomMatches(const QRegExp& _re, int _id, void* _payload) - : id(_id) - , regExp(_re) - , payload(_payload) - { - } - - public: - int id; - /*const*/ QRegExp regExp; - void* payload; - }; - - class RefNameMatches - { - public: - static RefNameMatches& self(); - - public: - const QRegExp reNamespaces; - const QRegExp reRemote; - const QRegExp reScopes; - QVector customMatches; - int nextId; - - private: - static RefNameMatches* sSelf; - RefNameMatches(); - }; - RefNameMatches* RefNameMatches::sSelf = NULL; RefNameMatches& RefNameMatches::self() @@ -260,35 +223,51 @@ namespace Git { } - class RefNamePrivate : public BasePrivate + // -- RefNamePrivate -------------------------------------------------------------------- >8 + + RefNamePrivate::RefNamePrivate() + : RepoObjectPrivate() + , isAnalyzed(false) + { + } + + RefNamePrivate::RefNamePrivate(const RefNamePrivate* refName) + : RepoObjectPrivate(refName->repo()) + , isAnalyzed(refName->isAnalyzed) + , isStage(refName->isStage) + , isBranch(refName->isBranch) + , isTag(refName->isTag) + , isNote(refName->isNote) + , isHead(refName->isHead) + , isMergeHead(refName->isMergeHead) + , isCommitNote(refName->isCommitNote) + , isPecuiliar(refName->isPecuiliar) + , fqrn(refName->fqrn) + , remote(refName->remote) + , name(refName->name) + , scopes(refName->scopes) + , namespaces(refName->namespaces) + , customMatches(refName->customMatches) + { + } + + RefNamePrivate::RefNamePrivate(RepositoryPrivate* repo) + : RepoObjectPrivate(repo) + , isAnalyzed(false) { - public: - bool isAnalyzed : 1; - - bool isStage : 1; - bool isBranch : 1; - bool isTag : 1; - bool isHead : 1; - bool isMergeHead : 1; - bool isCommitNote : 1; - bool isPecuiliar : 1; - - QString fqrn; - - QString remote; - QString name; - QStringList scopes; - QStringList namespaces; - QVector customMatches; - - public: - void ensureAnalyzed(); - void analyze(); - - private: - void scopeTest(QString sub); - bool analyzeCustom(); - }; + } + + RefNamePrivate::RefNamePrivate(RepositoryPrivate* repo, const QString& name) + : RepoObjectPrivate(repo) + , isAnalyzed(false) + , fqrn(name) + { + } + + bool RefNamePrivate::isRealReference() const + { + return false; + } void RefNamePrivate::ensureAnalyzed() { @@ -326,15 +305,13 @@ namespace Git { remote = name = QString(); scopes = namespaces = QStringList(); - isStage = isBranch = isTag = isHead = isMergeHead = isCommitNote = isPecuiliar = false; + isNote = isStage = isBranch = isTag = isHead = + isMergeHead = isCommitNote = isPecuiliar = false; customMatches.clear(); if (fqrn == QLatin1String("refs/stage")) { isStage = true; } - else if (fqrn == QLatin1String("refs/notes/commit")) { - isCommitNote = true; - } else if (fqrn == QLatin1String("MERGE_HEAD")) { isMergeHead = true; } @@ -343,12 +320,14 @@ namespace Git isBranch = true; isHead = true; } - else if (!analyzeCustom()) { + else { const QRegExp& reNS = RefNameMatches::self().reNamespaces; const QRegExp& reRem = RefNameMatches::self().reRemote; QString match = fqrn; + analyzeCustom(); + while (reNS.indexIn(match) != -1) { namespaces.append(reNS.cap(1)); match = reNS.cap(2); @@ -363,6 +342,11 @@ namespace Git scopeTest(match); } + else if (match.startsWith(QLatin1String("refs/notes/"))) { + isNote = true; + isCommitNote = (match == QLatin1String("refs/notes/commit")); + scopeTest(match.mid(11)); + } else if (match.startsWith(QLatin1String("refs/heads/"))) { isBranch = true; scopeTest(match.mid(11)); @@ -372,40 +356,101 @@ namespace Git scopeTest(match.mid(10)); } else { - isPecuiliar = true; + isPecuiliar = customMatches.count() == 0; } } isAnalyzed = true; } - } + ReferencePrivate* RefNamePrivate::cloned(git_reference* lgo) + { + ensureAnalyzed(); - RefName::RefName() - { - } + if (isBranch) { + return cloneAs(lgo); + } + + if (isTag) { + return cloneAs(lgo); + } + + if (isNote) { + return cloneAs(lgo); + } + + return cloneAs(lgo); + } + + /** + * @internal + * @brief Factory to create the correct ReferencePrivate + * + * @param[in] repo The repository for which to create the reference object. + * + * @param[in] name A fully qualified reference name. + * + * @param[in] lgo The libgit2 git_reference object. This is optional and defaults to + * `NULL`. If given, the new ReferencePrivate will point to it. If not + * given, we have to look it up first. + * + * @return A new ReferencePrivate object capable of holding a reference type that + * matches @a name. + * + * This works relatively efficient and reliable: We create a RefNamePrivate (on the stack, + * not the heap) and let it clone itself. Before cloning, it has to analyze itself in order + * to decide what reference private object to create. + * + * The cloning mechanism will then move over all the (already) analyzed data from the stack + * based RefNamePrivate. + * + * If no @a lgo is given and it cannot be looked up in @a repo under the @a name, `NULL` + * will be returned, as the resulting ReferencePrivate would be invalid and we cannot + * express that state in the private object. + * + */ + ReferencePrivate* RefNamePrivate::createRefObject(Repository::Private* repo, + const QString& name, git_reference* lgo) + { + if (!lgo) { + if (git_reference_lookup(&lgo, repo->mRepo, name.toUtf8().constData()) < 0) { + return NULL; + } + } + + return RefNamePrivate(repo, name).cloned(lgo); + } - RefName::RefName(const RefName& other) - : Base(other) - { } + GW_PRIVATE_IMPL(RefName, RepoObject) + + /** + * @brief Create a RefName (without Repository association) + * + * @param[in] refName Fully qualified reference name to analyze. + * + * Some kind of analyzations can only be performed when a repository is given. + * + */ RefName::RefName(const QString& refName) - : Base(*new Internal::RefNamePrivate) + : RepoObject(new Private) { GW_D(RefName); d->fqrn = refName; - d->isAnalyzed = false; - } - - RefName::~RefName() - { } - RefName& RefName::operator=(const RefName& other) + /** + * @brief Create a RefName (with Repository association) + * + * @param[in] refName Fully qualified reference name to analyze. + * + * Some kind of analyzations can only be performed when a repository is given. + * + */ + RefName::RefName(const Repository& repo, const QString& refName) + : RepoObject(new Private(Private::dataOf(repo),refName)) { - Base::operator =(other); - return *this; } /** @@ -432,6 +477,18 @@ namespace Git return d ? d->ensureAnalyzed(), d->isTag : false; } + /** + * @brief Is this a note? + * + * @return `true`, if this is a note + * + */ + bool RefName::isNote() + { + GW_D(RefName); + return d ? d->ensureAnalyzed(), d->isNote : false; + } + /** * @brief Is this a branch? * @@ -536,13 +593,13 @@ namespace Git /** * @brief Get the local name of the reference * - * @return If the reference is either a tag, a branch or HEAD, the scopeName() and name() - * are joined via a `/` and the result is returned. + * @return If the reference is either a tag, a note, a branch or HEAD, the scopeName() and + * name() are joined via a `/` and the result is returned. * */ QString RefName::localName() { - if (isBranch() || isTag()) { + if (isBranch() || isTag() || isNote()) { return isScoped() ? scopeName() % QChar(L'/') % name() : name(); } return QString(); @@ -592,6 +649,17 @@ namespace Git return isTag() ? localName() : QString(); } + /** + * @brief Get the name of the note if this reference is a note. + * + * @return If isNote() returns `true` then return localName() else an empty string. + * + */ + QString RefName::noteName() + { + return isNote() ? localName() : QString(); + } + /** * @brief Get the joined namespaces * @@ -708,6 +776,8 @@ namespace Git * short hand name for the remote `farfarawawy`'s default branch is just `farfaraway` (the FQRN * would be `refs/remotes/farfaraway/HEAD`). * + * Note that this deliberately doesn't work with `refs/notes/` references. + * * @return The short hand name for the reference. The short hand name contains the segments * consisting of remote() if present, all the scopes() and finally name(). * @@ -747,4 +817,21 @@ namespace Git return segments.join(QChar(L'/')); } + /** + * @brief Get the Reference this RefName was created from + * + * @return If this RefName object was created from a Reference, return that reference + * otherwise an invalid Reference object. + */ + Reference RefName::reference() const + { + GW_CD_EX(Reference); + + if (d && d->isRealReference()) { + return Reference(d); + } + + return Reference(); + } + } diff --git a/libGitWrap/RefName.hpp b/libGitWrap/RefName.hpp index b5bb195..b6188f6 100644 --- a/libGitWrap/RefName.hpp +++ b/libGitWrap/RefName.hpp @@ -19,11 +19,12 @@ #ifndef GIT_REF_NAME_HPP #define GIT_REF_NAME_HPP +#pragma once #include #include -#include "libGitWrap/Base.hpp" +#include "libGitWrap/RepoObject.hpp" namespace Git { @@ -35,20 +36,20 @@ namespace Git } - class GITWRAP_API RefName : public Base + class GITWRAP_API RefName : public RepoObject { + GW_PRIVATE_DECL(RefName, RepoObject, public) + public: - RefName(); - RefName(const RefName& other); + explicit RefName(const Repository& repo, const QString& refName); explicit RefName(const QString& refName); - ~RefName(); - RefName& operator=(const RefName& other); public: bool isRemote(); bool isTag(); bool isBranch(); + bool isNote(); bool isStage(); bool isHead(); @@ -74,12 +75,15 @@ namespace Git QString scopePrefix(); QString tagName(); + QString noteName(); QString branchName(); QString shorthand(); bool matchesCustomRule(int id); + Reference reference() const; + public: static int registerExpression(void* data, const QRegExp& regExp); static void unregisterExpression(int id); diff --git a/libGitWrap/RefSpec.cpp b/libGitWrap/RefSpec.cpp index 5715445..2dbe98d 100644 --- a/libGitWrap/RefSpec.cpp +++ b/libGitWrap/RefSpec.cpp @@ -14,9 +14,9 @@ * */ -#include "RefSpec.hpp" +#include "libGitWrap/RefSpec.hpp" -#include "Private/GitWrapPrivate.hpp" +#include "libGitWrap/Private/GitWrapPrivate.hpp" namespace Git { diff --git a/libGitWrap/RefSpec.hpp b/libGitWrap/RefSpec.hpp index af175c4..74d4b48 100644 --- a/libGitWrap/RefSpec.hpp +++ b/libGitWrap/RefSpec.hpp @@ -17,7 +17,7 @@ #ifndef GIT_REFSPEC_H #define GIT_REFSPEC_H -#include "GitWrap.hpp" +#include "libGitWrap/GitWrap.hpp" namespace Git { diff --git a/libGitWrap/Reference.cpp b/libGitWrap/Reference.cpp index ccf2df3..062d642 100644 --- a/libGitWrap/Reference.cpp +++ b/libGitWrap/Reference.cpp @@ -14,69 +14,108 @@ * */ -#include "ObjectCommit.hpp" -#include "ObjectId.hpp" -#include "Repository.hpp" -#include "Reference.hpp" -#include "RefName.hpp" - -#include "Private/GitWrapPrivate.hpp" -#include "Private/ReferencePrivate.hpp" +#include + +#include "libGitWrap/Commit.hpp" +#include "libGitWrap/Tree.hpp" +#include "libGitWrap/ObjectId.hpp" +#include "libGitWrap/Repository.hpp" +#include "libGitWrap/Reference.hpp" +#include "libGitWrap/RefName.hpp" +#include "libGitWrap/BranchRef.hpp" +#include "libGitWrap/TagRef.hpp" +#include "libGitWrap/NoteRef.hpp" + +#include "libGitWrap/Operations/CheckoutOperation.hpp" + +#include "libGitWrap/Private/GitWrapPrivate.hpp" +#include "libGitWrap/Private/ObjectPrivate.hpp" +#include "libGitWrap/Private/ReferencePrivate.hpp" +#include "libGitWrap/Private/BranchRefPrivate.hpp" +#include "libGitWrap/Private/TagRefPrivate.hpp" +#include "libGitWrap/Private/NoteRefPrivate.hpp" namespace Git { + /** + * @class Reference + * @ingroup GitWrap + * @brief Represents a git reference + * + */ namespace Internal { - ReferencePrivate::ReferencePrivate(RepositoryPrivate* repo, git_reference* ref) - : RepoObjectPrivate(repo) - , mRef(ref) + ReferencePrivate::ReferencePrivate(const RepositoryPrivate::Ptr& repo, git_reference* ref) + : RefNamePrivate(repo.data()) + , wasDeleted(false) + , reference(ref) + { + Q_ASSERT(reference); + fqrn = QString::fromUtf8(git_reference_name(reference)); + } + + ReferencePrivate::ReferencePrivate(const RepositoryPrivate::Ptr& repo, const QString& name, + git_reference* ref) + : RefNamePrivate(repo.data(), name) + , wasDeleted(false) + , reference(ref) + { + Q_ASSERT(reference); + } + + ReferencePrivate::ReferencePrivate(git_reference* ref, const RefNamePrivate* refName) + : RefNamePrivate(refName) + , wasDeleted(false) + , reference(ref) { - Q_ASSERT(ref); } ReferencePrivate::~ReferencePrivate() { - git_reference_free(mRef); + // We have to free the reference, no matter whether it was deleted or not. + git_reference_free(reference); } - } + bool ReferencePrivate::isRealReference() const + { + // This is used in RefName to determine if we can safely cast back to a Reference. + return true; + } - Reference::Reference() - { - } + ReferenceKinds ReferencePrivate::kind() const + { + return UnknownReference; + } - Reference::Reference(Internal::ReferencePrivate& _d) - : RepoObject(_d) - { - } + bool ReferencePrivate::isValidObject(Result &r) const + { + if (wasDeleted) { + r.setError("Tried to access a destroyed reference.", GIT_ERROR); + return false; + } + return r; + } - Reference::Reference( const Reference& other ) - : RepoObject(other) - { - } + CheckoutBaseOperation* ReferencePrivate::checkoutOperation(Result& result) const + { + Reference ref(this); + QScopedPointer op(new CheckoutTreeOperation); + op->setRepository(repo()); - Reference::~Reference() - { - } + op->setTree(ref.peeled(result)); + if (!result) { + return NULL; + } - Reference& Reference::operator=( const Reference& other ) - { - RepoObject::operator=(other); - return * this; - } + return op.take(); + } - bool Reference::operator==(const Reference &other) const - { - return RepoObject::operator==(other); } - bool Reference::operator!=(const Reference &other) const - { - return !( *this == other ); - } + GW_PRIVATE_IMPL(Reference, RepoObject) /** * @brief Compares two reference objects. @@ -87,20 +126,23 @@ namespace Git * * Note: References of different types are considered to be different. * + * This method sorts invalid Reference objects before valid ones. A Reference object that was + * destroied with the destroy() method will be treated as invalid. + * */ int Reference::compare(const Reference &other) const { GW_CD(Reference); Private* od = Private::dataOf(other); - if (!d) { + if (!d || d->wasDeleted) { return od ? -1 : 0; } - if (!od) { + if (!od || od->wasDeleted) { return 1; } - return git_reference_cmp(d->mRef, od->mRef); + return git_reference_cmp(d->reference, od->reference); } /** @@ -153,7 +195,7 @@ namespace Git return Reference(); } - return *new Private(repop, ref); + return Private::createRefObject(repop, name, ref); } @@ -177,14 +219,13 @@ namespace Git * */ Reference Reference::create(Result& result, Repository repo, - const QString& name, const ObjectCommit& commit) + const QString& name, const Commit& commit) { if (!commit.isValid()) { + result.setInvalidObject(); return Reference(); } - - ObjectId sha = commit.id(result); - return create(result, repo, name, sha); + return create(result, repo, name, commit.id()); } /** @@ -196,12 +237,12 @@ namespace Git { GW_CD(Reference); - if (!d) { + if (!d || d->wasDeleted) { GitWrap::lastResult().setInvalidObject(); return QString(); } - return QString::fromUtf8( git_reference_name( d->mRef ) ); + return d->fqrn; } /** @@ -212,7 +253,8 @@ namespace Git */ RefName Reference::nameAnalyzer() const { - return RefName(name()); + GW_CD_EX(Reference); + return RefName(d); } /** @@ -223,153 +265,229 @@ namespace Git QString Reference::prefix() const { const QString tmpName = name(); - return tmpName.left( tmpName.length() - shorthand().length() ); + return tmpName.left(tmpName.length() - shorthand().length()); } QString Reference::shorthand() const { GW_CD(Reference); - if (!d) { + if (!d || d->wasDeleted) { GitWrap::lastResult().setInvalidObject(); return QString(); } - return QString::fromUtf8( git_reference_shorthand( d->mRef ) ); + return QString::fromUtf8(git_reference_shorthand(d->reference)); } - Reference::Type Reference::type( Result& result ) const + ReferenceTypes Reference::type() const { - GW_CD_CHECKED(Reference, Invalid, result) + GW_CD(Reference); + if (!d || d->wasDeleted) { + return ReferenceInvalid; + } - switch( git_reference_type( d->mRef ) ) - { - case GIT_REF_SYMBOLIC: return Symbolic; - case GIT_REF_OID: return Direct; + switch (git_reference_type(d->reference)) { default: - case GIT_REF_INVALID: return Invalid; + case GIT_REF_INVALID: return ReferenceInvalid; + case GIT_REF_SYMBOLIC: return ReferenceSymbolic; + case GIT_REF_OID: return ReferenceDirect; } } - ObjectId Reference::objectId( Result& result ) const + ObjectId Reference::objectId() const { - GW_CD_CHECKED(Reference, ObjectId(), result); + GW_CD(Reference); + if (!d || d->wasDeleted) { + return ObjectId(); + } - if (type(result) != Direct) - { + if (type() != ReferenceDirect) { return ObjectId(); } - return ObjectId::fromRaw( git_reference_target( d->mRef )->id ); + return Private::oid2sha(git_reference_target(d->reference)); } - QString Reference::target( Result& result ) const + QString Reference::target() const { - GW_CD_CHECKED(Reference, QString(), result) + GW_CD(Reference); + if (!d || d->wasDeleted) { + return QString(); + } - if (!type(result) == Symbolic) { + if (type() != ReferenceSymbolic) { return QString(); } - return QString::fromUtf8( git_reference_symbolic_target( d->mRef ) ); + return QString::fromUtf8(git_reference_symbolic_target(d->reference)); } Reference Reference::resolved( Result& result ) const { - GW_CD_CHECKED(Reference, Reference(), result) + GW_CD_CHECKED(Reference, Reference(), result); git_reference* ref; - result = git_reference_resolve( &ref, d->mRef ); - if( !result ) - { + result = git_reference_resolve(&ref, d->reference); + if (!result) { return Reference(); } - return *new Internal::ReferencePrivate( d->repo(), ref ); + return PrivatePtr(new Private(d->repo(), ref)); } ObjectId Reference::resolveToObjectId( Result& result ) const { - Reference resolvedRef = resolved( result ); + Reference resolvedRef = resolved(result); if (!result) { return ObjectId(); } - return resolvedRef.objectId( result ); + return resolvedRef.objectId(); } bool Reference::isCurrentBranch() const { GW_CD(Reference); - return d && git_branch_is_head( d->mRef ); + return d && !d->wasDeleted && git_branch_is_head(d->reference); + } + + bool Reference::isBranch() const + { + GW_CD(Reference); + return d && !d->wasDeleted && git_reference_is_branch(d->reference); } bool Reference::isLocal() const { GW_CD(Reference); - if (!d) { + if (!d || d->wasDeleted) { GitWrap::lastResult().setInvalidObject(); return false; } - return git_reference_is_branch( d->mRef ); + return git_reference_is_branch(d->reference); } bool Reference::isRemote() const { GW_CD(Reference); - if (!d) { + if (!d || d->wasDeleted) { GitWrap::lastResult().setInvalidObject(); return false; } - return git_reference_is_remote( d->mRef ); + return git_reference_is_remote(d->reference); } - void Reference::checkout(Result &result, bool force, bool updateHEAD, - const QStringList &paths) const + Object Reference::peeled(Result& result, ObjectType ot) const + { + GW_CD_CHECKED(Reference, Object(), result); + + git_object* o = NULL; + result = git_reference_peel(&o, d->reference, Internal::objectType2gitotype(ot)); + + if (!result) { + return Object(); + } + + return Object::Private::create(d->repo(), o); + } + + CheckoutBaseOperation* Reference::checkoutOperation(Result& result) const + { + GW_CD_CHECKED(Reference, NULL, result); + return d->checkoutOperation(result); + } + + void Reference::checkout(Result& result, + CheckoutOptions opts, + CheckoutMode mode, + const QStringList& paths) const { GW_CD_CHECKED_VOID(Reference, result); + QString refToUpdate = name(); - git_object *o = NULL; - result = git_reference_peel( &o, d->mRef, GIT_OBJ_TREE ); - if ( !result ) return; + QScopedPointer op(checkoutOperation(result)); + if (!result) { + return; + } - git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; - opts.checkout_strategy = force ? GIT_CHECKOUT_FORCE : GIT_CHECKOUT_SAFE; - if ( !paths.isEmpty() ) - { - // TODO: don't copy, just map paths here - result = git_strarray_copy( &opts.paths, Internal::StrArrayWrapper( paths ) ); - if ( !result ) return; + bool doCreateLocal = opts.testFlag(CheckoutCreateLocalBranch); + bool doUpdateHEAD = opts.testFlag(CheckoutUpdateHEAD); + bool doAllowDetached = opts.testFlag(CheckoutAllowDetachHEAD); + bool doForceDetached = opts.testFlag(CheckoutForceDetachHEAD); + + /* + if (doCreateLocal) { + if (!op->supports(CheckoutCreateLocalBranch) ) { + result.setError("Operation not supported."); + return; + } + } + */ + + op->setOptions(opts); + op->setMode(mode); + op->setCheckoutPaths(paths); + op->setBackgroundMode(false); + + result = op->execute(); + if (!result) { + return; } - result = git_checkout_tree( d->repo()->mRepo, o, &opts ); - if ( updateHEAD ) - this->updateHEAD(result); + if (doUpdateHEAD) { + + } } + /** + * @brief Delete this reference + * + * The reference is deleted from the underlying data store. This does not mean, that the + * Reference object or any copies of it will become invalid, but when you try to invoke any + * method on this Reference object, it will fail. + * + * @param[in,out] result A Result object; see @ref GitWrapErrorHandling + * + */ void Reference::destroy(Result& result) { GW_D_CHECKED_VOID(Reference, result); - result = git_reference_delete( d->mRef ); + + result = git_reference_delete(d->reference); + + if (result) { + d->wasDeleted = true; + } + } + + bool Reference::wasDestroyed() const + { + GW_CD(Reference); + return d && d->wasDeleted; } - void Reference::move(Result &result, const ObjectCommit &target) + void Reference::move(Result &result, const Commit &target) { GW_D_CHECKED_VOID(Reference, result); - const ObjectId &targetId = target.id(result); - if ( !result || targetId.isNull() ) return; + ObjectId targetId = target.id(); + if (targetId.isNull()) { + return; + } git_reference* newRef = NULL; - result = git_reference_set_target( &newRef, d->mRef, Internal::ObjectId2git_oid( targetId ) ); - if ( result && (newRef != d->mRef) ) - { - git_reference_free( d->mRef ); - d->mRef = newRef; + result = git_reference_set_target(&newRef, d->reference, Private::sha(targetId)); + + if (result && (newRef != d->reference)) { + // even though we have a nre d->reference now, the name did not change. So nothing to + // update down in RefName's data. + git_reference_free(d->reference); + d->reference = newRef; } } @@ -378,30 +496,85 @@ namespace Git GW_D_CHECKED_VOID(Reference, result); git_reference* newRef = NULL; - result = git_reference_rename( &newRef, d->mRef, newName.toUtf8().constData(), force ); - if ( result && (newRef != d->mRef) ) - { - git_reference_free( d->mRef ); - d->mRef = newRef; + result = git_reference_rename(&newRef, d->reference, newName.toUtf8().constData(), force); + + if (result && (newRef != d->reference)) { + git_reference_free(d->reference); + + d->reference = newRef; + d->fqrn = newName; // Reset RefName's data + d->isAnalyzed = false; } } + /** + * @brief Point the repository's HEAD here + * + * Set HEAD detached to where this reference currently points to. + * + * @param[in,out] result A Result object; see @ref GitWrapErrorHandling + * + */ + void Reference::setAsDetachedHEAD(Result& result) const + { + GW_CD_CHECKED_VOID(Reference, result); + peeled(result).setAsDetachedHEAD(result); + } + void Reference::updateHEAD(Result &result) const { - GW_D_CHECKED_VOID(Reference, result); + GW_CD_CHECKED_VOID(Reference, result); - if (git_reference_is_branch(d->mRef)) { + if (git_reference_is_branch(d->reference)) { // reference is a local branch result = git_repository_set_head( d->repo()->mRepo, - git_reference_name(d->mRef)); + git_reference_name(d->reference)); } else { // reference is detached result = git_repository_set_head_detached( d->repo()->mRepo, - git_reference_target(d->mRef) ); + git_reference_target(d->reference)); + } + } + + ReferenceKinds Reference::kind() const + { + GW_CD(Reference); + + if (d && !d->wasDeleted) { + return d->kind(); + } + + return UnknownReference; + } + + BranchRef Reference::asBranch() const + { + if (kind() == BranchReference) { + GW_CD_EX(BranchRef); + return BranchRef(d); + } + return BranchRef(); + } + + TagRef Reference::asTag() const + { + if (kind() == TagReference) { + GW_CD_EX(TagRef); + return TagRef(d); + } + return TagRef(); + } + + NoteRef Reference::asNote() const + { + if (kind() == NoteReference) { + GW_CD_EX(NoteRef); + return NoteRef(d); } + return NoteRef(); } } diff --git a/libGitWrap/Reference.hpp b/libGitWrap/Reference.hpp index faed419..f5e7914 100644 --- a/libGitWrap/Reference.hpp +++ b/libGitWrap/Reference.hpp @@ -18,6 +18,7 @@ #define GIT_REFERENCE_H #include "libGitWrap/RepoObject.hpp" +#include "libGitWrap/Object.hpp" namespace Git { @@ -27,32 +28,13 @@ namespace Git class ReferencePrivate; } - /** - * @ingroup GitWrap - * @brief Represents a git reference - * - */ + class CheckoutBaseOperation; + class GITWRAP_API Reference : public RepoObject { + GW_PRIVATE_DECL(Reference, RepoObject, public) public: - typedef Internal::ReferencePrivate Private; - - enum Type - { - Direct, Symbolic, Invalid = -1 - }; - - public: - Reference(); - Reference(Internal::ReferencePrivate& _d); - Reference( const Reference& other ); - ~Reference(); - Reference& operator=( const Reference& other ); - - bool operator==( const Reference& other ) const; - bool operator!=( const Reference& other ) const; - - int compare( const Reference& other ) const; + int compare(const Reference& other) const; public: static Reference create( @@ -65,7 +47,7 @@ namespace Git Result& result, Repository repo, const QString& name, - const ObjectCommit& commit); + const Commit& commit); public: QString name() const; @@ -74,32 +56,61 @@ namespace Git RefName nameAnalyzer() const; - Type type( Result& result ) const; - ObjectId objectId( Result& result ) const; - QString target( Result& result ) const; + GW_DEPRECATED ReferenceTypes type(Result& result) const { return type(); } + GW_DEPRECATED ObjectId objectId(Result& result) const { return objectId(); } + GW_DEPRECATED QString target(Result& result) const { return target(); } + + ReferenceTypes type() const; + ObjectId objectId() const; + QString target() const; Reference resolved( Result& result ) const; ObjectId resolveToObjectId( Result& result ) const; + Object peeled(Result& result, ObjectType ot) const; + + template< class T > + T peeled(Result& result) const; + + ReferenceKinds kind() const; + + BranchRef asBranch() const; + TagRef asTag() const; + NoteRef asNote() const; + + template + T as() const; + bool isCurrentBranch() const; + bool isBranch() const; bool isLocal() const; bool isRemote() const; + bool wasDestroyed() const; + CheckoutBaseOperation* checkoutOperation(Result& result) const; void checkout( Result& result, - bool force = false, - bool updateHEAD = true, + CheckoutOptions opts = CheckoutNone, + CheckoutMode mode = CheckoutSafeCreate, const QStringList &paths = QStringList() ) const; void destroy( Result& result ); - void move( Result &result, const ObjectCommit &target ); + void setAsDetachedHEAD(Result& result) const; + + void move( Result &result, const Commit &target ); void rename(Result &result, const QString &newName , bool force = false ); void updateHEAD(Result &result) const; }; + template< class T > + inline T Reference::peeled(Result& result) const + { + return peeled(result, ObjectType(T::ObjectTypeId)).as(); + } + } -Q_DECLARE_METATYPE( Git::Reference ) +Q_DECLARE_METATYPE(Git::Reference) #endif diff --git a/libGitWrap/Remote.cpp b/libGitWrap/Remote.cpp index 8fc8823..7749b32 100644 --- a/libGitWrap/Remote.cpp +++ b/libGitWrap/Remote.cpp @@ -14,11 +14,11 @@ * */ -#include "Remote.hpp" -#include "Reference.hpp" -#include "RefSpec.hpp" +#include "libGitWrap/Remote.hpp" +#include "libGitWrap/Reference.hpp" +#include "libGitWrap/RefSpec.hpp" -#include "Private/RemotePrivate.hpp" +#include "libGitWrap/Private/RemotePrivate.hpp" namespace Git { @@ -26,7 +26,7 @@ namespace Git namespace Internal { - RemotePrivate::RemotePrivate(RepositoryPrivate* repo, git_remote* remote) + RemotePrivate::RemotePrivate(Repository::Private* repo, git_remote* remote) : RepoObjectPrivate(repo) , mRemote(remote) { @@ -40,28 +40,39 @@ namespace Git } - Remote::Remote() - { - } + GW_PRIVATE_IMPL(Remote, RepoObject) - Remote::Remote(Internal::RemotePrivate& _d) - : RepoObject(_d) + Remote Remote::create(Result& result, const Repository& repository, const QString& name, + const QString& url, const QString& fetchSpec) { - } + if (!result) { + return Remote(); + } - Remote::Remote(const Remote& other) - : RepoObject(other) - { - } + if (!repository.isValid()) { + result.setInvalidObject(); + return Remote(); + } - Remote::~Remote() - { - } + Repository::Private* rp = Private::dataOf(repository); - Remote& Remote::operator=(const Remote& other) - { - RepoObject::operator =(other); - return * this; + git_remote* remote = NULL; + result = git_remote_create(&remote, rp->mRepo, name.toUtf8().constData(), + url.toUtf8().constData() ); + if (!result) { + return Remote(); + } + + Remote remo = new Remote::Private(rp, remote); + + if (!fetchSpec.isEmpty()) { + remo.addFetchSpec(result, fetchSpec); + if (!result) { + return Remote(); + } + } + + return remo; } bool Remote::save( Result& result ) diff --git a/libGitWrap/Remote.hpp b/libGitWrap/Remote.hpp index 2868d87..40badab 100644 --- a/libGitWrap/Remote.hpp +++ b/libGitWrap/Remote.hpp @@ -37,18 +37,14 @@ namespace Git */ class GITWRAP_API Remote : public RepoObject { - public: - typedef Internal::RemotePrivate Private; + GW_PRIVATE_DECL(Remote, RepoObject, public); public: typedef RemoteList List; public: - Remote(); - Remote(Internal::RemotePrivate& _d); - Remote(const Remote& other); - ~Remote(); - Remote& operator=( const Remote& other ); + static Remote create(Result& result, const Repository& repository, const QString& name, + const QString& url, const QString& fetchSpec); public: bool save( Result& result ); diff --git a/libGitWrap/RepoObject.cpp b/libGitWrap/RepoObject.cpp index 0011c38..de485ae 100644 --- a/libGitWrap/RepoObject.cpp +++ b/libGitWrap/RepoObject.cpp @@ -26,32 +26,31 @@ namespace Git namespace Internal { - RepoObjectPrivate::RepoObjectPrivate(RepositoryPrivate* repo) + RepoObjectPrivate::RepoObjectPrivate() : BasePrivate() - , mRepo(repo) { } - RepositoryPrivate* RepoObjectPrivate::repo() const + RepoObjectPrivate::RepoObjectPrivate(const RepositoryPrivate::Ptr& repo) + : BasePrivate() + , mRepo(repo) { - return mRepo.data(); } - } + RepoObjectPrivate::RepoObjectPrivate(RepositoryPrivate* repo) + : BasePrivate() + , mRepo(repo) + { + } - RepoObject::RepoObject() - { - } + Repository::PrivatePtr RepoObjectPrivate::repo() const + { + return mRepo; + } - RepoObject::RepoObject(Internal::RepoObjectPrivate& _d) - : Base(_d) - { } - bool RepoObject::operator==(const RepoObject& other) const - { - return Base::operator==(other); - } + GW_PRIVATE_IMPL(RepoObject, Base) Repository RepoObject::repository(Result &result) const { @@ -61,7 +60,7 @@ namespace Git Repository RepoObject::repository() const { GW_CD(RepoObject); - return Repository(*d->repo()); + return d->repo(); } } diff --git a/libGitWrap/RepoObject.hpp b/libGitWrap/RepoObject.hpp index 697accb..65cc67e 100644 --- a/libGitWrap/RepoObject.hpp +++ b/libGitWrap/RepoObject.hpp @@ -34,18 +34,10 @@ namespace Git class GITWRAP_API RepoObject : public Base { + GW_PRIVATE_DECL(RepoObject, Base, protected) public: - RepoObject(); - - public: - bool operator==(const RepoObject& other) const; - - public: - Repository repository(Result &result) const; + GW_DEPRECATED Repository repository(Result &result) const; Repository repository() const; - - protected: - RepoObject(Internal::RepoObjectPrivate& _d); }; } diff --git a/libGitWrap/Repository.cpp b/libGitWrap/Repository.cpp index e7b7432..884d02d 100644 --- a/libGitWrap/Repository.cpp +++ b/libGitWrap/Repository.cpp @@ -14,27 +14,34 @@ * */ -#include "Result.hpp" -#include "Index.hpp" -#include "Remote.hpp" -#include "Repository.hpp" -#include "Reference.hpp" -#include "DiffList.hpp" -#include "Object.hpp" -#include "ObjectTag.hpp" -#include "ObjectTree.hpp" -#include "ObjectBlob.hpp" -#include "ObjectCommit.hpp" -#include "RevisionWalker.hpp" - -#include "Private/GitWrapPrivate.hpp" -#include "Private/IndexPrivate.hpp" -#include "Private/RemotePrivate.hpp" -#include "Private/RepositoryPrivate.hpp" -#include "Private/ReferencePrivate.hpp" -#include "Private/DiffListPrivate.hpp" -#include "Private/ObjectPrivate.hpp" -#include "Private/RevisionWalkerPrivate.hpp" +#include + +#include "libGitWrap/Result.hpp" +#include "libGitWrap/Index.hpp" +#include "libGitWrap/Remote.hpp" +#include "libGitWrap/Repository.hpp" +#include "libGitWrap/Reference.hpp" +#include "libGitWrap/DiffList.hpp" +#include "libGitWrap/Object.hpp" +#include "libGitWrap/Tag.hpp" +#include "libGitWrap/Tree.hpp" +#include "libGitWrap/Blob.hpp" +#include "libGitWrap/Commit.hpp" +#include "libGitWrap/RevisionWalker.hpp" +#include "libGitWrap/Submodule.hpp" +#include "libGitWrap/BranchRef.hpp" +#include "libGitWrap/TagRef.hpp" +#include "libGitWrap/NoteRef.hpp" + +#include "libGitWrap/Private/GitWrapPrivate.hpp" +#include "libGitWrap/Private/IndexPrivate.hpp" +#include "libGitWrap/Private/RemotePrivate.hpp" +#include "libGitWrap/Private/RepositoryPrivate.hpp" +#include "libGitWrap/Private/ReferencePrivate.hpp" +#include "libGitWrap/Private/DiffListPrivate.hpp" +#include "libGitWrap/Private/ObjectPrivate.hpp" +#include "libGitWrap/Private/SubmodulePrivate.hpp" +#include "libGitWrap/Private/RevisionWalkerPrivate.hpp" #include @@ -54,6 +61,12 @@ namespace Git { Q_ASSERT( mRepo ); + if (openedFrom.isValid()) { + Submodule::Private* smp = dataOf(openedFrom); + Q_ASSERT(smp); + smp->mSubRepo = NULL; + } + // This assert may not look right in the first place, but it IS: // mIndex is of type IndexPrivate* and will get a value as soon as Repository::index() // is called for the first time. IndexPrivate is a RepoObject and as such it increases @@ -91,63 +104,18 @@ namespace Git { cb_append_reference_data *data = (cb_append_reference_data *)payload; - data->refs.append(*new ReferencePrivate(data->ptr, reference)); + QString name = QString::fromUtf8(git_reference_name(reference)); + Reference::Private* ref = Reference::Private::createRefObject( + data->ptr, name, reference); + + data->refs.append(ref); return 0; } } - /** - * @internal - * @brief Create a Repository object - * @param[in] _d Pointer to private data. - */ - Repository::Repository(Internal::RepositoryPrivate& _d ) - : Base(_d) - { - } - - /** - * @brief Copy Constructor - * - * Creates a Repository object that represents the same repository as @a o. If @a o is an - * invalid Repository object, this will become an invalid one too. - * - * @param[in] o An existing Repository object - * - */ - Repository::Repository(const Repository& other) - : Base(other) - { - } - - /** - * @brief Create an invalid Repository object - */ - Repository::Repository() - { - } - - /** - * @brief Destructor - */ - Repository::~Repository() - { - } - - /** - * @brief Assignment operator - * - * @param[in] o An existing Repository object - * - * @return A reference to this repository object. - */ - Repository& Repository::operator=(const Repository& other) - { - Base::operator=(other); - return * this; - } + GW_PRIVATE_IMPL(Repository, Base) /** * @brief Create a new repository @@ -186,7 +154,7 @@ namespace Git return Repository(); } - return Repository(*new Internal::RepositoryPrivate(repo)); + return PrivatePtr(new Private(repo)); } /** @@ -244,6 +212,7 @@ namespace Git * @a path. * * @param[in] path The path of the repository to open. + * * @param[in,out] result A result object; see @ref GitWrapErrorHandling * * @return If successful, a `Repository` object for the opened repostiory will be returned. @@ -268,7 +237,23 @@ namespace Git return Repository(); } - return Repository(*new Internal::RepositoryPrivate(repo)); + return PrivatePtr(new Private(repo)); + } + + /** + * @brief Open a independant instance of this repository + * + * @param[in,out] result A result object; see @ref GitWrapErrorHandling + * + * @return A Repository object that refers to the same repository, but actually is + * absolutely independant of this repository object. + * + * The repository is opened using the working directory path, not the .git path. + * + */ + Repository Repository::reopen(Result& result) const + { + return open(basePath(), result); } /** @@ -334,10 +319,10 @@ namespace Git return Index(); } - d->mIndex = new Internal::IndexPrivate(d, index); + d->mIndex = new Index::Private(PrivatePtr(d), index); } - return Index(*d->mIndex); + return Index::PrivatePtr(d->mIndex); } /** @@ -620,7 +605,7 @@ namespace Git Reference Repository::HEAD( Result& result ) const { - GW_D_CHECKED(Repository, Reference(), result); + GW_CD_EX_CHECKED(Repository, Reference(), result); git_reference* refHead = NULL; @@ -630,92 +615,72 @@ namespace Git return Reference(); } - return *new Internal::ReferencePrivate(d, refHead); + return Reference::PrivatePtr(new Reference::Private(PrivatePtr(d), refHead)); } Object Repository::lookup( Result& result, const ObjectId& id, ObjectType ot ) { - GW_D_CHECKED(Repository, Object(), result); + GW_D_EX_CHECKED(Repository, Object(), result); git_object* obj = NULL; - git_otype gitObjType; - - switch( ot ) - { - case otAny: gitObjType = GIT_OBJ_ANY; break; - case otCommit: gitObjType = GIT_OBJ_COMMIT; break; - case otTree: gitObjType = GIT_OBJ_TREE; break; - case otTag: gitObjType = GIT_OBJ_TAG; break; - case otBlob: gitObjType = GIT_OBJ_BLOB; break; - default: Q_ASSERT( false ); return Object(); - } + git_otype gitObjType = Internal::objectType2gitotype(ot); - result = git_object_lookup( &obj, d->mRepo, (git_oid*) id.raw(), gitObjType ); - if( !result ) - { + result = git_object_lookup(&obj, d->mRepo, Private::sha(id), gitObjType); + if (!result) { return Object(); } - return *new Internal::ObjectPrivate(d, obj); + return Object::Private::create(d, obj); } - ObjectCommit Repository::lookupCommit(Result& result, const ObjectId& id) + Commit Repository::lookupCommit(Result& result, const ObjectId& id) { - return lookup( result, id, otCommit ).asCommit( result ); + return lookup( result, id, otCommit ).asCommit(); } - ObjectTree Repository::lookupTree(Result& result, const ObjectId& id) + Tree Repository::lookupTree(Result& result, const ObjectId& id) { - return lookup( result, id, otTree ).asTree( result ); + return lookup( result, id, otTree ).asTree(); } - ObjectBlob Repository::lookupBlob(Result& result, const ObjectId& id) + Blob Repository::lookupBlob(Result& result, const ObjectId& id) { - return lookup( result, id, otBlob ).asBlob( result ); + return lookup( result, id, otBlob ).asBlob(); } - ObjectTag Repository::lookupTag(Result& result, const ObjectId& id) + Tag Repository::lookupTag(Result& result, const ObjectId& id) { - return lookup( result, id, otTag ).asTag( result ); + return lookup( result, id, otTag ).asTag(); } Object Repository::lookup( Result& result, const QString& refName, ObjectType ot ) { - return lookup( result, lookupRef( result, refName ).resolveToObjectId( result ), ot ); + return lookup(result, reference(result, refName).resolveToObjectId(result), ot); } - ObjectCommit Repository::lookupCommit(Result& result, const QString& refName) + Commit Repository::lookupCommit(Result& result, const QString& refName) { - return lookupCommit( result, lookupRef( result, refName ).resolveToObjectId( result ) ); + return lookupCommit(result, reference(result, refName).resolveToObjectId(result)); } - ObjectTree Repository::lookupTree(Result& result, const QString& refName) + Tree Repository::lookupTree(Result& result, const QString& refName) { - return lookupTree( result, lookupRef( result, refName ).resolveToObjectId( result ) ); + return lookupTree(result, reference(result, refName).resolveToObjectId(result)); } - ObjectBlob Repository::lookupBlob(Result& result, const QString& refName) + Blob Repository::lookupBlob(Result& result, const QString& refName) { - return lookupBlob( result, lookupRef( result, refName ).resolveToObjectId( result ) ); + return lookupBlob(result, reference(result, refName).resolveToObjectId(result)); } - ObjectTag Repository::lookupTag(Result& result, const QString& refName) + Tag Repository::lookupTag(Result& result, const QString& refName) { - return lookupTag( result, lookupRef( result, refName ).resolveToObjectId( result ) ); + return lookupTag(result, reference(result, refName).resolveToObjectId(result)); } RevisionWalker Repository::newWalker( Result& result ) { - GW_D_CHECKED(Repository, RevisionWalker(), result); - git_revwalk* walker = NULL; - - result = git_revwalk_new( &walker, d->mRepo ); - if( !result ) - { - return RevisionWalker(); - } - - return *new Internal::RevisionWalkerPrivate(d, walker); + return RevisionWalker::create(result, *this); } bool Repository::shouldIgnore(Result& result, const QString& filePath) const @@ -743,7 +708,7 @@ namespace Git */ Remote::List Repository::allRemotes(Result& result) const { - GW_CD_CHECKED(Repository, Remote::List(), result); + GW_CD_EX_CHECKED(Repository, Remote::List(), result); git_strarray arr; result = git_remote_list( &arr, d->mRepo ); @@ -758,8 +723,7 @@ namespace Git if (!result) { return Remote::List(); } - Remote rm = *new Internal::RemotePrivate(const_cast< Internal::RepositoryPrivate* >(d), - remote); + Remote rm = new Remote::Private(d.data(), remote); remotes.append(rm); } @@ -801,7 +765,7 @@ namespace Git */ Remote Repository::remote(Result& result, const QString& remoteName) const { - GW_CD_CHECKED(Repository, Remote(), result); + GW_CD_EX_CHECKED(Repository, Remote(), result); git_remote* remote = NULL; result = git_remote_load( &remote, d->mRepo, remoteName.toUtf8().constData() ); @@ -811,60 +775,39 @@ namespace Git return Remote(); } - return *new Internal::RemotePrivate(const_cast(d), remote); + return new Remote::Private(d.data(), remote); } Remote Repository::createRemote(Result& result, const QString& remoteName, const QString& url, const QString& fetchSpec) { - GW_D_CHECKED(Repository, Remote(), result); - - git_remote* remote = NULL; - result = git_remote_create( &remote, d->mRepo, remoteName.toUtf8().constData(), - url.toUtf8().constData() ); - if( !result ) - { - return Remote(); - } - - Remote remo = *new Internal::RemotePrivate(d, remote); - - if( !fetchSpec.isEmpty() ) - { - remo.addFetchSpec( result, fetchSpec ); - if( !result ) - { - return Remote(); - } - } - - return remo; + return Remote::create(result, *this, remoteName, url, fetchSpec); } - DiffList Repository::diffCommitToCommit( Result& result, ObjectCommit oldCommit, - ObjectCommit newCommit ) + DiffList Repository::diffCommitToCommit( Result& result, Commit oldCommit, + Commit newCommit ) { return diffTreeToTree( result, oldCommit.tree( result ), newCommit.tree( result ) ); } - DiffList Repository::diffTreeToTree(Result& result, ObjectTree oldTree, ObjectTree newTree) + DiffList Repository::diffTreeToTree(Result& result, Tree oldTree, Tree newTree) { return oldTree.diffToTree( result, newTree ); } - DiffList Repository::diffIndexToTree(Result& result, ObjectTree oldTree) + DiffList Repository::diffIndexToTree(Result& result, Tree oldTree) { return oldTree.diffToIndex( result ); } - DiffList Repository::diffTreeToWorkingDir(Result& result, ObjectTree oldTree) + DiffList Repository::diffTreeToWorkingDir(Result& result, Tree oldTree) { return oldTree.diffToWorkingDir( result ); } DiffList Repository::diffIndexToWorkingDir( Result& result ) { - GW_D_CHECKED(Repository, DiffList(), result); + GW_D_EX_CHECKED(Repository, DiffList(), result); git_diff_list* diffList = NULL; result = git_diff_index_to_workdir( &diffList, d->mRepo, NULL, NULL ); @@ -873,7 +816,7 @@ namespace Git return DiffList(); } - return DiffList(*new Internal::DiffListPrivate(d, diffList)); + return DiffList::PrivatePtr(new DiffList::Private(d, diffList)); } namespace Internal @@ -885,12 +828,21 @@ namespace Git Submodule::List subs; }; - static int cb_enum_submodules( git_submodule* sm, const char* name, void* payload ) + static int cb_enum_submodules(git_submodule* sm, const char* name, void* payload) { - cb_enum_submodules_t* d = static_cast< cb_enum_submodules_t* >( payload ); - Q_ASSERT( d && name ); + cb_enum_submodules_t* d = static_cast(payload); + Q_ASSERT(d && name); + + Repository::PrivatePtr repo(d->repo); + d->subs.append(new SubmodulePrivate(repo, QString::fromUtf8(name))); + return 0; + } - d->subs.append( Submodule( d->repo, QString::fromUtf8( name ) ) ); + static int cb_enum_submodule_names(git_submodule* sm, const char* name, void* payload) + { + QStringList* sl = static_cast(payload); + Q_ASSERT(sl && name); + sl->append(QString::fromUtf8(name)); return 0; } @@ -910,28 +862,33 @@ namespace Git return data.subs; } - Submodule Repository::submodule(Result& result, const QString& name) + QStringList Repository::submoduleNames(Result& result) const { - GW_D_CHECKED(Repository, Submodule(), result); - return Submodule(d, name); + GW_CD_CHECKED(Repository, QStringList(), result); + QStringList names; + + result = git_submodule_foreach(d->mRepo, &Internal::cb_enum_submodule_names, &names); + if (!result) { + return QStringList(); + } + + return names; } - Reference Repository::lookupRef(Result& result, const QString& refName, bool dwim) + Submodule Repository::submodule(Result& result, const QString& name) const { - GW_D_CHECKED(Repository, Reference(), result); - - git_reference* ref = NULL; - if ( dwim ) - result = git_reference_dwim( &ref, d->mRepo, refName.toUtf8().constData() ); - else - result = git_reference_lookup( &ref, d->mRepo, refName.toUtf8().constData() ); + GW_CD_EX_CHECKED(Repository, Submodule(), result); - if( !result ) - { - return Reference(); + if (submoduleNames(result).contains(name)) { + return new Submodule::Private(d, name); } - return *new Internal::ReferencePrivate( d, ref ); + return Submodule(); + } + + Reference Repository::lookupRef(Result& result, const QString& refName, bool dwim) + { + return reference(result, refName, dwim); } /** @@ -955,4 +912,171 @@ namespace Git return result; } + /** + * @brief Set the HEAD to follow a branch + * + * @param[in,out] result A Result object; see @ref GitWrapErrorHandling + * + * @param[in] branchName The (possibly full qualified) reference name of the branch to + * follow. The branch doesn't need to exist. If it doesn't exist, + * the HEAD will become orphaned but point to the branch once it is + * created. + * + */ + void Repository::setHEAD(Result& result, const QString& branchName) + { + GW_D_CHECKED_VOID(Repository, result); + + result = git_repository_set_head(d->mRepo, branchName.toUtf8().constData()); + } + + /** + * @brief Set the HEAD to follow a branch + * + * @param[in,out] result A Result object; see @ref GitWrapErrorHandling + * + * @param[in] branch The branch to follow. + * + */ + void Repository::setHEAD(Result& result, const BranchRef& branch) + { + if (!result) { + return; + } + + if (!branch.isValid()) { + result.setInvalidObject(); + return; + } + + setHEAD(result, branch.name()); + } + + /** + * @brief Set the HEAD detached to a commit + * + * @param[in,out] result A Result object; see @ref GitWrapErrorHandling + * + * @param[in] commit The commit to point to. + * + */ + void Repository::setDetachedHEAD(Result& result, const Commit& commit) + { + GW_D_CHECKED_VOID(Repository, result); + + if (!commit.isValid()) { + result.setInvalidObject(); + return; + } + + setDetachedHEAD(result, commit.id()); + } + + /** + * @brief Set the HEAD detached to a commit + * + * @param[in,out] result A Result object; see @ref GitWrapErrorHandling + * + * @param[in] sha The has of the commit to point to. + * + */ + void Repository::setDetachedHEAD(Result& result, const ObjectId& sha) + { + GW_D_CHECKED_VOID(Repository, result); + result = git_repository_set_head_detached(d->mRepo, Private::sha(sha)); + } + + /** + * @brief Access the superproject for this repository + * + * @return If this repository was opened via Submodule::subRepository(), the Repository + * that owns the Submodule object from which this repository was opened. Otherwise + * an invalid Repository() object will be returned. + * + */ + Repository Repository::superproject() const + { + return superprojectSubmodule().repository(); + } + + /** + * @brief Access the superproject's submodule for this repository + * + * @return If this repository was opened via Submodule::subRepository(), this will return + * the Submodule object from which it was opened. + * + */ + Submodule Repository::superprojectSubmodule() const + { + GW_CD(Repository); + if (!d) { + return Submodule(); + } + + if (!d->openedFrom.isValid()) { + return Submodule(); + } + + return d->openedFrom; + } + + Reference Repository::reference(Result& result, const QString& refName, bool dwim) + { + GW_D_CHECKED(Repository, Reference(), result); + + //GW_D_EX_CHECKED(Repository, Reference(), result); + QString name = refName; + + git_reference* ref = NULL; + if (dwim) { + result = git_reference_dwim(&ref, d->mRepo, refName.toUtf8().constData()); + + if (!result) { + return Reference(); + } + + name = QString::fromUtf8(git_reference_name(ref)); + } + else { + result = git_reference_lookup( &ref, d->mRepo, refName.toUtf8().constData() ); + + if (!result) { + return Reference(); + } + } + + return Reference::Private::createRefObject(d, name, ref); + } + + BranchRef Repository::branchRef(Result& result, const QString& branchName) + { + Reference ref = reference(result, branchName, true); + if (!result) { + return BranchRef(); + } + + return ref.asBranch(); + } + + TagRef Repository::tagRef(Result& result, const QString& tagName) + { + Reference ref = reference(result, tagName, true); + if (!result) { + return TagRef(); + } + + return ref.asTag(); + } + + NoteRef Repository::noteRef(Result& result, const QString& noteName) + { + // dwin doesn't work for notes + Reference ref = reference(result, QLatin1Literal("refs/notes/") % noteName); + if (!result) { + return NoteRef(); + } + + return ref.asNote(); + } + } diff --git a/libGitWrap/Repository.hpp b/libGitWrap/Repository.hpp index b3bbf1c..bd86e0d 100644 --- a/libGitWrap/Repository.hpp +++ b/libGitWrap/Repository.hpp @@ -18,8 +18,8 @@ #define GIT_REPOSITORY_H #include "libGitWrap/Base.hpp" -#include "libGitWrap/Submodule.hpp" #include "libGitWrap/Remote.hpp" +#include "libGitWrap/Object.hpp" namespace Git { @@ -38,17 +38,7 @@ namespace Git */ class GITWRAP_API Repository : public Base { - public: - typedef Internal::RepositoryPrivate Private; - - public: - explicit Repository(Internal::RepositoryPrivate& _d); - Repository(); - Repository( const Repository& other ); - Repository& operator=( const Repository& other ); - - public: - ~Repository(); + GW_PRIVATE_DECL(Repository, Base, public) public: static Repository create( const QString& path, @@ -63,10 +53,17 @@ namespace Git static Repository open( const QString& path, Result& result ); + Repository reopen(Result& result) const; + bool isBare() const; bool isHeadDetached() const; bool detachHead(Result& result); + void setDetachedHEAD(Result& result, const ObjectId& sha); + void setDetachedHEAD(Result& result, const Commit& commit); + + void setHEAD(Result& result, const BranchRef& branch); + void setHEAD(Result& result, const QString& branchName); QString basePath() const; QString gitPath() const; @@ -84,56 +81,104 @@ namespace Git ResolvedRefs allResolvedRefs( Result& result ); + // ### move to BranchRef bool renameBranch( const QString& oldName, const QString& newName, bool force /* = false */, Result& result ); + Repository superproject() const; + Submodule superprojectSubmodule() const; + Index index( Result& result ); Git::StatusFlags status(Result &result, const QString &fileName) const; Git::StatusHash status(Result &result) const; Reference HEAD( Result& result ) const; - Reference lookupRef(Result& result, const QString& refName , bool dwim = false); - ObjectId resolveRef( Result& result, const QString& refName ); - Object lookup(Result& result, const ObjectId& id, ObjectType ot /* = otAny */); + GW_DEPRECATED Reference lookupRef(Result& result, const QString& refName , bool dwim = false); + ObjectId resolveRef(Result& result, const QString& refName); + + Reference reference(Result& result, const QString& refName, bool dwim = false); + BranchRef branchRef(Result& result, const QString& branchName); + TagRef tagRef(Result& result, const QString& tagName); + NoteRef noteRef(Result& result, const QString& noteName); + + // ### Deprecate and name these: commit, tree, blob and tag. + // ### Figure out what the QString-overload should be useful for! + Commit lookupCommit( Result& result, const ObjectId& id ); + Commit lookupCommit( Result& result, const QString& refName ); + + Tree lookupTree( Result& result, const ObjectId& id ); + Tree lookupTree( Result& result, const QString& refName ); + + Blob lookupBlob( Result& result, const ObjectId& id ); + Blob lookupBlob( Result& result, const QString& refName ); + + Tag lookupTag( Result& result, const ObjectId& id ); + Tag lookupTag( Result& result, const QString& refName ); - ObjectCommit lookupCommit( Result& result, const ObjectId& id ); - ObjectTree lookupTree( Result& result, const ObjectId& id ); - ObjectBlob lookupBlob( Result& result, const ObjectId& id ); - ObjectTag lookupTag( Result& result, const ObjectId& id ); + Object lookup(Result& result, const ObjectId& id, ObjectType ot); + Object lookup(Result& result, const QString& refName, ObjectType ot); - Object lookup(Result& result, const QString& refName, ObjectType ot /* = otAny */); + template< class T > + T lookup(Result& result, const ObjectId& id); - ObjectCommit lookupCommit( Result& result, const QString& refName ); - ObjectTree lookupTree( Result& result, const QString& refName ); - ObjectBlob lookupBlob( Result& result, const QString& refName ); - ObjectTag lookupTag( Result& result, const QString& refName ); + // ### Figure out, what this overload could be useful for! + template< class T > + T lookup(Result& result, const QString& refName); bool shouldIgnore( Result& result, const QString& filePath ) const; - RevisionWalker newWalker( Result& result ); + GW_DEPRECATED + RevisionWalker newWalker(Result& result); QStringList allRemoteNames( Result& result ) const; Remote::List allRemotes(Result& result) const; Remote remote( Result& result, const QString& remoteName ) const; - Remote createRemote( Result& result, const QString& remoteName, const QString& url, - const QString& fetchSpec ); - DiffList diffCommitToCommit(Result& result, ObjectCommit oldCommit, ObjectCommit newCommit); + GW_DEPRECATED + Remote createRemote(Result& result, const QString& remoteName, const QString& url, + const QString& fetchSpec); - DiffList diffTreeToTree( Result& result, ObjectTree oldTree, - ObjectTree newTree); + DiffList diffCommitToCommit(Result& result, Commit oldCommit, Commit newCommit); - DiffList diffIndexToTree( Result& result, ObjectTree oldTree ); + DiffList diffTreeToTree( Result& result, Tree oldTree, + Tree newTree); - DiffList diffTreeToWorkingDir( Result& result, ObjectTree oldTree ); + DiffList diffIndexToTree( Result& result, Tree oldTree ); + + DiffList diffTreeToWorkingDir( Result& result, Tree oldTree ); DiffList diffIndexToWorkingDir( Result& result ); - SubmoduleList submodules( Result& result ); - Submodule submodule( Result& result, const QString& name ); + SubmoduleList submodules(Result& result); + QStringList submoduleNames(Result& result) const; + Submodule submodule(Result& result, const QString& name) const; }; + template< class T > + inline T Repository::lookup(Result& result, const ObjectId& id) + { + return lookup(result, id, ObjectType(T::ObjectTypeId)).as(); + } + + template< class T > + inline T Repository::lookup(Result& result, const QString& refName) + { + return lookup(result, refName, ObjectType(T::ObjectTypeId)).as(); + } + + template<> + inline Object Repository::lookup(Result& result, const ObjectId& id) + { + return lookup(result, id, otAny); + } + + template<> + inline Object Repository::lookup(Result& result, const QString& refName) + { + return lookup(result, refName, otAny); + } + } Q_DECLARE_METATYPE( Git::Repository ) diff --git a/libGitWrap/Result.cpp b/libGitWrap/Result.cpp index 2780ea4..615eac7 100644 --- a/libGitWrap/Result.cpp +++ b/libGitWrap/Result.cpp @@ -14,9 +14,9 @@ * */ -#include "Result.hpp" +#include "libGitWrap/Result.hpp" -#include "Private/GitWrapPrivate.hpp" +#include "libGitWrap/Private/GitWrapPrivate.hpp" namespace Git { @@ -65,6 +65,25 @@ namespace Git } } + /** + * @internal + * @brief Set an error text. + * + * Sets @a szErrorText as text and @a code as error code. Sets the class to -1, which cannot be + * confused with libgit2 error classes. + * + * @param[in] szErrorText The text to set as error code. + * + * @param[in] code An error code to use. (Default to GIT_ERROR) + * + */ + void Result::setError(const char* szErrorText, int code) + { + mClass = -1; + mCode = code; + mText = QString::fromUtf8(szErrorText); + } + /** * @internal * @brief Assignment operator diff --git a/libGitWrap/Result.hpp b/libGitWrap/Result.hpp index 0f8799f..3603349 100644 --- a/libGitWrap/Result.hpp +++ b/libGitWrap/Result.hpp @@ -17,7 +17,7 @@ #ifndef GIT_ERROR_H #define GIT_ERROR_H -#include "GitWrap.hpp" +#include "libGitWrap/GitWrap.hpp" namespace Git { @@ -53,7 +53,8 @@ namespace Git void clear(); public: - void setError( int resultCode ); + void setError(const char* szErrorText, int code); + void setError(int resultCode); void setInvalidObject(); private: diff --git a/libGitWrap/RevisionWalker.cpp b/libGitWrap/RevisionWalker.cpp index 20ccc27..aab0721 100644 --- a/libGitWrap/RevisionWalker.cpp +++ b/libGitWrap/RevisionWalker.cpp @@ -40,23 +40,28 @@ namespace Git } - RevisionWalker::RevisionWalker() - { - } + GW_PRIVATE_IMPL(RevisionWalker, RepoObject) - RevisionWalker::RevisionWalker(Internal::RevisionWalkerPrivate& _d) - : RepoObject(_d) + RevisionWalker RevisionWalker::create(Result& result, const Repository& repository) { - } + if (!result) { + return RevisionWalker(); + } - RevisionWalker::~RevisionWalker() - { - } + if (!repository) { + return RevisionWalker(); + } - RevisionWalker& RevisionWalker::operator=(const RevisionWalker& other) - { - RepoObject::operator=(other); - return * this; + Repository::Private* rp = Private::dataOf(repository); + git_revwalk* walker = NULL; + + result = git_revwalk_new(&walker, rp->mRepo); + + if (!result) { + return RevisionWalker(); + } + + return new RevisionWalker::Private(rp, walker); } void RevisionWalker::reset( Result& result ) diff --git a/libGitWrap/RevisionWalker.hpp b/libGitWrap/RevisionWalker.hpp index 9f725e5..7b9a07d 100644 --- a/libGitWrap/RevisionWalker.hpp +++ b/libGitWrap/RevisionWalker.hpp @@ -34,11 +34,10 @@ namespace Git */ class GITWRAP_API RevisionWalker : public RepoObject { + GW_PRIVATE_DECL(RevisionWalker, RepoObject, public) + public: - RevisionWalker(); - RevisionWalker(Internal::RevisionWalkerPrivate& _d); - ~RevisionWalker(); - RevisionWalker& operator=( const RevisionWalker& other ); + static RevisionWalker create(Result& result, const Repository& repository); public: void reset( Result& result ); @@ -61,6 +60,6 @@ namespace Git } -Q_DECLARE_METATYPE( Git::RevisionWalker ) +Q_DECLARE_METATYPE(Git::RevisionWalker) #endif diff --git a/libGitWrap/Signature.cpp b/libGitWrap/Signature.cpp index e27f5c0..032edb7 100644 --- a/libGitWrap/Signature.cpp +++ b/libGitWrap/Signature.cpp @@ -14,9 +14,9 @@ * */ -#include "Signature.hpp" +#include "libGitWrap/Signature.hpp" -#include "Private/GitWrapPrivate.hpp" +#include "libGitWrap/Private/GitWrapPrivate.hpp" namespace Git { diff --git a/libGitWrap/Signature.hpp b/libGitWrap/Signature.hpp index c1ca8dc..f9e5ce1 100644 --- a/libGitWrap/Signature.hpp +++ b/libGitWrap/Signature.hpp @@ -17,7 +17,7 @@ #ifndef GIT_SIGNATURE_H #define GIT_SIGNATURE_H -#include "GitWrap.hpp" +#include "libGitWrap/GitWrap.hpp" namespace Git { diff --git a/libGitWrap/Submodule.cpp b/libGitWrap/Submodule.cpp index d26c672..33ab1e4 100644 --- a/libGitWrap/Submodule.cpp +++ b/libGitWrap/Submodule.cpp @@ -19,6 +19,7 @@ #include "libGitWrap/Repository.hpp" #include "libGitWrap/Private/RepositoryPrivate.hpp" +#include "libGitWrap/Private/SubmodulePrivate.hpp" namespace Git { @@ -26,32 +27,6 @@ namespace Git namespace Internal { - class SubmodulePrivate : public BasePrivate - { - public: - RepositoryPrivate::Ptr mOwnerRepo; - RepositoryPrivate::Ptr mMyRepo; - QString mName; - - public: - inline git_submodule* getSM( Result& rc ) const - { - git_submodule* sm = NULL; - - if( rc && mOwnerRepo && !mName.isEmpty() ) - { - rc = git_submodule_lookup( &sm, mOwnerRepo->mRepo, - mName.toUtf8().constData() ); - if( !rc ) - { - return NULL; - } - } - - return sm; - } - }; - /** * @internal * @ingroup GitWrap @@ -85,36 +60,54 @@ namespace Git return s; } - } - Submodule::Submodule() - { - } + SubmodulePrivate::SubmodulePrivate(const Repository::PrivatePtr& repo, const QString& name) + : RepoObjectPrivate(repo) + , mName(name) + , mSubRepo(NULL) + { + } - Submodule::Submodule(Internal::RepositoryPrivate* repo, const QString& name) - : Base(*new Private) - { - GW_D(Submodule); + git_submodule* SubmodulePrivate::getSM(Result& rc) const + { + git_submodule* sm = NULL; - d->mOwnerRepo = repo; - d->mName = name; - } + if (rc && repo() && !mName.isEmpty()) { + rc = git_submodule_lookup(&sm, repo()->mRepo, mName.toUtf8().constData()); + if (!rc) { + return NULL; + } + } - Submodule::Submodule(const Submodule& other) - : Base(other) - { - } + return sm; + } - Submodule& Submodule::operator=( const Submodule& other ) - { - Base::operator =(other); - return *this; - } + bool SubmodulePrivate::open(Result& result) + { + if (!result) { + return false; + } + + // already open? + if (mSubRepo) { + return true; + } + + git_repository* submodule_repo = NULL; + result = git_submodule_open(&submodule_repo, getSM(result)); + if (!result) { + return false; + } + + mSubRepo = new Repository::Private(submodule_repo); + return true; + } - Submodule::~Submodule() - { } + GW_PRIVATE_IMPL(Submodule, RepoObject) + + QString Submodule::name() const { GW_CD(Submodule); @@ -265,16 +258,29 @@ namespace Git return ObjectId::fromRaw( oid->id ); } - Repository Submodule::repository() const + /** + * @brief Get a Repository object for the submodule + * + * This method tries to open the submodule as a Repository and returns it. Subsequent calls will + * return the same Repository object until that goes totally out of scope. + * + * @param[in,out] result A Result object; see @ref GitWrapErrorHandling + * + * @return An existing or new Repository object for the submodule. An invalid + * Repository object if the submodule cannot be opened. + * + */ + Repository Submodule::subRepository(Result& result) { - GW_CD(Submodule); - return Repository(*d->mMyRepo.data()); - } + GW_D_CHECKED(Submodule, Repository(), result); - bool Submodule::isOpened() const - { - GW_CD(Submodule); - return d && d->mMyRepo; + if (!d->mSubRepo) { + if (!d->open(result)) { + return Repository(); + } + } + + return d->mSubRepo; } StatusFlags Submodule::status(Result &result) const @@ -291,29 +297,4 @@ namespace Git return Internal::convertSubmoduleStatus( status ); } - bool Submodule::open( Result& result ) - { - GW_D(Submodule); - if( !result || !d ) - return false; - - // already open? - if( d->mMyRepo ) - return true; - - git_repository *submodule_repo = 0; - result = git_submodule_open(&submodule_repo, d->getSM( result ) ); - if (!result) - return false; - - d->mMyRepo = new Internal::RepositoryPrivate( submodule_repo ); - return true; - } - - void Submodule::close() - { - GW_D(Submodule); - d->mMyRepo = NULL; - } - } diff --git a/libGitWrap/Submodule.hpp b/libGitWrap/Submodule.hpp index 45e18ee..ad21c04 100644 --- a/libGitWrap/Submodule.hpp +++ b/libGitWrap/Submodule.hpp @@ -18,6 +18,7 @@ #define GIT_SUBMODULE_H #include "libGitWrap/Base.hpp" +#include "libGitWrap/Repository.hpp" namespace Git { @@ -33,11 +34,9 @@ namespace Git * @brief Represents a git submodule * */ - class GITWRAP_API Submodule : public Base + class GITWRAP_API Submodule : public RepoObject { - public: - typedef Internal::SubmodulePrivate Private; - + GW_PRIVATE_DECL(Submodule, RepoObject, public) public: enum IgnoreStrategy { @@ -61,19 +60,6 @@ namespace Git */ typedef SubmoduleList List; - public: - /** - * @brief Submodule - * @param repo the owner repository - * @param name is used to lookup the submodule in the owner repository - */ - Submodule(Internal::RepositoryPrivate* repo, const QString& name); - Submodule(const Submodule& other); - Submodule(); - ~Submodule(); - - Submodule& operator=( const Submodule& other ); - public: QString name() const; QString path( Result& r ) const; @@ -111,27 +97,12 @@ namespace Git ObjectId wdOid() const; public: - Git::Repository repository() const; - - /** - * @brief Opens a submodule's repository. - * - * @return true, when repoitory could be opened successfully; false otherwise - */ - bool open(Result &result); - - /** - * @brief Closes the submodule's repository. - */ - void close(); - - bool isOpened() const; - + Repository subRepository(Result& result); StatusFlags status(Result &result) const; }; } -Q_DECLARE_METATYPE( Git::Submodule ) +Q_DECLARE_METATYPE(Git::Submodule) #endif diff --git a/libGitWrap/Tag.cpp b/libGitWrap/Tag.cpp new file mode 100644 index 0000000..fbaee43 --- /dev/null +++ b/libGitWrap/Tag.cpp @@ -0,0 +1,54 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 Sascha Cunz + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#include "libGitWrap/Tag.hpp" + +#include "libGitWrap/Private/GitWrapPrivate.hpp" +#include "libGitWrap/Private/TagPrivate.hpp" + +namespace Git +{ + + namespace Internal { + + TagPrivate::TagPrivate(const RepositoryPrivate::Ptr& repo, git_tag* o) + : ObjectPrivate(repo, reinterpret_cast(o)) + { + Q_ASSERT(o); + } + + TagPrivate::TagPrivate(const RepositoryPrivate::Ptr& repo, git_object* o) + : ObjectPrivate(repo, o) + { + Q_ASSERT(o); + Q_ASSERT(git_object_type(o) == GIT_OBJ_TAG); + } + + git_otype TagPrivate::otype() const + { + return GIT_OBJ_TAG; + } + + ObjectType TagPrivate::objectType() const + { + return otTag; + } + + } + + GW_PRIVATE_IMPL(Tag, Object) + +} diff --git a/libGitWrap/ObjectTag.cpp b/libGitWrap/Tag.hpp similarity index 56% rename from libGitWrap/ObjectTag.cpp rename to libGitWrap/Tag.hpp index 5017dee..21e71a5 100644 --- a/libGitWrap/ObjectTag.cpp +++ b/libGitWrap/Tag.hpp @@ -14,31 +14,41 @@ * */ -#include "ObjectTag.hpp" +#ifndef GIT_OBJECT_TAG_H +#define GIT_OBJECT_TAG_H -#include "Private/ObjectPrivate.hpp" -#include "Private/GitWrapPrivate.hpp" +#include "libGitWrap/GitWrap.hpp" +#include "libGitWrap/ObjectId.hpp" +#include "libGitWrap/Object.hpp" namespace Git { - ObjectTag::ObjectTag() + namespace Internal { + class TagPrivate; } - ObjectTag::ObjectTag( Internal::ObjectPrivate& _d ) - : Object(_d) + /** + * @ingroup GitWrap + * @brief Represents a git tag object. + * + */ + class GITWRAP_API Tag : public Object { - Result r; - if( ( type( r ) != otTag ) || !r ) - { - mData = NULL; - } - } + GW_PRIVATE_DECL(Tag, Object, public) + public: + enum { ObjectTypeId = otTag }; + }; - ObjectTag::ObjectTag( const ObjectTag& o ) - : Object( o ) + template<> + inline Tag Object::as() const { + return asTag(); } } + +Q_DECLARE_METATYPE(Git::Tag) + +#endif diff --git a/libGitWrap/TagRef.cpp b/libGitWrap/TagRef.cpp new file mode 100644 index 0000000..1cac72f --- /dev/null +++ b/libGitWrap/TagRef.cpp @@ -0,0 +1,55 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 The MacGitver-Developers + * + * (C) Sascha Cunz + * (C) Nils Fenner + * (C) Cunz RaD Ltd. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#include "libGitWrap/TagRef.hpp" +#include "libGitWrap/Private/TagRefPrivate.hpp" + +namespace Git +{ + + namespace Internal + { + + TagRefPrivate::TagRefPrivate(const RepositoryPrivate::Ptr& repo, + git_reference* reference) + : ReferencePrivate(repo, reference) + { + #ifdef QT_DEBUG + // We want this constructor to analyze only for the assert... + ensureAnalyzed(); + Q_ASSERT(isTag); + #endif + } + + TagRefPrivate::TagRefPrivate(git_reference* reference, const RefNamePrivate* refName) + : ReferencePrivate(reference, refName) + { + } + + ReferenceKinds TagRefPrivate::kind() const + { + return TagReference; + } + + } + + GW_PRIVATE_IMPL(TagRef, Reference) + +} diff --git a/libGitWrap/TagRef.hpp b/libGitWrap/TagRef.hpp new file mode 100644 index 0000000..ce8e7ce --- /dev/null +++ b/libGitWrap/TagRef.hpp @@ -0,0 +1,52 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 The MacGitver-Developers + * + * (C) Sascha Cunz + * (C) Nils Fenner + * (C) Cunz RaD Ltd. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GITWRAP_TAG_REF_HPP +#define GITWRAP_TAG_REF_HPP + +#include "libGitWrap/Reference.hpp" + +namespace Git +{ + + namespace Internal + { + + class TagRefPrivate; + + } + + class GITWRAP_API TagRef : public Reference + { + GW_PRIVATE_DECL(TagRef, Reference, public) + + public: + }; + + template<> + inline TagRef Reference::as() const { + return asTag(); + } + +} + +Q_DECLARE_METATYPE(Git::TagRef) + +#endif diff --git a/libGitWrap/Tree.cpp b/libGitWrap/Tree.cpp new file mode 100644 index 0000000..3031dba --- /dev/null +++ b/libGitWrap/Tree.cpp @@ -0,0 +1,164 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 Sascha Cunz + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#include "libGitWrap/DiffList.hpp" +#include "libGitWrap/Tree.hpp" +#include "libGitWrap/Repository.hpp" + +#include "libGitWrap/Private/GitWrapPrivate.hpp" +#include "libGitWrap/Private/DiffListPrivate.hpp" +#include "libGitWrap/Private/ObjectPrivate.hpp" +#include "libGitWrap/Private/RepositoryPrivate.hpp" +#include "libGitWrap/Private/TreeEntryPrivate.hpp" +#include "libGitWrap/Private/TreePrivate.hpp" + +namespace Git +{ + + namespace Internal { + + TreePrivate::TreePrivate(const RepositoryPrivate::Ptr& repo, git_tree* o) + : ObjectPrivate(repo, reinterpret_cast(o)) + { + Q_ASSERT(o); + } + + TreePrivate::TreePrivate(const RepositoryPrivate::Ptr& repo, git_object* o) + : ObjectPrivate(repo, o) + { + Q_ASSERT(o); + Q_ASSERT(git_object_type(o) == GIT_OBJ_TREE); + } + + git_otype TreePrivate::otype() const + { + return GIT_OBJ_TREE; + } + + ObjectType TreePrivate::objectType() const + { + return otTree; + } + + } + + GW_PRIVATE_IMPL(Tree, Object) + + Tree Tree::subPath(Result& result , const QString& pathName) const + { + GW_CD_CHECKED(Tree, Tree(), result) + + const git_tree_entry* entry = git_tree_entry_byname(d->o(), pathName.toUtf8().constData()); + if (!entry) { + return Tree(); + } + + git_object* subObject = 0; + result = git_tree_entry_to_object(&subObject, d->repo()->mRepo, entry); + if (!result) { + return Tree(); + } + + if (git_object_type(subObject) != GIT_OBJ_TREE) { + git_object_free(subObject); + return Tree(); + } + + return PrivatePtr(new Tree::Private(d->repo(), subObject)); + } + + DiffList Tree::diffToTree(Result& result , Tree newTree) + { + GW_D_CHECKED(Tree, DiffList(), result) + + Tree::Private* tp = Base::Private::dataOf(newTree); + + git_diff_list* diffList = NULL; + result = git_diff_tree_to_tree(&diffList, d->repo()->mRepo, d->o(), tp->o(), NULL); + if (!result) { + return DiffList(); + } + + return DiffList::PrivatePtr(new DiffList::Private(d->repo(), diffList)); + } + + DiffList Tree::diffToIndex(Result& result) + { + GW_D_CHECKED(Tree, DiffList(), result) + git_diff_list* diffList = NULL; + + result = git_diff_tree_to_index(&diffList, d->repo()->mRepo, d->o(), NULL, NULL); + if (!result) { + return DiffList(); + } + + return DiffList::PrivatePtr(new DiffList::Private(d->repo(), diffList)); + } + + DiffList Tree::diffToWorkingDir( Result& result ) + { + GW_D_CHECKED(Tree, DiffList(), result) + + git_diff_list* diffList = NULL; + result = git_diff_tree_to_workdir( &diffList, d->repo()->mRepo, d->o(), NULL ); + if (!result) { + return DiffList(); + } + + return DiffList::PrivatePtr(new DiffList::Private(d->repo(), diffList)); + } + + size_t Tree::entryCount() const + { + GW_CD(Tree); + return d ? git_tree_entrycount(d->o()) : 0; + } + + TreeEntry Tree::entryAt( size_t index ) const + { + GW_CD(Tree); + + if(!d) { + return TreeEntry(); + } + const git_tree_entry* entry = git_tree_entry_byindex(d->o(), index); + return TreeEntry::PrivatePtr(new TreeEntry::Private(entry)); + } + + TreeEntry Tree::entry(const QString& fileName) const + { + GW_CD(Tree); + + if (!d) { + return TreeEntry(); + } + + const git_tree_entry* entry = git_tree_entry_byname(d->o(), fileName.toUtf8().constData()); + return TreeEntry::PrivatePtr(new TreeEntry::Private(entry)); + } + + void Tree::checkout(Result& result, bool force, const QStringList &paths) const + { + GW_CD_CHECKED_VOID(Tree, result); + + git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; + opts.checkout_strategy = force ? GIT_CHECKOUT_FORCE : GIT_CHECKOUT_SAFE; + Internal::StrArray(opts.paths, paths); + + result = git_checkout_tree(d->repo()->mRepo, d->mObj, &opts); + } + +} diff --git a/libGitWrap/Tree.hpp b/libGitWrap/Tree.hpp new file mode 100644 index 0000000..e6680f8 --- /dev/null +++ b/libGitWrap/Tree.hpp @@ -0,0 +1,81 @@ +/* + * MacGitver + * Copyright (C) 2012-2013 Sascha Cunz + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License (Version 2) as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, see . + * + */ + +#ifndef GIT_OBJECT_TREE_H +#define GIT_OBJECT_TREE_H + +#include "libGitWrap/GitWrap.hpp" +#include "libGitWrap/ObjectId.hpp" +#include "libGitWrap/Object.hpp" +#include "libGitWrap/TreeEntry.hpp" + +namespace Git +{ + + namespace Internal + { + class TreePrivate; + } + + /** + * @ingroup GitWrap + * @brief Represents a git tree object + * + */ + class GITWRAP_API Tree : public Object + { + GW_PRIVATE_DECL(Tree, Object, public) + public: + enum { ObjectTypeId = otTree }; + + public: + Tree subPath( Result& result, const QString& pathName ) const; + + DiffList diffToTree( Result& result, Tree newTree ); + DiffList diffToIndex( Result& result ); + DiffList diffToWorkingDir( Result& result ); + + size_t entryCount() const; + TreeEntry entryAt( size_t index ) const; + TreeEntry entry( const QString& fileName ) const; + + void checkout(Result& result, + bool force = false, + const QStringList &paths = QStringList()) const; + + public: + inline TreeEntry operator[]( size_t index ) const + { + return entryAt( index ); + } + + inline TreeEntry operator[]( const QString& fileName ) const + { + return entry( fileName ); + } + }; + + template<> + inline Tree Object::as() const + { + return asTree(); + } + +} + +Q_DECLARE_METATYPE(Git::Tree) + +#endif diff --git a/libGitWrap/TreeBuilder.cpp b/libGitWrap/TreeBuilder.cpp index 8c3ca84..9d8707d 100644 --- a/libGitWrap/TreeBuilder.cpp +++ b/libGitWrap/TreeBuilder.cpp @@ -28,7 +28,7 @@ namespace Git namespace Internal { - TreeBuilderPrivate::TreeBuilderPrivate(RepositoryPrivate* repo, git_treebuilder* builder ) + TreeBuilderPrivate::TreeBuilderPrivate(const RepositoryPrivate::Ptr& repo, git_treebuilder* builder ) : RepoObjectPrivate( repo ) , mBuilder( builder ) { @@ -42,29 +42,7 @@ namespace Git } - TreeBuilder::TreeBuilder() - { - } - - TreeBuilder::TreeBuilder(const TreeBuilder& other) - : RepoObject(other) - { - } - - TreeBuilder::TreeBuilder(Internal::TreeBuilderPrivate& _d) - : RepoObject(_d) - { - } - - TreeBuilder::~TreeBuilder() - { - } - - TreeBuilder& TreeBuilder::operator=(const TreeBuilder& other) - { - RepoObject::operator =(other); - return * this; - } + GW_PRIVATE_IMPL(TreeBuilder, RepoObject) void TreeBuilder::clear( Result& result ) { @@ -80,7 +58,7 @@ namespace Git return result; } - bool TreeBuilder::insert( const QString& fileName, TreeEntryAttributes type, + bool TreeBuilder::insert( const QString& fileName, FileModes type, const ObjectId& oid, Result& result ) { GW_D_CHECKED(TreeBuilder, false, result); @@ -121,7 +99,7 @@ namespace Git return TreeEntry(); } - return *new Internal::TreeEntryPrivate(entry, true); + return TreeEntry::PrivatePtr(new TreeEntry::Private(entry, true)); } } diff --git a/libGitWrap/TreeBuilder.hpp b/libGitWrap/TreeBuilder.hpp index 65b8a53..7ebe7fc 100644 --- a/libGitWrap/TreeBuilder.hpp +++ b/libGitWrap/TreeBuilder.hpp @@ -33,18 +33,13 @@ namespace Git */ class GITWRAP_API TreeBuilder : public RepoObject { - public: - TreeBuilder(); - TreeBuilder(Internal::TreeBuilderPrivate& _d); - TreeBuilder(const TreeBuilder& other); - ~TreeBuilder(); - TreeBuilder& operator=( const TreeBuilder& other ); + GW_PRIVATE_DECL(TreeBuilder, RepoObject, public) public: void clear( Result& result ); TreeEntry get( Result& result, const QString& name ); - bool insert( const QString& fileName, TreeEntryAttributes type, const ObjectId& oid, + bool insert( const QString& fileName, FileModes type, const ObjectId& oid, Result& result ); bool remove( Result& result, const QString& fileName ); ObjectId write( Result& result ); diff --git a/libGitWrap/TreeEntry.cpp b/libGitWrap/TreeEntry.cpp index e69505e..0857695 100644 --- a/libGitWrap/TreeEntry.cpp +++ b/libGitWrap/TreeEntry.cpp @@ -42,41 +42,19 @@ namespace Git } - TreeEntry::TreeEntry() - { - } - - TreeEntry::TreeEntry(const TreeEntry& other) - : Base(other) - { - } - - TreeEntry::TreeEntry(Internal::TreeEntryPrivate& _d) - : Base(_d) - { - } - - TreeEntry::~TreeEntry() - { - } - - TreeEntry& TreeEntry::operator=( const TreeEntry& other ) - { - Base::operator =(other); - return * this; - } + GW_PRIVATE_IMPL(TreeEntry, Base) TreeEntry TreeEntry::clone() const { GW_CD(TreeEntry); - if(!d) { + if (!d) { return TreeEntry(); } - git_tree_entry* entry = git_tree_entry_dup( d->mEntry ); - Q_ASSERT( entry ); + git_tree_entry* entry = git_tree_entry_dup(d->mEntry); + Q_ASSERT(entry); - return *new Internal::TreeEntryPrivate( entry ); + return PrivatePtr(new Private(entry)); } ObjectId TreeEntry::sha1() const @@ -86,13 +64,12 @@ namespace Git return ObjectId(); } - const git_oid* oid = git_tree_entry_id( d->mEntry ); - if( !oid ) - { + const git_oid* oid = git_tree_entry_id(d->mEntry); + if (!oid) { return ObjectId(); } - return ObjectId::fromRaw( oid->id ); + return Private::oid2sha(oid); } QString TreeEntry::name() const @@ -102,14 +79,13 @@ namespace Git return QString(); } - const char* szName = git_tree_entry_name( d->mEntry ); + const char* szName = git_tree_entry_name(d->mEntry); - if( !szName ) - { + if (!szName) { return QString(); } - return QString::fromUtf8( szName ); + return QString::fromUtf8(szName); } ObjectType TreeEntry::type() const diff --git a/libGitWrap/TreeEntry.hpp b/libGitWrap/TreeEntry.hpp index 661a3c6..1023015 100644 --- a/libGitWrap/TreeEntry.hpp +++ b/libGitWrap/TreeEntry.hpp @@ -33,12 +33,7 @@ namespace Git */ class GITWRAP_API TreeEntry : public Base { - public: - TreeEntry(); - TreeEntry(Internal::TreeEntryPrivate& _d ); - TreeEntry(const TreeEntry& other); - ~TreeEntry(); - TreeEntry& operator=( const TreeEntry& other ); + GW_PRIVATE_DECL(TreeEntry, Base, public) public: TreeEntry clone() const; diff --git a/testGitWrap/TestRefName.cpp b/testGitWrap/TestRefName.cpp index c199d35..84e4661 100644 --- a/testGitWrap/TestRefName.cpp +++ b/testGitWrap/TestRefName.cpp @@ -348,10 +348,10 @@ TEST(RefName, Specials_CommitNotes) { EXPECT_FALSE(rn.isStage()); EXPECT_FALSE(rn.isCustom()); - EXPECT_STREQ("", qPrintable(rn.name())); + EXPECT_STREQ("commit", qPrintable(rn.name())); EXPECT_STREQ("", qPrintable(rn.branchName())); EXPECT_STREQ("", qPrintable(rn.tagName())); - EXPECT_STREQ("", qPrintable(rn.localName())); + EXPECT_STREQ("commit", qPrintable(rn.localName())); EXPECT_STREQ("", qPrintable(rn.scopeName())); EXPECT_STREQ("", qPrintable(rn.namespaceName())); EXPECT_STREQ("", qPrintable(rn.remote()));