Browse Source

Merge a4e467f20e into 711310d0c3

pull/6468/merge
Ricky Grassmuck 8 years ago
committed by GitHub
parent
commit
bcd22e65c4
  1. 2
      CouchPotato.py
  2. 9
      config.ini
  3. 9
      couchpotato/runner.py
  4. 25
      init/runtime-config.ini
  5. 209
      libs/argparse_config.py

2
CouchPotato.py

@ -33,7 +33,7 @@ class Loader(object):
# Get options via arg # Get options via arg
from couchpotato.runner import getOptions from couchpotato.runner import getOptions
self.options = getOptions(sys.argv[1:]) self.options = getOptions(sys.argv[1:], base_path)
# Load settings # Load settings
settings = Env.get('settings') settings = Env.get('settings')

9
config.ini

@ -0,0 +1,9 @@
# Runtime configuration file
# For all available options copy thefile located at
# "<Application-Home>/init/runtime-config.ini" to
# "<Application-Home>/config.ini"
# and edit it to fit your needs.
[default]
daemon:

9
couchpotato/runner.py

@ -13,6 +13,7 @@ import shutil
from CodernityDB.database_super_thread_safe import SuperThreadSafeDatabase from CodernityDB.database_super_thread_safe import SuperThreadSafeDatabase
from argparse import ArgumentParser from argparse import ArgumentParser
import argparse_config
from cache import FileSystemCache from cache import FileSystemCache
from couchpotato import KeyHandler, LoginHandler, LogoutHandler from couchpotato import KeyHandler, LoginHandler, LogoutHandler
from couchpotato.api import NonBlockHandler, ApiHandler from couchpotato.api import NonBlockHandler, ApiHandler
@ -27,9 +28,9 @@ from couchpotato.core.softchroot import SoftChrootInitError
try: from tornado.netutil import bind_unix_socket try: from tornado.netutil import bind_unix_socket
except: pass except: pass
def getOptions(args): def getOptions(args, base_path):
# Options # Options
conf = os.path.join(base_path, "config.ini")
parser = ArgumentParser(prog = 'CouchPotato.py') parser = ArgumentParser(prog = 'CouchPotato.py')
parser.add_argument('--data_dir', parser.add_argument('--data_dir',
dest = 'data_dir', help = 'Absolute or ~/ path of the data dir') dest = 'data_dir', help = 'Absolute or ~/ path of the data dir')
@ -46,6 +47,10 @@ def getOptions(args):
parser.add_argument('--pid_file', parser.add_argument('--pid_file',
dest = 'pid_file', help = 'Path to pidfile needed for daemon') dest = 'pid_file', help = 'Path to pidfile needed for daemon')
# parse applicaions runtime configuration file and set options
if os.path.exists(conf):
argparse_config.read_config_file(parser, conf)
options = parser.parse_args(args) options = parser.parse_args(args)
data_dir = os.path.expanduser(options.data_dir if options.data_dir else getDataDir()) data_dir = os.path.expanduser(options.data_dir if options.data_dir else getDataDir())

25
init/runtime-config.ini

@ -0,0 +1,25 @@
# A template for the CouchPotatoServer config.ini file
# Do not change the [default] section heading
[default]
# Uncomment to run CouchPotato as a daemon
# daemon:
# Uncomment to specify CouchPotato's data directory
# data_dir: /apps/configs/couchpotato
# Uncomment to specify the location of CouchPotato's settings file
# config_file: /home/couchpotato/settings.conf
# Uncomment to specifiy the location of the PID file
# pid_file: /home/couchpotato/cp.pid
# Uncomment to run CP in debug mode
# debug:
# Uncomment to log messages to the console instead of the log files
# console_log:
# Uncomment to limit logging
# quiet:

209
libs/argparse_config.py

@ -0,0 +1,209 @@
"""
Author: tikitu
"""
import ConfigParser
from argparse import _SubParsersAction, _StoreAction, _StoreConstAction
import argparse
__version__ = '0.5.1'
def get_config_parser(filename):
config_parser = ConfigParser.SafeConfigParser(allow_no_value=True)
config_parser.read([filename])
return config_parser
def read_config_file(arg_parser, filename):
config_parser = get_config_parser(filename)
read_config_parser(arg_parser, config_parser)
def read_config_parser(arg_parser, config_parser):
ReadConfig(config_parser=config_parser).walk_parser(arg_parser)
def add_config_block_subcommand(arg_parser, subparsers,
config_parser=None,
only_non_defaults=False):
"""
Add a subcommand "config-block" to the arg_parser, to be used as follows:
In myprog.py:
subparsers = arg_parser.add_subparsers(..., dest='command')
add_config_block_subcommand(arg_parser, subparsers)
# ...
parsed_args = arg_parser.parse_args()
if parsed_args.command == 'config':
print parsed_args.func(parsed_args)
exit(0)
On the commandline:
$ myprog.py config default --username tikitu --secret xyzzy
[default]
username: tikitu
secret: xyzzy
:param arg_parser:
:param config_parser:
:param dest:
:param only_non_defaults:
:return: None
"""
config_command_parser = subparsers.add_parser('config')
config_command_parser.add_argument('block')
config_command_parser.add_argument('commandline', nargs=argparse.REMAINDER)
def handle_args(orig_parsed_args):
if config_parser is not None:
read_config_parser(arg_parser, config_parser)
args_for_commandline = list(orig_parsed_args.commandline)
if orig_parsed_args.block == 'default':
subparsers.add_parser('dummy-command')
args_for_commandline.append('dummy-command')
else:
args_for_commandline.insert(0, orig_parsed_args.block)
parsed_args = arg_parser.parse_args(args_for_commandline)
return generate_config(arg_parser, parsed_args,
section=orig_parsed_args.block,
only_non_defaults=only_non_defaults)
config_command_parser.set_defaults(func=handle_args)
def generate_config(arg_parser, parsed_args, section='default',
only_non_defaults=False):
action = GenerateConfig(parsed_args, section,
only_non_defaults=only_non_defaults)
action.walk_parser(arg_parser)
return action.contents
class ArgParserWalker(object):
def start_section(self, section_name):
raise NotImplementedError()
def end_section(self):
raise NotImplementedError()
def process_parser_action(self, action, is_store_const=False):
raise NotImplementedError()
def walk_parser(self, arg_parser):
try:
self.start_section('default')
for action in arg_parser._actions:
if isinstance(action, _StoreAction):
self.process_parser_action(action)
elif isinstance(action, _StoreConstAction):
self.process_parser_action(action, is_store_const=True)
elif isinstance(action, _SubParsersAction):
for command, sub_parser in action.choices.items():
self.start_section(command)
for sub_action in sub_parser._actions:
self.process_parser_action(sub_action)
self.end_section()
self.end_section()
except DefaultError as e:
arg_parser.error(
u'[{section_name}] config option "{option_string}" '
u'must be {type_transformer}() value, got: {value}'.format(
section_name=e.section_name,
option_string=e.option_string,
type_transformer=e.type_transformer.__name__,
value=e.value
))
class GenerateConfig(ArgParserWalker):
def __init__(self, parsed_args, section, only_non_defaults=False):
self.parsed_args = parsed_args
self._contents = []
self._only_non_defaults = only_non_defaults
self._section = section
self._in_sections = []
def start_section(self, section_name):
self._in_sections.append(section_name)
if section_name == self._section:
if self._contents:
self._contents.append(u'')
self._contents.append(u'[{0}]'.format(section_name))
def end_section(self):
self._in_sections.pop()
@property
def contents(self):
return u'\n'.join(self._contents + [u''])
def process_parser_action(self, action, is_store_const=False):
if self._in_sections[-1] != self._section:
return
# take the longest string, likely the most informative
action_name = list(action.option_strings)
action_name.sort(key=lambda s: len(s), reverse=True)
action_name = _convert_option_string(action_name[0])
action_value = getattr(self.parsed_args, action.dest, None)
if self._only_non_defaults and action_value == action.default:
action_value = None
if action_value is not None:
if is_store_const:
self._contents.append(action_name)
else:
self._contents.append(u'{action_name}: {default_value}'.format(
action_name=action_name,
default_value=action_value, # hope it prints as wanted...
))
class ReadConfig(ArgParserWalker):
def __init__(self, config_parser=None):
self.sections = []
self.config_parser = config_parser
def start_section(self, section_name):
self.sections.append(section_name)
def end_section(self):
self.sections.pop()
@property
def current_section(self):
return self.sections[-1] if self.sections else None
def process_parser_action(self, action, is_store_const=False):
for option_string in action.option_strings:
option_string = _convert_option_string(option_string)
if self.config_parser.has_option(self.current_section,
option_string):
if is_store_const:
action.default = action.const
else:
value = self.config_parser.get(self.current_section,
option_string)
type_transformer = (action.type if action.type is not None
else lambda x: x)
try:
action.default = type_transformer(value)
except:
raise DefaultError(self.current_section,
option_string,
value,
type_transformer)
action.required = False
class DefaultError(Exception):
def __init__(self, section_name, option_string, value, type_transformer):
self.section_name = section_name
self.option_string = option_string
self.value = value
self.type_transformer = type_transformer
def _convert_option_string(op_s):
return op_s.lstrip('-').replace('-', '_')
Loading…
Cancel
Save