From: Michael Tremer Date: Wed, 10 Dec 2025 11:36:24 +0000 (+0000) Subject: exporters: Split logic for text and binary exporters X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4b1c6d02cb3355c6a963f923992388ca0aabed9e;p=dnsbl.git exporters: Split logic for text and binary exporters Signed-off-by: Michael Tremer --- diff --git a/src/dnsbl/exporters.py b/src/dnsbl/exporters.py index a52d749..a114430 100644 --- a/src/dnsbl/exporters.py +++ b/src/dnsbl/exporters.py @@ -22,6 +22,7 @@ import abc import dns.name import dns.rdataclass import dns.zone +import io class Exporter(abc.ABC): """ @@ -31,6 +32,13 @@ class Exporter(abc.ABC): self.backend = backend self.list = list + def __call__(self, f, **kwargs): + """ + The main entry point to export something with this exporter... + """ + # Export! + self.export(f, **kwargs) + @abc.abstractmethod def export(self, f, **kwargs): """ @@ -38,6 +46,24 @@ class Exporter(abc.ABC): """ raise NotImplementedError + +class TextExporter(Exporter): + def __call__(self, f, **kwargs): + detach = False + + # Convert any file handles to handle plain text + if not isinstance(f, io.TextIOBase): + f = io.TextIOWrapper(f, encoding="utf-8") + detach = True + + # Export! + super().__call__(f, **kwargs) + + # Detach the underlying stream. That way, the wrapper won't close + # the underlying file handle. + if detach: + f.detach() + def write_header(self, f, delim="#"): """ Writes a header @@ -81,7 +107,7 @@ class Exporter(abc.ABC): f.write("%s%s\n" % (delim, line)) -class DomainsExporter(Exporter): +class DomainsExporter(TextExporter): """ Exports the plain domains """ @@ -94,7 +120,7 @@ class DomainsExporter(Exporter): f.write("%s\n" % domain) -class HostsExporter(Exporter): +class HostsExporter(TextExporter): """ Exports a file like /etc/hosts """ @@ -107,7 +133,7 @@ class HostsExporter(Exporter): f.write("0.0.0.0 %s\n" % domain) -class ZoneExporter(Exporter): +class ZoneExporter(TextExporter): def export(self, f, ttl=60, rpz_action="."): # Write the header self.write_header(f, ";") diff --git a/src/dnsbl/lists.py b/src/dnsbl/lists.py index e3ee23e..042b81d 100644 --- a/src/dnsbl/lists.py +++ b/src/dnsbl/lists.py @@ -246,13 +246,6 @@ class List(sqlmodel.SQLModel, database.BackendMixin, table=True): """ Exports the list """ - detach = False - - # Convert any file handles to handle plain text - if not isinstance(f, io.TextIOBase): - f = io.TextIOWrapper(f, encoding="utf-8") - detach = True - formats = { "domains" : exporters.DomainsExporter, "dnsbl" : exporters.BlocklistExporter, @@ -269,9 +262,4 @@ class List(sqlmodel.SQLModel, database.BackendMixin, table=True): raise ValueError("Unknown output format: %s" % format) from e # Run the export - exporter.export(f, **kwargs) - - # Detach the underlying stream. That way, the wrapper won't close - # the underlying file handle. - if detach: - f.detach() + exporter(f, **kwargs) diff --git a/src/scripts/dnsbl.in b/src/scripts/dnsbl.in index e810d76..ecc5124 100644 --- a/src/scripts/dnsbl.in +++ b/src/scripts/dnsbl.in @@ -98,7 +98,7 @@ class CLI(object): # export export = subparsers.add_parser("export", help=_("Exports a list")) export.add_argument("list", help=_("The name of the list")) - export.add_argument("output", type=argparse.FileType("w"), + export.add_argument("output", type=argparse.FileType("wb"), help=_("The output file")) export.add_argument("--format", default="domains", choices=("domains", "dnsbl", "hosts", "rpz",), help=_("Output Format"))