Browse Source

Pull functionality pre-steps

- Added pull button and related popup
- Implemented basic remote fetch

Task: CuteGit#2
Alexey Edelev 5 years ago
parent
commit
28804afe7b
13 changed files with 155 additions and 14 deletions
  1. 4 2
      CuteGit.pro
  2. 15 1
      commitgraph.cpp
  3. 1 0
      commitgraph.h
  4. 31 0
      gitauthenticator.cpp
  5. 24 0
      gitauthenticator.h
  6. 1 1
      gitcommit.cpp
  7. 10 5
      gitcommit.h
  8. 16 2
      githandler.cpp
  9. 8 2
      githandler.h
  10. 22 0
      gitremote.cpp
  11. 4 1
      gitremote.h
  12. 18 0
      qml/TopBar.qml
  13. 1 0
      resources.qrc

+ 4 - 2
CuteGit.pro

@@ -43,7 +43,8 @@ SOURCES += \
     colorhandler.cpp \
     diffmodel.cpp \
     settings.cpp \
-    universallistmodelbase.cpp
+    universallistmodelbase.cpp \
+    gitauthenticator.cpp
 
 HEADERS += \
     githandler.h \
@@ -71,7 +72,8 @@ HEADERS += \
     colorhandler.h \
     diffmodel.h \
     settings.h \
-    universallistmodelbase.h
+    universallistmodelbase.h \
+    gitauthenticator.h
 
 RESOURCES += \
     resources.qrc

+ 15 - 1
commitgraph.cpp

@@ -118,14 +118,28 @@ void CommitGraph::findParents(GitCommit* commit)
 //        qDebug() << "Add commit to reverselist" << parentOid.toString();
         commitRaw = nullptr;
         git_commit_parent(&commitRaw, commit->raw(), 0);
+        if(commitRaw == nullptr) {
+            checkRoot(commit);
+        }
     }
 
-    if(reverseList.count() < 2) { //In case if only original commit in list, we didn't find anything new
+    if(reverseList.count() <= 1) { //In case if only original commit in list, we didn't find anything new
         return;
     }
     addCommits(reverseList);
 }
 
+void CommitGraph::checkRoot(GitCommit *commit)
+{
+    qDebug() << "Check root commit";
+    if(m_points.contains(commit->oid())) {
+        return;
+    }
+    GraphPoint* rootPoint = new GraphPoint(commit->oid(), this);
+    m_sortedPoints.prepend(QPointer<GraphPoint>(rootPoint));
+    m_points.insert(rootPoint->oid(), rootPoint);
+}
+
 void CommitGraph::addCommits(QList<GitOid>& reversList)
 {
     GraphPoint* point = nullptr;

+ 1 - 0
commitgraph.h

@@ -48,6 +48,7 @@ signals:
 private:
     void findParents(GitCommit *commit);
     void addCommits(QList<GitOid> &reversList);
+    void checkRoot(GitCommit *commit);
 
     QString m_color;
 

+ 31 - 0
gitauthenticator.cpp

@@ -0,0 +1,31 @@
+#include "gitauthenticator.h"
+#include <QDir>
+#include <QDebug>
+
+#include <git2/transport.h>
+
+namespace {
+QString DefaultPublicKey = QDir::homePath() + QString("/.ssh/id_rsa.pub");
+QString DefaultPrivateKey = QDir::homePath() + QString("/.ssh/id_rsa");
+}
+
+GitAuthenticator::GitAuthenticator()
+{
+
+}
+
+int GitAuthenticator::authenticate(GitRemote *remote, git_cred **credentials, const char *usernameFromUrl, unsigned int allowedTypes)
+{
+    if(allowedTypes & GIT_CREDTYPE_SSH_KEY) {
+        return authenticateSsh(remote, credentials, usernameFromUrl);
+    } else {
+        qWarning() << "Only ssh key-based authentication possible";
+    }
+    return -1;
+}
+
+int GitAuthenticator::authenticateSsh(GitRemote* remote, git_cred **credentials, const char* usernameFromUrl)
+{
+    //TODO: here might be advanced logic for key authentication
+    return git_cred_ssh_key_new(credentials, usernameFromUrl, DefaultPublicKey.toUtf8().data(), DefaultPrivateKey.toUtf8().data(), "");
+}

+ 24 - 0
gitauthenticator.h

@@ -0,0 +1,24 @@
+#ifndef GITAUTHENTICATOR_H
+#define GITAUTHENTICATOR_H
+
+#include <QObject>
+
+class GitRemote;
+struct git_cred;
+
+class GitAuthenticator : public QObject
+{
+    Q_OBJECT
+
+public:
+    int authenticate(GitRemote *remote, git_cred **credentials, const char *usernameFromUrl, unsigned int allowedTypes);
+    static GitAuthenticator* instance() {
+        static GitAuthenticator s_instance;
+        return &s_instance;
+    }
+private:
+    GitAuthenticator();
+    int authenticateSsh(GitRemote* remote, git_cred **credentials, const char* usernameFromUrl);
+};
+
+#endif // GITAUTHENTICATOR_H

+ 1 - 1
gitcommit.cpp

@@ -89,8 +89,8 @@ GitDiff* GitCommit::diff()
 
         if(parentRaw) {
             parent.reset(new GitCommit(parentRaw, repository()));
+            m_diff = GitDiff::diff(parent.data(), this);
         }
-        m_diff = GitDiff::diff(parent.data(), this);
     }
     return m_diff.data();
 }

+ 10 - 5
gitcommit.h

@@ -56,12 +56,17 @@ signals:
 private:
     GitCommit();
 
-    QString m_author;
-    QDateTime m_time;
-    QString m_message;
-    QString m_email;
+/*
+ * TODO: Seems cached values are not used. Don't remember why it's done this way.
+ * But it's better to remove them.
+ */
+//    QString m_author;
+//    QDateTime m_time;
+//    QString m_message;
+//    QString m_email;
+//    QString m_summary;
+
     QPointer<GitDiff> m_diff;
-    QString m_summary;
 };
 
 #endif // GITCOMMIT_H

+ 16 - 2
githandler.cpp

@@ -24,6 +24,7 @@
 #include <gitconsole.h>
 #include <graphpoint.h>
 #include <settings.h>
+#include <gitremote.h>
 
 GitHandler::GitHandler() : QObject()
   ,m_repositories(new RepositoryModel(this))
@@ -198,9 +199,22 @@ GitDiff* GitHandler::activeDiff() const
     return m_activeDiff.data();
 }
 
-void GitHandler::pull() const
+void GitHandler::pull(PullStrategy strategy) const
 {
-    //    git_remote_fetch(m_activeRepo->remote)
+    if(m_activeRepo->remotes().count() <= 0) {
+        qWarning() << "No remotes available for repository. Please add manually in console";
+        //TODO: duplicate with warning popup
+        return;
+    }
+
+    GitRemote *remote = m_activeRepo->remotes().first().data();
+    if(remote == nullptr) {
+        qCritical() << "Null remote in remotes detected. It's critical";
+        Q_ASSERT(remote == nullptr);
+        return;
+    }
+
+    remote->fetch();
 }
 
 void GitHandler::updateModels()

+ 8 - 2
githandler.h

@@ -29,7 +29,13 @@ class GitHandler : public QObject
     Q_PROPERTY(bool isBusy READ isBusy NOTIFY isBusyChanged)
     Q_PROPERTY(QUrl homePath READ homePath CONSTANT)
 
+    Q_ENUMS(PullStrategy)
 public:
+    enum PullStrategy {
+        Rebase,
+        Merge
+    };
+
     GitHandler();
     virtual ~GitHandler();
     Q_INVOKABLE void open(const QString &path, bool activate = false);
@@ -44,6 +50,8 @@ public:
 
     Q_INVOKABLE void copy(const QString& sha1);
 
+    Q_INVOKABLE void pull(PullStrategy strategy) const;
+
     RepositoryModel* repositories() const
     {
         return m_repositories;
@@ -66,8 +74,6 @@ public:
         return m_commits;
     }
 
-    void pull() const;
-
     BranchListModel* branchList() const
     {
         return m_branchList;

+ 22 - 0
gitremote.cpp

@@ -1,4 +1,5 @@
 #include "gitremote.h"
+#include <gitauthenticator.h>
 #include <git2/remote.h>
 
 GitRemote::GitRemote(git_remote* raw, GitRepository* parent) : GitBase(raw, parent)
@@ -17,3 +18,24 @@ QString GitRemote::name() const
 {
     return QString(git_remote_name(raw()));
 }
+
+void GitRemote::fetch()
+{
+    QString reflogRecord = QString("Fetch from remote: " + name());
+    git_fetch_options opts = GIT_FETCH_OPTIONS_INIT;
+    opts.callbacks.update_tips = [](const char *refname, const git_oid *a, const git_oid *b, void *data) -> int { return 0; };
+    opts.callbacks.sideband_progress = [](const char *str, int len, void *payload) -> int { return 0; };
+    opts.callbacks.transfer_progress = [](const git_transfer_progress *stats, void *payload) -> int {
+        qDebug() << "transferProgress: " << stats->total_objects << "/" << stats->received_objects;
+        return 0;
+    };
+    opts.callbacks.credentials = [](git_cred **cred, const char *url, const char *username_from_url, unsigned int allowed_types, void *payload) -> int {
+        qDebug() << "Url: " << url;
+        qDebug() << "Username: " << username_from_url;
+        qDebug() << "Allowed types: " << allowed_types;
+
+        return GitAuthenticator::instance()->authenticate(reinterpret_cast<GitRemote*>(payload), cred, username_from_url, allowed_types);
+    };
+    opts.callbacks.payload = this;
+    git_remote_fetch(m_raw, nullptr, &opts, reflogRecord.toLatin1().data());
+}

+ 4 - 1
gitremote.h

@@ -9,12 +9,15 @@ struct git_remote;
 class GitRemote : public GitBase<git_remote>
 {
     Q_OBJECT
-
 public:
     GitRemote(git_remote* raw, GitRepository* parent);
     static GitRemote* fromName(const QString& remoteName, GitRepository* parent);
 
+    void fetch();
+
     QString name() const;
+signals:
+
 private:
 };
 

+ 18 - 0
qml/TopBar.qml

@@ -2,6 +2,9 @@ import QtQuick 2.0
 import QtQuick.Dialogs 1.2
 import QtQuick.Controls 1.4
 import QtQuick.Controls.Styles 1.4
+
+import "popups"
+
 Item {
     id: root
     anchors.right: parent.right
@@ -47,6 +50,14 @@ Item {
                 repoOpenDialog.open()
             }
         }
+
+        Button {
+            anchors.verticalCenter: parent.verticalCenter
+            text: qsTr("Pull")
+            onClicked: {
+                pullDialog.open()
+            }
+        }
     }
 
     Row {
@@ -111,5 +122,12 @@ Item {
             }
         }
     }
+
+    PullStrategy {
+        id: pullDialog
+        onAccepted: {
+            _handler.pull(pullDialog.strategy)
+        }
+    }
 }
 

+ 1 - 0
resources.qrc

@@ -55,5 +55,6 @@
         <file>images/question-mark-4-24_active.png</file>
         <file>qml/InitialWizard.qml</file>
         <file>qml/RepositoryView.qml</file>
+        <file>qml/popups/PullStrategy.qml</file>
     </qresource>
 </RCC>