changeset 62:68aebc316898

* Some adjustments to process running (avoid timer): caller must now report errors * Function to find user's real name * Locate hg executable in path explicitly, use a setting to remember it
author Chris Cannam
date Wed, 17 Nov 2010 13:32:56 +0000
parents bf57a16315bd
children 2340b00561d2
files common.cpp common.h common_osx.mm debug.cpp easyhg.pro hgrunner.cpp hgrunner.h mainwindow.cpp mainwindow.h
diffstat 9 files changed, 206 insertions(+), 145 deletions(-) [+]
line wrap: on
line diff
--- a/common.cpp	Wed Nov 17 11:48:58 2010 +0000
+++ b/common.cpp	Wed Nov 17 13:32:56 2010 +0000
@@ -15,9 +15,44 @@
     COPYING included with this distribution for more information.
 */
 
+#include "common.h"
+#include "debug.h"
 
-#include "common.h"
+#include <QFileInfo>
+#include <QProcessEnvironment>
+#include <QStringList>
 
+#include <sys/types.h>
+#include <pwd.h>
+
+QString findExecutable(QString name)
+{
+    if (name != "") {
+        if (name[0] != '/') {
+            name = QFileInfo(name).fileName();
+            QString path =
+                QProcessEnvironment::systemEnvironment().value("PATH");
+            DEBUG << "findExecutable: seeking location for binary " << name
+                  << ": system path is " << path;
+#ifdef Q_OS_WIN32
+            QChar pathSep = ';';
+#else
+            QChar pathSep = ':';
+#endif
+            QStringList elements = path.split(pathSep, QString::SkipEmptyParts);
+            foreach (QString element, elements) {
+                QString full = QString("%1/%2").arg(element).arg(name);
+                QFileInfo fi(full);
+                if (fi.exists() && fi.isFile() && fi.isExecutable()) {
+                    name = full;
+                    break;
+                }
+            }
+        }
+    }
+    return name;
+}
+    
 QString getSystem()
 {
     #ifdef Q_WS_X11
@@ -35,15 +70,6 @@
     return QString("");
 }
 
-QString getHgBinaryName()
-{
-    if (getSystem() == "Windows")
-        return QString("hg.exe");
-    else
-        return QString("hg");
-}
-
-
 QString getHgDirName()
 {
     if (getSystem() == "Windows")
@@ -56,8 +82,35 @@
     }
 }
 
+#ifdef Q_OS_WIN32
+QString getUserRealName()
+{
+    const int maxlen = 1023;
+    TCHAR buf[maxlen + 2];
+    LPTSTR info = buf;
 
+    if (!GetUserNameEx(NameDisplay, info, maxlen)) {
+        return "";
+    }
 
+    return QString::fromUcs2(info);
+}
+#elif Q_OS_MAC
+// Nothing here: definition is in common_osx.mm
+#else
+QString getUserRealName()
+{
+    const int maxlen = 1023;
+    char buf[maxlen + 2];
 
+    if (getlogin_r(buf, maxlen)) return "";
 
+    struct passwd *p = getpwnam(buf);
+    if (!p) return "";
+    
+    QString s(p->pw_gecos);
+    if (s != "") s = s.split(',')[0];
+    return s;
+}
+#endif
 
--- a/common.h	Wed Nov 17 11:48:58 2010 +0000
+++ b/common.h	Wed Nov 17 13:32:56 2010 +0000
@@ -43,11 +43,13 @@
 
 #define NUM_PATHS_IN_MRU_LIST           5
 
+extern QString findExecutable(QString name);
 
 extern QString getSystem();
-extern QString getHgBinaryName();
 extern QString getHgDirName();
 
+extern QString getUserRealName();
+
 #endif 	//COMMON_H
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common_osx.mm	Wed Nov 17 13:32:56 2010 +0000
@@ -0,0 +1,16 @@
+
+#include "common.h"
+
+#include <QString>
+
+#ifdef Q_OS_MAC
+
+#include <Foundation/Foundation.h>
+
+QString getUserRealName()
+{
+    NSString *s = NSFullUserName();
+    return QString::fromLocal8Bit([s UTF8String]);
+}
+
+#endif
--- a/debug.cpp	Wed Nov 17 11:48:58 2010 +0000
+++ b/debug.cpp	Wed Nov 17 13:32:56 2010 +0000
@@ -24,6 +24,7 @@
 #include <QFile>
 #include <QDir>
 #include <QCoreApplication>
+#include <QDateTime>
 
 #include <cstdio>
 
@@ -53,6 +54,8 @@
             delete logFile;
             logFile = 0;
         }
+        *debug << endl << (const char *)prefix << "Log started at "
+               << QDateTime::currentDateTime().toString();
     }
     mutex.unlock();
 
--- a/easyhg.pro	Wed Nov 17 11:48:58 2010 +0000
+++ b/easyhg.pro	Wed Nov 17 13:32:56 2010 +0000
@@ -41,6 +41,10 @@
     colourset.cpp \
     debug.cpp
 
+macx-* {
+SOURCES += common_osx.mm
+}
+
 # ! [0]
 RESOURCES = hgexplorer.qrc
 win32 {
--- a/hgrunner.cpp	Wed Nov 17 11:48:58 2010 +0000
+++ b/hgrunner.cpp	Wed Nov 17 13:32:56 2010 +0000
@@ -16,6 +16,7 @@
 */
 
 #include "hgrunner.h"
+#include "common.h"
 #include "debug.h"
 
 #include <QPushButton>
@@ -23,6 +24,7 @@
 #include <QDialog>
 #include <QLabel>
 #include <QVBoxLayout>
+#include <QSettings>
 
 #include <iostream>
 #include <unistd.h>
@@ -44,8 +46,10 @@
     stdErr.clear();
 
     connect(proc, SIGNAL(started()), this, SLOT(started()));
-    connect(proc, SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)));
-    connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(finished(int, QProcess::ExitStatus)));
+    connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)),
+            this, SLOT(finished(int, QProcess::ExitStatus)));
+
+    reportErrors = false;
 }
 
 HgRunner::~HgRunner()
@@ -53,73 +57,37 @@
     delete proc;
 }
 
+QString HgRunner::getHgBinaryName()
+{
+    QSettings settings;
+    QString hg = settings.value("hgbinary", "hg").toString();
+    if (hg == "") hg = "hg";
+    hg = findExecutable(hg);
+    settings.setValue("hgbinary", hg);
+    return hg;
+}
+
 void HgRunner::started()
 {
     proc -> closeWriteChannel();
 }
 
+void HgRunner::saveOutput()
+{
+    stdOut = QString::fromUtf8(proc -> readAllStandardOutput());
+    stdErr = QString::fromUtf8(proc -> readAllStandardError());
+}
+
 void HgRunner::setProcExitInfo(int procExitCode, QProcess::ExitStatus procExitStatus)
 {
     exitCode = procExitCode;
     exitStatus = procExitStatus;
-    stdOut = QString::fromUtf8(proc -> readAllStandardOutput());
-    stdErr = QString::fromUtf8(proc -> readAllStandardError());
 
     DEBUG << "setProcExitInfo: " << stdOut.split("\n").size() << " line(s) of stdout, " << stdErr.split("\n").size() << " line(s) of stderr";
 
 //    std::cerr << "stdout was " << stdOut.toStdString() << std::endl;
 }
 
-void HgRunner::presentErrorToUser()
-{
-    QPushButton *okButton;
-    QListWidget *stdoL;
-    QListWidget *stdeL;
-    QString tmp;
-
-    QDialog *dlg = new QDialog(this);
-    dlg -> setMinimumWidth(800);
-    QVBoxLayout layout;
-
-    dlg -> setWindowTitle(tr("Mercurial error / warning"));
-
-    tmp.sprintf("%s: %d, %s: %d", "Exitcode", exitCode, "Exit status", exitStatus);
-    layout.addWidget(new QLabel(getLastCommandLine()));
-    layout.addWidget(new QLabel(tmp));
-    layout.addWidget(new QLabel(tr("Standard out:")));
-    stdoL = new QListWidget();
-    stdoL -> addItems(stdOut.split("\n"));
-    layout.addWidget(stdoL);
-
-    layout.addWidget(new QLabel(tr("Standard error:")));
-    stdeL = new QListWidget();
-    stdeL -> addItems(stdErr.split("\n"));
-    layout.addWidget(stdeL);
-
-    okButton = new QPushButton("Ok");
-    layout.addWidget(okButton);
-
-    connect(okButton, SIGNAL(clicked()), dlg, SLOT(accept()));
-    dlg -> setLayout(&layout);
-
-    dlg -> setModal(true);
-    dlg -> exec();
-}
-
-
-
-void HgRunner::error(QProcess::ProcessError)
-{
-    setProcExitInfo(proc -> exitCode(), proc -> exitStatus());
-
-    if (reportErrors)
-    {
-        presentErrorToUser();
-    }
-
-    isRunning = false;
-}
-
 QString HgRunner::getLastCommandLine()
 {
     return QString("Command line: " + lastHgCommand + " " + lastParams);
@@ -128,39 +96,34 @@
 void HgRunner::finished(int procExitCode, QProcess::ExitStatus procExitStatus)
 {
     setProcExitInfo(procExitCode, procExitStatus);
+    isRunning = false;
 
-    if (reportErrors)
-    {
-        if ((exitCode == 0) && (exitStatus == QProcess::NormalExit))
-        {
-            //All ok
-        }
-        else
-        {
-            presentErrorToUser();
-        }
+    if (procExitCode == 0 || procExitStatus == QProcess::NormalExit) {
+        emit commandCompleted();
+    } else {
+        emit commandFailed();
     }
-
-    isRunning = false;
 }
 
-bool HgRunner::isProcRunning()
+bool HgRunner::isCommandRunning()
 {
     return isRunning;
 }
 
-void HgRunner::killProc()
+void HgRunner::killCurrentCommand()
 {
-    if (isProcRunning())
-    {
+    if (isCommandRunning()) {
         proc -> kill();
     }
 }
 
+void HgRunner::startHgCommand(QString workingDir, QStringList params)
+{
+    startCommand(getHgBinaryName(), workingDir, params);
+}
 
-void HgRunner::startProc(QString hgExePathAndName, QString workingDir, QStringList params, bool reportErrors)
+void HgRunner::startCommand(QString command, QString workingDir, QStringList params)
 {
-    this -> reportErrors = reportErrors;
     isRunning = true;
     setRange(0, 0);
     setVisible(true);
@@ -174,15 +137,14 @@
         proc -> setWorkingDirectory(workingDir);
     }
 
-    lastHgCommand = hgExePathAndName;
+    lastHgCommand = command;
     lastParams = params.join(" ");
 
-    QString cmdline = hgExePathAndName;
+    QString cmdline = command;
     foreach (QString param, params) cmdline += " " + param;
     DEBUG << "HgRunner: starting: " << cmdline;
 
-    proc -> start(hgExePathAndName, params);
-
+    proc -> start(command, params);
 }
 
 int HgRunner::getExitCode()
--- a/hgrunner.h	Wed Nov 17 11:48:58 2010 +0000
+++ b/hgrunner.h	Wed Nov 17 13:32:56 2010 +0000
@@ -27,37 +27,47 @@
 {
     Q_OBJECT
 
-    public:
-        HgRunner(QWidget * parent = 0);
-        ~HgRunner();
+public:
+    HgRunner(QWidget * parent = 0);
+    ~HgRunner();
 
-        void startProc(QString hgExePathAndName, QString workingDir, QStringList params, bool reportErrors = true);
-        bool isProcRunning();
-        void killProc();
-        int  getExitCode();
-        void hideProgBar();
-        QString getStdOut();
+    void startHgCommand(QString workingDir, QStringList params);
+    void startCommand(QString command, QString workingDir, QStringList params);
 
-    private:
-        void setProcExitInfo(int procExitCode, QProcess::ExitStatus procExitStatus);
-        QString getLastCommandLine();
-        void presentErrorToUser();
+    bool isCommandRunning();
+    void killCurrentCommand();
 
-        bool                    reportErrors;
-        bool                    isRunning;
-        QProcess                *proc;
-        QString                 stdOut;
-        QString                 stdErr;
-        int                     exitCode;
-        QProcess::ExitStatus    exitStatus;
-        QString                 lastHgCommand;
-        QString                 lastParams;
+    int getExitCode();
+    QProcess::ExitStatus getExitStatus();
 
+    void hideProgBar();
 
-    private slots:
-        void started();
-        void error(QProcess::ProcessError error);
-        void finished(int procExitCode, QProcess::ExitStatus procExitStatus);
+    QString getStdOut();
+    
+signals:
+    void commandCompleted();
+    void commandFailed();
+
+private:
+    void saveOutput();
+    void setProcExitInfo(int procExitCode, QProcess::ExitStatus procExitStatus);
+    QString getLastCommandLine();
+    void presentErrorToUser();
+    QString getHgBinaryName();
+    
+    bool                    reportErrors;
+    bool                    isRunning;
+    QProcess                *proc;
+    QString                 stdOut;
+    QString                 stdErr;
+    int                     exitCode;
+    QProcess::ExitStatus    exitStatus;
+    QString                 lastHgCommand;
+    QString                 lastParams;
+
+private slots:
+    void started();
+    void finished(int procExitCode, QProcess::ExitStatus procExitStatus);
 };
 
 #endif // HGRUNNER_H
--- a/mainwindow.cpp	Wed Nov 17 11:48:58 2010 +0000
+++ b/mainwindow.cpp	Wed Nov 17 13:32:56 2010 +0000
@@ -32,6 +32,7 @@
 #include "mainwindow.h"
 #include "settingsdialog.h"
 #include "colourset.h"
+#include "debug.h"
 
 
 MainWindow::MainWindow()
@@ -43,8 +44,11 @@
     createToolBars();
     createStatusBar();
 
-    timerId = startTimer(200);
     runner = new HgRunner(this);
+    connect(runner, SIGNAL(commandCompleted()),
+            this, SLOT(commandCompleted()));
+    connect(runner, SIGNAL(commandFailed()),
+            this, SLOT(commandFailed()));
     runningAction = ACT_NONE;
     statusBar()->addPermanentWidget(runner);
 
@@ -70,6 +74,8 @@
         settings();
     }
 
+    DEBUG << "User's real name is " << getUserRealName() << endl;
+
     hgStat();
 }
 
@@ -114,7 +120,7 @@
             }
 
 
-            runner -> startProc(getHgBinaryName(), workFolderPath, params);
+            runner -> startHgCommand(workFolderPath, params);
             runningAction = ACT_STAT;
         }
     }
@@ -128,7 +134,7 @@
         params << "heads";
 
         //on empty repos, "hg heads" will fail, don't care of that.
-        runner -> startProc(getHgBinaryName(), workFolderPath, params, false);
+        runner -> startHgCommand(workFolderPath, params);
         runningAction = ACT_HEADS;
     }
 }
@@ -142,7 +148,7 @@
         params << "--template";
         params << "id: {rev}:{node|short}\\nauthor: {author}\\nbranch: {branches}\\ntag: {tag}\\ndatetime: {date|isodate}\\ntimestamp: {date|hgdate}\\nage: {date|age}\\nparents: {parents}\\ncomment: {desc|json}\\n\\n";
 
-        runner -> startProc(getHgBinaryName(), workFolderPath, params);
+        runner -> startHgCommand(workFolderPath, params);
         runningAction = ACT_LOG;
     }
 }
@@ -155,7 +161,7 @@
         QStringList params;
         params << "parents";
 
-        runner -> startProc(getHgBinaryName(), workFolderPath, params);
+        runner -> startHgCommand(workFolderPath, params);
         runningAction = ACT_PARENTS;
     }
 }
@@ -176,7 +182,7 @@
             {
                 params << "remove" << "--after" << "--force" << "--" << currentFile.mid(2);   //Jump over status marker characters (e.g "M ")
 
-                runner -> startProc(getHgBinaryName(), workFolderPath, params);
+                runner -> startHgCommand(workFolderPath, params);
                 runningAction = ACT_REMOVE;
             }
         }
@@ -194,7 +200,7 @@
         {
             params << "annotate" << "--" << currentFile.mid(2);   //Jump over status marker characters (e.g "M ")
 
-            runner -> startProc(getHgBinaryName(), workFolderPath, params);
+            runner -> startHgCommand(workFolderPath, params);
             runningAction = ACT_ANNOTATE;
         }
     }
@@ -212,7 +218,7 @@
         {
             params << "resolve" << "--mark" << "--" << currentFile.mid(2);   //Jump over status marker characters (e.g "M ")
 
-            runner -> startProc(getHgBinaryName(), workFolderPath, params);
+            runner -> startHgCommand(workFolderPath, params);
             runningAction = ACT_RESOLVE_MARK;
         }
     }
@@ -227,7 +233,7 @@
         QStringList params;
 
         params << "resolve" << "--list";
-        runner -> startProc(getHgBinaryName(), workFolderPath, params);
+        runner -> startHgCommand(workFolderPath, params);
         runningAction = ACT_RESOLVE_LIST;
     }
 }
@@ -261,7 +267,7 @@
             params << "add";
         }
 
-        runner -> startProc(getHgBinaryName(), workFolderPath, params);
+        runner -> startHgCommand(workFolderPath, params);
         runningAction = ACT_ADD;
     }
 }
@@ -330,7 +336,7 @@
                     params << "commit" << "--message" << comment << "--user" << userInfo;
                 }
 
-                runner -> startProc(getHgBinaryName(), workFolderPath, params);
+                runner -> startHgCommand(workFolderPath, params);
                 runningAction = ACT_COMMIT;
             }
         }
@@ -367,7 +373,7 @@
             {
                 params << "tag" << "--user" << userInfo << filterTag(tag);
 
-                runner -> startProc(getHgBinaryName(), workFolderPath, params);
+                runner -> startHgCommand(workFolderPath, params);
                 runningAction = ACT_TAG;
             }
         }
@@ -397,7 +403,7 @@
             editorName = """C:\\Program Files\\Windows NT\\Accessories\\wordpad.exe""";
         }
 
-        runner -> startProc(editorName, workFolderPath, params);
+        runner -> startCommand(editorName, workFolderPath, params);
         runningAction = ACT_HG_IGNORE;
     }
 }
@@ -416,7 +422,7 @@
         {
             //Diff parent file against working folder file
             params << "kdiff3" << "--" << currentFile.mid(2);
-            runner -> startProc(getHgBinaryName(), workFolderPath, params, false);
+            runner -> startHgCommand(workFolderPath, params);
             runningAction = ACT_FILEDIFF;
         }
     }
@@ -431,7 +437,7 @@
 
         //Diff parent against working folder (folder diff)
         params << "kdiff3";
-        runner -> startProc(getHgBinaryName(), workFolderPath, params, false);
+        runner -> startHgCommand(workFolderPath, params);
         runningAction = ACT_FOLDERDIFF;
     }
 }
@@ -452,7 +458,7 @@
         if ((!revA.isEmpty()) && (!revB.isEmpty()))
         {
             params << "kdiff3" << "--rev" << revA << "--rev" << revB;
-            runner -> startProc(getHgBinaryName(), workFolderPath, params, false);
+            runner -> startHgCommand(workFolderPath, params);
             runningAction = ACT_CHGSETDIFF;
         }
         else
@@ -474,7 +480,7 @@
         params << "update";
 
 
-        runner -> startProc(getHgBinaryName(), workFolderPath, params);
+        runner -> startHgCommand(workFolderPath, params);
         runningAction = ACT_UPDATE;
     }
 }
@@ -494,7 +500,7 @@
 
         params << "update" << "--rev" << rev << "--clean";
 
-        runner -> startProc(getHgBinaryName(), workFolderPath, params);
+        runner -> startHgCommand(workFolderPath, params);
 
         runningAction = ACT_UPDATE;
     }
@@ -510,7 +516,7 @@
 
         params << "revert" << "--no-backup" << "--" << currentFile.mid(2);
 
-        runner -> startProc(getHgBinaryName(), workFolderPath, params);
+        runner -> startHgCommand(workFolderPath, params);
         runningAction = ACT_REVERT;
     }
 }
@@ -522,7 +528,7 @@
         QStringList params;
 
         params << "resolve" << "--all";
-        runner -> startProc(getHgBinaryName(), workFolderPath, params);
+        runner -> startHgCommand(workFolderPath, params);
         runningAction = ACT_RETRY_MERGE;
     }
 }
@@ -536,7 +542,7 @@
 
         params << "merge";
 
-        runner -> startProc(getHgBinaryName(), workFolderPath, params);
+        runner -> startHgCommand(workFolderPath, params);
         runningAction = ACT_MERGE;
     }
 }
@@ -550,7 +556,7 @@
 
         params << "clone" << remoteRepoPath << workFolderPath;
 
-        runner -> startProc(getHgBinaryName(), workFolderPath, params);
+        runner -> startHgCommand(workFolderPath, params);
         runningAction = ACT_CLONEFROMREMOTE;
     }
 }
@@ -564,7 +570,7 @@
 
         params << "init";
 
-        runner -> startProc(getHgBinaryName(), workFolderPath, params);
+        runner -> startHgCommand(workFolderPath, params);
         runningAction = ACT_INIT;
     }
 }
@@ -578,7 +584,7 @@
 
         params << "incoming" << "--newest-first" << remoteRepoPath;
 
-        runner -> startProc(getHgBinaryName(), workFolderPath, params, false);
+        runner -> startHgCommand(workFolderPath, params);
         runningAction = ACT_INCOMING;
     }
 }
@@ -592,7 +598,7 @@
 
         params << "pull" << remoteRepoPath;
 
-        runner -> startProc(getHgBinaryName(), workFolderPath, params);
+        runner -> startHgCommand(workFolderPath, params);
         runningAction = ACT_PULL;
     }
 }
@@ -606,7 +612,7 @@
 
         params << "push" << remoteRepoPath;
 
-        runner -> startProc(getHgBinaryName(), workFolderPath, params);
+        runner -> startHgCommand(workFolderPath, params);
         runningAction = ACT_PUSH;
     }
 }
@@ -652,11 +658,11 @@
         QTextStream(&msg) << "Server running on address(es) (" << addrs << "), port 8000";
         params << "serve";
 
-        runner -> startProc(getHgBinaryName(), workFolderPath, params, false);
+        runner -> startHgCommand(workFolderPath, params);
         runningAction = ACT_SERVE;
 
         QMessageBox::information(this, "Serve", msg, QMessageBox::Close);
-        runner -> killProc();
+        runner -> killCurrentCommand();
     }
 }
 
@@ -893,14 +899,19 @@
 }
 
 
-void MainWindow::timerEvent(QTimerEvent *)
+void MainWindow::commandFailed()
+{
+    DEBUG << "MainWindow::commandFailed" << endl;
+}
+
+void MainWindow::commandCompleted()
 {
     bool shouldHgStat = false;
 
     if (runningAction != ACT_NONE)
     {
         //We are running some hg command...
-        if (runner -> isProcRunning() == false)
+        if (runner -> isCommandRunning() == false)
         {
             //Running has just ended.
             int exitCode = runner -> getExitCode();
--- a/mainwindow.h	Wed Nov 17 11:48:58 2010 +0000
+++ b/mainwindow.h	Wed Nov 17 13:32:56 2010 +0000
@@ -85,11 +85,12 @@
 
 protected:
     void closeEvent(QCloseEvent *event);
-    void timerEvent(QTimerEvent *event);
 
 public slots:
     void hgStat();
     void tabChanged(int currTab);
+    void commandCompleted();
+    void commandFailed();
 
 private slots:
     void about();
@@ -186,7 +187,6 @@
     QToolBar *repoToolBar;
     QToolBar *workFolderToolBar;
 
-    int         timerId;
     HGACTIONS   runningAction;
     HgRunner    *runner;