Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0c46bbc74 | ||
|
|
6a06f7329d | ||
|
|
16db07511a | ||
|
|
34863901fd | ||
|
|
3f5f8b71e8 | ||
|
|
618a98ee89 | ||
|
|
867e4d3cce | ||
|
|
3c019796c2 | ||
|
|
1c8448c1e1 |
@@ -44,10 +44,10 @@
|
|||||||
</screenshots>
|
</screenshots>
|
||||||
<content_rating type="oars-1.1" />
|
<content_rating type="oars-1.1" />
|
||||||
<releases>
|
<releases>
|
||||||
<release version="2.0.2" date="2023-07-08">
|
<release version="2.0.3" date="2023-07-08">
|
||||||
<description translatable="no">
|
<description translatable="no">
|
||||||
<ul>
|
<ul>
|
||||||
<li>Fixes an issue with internal data storage</li>
|
<li>Fixes an issue with Windows data storage</li>
|
||||||
</ul>
|
</ul>
|
||||||
</description>
|
</description>
|
||||||
</release>
|
</release>
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ Stored as a string.
|
|||||||
|
|
||||||
### source
|
### source
|
||||||
|
|
||||||
A unique ID for the source of the game in lowercase, without spaces.
|
A unique ID for the source of the game in lowercase, without spaces or underscores.
|
||||||
|
|
||||||
If a source provides multiple internal sources, these should be separately labeled, but share a common prefix. eg. `heoic_gog`, `heroic_epic`.
|
If a source provides multiple internal sources, these should be separately labeled, but share a common prefix. eg. `heoic_gog`, `heroic_epic`. This is the only place you should use an underscore.
|
||||||
|
|
||||||
Stored as a string.
|
Stored as a string.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
project('cartridges',
|
project('cartridges',
|
||||||
version: '2.0.2',
|
version: '2.0.3',
|
||||||
meson_version: '>= 0.59.0',
|
meson_version: '>= 0.59.0',
|
||||||
default_options: [ 'warning_level=2', 'werror=false', ],
|
default_options: [ 'warning_level=2', 'werror=false', ],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class LegendarySourceIterator(SourceIterator):
|
|||||||
class LegendarySource(Source):
|
class LegendarySource(Source):
|
||||||
name = "Legendary"
|
name = "Legendary"
|
||||||
executable_format = "legendary launch {app_name}"
|
executable_format = "legendary launch {app_name}"
|
||||||
available_on = {"linux", "win32"}
|
available_on = {"linux"}
|
||||||
|
|
||||||
iterator_class = LegendarySourceIterator
|
iterator_class = LegendarySourceIterator
|
||||||
config_location: Location = Location(
|
config_location: Location = Location(
|
||||||
|
|||||||
10
src/main.py
10
src/main.py
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import lzma
|
import lzma
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
@@ -49,6 +50,7 @@ from src.store.managers.online_cover_manager import OnlineCoverManager
|
|||||||
from src.store.managers.sgdb_manager import SGDBManager
|
from src.store.managers.sgdb_manager import SGDBManager
|
||||||
from src.store.managers.steam_api_manager import SteamAPIManager
|
from src.store.managers.steam_api_manager import SteamAPIManager
|
||||||
from src.store.store import Store
|
from src.store.store import Store
|
||||||
|
from src.utils.migrate_files_v1_to_v2 import migrate_files_v1_to_v2
|
||||||
from src.window import CartridgesWindow
|
from src.window import CartridgesWindow
|
||||||
|
|
||||||
|
|
||||||
@@ -64,6 +66,12 @@ class CartridgesApplication(Adw.Application):
|
|||||||
def do_activate(self): # pylint: disable=arguments-differ
|
def do_activate(self): # pylint: disable=arguments-differ
|
||||||
"""Called on app creation"""
|
"""Called on app creation"""
|
||||||
|
|
||||||
|
setup_logging()
|
||||||
|
log_system_info()
|
||||||
|
|
||||||
|
if os.name == "nt":
|
||||||
|
migrate_files_v1_to_v2()
|
||||||
|
|
||||||
# Set fallback icon-name
|
# Set fallback icon-name
|
||||||
Gtk.Window.set_default_icon_name(shared.APP_ID)
|
Gtk.Window.set_default_icon_name(shared.APP_ID)
|
||||||
|
|
||||||
@@ -279,7 +287,5 @@ class CartridgesApplication(Adw.Application):
|
|||||||
|
|
||||||
def main(_version):
|
def main(_version):
|
||||||
"""App entry point"""
|
"""App entry point"""
|
||||||
setup_logging()
|
|
||||||
log_system_info()
|
|
||||||
app = CartridgesApplication()
|
app = CartridgesApplication()
|
||||||
return app.run(sys.argv)
|
return app.run(sys.argv)
|
||||||
|
|||||||
128
src/utils/migrate_files_v1_to_v2.py
Normal file
128
src/utils/migrate_files_v1_to_v2.py
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
# migrate_files_v1_to_v2.py
|
||||||
|
#
|
||||||
|
# Copyright 2023 Geoffrey Coulaud
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from src import shared
|
||||||
|
|
||||||
|
old_data_dir = Path.home() / ".local" / "share"
|
||||||
|
old_cartridges_data_dir = old_data_dir / "cartridges"
|
||||||
|
migrated_file_path = old_cartridges_data_dir / ".migrated"
|
||||||
|
old_games_dir = old_cartridges_data_dir / "games"
|
||||||
|
old_covers_dir = old_cartridges_data_dir / "covers"
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_game_covers(game_path: Path):
|
||||||
|
"""Migrate a game covers from a source game path to the current dir"""
|
||||||
|
for suffix in (".tiff", ".gif"):
|
||||||
|
cover_path = old_covers_dir / game_path.with_suffix(suffix).name
|
||||||
|
if not cover_path.is_file():
|
||||||
|
continue
|
||||||
|
destination_cover_path = shared.covers_dir / cover_path.name
|
||||||
|
logging.info("Moving %s -> %s", str(cover_path), str(destination_cover_path))
|
||||||
|
cover_path.rename(destination_cover_path)
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_files_v1_to_v2():
|
||||||
|
"""
|
||||||
|
Migrate user data from the v1.X locations to the latest location.
|
||||||
|
|
||||||
|
Fix for commit 4a204442b5d8ba2e918f8c2605d72e483bf35efd
|
||||||
|
where the windows directories for data, config and cache changed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Skip if there is no old dir
|
||||||
|
# Skip if old == current
|
||||||
|
# Skip if already migrated
|
||||||
|
if (
|
||||||
|
not old_data_dir.is_dir()
|
||||||
|
or str(old_data_dir) == str(shared.data_dir)
|
||||||
|
or migrated_file_path.is_file()
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
logging.info("Migrating data dir %s", str(old_data_dir))
|
||||||
|
|
||||||
|
# Create the current data dir if needed
|
||||||
|
if not shared.data_dir.is_dir():
|
||||||
|
shared.data_dir.mkdir(parents=True)
|
||||||
|
|
||||||
|
old_game_paths = set(old_games_dir.glob("*.json"))
|
||||||
|
old_imported_game_paths = set(
|
||||||
|
filter(lambda path: path.name.startswith("imported_"), old_game_paths)
|
||||||
|
)
|
||||||
|
old_other_game_paths = old_game_paths - old_imported_game_paths
|
||||||
|
|
||||||
|
# Discover current imported games
|
||||||
|
imported_game_number = 0
|
||||||
|
imported_execs = set()
|
||||||
|
for game_path in shared.games_dir.glob("imported_*.json"):
|
||||||
|
try:
|
||||||
|
game_data = json.load(game_path.open("r"))
|
||||||
|
except (OSError, json.JSONDecodeError):
|
||||||
|
continue
|
||||||
|
number = int(game_data["game_id"].replace("imported_", ""))
|
||||||
|
imported_game_number = max(number, imported_game_number)
|
||||||
|
imported_execs.add(game_data["executable"])
|
||||||
|
|
||||||
|
# Migrate imported game files
|
||||||
|
for game_path in old_imported_game_paths:
|
||||||
|
try:
|
||||||
|
game_data = json.load(game_path.open("r"))
|
||||||
|
except (OSError, json.JSONDecodeError):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Don't migrate if there's a game with the same exec
|
||||||
|
if game_data["executable"] in imported_execs:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Migrate with updated index
|
||||||
|
imported_game_number += 1
|
||||||
|
game_id = f"imported_{imported_game_number}"
|
||||||
|
game_data["game_id"] = game_id
|
||||||
|
destination_game_path = shared.games_dir / f"{game_id}.json"
|
||||||
|
logging.info(
|
||||||
|
"Moving (updated id) %s -> %s", str(game_path), str(destination_game_path)
|
||||||
|
)
|
||||||
|
json.dump(
|
||||||
|
game_data,
|
||||||
|
destination_game_path.open("w"),
|
||||||
|
indent=4,
|
||||||
|
sort_keys=True,
|
||||||
|
)
|
||||||
|
game_path.unlink()
|
||||||
|
migrate_game_covers(game_path)
|
||||||
|
|
||||||
|
# Migrate all other games
|
||||||
|
for game_path in old_other_game_paths:
|
||||||
|
# Do nothing if already in games dir
|
||||||
|
destination_game_path = shared.games_dir / game_path.name
|
||||||
|
if destination_game_path.exists():
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Else, migrate the game
|
||||||
|
logging.info("Moving %s -> %s", str(game_path), str(destination_game_path))
|
||||||
|
game_path.rename(destination_game_path)
|
||||||
|
migrate_game_covers(game_path)
|
||||||
|
|
||||||
|
# Signal that this dir is migrated
|
||||||
|
migrated_file_path.touch()
|
||||||
|
logging.info("Migration done")
|
||||||
Reference in New Issue
Block a user