Skip to content
Snippets Groups Projects
gitclient.cpp 82 KiB
Newer Older
/**************************************************************************
con's avatar
con committed
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
**
** Contact: Nokia Corporation (qt-info@nokia.com)
con's avatar
con committed
**
** Commercial Usage
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
** GNU Lesser General Public License Usage
** 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.
** If you are unsure which license is appropriate for your use, please
hjk's avatar
hjk committed
** contact the sales department at http://qt.nokia.com/contact.
con's avatar
con 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"
con's avatar
con committed

#include <coreplugin/actionmanager/actionmanager.h>
hjk's avatar
hjk committed
#include <coreplugin/coreconstants.h>
con's avatar
con committed
#include <coreplugin/editormanager/editormanager.h>
hjk's avatar
hjk committed
#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
hjk's avatar
hjk committed
#include <coreplugin/uniqueidmanager.h>
#include <coreplugin/filemanager.h>
#include <coreplugin/iversioncontrol.h>

con's avatar
con committed
#include <texteditor/itexteditor.h>
hjk's avatar
hjk committed
#include <utils/qtcassert.h>
#include <utils/synchronousprocess.h>
hjk's avatar
hjk committed
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/vcsbaseoutputwindow.h>
#include <vcsbase/vcsbaseplugin.h>
con's avatar
con committed

#include <QtCore/QRegExp>
#include <QtCore/QTemporaryFile>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QSignalMapper>
con's avatar
con committed

#include <QtGui/QMainWindow> // for msg box parent
hjk's avatar
hjk committed
#include <QtGui/QMessageBox>
con's avatar
con committed

static const char *const kGitDirectoryC = ".git";
static const char *const kBranchIndicatorC = "# On branch";
con's avatar
con committed

inline Core::IEditor* locateEditor(const Core::ICore *core, const char *property, const QString &entry)
{
    foreach (Core::IEditor *ed, core->editorManager()->openedEditors())
        if (ed->file()->property(property).toString() == entry)
con's avatar
con committed
            return ed;
    return 0;
}

// Return converted command output, remove '\r' read on Windows
static inline QString commandOutputFromLocal8Bit(const QByteArray &a)
{
    QString output = QString::fromLocal8Bit(a);
    output.remove(QLatin1Char('\r'));
    return output;
}

// Return converted command output split into lines
static inline QStringList commandOutputLinesFromLocal8Bit(const QByteArray &a)
{
    QString output = commandOutputFromLocal8Bit(a);
    const QChar newLine = QLatin1Char('\n');
    if (output.endsWith(newLine))
        output.truncate(output.size() - 1);
    if (output.isEmpty())
        return QStringList();
    return output.split(newLine);
}

static inline VCSBase::VCSBaseOutputWindow *outputWindow()
{
    return VCSBase::VCSBaseOutputWindow::instance();
}

namespace Git {
namespace Internal {

static inline QString msgRepositoryNotFound(const QString &dir)
{
    return GitClient::tr("Unable to determine the repository for %1.").arg(dir);
}

static inline QString msgParseFilesFailed()
{
    return  GitClient::tr("Unable to parse the file output.");
}

// ---------------- GitClient

const char *GitClient::stashNamePrefix = "stash@{";

GitClient::GitClient(GitPlugin* plugin)
  : m_msgWait(tr("Waiting for data...")),
con's avatar
con committed
    m_plugin(plugin),
    m_core(Core::ICore::instance()),
    m_repositoryChangedSignalMapper(0),
    m_cachedGitVersion(0),
    m_hasCachedGitVersion(false)
con's avatar
con committed
{
con's avatar
con committed
}

GitClient::~GitClient()
{
}

const char *GitClient::noColorOption = "--no-color";

con's avatar
con committed
QString GitClient::findRepositoryForDirectory(const QString &dir)
{
    // Check for ".git/config"
    const QString checkFile = QLatin1String(kGitDirectoryC) + QLatin1String("/config");
    return VCSBase::VCSBasePlugin::findRepositoryForDirectory(dir, checkFile);
con's avatar
con committed
}

/* Create an editor associated to VCS output of a source file/directory
 * (using the file's codec). Makes use of a dynamic property to find an
 * existing instance and to reuse it (in case, say, 'git diff foo' is
 * already open). */
VCSBase::VCSBaseEditor
    *GitClient::createVCSEditor(const QString &id,
con's avatar
con committed
                                QString title,
                                // Source file or directory
                                const QString &source,
                                bool setSourceCodec,
                                // Dynamic property and value to identify that editor
                                const char *registerDynamicProperty,
                                const QString &dynamicPropertyValue) const
{
    VCSBase::VCSBaseEditor *rc = 0;
    Core::IEditor* outputEditor = locateEditor(m_core, registerDynamicProperty, dynamicPropertyValue);
    if (outputEditor) {
         // Exists already
        outputEditor->createNew(m_msgWait);
        rc = VCSBase::VCSBaseEditor::getVcsBaseEditor(outputEditor);
hjk's avatar
hjk committed
        QTC_ASSERT(rc, return 0);
con's avatar
con committed
    } else {
        // Create new, set wait message, set up with source and codec
        outputEditor = m_core->editorManager()->openEditorWithContents(id, &title, m_msgWait);
        outputEditor->file()->setProperty(registerDynamicProperty, dynamicPropertyValue);
con's avatar
con committed
        rc = VCSBase::VCSBaseEditor::getVcsBaseEditor(outputEditor);
        connect(rc, SIGNAL(annotateRevisionRequested(QString,QString,int)),
                this, SLOT(slotBlameRevisionRequested(QString,QString,int)));
hjk's avatar
hjk committed
        QTC_ASSERT(rc, return 0);
con's avatar
con committed
        rc->setSource(source);
        if (setSourceCodec)
hjk's avatar
hjk committed
            rc->setCodec(VCSBase::VCSBaseEditor::getCodec(source));
con's avatar
con committed
    }
    m_core->editorManager()->activateEditor(outputEditor, Core::EditorManager::ModeSwitch);
    rc->setForceReadOnly(true);
con's avatar
con committed
    return rc;
}

void GitClient::diff(const QString &workingDirectory,
                     const QStringList &diffArgs,
                     const QStringList &unstagedFileNames,
                     const QStringList &stagedFileNames)
con's avatar
con committed
{

    if (Git::Constants::debug)
        qDebug() << "diff" << workingDirectory << unstagedFileNames << stagedFileNames;

    const QString binary = QLatin1String(Constants::GIT_BINARY);
    const QString editorId = QLatin1String(Git::Constants::GIT_DIFF_EDITOR_ID);
con's avatar
con committed
    const QString title = tr("Git Diff");

    VCSBase::VCSBaseEditor *editor = createVCSEditor(editorId, title, workingDirectory, true, "originalFileName", workingDirectory);
Loading
Loading full blame...