28 Commits
Author SHA1 Message Date
Mikaël Capelle d86116a6af Force platform to Windows for pyright. 2024-06-09 14:19:11 +02:00
Mikaël Capelle ac75677fe3 Generate UI files in CI for linting. 2024-06-09 14:17:16 +02:00
Mikaël Capelle 979a060373 Install poetry in CI. 2024-06-09 13:58:22 +02:00
Mikaël Capelle 7f93d4f77b Update following uibase change for game features. (#5) 2024-06-09 12:26:22 +02:00
Mikaël Capelle 0f4f666c71 Change plugin requirement to use PyPi version. 2024-05-20 10:28:19 +02:00
Mikaël Capelle a0ca112ed0 Bump stubs. 2022-05-05 13:15:52 +02:00
Mikaël Capelle 7ef97f047c Merge pull request #4 from ModOrganizer2/update-cmake-common-qt6
Update cmake common qt6
2022-04-28 17:54:50 +02:00
Mikaël Capelle aff1cbb944 Fixes for Qt6. 2022-04-22 13:18:04 +02:00
Mikaël Capelle 6492f84eac Minor fixes. 2022-04-19 23:33:35 +02:00
Mikaël Capelle 7b3dc82f46 Update following cmake_common changes.
# Conflicts:
#	CMakeLists.txt
2022-04-19 22:03:11 +02:00
Jeremy Rimpo 76faacba19 Merge remote-tracking branch 'origin/master' into qt6 2022-04-17 20:17:40 -05:00
Mikaël Capelle 0c8d7261fd Merge pull request #3 from Holt59/update-interpreter
Update interpreter to fix issues with case-sensitive comparisons.
2022-02-05 14:33:38 +01:00
Mikaël Capelle 3cf15300fb Update interpreter to fix issues with case-sensitive comparisons. 2022-02-05 14:31:39 +01:00
Jeremy Rimpo 3bfd181704 Installer image improvements
- Expand size of options / image row
- Resize image with correct aspect ratio
- Add maximize button to titlebar
2021-12-26 01:23:16 -06:00
Jeremy Rimpo bffeb8c05f More PyQt6 enum fixes 2021-12-26 01:16:42 -06:00
Jeremy Rimpo f7a9c95d5b Fix issues with PyQt6 2021-12-25 20:54:10 -06:00
Jeremy Rimpo 793ab6273b Reformat the translations 2021-12-09 19:39:50 -06:00
Jeremy Rimpo 7e5ec2d11a Fix pylupdate parsing 2021-12-06 23:50:35 -06:00
Jeremy Rimpo ca343602ec PyQt6 Compatibility 2021-12-06 05:25:26 -06:00
Jeremy Rimpo e2202073dc Changes to compile with Qt6 + Boost 1.77 2021-12-05 03:42:40 -06:00
Mikaël Capelle fb91a1d2b6 Merge pull request #2 from Holt59/fix-optional-plugins
Fix not-selected plugins
2021-03-13 13:49:42 +01:00
Mikaël Capelle 9f71ac1517 Move not-selected plugins to 'optional'. 2021-03-13 13:48:45 +01:00
Mikaël Capelle 775d764950 Fix translations. 2021-02-06 19:28:26 +01:00
Mikaël Capelle 538a0f73e9 Make placeholder text not-translatable. 2021-02-03 18:35:19 +01:00
Mikaël Capelle ecefc5eb8a Fix FOMOD/OMOD detection. 2020-11-27 20:30:06 +01:00
Mikaël Capelle b9653b8322 Merge pull request #1 from ModOrganizer2/cmake-common
Add CMakeLists for MO2 build.
2020-11-25 17:51:27 +01:00
Mikaël Capelle b39be8c295 Add CMakeLists for MO2 build. 2020-11-23 10:56:59 +01:00
Mikaël Capelle 28deb0ce25 Fix release script. 2020-11-23 09:15:55 +01:00
22 changed files with 867 additions and 565 deletions
+20 -12
View File
@@ -8,17 +8,25 @@ jobs:
strategy:
max-parallel: 4
matrix:
python-version: [3.8]
python-version: [3.12]
steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox
- name: Test with tox
run: tox -e py38-lint
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- uses: abatilo/actions-poetry@v2
- name: Install package
run: poetry install
# generate UI file for linting
- name: Generate UI files
shell: pwsh
run: |
Get-ChildItem -Recurse -File -Include "*.ui" | ForEach-Object {
poetry run pyuic6 $_ -o ([io.path]::ChangeExtension($_.FullName, "py"))
}
- name: Lint
run: poetry run poe lint
+5
View File
@@ -8,7 +8,12 @@ src/ui/*.py
.tox
.vscode
# MO2 build files:
vsbuild
mob.log
# Generated files:
lib
src/lib
installer_wizard
installer_wizard-*.zip
+11
View File
@@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.16)
if(DEFINED DEPENDENCIES_DIR)
include(${DEPENDENCIES_DIR}/modorganizer_super/cmake_common/mo2.cmake)
else()
include(${CMAKE_CURRENT_LIST_DIR}/../cmake_common/mo2.cmake)
endif()
project(installer_wizard LANGUAGES NONE)
add_subdirectory(src)
-163
View File
@@ -1,163 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS><TS version="2.0">
<context>
<name>WizardInstallerComplete</name>
<message>
<location filename="src/ui/wizardinstallercomplete.py" line="151"/>
<source>Form</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallercomplete.py" line="152"/>
<source>The installer script has finished. The following sub-packages and plugins will be installed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallercomplete.py" line="153"/>
<source>Sub-Packages:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallercomplete.py" line="154"/>
<source>Plugins:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallercomplete.py" line="155"/>
<source>INI Tweaks:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallercomplete.py" line="156"/>
<source>Notes:</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>WizardInstallerDialog</name>
<message>
<location filename="src/ui/wizardinstallerdialog.py" line="75"/>
<source>BAIN Wizard Installer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerdialog.py" line="76"/>
<source>Name</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerdialog.py" line="77"/>
<source>Manual</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerdialog.py" line="78"/>
<source>Script</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerdialog.py" line="79"/>
<source>Back</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerdialog.py" line="80"/>
<source>Next</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerdialog.py" line="81"/>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>WizardInstallerError</name>
<message>
<location filename="src/ui/wizardinstallererror.py" line="52"/>
<source>Form</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallererror.py" line="54"/>
<source>TextLabel</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>WizardInstallerPage</name>
<message>
<location filename="src/ui/wizardinstallerpage.py" line="91"/>
<source>Form</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerpage.py" line="92"/>
<source>TextLabel</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerpage.py" line="93"/>
<source>Options:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerpage.py" line="94"/>
<source>Description:</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>WizardInstallerRequires</name>
<message>
<location filename="src/ui/wizardinstallerrequires.py" line="113"/>
<source>Form</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerrequires.py" line="114"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Warning:&lt;/span&gt; The following version requirements are not met for using this installer.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerrequires.py" line="115"/>
<source>Requirements</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerrequires.py" line="116"/>
<source>Graphics Extender</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerrequires.py" line="117"/>
<source>Wrye Bash</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerrequires.py" line="118"/>
<source>Need</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerrequires.py" line="119"/>
<source>Game</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerrequires.py" line="122"/>
<source>N/A</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerrequires.py" line="121"/>
<source>Have</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/wizardinstallerrequires.py" line="123"/>
<source>Script Extender</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>
+2 -1
View File
@@ -6,7 +6,8 @@ $target = ".\installer_wizard\"
Remove-Item -Recurse -Force -ErrorAction Ignore $target
New-Item -Path $target -Type Directory | Out-Null
Copy-Item -Recurse -Path .\src\* -Exclude "*.ui", "__pycache__" -Destination .\installer_wizard
Copy-Item -Recurse -Path .\src\* -Exclude "*.ui" -Destination $target
Get-ChildItem -Recurse $target -Include "__pycache__" | Remove-Item -Recurse -Force
Copy-Item .\installer_wizard_en.ts, .\README.md, .\LICENSE $target
# Find the version:
+1 -1
View File
@@ -1,5 +1,5 @@
# Install the lib:
pip install --target=.\src\lib --upgrade git+https://github.com/Holt59/bain-wizard-interpreter | Out-Null
pip install --target=.\src\lib --upgrade -r .\plugin-requirements.txt | Out-Null
# Convert ui files:
Get-ChildItem -Recurse -File -Include "*.ui" | ForEach-Object {
+1
View File
@@ -0,0 +1 @@
bain-wizard-interpreter==1.0.4
Generated
+220
View File
@@ -0,0 +1,220 @@
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
[[package]]
name = "antlr4-python3-runtime"
version = "4.13.1"
description = "ANTLR 4.13.1 runtime for Python 3"
optional = false
python-versions = "*"
files = [
{file = "antlr4-python3-runtime-4.13.1.tar.gz", hash = "sha256:3cd282f5ea7cfb841537fe01f143350fdb1c0b1ce7981443a2fa8513fddb6d1a"},
{file = "antlr4_python3_runtime-4.13.1-py3-none-any.whl", hash = "sha256:78ec57aad12c97ac039ca27403ad61cb98aaec8a3f9bb8144f889aa0fa28b943"},
]
[[package]]
name = "bain-wizard-interpreter"
version = "1.0.4"
description = "BAIN Wizard Interpreter based on wizparse."
optional = false
python-versions = "<4.0,>=3.11.1"
files = [
{file = "bain_wizard_interpreter-1.0.4-py3-none-any.whl", hash = "sha256:c6a084349caa6fd80d8fbf222869fb63df8ede337edbb8774dff557ae2a981bc"},
{file = "bain_wizard_interpreter-1.0.4.tar.gz", hash = "sha256:4ebd36112690775bab6c921c90422c9e5432901ca90860f36c5ba0153bb82079"},
]
[package.dependencies]
antlr4-python3-runtime = ">=4.13.1,<5.0.0"
chardet = ">=5.2.0,<6.0.0"
[[package]]
name = "chardet"
version = "5.2.0"
description = "Universal encoding detector for Python 3"
optional = false
python-versions = ">=3.7"
files = [
{file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"},
{file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"},
]
[[package]]
name = "mobase-stubs"
version = "2.5.1a0"
description = "PEP561 stub files for the mobase Python API."
optional = false
python-versions = "<4.0,>=3.12"
files = [
{file = "mobase_stubs-2.5.1a0-py3-none-any.whl", hash = "sha256:bcaecfae038b890d82280fc518f7e44f38d22d35801a8ba7ffa480f7756d6823"},
{file = "mobase_stubs-2.5.1a0.tar.gz", hash = "sha256:a8dc5574336ed3b1f673288447781f705a078472cf8808e05a36f129c81c8e20"},
]
[[package]]
name = "nodeenv"
version = "1.9.0"
description = "Node.js virtual environment builder"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [
{file = "nodeenv-1.9.0-py2.py3-none-any.whl", hash = "sha256:508ecec98f9f3330b636d4448c0f1a56fc68017c68f1e7857ebc52acf0eb879a"},
{file = "nodeenv-1.9.0.tar.gz", hash = "sha256:07f144e90dae547bf0d4ee8da0ee42664a42a04e02ed68e06324348dafe4bdb1"},
]
[[package]]
name = "pastel"
version = "0.2.1"
description = "Bring colors to your terminal."
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
{file = "pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364"},
{file = "pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d"},
]
[[package]]
name = "poethepoet"
version = "0.23.0"
description = "A task runner that works well with poetry."
optional = false
python-versions = ">=3.8"
files = [
{file = "poethepoet-0.23.0-py3-none-any.whl", hash = "sha256:d573ff31d7678e62b6f9bc9a1291ae2009ac14e0eead0a450598f9f05abb27a3"},
{file = "poethepoet-0.23.0.tar.gz", hash = "sha256:62a0a6a518df5985c191aee0c1fcd2bb6a0a04eb102997786fcdf118e4147d22"},
]
[package.dependencies]
pastel = ">=0.2.1,<0.3.0"
tomli = ">=1.2.2"
[package.extras]
poetry-plugin = ["poetry (>=1.0,<2.0)"]
[[package]]
name = "pyqt6"
version = "6.7.0"
description = "Python bindings for the Qt cross platform application toolkit"
optional = false
python-versions = ">=3.8"
files = [
{file = "PyQt6-6.7.0-cp38-abi3-macosx_10_14_universal2.whl", hash = "sha256:919ffb01020ece42209228bf94b4f2c156a6b77cc5a69a90a05e358b0333750b"},
{file = "PyQt6-6.7.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:e294f025f94493ee12b66efd6893fab309c9063172bb8a5b184f84dfc1ebcc49"},
{file = "PyQt6-6.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:9d8865fb6357dba032002c4554a9648e88f2b4706c929cc51fba58edafad91fc"},
{file = "PyQt6-6.7.0.tar.gz", hash = "sha256:3d31b2c59dc378ee26e16586d9469842483588142fc377280aad22aaf2fa6235"},
]
[package.dependencies]
PyQt6-Qt6 = ">=6.7.0,<6.8.0"
PyQt6-sip = ">=13.6,<14"
[[package]]
name = "pyqt6-qt6"
version = "6.7.1"
description = "The subset of a Qt installation needed by PyQt6."
optional = false
python-versions = "*"
files = [
{file = "PyQt6_Qt6-6.7.1-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:29622b5dd38740b4b6962e0c88d082d08fa10b64542ef5d911b04214aad70150"},
{file = "PyQt6_Qt6-6.7.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fbcfe66a57199c6a26542b8b9b2f2ee59d974db36293de335a1251f24c4fe917"},
{file = "PyQt6_Qt6-6.7.1-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:9fbab2a96d72d77d16021e259ef86a1a3c87adb0e7eebcc92df0d39f3fdf7e27"},
{file = "PyQt6_Qt6-6.7.1-py3-none-win_amd64.whl", hash = "sha256:590a2f30d15892b5259e6a17ecc0a755675b1b49f553d964e195e90094b44120"},
]
[[package]]
name = "pyqt6-sip"
version = "13.6.0"
description = "The sip module support for PyQt6"
optional = false
python-versions = ">=3.7"
files = [
{file = "PyQt6_sip-13.6.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d6b5f699aaed0ac1fcd23e8fbca70d8a77965831b7c1ce474b81b1678817a49d"},
{file = "PyQt6_sip-13.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8c282062125eea5baf830c6998587d98c50be7c3a817a057fb95fef647184012"},
{file = "PyQt6_sip-13.6.0-cp310-cp310-win32.whl", hash = "sha256:fa759b6339ff7e25f9afe2a6b651b775f0a36bcb3f5fa85e81a90d3b033c83f4"},
{file = "PyQt6_sip-13.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:8f9df9f7ccd8a9f0f1d36948c686f03ce1a1281543a3e636b7b7d5e086e1a436"},
{file = "PyQt6_sip-13.6.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b9c6b6f9cfccb48cbb78a59603145a698fb4ffd176764d7083e5bf47631d8df"},
{file = "PyQt6_sip-13.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:86a7b67c64436e32bffa9c28c9f21bf14a9faa54991520b12c3f6f435f24df7f"},
{file = "PyQt6_sip-13.6.0-cp311-cp311-win32.whl", hash = "sha256:58f68a48400e0b3d1ccb18090090299bad26e3aed7ccb7057c65887b79b8aeea"},
{file = "PyQt6_sip-13.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:0dfd22cfedd87e96f9d51e0778ca2ba3dc0be83e424e9e0f98f6994d8d9c90f0"},
{file = "PyQt6_sip-13.6.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3bf03e130fbfd75c9c06e687b86ba375410c7a9e835e4e03285889e61dd4b0c4"},
{file = "PyQt6_sip-13.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:43fb8551796030aae3d66d6e35e277494071ec6172cd182c9569ab7db268a2f5"},
{file = "PyQt6_sip-13.6.0-cp312-cp312-win32.whl", hash = "sha256:13885361ca2cb2f5085d50359ba61b3fabd41b139fb58f37332acbe631ef2357"},
{file = "PyQt6_sip-13.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:24441032a29791e82beb7dfd76878339058def0e97fdb7c1cea517f3a0e6e96b"},
{file = "PyQt6_sip-13.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3075d8b325382750829e6cde6971c943352309d35768a4d4da0587459606d562"},
{file = "PyQt6_sip-13.6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a6ce80bc24618d8a41be8ca51ad9f10e8bc4296dd90ab2809573df30a23ae0e5"},
{file = "PyQt6_sip-13.6.0-cp38-cp38-win32.whl", hash = "sha256:fa7b10af7488efc5e53b41dd42c0f421bde6c2865a107af7ae259aff9d841da9"},
{file = "PyQt6_sip-13.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:9adf672f9114687533a74d5c2d4c03a9a929ad5ad9c3e88098a7da1a440ab916"},
{file = "PyQt6_sip-13.6.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:98bf954103b087162fa63b3a78f30b0b63da22fd6450b610ec1b851dbb798228"},
{file = "PyQt6_sip-13.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:39854dba35f8e5a4288da26ecb5f40b4c5ec1932efffb3f49d5ea435a7f37fb3"},
{file = "PyQt6_sip-13.6.0-cp39-cp39-win32.whl", hash = "sha256:747f6ca44af81777a2c696bd501bc4815a53ec6fc94d4e25830e10bc1391f8ab"},
{file = "PyQt6_sip-13.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:33ea771fe777eb0d1a2c3ef35bcc3f7a286eb3ff09cd5b2fdd3d87d1f392d7e8"},
{file = "PyQt6_sip-13.6.0.tar.gz", hash = "sha256:2486e1588071943d4f6657ba09096dc9fffd2322ad2c30041e78ea3f037b5778"},
]
[[package]]
name = "pyright"
version = "1.1.365"
description = "Command line wrapper for pyright"
optional = false
python-versions = ">=3.7"
files = [
{file = "pyright-1.1.365-py3-none-any.whl", hash = "sha256:194d767a039f9034376b7ec8423841880ac6efdd061f3e283b4ad9fcd484a659"},
{file = "pyright-1.1.365.tar.gz", hash = "sha256:d7e69000939aed4bf823707086c30c84c005bdd39fac2dfb370f0e5be16c2ef2"},
]
[package.dependencies]
nodeenv = ">=1.6.0"
[package.extras]
all = ["twine (>=3.4.1)"]
dev = ["twine (>=3.4.1)"]
[[package]]
name = "ruff"
version = "0.2.2"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
{file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0a9efb032855ffb3c21f6405751d5e147b0c6b631e3ca3f6b20f917572b97eb6"},
{file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d450b7fbff85913f866a5384d8912710936e2b96da74541c82c1b458472ddb39"},
{file = "ruff-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecd46e3106850a5c26aee114e562c329f9a1fbe9e4821b008c4404f64ff9ce73"},
{file = "ruff-0.2.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e22676a5b875bd72acd3d11d5fa9075d3a5f53b877fe7b4793e4673499318ba"},
{file = "ruff-0.2.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1695700d1e25a99d28f7a1636d85bafcc5030bba9d0578c0781ba1790dbcf51c"},
{file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b0c232af3d0bd8f521806223723456ffebf8e323bd1e4e82b0befb20ba18388e"},
{file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f63d96494eeec2fc70d909393bcd76c69f35334cdbd9e20d089fb3f0640216ca"},
{file = "ruff-0.2.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a61ea0ff048e06de273b2e45bd72629f470f5da8f71daf09fe481278b175001"},
{file = "ruff-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1439c8f407e4f356470e54cdecdca1bd5439a0673792dbe34a2b0a551a2fe3"},
{file = "ruff-0.2.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:940de32dc8853eba0f67f7198b3e79bc6ba95c2edbfdfac2144c8235114d6726"},
{file = "ruff-0.2.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c126da55c38dd917621552ab430213bdb3273bb10ddb67bc4b761989210eb6e"},
{file = "ruff-0.2.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3b65494f7e4bed2e74110dac1f0d17dc8e1f42faaa784e7c58a98e335ec83d7e"},
{file = "ruff-0.2.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1ec49be4fe6ddac0503833f3ed8930528e26d1e60ad35c2446da372d16651ce9"},
{file = "ruff-0.2.2-py3-none-win32.whl", hash = "sha256:d920499b576f6c68295bc04e7b17b6544d9d05f196bb3aac4358792ef6f34325"},
{file = "ruff-0.2.2-py3-none-win_amd64.whl", hash = "sha256:cc9a91ae137d687f43a44c900e5d95e9617cb37d4c989e462980ba27039d239d"},
{file = "ruff-0.2.2-py3-none-win_arm64.whl", hash = "sha256:c9d15fc41e6054bfc7200478720570078f0b41c9ae4f010bcc16bd6f4d1aacdd"},
{file = "ruff-0.2.2.tar.gz", hash = "sha256:e62ed7f36b3068a30ba39193a14274cd706bc486fad521276458022f7bccb31d"},
]
[[package]]
name = "tomli"
version = "2.0.1"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.7"
files = [
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
[[package]]
name = "types-psutil"
version = "5.9.5.20240516"
description = "Typing stubs for psutil"
optional = false
python-versions = ">=3.8"
files = [
{file = "types-psutil-5.9.5.20240516.tar.gz", hash = "sha256:bb296f59fc56458891d0feb1994717e548a1bcf89936a2877df8792b822b4696"},
{file = "types_psutil-5.9.5.20240516-py3-none-any.whl", hash = "sha256:83146ded949a10167d9895e567b3b71e53ebc5e23fd8363eab62b3c76cce7b89"},
]
[metadata]
lock-version = "2.0"
python-versions = "^3.12"
content-hash = "e3a9cd106c3a545c4913ccf1956733525b3fe61323063bece381f6834b4ac0a4"
+63
View File
@@ -0,0 +1,63 @@
[tool.poetry]
name = "installer-wizard"
version = "1.0.3"
description = ""
authors = ["Mikaël Capelle <capelle.mikael@gmail.com>"]
license = "MIT"
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.12"
pyqt6 = "^6.7.0"
bain-wizard-interpreter = "1.0.4"
[tool.poetry.group.dev.dependencies]
pyright = "^1.1.365"
ruff = "^0.2.1"
types-psutil = "^5.9.5.20240516"
poethepoet = "^0.23.0"
mobase-stubs = { version = "2.5.1a0", allow-prereleases = true }
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.poe.tasks]
format-imports = "ruff check --select I . --fix"
format-ruff = "ruff format ."
format.sequence = ["format-imports", "format-ruff"]
lint-ruff = "ruff check ."
lint-ruff-format = "ruff format --check ."
lint-pyright = "pyright ."
lint.sequence = ["lint-ruff", "lint-ruff-format", "lint-pyright"]
lint.ignore_fail = "return_non_zero"
[tool.ruff]
target-version = "py310"
[tool.ruff.lint]
extend-select = ["B", "Q", "I"]
[tool.ruff.lint.isort.sections]
mobase = ["mobase"]
wizard = ["wizard"]
[tool.ruff.lint.isort]
required-imports = ["from __future__ import annotations"]
section-order = [
"future",
"standard-library",
"third-party",
"first-party",
"wizard",
"mobase",
"local-folder",
]
[tool.pyright]
exclude = ["lib", "venv", "src/ui"]
typeCheckingMode = "strict"
reportMissingTypeStubs = true
reportMissingModuleSource = false
pythonPlatform = "Windows"
-7
View File
@@ -1,7 +0,0 @@
black
PyQt5
mypy
flake8
flake8-black
mobase-stubs
git+https://github.com/Holt59/bain-wizard-interpreter
-45
View File
@@ -1,45 +0,0 @@
[flake8]
# Use black line length:
max-line-length = 88
extend-ignore =
# See https://github.com/PyCQA/pycodestyle/issues/373
E203,
exclude = lib,ui
[mypy]
warn_return_any = True
warn_unused_configs = True
namespace_packages = True
[mypy-antlr4.*]
ignore_missing_imports = True
[mypy-.ui.*]
ignore_missing_imports = True
[mypy-src.ui.*]
ignore_missing_imports = True
[mypy-wizard.antlr4.*]
ignore_errors = True
[mypy-pytest]
ignore_missing_imports = True
[tox:tox]
skipsdist = true
envlist = py38-lint
[testenv:py38-lint]
skip_install = true
deps =
black
mypy
flake8
flake8-black
mobase-stubs==2.4.0.a3
git+https://github.com/Holt59/bain-wizard-interpreter
commands =
black src --check --diff --exclude "lib" --exclude "ui"
flake8 src
mypy src
+4
View File
@@ -0,0 +1,4 @@
cmake_minimum_required(VERSION 3.16)
add_custom_target(installer_wizard ALL)
mo2_configure_python(installer_wizard MODULE)
+1 -2
View File
@@ -1,9 +1,8 @@
# -*- encoding: utf-8 -*-
"""
This file is the entry point of the module and must contain a createPlugin()
or createPlugins() function.
"""
from __future__ import annotations
import os
import site
+233 -168
View File
File diff suppressed because it is too large Load Diff
+97 -90
View File
@@ -1,21 +1,19 @@
# -*- encoding: utf-8 -*-
from __future__ import annotations
import re
import os
import re
import sys
from collections import defaultdict
from pathlib import Path
from typing import Dict, Optional, List, Union
from typing import Dict, List, Optional, Sequence, Union, cast
# MO2 ships with PyQt5, so you can use it in your plugins:
from PyQt5.QtWidgets import QApplication
from PyQt5 import QtWidgets
import mobase
from PyQt6 import QtWidgets
from PyQt6.QtWidgets import QApplication
from wizard.runner import WizardRunnerState
import mobase
from .dialog import WizardInstallerDialog
from .runner import make_interpreter
from .utils import make_ini_tweaks, merge_ini_tweaks
@@ -30,22 +28,19 @@ class WizardInstaller(mobase.IPluginInstallerSimple):
it is valid (for this installer) and then modify it if required before extraction.
"""
# Regex used to parse settings:
# regex used to parse settings
RE_DESCRIPTION = re.compile(r"select([0-9]+)-description")
RE_OPTION = re.compile(r"select([0-9]+)-option([0-9]+)")
_organizer: mobase.IOrganizer
# List of selected options:
# list of selected options
_installerOptions: Dict[str, List[str]]
_installerUsed: bool
def __init__(self):
super().__init__()
# Method for IPlugin - I will not details these here since those are quite
# self-explanatory and are common to all plugins:
def init(self, organizer: mobase.IOrganizer):
self._organizer = organizer
return True
@@ -53,6 +48,9 @@ class WizardInstaller(mobase.IPluginInstallerSimple):
def name(self):
return "BAIN Wizard Installer"
def localizedName(self) -> str:
return self._tr("BAIN Wizard Installer")
def author(self):
return "Holt59"
@@ -78,28 +76,31 @@ class WizardInstaller(mobase.IPluginInstallerSimple):
"prefer OMOD installer over this one when possible",
False,
),
# Above FOMOD:
# above FOMOD?
mobase.PluginSetting("priority", "priority of this installer", 120),
]
# Method for IPluginInstallerSimple:
# method for IPluginInstallerSimple
def priority(self):
return self._organizer.pluginSetting(self.name(), "priority")
def priority(self) -> int:
return cast(int, self._organizer.pluginSetting(self.name(), "priority"))
def isManualInstaller(self) -> bool:
return False
def onInstallationStart(
self, archive: str, reinstallation: bool, mod: Optional[mobase.IModInterface]
self,
archive: str,
reinstallation: bool,
current_mod: Optional[mobase.IModInterface],
):
self._installerUsed = False
self._installerOptions = {}
if mod:
settings = mod.pluginSettings(self.name())
if current_mod:
settings = current_mod.pluginSettings(self.name())
# First extract the description:
# first extract the description
descriptions: Dict[int, str] = {}
options: Dict[int, Dict[int, str]] = defaultdict(dict)
for setting, value in settings.items():
@@ -121,23 +122,27 @@ class WizardInstaller(mobase.IPluginInstallerSimple):
self._installerOptions[desc].append(options[kdesc][index])
def onInstallationEnd(
self, result: mobase.InstallResult, mod: Optional[mobase.IModInterface]
self, result: mobase.InstallResult, new_mod: Optional[mobase.IModInterface]
):
if result != mobase.InstallResult.SUCCESS or not self._installerUsed or not mod:
if (
result != mobase.InstallResult.SUCCESS
or not self._installerUsed
or not new_mod
):
return
mod.clearPluginSettings(self.name())
new_mod.clearPluginSettings(self.name())
for i, desc in enumerate(self._installerOptions):
mod.setPluginSetting(self.name(), f"select{i}-description", desc)
new_mod.setPluginSetting(self.name(), f"select{i}-description", desc)
for iopt, opt in enumerate(self._installerOptions[desc]):
mod.setPluginSetting(self.name(), f"select{i}-option{iopt}", opt)
new_mod.setPluginSetting(self.name(), f"select{i}-option{iopt}", opt)
def _hasFomodInstaller(self) -> bool:
# Do not consider the NCC installer.
return bool(self._organizer.pluginSetting("Fomod Installer", "enabled"))
# do not consider the NCC installer
return self._organizer.isPluginEnabled("Fomod Installer")
def _hasOmodInstaller(self) -> bool:
return bool(self._organizer.pluginSetting("Omod Installer", "enabled"))
return self._organizer.isPluginEnabled("Omod Installer")
def _getWizardArchiveBase(
self, tree: mobase.IFileTree, data_name: str, checker: mobase.ModDataChecker
@@ -159,16 +164,16 @@ class WizardInstaller(mobase.IPluginInstallerSimple):
if entry:
return tree
if len(tree) == 1 and isinstance(tree[0], mobase.IFileTree):
return self._getWizardArchiveBase(tree[0], data_name, checker)
if len(tree) == 1 and isinstance((root := tree[0]), mobase.IFileTree):
return self._getWizardArchiveBase(root, data_name, checker)
return None
def _getEntriesToExtract(
self,
tree: mobase.IFileTree,
extensions: List[str] = ["png", "jpg", "jpeg", "gif", "bmp", "ini"],
) -> List[mobase.FileTreeEntry]:
extensions: Sequence[str] = ["png", "jpg", "jpeg", "gif", "bmp", "ini"],
) -> list[mobase.FileTreeEntry]:
"""
Retrieve all the entries to extract from the given tree.
@@ -179,7 +184,7 @@ class WizardInstaller(mobase.IPluginInstallerSimple):
Returns:
A list of entries corresponding to files with the given extensions.
"""
entries = []
entries: list[mobase.FileTreeEntry] = []
def fn(path: str, entry: mobase.FileTreeEntry):
if entry.isFile() and entry.hasSuffix(extensions):
@@ -202,21 +207,19 @@ class WizardInstaller(mobase.IPluginInstallerSimple):
True if the file-tree can be installed, false otherwise.
"""
# Retrieve the name of the "data" folder:
# retrieve the name of the "data" folder
data_name = self._organizer.managedGame().dataDirectory().dirName()
# Retrieve the mod-data-checker:
checker: mobase.ModDataChecker = self._organizer.managedGame().feature(
mobase.ModDataChecker # type: ignore
)
# retrieve the mod-data-checker
checker = self._organizer.gameFeatures().gameFeature(mobase.ModDataChecker)
# Retrieve the base:
# retrieve the base
base = self._getWizardArchiveBase(tree, data_name, checker)
if not base:
return False
# Check FOMOD:
# check FOMOD for priority
fomod = base.exists("fomod/ModuleConfig.xml")
if (
fomod
@@ -232,9 +235,9 @@ class WizardInstaller(mobase.IPluginInstallerSimple):
def install(
self,
name: mobase.GuessedString,
otree: mobase.IFileTree,
tree: mobase.IFileTree,
version: str,
modId: int,
nexus_id: int,
) -> Union[mobase.InstallResult, mobase.IFileTree]:
"""
Perform the actual installation.
@@ -242,9 +245,9 @@ class WizardInstaller(mobase.IPluginInstallerSimple):
Args:
name: The "name" of the mod. This can be updated to change the name of the
mod.
otree: The original archive tree.
tree: The original archive tree.
version: The original version of the mod.
modId: The original ID of the mod.
nexus_id: The original ID of the mod.
Returns: We either return the modified file-tree (if the installation was
successful), or a InstallResult otherwise.
@@ -254,16 +257,14 @@ class WizardInstaller(mobase.IPluginInstallerSimple):
of the mod, in case those were updated by the installer.
"""
# Retrieve the name of the "data" folder:
# retrieve the name of the "data" folder
data_name = self._organizer.managedGame().dataDirectory().dirName()
# Retrieve the mod-data-checker:
checker: mobase.ModDataChecker = self._organizer.managedGame().feature(
mobase.ModDataChecker # type: ignore
)
# retrieve the mod-data-checker
checker = self._organizer.gameFeatures().gameFeature(mobase.ModDataChecker)
# Retrive the "base" folder:
base = self._getWizardArchiveBase(otree, data_name, checker)
# retrieve the "base" folder
base = self._getWizardArchiveBase(tree, data_name, checker)
if not base or not checker:
return mobase.InstallResult.NOT_ATTEMPTED
@@ -271,9 +272,9 @@ class WizardInstaller(mobase.IPluginInstallerSimple):
if wizard is None:
return mobase.InstallResult.NOT_ATTEMPTED
to_extract = self._getEntriesToExtract(otree)
to_extract = self._getEntriesToExtract(tree)
# Extract the script:
# extract the script
paths = self._manager().extractFiles([wizard] + to_extract, silent=False)
if len(paths) != len(to_extract) + 1:
return mobase.InstallResult.FAILED
@@ -289,29 +290,30 @@ class WizardInstaller(mobase.IPluginInstallerSimple):
name,
{
Path(entry.path()): Path(path)
for entry, path in zip(to_extract, paths[1:])
for entry, path in zip(to_extract, paths[1:], strict=True)
if not path.endswith(".ini")
},
self._installerOptions,
self._parentWidget(),
)
dialog.scriptButtonClicked.connect(lambda: os.startfile(script)) # type: ignore
dialog.scriptButtonClicked.connect( # pyright: ignore[reportUnknownMemberType, reportAttributeAccessIssue]
lambda: os.startfile(script)
)
# Note: Unlike the official installer, we do not have a "silent" setting,
# but it is really simple to add it.
if dialog.exec() == QtWidgets.QDialog.Accepted:
# We update the name with the user specified one:
# unlike the official installer, we do not have a "silent" setting, but it is
# really simple to add it
if dialog.exec() == QtWidgets.QDialog.DialogCode.Accepted:
# we update the name with the user specified one
name.update(dialog.name(), mobase.GuessQuality.USER)
# Create the tree with all the sub-packages:
tree = otree.createOrphanTree()
# create the tree with all the sub-packages
new_tree = tree.createOrphanTree()
for subpackage in dialog.subpackages():
entry = base.find(subpackage)
# Should never happens since we fetch the subpackage for the archive:
# should never happens since we fetch the subpackage for the archive
if not entry or not isinstance(entry, mobase.IFileTree):
print(
f"SubPackage {subpackage} not found in the archive.",
@@ -319,42 +321,48 @@ class WizardInstaller(mobase.IPluginInstallerSimple):
)
continue
tree.merge(entry)
new_tree.merge(entry)
# Handle renames:
# handle renames
for original, new in dialog.renames().items():
# Entry should be at the root:
entry = tree.find(original)
# entry should be at the root
entry = new_tree.find(original)
if not entry:
print(f"Plugin {original} not found, cannot rename.")
continue
tree.move(entry, new)
new_tree.move(entry, new)
# move not selected plugins to optional
for plugin, enabled in dialog.plugins().items():
if not enabled:
entry = new_tree.find(plugin)
if not entry:
continue # silently fail since the plugin should be disabled
new_tree.addDirectory("optional").insert(entry)
# TODO: INI Tweaks:
alltweaks = dialog.tweaks()
for filename, tweaks in alltweaks.items():
# Find the original file (if any):
o_entry = tree.find(filename)
# find the original file (if any)
o_entry = new_tree.find(filename)
o_filename: Optional[str] = None
if o_entry:
# Find the filepath from the list of extracted files:
# find the filepath from the list of extracted files
index = to_extract.index(o_entry)
# +1 because the first one is the script.
# +1 because the first one is the script
o_filename = paths[index + 1]
# If the file existed before, we keep the new one at the same
# place:
# if the file existed before, we keep the new one at the same place
if o_entry or Path(filename).parts[0].lower() == "ini tweaks":
entry = tree.addFile(filename, replace_if_exists=True)
entry = new_tree.addFile(filename, replace_if_exists=True)
# Otherwise we create it in INI Tweaks
# otherwise we create it in INI Tweaks
else:
entry = tree.addFile(
entry = new_tree.addFile(
os.path.join("INI Tweaks", filename), replace_if_exists=True
)
@@ -368,24 +376,23 @@ class WizardInstaller(mobase.IPluginInstallerSimple):
with open(filepath, "w") as fp:
fp.write(data)
# Mark stuff for saving:
# mark stuff for saving
self._installerUsed = True
self._installerOptions = dict(dialog.selectedOptions())
# Return the tree:
return tree
return new_tree
# If user requested a manual installation, we update the name (to keep it
# in the manual installation dialog) and just notify the installation manager:
# if user requested a manual installation, we update the name (to keep it
# in the manual installation dialog) and just notify the installation manager
elif dialog.isManualRequested():
name.update(dialog.name(), mobase.GuessQuality.USER)
return mobase.InstallResult.MANUAL_REQUESTED
# If user canceled, we simply notify the installation manager:
# if user canceled, we simply notify the installation manager
else:
return mobase.InstallResult.CANCELED
def _tr(self, str):
# We need this to translate string in Python. Check the common documentation
# for more details:
return QApplication.translate("WizardInstaller", str)
def _tr(self, value: str) -> str:
# we need this to translate string in Python. Check the common documentation
# for more details
return QApplication.translate("WizardInstaller", value)
+132
View File
@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>WizardInstallerComplete</name>
<message>
<location filename="ui\wizardinstallercomplete.ui" line="0" />
<source>The installer script has finished. The following sub-packages and plugins will be installed.</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallercomplete.ui" line="0" />
<source>Sub-Packages:</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallercomplete.ui" line="0" />
<source>Plugins:</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallercomplete.ui" line="0" />
<source>INI Tweaks:</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallercomplete.ui" line="0" />
<source>Notes:</source>
<translation type="unfinished" />
</message>
</context>
<context>
<name>WizardInstallerDialog</name>
<message>
<location filename="ui\wizardinstallerdialog.ui" line="0" />
<source>BAIN Wizard Installer</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallerdialog.ui" line="0" />
<source>Name</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallerdialog.ui" line="0" />
<source>Manual</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallerdialog.ui" line="0" />
<source>Script</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallerdialog.ui" line="0" />
<source>Back</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallerdialog.ui" line="0" />
<source>Next</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallerdialog.ui" line="0" />
<source>Cancel</source>
<translation type="unfinished" />
</message>
</context>
<context>
<name>WizardInstallerPage</name>
<message>
<location filename="ui\wizardinstallerpage.ui" line="0" />
<source>Options:</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallerpage.ui" line="0" />
<source>Description:</source>
<translation type="unfinished" />
</message>
</context>
<context>
<name>WizardInstallerRequires</name>
<message>
<location filename="ui\wizardinstallerrequires.ui" line="0" />
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=" font-weight:600;"&gt;Warning:&lt;/span&gt; The following version requirements are not met for using this installer.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallerrequires.ui" line="0" />
<source>Requirements</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallerrequires.ui" line="0" />
<source>Graphics Extender</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallerrequires.ui" line="0" />
<source>Wrye Bash</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallerrequires.ui" line="0" />
<source>Need</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallerrequires.ui" line="0" />
<source>Game</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallerrequires.ui" line="0" />
<location filename="ui\wizardinstallerrequires.ui" line="0" />
<source>N/A</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallerrequires.ui" line="0" />
<source>Have</source>
<translation type="unfinished" />
</message>
<message>
<location filename="ui\wizardinstallerrequires.ui" line="0" />
<source>Script Extender</source>
<translation type="unfinished" />
</message>
</context>
</TS>
+29 -38
View File
@@ -1,21 +1,19 @@
# -*- encoding: utf-8 -*-
from __future__ import annotations
import sys
from pathlib import Path
from typing import Iterable, List, Optional
import mobase
from typing import Any, Iterable, List, Optional
from wizard.interpreter import WizardInterpreter
from wizard.manager import ManagerModInterface
from wizard.severity import SeverityContext
from wizard.value import SubPackage, SubPackages
from wizard.utils import make_runner_context_factory
from wizard.value import SubPackage, SubPackages
import mobase
class MO2SubPackage(SubPackage):
_tree: mobase.IFileTree
_files: List[str]
@@ -23,12 +21,11 @@ class MO2SubPackage(SubPackage):
super().__init__(tree.name())
self._tree = tree
# We cannot perform lazy iteration on the tree in a Python way so we
# have to list the files:
# we cannot perform lazy iteration on the tree in a Python way so we
# have to list the files
self._files = []
def fn(folder, entry) -> mobase.IFileTree.WalkReturn:
def fn(folder: str, entry: mobase.FileTreeEntry) -> mobase.IFileTree.WalkReturn:
self._files.append(entry.path())
return mobase.IFileTree.CONTINUE
@@ -40,7 +37,6 @@ class MO2SubPackage(SubPackage):
class MO2SeverityContext(SeverityContext):
_organizer: mobase.IOrganizer
def __init__(self, organizer: mobase.IOrganizer):
@@ -52,21 +48,17 @@ class MO2SeverityContext(SeverityContext):
class MO2ManagerModInterface(ManagerModInterface):
_organizer: mobase.IOrganizer
_game: mobase.IPluginGame
_subpackages: SubPackages
def __init__(self, tree: mobase.IFileTree, organizer: mobase.IOrganizer):
self._organizer = organizer
self._game = organizer.managedGame()
checker: mobase.ModDataChecker = self._game.feature(
mobase.ModDataChecker # type: ignore
)
checker = self._organizer.gameFeatures().gameFeature(mobase.ModDataChecker)
# Read the subpackages:
# read the sub-packages
self._subpackages = SubPackages()
for entry in tree:
if isinstance(entry, mobase.IFileTree):
@@ -75,12 +67,12 @@ class MO2ManagerModInterface(ManagerModInterface):
self._subpackages.append(MO2SubPackage(entry))
continue
# Add entry with INI tweaks:
# add entry with INI tweaks
if entry.exists("INI Tweaks") or entry.exists("INI"):
self._subpackages.append(MO2SubPackage(entry))
continue
# We add folder with format "XXX Docs" where "XXX" is a number.
# we add folder with format "XXX Docs" where "XXX" is a number
parts = entry.name().split()
if (
len(parts) >= 2
@@ -104,7 +96,7 @@ class MO2ManagerModInterface(ManagerModInterface):
return 0
def compareSEVersion(self, version: str) -> int:
se = self._game.feature(mobase.ScriptExtender) # type: ignore
se = self._organizer.gameFeatures().gameFeature(mobase.ScriptExtender)
if not se:
return 1
v1 = mobase.VersionInfo(version)
@@ -117,11 +109,11 @@ class MO2ManagerModInterface(ManagerModInterface):
return 0
def compareGEVersion(self, version: str) -> int:
# Cannot do th is in MO2.
# cannot do th is in MO2
return 1
def compareWBVersion(self, version: str) -> int:
# Cannot do this in MO2.
# cannot do this in MO2
return 1
def _resolve(self, filepath: str) -> Optional[Path]:
@@ -135,8 +127,8 @@ class MO2ManagerModInterface(ManagerModInterface):
The path to the given file on the disk, or one of the file mapping
to it in the VFS, or None if the file does not exists.
"""
# TODO: This does not handle weird path that go back (..) and
# then in data again, e.g. ../data/xxx.esp.
# TODO: This does not handle weird path that go back (..) and then in data
# again, e.g. ../data/xxx.esp.
path: Optional[Path]
if filepath.startswith(".."):
path = Path(self._game.dataDirectory().absoluteFilePath(filepath))
@@ -162,7 +154,7 @@ class MO2ManagerModInterface(ManagerModInterface):
def getPluginLoadOrder(self, filename: str, fallback: int = -1) -> int:
return self._organizer.pluginList().loadOrder(filename)
def getPluginStatus(self, filename) -> int:
def getPluginStatus(self, filename: str) -> int:
state = self._organizer.pluginList().state(filename)
if state == mobase.PluginState.ACTIVE:
@@ -171,25 +163,24 @@ class MO2ManagerModInterface(ManagerModInterface):
return 0 # Or 1?
return -1
def getFilename(self, filepath: str) -> str:
path = self._resolve(filepath)
if path:
if path.is_file():
return path.name
def getFilename(self, path: str) -> str:
path_ = self._resolve(path)
if path_:
if path_.is_file():
return path_.name
return ""
def getFolder(self, filepath: str) -> str:
path = self._resolve(filepath)
if path:
if path.is_dir():
return path.name
def getFolder(self, path: str) -> str:
path_ = self._resolve(path)
if path_:
if path_.is_dir():
return path_.name
return ""
def make_interpreter(
base: mobase.IFileTree, organizer: mobase.IOrganizer
) -> WizardInterpreter:
) -> WizardInterpreter[Any]:
manager = MO2ManagerModInterface(base, organizer)
severity = MO2SeverityContext(organizer)
+1 -1
View File
@@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
+13 -3
View File
@@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
@@ -45,7 +45,7 @@
</size>
</property>
<property name="text">
<string>TextLabel</string>
<string notr="true"/>
</property>
</widget>
</item>
@@ -68,7 +68,7 @@
<item>
<widget class="QLabel" name="titleLabel">
<property name="text">
<string>TextLabel</string>
<string notr="true"/>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -82,6 +82,16 @@
<property name="readOnly">
<bool>true</bool>
</property>
<property name="markdown">
<string notr="true"/>
</property>
<property name="html">
<string notr="true">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
+7 -4
View File
@@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
@@ -27,7 +27,7 @@
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,1,0,1">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,2,0,1">
<property name="spacing">
<number>6</number>
</property>
@@ -93,7 +93,7 @@
<enum>QFrame::Sunken</enum>
</property>
<property name="text">
<string>TextLabel</string>
<string notr="true"/>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -136,7 +136,10 @@
<string/>
</property>
<property name="scaledContents">
<bool>true</bool>
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>

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