- fgfs --language=fr-FR now works as expected for the launcher (also with
--language=fr_FR as before): the value added by option --language to
the _languages member of FGLocale is normalized in "underscore" style
(e.g., fr_FR).
- Add-on translations must now use a hyphen in their property node names
in addon-metadata.xml (talking about children of <localized>): i.e.,
use for instance <fr-FR> there, not <fr_FR>. An exception
(addons::errors::error_loading_metadata_file) is thrown if one of
these nodes has a name containing an underscore.
Allow add-ons to define an FGData subdir, and support multiple —data=
command line arguments, to avoid the need to modify FG_ROOT (which might
be read-only). Allow additional data paths to be either higher or lower
priority than FG_ROOT, so that add-ons cannot replace files in FG_ROOT.
Fix for: https://sourceforge.net/p/flightgear/codetickets/2059/
When copying addon-config into the main property tree, skip props
which already exist and which are marked ARCHIVE, on the assumption
they came from autosave.xml.
Since the new _storagePath data member internally contains the add-on
id, changing _id after _storagePath has been initialized would make both
data members inconsistent. As changing the add-on id is probably not a
very useful operation, the simplest way to prevent such an inconsistency
from happening is to make Addon's _id data member const (as is already
the case for _storagePath), and thus remove Addon::setId().
Consequently, remove the Addon default constructor too, since add-ons
with an empty id would be ill-formed and couldn't be changed (_id being
const now). This leaves us with one Addon constructor:
Addon(std::string id, AddonVersion version = AddonVersion(),
SGPath basePath = SGPath(), std::string minFGVersionRequired = "",
std::string maxFGVersionRequired = "",
SGPropertyNode* addonNode = nullptr);
New methods Addon::createStorageDir() and Addon::getStoragePath() with
corresponding Nasal bindings in the addons.Addon ghost:
createStorageDir() method (returns the dir, doesn't fail if it already
exists)
storagePath read-only attribute to get the dir
The directory reserved for each add-on is
$FG_HOME/Export/Addons/ADDON_ID, but please use the above methods (or
the corresponding C++ ones) to avoid hardcoding such paths in your code.
Also create directory $FG_HOME/Export/Addons in fgInitConfig() as a way
of reserving the namespace, in order to prevent future failures in case
someone would have the strange idea to create it as a file...
If an add-on has a file named addon-menubar-items.xml in its base
directory, load it and add its items to the FG menubar.
Logically, fgStartNewReset() should call
flightgear::addons::AddonManager::instance()->addAddonMenusToFGMenubar()
in order to re-add the items, however doing so would cause the
add-on-specific menus to be added one more time on every reset, because
for some reason, commit 45ea8b5daa added
the PRESERVE attribute to /sim/menubar (apparently to preserve the state
of menu entries upon reset?).
Note: the addon-menubar-items.xml files are reloaded during reset,
however the menu bar doesn't reflect this, since adding the
reloaded items to the menu bar in fgStartNewReset() would cause
the add-on-specific menus to appear several times in the menu bar,
as explained above.
The add-on framework now uses the following files in each add-on
directory:
- addon-config.xml (previously: config.xml)
- addon-main.nas (previously: main.nas)
This is consistent with the addon-metadata.xml file that is already part
of the interface between FG core and add-ons. The goal is to make it
clearer, when browsing an add-on directory, which files belong to the
"FG core <-> add-on" interface and which files belong to the add-on
proper. This will be beneficial also when more files are added to the
"FG core <-> add-on" interface, such as possibly addon-events.xml in the
future.
This change is incompatible, thus it is the right time to do *before*
2018.2.1 is out, especially considering that this upcoming release
already has incompatible changes in the add-on API, namely the
requirement of the addon-metadata.xml file and the type of the argument
passed to each add-on's main() function. We'll try harder not to break
compatibility in the add-on API once 2018.2.1 is out. For now, it is
still a good time to try to get the API as clean as possible.
The previous priority was PRIORITY_NORMAL, which happens to be higher
than PRIORITY_DEFAULT. Even though the add-on resource provider should
be quite fast at rejecting resource paths that don't start with
'[addon=', I currently can't see any reason that justifies to give it a
higher priority than other paths added to the simgear::ResourceManager
with addBasePath(..., PRIORITY_DEFAULT).
This is another place where the add-on code uses regexps, and so far I
had forgotten to add the fallback code for compilers that don't support
<regex> as per the C++11 standard.
This method takes a string such as "this/is/a/relative/path" and returns
"[addon=ADDON_ID]this/is/a/relative/path", substituting the add-on
identifier for ADDON_ID.
This way, add-on authors don't even have to know the special syntax
'[addon=ADDON_ID]relative/path' used for add-on-specific resource paths,
and don't need to hardcode their add-on identifier inside each such path
either.
A resource can be specified with the syntax:
[addon=ADDON_ID]relative/path
Such a resource corresponds to the file $addon_base_path/relative/path
for the specific add-on whose identifier is ADDON_ID.
If the particular add-on isn't registered, looking up such a resource
throws sg_exception.
Replace the previously-written manual calls to "new SomeClass(...)" with
their equivalent using
flightgear::addons::shared_ptr_traits<>::makeStrongRef(). This way, when
SomeClassRef is changed from SGSharedPtr<SomeClass> to
std::shared_ptr<SomeClass>, these calls will magically use
std::make_shared<SomeClass>(...) instead of the "new SomeClass(...)"
call.
(everything described here lives in the namespace flightgear::addons)
New classes: Author, Maintainer, and Contact. Author and Maintainer
derive from Contact. For each contact, the following can be defined in
addon-metadata.xml: name, email, and url. See [1] for details about the
syntax and usage policy. Nasal bindings have been updated accordingly,
there are three new ghosts: addons.Contact, addons.Author and
addons.Maintainer.
The enum class UrlType has two new members: author and maintainer. The
Addon::getUrls() method has a new signature:
std::multimap<UrlType, QualifiedUrl> getUrls() const;
because non-empty 'url' fields for authors and maintainers contribute to
the result, and there can be an arbitrary number of authors and an
arbitrary number of maintainers defined for a given add-on---therefore,
std::map can't be used anymore.
Finally, QualifiedUrl has a new field (detail) which stores the author
name (resp. maintainer name) when the QualifiedUrl type is
UrlType::author (resp. UrlType::maintainer). Currently, this 'detail'
field is not used for other URL types, but this could be changed if
desired.
[1] https://sourceforge.net/p/flightgear/fgdata/ci/next/tree/Docs/README.add-ons
flightgear::addons::shared_ptr_traits allows one to easily switch for
instance from an SGSharedPtr<T> to an std::shared_ptr<T> for "all" uses
of a particular T, and automatically have std::make_shared<T>(...) used
instead of SGSharedPtr<T>(new T(...)) when creating a shared instance of
T. This is interesting because std::make_shared<T>() allocates all
needed memory as one block, whereas std::shared_ptr<T>(new T(args...))
would perform at least two allocations (one for the object T and one for
the control block of the shared pointer).
This is done via static methods (one for each kind of smart pointer):
shared_ptr_traits<SGSharedPtr<T>>::makeStrongRef()
shared_ptr_traits<std::shared_ptr<T>>::makeStrongRef()
that forward their arguments in the same way as std::make_shared<T>().
Normally, <regex> should be available and working in any compliant C++11
implementation, however at least g++ 4.8[1] lies about its C++11
compliance: its <regex> is utterly unusable, see [2] and [3] for
details.
This requires SimGear commit ab1e2d49abdf5b1aca9035a51d9d73d687f0eba7,
for the HAVE_WORKING_STD_REGEX preprocessor symbol.
[1] Which appears to be (precisely 4.8.5) the version shipped in
CentOS 7, and used on FlightGear's current Jenkins installation.
[2] https://stackoverflow.com/a/12665408/4756009
[3] https://sourceforge.net/p/flightgear/mailman/message/36170781/
Changes to test_AddonManagement.cxx:
- in testAddonVersionSuffix(), fgtest::initTestGlobals() was called
with the wrong test name (not used anyway, but might be in the
future);
- in testAddon():
* rename variable 'm' to 'addon' ('m' used to stand for the old
class name AddonMetadata);
* call fgtest::initTestGlobals() and fgtest::shutdownTestGlobals()
(not technically needed, but cleaner).
QualifiedUrl is essentially a pair containing an enum value
(addons::UrlType::homePage, addons::UrlType::download, etc.) and an
std::string for the URL per se, with adequate getters and setters.
Addon::getUrls() is for people who wish to process all non-empty URLs
occurring as part of the add-on metadata in batch.
Mailing-list discussion:
https://sourceforge.net/p/flightgear/mailman/message/36159711/
- Parsing of the addon-metadata.xml file is now handled by a new static
method of Addon:
static Addon fromAddonDir(const SGPath& addonPath);
This method will be reusable to gather all add-on metadata from a set
of add-on directories (just call the method once per add-on). This
change also simplifies AddonManager::registerAddonMetadata().
- New supported fields:
authors
maintainers
license/{designation,file,url}
url/{home-page,download,support,code-repository}
tags
See
https://sourceforge.net/p/flightgear/fgdata/ci/next/tree/Docs/README.add-ons
for documentation on these fields.
Mailing-list discussion:
around https://sourceforge.net/p/flightgear/mailman/message/36155660/
Move the format-version node inside /meta. It's not compatible of
course, but since the stuff this is breaking is only 2 or 3 days old,
let's go for it for nicer code and file format.
Sorry if you had already written an addon-metadata.xml file of your
own. In this case, just replace:
<format-version type="int">1</format-version>
with:
<meta>
<file-type type="string">FlightGear add-on metadata</file-type>
<format-version type="int">1</format-version>
</meta>
This should fix the following compilation error and other similar ones:
converting to ‘std::tuple<flightgear::AddonVersionSuffixPrereleaseType,
int, bool, int>’ from initializer list would use explicit constructor
‘constexpr std::tuple< <template-parameter-1-1> >::tuple(_UElements&&
...)
According to <https://stackoverflow.com/a/32084829/4756009>, the change
wouldn't be needed in C++14 (and it built fine with my g++) but we use
C++11.
This commit adds C++ classes for add-on management, most notably
AddonManager, Addon and AddonVersion. The AddonManager is used to
register add-ons. It relies on an std::map<std::string, AddonRef> to
hold the metadata of each registered add-on (keys of the std::map are
add-on identifiers, and AddonRef is currently SGSharedPtr<Addon>).
Accessor methods are available for:
- retrieving the list of registered or loaded add-ons (terminology
explained in $FG_ROOT/Docs/README.add-ons);
- checking if a particular add-on has already been registered or
loaded;
- for each add-on, obtaining an Addon instance which can be queried
for its name, id, version, base path, the minimum and maximum
FlightGear versions it requires, its base node in the Property Tree,
its order in the load sequence, short and long description strings,
home page, etc.
The most important metadata is made accessible in the Property Tree
under /addons/by-id/<addon-id> and the property
/addons/by-id/<addon-id>/loaded can be checked or listened to, in
order to determine when a particular add-on is loaded. There is also a
Nasal interface to access add-on metadata in a convenient way.
In order to provide this metadata, each add-on must from now on have in
its base directory a file called 'addon-metadata.xml'.
All this is documented in much more detail in
$FG_ROOT/Docs/README.add-ons.
Mailing-list discussion:
https://sourceforge.net/p/flightgear/mailman/message/36146017/