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 sys
from pathlib import Path
from typing import Any, Dict, Optional, Tuple
import requests
from typing import Any, Dict
from freqtrade.constants import USERPATH_STRATEGIES
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.")
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:
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/"
# First make sure the assets are removed.
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,
)
from freqtrade.commands.db_commands import start_convert_db
from freqtrade.commands.deploy_commands import (
from freqtrade.commands.deploy_ui import (
clean_ui_subdir,
download_and_install_ui,
get_ui_download_url,
@@ -612,13 +612,13 @@ def test_start_new_strategy_no_arg(mocker, caplog):
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(
"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"),
)
download_mock = mocker.patch("freqtrade.commands.deploy_commands.download_and_install_ui")
mocker.patch("freqtrade.commands.deploy_commands.read_ui_version", return_value=None)
download_mock = mocker.patch("freqtrade.commands.deploy_ui.download_and_install_ui")
mocker.patch("freqtrade.commands.deploy_ui.read_ui_version", return_value=None)
args = [
"install-ui",
]
@@ -642,13 +642,13 @@ def test_start_install_ui(mocker):
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_commands.Path.is_file", side_effect=[False, True])
rd_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.rmdir")
ul_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.unlink")
mocker.patch("freqtrade.commands.deploy_ui.Path.is_dir", side_effect=[True, True])
mocker.patch("freqtrade.commands.deploy_ui.Path.is_file", side_effect=[False, True])
rd_mock = mocker.patch("freqtrade.commands.deploy_ui.Path.rmdir")
ul_mock = mocker.patch("freqtrade.commands.deploy_ui.Path.unlink")
mocker.patch(
"freqtrade.commands.deploy_commands.Path.glob",
"freqtrade.commands.deploy_ui.Path.glob",
return_value=[Path("test1"), Path("test2"), Path(".gitkeep")],
)
folder = tmp_path / "uitests"
@@ -668,10 +668,10 @@ def test_download_and_install_ui(mocker, tmp_path):
file_like_object.seek(0)
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])
wb_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.write_bytes")
mocker.patch("freqtrade.commands.deploy_ui.Path.is_dir", side_effect=[True, False])
wb_mock = mocker.patch("freqtrade.commands.deploy_ui.Path.write_bytes")
folder = tmp_path / "uitests_dl"
folder.mkdir(exist_ok=True)
@@ -693,9 +693,7 @@ def test_get_ui_download_url(mocker):
[{"browser_download_url": "http://download.zip"}],
]
)
get_mock = mocker.patch(
"freqtrade.commands.deploy_commands.requests.get", return_value=response
)
get_mock = mocker.patch("freqtrade.commands.deploy_ui.requests.get", return_value=response)
x, last_version = get_ui_download_url()
assert get_mock.call_count == 2
assert last_version == "0.0.1"
@@ -718,9 +716,7 @@ def test_get_ui_download_url_direct(mocker):
},
]
)
get_mock = mocker.patch(
"freqtrade.commands.deploy_commands.requests.get", return_value=response
)
get_mock = mocker.patch("freqtrade.commands.deploy_ui.requests.get", return_value=response)
x, last_version = get_ui_download_url()
assert get_mock.call_count == 1
assert last_version == "0.0.2"