imip-agent

Changeset

1216:d2c6bd93269a
2017-02-05 Paul Boddie raw files shortlog changelog graph Replaced the manually-built manifests for scheduling and storage extensions with automatic detection of such modules, removing the tools previously used to define the available modules, and updating the documentation and installation script. This should avoid mutable files that might make packaging difficult and simplify package maintenance.
docs/wiki/Administration (file) imiptools/handlers/scheduling/manifest.py (file) imiptools/imports.py (file) imiptools/stores/manifest.py (file) tools/install.sh (file) tools/update_scheduling_modules.py tools/update_storage_modules.py
     1.1 --- a/docs/wiki/Administration	Tue Jan 31 16:18:55 2017 +0100
     1.2 +++ b/docs/wiki/Administration	Sun Feb 05 22:16:24 2017 +0100
     1.3 @@ -121,34 +121,12 @@
     1.4  in this package by adding files to the `scheduling` directory within the
     1.5  software installation.
     1.6  
     1.7 -After adding modules, a tool must be run to register the new modules:
     1.8 -
     1.9 -{{{
    1.10 -tools/update_scheduling_modules.py
    1.11 -}}}
    1.12 -
    1.13 -It is envisaged that the installation of additional scheduling modules and the
    1.14 -use of this tool will be performed by the packaging system provided by an
    1.15 -operating system distribution. The `tools/install.sh` script runs the above
    1.16 -tool as part of the installation process.
    1.17 -
    1.18  == Adding Storage Modules ==
    1.19  
    1.20  Storage modules reside in the `imiptools.stores` package. Extra modules can be
    1.21 -installed in this package by adding files or directories to the `stores`
    1.22 +installed in this package by adding files or directories to the `stores` 
    1.23  directory within the software installation.
    1.24  
    1.25 -After adding modules, a tool must be run to register the new modules:
    1.26 -
    1.27 -{{{
    1.28 -tools/update_storage_modules.py
    1.29 -}}}
    1.30 -
    1.31 -It is envisaged that the installation of additional storage modules and the
    1.32 -use of this tool will be performed by the packaging system provided by an
    1.33 -operating system distribution. The `tools/install.sh` script runs the above
    1.34 -tool as part of the installation process.
    1.35 -
    1.36  == Copying Stores and Changing Store Types ==
    1.37  
    1.38  A rudimentary tool is provided that can copy data between stores, even those of
     2.1 --- a/imiptools/handlers/scheduling/manifest.py	Tue Jan 31 16:18:55 2017 +0100
     2.2 +++ b/imiptools/handlers/scheduling/manifest.py	Sun Feb 05 22:16:24 2017 +0100
     2.3 @@ -1,45 +1,52 @@
     2.4 +#!/usr/bin/env python
     2.5 +
     2.6 +"""
     2.7 +Scheduling functions manifest.
     2.8 +
     2.9 +Copyright (C) 2017 Paul Boddie <paul@boddie.org.uk>
    2.10 +
    2.11 +This program is free software; you can redistribute it and/or modify it under
    2.12 +the terms of the GNU General Public License as published by the Free Software
    2.13 +Foundation; either version 3 of the License, or (at your option) any later
    2.14 +version.
    2.15 +
    2.16 +This program is distributed in the hope that it will be useful, but WITHOUT
    2.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    2.18 +FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    2.19 +details.
    2.20 +
    2.21 +You should have received a copy of the GNU General Public License along with
    2.22 +this program.  If not, see <http://www.gnu.org/licenses/>.
    2.23 +"""
    2.24 +
    2.25 +from imiptools.imports import get_extensions
    2.26 +from os.path import split
    2.27 +
    2.28 +reserved = ["__init__", "common", "manifest"]
    2.29 +
    2.30 +# Obtain details of this module's package.
    2.31 +
    2.32 +dirname = split(__file__)[0]
    2.33 +package = __name__.rsplit(".", 1)[0]
    2.34 +
    2.35 +# Define an attribute mapping names to modules.
    2.36 +
    2.37 +modules = {}
    2.38 +get_extensions(dirname, package, modules, reserved)
    2.39 +
    2.40 +# Define attributes mapping names to functions.
    2.41 +
    2.42  confirmation_functions = {}
    2.43  locking_functions = {}
    2.44  retraction_functions = {}
    2.45  scheduling_functions = {}
    2.46  unlocking_functions = {}
    2.47  
    2.48 -from imiptools.handlers.scheduling.access import (
    2.49 -    confirmation_functions as c,
    2.50 -    locking_functions as l,
    2.51 -    retraction_functions as r,
    2.52 -    scheduling_functions as s,
    2.53 -    unlocking_functions as u)
    2.54 -
    2.55 -confirmation_functions.update(c)
    2.56 -locking_functions.update(l)
    2.57 -retraction_functions.update(r)
    2.58 -scheduling_functions.update(s)
    2.59 -unlocking_functions.update(u)
    2.60 -
    2.61 -from imiptools.handlers.scheduling.freebusy import (
    2.62 -    confirmation_functions as c,
    2.63 -    locking_functions as l,
    2.64 -    retraction_functions as r,
    2.65 -    scheduling_functions as s,
    2.66 -    unlocking_functions as u)
    2.67 +for module in modules.values():
    2.68 +    confirmation_functions.update(module.confirmation_functions)
    2.69 +    locking_functions.update(module.locking_functions)
    2.70 +    retraction_functions.update(module.retraction_functions)
    2.71 +    scheduling_functions.update(module.scheduling_functions)
    2.72 +    unlocking_functions.update(module.unlocking_functions)
    2.73  
    2.74 -confirmation_functions.update(c)
    2.75 -locking_functions.update(l)
    2.76 -retraction_functions.update(r)
    2.77 -scheduling_functions.update(s)
    2.78 -unlocking_functions.update(u)
    2.79 -
    2.80 -from imiptools.handlers.scheduling.quota import (
    2.81 -    confirmation_functions as c,
    2.82 -    locking_functions as l,
    2.83 -    retraction_functions as r,
    2.84 -    scheduling_functions as s,
    2.85 -    unlocking_functions as u)
    2.86 -
    2.87 -confirmation_functions.update(c)
    2.88 -locking_functions.update(l)
    2.89 -retraction_functions.update(r)
    2.90 -scheduling_functions.update(s)
    2.91 -unlocking_functions.update(u)
    2.92 -
    2.93 +# vim: tabstop=4 expandtab shiftwidth=4
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/imiptools/imports.py	Sun Feb 05 22:16:24 2017 +0100
     3.3 @@ -0,0 +1,47 @@
     3.4 +#!/usr/bin/env python
     3.5 +
     3.6 +"""
     3.7 +Import utilities.
     3.8 +
     3.9 +Copyright (C) 2017 Paul Boddie <paul@boddie.org.uk>
    3.10 +
    3.11 +This program is free software; you can redistribute it and/or modify it under
    3.12 +the terms of the GNU General Public License as published by the Free Software
    3.13 +Foundation; either version 3 of the License, or (at your option) any later
    3.14 +version.
    3.15 +
    3.16 +This program is distributed in the hope that it will be useful, but WITHOUT
    3.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    3.18 +FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    3.19 +details.
    3.20 +
    3.21 +You should have received a copy of the GNU General Public License along with
    3.22 +this program.  If not, see <http://www.gnu.org/licenses/>.
    3.23 +"""
    3.24 +
    3.25 +from os.path import isdir, join, splitext
    3.26 +from os import listdir
    3.27 +from importlib import import_module
    3.28 +
    3.29 +def get_extensions(dirname, modname, stores, reserved):
    3.30 +
    3.31 +    "Import extensions inside 'dirname'."
    3.32 +
    3.33 +    for filename in listdir(dirname):
    3.34 +        pathname = join(dirname, filename)
    3.35 +
    3.36 +        # Descend into directories.
    3.37 +
    3.38 +        if isdir(pathname):
    3.39 +            get_extensions(pathname, "%s.%s" % (modname, filename),
    3.40 +                           stores, reserved)
    3.41 +            continue
    3.42 +
    3.43 +        # Identify modules and import them.
    3.44 +
    3.45 +        leafname, ext = splitext(filename)
    3.46 +
    3.47 +        if ext == ".py" and leafname not in reserved:
    3.48 +            stores[leafname] = import_module("%s.%s" % (modname, leafname))
    3.49 +
    3.50 +# vim: tabstop=4 expandtab shiftwidth=4
     4.1 --- a/imiptools/stores/manifest.py	Tue Jan 31 16:18:55 2017 +0100
     4.2 +++ b/imiptools/stores/manifest.py	Sun Feb 05 22:16:24 2017 +0100
     4.3 @@ -1,8 +1,37 @@
     4.4 -stores = {}
     4.5 +#!/usr/bin/env python
     4.6 +
     4.7 +"""
     4.8 +Store manifest.
     4.9 +
    4.10 +Copyright (C) 2017 Paul Boddie <paul@boddie.org.uk>
    4.11 +
    4.12 +This program is free software; you can redistribute it and/or modify it under
    4.13 +the terms of the GNU General Public License as published by the Free Software
    4.14 +Foundation; either version 3 of the License, or (at your option) any later
    4.15 +version.
    4.16 +
    4.17 +This program is distributed in the hope that it will be useful, but WITHOUT
    4.18 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    4.19 +FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    4.20 +details.
    4.21  
    4.22 -from imiptools.stores import file
    4.23 -stores['file'] = file
    4.24 +You should have received a copy of the GNU General Public License along with
    4.25 +this program.  If not, see <http://www.gnu.org/licenses/>.
    4.26 +"""
    4.27 +
    4.28 +from imiptools.imports import get_extensions
    4.29 +from os.path import split
    4.30 +
    4.31 +reserved = ["__init__", "common", "manifest"]
    4.32  
    4.33 -from imiptools.stores.database import postgresql
    4.34 -stores['postgresql'] = postgresql
    4.35 +# Obtain details of this module's package.
    4.36 +
    4.37 +dirname = split(__file__)[0]
    4.38 +package = __name__.rsplit(".", 1)[0]
    4.39  
    4.40 +# Define an attribute mapping names to modules.
    4.41 +
    4.42 +stores = {}
    4.43 +get_extensions(dirname, package, stores, reserved)
    4.44 +
    4.45 +# vim: tabstop=4 expandtab shiftwidth=4
     5.1 --- a/tools/install.sh	Tue Jan 31 16:18:55 2017 +0100
     5.2 +++ b/tools/install.sh	Sun Feb 05 22:16:24 2017 +0100
     5.3 @@ -44,6 +44,8 @@
     5.4  cp $AGENTS "$INSTALL_DIR"
     5.5  cp $MODULES "$INSTALL_DIR"
     5.6  
     5.7 +# Package modules.
     5.8 +
     5.9  for DIR in "$INSTALL_DIR/imiptools" \
    5.10             "$INSTALL_DIR/imiptools/stores" \
    5.11             "$INSTALL_DIR/imiptools/stores/database" \
    5.12 @@ -54,7 +56,8 @@
    5.13      fi
    5.14  done
    5.15  
    5.16 -# Remove any symbolic link to the config module.
    5.17 +# Remove any symbolic link to the config module. This linking is no longer
    5.18 +# supported, anyway.
    5.19  
    5.20  if [ -h "$INSTALL_DIR/imiptools/config.py" ]; then
    5.21      rm "$INSTALL_DIR/imiptools/config.py"
    5.22 @@ -138,8 +141,9 @@
    5.23  # Tools
    5.24  
    5.25  TOOLS="copy_store.py fix.sh init.sh init_user.sh make_freebusy.py set_delegates.py "\
    5.26 -"set_quota_groups.py set_quota_limits.py update_quotas.py update_scheduling_modules.py "\
    5.27 -"update_storage_modules.py"
    5.28 +"set_quota_groups.py set_quota_limits.py update_quotas.py"
    5.29 +
    5.30 +OLD_TOOLS="update_scheduling_modules.py update_storage_modules.py"
    5.31  
    5.32  if [ ! -e "$INSTALL_DIR/tools" ]; then
    5.33      mkdir -p "$INSTALL_DIR/tools"
    5.34 @@ -149,6 +153,12 @@
    5.35      cp "tools/$TOOL" "$INSTALL_DIR/tools/"
    5.36  done
    5.37  
    5.38 +for TOOL in $OLD_TOOLS; do
    5.39 +    if [ -e "$INSTALL_DIR/tools/$TOOL" ]; then
    5.40 +        rm "$INSTALL_DIR/tools/$TOOL"
    5.41 +    fi
    5.42 +done
    5.43 +
    5.44  # Web manager interface.
    5.45  
    5.46  if [ ! -e "$WEB_INSTALL_DIR" ]; then
    5.47 @@ -183,11 +193,3 @@
    5.48          done
    5.49      fi
    5.50  fi
    5.51 -
    5.52 -# Run the scheduling module update tool to regenerate the manifest module.
    5.53 -
    5.54 -PYTHONPATH="$INSTALL_DIR" "$INSTALL_DIR/tools/update_scheduling_modules.py"
    5.55 -
    5.56 -# Run the storage module update tool to regenerate the manifest module.
    5.57 -
    5.58 -PYTHONPATH="$INSTALL_DIR" "$INSTALL_DIR/tools/update_storage_modules.py"
     6.1 --- a/tools/update_scheduling_modules.py	Tue Jan 31 16:18:55 2017 +0100
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,80 +0,0 @@
     6.4 -#!/usr/bin/env python
     6.5 -
     6.6 -"""
     6.7 -Update the scheduling modules import manifest.
     6.8 -
     6.9 -Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
    6.10 -
    6.11 -This program is free software; you can redistribute it and/or modify it under
    6.12 -the terms of the GNU General Public License as published by the Free Software
    6.13 -Foundation; either version 3 of the License, or (at your option) any later
    6.14 -version.
    6.15 -
    6.16 -This program is distributed in the hope that it will be useful, but WITHOUT
    6.17 -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    6.18 -FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    6.19 -details.
    6.20 -
    6.21 -You should have received a copy of the GNU General Public License along with
    6.22 -this program.  If not, see <http://www.gnu.org/licenses/>.
    6.23 -"""
    6.24 -
    6.25 -from glob import glob
    6.26 -from os.path import join, split, splitext
    6.27 -import imp
    6.28 -
    6.29 -reserved = ["__init__.py", "common.py", "manifest.py"]
    6.30 -
    6.31 -# The main program generating a new version of the manifest module.
    6.32 -
    6.33 -if __name__ == "__main__":
    6.34 -    _f, dirname, _d = imp.find_module("imiptools/handlers")
    6.35 -    dirname = join(dirname, "scheduling")
    6.36 -
    6.37 -    # Get all Python files in the scheduling directory, filtering out the
    6.38 -    # reserved files that do not provide scheduling functions.
    6.39 -
    6.40 -    filenames = []
    6.41 -    found = glob(join(dirname, "*.py"))
    6.42 -    found.sort()
    6.43 -
    6.44 -    for filename in found:
    6.45 -        filename = split(filename)[-1]
    6.46 -        if filename not in reserved:
    6.47 -            filenames.append(filename)
    6.48 -
    6.49 -    # Open the manifest module and write code to import and combine the
    6.50 -    # functions from each module.
    6.51 -
    6.52 -    f = open(join(dirname, "manifest.py"), "w")
    6.53 -    try:
    6.54 -        print >>f, """\
    6.55 -confirmation_functions = {}
    6.56 -locking_functions = {}
    6.57 -retraction_functions = {}
    6.58 -scheduling_functions = {}
    6.59 -unlocking_functions = {}
    6.60 -"""
    6.61 -
    6.62 -        for filename in filenames:
    6.63 -            module = splitext(filename)[0]
    6.64 -
    6.65 -            print >>f, """\
    6.66 -from imiptools.handlers.scheduling.%s import (
    6.67 -    confirmation_functions as c,
    6.68 -    locking_functions as l,
    6.69 -    retraction_functions as r,
    6.70 -    scheduling_functions as s,
    6.71 -    unlocking_functions as u)
    6.72 -
    6.73 -confirmation_functions.update(c)
    6.74 -locking_functions.update(l)
    6.75 -retraction_functions.update(r)
    6.76 -scheduling_functions.update(s)
    6.77 -unlocking_functions.update(u)
    6.78 -""" % module
    6.79 -
    6.80 -    finally:
    6.81 -        f.close()
    6.82 -
    6.83 -# vim: tabstop=4 expandtab shiftwidth=4
     7.1 --- a/tools/update_storage_modules.py	Tue Jan 31 16:18:55 2017 +0100
     7.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.3 @@ -1,94 +0,0 @@
     7.4 -#!/usr/bin/env python
     7.5 -
     7.6 -"""
     7.7 -Update the storage modules import manifest.
     7.8 -
     7.9 -Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
    7.10 -
    7.11 -This program is free software; you can redistribute it and/or modify it under
    7.12 -the terms of the GNU General Public License as published by the Free Software
    7.13 -Foundation; either version 3 of the License, or (at your option) any later
    7.14 -version.
    7.15 -
    7.16 -This program is distributed in the hope that it will be useful, but WITHOUT
    7.17 -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    7.18 -FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    7.19 -details.
    7.20 -
    7.21 -You should have received a copy of the GNU General Public License along with
    7.22 -this program.  If not, see <http://www.gnu.org/licenses/>.
    7.23 -"""
    7.24 -
    7.25 -from glob import glob
    7.26 -from os import listdir
    7.27 -from os.path import commonprefix, isdir, join, split, splitext
    7.28 -import imp
    7.29 -
    7.30 -reserved = ["__init__.py", "common.py", "manifest.py"]
    7.31 -
    7.32 -def get_extensions(dirname):
    7.33 -    filenames = []
    7.34 -    found = glob(join(dirname, "*.py"))
    7.35 -    found.sort()
    7.36 -
    7.37 -    for filename in found:
    7.38 -        leafname = split(filename)[-1]
    7.39 -        if leafname not in reserved:
    7.40 -            filenames.append(filename)
    7.41 -
    7.42 -    return filenames
    7.43 -
    7.44 -# The main program generating a new version of the manifest module.
    7.45 -
    7.46 -if __name__ == "__main__":
    7.47 -    _f, dirname, _d = imp.find_module("imiptools/stores")
    7.48 -    dirname = join(dirname, "")
    7.49 -    manifest = join(dirname, "manifest.py")
    7.50 -
    7.51 -    # Get all Python files in the stores directory, filtering out the
    7.52 -    # reserved files that do not provide storage functions.
    7.53 -
    7.54 -    filenames = get_extensions(dirname)
    7.55 -
    7.56 -    # Get all extensions from directories in the stores directory.
    7.57 -
    7.58 -    found = listdir(dirname)
    7.59 -    found.sort()
    7.60 -
    7.61 -    for filename in found:
    7.62 -        filename = join(dirname, filename)
    7.63 -        if isdir(filename):
    7.64 -            filenames += get_extensions(filename)
    7.65 -
    7.66 -    # Open the manifest module and write code to import and combine the
    7.67 -    # functions from each module.
    7.68 -
    7.69 -    f = open(manifest, "w")
    7.70 -    try:
    7.71 -        print >>f, """\
    7.72 -stores = {}
    7.73 -"""
    7.74 -
    7.75 -        for filename in filenames:
    7.76 -            relative = filename[len(commonprefix([filename, dirname])):]
    7.77 -
    7.78 -            # NOTE: Converting POSIX paths to module paths.
    7.79 -
    7.80 -            module = splitext(relative)[0].replace("/", ".")
    7.81 -            module_parts = module.rsplit(".", 1)
    7.82 -
    7.83 -            # Get subpackage location and module.
    7.84 -
    7.85 -            module_parents = len(module_parts) > 1 and module_parts[0]
    7.86 -            module_name = module_parts[-1]
    7.87 -
    7.88 -            print >>f, """\
    7.89 -from imiptools.stores%s import %s
    7.90 -stores[%r] = %s
    7.91 -""" % (module_parents and ".%s" % module_parents or "",
    7.92 -       module_name, module_name, module_name)
    7.93 -
    7.94 -    finally:
    7.95 -        f.close()
    7.96 -
    7.97 -# vim: tabstop=4 expandtab shiftwidth=4