From ff5b37c785dbd2e495a9f1f08985be6f69a34528 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Thu, 22 Jun 2017 14:09:05 -0700 Subject: [PATCH 1/2] new --scripts switch overrides default scripts location --- interface/src/Application.cpp | 17 +++++++- interface/src/Menu.cpp | 4 +- libraries/script-engine/src/ScriptEngine.cpp | 40 +++++++++---------- libraries/script-engine/src/ScriptEngines.cpp | 21 ++++++---- libraries/script-engine/src/ScriptEngines.h | 3 ++ libraries/script-engine/src/ScriptsModel.cpp | 10 ++--- libraries/shared/src/PathUtils.cpp | 34 +++++++++++----- libraries/shared/src/PathUtils.h | 5 +-- 8 files changed, 85 insertions(+), 49 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e12c73d0bc..a7bed9fc9c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -903,6 +903,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _saveAvatarOverrideUrl = true; } + QString defaultScriptsLocation = getCmdOption(argc, constArgv, "--scripts"); + if (!defaultScriptsLocation.isEmpty()) { + PathUtils::defaultScriptsLocation(defaultScriptsLocation); + } + _glWidget = new GLCanvas(); getApplicationCompositor().setRenderingWidget(_glWidget); _window->setCentralWidget(_glWidget); @@ -1167,7 +1172,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // force the model the look at the correct directory (weird order of operations issue) scriptEngines->setScriptsLocation(scriptEngines->getScriptsLocation()); // do this as late as possible so that all required subsystems are initialized - scriptEngines->loadScripts(); + // If we've overridden the default scripts location, just load default scripts + // otherwise, load 'em all + if (!defaultScriptsLocation.isEmpty()) { + scriptEngines->loadDefaultScripts(); + scriptEngines->defaultScriptsLocationOverridden(true); + } else { + scriptEngines->loadScripts(); + } + // Make sure we don't time out during slow operations at startup updateHeartbeat(); @@ -5855,7 +5868,7 @@ void Application::showDialog(const QUrl& widgetUrl, const QUrl& tabletUrl, const void Application::showScriptLogs() { auto scriptEngines = DependencyManager::get(); - QUrl defaultScriptsLoc = defaultScriptsLocation(); + QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/debugging/debugWindow.js"); scriptEngines->loadScript(defaultScriptsLoc.toString()); } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8c9baa7c43..3fab5d3d37 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -300,7 +300,7 @@ Menu::Menu() { // Settings > Avatar... action = addActionToQMenuAndActionHash(settingsMenu, "Avatar..."); connect(action, &QAction::triggered, [] { - qApp->showDialog(QString("hifi/dialogs/AvatarPreferencesDialog.qml"), + qApp->showDialog(QString("hifi/dialogs/AvatarPreferencesDialog.qml"), QString("../../hifi/tablet/TabletAvatarPreferences.qml"), "AvatarPreferencesDialog"); }); @@ -626,7 +626,7 @@ Menu::Menu() { action = addActionToQMenuAndActionHash(audioDebugMenu, "Stats..."); connect(action, &QAction::triggered, [] { auto scriptEngines = DependencyManager::get(); - QUrl defaultScriptsLoc = defaultScriptsLocation(); + QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/utilities/audio/stats.js"); scriptEngines->loadScript(defaultScriptsLoc.toString()); }); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 67b16df1ce..096b3aecfa 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -172,7 +172,7 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const emit unhandledException(exception); } }, Qt::DirectConnection); - + setProcessEventsInterval(MSECS_PER_SECOND); if (isEntityServerScript()) { qCDebug(scriptengine) << "isEntityServerScript() -- limiting maxRetries to 1"; @@ -281,7 +281,7 @@ void ScriptEngine::runDebuggable() { scriptDebugMenu = nullptr; } } - disconnect(timer); + disconnect(timer); }); connect(timer, &QTimer::timeout, [this, timer] { @@ -340,7 +340,7 @@ void ScriptEngine::runInThread() { QThread* workerThread = new QThread(); workerThread->setObjectName(QString("js:") + getFilename().replace("about:","")); moveToThread(workerThread); - + // NOTE: If you connect any essential signals for proper shutdown or cleanup of // the script engine, make sure to add code to "reconnect" them to the // disconnectNonEssentialSignals() method @@ -1047,26 +1047,26 @@ void ScriptEngine::run() { auto beforeSleep = clock::now(); // Throttle to SCRIPT_FPS - // We'd like to try to keep the script at a solid SCRIPT_FPS update rate. And so we will + // We'd like to try to keep the script at a solid SCRIPT_FPS update rate. And so we will // calculate a sleepUntil to be the time from our start time until the original target - // sleepUntil for this frame. This approach will allow us to "catch up" in the event - // that some of our script udpates/frames take a little bit longer than the target average + // sleepUntil for this frame. This approach will allow us to "catch up" in the event + // that some of our script udpates/frames take a little bit longer than the target average // to execute. // NOTE: if we go to variable SCRIPT_FPS, then we will need to reconsider this approach const std::chrono::microseconds TARGET_SCRIPT_FRAME_DURATION(USECS_PER_SECOND / SCRIPT_FPS + 1); clock::time_point targetSleepUntil(startTime + (thisFrame++ * TARGET_SCRIPT_FRAME_DURATION)); - // However, if our sleepUntil is not at least our average update and timer execution time - // into the future it means our script is taking too long in its updates, and we want to - // punish the script a little bit. So we will force the sleepUntil to be at least our + // However, if our sleepUntil is not at least our average update and timer execution time + // into the future it means our script is taking too long in its updates, and we want to + // punish the script a little bit. So we will force the sleepUntil to be at least our // averageUpdate + averageTimerPerFrame time into the future. auto averageUpdate = totalUpdates / thisFrame; auto averageTimerPerFrame = _totalTimerExecution / thisFrame; auto averageTimerAndUpdate = averageUpdate + averageTimerPerFrame; auto sleepUntil = std::max(targetSleepUntil, beforeSleep + averageTimerAndUpdate); - // We don't want to actually sleep for too long, because it causes our scripts to hang - // on shutdown and stop... so we want to loop and sleep until we've spent our time in + // We don't want to actually sleep for too long, because it causes our scripts to hang + // on shutdown and stop... so we want to loop and sleep until we've spent our time in // purgatory, constantly checking to see if our script was asked to end bool processedEvents = false; while (!_isFinished && clock::now() < sleepUntil) { @@ -1399,7 +1399,7 @@ QString ScriptEngine::_requireResolve(const QString& moduleId, const QString& re if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { return QString(); } - QUrl defaultScriptsLoc = defaultScriptsLocation(); + QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); QUrl url(moduleId); auto displayId = moduleId; @@ -1465,7 +1465,7 @@ QString ScriptEngine::_requireResolve(const QString& moduleId, const QString& re canonical.setPath(file.canonicalFilePath()); } - bool disallowOutsideFiles = !defaultScriptsLocation().isParentOf(canonical) && !currentSandboxURL.isLocalFile(); + bool disallowOutsideFiles = !PathUtils::defaultScriptsLocation().isParentOf(canonical) && !currentSandboxURL.isLocalFile(); if (disallowOutsideFiles && !PathUtils::isDescendantOf(canonical, currentSandboxURL)) { return throwResolveError(makeError(message.arg( QString("path '%1' outside of origin script '%2' '%3'") @@ -1750,7 +1750,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac return; } if (DependencyManager::get()->isStopped()) { - scriptWarningMessage("Script.include() while shutting down is ignored... includeFiles:" + scriptWarningMessage("Script.include() while shutting down is ignored... includeFiles:" + includeFiles.join(",") + "parent script:" + getFilename()); return; // bail early } @@ -1762,7 +1762,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac bool isStandardLibrary = false; if (file.startsWith("/~/")) { thisURL = expandScriptUrl(QUrl::fromLocalFile(expandScriptPath(file))); - QUrl defaultScriptsLoc = defaultScriptsLocation(); + QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); if (!defaultScriptsLoc.isParentOf(thisURL)) { scriptWarningMessage("Script.include() -- skipping" + file + "-- outside of standard libraries"); continue; @@ -1774,7 +1774,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac bool disallowOutsideFiles = thisURL.isLocalFile() && !isStandardLibrary && !currentSandboxURL.isLocalFile(); if (disallowOutsideFiles && !PathUtils::isDescendantOf(thisURL, currentSandboxURL)) { - scriptWarningMessage("Script.include() ignoring file path" + thisURL.toString() + scriptWarningMessage("Script.include() ignoring file path" + thisURL.toString() + "outside of original entity script" + currentSandboxURL.toString()); } else { // We could also check here for CORS, but we don't yet. @@ -1844,7 +1844,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { if (DependencyManager::get()->isStopped()) { - scriptWarningMessage("Script.include() while shutting down is ignored... includeFile:" + scriptWarningMessage("Script.include() while shutting down is ignored... includeFile:" + includeFile + "parent script:" + getFilename()); return; // bail early } @@ -1862,12 +1862,12 @@ void ScriptEngine::load(const QString& loadFile) { return; } if (DependencyManager::get()->isStopped()) { - scriptWarningMessage("Script.load() while shutting down is ignored... loadFile:" + scriptWarningMessage("Script.load() while shutting down is ignored... loadFile:" + loadFile + "parent script:" + getFilename()); return; // bail early } if (!currentEntityIdentifier.isInvalidID()) { - scriptWarningMessage("Script.load() from entity script is ignored... loadFile:" + scriptWarningMessage("Script.load() from entity script is ignored... loadFile:" + loadFile + "parent script:" + getFilename() + "entity: " + currentEntityIdentifier.toString()); return; // bail early } @@ -2548,7 +2548,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS qCDebug(scriptengine) << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision"; #endif - + if (HIFI_AUTOREFRESH_FILE_SCRIPTS) { refreshFileScript(entityID); } diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 69de067d10..9200550ff2 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -74,7 +74,7 @@ ScriptEngines::ScriptEngines(ScriptEngine::Context context) QUrl normalizeScriptURL(const QUrl& rawScriptURL) { if (rawScriptURL.scheme() == "file") { QUrl fullNormal = rawScriptURL; - QUrl defaultScriptLoc = defaultScriptsLocation(); + QUrl defaultScriptLoc = PathUtils::defaultScriptsLocation(); // if this url is something "beneath" the default script url, replace the local path with ~ if (fullNormal.scheme() == defaultScriptLoc.scheme() && @@ -93,7 +93,7 @@ QUrl normalizeScriptURL(const QUrl& rawScriptURL) { QString expandScriptPath(const QString& rawPath) { QStringList splitPath = rawPath.split("/"); - QUrl defaultScriptsLoc = defaultScriptsLocation(); + QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); return defaultScriptsLoc.path() + "/" + splitPath.mid(2).join("/"); // 2 to skip the slashes in /~/ } @@ -112,7 +112,7 @@ QUrl expandScriptUrl(const QUrl& rawScriptURL) { QFileInfo fileInfo(url.toLocalFile()); url = QUrl::fromLocalFile(fileInfo.canonicalFilePath()); - QUrl defaultScriptsLoc = defaultScriptsLocation(); + QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); if (!defaultScriptsLoc.isParentOf(url)) { qCWarning(scriptengine) << "Script.include() ignoring file path" << rawScriptURL << "-- outside of standard libraries: " @@ -327,6 +327,13 @@ void ScriptEngines::saveScripts() { return; } + // don't save scripts if we started with --scripts, as we would overwrite + // the scripts that the user expects to be there when launched without the + // --scripts override. + if (_defaultScriptsLocationOverridden) { + return; + } + // Saves all currently running user-loaded scripts QVariantList list; @@ -533,11 +540,11 @@ void ScriptEngines::launchScriptEngine(ScriptEngine* scriptEngine) { initializer(scriptEngine); } - // FIXME disabling 'shift key' debugging for now. If you start up the application with - // the shift key held down, it triggers a deadlock because of script interfaces running + // FIXME disabling 'shift key' debugging for now. If you start up the application with + // the shift key held down, it triggers a deadlock because of script interfaces running // on the main thread auto const wantDebug = scriptEngine->isDebuggable(); // || (qApp->queryKeyboardModifiers() & Qt::ShiftModifier); - + if (HIFI_SCRIPT_DEBUGGABLES && wantDebug) { scriptEngine->runDebuggable(); } else { @@ -573,5 +580,5 @@ void ScriptEngines::onScriptEngineError(const QString& scriptFilename) { } QString ScriptEngines::getDefaultScriptsLocation() const { - return defaultScriptsLocation().toString(); + return PathUtils::defaultScriptsLocation().toString(); } diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index 91dc54a0ec..fbd5f370cf 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -66,6 +66,8 @@ public: Q_PROPERTY(QString defaultScriptsPath READ getDefaultScriptsLocation) + void defaultScriptsLocationOverridden(bool overridden) { _defaultScriptsLocationOverridden = overridden; }; + // Called at shutdown time void shutdownScripting(); bool isStopped() const { return _isStopped; } @@ -112,6 +114,7 @@ protected: ScriptsModel _scriptsModel; ScriptsModelFilter _scriptsModelFilter; std::atomic _isStopped { false }; + bool _defaultScriptsLocationOverridden { false }; }; QUrl normalizeScriptURL(const QUrl& rawScriptURL); diff --git a/libraries/script-engine/src/ScriptsModel.cpp b/libraries/script-engine/src/ScriptsModel.cpp index 31f3a96fbd..9b7a367773 100644 --- a/libraries/script-engine/src/ScriptsModel.cpp +++ b/libraries/script-engine/src/ScriptsModel.cpp @@ -125,15 +125,15 @@ int ScriptsModel::columnCount(const QModelIndex& parent) const { void ScriptsModel::updateScriptsLocation(const QString& newPath) { _fsWatcher.removePath(_localDirectory.absolutePath()); - + if (!newPath.isEmpty()) { _localDirectory.setPath(newPath); - + if (!_localDirectory.absolutePath().isEmpty()) { _fsWatcher.addPath(_localDirectory.absolutePath()); } } - + reloadLocalFiles(); } @@ -154,7 +154,7 @@ void ScriptsModel::reloadDefaultFiles() { } void ScriptsModel::requestDefaultFiles(QString marker) { - QUrl url(defaultScriptsLocation()); + QUrl url(PathUtils::defaultScriptsLocation()); // targets that don't have a scripts folder in the appropriate location will have an empty URL here if (!url.isEmpty()) { @@ -244,7 +244,7 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) { lastKey = xml.text().toString(); if (jsRegex.exactMatch(xml.text().toString())) { QString localPath = lastKey.split("/").mid(1).join("/"); - QUrl fullPath = defaultScriptsLocation(); + QUrl fullPath = PathUtils::defaultScriptsLocation(); fullPath.setPath(fullPath.path() + lastKey); const QString fullPathStr = normalizeScriptURL(fullPath).toString(); _treeNodes.append(new TreeNodeScript(localPath, fullPathStr, SCRIPT_ORIGIN_DEFAULT)); diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index 6e3acc5e99..d1a8ff757b 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -20,6 +20,8 @@ #include #include // std::once +//QUrl PathUtils::_overriddenDefaultScriptsLocation = QUrl(); + const QString& PathUtils::resourcesPath() { #ifdef Q_OS_MAC static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/../Resources/"; @@ -71,21 +73,33 @@ QString findMostRecentFileExtension(const QString& originalFileName, QVector - #include "DependencyManager.h" /**jsdoc @@ -38,11 +37,11 @@ public: static QString stripFilename(const QUrl& url); // note: this is FS-case-sensitive version of parentURL.isParentOf(childURL) static bool isDescendantOf(const QUrl& childURL, const QUrl& parentURL); + static QUrl defaultScriptsLocation(const QString& newDefault = ""); + }; QString fileNameWithoutExtension(const QString& fileName, const QVector possibleExtensions); QString findMostRecentFileExtension(const QString& originalFileName, QVector possibleExtensions); -QUrl defaultScriptsLocation(); - #endif // hifi_PathUtils_h From 7ef50042bafc79268f5fdb729032bb14f8636e5e Mon Sep 17 00:00:00 2001 From: David Kelly Date: Fri, 23 Jun 2017 08:00:18 -0700 Subject: [PATCH 2/2] remove turd --- libraries/shared/src/PathUtils.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index d1a8ff757b..9bf9d7bdcf 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -20,8 +20,6 @@ #include #include // std::once -//QUrl PathUtils::_overriddenDefaultScriptsLocation = QUrl(); - const QString& PathUtils::resourcesPath() { #ifdef Q_OS_MAC static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/../Resources/";