Mercurial > hg > easyhg
changeset 619:4f7ca2d192df
Merge
author | Chris Cannam |
---|---|
date | Tue, 03 Jul 2012 20:10:04 +0100 |
parents | 54ca6a0e9aef (current diff) 4d44bad5a8ef (diff) |
children | 7f1adcdc6cdc |
files | src/mainwindow.cpp |
diffstat | 19 files changed, 154 insertions(+), 65 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Tue Jul 03 20:09:46 2012 +0100 +++ b/.hgtags Tue Jul 03 20:10:04 2012 +0100 @@ -20,3 +20,4 @@ 9b300409c184d47d57fba49341b2a1818b7fd0bc easyhg_v1.2 8bcf7ce9b1d209b94f71593545fc5de7c008f5a3 easyhg_v1.2_win32_2 abfef4acceca78078fe0c3b7fa8794f9ec77a4d3 easyhg_v1.2.1 +aade37785eca08d98afa7d12a66a181e1a2f4e2c easyhg_v1.2.2
--- a/CHANGELOG Tue Jul 03 20:09:46 2012 +0100 +++ b/CHANGELOG Tue Jul 03 20:10:04 2012 +0100 @@ -1,3 +1,15 @@ + +Changes in v1.2.2 since v1.2.1: + * Fix failure to provide IV arg to AES CBC constructor in PyCrypto + * Update the history after a failed merge to show the merge + * Clear the history while cloning a new repo + * Show a sensible error when clone target can't be created + * Minor improvements to zooming in history widget + * Various other minor fixes + +Changes in v1.2.1 since v1.2: + * Fix a filesystem watcher bug (affecting OS/X only) + Changes in v1.2 since v1.1: * Add a Find function to both My Work and History tabs
--- a/easyhg.py Tue Jul 03 20:09:46 2012 +0100 +++ b/easyhg.py Tue Jul 03 20:10:04 2012 +0100 @@ -53,12 +53,18 @@ # "remember this password") feature without them # easyhg_authfile_imports_ok = True + try: from Crypto.Cipher import AES +except ImportError: + print "EasyHg: Failed to import Crypto.Cipher module required for authfile support (try installing PyCrypto?)" + easyhg_authfile_imports_ok = False + +try: import ConfigParser # Mercurial version won't write files import base64 except ImportError: - print "EasyHg: Failed to import required modules for authfile support" + print "EasyHg: Failed to import modules (ConfigParser, base64) required for authfile support" easyhg_authfile_imports_ok = False @@ -83,7 +89,8 @@ self.remember = False if self.use_auth_file: - self.auth_cipher = AES.new(self.auth_key, AES.MODE_CBC) + self.auth_cipher = AES.new(self.auth_key, AES.MODE_CBC, + os.urandom(16)) self.auth_file = os.path.expanduser(self.auth_file) self.load_auth_data()
--- a/easyhg.wxs Tue Jul 03 20:09:46 2012 +0100 +++ b/easyhg.wxs Tue Jul 03 20:10:04 2012 +0100 @@ -2,13 +2,13 @@ <Product Name="EasyMercurial" - Id="CDD72D35-518B-49E2-A389-B3F7C1AE289D" + Id="*" Language="1033" Codepage="1252" - Version="1.2.0" + Version="1.2.2" UpgradeCode="B82DFDA9-B9DE-49BC-93E5-0B96F9DEB04B" Manufacturer="Queen Mary, University of London"> - + <Package Id="*" Keywords="Installer" @@ -20,6 +20,8 @@ Compressed="yes" SummaryCodepage="1252"/> + <MajorUpgrade DowngradeErrorMessage="A later version of EasyMercurial is already installed. Setup will now exit."/> + <Media Id="1" Cabinet="easyhg.cab" EmbedCab="yes" DiskPrompt="CD-ROM #1"/> <Property Id="DiskPrompt" Value="EasyMercurial Installation [1]"/>
--- a/src/filestatuswidget.cpp Tue Jul 03 20:09:46 2012 +0100 +++ b/src/filestatuswidget.cpp Tue Jul 03 20:10:04 2012 +0100 @@ -441,6 +441,16 @@ } void +FileStatusWidget::clearWidgets() +{ + foreach (FileStates::State s, m_stateListMap.keys()) { + QListWidget *w = m_stateListMap[s]; + w->clear(); + w->parentWidget()->hide(); + } +} + +void FileStatusWidget::updateWidgets() { QDateTime lastInteractionTime;
--- a/src/filestatuswidget.h Tue Jul 03 20:09:46 2012 +0100 +++ b/src/filestatuswidget.h Tue Jul 03 20:10:04 2012 +0100 @@ -78,6 +78,7 @@ public slots: void clearSelections(); void updateWidgets(); + void clearWidgets(); // e.g. while cloning a new repo slowly void setSearchText(QString text);
--- a/src/fswatcher.cpp Tue Jul 03 20:09:46 2012 +0100 +++ b/src/fswatcher.cpp Tue Jul 03 20:10:04 2012 +0100 @@ -28,7 +28,7 @@ #include <deque> -#define DEBUG_FSWATCHER 1 +//#define DEBUG_FSWATCHER 1 /* * Watching the filesystem is trickier than it seems at first glance.
--- a/src/hgaction.h Tue Jul 03 20:09:46 2012 +0100 +++ b/src/hgaction.h Tue Jul 03 20:10:04 2012 +0100 @@ -70,7 +70,7 @@ QString executable; // empty for normal Hg, but gets filled in by hgrunner void *extraData; - HgAction() : action(ACT_NONE) { } + HgAction() : action(ACT_NONE), extraData(0) { } HgAction(HGACTIONS _action, QString _wd, QStringList _params) : action(_action), workingDir(_wd), params(_params), extraData(0) { } @@ -79,9 +79,10 @@ action(_action), workingDir(_wd), params(_params), extraData(_d) { } bool operator==(const HgAction &a) { - return (a.action == action && a.workingDir == workingDir && - a.params == params && a.executable == executable && - a.extraData == extraData); + bool equal = (a.action == action && a.workingDir == workingDir && + a.params == params && a.executable == executable && + a.extraData == extraData); + return equal; } bool shouldBeFast() const {
--- a/src/hgrunner.cpp Tue Jul 03 20:09:46 2012 +0100 +++ b/src/hgrunner.cpp Tue Jul 03 20:10:04 2012 +0100 @@ -151,8 +151,11 @@ void HgRunner::requestAction(HgAction action) { - DEBUG << "requestAction " << action.action << endl; + DEBUG << "requestAction " << action.action << ": " << m_queue.size() << " thing(s) in queue, current action is " << m_currentAction.action << endl; bool pushIt = true; + + action = expandEnvironment(action); + if (m_queue.empty()) { if (action == m_currentAction) { // this request is identical to the thing we're executing @@ -168,10 +171,50 @@ pushIt = false; } } - if (pushIt) m_queue.push_back(action); + if (pushIt) { + m_queue.push_back(action); + } checkQueue(); } +HgAction HgRunner::expandEnvironment(HgAction action) +{ + // Adjust the executable and params for action to match our actual + // environment. We do this when the action is received, rather + // than when we execute it, so that we can compare + // (post-expansion) commands to see e.g. whether the one just + // received is the same as the one we're currently executing + + QString executable = action.executable; + QStringList params = action.params; + + if (executable == "") { + // This is a Hg command + executable = getHgBinaryName(); + if (executable == "") executable = "hg"; + + QString ssh = getSshBinaryName(); + if (ssh != "") { + params.push_front(QString("ui.ssh=\"%1\"").arg(ssh)); + params.push_front("--config"); + } + + if (action.mayBeInteractive()) { + params.push_front("ui.interactive=true"); + params.push_front("--config"); + QSettings settings; + if (settings.value("useextension", true).toBool()) { + params = addExtensionOptions(params); + } + } + } + + action.executable = executable; + action.params = params; + + return action; +} + QString HgRunner::getHgBinaryName() { QSettings settings; @@ -349,6 +392,8 @@ HgAction completedAction = m_currentAction; + DEBUG << "HgRunner::finished: completed " << completedAction.action << endl; + m_isRunning = false; m_currentAction = HgAction(); @@ -503,40 +548,12 @@ void HgRunner::startCommand(HgAction action) { - QString executable = action.executable; - bool interactive = false; - QStringList params = action.params; - if (action.workingDir.isEmpty()) { // We require a working directory, never just operate in pwd emit commandFailed(action, "EasyMercurial: No working directory supplied, will not run Mercurial command without one", ""); return; } - if (executable == "") { - // This is a Hg command - executable = getHgBinaryName(); - if (executable == "") executable = "hg"; - - QString ssh = getSshBinaryName(); - if (ssh != "") { - params.push_front(QString("ui.ssh=\"%1\"").arg(ssh)); - params.push_front("--config"); - } - - if (action.mayBeInteractive()) { - params.push_front("ui.interactive=true"); - params.push_front("--config"); - QSettings settings; - if (settings.value("useextension", true).toBool()) { - params = addExtensionOptions(params); - } - interactive = true; - } - - //!!! want an option to use the mercurial_keyring extension as well - } - m_isRunning = true; m_progress->setRange(0, 0); if (!action.shouldBeFast()) { @@ -583,7 +600,7 @@ m_proc->setWorkingDirectory(action.workingDir); - if (interactive) { + if (action.mayBeInteractive()) { openTerminal(); if (m_ptySlaveFilename != "") { DEBUG << "HgRunner: connecting to pseudoterminal" << endl; @@ -593,22 +610,18 @@ } } - QString cmdline = executable; - foreach (QString param, params) cmdline += " " + param; + QString cmdline = action.executable; + foreach (QString param, action.params) cmdline += " " + param; DEBUG << "HgRunner: starting: " << cmdline << " with cwd " << action.workingDir << endl; m_currentAction = action; - // fill these out with what we actually ran - m_currentAction.executable = executable; - m_currentAction.params = params; - DEBUG << "set current action to " << m_currentAction.action << endl; emit commandStarting(action); - m_proc->start(executable, params); + m_proc->start(action.executable, action.params); } void HgRunner::closeProcInput()
--- a/src/hgrunner.h Tue Jul 03 20:09:46 2012 +0100 +++ b/src/hgrunner.h Tue Jul 03 20:10:04 2012 +0100 @@ -90,6 +90,7 @@ QProgressBar *m_progress; QPushButton *m_cancel; + HgAction expandEnvironment(HgAction); QStringList addExtensionOptions(QStringList); int m_ptyMasterFd;
--- a/src/hgtabwidget.cpp Tue Jul 03 20:09:46 2012 +0100 +++ b/src/hgtabwidget.cpp Tue Jul 03 20:10:04 2012 +0100 @@ -144,6 +144,12 @@ m_historyWidget->setClosedHeadIds(closed); } +void HgTabWidget::clearAll() +{ + m_fileStatusWidget->clearWidgets(); + m_historyWidget->clear(); +} + void HgTabWidget::updateFileStates() { m_fileStatusWidget->updateWidgets();
--- a/src/hgtabwidget.h Tue Jul 03 20:09:46 2012 +0100 +++ b/src/hgtabwidget.h Tue Jul 03 20:10:04 2012 +0100 @@ -52,6 +52,7 @@ void setHaveMerge(bool); + void clearAll(); void updateFileStates(); void updateHistory();
--- a/src/historywidget.cpp Tue Jul 03 20:09:46 2012 +0100 +++ b/src/historywidget.cpp Tue Jul 03 20:10:04 2012 +0100 @@ -205,6 +205,13 @@ } } +void HistoryWidget::clear() +{ + QGraphicsScene *oldScene = m_panned->scene(); + m_panned->setScene(0); + delete oldScene; +} + void HistoryWidget::layoutAll() { m_refreshNeeded = false;
--- a/src/historywidget.h Tue Jul 03 20:09:46 2012 +0100 +++ b/src/historywidget.h Tue Jul 03 20:10:04 2012 +0100 @@ -47,8 +47,6 @@ bool haveNewItems() const { return !m_newIds.empty(); } - void update(); - signals: void commit(); void revert(); @@ -72,7 +70,9 @@ public slots: void setSearchText(QString); - + void update(); + void clear(); + private: Changesets m_changesets; QStringList m_currentIds;
--- a/src/mainwindow.cpp Tue Jul 03 20:09:46 2012 +0100 +++ b/src/mainwindow.cpp Tue Jul 03 20:10:04 2012 +0100 @@ -766,9 +766,12 @@ f.open(QFile::ReadOnly); bool glob = false; + bool cr = false; // whether the last line examined ended with a CR while (!f.atEnd()) { QByteArray ba = f.readLine(); - QString s = QString::fromLocal8Bit(ba).trimmed(); + QString s = QString::fromLocal8Bit(ba); + cr = (s.endsWith('\n') || s.endsWith('\r')); + s = s.trimmed(); if (s.startsWith("syntax:")) { if (s.endsWith("glob")) { glob = true; @@ -782,6 +785,10 @@ f.open(QFile::Append); QTextStream out(&f); + if (!cr) { + out << endl; + } + if (!glob) { out << "syntax: glob" << endl; } @@ -1208,7 +1215,10 @@ if (!QDir().mkpath(m_workFolderPath)) { DEBUG << "hgCloneFromRemote: Failed to create target path " << m_workFolderPath << endl; - //!!! report error + QMessageBox::critical + (this, tr("Could not create target folder"), + tr("<qt><b>Could not create target folder</b><br><br>The local target folder \"%1\" does not exist<br>and could not be created.</qt>").arg(xmlEncode(m_workFolderPath))); + m_workFolderPath = ""; return; } } @@ -1217,6 +1227,7 @@ updateWorkFolderAndRepoNames(); m_hgTabs->updateWorkFolderFileList(""); + m_hgTabs->clearAll(); m_runner->requestAction(HgAction(ACT_CLONEFROMREMOTE, m_workFolderPath, params)); } @@ -1485,9 +1496,9 @@ QString explanation; if (initial) { - explanation = tr("Provide a URL to use for push and pull actions from the current local repository.<br>This will be the default for subsequent pushes and pulls.<br>You can change it using “Set Remote Location” on the File menu."); + explanation = tr("Provide a remote URL to use when pushing from, or pulling to, the local<br>repository <code>%1</code>.<br>This will be the default for subsequent pushes and pulls.<br>You can change it using “Set Remote Location” on the File menu.").arg(m_workFolderPath); } else { - explanation = tr("Provide a new URL to use for push and pull actions from the current local repository."); + explanation = tr("Provide a new remote URL to use when pushing from, or pulling to, the local<br>repository <code>%1</code>.").arg(m_workFolderPath); } d->addChoice("remote", @@ -2133,6 +2144,7 @@ tr("Some files were not merged successfully.<p>You can Merge again to repeat the interactive merge; use Revert to abandon the merge entirely; or edit the files that are in conflict in an editor and, when you are happy with them, choose Mark Resolved in each file's right-button menu."), stdErr); m_mergeCommitComment = ""; + hgQueryPaths(); return; case ACT_STAT: break; // go on to default report @@ -2882,7 +2894,7 @@ } foreach (QString r, recent) { QAction *a = m_recentMenu->addAction(r); - connect(a, SIGNAL(activated()), this, SLOT(recentMenuActivated())); + connect(a, SIGNAL(triggered()), this, SLOT(recentMenuActivated())); } } @@ -2890,11 +2902,11 @@ { //File actions m_openAct = new QAction(QIcon(":/images/fileopen.png"), tr("&Open..."), this); - m_openAct->setStatusTip(tr("Open an existing repository or working folder")); + m_openAct->setStatusTip(tr("Open a remote repository or an existing local folder")); m_openAct->setShortcut(tr("Ctrl+O")); - m_changeRemoteRepoAct = new QAction(tr("Set Remote &Location..."), this); - m_changeRemoteRepoAct->setStatusTip(tr("Set or change the default remote repository for pull and push actions")); + m_changeRemoteRepoAct = new QAction(tr("Set Push and Pull &Location..."), this); + m_changeRemoteRepoAct->setStatusTip(tr("Set or change the default URL for pull and push actions from this repository")); m_settingsAct = new QAction(QIcon(":/images/settings.png"), tr("&Settings..."), this); m_settingsAct->setStatusTip(tr("View and change application settings")); @@ -3014,10 +3026,9 @@ QMenu *remoteMenu; remoteMenu = menuBar()->addMenu(tr("&Remote")); - remoteMenu->addAction(m_changeRemoteRepoAct); - remoteMenu->addSeparator(); remoteMenu->addAction(m_hgIncomingAct); remoteMenu->addSeparator(); + remoteMenu->addAction(m_changeRemoteRepoAct); remoteMenu->addAction(m_hgPullAct); remoteMenu->addAction(m_hgPushAct);
--- a/src/multichoicedialog.cpp Tue Jul 03 20:09:46 2012 +0100 +++ b/src/multichoicedialog.cpp Tue Jul 03 20:10:04 2012 +0100 @@ -275,6 +275,17 @@ } } +bool +MultiChoiceDialog::urlComboNotUrl() const +{ + QString url = m_urlCombo->currentText(); + if (QRegExp("^\\w+://").indexIn(url) < 0) { + return true; + } else { + return false; + } +} + void MultiChoiceDialog::choiceChanged() { @@ -347,14 +358,18 @@ m_urlLabel->show(); m_urlCombo->show(); m_urlCombo->addItems(rf->getRecent()); - if (m_defaultEmpty[id]) m_urlCombo->lineEdit()->setText(""); + if (m_defaultEmpty[id] || urlComboNotUrl()) { + m_urlCombo->lineEdit()->setText(""); + } break; case UrlToDirectoryArg: m_urlLabel->show(); m_urlCombo->show(); m_urlCombo->addItems(rf->getRecent()); - if (m_defaultEmpty[id]) m_urlCombo->lineEdit()->setText(""); + if (m_defaultEmpty[id] || urlComboNotUrl()) { + m_urlCombo->lineEdit()->setText(""); + } m_fileLabel->setText(tr("&Folder:")); m_fileLabel->show(); m_fileCombo->show();
--- a/src/multichoicedialog.h Tue Jul 03 20:09:46 2012 +0100 +++ b/src/multichoicedialog.h Tue Jul 03 20:10:04 2012 +0100 @@ -88,6 +88,7 @@ QAbstractButton *m_okButton; QString getDefaultPath() const; + bool urlComboNotUrl() const; }; #endif // MULTICHOICEDIALOG_H
--- a/src/settingsdialog.cpp Tue Jul 03 20:09:46 2012 +0100 +++ b/src/settingsdialog.cpp Tue Jul 03 20:10:04 2012 +0100 @@ -268,7 +268,7 @@ QSettings settings; settings.beginGroup("Locations"); QString hg = settings.value("hgbinary", "").toString(); - if (hg == "") { + if (hg == "" || !QFile(hg).exists()) { hg = findInPath("hg", m_installPath, true); } if (hg != "") {