Add SceneLicense information to the Scene

Add documentation generator to SceneLicense
This commit is contained in:
Alexander Bock
2017-10-23 18:02:27 -07:00
parent 35d87402b7
commit eaca6c7487
19 changed files with 472 additions and 16 deletions
+4
View File
@@ -132,6 +132,8 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/scene/scene.cpp
${OPENSPACE_BASE_DIR}/src/scene/scene_doc.inl
${OPENSPACE_BASE_DIR}/src/scene/scene_lua.inl
${OPENSPACE_BASE_DIR}/src/scene/scenelicense.cpp
${OPENSPACE_BASE_DIR}/src/scene/scenelicensewriter.cpp
${OPENSPACE_BASE_DIR}/src/scene/sceneloader.cpp
${OPENSPACE_BASE_DIR}/src/scene/scenemanager.cpp
${OPENSPACE_BASE_DIR}/src/scene/scenegraphnode.cpp
@@ -286,6 +288,8 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/scene/rotation.h
${OPENSPACE_BASE_DIR}/include/openspace/scene/scale.h
${OPENSPACE_BASE_DIR}/include/openspace/scene/scene.h
${OPENSPACE_BASE_DIR}/include/openspace/scene/scenelicense.h
${OPENSPACE_BASE_DIR}/include/openspace/scene/scenelicensewriter.h
${OPENSPACE_BASE_DIR}/include/openspace/scene/sceneloader.h
${OPENSPACE_BASE_DIR}/include/openspace/scene/scenemanager.h
${OPENSPACE_BASE_DIR}/include/openspace/scene/scenegraphnode.h
@@ -30,6 +30,8 @@
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/misc/invariants.h>
#include <ghoul/logging/logmanager.h>
#include <fstream>
namespace {
@@ -158,6 +160,12 @@ std::string escapedJson(const std::string& text) {
case '\\':
jsonString += "\\\\";
break;
case '\n':
jsonString += "\\\\n";
break;
case '\r':
jsonString += "\\r";
break;
default:
jsonString += c;
}
+1
View File
@@ -58,6 +58,7 @@ const string ConfigurationManager::KeyPropertyDocumentation = "PropertyDocumenta
const string ConfigurationManager::KeyKeyboardShortcuts = "KeyboardShortcuts";
const string ConfigurationManager::KeyDocumentation = "Documentation";
const string ConfigurationManager::KeyFactoryDocumentation = "FactoryDocumentation";
const string ConfigurationManager::KeySceneLicenseDocumentation = "LicenseDocumentation";
const string ConfigurationManager::KeyConfigScene = "Scene";
const string ConfigurationManager::KeyConfigTasksRoot = "TasksRoot";
+8
View File
@@ -200,6 +200,14 @@ documentation::Documentation ConfigurationManager::Documentation() {
"created in the current application configuration. Any previous file in this "
"location will be silently overritten."
},
{
ConfigurationManager::KeySceneLicenseDocumentation,
new StringVerifier,
Optional::Yes,
"The file that will be created on startup containing the scene license "
"information. Any previous file in this location will be silently "
"overwritten."
},
{
ConfigurationManager::KeyLauncher,
new TableVerifier({
+10
View File
@@ -48,6 +48,7 @@
#include <openspace/scene/scene.h>
#include <openspace/scene/rotation.h>
#include <openspace/scene/scale.h>
#include <openspace/scene/scenelicense.h>
#include <openspace/scene/translation.h>
#include <openspace/scene/scenemanager.h>
@@ -645,6 +646,15 @@ void OpenSpaceEngine::loadScene(const std::string& scenePath) {
);
}
if (configurationManager().hasKey(ConfigurationManager::KeySceneLicenseDocumentation))
{
scene->writeSceneLicenseDocumentation(
absPath(configurationManager().value<std::string>(
ConfigurationManager::KeySceneLicenseDocumentation
))
);
}
// If a PropertyDocumentationFile was specified, generate it now.
if (configurationManager().hasKey(ConfigurationManager::KeyPropertyDocumentation)) {
scene->writeDocumentation(
+1 -1
View File
@@ -138,7 +138,7 @@ std::string KeyBindingManager::generateJson() const {
}
return jsonString;
}
}
scripting::LuaLibrary KeyBindingManager::luaLibrary() {
return {
+9
View File
@@ -139,6 +139,10 @@ void Scene::removeNode(SceneGraphNode* node, UpdateDependencies updateDeps) {
}
}
void Scene::addSceneLicense(SceneLicense license) {
_licenses.push_back(std::move(license));
}
void Scene::updateDependencies() {
sortTopologically();
}
@@ -272,6 +276,11 @@ const std::vector<SceneGraphNode*>& Scene::allSceneGraphNodes() const {
return _topologicallySortedNodes;
}
void Scene::writeSceneLicenseDocumentation(const std::string& path) const {
SceneLicenseWriter writer(_licenses);
writer.writeDocumentation(path);
}
std::string Scene::generateJson() const {
std::function<std::string(properties::PropertyOwner*)> createJson =
[&createJson](properties::PropertyOwner* owner) -> std::string
+94
View File
@@ -0,0 +1,94 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2017 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/scene/scenelicense.h>
#include <openspace/openspace.h>
#include <openspace/documentation/verifier.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/misc/assert.h>
#include <ghoul/misc/dictionary.h>
#include <fstream>
#include <sstream>
namespace {
const char* LicenseKeyName = "Name";
const char* LicenseKeyAttribution = "Attribution";
const char* LicenseKeyUrl = "URL";
const char* LicenseKeyLicenseText = "License";
} // namespace
namespace openspace {
documentation::Documentation SceneLicense::Documentation() {
using namespace documentation;
return {
"License Information",
"core_license",
{
{
LicenseKeyName,
new StringVerifier,
Optional::No,
"A short, descriptive name for the license employed for this node."
},
{
LicenseKeyAttribution,
new StringVerifier,
Optional::No,
"The organization that shall be attributed to the licensed content."
},
{
LicenseKeyUrl,
new StringVerifier,
Optional::Yes,
"The URL pointing to the original license."
},
{
LicenseKeyLicenseText,
new StringVerifier,
Optional::No,
"The full text of the license agreements."
}
}
};
}
SceneLicense::SceneLicense(const ghoul::Dictionary& dictionary, std::string m)
: module(std::move(m))
{
ghoul_assert(!module.empty(), "Module name must not be empty");
documentation::testSpecificationAndThrow(Documentation(), dictionary, "SceneLicense");
name = dictionary.value<std::string>(LicenseKeyName);
attribution = dictionary.value<std::string>(LicenseKeyAttribution);
dictionary.getValue(LicenseKeyUrl, url);
licenseText = dictionary.value<std::string>(LicenseKeyLicenseText);
}
} // namespace openspace
+82
View File
@@ -0,0 +1,82 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2017 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/scene/scenelicensewriter.h>
#include <sstream>
namespace {
const char* MainTemplateFilename = "${OPENSPACE_DATA}/web/scenelicense/main.hbs";
const char* SceneLicenseTemplateFilename = "${OPENSPACE_DATA}/web/scenelicense/scenelicense.hbs";
const char* JsFilename = "${OPENSPACE_DATA}/web/scenelicense/script.js";
} // namespace
namespace openspace {
SceneLicenseWriter::SceneLicenseWriter(const std::vector<SceneLicense>& licenses)
: DocumentationGenerator(
"Documentation",
"sceneLicenses",
{
{ "sceneLicenseTemplate", SceneLicenseTemplateFilename },
{ "mainTemplate", MainTemplateFilename }
},
JsFilename
)
, _licenses(licenses)
{}
std::string SceneLicenseWriter::generateJson() const {
std::stringstream json;
json << "[";
for (const SceneLicense& license : _licenses) {
json << "{";
json << "\"module\": \"" << escapedJson(license.module) << "\", ";
json << "\"name\": \"" << escapedJson(license.name) << "\", ";
json << "\"attribution\": \"" << escapedJson(license.attribution) << "\", ";
json << "\"url\": \"" << escapedJson(license.url) << "\", ";
json << "\"licenseText\": \"" << escapedJson(license.licenseText) << "\"";
json << "}";
if (&license != &(_licenses.back())) {
json << ",";
}
}
json << "]";
std::string jsonString = "";
for (const char& c : json.str()) {
if (c == '\'') {
jsonString += "\\'";
} else {
jsonString += c;
}
}
return jsonString;
}
} // namespace openspace
+66 -12
View File
@@ -40,6 +40,7 @@ namespace {
const char* KeyPathScene = "ScenePath";
const char* KeyModules = "Modules";
const char* ModuleExtension = ".mod";
const char* LicenseExtension = ".license";
//const char* KeyPathModule = "ModulePath";
//const char* RootNodeName = "Root";
@@ -97,6 +98,7 @@ std::unique_ptr<Scene> SceneLoader::loadScene(const std::string& path) {
std::vector<std::string> keys = moduleDictionary.keys();
std::vector<SceneLoader::LoadedNode> allNodes;
std::vector<SceneLicense> allLicenses;
{
// Inside loadDirectory the working directory is changed (for now), so we need
@@ -112,8 +114,19 @@ std::unique_ptr<Scene> SceneLoader::loadScene(const std::string& path) {
std::replace(fullName.begin(), fullName.end(), '/', FileSys.PathSeparator);
std::string path = FileSys.pathByAppendingComponent(modulesPath, fullName);
std::vector<SceneLoader::LoadedNode> nodes = loadDirectory(path, state);
std::move(nodes.begin(), nodes.end(), std::back_inserter(allNodes));
std::pair<std::vector<SceneLoader::LoadedNode>, std::vector<SceneLicense>>
nodes = loadDirectory(path, state);
std::move(
nodes.first.begin(),
nodes.first.end(),
std::back_inserter(allNodes)
);
std::move(
nodes.second.begin(),
nodes.second.end(),
std::back_inserter(allLicenses)
);
}
}
@@ -125,6 +138,10 @@ std::unique_ptr<Scene> SceneLoader::loadScene(const std::string& path) {
addLoadedNodes(*scene, std::move(allNodes));
for (SceneLicense& l : allLicenses) {
scene->addSceneLicense(std::move(l));
}
ghoul::Dictionary cameraDictionary;
sceneDictionary.getValue(KeyCamera, cameraDictionary);
LoadedCamera loadedCamera = loadCamera(cameraDictionary);
@@ -145,7 +162,8 @@ std::unique_ptr<Scene> SceneLoader::loadScene(const std::string& path) {
return scene;
}
std::vector<SceneGraphNode*> SceneLoader::importDirectory(Scene& scene, const std::string& path) {
std::pair<std::vector<SceneGraphNode*>, std::vector<SceneLicense>>
SceneLoader::importDirectory(Scene& scene, const std::string& path) {
lua_State* state = ghoul::lua::createNewLuaState();
OnExit(
// Delete the Lua state at the end of the scope, no matter what.
@@ -156,9 +174,11 @@ std::vector<SceneGraphNode*> SceneLoader::importDirectory(Scene& scene, const st
std::string absDirectoryPath = absPath(path);
ghoul::filesystem::Directory oldDirectory = FileSys.currentDirectory();
std::vector<SceneLoader::LoadedNode> nodes = loadDirectory(path, state);
std::pair<std::vector<SceneLoader::LoadedNode>, std::vector<SceneLicense>>
nodes = loadDirectory(path, state);
FileSys.setCurrentDirectory(oldDirectory);
return addLoadedNodes(scene, std::move(nodes));
return { addLoadedNodes(scene, std::move(nodes.first)), nodes.second };
}
SceneGraphNode* SceneLoader::importNodeDictionary(Scene& scene, const ghoul::Dictionary& dict) {
@@ -198,14 +218,15 @@ SceneLoader::LoadedCamera SceneLoader::loadCamera(const ghoul::Dictionary& camer
}
std::vector<SceneLoader::LoadedNode> SceneLoader::loadDirectory(
std::pair<std::vector<SceneLoader::LoadedNode>, std::vector<SceneLicense>>
SceneLoader::loadDirectory(
const std::string& path,
lua_State* luaState)
{
std::string::size_type pos = path.find_last_of(FileSys.PathSeparator);
if (pos == std::string::npos) {
LERROR("Error parsing directory name '" << path << "'");
return std::vector<SceneLoader::LoadedNode>();
return {};
}
std::string moduleName = path.substr(pos + 1);
std::string moduleFile = FileSys.pathByAppendingComponent(path, moduleName) + ModuleExtension;
@@ -218,9 +239,18 @@ std::vector<SceneLoader::LoadedNode> SceneLoader::loadDirectory(
FileSys.setCurrentDirectory(ghoul::filesystem::Directory(path));
// We have a module file, so it is a direct include.
return loadModule(moduleFile, luaState);
std::vector<SceneLoader::LoadedNode> nodes = loadModule(moduleFile, luaState);
std::vector<SceneLicense> licenses;
std::string licenseFile = FileSys.pathByAppendingComponent(path, moduleName) + LicenseExtension;
if (FileSys.fileExists(licenseFile)) {
licenses = loadLicense(licenseFile, moduleName);
}
return { std::move(nodes), licenses };
} else {
std::vector<SceneLoader::LoadedNode> allLoadedNodes;
std::vector<SceneLicense> allLicenses;
// If we do not have a module file, we have to include all subdirectories.
using ghoul::filesystem::Directory;
using std::string;
@@ -230,14 +260,25 @@ std::vector<SceneLoader::LoadedNode> SceneLoader::loadDirectory(
if (!FileSys.directoryExists(directoryPath)) {
LERROR("The directory " << directoryPath << " does not exist.");
return std::vector<SceneLoader::LoadedNode>();
return {};
}
for (const string& subdirectory : directory.readDirectories()) {
std::vector<SceneLoader::LoadedNode> loadedNodes = loadDirectory(subdirectory, luaState);
std::move(loadedNodes.begin(), loadedNodes.end(), std::back_inserter(allLoadedNodes));
std::pair<std::vector<SceneLoader::LoadedNode>, std::vector<SceneLicense>>
loadedNodes = loadDirectory(subdirectory, luaState);
std::move(
loadedNodes.first.begin(),
loadedNodes.first.end(),
std::back_inserter(allLoadedNodes)
);
std::move(
loadedNodes.second.begin(),
loadedNodes.second.end(),
std::back_inserter(allLicenses)
);
}
return allLoadedNodes;
return { std::move(allLoadedNodes), std::move(allLicenses) };
}
}
@@ -309,6 +350,19 @@ std::vector<SceneLoader::LoadedNode> SceneLoader::loadModule(const std::string&
return loadedNodes;
}
std::vector<SceneLicense> SceneLoader::loadLicense(const std::string& path, std::string module) {
ghoul::Dictionary licenseDictionary;
try {
ghoul::lua::loadDictionaryFromFile(path, licenseDictionary);
} catch (const ghoul::lua::LuaRuntimeException& e) {
LERRORC(e.component, e.message);
return {};
}
SceneLicense license(licenseDictionary, module);
return { license };
}
std::vector<SceneGraphNode*> SceneLoader::addLoadedNodes(Scene& scene, std::vector<SceneLoader::LoadedNode>&& loadedNodes) {
std::map<std::string, SceneGraphNode*> existingNodes = scene.nodesByName();
std::map<std::string, SceneGraphNode*> addedNodes;