Merge pull request #10790 from davidkelly/dk/scriptsSwitch

Command line switch to override default scripts location
This commit is contained in:
David Kelly 2017-06-23 08:53:40 -07:00 committed by GitHub
commit 63279f4525
8 changed files with 83 additions and 49 deletions

View file

@ -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<ScriptEngines>();
QUrl defaultScriptsLoc = defaultScriptsLocation();
QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation();
defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/debugging/debugWindow.js");
scriptEngines->loadScript(defaultScriptsLoc.toString());
}

View file

@ -303,7 +303,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");
});
@ -629,7 +629,7 @@ Menu::Menu() {
action = addActionToQMenuAndActionHash(audioDebugMenu, "Stats...");
connect(action, &QAction::triggered, [] {
auto scriptEngines = DependencyManager::get<ScriptEngines>();
QUrl defaultScriptsLoc = defaultScriptsLocation();
QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation();
defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/utilities/audio/stats.js");
scriptEngines->loadScript(defaultScriptsLoc.toString());
});

View file

@ -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<ScriptEngines>()->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<ScriptEngines>()->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<ScriptEngines>()->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);
}

View file

@ -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;
@ -541,11 +548,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 {
@ -581,5 +588,5 @@ void ScriptEngines::onScriptEngineError(const QString& scriptFilename) {
}
QString ScriptEngines::getDefaultScriptsLocation() const {
return defaultScriptsLocation().toString();
return PathUtils::defaultScriptsLocation().toString();
}

View file

@ -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; }
@ -113,6 +115,7 @@ protected:
ScriptsModelFilter _scriptsModelFilter;
std::atomic<bool> _isStopped { false };
std::atomic<bool> _isReloading { false };
bool _defaultScriptsLocationOverridden { false };
};
QUrl normalizeScriptURL(const QUrl& rawScriptURL);

View file

@ -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));

View file

@ -71,21 +71,33 @@ QString findMostRecentFileExtension(const QString& originalFileName, QVector<QSt
return newestFileName;
}
QUrl defaultScriptsLocation() {
// return "http://s3.amazonaws.com/hifi-public";
#ifdef Q_OS_WIN
QString path = QCoreApplication::applicationDirPath() + "/scripts";
#elif defined(Q_OS_OSX)
QString path = QCoreApplication::applicationDirPath() + "/../Resources/scripts";
#else
QString path = QCoreApplication::applicationDirPath() + "/scripts";
#endif
QUrl PathUtils::defaultScriptsLocation(const QString& newDefaultPath) {
static QString overriddenDefaultScriptsLocation = "";
QString path;
// set overriddenDefaultScriptLocation if it was passed in
if (!newDefaultPath.isEmpty()) {
overriddenDefaultScriptsLocation = newDefaultPath;
}
// use the overridden location if it is set
if (!overriddenDefaultScriptsLocation.isEmpty()) {
path = overriddenDefaultScriptsLocation;
} else {
#ifdef Q_OS_WIN
path = QCoreApplication::applicationDirPath() + "/scripts";
#elif defined(Q_OS_OSX)
path = QCoreApplication::applicationDirPath() + "/../Resources/scripts";
#else
path = QCoreApplication::applicationDirPath() + "/scripts";
#endif
}
// turn the string into a legit QUrl
QFileInfo fileInfo(path);
return QUrl::fromLocalFile(fileInfo.canonicalFilePath());
}
QString PathUtils::stripFilename(const QUrl& url) {
// Guard against meaningless query and fragment parts.
// Do NOT use PreferLocalFile as its behavior is unpredictable (e.g., on defaultScriptsLocation())

View file

@ -13,7 +13,6 @@
#define hifi_PathUtils_h
#include <QtCore/QObject>
#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<QString> possibleExtensions);
QString findMostRecentFileExtension(const QString& originalFileName, QVector<QString> possibleExtensions);
QUrl defaultScriptsLocation();
#endif // hifi_PathUtils_h