Compare commits
2 commits
78f97235a6
...
e0d6191541
Author | SHA1 | Date | |
---|---|---|---|
Izalia Mae | e0d6191541 | ||
Izalia Mae | 41ff3a0bdb |
154
rsync-backup.py
Executable file
154
rsync-backup.py
Executable file
|
@ -0,0 +1,154 @@
|
|||
#!/usr/bin/env python3
|
||||
import subprocess, sys, time, traceback
|
||||
from configparser import ConfigParser
|
||||
from getpass import getpass, getuser
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
exit=False
|
||||
sudo = {}
|
||||
procs = []
|
||||
|
||||
|
||||
def Rsync(src, dest, archive=False, bwlimit=None, exclude=[], user=None):
|
||||
cmd = []
|
||||
current_user = getuser()
|
||||
|
||||
if user and user != current_user:
|
||||
cmd.extend(['sudo', '-Su', user])
|
||||
|
||||
if not sudo.get(user):
|
||||
sudo[user] = getpass(f'[pysudo] password for {current_user}: ')
|
||||
|
||||
cmd.append('rsync')
|
||||
cmd.append('--partial')
|
||||
cmd.append('--progress')
|
||||
cmd.append('--numeric-ids')
|
||||
|
||||
if archive:
|
||||
cmd.append('-aAXhx')
|
||||
cmd.append('--delete')
|
||||
|
||||
if bwlimit:
|
||||
cmd.append(f'--bwlimit={int(bwlimit)*1000}')
|
||||
|
||||
if type(exclude) == str:
|
||||
exclude = [exclude]
|
||||
|
||||
for line in exclude:
|
||||
cmd.append('--exclude')
|
||||
cmd.append(line)
|
||||
|
||||
for line in [src, dest]:
|
||||
if not line.endswith('/'):
|
||||
line += '/'
|
||||
|
||||
cmd.append(line)
|
||||
|
||||
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE)
|
||||
|
||||
if user and user != current_user:
|
||||
password = sudo[user] + '\r'
|
||||
proc.communicate(input=password.encode())
|
||||
|
||||
return proc
|
||||
|
||||
|
||||
def load_config(path):
|
||||
path = Path(path)
|
||||
new_config = {}
|
||||
config = ConfigParser()
|
||||
config.read(path)
|
||||
|
||||
if not path.is_file():
|
||||
print('Config file not found at', path)
|
||||
return
|
||||
|
||||
config = dict(config)
|
||||
|
||||
if not config.get('DEFAULT'):
|
||||
print('Missing "DEFAULT" section in config')
|
||||
return
|
||||
|
||||
if not config['DEFAULT'].get('backup_dir'):
|
||||
print('Missing "backup_dir" setting')
|
||||
return
|
||||
|
||||
for category, var in config.items():
|
||||
if category == 'DEFAULT':
|
||||
new_config['backup_dir'] = var['backup_dir']
|
||||
continue
|
||||
|
||||
new_config[category] = {}
|
||||
|
||||
for k,v in var.items():
|
||||
new_config[category][k] = v
|
||||
|
||||
return new_config
|
||||
|
||||
|
||||
def main(config):
|
||||
global exit
|
||||
global procs
|
||||
|
||||
backup_dir = Path(config.get('backup_dir'))
|
||||
|
||||
try:
|
||||
for name, data in config.items():
|
||||
if name == 'backup_dir':
|
||||
continue
|
||||
|
||||
exclude = data.get('exclude', [])
|
||||
user = data.get('user')
|
||||
bwlimit = data.get('bwlimit')
|
||||
|
||||
if not data.get('src'):
|
||||
print(f'Missing source directory for {name}')
|
||||
continue
|
||||
|
||||
data['dest'] = str(backup_dir.joinpath(name))
|
||||
|
||||
for path in ['src', 'dest']:
|
||||
if not data[path].endswith('/'):
|
||||
data[path] += '/'
|
||||
|
||||
src = data.get('src')
|
||||
dest = data.get('dest')
|
||||
|
||||
print(f'Running backup for {name}')
|
||||
proc = Rsync(src, dest, archive=True, exclude=exclude, bwlimit=bwlimit, user=user)
|
||||
|
||||
if not proc:
|
||||
print(f'Failed to run backup for {name}')
|
||||
|
||||
else:
|
||||
procs.append(proc)
|
||||
proc.wait()
|
||||
|
||||
if exit:
|
||||
break
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print('Bye!')
|
||||
|
||||
for proc in procs:
|
||||
if proc.poll() == None:
|
||||
print('Terminating proc:', ' '.join(proc.args))
|
||||
proc.terminate()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = sys.argv[1:]
|
||||
configfile = Path.home().joinpath('.config', 'barkshark', 'pysync.ini')
|
||||
config = {}
|
||||
|
||||
if len(args) > 0:
|
||||
configfile = Path(args[0])
|
||||
|
||||
config = load_config(configfile)
|
||||
|
||||
if not config:
|
||||
print('failed to load config')
|
||||
sys.exit()
|
||||
|
||||
main(config)
|
51
tootctl.py
Executable file
51
tootctl.py
Executable file
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/env python3
|
||||
import os, sys
|
||||
|
||||
from os import environ
|
||||
from pathlib import Path
|
||||
from subprocess import Popen
|
||||
|
||||
|
||||
home = Path(environ.get('HOME', os.getcwd())).resolve()
|
||||
rubydir = home.joinpath('.rbenv/shims/ruby')
|
||||
mastodir = Path(environ.get('MASTO_DIR', home.joinpath('.local/opt/mastodon')))
|
||||
tootctl = mastodir.joinpath('bin/tootctl')
|
||||
jemalloc = Path('/usr/lib/x86_64-linux-gnu/libjemalloc.so.2')
|
||||
args = sys.argv[1:] if len(sys.argv) > 1 else []
|
||||
|
||||
environment = environ.copy()
|
||||
environment.update({
|
||||
'RAILS_ENV': 'production',
|
||||
'NODE_ENV': 'production',
|
||||
})
|
||||
|
||||
|
||||
def debian_11_check():
|
||||
info = {}
|
||||
|
||||
if not jemalloc.exists():
|
||||
return False
|
||||
|
||||
for line in open('/etc/os-release', 'r').readlines():
|
||||
key, value = line.split('=', 1)
|
||||
value = value.replace('\n', '')
|
||||
|
||||
if value.startswith('"') and value.endswith('"'):
|
||||
value = value[1:-1]
|
||||
|
||||
info[key] = value
|
||||
|
||||
return info['ID'].lower() == 'debian' and info['VERSION_ID'] == "11"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if debian_11_check():
|
||||
environment['LD_PRELOAD'] = str(jemalloc)
|
||||
|
||||
proc = Popen([str(rubydir), str(tootctl), *args], env=environment, cwd=mastodir)
|
||||
|
||||
try:
|
||||
proc.wait()
|
||||
|
||||
except KeyboardInterrupt:
|
||||
proc.terminate()
|
Loading…
Reference in a new issue