[arch-commits] Commit in vim-ansible/trunk (PKGBUILD generate.py)

David Runge dvzrv at archlinux.org
Mon Jul 13 14:53:47 UTC 2020


    Date: Monday, July 13, 2020 @ 14:53:46
  Author: dvzrv
Revision: 663413

upgpkg: vim-ansible 2.2-1: Upgrading to 2.2.

Including custom (but offered to upstream) script to generate reproducible
snippets for vim-ultisnips.
Removing patch, that was solely based on the snippets file ending up in the wrong location...

Added:
  vim-ansible/trunk/generate.py
Modified:
  vim-ansible/trunk/PKGBUILD

-------------+
 PKGBUILD    |   22 ++--
 generate.py |  276 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 287 insertions(+), 11 deletions(-)

Modified: PKGBUILD
===================================================================
--- PKGBUILD	2020-07-13 14:38:19 UTC (rev 663412)
+++ PKGBUILD	2020-07-13 14:53:46 UTC (rev 663413)
@@ -2,8 +2,8 @@
 
 _name=ansible-vim
 pkgname=vim-ansible
-pkgver=2.1
-pkgrel=2
+pkgver=2.2
+pkgrel=1
 pkgdesc="A vim plugin for syntax highlighting Ansible's common filetypes "
 arch=('any')
 url="https://github.com/pearofducks/ansible-vim"
@@ -13,9 +13,11 @@
 makedepends=('ansible' 'python')
 optdepends=('vim-ultisnips: for ansible snippets')
 source=("$pkgname-$pkgver.tar.gz::https://github.com/pearofducks/${_name}/archive/${pkgver}.tar.gz"
-        "${pkgname}-2.1-fix_ultisnips_generator.patch::https://github.com/pearofducks/ansible-vim/pull/98/commits/82fdc7f56363663a9452cf729398aac04f1f919c.patch")
-sha512sums=('630276ee0587bddea1ece4639e7bb744533dd212d3756f3071a188597e5091d4946536a9c6a4af013b6a3c0391a32d24809a0d10ab3d0b4e2fbaa7f4d89ac232'
-            '4e979c12514797af38621031d5a43c1ebbb2fb9e9c18684d75c45d85ca998d61f288c37f246c1b6abca66202c149c2c303ac15a19b110a1ea4ec13068b9c8f5b')
+        "generate.py")
+sha512sums=('73c9147c713b3eb2965f015c76c7c0495bf10518159ea69c16ee65cade2b670b59581b5a335f8e68bc91ff95e9238dd73228963aaa7a8f7d400904a973259f9c'
+            'e24f8c4cebb0a5f1f9e9bc0b005af1a957d1a986be8746039ca8f73d8b7c4c93ae352822e709c96f71b7726d1a6ca91be14f5553ef0153db9ad23a01b7a285a8')
+b2sums=('98b673265ee4274c285d49ea11d17d4055bbac15d8a0726123c1b75f473e55dc112a5a0bac5a08725a2fc2a6811e33bd8d2cfb2bcea9cd8d1088ef7eba87b6dd'
+        '0938ca439158af536ca04544c2015214b2d33d73dc36c93c0e048704bf71d6b0abc11f91f2c487a828bffe12b9c293587a027ee8883b95a2e411422f33ca4f74')
 
 prepare() {
   mv -v "${_name}-$pkgver" "$pkgname-$pkgver"
@@ -24,15 +26,13 @@
   # https://github.com/pearofducks/ansible-vim/issues/95
   sed -e 's/jinja2/jinja/g' \
       -i ftdetect/ansible.vim syntax/ansible.vim
-  # fixing ultisnips generator:
-  # https://github.com/pearofducks/ansible-vim/issue/96
-  # https://github.com/pearofducks/ansible-vim/issue/97
-  patch -Np1 -i "../${pkgname}-2.1-fix_ultisnips_generator.patch"
 }
 
 build() {
   cd "$pkgname-$pkgver"
-  python UltiSnips/generate.py --style 'dictionary' --sort
+  # generating a reproducible UltiSnips snippet file:
+  # https://github.com/pearofducks/ansible-vim/pull/105
+  python ../generate.py --style=dictionary
 }
 
 package() {
@@ -45,7 +45,7 @@
   install -vDm 644 syntax/ansible*.vim \
     -t "${pkgdir}/usr/share/vim/vimfiles/syntax/"
   install -vDm 644 ansible.snippets \
-    -t "${pkgdir}/usr/share/vim/vimfiles/snippets/"
+    -t "${pkgdir}/usr/share/vim/vimfiles/UltiSnips/"
   install -vDm 644 README.md -t "${pkgdir}/usr/share/doc/${pkgname}"
   install -vDm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
 }

Added: generate.py
===================================================================
--- generate.py	                        (rev 0)
+++ generate.py	2020-07-13 14:53:46 UTC (rev 663413)
@@ -0,0 +1,276 @@
+#!/usr/bin/env python3
+import argparse
+import os
+import os.path
+import ansible.modules
+from ansible.utils.plugin_docs import get_docstring
+from ansible.plugins.loader import fragment_loader
+from typing import Any, List
+
+
+OUTPUT_FILENAME = "ansible.snippets"
+OUTPUT_STYLE = ["multiline", "dictionary"]
+HEADER = [
+    "# NOTE: This file is auto-generated. Modifications may be overwritten.",
+    "priority -50",
+]
+MAX_DESCRIPTION_LENGTH = 512
+
+
+def get_files() -> List[str]:
+    """Return the sorted list of all module files that ansible provides
+
+    Returns
+    -------
+    List[str]
+        A list of strings representing the Python module files provided by
+        Ansible
+    """
+
+    file_names: List[str] = []
+    for root, dirs, files in os.walk(os.path.dirname(ansible.modules.__file__)):
+        file_names += [
+            f"{root}/{file_name}"
+            for file_name in files
+            if file_name.endswith(".py") and not file_name.startswith("__init__")
+        ]
+
+    return sorted(file_names)
+
+
+def get_docstrings(file_names: List[str]) -> List[Any]:
+    """Extract and return a list of docstring information from a list of files
+
+    Parameters
+    ----------
+    file_names: List[str]
+        A list of strings representing file names
+
+    Returns
+    -------
+    List[Any]
+        A list of AnsibleMapping objects, representing docstring information
+        (in dict form), excluding those that are marked as deprecated.
+
+    """
+
+    docstrings: List[Any] = []
+    docstrings += [
+        get_docstring(file_name, fragment_loader)[0] for file_name in file_names
+    ]
+    return [
+        docstring
+        for docstring in docstrings
+        if docstring and not docstring.get("deprecated")
+    ]
+
+
+def escape_strings(escapist: str) -> str:
+    """Escapes strings as required for ultisnips snippets
+
+    Escapes instances of \\, `, {, }, $
+
+    Parameters
+    ----------
+    escapist: str
+        A string to apply string replacement on
+
+    Returns
+    -------
+    str
+        The input string with all defined replacements applied
+    """
+
+    return (
+        escapist.replace("\\", "\\\\")
+        .replace("`", "\`")
+        .replace("{", "\{")
+        .replace("}", "\}")
+        .replace("$", "\$")
+        .replace("\"", "'")
+    )
+
+
+def option_data_to_snippet_completion(option_data: Any) -> str:
+    """Convert Ansible option info into a string used for ultisnip completion
+
+    Converts data about an Ansible module option (retrieved from an
+    AnsibleMapping object) into a formatted string that can be used within an
+    UltiSnip macro.
+
+    Parameters
+    ----------
+    option_data: Any
+        The option parameters
+
+    Returns
+    -------
+    str
+        A string representing one formatted option parameter
+    """
+
+    # join descriptions that are provided as lists and crop them
+    description = escape_strings(
+        "".join(option_data.get("description"))[0:MAX_DESCRIPTION_LENGTH]
+    )
+    default = option_data.get("default")
+    choices = option_data.get("choices")
+    option_type = option_data.get("type")
+
+    # if the option is of type "bool" return "yes" or "no"
+    if option_type and "bool" in option_type:
+        if default in [True, "True", "true", "yes"]:
+            return "true"
+        if default in [False, "False", "false", "no"]:
+            return "false"
+
+    # if there is no default and no choices, return the description
+    if not choices and default is None:
+        return f"# {description}"
+
+    # if there is a default but no choices return the default as string
+    if default is not None and not choices:
+        if len(str(default)) == 0:
+            return '""'
+        else:
+            if isinstance(default, str) and "\\" in default:
+                return f'"{escape_strings(str(default))}"'
+            elif isinstance(default, str):
+                return escape_strings(str(default))
+            else:
+                return default
+
+    # if there is a default and there are choices return the list of choices
+    # with the default prefixed with #
+    if default is not None and choices:
+        if isinstance(default, list):
+            # prefix default choice(s)
+            prefixed_choices = [
+                f"#{choice}" if choice in default else f"{choice}" for choice in choices
+            ]
+            return str(prefixed_choices)
+        else:
+            # prefix default choice
+            prefixed_choices = [
+                f"#{choice}" if str(choice) == str(default) else f"{choice}"
+                for choice in choices
+            ]
+            return "|".join(prefixed_choices)
+
+    # if there are choices but no default, return the choices as pipe separated
+    # list
+    if choices and default is None:
+        return "|".join([str(choice) for choice in choices])
+
+    # as fallback return empty string
+    return ""
+
+
+def module_options_to_snippet_options(module_options: Any) -> List[str]:
+    """Convert module options to UltiSnips snippet options
+
+    Parameters
+    ----------
+    module_options: Any
+        The "options" attribute of an AnsibleMapping object
+
+    Returns
+    -------
+    List[str]
+        A list of strings representing converted options
+    """
+
+    options: List[str] = []
+    delimiter = ": " if args.style == "dictionary" else "="
+
+    if not module_options:
+        return options
+
+    # order by option name
+    module_options = sorted(module_options.items(), key=lambda x: x[0])
+    # order by "required" attribute
+    module_options = sorted(
+        module_options, key=lambda x: x[1].get("required", False), reverse=True
+    )
+
+    # insert an empty option above the list of non-required options
+    for index, (_, option) in enumerate(module_options):
+        if not option.get("required"):
+            if index != 0:
+                module_options.insert(index, (None, None))
+            break
+
+    for index, (name, option_data) in enumerate(module_options, start=1):
+        # insert a line to seperate required/non-required options
+        if not name and not option_data:
+            options += [""]
+        else:
+            # the free_form option in some modules are special
+            if name == "free_form":
+                options += [
+                    f"\t${{{index}:{name}{delimiter}{option_data_to_snippet_completion(option_data)}}}"
+                ]
+            else:
+                options += [
+                    f"\t{name}{delimiter}${{{index}:{option_data_to_snippet_completion(option_data)}}}"
+                ]
+
+    return options
+
+
+def convert_docstring_to_snippet(docstring: Any) -> List[str]:
+    """Converts data about an Ansible module into an UltiSnips snippet string
+
+    Parameters
+    ----------
+    docstring: Any
+        An AnsibleMapping object representing the docstring for an Ansible
+        module
+
+    Returns
+    -------
+    str
+        A string representing an ultisnips compatible snippet of an Ansible
+        module
+    """
+
+    snippet: List[str] = []
+    snippet_options = "b"
+    module_name = docstring["module"]
+    module_short_description = docstring["short_description"]
+
+    snippet += [f'snippet {module_name} "{escape_strings(module_short_description)}" {snippet_options}']
+    if args.style == "dictionary":
+        snippet += [f"{module_name}:"]
+    else:
+        snippet += [f"{module_name}:{' >' if docstring.get('options') else ''}"]
+    module_options = module_options_to_snippet_options(docstring.get("options"))
+    snippet += module_options
+    snippet += ["endsnippet"]
+
+    return snippet
+
+
+if __name__ == "__main__":
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        "--output",
+        help=f"Output filename (default: {OUTPUT_FILENAME})",
+        default=OUTPUT_FILENAME,
+    )
+    parser.add_argument(
+        "--style",
+        help=f"YAML format used for snippets (default: {OUTPUT_STYLE[0]})",
+        choices=OUTPUT_STYLE,
+        default=OUTPUT_STYLE[0],
+    )
+    args = parser.parse_args()
+
+    docstrings = get_docstrings(get_files())
+    with open(args.output, "w") as f:
+        f.writelines(f"{header}\n" for header in HEADER)
+        for docstring in docstrings:
+            f.writelines(
+                f"{line}\n" for line in convert_docstring_to_snippet(docstring)
+            )


Property changes on: vim-ansible/trunk/generate.py
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property


More information about the arch-commits mailing list