2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2013-01-28 17:12:19 +01:00
|
|
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
2012-10-02 09:12:39 +02:00
|
|
|
** Contact: http://www.qt-project.org/legal
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** 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.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2012-10-02 09:12:39 +02:00
|
|
|
** 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
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2008-12-02 16:19:05 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "vcsbaseplugin.h"
|
2009-12-08 14:26:41 +01:00
|
|
|
#include "vcsbasesubmiteditor.h"
|
|
|
|
|
#include "vcsplugin.h"
|
2010-05-21 17:46:00 +02:00
|
|
|
#include "commonvcssettings.h"
|
2010-01-15 12:24:06 +01:00
|
|
|
#include "vcsbaseoutputwindow.h"
|
2009-12-08 14:26:41 +01:00
|
|
|
#include "corelistener.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-06-09 06:00:29 +03:00
|
|
|
#include <coreplugin/documentmanager.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <coreplugin/icore.h>
|
2013-03-25 11:36:51 +01:00
|
|
|
#include <coreplugin/id.h>
|
2009-12-08 14:26:41 +01:00
|
|
|
#include <coreplugin/iversioncontrol.h>
|
2010-03-25 16:23:37 +01:00
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
2009-12-08 14:26:41 +01:00
|
|
|
#include <coreplugin/vcsmanager.h>
|
|
|
|
|
#include <projectexplorer/projectexplorer.h>
|
|
|
|
|
#include <projectexplorer/project.h>
|
|
|
|
|
#include <utils/qtcassert.h>
|
2010-05-21 17:46:00 +02:00
|
|
|
#include <utils/synchronousprocess.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QDir>
|
|
|
|
|
#include <QSharedData>
|
|
|
|
|
#include <QScopedPointer>
|
|
|
|
|
#include <QSharedPointer>
|
|
|
|
|
#include <QProcessEnvironment>
|
|
|
|
|
#include <QTextCodec>
|
2009-12-08 14:26:41 +01:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QAction>
|
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
#include <QFileDialog>
|
2009-12-08 14:26:41 +01:00
|
|
|
|
2012-01-07 03:35:54 +01:00
|
|
|
using namespace Utils;
|
|
|
|
|
|
2010-05-21 17:46:00 +02:00
|
|
|
enum { debug = 0, debugRepositorySearch = 0, debugExecution = 0 };
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-03-28 14:19:17 +02:00
|
|
|
/*!
|
2012-01-07 12:31:48 +01:00
|
|
|
\namespace VcsBase
|
2013-06-05 14:29:24 +02:00
|
|
|
\brief The VcsBase namespace contains classes for the VcsBase plugin.
|
2011-03-28 14:19:17 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
2012-01-07 12:31:48 +01:00
|
|
|
\namespace VcsBase::Internal
|
2013-06-05 14:29:24 +02:00
|
|
|
\brief The Internal namespace contains internal classes for the VcsBase
|
|
|
|
|
plugin.
|
2011-03-28 14:19:17 +02:00
|
|
|
\internal
|
|
|
|
|
*/
|
2009-12-08 14:26:41 +01:00
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
namespace VcsBase {
|
2008-12-02 12:01:29 +01:00
|
|
|
namespace Internal {
|
|
|
|
|
|
2011-03-28 14:19:17 +02:00
|
|
|
/*!
|
2013-06-05 14:29:24 +02:00
|
|
|
\class VcsBase::Internal::State
|
2011-03-28 14:19:17 +02:00
|
|
|
|
2013-06-05 14:29:24 +02:00
|
|
|
\brief The State class provides the internal state created by the state
|
|
|
|
|
listener and VcsBasePluginState.
|
2011-03-28 14:19:17 +02:00
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
Aggregated in the QSharedData of VcsBase::VcsBasePluginState.
|
2011-03-28 14:19:17 +02:00
|
|
|
*/
|
2009-12-08 14:26:41 +01:00
|
|
|
|
2012-01-07 03:35:54 +01:00
|
|
|
struct State
|
|
|
|
|
{
|
2009-12-08 14:26:41 +01:00
|
|
|
void clearFile();
|
2010-03-25 16:23:37 +01:00
|
|
|
void clearPatchFile();
|
2009-12-08 14:26:41 +01:00
|
|
|
void clearProject();
|
|
|
|
|
inline void clear();
|
|
|
|
|
|
|
|
|
|
bool equals(const State &rhs) const;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-12-08 14:26:41 +01:00
|
|
|
inline bool hasFile() const { return !currentFile.isEmpty(); }
|
|
|
|
|
inline bool hasProject() const { return !currentProjectPath.isEmpty(); }
|
|
|
|
|
inline bool isEmpty() const { return !hasFile() && !hasProject(); }
|
|
|
|
|
|
|
|
|
|
QString currentFile;
|
|
|
|
|
QString currentFileName;
|
2010-03-25 16:23:37 +01:00
|
|
|
QString currentPatchFile;
|
|
|
|
|
QString currentPatchFileDisplayName;
|
|
|
|
|
|
2009-12-08 14:26:41 +01:00
|
|
|
QString currentFileDirectory;
|
|
|
|
|
QString currentFileTopLevel;
|
|
|
|
|
|
|
|
|
|
QString currentProjectPath;
|
|
|
|
|
QString currentProjectName;
|
|
|
|
|
QString currentProjectTopLevel;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void State::clearFile()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-12-08 14:26:41 +01:00
|
|
|
currentFile.clear();
|
|
|
|
|
currentFileName.clear();
|
|
|
|
|
currentFileDirectory.clear();
|
|
|
|
|
currentFileTopLevel.clear();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-03-25 16:23:37 +01:00
|
|
|
void State::clearPatchFile()
|
|
|
|
|
{
|
|
|
|
|
currentPatchFile.clear();
|
|
|
|
|
currentPatchFileDisplayName.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-08 14:26:41 +01:00
|
|
|
void State::clearProject()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-12-08 14:26:41 +01:00
|
|
|
currentProjectPath.clear();
|
|
|
|
|
currentProjectName.clear();
|
|
|
|
|
currentProjectTopLevel.clear();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-12-08 14:26:41 +01:00
|
|
|
void State::clear()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2009-12-08 14:26:41 +01:00
|
|
|
clearFile();
|
2010-03-25 16:23:37 +01:00
|
|
|
clearPatchFile();
|
2009-12-08 14:26:41 +01:00
|
|
|
clearProject();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool State::equals(const State &rhs) const
|
|
|
|
|
{
|
|
|
|
|
return currentFile == rhs.currentFile
|
|
|
|
|
&& currentFileName == rhs.currentFileName
|
2010-03-25 16:23:37 +01:00
|
|
|
&& currentPatchFile == rhs.currentPatchFile
|
2010-12-02 13:04:59 +01:00
|
|
|
&& currentPatchFileDisplayName == rhs.currentPatchFileDisplayName
|
2009-12-08 14:26:41 +01:00
|
|
|
&& currentFileTopLevel == rhs.currentFileTopLevel
|
|
|
|
|
&& currentProjectPath == rhs.currentProjectPath
|
|
|
|
|
&& currentProjectName == rhs.currentProjectName
|
|
|
|
|
&& currentProjectTopLevel == rhs.currentProjectTopLevel;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-12-08 14:26:41 +01:00
|
|
|
QDebug operator<<(QDebug in, const State &state)
|
|
|
|
|
{
|
|
|
|
|
QDebug nospace = in.nospace();
|
|
|
|
|
nospace << "State: ";
|
|
|
|
|
if (state.isEmpty()) {
|
|
|
|
|
nospace << "<empty>";
|
|
|
|
|
} else {
|
|
|
|
|
if (state.hasFile()) {
|
|
|
|
|
nospace << "File=" << state.currentFile
|
|
|
|
|
<< ',' << state.currentFileTopLevel;
|
|
|
|
|
} else {
|
|
|
|
|
nospace << "<no file>";
|
|
|
|
|
}
|
|
|
|
|
nospace << '\n';
|
|
|
|
|
if (state.hasProject()) {
|
|
|
|
|
nospace << " Project=" << state.currentProjectName
|
|
|
|
|
<< ',' << state.currentProjectPath
|
|
|
|
|
<< ',' << state.currentProjectTopLevel;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
nospace << "<no project>";
|
|
|
|
|
}
|
|
|
|
|
nospace << '\n';
|
|
|
|
|
}
|
|
|
|
|
return in;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-28 14:19:17 +02:00
|
|
|
/*!
|
2012-01-07 12:31:48 +01:00
|
|
|
\class VcsBase::Internal::StateListener
|
2011-03-28 14:19:17 +02:00
|
|
|
|
2013-06-05 14:29:24 +02:00
|
|
|
\brief The StateListener class connects to the relevant signals of \QC,
|
|
|
|
|
tries to find version
|
2011-03-28 14:19:17 +02:00
|
|
|
controls and emits signals to the plugin instances.
|
|
|
|
|
|
|
|
|
|
Singleton (as not to do checks multiple times).
|
|
|
|
|
*/
|
2009-12-08 14:26:41 +01:00
|
|
|
|
2012-01-07 03:35:54 +01:00
|
|
|
class StateListener : public QObject
|
|
|
|
|
{
|
2009-12-08 14:26:41 +01:00
|
|
|
Q_OBJECT
|
2012-01-07 03:35:54 +01:00
|
|
|
|
2009-12-08 14:26:41 +01:00
|
|
|
public:
|
|
|
|
|
explicit StateListener(QObject *parent);
|
|
|
|
|
|
|
|
|
|
signals:
|
2012-01-07 12:31:48 +01:00
|
|
|
void stateChanged(const VcsBase::Internal::State &s, Core::IVersionControl *vc);
|
2009-12-08 14:26:41 +01:00
|
|
|
|
2010-04-26 09:12:58 +02:00
|
|
|
public slots:
|
2009-12-08 14:26:41 +01:00
|
|
|
void slotStateChanged();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
StateListener::StateListener(QObject *parent) :
|
|
|
|
|
QObject(parent)
|
|
|
|
|
{
|
2012-01-24 15:36:40 +01:00
|
|
|
connect(Core::ICore::editorManager(), SIGNAL(currentEditorChanged(Core::IEditor*)),
|
2009-12-08 14:26:41 +01:00
|
|
|
this, SLOT(slotStateChanged()));
|
2012-01-24 15:36:40 +01:00
|
|
|
connect(Core::ICore::editorManager(), SIGNAL(currentEditorStateChanged(Core::IEditor*)),
|
2010-12-02 13:04:59 +01:00
|
|
|
this, SLOT(slotStateChanged()));
|
2012-01-24 15:36:40 +01:00
|
|
|
connect(Core::ICore::vcsManager(), SIGNAL(repositoryChanged(QString)),
|
2011-09-13 15:05:50 +00:00
|
|
|
this, SLOT(slotStateChanged()));
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-12-08 14:26:41 +01:00
|
|
|
if (ProjectExplorer::ProjectExplorerPlugin *pe = ProjectExplorer::ProjectExplorerPlugin::instance())
|
|
|
|
|
connect(pe, SIGNAL(currentProjectChanged(ProjectExplorer::Project*)),
|
|
|
|
|
this, SLOT(slotStateChanged()));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-03-25 16:23:37 +01:00
|
|
|
static inline QString displayNameOfEditor(const QString &fileName)
|
|
|
|
|
{
|
|
|
|
|
const QList<Core::IEditor*> editors = Core::EditorManager::instance()->editorsForFileName(fileName);
|
|
|
|
|
if (!editors.isEmpty())
|
|
|
|
|
return editors.front()->displayName();
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-08 14:26:41 +01:00
|
|
|
void StateListener::slotStateChanged()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2012-01-24 15:36:40 +01:00
|
|
|
Core::VcsManager *vcsManager = Core::ICore::vcsManager();
|
2009-12-08 14:26:41 +01:00
|
|
|
|
2009-12-14 10:56:50 +01:00
|
|
|
// Get the current file. Are we on a temporary submit editor indicated by
|
|
|
|
|
// temporary path prefix or does the file contains a hash, indicating a project
|
|
|
|
|
// folder?
|
2009-12-08 14:26:41 +01:00
|
|
|
State state;
|
2012-05-08 09:43:14 +02:00
|
|
|
Core::IEditor *currentEditor = Core::EditorManager::currentEditor();
|
|
|
|
|
if (!currentEditor || !currentEditor->document())
|
2011-10-06 19:36:26 +02:00
|
|
|
state.currentFile.clear();
|
|
|
|
|
else
|
2013-07-04 13:30:26 +02:00
|
|
|
state.currentFile = currentEditor->document()->filePath();
|
2010-03-25 16:23:37 +01:00
|
|
|
QScopedPointer<QFileInfo> currentFileInfo; // Instantiate QFileInfo only once if required.
|
2009-12-14 10:56:50 +01:00
|
|
|
if (!state.currentFile.isEmpty()) {
|
2010-03-25 16:23:37 +01:00
|
|
|
const bool isTempFile = state.currentFile.startsWith(QDir::tempPath());
|
|
|
|
|
// Quick check: Does it look like a patch?
|
|
|
|
|
const bool isPatch = state.currentFile.endsWith(QLatin1String(".patch"))
|
|
|
|
|
|| state.currentFile.endsWith(QLatin1String(".diff"));
|
|
|
|
|
if (isPatch) {
|
|
|
|
|
// Patch: Figure out a name to display. If it is a temp file, it could be
|
|
|
|
|
// Codepaster. Use the display name of the editor.
|
|
|
|
|
state.currentPatchFile = state.currentFile;
|
|
|
|
|
if (isTempFile)
|
|
|
|
|
state.currentPatchFileDisplayName = displayNameOfEditor(state.currentPatchFile);
|
|
|
|
|
if (state.currentPatchFileDisplayName.isEmpty()) {
|
|
|
|
|
currentFileInfo.reset(new QFileInfo(state.currentFile));
|
|
|
|
|
state.currentPatchFileDisplayName = currentFileInfo->fileName();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// For actual version control operations on it:
|
|
|
|
|
// Do not show temporary files and project folders ('#')
|
|
|
|
|
if (isTempFile || state.currentFile.contains(QLatin1Char('#')))
|
2009-12-14 10:56:50 +01:00
|
|
|
state.currentFile.clear();
|
|
|
|
|
}
|
2010-12-02 13:04:59 +01:00
|
|
|
|
2009-12-08 14:26:41 +01:00
|
|
|
// Get the file and its control. Do not use the file unless we find one
|
|
|
|
|
Core::IVersionControl *fileControl = 0;
|
|
|
|
|
if (!state.currentFile.isEmpty()) {
|
2010-03-25 16:23:37 +01:00
|
|
|
if (currentFileInfo.isNull())
|
|
|
|
|
currentFileInfo.reset(new QFileInfo(state.currentFile));
|
|
|
|
|
state.currentFileDirectory = currentFileInfo->absolutePath();
|
|
|
|
|
state.currentFileName = currentFileInfo->fileName();
|
2009-12-08 14:26:41 +01:00
|
|
|
fileControl = vcsManager->findVersionControlForDirectory(state.currentFileDirectory,
|
|
|
|
|
&state.currentFileTopLevel);
|
|
|
|
|
if (!fileControl)
|
|
|
|
|
state.clearFile();
|
|
|
|
|
}
|
|
|
|
|
// Check for project, find the control
|
|
|
|
|
Core::IVersionControl *projectControl = 0;
|
2012-01-24 18:57:39 +01:00
|
|
|
if (const ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectExplorerPlugin::currentProject()) {
|
2010-03-25 13:19:27 +01:00
|
|
|
state.currentProjectPath = currentProject->projectDirectory();
|
2010-01-07 18:17:24 +01:00
|
|
|
state.currentProjectName = currentProject->displayName();
|
2009-12-08 14:26:41 +01:00
|
|
|
projectControl = vcsManager->findVersionControlForDirectory(state.currentProjectPath,
|
|
|
|
|
&state.currentProjectTopLevel);
|
|
|
|
|
if (projectControl) {
|
|
|
|
|
// If we have both, let the file's one take preference
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
if (fileControl && projectControl != fileControl)
|
2009-12-08 14:26:41 +01:00
|
|
|
state.clearProject();
|
|
|
|
|
} else {
|
|
|
|
|
state.clearProject(); // No control found
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Assemble state and emit signal.
|
|
|
|
|
Core::IVersionControl *vc = state.currentFile.isEmpty() ? projectControl : fileControl;
|
2010-03-25 16:23:37 +01:00
|
|
|
if (!vc) // Need a repository to patch
|
|
|
|
|
state.clearPatchFile();
|
2009-12-08 14:26:41 +01:00
|
|
|
if (debug)
|
2010-01-07 18:17:24 +01:00
|
|
|
qDebug() << state << (vc ? vc->displayName() : QString(QLatin1String("No version control")));
|
2009-12-08 14:26:41 +01:00
|
|
|
emit stateChanged(state, vc);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2008-12-02 17:05:53 +01:00
|
|
|
|
2009-12-08 14:26:41 +01:00
|
|
|
} // namespace Internal
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
class VcsBasePluginStateData : public QSharedData
|
2012-01-07 03:35:54 +01:00
|
|
|
{
|
2009-12-08 14:26:41 +01:00
|
|
|
public:
|
|
|
|
|
Internal::State m_state;
|
|
|
|
|
};
|
|
|
|
|
|
2011-03-28 14:19:17 +02:00
|
|
|
/*!
|
2012-01-07 12:31:48 +01:00
|
|
|
\class VcsBase::VcsBasePluginState
|
2011-03-28 14:19:17 +02:00
|
|
|
|
2013-06-05 14:29:24 +02:00
|
|
|
\brief The VcsBasePluginState class provides relevant state information
|
|
|
|
|
about the VCS plugins.
|
2011-03-28 14:19:17 +02:00
|
|
|
|
|
|
|
|
Qt Creator's state relevant to VCS plugins is a tuple of
|
|
|
|
|
|
|
|
|
|
\list
|
2013-02-06 08:50:23 +01:00
|
|
|
\li Current file and it's version system control/top level
|
|
|
|
|
\li Current project and it's version system control/top level
|
2011-03-28 14:19:17 +02:00
|
|
|
\endlist
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
\sa VcsBase::VcsBasePlugin
|
2011-03-28 14:19:17 +02:00
|
|
|
*/
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
VcsBasePluginState::VcsBasePluginState() : data(new VcsBasePluginStateData)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
VcsBasePluginState::VcsBasePluginState(const VcsBasePluginState &rhs) : data(rhs.data)
|
2009-03-19 17:40:01 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
VcsBasePluginState &VcsBasePluginState::operator=(const VcsBasePluginState &rhs)
|
2009-03-20 14:20:28 +01:00
|
|
|
{
|
2009-12-08 14:26:41 +01:00
|
|
|
if (this != &rhs)
|
|
|
|
|
data.operator=(rhs.data);
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
VcsBasePluginState::~VcsBasePluginState()
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
QString VcsBasePluginState::currentFile() const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
return data->m_state.currentFile;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
QString VcsBasePluginState::currentFileName() const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
return data->m_state.currentFileName;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
QString VcsBasePluginState::currentFileTopLevel() const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
return data->m_state.currentFileTopLevel;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
QString VcsBasePluginState::currentFileDirectory() const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
return data->m_state.currentFileDirectory;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
QString VcsBasePluginState::relativeCurrentFile() const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
2012-04-17 08:01:25 +02:00
|
|
|
QTC_ASSERT(hasFile(), return QString());
|
2009-12-08 14:26:41 +01:00
|
|
|
return QDir(data->m_state.currentFileTopLevel).relativeFilePath(data->m_state.currentFile);
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
QString VcsBasePluginState::currentPatchFile() const
|
2010-03-25 16:23:37 +01:00
|
|
|
{
|
|
|
|
|
return data->m_state.currentPatchFile;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
QString VcsBasePluginState::currentPatchFileDisplayName() const
|
2010-03-25 16:23:37 +01:00
|
|
|
{
|
|
|
|
|
return data->m_state.currentPatchFileDisplayName;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
QString VcsBasePluginState::currentProjectPath() const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
return data->m_state.currentProjectPath;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
QString VcsBasePluginState::currentProjectName() const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
return data->m_state.currentProjectName;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
QString VcsBasePluginState::currentProjectTopLevel() const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
return data->m_state.currentProjectTopLevel;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
QStringList VcsBasePluginState::relativeCurrentProject() const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
QStringList rc;
|
2012-04-17 08:01:25 +02:00
|
|
|
QTC_ASSERT(hasProject(), return rc);
|
2009-12-08 14:26:41 +01:00
|
|
|
if (data->m_state.currentProjectTopLevel != data->m_state.currentProjectPath)
|
|
|
|
|
rc.append(QDir(data->m_state.currentProjectTopLevel).relativeFilePath(data->m_state.currentProjectPath));
|
|
|
|
|
return rc;
|
2009-03-20 14:20:28 +01:00
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
bool VcsBasePluginState::hasTopLevel() const
|
2009-03-20 14:20:28 +01:00
|
|
|
{
|
2009-12-08 14:26:41 +01:00
|
|
|
return data->m_state.hasFile() || data->m_state.hasProject();
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
QString VcsBasePluginState::topLevel() const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
return hasFile() ? data->m_state.currentFileTopLevel : data->m_state.currentProjectTopLevel;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
bool VcsBasePluginState::equals(const Internal::State &rhs) const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
return data->m_state.equals(rhs);
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
bool VcsBasePluginState::equals(const VcsBasePluginState &rhs) const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
return equals(rhs.data->m_state);
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
void VcsBasePluginState::clear()
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
data->m_state.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
void VcsBasePluginState::setState(const Internal::State &s)
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
data->m_state = s;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
bool VcsBasePluginState::isEmpty() const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
return data->m_state.isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
bool VcsBasePluginState::hasFile() const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
return data->m_state.hasFile();
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
bool VcsBasePluginState::hasPatchFile() const
|
2010-03-25 16:23:37 +01:00
|
|
|
{
|
|
|
|
|
return !data->m_state.currentPatchFile.isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
bool VcsBasePluginState::hasProject() const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
return data->m_state.hasProject();
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
VCSBASE_EXPORT QDebug operator<<(QDebug in, const VcsBasePluginState &state)
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
in << state.data->m_state;
|
|
|
|
|
return in;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-28 14:19:17 +02:00
|
|
|
/*!
|
2012-01-07 12:31:48 +01:00
|
|
|
\class VcsBase::VcsBasePlugin
|
2011-03-28 14:19:17 +02:00
|
|
|
|
2013-06-05 14:29:24 +02:00
|
|
|
\brief The VcsBasePlugin class is the base class for all version control
|
|
|
|
|
plugins.
|
2011-03-28 14:19:17 +02:00
|
|
|
|
|
|
|
|
The plugin connects to the
|
|
|
|
|
relevant change signals in Qt Creator and calls the virtual
|
|
|
|
|
updateActions() for the plugins to update their menu actions
|
|
|
|
|
according to the new state. This is done centrally to avoid
|
|
|
|
|
single plugins repeatedly invoking searches/QFileInfo on files,
|
|
|
|
|
etc.
|
|
|
|
|
|
|
|
|
|
Independently, there are accessors for current patch files, which return
|
|
|
|
|
a file name if the current file could be a patch file which could be applied
|
|
|
|
|
and a repository exists.
|
|
|
|
|
|
|
|
|
|
If current file/project are managed
|
|
|
|
|
by different version controls, the project is discarded and only
|
|
|
|
|
the current file is taken into account, allowing to do a diff
|
|
|
|
|
also when the project of a file is not opened.
|
|
|
|
|
|
|
|
|
|
When triggering an action, a copy of the state should be made to
|
|
|
|
|
keep it, as it may rapidly change due to context changes, etc.
|
|
|
|
|
|
|
|
|
|
The class also detects the VCS plugin submit editor closing and calls
|
|
|
|
|
the virtual submitEditorAboutToClose() to trigger the submit process.
|
|
|
|
|
*/
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
struct VcsBasePluginPrivate
|
2011-11-10 11:36:51 +01:00
|
|
|
{
|
2013-04-18 12:06:43 +02:00
|
|
|
explicit VcsBasePluginPrivate();
|
2009-12-08 14:26:41 +01:00
|
|
|
|
2010-01-12 16:45:21 +01:00
|
|
|
inline bool supportsRepositoryCreation() const;
|
|
|
|
|
|
2013-04-18 12:06:43 +02:00
|
|
|
QPointer<VcsBaseSubmitEditor> m_submitEditor;
|
2009-12-08 14:26:41 +01:00
|
|
|
Core::IVersionControl *m_versionControl;
|
2012-01-07 12:31:48 +01:00
|
|
|
VcsBasePluginState m_state;
|
2009-12-08 14:26:41 +01:00
|
|
|
int m_actionState;
|
2010-01-15 12:24:06 +01:00
|
|
|
QAction *m_testSnapshotAction;
|
|
|
|
|
QAction *m_testListSnapshotsAction;
|
|
|
|
|
QAction *m_testRestoreSnapshotAction;
|
|
|
|
|
QAction *m_testRemoveSnapshotAction;
|
|
|
|
|
QString m_testLastSnapshot;
|
2009-12-08 14:26:41 +01:00
|
|
|
|
|
|
|
|
static Internal::StateListener *m_listener;
|
|
|
|
|
};
|
|
|
|
|
|
2013-04-18 12:06:43 +02:00
|
|
|
VcsBasePluginPrivate::VcsBasePluginPrivate() :
|
2009-12-08 14:26:41 +01:00
|
|
|
m_versionControl(0),
|
2010-01-15 12:24:06 +01:00
|
|
|
m_actionState(-1),
|
|
|
|
|
m_testSnapshotAction(0),
|
|
|
|
|
m_testListSnapshotsAction(0),
|
|
|
|
|
m_testRestoreSnapshotAction(0),
|
|
|
|
|
m_testRemoveSnapshotAction(0)
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
bool VcsBasePluginPrivate::supportsRepositoryCreation() const
|
2010-01-12 16:45:21 +01:00
|
|
|
{
|
|
|
|
|
return m_versionControl && m_versionControl->supportsOperation(Core::IVersionControl::CreateRepositoryOperation);
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
Internal::StateListener *VcsBasePluginPrivate::m_listener = 0;
|
2009-12-08 14:26:41 +01:00
|
|
|
|
2013-04-18 12:06:43 +02:00
|
|
|
VcsBasePlugin::VcsBasePlugin() :
|
|
|
|
|
d(new VcsBasePluginPrivate())
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
VcsBasePlugin::~VcsBasePlugin()
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
delete d;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
void VcsBasePlugin::initializeVcs(Core::IVersionControl *vc)
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
d->m_versionControl = vc;
|
|
|
|
|
addAutoReleasedObject(vc);
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
Internal::VcsPlugin *plugin = Internal::VcsPlugin::instance();
|
|
|
|
|
connect(plugin->coreListener(), SIGNAL(submitEditorAboutToClose(VcsBaseSubmitEditor*,bool*)),
|
|
|
|
|
this, SLOT(slotSubmitEditorAboutToClose(VcsBaseSubmitEditor*,bool*)));
|
2009-12-08 14:26:41 +01:00
|
|
|
// First time: create new listener
|
2012-01-07 12:31:48 +01:00
|
|
|
if (!VcsBasePluginPrivate::m_listener)
|
|
|
|
|
VcsBasePluginPrivate::m_listener = new Internal::StateListener(plugin);
|
|
|
|
|
connect(VcsBasePluginPrivate::m_listener,
|
2012-03-05 22:30:59 +01:00
|
|
|
SIGNAL(stateChanged(VcsBase::Internal::State,Core::IVersionControl*)),
|
2009-12-08 14:26:41 +01:00
|
|
|
this,
|
2012-01-07 12:31:48 +01:00
|
|
|
SLOT(slotStateChanged(VcsBase::Internal::State,Core::IVersionControl*)));
|
2013-06-03 18:53:44 +02:00
|
|
|
// VCSes might have become (un-)available, so clear the VCS directory cache
|
|
|
|
|
connect(vc, SIGNAL(configurationChanged()),
|
|
|
|
|
Core::ICore::vcsManager(), SLOT(clearVersionControlCache()));
|
2013-06-13 21:28:12 +03:00
|
|
|
connect(vc, SIGNAL(configurationChanged()),
|
|
|
|
|
VcsBasePluginPrivate::m_listener, SLOT(slotStateChanged()));
|
2009-12-08 14:26:41 +01:00
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
void VcsBasePlugin::extensionsInitialized()
|
2010-04-26 09:12:58 +02:00
|
|
|
{
|
|
|
|
|
// Initialize enable menus.
|
2012-01-07 12:31:48 +01:00
|
|
|
VcsBasePluginPrivate::m_listener->slotStateChanged();
|
2010-04-26 09:12:58 +02:00
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
void VcsBasePlugin::slotSubmitEditorAboutToClose(VcsBaseSubmitEditor *submitEditor, bool *result)
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
if (debug)
|
2013-04-18 12:06:43 +02:00
|
|
|
qDebug() << this << "plugin's submit editor"
|
|
|
|
|
<< d->m_submitEditor << (d->m_submitEditor ? d->m_submitEditor->id().name() : "")
|
|
|
|
|
<< "closing submit editor" << submitEditor << submitEditor->id().name();
|
|
|
|
|
if (submitEditor == d->m_submitEditor)
|
|
|
|
|
*result = submitEditorAboutToClose();
|
2009-12-08 14:26:41 +01:00
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
Core::IVersionControl *VcsBasePlugin::versionControl() const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
return d->m_versionControl;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
void VcsBasePlugin::slotStateChanged(const VcsBase::Internal::State &newInternalState, Core::IVersionControl *vc)
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
if (vc == d->m_versionControl) {
|
|
|
|
|
// We are directly affected: Change state
|
|
|
|
|
if (!d->m_state.equals(newInternalState)) {
|
|
|
|
|
d->m_state.setState(newInternalState);
|
2012-01-07 12:31:48 +01:00
|
|
|
updateActions(VcsEnabled);
|
2009-03-20 14:20:28 +01:00
|
|
|
}
|
2009-12-08 14:26:41 +01:00
|
|
|
} else {
|
|
|
|
|
// Some other VCS plugin or state changed: Reset us to empty state.
|
2012-01-07 12:31:48 +01:00
|
|
|
const ActionState newActionState = vc ? OtherVcsEnabled : NoVcsEnabled;
|
2009-12-08 14:26:41 +01:00
|
|
|
if (d->m_actionState != newActionState || !d->m_state.isEmpty()) {
|
|
|
|
|
d->m_actionState = newActionState;
|
2012-01-07 12:31:48 +01:00
|
|
|
const VcsBasePluginState emptyState;
|
2009-12-08 14:26:41 +01:00
|
|
|
d->m_state = emptyState;
|
|
|
|
|
updateActions(newActionState);
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-03-20 14:20:28 +01:00
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
const VcsBasePluginState &VcsBasePlugin::currentState() const
|
2009-03-20 14:20:28 +01:00
|
|
|
{
|
2009-12-08 14:26:41 +01:00
|
|
|
return d->m_state;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
bool VcsBasePlugin::enableMenuAction(ActionState as, QAction *menuAction) const
|
2009-12-08 14:26:41 +01:00
|
|
|
{
|
|
|
|
|
if (debug)
|
|
|
|
|
qDebug() << "enableMenuAction" << menuAction->text() << as;
|
|
|
|
|
switch (as) {
|
2012-01-07 12:31:48 +01:00
|
|
|
case VcsBase::VcsBasePlugin::NoVcsEnabled: {
|
2010-01-12 16:45:21 +01:00
|
|
|
const bool supportsCreation = d->supportsRepositoryCreation();
|
2010-04-16 14:12:18 +02:00
|
|
|
menuAction->setVisible(supportsCreation);
|
2010-01-12 16:45:21 +01:00
|
|
|
menuAction->setEnabled(supportsCreation);
|
|
|
|
|
return supportsCreation;
|
|
|
|
|
}
|
2012-01-07 12:31:48 +01:00
|
|
|
case VcsBase::VcsBasePlugin::OtherVcsEnabled:
|
2009-12-08 14:26:41 +01:00
|
|
|
menuAction->setVisible(false);
|
|
|
|
|
return false;
|
2012-01-07 12:31:48 +01:00
|
|
|
case VcsBase::VcsBasePlugin::VcsEnabled:
|
2009-12-08 14:26:41 +01:00
|
|
|
menuAction->setVisible(true);
|
|
|
|
|
menuAction->setEnabled(true);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2009-03-20 14:20:28 +01:00
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
void VcsBasePlugin::promptToDeleteCurrentFile()
|
2010-01-11 15:22:17 +01:00
|
|
|
{
|
2012-01-07 12:31:48 +01:00
|
|
|
const VcsBasePluginState state = currentState();
|
2012-04-17 08:01:25 +02:00
|
|
|
QTC_ASSERT(state.hasFile(), return);
|
2012-01-24 15:36:40 +01:00
|
|
|
const bool rc = Core::ICore::vcsManager()->promptToDelete(versionControl(), state.currentFile());
|
2010-01-11 15:22:17 +01:00
|
|
|
if (!rc)
|
2010-07-05 09:52:32 +02:00
|
|
|
QMessageBox::warning(0, tr("Version Control"),
|
|
|
|
|
tr("The file '%1' could not be deleted.").
|
|
|
|
|
arg(QDir::toNativeSeparators(state.currentFile())),
|
|
|
|
|
QMessageBox::Ok);
|
2010-01-11 15:22:17 +01:00
|
|
|
}
|
|
|
|
|
|
2010-01-12 16:45:21 +01:00
|
|
|
static inline bool ask(QWidget *parent, const QString &title, const QString &question, bool defaultValue = true)
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
const QMessageBox::StandardButton defaultButton = defaultValue ? QMessageBox::Yes : QMessageBox::No;
|
|
|
|
|
return QMessageBox::question(parent, title, question, QMessageBox::Yes|QMessageBox::No, defaultButton) == QMessageBox::Yes;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
void VcsBasePlugin::createRepository()
|
2010-01-12 16:45:21 +01:00
|
|
|
{
|
|
|
|
|
QTC_ASSERT(d->m_versionControl->supportsOperation(Core::IVersionControl::CreateRepositoryOperation), return);
|
|
|
|
|
// Find current starting directory
|
|
|
|
|
QString directory;
|
2012-01-24 18:57:39 +01:00
|
|
|
if (const ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectExplorerPlugin::currentProject())
|
2013-07-04 13:30:26 +02:00
|
|
|
directory = QFileInfo(currentProject->document()->filePath()).absolutePath();
|
2010-01-12 16:45:21 +01:00
|
|
|
// Prompt for a directory that is not under version control yet
|
2012-07-19 15:31:22 +04:00
|
|
|
QWidget *mw = Core::ICore::mainWindow();
|
2010-01-12 16:45:21 +01:00
|
|
|
do {
|
2010-05-14 15:45:43 +02:00
|
|
|
directory = QFileDialog::getExistingDirectory(mw, tr("Choose Repository Directory"), directory);
|
2010-01-12 16:45:21 +01:00
|
|
|
if (directory.isEmpty())
|
|
|
|
|
return;
|
2012-01-24 15:36:40 +01:00
|
|
|
const Core::IVersionControl *managingControl = Core::ICore::vcsManager()->findVersionControlForDirectory(directory);
|
2010-01-12 16:45:21 +01:00
|
|
|
if (managingControl == 0)
|
|
|
|
|
break;
|
|
|
|
|
const QString question = tr("The directory '%1' is already managed by a version control system (%2)."
|
|
|
|
|
" Would you like to specify another directory?").arg(directory, managingControl->displayName());
|
|
|
|
|
|
|
|
|
|
if (!ask(mw, tr("Repository already under version control"), question))
|
|
|
|
|
return;
|
|
|
|
|
} while (true);
|
|
|
|
|
// Create
|
|
|
|
|
const bool rc = d->m_versionControl->vcsCreateRepository(directory);
|
2010-07-05 09:52:32 +02:00
|
|
|
const QString nativeDir = QDir::toNativeSeparators(directory);
|
2010-01-12 16:45:21 +01:00
|
|
|
if (rc) {
|
2010-09-21 17:17:54 +02:00
|
|
|
QMessageBox::information(mw, tr("Repository Created"),
|
2010-07-05 09:52:32 +02:00
|
|
|
tr("A version control repository has been created in %1.").
|
|
|
|
|
arg(nativeDir));
|
2010-01-12 16:45:21 +01:00
|
|
|
} else {
|
2010-09-21 17:17:54 +02:00
|
|
|
QMessageBox::warning(mw, tr("Repository Creation Failed"),
|
2010-07-05 09:52:32 +02:00
|
|
|
tr("A version control repository could not be created in %1.").
|
|
|
|
|
arg(nativeDir));
|
2010-01-12 16:45:21 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-18 12:06:43 +02:00
|
|
|
void VcsBasePlugin::setSubmitEditor(VcsBaseSubmitEditor *submitEditor)
|
|
|
|
|
{
|
|
|
|
|
d->m_submitEditor = submitEditor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VcsBaseSubmitEditor *VcsBasePlugin::submitEditor() const
|
|
|
|
|
{
|
|
|
|
|
return d->m_submitEditor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool VcsBasePlugin::raiseSubmitEditor() const
|
|
|
|
|
{
|
|
|
|
|
if (!d->m_submitEditor)
|
|
|
|
|
return false;
|
2013-05-31 12:52:53 +02:00
|
|
|
Core::EditorManager::activateEditor(d->m_submitEditor, Core::EditorManager::IgnoreNavigationHistory);
|
2013-04-18 12:06:43 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-15 12:24:06 +01:00
|
|
|
// For internal tests: Create actions driving IVersionControl's snapshot interface.
|
2012-01-07 12:31:48 +01:00
|
|
|
QList<QAction*> VcsBasePlugin::createSnapShotTestActions()
|
2010-01-15 12:24:06 +01:00
|
|
|
{
|
|
|
|
|
if (!d->m_testSnapshotAction) {
|
|
|
|
|
d->m_testSnapshotAction = new QAction(QLatin1String("Take snapshot"), this);
|
|
|
|
|
connect(d->m_testSnapshotAction, SIGNAL(triggered()), this, SLOT(slotTestSnapshot()));
|
|
|
|
|
d->m_testListSnapshotsAction = new QAction(QLatin1String("List snapshots"), this);
|
|
|
|
|
connect(d->m_testListSnapshotsAction, SIGNAL(triggered()), this, SLOT(slotTestListSnapshots()));
|
|
|
|
|
d->m_testRestoreSnapshotAction = new QAction(QLatin1String("Restore snapshot"), this);
|
|
|
|
|
connect(d->m_testRestoreSnapshotAction, SIGNAL(triggered()), this, SLOT(slotTestRestoreSnapshot()));
|
|
|
|
|
d->m_testRemoveSnapshotAction = new QAction(QLatin1String("Remove snapshot"), this);
|
|
|
|
|
connect(d->m_testRemoveSnapshotAction, SIGNAL(triggered()), this, SLOT(slotTestRemoveSnapshot()));
|
|
|
|
|
}
|
|
|
|
|
QList<QAction*> rc;
|
|
|
|
|
rc << d->m_testSnapshotAction << d->m_testListSnapshotsAction << d->m_testRestoreSnapshotAction
|
|
|
|
|
<< d->m_testRemoveSnapshotAction;
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
void VcsBasePlugin::slotTestSnapshot()
|
2010-01-15 12:24:06 +01:00
|
|
|
{
|
2012-04-17 08:01:25 +02:00
|
|
|
QTC_ASSERT(currentState().hasTopLevel(), return);
|
2010-01-15 12:24:06 +01:00
|
|
|
d->m_testLastSnapshot = versionControl()->vcsCreateSnapshot(currentState().topLevel());
|
|
|
|
|
qDebug() << "Snapshot " << d->m_testLastSnapshot;
|
2012-01-07 12:31:48 +01:00
|
|
|
VcsBaseOutputWindow::instance()->append(QLatin1String("Snapshot: ") + d->m_testLastSnapshot);
|
2010-01-15 12:24:06 +01:00
|
|
|
if (!d->m_testLastSnapshot.isEmpty())
|
|
|
|
|
d->m_testRestoreSnapshotAction->setText(QLatin1String("Restore snapshot ") + d->m_testLastSnapshot);
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
void VcsBasePlugin::slotTestListSnapshots()
|
2010-01-15 12:24:06 +01:00
|
|
|
{
|
2012-04-17 08:01:25 +02:00
|
|
|
QTC_ASSERT(currentState().hasTopLevel(), return);
|
2010-01-15 12:24:06 +01:00
|
|
|
const QStringList snapshots = versionControl()->vcsSnapshots(currentState().topLevel());
|
|
|
|
|
qDebug() << "Snapshots " << snapshots;
|
2012-01-07 12:31:48 +01:00
|
|
|
VcsBaseOutputWindow::instance()->append(QLatin1String("Snapshots: ") + snapshots.join(QLatin1String(", ")));
|
2010-01-15 12:24:06 +01:00
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
void VcsBasePlugin::slotTestRestoreSnapshot()
|
2010-01-15 12:24:06 +01:00
|
|
|
{
|
2012-04-17 08:01:25 +02:00
|
|
|
QTC_ASSERT(currentState().hasTopLevel() && !d->m_testLastSnapshot.isEmpty(), return);
|
2010-01-15 12:24:06 +01:00
|
|
|
const bool ok = versionControl()->vcsRestoreSnapshot(currentState().topLevel(), d->m_testLastSnapshot);
|
|
|
|
|
const QString msg = d->m_testLastSnapshot+ (ok ? QLatin1String(" restored") : QLatin1String(" failed"));
|
|
|
|
|
qDebug() << msg;
|
2012-01-07 12:31:48 +01:00
|
|
|
VcsBaseOutputWindow::instance()->append(msg);
|
2010-01-15 12:24:06 +01:00
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
void VcsBasePlugin::slotTestRemoveSnapshot()
|
2010-01-15 12:24:06 +01:00
|
|
|
{
|
2012-04-17 08:01:25 +02:00
|
|
|
QTC_ASSERT(currentState().hasTopLevel() && !d->m_testLastSnapshot.isEmpty(), return);
|
2010-01-15 12:24:06 +01:00
|
|
|
const bool ok = versionControl()->vcsRemoveSnapshot(currentState().topLevel(), d->m_testLastSnapshot);
|
|
|
|
|
const QString msg = d->m_testLastSnapshot+ (ok ? QLatin1String(" removed") : QLatin1String(" failed"));
|
|
|
|
|
qDebug() << msg;
|
2012-01-07 12:31:48 +01:00
|
|
|
VcsBaseOutputWindow::instance()->append(msg);
|
2010-01-15 12:24:06 +01:00
|
|
|
d->m_testLastSnapshot.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-19 17:41:14 +02:00
|
|
|
// Find top level for version controls like git/Mercurial that have
|
|
|
|
|
// a directory at the top of the repository.
|
|
|
|
|
// Note that checking for the existence of files is preferred over directories
|
|
|
|
|
// since checking for directories can cause them to be created when
|
|
|
|
|
// AutoFS is used (due its automatically creating mountpoints when querying
|
|
|
|
|
// a directory). In addition, bail out when reaching the home directory
|
|
|
|
|
// of the user or root (generally avoid '/', where mountpoints are created).
|
2012-01-07 12:31:48 +01:00
|
|
|
QString VcsBasePlugin::findRepositoryForDirectory(const QString &dirS,
|
2010-05-19 17:41:14 +02:00
|
|
|
const QString &checkFile)
|
|
|
|
|
{
|
|
|
|
|
if (debugRepositorySearch)
|
2012-01-07 12:31:48 +01:00
|
|
|
qDebug() << ">VcsBasePlugin::findRepositoryForDirectory" << dirS << checkFile;
|
2010-05-19 17:41:14 +02:00
|
|
|
QTC_ASSERT(!dirS.isEmpty() && !checkFile.isEmpty(), return QString());
|
|
|
|
|
|
|
|
|
|
const QString root = QDir::rootPath();
|
|
|
|
|
const QString home = QDir::homePath();
|
|
|
|
|
|
|
|
|
|
QDir directory(dirS);
|
|
|
|
|
do {
|
|
|
|
|
const QString absDirPath = directory.absolutePath();
|
|
|
|
|
if (absDirPath == root || absDirPath == home)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (QFileInfo(directory, checkFile).isFile()) {
|
|
|
|
|
if (debugRepositorySearch)
|
2012-01-07 12:31:48 +01:00
|
|
|
qDebug() << "<VcsBasePlugin::findRepositoryForDirectory> " << absDirPath;
|
2010-05-19 17:41:14 +02:00
|
|
|
return absDirPath;
|
|
|
|
|
}
|
|
|
|
|
} while (directory.cdUp());
|
|
|
|
|
if (debugRepositorySearch)
|
2012-01-07 12:31:48 +01:00
|
|
|
qDebug() << "<VcsBasePlugin::findRepositoryForDirectory bailing out at " << directory.absolutePath();
|
2010-05-19 17:41:14 +02:00
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-21 17:46:00 +02:00
|
|
|
// Is SSH prompt configured?
|
|
|
|
|
static inline QString sshPrompt()
|
|
|
|
|
{
|
2012-01-07 12:31:48 +01:00
|
|
|
return VcsBase::Internal::VcsPlugin::instance()->settings().sshPasswordPrompt;
|
2010-05-21 17:46:00 +02:00
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
bool VcsBasePlugin::isSshPromptConfigured()
|
2010-05-21 17:46:00 +02:00
|
|
|
{
|
|
|
|
|
return !sshPrompt().isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
void VcsBasePlugin::setProcessEnvironment(QProcessEnvironment *e, bool forceCLocale)
|
2010-05-21 17:46:00 +02:00
|
|
|
{
|
2010-06-15 12:17:09 +02:00
|
|
|
if (forceCLocale)
|
|
|
|
|
e->insert(QLatin1String("LANG"), QString(QLatin1Char('C')));
|
2010-05-21 17:46:00 +02:00
|
|
|
const QString sshPromptBinary = sshPrompt();
|
|
|
|
|
if (!sshPromptBinary.isEmpty())
|
|
|
|
|
e->insert(QLatin1String("SSH_ASKPASS"), sshPromptBinary);
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-22 14:53:20 +01:00
|
|
|
// Run a process fully synchronously, returning Utils::SynchronousProcessResponse
|
2012-01-07 12:31:48 +01:00
|
|
|
// response struct and using the VcsBasePlugin flags as applicable
|
2012-01-07 03:35:54 +01:00
|
|
|
static SynchronousProcessResponse runVcsFullySynchronously(const QString &workingDir,
|
2010-11-22 14:53:20 +01:00
|
|
|
const QString &binary,
|
|
|
|
|
const QStringList &arguments,
|
|
|
|
|
int timeOutMS,
|
|
|
|
|
QProcessEnvironment env,
|
|
|
|
|
unsigned flags,
|
|
|
|
|
QTextCodec *outputCodec = 0)
|
|
|
|
|
{
|
2012-01-25 16:26:47 +01:00
|
|
|
SynchronousProcessResponse response;
|
|
|
|
|
if (binary.isEmpty()) {
|
|
|
|
|
response.result = SynchronousProcessResponse::StartFailed;
|
|
|
|
|
return response;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
VcsBase::VcsBaseOutputWindow *outputWindow = VcsBase::VcsBaseOutputWindow::instance();
|
2010-11-22 14:53:20 +01:00
|
|
|
|
|
|
|
|
// Set up process
|
|
|
|
|
unsigned processFlags = 0;
|
2012-01-07 12:31:48 +01:00
|
|
|
if (VcsBasePlugin::isSshPromptConfigured() && (flags & VcsBasePlugin::SshPasswordPrompt))
|
2012-01-07 03:35:54 +01:00
|
|
|
processFlags |= SynchronousProcess::UnixTerminalDisabled;
|
|
|
|
|
QSharedPointer<QProcess> process = SynchronousProcess::createProcess(processFlags);
|
2010-11-22 14:53:20 +01:00
|
|
|
if (!workingDir.isEmpty())
|
|
|
|
|
process->setWorkingDirectory(workingDir);
|
|
|
|
|
process->setProcessEnvironment(env);
|
2012-01-07 12:31:48 +01:00
|
|
|
if (flags & VcsBasePlugin::MergeOutputChannels)
|
2010-11-22 14:53:20 +01:00
|
|
|
process->setProcessChannelMode(QProcess::MergedChannels);
|
|
|
|
|
|
|
|
|
|
// Start
|
2011-06-14 16:47:10 +02:00
|
|
|
process->start(binary, arguments, QIODevice::ReadOnly);
|
|
|
|
|
process->closeWriteChannel();
|
2010-11-22 14:53:20 +01:00
|
|
|
if (!process->waitForStarted()) {
|
2012-01-07 03:35:54 +01:00
|
|
|
response.result = SynchronousProcessResponse::StartFailed;
|
2010-11-22 14:53:20 +01:00
|
|
|
return response;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// process output
|
|
|
|
|
QByteArray stdOut;
|
|
|
|
|
QByteArray stdErr;
|
|
|
|
|
const bool timedOut =
|
2012-01-07 03:35:54 +01:00
|
|
|
!SynchronousProcess::readDataFromProcess(*process.data(), timeOutMS,
|
2010-11-22 14:53:20 +01:00
|
|
|
&stdOut, &stdErr, true);
|
|
|
|
|
|
|
|
|
|
if (!stdErr.isEmpty()) {
|
2012-01-31 10:57:10 +01:00
|
|
|
response.stdErr = QString::fromLocal8Bit(stdErr).remove(QLatin1Char('\r'));
|
2012-01-07 12:31:48 +01:00
|
|
|
if (!(flags & VcsBasePlugin::SuppressStdErrInLogWindow))
|
2010-11-22 14:53:20 +01:00
|
|
|
outputWindow->append(response.stdErr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!stdOut.isEmpty()) {
|
|
|
|
|
response.stdOut = (outputCodec ? outputCodec->toUnicode(stdOut) : QString::fromLocal8Bit(stdOut))
|
2012-01-31 10:57:10 +01:00
|
|
|
.remove(QLatin1Char('\r'));
|
2012-01-07 12:31:48 +01:00
|
|
|
if (flags & VcsBasePlugin::ShowStdOutInLogWindow)
|
2010-11-22 14:53:20 +01:00
|
|
|
outputWindow->append(response.stdOut);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Result
|
|
|
|
|
if (timedOut) {
|
2012-01-07 03:35:54 +01:00
|
|
|
response.result = SynchronousProcessResponse::Hang;
|
2010-11-22 14:53:20 +01:00
|
|
|
} else if (process->exitStatus() != QProcess::NormalExit) {
|
2012-01-07 03:35:54 +01:00
|
|
|
response.result = SynchronousProcessResponse::TerminatedAbnormally;
|
2010-11-22 14:53:20 +01:00
|
|
|
} else {
|
|
|
|
|
response.result = process->exitCode() == 0 ?
|
2012-01-07 03:35:54 +01:00
|
|
|
SynchronousProcessResponse::Finished :
|
|
|
|
|
SynchronousProcessResponse::FinishedError;
|
2010-11-22 14:53:20 +01:00
|
|
|
}
|
|
|
|
|
return response;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
SynchronousProcessResponse VcsBasePlugin::runVcs(const QString &workingDir,
|
2011-10-05 10:35:24 +00:00
|
|
|
const QString &binary,
|
|
|
|
|
const QStringList &arguments,
|
|
|
|
|
int timeOutMS,
|
|
|
|
|
unsigned flags,
|
|
|
|
|
QTextCodec *outputCodec)
|
2010-05-21 17:46:00 +02:00
|
|
|
{
|
|
|
|
|
const QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
2012-01-07 12:31:48 +01:00
|
|
|
return runVcs(workingDir, binary, arguments, timeOutMS, env,
|
2010-05-21 17:46:00 +02:00
|
|
|
flags, outputCodec);
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
SynchronousProcessResponse VcsBasePlugin::runVcs(const QString &workingDir,
|
2012-01-07 03:35:54 +01:00
|
|
|
const QString &binary,
|
|
|
|
|
const QStringList &arguments,
|
|
|
|
|
int timeOutMS,
|
|
|
|
|
QProcessEnvironment env,
|
|
|
|
|
unsigned flags,
|
|
|
|
|
QTextCodec *outputCodec)
|
2010-05-21 17:46:00 +02:00
|
|
|
{
|
2012-01-25 16:26:47 +01:00
|
|
|
SynchronousProcessResponse response;
|
|
|
|
|
|
|
|
|
|
if (binary.isEmpty()) {
|
|
|
|
|
response.result = SynchronousProcessResponse::StartFailed;
|
|
|
|
|
return response;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
VcsBase::VcsBaseOutputWindow *outputWindow = VcsBase::VcsBaseOutputWindow::instance();
|
2010-05-21 17:46:00 +02:00
|
|
|
|
|
|
|
|
if (!(flags & SuppressCommandLogging))
|
|
|
|
|
outputWindow->appendCommand(workingDir, binary, arguments);
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
const bool sshPromptConfigured = VcsBasePlugin::isSshPromptConfigured();
|
2010-05-21 17:46:00 +02:00
|
|
|
if (debugExecution) {
|
|
|
|
|
QDebug nsp = qDebug().nospace();
|
2012-01-07 12:31:48 +01:00
|
|
|
nsp << "VcsBasePlugin::runVcs" << workingDir << binary << arguments
|
2010-05-21 17:46:00 +02:00
|
|
|
<< timeOutMS;
|
|
|
|
|
if (flags & ShowStdOutInLogWindow)
|
|
|
|
|
nsp << "stdout";
|
|
|
|
|
if (flags & SuppressStdErrInLogWindow)
|
|
|
|
|
nsp << "suppress_stderr";
|
|
|
|
|
if (flags & SuppressFailMessageInLogWindow)
|
|
|
|
|
nsp << "suppress_fail_msg";
|
|
|
|
|
if (flags & MergeOutputChannels)
|
|
|
|
|
nsp << "merge_channels";
|
|
|
|
|
if (flags & SshPasswordPrompt)
|
|
|
|
|
nsp << "ssh (" << sshPromptConfigured << ')';
|
|
|
|
|
if (flags & SuppressCommandLogging)
|
|
|
|
|
nsp << "suppress_log";
|
2010-06-15 12:17:09 +02:00
|
|
|
if (flags & ForceCLocale)
|
|
|
|
|
nsp << "c_locale";
|
2010-11-22 14:53:20 +01:00
|
|
|
if (flags & FullySynchronously)
|
|
|
|
|
nsp << "fully_synchronously";
|
2013-06-09 06:00:29 +03:00
|
|
|
if (flags & ExpectRepoChanges)
|
|
|
|
|
nsp << "expect_repo_changes";
|
2010-05-21 17:46:00 +02:00
|
|
|
if (outputCodec)
|
|
|
|
|
nsp << " Codec: " << outputCodec->name();
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
VcsBase::VcsBasePlugin::setProcessEnvironment(&env, (flags & ForceCLocale));
|
2010-11-22 14:53:20 +01:00
|
|
|
|
2013-06-19 11:45:05 +02:00
|
|
|
// TODO tell the document manager about expected repository changes
|
|
|
|
|
// if (flags & ExpectRepoChanges)
|
|
|
|
|
// Core::DocumentManager::expectDirectoryChange(workingDir);
|
2010-11-22 14:53:20 +01:00
|
|
|
if (flags & FullySynchronously) {
|
2012-01-07 03:35:54 +01:00
|
|
|
response = runVcsFullySynchronously(workingDir, binary, arguments, timeOutMS,
|
2010-11-22 14:53:20 +01:00
|
|
|
env, flags, outputCodec);
|
2010-05-21 17:46:00 +02:00
|
|
|
} else {
|
2010-11-22 14:53:20 +01:00
|
|
|
// Run, connect stderr to the output window
|
2012-01-07 03:35:54 +01:00
|
|
|
SynchronousProcess process;
|
2010-11-22 14:53:20 +01:00
|
|
|
if (!workingDir.isEmpty())
|
|
|
|
|
process.setWorkingDirectory(workingDir);
|
|
|
|
|
|
|
|
|
|
process.setProcessEnvironment(env);
|
|
|
|
|
process.setTimeout(timeOutMS);
|
|
|
|
|
if (outputCodec)
|
2013-07-01 22:27:44 +03:00
|
|
|
process.setCodec(outputCodec);
|
2010-11-22 14:53:20 +01:00
|
|
|
|
|
|
|
|
// Suppress terminal on UNIX for ssh prompts if it is configured.
|
|
|
|
|
if (sshPromptConfigured && (flags & SshPasswordPrompt))
|
2012-01-07 03:35:54 +01:00
|
|
|
process.setFlags(SynchronousProcess::UnixTerminalDisabled);
|
2010-11-22 14:53:20 +01:00
|
|
|
|
|
|
|
|
// connect stderr to the output window if desired
|
|
|
|
|
if (flags & MergeOutputChannels) {
|
|
|
|
|
process.setProcessChannelMode(QProcess::MergedChannels);
|
|
|
|
|
} else {
|
|
|
|
|
if (!(flags & SuppressStdErrInLogWindow)) {
|
|
|
|
|
process.setStdErrBufferedSignalsEnabled(true);
|
|
|
|
|
connect(&process, SIGNAL(stdErrBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
|
|
|
|
|
}
|
2010-05-21 17:46:00 +02:00
|
|
|
}
|
|
|
|
|
|
2010-11-22 14:53:20 +01:00
|
|
|
// connect stdout to the output window if desired
|
|
|
|
|
if (flags & ShowStdOutInLogWindow) {
|
|
|
|
|
process.setStdOutBufferedSignalsEnabled(true);
|
|
|
|
|
connect(&process, SIGNAL(stdOutBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
|
|
|
|
|
}
|
2010-05-21 17:46:00 +02:00
|
|
|
|
2010-11-22 14:53:20 +01:00
|
|
|
process.setTimeOutMessageBoxEnabled(true);
|
2010-05-21 17:46:00 +02:00
|
|
|
|
2010-11-22 14:53:20 +01:00
|
|
|
// Run!
|
|
|
|
|
response = process.run(binary, arguments);
|
|
|
|
|
}
|
2010-05-21 17:46:00 +02:00
|
|
|
|
2010-05-25 11:48:53 +02:00
|
|
|
// Success/Fail message in appropriate window?
|
2012-01-07 03:35:54 +01:00
|
|
|
if (response.result == SynchronousProcessResponse::Finished) {
|
2010-05-25 11:48:53 +02:00
|
|
|
if (flags & ShowSuccessMessage)
|
2010-11-22 14:53:20 +01:00
|
|
|
outputWindow->append(response.exitMessage(binary, timeOutMS));
|
2010-05-25 11:48:53 +02:00
|
|
|
} else {
|
|
|
|
|
if (!(flags & SuppressFailMessageInLogWindow))
|
2010-11-22 14:53:20 +01:00
|
|
|
outputWindow->appendError(response.exitMessage(binary, timeOutMS));
|
2010-05-25 11:48:53 +02:00
|
|
|
}
|
2013-06-19 11:45:05 +02:00
|
|
|
// TODO tell the document manager that the directory now received all expected changes
|
|
|
|
|
// if (flags & ExpectRepoChanges)
|
|
|
|
|
// Core::DocumentManager::unexpectDirectoryChange(workingDir);
|
2010-05-21 17:46:00 +02:00
|
|
|
|
2010-11-22 14:53:20 +01:00
|
|
|
return response;
|
2010-05-21 17:46:00 +02:00
|
|
|
}
|
2011-03-24 15:44:39 +01:00
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
bool VcsBasePlugin::runFullySynchronous(const QString &workingDirectory,
|
2011-10-05 10:35:24 +00:00
|
|
|
const QString &binary,
|
|
|
|
|
const QStringList &arguments,
|
|
|
|
|
const QProcessEnvironment &env,
|
|
|
|
|
QByteArray* outputText,
|
|
|
|
|
QByteArray* errorText,
|
|
|
|
|
int timeoutMS,
|
2013-06-09 06:00:29 +03:00
|
|
|
unsigned flags)
|
2011-10-05 10:35:24 +00:00
|
|
|
{
|
2012-01-25 16:26:47 +01:00
|
|
|
if (binary.isEmpty())
|
|
|
|
|
return false;
|
|
|
|
|
|
2013-06-09 06:00:29 +03:00
|
|
|
if (!(flags & SuppressCommandLogging))
|
2013-01-30 21:04:41 +02:00
|
|
|
VcsBase::VcsBaseOutputWindow::instance()->appendCommand(workingDirectory, binary, arguments);
|
2011-10-05 10:35:24 +00:00
|
|
|
|
2013-06-19 11:45:05 +02:00
|
|
|
// TODO tell the document manager about expected repository changes
|
|
|
|
|
// if (flags & ExpectRepoChanges)
|
|
|
|
|
// Core::DocumentManager::expectDirectoryChange(workingDirectory);
|
2011-10-05 10:35:24 +00:00
|
|
|
QProcess process;
|
|
|
|
|
process.setWorkingDirectory(workingDirectory);
|
|
|
|
|
process.setProcessEnvironment(env);
|
|
|
|
|
|
|
|
|
|
process.start(binary, arguments);
|
|
|
|
|
process.closeWriteChannel();
|
|
|
|
|
if (!process.waitForStarted()) {
|
|
|
|
|
if (errorText) {
|
|
|
|
|
const QString msg = QString::fromLatin1("Unable to execute '%1': %2:")
|
|
|
|
|
.arg(binary, process.errorString());
|
|
|
|
|
*errorText = msg.toLocal8Bit();
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-21 19:58:59 +02:00
|
|
|
if (!SynchronousProcess::readDataFromProcess(process, timeoutMS, outputText, errorText, true)) {
|
|
|
|
|
if (errorText)
|
|
|
|
|
errorText->append(tr("Error: Executable timed out after %1s.").arg(timeoutMS / 1000).toLocal8Bit());
|
2012-01-07 03:35:54 +01:00
|
|
|
SynchronousProcess::stopProcess(process);
|
2011-10-05 10:35:24 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2013-06-19 11:45:05 +02:00
|
|
|
// TODO tell the document manager that the directory now received all expected changes
|
|
|
|
|
// if (flags & ExpectRepoChanges)
|
|
|
|
|
// Core::DocumentManager::unexpectDirectoryChange(workingDirectory);
|
2011-10-05 10:35:24 +00:00
|
|
|
|
2013-06-30 20:51:00 +03:00
|
|
|
if (process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0) {
|
|
|
|
|
if (flags & ExpectRepoChanges)
|
|
|
|
|
Core::ICore::vcsManager()->emitRepositoryChanged(workingDirectory);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2011-10-05 10:35:24 +00:00
|
|
|
}
|
|
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
bool VcsBasePlugin::runPatch(const QByteArray &input, const QString &workingDirectory,
|
2011-03-24 15:44:39 +01:00
|
|
|
int strip, bool reverse)
|
|
|
|
|
{
|
2012-01-07 12:31:48 +01:00
|
|
|
VcsBaseOutputWindow *ow = VcsBaseOutputWindow::instance();
|
|
|
|
|
const QString patch = Internal::VcsPlugin::instance()->settings().patchCommand;
|
2011-03-24 15:44:39 +01:00
|
|
|
if (patch.isEmpty()) {
|
2011-06-15 17:20:33 +02:00
|
|
|
ow->appendError(tr("There is no patch-command configured in the common 'Version Control' settings."));
|
2011-03-24 15:44:39 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QProcess patchProcess;
|
|
|
|
|
if (!workingDirectory.isEmpty())
|
|
|
|
|
patchProcess.setWorkingDirectory(workingDirectory);
|
|
|
|
|
QStringList args(QLatin1String("-p") + QString::number(strip));
|
|
|
|
|
if (reverse)
|
|
|
|
|
args << QLatin1String("-R");
|
2013-07-01 22:56:36 +03:00
|
|
|
ow->appendCommand(workingDirectory, patch, args);
|
2011-03-24 15:44:39 +01:00
|
|
|
patchProcess.start(patch, args);
|
|
|
|
|
if (!patchProcess.waitForStarted()) {
|
|
|
|
|
ow->appendError(tr("Unable to launch '%1': %2").arg(patch, patchProcess.errorString()));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
patchProcess.write(input);
|
|
|
|
|
patchProcess.closeWriteChannel();
|
|
|
|
|
QByteArray stdOut;
|
|
|
|
|
QByteArray stdErr;
|
2012-01-07 03:35:54 +01:00
|
|
|
if (!SynchronousProcess::readDataFromProcess(patchProcess, 30000, &stdOut, &stdErr, true)) {
|
|
|
|
|
SynchronousProcess::stopProcess(patchProcess);
|
2011-03-24 15:44:39 +01:00
|
|
|
ow->appendError(tr("A timeout occurred running '%1'").arg(patch));
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if (!stdOut.isEmpty())
|
|
|
|
|
ow->append(QString::fromLocal8Bit(stdOut));
|
|
|
|
|
if (!stdErr.isEmpty())
|
|
|
|
|
ow->append(QString::fromLocal8Bit(stdErr));
|
|
|
|
|
|
|
|
|
|
if (patchProcess.exitStatus() != QProcess::NormalExit) {
|
|
|
|
|
ow->appendError(tr("'%1' crashed.").arg(patch));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (patchProcess.exitCode() != 0) {
|
2011-03-28 11:59:26 +02:00
|
|
|
ow->appendError(tr("'%1' failed (exit code %2).").arg(patch).arg(patchProcess.exitCode()));
|
2011-03-24 15:44:39 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2012-01-07 03:35:54 +01:00
|
|
|
|
2012-01-07 12:31:48 +01:00
|
|
|
} // namespace VcsBase
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-12-08 14:26:41 +01:00
|
|
|
#include "vcsbaseplugin.moc"
|