]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
Add want_origin parameter to zone to_text() and to_file().
authorBob Halley <halley@dnspython.org>
Sun, 13 Jun 2021 21:50:13 +0000 (14:50 -0700)
committerBob Halley <halley@dnspython.org>
Sun, 13 Jun 2021 21:50:13 +0000 (14:50 -0700)
[Issue #654]

dns/zone.py
tests/example4.good [new file with mode: 0644]
tests/test_zone.py

index 65eb35b294406a618f86393a1fed6ce207422438..9c3204b366c84b12ce4d94e6fce284f5c8c8f29a 100644 (file)
@@ -584,7 +584,7 @@ class Zone(dns.transaction.TransactionManager):
                         yield (name, rds.ttl, rdata)
 
     def to_file(self, f, sorted=True, relativize=True, nl=None,
-                want_comments=False):
+                want_comments=False, want_origin=False):
         """Write a zone to a file.
 
         *f*, a file or `str`.  If *f* is a string, it is treated
@@ -606,6 +606,10 @@ class Zone(dns.transaction.TransactionManager):
         *want_comments*, a ``bool``.  If ``True``, emit end-of-line comments
         as part of writing the file.  If ``False``, the default, do not
         emit them.
+
+        *want_origin*, a ``bool``.  If ``True``, emit a $ORIGIN line at
+        the start of the file.  If ``False``, the default, do not emit
+        one.
         """
 
         with contextlib.ExitStack() as stack:
@@ -628,6 +632,16 @@ class Zone(dns.transaction.TransactionManager):
                 nl_b = nl
                 nl = nl.decode()
 
+            if want_origin:
+                l = '$ORIGIN ' + self.origin.to_text()
+                l_b = l.encode(file_enc)
+                try:
+                    f.write(l_b)
+                    f.write(nl_b)
+                except TypeError:  # textual mode
+                    f.write(l)
+                    f.write(nl)
+
             if sorted:
                 names = list(self.keys())
                 names.sort()
@@ -647,7 +661,7 @@ class Zone(dns.transaction.TransactionManager):
                     f.write(nl)
 
     def to_text(self, sorted=True, relativize=True, nl=None,
-                want_comments=False):
+                want_comments=False, want_origin=False):
         """Return a zone's text as though it were written to a file.
 
         *sorted*, a ``bool``.  If True, the default, then the file
@@ -667,10 +681,15 @@ class Zone(dns.transaction.TransactionManager):
         as part of writing the file.  If ``False``, the default, do not
         emit them.
 
+        *want_origin*, a ``bool``.  If ``True``, emit a $ORIGIN line at
+        the start of the output.  If ``False``, the default, do not emit
+        one.
+
         Returns a ``str``.
         """
         temp_buffer = io.StringIO()
-        self.to_file(temp_buffer, sorted, relativize, nl, want_comments)
+        self.to_file(temp_buffer, sorted, relativize, nl, want_comments,
+                     want_origin)
         return_value = temp_buffer.getvalue()
         temp_buffer.close()
         return return_value
diff --git a/tests/example4.good b/tests/example4.good
new file mode 100644 (file)
index 0000000..f2c90d7
--- /dev/null
@@ -0,0 +1,154 @@
+$ORIGIN example.
+@ 300 IN SOA ns1 hostmaster 1 2 3 4 5
+@ 300 IN NS ns1
+@ 300 IN NS ns2
+@ 300 IN NSEC3PARAM 1 1 12 aabbccdd
+@ 300 IN NSEC3PARAM 1 1 12 -
+* 300 IN MX 10 mail
+a 300 IN TXT "foo foo foo"
+a 300 IN PTR foo.net.
+a01 3600 IN A 0.0.0.0
+a02 3600 IN A 255.255.255.255
+aaaa01 3600 IN AAAA ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+aaaa02 3600 IN AAAA ::1
+afsdb01 3600 IN AFSDB 0 hostname
+afsdb02 3600 IN AFSDB 65535 .
+amtrelay01 3600 IN AMTRELAY 0 0 0 .
+amtrelay02 3600 IN AMTRELAY 0 1 0 .
+amtrelay03 3600 IN AMTRELAY 10 0 1 203.0.113.15
+amtrelay04 3600 IN AMTRELAY 10 0 2 2001:db8::15
+amtrelay05 3600 IN AMTRELAY 128 1 3 amtrelays.example.com.
+apl01 3600 IN APL 1:192.168.32.0/21 !1:192.168.38.0/28
+apl02 3600 IN APL 1:224.0.0.0/4 2:FF00:0:0:0:0:0:0:0/8
+avc01 3600 IN AVC "app-name:WOLFGANG|app-class:OAM|business=yes"
+b 300 IN CNAME foo.net.
+c 300 IN A 73.80.65.49
+caa01 3600 IN CAA 0 issue "ca.example.net"
+caa02 3600 IN CAA 0 iodef "mailto:security@example.com"
+caa03 3600 IN CAA 0 iodef "http://iodef.example.com/"
+caa04 3600 IN CAA 0 issue "ca.example.net; account=230123"
+caa05 3600 IN CAA 0 issue "ca.example.net; policy=ev"
+caa06 3600 IN CAA 128 tbs "Unknown"
+cdnskey01 3600 IN CDNSKEY 256 3 8 AwEAAbmiLgh411Pz3v3XCSBrvYf52A/G v55ItN1NbOLHCqt3Ec3p+VB/kQ87VjjM rycanZFnZT4l9uCFuYh21CcyxVpcxExb M0UuhX5rJoDyeFSXoQlkHrB01osPl5Vr i5YmKtcmqGxZ9An0VSunohkyiX1SrNRZ SdQnk9/pIHDe/c8D
+cds01 3600 IN CDS 12345 3 1 123456789abcdef67890123456789abcdef67890
+cert01 3600 IN CERT 65534 65535 PRIVATEOID MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY=
+cname01 3600 IN CNAME cname-target.
+cname02 3600 IN CNAME cname-target
+cname03 3600 IN CNAME .
+csync0 3600 IN CSYNC 12345 0 A MX RRSIG NSEC TYPE1234
+d 300 IN A 73.80.65.49
+dhcid01 3600 IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69 lOjxfNuVAA2kjEA=
+dhcid02 3600 IN DHCID AAEBOSD+XR3Os/0LozeXVqcNc7FwCfQd WL3b/NaiUDlW2No=
+dhcid03 3600 IN DHCID AAABxLmlskllE0MVjd57zHcWmEH3pCQ6 VytcKD//7es/deY=
+dlv01 3600 IN DLV 12345 3 1 123456789abcdef67890123456789abcdef67890
+dname01 3600 IN DNAME dname-target.
+dname02 3600 IN DNAME dname-target
+dname03 3600 IN DNAME .
+dnskey01 3600 IN DNSKEY 512 255 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8=
+dnskey02 3600 IN DNSKEY 257 3 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRu niJDBzC7w0aRyzWZriO6i2odGWWQVucZ qKVsENW91IOW4vqudngPZsY3GvQ/xVA8 /7pyFj6b7Esga60zyGW6LFe9r8n6paHr lG5ojqf0BaqHT+8=
+ds01 3600 IN DS 12345 3 1 123456789abcdef67890123456789abcdef67890
+e 300 IN MX 10 mail
+e 300 IN TXT "one"
+e 300 IN TXT "three"
+e 300 IN TXT "two"
+e 300 IN A 73.80.65.49
+e 300 IN A 73.80.65.50
+e 300 IN A 73.80.65.52
+e 300 IN A 73.80.65.51
+f 300 IN A 73.80.65.52
+gpos01 3600 IN GPOS -22.6882 116.8652 250.0
+hinfo01 3600 IN HINFO "Generic PC clone" "NetBSD-1.4"
+hinfo02 3600 IN HINFO "PC" "NetBSD"
+hip01 3600 IN HIP 2 200100107b1a74df365639cc39f1d578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D
+hip02 3600 IN HIP 2 200100107b1a74df365639cc39f1d578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs.example.com.
+hip03 3600 IN HIP 2 200100107b1a74df365639cc39f1d578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs1.example.com. rvs2.example.com.
+https01 3600 IN HTTPS 0 svc
+https02 3600 IN HTTPS 1 . port="8002" ech="abcd"
+ipseckey01 3600 IN IPSECKEY 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ==
+ipseckey02 3600 IN IPSECKEY 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ==
+ipseckey03 3600 IN IPSECKEY 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ==
+ipseckey04 3600 IN IPSECKEY 10 2 2 2001:0DB8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ==
+ipseckey05 3600 IN IPSECKEY 10 3 2 mygateway2 AQNRU3mG7TVTO2BkR47usntb102uFJtu gbo6BSGvgqt4AQ==
+isdn01 3600 IN ISDN "isdn-address"
+isdn02 3600 IN ISDN "isdn-address" "subaddress"
+isdn03 3600 IN ISDN "isdn-address"
+isdn04 3600 IN ISDN "isdn-address" "subaddress"
+kx01 3600 IN KX 10 kdc
+kx02 3600 IN KX 10 .
+loc01 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m
+loc02 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m
+loc03 3600 IN LOC 60 9 0.000 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m
+loc04 3600 IN LOC 60 9 1.500 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m
+loc05 3600 IN LOC 60 9 1.510 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m
+loc06 3600 IN LOC 60 9 1.000 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m
+loc07 3600 IN LOC 0 9 1.000 N 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m
+loc08 3600 IN LOC 0 9 1.000 S 24 39 0.000 E 10.00m 90000000.00m 2000.00m 20.00m
+mx01 3600 IN MX 10 mail
+mx02 3600 IN MX 10 .
+naptr01 3600 IN NAPTR 0 0 "" "" "" .
+naptr02 3600 IN NAPTR 65535 65535 "blurgh" "blorf" "blegh" foo.
+ns1 300 IN A 10.53.0.1
+ns2 300 IN A 10.53.0.2
+nsap-ptr01 3600 IN NSAP-PTR foo.
+nsap-ptr01 3600 IN NSAP-PTR .
+nsap01 3600 IN NSAP 0x47000580005a0000000001e133ffffff00016100
+nsap02 3600 IN NSAP 0x47000580005a0000000001e133ffffff00016100
+nsec01 3600 IN NSEC a.secure A MX RRSIG NSEC TYPE1234
+nsec02 3600 IN NSEC . NSAP-PTR NSEC
+nsec03 3600 IN NSEC . NSEC TYPE65535
+nsec301 3600 IN NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM
+nsec302 3600 IN NSEC3 1 1 12 - 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM
+openpgpkey 3600 IN OPENPGPKEY mQENBEteQDsBCADYnatn9+5t43AdJlVk9dZC2RM0idPQcmrrKcjeAWDnISqoJzkvQ8ifX6mefquTBsDZC279uXShyTffYzQtvP2r9ewkK7zmSv52Ar563TSULAMwiLpe0gGQE0ex20mX5ggtYn6czdbEtcKpW0t+AfDqRk5YcpgqfZKXapKQ+A3CwWJKP9i3ldx2Jz//kuru4YqROLBYyB8D6V2jNUFOdaP6j5C5prh9dxfYFp2O/xFeAKLWlWuH9o96INUoIhgdEyj9PHPT3c821NMZu8tCvsZgUB+QPbHA/QYGa+aollcdGkJpVxXoHhbu6aMx/B+pXg55WM5pqOxmoVjyViHIUYfPABEBAAG0IUJvYiBIYWxsZXkgPGhhbGxleUBkbnNweXRob24ub3JnPokBPgQTAQIAKAUCS15AOwIbAwUJA8JnAAYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQ6o6Gb8yUnXaflQgAhlhIqZGncRw3LV3d24JmPD+UEcEGiVh2b/Ic/1TMec46Ts7ZqRXAcOATNteQmpzqexx+BRKDWU8ZgYx12J4GZmC06jABr2JDWxgvbMX9qjkUUgDGZZgAS/B2x5AmKgy2ZnCUlaKfePcKmtKTB9yNJ8v/WERlFdGaUveEUiFU8g75xp1Hj9Wp9sXCg9yeG1K2RwQ3RQd5tLudhyE67EQdFGgqQFynR53md7cmVhAGopKLwMkpCtToKUlxxlfnDfpKZhhXThmhA0PsUQUkJptfGwYwH3O2N3KzfUw3wXRvLa3hona3TlHk3kfg7Qyd7oP4AZGbJKp97YHnfqo1kp8rObkBDQRLXkA7AQgA0ePG7g5GgZ/1SdtGZlJJiE2X15vTUc3KGfmx/kI5NaUDu4fXb+XK+yFy9I/X+UJ46JSkyhj6QvUxpoI+A7WWk9ThfjbynoZxRD820KbqidqxBSgtFF36SRWzmX8DZfKKAskT9ZGU1odeSKDXLCJF7qAbZVRTuFRiDFGwtoVIICeE6Xd65JO6ufhad+ELhgFt95vRwTiFvVrBRjwF7ZgN/nOXfYncxZ/2mpFqfwsnB2eu0A2XZBm8IngsSmr/Wrz1RQ7+SNMqt77E7CKwBX7UIAZgyoJxIRxWirJoOt1rIm5VUqRR25ubXLuzx9PaHYiC5GiQIU45pWAd0IWcTI/MJQARAQABiQElBBgBAgAPBQJLXkA7AhsMBQkDwmcAAAoJEOqOhm/MlJ12HRsIAKrB9E++9X9W6VTXBfdkShCFv0ykZVn2eVs6tkqzoub9s4f+Z5ylWw+a5nkMDMdGVe6bn4A3oIAbf0Tjykq1AetZLVPsHl/QosTbSQluis/PEvJkTQXHaKHB3bFhwA90c/3HNhrLGugt9AmcfLf9LAynXDgNLV5eYdPYqfKE+27qjEBARf6PYh/8WQ8CPKS8DILFbwCZbRxUogyrZf/7AiHAGdJi8dmpR1WPQYef2hF3kqGX6NngLBPzZ6CQRaHBhD4pHU1S/IRSlx9/3Ytww32PYD9AyO732NmCUcq3bmvqcOWy4Cc1NkEwU0Vg0qzwVBNGb84v/ex2MouwtAYScwc=
+ptr01 3600 IN PTR @
+px01 3600 IN PX 65535 foo. bar.
+px02 3600 IN PX 65535 . .
+rp01 3600 IN RP mbox-dname txt-dname
+rp02 3600 IN RP . .
+rrsig01 3600 IN RRSIG NSEC 1 3 3600 20200101000000 20030101000000 2143 foo MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY=
+rrsig02 3600 IN RRSIG NSEC 1 3 3600 20200101000000 20030101000000 2143 foo MxFcby9k/yvedMfQgKzhH5er0Mu/vILz 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY=
+rt01 3600 IN RT 0 intermediate-host
+rt02 3600 IN RT 65535 .
+s 300 IN NS ns.s
+ns.s 300 IN A 73.80.65.49
+smimea1 3600 IN SMIMEA 3 1 1 a9cdf989b504fe5dca90c0d2167b6550570734f7c763e09fdf88904e06157065
+smimea2 3600 IN SMIMEA 1 0 1 efddf0d915c7bdc5782c0881e1b2a95ad099fbdd06d7b1f77982d9364338d955
+smimea3 3600 IN SMIMEA 1 0 2 81ee7f6c0ecc6b09b7785a9418f54432de630dd54dc6ee9e3c49de547708d236d4c413c3e97e44f969e635958aa410495844127c04883503e5b024cf7a8f6a94
+spf 3600 IN SPF "v=spf1 mx -all"
+srv01 3600 IN SRV 0 0 0 .
+srv02 3600 IN SRV 65535 65535 65535 old-slow-box.example.com.
+sshfp1 3600 IN SSHFP 1 1 aa549bfe898489c02d1715d97d79c57ba2fa76ab
+svcb01 3600 IN SVCB 100 foo.com. mandatory="alpn,port" alpn="h2,h3" no-default-alpn port="12345" ipv4hint="1.2.3.4,4.3.2.1" ech="abcd" ipv6hint="1::2,3::4" key12345="foo"
+t 301 IN A 73.80.65.49
+tlsa1 3600 IN TLSA 3 1 1 a9cdf989b504fe5dca90c0d2167b6550570734f7c763e09fdf88904e06157065
+tlsa2 3600 IN TLSA 1 0 1 efddf0d915c7bdc5782c0881e1b2a95ad099fbdd06d7b1f77982d9364338d955
+tlsa3 3600 IN TLSA 1 0 2 81ee7f6c0ecc6b09b7785a9418f54432de630dd54dc6ee9e3c49de547708d236d4c413c3e97e44f969e635958aa410495844127c04883503e5b024cf7a8f6a94
+txt01 3600 IN TXT "foo"
+txt02 3600 IN TXT "foo" "bar"
+txt03 3600 IN TXT "foo"
+txt04 3600 IN TXT "foo" "bar"
+txt05 3600 IN TXT "foo bar"
+txt06 3600 IN TXT "foo bar"
+txt07 3600 IN TXT "foo bar"
+txt08 3600 IN TXT "foo\010bar"
+txt09 3600 IN TXT "foo\010bar"
+txt10 3600 IN TXT "foo bar"
+txt11 3600 IN TXT "\"foo\""
+txt12 3600 IN TXT "\"foo\""
+txt13 3600 IN TXT "foo;"
+txt14 3600 IN TXT "foo;"
+txt15 3600 IN TXT "bar\\;"
+u 300 IN TXT "txt-not-in-nxt"
+a.u 300 IN A 73.80.65.49
+b.u 300 IN A 73.80.65.49
+unknown2 3600 IN TYPE999 \# 8 0a0000010a000001
+unknown3 3600 IN A 127.0.0.2
+uri01 3600 IN URI 10 1 "ftp://ftp1.example.com/public"
+uri02 3600 IN URI 10 1 "http://www.example.com/path"
+wks01 3600 IN WKS 10.0.0.1 6 0 1 2 21 23
+wks02 3600 IN WKS 10.0.0.1 17 0 1 2 53
+wks03 3600 IN WKS 10.0.0.2 6 65535
+x2501 3600 IN X25 "123456789"
+zonemd01 3600 IN ZONEMD 2018031900 1 1 62e6cf51b02e54b9b5f967d547ce43136792901f9f88e637493daaf401c92c279dd10f0edb1c56f8080211f8480ee306
+zonemd02 3600 IN ZONEMD 2018031900 1 2 08cfa1115c7b948c4163a901270395ea226a930cd2cbcf2fa9a5e6eb85f37c8a4e114d884e66f176eab121cb02db7d652e0cc4827e7a3204f166b47e5613fd27
+zonemd03 3600 IN ZONEMD 2018031900 1 240 e2d523f654b9422a96c5a8f44607bbee
+zonemd04 3600 IN ZONEMD 2018031900 241 1 e1846540e33a9e4189792d18d5d131f605fc283eaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
index 26adc878173681e30b9f1cb9533d0b8a51922c9e..e8dd9667a053a79f7720cbad19a3e959ca5a7812 100644 (file)
@@ -332,6 +332,34 @@ class ZoneTestCase(unittest.TestCase):
                 os.unlink(here('example3.out'))
         self.assertTrue(ok)
 
+    def testToFileTextualWithOrigin(self):
+        z = dns.zone.from_file(here('example'), 'example')
+        try:
+            f = open(here('example4-textual.out'), 'w')
+            z.to_file(f, want_origin=True)
+            f.close()
+            ok = compare_files('testToFileTextualWithOrigin',
+                               here('example4-textual.out'),
+                               here('example4.good'))
+        finally:
+            if not _keep_output:
+                os.unlink(here('example4-textual.out'))
+        self.assertTrue(ok)
+
+    def testToFileBinaryWithOrigin(self):
+        z = dns.zone.from_file(here('example'), 'example')
+        try:
+            f = open(here('example4-binary.out'), 'wb')
+            z.to_file(f, want_origin=True)
+            f.close()
+            ok = compare_files('testToFileBinaryWithOrigin',
+                               here('example4-binary.out'),
+                               here('example4.good'))
+        finally:
+            if not _keep_output:
+                os.unlink(here('example4-binary.out'))
+        self.assertTrue(ok)
+
     def testFromText(self):
         z = dns.zone.from_text(example_text, 'example.', relativize=True)
         f = StringIO()