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