#!/usr/bin/env python3
import sys
import blenderfarm
class Action:
def __init__(self):
self.name = ''
self.description = ''
self.options = []
self.prefix = ''
def __lt__(self, other):
return self.name < other.name
def parse_arguments(self, args, raise_errors=False):
options = {}
for option_index in range(len(self.options)):
option_format = Action.get_option_format(self.options[option_index])
option_name = option_format['name']
option_value = option_format['default']
if len(args) >= option_index + 1:
option_value = args[option_index]
elif not option_format['optional'] and raise_errors:
print('! option "' + option_name + '" (for action "' + self.name + '") is not optional')
exit(1)
options[option_name] = option_value
if len(args) > len(self.options):
options['__'] = args[len(self.options):]
else:
options['__'] = []
return options
@staticmethod
def get_option_help(option):
option_format = Action.get_option_format(option)
name = option_format['name']
if option_format['optional']:
return '[' + name + ']'
return '<' + name + '>'
@staticmethod
def get_option_format(option):
option_format = {
'name': None,
'optional': False,
'default': None
}
if option.startswith('?'):
option = option[1:]
option_format['optional'] = True
if '=' in option:
option_format['default'] = option.split('=')[1]
option = option.split('=')[0]
option_format['name'] = option
return option_format
def get_string_options_list(self):
options = []
for option in self.options:
options.append(Action.get_option_help(option))
return ' '.join(options)
def get_help_line(self):
return self.prefix + ' ' + self.name.ljust(12) + ' ' + self.get_string_options_list().ljust(24) + ' ' + self.description
def get_help_usage(self):
return (self.prefix + ' ' + self.name + ' ' + self.get_string_options_list()).ljust(48) + self.description
def help(self, options):
_ = options
print(self.get_help_usage())
def invoke(self, options): # pylint: disable=no-self-use
_ = options
print('override me')
class ActionList(Action):
def __init__(self):
super().__init__()
self.options = ['action']
self.actions = []
def get_action(self, name):
name = name.lower().strip()
for action in self.actions:
if action.name == name:
return action
return None
def help(self, options):
action_name = options['action']
if action_name:
action = self.get_action(action_name)
if action:
action.prefix = self.prefix + ' ' + self.name
action.help(action.parse_arguments(options['__']))
return
print(self.get_help_usage())
print()
for action in self.actions:
action.prefix = self.prefix + ' ' + self.name
print(action.get_help_usage())
def invoke(self, options):
action_name = options['action']
arguments = options['__']
action = self.get_action(action_name)
if not action:
self.help(options)
print()
print('! no such sub-action "' + action_name + '"')
return
action.prefix = self.prefix + ' ' + self.name
action.invoke(action.parse_arguments(arguments, True))
class HelpAction(Action):
def __init__(self):
super().__init__()
self.name = 'help'
self.description = 'prints out help'
self.options = ['?module']
def invoke(self, options):
print()
if options['module'] != None:
action_name = options['module']
action = get_action(action_name)
if not action:
print_help()
print()
print('! no such action "' + action_name + '"')
return
action.prefix = self.prefix
action.help(action.parse_arguments(options['__']))
else:
print_help()
print()
class VersionAction(Action):
def __init__(self):
super().__init__()
self.name = 'version'
self.description = 'prints out the blenderfarm version'
def help(self, options):
print(self.get_help_usage())
print()
print('only the version is printed, to make machine-parsing possible.')
def invoke(self, options):
print(blenderfarm.__version__)
class ServerAction(Action):
def __init__(self):
super().__init__()
self.name = 'server'
self.description = 'starts the blenderfarm server'
self.options = ['?host=0.0.0.0', '?port=44363']
def help(self, options):
print(self.description)
print()
print('accepts two arguments: [host] and [port].')
print('If omitted, the defaults of "0.0.0.0" and "44363" are used.')
def invoke(self, options):
host = options['host']
port = options['port']
try:
port = int(port)
except ValueError:
print('! invalid port number "' + port + '"')
return
server = blenderfarm.server.Server(host=host, port=port)
print('starting blenderfarm server at ' + host + ' (' + str(port) + ')...')
server.start()
class AdminUserAddAction(Action):
def __init__(self):
super().__init__()
self.name = 'add'
self.description = 'adds a new user'
self.options = ['username']
def help(self, options):
print(self.description)
print()
print('the username must not exist yet')
def invoke(self, options):
username = options['username']
users_db = blenderfarm.db.Users()
user = users_db.get_user(username)
if user:
print('that username already exists:')
else:
user = users_db.add(username)
print('user creation successful:')
print(user.get_username_key())
class AdminUserRemoveAction(Action):
def __init__(self):
super().__init__()
self.name = 'remove'
self.description = 'removes a user'
self.options = ['username']
def invoke(self, options):
username = options['username']
users_db = blenderfarm.db.Users()
if not users_db.get_user(username):
print('! that username does not exist')
return
users_db.remove(username)
print('user deletion successful; "' + username + '" no longer exists')
class AdminUserRekeyAction(Action):
def __init__(self):
super().__init__()
self.name = 'rekey'
self.description = 'deletes the old user key and creates a new one'
self.options = ['username']
def invoke(self, options):
username = options['username']
users_db = blenderfarm.db.Users()
user = users_db.get_user(username)
if not user:
print('! that username does not exist')
return
users_db.rekey(username)
print('user rekey successful')
print(user.get_username_key())
class AdminUserListAction(Action):
def __init__(self):
super().__init__()
self.name = 'list'
self.description = 'lists users and keys'
self.options = ['?username']
def help(self, options):
print(self.get_help_usage())
print()
print('lists existing users on this blenderfarm server')
print('if the optional parameter [username] is present, only lists that user')
def invoke(self, options):
users_db = blenderfarm.db.Users()
username = options['username']
if username:
user = users_db.get_user(username)
if user:
print('...')
print(user.get_username_key())
print('...')
return
print('! that username does not exist')
return
for user in users_db.get_users():
print(user.get_username_key())
class AdminUserAction(ActionList):
def __init__(self):
super().__init__()
self.name = 'user'
self.description = 'blenderfarm server user administration commands'
self.actions = [
AdminUserAddAction(),
AdminUserRemoveAction(),
AdminUserRekeyAction(),
AdminUserListAction()
]
class AdminAction(ActionList):
def __init__(self):
super().__init__()
self.name = 'admin'
self.description = 'blenderfarm server administration commands'
self.actions = [
AdminUserAction()
]
ACTIONS = [
HelpAction(),
VersionAction(),
ServerAction(),
AdminUserAction(),
AdminAction()
]
ACTIONS.sort()
def print_version():
print('blenderfarm version ' + blenderfarm.__version__)
def print_help():
print('actions:')
print()
for action in ACTIONS:
action.prefix = sys.argv[0]
print(action.get_help_line())
def print_usage():
print('usage: ' + sys.argv[0] + ' <action> [options...]')
print()
print_help()
def get_action(name):
name = name.lower().strip()
for action in ACTIONS:
if action.name == name:
return action
return None
def run():
if len(sys.argv) < 2:
print_usage()
exit(1)
action_name = sys.argv[1]
action = get_action(action_name)
if not action:
print_usage()
print()
print('! no such action "' + action_name + '"')
exit(1)
action.prefix = sys.argv[0]
action.invoke(action.parse_arguments(sys.argv[2:]))
if __name__ == '__main__':
run()