Move to VCPKG.

* Remove SConscript related files.
* Update for libbsarch.
* Force-load translations from uibase and gamebryo/creation.
* Set option to use deprecated uibase include paths.
* Bring githubpp here and add a standalone preset.
* Full standalone build.
This commit is contained in:
Mikaël Capelle
2024-10-20 11:57:37 +02:00
parent 61ef16d08d
commit bb4f3fd74b
30 changed files with 644 additions and 3812 deletions
+39 -7
View File
@@ -6,15 +6,47 @@ on:
pull_request:
types: [opened, synchronize, reopened]
env:
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
jobs:
build:
runs-on: windows-2022
steps:
- name: Build ModOrganizer 2
uses: ModOrganizer2/build-with-mob-action@master
# https://learn.microsoft.com/en-us/vcpkg/consume/binary-caching-github-actions-cache
- name: Export GitHub Actions cache environment variables
uses: actions/github-script@v7
with:
qt-modules: qtpositioning qtwebchannel qtwebengine qtwebsockets
mo2-third-parties:
7z zlib gtest libbsarch libloot openssl bzip2 python lz4 spdlog
boost boost-di sip pyqt pybind11 ss licenses explorerpp DirectXTex
mo2-dependencies: usvfs cmake_common uibase githubpp bsatk esptk archive lootcli game_gamebryo
script: |
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
- name: Install Qt
uses: jurplel/install-qt-action@v3
with:
version: 6.7.0
modules:
cache: true
- uses: actions/checkout@v4
- name: "Set environmental variables"
shell: bash
run: |
echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV
- name: Configure ModOrganizer
shell: pwsh
run: |
cmake --preset vs2022-windows-standalone `
"-DCMAKE_PREFIX_PATH=${env:QT_ROOT_DIR}\msvc2019_64" `
"-DCMAKE_INSTALL_PREFIX=install"
- name: Build ModOrganizer
run: cmake --build vsbuild --config RelWithDebInfo --target INSTALL
- name: Package ModOrganizer
uses: actions/upload-artifact@master
with:
name: modorganizer
path: ./install
-46
View File
@@ -1,46 +0,0 @@
syntax: glob
scons_configure.py
scons-ModOrganizer-*
ModOrganizer-build-desktop*
outputd/*
output/*
build-ModOrganizer-*
source/NCC/*/bin
source/NCC/*/obj
source/NCC/bin
*.orig
source/plugins/proxyPython/build
staging/*
source - Copy/*
ModOrganizer-build-*
pdbs/*
source/NCC/BossDummy.x/*
*.ts
staging_prepare/*
staging_trans/*
tools/python_zip/*
Makefile
html
*.vcxproj
*.pdb
*.dll
*.exp
*.tlog
*.user
*.obj
*.suo
*.sln
*.log
*.filters
*.lib
source/organizer/resources/contents/icons
source/plugins/build-*
*/GeneratedFiles/*
translations/*
source/LocalPaths.pri
source/*/Win32/Debug/*
source/plugins/*/Win32/Debug/*
*~
syntax: regexp
Makefile\.(Debug|Release)
source/.*/debug/.*
+15 -10
View File
@@ -1,16 +1,21 @@
cmake_minimum_required(VERSION 3.16)
# TODO: move these to cmake_common?
set(OPENSSL_USE_STATIC_LIBS FALSE CACHE STRING "" FORCE)
set(MySQL_INCLUDE_DIRS CACHE STRING "" FORCE)
if(DEFINED DEPENDENCIES_DIR)
include(${DEPENDENCIES_DIR}/modorganizer_super/cmake_common/mo2.cmake)
else()
include(${CMAKE_CURRENT_LIST_DIR}/../cmake_common/mo2.cmake)
endif()
# TODO: clean include directives
set(MO2_CMAKE_DEPRECATED_UIBASE_INCLUDE ON)
project(organizer)
# if MO2_INSTALL_IS_BIN is set, this means that we should install directly into the
# installation prefix, without the bin/ subfolder, typically for a standalone build
# to update an existing install
if (MO2_INSTALL_IS_BIN)
set(_bin ".")
else()
set(_bin bin)
endif()
add_subdirectory(src)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dump_running_process.bat DESTINATION bin)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT organizer)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dump_running_process.bat DESTINATION ${_bin})
+59
View File
@@ -0,0 +1,59 @@
{
"configurePresets": [
{
"errors": {
"deprecated": true
},
"hidden": true,
"name": "cmake-dev",
"warnings": {
"deprecated": true,
"dev": true
}
},
{
"cacheVariables": {
"VCPKG_MANIFEST_NO_DEFAULT_FEATURES": {
"type": "BOOL",
"value": "ON"
}
},
"toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"hidden": true,
"name": "vcpkg"
},
{
"binaryDir": "${sourceDir}/vsbuild",
"architecture": {
"strategy": "set",
"value": "x64"
},
"cacheVariables": {
"CMAKE_CXX_FLAGS": "/EHsc /MP /W4",
"VCPKG_TARGET_TRIPLET": {
"type": "STRING",
"value": "x64-windows-static-md"
}
},
"generator": "Visual Studio 17 2022",
"inherits": ["cmake-dev", "vcpkg"],
"name": "vs2022-windows",
"toolset": "v143"
},
{
"cacheVariables": {
"VCPKG_MANIFEST_FEATURES": {
"type": "STRING",
"value": "standalone"
},
"MO2_INSTALL_IS_BIN": {
"type": "BOOL",
"value": "ON"
}
},
"inherits": "vs2022-windows",
"name": "vs2022-windows-standalone"
}
],
"version": 4
}
-713
View File
File diff suppressed because it is too large Load Diff
-77
View File
@@ -1,77 +0,0 @@
version: dev-appveyor{build}
skip_branch_with_pr: true
image: Visual Studio 2019
init:
- ps: >-
# define build version depending on nightly or normal build
if($env:APPVEYOR_SCHEDULED_BUILD -eq 'True'){
$timestamp= Get-Date -Format "ddMMyyyy-HHmm"
Update-AppveyorBuild -Version "$($env:MO_VERSION)$($env:VER_STUB_NIGHTLY)$timestamp"
} else {
Update-AppveyorBuild -Version "$($env:MO_VERSION)$($env:VER_STUB_NORMAL)$($env:APPVEYOR_BUILD_NUMBER)"
}
Write-Host Build version set to: $env:APPVEYOR_BUILD_VERSION
environment:
WEBHOOK_URL:
secure: gOKbXaZM9ImtMD5XrYITvdyZUW/az082G9OIN1EC1VaKiI9iefpxhBavJ6Al6CzIZvQ+3pxnLqjmNgA7cDc22wcj2kB4hSG5qhbTI8wGa8jLQ5L65nuRZ3vrIqghBz9G3GLglgZkg6eqH9r3Kqc6UzcpCGzxxPOqm550nRcIiUU=
MO_VERSION: 2.4.0
VER_STUB_NORMAL: dev-appveyor-
VER_STUB_NIGHTLY: dev-nightly-
build_script:
- pwsh: >-
# Maintenance comments:
# APPVEYOR_BUILD_FOLDER= "c:\projects\modorganizer-slug"
# -Need to update py3 version used to invoke unimake.py once in a while.
# -Need update MO_VERSION env variable after each release.
# -Always clones umbrella master
# -Will checkout all the branches matching the one that triggered the build on the main repo.
# End comments.
$ErrorActionPreference = 'Stop'
git clone --depth=1 --no-single-branch https://github.com/ModOrganizer2/modorganizer-umbrella.git c:\projects\modorganizer-umbrella
New-Item -ItemType Directory -Path ${env:APPVEYOR_BUILD_FOLDER}\modorganizer-build
cd c:\projects\modorganizer-umbrella
($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH -eq $null) ? ($branch = $env:APPVEYOR_REPO_BRANCH) : ($branch = $env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH)
git checkout $(git show-ref --verify --quiet refs/remotes/origin/${branch} || echo '-b') ${branch}
C:\Python38-x64\python.exe unimake.py -d ${env:APPVEYOR_BUILD_FOLDER}\modorganizer-build -s Appveyor_Build=True -s Feature_Branch=${env:APPVEYOR_REPO_BRANCH} -s override_build_version=${env:APPVEYOR_BUILD_VERSION}
if($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode ) }
test: off
artifacts:
- path: '\modorganizer-build\install\bin\ModOrganizer.exe'
name: Mod.Organizer-$(APPVEYOR_BUILD_VERSION)
- path: '\modorganizer-build\install\pdb\ModOrganizer.pdb'
name: PDB-Mod.Organizer-$(APPVEYOR_BUILD_VERSION)
deploy: off
on_success:
- ps: >-
Set-Location -Path $env:APPVEYOR_BUILD_FOLDER
Invoke-RestMethod https://raw.githubusercontent.com/DiscordHooks/appveyor-discord-webhook/master/send.ps1 -o send.ps1
if($env:APPVEYOR_SCHEDULED_BUILD -ne 'True'){
./send.ps1 success $env:WEBHOOK_URL
}
on_failure:
- ps: >-
Set-Location -Path $env:APPVEYOR_BUILD_FOLDER
Invoke-RestMethod https://raw.githubusercontent.com/DiscordHooks/appveyor-discord-webhook/master/send.ps1 -o send.ps1
if($env:APPVEYOR_SCHEDULED_BUILD -ne 'True'){
./send.ps1 failure $env:WEBHOOK_URL
}
-30
View File
@@ -1,30 +0,0 @@
[
# for boost???
# These are probably correct but might need a revisit as if you look at the boost documentation pages, it
# can give you huge lists of alternate includes...
{ symbol: [ "BOOST_FOREACH", "private", "<boost/foreach.hpp>", "public" ] },
{ include: [ "@\"boost/bind/.*\"", "private", "<boost/bind.hpp>", "public" ] },
{ include: [ "@\"boost/algorithm/string/.*\"", "private", "<boost/algorithm/string.hpp>", "public" ] },
{ include: [ "@\"boost/assign/.*\"", "private", "<boost/assign.hpp>", "public" ] },
{ include: [ "@\"boost/filesystem/.*\"", "private", "<boost/filesystem.hpp>", "public" ] },
{ include: [ "@\"boost/format/.*\"", "private", "<boost/format.hpp>", "public" ] },
{ include: [ "@\"boost/function/.*\"", "private", "<boost/function.hpp>", "public" ] },
{ include: [ "@\"boost/local/.*\"", "private", "<boost/locale.hpp>", "public" ] },
{ include: [ "@\"boost/python/.*\"", "private", "<boost/python.hpp>", "public" ] },
{ include: [ "@\"boost/signals2/.*\"", "private", "<boost/signals2.hpp>", "public" ] },
{ include: [ "\"boost/smart_ptr/scoped_array.hpp\"", "private", "<boost/scoped_array.hpp>", "public" ] },
{ include: [ "\"boost/smart_ptr/shared_ptr.hpp\"", "private", "<boost/shared_ptr.hpp>", "public" ] },
# this appears to be excessive
#{ include: [ "@\"boost/thread/.*\"", "private", "<boost/thread.hpp>", "public" ] },
# And this is specific to us
{ include: [ "\"appconfig.inc\"", "private", "\"appconfig.h\"", "public" ] },
]
# Ones I don't yet know how to deal with
#include "boost/fusion/container/vector/vector10_fwd.hpp" // for fusion
#include "boost/iterator/iterator_facade.hpp" // for operator!=
#include "boost/iterator/iterator_facade.hpp"
-2478
View File
File diff suppressed because it is too large Load Diff
-33
View File
@@ -1,33 +0,0 @@
# This python script contains the configuration for scons
# Copy this to scons_configure.py and adjust to taste.
# Path to your boost install - it should have a boost/ subdirectory and a stage/
# subdirectory. The scons script will use stage/lib if there, or the appropriate
# version for your compiler, if you installed the multiple-build version
BOOSTPATH = r"C:\Apps\boost_1_55_0"
# Version of Visual Studio to use, if you wish to use a specific version. If you
# don't specify a version, the latest will be picked.. See the scons manual for
# supported values.
#MSVC_VERSION = '10.0Exp'
# Path to your python install
# You don't really need to set this up but you might if (say) you have a 32- and
# 64-bit python install and scons has been installed for the 64 bit version
#PYTHONPATH=r"C:\Apps\Python"
# Path to your QT install. This might constrain the version of MSVC you can use.
# This seems to be set by QTCreator
#QTDIR = r"C:\Apps\Qt\4.8.6"
# Path to 7-zip sources
SEVENZIPPATH = r"C:\Apps\7-Zip\7z920"
# Path to zlib. Please read the README file for more information about how this
# needs to be set up
ZLIBPATH = r"C:\Apps\zlib-1.2.8"
# Source control programs. Sadly I can't get this information from qt, even
# though you have to set it up in the configuration
GIT = r"C:\Program Files\git\bin\git.exe"
MERCURIAL = r"C:\Program Files\TortoiseHg\hg.exe"
+91 -20
View File
@@ -1,36 +1,106 @@
cmake_minimum_required(VERSION 3.16)
find_package(mo2-cmake CONFIG REQUIRED)
find_package(usvfs CONFIG REQUIRED)
find_package(mo2-uibase CONFIG REQUIRED)
find_package(mo2-archive CONFIG REQUIRED)
find_package(mo2-lootcli-header CONFIG REQUIRED)
find_package(mo2-bsatk CONFIG REQUIRED)
find_package(mo2-esptk CONFIG REQUIRED)
find_package(mo2-dds-header CONFIG REQUIRED)
find_package(mo2-libbsarch CONFIG REQUIRED)
find_package(Qt6 REQUIRED COMPONENTS WebEngineWidgets WebSockets)
find_package(Boost CONFIG REQUIRED COMPONENTS program_options thread interprocess signals2 uuid accumulators)
find_package(7zip CONFIG REQUIRED)
find_package(lz4 CONFIG REQUIRED)
find_package(ZLIB REQUIRED)
add_executable(organizer)
set_target_properties(organizer PROPERTIES OUTPUT_NAME "ModOrganizer")
mo2_configure_executable(organizer
WARNINGS OFF
EXTRA_TRANSLATIONS ${MO2_SUPER_PATH}/game_gamebryo/src ${MO2_UIBASE_PATH}/src
PRIVATE_DEPENDS
uibase githubpp bsatk esptk archive usvfs lootcli boost::program_options
DirectXTex libbsarch Qt::WebEngineWidgets Qt::WebSockets)
target_link_libraries(organizer PUBLIC Shlwapi)
target_include_directories(organizer PUBLIC ${DDS_ROOT})
mo2_install_target(organizer)
set_target_properties(organizer PROPERTIES
OUTPUT_NAME "ModOrganizer"
WIN32_EXECUTABLE TRUE)
# disable translations because we want to be able to install somewhere else if
# required
mo2_configure_target(organizer WARNINGS 4 TRANSLATIONS OFF)
# we add translations "manually" to handle MO2_INSTALL_IS_BIN
mo2_add_translations(organizer
INSTALL_RELEASE
INSTALL_DIRECTORY "${_bin}/translations"
SOURCES ${CMAKE_CURRENT_SOURCE_DIR})
mo2_set_project_to_run_from_install(
organizer EXECUTABLE ${CMAKE_INSTALL_PREFIX}/${_bin}/ModOrganizer.exe)
target_link_libraries(organizer PRIVATE
Shlwapi Bcrypt
usvfs::usvfs mo2::uibase mo2::archive mo2::libbsarch
mo2::bsatk mo2::esptk mo2::lootcli-header
Boost::program_options Boost::signals2 Boost::uuid Boost::accumulators
Qt6::WebEngineWidgets Qt6::WebSockets Version Dbghelp)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/dlls.manifest.qt6"
DESTINATION bin/dlls
DESTINATION ${_bin}/dlls
CONFIGURATIONS Release RelWithDebInfo
RENAME dlls.manifest)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/dlls.manifest.debug.qt6"
DESTINATION bin/dlls
DESTINATION ${_bin}/dlls
CONFIGURATIONS Debug
RENAME dlls.manifest)
install(DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}/stylesheets"
"${CMAKE_CURRENT_SOURCE_DIR}/tutorials"
DESTINATION bin)
if (NOT MO2_SKIP_STYLESHEETS_INSTALL)
install(
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/stylesheets"
DESTINATION ${_bin})
endif()
if (NOT MO2_SKIP_TUTORIALS_INSTALL)
install(
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tutorials"
DESTINATION ${_bin})
endif()
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/resources/markdown.html"
DESTINATION bin/resources)
DESTINATION ${_bin}/resources)
mo2_deploy_qt(BINARIES ModOrganizer.exe uibase.dll plugins/bsa_packer.dll)
# install ModOrganizer.exe itself
install(FILES $<TARGET_FILE:organizer> DESTINATION ${_bin})
# install dependencies DLLs
install(FILES $<TARGET_FILE:mo2::libbsarch> DESTINATION ${_bin}/dlls)
install(FILES $<TARGET_FILE:mo2::archive> DESTINATION ${_bin}/dlls)
install(FILES $<TARGET_FILE:7zip::7zip> DESTINATION ${_bin}/dlls)
# this may copy over the ones from uibase/usvfs
# - when building with mob, this should not matter as the files should be identical
# - when building standalone, this should help having matching USVFS DLL between the
# build and the installation
# - this may cause issue with uibase in standalone mode if the installed version does
# not match the one used for the build, but there would be other issue anyway (e.g.
# different uibase.dll between modorganizer and plugins)
#
install(FILES
$<TARGET_FILE:mo2::uibase>
$<TARGET_FILE:usvfs_x64::usvfs_dll>
$<TARGET_FILE:usvfs_x86::usvfs_dll>
$<TARGET_FILE:usvfs_x64::usvfs_proxy>
$<TARGET_FILE:usvfs_x86::usvfs_proxy>
DESTINATION ${_bin})
# do not install PDB if CMAKE_INSTALL_PREFIX is "bin"
if (NOT MO2_INSTALL_IS_BIN)
install(FILES $<TARGET_PDB_FILE:organizer> DESTINATION pdb)
endif()
mo2_deploy_qt(
DIRECTORY ${_bin}
BINARIES ModOrganizer.exe $<TARGET_FILE_NAME:mo2::uibase>)
# set source groups for VS
mo2_add_filter(NAME src/application GROUPS
iuserinterface
commandline
@@ -49,14 +119,15 @@ mo2_add_filter(NAME src/browser GROUPS
)
mo2_add_filter(NAME src/categories GROUPS
categories
categories
categoriestable
categoriesdialog
categoriesdialog
categoryimportdialog
)
mo2_add_filter(NAME src/core GROUPS
archivefiletree
githubpp
installationmanager
nexusinterface
nxmaccessmanager
-60
View File
@@ -1,60 +0,0 @@
TEMPLATE = subdirs
SUBDIRS = bsatk \
shared \
uibase \
esptk \
organizer \
hookdll \
archive \
helper \
plugins \
nxmhandler \
BossDummy \
pythonRunner \
loot_cli
pythonRunner.depends = uibase
plugins.depends = pythonRunner uibase
hookdll.depends = shared
organizer.depends = shared uibase plugins
CONFIG(debug, debug|release) {
DESTDIR = $$PWD/../outputd
} else {
DESTDIR = $$PWD/../output
}
STATICDATAPATH = $${DESTDIR}\\..\\tools\\static_data\\dlls
DLLSPATH = $${DESTDIR}\\dlls
otherlibs.path = $$DLLSPATH
otherlibs.files += $${STATICDATAPATH}\\7z.dll \
$${BOOSTPATH}\\stage\\lib\\boost_python-vc*-mt-1*.dll
qtlibs.path = $$DLLSPATH
greaterThan(QT_MAJOR_VERSION, 4) {
QTLIBNAMES += Core Gui Network OpenGL Script Sql Svg Qml Quick Webkit Widgets Xml XmlPatterns
} else {
QTLIBNAMES += Core Declarative Gui Network OpenGL Script Sql Svg Webkit Xml XmlPatterns
}
greaterThan(QT_MAJOR_VERSION, 5) {
QTLIBNAMES += OpenGLWidgets
}
QTLIBSUFFIX = $${QT_MAJOR_VERSION}.dll
CONFIG(debug, debug|release): QTLIBSUFFIX = "d$${QTLIBSUFFIX}" # Can't use Debug: .. here, it ignores the line - no idea why, as it works in BossDummy.pro
for(QTNAME, QTLIBNAMES) {
QTFILE = Qt$${QTNAME}
qtlibs.files += $$[QT_INSTALL_BINS]\\$${QTFILE}$${QTLIBSUFFIX}
}
INSTALLS += qtlibs otherlibs
OTHER_FILES +=\
../SConstruct\
../scons_configure.py\
SConscript
-179
View File
@@ -1,179 +0,0 @@
import ctypes
import os
import subprocess
def resolve_name(source):
# Get the actual name of the file, after reparse points and symlinks are
# taken into account.
GENERIC_READ = 0x80000000
FILE_SHARE_READ = 0x1
OPEN_EXISTING = 0x3
FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
handle = ctypes.windll.kernel32.CreateFileA(source,
GENERIC_READ,
FILE_SHARE_READ,
None,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
None)
# get the target
FILE_NAME_NORMALIZED = 0x0
FILE_NAME_OPENED = 0x8
buff = ctypes.create_string_buffer(1024)
res = ctypes.windll.kernel32.GetFinalPathNameByHandleA(handle,
buff,
ctypes.sizeof(buff),
FILE_NAME_NORMALIZED)
target = buff.value
ctypes.windll.kernel32.CloseHandle(handle)
return target
def search_up(path, target):
while True:
if os.path.exists(os.path.join(path, target)):
return True
npath = os.path.dirname(path)
if npath == path:
break
path = npath
return False
Import('qt_env')
env = qt_env.Clone()
modules = [
'Core',
'Gui',
'Network',
'Script',
'Sql',
'WebKit',
'Xml',
'XmlPatterns',
'Declarative'
]
if env['QT_MAJOR_VERSION'] > 4:
modules += [
'Widgets',
'Qml',
'WebKitWidgets'
]
env.EnableQtModules(*modules)
env.Uic(env.Glob('*.ui'))
env.RequireLibraries('uibase', 'shared', 'bsatk', 'esptk')
env.AppendUnique(LIBS = [
'shell32',
'user32',
'ole32',
'advapi32',
'gdi32',
'shlwapi',
'Psapi',
'Version'
])
# We have to 'persuade' moc to generate certain other targets and inject them
# into the list of cpps
other_sources = env.AddExtraMoc(env.Glob('*.h'))
for file in env.Glob('*.rc'):
other_sources.append(env.RES(file))
# Note the order of this is important, or you can pick up the wrong report.h...
# Doing appendunique seems to throw the moc code into a tizzy
env['CPPPATH'] += [
'../archive',
'../plugins/gamefeatures',
'.', # Why is this necessary?
'${LOOTPATH}',
'${BOOSTPATH}',
]
#########################FUDGE###############################
env['CPPPATH'] += [
'../plugins/gameGamebryo',
]
#############################################################
env.AppendUnique(CPPDEFINES = [
'_UNICODE',
'_CRT_SECURE_NO_WARNINGS',
'_SCL_SECURE_NO_WARNINGS',
'BOOST_DISABLE_ASSERTS',
'NDEBUG',
'QT_MESSAGELOGCONTEXT'
])
# Boost produces very long names with msvc truncates. Doesn't seem to cause
# problems.
# Also note to remove the -wd4100 I hacked the boost headers (tagged_argument.hpp)
# appropriately.
env.AppendUnique(CPPFLAGS = [ '-wd4503' ])
env.AppendUnique(LINKFLAGS = [
'/SUBSYSTEM:WINDOWS',
'${EXE_MANIFEST_DEPENDENCY}'
])
# modeltest is optional and it doesn't compile anyway...
cpp_files = [
x for x in env.Glob('*.cpp', source = True)
if x.name != 'modeltest.cpp' and x.name != 'aboutdialog.cpp' and \
not x.name.startswith('moc_') # I think this is a strange bug
]
about_env = env.Clone()
# This is somewhat of a hack until I can work out a way of setting up a build
# with all the repos without using millions of junction points
try:
target = resolve_name(Dir('.').srcnode().abspath)
if search_up(target, '.hg'):
hgid = subprocess.check_output([env['MERCURIAL'], 'id', '-i']).rstrip()
elif search_up(target, '.git'):
hgid = subprocess.check_output([env['GIT'], '-C', target, 'describe',
'--tag']).rstrip()
else:
hgid = "Unknown"
except:
hgid = "Problem determining version"
# FIXME: It'd be much easier to stringify this in the source code
about_env.AppendUnique(CPPDEFINES = [ 'HGID=\\"%s\\"' % hgid ])
other_sources.append(about_env.StaticObject('aboutdialog.cpp'))
env.AppendUnique(LIBPATH = "${ZLIBPATH}/build")
env.AppendUnique(LIBS = 'zlibstatic')
prog = env.Program('ModOrganizer',
cpp_files + env.Glob('*.qrc') + other_sources)
env.InstallModule(prog)
for subdir in ('tutorials', 'stylesheets'):
env.Install(os.path.join(env['INSTALL_PATH'], subdir),
env.Glob(os.path.join(subdir, '*')))
# FIXME Sort the translations. Except they don't exist on the 1.2 branch
res = env['QT_USED_MODULES']
Return('res')
"""
CONFIG(debug, debug|release) {
} else {
QMAKE_CXXFLAGS += /Zi /GL
QMAKE_LFLAGS += /DEBUG /LTCG /OPT:REF /OPT:ICF
}
TRANSLATIONS = organizer_en.ts
QMAKE_POST_LINK += xcopy /y /s /I $$quote($$BASEDIR\\*.qm) $$quote($$DSTDIR)\\translations $$escape_expand(\\n)
"""
+2 -2
View File
@@ -20,8 +20,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#ifndef ARCHIVEFILENETRY_H
#define ARCHIVEFILENTRY_H
#include "archive.h"
#include "ifiletree.h"
#include <archive/archive.h>
#include <uibase/ifiletree.h>
/**
*
+204
View File
@@ -0,0 +1,204 @@
#include "github.h"
#include <QEventLoop>
#include <QJsonDocument>
#include <QNetworkRequest>
#include <QCoreApplication>
#include <QThread>
static const QString GITHUB_URL("https://api.github.com");
static const QString USER_AGENT("GitHubPP");
GitHub::GitHub(const char* clientId) : m_AccessManager(new QNetworkAccessManager(this))
{}
GitHub::~GitHub()
{
// delete all the replies since they depend on the access manager, which is
// about to be deleted
for (auto* reply : m_replies) {
reply->disconnect();
delete reply;
}
}
QJsonArray GitHub::releases(const Repository& repo)
{
QJsonDocument result = request(
Method::GET, QString("repos/%1/%2/releases").arg(repo.owner, repo.project),
QByteArray(), true);
return result.array();
}
void GitHub::releases(const Repository& repo,
const std::function<void(const QJsonArray&)>& callback)
{
request(
Method::GET, QString("repos/%1/%2/releases").arg(repo.owner, repo.project),
QByteArray(),
[callback](const QJsonDocument& result) {
callback(result.array());
},
true);
}
QJsonDocument GitHub::handleReply(QNetworkReply* reply)
{
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (statusCode != 200) {
return QJsonDocument(QJsonObject(
{{"http_status", statusCode},
{"redirection",
reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toString()},
{"reason",
reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()}}));
}
QByteArray data = reply->readAll();
if (data.isNull() || data.isEmpty() || (strcmp(data.constData(), "null") == 0)) {
return QJsonDocument();
}
QJsonParseError parseError;
QJsonDocument result = QJsonDocument::fromJson(data, &parseError);
if (parseError.error != QJsonParseError::NoError) {
return QJsonDocument(QJsonObject({{"parse_error", parseError.errorString()}}));
}
return result;
}
QNetworkReply* GitHub::genReply(Method method, const QString& path,
const QByteArray& data, bool relative)
{
QNetworkRequest request(relative ? GITHUB_URL + "/" + path : path);
request.setHeader(QNetworkRequest::UserAgentHeader, USER_AGENT);
request.setRawHeader("Accept", "application/vnd.github.v3+json");
switch (method) {
case Method::GET:
return m_AccessManager->get(request);
case Method::POST:
return m_AccessManager->post(request, data);
default:
// this shouldn't be possible as all enum options are handled
throw std::runtime_error("invalid method");
}
}
QJsonDocument GitHub::request(Method method, const QString& path,
const QByteArray& data, bool relative)
{
QEventLoop wait;
QNetworkReply* reply = genReply(method, path, data, relative);
connect(reply, SIGNAL(finished), &wait, SLOT(quit()));
wait.exec();
QJsonDocument result = handleReply(reply);
reply->deleteLater();
QJsonObject object = result.object();
if (object.value("http_status").toDouble() == 301.0) {
return request(method, object.value("redirection").toString(), data, false);
} else {
return result;
}
}
void GitHub::request(Method method, const QString& path, const QByteArray& data,
const std::function<void(const QJsonDocument&)>& callback,
bool relative)
{
// make sure the timer is owned by this so it's deleted correctly and
// doesn't fire after the GitHub object is destroyed; this happens when
// restarting MO by switching instances, for example
QTimer* timer = new QTimer(this);
timer->setSingleShot(true);
timer->setInterval(10000);
QNetworkReply* reply = genReply(method, path, data, relative);
// remember this reply so it can be deleted in the destructor if necessary
m_replies.push_back(reply);
Request req = {method, data, callback, timer, reply};
// finished
connect(reply, &QNetworkReply::finished, [this, req] {
onFinished(req);
});
// error
connect(reply, qOverload<QNetworkReply::NetworkError>(&QNetworkReply::errorOccurred),
[this, req](auto&& error) {
onError(req, error);
});
// timeout
connect(timer, &QTimer::timeout, [this, req] {
onTimeout(req);
});
timer->start();
}
void GitHub::onFinished(const Request& req)
{
QJsonDocument result = handleReply(req.reply);
QJsonObject object = result.object();
req.timer->stop();
if (object.value("http_status").toInt() == 301) {
request(req.method, object.value("redirection").toString(), req.data, req.callback,
false);
} else {
req.callback(result);
}
deleteReply(req.reply);
}
void GitHub::onError(const Request& req, QNetworkReply::NetworkError error)
{
// the only way the request can be aborted is when there's a timeout, which
// already logs a message
if (error != QNetworkReply::OperationCanceledError) {
qCritical().noquote().nospace()
<< "Github: request for " << req.reply->url().toString() << " failed, "
<< req.reply->errorString() << " (" << error << ")";
}
req.timer->stop();
req.reply->disconnect();
QJsonObject root({{"network_error", req.reply->errorString()}});
QJsonDocument doc(root);
req.callback(doc);
deleteReply(req.reply);
}
void GitHub::onTimeout(const Request& req)
{
qCritical().noquote().nospace()
<< "Github: request for " << req.reply->url().toString() << " timed out";
// don't delete the reply, abort will fire the error() handler above
req.reply->abort();
}
void GitHub::deleteReply(QNetworkReply* reply)
{
// remove from the list
auto itor = std::find(m_replies.begin(), m_replies.end(), reply);
if (itor != m_replies.end()) {
m_replies.erase(itor);
}
// delete
reply->deleteLater();
}
+108
View File
@@ -0,0 +1,108 @@
#pragma once
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkAccessManager>
#include <QNetworkCookieJar>
#include <QNetworkReply>
#include <QTimer>
#include <functional>
class GitHubException : public std::exception
{
public:
GitHubException(const QJsonObject& errorObj) : std::exception()
{
initMessage(errorObj);
}
virtual ~GitHubException() throw() override {}
virtual const char* what() const throw() { return m_Message.constData(); }
private:
void initMessage(const QJsonObject& obj)
{
if (obj.contains("http_status")) {
m_Message = QString("HTTP Status %1: %2")
.arg(obj.value("http_status").toInt())
.arg(obj.value("reason").toString())
.toUtf8();
} else if (obj.contains("parse_error")) {
m_Message = QString("Parsing failed: %1")
.arg(obj.value("parse_error").toString())
.toUtf8();
} else if (obj.contains("network_error")) {
m_Message = QString("Network failed: %1")
.arg(obj.value("network_error").toString())
.toUtf8();
} else {
m_Message = "Unknown error";
}
}
QByteArray m_Message;
};
class GitHub : public QObject
{
Q_OBJECT
public:
enum class Method
{
GET,
POST
};
struct Repository
{
Repository(const QString& owner, const QString& project)
: owner(owner), project(project)
{}
QString owner;
QString project;
};
public:
GitHub(const char* clientId = nullptr);
~GitHub();
QJsonArray releases(const Repository& repo);
void releases(const Repository& repo,
const std::function<void(const QJsonArray&)>& callback);
private:
QJsonDocument request(Method method, const QString& path, const QByteArray& data,
bool relative);
void request(Method method, const QString& path, const QByteArray& data,
const std::function<void(const QJsonDocument&)>& callback,
bool relative);
QJsonDocument handleReply(QNetworkReply* reply);
QNetworkReply* genReply(Method method, const QString& path, const QByteArray& data,
bool relative);
private:
struct Request
{
Method method = Method::GET;
QByteArray data;
std::function<void(const QJsonDocument&)> callback;
QTimer* timer = nullptr;
QNetworkReply* reply = nullptr;
};
QNetworkAccessManager* m_AccessManager;
// remember the replies that are in flight and delete them in the destructor
std::vector<QNetworkReply*> m_replies;
void onFinished(const Request& req);
void onError(const Request& req, QNetworkReply::NetworkError error);
void onTimeout(const Request& req);
void deleteReply(QNetworkReply* reply);
};
+6 -6
View File
@@ -20,17 +20,17 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#ifndef INSTALLATIONMANAGER_H
#define INSTALLATIONMANAGER_H
#include <guessedvalue.h>
#include <ifiletree.h>
#include <iinstallationmanager.h>
#include <iplugininstaller.h>
#include <archive/archive.h>
#include <uibase/errorcodes.h>
#include <uibase/guessedvalue.h>
#include <uibase/ifiletree.h>
#include <uibase/iinstallationmanager.h>
#include <uibase/iplugininstaller.h>
#include <QObject>
#define WIN32_LEAN_AND_MEAN
#include <QProgressDialog>
#include <Windows.h>
#include <archive.h>
#include <errorcodes.h>
#include <map>
#include <set>
+12 -6
View File
@@ -60,8 +60,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "problemsdialog.h"
#include "profile.h"
#include "profilesdialog.h"
#include "report.h"
#include "savegameinfo.h"
#include "savestab.h"
#include "selectiondialog.h"
#include "serverinfo.h"
@@ -69,15 +67,17 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "shared/appconfig.h"
#include "spawn.h"
#include "statusbar.h"
#include "tutorialmanager.h"
#include "versioninfo.h"
#include <bsainvalidation.h>
#include <dataarchives.h>
#include <safewritefile.h>
#include <scopeguard.h>
#include <taskprogressmanager.h>
#include <usvfs.h>
#include <utility.h>
#include <uibase/game_features/savegameinfo.h>
#include <uibase/report.h>
#include <uibase/tutorialmanager.h>
#include <uibase/utility.h>
#include <uibase/versioninfo.h>
#include <usvfs/usvfs.h>
#include "directoryrefresher.h"
#include "shared/directoryentry.h"
@@ -2884,6 +2884,12 @@ void MainWindow::languageChange(const QString& newLanguage)
installTranslator("qt");
installTranslator("qtbase");
installTranslator(ToQString(AppConfig::translationPrefix()));
installTranslator("uibase");
// TODO: this will probably be changed once extension come out
installTranslator("game_gamebryo");
installTranslator("game_creation");
for (const QString& fileName : m_PluginContainer.pluginFileNames()) {
installTranslator(QFileInfo(fileName).baseName());
}
+8 -7
View File
@@ -20,19 +20,20 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "bsafolder.h"
#include <bsatk/bsafolder.h>
#include <uibase/errorcodes.h>
#include <uibase/imoinfo.h>
#include <uibase/iplugingame.h>
#include <uibase/log.h>
#include <uibase/tutorialcontrol.h>
#include "delayedfilewriter.h"
#include "errorcodes.h"
#include "imoinfo.h"
#include "iplugingame.h" //namespace MOBase { class IPluginGame; }
#include "iuserinterface.h"
#include "modinfo.h"
#include "modlistbypriorityproxy.h"
#include "modlistsortproxy.h"
#include "plugincontainer.h" //class PluginContainer;
#include "plugincontainer.h"
#include "shared/fileregisterfwd.h"
#include "tutorialcontrol.h"
#include <log.h>
class Executable;
class CategoryFactory;
+8 -8
View File
@@ -29,15 +29,15 @@
#include "spawn.h"
#include "syncoverwritedialog.h"
#include "virtualfiletree.h"
#include <dataarchives.h>
#include <ipluginmodpage.h>
#include <localsavegames.h>
#include <questionboxmemory.h>
#include <report.h>
#include <scopeguard.h>
#include <scriptextender.h>
#include <usvfs.h>
#include <utility.h>
#include <uibase/game_features/dataarchives.h>
#include <uibase/game_features/localsavegames.h>
#include <uibase/game_features/scriptextender.h>
#include <uibase/report.h>
#include <uibase/scopeguard.h>
#include <uibase/utility.h>
#include <usvfs/usvfs.h>
#include <QApplication>
#include <QCoreApplication>
@@ -71,7 +71,7 @@
#include <tuple>
#include <utility>
#include "bs_archive.h"
#include <libbsarch/bs_archive.h>
#include "organizerproxy.h"
+18 -19
View File
@@ -16,24 +16,11 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pluginlist.h"
#include "modinfo.h"
#include "modlist.h"
#include "scopeguard.h"
#include "settings.h"
#include "shared/directoryentry.h"
#include "shared/fileentry.h"
#include "shared/filesorigin.h"
#include "viewmarkingscrollbar.h"
#include "shared/windows_error.h"
#include <espfile.h>
#include <gameplugins.h>
#include <iplugingame.h>
#include <report.h>
#include <safewritefile.h>
#include <utility.h>
#include <algorithm>
#include <ctime>
#include <stdexcept>
#include <QApplication>
#include <QCoreApplication>
@@ -50,11 +37,23 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QString>
#include <QtDebug>
#include <algorithm>
#include <ctime>
#include <stdexcept>
#include <esptk/espfile.h>
#include <uibase/iplugingame.h>
#include <uibase/report.h>
#include <uibase/safewritefile.h>
#include <uibase/scopeguard.h>
#include <uibase/utility.h>
#include "gameplugins.h"
#include "modinfo.h"
#include "modlist.h"
#include "organizercore.h"
#include "settings.h"
#include "shared/directoryentry.h"
#include "shared/fileentry.h"
#include "shared/filesorigin.h"
#include "shared/windows_error.h"
#include "viewmarkingscrollbar.h"
using namespace MOBase;
using namespace MOShared;

Some files were not shown because too many files have changed in this diff Show More