backup-docker-to-local 1.2.0__py3-none-any.whl → 1.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {backup_docker_to_local-1.2.0.dist-info → backup_docker_to_local-1.4.0.dist-info}/METADATA +1 -1
- {backup_docker_to_local-1.2.0.dist-info → backup_docker_to_local-1.4.0.dist-info}/RECORD +11 -11
- {backup_docker_to_local-1.2.0.dist-info → backup_docker_to_local-1.4.0.dist-info}/WHEEL +1 -1
- baudolo/backup/app.py +1 -0
- baudolo/backup/cli.py +1 -1
- baudolo/backup/compose.py +94 -3
- baudolo/backup/db.py +4 -4
- baudolo/seed/__main__.py +21 -11
- {backup_docker_to_local-1.2.0.dist-info → backup_docker_to_local-1.4.0.dist-info}/entry_points.txt +0 -0
- {backup_docker_to_local-1.2.0.dist-info → backup_docker_to_local-1.4.0.dist-info}/licenses/LICENSE +0 -0
- {backup_docker_to_local-1.2.0.dist-info → backup_docker_to_local-1.4.0.dist-info}/top_level.txt +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
backup_docker_to_local-1.
|
|
1
|
+
backup_docker_to_local-1.4.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
|
2
2
|
baudolo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
baudolo/backup/__init__.py,sha256=5BfF8JBXB2j6sAptcmswtbjlajNWxOho6_CjwIamO7k,30
|
|
4
4
|
baudolo/backup/__main__.py,sha256=118gZ0wij9_PAtR-jlG7LizrhrxwhHlAcAPW1eFeJtU,140
|
|
5
|
-
baudolo/backup/app.py,sha256=
|
|
6
|
-
baudolo/backup/cli.py,sha256=
|
|
7
|
-
baudolo/backup/compose.py,sha256=
|
|
8
|
-
baudolo/backup/db.py,sha256=
|
|
5
|
+
baudolo/backup/app.py,sha256=Msx4DLi9URo9KWiT73riRD9csAQKvqZC6R2uRuEFqhk,6551
|
|
6
|
+
baudolo/backup/cli.py,sha256=CIckfVsU03ajZTI7zj3TB-AuvaOeJMbTB6rNCOKymXE,2473
|
|
7
|
+
baudolo/backup/compose.py,sha256=b-qKimuCcNhvHvDNDyNhmtDPcBpN2pmlJNBgy2fiPg0,3637
|
|
8
|
+
baudolo/backup/db.py,sha256=_7_Vy8nMql1vaaL1g0kbLtRHhGx65T560DsckZFRJ-k,4462
|
|
9
9
|
baudolo/backup/docker.py,sha256=6Sj9fpf1bm-CoqoeerQaq059VyDnF1Pj2ketzIt1Nkk,1364
|
|
10
10
|
baudolo/backup/shell.py,sha256=guMHWcRb0Qlrz79gqFqmJLXVQK8cJEvNkhkMe5Tpgwc,738
|
|
11
11
|
baudolo/backup/volume.py,sha256=DWBp_dZUo-a0MfnbwEd8jRAAHvSyN6vGdRSye0iQJbE,1485
|
|
@@ -17,9 +17,9 @@ baudolo/restore/run.py,sha256=rai5F27D6F8RRnFMyjcEGiHBAlVXtMOJoazs6zkLSC0,2302
|
|
|
17
17
|
baudolo/restore/db/__init__.py,sha256=C4K_YAB0F9p8QhZRZIRyV2naMb54Qf_1O2cDxwwVQAI,59
|
|
18
18
|
baudolo/restore/db/mariadb.py,sha256=_JEQFuF4GhTl8lKmgk2gsHYcXHcpCKrf32tigMSeTKI,2782
|
|
19
19
|
baudolo/restore/db/postgres.py,sha256=_NIlcxdpcQIUZ8SNBWfWIaH1oGIkmZy9emFMgjGznhk,1446
|
|
20
|
-
baudolo/seed/__main__.py,sha256=
|
|
21
|
-
backup_docker_to_local-1.
|
|
22
|
-
backup_docker_to_local-1.
|
|
23
|
-
backup_docker_to_local-1.
|
|
24
|
-
backup_docker_to_local-1.
|
|
25
|
-
backup_docker_to_local-1.
|
|
20
|
+
baudolo/seed/__main__.py,sha256=BnN0Ckdjr30r6yxORq-ctrdmkT0yfeRIuXnyhKSe8Us,3430
|
|
21
|
+
backup_docker_to_local-1.4.0.dist-info/METADATA,sha256=Oaxj5qZJ97MdokIS5TrG0h-vNgHKllODdUIhdHU2Y24,7200
|
|
22
|
+
backup_docker_to_local-1.4.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
23
|
+
backup_docker_to_local-1.4.0.dist-info/entry_points.txt,sha256=92f5jPSjW__9-u5gzwmWkdiHKt4ysEFCVmwMtorQCv4,147
|
|
24
|
+
backup_docker_to_local-1.4.0.dist-info/top_level.txt,sha256=y_5iNpF7EdLzqWWXIDfcTJpqijyy2hvrYgNiJXrN4r4,8
|
|
25
|
+
backup_docker_to_local-1.4.0.dist-info/RECORD,,
|
baudolo/backup/app.py
CHANGED
baudolo/backup/cli.py
CHANGED
baudolo/backup/compose.py
CHANGED
|
@@ -1,13 +1,104 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
+
import shutil
|
|
4
5
|
import subprocess
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import List, Optional
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _detect_env_file(project_dir: Path) -> Optional[Path]:
|
|
11
|
+
"""
|
|
12
|
+
Detect Compose env file in a directory.
|
|
13
|
+
Preference (same as Infinito.Nexus wrapper):
|
|
14
|
+
1) <dir>/.env (file)
|
|
15
|
+
2) <dir>/.env/env (file) (legacy layout)
|
|
16
|
+
"""
|
|
17
|
+
c1 = project_dir / ".env"
|
|
18
|
+
if c1.is_file():
|
|
19
|
+
return c1
|
|
20
|
+
|
|
21
|
+
c2 = project_dir / ".env" / "env"
|
|
22
|
+
if c2.is_file():
|
|
23
|
+
return c2
|
|
24
|
+
|
|
25
|
+
return None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _detect_compose_files(project_dir: Path) -> List[Path]:
|
|
29
|
+
"""
|
|
30
|
+
Detect Compose file stack in a directory (same as Infinito.Nexus wrapper).
|
|
31
|
+
Always requires docker-compose.yml.
|
|
32
|
+
Optionals:
|
|
33
|
+
- docker-compose.override.yml
|
|
34
|
+
- docker-compose.ca.override.yml
|
|
35
|
+
"""
|
|
36
|
+
base = project_dir / "docker-compose.yml"
|
|
37
|
+
if not base.is_file():
|
|
38
|
+
raise FileNotFoundError(f"Missing docker-compose.yml in: {project_dir}")
|
|
39
|
+
|
|
40
|
+
files = [base]
|
|
41
|
+
|
|
42
|
+
override = project_dir / "docker-compose.override.yml"
|
|
43
|
+
if override.is_file():
|
|
44
|
+
files.append(override)
|
|
45
|
+
|
|
46
|
+
ca_override = project_dir / "docker-compose.ca.override.yml"
|
|
47
|
+
if ca_override.is_file():
|
|
48
|
+
files.append(ca_override)
|
|
49
|
+
|
|
50
|
+
return files
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _compose_wrapper_path() -> Optional[str]:
|
|
54
|
+
"""
|
|
55
|
+
Prefer the Infinito.Nexus compose wrapper if present.
|
|
56
|
+
Equivalent to: `which compose`
|
|
57
|
+
"""
|
|
58
|
+
return shutil.which("compose")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _build_compose_cmd(project_dir: str, passthrough: List[str]) -> List[str]:
|
|
62
|
+
"""
|
|
63
|
+
Build the compose command for this project directory.
|
|
64
|
+
|
|
65
|
+
Behavior:
|
|
66
|
+
- If `compose` wrapper exists: use it with --chdir (so it resolves -f/--env-file itself)
|
|
67
|
+
- Else: use `docker compose` and replicate wrapper's file/env detection.
|
|
68
|
+
"""
|
|
69
|
+
pdir = Path(project_dir).resolve()
|
|
70
|
+
|
|
71
|
+
wrapper = _compose_wrapper_path()
|
|
72
|
+
if wrapper:
|
|
73
|
+
# Wrapper defaults project name to basename of --chdir.
|
|
74
|
+
# "--" ensures wrapper stops parsing its own args.
|
|
75
|
+
return [wrapper, "--chdir", str(pdir), "--", *passthrough]
|
|
76
|
+
|
|
77
|
+
# Fallback: pure docker compose, but mirror wrapper behavior.
|
|
78
|
+
files = _detect_compose_files(pdir)
|
|
79
|
+
env_file = _detect_env_file(pdir)
|
|
80
|
+
|
|
81
|
+
cmd: List[str] = ["docker", "compose"]
|
|
82
|
+
for f in files:
|
|
83
|
+
cmd += ["-f", str(f)]
|
|
84
|
+
if env_file:
|
|
85
|
+
cmd += ["--env-file", str(env_file)]
|
|
86
|
+
|
|
87
|
+
cmd += passthrough
|
|
88
|
+
return cmd
|
|
5
89
|
|
|
6
90
|
|
|
7
91
|
def hard_restart_docker_services(dir_path: str) -> None:
|
|
8
|
-
print(f"Hard restart
|
|
9
|
-
|
|
10
|
-
|
|
92
|
+
print(f"Hard restart compose services in: {dir_path}", flush=True)
|
|
93
|
+
|
|
94
|
+
down_cmd = _build_compose_cmd(dir_path, ["down"])
|
|
95
|
+
up_cmd = _build_compose_cmd(dir_path, ["up", "-d"])
|
|
96
|
+
|
|
97
|
+
print(">>> " + " ".join(down_cmd), flush=True)
|
|
98
|
+
subprocess.run(down_cmd, check=True)
|
|
99
|
+
|
|
100
|
+
print(">>> " + " ".join(up_cmd), flush=True)
|
|
101
|
+
subprocess.run(up_cmd, check=True)
|
|
11
102
|
|
|
12
103
|
|
|
13
104
|
def handle_docker_compose_services(
|
baudolo/backup/db.py
CHANGED
|
@@ -52,7 +52,9 @@ def _atomic_write_cmd(cmd: str, out_file: str) -> None:
|
|
|
52
52
|
execute_shell_command(f"mv {tmp} {out_file}")
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
def fallback_pg_dumpall(
|
|
55
|
+
def fallback_pg_dumpall(
|
|
56
|
+
container: str, username: str, password: str, out_file: str
|
|
57
|
+
) -> None:
|
|
56
58
|
"""
|
|
57
59
|
Perform a full Postgres cluster dump using pg_dumpall.
|
|
58
60
|
"""
|
|
@@ -103,9 +105,7 @@ def backup_database(
|
|
|
103
105
|
"'*' is currently only supported for Postgres."
|
|
104
106
|
)
|
|
105
107
|
|
|
106
|
-
cluster_file = os.path.join(
|
|
107
|
-
out_dir, f"{instance_name}.cluster.backup.sql"
|
|
108
|
-
)
|
|
108
|
+
cluster_file = os.path.join(out_dir, f"{instance_name}.cluster.backup.sql")
|
|
109
109
|
fallback_pg_dumpall(container, user, password, cluster_file)
|
|
110
110
|
produced = True
|
|
111
111
|
continue
|
baudolo/seed/__main__.py
CHANGED
|
@@ -7,10 +7,11 @@ import re
|
|
|
7
7
|
import sys
|
|
8
8
|
import pandas as pd
|
|
9
9
|
from typing import Optional
|
|
10
|
-
|
|
10
|
+
from pandas.errors import EmptyDataError
|
|
11
11
|
|
|
12
12
|
DB_NAME_RE = re.compile(r"^[a-zA-Z0-9_][a-zA-Z0-9_-]*$")
|
|
13
13
|
|
|
14
|
+
|
|
14
15
|
def _validate_database_value(value: Optional[str], *, instance: str) -> str:
|
|
15
16
|
v = (value or "").strip()
|
|
16
17
|
if v == "":
|
|
@@ -31,6 +32,11 @@ def _validate_database_value(value: Optional[str], *, instance: str) -> str:
|
|
|
31
32
|
)
|
|
32
33
|
return v
|
|
33
34
|
|
|
35
|
+
|
|
36
|
+
def _empty_df() -> pd.DataFrame:
|
|
37
|
+
return pd.DataFrame(columns=["instance", "database", "username", "password"])
|
|
38
|
+
|
|
39
|
+
|
|
34
40
|
def check_and_add_entry(
|
|
35
41
|
file_path: str,
|
|
36
42
|
instance: str,
|
|
@@ -48,17 +54,21 @@ def check_and_add_entry(
|
|
|
48
54
|
database = _validate_database_value(database, instance=instance)
|
|
49
55
|
|
|
50
56
|
if os.path.exists(file_path):
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
try:
|
|
58
|
+
df = pd.read_csv(
|
|
59
|
+
file_path,
|
|
60
|
+
sep=";",
|
|
61
|
+
dtype=str,
|
|
62
|
+
keep_default_na=False,
|
|
63
|
+
)
|
|
64
|
+
except EmptyDataError:
|
|
65
|
+
print(
|
|
66
|
+
f"WARNING: databases.csv exists but is empty: {file_path}. Creating header columns.",
|
|
67
|
+
file=sys.stderr,
|
|
68
|
+
)
|
|
69
|
+
df = _empty_df()
|
|
57
70
|
else:
|
|
58
|
-
df =
|
|
59
|
-
columns=["instance", "database", "username", "password"]
|
|
60
|
-
)
|
|
61
|
-
|
|
71
|
+
df = _empty_df()
|
|
62
72
|
mask = (df["instance"] == instance) & (df["database"] == database)
|
|
63
73
|
|
|
64
74
|
if mask.any():
|
{backup_docker_to_local-1.2.0.dist-info → backup_docker_to_local-1.4.0.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{backup_docker_to_local-1.2.0.dist-info → backup_docker_to_local-1.4.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{backup_docker_to_local-1.2.0.dist-info → backup_docker_to_local-1.4.0.dist-info}/top_level.txt
RENAMED
|
File without changes
|