Skip to content
Snippets Groups Projects
gitclient.cpp 140 KiB
Newer Older
hjk's avatar
hjk committed
/****************************************************************************
con's avatar
con committed
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
**
hjk's avatar
hjk committed
** This file is part of Qt Creator.
con's avatar
con committed
**
hjk's avatar
hjk committed
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
****************************************************************************/
hjk's avatar
hjk committed

con's avatar
con committed
#include "gitclient.h"
#include "gitutils.h"
con's avatar
con committed
#include "commitdata.h"
hjk's avatar
hjk committed
#include "gitconstants.h"
#include "gitplugin.h"
#include "gitversioncontrol.h"
#include "mergetool.h"
con's avatar
con committed

#include <vcsbase/submitfilemodel.h>

con's avatar
con committed
#include <coreplugin/editormanager/editormanager.h>
hjk's avatar
hjk committed
#include <coreplugin/icore.h>
#include <coreplugin/vcsmanager.h>
#include <coreplugin/iversioncontrol.h>

#include <utils/hostosinfo.h>
hjk's avatar
hjk committed
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/synchronousprocess.h>
#include <utils/fileutils.h>
Tobias Hunger's avatar
Tobias Hunger committed
#include <vcsbase/command.h>
hjk's avatar
hjk committed
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/vcsbaseeditorparameterwidget.h>
#include <vcsbase/vcsbaseoutputwindow.h>
#include <vcsbase/vcsbaseplugin.h>
con's avatar
con committed

#include <diffeditor/diffeditor.h>
#include <diffeditor/diffshoweditor.h>
#include <diffeditor/diffeditorconstants.h>

#include <QCoreApplication>
#include <QFileInfo>
#include <QHash>
#include <QRegExp>
#include <QSignalMapper>
#include <QTime>
con's avatar
con committed

#include <QMessageBox>
#include <QPushButton>
#include <QToolButton>
#include <QTextCodec>
con's avatar
con committed

static const char GIT_DIRECTORY[] = ".git";
static const char graphLogFormatC[] = "%h %d %an %s %ci";
static const char HEAD[] = "HEAD";
static const char noColorOption[] = "--no-color";
static const char decorateOption[] = "--decorate";
con's avatar
con committed

namespace Git {
namespace Internal {

using VcsBase::VcsBasePlugin;

class GitDiffHandler : public QObject
{
    Q_OBJECT

public:
    enum RevisionType {
        WorkingTree,
        Index,
        Other
    };

    struct Revision {
        Revision() : type(WorkingTree) { }
        Revision(RevisionType t) : type(t) { }
        Revision(RevisionType t, const QString &i) : type(t), id(i) { }
        RevisionType type;
        QString id; // can be sha or HEAD
        QString infoText() const
        {
            switch (type) {
            case WorkingTree: return tr("Working tree");
            case Index:       return tr("Index");
            default:          return id;
            }
        }
    };

    GitDiffHandler(DiffEditor::DiffEditor *editor,
                   const QString &gitPath,
                   const QString &workingDirectory,
                   const QProcessEnvironment &environment,
                   int timeout);

    // index -> working tree
    void diffFile(const QString &fileName);
    // stagedFileNames:   HEAD -> index
    // unstagedFileNames: index -> working tree
    void diffFiles(const QStringList &stagedFileNames, const QStringList &unstagedFileNames);
    // index -> working tree
    void diffProjects(const QStringList &projectPaths);
    // index -> working tree
    void diffRepository();
    // branch HEAD -> working tree
    void diffBranch(const QString &branchName);
    // id^ -> id
    void show(const QString &id);
    void slotShowDescriptionReceived(const QString &data);
    void slotFileListReceived(const QString &fileList);
    void slotFileContentsReceived(const QString &contents);
    void collectShowDescription(const QString &id);
    void collectFilesList(const QStringList &additionalArguments);
    void prepareForCollection();
    void collectFilesContents();
    void feedEditor();
    QString workingTreeContents(const QString &fileName) const;

    QPointer<DiffEditor::DiffEditor> m_editor;
    const QString m_gitPath;
    const QString m_workingDirectory;
    const QProcessEnvironment m_processEnvironment;
    const int m_timeout;
    const QString m_waitMessage;

    struct RevisionRange {
        RevisionRange() { }
        RevisionRange(const Revision &b, const Revision &e) : begin(b), end(e) { }
        Revision begin;
        Revision end;
    // filename, revision range
    QMap<QString, QList<RevisionRange> > m_requestedRevisionRanges;
    // filename, revision, dummy
    QMap<QString, QMap<Revision, bool> > m_pendingRevisions;
    // filename, revision, contents
    QMap<QString, QMap<Revision, QString> > m_collectedRevisions;
    RevisionRange m_requestedRevisionRange;
inline bool operator<(const GitDiffHandler::Revision &rev1, const GitDiffHandler::Revision &rev2)
{
    if (rev1.type != rev2.type)
        return rev1.type < rev2.type;
    return rev1.id < rev2.id;
}

GitDiffHandler::GitDiffHandler(DiffEditor::DiffEditor *editor,
               const QString &gitPath,
               const QString &workingDirectory,
               const QProcessEnvironment &environment,
               int timeout)
    : m_editor(editor),
      m_gitPath(gitPath),
      m_workingDirectory(workingDirectory),
      m_processEnvironment(environment),
      m_timeout(timeout),
      m_waitMessage(tr("Waiting for data..."))
{
}

void GitDiffHandler::diffFile(const QString &fileName)
{
    m_requestedRevisionRange = RevisionRange(
                Revision(Index),
                Revision(WorkingTree));

    collectFilesList(QStringList() << QLatin1String("--") << fileName);
Loading
Loading full blame...