Skip to content

Commit d71e26e

Browse files
authored
Refactor (#33)
A simple start for a refactor. This is not a whole refactor because most problems that I see with the current code a in places that would be changed by already open issues. These places should be cleaned up in the corresponding PRs for the issues.
1 parent 68bd01d commit d71e26e

File tree

17 files changed

+755
-694
lines changed

17 files changed

+755
-694
lines changed

.pylintrc

Lines changed: 0 additions & 566 deletions
This file was deleted.

pylintrc.toml

Lines changed: 617 additions & 0 deletions
Large diffs are not rendered by default.

src/rsnapshot_docker_compose_backup/backup_planer.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@
1010
from dataclasses import dataclass
1111
import os
1212
from pathlib import Path
13-
from typing import List
1413

15-
from rsnapshot_docker_compose_backup.container import Container
14+
from rsnapshot_docker_compose_backup.structure.container import Container
1615

1716
# Other imports
1817
from rsnapshot_docker_compose_backup.global_values import set_folder, set_config_file
19-
from rsnapshot_docker_compose_backup import docker_compose
18+
from rsnapshot_docker_compose_backup.docker import docker_compose
2019

2120

2221
@dataclass
@@ -48,7 +47,7 @@ def parse_arguments() -> ProgramArgs:
4847
def run(args: ProgramArgs) -> str:
4948
set_folder(args.folder)
5049
set_config_file(args.config)
51-
docker_container: List[Container] = docker_compose.find_container(args.folder)
50+
docker_container: list[Container] = docker_compose.find_container(args.folder)
5251
result: list[str] = []
5352
for container in docker_container:
5453
container_result = container.backup()

src/rsnapshot_docker_compose_backup/config/__init__.py

Whitespace-only changes.

src/rsnapshot_docker_compose_backup/abstract_config.py renamed to src/rsnapshot_docker_compose_backup/config/abstract_config.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
from pathlib import Path
44
import re
55
from abc import ABC, abstractmethod
6-
from typing import Any, Callable, Dict, List
6+
from typing import Any, Callable, Union
77

88
from rsnapshot_docker_compose_backup.utils import CaseInsensitiveRe
9-
from rsnapshot_docker_compose_backup.volume import Volume
9+
from rsnapshot_docker_compose_backup.structure.volume import Volume
1010

1111

1212
class AbstractConfig(ABC):
@@ -24,9 +24,9 @@ class AbstractConfig(ABC):
2424
]
2525

2626
def __init__(self, config_path: Path, name: str):
27-
self.enabled_actions: Dict[str, bool] = {}
28-
self.backup_steps: Dict[str, str] = {}
29-
self.vars: Dict[str, str | List[Volume]] = {}
27+
self.enabled_actions: dict[str, bool] = {}
28+
self.backup_steps: dict[str, str] = {}
29+
self.vars: dict[str, Union[str, list[Volume]]] = {}
3030
for step in self.backupOrder:
3131
self.backup_steps[step] = ""
3232
self._load_config_file(config_path, name)
@@ -55,15 +55,17 @@ def _load_config_file(self, config_path: Path, section_name: str) -> None:
5555
if config_file.has_section(actions_section):
5656
for action in config_file.options(actions_section):
5757
val = config_file.get(actions_section, action, fallback=None)
58-
use = val is None or val.lower() in ["true"]
58+
use = val is None or val.lower() in {"true"}
5959
self.enabled_actions[action] = use
6060
vars_section = self.vars_name(section_name)
6161
if config_file.has_section(vars_section):
6262
for var in config_file.options(vars_section):
6363
val = config_file.get(vars_section, var)
6464
self.vars["${}".format(var)] = val
6565

66-
def _resolve_vars(self, cmd: str, variables: Dict[str, str | list[Volume]]) -> str:
66+
def _resolve_vars(
67+
self, cmd: str, variables: dict[str, Union[str, list[Volume]]]
68+
) -> str:
6769
for var in variables.keys():
6870
if var.lower() in cmd.lower():
6971
replace_function = _replace_var.get(type(variables[var]))
@@ -104,7 +106,7 @@ def ireplace(old: str, new: str, text: str) -> str:
104106
return text
105107

106108

107-
def _replace_list(cmd: str, var: str, val: list[list[Any] | str | Volume]) -> str:
109+
def _replace_list(cmd: str, var: str, val: list[Union[list[Any], str, Volume]]) -> str:
108110
result: str = ""
109111
for i in val:
110112
result += str(_replace_var[type(i)](cmd, var, i)) + "\n"
@@ -122,7 +124,7 @@ def _replace_volume(cmd: str, var: str, val: Volume) -> str:
122124
return tmp
123125

124126

125-
_replace_var: Dict[type, Callable[..., str]] = {
127+
_replace_var: dict[type, Callable[..., str]] = {
126128
list: _replace_list,
127129
str: _replace_str,
128130
Volume: _replace_volume,
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#This is the default config of the rsnapshot-docker-compose-backup program.
2+
3+
#This section can contain rsnapshot commands that are executed in the different steps of the container backup
4+
[{default_config}]
5+
#Example:
6+
#run_backup=backup_script echo "Hello" > helloWorld test/
7+
8+
#This section contains settings that can be set. This section can only be used in the default config.
9+
[{default_config_settings}]
10+
#This outputs the Start and End Times for each backup command to the log.
11+
#Rsnapshot doesn't log timestamps
12+
logTime = true
13+
14+
[{default_config_vars}]
15+
#This setting corresponds to the var with the same name and can be used as a prefix in the folder path
16+
backupprefixfolder = .
17+
18+
#This Section controls which actions should be enabled
19+
[{default_config_actions}]
20+
#This action stops the container before copying the volumes and starts it after it finished.
21+
stopcontainer = true
22+
23+
#This action backups all volumes of the container
24+
volumebackup = true
25+
26+
#This action saves the docker-compose.yml
27+
yamlbackup = true
28+
imagebackup = true
29+
30+
#The following actions are disabled by default
31+
logbackup = false
32+
projectDirBackup = false
33+
34+
#The following is the definition of actions that can be used in the backup
35+
36+
[{actions}.volumeBackup]
37+
backup = backup\t$volumes.path\t$backupPrefixFolder/$serviceName/$volumes.name
38+
39+
[{actions}.yamlBackup]
40+
runtime_backup = backup\t$projectFolder\t$backupPrefixFolder/$serviceName/yaml\t+rsync_long_args=--include=*.yml,+rsync_long_args=--include=*.yaml
41+
42+
[{actions}.projectDirBackup]
43+
backup = backup\t$projectFolder\t$backupPrefixFolder/$serviceName/projectDir
44+
45+
[{actions}.imageBackup]
46+
runtime_backup = backup_script\t/usr/bin/docker image save $image -o $serviceName_image.tar\t$backupPrefixFolder/$serviceName/image
47+
48+
[{actions}.logBackup]
49+
backup = backup_script\t/usr/bin/docker logs $containerID > $serviceName_logs.log 2>&1\t$backupPrefixFolder/$serviceName/log
50+
51+
[{actions}.stopContainer]
52+
stop = backup_exec\tcd $projectFolder; /usr/bin/docker-compose stop
53+
restart = backup_exec\tcd $projectFolder; /usr/bin/docker-compose start
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import configparser
2+
from importlib import resources
23
import os
34
from pathlib import Path
45
import re
5-
from typing import Dict, Optional
6+
import sys
7+
from typing import Optional
68

79
from rsnapshot_docker_compose_backup import global_values
8-
from rsnapshot_docker_compose_backup.abstract_config import AbstractConfig
10+
from rsnapshot_docker_compose_backup.config.abstract_config import AbstractConfig
911
from rsnapshot_docker_compose_backup.utils import CaseInsensitiveRe
1012

1113

@@ -22,7 +24,7 @@ class DefaultConfig(AbstractConfig):
2224
"onlyRunning": True,
2325
}
2426

25-
actions: Dict[str, Dict[str, str]] = {}
27+
actions: dict[str, dict[str, str]] = {}
2628

2729
@staticmethod
2830
def get_instance() -> "DefaultConfig":
@@ -51,8 +53,19 @@ def __init__(self) -> None:
5153
self._load_settings()
5254

5355
def _create_default_config(self) -> None:
54-
with open(self.filename, "w", encoding="UTF-8") as config_file:
55-
config_file.write(defaultConfigContent)
56+
with resources.open_text(
57+
"rsnapshot_docker_compose_backup.config", "backup.ini"
58+
) as default_backup_ini:
59+
default_config = default_backup_ini.read().format(
60+
default_config=self.defaultConfig,
61+
default_config_actions=self.actions_name(self.defaultConfig),
62+
default_config_vars=self.vars_name(self.defaultConfig),
63+
actions=self.actionSection,
64+
default_config_settings=self.settingsSection,
65+
)
66+
67+
with open(self.filename, "w", encoding="UTF-8") as config_file:
68+
config_file.write(default_config)
5669

5770
def get_step(self, step: str) -> str:
5871
return self.backup_steps.get(step, "")
@@ -68,7 +81,7 @@ def _load_actions(self) -> None:
6881
action_name = section[len(self.actionSection + ".") :]
6982
commands = {}
7083
for step in self.backup_steps:
71-
if config_file.has_option(section, step):
84+
if config_file.has_option(section.lower(), step):
7285
commands[step] = config_file.get(section, step).strip() + "\n"
7386
if commands:
7487
self.actions[action_name] = commands
@@ -89,67 +102,3 @@ def _load_settings(self) -> None:
89102

90103
def get_action(self, name: str) -> dict[str, str]:
91104
return self.actions[name]
92-
93-
94-
defaultConfigContent = """
95-
#This is the default config of the rsnapshot-docker-compose-backup program.
96-
97-
#This section can contain rsnapshot commands that are executed in the different steps of the container backup
98-
[{default_config}]
99-
#Example:
100-
#run_backup=backup_script echo "Hello" > helloWorld test/
101-
102-
#This section contains settings that can be set. This section can only be used in the default config.
103-
[{default_config_settings}]
104-
#This outputs the Start and End Times for each backup command to the log.
105-
#Rsnapshot doesn't log timestamps
106-
logTime = true
107-
108-
[{default_config_vars}]
109-
#This setting corresponds to the var with the same name and can be used as a prefix in the folder path
110-
backupprefixfolder = .
111-
112-
#This Section controls which actions should be enabled
113-
[{default_config_actions}]
114-
#This action stops the container before copying the volumes and starts it after it finished.
115-
stopcontainer = true
116-
117-
#This action backups all volumes of the container
118-
volumebackup = true
119-
120-
#This action saves the docker-compose.yml
121-
yamlbackup = true
122-
imagebackup = true
123-
124-
#The following actions are disabled by default
125-
logbackup = false
126-
projectDirBackup = false
127-
128-
#The following is the definition of actions that can be used in the backup
129-
130-
[{actions}.volumeBackup]
131-
backup = backup\t$volumes.path\t$backupPrefixFolder/$serviceName/$volumes.name
132-
133-
[{actions}.yamlBackup]
134-
runtime_backup = backup\t$projectFolder\t$backupPrefixFolder/$serviceName/yaml\t+rsync_long_args=--include=*.yml,+rsync_long_args=--include=*.yaml
135-
136-
[{actions}.projectDirBackup]
137-
backup = backup\t$projectFolder\t$backupPrefixFolder/$serviceName/projectDir
138-
139-
[{actions}.imageBackup]
140-
runtime_backup = backup_script\t/usr/bin/docker image save $image -o $serviceName_image.tar\t$backupPrefixFolder/$serviceName/image
141-
142-
[{actions}.logBackup]
143-
backup = backup_script\t/usr/bin/docker logs $containerID > $serviceName_logs.log 2>&1\t$backupPrefixFolder/$serviceName/log
144-
145-
[{actions}.stopContainer]
146-
stop = backup_exec\tcd $projectFolder; /usr/bin/docker-compose stop
147-
restart = backup_exec\tcd $projectFolder; /usr/bin/docker-compose start
148-
149-
""".format(
150-
default_config=DefaultConfig.defaultConfig,
151-
default_config_actions=DefaultConfig.actions_name(DefaultConfig.defaultConfig),
152-
default_config_vars=DefaultConfig.vars_name(DefaultConfig.defaultConfig),
153-
actions=DefaultConfig.actionSection,
154-
default_config_settings=DefaultConfig.settingsSection,
155-
)

src/rsnapshot_docker_compose_backup/docker/__init__.py

Whitespace-only changes.

src/rsnapshot_docker_compose_backup/docker.py renamed to src/rsnapshot_docker_compose_backup/docker/docker.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import json
22
import re
3-
from typing import List, Any
3+
from typing import Any, Optional
44

55
from rsnapshot_docker_compose_backup.utils import command
6-
from rsnapshot_docker_compose_backup.volume import Volume
6+
from rsnapshot_docker_compose_backup.structure.volume import Volume
77

88

99
def inspect(container: str) -> Any:
@@ -12,7 +12,7 @@ def inspect(container: str) -> Any:
1212
return json.loads(command("docker inspect {}".format(container)).stdout)[0]
1313

1414

15-
def ps(container_id: str | None = None) -> str:
15+
def ps(container_id: Optional[str] = None) -> str:
1616
result = command("docker ps -a").stdout
1717
if container_id:
1818
for line in ps().splitlines():
@@ -22,8 +22,8 @@ def ps(container_id: str | None = None) -> str:
2222
return result
2323

2424

25-
def volumes(container_id: str) -> List[Volume]:
26-
result: List[Volume] = []
25+
def volumes(container_id: str) -> list[Volume]:
26+
result: list[Volume] = []
2727
container_info = inspect(container_id)
2828
for mount in container_info["Mounts"]:
2929
if mount["Type"] == "volume":

src/rsnapshot_docker_compose_backup/docker_compose.py renamed to src/rsnapshot_docker_compose_backup/docker/docker_compose.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,21 @@
44
import os
55
from pathlib import Path
66
import re
7-
from typing import List, Tuple
87
from concurrent import futures
98
import json
9+
from typing import Optional
1010

11-
from rsnapshot_docker_compose_backup.container import Container
11+
from rsnapshot_docker_compose_backup.structure.container import Container
1212
from rsnapshot_docker_compose_backup.utils import command
1313

1414

1515
def get_binary() -> str:
1616
if command("docker compose").returncode == 0:
1717
return "docker compose"
18-
elif command("docker-compose").returncode == 0:
18+
if command("docker-compose").returncode == 0:
1919
return "docker-compose"
20-
else:
21-
raise Exception("Docker Compose is not installed")
20+
21+
raise Exception("Docker Compose is not installed")
2222

2323

2424
def get_container_id(service_name: str, path: Path) -> str:
@@ -52,12 +52,12 @@ def container_stopped(container_id: str) -> bool:
5252
return status.stdout.startswith("Exited")
5353

5454

55-
def find_container(root_folder: Path) -> List[Container]:
56-
all_container: List[Container] = []
57-
docker_dirs: List[Path] = find_docker_dirs(root_folder)
55+
def find_container(root_folder: Path) -> list[Container]:
56+
all_container: list[Container] = []
57+
docker_dirs: list[Path] = find_docker_dirs(root_folder)
5858
with futures.ProcessPoolExecutor() as pool:
5959
for service_list, directory in pool.map(get_services, docker_dirs):
60-
# container_list: List[str] = get_services(output)
60+
# container_list: list[str] = get_services(output)
6161
for container_info in service_list:
6262
if container_info.container_id:
6363
all_container.append(
@@ -79,25 +79,25 @@ class ContainerInfo:
7979
container_id: str
8080

8181

82-
def get_services(path: Path) -> Tuple[List[ContainerInfo], Path]:
83-
service_name: List[str] = command(
82+
def get_services(path: Path) -> tuple[list[ContainerInfo], Path]:
83+
service_name: list[str] = command(
8484
"{} config --services".format(get_binary()), path=path
8585
).stdout.splitlines()
8686
# Docker doesn't return it always in the same order
8787
service_name.sort()
8888
# print(service_name)
89-
services: List[ContainerInfo] = []
89+
services: list[ContainerInfo] = []
9090
for service in service_name:
9191
container_id = get_container_id(service, path)
9292
container_name = get_container_name(service, path)
9393
services.append(ContainerInfo(service, container_name, container_id))
9494
return services, path
9595

9696

97-
def find_docker_dirs(root_folder: Path = Path(os.getcwd())) -> List[Path]:
97+
def find_docker_dirs(root_folder: Path = Path(os.getcwd())) -> list[Path]:
9898
"""Finds all docker-compose dirs in current sub folder
9999
:returns: a list of all folders"""
100-
dirs: List[Path] = []
100+
dirs: list[Path] = []
101101
docker_compose_files = [
102102
"compose.yaml",
103103
"compose.yml",
@@ -112,17 +112,17 @@ def find_docker_dirs(root_folder: Path = Path(os.getcwd())) -> List[Path]:
112112
return dirs
113113

114114

115-
def get_running_container(ps_out: str) -> List[str]:
115+
def get_running_container(ps_out: str) -> list[str]:
116116
return get_container(ps_out, state="UP")
117117

118118

119119
def get_column(column_nr: int, input_str: str) -> str:
120120
return re.sub(r"\s\s+", " ", input_str).split(" ")[column_nr]
121121

122122

123-
def get_container(ps_out: str, state: str | None = None) -> List[str]:
124-
all_container: List[str] = ps_out.splitlines()[2:]
125-
container: List[str] = []
123+
def get_container(ps_out: str, state: Optional[str] = None) -> list[str]:
124+
all_container: list[str] = ps_out.splitlines()[2:]
125+
container: list[str] = []
126126
if not all_container:
127127
return []
128128
for line in all_container:

0 commit comments

Comments
 (0)