From d852308dc6207a053e8d195eb63c40517c855360 Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Mon, 25 May 2020 19:45:40 +0100 Subject: [PATCH] Nasal library load order Previously, the Nasal files in fgdata/Nasal/*.nas were loaded in file-name order. This created a particular problem file files beginning with "a" which might want to use props.nas. This adds support for an ordered list of files to be defined in the property tree that will be loaded before the rest of the Nasal files. --- src/Scripting/NasalSys.cxx | 56 ++++++++++++++++++++++++-------------- src/Scripting/NasalSys.hxx | 4 +-- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/Scripting/NasalSys.cxx b/src/Scripting/NasalSys.cxx index c391c2c65..5b7e129e7 100644 --- a/src/Scripting/NasalSys.cxx +++ b/src/Scripting/NasalSys.cxx @@ -820,12 +820,12 @@ static naRef f_custom_stat(naContext ctx, naRef me, int argc, naRef* args) naRef pathArg = argc > 0 ? naStringValue(ctx, args[0]) : naNil(); if (!naIsString(pathArg)) naRuntimeError(ctx, "bad argument to stat()"); - + const auto path = SGPath::fromUtf8(naStr_data(pathArg)); if (!path.exists()) { return naNil(); } - + const SGPath filename = fgValidatePath(path, false ); if (filename.isNull()) { SG_LOG(SG_NASAL, SG_ALERT, "stat(): reading '" << @@ -835,10 +835,10 @@ static naRef f_custom_stat(naContext ctx, naRef me, int argc, naRef* args) naRuntimeError(ctx, "stat(): access denied (unauthorized directory)"); return naNil(); } - + naRef result = naNewVector(ctx); naVec_setsize(ctx, result, 12); - + // every use in fgdata/Nasal only uses stat() to test existence of // files, not to check any of this information. int n = 0; @@ -1019,7 +1019,7 @@ void FGNasalSys::init() hashset(_globals, "utf8", naInit_utf8(_context)); initLogLevelConstants(); - + // Add our custom extension functions: for(i=0; funcs[i].name; i++) hashset(_globals, funcs[i].name, @@ -1079,7 +1079,7 @@ void FGNasalSys::init() // Now load the various source files in the Nasal directory simgear::Dir nasalDir(SGPath(globals->get_fg_root(), "Nasal")); - loadScriptDirectory(nasalDir); + loadScriptDirectory(nasalDir, globals->get_props()->getNode("/sim/nasal-load-priority")); // Add modules in Nasal subdirectories to property tree simgear::PathList directories = nasalDir.children(simgear::Dir::TYPE_DIR+ @@ -1158,7 +1158,7 @@ void FGNasalSys::shutdown() SG_LOG(SG_NASAL, SG_DEV_WARN, "Extant:" << pt << " : " << pt->name()); } } - + _inited = false; } @@ -1181,11 +1181,11 @@ void FGNasalSys::update(double) { if( NasalClipboard::getInstance() ) NasalClipboard::getInstance()->update(); - + std::for_each(_dead_listener.begin(), _dead_listener.end(), []( FGNasalListener* l) { delete l; }); _dead_listener.clear(); - + if (!_loadList.empty()) { if( _delay_load ) @@ -1223,17 +1223,33 @@ bool pathSortPredicate(const SGPath& p1, const SGPath& p2) return p1.file() < p2.file(); } -// Loads all scripts in given directory -void FGNasalSys::loadScriptDirectory(simgear::Dir nasalDir) +// Loads all scripts in given directory, with an optional partial ordering of +// files defined in loadorder. +void FGNasalSys::loadScriptDirectory(simgear::Dir nasalDir, SGPropertyNode* loadorder) { simgear::PathList scripts = nasalDir.children(simgear::Dir::TYPE_FILE, ".nas"); + + if (loadorder != nullptr && loadorder->hasChild("file")) { + // Load any scripts defined in the loadorder in order, removing them from + // the list so they don't get loaded twice. + simgear::PropertyList files = loadorder->getChildren("file"); + + auto loadAndErase = [ &scripts, &nasalDir, this ] (SGPropertyNode_ptr n) { + SGPath p = SGPath(nasalDir.path(), n->getStringValue()); + auto script = std::find(scripts.begin(), scripts.end(), p); + if (script != scripts.end()) { + this->loadModule(p, p.file_base().c_str()); + scripts.erase(script); + } + }; + + std::for_each(files.begin(), files.end(), loadAndErase); + } + + // Load any remaining scripts. // Note: simgear::Dir already reports file entries in a deterministic order, // so a fixed loading sequence is guaranteed (same for every user) - for (unsigned int i=0; iloadModule(p, p.file_base().c_str()); }); } // Create module with list of scripts @@ -1348,7 +1364,7 @@ void FGNasalSys::logError(naContext context) { string errorMessage = naGetError(context); SG_LOG(SG_NASAL, SG_ALERT, "Nasal runtime error: " << errorMessage); - + string_list nasalStack; logNasalStack(context, nasalStack); flightgear::sentryReportNasalError(errorMessage, nasalStack); @@ -1362,16 +1378,16 @@ void FGNasalSys::logNasalStack(naContext context, string_list& stack) stack.push_back(string{naStr_data(naGetSourceFile(context, 0))} + ", line " + std::to_string(naGetLine(context, 0))); - + SG_LOG(SG_NASAL, SG_ALERT, " at " << naStr_data(naGetSourceFile(context, 0)) << ", line " << naGetLine(context, 0)); - + for(int i=1; i