move argument/column handling to decoder (prepare for more post-processing in decoder)

This commit is contained in:
Stefan Bühler 2023-04-28 19:44:13 +02:00
parent 1c5b971d86
commit c03374d6df
3 changed files with 44 additions and 59 deletions

View File

@ -74,6 +74,9 @@ _TArgs = typing.TypeVar("_TArgs", bound="BaseArguments")
@dataclasses.dataclass(slots=True, kw_only=True) @dataclasses.dataclass(slots=True, kw_only=True)
class BaseArguments: class BaseArguments:
def __post_init__(self) -> None:
pass
@classmethod @classmethod
def add_fields_to_parser( def add_fields_to_parser(
cls: type[_TArgs], cls: type[_TArgs],

View File

@ -1,12 +1,28 @@
from __future__ import annotations from __future__ import annotations
import argparse
import dataclasses import dataclasses
from ldaptool._utils import argclasses from ldaptool._utils import argclasses
def _parser_add_attributes(parser: argparse.ArgumentParser, dest: str) -> None:
parser.add_argument(
metavar="attributes",
dest=dest,
nargs="*",
help="""
Attributes to lookup (and columns to display in tables).
Fake attributes `dndomain`, `dnpath` an `dnfullpath` are available (created from dn).
""",
)
@dataclasses.dataclass(slots=True, kw_only=True) @dataclasses.dataclass(slots=True, kw_only=True)
class Arguments(argclasses.BaseArguments): class Arguments(argclasses.BaseArguments):
columns: list[str] = dataclasses.field(default_factory=list, metadata=argclasses.manual(_parser_add_attributes))
attributes: list[str] = dataclasses.field(default_factory=list)
json: bool = dataclasses.field( json: bool = dataclasses.field(
default=False, default=False,
metadata=argclasses.arg(help="Use full json output"), metadata=argclasses.arg(help="Use full json output"),
@ -19,29 +35,30 @@ class Arguments(argclasses.BaseArguments):
default=", ", default=", ",
metadata=argclasses.arg(help="Separator to join multiple values of one attribute with (default: %(default)r)"), metadata=argclasses.arg(help="Separator to join multiple values of one attribute with (default: %(default)r)"),
) )
dateonly: bool = dataclasses.field( dateonly: bool = dataclasses.field(
default=True, default=True,
metadata=argclasses.arg(help="Use only date part of decoded timestamps"), metadata=argclasses.arg(help="Use only date part of decoded timestamps"),
) )
dndomain: bool = dataclasses.field(
default=False, dndomain: bool = False
metadata=argclasses.arg(help="Whether to export a virtual dndomain attribute (DNS domain from dn)"), dnpath: bool = False
) dnfullpath: bool = False
dnpath: bool = dataclasses.field(
default=False, def __post_init__(self) -> None:
metadata=argclasses.arg( super(Arguments, self).__post_init__() # super() not working here, unclear why.
help="""
Whether to export a virtual dnpath attribute # extract special attribute names
('/' joined values of reversed DN without DNS labels) attributes_set: dict[str, str] = {arg.lower(): arg for arg in self.columns} # index by lowercase name
""" # create fake attributes on demand
), if attributes_set.pop("dndomain", ""):
) self.dndomain = True
dnfullpath: bool = dataclasses.field( if attributes_set.pop("dnpath", ""):
default=False, self.dnpath = True
metadata=argclasses.arg( if attributes_set.pop("dnfullpath", ""):
help=""" self.dnfullpath = True
Whether to export a virtual dnfullpath attribute # store remaining attributes (with original case)
('/' joined values of reversed DN; DNS domain as first label) self.attributes = list(attributes_set.values())
""" if self.columns and not self.attributes:
), # if we only wanted fake attributes, make sure we only request 'dn' - empty list would query all attributes
) self.attributes = ["dn"]

View File

@ -1,6 +1,5 @@
from __future__ import annotations from __future__ import annotations
import argparse
import dataclasses import dataclasses
import typing import typing
@ -8,28 +7,8 @@ import ldaptool.decode.arguments
from ldaptool._utils import argclasses from ldaptool._utils import argclasses
def _parser_add_attributes(parser: argparse.ArgumentParser, dest: str) -> None:
parser.add_argument(
metavar="attributes",
dest=dest,
nargs="*",
help="""
Attributes to lookup (and columns to display in tables).
Fake attributes `dndomain`, `dnpath` an `dnfullpath` are available (created from dn).
""",
)
@dataclasses.dataclass(slots=True, kw_only=True) @dataclasses.dataclass(slots=True, kw_only=True)
class Arguments(ldaptool.decode.arguments.Arguments): class Arguments(ldaptool.decode.arguments.Arguments):
# overwrite fields for fake attributes to remove them from argparse;
# we enable those based on the attribute list
dndomain: bool = False
dnpath: bool = False
dnfullpath: bool = False
attributes: list[str] = dataclasses.field(default_factory=list, metadata=argclasses.manual(_parser_add_attributes))
columns: list[str] = dataclasses.field(default_factory=list)
filter: typing.Optional[str] = dataclasses.field(default=None, metadata=argclasses.arg(help="LDAP query filter")) filter: typing.Optional[str] = dataclasses.field(default=None, metadata=argclasses.arg(help="LDAP query filter"))
find: typing.Optional[str] = dataclasses.field( find: typing.Optional[str] = dataclasses.field(
default=None, default=None,
@ -75,6 +54,8 @@ class Arguments(ldaptool.decode.arguments.Arguments):
) )
def __post_init__(self) -> None: def __post_init__(self) -> None:
super(Arguments, self).__post_init__() # super() not working here, unclear why.
if not self.filter is None: if not self.filter is None:
if not self.find is None: if not self.find is None:
raise SystemExit("Can't use both --find and --filter") raise SystemExit("Can't use both --find and --filter")
@ -86,19 +67,3 @@ class Arguments(ldaptool.decode.arguments.Arguments):
else: else:
# probably doesn't like empty filter? # probably doesn't like empty filter?
self.filter = "(objectClass=*)" self.filter = "(objectClass=*)"
# extract special attribute names
self.columns = self.attributes # use all names for columns (headings and their order)
attributes_set: dict[str, str] = {arg.lower(): arg for arg in self.attributes} # index by lowercase name
# create fake attributes on demand
if attributes_set.pop("dndomain", ""):
self.dndomain = True
if attributes_set.pop("dnpath", ""):
self.dnpath = True
if attributes_set.pop("dnfullpath", ""):
self.dnfullpath = True
# store remaining attributes (with original case)
self.attributes = list(attributes_set.values())
if self.columns and not self.attributes:
# if we only wanted fake attributes, make sure we only request 'dn' - empty list would query all attributes
self.attributes = ["dn"]