Coverage for python/univention/ldif.py: 74%
60 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#!/usr/bin/python3
2# SPDX-FileCopyrightText: 2004-2026 Univention GmbH
3# SPDX-License-Identifier: AGPL-3.0-only
5"""Univention LDIF tool"""
8import re
9import sys
10from argparse import ArgumentParser
11from base64 import b64decode
12from collections.abc import Iterable, Iterator
13from typing import IO
16__all__ = [
17 "ldif_decode",
18 "ldif_normalize",
19 "ldif_unwrap",
20]
22RE_B64 = re.compile(r'^([a-zA-Z0-9-]+):: (.*)')
25def ldif_decode(src: IO[str] = sys.stdin, dst: IO[bytes] = sys.stdout.buffer) -> None:
26 """Decode bas64 in LDIF."""
27 try:
28 for line in src:
29 dst.write(decode64(line))
30 except BrokenPipeError:
31 pass
34def decode(stream: Iterable[str]) -> Iterator[bytes]:
35 for line in stream:
36 yield decode64(line)
39def decode64(line: str) -> bytes:
40 m = RE_B64.search(line)
41 if m:
42 attr, encoded = m.groups()
43 decoded = b64decode(encoded)
44 return b"%s: %s\n" % (attr.encode("utf-8"), decoded)
45 else:
46 return line.encode("utf-8")
49def ldif_unwrap(src: IO[str] = sys.stdin, dst: IO[bytes] = sys.stdout.buffer) -> None:
50 """Unwrap LDIF."""
51 try:
52 for line in unwrap(src):
53 dst.write(line.encode("utf-8"))
54 except BrokenPipeError:
55 pass
58def unwrap(stream: Iterable[str]) -> Iterator[str]:
59 prev = ""
60 for line in stream:
61 if line[:1] in (' ', '\t'):
62 prev = prev.rstrip("\n\r") + line[1:]
63 else:
64 if prev:
65 yield prev
66 prev = line
68 if prev: 68 ↛ exitline 68 didn't return from function 'unwrap' because the condition on line 68 was always true
69 yield prev
72def ldif_normalize(src: IO[str] = sys.stdin, dst: IO[bytes] = sys.stdout.buffer) -> None:
73 """Unwrap and base64 decode LDIF."""
74 try:
75 for line in unwrap(src):
76 dst.write(decode64(line))
77 except BrokenPipeError:
78 pass
81def main() -> None:
82 parser = ArgumentParser(description=__doc__)
83 parser.add_argument("--src", "-s", default="-", help="Source input")
84 parser.add_argument("--dst", "-d", default="-", help="Destination output")
86 parser.set_defaults(func=ldif_normalize)
87 subparsers = parser.add_subparsers(help="Sub-command help")
89 parser_decode = subparsers.add_parser("decode", help=ldif_decode.__doc__)
90 parser_decode.set_defaults(func=ldif_decode)
92 parser_unwrap = subparsers.add_parser("unwrap", help=ldif_unwrap.__doc__)
93 parser_unwrap.set_defaults(func=ldif_unwrap)
95 args = parser.parse_args()
96 src = sys.stdin if args.src == "-" else open(args.src)
97 dst = sys.stdout if args.dst == "-" else open(args.dst, "w")
98 args.func(src, dst.buffer)
101if __name__ == "__main__":
102 main()