A little cleanup refactor of packages
This commit is contained in:
parent
d950f0c521
commit
0a9f37ae63
@ -1,6 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
|
from collections.abc import Generator
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
from enum import auto
|
from enum import auto
|
||||||
@ -113,14 +114,6 @@ class Package:
|
|||||||
version = cast(str, desired_release["tag_name"])
|
version = cast(str, desired_release["tag_name"])
|
||||||
hacs_json = self.get_hacs_json(version)
|
hacs_json = self.get_hacs_json(version)
|
||||||
|
|
||||||
# Based on type, if we have no hacs json, we can provide some possible paths for the download but won't know
|
|
||||||
# If a plugin:
|
|
||||||
# First, check in root/dist/ for a js file named the same as the repo or with "lovelace-" prefix removed
|
|
||||||
# Second will be looking for a realeases for a js file named the same name as the repo or with loveace- prefix removed
|
|
||||||
# Third will be looking in the root dir for a js file named the same as the repo or with loveace- prefix removed
|
|
||||||
# If an integration:
|
|
||||||
# We always use the zipball_url
|
|
||||||
|
|
||||||
download_url = None
|
download_url = None
|
||||||
if filename := hacs_json.get("filename"):
|
if filename := hacs_json.get("filename"):
|
||||||
for asset in desired_release["assets"]:
|
for asset in desired_release["assets"]:
|
||||||
@ -136,6 +129,7 @@ class Package:
|
|||||||
return version, download_url
|
return version, download_url
|
||||||
|
|
||||||
def get_hacs_json(self, version: str | None = None) -> dict:
|
def get_hacs_json(self, version: str | None = None) -> dict:
|
||||||
|
"""Fetches the hacs.json file for the package."""
|
||||||
version = version or self.version
|
version = version or self.version
|
||||||
response = requests.get(
|
response = requests.get(
|
||||||
f"https://raw.githubusercontent.com/{self.owner}/{self.name}/{version}/hacs.json"
|
f"https://raw.githubusercontent.com/{self.owner}/{self.name}/{version}/hacs.json"
|
||||||
@ -148,12 +142,7 @@ class Package:
|
|||||||
return response.json()
|
return response.json()
|
||||||
|
|
||||||
def install_plugin(self, hass_config_path: Path):
|
def install_plugin(self, hass_config_path: Path):
|
||||||
# First, check in root/dist/ for a js file named the same as the repo or with "lovelace-" prefix removed
|
"""Installs the plugin package."""
|
||||||
# Second will be looking for a realeases for a js file named the same name as the repo or with loveace- prefix removed
|
|
||||||
# Third will be looking in the root dir for a js file named the same as the repo or with loveace- prefix removed
|
|
||||||
# If none of these are found, raise an error
|
|
||||||
# If a file is found, write it to www/js/<filename>.js and write a file www/js/<filename>-unhacs.txt with the
|
|
||||||
# serialized package
|
|
||||||
|
|
||||||
valid_filenames: Iterable[str]
|
valid_filenames: Iterable[str]
|
||||||
if filename := self.get_hacs_json().get("filename"):
|
if filename := self.get_hacs_json().get("filename"):
|
||||||
@ -166,28 +155,29 @@ class Package:
|
|||||||
f"{self.name}-bundle.js",
|
f"{self.name}-bundle.js",
|
||||||
)
|
)
|
||||||
|
|
||||||
def real_get(filename) -> requests.Response:
|
def real_get(filename) -> requests.Response | None:
|
||||||
plugin = requests.get(
|
urls = [
|
||||||
f"https://raw.githubusercontent.com/{self.owner}/{self.version}/dist/{filename}"
|
f"https://raw.githubusercontent.com/{self.owner}/{self.version}/dist/{filename}",
|
||||||
)
|
f"https://github.com/{self.owner}/{self.name}/releases/download/{self.version}/{filename}",
|
||||||
if plugin.status_code == 404:
|
f"https://raw.githubusercontent.com/{self.owner}/{self.version}/{filename}",
|
||||||
plugin = requests.get(
|
]
|
||||||
f"https://github.com/{self.owner}/{self.name}/releases/download/{self.version}/{filename}"
|
|
||||||
)
|
for url in urls:
|
||||||
if plugin.status_code == 404:
|
plugin = requests.get(url)
|
||||||
plugin = requests.get(
|
|
||||||
f"https://raw.githubusercontent.com/{self.owner}/{self.version}/{filename}"
|
if int(plugin.status_code / 100) == 4:
|
||||||
)
|
continue
|
||||||
|
|
||||||
plugin.raise_for_status()
|
plugin.raise_for_status()
|
||||||
|
|
||||||
return plugin
|
return plugin
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
for filename in valid_filenames:
|
for filename in valid_filenames:
|
||||||
try:
|
|
||||||
plugin = real_get(filename)
|
plugin = real_get(filename)
|
||||||
|
if plugin:
|
||||||
break
|
break
|
||||||
except requests.HTTPError:
|
|
||||||
pass
|
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"No valid filename found for package {self.name}")
|
raise ValueError(f"No valid filename found for package {self.name}")
|
||||||
|
|
||||||
@ -198,6 +188,7 @@ class Package:
|
|||||||
yaml.dump(self.to_yaml(), js_path.joinpath(f"{filename}-unhacs.yaml").open("w"))
|
yaml.dump(self.to_yaml(), js_path.joinpath(f"{filename}-unhacs.yaml").open("w"))
|
||||||
|
|
||||||
def install_integration(self, hass_config_path: Path):
|
def install_integration(self, hass_config_path: Path):
|
||||||
|
"""Installs the integration package."""
|
||||||
zipball_url = f"https://codeload.github.com/{self.owner}/{self.name}/zip/refs/tags/{self.version}"
|
zipball_url = f"https://codeload.github.com/{self.owner}/{self.name}/zip/refs/tags/{self.version}"
|
||||||
response = requests.get(zipball_url)
|
response = requests.get(zipball_url)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
@ -227,6 +218,7 @@ class Package:
|
|||||||
yaml.dump(self.to_yaml(), dest.joinpath("unhacs.yaml").open("w"))
|
yaml.dump(self.to_yaml(), dest.joinpath("unhacs.yaml").open("w"))
|
||||||
|
|
||||||
def install(self, hass_config_path: Path):
|
def install(self, hass_config_path: Path):
|
||||||
|
"""Installs the package."""
|
||||||
if self.package_type == PackageType.PLUGIN:
|
if self.package_type == PackageType.PLUGIN:
|
||||||
self.install_plugin(hass_config_path)
|
self.install_plugin(hass_config_path)
|
||||||
elif self.package_type == PackageType.INTEGRATION:
|
elif self.package_type == PackageType.INTEGRATION:
|
||||||
@ -235,6 +227,7 @@ class Package:
|
|||||||
raise NotImplementedError(f"Unknown package type {self.package_type}")
|
raise NotImplementedError(f"Unknown package type {self.package_type}")
|
||||||
|
|
||||||
def uninstall(self, hass_config_path: Path) -> bool:
|
def uninstall(self, hass_config_path: Path) -> bool:
|
||||||
|
"""Uninstalls the package if it is installed, returning True if it was uninstalled."""
|
||||||
if self.path:
|
if self.path:
|
||||||
if self.path.is_dir():
|
if self.path.is_dir():
|
||||||
shutil.rmtree(self.path)
|
shutil.rmtree(self.path)
|
||||||
@ -251,35 +244,20 @@ class Package:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def installed_package(self, hass_config_path: Path) -> "Package|None":
|
def installed_package(self, hass_config_path: Path) -> "Package|None":
|
||||||
for custom_component in (hass_config_path / "custom_components").glob("*"):
|
"""Returns the installed package if it exists, otherwise None."""
|
||||||
unhacs = custom_component / "unhacs.yaml"
|
for package in get_installed_packages(hass_config_path, [self.package_type]):
|
||||||
if unhacs.exists():
|
if package.url == self.url:
|
||||||
installed_package = Package.from_yaml(yaml.safe_load(unhacs.open()))
|
return package
|
||||||
installed_package.path = custom_component
|
|
||||||
if (
|
|
||||||
installed_package.name == self.name
|
|
||||||
and installed_package.url == self.url
|
|
||||||
):
|
|
||||||
return installed_package
|
|
||||||
|
|
||||||
for js_unhacs in (hass_config_path / "www" / "js").glob("*-unhacs.yaml"):
|
|
||||||
installed_package = Package.from_yaml(yaml.safe_load(js_unhacs.open()))
|
|
||||||
installed_package.path = js_unhacs.with_name(
|
|
||||||
js_unhacs.name.removesuffix("-unhacs.yaml")
|
|
||||||
)
|
|
||||||
if (
|
|
||||||
installed_package.name == self.name
|
|
||||||
and installed_package.url == self.url
|
|
||||||
):
|
|
||||||
return installed_package
|
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def is_update(self, hass_config_path: Path) -> bool:
|
def is_update(self, hass_config_path: Path) -> bool:
|
||||||
|
"""Returns True if the package is not installed or the installed version is different from the latest."""
|
||||||
installed_package = self.installed_package(hass_config_path)
|
installed_package = self.installed_package(hass_config_path)
|
||||||
return installed_package is None or installed_package.version != self.version
|
return installed_package is None or installed_package.version != self.version
|
||||||
|
|
||||||
def get_latest(self) -> "Package":
|
def get_latest(self) -> "Package":
|
||||||
|
"""Returns a new Package representing the latest version of this package."""
|
||||||
package = self.to_yaml()
|
package = self.to_yaml()
|
||||||
package.pop("version")
|
package.pop("version")
|
||||||
return Package(**package)
|
return Package(**package)
|
||||||
@ -287,24 +265,28 @@ class Package:
|
|||||||
|
|
||||||
def get_installed_packages(
|
def get_installed_packages(
|
||||||
hass_config_path: Path = DEFAULT_HASS_CONFIG_PATH,
|
hass_config_path: Path = DEFAULT_HASS_CONFIG_PATH,
|
||||||
) -> list[Package]:
|
package_types: Iterable[PackageType] = (
|
||||||
packages = []
|
PackageType.INTEGRATION,
|
||||||
|
PackageType.PLUGIN,
|
||||||
|
),
|
||||||
|
) -> Generator[Package, None, None]:
|
||||||
# Integration packages
|
# Integration packages
|
||||||
|
if PackageType.INTEGRATION in package_types:
|
||||||
for custom_component in (hass_config_path / "custom_components").glob("*"):
|
for custom_component in (hass_config_path / "custom_components").glob("*"):
|
||||||
unhacs = custom_component / "unhacs.yaml"
|
unhacs = custom_component / "unhacs.yaml"
|
||||||
if unhacs.exists():
|
if unhacs.exists():
|
||||||
package = Package.from_yaml(yaml.safe_load(unhacs.open()))
|
package = Package.from_yaml(yaml.safe_load(unhacs.open()))
|
||||||
package.path = custom_component
|
package.path = custom_component
|
||||||
packages.append(package)
|
yield package
|
||||||
|
|
||||||
# Plugin packages
|
# Plugin packages
|
||||||
|
if PackageType.PLUGIN in package_types:
|
||||||
for js_unhacs in (hass_config_path / "www" / "js").glob("*-unhacs.yaml"):
|
for js_unhacs in (hass_config_path / "www" / "js").glob("*-unhacs.yaml"):
|
||||||
package = Package.from_yaml(yaml.safe_load(js_unhacs.open()))
|
package = Package.from_yaml(yaml.safe_load(js_unhacs.open()))
|
||||||
package.path = js_unhacs.with_name(js_unhacs.name.removesuffix("-unhacs.yaml"))
|
package.path = js_unhacs.with_name(
|
||||||
packages.append(package)
|
js_unhacs.name.removesuffix("-unhacs.yaml")
|
||||||
|
)
|
||||||
return packages
|
yield package
|
||||||
|
|
||||||
|
|
||||||
# Read a list of Packages from a text file in the plain text format "URL version name"
|
# Read a list of Packages from a text file in the plain text format "URL version name"
|
||||||
|
Loading…
Reference in New Issue
Block a user