Skip to content

Commit b4065b5

Browse files
authored
Added compression option for backup command (#35)
This commit introduces a new feature to the backup command in the CLI tool, allowing users to compress their backups for more efficient storage management. The --compress flag can be used to enable this option, which compresses the backup directory into a tar.gz file and places it in the specified output directory. Signed-off-by: Anton Kremenetsky <anton.kremenetsky@gmail.com>
1 parent 586a5b3 commit b4065b5

File tree

3 files changed

+59
-3
lines changed

3 files changed

+59
-3
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,3 +295,11 @@ genesis backup -oneshot
295295
```
296296

297297
This command will backup the current installation to the specified directory once and exit.
298+
299+
### Compuressed Backup
300+
301+
Run backup of all libvirt domains and store a compressed archive of the backup in the current directory:
302+
303+
```bash
304+
genesis backup --compress
305+
```

genesis_devtools/cmd/cli.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -399,17 +399,27 @@ def get_project_version_cmd(element_dir: str) -> None:
399399
is_flag=True,
400400
help="Do a backup once and exit",
401401
)
402+
@click.option(
403+
"-c",
404+
"--compress",
405+
default=False,
406+
type=bool,
407+
show_default=True,
408+
is_flag=True,
409+
help="Compress the backup.",
410+
)
402411
def bakcup_cmd(
403412
name: tp.List[str] | None,
404413
backup_dir: str,
405414
period: c.BackupPeriod,
406415
oneshot: bool,
416+
compress: bool,
407417
) -> None:
408418
# Do a single backup and exit
409419
if oneshot:
410420
domains = _domains_for_backup(name, raise_on_domain_absence=True)
411421
backup_path = utils.backup_path(backup_dir)
412-
_do_backup(backup_path, domains)
422+
_do_backup(backup_path, domains, compress)
413423
click.secho("Backup done", fg="green")
414424
return
415425

@@ -428,7 +438,7 @@ def bakcup_cmd(
428438

429439
click.secho(f"Backup started at {time.strftime('%Y-%m-%d %H:%M:%S')}")
430440
backup_path = utils.backup_path(backup_dir)
431-
_do_backup(backup_path, domains)
441+
_do_backup(backup_path, domains, compress)
432442

433443
click.secho(
434444
f"Next backup at: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(next_ts))}"
@@ -441,7 +451,9 @@ def bakcup_cmd(
441451
time.sleep(timeout)
442452

443453

444-
def _do_backup(backup_path: str, domains: tp.List[str]) -> None:
454+
def _do_backup(
455+
backup_path: str, domains: tp.List[str], compress: bool = False
456+
) -> None:
445457
os.makedirs(backup_path, exist_ok=True)
446458

447459
table = prettytable.PrettyTable()
@@ -481,6 +493,20 @@ def _do_backup(backup_path: str, domains: tp.List[str]) -> None:
481493
click.echo(f"Summary: {backup_path}")
482494
click.echo(table)
483495

496+
if not compress:
497+
return
498+
499+
click.echo(f"Compressing {backup_path}")
500+
compress_directory = os.path.dirname(backup_path)
501+
try:
502+
utils.compress_dir(backup_path, compress_directory)
503+
except Exception:
504+
click.secho(f"Compression of {backup_path} failed", fg="red")
505+
return
506+
507+
click.secho(f"Compression of {backup_path} done", fg="green")
508+
shutil.rmtree(backup_path)
509+
484510

485511
def _domains_for_backup(
486512
names: tp.List[str] | None = None, raise_on_domain_absence: bool = False

genesis_devtools/utils.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import os
1919
import time
20+
import shutil
2021
import itertools
2122
import typing as tp
2223
from importlib.metadata import entry_points
@@ -212,3 +213,24 @@ def human_readable_size(size: int, decimal_places: int = 2):
212213
def backup_path(backup_dir: str) -> str:
213214
backup_relative_path = time.strftime("%Y-%m-%d-%H-%M-%S")
214215
return os.path.join(backup_dir, backup_relative_path)
216+
217+
218+
def compress_dir(
219+
directory: str, output_dir: str, compression_format: str = "gztar"
220+
) -> None:
221+
"""
222+
Compresses the specified directory and places the archive in the
223+
output directory.
224+
225+
:param directory: The path to the directory to be compressed.
226+
:param output_dir: The path to the directory where the compressed
227+
archive will be placed.
228+
"""
229+
# Ensure the output directory exists
230+
os.makedirs(output_dir, exist_ok=True)
231+
232+
# Define the base name for the archive (without extension)
233+
archive_base_name = os.path.join(output_dir, os.path.basename(directory))
234+
235+
# Create a zip archive of the directory
236+
shutil.make_archive(archive_base_name, compression_format, directory)

0 commit comments

Comments
 (0)