diff --git a/CHANGES b/CHANGES index 78b31ed0..bd87a91c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +2.0.12 + - enhancement: [system] option scriptpath now supports a comma + separated list of directories in which customizations are stored. 2.0.11 - bugfix: weather.py fix incorrect postal code return from Accu Weather. Changed the default to populate search by city/state instead of diff --git a/docs/default_api.rst b/docs/default_api.rst index 35d7bfe4..36aae20a 100644 --- a/docs/default_api.rst +++ b/docs/default_api.rst @@ -2,7 +2,13 @@ Customizing your board ====================== -The ``default.ini`` file option, *scriptpath*, of section *[system]*, defines folder ``'default/'``, containing the scripts documented in this section. +The ``default.ini`` file option, *scriptpath*, of section *[system]*, defines folder ``'default/'``, containing the scripts documented in this section. *scriptpath* accepts a comma delimited list of directories in which to store your customizations. Noting that the left most entry is of the highest preference. + +For example. + + scriptpath = /opt/bbs/scripts,/usr/local/src/x84/x84/default + +x84 searches for scripts in ``/opt/bbs/scripts`` first and then ``/usr/local/src/x84/x84/default``. This allows you to keep any customizations outside of the main source tree and then fall back to x84 defaults if they're not present in your customizations directory. Additional scripts can be found at https://github.com/x84-extras diff --git a/docs/web.rst b/docs/web.rst index fbda161b..451deebf 100644 --- a/docs/web.rst +++ b/docs/web.rst @@ -51,7 +51,8 @@ Serving static files One of x/84's internal web modules is called ``static``. If you enable this module, x/84 will serve static file content from the ``www-static`` subdirectory -of your system's script path. If you wish to set the document root to some other +of your system's top-level ``scriptpath``. The top-level refers to the first +item in this array. If you wish to set the document root to some other location, use the ``document_root`` option in the ``[web]`` section of your configuration file. :: diff --git a/x84/bbs/session.py b/x84/bbs/session.py index e8395592..0de6488d 100644 --- a/x84/bbs/session.py +++ b/x84/bbs/session.py @@ -75,7 +75,7 @@ class Session(object): _decoder = None _activity = None _user = None - _script_module = None + _script_module = [] def __init__(self, terminal, sid, env, child_pipes, kind, addrport, matrix_args, matrix_kwargs): @@ -253,13 +253,19 @@ def show_traceback(self): @property def script_path(self): - """ Base filepath folder for all scripts. """ - val = get_ini('system', 'scriptpath') - # ensure folder exists - assert os.path.isdir(val), ( - 'configuration section [system], value scriptpath: ' - 'not a folder: {!r}'.format(val)) - return val + """ + Base filepath folder for all scripts. + + :rtype: list + """ + scriptpath_dirs = get_ini('system', 'scriptpath', split=True) + + # ensure all specified folders exist + for directory in scriptpath_dirs: + assert os.path.isdir(directory), ( + 'configuration section [system], value scriptpath: ' + 'not a folder: {!r}'.format(directory)) + return scriptpath_dirs @property def current_script(self): @@ -271,19 +277,26 @@ def current_script(self): @property def script_module(self): - """ Base python module instance for userland scripts. """ - if self._script_module is None: - # load default/__init__.py as 'default', - folder_name = os.path.basename(self.script_path) - - # put it in sys.path for relative imports - if self.script_path not in sys.path: - sys.path.insert(0, self.script_path) - - # discover import path to __init__.py, store result - lookup = imp.find_module('__init__', [self.script_path]) - self._script_module = imp.load_module(folder_name, *lookup) - self._script_module.__path__ = self.script_path + """ + Base python module instance for userland scripts. + + :rtype: list + """ + if not self._script_module: + + for directory in self.script_path: + # load default/__init__.py as 'default', + folder_name = os.path.basename(directory) + + # put it in sys.path for relative imports + if directory not in sys.path: + sys.path.insert(0, directory) + + # discover import path to __init__.py, store result + lookup = imp.find_module('__init__', [directory]) + scr_module = imp.load_module(folder_name, *lookup) + scr_module.__path__ = directory + self._script_module.append(scr_module) return self._script_module @property @@ -657,16 +670,17 @@ def runscript(self, script): # if given a script name such as 'extras.target', adjust the lookup # path to be extended by {default_scriptdir}/extras, and adjust # script_name to be just 'target'. - script_relpath = self.script_module.__path__ - lookup_paths = [script_relpath] + script_relpath = [ directory.__path__ for directory in self.script_module ] + lookup_paths = script_relpath[:] + if '.' not in script.name: script_name = script.name else: # build another system path, relative to `script_module' remaining, script_name = script.name.rsplit('.', 1) - _lookup_path = os.path.join(script_relpath, *remaining.split('.')) - lookup_paths.append(_lookup_path) - + for dir_relpath in script_relpath: + _lookup_path = os.path.join(dir_relpath, *remaining.split('.')) + lookup_paths.append(_lookup_path) lookup = imp.find_module(script_name, lookup_paths) module = imp.load_module(script_name, *lookup) diff --git a/x84/webmodules/static.py b/x84/webmodules/static.py index 32b463a2..82188a61 100644 --- a/x84/webmodules/static.py +++ b/x84/webmodules/static.py @@ -44,8 +44,8 @@ def web_module(): # determine document root for web server static_root = (get_ini('web', 'document_root') - or os.path.join(get_ini('system', 'scriptpath'), - 'www-static')) + or os.path.join(get_ini('system', 'scriptpath', + split=True)[0], 'www-static')) StaticApp.static_root = static_root return { diff --git a/x84/webserve.py b/x84/webserve.py index c58b7589..3463f8bd 100755 --- a/x84/webserve.py +++ b/x84/webserve.py @@ -191,10 +191,11 @@ def main(background_daemon=True): log = logging.getLogger(__name__) - SCRIPT_PATH = get_ini(section='system', key='scriptpath') + SCRIPT_PATH = get_ini(section='system', key='scriptpath', split=True) # ensure the SCRIPT_PATH is in os environment PATH for module lookup. - sys.path.insert(0, os.path.expanduser(SCRIPT_PATH)) + for directory in SCRIPT_PATH: + sys.path.insert(0, os.path.expanduser(directory)) web_modules = get_ini(section='web', key='modules', split=True)