# HG changeset patch # User Chris Cannam # Date 1341342604 -3600 # Node ID 4f7ca2d192dfcaeed8ce60538dfe5fbfa9cb4a38 # Parent 54ca6a0e9aeff29a2e9080dc0088b0ec628633a0# Parent 4d44bad5a8efc55d47d3b503fb7ee67261e05990 Merge diff -r 54ca6a0e9aef -r 4f7ca2d192df .hgtags --- 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 diff -r 54ca6a0e9aef -r 4f7ca2d192df CHANGELOG --- 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 diff -r 54ca6a0e9aef -r 4f7ca2d192df easyhg.py --- 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() diff -r 54ca6a0e9aef -r 4f7ca2d192df easyhg.wxs --- 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 @@ - + + + diff -r 54ca6a0e9aef -r 4f7ca2d192df src/filestatuswidget.cpp --- 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; diff -r 54ca6a0e9aef -r 4f7ca2d192df src/filestatuswidget.h --- 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); diff -r 54ca6a0e9aef -r 4f7ca2d192df src/fswatcher.cpp --- 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 -#define DEBUG_FSWATCHER 1 +//#define DEBUG_FSWATCHER 1 /* * Watching the filesystem is trickier than it seems at first glance. diff -r 54ca6a0e9aef -r 4f7ca2d192df src/hgaction.h --- 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 { diff -r 54ca6a0e9aef -r 4f7ca2d192df src/hgrunner.cpp --- 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() diff -r 54ca6a0e9aef -r 4f7ca2d192df src/hgrunner.h --- 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; diff -r 54ca6a0e9aef -r 4f7ca2d192df src/hgtabwidget.cpp --- 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(); diff -r 54ca6a0e9aef -r 4f7ca2d192df src/hgtabwidget.h --- 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(); diff -r 54ca6a0e9aef -r 4f7ca2d192df src/historywidget.cpp --- 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; diff -r 54ca6a0e9aef -r 4f7ca2d192df src/historywidget.h --- 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; diff -r 54ca6a0e9aef -r 4f7ca2d192df src/mainwindow.cpp --- 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("Could not create target folder

The local target folder \"%1\" does not exist
and could not be created.
").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.
This will be the default for subsequent pushes and pulls.
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
repository %1.
This will be the default for subsequent pushes and pulls.
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
repository %1.").arg(m_workFolderPath); } d->addChoice("remote", @@ -2133,6 +2144,7 @@ tr("Some files were not merged successfully.

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); diff -r 54ca6a0e9aef -r 4f7ca2d192df src/multichoicedialog.cpp --- 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(); diff -r 54ca6a0e9aef -r 4f7ca2d192df src/multichoicedialog.h --- 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 diff -r 54ca6a0e9aef -r 4f7ca2d192df src/settingsdialog.cpp --- 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 != "") { diff -r 54ca6a0e9aef -r 4f7ca2d192df src/version.h --- a/src/version.h Tue Jul 03 20:09:46 2012 +0100 +++ b/src/version.h Tue Jul 03 20:10:04 2012 +0100 @@ -1,1 +1,1 @@ -#define EASYHG_VERSION "1.2.1" +#define EASYHG_VERSION "1.2.2"