Comment 1 for bug 1359931

Revision history for this message
Eric Snow (ericsnowcurrently) wrote : Re: Provide reviewboard-specific interfaces.

I imagine that the hook code would be something like this:

INJECTED_WARNING = """
#------------------------------------------------------------------------------
# The following is the import code for the settings directory injected by Juju
#------------------------------------------------------------------------------
"""

PKG = '_juju_extensions_settings'
PKG_DIR = os.path.join(os.path.dirname(path_to_rb_settings_py), PKG)

def open_settings(extname):
    filename = os.path.join(PKG_DIR, extname + '_settings.py')
    try:
        return open(filename, 'r+')
    except IOError:
        if os.path.exists(filename):
            raise

    if not os.path.exists(PKG_DIR):
        os.mkdir(PKG_DIR)
        with open(path_to_rb_settings_py, 'a') as settings_py:
            settings_py.write(INJECTED_WARNING)
            settings_py.write("from {} import *".format(PKG))
    extfile = open(filename, 'w+')

    with open(os.path.join(PKG_DIR, '__init__.py'), 'a') as initfile:
        initfile.write('from .{} import *\n'.format(extname))

    return extfile

def set_settings(extname, settings):
    # inspired by what the django charm does.

    lines = []
    for name, value in settings.items():
        line = '{} = {!r}\n'.format(name, value)
        try:
            ast.literal_eval(line)
        except SyntaxError:
            hookenv.log('bad setting: {!r}'.format(line))
            return # fail?
        lines.append(line)

    with open_settings(extname) as extfile:
        extfile.writelines(lines)
        extfile.truncate()

    # Force RB to reload settings.py.i
    touch(path_to_rb_settings_py)

def clear_settings(extname=None):
    if extname is not None:
        filename = os.path.join(PKG_DIR, extname + '_settings.py')
        if os.path.exists(filename):
            os.remove(filename)
            extline = 'from .{} import *\n'.format(extname)
            with open(os.path.join(PKG_DIR, '__init__.py'), 'r+') as initfile:
                last = 0
                for line in initfile:
                    if line == extline:
                        break
                    last += len(line)
                lines = []
                for line in initfile:
                    lines.append(line)
                initfile.seek(last)
                initfile.writelines(lines)
                initfile.truncate()
    else:
        if os.path.exists(PKG_DIR):
            os.rmdir(PKG_DIR)
            # remove import from path_to_rb_settings_py?

def related_name():
    """Return the name of the extension in the current relation."""
    # We just use the service name.
    unit = hookenv.related_units()[0]
    service = unit.partition('/')[0]
    return service

def _handle_relation_settings():
    requested = hookenv.relation_get('settings')
    if not requested:
        # no settings to add
        return

    name = related_name()
    settings = hookenv.relation_get('_all_settings') or {}
    settings.update(requested)
    try:
        set_settings(name, settings)
    except Exception as e:
        hookenv.log("could not update reviewboard settings: {}".format(e))

# hooks

@hooks.hook('reviewboard-extensions-relation-joined')
def reviewboard_extensions_relation_joined():
    # Force reviewboard to reload, thus recognizing the new extension.
    touch(path_to_rb_settings_py)

@hooks.hook('reviewboard-extensions-relation-changed')
def reviewboard_extensions_relation_changed():
    _handle_relation_settings()

@hooks.hook('reviewboard-extensions-relation-departed')
def reviewboard_extensions_relation_departed():
    clear_settings(related_name())

@hooks.hook('reviewboard-extensions-relation-broken')
def reviewboard_extensions_relation_broken():
    clear_settings(related_name())

@hooks.hook('stop')
def stop():
    ...
    clear_settings()