Skip to content
This repository has been archived by the owner on Apr 21, 2023. It is now read-only.

Improve profile management #467

Merged
merged 2 commits into from
Dec 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 14 additions & 30 deletions bcml/_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from tempfile import NamedTemporaryFile, mkdtemp
from time import sleep
from threading import Thread
from typing import List, Optional
from typing import Dict, List, Optional
from xml.dom import minidom

import requests
Expand Down Expand Up @@ -335,43 +335,27 @@ def get_backups(self):
for b in [(b.stem.split("---"), str(b)) for b in install.get_backups()]
]

def get_profiles(self):
return [
{"name": (d / ".profile").read_text("utf-8"), "path": str(d)}
for d in {d for d in util.get_profiles_dir().glob("*") if d.is_dir()}
]
def get_profiles(self) -> List[Dict[str, str]]:
return util.get_profiles()

def get_current_profile(self):
profile = util.get_modpack_dir() / ".profile"
with locks.mod_dir:
if not (util.get_modpack_dir() / ".profile").exists():
profile.write_text("Default")
return "Default"
return profile.read_text("utf-8")
def get_current_profile(self) -> Dict[str, str]:
return util.get_current_profile()

@win_or_lose
@install.refresher
def set_profile(self, params):
mod_dir = util.get_modpack_dir()
with locks.mod_dir:
rmtree(mod_dir)
copytree(params["profile"], mod_dir)
def set_profile(self, params) -> None:
profile_name = str(params["profile"]["name"]).strip()
util.set_profile(profile_name)

@win_or_lose
def delete_profile(self, params):
rmtree(params["profile"])
def delete_profile(self, params) -> None:
profile_name = str(params["profile"]["name"]).strip()
util.delete_profile(profile_name)

@win_or_lose
def save_profile(self, params):
mod_dir = util.get_modpack_dir()
profile = mod_dir / ".profile"
profile.write_text(params["profile"])
profile_dir = util.get_profiles_dir() / util.get_safe_pathname(
params["profile"]
)
if profile_dir.exists():
rmtree(profile_dir)
copytree(mod_dir, profile_dir)
def save_profile(self, params) -> None:
profile_name = str(params["profile"]["name"]).strip().replace("\t", "")
util.save_profile(profile_name)

def check_mod_options(self, params):
metas = {
Expand Down
2 changes: 1 addition & 1 deletion bcml/assets/scripts/bundle.js

Large diffs are not rendered by default.

8 changes: 3 additions & 5 deletions bcml/assets/src/js/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -269,16 +269,14 @@ class App extends React.Component {
let progressTitle;
let action;
if (operation == "save") {
progressTitle = "Saving Profile";
progressTitle = `Saving Profile: ${profile.name}`;
action = pywebview.api.save_profile;
} else if (operation == "load") {
progressTitle = `Loading ${profile.name}`;
progressTitle = `Loading Profile: ${profile.name}`;
action = pywebview.api.set_profile;
profile = profile.path;
} else {
progressTitle = `Deleting ${profile.name}`;
progressTitle = `Deleting Profile: ${profile.name}`;
action = pywebview.api.delete_profile;
profile = profile.path;
}
const task = () =>
this.setState(
Expand Down
8 changes: 4 additions & 4 deletions bcml/assets/src/js/Profile.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class ProfileModal extends React.Component {

this.state = {
profiles: [],
currentProfile: "Default",
currentProfile: null,
profileName: ""
};
}
Expand Down Expand Up @@ -38,11 +38,11 @@ class ProfileModal extends React.Component {
</Modal.Header>
<Modal.Body>
<div className="h5">
<strong>Current Profile:</strong> {this.state.currentProfile}
<strong>Current Profile:</strong> {this.state.currentProfile?.name || <i>None</i>}
</div>
<InputGroup className="mb-3">
<FormControl
placeholder="Name new profile"
placeholder="New profile name"
value={this.state.profileName}
onChange={e =>
this.setState({ profileName: e.currentTarget.value })
Expand All @@ -53,7 +53,7 @@ class ProfileModal extends React.Component {
variant="primary"
disabled={!this.state.profileName}
onClick={() =>
this.props.onSave(this.state.profileName, "save")
this.props.onSave({ name: this.state.profileName }, "save")
GingerAvalanche marked this conversation as resolved.
Show resolved Hide resolved
}>
Save
</Button>
Expand Down
89 changes: 88 additions & 1 deletion bcml/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
from oead.aamp import ParameterIO, ParameterList # pylint:disable=import-error
from webview import Window # pylint: disable=wrong-import-order

from bcml import bcml as rsext
from bcml import bcml as rsext, locks
from bcml import pickles, DEBUG # pylint: disable=unused-import
from bcml.__version__ import VERSION

Expand Down Expand Up @@ -852,6 +852,93 @@ def get_profiles_dir() -> Path:
return get_storage_dir() / ("profiles" if get_settings("wiiu") else "profiles_nx")


class ProfileNotFoundError(Exception):
pass


def get_profiles() -> List[Dict[str, str]]:
profiles = []
profiles_dir = get_profiles_dir().glob("*")
for entry in profiles_dir:
if not entry.is_dir():
continue
profile = parse_profile_file(entry / ".profile")
profile["path"] = str(entry)
profiles.append(profile)
return profiles


def get_profile(profile_name: str) -> Dict[str, str]:
profiles_dir = get_profiles_dir().glob("*")
for entry in profiles_dir:
if not entry.is_dir():
continue
profile = parse_profile_file(entry / ".profile")
if profile["name"] == profile_name:
profile["path"] = str(entry)
return profile
raise ProfileNotFoundError(f"No profile found with name: '{profile_name}'")


def get_profile_path(profile_name: str) -> Path:
profiles_dir = get_profiles_dir().glob("*")
for entry in profiles_dir:
if not entry.is_dir():
continue
profile = parse_profile_file(entry / ".profile")
if profile["name"] == profile_name:
return str(entry)
raise ProfileNotFoundError(f"No profile found with name: '{profile_name}'")


def get_current_profile() -> Union[Dict[str, str], None]:
current_profile_file = get_modpack_dir() / ".profile"
if not current_profile_file.exists():
return None
profile = parse_profile_file(current_profile_file)
try:
profile["path"] = get_profile_path(profile["name"])
except ProfileNotFoundError:
profile["path"] = None
return profile


def parse_profile_file(profile_file: Path) -> Dict[str, str]:
if not profile_file.exists():
raise FileNotFoundError(f"Profile file not found: '{profile_file}'")
profile_data = profile_file.read_text("utf-8").split("\t")
return {"name": profile_data[0]}


def set_profile(profile_name: str) -> None:
profile_path = get_profile_path(profile_name)
mod_dir = get_modpack_dir()
with locks.mod_dir:
shutil.rmtree(mod_dir)
shutil.copytree(profile_path, mod_dir)


def delete_profile(profile_name: str) -> None:
profile_path = get_profile_path(profile_name)
shutil.rmtree(profile_path)
current_profile = get_current_profile()
if current_profile and current_profile["name"] == profile_name:
with locks.mod_dir:
os.remove(get_modpack_dir() / ".profile")


def save_profile(profile_name: str) -> None:
profile_data = [profile_name]
mod_dir = get_modpack_dir()
profile_file = mod_dir / ".profile"
profile_file.write_text("\t".join(profile_data))
profile_dir = get_profiles_dir() / get_safe_pathname(profile_name)
if profile_dir.exists():
shutil.rmtree(profile_dir)
with locks.mod_dir:
shutil.copytree(mod_dir, profile_dir)


@lru_cache(None)
def get_game_file(path: Union[Path, str], aoc: bool = False) -> Path:
if str(path).replace("\\", "/").startswith(f"{get_content_path()}/"):
Expand Down