1 """Home Assistant module to handle restoring backups."""
3 from dataclasses
import dataclass
6 from pathlib
import Path
9 from tempfile
import TemporaryDirectory
11 from awesomeversion
import AwesomeVersion
14 from .const
import __version__
as HA_VERSION
16 RESTORE_BACKUP_FILE =
".HA_RESTORE"
17 KEEP_PATHS = (
"backups",)
19 _LOGGER = logging.getLogger(__name__)
24 """Definition for restore backup file content."""
26 backup_file_path: Path
30 """Return the contents of the restore backup file."""
31 instruction_path = config_dir.joinpath(RESTORE_BACKUP_FILE)
33 instruction_content = json.loads(instruction_path.read_text(encoding=
"utf-8"))
35 backup_file_path=Path(instruction_content[
"path"])
37 except (FileNotFoundError, json.JSONDecodeError):
42 """Delete all files and directories in the config directory except for the backups directory."""
43 keep_paths = [config_dir.joinpath(path)
for path
in KEEP_PATHS]
44 config_contents = sorted(
45 [entry
for entry
in config_dir.iterdir()
if entry
not in keep_paths]
48 for entry
in config_contents:
49 entrypath = config_dir.joinpath(entry)
51 if entrypath.is_file():
53 elif entrypath.is_dir():
54 shutil.rmtree(entrypath)
58 """Extract the backup file to the config directory."""
60 TemporaryDirectory()
as tempdir,
61 securetar.SecureTarFile(
68 path=Path(tempdir,
"extracted"),
69 members=securetar.secure_path(ostf),
70 filter=
"fully_trusted",
72 backup_meta_file = Path(tempdir,
"extracted",
"backup.json")
73 backup_meta = json.loads(backup_meta_file.read_text(encoding=
"utf8"))
76 backup_meta_version := AwesomeVersion(
77 backup_meta[
"homeassistant"][
"version"]
81 f
"You need at least Home Assistant version {backup_meta_version} to restore this backup"
84 with securetar.SecureTarFile(
88 f
"homeassistant.tar{'.gz' if backup_meta["compressed
"] else ''}",
90 gzip=backup_meta[
"compressed"],
93 for member
in istf.getmembers():
94 if member.name ==
"data":
96 member.name = member.name.replace(
"data/",
"")
102 for member
in securetar.secure_path(istf)
103 if member.name !=
"data"
105 filter=
"fully_trusted",
110 """Restore the backup file if any.
112 Returns True if a restore backup file was found and restored, False otherwise.
114 config_dir = Path(config_dir_path)
118 logging.basicConfig(stream=sys.stdout, level=logging.INFO)
119 backup_file_path = restore_content.backup_file_path
120 _LOGGER.info(
"Restoring %s", backup_file_path)
123 except FileNotFoundError
as err:
124 raise ValueError(f
"Backup file {backup_file_path} does not exist")
from err
125 _LOGGER.info(
"Restore complete, restarting")
None _clear_configuration_directory(Path config_dir)
None _extract_backup(Path config_dir, Path backup_file_path)
RestoreBackupFileContent|None restore_backup_file_content(Path config_dir)
bool restore_backup(str config_dir_path)