[lfs-patches] r2950 - trunk/qtchooser

krejzi at higgs.linuxfromscratch.org krejzi at higgs.linuxfromscratch.org
Thu Jul 24 04:55:12 PDT 2014


Author: krejzi
Date: Thu Jul 24 04:55:12 2014
New Revision: 2950

Log:
Add qtchooser patch.

Added:
   trunk/qtchooser/
   trunk/qtchooser/qtchooser-39-upstream_fixes-1.patch

Added: trunk/qtchooser/qtchooser-39-upstream_fixes-1.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/qtchooser/qtchooser-39-upstream_fixes-1.patch	Thu Jul 24 04:55:12 2014	(r2950)
@@ -0,0 +1,558 @@
+Submitted By:            Armin K. <krejzi at email dot com>
+Date:                    2014-07-24
+Initial Package Version: 39
+Upstream Status:         Fixed
+Origin:                  Upstream
+Description:             Latest upstream changes required to support Qt 5.3.
+
+--- a/doc/qtchooser.1	2013-12-16 08:03:54.000000000 +0100
++++ b/doc/qtchooser.1	2014-07-24 13:43:32.545065202 +0200
+@@ -50,6 +50,12 @@
+ .RE
+ .SH ENVIRONMENT
+ .TP
++.B QTCHOOSER_NO_GLOBAL_DIR
++If qtchooser has been built with \fBQTCHOOSER_GLOBAL_DIR\fR (predefined search
++paths for qtchooser's configuration files, useful in some distros), setting this
++variable will override its effect.
++.RE
++.TP
+ .B QT_SELECT
+ Same as \fB\-qt=\fIversion\fR. If set, the selected configuration is used and binaries
+ symlinked to qtchooser will be executed without additional parameters.
+--- a/Makefile	2013-12-16 08:03:54.000000000 +0100
++++ b/Makefile	2014-07-24 13:46:45.657357529 +0200
+@@ -1,3 +1,4 @@
++MKDIR  = mkdir -p
+ prefix = /usr
+ bindir = $(prefix)/bin
+ TOOLS = assistant \
+@@ -18,10 +19,12 @@
+ 	qglinfo \
+ 	qhelpconverter \
+ 	qhelpgenerator \
++	qlalr \
+ 	qmake \
+ 	qml \
+ 	qml1plugindump \
+ 	qmlbundle \
++	qmlimportscanner \
+ 	qmlmin \
+ 	qmlplugindump \
+ 	qmlprofiler \
+@@ -29,6 +32,8 @@
+ 	qmltestrunner \
+ 	qmlviewer \
+ 	qtconfig \
++	qtdiag \
++	qtpaths \
+ 	rcc \
+ 	uic \
+ 	uic3 \
+@@ -56,6 +61,8 @@
+ 	case `uname -s` in Darwin) \
+ 	    for tool in $(MACTOOLS); do ln -sf qtchooser "$(INSTALL_ROOT)$(bindir)/$$tool"; done \
+ 	;; esac
++	$(MKDIR) $(INSTALL_ROOT)$(prefix)/share/man/man1
++	install -m 644 -p doc/qtchooser.1 $(INSTALL_ROOT)$(prefix)/share/man/man1
+ 
+ uninstall:
+ 	cd src/qtchooser && $(MAKE) uninstall
+--- a/scripts/qtchooser.bash	2013-12-16 08:03:54.000000000 +0100
++++ b/scripts/qtchooser.bash	2014-07-24 13:47:52.139245337 +0200
+@@ -56,3 +56,15 @@
+     eval "$1=\"\${contents[*]}\""
+ }
+ 
++# completion:
++function _qt()
++{
++    COMPREPLY=()
++    if [ ${#COMP_WORDS[@]} -eq 2 ] && [ $COMP_CWORD -eq 1 ]; then
++        local cur opts
++        cur="${COMP_WORDS[COMP_CWORD]}"
++        opts=`qtchooser -list-versions`
++        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
++    fi
++}
++complete -F _qt qt
+--- a/src/qtchooser/main.cpp	2013-12-16 08:03:54.000000000 +0100
++++ b/src/qtchooser/main.cpp	2014-07-24 13:47:14.686178258 +0200
+@@ -60,6 +60,7 @@
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
++#include <limits.h>
+ 
+ #if defined(_WIN32) || defined(__WIN32__)
+ #  include <process.h>
+@@ -68,7 +69,9 @@
+ #  define EXE_SUFFIX ".exe"
+ #else
+ #  include <sys/types.h>
++#  include <sys/stat.h>
+ #  include <dirent.h>
++#  include <fcntl.h>
+ #  include <libgen.h>
+ #  include <pwd.h>
+ #  include <unistd.h>
+@@ -87,7 +90,17 @@
+     PrintHelp,
+     RunTool,
+     ListVersions,
+-    PrintEnvironment
++    PrintEnvironment,
++    Install
++};
++
++enum InstallOptions
++{
++    GlobalInstall    = 0,
++    LocalInstall     = 1,
++
++    NoOverwrite      = 0,
++    ForceOverwrite   = 2
+ };
+ 
+ struct Sdk
+@@ -106,6 +119,7 @@
+     int listVersions();
+     int printEnvironment(const string &targetSdk);
+     int runTool(const string &targetSdk, const string &targetTool, char **argv);
++    int install(const string &sdkName, const string &qmake, int installOptions);
+ 
+ private:
+     vector<string> searchPaths() const;
+@@ -123,6 +137,7 @@
+ {
+     puts("Usage:\n"
+          "  qtchooser { -l | -list-versions | -print-env }\n"
++         "  qtchooser -install [-f] [-local] <name> <path-to-qmake>\n"
+          "  qtchooser -run-tool=<tool name> [-qt=<Qt version>] [program arguments]\n"
+          "  <executable name> [-qt=<Qt version>] [program arguments]\n"
+          "\n"
+@@ -204,6 +219,51 @@
+     return false;
+ }
+ 
++static bool readLine(FILE *f, string *result)
++{
++#if _POSIX_VERSION >= 200809L
++    size_t len = 0;
++    char *line = 0;
++    ssize_t read = getline(&line, &len, f);
++    if (read < 0) {
++        free(line);
++        return false;
++    }
++
++    line[strlen(line) - 1] = '\0';
++    *result = line;
++    free(line);
++#elif defined(PATH_MAX)
++    char buf[PATH_MAX];
++    if (!fgets(buf, PATH_MAX - 1, f))
++        return false;
++
++    buf[PATH_MAX - 1] = '\0';
++    buf[strlen(buf) - 1] = '\0';
++    *result = buf;
++#else
++# error "POSIX < 2008 and no PATH_MAX, fix me"
++#endif
++    return true;
++}
++
++static bool mkparentdir(string name)
++{
++    // create the dir containing this dir
++    size_t pos = name.rfind('/');
++    if (pos == string::npos)
++        return false;
++    name.erase(pos);
++    if (mkdir(name.c_str(), 0777) == -1) {
++        if (errno != ENOENT)
++            return false;
++        // try this dir's parent too
++        if (!mkparentdir(name))
++            return false;
++    }
++    return true;
++}
++
+ int ToolWrapper::runTool(const string &targetSdk, const string &targetTool, char **argv)
+ {
+     Sdk sdk = selectSdk(targetSdk);
+@@ -240,6 +300,105 @@
+ #endif
+ }
+ 
++static const char *to_number(int number)
++{
++    // obviously not thread-safe
++    static char buffer[sizeof "2147483647"];
++    snprintf(buffer, sizeof buffer, "%d", number);
++    return buffer;
++}
++
++int ToolWrapper::install(const string &sdkName, const string &qmake, int installOptions)
++{
++    if (qmake.size() == 0) {
++        fprintf(stderr, "%s: missing option: path to qmake\n", argv0);
++        return 1;
++    }
++
++    if ((installOptions & ForceOverwrite) == 0) {
++        Sdk matchedSdk = iterateSdks(sdkName, &ToolWrapper::matchSdk);
++        if (matchedSdk.isValid()) {
++            fprintf(stderr, "%s: SDK \"%s\" already exists\n", argv0, sdkName.c_str());
++            return 1;
++        }
++    }
++
++    // first of all, get the bin and lib dirs from qmake
++    string bindir, libdir;
++    FILE *bin, *lib;
++    bin = popen(("'" + qmake + "' -query QT_INSTALL_BINS").c_str(), "r");
++    lib = popen(("'" + qmake + "' -query QT_INSTALL_LIBS").c_str(), "r");
++
++    if (!readLine(bin, &bindir) || !readLine(lib, &libdir)\
++            || pclose(bin) == -1 || pclose(lib) == -1) {
++        fprintf(stderr, "%s: error running %s: %s\n", argv0, qmake.c_str(), strerror(errno));
++        return 1;
++    }
++
++    const string sdkFileName = sdkName + confSuffix;
++    const string fileContents = bindir + "\n" + libdir + "\n";
++    string sdkFullPath;
++
++    // get the list of paths to try and install the SDK on the first we are able to;
++    // since the list is sorted in search order, we need to try in the reverse order
++    const vector<string> paths = searchPaths();
++    vector<string>::const_iterator it = paths.end();
++    vector<string>::const_iterator prev = it - 1;
++    for ( ; it != paths.begin(); it = prev--) {
++        sdkFullPath = *prev + sdkFileName;
++
++        // are we trying to install here?
++        bool installHere = (installOptions & LocalInstall) == 0 || prev == paths.begin();
++        if (!installHere)
++            continue;
++
++#ifdef QTCHOOSER_TEST_MODE
++        puts(sdkFullPath.c_str());
++        puts(fileContents.c_str());
++        return 0;
++#else
++        // we're good, create the SDK name
++        string tempname = sdkFullPath + "." + to_number(rand());
++        int fd;
++        // create a temporary file here
++        while (true) {
++            fd = ::open(tempname.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0666);
++            if (fd == -1 && errno == EEXIST)
++                continue;
++            if (fd == -1 && errno == ENOENT) {
++                // could be because the dir itself doesn't exist
++                if (mkparentdir(tempname))
++                    continue;
++            }
++            break;
++        }
++        if (fd == -1)
++            continue;
++
++        size_t bytesWritten = 0;
++        while (bytesWritten < fileContents.size()) {
++            ssize_t written = ::write(fd, fileContents.data() + bytesWritten, fileContents.size() - bytesWritten);
++            if (written == -1) {
++                fprintf(stderr, "%s: error writing to \"%s\": %s\n", argv0, tempname.c_str(), strerror(errno));
++                ::close(fd);
++                return 1;
++            }
++
++            bytesWritten += written;
++        }
++
++        // atomic rename
++        ::close(fd);
++        if (rename(tempname.c_str(), sdkFullPath.c_str()) == 0)
++            return 0;   // success
++#endif
++    }
++
++    // if we got here, we failed to create the file
++    fprintf(stderr, "%s: could not create SDK: %s: %s\n", argv0, sdkFullPath.c_str(), strerror(errno));
++    return 1;
++}
++
+ static vector<string> stringSplit(const char *source)
+ {
+ #if defined(_WIN32) || defined(__WIN32__)
+@@ -377,44 +536,10 @@
+         // 1) the first line contains the path to the Qt tools like qmake
+         // 2) the second line contains the path to the Qt libraries
+         // further lines are reserved for future enhancement
+-#if _POSIX_VERSION >= 200809L
+-        size_t len = 0;
+-        char *line = 0;
+-        ssize_t read = getline(&line, &len, f);
+-        if (read < 0) {
+-            free(line);
+-            fclose(f);
+-            return false;
+-        }
+-        sdk.toolsPath = line;
+-
+-        read = getline(&line, &len, f);
+-        if (read < 0) {
+-            free(line);
+-            fclose(f);
+-            return false;
+-        }
+-        sdk.librariesPath = line;
+-
+-        free(line);
+-#elif defined(PATH_MAX)
+-        char buf[PATH_MAX];
+-        if (!fgets(buf, PATH_MAX - 1, f)) {
+-            fclose(f);
+-            return false;
+-        }
+-        sdk.toolsPath = buf;
+-
+-        if (!fgets(buf, PATH_MAX - 1, f)) {
++        if (!readLine(f, &sdk.toolsPath) || !readLine(f, &sdk.librariesPath)) {
+             fclose(f);
+             return false;
+         }
+-        sdk.librariesPath = buf;
+-#else
+-# error "POSIX < 2008 and no PATH_MAX, fix me"
+-#endif
+-        sdk.toolsPath.erase(sdk.toolsPath.size() - 1); // drop newline
+-        sdk.librariesPath.erase(sdk.librariesPath.size() - 1); // drop newline
+ 
+         fclose(f);
+         return true;
+@@ -487,6 +612,9 @@
+     // running qtchooser itself
+     // check for our arguments
+     operatingMode = PrintHelp;
++    int installOptions = 0;
++    string sdkName;
++    string qmakePath;
+     for ( ; optind < argc; ++optind) {
+         char *arg = argv[optind];
+         if (*arg == '-') {
+@@ -496,14 +624,30 @@
+             // double-dash arguments are OK too
+             if (*arg == '-')
+                 ++arg;
+-            if (strcmp(arg, "list-versions") == 0 || strcmp(arg, "l") == 0) {
++            if (strcmp(arg, "install") == 0) {
++                operatingMode = Install;
++            } else if (operatingMode == Install && (strcmp(arg, "force") == 0 || strcmp(arg, "f") == 0)) {
++                installOptions |= ForceOverwrite;
++            } else if (strcmp(arg, "list-versions") == 0 || strcmp(arg, "l") == 0) {
+                 operatingMode = ListVersions;
++            } else if (operatingMode == Install && strcmp(arg, "local") == 0) {
++                installOptions |= LocalInstall;
+             } else if (beginsWith(arg, "print-env")) {
+                 operatingMode = PrintEnvironment;
+             } else if (strcmp(arg, "help") != 0) {
+                 fprintf(stderr, "%s: unknown option: %s\n", argv0, arg - 1);
+                 return 1;
+             }
++        } else if (operatingMode == Install) {
++            if (qmakePath.size()) {
++                fprintf(stderr, "%s: install mode takes exactly two arguments; unknown option: %s\n", argv0, arg);
++                return 1;
++            }
++            if (sdkName.size()) {
++                qmakePath = arg;
++            } else {
++                sdkName = strlen(arg) ? arg : "default";
++            }
+         } else {
+             fprintf(stderr, "%s: unknown argument: %s\n", argv0, arg);
+             return 1;
+@@ -526,5 +670,8 @@
+ 
+     case ListVersions:
+         return wrapper.listVersions();
++
++    case Install:
++        return wrapper.install(sdkName, qmakePath, installOptions);
+     }
+ }
+--- a/tests/auto/qtchooser/testdata/config1/qtchooser/later.conf	1970-01-01 01:00:00.000000000 +0100
++++ b/tests/auto/qtchooser/testdata/config1/qtchooser/later.conf	2014-07-24 13:47:14.686178258 +0200
+@@ -0,0 +1,2 @@
++/later/tooldir
++/later/libdir
+--- a/tests/auto/qtchooser/tst_qtchooser.cpp	2013-12-16 08:03:54.000000000 +0100
++++ b/tests/auto/qtchooser/tst_qtchooser.cpp	2014-07-24 13:47:14.687178286 +0200
+@@ -57,9 +57,9 @@
+ #endif
+ 
+ #define VERIFY_NORMAL_EXIT(proc) \
+-    if (!proc) return; \
+-    QCOMPARE(proc->readAllStandardError().constData(), ""); \
+-    QCOMPARE(proc->exitCode(), 0)
++    if (!(proc)) return; \
++    QCOMPARE((proc)->readAllStandardError().constData(), ""); \
++    QCOMPARE((proc)->exitCode(), 0)
+ 
+ class tst_ToolChooser : public QObject
+ {
+@@ -73,6 +73,7 @@
+         CommandLine = 0x8
+     };
+     QProcessEnvironment testModeEnvironment;
++    QString testData;
+     QString toolPath;
+     QString pathsWithDefault;
+     QString tempFileName;
+@@ -100,15 +101,18 @@
+     void defaultQt();
+     void passArgs_data();
+     void passArgs();
++    void install_data();
++    void install();
++    void install2();
+ };
+ 
+ tst_ToolChooser::tst_ToolChooser()
+     : testModeEnvironment(QProcessEnvironment::systemEnvironment())
+ {
+ #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+-    QString testData = QFINDTESTDATA("testdata");
++    testData = QFINDTESTDATA("testdata");
+ #else
+-    QString testData = SRCDIR "testdata";
++    testData = SRCDIR "testdata";
+ #endif
+     pathsWithDefault = testData + "/config1" LIST_SEP +
+             testData + "/config2";
+@@ -374,6 +378,120 @@
+     QCOMPARE(QString::fromLocal8Bit(procstdout), expected.join("\n"));
+ }
+ 
++void tst_ToolChooser::install_data()
++{
++    QTest::addColumn<QStringList>("args");
++    QTest::addColumn<QString>("expectedName");
++
++    QTest::newRow("missing-name") << QStringList() << QString();
++    QTest::newRow("missing-qmake") << (QStringList() << "sdk") << QString();
++
++    QString qmake = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmake";
++    QVERIFY(QFile::exists(qmake));
++
++    QStringList baseArgs;
++    baseArgs << "5" << qmake;
++
++    QTest::newRow("global-wouldoverwrite") << baseArgs << QString();
++    QTest::newRow("local-wouldoverwrite") << (QStringList() << "-local" << baseArgs) << QString();
++
++    baseArgs.prepend("-f");
++    QTest::newRow("global-overwrite") << baseArgs << testData + "/config2/qtchooser/5.conf";
++    QTest::newRow("local-overwrite") << (QStringList() << "-local" << baseArgs) << "/dev/null/qtchooser/5.conf";
++
++    baseArgs.clear();
++    baseArgs << "newname" << qmake;
++    QTest::newRow("global-newname") << baseArgs << testData + "/config2/qtchooser/newname.conf";
++    QTest::newRow("local-newname") << (QStringList() << "-local" << baseArgs) << "/dev/null/qtchooser/newname.conf";
++
++    // ensure that we find an SDK in a later path, even if we could install on an earlier one
++    QTest::newRow("global-wouldoverwrite-later") << (QStringList() << "later" << qmake) << QString();
++}
++
++void tst_ToolChooser::install()
++{
++    QFETCH(QStringList, args);
++    QFETCH(QString, expectedName);
++
++    QProcessEnvironment env = testModeEnvironment;
++    QScopedPointer<QProcess> proc(execute((QStringList() << "-install") + args, env));
++    QVERIFY(!!proc);
++    if (expectedName.isEmpty()) {
++        QByteArray err = proc->readAllStandardError();
++        QVERIFY(!err.isEmpty());
++        QVERIFY(proc->exitCode() != 0);
++        qDebug() << err.trimmed();
++    } else {
++        VERIFY_NORMAL_EXIT(proc);
++
++        QByteArray out = proc->readLine();
++        QVERIFY(!out.isEmpty());
++        QCOMPARE(QString(out).trimmed(), expectedName);
++
++        out = proc->readLine();
++        QCOMPARE(QString(out).trimmed(), QLibraryInfo::location(QLibraryInfo::BinariesPath));
++
++        out = proc->readLine();
++        QCOMPARE(QString(out).trimmed(), QLibraryInfo::location(QLibraryInfo::LibrariesPath));
++    }
++}
++
++void tst_ToolChooser::install2()
++{
++    // verify that the root is not writable by the current user
++    QString root = QDir::rootPath();
++    {
++        QFile f(root + "qtchooser");
++        QVERIFY(!f.exists());
++        QVERIFY(!f.open(QIODevice::ReadWrite));
++    }
++
++    QTemporaryDir tempdir;
++    QDir dir(tempdir.path());
++    dir.mkdir("/global");
++    dir.mkdir("/home");
++
++    QString realToolPath = QCoreApplication::applicationDirPath() + "/../../../src/qtchooser/qtchooser" EXE_SUFFIX;
++    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
++    env.remove("XDG_CONFIG_HOME");
++    env.insert("XDG_CONFIG_DIRS", tempdir.path() + "/global/etc/xdg" LIST_SEP "/");
++    env.insert("HOME", tempdir.path() + "/home");
++
++    QProcess proc;
++    proc.setProcessEnvironment(env);
++    QString qmake = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmake";
++    QString expectedContents = QLibraryInfo::location(QLibraryInfo::BinariesPath) + '\n' +
++                               QLibraryInfo::location(QLibraryInfo::LibrariesPath) + '\n';
++
++    // test 1: check that it installs into $HOME and recursively mkdirs
++    proc.setProgram(realToolPath);
++    proc.setArguments(QStringList() << "-install" << "-local" << "test" << qmake);
++    proc.start();
++    QVERIFY(proc.waitForFinished());
++    VERIFY_NORMAL_EXIT(&proc);
++
++    // find the file it must've created
++    {
++        QFile f(tempdir.path() + "/home/.config/qtchooser/test.conf");
++        QVERIFY2(f.open(QIODevice::ReadOnly), qPrintable(f.errorString()));
++        QCOMPARE(f.readAll(), expectedContents.toLocal8Bit());
++    }
++    QVERIFY(!QFile::exists(tempdir.path() + "/global/etc/xdg/qtchooser/test.conf"));
++
++    // test 2: check that it can create a global override
++    proc.setArguments(QStringList() << "-install" << "-f" << "test" << qmake);
++    proc.start();
++    QVERIFY(proc.waitForFinished());
++    VERIFY_NORMAL_EXIT(&proc);
++
++    // find the global file
++    {
++        QFile f(tempdir.path() + "/global/etc/xdg/qtchooser/test.conf");
++        QVERIFY2(f.open(QIODevice::ReadOnly), qPrintable(f.errorString()));
++        QCOMPARE(f.readAll(), expectedContents.toLocal8Bit());
++    }
++}
++
+ QTEST_MAIN(tst_ToolChooser)
+ 
+ #include "tst_qtchooser.moc"


More information about the patches mailing list