-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'dev' into zwave_custom_param
- Loading branch information
Showing
925 changed files
with
27,223 additions
and
8,102 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
@@ -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: | ||
|
@@ -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: | | ||
|
@@ -949,6 +949,7 @@ jobs: | |
--timeout=9 \ | ||
--durations=10 \ | ||
--numprocesses auto \ | ||
--snapshot-details \ | ||
--dist=loadfile \ | ||
${cov_params[@]} \ | ||
-o console_output_style=count \ | ||
|
@@ -1071,6 +1072,7 @@ jobs: | |
-qq \ | ||
--timeout=20 \ | ||
--numprocesses 1 \ | ||
--snapshot-details \ | ||
${cov_params[@]} \ | ||
-o console_output_style=count \ | ||
--durations=10 \ | ||
|
@@ -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 }} | ||
|
@@ -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] | ||
|
@@ -1197,6 +1201,7 @@ jobs: | |
-qq \ | ||
--timeout=9 \ | ||
--numprocesses 1 \ | ||
--snapshot-details \ | ||
${cov_params[@]} \ | ||
-o console_output_style=count \ | ||
--durations=0 \ | ||
|
@@ -1343,6 +1348,7 @@ jobs: | |
-qq \ | ||
--timeout=9 \ | ||
--numprocesses auto \ | ||
--snapshot-details \ | ||
${cov_params[@]} \ | ||
-o console_output_style=count \ | ||
--durations=0 \ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.