mirror of
https://github.com/ModOrganizer2/modorganizer-installer_wizard.git
synced 2026-07-27 14:07:59 -07:00
Compare commits
28
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d86116a6af | ||
|
|
ac75677fe3 | ||
|
|
979a060373 | ||
|
|
7f93d4f77b | ||
|
|
0f4f666c71 | ||
|
|
a0ca112ed0 | ||
|
|
7ef97f047c | ||
|
|
aff1cbb944 | ||
|
|
6492f84eac | ||
|
|
7b3dc82f46 | ||
|
|
76faacba19 | ||
|
|
0c8d7261fd | ||
|
|
3cf15300fb | ||
|
|
3bfd181704 | ||
|
|
bffeb8c05f | ||
|
|
f7a9c95d5b | ||
|
|
793ab6273b | ||
|
|
7e5ec2d11a | ||
|
|
ca343602ec | ||
|
|
e2202073dc | ||
|
|
fb91a1d2b6 | ||
|
|
9f71ac1517 | ||
|
|
775d764950 | ||
|
|
538a0f73e9 | ||
|
|
ecefc5eb8a | ||
|
|
b9653b8322 | ||
|
|
b39be8c295 | ||
|
|
28deb0ce25 |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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><html><head/><body><p><span style=" font-weight:600;">Warning:</span> The following version requirements are not met for using this installer.</p></body></html></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
@@ -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,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 {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
bain-wizard-interpreter==1.0.4
|
||||
Generated
+220
@@ -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"
|
||||
@@ -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"
|
||||
@@ -1,7 +0,0 @@
|
||||
black
|
||||
PyQt5
|
||||
mypy
|
||||
flake8
|
||||
flake8-black
|
||||
mobase-stubs
|
||||
git+https://github.com/Holt59/bain-wizard-interpreter
|
||||
@@ -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
|
||||
@@ -0,0 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
add_custom_target(installer_wizard ALL)
|
||||
mo2_configure_python(installer_wizard MODULE)
|
||||
+1
-2
@@ -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
File diff suppressed because it is too large
Load Diff
+97
-90
@@ -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)
|
||||
|
||||
@@ -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><html><head/><body><p><span style=" font-weight:600;">Warning:</span> The following version requirements are not met for using this installer.</p></body></html></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
@@ -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)
|
||||
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user