diff options
-rw-r--r-- | CMakeLists.txt | 12 | ||||
-rw-r--r-- | config.h.in | 30 | ||||
-rw-r--r-- | src/plugins/filesystem/FileLocator.cpp | 128 | ||||
-rw-r--r-- | src/plugins/filesystem/FileLocator.hpp | 51 | ||||
-rw-r--r-- | src/plugins/filesystem/SpecialPaths.cpp | 67 | ||||
-rw-r--r-- | src/plugins/filesystem/SpecialPaths.hpp | 83 | ||||
-rw-r--r-- | test/plugins/filesystem/FileLocatorTest.cpp | 4 |
7 files changed, 342 insertions, 33 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index b30e3f4..2d19b18 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,6 +81,18 @@ IF(TEST) ENDIF() ################################################################################ +# Commands for assembling and including the configuration file # +################################################################################ + +CONFIGURE_FILE( + "${PROJECT_SOURCE_DIR}/config.h.in" + "${PROJECT_BINARY_DIR}/config.h" +) + +# Adapt the include path for finding the configuration file +INCLUDE_DIRECTORIES("${PROJECT_BINARY_DIR}") + +################################################################################ # Commands for building Ousía # ################################################################################ diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..7df0a2c --- /dev/null +++ b/config.h.in @@ -0,0 +1,30 @@ +/* + Ousía + Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _OUSIA_CONFIG_H_ +#define _OUSIA_CONFIG_H_ + +#ifndef NDEBUG +#define OUSIA_DEBUG_DIR "@PROJECT_SOURCE_DIR@" +#else +#define OUSIA_DEBUG_DIR "" +#endif +#define OUSIA_INSTALL_DATA_DIR "@CMAKE_INSTALL_PREFIX@/share/ousia" + +#endif /* _OUSIA_CONFIG_H_ */ + diff --git a/src/plugins/filesystem/FileLocator.cpp b/src/plugins/filesystem/FileLocator.cpp index 9ab398e..7bb3a58 100644 --- a/src/plugins/filesystem/FileLocator.cpp +++ b/src/plugins/filesystem/FileLocator.cpp @@ -16,64 +16,140 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "FileLocator.hpp" +#ifndef NDEBUG +#include <iostream> +#endif + +#include <algorithm> +#include <fstream> #include <boost/filesystem.hpp> -#include <fstream> +#include "FileLocator.hpp" +#include "SpecialPaths.hpp" + +namespace fs = boost::filesystem; namespace ousia { +void FileLocator::addPath(const std::string &path, + std::vector<std::string> &paths) +{ + auto it = std::find(paths.begin(), paths.end(), path); + if (it == paths.end()) { + paths.push_back(path); + } +} + void FileLocator::addSearchPath(const std::string &path, std::set<ResourceType> types) { - // Canonicalize the given path - std::string canonicalPath = - boost::filesystem::canonical(path).generic_string(); + if (path.empty() || !fs::exists(path)) { + return; + } + + // Canonicalize the given path, check whether it exists + std::string canonicalPath = fs::canonical(path).generic_string(); + +#ifndef NDEBUG + std::cout << "FileLocator: Adding search path " << canonicalPath + << std::endl; +#endif // Insert the path for all given types. for (auto &type : types) { auto it = searchPaths.find(type); if (it != searchPaths.end()) { - it->second.push_back(canonicalPath); + addPath(canonicalPath, it->second); } else { searchPaths.insert({type, {canonicalPath}}); } } } +void FileLocator::addSearchPath(const std::string &path, ResourceType type) +{ + addSearchPath(path, std::set<ResourceType>{type}); +} + +void FileLocator::addDefaultSearchPaths(const std::string &relativeTo) +{ + // Abort if the base directory is empty + if (relativeTo.empty()) { + return; + } + + // Abort if the base directory does not exist or is not a directory + fs::path base(relativeTo); + if (!fs::exists(base) || !fs::is_directory(base)) { + return; + } + + // Add the search paths + addSearchPath(base.generic_string(), ResourceType::UNKNOWN); + addSearchPath((base / "domain").generic_string(), + ResourceType::DOMAIN_DESC); + addSearchPath((base / "typesystem").generic_string(), + ResourceType::TYPESYSTEM); +} + +void FileLocator::addDefaultSearchPaths() +{ + addDefaultSearchPaths(SpecialPaths::getGlobalDataDir()); + addDefaultSearchPaths(SpecialPaths::getLocalDataDir()); +#ifndef NDEBUG + addDefaultSearchPaths(SpecialPaths::getDebugDataDir()); + addDefaultSearchPaths(SpecialPaths::getDebugTestdataDir()); +#endif +} + bool FileLocator::doLocate(Resource &resource, const std::string &path, const ResourceType type, const std::string &relativeTo) const { - boost::filesystem::path base(relativeTo); - if (boost::filesystem::exists(base)) { - // Look if 'relativeTo' is a directory already. - if (!boost::filesystem::is_directory(base)) { - // If not we use the parent directory. - base = base.parent_path(); - } + if (!relativeTo.empty()) { + fs::path base(relativeTo); + if (fs::exists(base)) { + // Look if 'relativeTo' is a directory already. + if (!fs::is_directory(base)) { + // If not we use the parent directory. + base = base.parent_path(); + } - // Use the / operator to append the path. - base /= path; + // Use the / operator to append the path. + base /= path; - // If we already found a fitting resource there, use that. - if (boost::filesystem::exists(base)) { - std::string location = - boost::filesystem::canonical(base).generic_string(); - resource = Resource(true, *this, type, location); - return true; + // If we already found a fitting resource there, use that. + if (fs::exists(base)) { + std::string location = fs::canonical(base).generic_string(); +#ifndef NDEBUG + std::cout << "FileLocator: Found \"" << path << "\" at " + << location << std::endl; +#endif + resource = Resource(true, *this, type, location); + return true; + } } } - // Otherwise look in the search paths. + // Otherwise look in the search paths, search backwards, last defined search + // paths have a higher precedence auto it = searchPaths.find(type); if (it != searchPaths.end()) { - for (boost::filesystem::path p : it->second) { + const auto &paths = it->second; + for (auto it = paths.rbegin(); it != paths.rend(); it++) { +#ifndef NDEBUG + std::cout << "FileLocator: Searching for \"" << path << "\" in " + << *it << std::endl; +#endif + fs::path p{*it}; p /= path; - if (boost::filesystem::exists(p)) { - std::string location = - boost::filesystem::canonical(p).generic_string(); + if (fs::exists(p)) { + std::string location = fs::canonical(p).generic_string(); +#ifndef NDEBUG + std::cout << "FileLocator: Found \"" << path << "\" at " + << location << std::endl; +#endif resource = Resource(true, *this, type, location); return true; } diff --git a/src/plugins/filesystem/FileLocator.hpp b/src/plugins/filesystem/FileLocator.hpp index ffe5c8f..6d3bbf0 100644 --- a/src/plugins/filesystem/FileLocator.hpp +++ b/src/plugins/filesystem/FileLocator.hpp @@ -16,6 +16,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/** + * @file FileLocator.hpp + * + * Contains the FileLocator class which is used to locate resources and to + * canonicalize file system paths. + * + * @author Benjamin Paaßen (bpassen@techfak.uni-bielefeld.de) + */ + #ifndef _OUSIA_FILE_LOCATOR_HPP_ #define _OUSIA_FILE_LOCATOR_HPP_ @@ -39,7 +48,7 @@ namespace ousia { class FileLocator : public ResourceLocator { public: /** - * Type alias representing a Res + * Type alias representing the internal search path list. */ using SearchPaths = std::map<ResourceType, std::vector<std::string>>; @@ -49,6 +58,25 @@ private: */ SearchPaths searchPaths; + /** + * Internally used to add a search path to the given vector without + * duplications. + * + * @parm path is the path that should be added to the vector (must be + * canonicalized). + * @parm paths is the list to which the path should be added. + */ + void addPath(const std::string &path, std::vector<std::string> &paths); + + /** + * Internally used to add the default search paths for various resource + * types relative to a certain parent directory. + * + * @param relativeTo is the base directory relative to which the search + * paths ought to be setup. + */ + void addDefaultSearchPaths(const std::string &relativeTo); + protected: bool doLocate(Resource &resource, const std::string &path, const ResourceType type, @@ -74,11 +102,24 @@ public: * Adds a search path. Implicitly adds the search path for the "unknown" * * @param path is a fully qualified/canonical path to a directory. - * @param types is a set of Resource Types. The FileLocator will look for - * resources of the specified types at the given path in the - * future. + * @param type is a single type for which the path should be added. + */ + void addSearchPath(const std::string &path, + ResourceType type = ResourceType::UNKNOWN); + + /** + * Adds platform-specific default search paths. These include + * (in order of their precedence): + * <ul> + * <li>The user application data directory (~/.local/share/ousia/ on + * UNIX)</li> + * <li>The global application data directory used for make install + * (default is /usr/local/share on UNIX)</li> + * </ul> + * Resource type specific subdirectories (domain, typesytem, etc.) + * are automatically added to the aforementioned paths. */ - void addSearchPath(const std::string &path); + void addDefaultSearchPaths(); /** * Returns the backing map containing all search paths for a given type. diff --git a/src/plugins/filesystem/SpecialPaths.cpp b/src/plugins/filesystem/SpecialPaths.cpp new file mode 100644 index 0000000..97bdb9c --- /dev/null +++ b/src/plugins/filesystem/SpecialPaths.cpp @@ -0,0 +1,67 @@ +/* + Ousía + Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <cstdlib> +#include <boost/filesystem.hpp> + +#include <config.h> + +#include "SpecialPaths.hpp" + +namespace fs = boost::filesystem; + +namespace ousia { + +std::string SpecialPaths::getHomeDir() +{ + char *home = getenv("HOME"); + if (home) { + return std::string{home}; + } + return std::string{}; +} + +std::string SpecialPaths::getGlobalDataDir() +{ + return OUSIA_INSTALL_DATA_DIR; +} + +std::string SpecialPaths::getLocalDataDir() +{ + std::string home = getHomeDir(); + if (!home.empty()) { + fs::path homePath{home}; + return (homePath / ".local/share/ousia").generic_string(); + } + return std::string{}; +} + +std::string SpecialPaths::getDebugDataDir() +{ + fs::path debug{OUSIA_DEBUG_DIR}; + return (debug / "data").generic_string(); +} + +std::string SpecialPaths::getDebugTestdataDir() +{ + fs::path debug{OUSIA_DEBUG_DIR}; + return (debug / "testdata").generic_string(); +} + +} + diff --git a/src/plugins/filesystem/SpecialPaths.hpp b/src/plugins/filesystem/SpecialPaths.hpp new file mode 100644 index 0000000..84524fe --- /dev/null +++ b/src/plugins/filesystem/SpecialPaths.hpp @@ -0,0 +1,83 @@ +/* + Ousía + Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/** + * @file SpecialPaths.hpp + * + * Access to platform specific special paths. + * + * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) + */ + +#ifndef _OUSIA_SPECIAL_PATHS_HPP_ +#define _OUSIA_SPECIAL_PATHS_HPP_ + +#include <string> + +namespace ousia { + +/** + * Class containing static functions providing access to special paths. + */ +class SpecialPaths { +public: + /** + * Returns the home directory of the current user or an empty string if the + * functionality is not available. + * + * @return path to the home director or empty string on failure. + */ + static std::string getHomeDir(); + + /** + * Returns the global application data directory (e.g. /usr/share/ousia on + * unix). + * + * @return path to the installation data directory, empty string on failure. + */ + static std::string getGlobalDataDir(); + + /** + * Returns the local application data directory (e.g. + * /home/usre/.local/share/ousia on unix). + * + * @return path to the local data directory, empty string on failure. + */ + static std::string getLocalDataDir(); + + /** + * Returns the path to the application data when running a debug build. + * + * @return path to the application data when running a debug build. Returns + * an empty string otherwise. + */ + static std::string getDebugDataDir(); + + /** + * Returns the path to the test data when running a debug build with enabled + * tests. + * + * @return path to the test data when running a debug build, Returns an + * empty string otherwise. + */ + static std::string getDebugTestdataDir(); +}; +} + +#endif /* _OUSIA_SPECIAL_PATHS_HPP_ */ + diff --git a/test/plugins/filesystem/FileLocatorTest.cpp b/test/plugins/filesystem/FileLocatorTest.cpp index 473b15e..056d05e 100644 --- a/test/plugins/filesystem/FileLocatorTest.cpp +++ b/test/plugins/filesystem/FileLocatorTest.cpp @@ -18,7 +18,7 @@ #include <gtest/gtest.h> -#include <plugins/boost/FileLocator.hpp> +#include <plugins/filesystem/FileLocator.hpp> #include <boost/filesystem.hpp> @@ -114,7 +114,7 @@ TEST(FileLocator, testLocate) assert_not_located(instance, "FileLocator.hpp", relativeTo); // Add the respective search path. - instance.addSearchPath((start / "src/plugins/boost").generic_string(), + instance.addSearchPath((start / "src/plugins/filesystem").generic_string(), {ResourceType::DOMAIN_DESC}); // Now we should be able to find both. assert_located(instance, "CMakeLists.txt", relativeTo); |