mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 01:37:08 +00:00
Create backups files without having to copy inner tarballs (#110267)
This commit is contained in:
parent
0e833c5fe3
commit
3a053afac6
@ -4,11 +4,12 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
from dataclasses import asdict, dataclass
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
from pathlib import Path
|
||||
import tarfile
|
||||
from tarfile import TarError
|
||||
from tempfile import TemporaryDirectory
|
||||
import time
|
||||
from typing import Any, Protocol, cast
|
||||
|
||||
from securetar import SecureTarFile, atomic_contents_add
|
||||
@ -17,7 +18,7 @@ from homeassistant.const import __version__ as HAVERSION
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import integration_platform
|
||||
from homeassistant.helpers.json import save_json
|
||||
from homeassistant.helpers.json import json_bytes
|
||||
from homeassistant.util import dt as dt_util
|
||||
from homeassistant.util.json import json_loads_object
|
||||
|
||||
@ -228,18 +229,18 @@ class BackupManager:
|
||||
LOGGER.debug("Creating backup directory")
|
||||
self.backup_dir.mkdir()
|
||||
|
||||
with TemporaryDirectory() as tmp_dir, SecureTarFile(
|
||||
outer_secure_tarfile = SecureTarFile(
|
||||
tar_file_path, "w", gzip=False, bufsize=BUF_SIZE
|
||||
) as tar_file:
|
||||
tmp_dir_path = Path(tmp_dir)
|
||||
save_json(
|
||||
tmp_dir_path.joinpath("./backup.json").as_posix(),
|
||||
backup_data,
|
||||
)
|
||||
with SecureTarFile(
|
||||
tmp_dir_path.joinpath("./homeassistant.tar.gz").as_posix(),
|
||||
"w",
|
||||
bufsize=BUF_SIZE,
|
||||
)
|
||||
with outer_secure_tarfile as outer_secure_tarfile_tarfile:
|
||||
raw_bytes = json_bytes(backup_data)
|
||||
fileobj = io.BytesIO(raw_bytes)
|
||||
tar_info = tarfile.TarInfo(name="./backup.json")
|
||||
tar_info.size = len(raw_bytes)
|
||||
tar_info.mtime = int(time.time())
|
||||
outer_secure_tarfile_tarfile.addfile(tar_info, fileobj=fileobj)
|
||||
with outer_secure_tarfile.create_inner_tar(
|
||||
"./homeassistant.tar.gz", gzip=True
|
||||
) as core_tar:
|
||||
atomic_contents_add(
|
||||
tar_file=core_tar,
|
||||
@ -247,7 +248,7 @@ class BackupManager:
|
||||
excludes=EXCLUDE_FROM_BACKUP,
|
||||
arcname="data",
|
||||
)
|
||||
tar_file.add(tmp_dir_path, arcname=".")
|
||||
|
||||
return tar_file_path.stat().st_size
|
||||
|
||||
|
||||
|
@ -29,11 +29,11 @@ async def _mock_backup_generation(manager: BackupManager):
|
||||
Path(".storage"),
|
||||
]
|
||||
|
||||
with patch("tarfile.open", MagicMock()) as mocked_tarfile, patch(
|
||||
"pathlib.Path.iterdir", _mock_iterdir
|
||||
), patch("pathlib.Path.stat", MagicMock(st_size=123)), patch(
|
||||
"pathlib.Path.is_file", lambda x: x.name != ".storage"
|
||||
), patch(
|
||||
with patch(
|
||||
"homeassistant.components.backup.manager.SecureTarFile"
|
||||
) as mocked_tarfile, patch("pathlib.Path.iterdir", _mock_iterdir), patch(
|
||||
"pathlib.Path.stat", MagicMock(st_size=123)
|
||||
), patch("pathlib.Path.is_file", lambda x: x.name != ".storage"), patch(
|
||||
"pathlib.Path.is_dir",
|
||||
lambda x: x.name == ".storage",
|
||||
), patch(
|
||||
@ -46,21 +46,20 @@ async def _mock_backup_generation(manager: BackupManager):
|
||||
"pathlib.Path.mkdir",
|
||||
MagicMock(),
|
||||
), patch(
|
||||
"homeassistant.components.backup.manager.save_json"
|
||||
) as mocked_save_json, patch(
|
||||
"homeassistant.components.backup.manager.json_bytes",
|
||||
return_value=b"{}", # Empty JSON
|
||||
) as mocked_json_bytes, patch(
|
||||
"homeassistant.components.backup.manager.HAVERSION",
|
||||
"2025.1.0",
|
||||
):
|
||||
await manager.generate_backup()
|
||||
|
||||
assert mocked_save_json.call_count == 1
|
||||
assert mocked_save_json.call_args[0][1]["homeassistant"] == {
|
||||
"version": "2025.1.0"
|
||||
}
|
||||
|
||||
assert (
|
||||
manager.backup_dir.as_posix()
|
||||
in mocked_tarfile.call_args_list[0].kwargs["name"]
|
||||
assert mocked_json_bytes.call_count == 1
|
||||
backup_json_dict = mocked_json_bytes.call_args[0][0]
|
||||
assert isinstance(backup_json_dict, dict)
|
||||
assert backup_json_dict["homeassistant"] == {"version": "2025.1.0"}
|
||||
assert manager.backup_dir.as_posix() in str(
|
||||
mocked_tarfile.call_args_list[0][0][0]
|
||||
)
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user