mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-06-13 12:15:09 +03:00
Addition of proper branch slection (#168)
* This is a bit better, but branch selection still isn't working -_- * I'm the king of oversight * Selecting different branch checks for updates * Stable doesn't detect old versions, which indicates it doesn't work * Start adding deckyState for plugin updating * Few tweaks * Disable nightly selection * Update decky-frontend-lib and move useSetting set setting to async
This commit is contained in:
+38
-11
@@ -1,25 +1,26 @@
|
||||
import uuid
|
||||
from logging import getLogger
|
||||
from json.decoder import JSONDecodeError
|
||||
|
||||
from asyncio import sleep
|
||||
from ensurepip import version
|
||||
from json.decoder import JSONDecodeError
|
||||
from logging import getLogger
|
||||
from os import getcwd, path, remove
|
||||
from subprocess import call
|
||||
|
||||
from aiohttp import ClientSession, web
|
||||
|
||||
from injector import inject_to_tab, get_tab
|
||||
|
||||
from os import getcwd, path, remove
|
||||
|
||||
from subprocess import call
|
||||
|
||||
import helpers
|
||||
from injector import get_tab, inject_to_tab
|
||||
from settings import SettingsManager
|
||||
|
||||
logger = getLogger("Updater")
|
||||
|
||||
class Updater:
|
||||
def __init__(self, context) -> None:
|
||||
self.context = context
|
||||
self.settings = self.context.settings
|
||||
# Exposes updater methods to frontend
|
||||
self.updater_methods = {
|
||||
"get_branch": self.get_branch,
|
||||
"get_version": self.get_version,
|
||||
"do_update": self.do_update,
|
||||
"do_restart": self.do_restart,
|
||||
@@ -27,6 +28,13 @@ class Updater:
|
||||
}
|
||||
self.remoteVer = None
|
||||
self.allRemoteVers = None
|
||||
try:
|
||||
self.currentBranch = self.get_branch(self.context.settings)
|
||||
if int(self.currentBranch) == -1:
|
||||
raise ValueError("get_branch could not determine branch!")
|
||||
except:
|
||||
self.currentBranch = 0
|
||||
logger.error("Current branch could not be determined, defaulting to \"Stable\"")
|
||||
try:
|
||||
with open(path.join(getcwd(), ".loader.version"), 'r') as version_file:
|
||||
self.localVer = version_file.readline().replace("\n", "")
|
||||
@@ -55,6 +63,10 @@ class Updater:
|
||||
res["success"] = False
|
||||
return web.json_response(res)
|
||||
|
||||
async def get_branch(self, manager: SettingsManager):
|
||||
logger.debug("current branch: %i" % manager.getSetting("branch", -1))
|
||||
return manager.getSetting("branch", -1)
|
||||
|
||||
async def get_version(self):
|
||||
if self.localVer:
|
||||
return {
|
||||
@@ -67,11 +79,27 @@ class Updater:
|
||||
return {"current": "unknown", "remote": self.remoteVer, "all": self.allRemoteVers, "updatable": False}
|
||||
|
||||
async def check_for_updates(self):
|
||||
logger.debug("checking for updates")
|
||||
selectedBranch = await self.get_branch(self.context.settings)
|
||||
async with ClientSession() as web:
|
||||
async with web.request("GET", "https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases", ssl=helpers.get_ssl_context()) as res:
|
||||
remoteVersions = await res.json()
|
||||
self.allRemoteVers = remoteVersions
|
||||
self.remoteVer = next(filter(lambda ver: ver["prerelease"] and ver["tag_name"].startswith("v") and ver["tag_name"].find("-pre"), remoteVersions), None)
|
||||
logger.debug("determining release type to find, branch is %i" % selectedBranch)
|
||||
if selectedBranch == 0:
|
||||
logger.debug("release type: release")
|
||||
self.remoteVer = next(filter(lambda ver: ver["tag_name"].startswith("v") and not ver["prerelease"] and ver["tag_name"], remoteVersions), None)
|
||||
elif selectedBranch == 1:
|
||||
logger.debug("release type: pre-release")
|
||||
self.remoteVer = next(filter(lambda ver: ver["prerelease"] and ver["tag_name"].startswith("v") and ver["tag_name"].find("-pre"), remoteVersions), None)
|
||||
# elif selectedBranch == 2:
|
||||
# logger.debug("release type: nightly")
|
||||
# self.remoteVer = next(filter(lambda ver: ver["prerelease"] and ver["tag_name"].startswith("v") and ver["tag_name"].find("nightly"), remoteVersions), None)
|
||||
else:
|
||||
logger.error("release type: NOT FOUND")
|
||||
raise ValueError("no valid branch found")
|
||||
# doesn't make it to this line below or farther
|
||||
# logger.debug("Remote Version: %s" % self.remoteVer.find("name"))
|
||||
logger.info("Updated remote version information")
|
||||
tab = await get_tab("SP")
|
||||
await tab.evaluate_js(f"window.DeckyPluginLoader.notifyUpdates()", False, True, False)
|
||||
@@ -88,7 +116,6 @@ class Updater:
|
||||
|
||||
async def do_update(self):
|
||||
version = self.remoteVer["tag_name"]
|
||||
#TODO don't hardcode this
|
||||
download_url = self.remoteVer["assets"][0]["browser_download_url"]
|
||||
|
||||
tab = await get_tab("SP")
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"decky-frontend-lib": "^1.8.0",
|
||||
"decky-frontend-lib": "^1.8.2",
|
||||
"react-icons": "^4.4.0",
|
||||
"react-markdown": "^8.0.3",
|
||||
"remark-gfm": "^3.0.1"
|
||||
|
||||
Generated
+4
-4
@@ -9,7 +9,7 @@ specifiers:
|
||||
'@types/react': 16.14.0
|
||||
'@types/react-router': 5.1.18
|
||||
'@types/webpack': ^5.28.0
|
||||
decky-frontend-lib: ^1.8.0
|
||||
decky-frontend-lib: ^1.8.2
|
||||
husky: ^8.0.1
|
||||
import-sort-style-module: ^6.0.0
|
||||
inquirer: ^8.2.4
|
||||
@@ -27,7 +27,7 @@ specifiers:
|
||||
typescript: ^4.7.4
|
||||
|
||||
dependencies:
|
||||
decky-frontend-lib: 1.8.0
|
||||
decky-frontend-lib: 1.8.2
|
||||
react-icons: 4.4.0_react@16.14.0
|
||||
react-markdown: 8.0.3_vshvapmxg47tngu7tvrsqpq55u
|
||||
remark-gfm: 3.0.1
|
||||
@@ -875,8 +875,8 @@ packages:
|
||||
dependencies:
|
||||
ms: 2.1.2
|
||||
|
||||
/decky-frontend-lib/1.8.0:
|
||||
resolution: {integrity: sha512-ZPJdbkNI5d/d/19Hv97FVgFyMerYUzwXavYGv8euLMrbH9XuVM4KAx0mbKkO0SQUl75HKQ3LxsaCpA6QLDr9EA==}
|
||||
/decky-frontend-lib/1.8.2:
|
||||
resolution: {integrity: sha512-SwGoUBpKd8OM3kovItW+oCpevDiDXFu0UaUh1vyD4BYG0s+4uQBdeevWLhyJHk0402pAUDrOL8022jpana5dnA==}
|
||||
dependencies:
|
||||
minimist: 1.2.6
|
||||
dev: false
|
||||
|
||||
@@ -2,6 +2,7 @@ import { FC, createContext, useContext, useEffect, useState } from 'react';
|
||||
|
||||
import { Plugin } from '../plugin';
|
||||
import { PluginUpdateMapping } from '../store';
|
||||
import { VerInfo } from '../updater';
|
||||
|
||||
interface PublicDeckyState {
|
||||
plugins: Plugin[];
|
||||
@@ -9,6 +10,7 @@ interface PublicDeckyState {
|
||||
updates: PluginUpdateMapping | null;
|
||||
hasLoaderUpdate?: boolean;
|
||||
isLoaderUpdating: boolean;
|
||||
versionInfo: VerInfo | null;
|
||||
}
|
||||
|
||||
export class DeckyState {
|
||||
@@ -17,6 +19,7 @@ export class DeckyState {
|
||||
private _updates: PluginUpdateMapping | null = null;
|
||||
private _hasLoaderUpdate: boolean = false;
|
||||
private _isLoaderUpdating: boolean = false;
|
||||
private _versionInfo: VerInfo | null = null;
|
||||
|
||||
public eventBus = new EventTarget();
|
||||
|
||||
@@ -27,9 +30,15 @@ export class DeckyState {
|
||||
updates: this._updates,
|
||||
hasLoaderUpdate: this._hasLoaderUpdate,
|
||||
isLoaderUpdating: this._isLoaderUpdating,
|
||||
versionInfo: this._versionInfo,
|
||||
};
|
||||
}
|
||||
|
||||
setVersionInfo(versionInfo: VerInfo) {
|
||||
this._versionInfo = versionInfo;
|
||||
this.notifyUpdate();
|
||||
}
|
||||
|
||||
setPlugins(plugins: Plugin[]) {
|
||||
this._plugins = plugins;
|
||||
this.notifyUpdate();
|
||||
@@ -66,6 +75,7 @@ export class DeckyState {
|
||||
}
|
||||
|
||||
interface DeckyStateContext extends PublicDeckyState {
|
||||
setVersionInfo(versionInfo: VerInfo): void;
|
||||
setIsLoaderUpdating(hasUpdate: boolean): void;
|
||||
setActivePlugin(name: string): void;
|
||||
closeActivePlugin(): void;
|
||||
@@ -93,12 +103,13 @@ export const DeckyStateContextProvider: FC<Props> = ({ children, deckyState }) =
|
||||
}, []);
|
||||
|
||||
const setIsLoaderUpdating = (hasUpdate: boolean) => deckyState.setIsLoaderUpdating(hasUpdate);
|
||||
const setVersionInfo = (versionInfo: VerInfo) => deckyState.setVersionInfo(versionInfo);
|
||||
const setActivePlugin = (name: string) => deckyState.setActivePlugin(name);
|
||||
const closeActivePlugin = () => deckyState.closeActivePlugin();
|
||||
|
||||
return (
|
||||
<DeckyStateContext.Provider
|
||||
value={{ ...publicDeckyState, setIsLoaderUpdating, setActivePlugin, closeActivePlugin }}
|
||||
value={{ ...publicDeckyState, setIsLoaderUpdating, setVersionInfo, setActivePlugin, closeActivePlugin }}
|
||||
>
|
||||
{children}
|
||||
</DeckyStateContext.Provider>
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
import { Dropdown, Field } from 'decky-frontend-lib';
|
||||
import { FunctionComponent } from 'react';
|
||||
|
||||
import { callUpdaterMethod } from '../../../../updater';
|
||||
import { useSetting } from '../../../../utils/hooks/useSetting';
|
||||
|
||||
enum UpdateBranch {
|
||||
Stable,
|
||||
Prerelease,
|
||||
Nightly,
|
||||
// Nightly,
|
||||
}
|
||||
|
||||
const BranchSelect: FunctionComponent<{}> = () => {
|
||||
const [selectedBranch, setSelectedBranch] = useSetting<UpdateBranch>('branch', UpdateBranch.Prerelease);
|
||||
|
||||
return (
|
||||
// Returns numerical values from 0 to 2 (with current branch setup as of 8/28/22)
|
||||
// 0 being stable, 1 being pre-release and 2 being nightly
|
||||
<Field label="Update Channel">
|
||||
<Dropdown
|
||||
rgOptions={Object.values(UpdateBranch)
|
||||
@@ -22,8 +25,10 @@ const BranchSelect: FunctionComponent<{}> = () => {
|
||||
data: UpdateBranch[branch],
|
||||
}))}
|
||||
selectedOption={selectedBranch}
|
||||
onChange={(newVal) => {
|
||||
setSelectedBranch(newVal.data);
|
||||
onChange={async (newVal) => {
|
||||
await setSelectedBranch(newVal.data);
|
||||
callUpdaterMethod('check_for_updates');
|
||||
console.log('switching branches!');
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
|
||||
@@ -55,20 +55,12 @@ function PatchNotesModal({ versionInfo, closeModal }: { versionInfo: VerInfo | n
|
||||
}
|
||||
|
||||
export default function UpdaterSettings() {
|
||||
const { isLoaderUpdating, setIsLoaderUpdating } = useDeckyState();
|
||||
const { isLoaderUpdating, setIsLoaderUpdating, versionInfo, setVersionInfo } = useDeckyState();
|
||||
|
||||
const [versionInfo, setVersionInfo] = useState<VerInfo | null>(null);
|
||||
const [checkingForUpdates, setCheckingForUpdates] = useState<boolean>(false);
|
||||
const [updateProgress, setUpdateProgress] = useState<number>(-1);
|
||||
const [reloading, setReloading] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const res = (await callUpdaterMethod('get_version')) as { result: VerInfo };
|
||||
setVersionInfo(res.result);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
window.DeckyUpdater = {
|
||||
updateProgress: (i) => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useState } from 'react';
|
||||
import { FaShapes } from 'react-icons/fa';
|
||||
|
||||
import { installFromURL } from '../../../../store';
|
||||
// import BranchSelect from './BranchSelect';
|
||||
import BranchSelect from './BranchSelect';
|
||||
import RemoteDebuggingSettings from './RemoteDebugging';
|
||||
import UpdaterSettings from './Updater';
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function GeneralSettings() {
|
||||
/>
|
||||
</Field> */}
|
||||
<UpdaterSettings />
|
||||
{/* <BranchSelect /> */}
|
||||
<BranchSelect />
|
||||
<RemoteDebuggingSettings />
|
||||
<Field
|
||||
label="Manual plugin install"
|
||||
|
||||
@@ -52,10 +52,8 @@ class PluginLoader extends Logger {
|
||||
),
|
||||
icon: (
|
||||
<DeckyStateContextProvider deckyState={this.deckyState}>
|
||||
<>
|
||||
<FaPlug />
|
||||
<TabIcon />
|
||||
</>
|
||||
<FaPlug />
|
||||
<TabIcon />
|
||||
</DeckyStateContextProvider>
|
||||
),
|
||||
});
|
||||
@@ -105,6 +103,7 @@ class PluginLoader extends Logger {
|
||||
|
||||
public async notifyUpdates() {
|
||||
const versionInfo = (await callUpdaterMethod('get_version')).result as VerInfo;
|
||||
this.deckyState.setVersionInfo(versionInfo);
|
||||
if (versionInfo?.remote && versionInfo?.remote?.tag_name != versionInfo?.current) {
|
||||
this.toaster.toast({
|
||||
title: 'Decky',
|
||||
|
||||
@@ -10,9 +10,8 @@ interface SetSettingArgs<T> {
|
||||
value: T;
|
||||
}
|
||||
|
||||
export function useSetting<T>(key: string, def: T): [value: T | null, setValue: (value: T) => void] {
|
||||
export function useSetting<T>(key: string, def: T): [value: T | null, setValue: (value: T) => Promise<void>] {
|
||||
const [value, setValue] = useState(def);
|
||||
const [ready, setReady] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
@@ -20,20 +19,18 @@ export function useSetting<T>(key: string, def: T): [value: T | null, setValue:
|
||||
key,
|
||||
default: def,
|
||||
} as GetSettingArgs<T>)) as { result: T };
|
||||
setReady(true);
|
||||
setValue(res.result);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (ready)
|
||||
(async () => {
|
||||
await window.DeckyPluginLoader.callServerMethod('set_setting', {
|
||||
key,
|
||||
value,
|
||||
} as SetSettingArgs<T>);
|
||||
})();
|
||||
}, [value]);
|
||||
|
||||
return [value, setValue];
|
||||
return [
|
||||
value,
|
||||
async (val: T) => {
|
||||
setValue(val);
|
||||
await window.DeckyPluginLoader.callServerMethod('set_setting', {
|
||||
key,
|
||||
value: val,
|
||||
} as SetSettingArgs<T>);
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user