mirror of
https://github.com/loot/libloot-python.git
synced 2026-07-27 14:14:13 -07:00
Update to libloot v0.14.0
libloot is the renamed LOOT API. This adds a requirement on C++17, and so MSVC 2017 on Windows. pybind11 doesn't provide handling for std::filesystem::path, so wrapper functions are used to perform the necessary one-way conversion without having to expose the complexity on the Python side.
This commit is contained in:
+23
-16
@@ -6,6 +6,10 @@ include(ExternalProject)
|
||||
set(EXTERNAL_PROJECTS_PATH "${CMAKE_BINARY_DIR}/external/src")
|
||||
make_directory(${EXTERNAL_PROJECTS_PATH})
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
##############################
|
||||
# Get Build Revision
|
||||
##############################
|
||||
@@ -50,25 +54,25 @@ add_subdirectory(${PYBIND11_EXTRACTED_PATH})
|
||||
#######################################
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
set(LOOT_API_URL "https://github.com/loot/loot-api/releases/download/0.13.2/loot_api-0.13.2-0-g5956e60_dev-win32.7z")
|
||||
set(LIBLOOT_URL "https://github.com/loot/libloot/releases/download/0.14.0/libloot-0.14.0-0-g2e074a4_dev-win32.7z")
|
||||
else()
|
||||
set(LOOT_API_URL "https://github.com/loot/loot-api/releases/download/0.13.2/loot-api.tar.xz")
|
||||
set(LIBLOOT_URL "https://github.com/loot/libloot/releases/download/0.14.0/libloot.tar.xz")
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(loot-api-c++
|
||||
ExternalProject_Add(libloot
|
||||
PREFIX "external"
|
||||
URL ${LOOT_API_URL}
|
||||
URL ${LIBLOOT_URL}
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
ExternalProject_Get_Property(loot-api-c++ SOURCE_DIR)
|
||||
set(LOOT_API_EXTRACTED_PATH ${SOURCE_DIR})
|
||||
ExternalProject_Get_Property(libloot SOURCE_DIR)
|
||||
set(LIBLOOT_EXTRACTED_PATH ${SOURCE_DIR})
|
||||
|
||||
include_directories("${CMAKE_SOURCE_DIR}/src"
|
||||
"${LOOT_API_EXTRACTED_PATH}/include")
|
||||
link_directories(${LOOT_API_EXTRACTED_PATH})
|
||||
set(LOOT_API_STATIC_LIBRARY "${CMAKE_STATIC_LIBRARY_PREFIX}loot_api${CMAKE_STATIC_LIBRARY_SUFFIX}")
|
||||
set(LOOT_API_SHARED_LIBRARY "${CMAKE_SHARED_LIBRARY_PREFIX}loot_api${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||
"${LIBLOOT_EXTRACTED_PATH}/include")
|
||||
link_directories(${LIBLOOT_EXTRACTED_PATH})
|
||||
set(LIBLOOT_STATIC_LIBRARY "${CMAKE_STATIC_LIBRARY_PREFIX}loot${CMAKE_STATIC_LIBRARY_SUFFIX}")
|
||||
set(LIBLOOT_SHARED_LIBRARY "${CMAKE_SHARED_LIBRARY_PREFIX}loot${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||
|
||||
#######################################
|
||||
# Test Masterlist
|
||||
@@ -85,16 +89,19 @@ ExternalProject_Add(test-masterlist
|
||||
# Python Module
|
||||
#######################################
|
||||
|
||||
# pybind11 v2.1.1 doesn't recognise MSVC as supporting C++17, so force it.
|
||||
add_definitions(-DPYBIND11_CPP17)
|
||||
|
||||
pybind11_add_module(loot_api "${CMAKE_SOURCE_DIR}/src/main.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/convenience.cpp"
|
||||
"${CMAKE_BINARY_DIR}/generated/wrapper_version.cpp")
|
||||
|
||||
add_dependencies(loot_api loot-api-c++ test-masterlist)
|
||||
add_dependencies(loot_api libloot test-masterlist)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
target_link_libraries(loot_api PRIVATE ${LOOT_API_STATIC_LIBRARY})
|
||||
target_link_libraries(loot_api PRIVATE ${LIBLOOT_STATIC_LIBRARY})
|
||||
else()
|
||||
target_link_libraries(loot_api PRIVATE ${LOOT_API_SHARED_LIBRARY})
|
||||
target_link_libraries(loot_api PRIVATE ${LIBLOOT_SHARED_LIBRARY})
|
||||
endif()
|
||||
|
||||
########################################
|
||||
@@ -106,8 +113,8 @@ find_package(PythonInterp REQUIRED)
|
||||
# Copy the API binary to the build directory.
|
||||
add_custom_command(TARGET loot_api POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${LOOT_API_EXTRACTED_PATH}/${LOOT_API_SHARED_LIBRARY}"
|
||||
"$<TARGET_FILE_DIR:loot_api>/${LOOT_API_SHARED_LIBRARY}")
|
||||
"${LIBLOOT_EXTRACTED_PATH}/${LIBLOOT_SHARED_LIBRARY}"
|
||||
"$<TARGET_FILE_DIR:loot_api>/${LIBLOOT_SHARED_LIBRARY}")
|
||||
|
||||
# Copy the test masterlist to the build directory.
|
||||
ExternalProject_Get_Property(test-masterlist SOURCE_DIR)
|
||||
@@ -130,7 +137,7 @@ install(TARGETS loot_api
|
||||
DESTINATION "."
|
||||
CONFIGURATIONS Release RelWithDebInfo)
|
||||
|
||||
install(FILES "${LOOT_API_EXTRACTED_PATH}/${LOOT_API_SHARED_LIBRARY}"
|
||||
install(FILES "${LIBLOOT_EXTRACTED_PATH}/${LIBLOOT_SHARED_LIBRARY}"
|
||||
"${CMAKE_SOURCE_DIR}/docs/README.md"
|
||||
DESTINATION "."
|
||||
CONFIGURATIONS Release RelWithDebInfo)
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
os: Visual Studio 2015
|
||||
os: Visual Studio 2017
|
||||
|
||||
version: "{build}-{branch}"
|
||||
|
||||
@@ -17,7 +17,7 @@ before_build:
|
||||
- cd %APPVEYOR_BUILD_FOLDER%
|
||||
- ps: mkdir build
|
||||
- cd build
|
||||
- cmake .. -G "Visual Studio 14 2015"
|
||||
- cmake .. -G "Visual Studio 15 2017"
|
||||
|
||||
build:
|
||||
verbosity: minimal
|
||||
@@ -54,7 +54,7 @@ deploy:
|
||||
tag: $(APPVEYOR_REPO_TAG_NAME)
|
||||
release: LOOT API Python Module v$(APPVEYOR_REPO_TAG_NAME)
|
||||
description: |
|
||||
Requires Windows 7 or later and the [MSVC 2015 x86 redistributable](https://download.microsoft.com/download/6/A/A/6AA4EDFF-645B-48C5-81CC-ED5963AEAD48/vc_redist.x86.exe), and [7-Zip](http://www.7-zip.org/) to extract the archive.
|
||||
Requires Windows 7 or later and the [MSVC 2017 x86 redistributable](https://download.visualstudio.microsoft.com/download/pr/749aa419-f9e4-4578-a417-a43786af205e/d59197078cc425377be301faba7dd87a/vc_redist.x86.exe), and [7-Zip](http://www.7-zip.org/) to extract the archive.
|
||||
auth_token:
|
||||
secure: yDqT5l/e5MntbW99V6+MHlfFgNv+UIogFfeyUVqtFk5lFRB/dAraLLwKCLl6y+DH
|
||||
artifact: loot_api_python
|
||||
|
||||
+16
-8
@@ -31,21 +31,25 @@ PluginTags GetPluginTags(const std::shared_ptr<DatabaseInterface> db, const std:
|
||||
PluginTags tags;
|
||||
|
||||
auto metadata = db->GetPluginMetadata(plugin, false, evaluateConditions);
|
||||
for (const auto &tag : metadata.GetTags()) {
|
||||
if (metadata.has_value()) {
|
||||
for (const auto &tag : metadata.value().GetTags()) {
|
||||
if (tag.IsAddition())
|
||||
tags.added.insert(tag.GetName());
|
||||
else
|
||||
tags.removed.insert(tag.GetName());
|
||||
}
|
||||
}
|
||||
|
||||
metadata = db->GetPluginUserMetadata(plugin, evaluateConditions);
|
||||
tags.userlist_modified = !metadata.GetTags().empty();
|
||||
for (const auto &tag : metadata.GetTags()) {
|
||||
if (metadata.has_value()) {
|
||||
tags.userlist_modified = !metadata.value().GetTags().empty();
|
||||
for (const auto &tag : metadata.value().GetTags()) {
|
||||
if (tag.IsAddition())
|
||||
tags.added.insert(tag.GetName());
|
||||
else
|
||||
tags.removed.insert(tag.GetName());
|
||||
}
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
@@ -53,21 +57,25 @@ PluginTags GetPluginTags(const std::shared_ptr<DatabaseInterface> db, const std:
|
||||
PluginCleanliness GetPluginCleanliness(const std::shared_ptr<DatabaseInterface> db, const std::string& plugin, bool evaluateConditions) {
|
||||
auto metadata = db->GetPluginMetadata(plugin, true, evaluateConditions);
|
||||
|
||||
if (metadata.GetDirtyInfo().empty()) {
|
||||
if (metadata.GetCleanInfo().empty()) {
|
||||
if (metadata.has_value()) {
|
||||
if (metadata.value().GetDirtyInfo().empty()) {
|
||||
if (metadata.value().GetCleanInfo().empty()) {
|
||||
return PluginCleanliness::unknown;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return PluginCleanliness::clean;
|
||||
}
|
||||
} else if (!metadata.GetCleanInfo().empty()) {
|
||||
}
|
||||
else if (!metadata.value().GetCleanInfo().empty()) {
|
||||
return PluginCleanliness::unknown;
|
||||
}
|
||||
|
||||
for (const auto& info : metadata.GetDirtyInfo()) {
|
||||
for (const auto& info : metadata.value().GetDirtyInfo()) {
|
||||
if (info.ChooseInfo("en").GetText().find("Do not clean") != std::string::npos) {
|
||||
return PluginCleanliness::do_not_clean;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PluginCleanliness::unknown;
|
||||
}
|
||||
|
||||
+30
-6
@@ -34,8 +34,32 @@ using pybind11::arg;
|
||||
using pybind11::enum_;
|
||||
using pybind11::class_;
|
||||
using pybind11::metaclass;
|
||||
using std::filesystem::path;
|
||||
using std::filesystem::u8path;
|
||||
|
||||
namespace loot {
|
||||
namespace py {
|
||||
std::shared_ptr<GameInterface> CreateGameHandle(GameType gameType, std::string gamePath, std::string gameLocalPath) {
|
||||
return CreateGameHandle(gameType, u8path(gamePath), u8path(gameLocalPath));
|
||||
}
|
||||
|
||||
void LoadLists(std::shared_ptr<DatabaseInterface> db, std::string masterlistPath, std::string userlistPath) {
|
||||
return db->LoadLists(u8path(masterlistPath), u8path(userlistPath));
|
||||
}
|
||||
|
||||
void WriteMinimalList(std::shared_ptr<DatabaseInterface> db, std::string outputFile, bool overwrite) {
|
||||
return db->WriteMinimalList(u8path(outputFile), overwrite);
|
||||
}
|
||||
|
||||
bool UpdateMasterlist(std::shared_ptr<DatabaseInterface> db, std::string masterlistPath, std::string remoteUrl, std::string remoteBranch) {
|
||||
return db->UpdateMasterlist(u8path(masterlistPath), remoteUrl, remoteBranch);
|
||||
}
|
||||
|
||||
MasterlistInfo GetMasterlistRevision(std::shared_ptr<DatabaseInterface> db, std::string masterlistPath, bool getShortId) {
|
||||
return db->GetMasterlistRevision(u8path(masterlistPath), getShortId);
|
||||
}
|
||||
}
|
||||
|
||||
void bindEnums(pybind11::module& module) {
|
||||
enum_<GameType>(module, "GameType")
|
||||
.value("tes4", GameType::tes4)
|
||||
@@ -94,7 +118,7 @@ void bindVersionClasses(pybind11::module& module) {
|
||||
.def_readonly_static("minor", &LootVersion::minor)
|
||||
.def_readonly_static("patch", &LootVersion::patch)
|
||||
.def_readonly_static("revision", &LootVersion::revision)
|
||||
.def_static("string", LootVersion::string);
|
||||
.def_static("string", LootVersion::GetVersionString);
|
||||
|
||||
class_<WrapperVersion>(module, "WrapperVersion")
|
||||
.def_readonly_static("major", &WrapperVersion::major)
|
||||
@@ -110,9 +134,9 @@ void bindInterfaceClasses(pybind11::module& module) {
|
||||
.def("get_database", &GameInterface::GetDatabase);
|
||||
|
||||
class_<DatabaseInterface, std::shared_ptr<DatabaseInterface>>(module, "DatabaseInterface")
|
||||
.def("load_lists", &DatabaseInterface::LoadLists, arg("masterlist_path"), arg("userlist_path") = "")
|
||||
.def("update_masterlist", &DatabaseInterface::UpdateMasterlist)
|
||||
.def("get_masterlist_revision", &DatabaseInterface::GetMasterlistRevision)
|
||||
.def("load_lists", &py::LoadLists, arg("masterlist_path"), arg("userlist_path") = "")
|
||||
.def("update_masterlist", &py::UpdateMasterlist)
|
||||
.def("get_masterlist_revision", &py::GetMasterlistRevision)
|
||||
.def("get_plugin_metadata", &DatabaseInterface::GetPluginMetadata,
|
||||
arg("plugin"),
|
||||
arg("includeUserMetadata") = true,
|
||||
@@ -123,7 +147,7 @@ void bindInterfaceClasses(pybind11::module& module) {
|
||||
.def("get_plugin_cleanliness", &GetPluginCleanliness,
|
||||
arg("plugin"),
|
||||
arg("evaluateConditions") = false)
|
||||
.def("write_minimal_list", &DatabaseInterface::WriteMinimalList);
|
||||
.def("write_minimal_list", &py::WriteMinimalList);
|
||||
}
|
||||
|
||||
void bindClasses(pybind11::module& module) {
|
||||
@@ -139,7 +163,7 @@ void bindFunctions(pybind11::module& module) {
|
||||
|
||||
module.def("initialise_locale", &InitialiseLocale, arg("id") = "");
|
||||
|
||||
module.def("create_game_handle", &CreateGameHandle,
|
||||
module.def("create_game_handle", &py::CreateGameHandle,
|
||||
arg("game"),
|
||||
arg("game_path"),
|
||||
arg("game_local_path") = "");
|
||||
|
||||
+4
-4
@@ -40,14 +40,14 @@ class GameFixture(unittest.TestCase):
|
||||
class TestLootApi(GameFixture):
|
||||
def test_is_compatible(self):
|
||||
self.assertFalse(is_compatible(0, 9, 0))
|
||||
self.assertTrue(is_compatible(0, 13, 0))
|
||||
self.assertTrue(is_compatible(0, 14, 0))
|
||||
|
||||
def test_version(self):
|
||||
self.assertEqual(Version.major, 0)
|
||||
self.assertEqual(Version.minor, 13)
|
||||
self.assertEqual(Version.patch, 2)
|
||||
self.assertEqual(Version.minor, 14)
|
||||
self.assertEqual(Version.patch, 0)
|
||||
self.assertNotEqual(Version.revision, u'')
|
||||
self.assertEqual(Version.string(), "0.13.2")
|
||||
self.assertEqual(Version.string(), "0.14.0")
|
||||
|
||||
def test_wrapper_version(self):
|
||||
self.assertEqual(WrapperVersion.major, 3)
|
||||
|
||||
Reference in New Issue
Block a user