Change collection PS util import pattern (#61307)
* Change collection PS util import pattern * Add changes for py2 compat * fix up regex and doc errors * fix up import analysis * Sanity fix for 2.6 CI workers * Get collection util path for coverage collection
This commit is contained in:
parent
eaa6848932
commit
66f52b74b1
18 changed files with 267 additions and 56 deletions
2
changelogs/fragments/powershell-collection_util.yaml
Normal file
2
changelogs/fragments/powershell-collection_util.yaml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
minor_changes:
|
||||||
|
- Adjusted PowerShell and C# collection util imports to use a Python package name that reflects the location of the util in the collection. This is a breaking change, for more information see :ref:`porting_2.9_guide` for more information.
|
|
@ -86,10 +86,10 @@ module_utils
|
||||||
|
|
||||||
When coding with ``module_utils`` in a collection, the Python ``import`` statement needs to take into account the FQCN along with the ``ansible_collections`` convention. The resulting Python import will look like ``from ansible_collections.{namespace}.{collection}.plugins.module_utils.{util} import {something}``
|
When coding with ``module_utils`` in a collection, the Python ``import`` statement needs to take into account the FQCN along with the ``ansible_collections`` convention. The resulting Python import will look like ``from ansible_collections.{namespace}.{collection}.plugins.module_utils.{util} import {something}``
|
||||||
|
|
||||||
The following example snippet shows a module using both default Ansible ``module_utils`` and
|
The following example snippets show a Python and PowerShell module using both default Ansible ``module_utils`` and
|
||||||
those provided by a collection. In this example the namespace is
|
those provided by a collection. In this example the namespace is ``ansible_example``, the collection is ``community``.
|
||||||
``ansible_example``, the collection is ``community``, and the ``module_util`` in
|
In the Python example the ``module_util`` in question is called ``qradar`` such that the FQCN is
|
||||||
question is called ``qradar`` such that the FQCN is ``ansible_example.community.plugins.module_utils.qradar``:
|
``ansible_example.community.plugins.module_utils.qradar``:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -117,6 +117,26 @@ question is called ``qradar`` such that the FQCN is ``ansible_example.community.
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
In the PowerShell example the ``module_util`` in question is called ``hyperv`` such that the FCQN is
|
||||||
|
``ansible_example.community.plugins.module_utils.hyperv``:
|
||||||
|
|
||||||
|
.. code-block:: powershell
|
||||||
|
|
||||||
|
#!powershell
|
||||||
|
#AnsibleRequires -CSharpUtil Ansible.Basic
|
||||||
|
#AnsibleRequires -PowerShell ansible_collections.ansible_example.community.plugins.module_utils.hyperv
|
||||||
|
|
||||||
|
$spec = @{
|
||||||
|
name = @{ required = $true; type = "str" }
|
||||||
|
state = @{ required = $true; choices = @("present", "absent") }
|
||||||
|
}
|
||||||
|
$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
|
||||||
|
|
||||||
|
Invoke-HyperVFunction -Name $module.Params.name
|
||||||
|
|
||||||
|
$module.ExitJson()
|
||||||
|
|
||||||
|
|
||||||
roles directory
|
roles directory
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,29 @@ Deprecated
|
||||||
No notable changes
|
No notable changes
|
||||||
|
|
||||||
|
|
||||||
|
Collection loader changes
|
||||||
|
=========================
|
||||||
|
|
||||||
|
The way to import a PowerShell or C# module util from a collection has changed in the Ansible 2.9 release. In Ansible
|
||||||
|
2.8 a util was imported with the following syntax:
|
||||||
|
|
||||||
|
.. code-block:: powershell
|
||||||
|
|
||||||
|
#AnsibleRequires -CSharpUtil AnsibleCollections.namespace_name.collection_name.util_filename
|
||||||
|
#AnsibleRequires -PowerShell AnsibleCollections.namespace_name.collection_name.util_filename
|
||||||
|
|
||||||
|
In Ansible 2.9 this was changed to:
|
||||||
|
|
||||||
|
.. code-block:: powershell
|
||||||
|
|
||||||
|
#AnsibleRequires -CSharpUtil ansible_collections.namespace_name.collection_name.plugins.module_utils.util_filename
|
||||||
|
#AnsibleRequires -PowerShell ansible_collections.namespace_name.collection_name.plugins.module_utils.util_filename
|
||||||
|
|
||||||
|
The change in the collection import name also requires any C# util namespaces to be updated with the newer name
|
||||||
|
format. This is more verbose but is designed to make sure we avoid plugin name conflicts across separate plugin types
|
||||||
|
and to standardise how imports work in PowerShell with how Python modules work.
|
||||||
|
|
||||||
|
|
||||||
Modules
|
Modules
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
import errno
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import pkgutil
|
import pkgutil
|
||||||
|
@ -13,9 +14,15 @@ import re
|
||||||
|
|
||||||
from distutils.version import LooseVersion
|
from distutils.version import LooseVersion
|
||||||
|
|
||||||
|
# HACK: keep Python 2.6 controller tests happy in CI until they're properly split
|
||||||
|
try:
|
||||||
|
from importlib import import_module
|
||||||
|
except ImportError:
|
||||||
|
import_module = __import__
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.module_utils._text import to_bytes, to_text
|
from ansible.module_utils._text import to_bytes, to_native, to_text
|
||||||
from ansible.plugins.loader import ps_module_utils_loader
|
from ansible.plugins.loader import ps_module_utils_loader
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,10 +42,32 @@ class PSModuleDepFinder(object):
|
||||||
self.os_version = None
|
self.os_version = None
|
||||||
self.become = False
|
self.become = False
|
||||||
|
|
||||||
self._re_cs_module = re.compile(to_bytes(r'(?i)^using\s((Ansible\..+)|(AnsibleCollections\.\w.+\.\w.+\w.+));\s*$'))
|
self._re_cs_module = [
|
||||||
self._re_cs_in_ps_module = re.compile(to_bytes(r'(?i)^#\s*ansiblerequires\s+-csharputil\s+((Ansible\..+)|(AnsibleCollections\.\w.+\.\w.+\w.+))'))
|
# Reference C# module_util in another C# util
|
||||||
self._re_coll_ps_in_ps_module = re.compile(to_bytes(r'(?i)^#\s*ansiblerequires\s+-powershell\s+((Ansible\..+)|(AnsibleCollections\.\w.+\.\w.+\w.+))'))
|
# 'using ansible_collections.{namespace}.{collection}.plugins.module_utils.{name}'
|
||||||
self._re_module = re.compile(to_bytes(r'(?i)^#\s*requires\s+\-module(?:s?)\s*(Ansible\.ModuleUtils\..+)'))
|
re.compile(to_bytes(r'(?i)^using\s((Ansible\..+)|'
|
||||||
|
r'(ansible_collections\.\w+\.\w+\.plugins\.module_utils\.[\w\.]+));\s*$')),
|
||||||
|
]
|
||||||
|
|
||||||
|
self._re_cs_in_ps_module = [
|
||||||
|
# Reference C# module_util in a PowerShell module
|
||||||
|
# '#AnsibleRequires -CSharpUtil Ansible.{name}'
|
||||||
|
# '#AnsibleRequires -CSharpUtil ansible_collections.{namespace}.{collection}.plugins.module_utils.{name}'
|
||||||
|
re.compile(to_bytes(r'(?i)^#\s*ansiblerequires\s+-csharputil\s+((Ansible\..+)|'
|
||||||
|
r'(ansible_collections\.\w+\.\w+\.plugins\.module_utils\.[\w\.]+))')),
|
||||||
|
]
|
||||||
|
|
||||||
|
self._re_ps_module = [
|
||||||
|
# Original way of referencing a builtin module_util
|
||||||
|
# '#Requires -Module Ansible.ModuleUtils.{name}
|
||||||
|
re.compile(to_bytes(r'(?i)^#\s*requires\s+\-module(?:s?)\s*(Ansible\.ModuleUtils\..+)')),
|
||||||
|
# New way of referencing a builtin and collection module_util
|
||||||
|
# '#AnsibleRequires -PowerShell ansible_collections.{namespace}.{collection}.plugins.module_utils.{name}'
|
||||||
|
# '#AnsibleRequires -PowerShell Ansible.ModuleUtils.{name}'
|
||||||
|
re.compile(to_bytes(r'(?i)^#\s*ansiblerequires\s+-powershell\s+(((Ansible\.ModuleUtils\..+))|'
|
||||||
|
r'(ansible_collections\.\w+\.\w+\.plugins\.module_utils\.[\w\.]+))')),
|
||||||
|
]
|
||||||
|
|
||||||
self._re_wrapper = re.compile(to_bytes(r'(?i)^#\s*ansiblerequires\s+-wrapper\s+(\w*)'))
|
self._re_wrapper = re.compile(to_bytes(r'(?i)^#\s*ansiblerequires\s+-wrapper\s+(\w*)'))
|
||||||
self._re_ps_version = re.compile(to_bytes(r'(?i)^#requires\s+\-version\s+([0-9]+(\.[0-9]+){0,3})$'))
|
self._re_ps_version = re.compile(to_bytes(r'(?i)^#requires\s+\-version\s+([0-9]+(\.[0-9]+){0,3})$'))
|
||||||
self._re_os_version = re.compile(to_bytes(r'(?i)^#ansiblerequires\s+\-osversion\s+([0-9]+(\.[0-9]+){0,3})$'))
|
self._re_os_version = re.compile(to_bytes(r'(?i)^#ansiblerequires\s+\-osversion\s+([0-9]+(\.[0-9]+){0,3})$'))
|
||||||
|
@ -55,28 +84,30 @@ class PSModuleDepFinder(object):
|
||||||
if powershell:
|
if powershell:
|
||||||
checks = [
|
checks = [
|
||||||
# PS module contains '#Requires -Module Ansible.ModuleUtils.*'
|
# PS module contains '#Requires -Module Ansible.ModuleUtils.*'
|
||||||
(self._re_module, self.ps_modules, ".psm1"),
|
|
||||||
# PS module contains '#AnsibleRequires -Powershell Ansible.*' (or FQ collections module_utils ref)
|
# PS module contains '#AnsibleRequires -Powershell Ansible.*' (or FQ collections module_utils ref)
|
||||||
(self._re_coll_ps_in_ps_module, self.ps_modules, ".psm1"),
|
(self._re_ps_module, self.ps_modules, ".psm1"),
|
||||||
# PS module contains '#AnsibleRequires -CSharpUtil Ansible.*'
|
# PS module contains '#AnsibleRequires -CSharpUtil Ansible.*'
|
||||||
(self._re_cs_in_ps_module, cs_utils, ".cs"),
|
(self._re_cs_in_ps_module, cs_utils, ".cs"),
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
checks = [
|
checks = [
|
||||||
# CS module contains 'using Ansible.*;' or 'using AnsibleCollections.ns.coll.*;'
|
# CS module contains 'using Ansible.*;' or 'using ansible_collections.ns.coll.plugins.module_utils.*;'
|
||||||
(self._re_cs_module, cs_utils, ".cs"),
|
(self._re_cs_module, cs_utils, ".cs"),
|
||||||
]
|
]
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
for check in checks:
|
for check in checks:
|
||||||
match = check[0].match(line)
|
for pattern in check[0]:
|
||||||
if match:
|
match = pattern.match(line)
|
||||||
# tolerate windows line endings by stripping any remaining
|
if match:
|
||||||
# newline chars
|
# tolerate windows line endings by stripping any remaining
|
||||||
module_util_name = self._normalize_mu_name(match.group(1).rstrip())
|
# newline chars
|
||||||
|
module_util_name = to_text(match.group(1).rstrip())
|
||||||
|
|
||||||
if module_util_name not in check[1].keys():
|
if module_util_name not in check[1].keys():
|
||||||
module_utils.add((module_util_name, check[2]))
|
module_utils.add((module_util_name, check[2]))
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
if powershell:
|
if powershell:
|
||||||
ps_version_match = self._re_ps_version.match(line)
|
ps_version_match = self._re_ps_version.match(line)
|
||||||
|
@ -128,12 +159,40 @@ class PSModuleDepFinder(object):
|
||||||
def _add_module(self, name, wrapper=False):
|
def _add_module(self, name, wrapper=False):
|
||||||
m, ext = name
|
m, ext = name
|
||||||
m = to_text(m)
|
m = to_text(m)
|
||||||
mu_path = ps_module_utils_loader.find_plugin(m, ext)
|
if m.startswith("Ansible."):
|
||||||
if not mu_path:
|
# Builtin util, use plugin loader to get the data
|
||||||
raise AnsibleError('Could not find imported module support code '
|
mu_path = ps_module_utils_loader.find_plugin(m, ext)
|
||||||
'for \'%s\'' % m)
|
|
||||||
|
if not mu_path:
|
||||||
|
raise AnsibleError('Could not find imported module support code '
|
||||||
|
'for \'%s\'' % m)
|
||||||
|
|
||||||
|
module_util_data = to_bytes(_slurp(mu_path))
|
||||||
|
else:
|
||||||
|
# Collection util, load the package data based on the util import.
|
||||||
|
submodules = tuple(m.split("."))
|
||||||
|
n_package_name = to_native('.'.join(submodules[:-1]), errors='surrogate_or_strict')
|
||||||
|
n_resource_name = to_native(submodules[-1] + ext, errors='surrogate_or_strict')
|
||||||
|
|
||||||
|
try:
|
||||||
|
module_util = import_module(to_native(n_package_name))
|
||||||
|
module_util_data = to_bytes(pkgutil.get_data(n_package_name, n_resource_name),
|
||||||
|
errors='surrogate_or_strict')
|
||||||
|
|
||||||
|
# Get the path of the util which is required for coverage collection.
|
||||||
|
resource_paths = list(module_util.__path__)
|
||||||
|
if len(resource_paths) != 1:
|
||||||
|
# This should never happen with a collection but we are just being defensive about it.
|
||||||
|
raise AnsibleError("Internal error: Referenced module_util package '%s' contains 0 or multiple "
|
||||||
|
"import locations when we only expect 1." % n_package_name)
|
||||||
|
mu_path = os.path.join(resource_paths[0], n_resource_name)
|
||||||
|
except OSError as err:
|
||||||
|
if err.errno == errno.ENOENT:
|
||||||
|
raise AnsibleError('Could not find collection imported module support code for \'%s\''
|
||||||
|
% to_native(m))
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
module_util_data = to_bytes(_slurp(mu_path))
|
|
||||||
util_info = {
|
util_info = {
|
||||||
'data': module_util_data,
|
'data': module_util_data,
|
||||||
'path': to_text(mu_path),
|
'path': to_text(mu_path),
|
||||||
|
@ -164,15 +223,6 @@ class PSModuleDepFinder(object):
|
||||||
if LooseVersion(new_version) > LooseVersion(existing_version):
|
if LooseVersion(new_version) > LooseVersion(existing_version):
|
||||||
setattr(self, attribute, new_version)
|
setattr(self, attribute, new_version)
|
||||||
|
|
||||||
def _normalize_mu_name(self, mu):
|
|
||||||
# normalize Windows module_utils to remove 'AnsibleCollections.' prefix so the plugin loader can find them
|
|
||||||
mu = to_text(mu)
|
|
||||||
|
|
||||||
if not mu.startswith(u'AnsibleCollections.'):
|
|
||||||
return mu
|
|
||||||
|
|
||||||
return mu.replace(u'AnsibleCollections.', u'', 1)
|
|
||||||
|
|
||||||
|
|
||||||
def _slurp(path):
|
def _slurp(path):
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
|
|
|
@ -73,9 +73,13 @@ Function Add-CSharpType {
|
||||||
$defined_symbols.Add("WINDOWS") > $null
|
$defined_symbols.Add("WINDOWS") > $null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Store any TypeAccelerators shortcuts the util wants us to set
|
||||||
|
$type_accelerators = [System.Collections.Generic.List`1[Hashtable]]@()
|
||||||
|
|
||||||
# pattern used to find referenced assemblies in the code
|
# pattern used to find referenced assemblies in the code
|
||||||
$assembly_pattern = [Regex]"//\s*AssemblyReference\s+-Name\s+(?<Name>[\w.]*)(\s+-CLR\s+(?<CLR>Core|Framework))?"
|
$assembly_pattern = [Regex]"//\s*AssemblyReference\s+-Name\s+(?<Name>[\w.]*)(\s+-CLR\s+(?<CLR>Core|Framework))?"
|
||||||
$no_warn_pattern = [Regex]"//\s*NoWarn\s+-Name\s+(?<Name>[\w\d]*)(\s+-CLR\s+(?<CLR>Core|Framework))?"
|
$no_warn_pattern = [Regex]"//\s*NoWarn\s+-Name\s+(?<Name>[\w\d]*)(\s+-CLR\s+(?<CLR>Core|Framework))?"
|
||||||
|
$type_pattern = [Regex]"//\s*TypeAccelerator\s+-Name\s+(?<Name>[\w.]*)\s+-TypeName\s+(?<TypeName>[\w.]*)"
|
||||||
|
|
||||||
# PSCore vs PSDesktop use different methods to compile the code,
|
# PSCore vs PSDesktop use different methods to compile the code,
|
||||||
# PSCore uses Roslyn and can compile the code purely in memory
|
# PSCore uses Roslyn and can compile the code purely in memory
|
||||||
|
@ -105,6 +109,7 @@ Function Add-CSharpType {
|
||||||
# scan through code and add any assemblies that match
|
# scan through code and add any assemblies that match
|
||||||
# //AssemblyReference -Name ... [-CLR Core]
|
# //AssemblyReference -Name ... [-CLR Core]
|
||||||
# //NoWarn -Name ... [-CLR Core]
|
# //NoWarn -Name ... [-CLR Core]
|
||||||
|
# //TypeAccelerator -Name ... -TypeName ...
|
||||||
$assembly_matches = $assembly_pattern.Matches($reference)
|
$assembly_matches = $assembly_pattern.Matches($reference)
|
||||||
foreach ($match in $assembly_matches) {
|
foreach ($match in $assembly_matches) {
|
||||||
$clr = $match.Groups["CLR"].Value
|
$clr = $match.Groups["CLR"].Value
|
||||||
|
@ -126,6 +131,11 @@ Function Add-CSharpType {
|
||||||
$ignore_warnings.Add($match.Groups["Name"], [Microsoft.CodeAnalysis.ReportDiagnostic]::Suppress)
|
$ignore_warnings.Add($match.Groups["Name"], [Microsoft.CodeAnalysis.ReportDiagnostic]::Suppress)
|
||||||
}
|
}
|
||||||
$syntax_trees.Add([Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree]::ParseText($reference, $parse_options)) > $null
|
$syntax_trees.Add([Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree]::ParseText($reference, $parse_options)) > $null
|
||||||
|
|
||||||
|
$type_matches = $type_pattern.Matches($reference)
|
||||||
|
foreach ($match in $type_matches) {
|
||||||
|
$type_accelerators.Add(@{Name=$match.Groups["Name"].Value; TypeName=$match.Groups["TypeName"].Value})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Release seems to contain the correct line numbers compared to
|
# Release seems to contain the correct line numbers compared to
|
||||||
|
@ -239,6 +249,7 @@ Function Add-CSharpType {
|
||||||
# scan through code and add any assemblies that match
|
# scan through code and add any assemblies that match
|
||||||
# //AssemblyReference -Name ... [-CLR Framework]
|
# //AssemblyReference -Name ... [-CLR Framework]
|
||||||
# //NoWarn -Name ... [-CLR Framework]
|
# //NoWarn -Name ... [-CLR Framework]
|
||||||
|
# //TypeAccelerator -Name ... -TypeName ...
|
||||||
$assembly_matches = $assembly_pattern.Matches($reference)
|
$assembly_matches = $assembly_pattern.Matches($reference)
|
||||||
foreach ($match in $assembly_matches) {
|
foreach ($match in $assembly_matches) {
|
||||||
$clr = $match.Groups["CLR"].Value
|
$clr = $match.Groups["CLR"].Value
|
||||||
|
@ -261,6 +272,11 @@ Function Add-CSharpType {
|
||||||
$ignore_warnings.Add($warning_id) > $null
|
$ignore_warnings.Add($warning_id) > $null
|
||||||
}
|
}
|
||||||
$compile_units.Add((New-Object -TypeName System.CodeDom.CodeSnippetCompileUnit -ArgumentList $reference)) > $null
|
$compile_units.Add((New-Object -TypeName System.CodeDom.CodeSnippetCompileUnit -ArgumentList $reference)) > $null
|
||||||
|
|
||||||
|
$type_matches = $type_pattern.Matches($reference)
|
||||||
|
foreach ($match in $type_matches) {
|
||||||
|
$type_accelerators.Add(@{Name=$match.Groups["Name"].Value; TypeName=$match.Groups["TypeName"].Value})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ($ignore_warnings.Count -gt 0) {
|
if ($ignore_warnings.Count -gt 0) {
|
||||||
$compiler_options.Add("/nowarn:" + ([String]::Join(",", $ignore_warnings.ToArray()))) > $null
|
$compiler_options.Add("/nowarn:" + ([String]::Join(",", $ignore_warnings.ToArray()))) > $null
|
||||||
|
@ -281,6 +297,23 @@ Function Add-CSharpType {
|
||||||
$compiled_assembly = $compile.CompiledAssembly
|
$compiled_assembly = $compile.CompiledAssembly
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$type_accelerator = [PSObject].Assembly.GetType("System.Management.Automation.TypeAccelerators")
|
||||||
|
foreach ($accelerator in $type_accelerators) {
|
||||||
|
$type_name = $accelerator.TypeName
|
||||||
|
$found = $false
|
||||||
|
|
||||||
|
foreach ($assembly_type in $compiled_assembly.GetTypes()) {
|
||||||
|
if ($assembly_type.Name -eq $type_name) {
|
||||||
|
$type_accelerator::Add($accelerator.Name, $assembly_type)
|
||||||
|
$found = $true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (-not $found) {
|
||||||
|
throw "Failed to find compiled class '$type_name' for custom TypeAccelerator."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# return the compiled assembly if PassThru is set.
|
# return the compiled assembly if PassThru is set.
|
||||||
if ($PassThru) {
|
if ($PassThru) {
|
||||||
return $compiled_assembly
|
return $compiled_assembly
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace AnsibleCollections.testns.testcoll.AnotherCSMU
|
namespace ansible_collections.testns.testcoll.plugins.module_utils.AnotherCSMU
|
||||||
{
|
{
|
||||||
public class AnotherThing
|
public class AnotherThing
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
using AnsibleCollections.testns.testcoll.AnotherCSMU;
|
using ansible_collections.testns.testcoll.plugins.module_utils.AnotherCSMU;
|
||||||
|
using ansible_collections.testns.testcoll.plugins.module_utils.subpkg.subcs;
|
||||||
|
|
||||||
namespace AnsibleCollections.testns.testcoll.MyCSMU
|
//TypeAccelerator -Name MyCSMU -TypeName CustomThing
|
||||||
|
|
||||||
|
namespace ansible_collections.testns.testcoll.plugins.module_utils.MyCSMU
|
||||||
{
|
{
|
||||||
public class CustomThing
|
public class CustomThing
|
||||||
{
|
{
|
||||||
public static string HelloWorld()
|
public static string HelloWorld()
|
||||||
{
|
{
|
||||||
string res = AnotherThing.CallMe();
|
string res1 = AnotherThing.CallMe();
|
||||||
return String.Format("Hello from user_mu collection-hosted MyCSMU, also {0}", res);
|
string res2 = NestedUtil.HelloWorld();
|
||||||
|
return String.Format("Hello from user_mu collection-hosted MyCSMU, also {0} and {1}", res1, res2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
Function CallMe-FromUserPSMU {
|
Function Invoke-FromUserPSMU {
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Test function
|
Test function
|
||||||
|
@ -6,4 +6,4 @@ Function CallMe-FromUserPSMU {
|
||||||
return "from user_mu"
|
return "from user_mu"
|
||||||
}
|
}
|
||||||
|
|
||||||
Export-ModuleMember -Function CallMe-FromUserPSMU
|
Export-ModuleMember -Function Invoke-FromUserPSMU
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ansible_collections.testns.testcoll.plugins.module_utils.subpkg.subcs
|
||||||
|
{
|
||||||
|
public class NestedUtil
|
||||||
|
{
|
||||||
|
public static string HelloWorld()
|
||||||
|
{
|
||||||
|
string res = "Hello from subpkg.subcs";
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
Function Invoke-SubUserPSMU {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Test function
|
||||||
|
#>
|
||||||
|
return "from subpkg.subps.psm1"
|
||||||
|
}
|
||||||
|
|
||||||
|
Export-ModuleMember -Function Invoke-SubUserPSMU
|
|
@ -3,11 +3,12 @@
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
#AnsibleRequires -CSharpUtil Ansible.Basic
|
#AnsibleRequires -CSharpUtil Ansible.Basic
|
||||||
#AnsibleRequires -CSharpUtil AnsibleCollections.testns.testcoll.MyCSMU
|
#AnsibleRequires -CSharpUtil ansible_collections.testns.testcoll.plugins.module_utils.MyCSMU
|
||||||
|
#AnsibleRequires -CSharpUtil ansible_collections.testns.testcoll.plugins.module_utils.subpkg.subcs
|
||||||
|
|
||||||
$spec = @{
|
$spec = @{
|
||||||
options = @{
|
options = @{
|
||||||
data = @{ type = "str"; default = "called from $([AnsibleCollections.testns.testcoll.MyCSMU.CustomThing]::HelloWorld())" }
|
data = @{ type = "str"; default = "called from $([ansible_collections.testns.testcoll.plugins.module_utils.MyCSMU.CustomThing]::HelloWorld())" }
|
||||||
}
|
}
|
||||||
supports_check_mode = $true
|
supports_check_mode = $true
|
||||||
}
|
}
|
||||||
|
@ -20,4 +21,6 @@ if ($data -eq "crash") {
|
||||||
|
|
||||||
$module.Result.ping = $data
|
$module.Result.ping = $data
|
||||||
$module.Result.source = "user"
|
$module.Result.source = "user"
|
||||||
|
$module.Result.subpkg = [ansible_collections.testns.testcoll.plugins.module_utils.subpkg.subcs.NestedUtil]::HelloWorld()
|
||||||
|
$module.Result.type_accelerator = "called from $([MyCSMU]::HelloWorld())"
|
||||||
$module.ExitJson()
|
$module.ExitJson()
|
|
@ -3,11 +3,12 @@
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
#AnsibleRequires -CSharpUtil Ansible.Basic
|
#AnsibleRequires -CSharpUtil Ansible.Basic
|
||||||
#AnsibleRequires -Powershell AnsibleCollections.testns.testcoll.MyPSMU
|
#AnsibleRequires -Powershell ansible_collections.testns.testcoll.plugins.module_utils.MyPSMU
|
||||||
|
#AnsibleRequires -PowerShell ansible_collections.testns.testcoll.plugins.module_utils.subpkg.subps
|
||||||
|
|
||||||
$spec = @{
|
$spec = @{
|
||||||
options = @{
|
options = @{
|
||||||
data = @{ type = "str"; default = "called from $(CallMe-FromUserPSMU)" }
|
data = @{ type = "str"; default = "called from $(Invoke-FromUserPSMU)" }
|
||||||
}
|
}
|
||||||
supports_check_mode = $true
|
supports_check_mode = $true
|
||||||
}
|
}
|
||||||
|
@ -20,4 +21,5 @@ if ($data -eq "crash") {
|
||||||
|
|
||||||
$module.Result.ping = $data
|
$module.Result.ping = $data
|
||||||
$module.Result.source = "user"
|
$module.Result.source = "user"
|
||||||
|
$module.Result.subpkg = Invoke-SubUserPSMU
|
||||||
$module.ExitJson()
|
$module.ExitJson()
|
|
@ -29,7 +29,7 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# run test playbook
|
# run test playbook
|
||||||
ansible-playbook -i "${INVENTORY_PATH}" -i ./a.statichost.yml -v "${TEST_PLAYBOOK}"
|
ansible-playbook -i "${INVENTORY_PATH}" -i ./a.statichost.yml -v "${TEST_PLAYBOOK}" "$@"
|
||||||
|
|
||||||
# test adjacent with --playbook-dir
|
# test adjacent with --playbook-dir
|
||||||
export ANSIBLE_COLLECTIONS_PATHS=''
|
export ANSIBLE_COLLECTIONS_PATHS=''
|
||||||
|
|
|
@ -16,5 +16,13 @@
|
||||||
that:
|
that:
|
||||||
- selfcontained_out.source == 'user'
|
- selfcontained_out.source == 'user'
|
||||||
- csbasic_only_out.source == 'user'
|
- csbasic_only_out.source == 'user'
|
||||||
- uses_coll_psmu.source == 'user' and 'user_mu' in uses_coll_psmu.ping
|
# win_uses_coll_psmu
|
||||||
- uses_coll_csmu.source == 'user' and 'user_mu' in uses_coll_csmu.ping
|
- uses_coll_psmu.source == 'user'
|
||||||
|
- "'user_mu' in uses_coll_psmu.ping"
|
||||||
|
- uses_coll_psmu.subpkg == 'from subpkg.subps.psm1'
|
||||||
|
# win_uses_coll_csmu
|
||||||
|
- uses_coll_csmu.source == 'user'
|
||||||
|
- "'user_mu' in uses_coll_csmu.ping"
|
||||||
|
- "'Hello from subpkg.subcs' in uses_coll_csmu.ping"
|
||||||
|
- uses_coll_csmu.subpkg == 'Hello from subpkg.subcs'
|
||||||
|
- uses_coll_csmu.type_accelerator == uses_coll_csmu.ping
|
||||||
|
|
|
@ -227,5 +227,50 @@ Add-CSharpType -References $defined_symbol -CompileSymbols "SYMBOL1"
|
||||||
$actual = [Namespace8.Class8]::GetString()
|
$actual = [Namespace8.Class8]::GetString()
|
||||||
Assert-Equals -actual $actual -expected "symbol"
|
Assert-Equals -actual $actual -expected "symbol"
|
||||||
|
|
||||||
|
$type_accelerator = @'
|
||||||
|
using System;
|
||||||
|
|
||||||
|
//TypeAccelerator -Name AnsibleType -TypeName Class9
|
||||||
|
|
||||||
|
namespace Namespace9
|
||||||
|
{
|
||||||
|
public class Class9
|
||||||
|
{
|
||||||
|
public static string GetString()
|
||||||
|
{
|
||||||
|
return "a";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'@
|
||||||
|
Add-CSharpType -Reference $type_accelerator
|
||||||
|
$actual = [AnsibleType]::GetString()
|
||||||
|
Assert-Equals -actual $actual -expected "a"
|
||||||
|
|
||||||
|
$missing_type_class = @'
|
||||||
|
using System;
|
||||||
|
|
||||||
|
//TypeAccelerator -Name AnsibleTypeMissing -TypeName MissingClass
|
||||||
|
|
||||||
|
namespace Namespace10
|
||||||
|
{
|
||||||
|
public class Class10
|
||||||
|
{
|
||||||
|
public static string GetString()
|
||||||
|
{
|
||||||
|
return "b";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'@
|
||||||
|
$failed = $false
|
||||||
|
try {
|
||||||
|
Add-CSharpType -Reference $missing_type_class
|
||||||
|
} catch {
|
||||||
|
$failed = $true
|
||||||
|
Assert-Equals -actual $_.Exception.Message -expected "Failed to find compiled class 'MissingClass' for custom TypeAccelerator."
|
||||||
|
}
|
||||||
|
Assert-Equals -actual $failed -expected $true
|
||||||
|
|
||||||
$result.res = "success"
|
$result.res = "success"
|
||||||
Exit-Json -obj $result
|
Exit-Json -obj $result
|
||||||
|
|
|
@ -49,7 +49,7 @@ def get_csharp_module_utils_name(path): # type: (str) -> str
|
||||||
base_path = data_context().content.module_utils_csharp_path
|
base_path = data_context().content.module_utils_csharp_path
|
||||||
|
|
||||||
if data_context().content.collection:
|
if data_context().content.collection:
|
||||||
prefix = 'AnsibleCollections.' + data_context().content.collection.prefix
|
prefix = 'ansible_collections.' + data_context().content.collection.prefix + 'plugins.module_utils.'
|
||||||
else:
|
else:
|
||||||
prefix = ''
|
prefix = ''
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ def extract_csharp_module_utils_imports(path, module_utils, is_pure_csharp):
|
||||||
if is_pure_csharp:
|
if is_pure_csharp:
|
||||||
pattern = re.compile(r'(?i)^using\s((?:Ansible|AnsibleCollections)\..+);$')
|
pattern = re.compile(r'(?i)^using\s((?:Ansible|AnsibleCollections)\..+);$')
|
||||||
else:
|
else:
|
||||||
pattern = re.compile(r'(?i)^#\s*ansiblerequires\s+-csharputil\s+((?:Ansible|AnsibleCollections)\..+)')
|
pattern = re.compile(r'(?i)^#\s*ansiblerequires\s+-csharputil\s+((?:Ansible|ansible.collections)\..+)')
|
||||||
|
|
||||||
with open(path, 'r') as module_file:
|
with open(path, 'r') as module_file:
|
||||||
for line_number, line in enumerate(module_file, 1):
|
for line_number, line in enumerate(module_file, 1):
|
||||||
|
|
|
@ -45,7 +45,7 @@ def get_powershell_module_utils_name(path): # type: (str) -> str
|
||||||
base_path = data_context().content.module_utils_powershell_path
|
base_path = data_context().content.module_utils_powershell_path
|
||||||
|
|
||||||
if data_context().content.collection:
|
if data_context().content.collection:
|
||||||
prefix = 'AnsibleCollections.' + data_context().content.collection.prefix
|
prefix = 'ansible_collections.' + data_context().content.collection.prefix + '.plugins.module_utils.'
|
||||||
else:
|
else:
|
||||||
prefix = ''
|
prefix = ''
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ def extract_powershell_module_utils_imports(path, module_utils):
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
line_number += 1
|
line_number += 1
|
||||||
match = re.search(r'(?i)^#\s*(?:requires\s+-module(?:s?)|ansiblerequires\s+-powershell)\s*((?:Ansible|AnsibleCollections)\..+)', line)
|
match = re.search(r'(?i)^#\s*(?:requires\s+-module(?:s?)|ansiblerequires\s+-powershell)\s*((?:Ansible|ansible_collections)\..+)', line)
|
||||||
|
|
||||||
if not match:
|
if not match:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -6027,7 +6027,6 @@ test/integration/targets/async_fail/library/async_test.py future-import-boilerpl
|
||||||
test/integration/targets/async_fail/library/async_test.py metaclass-boilerplate
|
test/integration/targets/async_fail/library/async_test.py metaclass-boilerplate
|
||||||
test/integration/targets/aws_lambda/files/mini_lambda.py future-import-boilerplate
|
test/integration/targets/aws_lambda/files/mini_lambda.py future-import-boilerplate
|
||||||
test/integration/targets/aws_lambda/files/mini_lambda.py metaclass-boilerplate
|
test/integration/targets/aws_lambda/files/mini_lambda.py metaclass-boilerplate
|
||||||
test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyPSMU.psm1 pslint:PSUseApprovedVerbs
|
|
||||||
test/integration/targets/expect/files/test_command.py future-import-boilerplate
|
test/integration/targets/expect/files/test_command.py future-import-boilerplate
|
||||||
test/integration/targets/expect/files/test_command.py metaclass-boilerplate
|
test/integration/targets/expect/files/test_command.py metaclass-boilerplate
|
||||||
test/integration/targets/get_url/files/testserver.py future-import-boilerplate
|
test/integration/targets/get_url/files/testserver.py future-import-boilerplate
|
||||||
|
|
Loading…
Add table
Reference in a new issue