Coverage for python/univention/config_registry/misc.py: 100%
49 statements
« prev ^ index » next coverage.py v7.6.0, created at 2026-09-11 14:11 +0000
« prev ^ index » next coverage.py v7.6.0, created at 2026-09-11 14:11 +0000
1"""Univention Configuration Registry helper functions."""
2# main configuration registry classes
3#
4# SPDX-FileCopyrightText: 2004-2026 Univention GmbH
5# SPDX-License-Identifier: AGPL-3.0-only
8import os
9import re
10import string # pylint: disable-msg=W0402
11import sys
12from shlex import quote as escape_value
13from typing import IO
16__all__ = [
17 'INVALID_KEY_CHARS',
18 'directory_files',
19 'escape_value',
20 'key_shell_escape',
21 'replace_dict',
22 'replace_umlaut',
23 'validate_key',
24]
27def replace_dict(line: str, dictionary: dict[str, str]) -> str:
28 """
29 Map any character from line to its value from dictionary.
31 >>> replace_dict('kernel', {'e': 'E', 'k': '', 'n': 'pp'})
32 'ErppEl'
33 """
34 return ''.join(dictionary.get(_, _) for _ in line)
37def replace_umlaut(line: str) -> str:
38 """
39 Replace german umlauts.
41 >>> replace_umlaut(u'überschrieben') == u'ueberschrieben'
42 True
43 """
44 return replace_dict(line, UMLAUTS) # pylint: disable-msg=E1101
47UMLAUTS = { # type: ignore # pylint: disable-msg=W0612
48 'Ä': 'Ae',
49 'ä': 'ae',
50 'Ö': 'Oe',
51 'ö': 'oe',
52 'Ü': 'Ue',
53 'ü': 'ue',
54 'ß': 'ss',
55}
58def asciify(text: str) -> str:
59 """
60 Replace any non-ASCII characters.
62 :param text: Input text.
63 :returns: Replaced text.
64 """
65 return text.encode('ascii', 'replace').decode("ascii")
68def key_shell_escape(line: str) -> str:
69 """
70 Escape variable name by substituting shell invalid characters by '_'.
72 :param line: UCR variable name.
73 :returns: substitued variable name
74 """
75 if not line:
76 raise ValueError('got empty line')
77 new_line = []
78 if line[0] in string.digits:
79 new_line.append('_')
80 for letter in line:
81 if letter in VALID_CHARS: # pylint: disable-msg=E1101
82 new_line.append(letter)
83 else:
84 new_line.append('_')
86 return ''.join(new_line)
89VALID_CHARS = ( # type: ignore # pylint: disable-msg=W0612
90 string.ascii_letters + string.digits + '_')
93def validate_key(key: str, out: IO = sys.stderr) -> bool:
94 """
95 Check if key consists of only shell valid characters.
97 :param key: UCR variable name to check.
98 :param out: Output stream where error message is printed to.
99 :returns: `True` if the name is valid, `False` otherwise.
100 """
101 old = key
102 key = replace_umlaut(key)
104 if old != key:
105 print('Umlauts in config variable key are not recommended. Please consider renaming "%s" to %s.' % (old, key), file=out)
106 # return False # Bug #53742
108 if len(key) > 0:
109 if ': ' in key:
110 print('Please fix invalid ": " in config variable key "%s".' % (key,), file=out)
111 return False
112 match = INVALID_KEY_CHARS.search(key)
114 if not match:
115 return True
116 print('Please fix invalid character "%s" in config variable key "%s".' % (match.group(), key), file=out)
117 return False
120INVALID_KEY_CHARS = re.compile('[][\r\n!"#$%&\'()+,;<=>?\\\\`{}§]')
123def directory_files(directory: str) -> list[str]:
124 """
125 Return a list of all files below the given directory.
127 :param directory: Base directory path.
128 :returns: List of absolute file names.
129 """
130 result = []
131 for dirpath, _dirnames, filenames in os.walk(directory):
132 for filename in filenames:
133 filename = os.path.join(dirpath, filename)
134 if os.path.isfile(filename):
135 result.append(filename)
136 return result