umu-commander 1.5.3__tar.gz → 1.5.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of umu-commander might be problematic. Click here for more details.
- umu_commander-1.5.5/.idea/shelf/Uncommitted_changes_before_rebase_[Changes]/shelved.patch +229 -0
- {umu_commander-1.5.3 → umu_commander-1.5.5}/.idea/workspace.xml +89 -87
- {umu_commander-1.5.3 → umu_commander-1.5.5}/PKG-INFO +10 -3
- {umu_commander-1.5.3 → umu_commander-1.5.5}/README.md +8 -1
- {umu_commander-1.5.3 → umu_commander-1.5.5}/pyproject.toml +7 -4
- umu_commander-1.5.5/src/umu_commander/configuration.py +77 -0
- umu_commander-1.5.5/src/umu_commander/database.py +54 -0
- {umu_commander-1.5.3 → umu_commander-1.5.5}/src/umu_commander/main.py +6 -6
- {umu_commander-1.5.3 → umu_commander-1.5.5}/src/umu_commander/proton.py +4 -4
- {umu_commander-1.5.3 → umu_commander-1.5.5}/src/umu_commander/tracking.py +7 -7
- {umu_commander-1.5.3 → umu_commander-1.5.5}/src/umu_commander/umu_config.py +8 -3
- {umu_commander-1.5.3 → umu_commander-1.5.5}/src/umu_commander/util.py +1 -1
- {umu_commander-1.5.3 → umu_commander-1.5.5}/tests/test_config.py +2 -2
- {umu_commander-1.5.3 → umu_commander-1.5.5}/tests/test_db.py +4 -3
- {umu_commander-1.5.3 → umu_commander-1.5.5}/tests/test_proton.py +1 -1
- {umu_commander-1.5.3 → umu_commander-1.5.5}/tests/test_tracking.py +2 -2
- umu_commander-1.5.3/src/umu_commander/configuration.py +0 -72
- umu_commander-1.5.3/src/umu_commander/database.py +0 -43
- {umu_commander-1.5.3 → umu_commander-1.5.5}/.gitignore +0 -0
- {umu_commander-1.5.3 → umu_commander-1.5.5}/.idea/.gitignore +0 -0
- {umu_commander-1.5.3 → umu_commander-1.5.5}/.idea/inspectionProfiles/Project_Default.xml +0 -0
- {umu_commander-1.5.3 → umu_commander-1.5.5}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
- {umu_commander-1.5.3 → umu_commander-1.5.5}/.idea/misc.xml +0 -0
- {umu_commander-1.5.3 → umu_commander-1.5.5}/.idea/modules.xml +0 -0
- {umu_commander-1.5.3 → umu_commander-1.5.5}/.idea/umu-commander.iml +0 -0
- {umu_commander-1.5.3 → umu_commander-1.5.5}/.idea/vcs.xml +0 -0
- {umu_commander-1.5.3 → umu_commander-1.5.5}/LICENSE.txt +0 -0
- {umu_commander-1.5.3 → umu_commander-1.5.5}/example_config.toml +0 -0
- {umu_commander-1.5.3 → umu_commander-1.5.5}/src/umu_commander/__init__.py +0 -0
- {umu_commander-1.5.3 → umu_commander-1.5.5}/src/umu_commander/classes.py +0 -0
- {umu_commander-1.5.3 → umu_commander-1.5.5}/tests/__init__.py +0 -0
- {umu_commander-1.5.3 → umu_commander-1.5.5}/tests/test_manual.py +0 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
Index: tests/test_db.py
|
|
2
|
+
IDEA additional info:
|
|
3
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
|
|
4
|
+
<+>import unittest\nfrom json import JSONDecodeError\n\nimport umu_commander.configuration as config\nfrom tests import *\nfrom umu_commander.database import Database as db\n\n\nclass Database(unittest.TestCase):\n def setUp(self):\n config.DB_DIR = TESTING_DIR\n setup()\n\n def tearDown(self):\n teardown()\n\n def test_missing_db(self):\n db.load()\n self.assertEqual(db.get(), {})\n\n def test_malformed_db(self):\n with open(os.path.join(config.DB_DIR, config.DB_NAME), \"tw\") as db_file:\n db_file.write(\"{\")\n\n with self.assertRaises(JSONDecodeError):\n db.load()\n\n def test_addition_removal(self):\n db.load()\n db.get(PROTON_DIR_1, PROTON_BIG).append(USER_DIR)\n\n self.assertIn(PROTON_BIG, db.get(PROTON_DIR_1))\n self.assertIn(USER_DIR, db.get(PROTON_DIR_1, PROTON_BIG))\n\n db.get(PROTON_DIR_1, PROTON_BIG).remove(USER_DIR)\n\n self.assertIn(PROTON_BIG, db.get(PROTON_DIR_1))\n self.assertNotIn(USER_DIR, db.get(PROTON_DIR_1, PROTON_BIG))\n\n del db.get(PROTON_DIR_1)[PROTON_BIG]\n self.assertNotIn(PROTON_BIG, db.get(PROTON_DIR_1))\n
|
|
5
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
|
|
6
|
+
<+>UTF-8
|
|
7
|
+
===================================================================
|
|
8
|
+
diff --git a/tests/test_db.py b/tests/test_db.py
|
|
9
|
+
--- a/tests/test_db.py (revision 2c990ed1cab5a20498dc2cfe9bd4e331f60cb3af)
|
|
10
|
+
+++ b/tests/test_db.py (date 1754467945899)
|
|
11
|
+
@@ -2,8 +2,8 @@
|
|
12
|
+
from json import JSONDecodeError
|
|
13
|
+
|
|
14
|
+
import umu_commander.configuration as config
|
|
15
|
+
+import umu_commander.database as db
|
|
16
|
+
from tests import *
|
|
17
|
+
-from umu_commander.database import Database as db
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Database(unittest.TestCase):
|
|
21
|
+
Index: tests/test_config.py
|
|
22
|
+
IDEA additional info:
|
|
23
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
|
|
24
|
+
<+>import os.path\nimport unittest\n\nimport umu_commander.configuration as config\nfrom tests import *\nfrom umu_commander import configuration\n\n\nclass Config(unittest.TestCase):\n def setUp(self):\n configuration._CONFIG_DIR = TESTING_DIR\n configuration.DB_DIR = TESTING_DIR\n setup()\n\n def tearDown(self):\n teardown()\n\n def test_missing_config(self):\n config.load()\n self.assertTrue(\n os.path.exists(os.path.join(TESTING_DIR, configuration._CONFIG_NAME))\n )\n config.load()\n
|
|
25
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
|
|
26
|
+
<+>UTF-8
|
|
27
|
+
===================================================================
|
|
28
|
+
diff --git a/tests/test_config.py b/tests/test_config.py
|
|
29
|
+
--- a/tests/test_config.py (revision 2c990ed1cab5a20498dc2cfe9bd4e331f60cb3af)
|
|
30
|
+
+++ b/tests/test_config.py (date 1754467762383)
|
|
31
|
+
@@ -8,7 +8,7 @@
|
|
32
|
+
|
|
33
|
+
class Config(unittest.TestCase):
|
|
34
|
+
def setUp(self):
|
|
35
|
+
- configuration._CONFIG_DIR = TESTING_DIR
|
|
36
|
+
+ configuration.CONFIG_DIR = TESTING_DIR
|
|
37
|
+
configuration.DB_DIR = TESTING_DIR
|
|
38
|
+
setup()
|
|
39
|
+
|
|
40
|
+
@@ -18,6 +18,6 @@
|
|
41
|
+
def test_missing_config(self):
|
|
42
|
+
config.load()
|
|
43
|
+
self.assertTrue(
|
|
44
|
+
- os.path.exists(os.path.join(TESTING_DIR, configuration._CONFIG_NAME))
|
|
45
|
+
+ os.path.exists(os.path.join(TESTING_DIR, configuration.CONFIG_NAME))
|
|
46
|
+
)
|
|
47
|
+
config.load()
|
|
48
|
+
Index: src/umu_commander/database.py
|
|
49
|
+
IDEA additional info:
|
|
50
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
|
|
51
|
+
<+>import json\nimport os\nfrom collections import defaultdict\n\nimport umu_commander.configuration as config\n\n\nclass Database:\n _db: defaultdict[str, defaultdict[str, list[str]]]\n\n @staticmethod\n def load():\n if not os.path.exists(config.DB_DIR):\n os.mkdir(config.DB_DIR)\n\n try:\n with open(os.path.join(config.DB_DIR, config.DB_NAME), \"rt\") as db_file:\n Database._db = defaultdict(lambda: defaultdict(list))\n Database._db.update(json.load(db_file))\n\n except FileNotFoundError:\n Database._db = defaultdict(lambda: defaultdict(list))\n\n @staticmethod\n def dump():\n with open(os.path.join(config.DB_DIR, config.DB_NAME), \"wt\") as db_file:\n # noinspection PyTypeChecker\n json.dump(Database._db, db_file, indent=\"\\t\")\n\n @staticmethod\n def get(\n proton_dir: str = None, proton_ver: str = None\n ) -> dict[str, dict[str, list[str]]] | dict[str, list[str]] | list[str]:\n if proton_dir is None and proton_ver is None:\n return Database._db\n\n if proton_ver is None:\n return Database._db[proton_dir]\n\n if proton_ver not in Database._db[proton_dir]:\n Database._db[proton_dir][proton_ver] = []\n\n return Database._db[proton_dir][proton_ver]\n
|
|
52
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
|
|
53
|
+
<+>UTF-8
|
|
54
|
+
===================================================================
|
|
55
|
+
diff --git a/src/umu_commander/database.py b/src/umu_commander/database.py
|
|
56
|
+
--- a/src/umu_commander/database.py (revision 2c990ed1cab5a20498dc2cfe9bd4e331f60cb3af)
|
|
57
|
+
+++ b/src/umu_commander/database.py (date 1754467762394)
|
|
58
|
+
@@ -4,40 +4,46 @@
|
|
59
|
+
|
|
60
|
+
import umu_commander.configuration as config
|
|
61
|
+
|
|
62
|
+
+_db: defaultdict[str, defaultdict[str, list[str]]] = defaultdict(
|
|
63
|
+
+ lambda: defaultdict(list)
|
|
64
|
+
+)
|
|
65
|
+
|
|
66
|
+
-class Database:
|
|
67
|
+
- _db: defaultdict[str, defaultdict[str, list[str]]]
|
|
68
|
+
|
|
69
|
+
- @staticmethod
|
|
70
|
+
- def load():
|
|
71
|
+
- if not os.path.exists(config.DB_DIR):
|
|
72
|
+
- os.mkdir(config.DB_DIR)
|
|
73
|
+
+def load():
|
|
74
|
+
+ global _db
|
|
75
|
+
+
|
|
76
|
+
+ if not os.path.exists(config.DB_DIR):
|
|
77
|
+
+ os.mkdir(config.DB_DIR)
|
|
78
|
+
|
|
79
|
+
- try:
|
|
80
|
+
- with open(os.path.join(config.DB_DIR, config.DB_NAME), "rt") as db_file:
|
|
81
|
+
- Database._db = defaultdict(lambda: defaultdict(list))
|
|
82
|
+
- Database._db.update(json.load(db_file))
|
|
83
|
+
+ db_path: str = os.path.join(config.DB_DIR, config.DB_NAME)
|
|
84
|
+
+ if not os.path.exists(db_path):
|
|
85
|
+
+ return
|
|
86
|
+
|
|
87
|
+
- except FileNotFoundError:
|
|
88
|
+
- Database._db = defaultdict(lambda: defaultdict(list))
|
|
89
|
+
+ with open(os.path.join(db_path), "rt") as db_file:
|
|
90
|
+
+ _db.update(json.load(db_file))
|
|
91
|
+
|
|
92
|
+
- @staticmethod
|
|
93
|
+
- def dump():
|
|
94
|
+
- with open(os.path.join(config.DB_DIR, config.DB_NAME), "wt") as db_file:
|
|
95
|
+
- # noinspection PyTypeChecker
|
|
96
|
+
- json.dump(Database._db, db_file, indent="\t")
|
|
97
|
+
+
|
|
98
|
+
+def dump():
|
|
99
|
+
+ if not os.path.exists(config.DB_DIR):
|
|
100
|
+
+ os.mkdir(config.DB_DIR)
|
|
101
|
+
+
|
|
102
|
+
+ with open(os.path.join(config.DB_DIR, config.DB_NAME), "wt") as db_file:
|
|
103
|
+
+ # noinspection PyTypeChecker
|
|
104
|
+
+ json.dump(_db, db_file, indent="\t")
|
|
105
|
+
|
|
106
|
+
- @staticmethod
|
|
107
|
+
- def get(
|
|
108
|
+
- proton_dir: str = None, proton_ver: str = None
|
|
109
|
+
- ) -> dict[str, dict[str, list[str]]] | dict[str, list[str]] | list[str]:
|
|
110
|
+
- if proton_dir is None and proton_ver is None:
|
|
111
|
+
- return Database._db
|
|
112
|
+
+
|
|
113
|
+
+def get(
|
|
114
|
+
+ proton_dir: str = None, proton_ver: str = None
|
|
115
|
+
+) -> dict[str, dict[str, list[str]]] | dict[str, list[str]] | list[str]:
|
|
116
|
+
+ global _db
|
|
117
|
+
+
|
|
118
|
+
+ if proton_dir is None and proton_ver is None:
|
|
119
|
+
+ return _db
|
|
120
|
+
|
|
121
|
+
- if proton_ver is None:
|
|
122
|
+
- return Database._db[proton_dir]
|
|
123
|
+
+ if proton_ver is None:
|
|
124
|
+
+ return _db[proton_dir]
|
|
125
|
+
|
|
126
|
+
- if proton_ver not in Database._db[proton_dir]:
|
|
127
|
+
- Database._db[proton_dir][proton_ver] = []
|
|
128
|
+
+ if proton_ver not in _db[proton_dir]:
|
|
129
|
+
+ _db[proton_dir][proton_ver] = []
|
|
130
|
+
|
|
131
|
+
- return Database._db[proton_dir][proton_ver]
|
|
132
|
+
+ return _db[proton_dir][proton_ver]
|
|
133
|
+
Index: tests/test_tracking.py
|
|
134
|
+
IDEA additional info:
|
|
135
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
|
|
136
|
+
<+>import unittest\n\nimport umu_commander.configuration as config\nfrom tests import *\nfrom umu_commander import tracking\nfrom umu_commander.classes import ProtonVer\nfrom umu_commander.database import Database as db\n\n\nclass Tracking(unittest.TestCase):\n def setUp(self):\n config.DB_DIR = TESTING_DIR\n setup()\n db.load()\n\n def tearDown(self):\n teardown()\n\n def test_track_untrack(self):\n os.chdir(USER_DIR)\n\n tracking.track(ProtonVer(PROTON_DIR_1, PROTON_BIG), refresh_versions=False)\n self.assertIn(PROTON_BIG, db.get(PROTON_DIR_1))\n self.assertIn(USER_DIR, db.get(PROTON_DIR_1, PROTON_BIG))\n\n tracking.untrack(quiet=True)\n self.assertIn(PROTON_BIG, db.get(PROTON_DIR_1))\n self.assertNotIn(USER_DIR, db.get(PROTON_DIR_1, PROTON_BIG))\n\n def test_track_auto_untrack(self):\n os.chdir(USER_DIR)\n\n tracking.track(ProtonVer(PROTON_DIR_1, PROTON_BIG), refresh_versions=False)\n self.assertIn(PROTON_BIG, db.get(PROTON_DIR_1))\n self.assertIn(USER_DIR, db.get(PROTON_DIR_1, PROTON_BIG))\n\n os.rmdir(USER_DIR)\n tracking.untrack_unlinked()\n self.assertIn(PROTON_BIG, db.get(PROTON_DIR_1))\n self.assertNotIn(\n USER_DIR,\n db.get(PROTON_DIR_1, PROTON_BIG),\n \"Auto untrack did not untrack removed directory.\",\n )\n
|
|
137
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
|
|
138
|
+
<+>UTF-8
|
|
139
|
+
===================================================================
|
|
140
|
+
diff --git a/tests/test_tracking.py b/tests/test_tracking.py
|
|
141
|
+
--- a/tests/test_tracking.py (revision 2c990ed1cab5a20498dc2cfe9bd4e331f60cb3af)
|
|
142
|
+
+++ b/tests/test_tracking.py (date 1754467945864)
|
|
143
|
+
@@ -1,10 +1,10 @@
|
|
144
|
+
import unittest
|
|
145
|
+
|
|
146
|
+
import umu_commander.configuration as config
|
|
147
|
+
+import umu_commander.database as db
|
|
148
|
+
from tests import *
|
|
149
|
+
from umu_commander import tracking
|
|
150
|
+
from umu_commander.classes import ProtonVer
|
|
151
|
+
-from umu_commander.database import Database as db
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class Tracking(unittest.TestCase):
|
|
155
|
+
Index: src/umu_commander/proton.py
|
|
156
|
+
IDEA additional info:
|
|
157
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
|
|
158
|
+
<+>import os\nimport re\nimport subprocess\n\nimport umu_commander.configuration as config\nfrom umu_commander.classes import ProtonDir, ProtonVer\nfrom umu_commander.database import Database as db\n\n\ndef _natural_sort_proton_ver_key(p: ProtonVer, _nsre=re.compile(r\"(\\d+)\")):\n s: str = p.version_num\n return [int(text) if text.isdigit() else text for text in _nsre.split(s)]\n\n\ndef refresh_proton_versions():\n print(\"Updating umu Proton.\")\n umu_update_process = subprocess.run(\n [\"umu-run\", '\"\"'],\n env={\"PROTONPATH\": \"UMU-Latest\", \"UMU_LOG\": \"debug\"},\n capture_output=True,\n text=True,\n )\n\n for line in umu_update_process.stderr.split(\"\\n\"):\n if \"PROTONPATH\" in line and \"/\" in line:\n try:\n left: int = line.rfind(\"/\") + 1\n print(f\"Using {line[left:len(line) - 1]}.\")\n except ValueError:\n print(\"Could not fetch latest UMU-Proton.\")\n\n break\n\n\ndef _sort_proton_versions(versions: list[ProtonVer]) -> list[ProtonVer]:\n return sorted(versions, key=_natural_sort_proton_ver_key, reverse=True)\n\n\ndef collect_proton_versions(\n sort: bool = False, user_count: bool = False\n) -> list[ProtonDir]:\n def get_user_count(proton_dir: str, proton_ver) -> str:\n return (\n \"(\" + str(len(db.get(proton_dir, proton_ver))) + \")\"\n if proton_ver in db.get(proton_dir)\n else \"(-)\"\n )\n\n proton_dirs: list[ProtonDir] = []\n for proton_dir in config.PROTON_PATHS:\n versions: list[ProtonVer] = [\n ProtonVer(\n proton_dir,\n version,\n get_user_count(proton_dir, version) if user_count else \"\",\n )\n for version in os.listdir(proton_dir)\n if os.path.isdir(os.path.join(proton_dir, version))\n ]\n\n if sort:\n versions = sorted(versions, key=_natural_sort_proton_ver_key, reverse=True)\n\n proton_dirs.append(\n ProtonDir(proton_dir, f\"Proton versions in {proton_dir}:\", versions)\n )\n\n return proton_dirs\n\n\ndef get_latest_umu_proton():\n umu_proton_versions: list[ProtonVer] = [\n ProtonVer(config.UMU_PROTON_PATH, version)\n for version in os.listdir(config.UMU_PROTON_PATH)\n if \"UMU\" in version\n and os.path.isdir(os.path.join(config.UMU_PROTON_PATH, version))\n ]\n umu_proton_versions = sorted(\n umu_proton_versions, key=_natural_sort_proton_ver_key, reverse=True\n )\n\n return umu_proton_versions[0].version_num\n
|
|
159
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
|
|
160
|
+
<+>UTF-8
|
|
161
|
+
===================================================================
|
|
162
|
+
diff --git a/src/umu_commander/proton.py b/src/umu_commander/proton.py
|
|
163
|
+
--- a/src/umu_commander/proton.py (revision 2c990ed1cab5a20498dc2cfe9bd4e331f60cb3af)
|
|
164
|
+
+++ b/src/umu_commander/proton.py (date 1754467945890)
|
|
165
|
+
@@ -3,8 +3,8 @@
|
|
166
|
+
import subprocess
|
|
167
|
+
|
|
168
|
+
import umu_commander.configuration as config
|
|
169
|
+
+import umu_commander.database as db
|
|
170
|
+
from umu_commander.classes import ProtonDir, ProtonVer
|
|
171
|
+
-from umu_commander.database import Database as db
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _natural_sort_proton_ver_key(p: ProtonVer, _nsre=re.compile(r"(\d+)")):
|
|
175
|
+
Index: src/umu_commander/tracking.py
|
|
176
|
+
IDEA additional info:
|
|
177
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
|
|
178
|
+
<+>import os\nimport shutil\n\nfrom umu_commander.classes import ProtonDir, ProtonVer\nfrom umu_commander.database import Database as db\nfrom umu_commander.proton import (\n collect_proton_versions,\n get_latest_umu_proton,\n refresh_proton_versions,\n)\nfrom umu_commander.util import (\n get_selection,\n)\n\n\ndef untrack(quiet: bool = False):\n current_dir: str = os.getcwd()\n for proton_dir in db.get().keys():\n for proton_ver in db.get(proton_dir):\n if current_dir in db.get(proton_dir, proton_ver):\n db.get(proton_dir, proton_ver).remove(current_dir)\n\n if not quiet:\n print(\"Directory removed from all user lists.\")\n\n\ndef track(\n proton_ver: ProtonVer = None, refresh_versions: bool = True, quiet: bool = False\n):\n if refresh_versions:\n refresh_proton_versions()\n\n if proton_ver is None:\n proton_ver: ProtonVer = get_selection(\n \"Select Proton version to add directory as user:\",\n None,\n collect_proton_versions(sort=True),\n ).as_proton_ver()\n\n untrack(quiet=True)\n current_directory: str = os.getcwd()\n db.get(proton_ver.dir, proton_ver.version_num).append(current_directory)\n\n if not quiet:\n print(\n f\"Directory {current_directory} added to Proton version's {proton_ver.version_num} in {proton_ver.dir} user list.\"\n )\n\n\ndef users():\n proton_dirs: list[ProtonDir] = collect_proton_versions(sort=True, user_count=True)\n\n proton_ver: ProtonVer = get_selection(\n \"Select Proton version to view user list:\", None, proton_dirs\n ).as_proton_ver()\n\n if proton_ver.dir in db.get() and proton_ver.version_num in db.get(proton_ver.dir):\n version_users: list[str] = db.get(proton_ver.dir, proton_ver.version_num)\n if len(version_users) > 0:\n print(f\"Directories using {proton_ver.version_num} of {proton_ver.dir}:\")\n print(*version_users, sep=\"\\n\")\n else:\n print(\"No directories currently use this version.\")\n else:\n print(\"This version hasn't been used by umu before.\")\n\n\ndef delete():\n for proton_dir in db.get().keys():\n for proton_ver, version_users in db.get(proton_dir).copy().items():\n if proton_ver == get_latest_umu_proton():\n continue\n\n if len(version_users) == 0:\n selection: str = input(\n f\"{proton_ver} in {proton_dir} has no using directories, delete? (Y/N) ? \"\n )\n if selection.lower() == \"y\":\n try:\n shutil.rmtree(os.path.join(proton_dir, proton_ver))\n except FileNotFoundError:\n pass\n del db.get(proton_dir)[proton_ver]\n\n\ndef untrack_unlinked():\n for proton_dir in db.get().keys():\n for proton_ver, version_users in db.get()[proton_dir].items():\n for user in version_users:\n if not os.path.exists(user):\n db.get(proton_dir, proton_ver).remove(user)\n
|
|
179
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
|
|
180
|
+
<+>UTF-8
|
|
181
|
+
===================================================================
|
|
182
|
+
diff --git a/src/umu_commander/tracking.py b/src/umu_commander/tracking.py
|
|
183
|
+
--- a/src/umu_commander/tracking.py (revision 2c990ed1cab5a20498dc2cfe9bd4e331f60cb3af)
|
|
184
|
+
+++ b/src/umu_commander/tracking.py (date 1754467945881)
|
|
185
|
+
@@ -1,8 +1,8 @@
|
|
186
|
+
import os
|
|
187
|
+
import shutil
|
|
188
|
+
|
|
189
|
+
+import umu_commander.database as db
|
|
190
|
+
from umu_commander.classes import ProtonDir, ProtonVer
|
|
191
|
+
-from umu_commander.database import Database as db
|
|
192
|
+
from umu_commander.proton import (
|
|
193
|
+
collect_proton_versions,
|
|
194
|
+
get_latest_umu_proton,
|
|
195
|
+
Index: src/umu_commander/main.py
|
|
196
|
+
IDEA additional info:
|
|
197
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
|
|
198
|
+
<+>#!/usr/bin/python3\nimport os\nimport sys\nfrom json import JSONDecodeError\n\nimport umu_commander.configuration as config\nfrom umu_commander import tracking, umu_config\nfrom umu_commander.classes import ExitCode\nfrom umu_commander.configuration import _CONFIG_DIR, _CONFIG_NAME\nfrom umu_commander.database import Database as db\n\n\ndef print_help():\n print(\n \"umu-commander is an interactive CLI tool to help you manage Proton versions used by umu, as well as create enhanced launch configs.\",\n \"\",\n \"For details, explanations, and more, see the README.md file, or visit https://github.com/Mpaxlamitsounas/umu-commander.\",\n sep=\"\\n\",\n )\n\n\ndef main() -> ExitCode:\n try:\n config.load()\n except (JSONDecodeError, KeyError):\n config_path: str = os.path.join(_CONFIG_DIR, _CONFIG_NAME)\n print(f\"Config file at {config_path} could not be read.\")\n os.rename(config_path, os.path.join(_CONFIG_DIR, _CONFIG_NAME + \".old\"))\n\n try:\n db.load()\n except JSONDecodeError:\n db_path: str = os.path.join(config.DB_DIR, config.DB_NAME)\n print(f\"Tracking file at {db_path} could not be read.\")\n os.rename(db_path, os.path.join(config.DB_DIR, config.DB_NAME + \".old\"))\n\n if len(sys.argv) == 1:\n print_help()\n return ExitCode.SUCCESS.value\n\n verb: str = sys.argv[1]\n match verb:\n case \"track\":\n tracking.track()\n case \"untrack\":\n tracking.untrack()\n case \"users\":\n tracking.users()\n case \"delete\":\n tracking.delete()\n case \"create\":\n umu_config.create()\n case \"run\":\n umu_config.run()\n case _:\n print(\"Invalid verb.\")\n print_help()\n return ExitCode.INVALID_SELECTION.value\n\n tracking.untrack_unlinked()\n db.dump()\n config.dump()\n\n return ExitCode.SUCCESS.value\n\n\nif __name__ == \"__main__\":\n exit(main())\n
|
|
199
|
+
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
|
|
200
|
+
<+>UTF-8
|
|
201
|
+
===================================================================
|
|
202
|
+
diff --git a/src/umu_commander/main.py b/src/umu_commander/main.py
|
|
203
|
+
--- a/src/umu_commander/main.py (revision 2c990ed1cab5a20498dc2cfe9bd4e331f60cb3af)
|
|
204
|
+
+++ b/src/umu_commander/main.py (date 1754467945908)
|
|
205
|
+
@@ -4,10 +4,10 @@
|
|
206
|
+
from json import JSONDecodeError
|
|
207
|
+
|
|
208
|
+
import umu_commander.configuration as config
|
|
209
|
+
+import umu_commander.database as db
|
|
210
|
+
from umu_commander import tracking, umu_config
|
|
211
|
+
from umu_commander.classes import ExitCode
|
|
212
|
+
-from umu_commander.configuration import _CONFIG_DIR, _CONFIG_NAME
|
|
213
|
+
-from umu_commander.database import Database as db
|
|
214
|
+
+from umu_commander.configuration import CONFIG_DIR, CONFIG_NAME
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def print_help():
|
|
218
|
+
@@ -23,9 +23,9 @@
|
|
219
|
+
try:
|
|
220
|
+
config.load()
|
|
221
|
+
except (JSONDecodeError, KeyError):
|
|
222
|
+
- config_path: str = os.path.join(_CONFIG_DIR, _CONFIG_NAME)
|
|
223
|
+
+ config_path: str = os.path.join(CONFIG_DIR, CONFIG_NAME)
|
|
224
|
+
print(f"Config file at {config_path} could not be read.")
|
|
225
|
+
- os.rename(config_path, os.path.join(_CONFIG_DIR, _CONFIG_NAME + ".old"))
|
|
226
|
+
+ os.rename(config_path, os.path.join(CONFIG_DIR, CONFIG_NAME + ".old"))
|
|
227
|
+
|
|
228
|
+
try:
|
|
229
|
+
db.load()
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
<option name="autoReloadType" value="SELECTIVE" />
|
|
5
5
|
</component>
|
|
6
6
|
<component name="ChangeListManager">
|
|
7
|
-
<list default="true" id="043620f1-711f-4c27-a2e2-15fa501e8ce0" name="Changes" comment="1.5.
|
|
7
|
+
<list default="true" id="043620f1-711f-4c27-a2e2-15fa501e8ce0" name="Changes" comment="1.5.4">
|
|
8
|
+
<change beforePath="$PROJECT_DIR$/pyproject.toml" beforeDir="false" afterPath="$PROJECT_DIR$/pyproject.toml" afterDir="false" />
|
|
9
|
+
</list>
|
|
8
10
|
<option name="SHOW_DIALOG" value="false" />
|
|
9
11
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
10
12
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
@@ -50,46 +52,46 @@
|
|
|
50
52
|
<option name="hideEmptyMiddlePackages" value="true" />
|
|
51
53
|
<option name="showLibraryContents" value="true" />
|
|
52
54
|
</component>
|
|
53
|
-
<component name="PropertiesComponent"
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
55
|
+
<component name="PropertiesComponent">{
|
|
56
|
+
"keyToString": {
|
|
57
|
+
"Python tests.Python tests for test_config.Config.executor": "Run",
|
|
58
|
+
"Python tests.Python tests for test_config.Config.test_missing_config.executor": "Run",
|
|
59
|
+
"Python tests.Python tests for test_db.DB.executor": "Run",
|
|
60
|
+
"Python tests.Python tests for test_proton.Tracking.executor": "Run",
|
|
61
|
+
"Python tests.Python tests for test_proton.Tracking.test_collect_proton_versions.executor": "Run",
|
|
62
|
+
"Python tests.Python tests for test_tracking.Tracking.executor": "Run",
|
|
63
|
+
"Python tests.Python tests for test_tracking.Tracking.test_track.executor": "Run",
|
|
64
|
+
"Python tests.Python tests for test_tracking.Tracking.test_track_untrack.executor": "Run",
|
|
65
|
+
"Python tests.Python tests for test_tracking.TrackingTest.executor": "Run",
|
|
66
|
+
"Python tests.Python tests for test_tracking.TrackingTest.test_track.executor": "Run",
|
|
67
|
+
"Python tests.Python tests for tests.test_db.DB.executor": "Run",
|
|
68
|
+
"Python tests.Python tests for tests.test_db.DBTest.executor": "Run",
|
|
69
|
+
"Python tests.Python tests for tests.test_db.DBTest.test_addition_removal.executor": "Run",
|
|
70
|
+
"Python tests.Python tests for tests.test_db.DBTest.test_malformed_db.executor": "Run",
|
|
71
|
+
"Python tests.Python tests for tests.test_db.DBTest.test_missing_db.executor": "Run",
|
|
72
|
+
"Python tests.Python tests for tests.test_tracking.Tracking.executor": "Run",
|
|
73
|
+
"Python tests.Python tests for tests.test_tracking.TrackingTest.executor": "Debug",
|
|
74
|
+
"Python tests.Python tests for tests.test_tracking.TrackingTest.test_track.executor": "Run",
|
|
75
|
+
"Python tests.Python tests in tests.executor": "Run",
|
|
76
|
+
"Python tests.Run tests.executor": "Run",
|
|
77
|
+
"Python.create.executor": "Run",
|
|
78
|
+
"Python.delete.executor": "Run",
|
|
79
|
+
"Python.manage.executor": "Run",
|
|
80
|
+
"Python.run.executor": "Run",
|
|
81
|
+
"Python.track.executor": "Run",
|
|
82
|
+
"Python.umu-commander.executor": "Run",
|
|
83
|
+
"Python.untrack.executor": "Run",
|
|
84
|
+
"Python.users.executor": "Run",
|
|
85
|
+
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
86
|
+
"RunOnceActivity.git.unshallow": "true",
|
|
87
|
+
"Shell Script.Build.executor": "Run",
|
|
88
|
+
"Shell Script.Upload.executor": "Run",
|
|
89
|
+
"git-widget-placeholder": "master",
|
|
90
|
+
"last_opened_file_path": "/home/hiroshi/Code/Python/umu-commander/tests",
|
|
91
|
+
"run.code.analysis.last.selected.profile": "aDefault",
|
|
92
|
+
"settings.editor.selected.configurable": "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable"
|
|
91
93
|
}
|
|
92
|
-
}
|
|
94
|
+
}</component>
|
|
93
95
|
<component name="RecentsManager">
|
|
94
96
|
<key name="CopyFile.RECENT_KEYS">
|
|
95
97
|
<recent name="$PROJECT_DIR$/tests" />
|
|
@@ -379,46 +381,6 @@
|
|
|
379
381
|
<option name="presentableId" value="Default" />
|
|
380
382
|
<updated>1751043400140</updated>
|
|
381
383
|
</task>
|
|
382
|
-
<task id="LOCAL-00009" summary="Update readme and decapitalise umu">
|
|
383
|
-
<option name="closed" value="true" />
|
|
384
|
-
<created>1751918299613</created>
|
|
385
|
-
<option name="number" value="00009" />
|
|
386
|
-
<option name="presentableId" value="LOCAL-00009" />
|
|
387
|
-
<option name="project" value="LOCAL" />
|
|
388
|
-
<updated>1751918299613</updated>
|
|
389
|
-
</task>
|
|
390
|
-
<task id="LOCAL-00010" summary="Add example config">
|
|
391
|
-
<option name="closed" value="true" />
|
|
392
|
-
<created>1751919191540</created>
|
|
393
|
-
<option name="number" value="00010" />
|
|
394
|
-
<option name="presentableId" value="LOCAL-00010" />
|
|
395
|
-
<option name="project" value="LOCAL" />
|
|
396
|
-
<updated>1751919191540</updated>
|
|
397
|
-
</task>
|
|
398
|
-
<task id="LOCAL-00011" summary="Tweak "latest umu" functionality">
|
|
399
|
-
<option name="closed" value="true" />
|
|
400
|
-
<created>1751919211128</created>
|
|
401
|
-
<option name="number" value="00011" />
|
|
402
|
-
<option name="presentableId" value="LOCAL-00011" />
|
|
403
|
-
<option name="project" value="LOCAL" />
|
|
404
|
-
<updated>1751919211128</updated>
|
|
405
|
-
</task>
|
|
406
|
-
<task id="LOCAL-00012" summary="Update readme">
|
|
407
|
-
<option name="closed" value="true" />
|
|
408
|
-
<created>1751919216236</created>
|
|
409
|
-
<option name="number" value="00012" />
|
|
410
|
-
<option name="presentableId" value="LOCAL-00012" />
|
|
411
|
-
<option name="project" value="LOCAL" />
|
|
412
|
-
<updated>1751919216236</updated>
|
|
413
|
-
</task>
|
|
414
|
-
<task id="LOCAL-00013" summary="Automatically untrack removed directories">
|
|
415
|
-
<option name="closed" value="true" />
|
|
416
|
-
<created>1751919326145</created>
|
|
417
|
-
<option name="number" value="00013" />
|
|
418
|
-
<option name="presentableId" value="LOCAL-00013" />
|
|
419
|
-
<option name="project" value="LOCAL" />
|
|
420
|
-
<updated>1751919326145</updated>
|
|
421
|
-
</task>
|
|
422
384
|
<task id="LOCAL-00014" summary="Update readme">
|
|
423
385
|
<option name="closed" value="true" />
|
|
424
386
|
<created>1751919652836</created>
|
|
@@ -771,7 +733,47 @@
|
|
|
771
733
|
<option name="project" value="LOCAL" />
|
|
772
734
|
<updated>1754003619303</updated>
|
|
773
735
|
</task>
|
|
774
|
-
<
|
|
736
|
+
<task id="LOCAL-00058" summary="made typo.">
|
|
737
|
+
<option name="closed" value="true" />
|
|
738
|
+
<created>1754004029502</created>
|
|
739
|
+
<option name="number" value="00058" />
|
|
740
|
+
<option name="presentableId" value="LOCAL-00058" />
|
|
741
|
+
<option name="project" value="LOCAL" />
|
|
742
|
+
<updated>1754004029502</updated>
|
|
743
|
+
</task>
|
|
744
|
+
<task id="LOCAL-00059" summary="1.5.3">
|
|
745
|
+
<option name="closed" value="true" />
|
|
746
|
+
<created>1754004038591</created>
|
|
747
|
+
<option name="number" value="00059" />
|
|
748
|
+
<option name="presentableId" value="LOCAL-00059" />
|
|
749
|
+
<option name="project" value="LOCAL" />
|
|
750
|
+
<updated>1754004038591</updated>
|
|
751
|
+
</task>
|
|
752
|
+
<task id="LOCAL-00060" summary="Fix error code returning">
|
|
753
|
+
<option name="closed" value="true" />
|
|
754
|
+
<created>1754004871181</created>
|
|
755
|
+
<option name="number" value="00060" />
|
|
756
|
+
<option name="presentableId" value="LOCAL-00060" />
|
|
757
|
+
<option name="project" value="LOCAL" />
|
|
758
|
+
<updated>1754004871181</updated>
|
|
759
|
+
</task>
|
|
760
|
+
<task id="LOCAL-00061" summary="Update documentation.">
|
|
761
|
+
<option name="closed" value="true" />
|
|
762
|
+
<created>1754005126667</created>
|
|
763
|
+
<option name="number" value="00061" />
|
|
764
|
+
<option name="presentableId" value="LOCAL-00061" />
|
|
765
|
+
<option name="project" value="LOCAL" />
|
|
766
|
+
<updated>1754005126667</updated>
|
|
767
|
+
</task>
|
|
768
|
+
<task id="LOCAL-00062" summary="1.5.4">
|
|
769
|
+
<option name="closed" value="true" />
|
|
770
|
+
<created>1754005137926</created>
|
|
771
|
+
<option name="number" value="00062" />
|
|
772
|
+
<option name="presentableId" value="LOCAL-00062" />
|
|
773
|
+
<option name="project" value="LOCAL" />
|
|
774
|
+
<updated>1754005137926</updated>
|
|
775
|
+
</task>
|
|
776
|
+
<option name="localTasksCounter" value="63" />
|
|
775
777
|
<servers />
|
|
776
778
|
</component>
|
|
777
779
|
<component name="Vcs.Log.Tabs.Properties">
|
|
@@ -798,11 +800,6 @@
|
|
|
798
800
|
</option>
|
|
799
801
|
</component>
|
|
800
802
|
<component name="VcsManagerConfiguration">
|
|
801
|
-
<MESSAGE value="Add UMU_PROTON_DIR config key" />
|
|
802
|
-
<MESSAGE value="Rename DB methods Rename variables for consistency Use dataclasses to group data better Add full support for multiple proton directories" />
|
|
803
|
-
<MESSAGE value="shorter" />
|
|
804
|
-
<MESSAGE value="Add some comments, rename a DB method" />
|
|
805
|
-
<MESSAGE value="Move src code to src directory" />
|
|
806
803
|
<MESSAGE value="Update documentation on the change" />
|
|
807
804
|
<MESSAGE value="Reorganised project Split methods from util.py into proton.py Various fixes Formatting" />
|
|
808
805
|
<MESSAGE value="Add project files" />
|
|
@@ -823,6 +820,11 @@
|
|
|
823
820
|
<MESSAGE value="Improve config handling" />
|
|
824
821
|
<MESSAGE value="Update documentation" />
|
|
825
822
|
<MESSAGE value="1.5.2" />
|
|
826
|
-
<
|
|
823
|
+
<MESSAGE value="made typo." />
|
|
824
|
+
<MESSAGE value="1.5.3" />
|
|
825
|
+
<MESSAGE value="Fix error code returning" />
|
|
826
|
+
<MESSAGE value="Update documentation." />
|
|
827
|
+
<MESSAGE value="1.5.4" />
|
|
828
|
+
<option name="LAST_COMMIT_MESSAGE" value="1.5.4" />
|
|
827
829
|
</component>
|
|
828
830
|
</project>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: umu-commander
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.5
|
|
4
4
|
Summary: umu-commander is an interactive CLI tool to help you manage umu.
|
|
5
5
|
Project-URL: Homepage, https://github.com/Mpaxlamitsounas/umu-commander
|
|
6
6
|
Project-URL: Issues, https://github.com/Mpaxlamitsounas/umu-commander/issues
|
|
7
7
|
Author-email: Mpaxlamitsounas <worldstudy123@gmail.com>
|
|
8
8
|
License-Expression: MIT
|
|
9
9
|
License-File: LICENSE.txt
|
|
10
|
-
Keywords: umu
|
|
10
|
+
Keywords: umu,umu-launcher
|
|
11
11
|
Classifier: Operating System :: POSIX :: Linux
|
|
12
12
|
Classifier: Programming Language :: Python :: 3
|
|
13
13
|
Requires-Python: >=3.12
|
|
@@ -49,4 +49,11 @@ umu-commander needs one of the following verbs specified after the executable na
|
|
|
49
49
|
* This is NOT equivalent to `umu-run --config <config_name>`, as vanilla umu configs do not support setting environment variables as of 07/2025.
|
|
50
50
|
|
|
51
51
|
### Installation/Usage
|
|
52
|
-
Add umu-run to your PATH and then install with pipx by running `pipx install umu-commander`. After that you can invoke umu-commander by running `umu-commander <verb>`.
|
|
52
|
+
Add umu-run to your PATH and then install with pipx by running `pipx install umu-commander`. After that you can invoke umu-commander by running `umu-commander <verb>`.
|
|
53
|
+
|
|
54
|
+
### Return codes
|
|
55
|
+
| Number | Name | Description |
|
|
56
|
+
|:-------|:------------------|:----------------------------------------------------------------|
|
|
57
|
+
| 0 | SUCCESS | Program executed as intended. |
|
|
58
|
+
| 1 | READING_ERROR | Failed to parse a file and could not recover. |
|
|
59
|
+
| 2 | INVALID_SELECTION | User selected an invalid verb or there are no valid selections. |
|
|
@@ -33,4 +33,11 @@ umu-commander needs one of the following verbs specified after the executable na
|
|
|
33
33
|
* This is NOT equivalent to `umu-run --config <config_name>`, as vanilla umu configs do not support setting environment variables as of 07/2025.
|
|
34
34
|
|
|
35
35
|
### Installation/Usage
|
|
36
|
-
Add umu-run to your PATH and then install with pipx by running `pipx install umu-commander`. After that you can invoke umu-commander by running `umu-commander <verb>`.
|
|
36
|
+
Add umu-run to your PATH and then install with pipx by running `pipx install umu-commander`. After that you can invoke umu-commander by running `umu-commander <verb>`.
|
|
37
|
+
|
|
38
|
+
### Return codes
|
|
39
|
+
| Number | Name | Description |
|
|
40
|
+
|:-------|:------------------|:----------------------------------------------------------------|
|
|
41
|
+
| 0 | SUCCESS | Program executed as intended. |
|
|
42
|
+
| 1 | READING_ERROR | Failed to parse a file and could not recover. |
|
|
43
|
+
| 2 | INVALID_SELECTION | User selected an invalid verb or there are no valid selections. |
|
|
@@ -4,9 +4,9 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "umu-commander"
|
|
7
|
-
version = "1.5.
|
|
7
|
+
version = "1.5.5"
|
|
8
8
|
authors = [
|
|
9
|
-
|
|
9
|
+
{ name = "Mpaxlamitsounas", email = "worldstudy123@gmail.com" },
|
|
10
10
|
]
|
|
11
11
|
description = "umu-commander is an interactive CLI tool to help you manage umu."
|
|
12
12
|
readme = "README.md"
|
|
@@ -15,13 +15,16 @@ classifiers = [
|
|
|
15
15
|
"Programming Language :: Python :: 3",
|
|
16
16
|
"Operating System :: POSIX :: Linux",
|
|
17
17
|
]
|
|
18
|
-
dependencies =[
|
|
18
|
+
dependencies = [
|
|
19
19
|
"tomli-w"
|
|
20
20
|
]
|
|
21
21
|
|
|
22
22
|
license = "MIT"
|
|
23
23
|
license-files = ["LICEN[CS]E*"]
|
|
24
|
-
keywords = [
|
|
24
|
+
keywords = [
|
|
25
|
+
"umu",
|
|
26
|
+
"umu-launcher"
|
|
27
|
+
]
|
|
25
28
|
|
|
26
29
|
[project.urls]
|
|
27
30
|
Homepage = "https://github.com/Mpaxlamitsounas/umu-commander"
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import os
|
|
3
|
+
import tomllib
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import tomli_w
|
|
8
|
+
|
|
9
|
+
from umu_commander.classes import DLLOverride
|
|
10
|
+
|
|
11
|
+
CONFIG_DIR: str = os.path.join(Path.home(), ".config")
|
|
12
|
+
CONFIG_NAME: str = "umu-commander.toml"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
PROTON_PATHS: tuple[str, ...] = (
|
|
16
|
+
os.path.join(Path.home(), ".local/share/Steam/compatibilitytools.d/"),
|
|
17
|
+
os.path.join(Path.home(), ".local/share/umu/compatibilitytools"),
|
|
18
|
+
)
|
|
19
|
+
UMU_PROTON_PATH: str = os.path.join(
|
|
20
|
+
Path.home(), ".local/share/Steam/compatibilitytools.d/"
|
|
21
|
+
)
|
|
22
|
+
DB_NAME: str = "tracking.json"
|
|
23
|
+
DB_DIR: str = os.path.join(Path.home(), ".local/share/umu/compatibilitytools")
|
|
24
|
+
UMU_CONFIG_NAME: str = "umu-config.toml"
|
|
25
|
+
DEFAULT_PREFIX_DIR: str = os.path.join(Path.home(), ".local/share/wineprefixes/")
|
|
26
|
+
DLL_OVERRIDES_OPTIONS: tuple[DLLOverride, ...] = (
|
|
27
|
+
DLLOverride("winhttp for BepInEx", "winhttp.dll=n;"),
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def load():
|
|
32
|
+
config_path: str = os.path.join(CONFIG_DIR, CONFIG_NAME)
|
|
33
|
+
if not os.path.exists(config_path):
|
|
34
|
+
return
|
|
35
|
+
|
|
36
|
+
with open(config_path, "rb") as conf_file:
|
|
37
|
+
toml_conf = tomllib.load(conf_file)
|
|
38
|
+
if "DLL_OVERRIDES_OPTIONS" in toml_conf:
|
|
39
|
+
toml_conf["DLL_OVERRIDES_OPTIONS"] = tuple(
|
|
40
|
+
[
|
|
41
|
+
DLLOverride(label, override_str)
|
|
42
|
+
for label, override_str in toml_conf[
|
|
43
|
+
"DLL_OVERRIDES_OPTIONS"
|
|
44
|
+
].items()
|
|
45
|
+
]
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
module = importlib.import_module(__name__)
|
|
49
|
+
for key, value in toml_conf.items():
|
|
50
|
+
setattr(module, key, value)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _get_attributes() -> dict[str, Any]:
|
|
54
|
+
module = importlib.import_module(__name__)
|
|
55
|
+
attributes: dict[str, Any] = {}
|
|
56
|
+
for key in dir(module):
|
|
57
|
+
value = getattr(module, key)
|
|
58
|
+
if not key.startswith("_") and not callable(value) and key.upper() == key:
|
|
59
|
+
attributes[key] = value
|
|
60
|
+
|
|
61
|
+
return attributes
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def dump():
|
|
65
|
+
if not os.path.exists(CONFIG_DIR):
|
|
66
|
+
os.mkdir(CONFIG_DIR)
|
|
67
|
+
|
|
68
|
+
with open(os.path.join(CONFIG_DIR, CONFIG_NAME), "wb") as conf_file:
|
|
69
|
+
toml_conf = _get_attributes()
|
|
70
|
+
del toml_conf["CONFIG_DIR"]
|
|
71
|
+
del toml_conf["CONFIG_NAME"]
|
|
72
|
+
|
|
73
|
+
toml_conf["DLL_OVERRIDES_OPTIONS"] = dict(
|
|
74
|
+
[(override.info, override.value) for override in DLL_OVERRIDES_OPTIONS]
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
tomli_w.dump(toml_conf, conf_file)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
from collections import defaultdict
|
|
4
|
+
|
|
5
|
+
import umu_commander.configuration as config
|
|
6
|
+
|
|
7
|
+
_db: defaultdict[str, defaultdict[str, list[str]]] = defaultdict(
|
|
8
|
+
lambda: defaultdict(list)
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def load():
|
|
13
|
+
global _db
|
|
14
|
+
|
|
15
|
+
if not os.path.exists(config.DB_DIR):
|
|
16
|
+
os.mkdir(config.DB_DIR)
|
|
17
|
+
|
|
18
|
+
db_path: str = os.path.join(config.DB_DIR, config.DB_NAME)
|
|
19
|
+
if not os.path.exists(db_path):
|
|
20
|
+
return
|
|
21
|
+
|
|
22
|
+
with open(os.path.join(db_path), "rt") as db_file:
|
|
23
|
+
_db.update(json.load(db_file))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def dump():
|
|
27
|
+
if not os.path.exists(config.DB_DIR):
|
|
28
|
+
os.mkdir(config.DB_DIR)
|
|
29
|
+
|
|
30
|
+
with open(os.path.join(config.DB_DIR, config.DB_NAME), "wt") as db_file:
|
|
31
|
+
# noinspection PyTypeChecker
|
|
32
|
+
json.dump(_db, db_file, indent="\t")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get(
|
|
36
|
+
proton_dir: str = None, proton_ver: str = None
|
|
37
|
+
) -> dict[str, dict[str, list[str]]] | dict[str, list[str]] | list[str]:
|
|
38
|
+
global _db
|
|
39
|
+
|
|
40
|
+
if proton_dir is None and proton_ver is None:
|
|
41
|
+
return _db
|
|
42
|
+
|
|
43
|
+
if proton_ver is None:
|
|
44
|
+
return _db[proton_dir]
|
|
45
|
+
|
|
46
|
+
if proton_ver not in _db[proton_dir]:
|
|
47
|
+
_db[proton_dir][proton_ver] = []
|
|
48
|
+
|
|
49
|
+
return _db[proton_dir][proton_ver]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _reset():
|
|
53
|
+
global _db
|
|
54
|
+
_db = defaultdict(lambda: defaultdict(list))
|
|
@@ -3,11 +3,11 @@ import os
|
|
|
3
3
|
import sys
|
|
4
4
|
from json import JSONDecodeError
|
|
5
5
|
|
|
6
|
+
import umu_commander.configuration as config
|
|
7
|
+
import umu_commander.database as db
|
|
6
8
|
from umu_commander import tracking, umu_config
|
|
7
9
|
from umu_commander.classes import ExitCode
|
|
8
10
|
from umu_commander.configuration import CONFIG_DIR, CONFIG_NAME
|
|
9
|
-
from umu_commander.configuration import Configuration as config
|
|
10
|
-
from umu_commander.database import Database as db
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def print_help():
|
|
@@ -36,7 +36,7 @@ def main() -> ExitCode:
|
|
|
36
36
|
|
|
37
37
|
if len(sys.argv) == 1:
|
|
38
38
|
print_help()
|
|
39
|
-
return ExitCode.SUCCESS
|
|
39
|
+
return ExitCode.SUCCESS.value
|
|
40
40
|
|
|
41
41
|
verb: str = sys.argv[1]
|
|
42
42
|
match verb:
|
|
@@ -55,14 +55,14 @@ def main() -> ExitCode:
|
|
|
55
55
|
case _:
|
|
56
56
|
print("Invalid verb.")
|
|
57
57
|
print_help()
|
|
58
|
-
return ExitCode.INVALID_SELECTION
|
|
58
|
+
return ExitCode.INVALID_SELECTION.value
|
|
59
59
|
|
|
60
60
|
tracking.untrack_unlinked()
|
|
61
61
|
db.dump()
|
|
62
62
|
config.dump()
|
|
63
63
|
|
|
64
|
-
return ExitCode.SUCCESS
|
|
64
|
+
return ExitCode.SUCCESS.value
|
|
65
65
|
|
|
66
66
|
|
|
67
67
|
if __name__ == "__main__":
|
|
68
|
-
exit(main()
|
|
68
|
+
exit(main())
|
|
@@ -2,9 +2,9 @@ import os
|
|
|
2
2
|
import re
|
|
3
3
|
import subprocess
|
|
4
4
|
|
|
5
|
+
import umu_commander.configuration as config
|
|
6
|
+
import umu_commander.database as db
|
|
5
7
|
from umu_commander.classes import ProtonDir, ProtonVer
|
|
6
|
-
from umu_commander.configuration import Configuration as config
|
|
7
|
-
from umu_commander.database import Database as db
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def _natural_sort_proton_ver_key(p: ProtonVer, _nsre=re.compile(r"(\d+)")):
|
|
@@ -25,9 +25,9 @@ def refresh_proton_versions():
|
|
|
25
25
|
if "PROTONPATH" in line and "/" in line:
|
|
26
26
|
try:
|
|
27
27
|
left: int = line.rfind("/") + 1
|
|
28
|
-
print(f"
|
|
28
|
+
print(f":Latest umu Proton: {line[left:len(line) - 1]}.")
|
|
29
29
|
except ValueError:
|
|
30
|
-
print("Could not fetch latest
|
|
30
|
+
print("Could not fetch latest umu Proton.")
|
|
31
31
|
|
|
32
32
|
break
|
|
33
33
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import shutil
|
|
3
3
|
|
|
4
|
+
import umu_commander.database as db
|
|
4
5
|
from umu_commander.classes import ProtonDir, ProtonVer
|
|
5
|
-
from umu_commander.database import Database as db
|
|
6
6
|
from umu_commander.proton import (
|
|
7
7
|
collect_proton_versions,
|
|
8
8
|
get_latest_umu_proton,
|
|
@@ -21,7 +21,7 @@ def untrack(quiet: bool = False):
|
|
|
21
21
|
db.get(proton_dir, proton_ver).remove(current_dir)
|
|
22
22
|
|
|
23
23
|
if not quiet:
|
|
24
|
-
print("Directory removed from all
|
|
24
|
+
print("Directory removed from all tracking lists.")
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
def track(
|
|
@@ -32,7 +32,7 @@ def track(
|
|
|
32
32
|
|
|
33
33
|
if proton_ver is None:
|
|
34
34
|
proton_ver: ProtonVer = get_selection(
|
|
35
|
-
"Select Proton version to
|
|
35
|
+
"Select Proton version to track directory with:",
|
|
36
36
|
None,
|
|
37
37
|
collect_proton_versions(sort=True),
|
|
38
38
|
).as_proton_ver()
|
|
@@ -43,7 +43,7 @@ def track(
|
|
|
43
43
|
|
|
44
44
|
if not quiet:
|
|
45
45
|
print(
|
|
46
|
-
f"Directory {current_directory} added to Proton version's {proton_ver.version_num} in {proton_ver.dir}
|
|
46
|
+
f"Directory {current_directory} added to Proton version's {proton_ver.version_num} in {proton_ver.dir} tracking list."
|
|
47
47
|
)
|
|
48
48
|
|
|
49
49
|
|
|
@@ -57,10 +57,10 @@ def users():
|
|
|
57
57
|
if proton_ver.dir in db.get() and proton_ver.version_num in db.get(proton_ver.dir):
|
|
58
58
|
version_users: list[str] = db.get(proton_ver.dir, proton_ver.version_num)
|
|
59
59
|
if len(version_users) > 0:
|
|
60
|
-
print(f"Directories
|
|
60
|
+
print(f"Directories tracked by {proton_ver.version_num} of {proton_ver.dir}:")
|
|
61
61
|
print(*version_users, sep="\n")
|
|
62
62
|
else:
|
|
63
|
-
print("
|
|
63
|
+
print("This version is tracking no directories.")
|
|
64
64
|
else:
|
|
65
65
|
print("This version hasn't been used by umu before.")
|
|
66
66
|
|
|
@@ -73,7 +73,7 @@ def delete():
|
|
|
73
73
|
|
|
74
74
|
if len(version_users) == 0:
|
|
75
75
|
selection: str = input(
|
|
76
|
-
f"{proton_ver} in {proton_dir}
|
|
76
|
+
f"Version {proton_ver} in {proton_dir} is tracking no directories, delete? (Y/N) ? "
|
|
77
77
|
)
|
|
78
78
|
if selection.lower() == "y":
|
|
79
79
|
try:
|
|
@@ -5,9 +5,9 @@ from typing import Any
|
|
|
5
5
|
|
|
6
6
|
import tomli_w
|
|
7
7
|
|
|
8
|
+
import umu_commander.configuration as config
|
|
8
9
|
from umu_commander import tracking
|
|
9
10
|
from umu_commander.classes import DLLOverride, ProtonVer
|
|
10
|
-
from umu_commander.configuration import Configuration as config
|
|
11
11
|
from umu_commander.proton import collect_proton_versions, refresh_proton_versions
|
|
12
12
|
from umu_commander.util import (
|
|
13
13
|
get_selection,
|
|
@@ -54,7 +54,7 @@ def create():
|
|
|
54
54
|
]
|
|
55
55
|
selected: set[int] = set()
|
|
56
56
|
while True:
|
|
57
|
-
print("Select DLLs to override,
|
|
57
|
+
print("Select DLLs to override, multiple can be selected:")
|
|
58
58
|
for idx, override in enumerate(possible_overrides):
|
|
59
59
|
if idx in selected:
|
|
60
60
|
idx = "Y"
|
|
@@ -122,10 +122,14 @@ def create():
|
|
|
122
122
|
if not selected_umu_latest:
|
|
123
123
|
tracking.track(proton_ver, False)
|
|
124
124
|
except:
|
|
125
|
-
print("Could not create
|
|
125
|
+
print("Could not create configuration file.")
|
|
126
126
|
|
|
127
127
|
|
|
128
128
|
def run():
|
|
129
|
+
if not os.path.exists(config.UMU_CONFIG_NAME):
|
|
130
|
+
print("No umu config in current directory.")
|
|
131
|
+
return
|
|
132
|
+
|
|
129
133
|
with open(config.UMU_CONFIG_NAME, "rb") as toml_file:
|
|
130
134
|
toml_conf = tomllib.load(toml_file)
|
|
131
135
|
|
|
@@ -137,3 +141,4 @@ def run():
|
|
|
137
141
|
args=["umu-run", "--config", config.UMU_CONFIG_NAME],
|
|
138
142
|
env=os.environ,
|
|
139
143
|
)
|
|
144
|
+
|
|
@@ -58,7 +58,7 @@ def get_selection(
|
|
|
58
58
|
) -> Element:
|
|
59
59
|
if not _selection_set_valid(selection_elements, selection_groups):
|
|
60
60
|
print("Nothing to select from.")
|
|
61
|
-
exit(ExitCode.INVALID_SELECTION)
|
|
61
|
+
exit(ExitCode.INVALID_SELECTION.value)
|
|
62
62
|
|
|
63
63
|
if selection_groups is None:
|
|
64
64
|
selection_groups = []
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import os.path
|
|
2
2
|
import unittest
|
|
3
3
|
|
|
4
|
+
import umu_commander.configuration as config
|
|
4
5
|
from tests import *
|
|
5
6
|
from umu_commander import configuration
|
|
6
|
-
from umu_commander.configuration import Configuration as config
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class Config(unittest.TestCase):
|
|
@@ -16,7 +16,7 @@ class Config(unittest.TestCase):
|
|
|
16
16
|
teardown()
|
|
17
17
|
|
|
18
18
|
def test_missing_config(self):
|
|
19
|
-
config.
|
|
19
|
+
config.dump()
|
|
20
20
|
self.assertTrue(
|
|
21
21
|
os.path.exists(os.path.join(TESTING_DIR, configuration.CONFIG_NAME))
|
|
22
22
|
)
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
from json import JSONDecodeError
|
|
3
3
|
|
|
4
|
+
import umu_commander.configuration as config
|
|
5
|
+
import umu_commander.database as db
|
|
4
6
|
from tests import *
|
|
5
|
-
from umu_commander.configuration import Configuration as config
|
|
6
|
-
from umu_commander.database import Database as db
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class Database(unittest.TestCase):
|
|
10
10
|
def setUp(self):
|
|
11
11
|
config.DB_DIR = TESTING_DIR
|
|
12
12
|
setup()
|
|
13
|
+
db._reset()
|
|
13
14
|
|
|
14
15
|
def tearDown(self):
|
|
15
16
|
teardown()
|
|
16
17
|
|
|
17
18
|
def test_missing_db(self):
|
|
18
19
|
db.load()
|
|
19
|
-
self.assertEqual(db.get(), {})
|
|
20
|
+
self.assertEqual(db.get().keys(), {}.keys())
|
|
20
21
|
|
|
21
22
|
def test_malformed_db(self):
|
|
22
23
|
with open(os.path.join(config.DB_DIR, config.DB_NAME), "tw") as db_file:
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
|
|
3
|
+
import umu_commander.configuration as config
|
|
3
4
|
from tests import *
|
|
4
5
|
from umu_commander import proton
|
|
5
6
|
from umu_commander.classes import Group
|
|
6
|
-
from umu_commander.configuration import Configuration as config
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class Tracking(unittest.TestCase):
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
|
|
3
|
+
import umu_commander.configuration as config
|
|
4
|
+
import umu_commander.database as db
|
|
3
5
|
from tests import *
|
|
4
6
|
from umu_commander import tracking
|
|
5
7
|
from umu_commander.classes import ProtonVer
|
|
6
|
-
from umu_commander.configuration import Configuration as config
|
|
7
|
-
from umu_commander.database import Database as db
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class Tracking(unittest.TestCase):
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import tomllib
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
|
|
5
|
-
import tomli_w
|
|
6
|
-
|
|
7
|
-
from umu_commander.classes import DLLOverride
|
|
8
|
-
|
|
9
|
-
CONFIG_DIR: str = os.path.join(Path.home(), ".config")
|
|
10
|
-
CONFIG_NAME: str = "umu-commander.toml"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class Configuration:
|
|
14
|
-
PROTON_PATHS: tuple[str, ...] = (
|
|
15
|
-
os.path.join(Path.home(), ".local/share/Steam/compatibilitytools.d/"),
|
|
16
|
-
os.path.join(Path.home(), ".local/share/umu/compatibilitytools"),
|
|
17
|
-
)
|
|
18
|
-
UMU_PROTON_PATH: str = os.path.join(
|
|
19
|
-
Path.home(), ".local/share/Steam/compatibilitytools.d/"
|
|
20
|
-
)
|
|
21
|
-
DB_NAME: str = "tracking.json"
|
|
22
|
-
DB_DIR: str = os.path.join(Path.home(), ".local/share/umu/compatibilitytools")
|
|
23
|
-
UMU_CONFIG_NAME: str = "umu-config.toml"
|
|
24
|
-
DEFAULT_PREFIX_DIR: str = os.path.join(Path.home(), ".local/share/wineprefixes/")
|
|
25
|
-
DLL_OVERRIDES_OPTIONS: tuple[DLLOverride, ...] = (
|
|
26
|
-
DLLOverride("winhttp for BepInEx", "winhttp.dll=n;"),
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
@staticmethod
|
|
30
|
-
def load():
|
|
31
|
-
try:
|
|
32
|
-
with open(os.path.join(CONFIG_DIR, CONFIG_NAME), "rb") as conf_file:
|
|
33
|
-
toml_conf = tomllib.load(conf_file)
|
|
34
|
-
toml_conf["DLL_OVERRIDES_OPTIONS"] = tuple(
|
|
35
|
-
[
|
|
36
|
-
DLLOverride(label, override_str)
|
|
37
|
-
for label, override_str in toml_conf[
|
|
38
|
-
"DLL_OVERRIDES_OPTIONS"
|
|
39
|
-
].items()
|
|
40
|
-
]
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
for key, value in toml_conf.items():
|
|
44
|
-
setattr(Configuration, key, value)
|
|
45
|
-
|
|
46
|
-
except FileNotFoundError:
|
|
47
|
-
Configuration.dump()
|
|
48
|
-
|
|
49
|
-
@staticmethod
|
|
50
|
-
def dump():
|
|
51
|
-
if not os.path.exists(CONFIG_DIR):
|
|
52
|
-
os.mkdir(CONFIG_DIR)
|
|
53
|
-
|
|
54
|
-
with open(os.path.join(CONFIG_DIR, CONFIG_NAME), "wb") as conf_file:
|
|
55
|
-
toml_conf = Configuration._get_attributes()
|
|
56
|
-
toml_conf["DLL_OVERRIDES_OPTIONS"] = dict(
|
|
57
|
-
[
|
|
58
|
-
(override.info, override.value)
|
|
59
|
-
for override in Configuration.DLL_OVERRIDES_OPTIONS
|
|
60
|
-
]
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
tomli_w.dump(toml_conf, conf_file)
|
|
64
|
-
|
|
65
|
-
@staticmethod
|
|
66
|
-
def _get_attributes():
|
|
67
|
-
attributes = {}
|
|
68
|
-
for key, value in vars(Configuration).items():
|
|
69
|
-
if not key.startswith("__") and not callable(getattr(Configuration, key)):
|
|
70
|
-
attributes[key] = value
|
|
71
|
-
|
|
72
|
-
return attributes
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import os
|
|
3
|
-
from collections import defaultdict
|
|
4
|
-
|
|
5
|
-
from umu_commander.configuration import Configuration as config
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class Database:
|
|
9
|
-
_db: defaultdict[str, defaultdict[str, list[str]]]
|
|
10
|
-
|
|
11
|
-
@staticmethod
|
|
12
|
-
def load():
|
|
13
|
-
if not os.path.exists(config.DB_DIR):
|
|
14
|
-
os.mkdir(config.DB_DIR)
|
|
15
|
-
|
|
16
|
-
try:
|
|
17
|
-
with open(os.path.join(config.DB_DIR, config.DB_NAME), "rt") as db_file:
|
|
18
|
-
Database._db = defaultdict(lambda: defaultdict(list))
|
|
19
|
-
Database._db.update(json.load(db_file))
|
|
20
|
-
|
|
21
|
-
except FileNotFoundError:
|
|
22
|
-
Database._db = defaultdict(lambda: defaultdict(list))
|
|
23
|
-
|
|
24
|
-
@staticmethod
|
|
25
|
-
def dump():
|
|
26
|
-
with open(os.path.join(config.DB_DIR, config.DB_NAME), "wt") as db_file:
|
|
27
|
-
# noinspection PyTypeChecker
|
|
28
|
-
json.dump(Database._db, db_file, indent="\t")
|
|
29
|
-
|
|
30
|
-
@staticmethod
|
|
31
|
-
def get(
|
|
32
|
-
proton_dir: str = None, proton_ver: str = None
|
|
33
|
-
) -> dict[str, dict[str, list[str]]] | dict[str, list[str]] | list[str]:
|
|
34
|
-
if proton_dir is None and proton_ver is None:
|
|
35
|
-
return Database._db
|
|
36
|
-
|
|
37
|
-
if proton_ver is None:
|
|
38
|
-
return Database._db[proton_dir]
|
|
39
|
-
|
|
40
|
-
if proton_ver not in Database._db[proton_dir]:
|
|
41
|
-
Database._db[proton_dir][proton_ver] = []
|
|
42
|
-
|
|
43
|
-
return Database._db[proton_dir][proton_ver]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|