Skip to content
This repository was archived by the owner on Aug 20, 2021. It is now read-only.

Commit

Permalink
Merge pull request #269 from jesseward/x84-241-child-config-directory
Browse files Browse the repository at this point in the history
Implement child config directory in [system] option scriptpath
  • Loading branch information
jquast committed Apr 13, 2015
2 parents fff7bf4 + 9f068dc commit e1ff384
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 32 deletions.
3 changes: 3 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -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
Expand Down
8 changes: 7 additions & 1 deletion docs/default_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 2 additions & 1 deletion docs/web.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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. ::

Expand Down
66 changes: 40 additions & 26 deletions x84/bbs/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand All @@ -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
Expand Down Expand Up @@ -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)

Expand Down
4 changes: 2 additions & 2 deletions x84/webmodules/static.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
5 changes: 3 additions & 2 deletions x84/webserve.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down

2 comments on commit e1ff384

@nolageek
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error when using child config directory.

Mon-04-13 05:35PM ERROR session.py:386 anonymous[telnet-98.231.143.159:55473] File "/home/x84/x84/local/lib/python2.7/site-packages/x84/bbs/session.py", line 296, in script_module
Mon-04-13 05:35PM ERROR session.py:386 anonymous[telnet-98.231.143.159:55473] lookup = imp.find_module('init', [directory])
Mon-04-13 05:35PM ERROR session.py:386 anonymous[telnet-98.231.143.159:55473]
Mon-04-13 05:35PM ERROR session.py:386 anonymous[telnet-98.231.143.159:55473] ImportError: No module named init
Mon-04-13 05:35PM ERROR session.py:339 anonymous[telnet-98.231.143.159:55473] stop after general exception in matrix

/.x84/default.ini contains:

scriptpath = /home/x84/x84/local/lib/python2.7/site-packages/x84/district,/home/x84/x84/local/lib/python2.7/site-packages/x84/default

/.../district just has top.py and main.py for now.

@jquast
Copy link
Owner Author

@jquast jquast commented on e1ff384 Apr 13, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make an empty file named __init__.py

When a python module is declared as a folder, such file is required to recognize it as a "module". https://docs.python.org/2/tutorial/modules.html#packages

The init.py files are required to make Python treat the directories as containing packages; this is done to prevent directories with a common name, such as string, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, init.py can just be an empty file, but it can also execute initialization code for the package or set the all variable, described later.

Please sign in to comment.