forked from qt-creator/qt-creator
Mercurial: Work on Windows using Tortoise Hg, polishing.
Do not use "cmd /c hg" on Windows as this will fail randomly depending on arguments with blanks, such as "-U 8". Output log messages about synchronous commands, format author correctly, label menus correctly.
This commit is contained in:
@@ -55,6 +55,17 @@ QTCREATOR_UTILS_EXPORT QString winErrorMessage(unsigned long error)
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static inline QString msgCannotLoad(const char *lib, const QString &why)
|
||||
{
|
||||
return QString::fromLatin1("Unable load %1: %2").arg(QLatin1String(lib), why);
|
||||
}
|
||||
|
||||
static inline QString msgCannotResolve(const char *lib)
|
||||
{
|
||||
return QString::fromLatin1("Unable to resolve all required symbols in %1").arg(QLatin1String(lib));
|
||||
}
|
||||
|
||||
QTCREATOR_UTILS_EXPORT QString winGetDLLVersion(WinDLLVersionType t,
|
||||
const QString &name,
|
||||
QString *errorMessage)
|
||||
@@ -67,7 +78,7 @@ QTCREATOR_UTILS_EXPORT QString winGetDLLVersion(WinDLLVersionType t,
|
||||
const char *versionDLLC = "version.dll";
|
||||
QLibrary versionLib(QLatin1String(versionDLLC), 0);
|
||||
if (!versionLib.load()) {
|
||||
*errorMessage = QString::fromLatin1("Unable load %1: %2").arg(QLatin1String(versionDLLC), versionLib.errorString());
|
||||
*errorMessage = msgCannotLoad(versionDLLC, versionLib.errorString());
|
||||
return QString();
|
||||
}
|
||||
// MinGW requires old-style casts
|
||||
@@ -75,7 +86,7 @@ QTCREATOR_UTILS_EXPORT QString winGetDLLVersion(WinDLLVersionType t,
|
||||
GetFileVersionInfoWProtoType getFileVersionInfoW = (GetFileVersionInfoWProtoType)(versionLib.resolve("GetFileVersionInfoW"));
|
||||
VerQueryValueWProtoType verQueryValueW = (VerQueryValueWProtoType)(versionLib.resolve("VerQueryValueW"));
|
||||
if (!getFileVersionInfoSizeW || !getFileVersionInfoW || !verQueryValueW) {
|
||||
*errorMessage = QString::fromLatin1("Unable to resolve all required symbols in %1").arg(QLatin1String(versionDLLC));
|
||||
*errorMessage = msgCannotResolve(versionDLLC);
|
||||
return QString();
|
||||
}
|
||||
|
||||
@@ -111,4 +122,37 @@ QTCREATOR_UTILS_EXPORT QString winGetDLLVersion(WinDLLVersionType t,
|
||||
return rc;
|
||||
}
|
||||
|
||||
QTCREATOR_UTILS_EXPORT QString getShortPathName(const QString &name, QString *errorMessage)
|
||||
{
|
||||
typedef DWORD (APIENTRY *GetShortPathNameProtoType)(LPCTSTR, LPTSTR, DWORD);
|
||||
|
||||
if (name.isEmpty())
|
||||
return name;
|
||||
|
||||
const char *kernel32DLLC = "kernel32.dll";
|
||||
|
||||
QLibrary kernel32Lib(kernel32DLLC, 0);
|
||||
if (!kernel32Lib.isLoaded() && !kernel32Lib.load()) {
|
||||
*errorMessage = msgCannotLoad(kernel32DLLC, kernel32Lib.errorString());
|
||||
return QString();
|
||||
}
|
||||
|
||||
// MinGW requires old-style casts
|
||||
GetShortPathNameProtoType getShortPathNameW = (GetShortPathNameProtoType)(kernel32Lib.resolve("GetShortPathNameW"));
|
||||
if (!getShortPathNameW) {
|
||||
*errorMessage = msgCannotResolve(kernel32DLLC);
|
||||
return QString();
|
||||
}
|
||||
// Determine length, then convert.
|
||||
const LPCTSTR nameC = reinterpret_cast<LPCTSTR>(name.utf16()); // MinGW
|
||||
const DWORD length = (*getShortPathNameW)(nameC, NULL, 0);
|
||||
if (length == 0)
|
||||
return name;
|
||||
TCHAR *buffer = new TCHAR[length];
|
||||
(*getShortPathNameW)(nameC, buffer, length);
|
||||
const QString rc = QString::fromUtf16(reinterpret_cast<const ushort *>(buffer), length);
|
||||
delete [] buffer;
|
||||
return rc;
|
||||
}
|
||||
|
||||
} // namespace Utils
|
||||
|
||||
@@ -47,5 +47,10 @@ enum WinDLLVersionType { WinDLLFileVersion, WinDLLProductVersion };
|
||||
QTCREATOR_UTILS_EXPORT QString winGetDLLVersion(WinDLLVersionType t,
|
||||
const QString &name,
|
||||
QString *errorMessage);
|
||||
|
||||
// Return the short (8.3) file name
|
||||
QTCREATOR_UTILS_EXPORT QString getShortPathName(const QString &name,
|
||||
QString *errorMessage);
|
||||
|
||||
} // namespace Utils
|
||||
#endif // WINUTILS_H
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <vcsbase/vcsbaseeditor.h>
|
||||
#include <vcsbase/vcsbaseoutputwindow.h>
|
||||
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QSharedPointer>
|
||||
@@ -80,7 +81,7 @@ bool MercurialClient::add(const QString &filename)
|
||||
QStringList args;
|
||||
args << QLatin1String("add") << file.absoluteFilePath();
|
||||
|
||||
return hgProcessSync(file, args);
|
||||
return executeHgSynchronously(file, args);
|
||||
}
|
||||
|
||||
bool MercurialClient::remove(const QString &filename)
|
||||
@@ -89,7 +90,7 @@ bool MercurialClient::remove(const QString &filename)
|
||||
QStringList args;
|
||||
args << QLatin1String("remove") << file.absoluteFilePath();
|
||||
|
||||
return hgProcessSync(file, args);
|
||||
return executeHgSynchronously(file, args);
|
||||
}
|
||||
|
||||
bool MercurialClient::manifestSync(const QString &filename)
|
||||
@@ -98,7 +99,7 @@ bool MercurialClient::manifestSync(const QString &filename)
|
||||
QStringList args(QLatin1String("manifest"));
|
||||
|
||||
QByteArray output;
|
||||
hgProcessSync(file, args, &output);
|
||||
executeHgSynchronously(file, args, &output);
|
||||
|
||||
const QStringList files = QString::fromLocal8Bit(output).split(QLatin1Char('\n'));
|
||||
|
||||
@@ -111,25 +112,31 @@ bool MercurialClient::manifestSync(const QString &filename)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MercurialClient::hgProcessSync(const QFileInfo &file, const QStringList &args,
|
||||
QByteArray *output) const
|
||||
bool MercurialClient::executeHgSynchronously(const QFileInfo &file, const QStringList &args,
|
||||
QByteArray *output) const
|
||||
{
|
||||
QProcess hgProcess;
|
||||
hgProcess.setWorkingDirectory(file.isDir() ? file.absoluteFilePath() : file.absolutePath());
|
||||
|
||||
MercurialSettings *settings = MercurialPlugin::instance()->settings();
|
||||
QStringList arguments = settings->standardArguments();
|
||||
arguments << args;
|
||||
const MercurialSettings *settings = MercurialPlugin::instance()->settings();
|
||||
const QString binary = settings->binary();
|
||||
const QStringList arguments = MercurialPlugin::instance()->standardArguments() + args;
|
||||
|
||||
hgProcess.start(settings->binary(), arguments);
|
||||
VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
|
||||
outputWindow->appendCommand(MercurialJobRunner::msgExecute(binary, arguments));
|
||||
|
||||
if (!hgProcess.waitForStarted())
|
||||
hgProcess.start(binary, arguments);
|
||||
|
||||
if (!hgProcess.waitForStarted()) {
|
||||
outputWindow->appendError(MercurialJobRunner::msgStartFailed(binary, hgProcess.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
hgProcess.closeWriteChannel();
|
||||
|
||||
if (!hgProcess.waitForFinished(settings->timeout())) {
|
||||
hgProcess.terminate();
|
||||
outputWindow->appendError(MercurialJobRunner::msgTimeout(settings->timeout()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -145,7 +152,7 @@ bool MercurialClient::hgProcessSync(const QFileInfo &file, const QStringList &ar
|
||||
QString MercurialClient::branchQuerySync(const QFileInfo &repositoryRoot)
|
||||
{
|
||||
QByteArray output;
|
||||
if (hgProcessSync(repositoryRoot, QStringList(QLatin1String("branch")), &output))
|
||||
if (executeHgSynchronously(repositoryRoot, QStringList(QLatin1String("branch")), &output))
|
||||
return QTextCodec::codecForLocale()->toUnicode(output).trimmed();
|
||||
|
||||
return QLatin1String("Unknown Branch");
|
||||
@@ -237,8 +244,7 @@ void MercurialClient::revert(const QFileInfo &fileOrDir, const QString &revision
|
||||
|
||||
void MercurialClient::status(const QFileInfo &fileOrDir)
|
||||
{
|
||||
QStringList args;
|
||||
args << QLatin1String("status");
|
||||
QStringList args(QLatin1String("status"));
|
||||
if (!fileOrDir.isDir())
|
||||
args.append(fileOrDir.absoluteFilePath());
|
||||
|
||||
@@ -301,8 +307,7 @@ void MercurialClient::import(const QFileInfo &repositoryRoot, const QStringList
|
||||
|
||||
void MercurialClient::pull(const QFileInfo &repositoryRoot, const QString &repository)
|
||||
{
|
||||
QStringList args;
|
||||
args << QLatin1String("pull");
|
||||
QStringList args(QLatin1String("pull"));
|
||||
if (!repository.isEmpty())
|
||||
args.append(repository);
|
||||
|
||||
@@ -312,8 +317,7 @@ void MercurialClient::pull(const QFileInfo &repositoryRoot, const QString &repos
|
||||
|
||||
void MercurialClient::push(const QFileInfo &repositoryRoot, const QString &repository)
|
||||
{
|
||||
QStringList args;
|
||||
args << QLatin1String("push");
|
||||
QStringList args(QLatin1String("push"));
|
||||
if (!repository.isEmpty())
|
||||
args.append(repository);
|
||||
|
||||
@@ -384,12 +388,12 @@ void MercurialClient::update(const QFileInfo &repositoryRoot, const QString &rev
|
||||
}
|
||||
|
||||
void MercurialClient::commit(const QFileInfo &repositoryRoot, const QStringList &files,
|
||||
const QString &commiterInfo, const QString &commitMessageFile)
|
||||
const QString &committerInfo, const QString &commitMessageFile)
|
||||
{
|
||||
QStringList args;
|
||||
|
||||
args << QLatin1String("commit") << QLatin1String("-u") << commiterInfo
|
||||
<< QLatin1String("-l") << commitMessageFile << files;
|
||||
QStringList args(QLatin1String("commit"));
|
||||
if (!committerInfo.isEmpty())
|
||||
args << QLatin1String("-u") << committerInfo;
|
||||
args << QLatin1String("-l") << commitMessageFile << files;
|
||||
QSharedPointer<HgTask> job(new HgTask(repositoryRoot.absoluteFilePath(), args, false));
|
||||
jobManager->enqueueJob(job);
|
||||
}
|
||||
|
||||
@@ -88,8 +88,8 @@ private slots:
|
||||
void statusParser(const QByteArray &data);
|
||||
|
||||
private:
|
||||
bool hgProcessSync(const QFileInfo &file, const QStringList &args,
|
||||
QByteArray *output=0) const;
|
||||
bool executeHgSynchronously(const QFileInfo &file, const QStringList &args,
|
||||
QByteArray *output=0) const;
|
||||
|
||||
MercurialJobRunner *jobManager;
|
||||
Core::ICore *core;
|
||||
|
||||
@@ -132,8 +132,17 @@ void MercurialCommitWidget::setFields(const QString &repositoryRoot, const QStri
|
||||
|
||||
QString MercurialCommitWidget::committer()
|
||||
{
|
||||
QString user = mercurialCommitPanelUi.authorLineEdit->text() + QLatin1String(" <") +
|
||||
mercurialCommitPanelUi.emailLineEdit->text() + QLatin1Char('>');
|
||||
const QString author = mercurialCommitPanelUi.authorLineEdit->text();
|
||||
const QString email = mercurialCommitPanelUi.emailLineEdit->text();
|
||||
if (author.isEmpty())
|
||||
return QString();
|
||||
|
||||
QString user = author;
|
||||
if (!email.isEmpty()) {
|
||||
user += QLatin1String(" <");
|
||||
user += email;
|
||||
user += QLatin1Char('>');
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
@@ -132,6 +132,21 @@ void MercurialJobRunner::run()
|
||||
}
|
||||
}
|
||||
|
||||
QString MercurialJobRunner::msgExecute(const QString &binary, const QStringList &args)
|
||||
{
|
||||
return tr("Executing: %1 %2\n").arg(binary, args.join(QString(QLatin1Char(' '))));
|
||||
}
|
||||
|
||||
QString MercurialJobRunner::msgStartFailed(const QString &binary, const QString &why)
|
||||
{
|
||||
return tr("Unable to start mercurial process '%1': %2").arg(binary, why);
|
||||
}
|
||||
|
||||
QString MercurialJobRunner::msgTimeout(int timeoutMS)
|
||||
{
|
||||
return tr("Timed out after %1ms waiting for mercurial process to finish.").arg(timeoutMS);
|
||||
}
|
||||
|
||||
void MercurialJobRunner::task(const QSharedPointer<HgTask> &job)
|
||||
{
|
||||
HgTask *taskData = job.data();
|
||||
@@ -155,8 +170,8 @@ void MercurialJobRunner::task(const QSharedPointer<HgTask> &job)
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
const QString starting = tr("Executing: %1 %2\n").arg(binary, taskData->args().join(QString(QLatin1Char(' '))));
|
||||
emit commandStarted(starting);
|
||||
const QStringList args = standardArguments + taskData->args();
|
||||
emit commandStarted(msgExecute(binary, args));
|
||||
//infom the user of what we are going to try and perform
|
||||
|
||||
if (Constants::debug)
|
||||
@@ -165,13 +180,11 @@ void MercurialJobRunner::task(const QSharedPointer<HgTask> &job)
|
||||
QProcess hgProcess;
|
||||
hgProcess.setWorkingDirectory(taskData->repositoryRoot());
|
||||
|
||||
QStringList args = standardArguments;
|
||||
args << taskData->args();
|
||||
|
||||
hgProcess.start(binary, args);
|
||||
|
||||
if (!hgProcess.waitForStarted()) {
|
||||
emit error(tr("Unable to start mercurial process '%1': %2").arg(binary, hgProcess.errorString()));
|
||||
if (!hgProcess.waitForStarted()) {
|
||||
emit error(msgStartFailed(binary, hgProcess.errorString()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -179,7 +192,7 @@ void MercurialJobRunner::task(const QSharedPointer<HgTask> &job)
|
||||
|
||||
if (!hgProcess.waitForFinished(timeout)) {
|
||||
hgProcess.terminate();
|
||||
emit error(tr("Timed out waiting for mercurial process to finish."));
|
||||
emit error(msgTimeout(timeout));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,8 @@ private:
|
||||
VCSBase::VCSBaseEditor *editor;
|
||||
};
|
||||
|
||||
|
||||
/* A job queue running in a separate thread, executing commands
|
||||
* and emitting status/log signals. */
|
||||
class MercurialJobRunner : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -80,6 +81,10 @@ public:
|
||||
void enqueueJob(const QSharedPointer<HgTask> &job);
|
||||
void restart();
|
||||
|
||||
static QString msgExecute(const QString &binary, const QStringList &args);
|
||||
static QString msgStartFailed(const QString &binary, const QString &why);
|
||||
static QString msgTimeout(int timeoutMS);
|
||||
|
||||
protected:
|
||||
void run();
|
||||
|
||||
|
||||
@@ -199,6 +199,11 @@ MercurialSettings *MercurialPlugin::settings()
|
||||
return mercurialSettings;
|
||||
}
|
||||
|
||||
QStringList MercurialPlugin::standardArguments() const
|
||||
{
|
||||
return mercurialSettings->standardArguments();
|
||||
}
|
||||
|
||||
void MercurialPlugin::createMenu()
|
||||
{
|
||||
QList<int> context = QList<int>()<< core->uniqueIDManager()->uniqueIdentifier(QLatin1String(Core::Constants::C_GLOBAL));
|
||||
@@ -316,7 +321,7 @@ void MercurialPlugin::createDirectoryActions(const QList<int> &context)
|
||||
connect(action, SIGNAL(triggered()), this, SLOT(logRepository()));
|
||||
mercurialContainer->addAction(command);
|
||||
|
||||
action = new QAction(tr("Revert"), this);
|
||||
action = new QAction(tr("Revert..."), this);
|
||||
actionList.append(action);
|
||||
command = actionManager->registerAction(action, QLatin1String(Constants::REVERTMULTI), context);
|
||||
connect(action, SIGNAL(triggered()), this, SLOT(revertMulti()));
|
||||
@@ -354,43 +359,43 @@ void MercurialPlugin::statusMulti()
|
||||
|
||||
void MercurialPlugin::createRepositoryActions(const QList<int> &context)
|
||||
{
|
||||
QAction *action = new QAction(tr("Pull"), this);
|
||||
QAction *action = new QAction(tr("Pull..."), this);
|
||||
actionList.append(action);
|
||||
Core::Command *command = actionManager->registerAction(action, QLatin1String(Constants::PULL), context);
|
||||
connect(action, SIGNAL(triggered()), this, SLOT(pull()));
|
||||
mercurialContainer->addAction(command);
|
||||
|
||||
action = new QAction(tr("Push"), this);
|
||||
action = new QAction(tr("Push..."), this);
|
||||
actionList.append(action);
|
||||
command = actionManager->registerAction(action, QLatin1String(Constants::PUSH), context);
|
||||
connect(action, SIGNAL(triggered()), this, SLOT(push()));
|
||||
mercurialContainer->addAction(command);
|
||||
|
||||
action = new QAction(tr("Update"), this);
|
||||
action = new QAction(tr("Update..."), this);
|
||||
actionList.append(action);
|
||||
command = actionManager->registerAction(action, QLatin1String(Constants::UPDATE), context);
|
||||
connect(action, SIGNAL(triggered()), this, SLOT(update()));
|
||||
mercurialContainer->addAction(command);
|
||||
|
||||
action = new QAction(tr("Import"), this);
|
||||
action = new QAction(tr("Import..."), this);
|
||||
actionList.append(action);
|
||||
command = actionManager->registerAction(action, QLatin1String(Constants::IMPORT), context);
|
||||
connect(action, SIGNAL(triggered()), this, SLOT(import()));
|
||||
mercurialContainer->addAction(command);
|
||||
|
||||
action = new QAction(tr("Incoming"), this);
|
||||
action = new QAction(tr("Incoming..."), this);
|
||||
actionList.append(action);
|
||||
command = actionManager->registerAction(action, QLatin1String(Constants::INCOMING), context);
|
||||
connect(action, SIGNAL(triggered()), this, SLOT(incoming()));
|
||||
mercurialContainer->addAction(command);
|
||||
|
||||
action = new QAction(tr("Outgoing"), this);
|
||||
action = new QAction(tr("Outgoing..."), this);
|
||||
actionList.append(action);
|
||||
command = actionManager->registerAction(action, QLatin1String(Constants::OUTGOING), context);
|
||||
connect(action, SIGNAL(triggered()), this, SLOT(outgoing()));
|
||||
mercurialContainer->addAction(command);
|
||||
|
||||
action = new QAction(tr("Commit"), this);
|
||||
action = new QAction(tr("Commit..."), this);
|
||||
actionList.append(action);
|
||||
command = actionManager->registerAction(action, QLatin1String(Constants::COMMIT), context);
|
||||
command->setDefaultKeySequence(QKeySequence(tr("Alt+H,Alt+C")));
|
||||
|
||||
@@ -83,6 +83,7 @@ public:
|
||||
QString currentProjectName();
|
||||
QFileInfo currentProjectRoot();
|
||||
bool closeEditor(Core::IEditor *editor);
|
||||
QStringList standardArguments() const;
|
||||
|
||||
MercurialSettings *settings();
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include "constants.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <QtCore/QSettings>
|
||||
|
||||
|
||||
@@ -134,11 +133,5 @@ void MercurialSettings::readSettings()
|
||||
void MercurialSettings::setBinAndArgs()
|
||||
{
|
||||
standardArgs.clear();
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
bin = QLatin1String("cmd.exe");
|
||||
standardArgs << "/c" << app;
|
||||
#else
|
||||
bin = app;
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user