From 26e01bbacdfac3bf07eb76f6eca87e37b4934aae Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 30 Mar 2016 13:33:49 -0700 Subject: [PATCH] rewrite a bunch of path/url mangling code --- libraries/script-engine/src/ScriptEngine.cpp | 2 +- libraries/script-engine/src/ScriptEngines.cpp | 130 ++++++++++-------- libraries/script-engine/src/ScriptEngines.h | 6 +- libraries/script-engine/src/ScriptsModel.cpp | 33 +++-- libraries/shared/src/PathUtils.cpp | 10 +- libraries/shared/src/PathUtils.h | 2 +- 6 files changed, 104 insertions(+), 79 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 3f403b3677..883cd0c5c6 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -234,7 +234,7 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) { void ScriptEngine::scriptContentsAvailable(const QUrl& url, const QString& scriptContents) { _scriptContents = scriptContents; if (_wantSignals) { - emit scriptLoaded(_fileNameString); + emit scriptLoaded(url.toString()); } } diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index a62deb89bc..96e4180704 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -42,52 +42,49 @@ ScriptEngines::ScriptEngines() _scriptsModelFilter.setDynamicSortFilter(true); } -QString normalizeScriptUrl(const QString& rawScriptUrl) { - if (!rawScriptUrl.startsWith("http:") && !rawScriptUrl.startsWith("https:") && !rawScriptUrl.startsWith("atp:")) { -#ifdef Q_OS_LINUX - if (rawScriptUrl.startsWith("file:")) { - return rawScriptUrl; +QUrl normalizeScriptURL(const QUrl& rawScriptURL) { + if (rawScriptURL.scheme() == "file") { + QUrl fullNormal = rawScriptURL; + QUrl defaultScriptLoc = defaultScriptsLocation(); + + #ifdef Q_OS_LINUX + #else + // Force lowercase on file scripts because of drive letter weirdness. + if (rawScriptURL.isLocalFile()) { + fullNormal.setPath(fullNormal.path.toLower()); } - return QUrl::fromLocalFile(rawScriptUrl).toString(); -#else - QString fullNormal; - if (rawScriptUrl.startsWith("file:")) { - fullNormal = rawScriptUrl.toLower(); - } else { - // Force lowercase on file scripts because of drive letter weirdness. - fullNormal = QUrl::fromLocalFile(rawScriptUrl).toString().toLower(); - } - QString defaultScriptLoc = defaultScriptsLocation(); - if (fullNormal.startsWith(defaultScriptLoc)) { - return "~" + fullNormal.mid(defaultScriptLoc.size()); + #endif + // if this url is something "beneath" the default script url, replace the local path with ~ + if (fullNormal.scheme() == defaultScriptLoc.scheme() && + fullNormal.host() == defaultScriptLoc.host() && + fullNormal.path().startsWith(defaultScriptLoc.path())) { + fullNormal.setPath("/~/" + fullNormal.path().mid(defaultScriptLoc.path().size())); } return fullNormal; -#endif - + } else if (rawScriptURL.scheme() == "http" || rawScriptURL.scheme() == "https" || rawScriptURL.scheme() == "atp") { + return rawScriptURL; + } else { + // don't accidently support gopher + return QUrl(""); } - return QUrl(rawScriptUrl).toString(); } -QString expandScriptUrl(const QString& normalizedScriptURL) { - if (normalizedScriptURL.startsWith("http:") || - normalizedScriptURL.startsWith("https:") || - normalizedScriptURL.startsWith("atp:")) { - return QUrl(normalizedScriptURL).toString(); - } - - QUrl url; - if (normalizedScriptURL.startsWith("file:")) { - url = QUrl(normalizedScriptURL); +QUrl expandScriptUrl(const QUrl& normalizedScriptURL) { + if (normalizedScriptURL.scheme() == "http" || + normalizedScriptURL.scheme() == "https" || + normalizedScriptURL.scheme() == "atp") { + return normalizedScriptURL; + } else if (normalizedScriptURL.scheme() == "file") { + if (normalizedScriptURL.path().startsWith("/~/")) { + QUrl url = normalizedScriptURL; + QStringList splitPath = url.path().split("/"); + QUrl defaultScriptsLoc = defaultScriptsLocation(); + url.setPath(defaultScriptsLoc.path() + "/" + splitPath.mid(2).join("/")); // 2 to skip the slashes in /~/ + return url; + } + return normalizedScriptURL; } else { - url = QUrl::fromLocalFile(normalizedScriptURL); - } - - QString path = url.path(); - QStringList splitPath = path.split("/"); - if (splitPath.size() > 0 && splitPath[0] == "~") { - QString defaultScriptLoc = defaultScriptsLocation(); - url.setPath(defaultScriptLoc + splitPath.mid(1).join("/")); - return url.toString(); + return QUrl(""); } } @@ -229,14 +226,21 @@ QVariantList ScriptEngines::getRunning() { auto runningScripts = getRunningScripts(); foreach(const QString& runningScript, runningScripts) { QUrl runningScriptURL = QUrl(runningScript); - if (runningScriptURL.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) { + if (!runningScriptURL.isValid()) { runningScriptURL = QUrl::fromLocalFile(runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded))); } QVariantMap resultNode; resultNode.insert("name", runningScriptURL.fileName()); - resultNode.insert("url", runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded))); + QUrl displayURL = expandScriptUrl(QUrl(runningScriptURL)); + QString displayURLString; + if (displayURL.isLocalFile()) { + displayURLString = displayURL.toLocalFile(); + } else { + displayURLString = displayURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded)); + } + resultNode.insert("url", displayURLString); // The path contains the exact path/URL of the script, which also is used in the stopScript function. - resultNode.insert("path", runningScript); + resultNode.insert("path", normalizeScriptURL(runningScript).toString()); resultNode.insert("local", runningScriptURL.isLocalFile()); result.append(resultNode); } @@ -247,7 +251,9 @@ QVariantList ScriptEngines::getRunning() { static const QString SETTINGS_KEY = "Settings"; void ScriptEngines::loadDefaultScripts() { - loadScript(defaultScriptsLocation() + "/scripts/defaultScripts.js"); + QUrl defaultScriptsLoc = defaultScriptsLocation(); + defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "/scripts/defaultScripts.js"); + loadScript(defaultScriptsLoc.toString()); } void ScriptEngines::loadOneScript(const QString& scriptFilename) { @@ -296,7 +302,7 @@ void ScriptEngines::saveScripts() { for (auto it = runningScripts.begin(); it != runningScripts.end(); ++it) { if (getScriptEngine(*it)->isUserLoaded()) { settings.setArrayIndex(i); - settings.setValue("script", *it); + settings.setValue("script", normalizeScriptURL(*it).toString()); ++i; } } @@ -338,11 +344,16 @@ void ScriptEngines::stopAllScripts(bool restart) { } } -bool ScriptEngines::stopScript(const QString& rawScriptUrl, bool restart) { +bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) { bool stoppedScript = false; { + QUrl scriptURL = normalizeScriptURL(QUrl(rawScriptURL)); + if (!scriptURL.isValid()) { + scriptURL = normalizeScriptURL(QUrl::fromLocalFile(rawScriptURL)); + } + const QString scriptURLString = scriptURL.toString(); + QReadLocker lock(&_scriptEnginesHashLock); - const QString scriptURLString = normalizeScriptUrl(rawScriptUrl); if (_scriptEnginesHash.contains(scriptURLString)) { ScriptEngine* scriptEngine = _scriptEnginesHash[scriptURLString]; if (restart) { @@ -375,18 +386,19 @@ void ScriptEngines::reloadAllScripts() { stopAllScripts(true); } -ScriptEngine* ScriptEngines::loadScript(const QString& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor, bool activateMainWindow, bool reload) { +ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor, + bool activateMainWindow, bool reload) { if (thread() != QThread::currentThread()) { ScriptEngine* result { nullptr }; QMetaObject::invokeMethod(this, "loadScript", Qt::BlockingQueuedConnection, Q_RETURN_ARG(ScriptEngine*, result), - Q_ARG(QString, scriptFilename), + Q_ARG(QUrl, scriptFilename), Q_ARG(bool, isUserLoaded), Q_ARG(bool, loadScriptFromEditor), Q_ARG(bool, activateMainWindow), Q_ARG(bool, reload)); return result; } - QUrl scriptUrl(scriptFilename); + QUrl scriptUrl = normalizeScriptURL(scriptFilename); auto scriptEngine = getScriptEngine(scriptUrl.toString()); if (scriptEngine) { return scriptEngine; @@ -399,7 +411,7 @@ ScriptEngine* ScriptEngines::loadScript(const QString& scriptFilename, bool isUs }, Qt::QueuedConnection); - if (scriptFilename.isNull()) { + if (scriptFilename.isEmpty()) { launchScriptEngine(scriptEngine); } else { // connect to the appropriate signals of this script engine @@ -407,17 +419,17 @@ ScriptEngine* ScriptEngines::loadScript(const QString& scriptFilename, bool isUs connect(scriptEngine, &ScriptEngine::errorLoadingScript, this, &ScriptEngines::onScriptEngineError); // get the script engine object to load the script at the designated script URL - scriptEngine->loadURL(scriptUrl, reload); + scriptEngine->loadURL(QUrl(expandScriptUrl(scriptUrl.toString())), reload); } return scriptEngine; } -ScriptEngine* ScriptEngines::getScriptEngine(const QString& rawScriptUrl) { +ScriptEngine* ScriptEngines::getScriptEngine(const QString& rawScriptURL) { ScriptEngine* result = nullptr; { QReadLocker lock(&_scriptEnginesHashLock); - const QString scriptURLString = normalizeScriptUrl(rawScriptUrl); + const QString scriptURLString = normalizeScriptURL(QUrl(rawScriptURL)).toString(); auto it = _scriptEnginesHash.find(scriptURLString); if (it != _scriptEnginesHash.end()) { result = it.value(); @@ -427,15 +439,17 @@ ScriptEngine* ScriptEngines::getScriptEngine(const QString& rawScriptUrl) { } // FIXME - change to new version of ScriptCache loading notification -void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptUrl) { - UserActivityLogger::getInstance().loadedScript(rawScriptUrl); +void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) { + UserActivityLogger::getInstance().loadedScript(rawScriptURL); ScriptEngine* scriptEngine = qobject_cast(sender()); launchScriptEngine(scriptEngine); { QWriteLocker lock(&_scriptEnginesHashLock); - const QString scriptURLString = normalizeScriptUrl(rawScriptUrl); + QUrl url = QUrl(rawScriptURL); + QUrl normalized = normalizeScriptURL(url); + const QString scriptURLString = normalized.toString(); _scriptEnginesHash.insertMulti(scriptURLString, scriptEngine); } emit scriptCountChanged(); @@ -458,11 +472,11 @@ void ScriptEngines::launchScriptEngine(ScriptEngine* scriptEngine) { } -void ScriptEngines::onScriptFinished(const QString& rawScriptUrl, ScriptEngine* engine) { +void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptEngine* engine) { bool removed = false; { QWriteLocker lock(&_scriptEnginesHashLock); - const QString scriptURLString = normalizeScriptUrl(rawScriptUrl); + const QString scriptURLString = normalizeScriptURL(QUrl(rawScriptURL)).toString(); for (auto it = _scriptEnginesHash.find(scriptURLString); it != _scriptEnginesHash.end(); ++it) { if (it.value() == engine) { _scriptEnginesHash.erase(it); diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index ab0d17d9f3..a0d914ec64 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -51,7 +51,7 @@ public: ScriptsModelFilter* scriptsModelFilter() { return &_scriptsModelFilter; }; Q_INVOKABLE void loadOneScript(const QString& scriptFilename); - Q_INVOKABLE ScriptEngine* loadScript(const QString& scriptFilename = QString(), + Q_INVOKABLE ScriptEngine* loadScript(const QUrl& scriptFilename = QString(), bool isUserLoaded = true, bool loadScriptFromEditor = false, bool activateMainWindow = false, bool reload = false); Q_INVOKABLE bool stopScript(const QString& scriptHash, bool restart = false); @@ -96,7 +96,7 @@ protected: ScriptsModelFilter _scriptsModelFilter; }; -QString normalizeScriptUrl(const QString& rawScriptUrl); -QString expandScriptUrl(const QString& normalizedScriptURL); +QUrl normalizeScriptURL(const QUrl& rawScriptURL); +QUrl expandScriptUrl(const QUrl& normalizedScriptURL); #endif // hifi_ScriptEngine_h diff --git a/libraries/script-engine/src/ScriptsModel.cpp b/libraries/script-engine/src/ScriptsModel.cpp index 5b368095e0..f616847528 100644 --- a/libraries/script-engine/src/ScriptsModel.cpp +++ b/libraries/script-engine/src/ScriptsModel.cpp @@ -158,14 +158,21 @@ void ScriptsModel::requestDefaultFiles(QString marker) { QUrl url(defaultScriptsLocation()); if (url.isLocalFile()) { - QString localDir = url.toLocalFile() + "/scripts"; + // if the url indicates a local directory, use QDirIterator + // QString localDir = url.toLocalFile() + "/scripts"; + QString localDir = expandScriptUrl(url).toLocalFile() + "/scripts"; + int localDirPartCount = localDir.split("/").size(); QDirIterator it(localDir, QStringList() << "*.js", QDir::Files, QDirIterator::Subdirectories); while (it.hasNext()) { - QString jsFullPath = normalizeScriptUrl(it.next()); - QString jsPartialPath = normalizeScriptUrl(jsFullPath.mid(localDir.length() + 1)); // + 1 to skip a separator - _treeNodes.append(new TreeNodeScript(jsPartialPath, jsFullPath, SCRIPT_ORIGIN_DEFAULT)); + QUrl jsFullPath = QUrl::fromLocalFile(it.next()); + // QString jsPartialPath = jsFullPath.path().mid(localDir.length() + 1); // + 1 to skip a separator + QString jsPartialPath = jsFullPath.path().split("/").mid(localDirPartCount).join("/"); + jsFullPath = normalizeScriptURL(jsFullPath); + _treeNodes.append(new TreeNodeScript(jsPartialPath, jsFullPath.toString(), SCRIPT_ORIGIN_DEFAULT)); } + _loadingScripts = false; } else { + // the url indicates http(s), use QNetworkRequest QUrlQuery query; query.addQueryItem(PREFIX_PARAMETER_NAME, MODELS_LOCATION); if (!marker.isEmpty()) { @@ -227,11 +234,13 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) { while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == CONTAINER_NAME)) { if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == KEY_NAME) { xml.readNext(); - lastKey = normalizeScriptUrl(xml.text().toString()); + lastKey = xml.text().toString(); if (jsRegex.exactMatch(xml.text().toString())) { - _treeNodes.append(new TreeNodeScript(lastKey.mid(MODELS_LOCATION.length()), - defaultScriptsLocation() + "/" + lastKey, - SCRIPT_ORIGIN_DEFAULT)); + QString localPath = lastKey.split("/").mid(1).join("/"); + QUrl fullPath = defaultScriptsLocation(); + fullPath.setPath(fullPath.path() + "/" + lastKey); + const QString fullPathStr = normalizeScriptURL(fullPath).toString(); + _treeNodes.append(new TreeNodeScript(localPath, fullPathStr, SCRIPT_ORIGIN_DEFAULT)); } } xml.readNext(); @@ -274,9 +283,9 @@ void ScriptsModel::reloadLocalFiles() { const QFileInfoList localFiles = _localDirectory.entryInfoList(); for (int i = 0; i < localFiles.size(); i++) { QFileInfo file = localFiles[i]; - QString fileName = normalizeScriptUrl(file.fileName()); - QString absPath = normalizeScriptUrl(file.absoluteFilePath()); - _treeNodes.append(new TreeNodeScript(fileName, absPath, SCRIPT_ORIGIN_LOCAL)); + QString fileName = file.fileName(); + QUrl absPath = normalizeScriptURL(QUrl::fromLocalFile(file.absoluteFilePath())); + _treeNodes.append(new TreeNodeScript(fileName, absPath.toString(), SCRIPT_ORIGIN_LOCAL)); } rebuildTree(); endResetModel(); @@ -302,7 +311,7 @@ void ScriptsModel::rebuildTree() { for (pathIterator = pathList.constBegin(); pathIterator != pathList.constEnd(); ++pathIterator) { hash.append(*pathIterator + "/"); if (!folders.contains(hash)) { - folders[hash] = new TreeNodeFolder(normalizeScriptUrl(*pathIterator), parent); + folders[hash] = new TreeNodeFolder(*pathIterator, parent); } parent = folders[hash]; } diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index 2e8d4a4e6a..0fe11df28a 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include "PathUtils.h" @@ -54,12 +55,13 @@ QString findMostRecentFileExtension(const QString& originalFileName, QVector possibleExtensions); QString findMostRecentFileExtension(const QString& originalFileName, QVector possibleExtensions); -QString defaultScriptsLocation(); +QUrl defaultScriptsLocation(); #endif // hifi_PathUtils_h