Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Start using the new plugin infrastructure
  • Loading branch information
dwhswenson committed May 14, 2020
commit 45ed025fb1bf13c4b93f8264f1beec7e7e75a8ef
65 changes: 16 additions & 49 deletions paths_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
import logging
import logging.config
import os
import pathlib

import click
# import click_completion
# click_completion.init()

from .plugin_management import FilePluginLoader, NamespacePluginLoader

CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])

_POSSIBLE_PLUGIN_FOLDERS = [
Expand All @@ -21,24 +24,27 @@
'cli-plugins'),
]

OPSPlugin = collections.namedtuple("OPSPlugin",
['name', 'filename', 'func', 'section'])


class OpenPathSamplingCLI(click.MultiCommand):
"""Main class for the command line interface

Most of the logic here is about handling the plugin infrastructure.
"""
def __init__(self, *args, **kwargs):
# the logic here is all about loading the plugins
self.plugin_folders = []
for folder in _POSSIBLE_PLUGIN_FOLDERS:
if folder not in self.plugin_folders and os.path.exists(folder):
self.plugin_folders.append(folder)
commands = str(pathlib.Path(__file__).parent.resolve() / 'commands')
def app_dir_plugins(posix):
return str(pathlib.Path(
click.get_app_dir("OpenPathSampling", force_posix=posix)
).resolve() / 'cli-plugins')

plugin_files = self._list_plugin_files(self.plugin_folders)
plugins = self._load_plugin_files(plugin_files)
self.plugin_loaders = [
FilePluginLoader(commands),
FilePluginLoader(app_dir_plugins(posix=False)),
FilePluginLoader(app_dir_plugins(posix=True)),
NamespacePluginLoader('paths_cli.plugins')
]

plugins = sum([loader() for loader in self.plugin_loaders], [])

self._get_command = {}
self._sections = collections.defaultdict(list)
Expand All @@ -62,45 +68,6 @@ def _deregister_plugin(self, plugin):
def plugin_for_command(self, command_name):
return {p.name: p for p in self.plugins}[command_name]

@staticmethod
def _list_plugin_files(plugin_folders):
def is_plugin(filename):
return (
filename.endswith(".py") and not filename.startswith("_")
and not filename.startswith(".")
)

plugin_files = []
for folder in plugin_folders:
files = [os.path.join(folder, f) for f in os.listdir(folder)
if is_plugin(f)]
plugin_files += files
return plugin_files

@staticmethod
def _filename_to_command_name(filename):
command_name = filename[:-3] # get rid of .py
command_name = command_name.replace('_', '-') # commands use -
return command_name

@staticmethod
def _load_plugin(name):
ns = {}
with open(name) as f:
code = compile(f.read(), name, 'exec')
eval(code, ns, ns)
return ns['CLI'], ns['SECTION']

def _load_plugin_files(self, plugin_files):
plugins = []
for full_name in plugin_files:
_, filename = os.path.split(full_name)
command_name = self._filename_to_command_name(filename)
func, section = self._load_plugin(full_name)
plugins.append(OPSPlugin(name=command_name, filename=full_name,
func=func, section=section))
return plugins

def list_commands(self, ctx):
return list(self._get_command.keys())

Expand Down
4 changes: 4 additions & 0 deletions paths_cli/plugin_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ def is_plugin(filename):
filename.endswith(".py") and not filename.startswith("_")
and not filename.startswith(".")
)

if not os.path.exists(os.path.join(self.search_path)):
return []

candidates = [os.path.join(self.search_path, f)
for f in os.listdir(self.search_path)
if is_plugin(f)]
Expand Down
Empty file added paths_cli/plugins/__init__.py
Empty file.