Spack can be extended with external commands (#8612)

This provides a mechanism to implement a new Spack command in a
separate directory, and with a small configuration change point Spack
to the new command.

To register the command, the directory must be added to the
"extensions" section of config.yaml. The command directory name must
have the prefix "spack-", and have the following layout:

  spack-X/
    pytest.ini #optional, for testing
    X/
	  cmd/
	    name-of-command1.py
	    name-of-command2.py
	    ...
    tests/ #optional
      conftest.py
	  test_name-of-command1.py
    templates/ #optional jinja templates, if needed

And in config.yaml:

  config:
    extensions:
      - /path/to/spack-X

If the extension includes tests, you can run them via spack by adding
the --extension option, like "spack test --extension=X"
This commit is contained in:
Massimiliano Culpo
2019-03-29 00:56:36 +01:00
committed by Peter Scheibel
parent b2b91a1f00
commit 0a006351c8
8 changed files with 225 additions and 19 deletions

View File

@@ -12,6 +12,8 @@
import inspect
from datetime import datetime, timedelta
from six import string_types
import sys
# Ignore emacs backups when listing modules
ignore_modules = [r'^\.#', '~$']
@@ -597,3 +599,33 @@ def __str__(self):
def __repr__(self):
return repr(self.ref_function())
def load_module_from_file(module_name, module_path):
"""Loads a python module from the path of the corresponding file.
Args:
module_name (str): namespace where the python module will be loaded,
e.g. ``foo.bar``
module_path (str): path of the python file containing the module
Returns:
A valid module object
Raises:
ImportError: when the module can't be loaded
FileNotFoundError: when module_path doesn't exist
"""
if sys.version_info[0] == 3 and sys.version_info[1] >= 5:
import importlib.util
spec = importlib.util.spec_from_file_location(module_name, module_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
elif sys.version_info[0] == 3 and sys.version_info[1] < 5:
import importlib.machinery
loader = importlib.machinery.SourceFileLoader(module_name, module_path)
module = loader.load_module()
elif sys.version_info[0] == 2:
import imp
module = imp.load_source(module_name, module_path)
return module