Switch from Bash to Python #873
Replies: 32 comments 123 replies
-
I've been definitely starting to think that working in Bash has started to become cumbersome. Working out SSO and API in the past week had me literally yelling 'why did I take on maintaining a bash-only program' 😅
Distribution would definitely be better served as some kind of AppImage or via package managers. Plus it would've been easier to find dependencies like
I'm most familiar with Python. Nowhere near an exit, but then again, I never was with Bash either. It seems like the best option. Aside from the redirector already being written in C, I don't see any reason not to use Python. I had actually started working on something of a UI concept in Python. Regardless, I'm down for it. Thanks for everything you've managed to do here. |
Beta Was this translation helpful? Give feedback.
-
|
Ooh, that looks nice. I might start trying to puzzle out how such a rewrite might fit together over the holiday weekend if I'm not to swamped by requests from family. |
Beta Was this translation helpful? Give feedback.
-
|
A bit of brainstorming, these are the functions we'd need to hit, general goals, a few ideas and considerations Primary Functions(Not necessarily in this order)
Secondary Functions
Goals
Ideas:
Unknowns
|
Beta Was this translation helpful? Give feedback.
-
|
Drew up an example filetree, just to help kinda visualize and figure out where the gaps are. modorganizer2-linux-installer/
├─ .github/
│ ├─ ISSUE_TEMPLATE/
│ │ ├─ config.yml # Forces issue templates
│ │ ├─ report-bug.yml # Issue Template - Bug Report
│ │ ├─ request-feature.yml # Issue Template - Feature Request
│ │ └─ request-game.yml # Issue Template - Game Request
│ │
│ ├─ README/
│ │ ├─ modorganizer2-linux-installer.svg # Logo
│ │ ├─ V5-README.md # "RockerBacon Era" README (for archival purposes)
│ │ └─ V6-README.md # Pre-Python (current) README (for archival purposes)
│ │
│ ├─ workflows/
│ │ ├─ build.yml # Action for compiling release [workflow_dispatch]
│ │ └─ formatting.yml # Action for ensuring formatting (linter, black style) [pull_request]
│ ├─ CONTRIBUTING.md # Contribution guidelines and environment setup
│ └─ README.md # Current README
│
├─ configs/
│ ├─ gamesinfo.json # Game Info
│ └─ pluginsinfo.json # Plugin Info
│
├─ src/
│ ├─ ui/ # User interface (replaces 'step'?)
│ │ ├─ precheck.py # Pre-run check (update check, root check, dependencies (if any))
│ │ ├─ select-game.py # Choose game and load related info
│ │ └─ etc...
│ ├─ util/ # Utilities/Helpers (downloader, extracter, etc)
│ │ ├─ nxm/ # Nexus related functions (nxm handlers, api/sso)
│ │ ├─ steam/ # Steam related functions (library scan, prefix handling(?), redirector install, redirector source(?))
│ │ ├─ proton/ # Proton related functions (prefix cleanup, configuration)
│ │ ├─ download.py # Download manager
│ │ ├─ helper.py # File extraction helper
│ │ └─ logger.py # Logging helper
│ ├─ __init__.py # Initializing script
│ └─ uninstall.py # Uninstall process
│
├─ steam-redirector/ # Redirector source(?)
├─ .gitignore
├─ LICENSE
├─ Makefile # Compiling
├─ requirements.txt # Python dependencies
└─ shell.nix # Nix packaging |
Beta Was this translation helpful? Give feedback.
-
|
Damn, you've been busy! 😆 Some thoughts:
|
Beta Was this translation helpful? Give feedback.
-
|
@ashtonqlb brought up SulfurNitride/NaK, another MO2 installer. Thought we might be able to pull some inspiration from it. Thing is, I can't make heads or tails of the project. It's about as AI slop as you can get. (That's not an allegation, their README states it's gen'd with Claude) LINT won't be a 'vibe coding' project. With the amount of hallucinations it gets, and it's tendencies to make scripts 10x more complex than needed.. any code that's clearly been gen'd will be declined. Use AI for the occasional debug, syntax check, or whatever? That's your deal, not mine. Just don't poison this codebase. This isn't specifically directed at anyone. Just a general statement. |
Beta Was this translation helpful? Give feedback.
-
|
rewrite branch created and prepped |
Beta Was this translation helpful? Give feedback.
-
Steam RedirectorAdditional thought on the redirector; I'm not sure how feasible this is - having never played with python EXE compilation - but it would be neat if we could have the utility dynamically "compile" a python script into the redirector on the fly. It adds complexity, but has the benefits of removing the less-understood C dependency, removing the required extra compilation before packaging, and reduces the number of files we rely on being in the correct place at install time. Maybe something to look into later. |
Beta Was this translation helpful? Give feedback.
-
Data Structure DiscussionAs aforementioned, I'm looking at how we might transition game info, resource info, and plugin info (or more uniformly structure in this case) into JSON; and how to best hold the "state" data. WIP in my fork of the rewrite tree. Some thoughts so far:
|
Beta Was this translation helpful? Give feedback.
-
|
Linting is implemented as a pre-commit hook and a pull request action. |
Beta Was this translation helpful? Give feedback.
-
Development EnvironmentI'll try and get started on this over the holiday weekend. To reiterate, I'm thinking a script that builds a...
Goals:
|
Beta Was this translation helpful? Give feedback.
-
|
step/load_gameinfo.sh has been converted. ...I think. I don't own any supported games on Epic to test all the cases with. I had to juryrig the game_info.json with info for Assassin's Creed 1 (and a bunch of placeholders) in order to see if it would even attempt, and those tests were successful. Also added log output with a |
Beta Was this translation helpful? Give feedback.
-
|
steps clean_game_prefix and configure_steam_wineprefix have been added as configure_prefix |
Beta Was this translation helpful? Give feedback.
-
|
Need opinions:
|
Beta Was this translation helpful? Give feedback.
-
|
Implemented script extender download and installation, with the checksum validation for existing downloads. Took a moment to sort out, I'll manage the rest of the external resources tomorrow. |
Beta Was this translation helpful? Give feedback.
-
|
Sorry for the longer than expected absence. My homelab corrupted thanks to a faulty breaker so I spent most of last week getting it back online. Updates to the above list:
Up next, in order:
|
Beta Was this translation helpful? Give feedback.
-
|
The --list and --uninstall command have been added. --listSimply lists all the instances found in the state file --uninstallLists all the instances and lets the user choose to remove one or all of them from the system. It restores the game .exe file from the backup, deletes the mo2-lint instance folder, and removes the instance entry from the state file. Additionally, let's the user choose between a permanent deletion or sending to trash Additionally, using |
Beta Was this translation helpful? Give feedback.
-
|
It's nearly complete! Three steps remain:
I'm planning on handling these in this order as it doesn't make much sense to rewrite the redirector twice (once for the Python translation, once to adapt to the refactor. |
Beta Was this translation helpful? Give feedback.
-
|
Up to this point I've had the game/plugin/resource files in a JSON structure, but I'm starting to lean towards switching to YAML. It's a bit more user-readable and as far as I can tell, takes up less file space. (that being said, I know my original JSON was a bit messy, what with redeclaring script extender versions for each launcher instead of declaring launchers that each SE is compatible with) Examples:JSON[
"oblivion": {
"display_name": "Oblivion",
"nexus_slug": "oblivion",
"launcher_ids": {
"steam": 22330,
"gog": 1458058109
},
"subdirectory": "Oblivion",
"executable": "OblivionLauncher.exe",
"tricks": [
"d3dcompiler_43",
"d3dx9"
],
"script_extenders": {
"epic": null,
"gog": [
{
"version": "22.13",
"runtime": "1.10.163",
"download_url": "https://github.com/llde/xOBSE/releases/download/22.13/xOBSE-22.13.zip",
"checksum": "92d18411a9da803ffaac8c0b005cb6b37c4f9ce2f1571215f39363760d832bf2",
"file_whitelist": [
"Data",
"obse_1_2_416.dll",
"obse_editor_1_2.dll",
"obse_loader.exe"
]
}
],
"steam": [
{
"version": "22.13",
"runtime": "1.10.163",
"download_url": "https://github.com/llde/xOBSE/releases/download/22.13/xOBSE-22.13.zip",
"checksum": "92d18411a9da803ffaac8c0b005cb6b37c4f9ce2f1571215f39363760d832bf2",
"file_whitelist": [
"Data",
"obse_1_2_416.dll",
"obse_editor_1_2.dll",
"obse_steam_loader.dll",
"obse_loader.exe"
]
}
]
}
}
]YAMLoblivion:
name: 'The Elder Scrolls IV: Oblivion'
nexus_slug: oblivion
launcher_ids:
steam: 22330
gog: 1458058109
subdirectory: Oblivion
executable: OblivionLauncher.exe
tricks:
- "d3dcompiler_43"
- "d3dx9"
script_extender:
- version: "22.13"
runtime:
steam:
- "1.2.0416"
gog:
- "1.2.0416"
download:
checksum: 92d18411a9da803ffaac8c0b005cb6b37c4f9ce2f1571215f39363760d832bf2
direct:
url: "http://www.uesp.net/downloads/files/obse/obse_22_13.zip"
file_whitelist:
- "Data"
- "obse_1_2_416.dll"
- "obse_editor_1_2.dll"
- "obse_loader.exe"
- "obse_steam_loader.dll"I think my main gripe is just the {} structuring |
Beta Was this translation helpful? Give feedback.
-
|
Hi, I'm wondering whether the redirector is actually still needed? The main argument in #275 (comment) against using a Steam shortcut was that it seems to be unstable. I don't know if Steam has made changes to their VDF structure in the past 4 years. On the other hand, I was playing the Tuxborn Wabbajack list for several weeks now, which is installed using a Steam shortcut and doesn't use a redirector or similar mechanism, but simply calls the SKSE launcher. I'm also working on a setup for linux, which will allow for easy developing of mods and/or modlists using MO2. This setup also runs with a steam shortcut, currently calling the native skyrim launcher, but eventually should end up calling the SKSE launcher. No redirector is needed for this. In both occasions I didn't come upon any issues which were related to using a Steam shortcut. So, have you checked about the state of actually using native steam mechanics, and additionally applying tricks in the games compatdata folder would be a working alternative? I'm aware you are currently working on placing the redirector outside the game directory, which would be, for me, a must-have for the installer to be an alternative to a manual setup, but still having no actual need anymore for this would, in my opinion, even better. |
Beta Was this translation helpful? Give feedback.
-
|
Alright! As of 82c4597, the only things left to do are refactor the NXM handler and the Redirector rewrite. Then maybe one more general refactor, to make sure things are clean. At least, I believe that's all that needs to be done. Some testing would be great. @tim-elmer @waebbl @shawly @daemon-mouse @AceOfKestrels If you do indulge me, I'd recommend using a directory separate from your current MO2 installs, just in case something goes wrong. A build of the most recent commit is available in the Action artifacts. https://github.com/Furglitch/modorganizer2-linux-installer/actions/runs/21856057709 As for using it, I've been writing documentation alongside the code. Improvements since my last update:
Things I have tested:
Then I did it all again until no weird issues were left over Known issues:
If you do test, please let me know of any issues you run into, or any edge cases I may have missed! Thanks a ton. Ideas I need feedback on:
Again, thanks for all your help thus far. I might take a small 1-2 day break as my server's busted and I gotta get that back up since I have a few people who use the services on it. |
Beta Was this translation helpful? Give feedback.
-
|
Is there a build that currently runs? I wanna see if will work on nixos or if a flake will be needed. |
Beta Was this translation helpful? Give feedback.
-
|
I've started reviewing the new Python code now that I have a bit of time. Would you be interested in making this a uv project? It would make it much easier for others to contribute by locking in dependencies, rather than using a requirements.txt file. This prevents situations where two developers see different behavior because they crafted their virtual environments at different times — using uv, every developer's environment would be identical and easy to set up. To boot, it would make the Makefile much smaller. The only downside is that developers would need to install uv, but this is becoming increasingly common for Python programmers. If you're interested, let me know and I can submit a PR converting the project over to uv so you can see what I mean and try it for yourself. On another note, I absolutely love seeing the use of ruff and pydantic here! |
Beta Was this translation helpful? Give feedback.
-
|
I'll just post the artifact list here so that people can test with the most recent version lol https://github.com/Furglitch/modorganizer2-linux-installer/actions/workflows/build-artifact.yml |
Beta Was this translation helpful? Give feedback.
-
|
I'm going to be out of state this week for work training (that I've already received.. yay), but when I come back, I'll start work on the handler and redirector. |
Beta Was this translation helpful? Give feedback.
-
|
Just curious about how the current instances of MO2 with the switch to the Python version will be handled. Will this do an in-place upgrade of the existing instances, or will all prior version instances be incompatible and need to be fully replaced? If they need to be fully replaced, will there be any sort of an option to import mods from prior version instances? |
Beta Was this translation helpful? Give feedback.
-
|
I want to apologize once again for another extended absence. Things have been... hectic. My home server went down (not fixed), my computer decided to die on me (fixed), i've been out of town for work training quite a bit, and we're all of a sudden moving apartments at the end of the month. Thanks for the patience. 5524a96 fixes the broken-until-now NXM:// handler, at least as far as I could think to test it. I'll be actively working on the new redirector system over, and hope to have it done in the next week. |
Beta Was this translation helpful? Give feedback.
-
|
The redirector is finished!* At first I thought we wouldn't need it at all, but it turns out proton/wine doesn't play well with symlinks as a launch option So we still have the redirector, but it's fully in python and with the launch option implementation, we no longer need to replace the game's executable to run! Which brings the added bonus of bringing LOOT functionality back to single-executable games like Starfield (tested) :) I also managed to implement the same functionality in Heroic! So all three launchers (Steam, Heroic, and Lutris) are fully supported with the new redirector and launch option system. If anyone wants to give it a try, the lastest artifact is here. * I haven't tested as thoroughly as possible since it's 0400, but initial tests look good! Tests were run with Oblivion on all three launchers, and Starfield on Steam, with basic MO2 launching, game launching, LOOT tests, and game launching. I'll run another batch of testing (this run) tomorrow, and I would appreciate if anyone else could also give it a try and report any issues they encounter. @tim-elmer | @daemon-mouse |
Beta Was this translation helpful? Give feedback.
-
|
Another week out of town for work training starting tomorrow afternoon. Hopefully the morning is slow so I can churn out fixes for some of the major issues. |
Beta Was this translation helpful? Give feedback.
-
|
I got MO2 launching for morrowind and oblivion on steam deck but not for fallout3 and falloutnv. I still don't know why uv-installed protontricks needs to be pointed at winetricks when the standard python/pip-installed package finds something (not sure where). My manual workaround is to download winetricks earlier than the rest of the external resources and set $WINETRICKS; I submitted a PR that implements this. I also found a shortfall in the launch option selector solution. Games launched via the command Btw @Furglitch nxm links have never worked for me on steam deck even with the bash version of the code. I was able to configure the link handler but I think it took editing the .desktop file to show up in the system link handler GUI. MO2 still doesn't react tho |
Beta Was this translation helpful? Give feedback.






Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I love that this project exists, I appreciate the work that's gone into it, and I love that I've been able to make some small contributions to it. That said, every time I try to work on this codebase I get a headache.
As rockerbacon mentioned back in 2020, the main reason for using bash was ease of integration and rapid iteration. Valid as that may have been, I'm beginning to wonder if the project wouldn't be better served by an easier to understand language.
The project has grown significantly in features, and I'm concerned that maintainability may begin to suffer as the logic becomes harder to understand. We're also increasing our dependency load as such, and it'd be very nice to be able to provide the user a complete or automatic package rather than "install x, y, and z". I've also run into the hurdle of debugging bash scripts multiple times, and can't help but think that hunting down issues would be easier with an actual debugger.
As for what to move to, I'd lean towards Python due to its ubiquity and friendliness, but I'm open to other suggestions - ideally minimizing dependencies (Python, for example, is already on most systems, but something like .NET is much less common) - and maximizing ease of adoption (we don't really need C's performance, and neither Furglitch nor myself are terribly familiar with it).
Thoughts? (apologies for the issue, we don't have discussions enabled)
Beta Was this translation helpful? Give feedback.
All reactions