added get_hash_map and comp_dict_changes to get information about all the files of an extracted game

This commit is contained in:
Faraphel 2022-08-27 00:28:15 +02:00
parent b9d6913e22
commit 9f8aa05c04
7 changed files with 72 additions and 33 deletions

View file

@ -1,9 +1,3 @@
import os
import sys
from threading import Thread
from typing import Callable
# metadata # metadata
__version__ = (0, 12, 0) __version__ = (0, 12, 0)
__author__ = 'Faraphel' __author__ = 'Faraphel'
@ -21,33 +15,10 @@ Mo: int = 1_000 * Ko
Go: int = 1_000 * Mo Go: int = 1_000 * Mo
minimum_space_available: int = 15*Go minimum_space_available: int = 15*Go
file_block_size: int = 128*Ko
# global type hint # global type hint
TemplateSafeEval: str TemplateSafeEval: str
TemplateMultipleSafeEval: str TemplateMultipleSafeEval: str
Env: dict[str, any] Env: dict[str, any]
# useful functions
def threaded(func: Callable) -> Callable:
"""
Decorate a function to run in a separate thread
:param func: a function
:return: the decorated function
"""
def wrapper(*args, **kwargs):
# run the function in a Daemon, so it will stop when the main thread stops
thread = Thread(target=func, args=args, kwargs=kwargs, daemon=True)
thread.start()
return thread
return wrapper
def restart_program():
"""
Restart the program
"""
os.execl(sys.executable, sys.executable, *sys.argv)

View file

@ -17,6 +17,7 @@ from source.progress import Progress
from source.translation import translate as _, translate_external from source.translation import translate as _, translate_external
from source import plugins from source import plugins
from source import * from source import *
from source.utils import threaded
import os import os
from source.mkw.collection.Extension import Extension from source.mkw.collection.Extension import Extension

View file

@ -1,8 +1,10 @@
import hashlib
import shutil import shutil
from io import BytesIO from io import BytesIO
from pathlib import Path from pathlib import Path
from typing import Generator, IO, TYPE_CHECKING from typing import Generator, IO, TYPE_CHECKING
from source import file_block_size
from source.mkw.ModConfig import ModConfig from source.mkw.ModConfig import ModConfig
from source.mkw.Patch.Patch import Patch from source.mkw.Patch.Patch import Patch
from source.mkw.collection.Extension import Extension from source.mkw.collection.Extension import Extension
@ -202,3 +204,20 @@ class ExtractedGame:
shutil.rmtree(self.path) shutil.rmtree(self.path)
return converted_game return converted_game
def get_hash_map(self) -> dict[str, str]:
"""
Return a dictionary associating all the game subfiles to a hash
:return: a dictionary associating all the game subfiles to a hash
"""
md5_map: dict[str, str] = {}
for fp in filter(lambda fp: fp.is_file(), self.path.rglob("*")):
hasher = hashlib.md5()
with open(fp, "rb") as file:
while block := file.read(file_block_size):
hasher.update(block)
md5_map[str(fp.relative_to(self.path))] = hasher.hexdigest()
return md5_map

View file

@ -7,6 +7,7 @@ from source.mkw.collection.Extension import Extension
from source.mkw.collection.Region import Region from source.mkw.collection.Region import Region
from source.option import Options from source.option import Options
from source.progress import Progress from source.progress import Progress
from source.utils import comp_dict_changes
from source.wt.wit import WITPath from source.wt.wit import WITPath
from source.translation import translate as _ from source.translation import translate as _
@ -123,6 +124,9 @@ class Game:
yield Progress(title=_("EXTRACTION"), set_part=1) yield Progress(title=_("EXTRACTION"), set_part=1)
yield from self.extract(extracted_game.path) yield from self.extract(extracted_game.path)
# Riivolution hash map for the final comparaison
riivolution_original_hash_map = extracted_game.get_hash_map()
# install mystuff # install mystuff
yield Progress(title=_("MYSTUFF"), set_part=2) yield Progress(title=_("MYSTUFF"), set_part=2)
mystuff_packs = options.mystuff_packs.get() mystuff_packs = options.mystuff_packs.get()
@ -158,7 +162,15 @@ class Game:
yield from extracted_game.install_all_patch(mod_config) yield from extracted_game.install_all_patch(mod_config)
yield from extracted_game.recreate_all_szs() yield from extracted_game.recreate_all_szs()
# Riivolution comparaison
riivolution_patched_hash_map = extracted_game.get_hash_map()
riivolution_diff: dict[str, Path] = comp_dict_changes(
riivolution_original_hash_map,
riivolution_patched_hash_map
)
# convert the extracted game into a file # convert the extracted game into a file
yield Progress(title=_("CONVERTING_TO_GAME_FILE"), set_part=7) yield Progress(title=_("CONVERTING_TO_GAME_FILE"), set_part=7)
converted_game: WITPath = yield from extracted_game.convert_to(output_type) converted_game: WITPath = yield from extracted_game.convert_to(output_type)
if converted_game is not None: yield from Game(converted_game.path).edit(mod_config) if converted_game is not None: yield from Game(converted_game.path).edit(mod_config)

View file

@ -1,11 +1,11 @@
import shutil import shutil
from dataclasses import dataclass, field from dataclasses import dataclass, field
from pathlib import Path from pathlib import Path
from typing import Generator, Callable, Iterator, Iterable, TYPE_CHECKING from typing import Generator, Callable, Iterator, TYPE_CHECKING
import json import json
from PIL import Image from PIL import Image
from source import threaded from source.utils import threaded
from source.mkw import Tag from source.mkw import Tag
from source.mkw.ModSettings.ModSettingsGroup import ModSettingsGroup from source.mkw.ModSettings.ModSettingsGroup import ModSettingsGroup
from source.mkw.Track.Cup import Cup from source.mkw.Track.Cup import Cup

View file

@ -1,7 +1,7 @@
import json import json
from pathlib import Path from pathlib import Path
from source import restart_program from source.utils import restart_program
class OptionLoadingError(Exception): class OptionLoadingError(Exception):

36
source/utils.py Normal file
View file

@ -0,0 +1,36 @@
import os
import sys
from threading import Thread
from typing import Callable
# useful functions
def threaded(func: Callable) -> Callable:
"""
Decorate a function to run in a separate thread
:param func: a function
:return: the decorated function
"""
def wrapper(*args, **kwargs):
# run the function in a Daemon, so it will stop when the main thread stops
thread = Thread(target=func, args=args, kwargs=kwargs, daemon=True)
thread.start()
return thread
return wrapper
def restart_program():
"""
Restart the program
"""
os.execl(sys.executable, sys.executable, *sys.argv)
def comp_dict_changes(d_old: dict, d_new: dict) -> dict:
"""
Return a comparaison dict showing every value that changed between d_old and d_new. Deleted value are ignored.
Example : {"a": 1, "b": 3, "d": 13}, {"b": 2, "c": 10, "d": 13} -> {"b": 2, "c": 10}
"""
return {name: value for name, value in d_new.items() if d_old.get(name) != value}