refactor: move ui deployment to it's own file

This commit is contained in:
Matthias
2024-10-05 13:06:19 +02:00
parent 092275a981
commit 24c09d0319
3 changed files with 107 additions and 95 deletions

View File

@@ -1,9 +1,7 @@
import logging import logging
import sys import sys
from pathlib import Path from pathlib import Path
from typing import Any, Dict, Optional, Tuple from typing import Any, Dict
import requests
from freqtrade.constants import USERPATH_STRATEGIES from freqtrade.constants import USERPATH_STRATEGIES
from freqtrade.enums import RunMode from freqtrade.enums import RunMode
@@ -101,80 +99,14 @@ def start_new_strategy(args: Dict[str, Any]) -> None:
raise ConfigurationError("`new-strategy` requires --strategy to be set.") raise ConfigurationError("`new-strategy` requires --strategy to be set.")
def clean_ui_subdir(directory: Path):
if directory.is_dir():
logger.info("Removing UI directory content.")
for p in reversed(list(directory.glob("**/*"))): # iterate contents from leaves to root
if p.name in (".gitkeep", "fallback_file.html"):
continue
if p.is_file():
p.unlink()
elif p.is_dir():
p.rmdir()
def read_ui_version(dest_folder: Path) -> Optional[str]:
file = dest_folder / ".uiversion"
if not file.is_file():
return None
with file.open("r") as f:
return f.read()
def download_and_install_ui(dest_folder: Path, dl_url: str, version: str):
from io import BytesIO
from zipfile import ZipFile
logger.info(f"Downloading {dl_url}")
resp = requests.get(dl_url, timeout=req_timeout).content
dest_folder.mkdir(parents=True, exist_ok=True)
with ZipFile(BytesIO(resp)) as zf:
for fn in zf.filelist:
with zf.open(fn) as x:
destfile = dest_folder / fn.filename
if fn.is_dir():
destfile.mkdir(exist_ok=True)
else:
destfile.write_bytes(x.read())
with (dest_folder / ".uiversion").open("w") as f:
f.write(version)
def get_ui_download_url(version: Optional[str] = None) -> Tuple[str, str]:
base_url = "https://api.github.com/repos/freqtrade/frequi/"
# Get base UI Repo path
resp = requests.get(f"{base_url}releases", timeout=req_timeout)
resp.raise_for_status()
r = resp.json()
if version:
tmp = [x for x in r if x["name"] == version]
if tmp:
latest_version = tmp[0]["name"]
assets = tmp[0].get("assets", [])
else:
raise ValueError("UI-Version not found.")
else:
latest_version = r[0]["name"]
assets = r[0].get("assets", [])
dl_url = ""
if assets and len(assets) > 0:
dl_url = assets[0]["browser_download_url"]
# URL not found - try assets url
if not dl_url:
assets = r[0]["assets_url"]
resp = requests.get(assets, timeout=req_timeout)
r = resp.json()
dl_url = r[0]["browser_download_url"]
return dl_url, latest_version
def start_install_ui(args: Dict[str, Any]) -> None: def start_install_ui(args: Dict[str, Any]) -> None:
from freqtrade.commands.deploy_ui import (
clean_ui_subdir,
download_and_install_ui,
get_ui_download_url,
read_ui_version,
)
dest_folder = Path(__file__).parents[1] / "rpc/api_server/ui/installed/" dest_folder = Path(__file__).parents[1] / "rpc/api_server/ui/installed/"
# First make sure the assets are removed. # First make sure the assets are removed.
dl_url, latest_version = get_ui_download_url(args.get("ui_version")) dl_url, latest_version = get_ui_download_url(args.get("ui_version"))

View File

@@ -0,0 +1,84 @@
import logging
from pathlib import Path
from typing import Optional, Tuple
import requests
logger = logging.getLogger(__name__)
# Timeout for requests
req_timeout = 30
def clean_ui_subdir(directory: Path):
if directory.is_dir():
logger.info("Removing UI directory content.")
for p in reversed(list(directory.glob("**/*"))): # iterate contents from leaves to root
if p.name in (".gitkeep", "fallback_file.html"):
continue
if p.is_file():
p.unlink()
elif p.is_dir():
p.rmdir()
def read_ui_version(dest_folder: Path) -> Optional[str]:
file = dest_folder / ".uiversion"
if not file.is_file():
return None
with file.open("r") as f:
return f.read()
def download_and_install_ui(dest_folder: Path, dl_url: str, version: str):
from io import BytesIO
from zipfile import ZipFile
logger.info(f"Downloading {dl_url}")
resp = requests.get(dl_url, timeout=req_timeout).content
dest_folder.mkdir(parents=True, exist_ok=True)
with ZipFile(BytesIO(resp)) as zf:
for fn in zf.filelist:
with zf.open(fn) as x:
destfile = dest_folder / fn.filename
if fn.is_dir():
destfile.mkdir(exist_ok=True)
else:
destfile.write_bytes(x.read())
with (dest_folder / ".uiversion").open("w") as f:
f.write(version)
def get_ui_download_url(version: Optional[str] = None) -> Tuple[str, str]:
base_url = "https://api.github.com/repos/freqtrade/frequi/"
# Get base UI Repo path
resp = requests.get(f"{base_url}releases", timeout=req_timeout)
resp.raise_for_status()
r = resp.json()
if version:
tmp = [x for x in r if x["name"] == version]
if tmp:
latest_version = tmp[0]["name"]
assets = tmp[0].get("assets", [])
else:
raise ValueError("UI-Version not found.")
else:
latest_version = r[0]["name"]
assets = r[0].get("assets", [])
dl_url = ""
if assets and len(assets) > 0:
dl_url = assets[0]["browser_download_url"]
# URL not found - try assets url
if not dl_url:
assets = r[0]["assets_url"]
resp = requests.get(assets, timeout=req_timeout)
r = resp.json()
dl_url = r[0]["browser_download_url"]
return dl_url, latest_version

View File

@@ -31,7 +31,7 @@ from freqtrade.commands import (
start_webserver, start_webserver,
) )
from freqtrade.commands.db_commands import start_convert_db from freqtrade.commands.db_commands import start_convert_db
from freqtrade.commands.deploy_commands import ( from freqtrade.commands.deploy_ui import (
clean_ui_subdir, clean_ui_subdir,
download_and_install_ui, download_and_install_ui,
get_ui_download_url, get_ui_download_url,
@@ -612,13 +612,13 @@ def test_start_new_strategy_no_arg(mocker, caplog):
def test_start_install_ui(mocker): def test_start_install_ui(mocker):
clean_mock = mocker.patch("freqtrade.commands.deploy_commands.clean_ui_subdir") clean_mock = mocker.patch("freqtrade.commands.deploy_ui.clean_ui_subdir")
get_url_mock = mocker.patch( get_url_mock = mocker.patch(
"freqtrade.commands.deploy_commands.get_ui_download_url", "freqtrade.commands.deploy_ui.get_ui_download_url",
return_value=("https://example.com/whatever", "0.0.1"), return_value=("https://example.com/whatever", "0.0.1"),
) )
download_mock = mocker.patch("freqtrade.commands.deploy_commands.download_and_install_ui") download_mock = mocker.patch("freqtrade.commands.deploy_ui.download_and_install_ui")
mocker.patch("freqtrade.commands.deploy_commands.read_ui_version", return_value=None) mocker.patch("freqtrade.commands.deploy_ui.read_ui_version", return_value=None)
args = [ args = [
"install-ui", "install-ui",
] ]
@@ -642,13 +642,13 @@ def test_start_install_ui(mocker):
def test_clean_ui_subdir(mocker, tmp_path, caplog): def test_clean_ui_subdir(mocker, tmp_path, caplog):
mocker.patch("freqtrade.commands.deploy_commands.Path.is_dir", side_effect=[True, True]) mocker.patch("freqtrade.commands.deploy_ui.Path.is_dir", side_effect=[True, True])
mocker.patch("freqtrade.commands.deploy_commands.Path.is_file", side_effect=[False, True]) mocker.patch("freqtrade.commands.deploy_ui.Path.is_file", side_effect=[False, True])
rd_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.rmdir") rd_mock = mocker.patch("freqtrade.commands.deploy_ui.Path.rmdir")
ul_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.unlink") ul_mock = mocker.patch("freqtrade.commands.deploy_ui.Path.unlink")
mocker.patch( mocker.patch(
"freqtrade.commands.deploy_commands.Path.glob", "freqtrade.commands.deploy_ui.Path.glob",
return_value=[Path("test1"), Path("test2"), Path(".gitkeep")], return_value=[Path("test1"), Path("test2"), Path(".gitkeep")],
) )
folder = tmp_path / "uitests" folder = tmp_path / "uitests"
@@ -668,10 +668,10 @@ def test_download_and_install_ui(mocker, tmp_path):
file_like_object.seek(0) file_like_object.seek(0)
requests_mock.content = file_like_object.read() requests_mock.content = file_like_object.read()
mocker.patch("requests.get", return_value=requests_mock) mocker.patch("freqtrade.commands.deploy_ui.requests.get", return_value=requests_mock)
mocker.patch("freqtrade.commands.deploy_commands.Path.is_dir", side_effect=[True, False]) mocker.patch("freqtrade.commands.deploy_ui.Path.is_dir", side_effect=[True, False])
wb_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.write_bytes") wb_mock = mocker.patch("freqtrade.commands.deploy_ui.Path.write_bytes")
folder = tmp_path / "uitests_dl" folder = tmp_path / "uitests_dl"
folder.mkdir(exist_ok=True) folder.mkdir(exist_ok=True)
@@ -693,9 +693,7 @@ def test_get_ui_download_url(mocker):
[{"browser_download_url": "http://download.zip"}], [{"browser_download_url": "http://download.zip"}],
] ]
) )
get_mock = mocker.patch( get_mock = mocker.patch("freqtrade.commands.deploy_ui.requests.get", return_value=response)
"freqtrade.commands.deploy_commands.requests.get", return_value=response
)
x, last_version = get_ui_download_url() x, last_version = get_ui_download_url()
assert get_mock.call_count == 2 assert get_mock.call_count == 2
assert last_version == "0.0.1" assert last_version == "0.0.1"
@@ -718,9 +716,7 @@ def test_get_ui_download_url_direct(mocker):
}, },
] ]
) )
get_mock = mocker.patch( get_mock = mocker.patch("freqtrade.commands.deploy_ui.requests.get", return_value=response)
"freqtrade.commands.deploy_commands.requests.get", return_value=response
)
x, last_version = get_ui_download_url() x, last_version = get_ui_download_url()
assert get_mock.call_count == 1 assert get_mock.call_count == 1
assert last_version == "0.0.2" assert last_version == "0.0.2"