Skip to content

Commit

Permalink
Merge branch 'dev' into zwave_custom_param
Browse files Browse the repository at this point in the history
  • Loading branch information
MindFreeze authored Nov 7, 2024
2 parents 5fa8b94 + cb97f2f commit a4e61f3
Show file tree
Hide file tree
Showing 925 changed files with 27,223 additions and 8,102 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ jobs:

- name: Generate artifact attestation
if: needs.init.outputs.channel != 'dev' && needs.init.outputs.publish == 'true'
uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3
uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # v1.4.4
with:
subject-name: ${{ env.HASSFEST_IMAGE_NAME }}
subject-digest: ${{ steps.push.outputs.digest }}
Expand Down
20 changes: 13 additions & 7 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ env:
CACHE_VERSION: 11
UV_CACHE_VERSION: 1
MYPY_CACHE_VERSION: 9
HA_SHORT_VERSION: "2024.11"
HA_SHORT_VERSION: "2024.12"
DEFAULT_PYTHON: "3.12"
ALL_PYTHON_VERSIONS: "['3.12']"
# 10.3 is the oldest supported version
Expand Down Expand Up @@ -622,13 +622,13 @@ jobs:
steps:
- name: Check out code from GitHub
uses: actions/[email protected]
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/[email protected]
with:
python-version: ${{ env.DEFAULT_PYTHON }}
python-version: ${{ matrix.python-version }}
check-latest: true
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment
- name: Restore full Python ${{ matrix.python-version }} virtual environment
id: cache-venv
uses: actions/cache/[email protected]
with:
Expand Down Expand Up @@ -823,7 +823,7 @@ jobs:
fail-fast: false
matrix:
python-version: ${{ fromJson(needs.info.outputs.python_versions) }}
name: Split tests for full run Python ${{ matrix.python-version }}
name: Split tests for full run
steps:
- name: Install additional OS dependencies
run: |
Expand Down Expand Up @@ -949,6 +949,7 @@ jobs:
--timeout=9 \
--durations=10 \
--numprocesses auto \
--snapshot-details \
--dist=loadfile \
${cov_params[@]} \
-o console_output_style=count \
Expand Down Expand Up @@ -1071,6 +1072,7 @@ jobs:
-qq \
--timeout=20 \
--numprocesses 1 \
--snapshot-details \
${cov_params[@]} \
-o console_output_style=count \
--durations=10 \
Expand Down Expand Up @@ -1102,7 +1104,7 @@ jobs:
./script/check_dirty
pytest-postgres:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
services:
postgres:
image: ${{ matrix.postgresql-group }}
Expand Down Expand Up @@ -1142,7 +1144,9 @@ jobs:
sudo apt-get -y install \
bluez \
ffmpeg \
libturbojpeg \
libturbojpeg
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y
sudo apt-get -y install \
postgresql-server-dev-14
- name: Check out code from GitHub
uses: actions/[email protected]
Expand Down Expand Up @@ -1197,6 +1201,7 @@ jobs:
-qq \
--timeout=9 \
--numprocesses 1 \
--snapshot-details \
${cov_params[@]} \
-o console_output_style=count \
--durations=0 \
Expand Down Expand Up @@ -1343,6 +1348,7 @@ jobs:
-qq \
--timeout=9 \
--numprocesses auto \
--snapshot-details \
${cov_params[@]} \
-o console_output_style=count \
--durations=0 \
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.7.1
rev: v0.7.2
hooks:
- id: ruff
args:
Expand Down
2 changes: 2 additions & 0 deletions .strict-typing
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ homeassistant.components.geo_location.*
homeassistant.components.geocaching.*
homeassistant.components.gios.*
homeassistant.components.glances.*
homeassistant.components.go2rtc.*
homeassistant.components.goalzero.*
homeassistant.components.google.*
homeassistant.components.google_assistant_sdk.*
Expand Down Expand Up @@ -323,6 +324,7 @@ homeassistant.components.moon.*
homeassistant.components.mopeka.*
homeassistant.components.motionmount.*
homeassistant.components.mqtt.*
homeassistant.components.music_assistant.*
homeassistant.components.my.*
homeassistant.components.mysensors.*
homeassistant.components.myuplink.*
Expand Down
6 changes: 4 additions & 2 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -496,8 +496,8 @@ build.json @home-assistant/supervisor
/tests/components/freebox/ @hacf-fr @Quentame
/homeassistant/components/freedompro/ @stefano055415
/tests/components/freedompro/ @stefano055415
/homeassistant/components/fritz/ @mammuth @AaronDavidSchneider @chemelli74 @mib1185
/tests/components/fritz/ @mammuth @AaronDavidSchneider @chemelli74 @mib1185
/homeassistant/components/fritz/ @AaronDavidSchneider @chemelli74 @mib1185
/tests/components/fritz/ @AaronDavidSchneider @chemelli74 @mib1185
/homeassistant/components/fritzbox/ @mib1185 @flabbamann
/tests/components/fritzbox/ @mib1185 @flabbamann
/homeassistant/components/fritzbox_callmonitor/ @cdce8p
Expand Down Expand Up @@ -954,6 +954,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/msteams/ @peroyvind
/homeassistant/components/mullvad/ @meichthys
/tests/components/mullvad/ @meichthys
/homeassistant/components/music_assistant/ @music-assistant
/tests/components/music_assistant/ @music-assistant
/homeassistant/components/mutesync/ @currentoor
/tests/components/mutesync/ @currentoor
/homeassistant/components/my/ @home-assistant/core
Expand Down
7 changes: 4 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ FROM ${BUILD_FROM}
# Synchronize with homeassistant/core.py:async_stop
ENV \
S6_SERVICES_GRACETIME=240000 \
UV_SYSTEM_PYTHON=true
UV_SYSTEM_PYTHON=true \
UV_NO_CACHE=true

ARG QEMU_CPU

# Install uv
RUN pip3 install uv==0.4.22
RUN pip3 install uv==0.4.28

WORKDIR /usr/src

Expand Down Expand Up @@ -54,7 +55,7 @@ RUN \
"armv7") go2rtc_suffix='arm' ;; \
*) go2rtc_suffix=${BUILD_ARCH} ;; \
esac \
&& curl -L https://github.com/AlexxIT/go2rtc/releases/download/v1.9.4/go2rtc_linux_${go2rtc_suffix} --output /bin/go2rtc \
&& curl -L https://github.com/AlexxIT/go2rtc/releases/download/v1.9.6/go2rtc_linux_${go2rtc_suffix} --output /bin/go2rtc \
&& chmod +x /bin/go2rtc \
# Verify go2rtc can be executed
&& go2rtc --version
Expand Down
4 changes: 4 additions & 0 deletions homeassistant/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import sys
import threading

from .backup_restore import restore_backup
from .const import REQUIRED_PYTHON_VER, RESTART_EXIT_CODE, __version__

FAULT_LOG_FILENAME = "home-assistant.log.fault"
Expand Down Expand Up @@ -182,6 +183,9 @@ def main() -> int:
return scripts.run(args.script)

config_dir = os.path.abspath(os.path.join(os.getcwd(), args.config))
if restore_backup(config_dir):
return RESTART_EXIT_CODE

ensure_config_path(config_dir)

# pylint: disable-next=import-outside-toplevel
Expand Down
126 changes: 126 additions & 0 deletions homeassistant/backup_restore.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
"""Home Assistant module to handle restoring backups."""

from dataclasses import dataclass
import json
import logging
from pathlib import Path
import shutil
import sys
from tempfile import TemporaryDirectory

from awesomeversion import AwesomeVersion
import securetar

from .const import __version__ as HA_VERSION

RESTORE_BACKUP_FILE = ".HA_RESTORE"
KEEP_PATHS = ("backups",)

_LOGGER = logging.getLogger(__name__)


@dataclass
class RestoreBackupFileContent:
"""Definition for restore backup file content."""

backup_file_path: Path


def restore_backup_file_content(config_dir: Path) -> RestoreBackupFileContent | None:
"""Return the contents of the restore backup file."""
instruction_path = config_dir.joinpath(RESTORE_BACKUP_FILE)
try:
instruction_content = json.loads(instruction_path.read_text(encoding="utf-8"))
return RestoreBackupFileContent(
backup_file_path=Path(instruction_content["path"])
)
except (FileNotFoundError, json.JSONDecodeError):
return None


def _clear_configuration_directory(config_dir: Path) -> None:
"""Delete all files and directories in the config directory except for the backups directory."""
keep_paths = [config_dir.joinpath(path) for path in KEEP_PATHS]
config_contents = sorted(
[entry for entry in config_dir.iterdir() if entry not in keep_paths]
)

for entry in config_contents:
entrypath = config_dir.joinpath(entry)

if entrypath.is_file():
entrypath.unlink()
elif entrypath.is_dir():
shutil.rmtree(entrypath)


def _extract_backup(config_dir: Path, backup_file_path: Path) -> None:
"""Extract the backup file to the config directory."""
with (
TemporaryDirectory() as tempdir,
securetar.SecureTarFile(
backup_file_path,
gzip=False,
mode="r",
) as ostf,
):
ostf.extractall(
path=Path(tempdir, "extracted"),
members=securetar.secure_path(ostf),
filter="fully_trusted",
)
backup_meta_file = Path(tempdir, "extracted", "backup.json")
backup_meta = json.loads(backup_meta_file.read_text(encoding="utf8"))

if (
backup_meta_version := AwesomeVersion(
backup_meta["homeassistant"]["version"]
)
) > HA_VERSION:
raise ValueError(
f"You need at least Home Assistant version {backup_meta_version} to restore this backup"
)

with securetar.SecureTarFile(
Path(
tempdir,
"extracted",
f"homeassistant.tar{'.gz' if backup_meta["compressed"] else ''}",
),
gzip=backup_meta["compressed"],
mode="r",
) as istf:
for member in istf.getmembers():
if member.name == "data":
continue
member.name = member.name.replace("data/", "")
_clear_configuration_directory(config_dir)
istf.extractall(
path=config_dir,
members=[
member
for member in securetar.secure_path(istf)
if member.name != "data"
],
filter="fully_trusted",
)


def restore_backup(config_dir_path: str) -> bool:
"""Restore the backup file if any.
Returns True if a restore backup file was found and restored, False otherwise.
"""
config_dir = Path(config_dir_path)
if not (restore_content := restore_backup_file_content(config_dir)):
return False

logging.basicConfig(stream=sys.stdout, level=logging.INFO)
backup_file_path = restore_content.backup_file_path
_LOGGER.info("Restoring %s", backup_file_path)
try:
_extract_backup(config_dir, backup_file_path)
except FileNotFoundError as err:
raise ValueError(f"Backup file {backup_file_path} does not exist") from err
_LOGGER.info("Restore complete, restarting")
return True
2 changes: 1 addition & 1 deletion homeassistant/components/adguard/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from adguardhome import AdGuardHome, AdGuardHomeConnectionError
import voluptuous as vol

from homeassistant.components.hassio import HassioServiceInfo
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import (
CONF_HOST,
Expand All @@ -18,6 +17,7 @@
CONF_VERIFY_SSL,
)
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.service_info.hassio import HassioServiceInfo

from .const import DOMAIN

Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/advantage_air/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ async def async_get():
coordinator = DataUpdateCoordinator(
hass,
_LOGGER,
config_entry=entry,
name="Advantage Air",
update_method=async_get,
update_interval=timedelta(seconds=ADVANTAGE_AIR_SYNC_INTERVAL),
Expand Down
15 changes: 2 additions & 13 deletions homeassistant/components/aemet/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""The AEMET OpenData component."""

from dataclasses import dataclass
import logging

from aemet_opendata.exceptions import AemetError, TownNotFound
Expand All @@ -13,20 +12,10 @@
from homeassistant.helpers import aiohttp_client

from .const import CONF_STATION_UPDATES, PLATFORMS
from .coordinator import WeatherUpdateCoordinator
from .coordinator import AemetConfigEntry, AemetData, WeatherUpdateCoordinator

_LOGGER = logging.getLogger(__name__)

type AemetConfigEntry = ConfigEntry[AemetData]


@dataclass
class AemetData:
"""Aemet runtime data."""

name: str
coordinator: WeatherUpdateCoordinator


async def async_setup_entry(hass: HomeAssistant, entry: AemetConfigEntry) -> bool:
"""Set up AEMET OpenData as config entry."""
Expand All @@ -46,7 +35,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AemetConfigEntry) -> boo
except AemetError as err:
raise ConfigEntryNotReady(err) from err

weather_coordinator = WeatherUpdateCoordinator(hass, aemet)
weather_coordinator = WeatherUpdateCoordinator(hass, entry, aemet)
await weather_coordinator.async_config_entry_first_refresh()

entry.runtime_data = AemetData(name=name, coordinator=weather_coordinator)
Expand Down
Loading

0 comments on commit a4e61f3

Please sign in to comment.