Coverage for gsb/rewind.py: 100%
20 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-08 20:16 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-08 20:16 +0000
1"""Functionality for restoring to an old backup"""
3import logging
4from pathlib import Path
6from . import _git, backup
7from .logging import IMPORTANT
9LOGGER = logging.getLogger(__name__)
12def generate_restore_tag_name(revision: str) -> str:
13 """Generate a new calver-ish tag name
15 Parameters
16 ----------
17 revision : str
18 The commit hash or tag name of the backup to restore
20 Returns
21 -------
22 str
23 A tag name that indicates both the time a backup was restored and the
24 identifier of the original revision
25 """
26 return f"{backup.generate_tag_name()}.restore_of_{revision}"
29def restore_backup(repo_root: Path, revision: str, keep_gsb_files: bool = True) -> str:
30 """Rewind to a previous backup state and create a new backup
32 Parameters
33 ----------
34 repo_root : Path
35 The directory containing the GSB-managed repo
36 revision : str
37 The commit hash or tag name of the backup to restore
38 keep_gsb_files : bool, optional
39 By default, `.gsb_manifest` and `.gitignore` *will not* be restored
40 (that is, the latest versions will be kept). To override this behavior,
41 pass in `keep_gsb_files = False`.
43 Returns
44 -------
45 str
46 The tag name of the new restored backup
48 Notes
49 -----
50 Before creating the backup, any un-backed up changes will first be backed up
52 Raises
53 ------
54 OSError
55 If the specified repo does not exist or is not a GSB-managed repo
56 ValueError
57 If the specified revision does not exist
58 """
59 _git.show(repo_root, revision)
61 LOGGER.log(
62 IMPORTANT, "Backing up any unsaved changes before rewinding to %s", revision
63 )
64 try:
65 orig_head = backup.create_backup(
66 repo_root, f"Backing up state before rewinding to {revision}"
67 )
68 except ValueError as already_backed_up:
69 LOGGER.warning("Nothing to back up: %s", already_backed_up)
70 orig_head = _git.show(repo_root, "HEAD").hash # type: ignore[union-attr]
72 _git.reset(repo_root, revision, hard=True)
73 _git.reset(repo_root, orig_head, hard=False)
74 if keep_gsb_files:
75 _git.checkout_files(repo_root, orig_head, backup.REQUIRED_FILES)
76 return backup.create_backup(
77 repo_root,
78 f"Restored to {revision}",
79 tag_name=generate_restore_tag_name(revision),
80 )