forked from qt-creator/qt-creator
VCS[git], CodePaster: Add support for applying patches.
Modify CodePaster::fetch to do a mimetype detection on the content, create a filename with the matching extension and open that file. This gives correct syntax highlighting and makes "Save as" more convenient. Keep the file around and delete on exit. Modify patch mimetype with some content detection (higher priority than C++). Add a "current patch file" to the VCSBasePlugin::State. Add "Apply patch" to git with whitespace fix.
This commit is contained in:
@@ -973,6 +973,26 @@ bool GitClient::synchronousCleanList(const QString &workingDirectory,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GitClient::synchronousApplyPatch(const QString &workingDirectory,
|
||||
const QString &file, QString *errorMessage)
|
||||
{
|
||||
if (Git::Constants::debug)
|
||||
qDebug() << Q_FUNC_INFO << workingDirectory;
|
||||
QStringList args;
|
||||
args << QLatin1String("apply") << QLatin1String("--whitespace=fix") << file;
|
||||
QByteArray outputText;
|
||||
QByteArray errorText;
|
||||
const bool rc = synchronousGit(workingDirectory, args, &outputText, &errorText);
|
||||
if (rc) {
|
||||
if (!errorText.isEmpty())
|
||||
*errorMessage = tr("There were warnings while applying %1 to %2:\n%3").arg(file, workingDirectory, commandOutputFromLocal8Bit(errorText));
|
||||
} else {
|
||||
*errorMessage = tr("Unable apply patch %1 to %2: %3").arg(file, workingDirectory, commandOutputFromLocal8Bit(errorText));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Factory function to create an asynchronous command
|
||||
GitCommand *GitClient::createCommand(const QString &workingDirectory,
|
||||
VCSBase::VCSBaseEditor* editor,
|
||||
|
||||
@@ -106,6 +106,7 @@ public:
|
||||
const QStringList &files = QStringList(),
|
||||
QString *errorMessage = 0);
|
||||
bool synchronousCleanList(const QString &workingDirectory, QStringList *files, QString *errorMessage);
|
||||
bool synchronousApplyPatch(const QString &workingDirectory, const QString &file, QString *errorMessage);
|
||||
bool synchronousInit(const QString &workingDirectory);
|
||||
bool synchronousCheckoutFiles(const QString &workingDirectory,
|
||||
QStringList files = QStringList(),
|
||||
|
||||
@@ -50,6 +50,8 @@
|
||||
#include <coreplugin/actionmanager/actioncontainer.h>
|
||||
#include <coreplugin/actionmanager/command.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/editormanager/ieditor.h>
|
||||
#include <coreplugin/filemanager.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/parameteraction.h>
|
||||
@@ -126,6 +128,7 @@ GitPlugin::GitPlugin() :
|
||||
m_undoAction(0),
|
||||
m_redoAction(0),
|
||||
m_menuAction(0),
|
||||
m_applyCurrentFilePatchAction(0),
|
||||
m_gitClient(0),
|
||||
m_changeSelectionDialog(0),
|
||||
m_submitActionTriggered(false)
|
||||
@@ -386,6 +389,20 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
|
||||
tr("Log Repository"), QLatin1String("Git.LogRepository"),
|
||||
globalcontext, true, &GitClient::graphLog);
|
||||
|
||||
// Apply current file as patch is handled specially.
|
||||
parameterActionCommand =
|
||||
createParameterAction(actionManager, gitContainer,
|
||||
tr("Apply Patch"), tr("Apply \"%1\""),
|
||||
QLatin1String("Git.ApplyCurrentFilePatch"),
|
||||
globalcontext, true);
|
||||
m_applyCurrentFilePatchAction = parameterActionCommand.first;
|
||||
connect(m_applyCurrentFilePatchAction, SIGNAL(triggered()), this,
|
||||
SLOT(applyCurrentFilePatch()));
|
||||
|
||||
createRepositoryAction(actionManager, gitContainer,
|
||||
tr("Apply Patch..."), QLatin1String("Git.ApplyPatch"),
|
||||
globalcontext, true, SLOT(promptApplyPatch()));
|
||||
|
||||
createRepositoryAction(actionManager, gitContainer,
|
||||
tr("Undo Repository Changes"), QLatin1String("Git.UndoRepository"),
|
||||
globalcontext, false, SLOT(undoRepositoryChanges()));
|
||||
@@ -805,6 +822,74 @@ void GitPlugin::cleanRepository(const QString &directory)
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
// If the file is modified in an editor, make sure it is saved.
|
||||
static bool ensureFileSaved(const QString &fileName)
|
||||
{
|
||||
const QList<Core::IEditor*> editors = Core::EditorManager::instance()->editorsForFileName(fileName);
|
||||
if (editors.isEmpty())
|
||||
return true;
|
||||
Core::IFile *file = editors.front()->file();
|
||||
if (!file || !file->isModified())
|
||||
return true;
|
||||
Core::FileManager *fm = Core::ICore::instance()->fileManager();
|
||||
bool canceled;
|
||||
QList<Core::IFile *> files;
|
||||
files << file;
|
||||
fm->saveModifiedFiles(files, &canceled);
|
||||
return !canceled;
|
||||
}
|
||||
|
||||
void GitPlugin::applyCurrentFilePatch()
|
||||
{
|
||||
const VCSBase::VCSBasePluginState state = currentState();
|
||||
QTC_ASSERT(state.hasPatchFile() && state.hasTopLevel(), return);
|
||||
const QString patchFile = state.currentPatchFile();
|
||||
if (!ensureFileSaved(patchFile))
|
||||
return;
|
||||
applyPatch(state.topLevel(), patchFile);
|
||||
}
|
||||
|
||||
void GitPlugin::promptApplyPatch()
|
||||
{
|
||||
const VCSBase::VCSBasePluginState state = currentState();
|
||||
QTC_ASSERT(state.hasTopLevel(), return);
|
||||
applyPatch(state.topLevel(), QString());
|
||||
}
|
||||
|
||||
void GitPlugin::applyPatch(const QString &workingDirectory, QString file)
|
||||
{
|
||||
// Ensure user has been notified about pending changes
|
||||
switch (m_gitClient->ensureStash(workingDirectory)) {
|
||||
case GitClient::StashUnchanged:
|
||||
case GitClient::Stashed:
|
||||
case GitClient::NotStashed:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
// Prompt for file
|
||||
if (file.isEmpty()) {
|
||||
const QString filter = tr("Patches (*.patch *.diff)");
|
||||
file = QFileDialog::getOpenFileName(Core::ICore::instance()->mainWindow(),
|
||||
tr("Choose patch"),
|
||||
QString(), filter);
|
||||
if (file.isEmpty())
|
||||
return;
|
||||
}
|
||||
// Run!
|
||||
VCSBase::VCSBaseOutputWindow *outwin = VCSBase::VCSBaseOutputWindow::instance();
|
||||
QString errorMessage;
|
||||
if (m_gitClient->synchronousApplyPatch(workingDirectory, file, &errorMessage)) {
|
||||
if (errorMessage.isEmpty()) {
|
||||
outwin->append(tr("Patch %1 successfully applied to %2").arg(file, workingDirectory));
|
||||
} else {
|
||||
outwin->append(errorMessage);
|
||||
}
|
||||
} else {
|
||||
outwin->appendError(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void GitPlugin::stash()
|
||||
{
|
||||
// Simple stash without prompt, reset repo.
|
||||
@@ -866,6 +951,8 @@ void GitPlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as)
|
||||
const QString fileName = currentState().currentFileName();
|
||||
foreach (Utils::ParameterAction *fileAction, m_fileActions)
|
||||
fileAction->setParameter(fileName);
|
||||
// If the current file looks like a patch, offer to apply
|
||||
m_applyCurrentFilePatchAction->setParameter(currentState().currentPatchFileDisplayName());
|
||||
|
||||
const QString projectName = currentState().currentProjectName();
|
||||
foreach (Utils::ParameterAction *projectAction, m_projectActions)
|
||||
|
||||
@@ -115,6 +115,8 @@ private slots:
|
||||
void unstageFile();
|
||||
void cleanProject();
|
||||
void cleanRepository();
|
||||
void applyCurrentFilePatch();
|
||||
void promptApplyPatch();
|
||||
void gitClientMemberFuncRepositoryAction();
|
||||
|
||||
void showCommit();
|
||||
@@ -170,6 +172,7 @@ private:
|
||||
Core::IEditor *openSubmitEditor(const QString &fileName, const CommitData &cd);
|
||||
void cleanCommitMessageFile();
|
||||
void cleanRepository(const QString &directory);
|
||||
void applyPatch(const QString &workingDirectory, QString file = QString());
|
||||
|
||||
static GitPlugin *m_instance;
|
||||
Core::ICore *m_core;
|
||||
@@ -187,6 +190,7 @@ private:
|
||||
QVector<Utils::ParameterAction *> m_fileActions;
|
||||
QVector<Utils::ParameterAction *> m_projectActions;
|
||||
QVector<QAction *> m_repositoryActions;
|
||||
Utils::ParameterAction *m_applyCurrentFilePatchAction;
|
||||
|
||||
GitClient *m_gitClient;
|
||||
ChangeSelectionDialog *m_changeSelectionDialog;
|
||||
|
||||
Reference in New Issue
Block a user