community.general/plugins/module_utils/homebrew.py
Felix Fontein 8f8a0e1d7c
Some checks are pending
EOL CI / EOL Sanity (Ⓐ2.17) (push) Waiting to run
EOL CI / EOL Units (Ⓐ2.17+py3.10) (push) Waiting to run
EOL CI / EOL Units (Ⓐ2.17+py3.12) (push) Waiting to run
EOL CI / EOL Units (Ⓐ2.17+py3.7) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.17+alpine319+py:azp/posix/1/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.17+alpine319+py:azp/posix/2/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.17+alpine319+py:azp/posix/3/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.17+fedora39+py:azp/posix/1/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.17+fedora39+py:azp/posix/2/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.17+fedora39+py:azp/posix/3/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.17+ubuntu2004+py:azp/posix/1/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.17+ubuntu2004+py:azp/posix/2/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.17+ubuntu2004+py:azp/posix/3/) (push) Waiting to run
nox / Run extra sanity tests (push) Waiting to run
Fix __future__ imports, __metaclass__ = type, and remove explicit UTF-8 encoding statement for Python files (#10886)
* Adjust all __future__ imports:

for i in $(grep -REl "__future__.*absolute_import" plugins/ tests/); do
  sed -e 's/from __future__ import .*/from __future__ import annotations/g' -i $i;
done

* Remove all UTF-8 encoding specifications for Python source files:

for i in $(grep -REl '[-][*]- coding: utf-8 -[*]-' plugins/ tests/); do
  sed -e '/^# -\*- coding: utf-8 -\*-/d' -i $i;
done

* Remove __metaclass__ = type:

for i in $(grep -REl '__metaclass__ = type' plugins/ tests/); do
  sed -e '/^__metaclass__ = type/d' -i $i;
done
2025-10-10 19:52:04 +02:00

140 lines
4.2 KiB
Python

# Copyright (c) Ansible project
# Simplified BSD License (see LICENSES/BSD-2-Clause.txt or https://opensource.org/licenses/BSD-2-Clause)
# SPDX-License-Identifier: BSD-2-Clause
from __future__ import annotations
import os
import re
from ansible.module_utils.six import string_types
def _create_regex_group_complement(s):
lines = (line.strip() for line in s.split("\n") if line.strip())
chars = filter(None, (line.split("#")[0].strip() for line in lines))
group = r"[^" + r"".join(chars) + r"]"
return re.compile(group)
class HomebrewValidate(object):
# class regexes ------------------------------------------------ {{{
VALID_PATH_CHARS = r"""
\w # alphanumeric characters (i.e., [a-zA-Z0-9_])
\s # spaces
: # colons
{sep} # the OS-specific path separator
. # dots
\- # dashes
""".format(
sep=os.path.sep
)
VALID_BREW_PATH_CHARS = r"""
\w # alphanumeric characters (i.e., [a-zA-Z0-9_])
\s # spaces
{sep} # the OS-specific path separator
. # dots
\- # dashes
""".format(
sep=os.path.sep
)
VALID_PACKAGE_CHARS = r"""
\w # alphanumeric characters (i.e., [a-zA-Z0-9_])
. # dots
/ # slash (for taps)
\+ # plusses
\- # dashes
: # colons (for URLs)
@ # at-sign
"""
INVALID_PATH_REGEX = _create_regex_group_complement(VALID_PATH_CHARS)
INVALID_BREW_PATH_REGEX = _create_regex_group_complement(VALID_BREW_PATH_CHARS)
INVALID_PACKAGE_REGEX = _create_regex_group_complement(VALID_PACKAGE_CHARS)
# /class regexes ----------------------------------------------- }}}
# class validations -------------------------------------------- {{{
@classmethod
def valid_path(cls, path):
"""
`path` must be one of:
- list of paths
- a string containing only:
- alphanumeric characters
- dashes
- dots
- spaces
- colons
- os.path.sep
"""
if isinstance(path, string_types):
return not cls.INVALID_PATH_REGEX.search(path)
try:
iter(path)
except TypeError:
return False
else:
paths = path
return all(cls.valid_brew_path(path_) for path_ in paths)
@classmethod
def valid_brew_path(cls, brew_path):
"""
`brew_path` must be one of:
- None
- a string containing only:
- alphanumeric characters
- dashes
- dots
- spaces
- os.path.sep
"""
if brew_path is None:
return True
return isinstance(
brew_path, string_types
) and not cls.INVALID_BREW_PATH_REGEX.search(brew_path)
@classmethod
def valid_package(cls, package):
"""A valid package is either None or alphanumeric."""
if package is None:
return True
return isinstance(
package, string_types
) and not cls.INVALID_PACKAGE_REGEX.search(package)
def parse_brew_path(module):
# type: (...) -> str
"""Attempt to find the Homebrew executable path.
Requires:
- module has a `path` parameter
- path is a valid path string for the target OS. Otherwise, module.fail_json()
is called with msg="Invalid_path: <path>".
"""
path = module.params["path"]
if not HomebrewValidate.valid_path(path):
module.fail_json(msg="Invalid path: {0}".format(path))
if isinstance(path, string_types):
paths = path.split(":")
elif isinstance(path, list):
paths = path
else:
module.fail_json(msg="Invalid path: {0}".format(path))
brew_path = module.get_bin_path("brew", required=True, opt_dirs=paths)
if not HomebrewValidate.valid_brew_path(brew_path):
module.fail_json(msg="Invalid brew path: {0}".format(brew_path))
return brew_path