Ran black formatter
parent
4cb97897a7
commit
75b5b5b316
|
@ -7,19 +7,32 @@ from specs import parse_specs_file
|
||||||
def except_hook(ext_type, value, traceback):
|
def except_hook(ext_type, value, traceback):
|
||||||
sys.stderr.write("{}: {}\n".format(ext_type.__name__, value))
|
sys.stderr.write("{}: {}\n".format(ext_type.__name__, value))
|
||||||
|
|
||||||
|
|
||||||
sys.excepthook = except_hook
|
sys.excepthook = except_hook
|
||||||
|
|
||||||
|
|
||||||
# Define parser
|
# Define parser
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description='Backup directories and Docker volumes.')
|
description="Backup directories and Docker volumes."
|
||||||
parser.add_argument('-f', '--file', action='append', dest='file',
|
)
|
||||||
help='File containing spec definitions.')
|
parser.add_argument(
|
||||||
parser.add_argument('-j', '--json', action='store_const', const=True,
|
"-f",
|
||||||
default=False, help='Print out the parsed specs as JSON '
|
"--file",
|
||||||
'and exit')
|
action="append",
|
||||||
parser.add_argument('spec', nargs='*',
|
dest="file",
|
||||||
help='The specs to process. Defaults to all.')
|
help="File containing spec definitions.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-j",
|
||||||
|
"--json",
|
||||||
|
action="store_const",
|
||||||
|
const=True,
|
||||||
|
default=False,
|
||||||
|
help="Print out the parsed specs as JSON " "and exit",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"spec", nargs="*", help="The specs to process. Defaults to all."
|
||||||
|
)
|
||||||
|
|
||||||
# Parse arguments
|
# Parse arguments
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
@ -32,6 +45,7 @@ if args.spec:
|
||||||
# Dump parsed data as json
|
# Dump parsed data as json
|
||||||
if args.json:
|
if args.json:
|
||||||
import json
|
import json
|
||||||
|
|
||||||
print(json.dumps([spec.to_dict() for spec in specs], indent=4))
|
print(json.dumps([spec.to_dict() for spec in specs], indent=4))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -37,10 +37,7 @@ def parse_specs_file(path: Path) -> List[Spec]:
|
||||||
"destination": None,
|
"destination": None,
|
||||||
"limit": None,
|
"limit": None,
|
||||||
"volume": False,
|
"volume": False,
|
||||||
"notify": {
|
"notify": {"title": "Backup Notification", "events": ["failure"]},
|
||||||
"title": "Backup Notification",
|
|
||||||
"events": ["failure"]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Read YAML file
|
# Read YAML file
|
||||||
|
@ -58,9 +55,11 @@ def parse_specs_file(path: Path) -> List[Spec]:
|
||||||
specs = []
|
specs = []
|
||||||
# Check format for each spec
|
# Check format for each spec
|
||||||
for key in data["specs"]:
|
for key in data["specs"]:
|
||||||
specs.append(Spec.from_dict(key, combine_with_skeleton(
|
specs.append(
|
||||||
data["specs"][key], spec_skel)
|
Spec.from_dict(
|
||||||
))
|
key, combine_with_skeleton(data["specs"][key], spec_skel)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return specs
|
return specs
|
||||||
|
|
||||||
|
@ -95,20 +94,3 @@ def combine_with_skeleton(data: Dict, skel: Dict) -> Dict:
|
||||||
data[key] = combine_with_skeleton(data[key], value)
|
data[key] = combine_with_skeleton(data[key], value)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
# Test cases
|
|
||||||
if __name__ == "__main__":
|
|
||||||
d1 = {
|
|
||||||
"a": 5
|
|
||||||
}
|
|
||||||
s1 = {
|
|
||||||
"a": 7,
|
|
||||||
"b": 2
|
|
||||||
}
|
|
||||||
r1 = {
|
|
||||||
"a": 5,
|
|
||||||
"b": 2
|
|
||||||
}
|
|
||||||
|
|
||||||
assert combine_with_skeleton(d1, s1) == r1
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
from pathlib import Path
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import requests
|
import requests
|
||||||
import os
|
import os
|
||||||
|
@ -20,18 +19,18 @@ class Spec:
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
"destination": str(self.destination),
|
"destination": str(self.destination),
|
||||||
"limit": self.limit,
|
"limit": self.limit,
|
||||||
"notify": {
|
"notify": {"title": self.title, "events": self.events},
|
||||||
"title": self.title,
|
|
||||||
"events": self.events
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def backup(self):
|
def backup(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def remove_redundant(self):
|
def remove_redundant(self):
|
||||||
tarballs = sorted(self.destination.glob('*.tar.gz'),
|
tarballs = sorted(
|
||||||
key=os.path.getmtime, reverse=True)
|
self.destination.glob("*.tar.gz"),
|
||||||
|
key=os.path.getmtime,
|
||||||
|
reverse=True,
|
||||||
|
)
|
||||||
|
|
||||||
if len(tarballs) >= self.limit:
|
if len(tarballs) >= self.limit:
|
||||||
for path in tarballs[self.limit - 1 :]:
|
for path in tarballs[self.limit - 1 :]:
|
||||||
|
@ -59,21 +58,16 @@ class Spec:
|
||||||
return
|
return
|
||||||
|
|
||||||
url = "https://maker.ifttt.com/trigger/{}/with/key/{}".format(
|
url = "https://maker.ifttt.com/trigger/{}/with/key/{}".format(
|
||||||
"phone_notifications",
|
"phone_notifications", key
|
||||||
key
|
|
||||||
)
|
)
|
||||||
|
|
||||||
data = {
|
data = {"value1": self.title, "value2": message}
|
||||||
"value1": self.title,
|
|
||||||
"value2": message
|
|
||||||
}
|
|
||||||
|
|
||||||
requests.post(url, data=data)
|
requests.post(url, data=data)
|
||||||
|
|
||||||
def get_filename(self):
|
def get_filename(self):
|
||||||
return '{}_{}.tar.gz'.format(
|
return "{}_{}.tar.gz".format(
|
||||||
self.name,
|
self.name, datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
||||||
datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -85,11 +79,12 @@ class Spec:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_file(path: str):
|
def from_file(path: str):
|
||||||
with open(path, 'r') as yaml_file:
|
with open(path, "r") as yaml_file:
|
||||||
data = yaml.load(yaml_file, Loader=yaml.Loader)
|
data = yaml.load(yaml_file, Loader=yaml.Loader)
|
||||||
|
|
||||||
return [Spec.from_dict(name, info)
|
return [
|
||||||
for name, info in data["specs"].items()]
|
Spec.from_dict(name, info) for name, info in data["specs"].items()
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class DirSpec(Spec):
|
class DirSpec(Spec):
|
||||||
|
@ -103,8 +98,7 @@ class DirSpec(Spec):
|
||||||
|
|
||||||
status_code = os.system(
|
status_code = os.system(
|
||||||
"tar -C '{}' -czf '{}' -- .".format(
|
"tar -C '{}' -czf '{}' -- .".format(
|
||||||
self.source,
|
self.source, self.destination / self.get_filename()
|
||||||
self.destination / self.get_filename()
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -118,9 +112,10 @@ class DirSpec(Spec):
|
||||||
data["destination"],
|
data["destination"],
|
||||||
data["limit"],
|
data["limit"],
|
||||||
data["notify"]["title"],
|
data["notify"]["title"],
|
||||||
data["notify"]["events"]
|
data["notify"]["events"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class VolumeSpec(Spec):
|
class VolumeSpec(Spec):
|
||||||
def __init__(self, name, volume, destination, limit, title, events=None):
|
def __init__(self, name, volume, destination, limit, title, events=None):
|
||||||
super().__init__(name, destination, limit, title, events)
|
super().__init__(name, destination, limit, title, events)
|
||||||
|
@ -131,9 +126,7 @@ class VolumeSpec(Spec):
|
||||||
status_code = os.system(
|
status_code = os.system(
|
||||||
"docker run --rm -v '{}:/from' -v '{}:/to' alpine:latest "
|
"docker run --rm -v '{}:/from' -v '{}:/to' alpine:latest "
|
||||||
"tar -C /from -czf '/to/{}' -- .".format(
|
"tar -C /from -czf '/to/{}' -- .".format(
|
||||||
self.volume,
|
self.volume, self.destination, self.get_filename()
|
||||||
self.destination,
|
|
||||||
self.get_filename()
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -145,5 +138,5 @@ class VolumeSpec(Spec):
|
||||||
data["destination"],
|
data["destination"],
|
||||||
data["limit"],
|
data["limit"],
|
||||||
data["notify"]["title"],
|
data["notify"]["title"],
|
||||||
data["notify"]["events"]
|
data["notify"]["events"],
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue