Commit 83d51b26 authored by Petar Perisin's avatar Petar Perisin
Browse files

Gerrit: added ability to save path for applying patches



Change-Id: I3cc8f1d19784145a7fbf19c321ccbc079847fbc2
Reviewed-by: Orgad Shaneh's avatarOrgad Shaneh <orgads@gmail.com>
Reviewed-by: default avatarPetar Perisin <petar.perisin@gmail.com>
Reviewed-by: default avatarFriedemann Kleint <Friedemann.Kleint@digia.com>
Reviewed-by: default avatarTobias Hunger <tobias.hunger@digia.com>
parent 42547062
......@@ -32,6 +32,7 @@
#include "gerritparameters.h"
#include <utils/filterlineedit.h>
#include <utils/qtcassert.h>
#include <coreplugin/icore.h>
#include <QVBoxLayout>
......@@ -103,7 +104,9 @@ GerritDialog::GerritDialog(const QSharedPointer<GerritParameters> &p,
, m_detailsBrowser(new QTextBrowser)
, m_queryLineEdit(new QueryValidatingLineEdit)
, m_filterLineEdit(new Utils::FilterLineEdit)
, m_repositoryChooser(new Utils::PathChooser)
, m_buttonBox(new QDialogButtonBox(QDialogButtonBox::Close))
, m_repositoryChooserLabel(new QLabel(tr("Apply in: "), this))
, m_fetchRunning(false)
{
setWindowTitle(tr("Gerrit %1@%2").arg(p->user, p->host));
......@@ -157,9 +160,15 @@ GerritDialog::GerritDialog(const QSharedPointer<GerritParameters> &p,
m_detailsBrowser->setTextInteractionFlags(Qt::TextBrowserInteraction);
detailsLayout->addWidget(m_detailsBrowser);
m_displayButton = addActionButton(tr("Diff..."), SLOT(slotFetchDisplay()));
m_applyButton = addActionButton(tr("Apply..."), SLOT(slotFetchApply()));
m_checkoutButton = addActionButton(tr("Checkout..."), SLOT(slotFetchCheckout()));
m_repositoryChooser->setExpectedKind(Utils::PathChooser::Directory);
QHBoxLayout *repoPathLayout = new QHBoxLayout;
repoPathLayout->addWidget(m_repositoryChooserLabel);
repoPathLayout->addWidget(m_repositoryChooser);
detailsLayout->addLayout(repoPathLayout);
m_displayButton = addActionButton(QString(), SLOT(slotFetchDisplay()));
m_applyButton = addActionButton(QString(), SLOT(slotFetchApply()));
m_checkoutButton = addActionButton(QString(), SLOT(slotFetchCheckout()));
m_refreshButton = addActionButton(tr("Refresh"), SLOT(slotRefresh()));
connect(m_model, SIGNAL(refreshStateChanged(bool)),
......@@ -185,6 +194,35 @@ GerritDialog::GerritDialog(const QSharedPointer<GerritParameters> &p,
m_treeView->setFocus();
}
QString GerritDialog::repositoryPath() const
{
return m_repositoryChooser->path();
}
void GerritDialog::displayRepositoryPath()
{
QTC_ASSERT(m_parameters, return);
m_repositoryChooser->setVisible(!m_parameters->promptPath);
m_repositoryChooserLabel->setVisible(!m_parameters->promptPath);
if (m_repositoryChooser->path().isEmpty())
m_repositoryChooser->setPath(m_parameters->repositoryPath);
if (m_parameters->promptPath) {
m_displayButton->setText(tr("Diff..."));
m_applyButton->setText(tr("Apply..."));
m_checkoutButton->setText(tr("Checkout..."));
} else {
m_displayButton->setText(tr("Diff"));
m_applyButton->setText(tr("Apply"));
m_checkoutButton->setText(tr("Checkout"));
}
}
void GerritDialog::showEvent(QShowEvent *event)
{
displayRepositoryPath();
QDialog::showEvent(event);
}
QPushButton *GerritDialog::addActionButton(const QString &text, const char *buttonSlot)
{
QPushButton *button = m_buttonBox->addButton(text, QDialogButtonBox::ActionRole);
......
......@@ -31,6 +31,7 @@
#define GERRIT_INTERNAL_GERRITDIALOG_H
#include <utils/filterlineedit.h>
#include <utils/pathchooser.h>
#include <QDialog>
#include <QSharedPointer>
......@@ -78,6 +79,7 @@ public:
explicit GerritDialog(const QSharedPointer<GerritParameters> &p,
QWidget *parent = 0);
~GerritDialog();
QString repositoryPath() const;
signals:
void fetchDisplay(const QSharedPointer<Gerrit::Internal::GerritChange> &);
......@@ -88,6 +90,9 @@ public slots:
void fetchStarted(const QSharedPointer<Gerrit::Internal::GerritChange> &change);
void fetchFinished();
protected:
void showEvent(QShowEvent *event);
private slots:
void slotCurrentChanged();
void slotDoubleClicked(const QModelIndex &);
......@@ -96,6 +101,7 @@ private slots:
void slotFetchApply();
void slotFetchCheckout();
void slotRefresh();
void displayRepositoryPath();
private:
const QStandardItem *itemAt(const QModelIndex &i, int column = 0) const;
......@@ -112,11 +118,13 @@ private:
QTextBrowser *m_detailsBrowser;
QueryValidatingLineEdit *m_queryLineEdit;
Utils::FilterLineEdit *m_filterLineEdit;
Utils::PathChooser *m_repositoryChooser;
QDialogButtonBox *m_buttonBox;
QPushButton *m_displayButton;
QPushButton *m_applyButton;
QPushButton *m_checkoutButton;
QPushButton *m_refreshButton;
QLabel *m_repositoryChooserLabel;
bool m_fetchRunning;
};
......
......@@ -84,8 +84,10 @@ GerritOptionsWidget::GerritOptionsWidget(QWidget *parent)
, m_hostLineEdit(new QLineEdit(this))
, m_userLineEdit(new QLineEdit(this))
, m_sshChooser(new Utils::PathChooser)
, m_repositoryChooser(new Utils::PathChooser)
, m_portSpinBox(new QSpinBox(this))
, m_httpsCheckBox(new QCheckBox(tr("HTTPS")))
, m_promptPathCheckBox(new QCheckBox(tr("Always prompt for repository folder")))
{
QFormLayout *formLayout = new QFormLayout(this);
formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
......@@ -94,6 +96,11 @@ GerritOptionsWidget::GerritOptionsWidget(QWidget *parent)
m_sshChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
m_sshChooser->setCommandVersionArguments(QStringList(QLatin1String("-V")));
formLayout->addRow(tr("&ssh:"), m_sshChooser);
formLayout->addRow(tr("&Repository:"), m_repositoryChooser);
m_repositoryChooser->setToolTip(tr("Default repository where patches will be applied."));
formLayout->addRow(tr("Pr&ompt:"), m_promptPathCheckBox);
m_promptPathCheckBox->setToolTip(tr("If checked, user will always be\n"
"asked to confirm the repository path."));
m_portSpinBox->setMinimum(1);
m_portSpinBox->setMaximum(65535);
formLayout->addRow(tr("&Port:"), m_portSpinBox);
......@@ -110,8 +117,10 @@ GerritParameters GerritOptionsWidget::parameters() const
result.host = m_hostLineEdit->text().trimmed();
result.user = m_userLineEdit->text().trimmed();
result.ssh = m_sshChooser->path();
result.repositoryPath = m_repositoryChooser->path();
result.port = m_portSpinBox->value();
result.https = m_httpsCheckBox->isChecked();
result.promptPath = m_promptPathCheckBox->isChecked();
return result;
}
......@@ -120,8 +129,10 @@ void GerritOptionsWidget::setParameters(const GerritParameters &p)
m_hostLineEdit->setText(p.host);
m_userLineEdit->setText(p.user);
m_sshChooser->setPath(p.ssh);
m_repositoryChooser->setPath(p.repositoryPath);
m_portSpinBox->setValue(p.port);
m_httpsCheckBox->setChecked(p.https);
m_promptPathCheckBox->setChecked(p.promptPath);
}
} // namespace Internal
......
......@@ -63,8 +63,10 @@ private:
QLineEdit *m_hostLineEdit;
QLineEdit *m_userLineEdit;
Utils::PathChooser *m_sshChooser;
Utils::PathChooser *m_repositoryChooser;
QSpinBox *m_portSpinBox;
QCheckBox *m_httpsCheckBox;
QCheckBox *m_promptPathCheckBox;
};
class GerritOptionsPage : public VcsBase::VcsBaseOptionsPage
......
......@@ -50,7 +50,9 @@ static const char userKeyC[] = "User";
static const char portKeyC[] = "Port";
static const char portFlagKeyC[] = "PortFlag";
static const char sshKeyC[] = "Ssh";
static const char repositoryKeyC[] = "RepoPath";
static const char httpsKeyC[] = "Https";
static const char promptPathKeyC[] = "PromptPath";
static const char defaultHostC[] = "codereview.qt-project.org";
static const char defaultSshC[] = "ssh";
static const char savedQueriesKeyC[] = "SavedQueries";
......@@ -99,6 +101,7 @@ GerritParameters::GerritParameters()
: host(QLatin1String(defaultHostC))
, port(defaultPort)
, https(true)
, promptPath(true)
, portFlag(QLatin1String(defaultPortFlag))
{
}
......@@ -118,8 +121,8 @@ QString GerritParameters::sshHostArgument() const
bool GerritParameters::equals(const GerritParameters &rhs) const
{
return port == rhs.port && host == rhs.host && user == rhs.user
&& ssh == rhs.ssh && https == rhs.https;
return port == rhs.port && host == rhs.host && user == rhs.user && promptPath == rhs.promptPath
&& ssh == rhs.ssh && https == rhs.https && repositoryPath == rhs.repositoryPath;
}
void GerritParameters::toSettings(QSettings *s) const
......@@ -130,7 +133,9 @@ void GerritParameters::toSettings(QSettings *s) const
s->setValue(QLatin1String(portKeyC), port);
s->setValue(QLatin1String(portFlagKeyC), portFlag);
s->setValue(QLatin1String(sshKeyC), ssh);
s->setValue(QLatin1String(repositoryKeyC), repositoryPath);
s->setValue(QLatin1String(httpsKeyC), https);
s->setValue(QLatin1String(promptPathKeyC), promptPath);
s->endGroup();
}
......@@ -147,11 +152,13 @@ void GerritParameters::fromSettings(const QSettings *s)
host = s->value(rootKey + QLatin1String(hostKeyC), QLatin1String(defaultHostC)).toString();
user = s->value(rootKey + QLatin1String(userKeyC), QString()).toString();
ssh = s->value(rootKey + QLatin1String(sshKeyC), QString()).toString();
repositoryPath = s->value(rootKey + QLatin1String(repositoryKeyC), QString()).toString();
port = s->value(rootKey + QLatin1String(portKeyC), QVariant(int(defaultPort))).toInt();
portFlag = s->value(rootKey + QLatin1String(portFlagKeyC), QLatin1String(defaultPortFlag)).toString();
savedQueries = s->value(rootKey + QLatin1String(savedQueriesKeyC), QString()).toString()
.split(QLatin1String(","));
https = s->value(rootKey + QLatin1String(httpsKeyC), QVariant(true)).toBool();
promptPath = s->value(rootKey + QLatin1String(promptPathKeyC), QVariant(true)).toBool();
if (ssh.isEmpty())
ssh = detectSsh();
}
......
......@@ -55,8 +55,10 @@ public:
unsigned short port;
QString user;
QString ssh;
QString repositoryPath;
QStringList savedQueries;
bool https;
bool promptPath;
QString portFlag;
};
......
......@@ -60,8 +60,10 @@
#include <QRegExp>
#include <QAction>
#include <QFileDialog>
#include <QMessageBox>
#include <QTemporaryFile>
#include <QDir>
#include <QMap>
enum { debug = 0 };
......@@ -411,14 +413,79 @@ void GerritPlugin::fetch(const QSharedPointer<Gerrit::Internal::GerritChange> &c
if (git.isEmpty())
return;
// Ask the user for a repository to retrieve the change.
const QString title =
tr("Enter Local Repository for '%1' (%2)").arg(change->project, change->branch);
const QString suggestedRespository =
findLocalRepository(change->project, change->branch);
const QString repository =
QFileDialog::getExistingDirectory(m_dialog.data(),
title, suggestedRespository);
Git::Internal::GitClient* gitClient = Git::Internal::GitPlugin::instance()->gitClient();
QString repository;
bool verifiedRepository = false;
if (!m_dialog.isNull() && !m_parameters.isNull() && !m_parameters->promptPath
&& QFile::exists(m_dialog->repositoryPath())) {
repository = gitClient->findRepositoryForDirectory(m_dialog->repositoryPath());
}
if (!repository.isEmpty()) {
// Check if remote from a working dir is the same as remote from patch
QMap<QString, QString> remotesList = gitClient->synchronousRemotesList(repository);
if (!remotesList.isEmpty()) {
QStringList remotes = remotesList.values();
foreach (QString remote, remotes) {
if (remote.endsWith(QLatin1String(".git")))
remote.chop(4);
if (remote.contains(m_parameters->host) && remote.endsWith(change->project)) {
verifiedRepository = true;
break;
}
}
if (!verifiedRepository && QFile::exists(repository + QLatin1String("/.gitmodules"))) {
QMap<QString,QString> submodules = gitClient->synchronousSubmoduleList(repository);
QMap<QString,QString>::const_iterator i = submodules.constBegin();
while (i != submodules.constEnd()) {
QString remote = i.value();
if (remote.endsWith(QLatin1String(".git")))
remote.chop(4);
if (remote.contains(m_parameters->host) && remote.endsWith(change->project)
&& QFile::exists(repository + QLatin1Char('/') + i.key())) {
repository = QDir::cleanPath(repository + QLatin1Char('/') + i.key());
verifiedRepository = true;
break;
}
++i;
}
}
if (!verifiedRepository){
QMessageBox::StandardButton answer = QMessageBox::question(
Core::ICore::mainWindow(), tr("Remote not Verified"),
tr("Change host: %1\nand project: %2\n\nwere not verified among remotes"
" in %3. Select different folder?")
.arg(m_parameters->host,
change->project,
QDir::toNativeSeparators(repository)),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
QMessageBox::Yes);
switch (answer) {
case QMessageBox::Cancel:
return;
case QMessageBox::No:
verifiedRepository = true;
break;
default:
break;
}
}
}
}
if (!verifiedRepository) {
// Ask the user for a repository to retrieve the change.
const QString title =
tr("Enter Local Repository for '%1' (%2)").arg(change->project, change->branch);
const QString suggestedRespository =
findLocalRepository(change->project, change->branch);
repository = QFileDialog::getExistingDirectory(m_dialog.data(),
title, suggestedRespository);
}
if (repository.isEmpty())
return;
......
......@@ -1504,6 +1504,67 @@ bool GitClient::synchronousRemoteCmd(const QString &workingDirectory, QStringLis
return true;
}
QMap<QString,QString> GitClient::synchronousRemotesList(const QString &workingDirectory,
QString *errorMessage)
{
QMap<QString,QString> result;
QString output;
QString error;
QStringList args(QLatin1String("-v"));
if (!synchronousRemoteCmd(workingDirectory, args, &output, &error)) {
if (errorMessage)
*errorMessage = error;
else
outputWindow()->append(error);
return result;
}
QStringList remotes = output.split(QLatin1String("\n"));
foreach (const QString &remote, remotes) {
if (!remote.endsWith(QLatin1String(" (fetch)")))
continue;
QStringList tokens = remote.split(QRegExp(QLatin1String("\\s")),
QString::SkipEmptyParts);
if (tokens.count() != 3)
continue;
result.insert(tokens.at(0), tokens.at(1));
}
return result;
}
QMap<QString,QString> GitClient::synchronousSubmoduleList(const QString &workingDirectory,
QString *errorMessage)
{
QStringList args;
QMap<QString,QString> result;
args << QLatin1String("config") << QLatin1String("-l");
QByteArray outputText;
QByteArray errorText;
const bool rc = fullySynchronousGit(workingDirectory, args, &outputText, &errorText);
if (!rc) {
QString message = tr("Cannot run \"git config -l\" in \"%1\": %2").
arg(QDir::toNativeSeparators(workingDirectory), commandOutputFromLocal8Bit(errorText));
if (errorMessage)
*errorMessage = message;
else
outputWindow()->append(message);
return result;
}
QStringList outputList = commandOutputLinesFromLocal8Bit(outputText);
QString urlKey = QLatin1String(".url=");
foreach (const QString& line, outputList) {
if (line.startsWith(QLatin1String("submodule."))) {
result.insertMulti(line.mid(10, line.indexOf(urlKey) - 10),
line.mid(line.indexOf(urlKey, 10) + 5));
}
}
return result;
}
bool GitClient::synchronousShow(const QString &workingDirectory, const QString &id,
QString *output, QString *errorMessage)
{
......
......@@ -182,6 +182,11 @@ public:
QString *output, QString *errorMessage);
bool synchronousRemoteCmd(const QString &workingDirectory, QStringList remoteArgs,
QString *output, QString *errorMessage);
QMap<QString,QString> synchronousRemotesList(const QString &workingDirectory,
QString *errorMessage = 0);
QMap<QString,QString> synchronousSubmoduleList(const QString &workingDirectory,
QString *errorMessage = 0);
bool synchronousShow(const QString &workingDirectory, const QString &id,
QString *output, QString *errorMessage);
bool synchronousParentRevisions(const QString &workingDirectory,
......
......@@ -33,21 +33,6 @@
namespace Git {
namespace Internal {
// Parse a branch line: " *name sha description".
bool RemoteModel::Remote::parse(const QString &line)
{
if (!line.endsWith(QLatin1String(" (fetch)")))
return false;
QStringList tokens = line.split(QRegExp(QLatin1String("\\s")), QString::SkipEmptyParts);
if (tokens.count() != 3)
return false;
name = tokens.at(0);
url = tokens.at(1);
return true;
}
// ------ RemoteModel
RemoteModel::RemoteModel(GitClient *client, QObject *parent) :
QAbstractTableModel(parent),
......@@ -192,21 +177,21 @@ void RemoteModel::clear()
bool RemoteModel::refresh(const QString &workingDirectory, QString *errorMessage)
{
// Run branch command with verbose.
QStringList remoteArgs;
remoteArgs << QLatin1String("-v");
QString output;
if (!m_client->synchronousRemoteCmd(workingDirectory, remoteArgs, &output, errorMessage))
// get list of remotes.
QMap<QString,QString> remotesList =
m_client->synchronousRemotesList(workingDirectory, errorMessage);
if (remotesList.isEmpty())
return false;
// Parse output
m_workingDirectory = workingDirectory;
beginResetModel();
m_remotes.clear();
const QStringList lines = output.split(QLatin1Char('\n'));
for (int r = 0; r < lines.count(); ++r) {
foreach (const QString &remoteName, remotesList.keys()) {
Remote newRemote;
if (newRemote.parse(lines.at(r)))
m_remotes.push_back(newRemote);
newRemote.name = remoteName;
newRemote.url = remotesList.value(remoteName);
m_remotes.push_back(newRemote);
}
endResetModel();
return true;
......
......@@ -70,8 +70,6 @@ public:
protected:
struct Remote {
bool parse(const QString &line);
QString name;
QString url;
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment