improve tootctl.py
This commit is contained in:
parent
e0d6191541
commit
20cf654b38
178
tootctl.py
178
tootctl.py
|
@ -1,23 +1,150 @@
|
|||
#!/usr/bin/env python3
|
||||
import os, sys
|
||||
__software__ = 'PyTootctl'
|
||||
__version__ = '0.1.1'
|
||||
__author__ = 'Zoey Mae'
|
||||
__homepage__ = 'https://git.barkshark.xyz/izaliamae/scripts/tootctl.py'
|
||||
__license__ = 'CNPL v7+'
|
||||
__license_url__ = 'https://thufie.lain.haus/files/CNPLv7.md'
|
||||
|
||||
## Usage:
|
||||
## Toss in a directory in path (optional) and run like any other program. ex: tootctl.py media remove --days=4
|
||||
|
||||
## PyTootctl-specific commands:
|
||||
## tootctl.py set {key} {value}: set a config option
|
||||
## tootctl.py config: list the current config. Any invalid paths will be noted.
|
||||
|
||||
## Note:
|
||||
## This can be safely ran from cron or other environments that don't import your .bashrc or .profile.
|
||||
|
||||
## Todo:
|
||||
## Add help command
|
||||
|
||||
import json, logging, 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')
|
||||
home = Path('~').expanduser()
|
||||
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',
|
||||
})
|
||||
if str(home) == os.getcwd():
|
||||
cfg_path = Path('pytootctl.json').resolve()
|
||||
|
||||
else:
|
||||
cfg_path = home.joinpath('.config/barkshark/pytootctl.json')
|
||||
|
||||
|
||||
class Config(dict):
|
||||
defaults = dict(
|
||||
ruby = Path(environ.get('RUBY_BIN', home.joinpath('.rbenv/shims/ruby'))),
|
||||
mastodon = home.joinpath('mastodon'),
|
||||
environment = 'production',
|
||||
log_level = 'INFO'
|
||||
)
|
||||
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(**self.defaults)
|
||||
|
||||
if cfg_path.exists():
|
||||
self.read()
|
||||
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
key = key.lower()
|
||||
|
||||
if key not in self.defaults:
|
||||
raise KeyError(f'Not a valid config option: {key}')
|
||||
|
||||
if value == 'default':
|
||||
value = self.defaults[key]
|
||||
|
||||
if key in ['ruby', 'mastodon']:
|
||||
value = Path(value).resolve()
|
||||
|
||||
elif key == 'log_level':
|
||||
if value.upper() not in ['CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG']:
|
||||
raise ValueError(f'Invalid logging level: {value}')
|
||||
|
||||
value = value.upper()
|
||||
logging.getLogger().setLevel(value)
|
||||
|
||||
super().__setitem__(key, value)
|
||||
|
||||
|
||||
def __getattr__(self, key):
|
||||
return self[key]
|
||||
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
self[key] = value
|
||||
|
||||
|
||||
def update(self, data):
|
||||
for key, value in data.items():
|
||||
self[key] = value
|
||||
|
||||
|
||||
def json(self, indent=4):
|
||||
return json.dumps({k: str(v) for k,v in self.items()}, indent=indent)
|
||||
|
||||
|
||||
def read(self):
|
||||
with cfg_path.open('r') as fd:
|
||||
try:
|
||||
self.update(json.loads(fd.read()))
|
||||
|
||||
except json.decoder.JSONDecodeError:
|
||||
logging.error('Failed to parse config. Continuing with defaults.')
|
||||
|
||||
|
||||
def write(self):
|
||||
cfg_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with cfg_path.open('w') as fd:
|
||||
fd.write(self.json())
|
||||
|
||||
|
||||
class Command:
|
||||
def __init__(self, arguments):
|
||||
try:
|
||||
cmd = arguments[0]
|
||||
|
||||
except IndexError:
|
||||
raise AttributeError('No command specified')
|
||||
|
||||
args = arguments[1:] if len(arguments) > 1 else []
|
||||
|
||||
self.response = self[cmd](*args)
|
||||
|
||||
|
||||
def __getitem__(self, key):
|
||||
return getattr(self, f'cmd_{key}')
|
||||
|
||||
|
||||
def cmd_set(self, key, value):
|
||||
logging.debug(f'Setting {key}: {value}')
|
||||
config[key] = value
|
||||
config.write()
|
||||
self.cmd_config()
|
||||
|
||||
|
||||
def cmd_config(self):
|
||||
print('Current config:')
|
||||
|
||||
for k,v in config.items():
|
||||
line = f' {k}: {v}'
|
||||
|
||||
if isinstance(v, Path) and not v.exists():
|
||||
line += ' (missing)'
|
||||
|
||||
print(line)
|
||||
|
||||
|
||||
def cmd_usage(self, command=None):
|
||||
print('Not implemented yet')
|
||||
|
||||
|
||||
def debian_11_check():
|
||||
|
@ -39,10 +166,37 @@ def debian_11_check():
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig()
|
||||
|
||||
config = Config()
|
||||
tootctl = config.mastodon.joinpath('bin/tootctl')
|
||||
args = sys.argv[1:] if len(sys.argv) > 1 else []
|
||||
|
||||
try:
|
||||
Command(args)
|
||||
sys.exit(0)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if not config.ruby.exists():
|
||||
logging.error(f'Cannot find ruby at "{config.ruby}"')
|
||||
sys.exit(1)
|
||||
|
||||
if not tootctl.exists():
|
||||
logging.error(f'Cannot find tootctl at "{tootctl}"')
|
||||
sys.exit(1)
|
||||
|
||||
environment = environ.copy()
|
||||
environment.update({
|
||||
'RAILS_ENV': config.environment,
|
||||
'NODE_ENV': config.environment
|
||||
})
|
||||
|
||||
if debian_11_check():
|
||||
logging.debug('Debian Bullseye with Jemalloc detected. Applying workaround.')
|
||||
environment['LD_PRELOAD'] = str(jemalloc)
|
||||
|
||||
proc = Popen([str(rubydir), str(tootctl), *args], env=environment, cwd=mastodir)
|
||||
proc = Popen([str(config.ruby), str(tootctl), *args], env=environment, cwd=config.mastodon)
|
||||
|
||||
try:
|
||||
proc.wait()
|
||||
|
|
Loading…
Reference in a new issue