ansilbe-doc list collections plugins (#67928)
Now -l and -F will list plugins from discover-able collections
This commit is contained in:
parent
1570098e86
commit
0f5a63f1b9
3 changed files with 86 additions and 3 deletions
|
@ -26,7 +26,7 @@ from ansible.parsing.metadata import extract_metadata
|
|||
from ansible.parsing.plugin_docs import read_docstub
|
||||
from ansible.parsing.yaml.dumper import AnsibleDumper
|
||||
from ansible.plugins.loader import action_loader, fragment_loader
|
||||
from ansible.utils.collection_loader import set_collection_playbook_paths
|
||||
from ansible.utils.collection_loader import set_collection_playbook_paths, list_collection_dirs, get_collection_name_from_path
|
||||
from ansible.utils.display import Display
|
||||
from ansible.utils.plugin_docs import BLACKLIST, get_docstring, get_versioned_doclink
|
||||
display = Display()
|
||||
|
@ -36,6 +36,17 @@ def jdump(text):
|
|||
display.display(json.dumps(text, sort_keys=True, indent=4))
|
||||
|
||||
|
||||
def add_collection_plugins(plugin_list, plugin_type):
|
||||
|
||||
colldirs = list_collection_dirs()
|
||||
for ns in colldirs.keys():
|
||||
for path in colldirs[ns]:
|
||||
|
||||
collname = get_collection_name_from_path(path)
|
||||
ptype = C.COLLECTION_PTYPE_COMPAT.get(plugin_type, plugin_type)
|
||||
plugin_list.update(DocCLI.find_plugins(os.path.join(path, 'plugins', ptype), plugin_type, collname))
|
||||
|
||||
|
||||
class RemovedPlugin(Exception):
|
||||
pass
|
||||
|
||||
|
@ -125,6 +136,8 @@ class DocCLI(CLI):
|
|||
for path in paths:
|
||||
self.plugin_list.update(DocCLI.find_plugins(path, plugin_type))
|
||||
|
||||
add_collection_plugins(self.plugin_list, plugin_type)
|
||||
|
||||
plugins = self._get_plugin_list_filenames(loader)
|
||||
if do_json:
|
||||
jdump(plugins)
|
||||
|
@ -146,6 +159,8 @@ class DocCLI(CLI):
|
|||
for path in paths:
|
||||
self.plugin_list.update(DocCLI.find_plugins(path, plugin_type))
|
||||
|
||||
add_collection_plugins(self.plugin_list, plugin_type)
|
||||
|
||||
descs = self._get_plugin_list_descriptions(loader)
|
||||
if do_json:
|
||||
jdump(descs)
|
||||
|
@ -349,7 +364,7 @@ class DocCLI(CLI):
|
|||
return text
|
||||
|
||||
@staticmethod
|
||||
def find_plugins(path, ptype):
|
||||
def find_plugins(path, ptype, collection=None):
|
||||
|
||||
display.vvvv("Searching %s for plugins" % path)
|
||||
|
||||
|
@ -386,6 +401,10 @@ class DocCLI(CLI):
|
|||
plugin = plugin.lstrip('_') # remove underscore from deprecated plugins
|
||||
|
||||
if plugin not in BLACKLIST.get(bkey, ()):
|
||||
|
||||
if collection:
|
||||
plugin = '%s.%s' % (collection, plugin)
|
||||
|
||||
plugin_list.add(plugin)
|
||||
display.vvvv("Added %s" % plugin)
|
||||
|
||||
|
|
|
@ -97,6 +97,7 @@ BECOME_METHODS = _DeprecatedSequenceConstant(
|
|||
# CONSTANTS ### yes, actual ones
|
||||
BLACKLIST_EXTS = ('.pyc', '.pyo', '.swp', '.bak', '~', '.rpm', '.md', '.txt', '.rst')
|
||||
BOOL_TRUE = BOOLEANS_TRUE
|
||||
COLLECTION_PTYPE_COMPAT = {'module': 'modules'}
|
||||
DEFAULT_BECOME_PASS = None
|
||||
DEFAULT_PASSWORD_CHARS = to_text(ascii_letters + digits + ".,:-_", errors='strict') # characters included in auto-generated passwords
|
||||
DEFAULT_REMOTE_PASS = None
|
||||
|
|
|
@ -6,17 +6,21 @@ __metaclass__ = type
|
|||
|
||||
import os
|
||||
import os.path
|
||||
import pkgutil
|
||||
import re
|
||||
import sys
|
||||
|
||||
from types import ModuleType
|
||||
from collections import defaultdict
|
||||
|
||||
from ansible import constants as C
|
||||
from ansible.utils.display import Display
|
||||
from ansible.module_utils._text import to_bytes, to_native, to_text
|
||||
from ansible.module_utils.compat.importlib import import_module
|
||||
from ansible.module_utils.six import iteritems, string_types, with_metaclass
|
||||
from ansible.utils.singleton import Singleton
|
||||
|
||||
display = Display()
|
||||
|
||||
_SYNTHETIC_PACKAGES = {
|
||||
# these provide fallback package definitions when there are no on-disk paths
|
||||
'ansible_collections': dict(type='pkg_only', allow_external_subpackages=True),
|
||||
|
@ -28,6 +32,8 @@ _SYNTHETIC_PACKAGES = {
|
|||
'ansible_collections.ansible.builtin.plugins.modules': dict(type='flatmap', flatmap='ansible.modules', graft=True),
|
||||
}
|
||||
|
||||
FLAG_FILES = frozenset(['MANIFEST.json', 'galaxy.yml'])
|
||||
|
||||
|
||||
# FIXME: exception handling/error logging
|
||||
class AnsibleCollectionLoader(with_metaclass(Singleton, object)):
|
||||
|
@ -588,3 +594,60 @@ def get_collection_name_from_path(path):
|
|||
|
||||
def set_collection_playbook_paths(b_playbook_paths):
|
||||
AnsibleCollectionLoader().set_playbook_paths(b_playbook_paths)
|
||||
|
||||
|
||||
def is_collection_path(path):
|
||||
|
||||
if os.path.isdir(path):
|
||||
for flag in FLAG_FILES:
|
||||
if os.path.exists(os.path.join(path, flag)):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def list_valid_collection_paths(search_paths=None, warn=False):
|
||||
|
||||
found_paths = []
|
||||
if search_paths is None:
|
||||
search_paths = C.COLLECTIONS_PATHS
|
||||
|
||||
for path in search_paths:
|
||||
|
||||
if not os.path.exists(path):
|
||||
# warn for missing, but not if default
|
||||
if warn:
|
||||
display.warning("The configured collection path {0} does not exist.".format(path))
|
||||
continue
|
||||
|
||||
if not os.path.isdir(path):
|
||||
if warn:
|
||||
display.warning("The configured collection path {0}, exists, but it is not a directory.".format(path))
|
||||
continue
|
||||
|
||||
found_paths.append(path)
|
||||
|
||||
return found_paths
|
||||
|
||||
|
||||
def list_collection_dirs(search_paths=None, namespace=None):
|
||||
|
||||
collections = defaultdict(list)
|
||||
paths = list_valid_collection_paths(search_paths)
|
||||
for path in paths:
|
||||
|
||||
if os.path.isdir(path):
|
||||
coll_root = os.path.join(path, 'ansible_collections')
|
||||
|
||||
if os.path.exists(coll_root) and os.path.isdir(coll_root):
|
||||
for namespace in os.listdir(coll_root):
|
||||
namespace_dir = os.path.join(coll_root, namespace)
|
||||
|
||||
if os.path.isdir(namespace_dir):
|
||||
for collection in os.listdir(namespace_dir):
|
||||
coll_dir = os.path.join(namespace_dir, collection)
|
||||
|
||||
if is_collection_path(coll_dir):
|
||||
collections[namespace].append(os.path.join(namespace_dir, collection))
|
||||
|
||||
return collections
|
||||
|
|
Loading…
Reference in a new issue