121 } |
125 } |
122 |
126 |
123 return $out // $ttl; |
127 return $out // $ttl; |
124 } |
128 } |
125 |
129 |
126 { |
130 sub nice { |
127 my %order = map { state $n = 0; $_ => ++$n } qw(SOA NS TXT MX A AAAA SSHFP); |
131 |
128 |
132 # get a list of { id => $id, rrset => \%rrset } |
129 sub nice { |
133 # we do a schwartz transformation here |
130 |
134 # [ reverse LABEL, RRSET ] |
131 # get a list of { id => $id, rrset => \%rrset } |
135 my @zone = map { $_->[1] } |
132 # we do a schwartz transformation here |
136 sort { |
133 # [ reverse LABEL, RRSET ] |
137 $a->[0] cmp $b->[0] |
134 my @zone = map { $_->[1] } |
138 or length $a->[1]{label} <=> length $b->[1]{label} |
135 sort { |
139 or ($ORDER{ $a->[1]{rrtype} } // 99) <=> ($ORDER{ $b->[1]{rrtype} } // 99) |
136 $a->[0] cmp $b->[0] |
140 } |
137 or length $a->[1]{label} <=> length $b->[1]{label} |
141 map { [scalar reverse($_->{label}), $_] } map { $_->{rrset} } @_; |
138 or ($order{ $a->[1]{rrtype} } // 99) <=> ($order{ $b->[1]{rrtype} } // 99) |
142 |
139 } |
143 my @out; |
140 map { [scalar reverse($_->{label}), $_] } map { $_->{rrset} } @_; |
144 my $origin = (grep { $_->{rrtype} eq 'SOA' } @zone)[0]->{label}; |
141 |
145 my $ttl = (grep { $_->{rrtype} eq 'SOA' } @zone)[0]->{ttl}; |
142 my @out; |
146 my $len1 = |
143 my $origin = (grep { $_->{rrtype} eq 'SOA' } @zone)[0]->{label}; |
147 (sort { $a <=> $b } map { index $_->{label}, '.' } @zone)[-1]; |
144 my $ttl = (grep { $_->{rrtype} eq 'SOA' } @zone)[0]->{ttl}; |
148 my $len2 = (sort { $a <=> $b } map { length $_->{rrtype} } @zone)[-1]; |
145 my $len1 = |
149 push @out, "\$ORIGIN $origin", "\$TTL " . ttl2h($ttl); |
146 (sort { $a <=> $b } map { index $_->{label}, '.' } @zone)[-1]; |
150 |
147 my $len2 = (sort { $a <=> $b } map { length $_->{rrtype} } @zone)[-1]; |
151 my $print = sub { |
148 push @out, "\$ORIGIN $origin", "\$TTL " . ttl2h($ttl); |
152 my %r = %{ +shift }; |
149 |
153 state $last_label; |
150 my $print = sub { |
154 |
151 my %r = %{ +shift }; |
155 $r{label} = '@' if $r{label} eq $origin; |
152 state $last_label; |
156 $r{label} =~ s{\.\Q$origin\E$}{}; |
153 |
157 $r{data} =~ s{\.\Q$origin\E$}{} |
154 $r{label} = '@' if $r{label} eq $origin; |
158 if $r{rrtype} ~~ [qw(CNAME MX SOA PTR)]; |
155 $r{label} =~ s{\.\Q$origin\E$}{}; |
159 $r{data} =~ s{\Q$origin\E$}{\@} if $r{rrtype} ~~ [qw(CNAME MX)]; |
156 $r{data} =~ s{\.\Q$origin\E$}{} |
160 $r{ttl} = $r{ttl} == $ttl ? '' : ttl2h($r{ttl}); |
157 if $r{rrtype} ~~ [qw(CNAME MX SOA PTR)]; |
161 $r{label} = do { |
158 $r{data} =~ s{\Q$origin\E$}{\@} if $r{rrtype} ~~ [qw(CNAME MX)]; |
162 if (defined $last_label and $r{label} eq $last_label) { '' } |
159 $r{ttl} = $r{ttl} == $ttl ? '' : ttl2h($r{ttl}); |
163 else { $last_label = $r{label} } |
160 $r{label} = do { |
164 }; |
161 if (defined $last_label and $r{label} eq $last_label) { '' } |
165 |
162 else { $last_label = $r{label} } |
166 return sprintf '%-*s %6s %-*s %s', |
163 }; |
167 $len1 => $r{label}, |
164 |
168 $r{ttl}, |
165 return sprintf '%-*s %6s %-*s %s', |
169 $len2 => $r{rrtype}, |
166 $len1 => $r{label}, |
170 $r{data}; |
167 $r{ttl}, |
171 }; |
168 $len2 => $r{rrtype}, |
172 push @out, '; do NOT EDIT the SOA records SERIAL number!'; |
169 $r{data}; |
173 push @out, $print->($_) foreach @zone; |
170 }; |
174 return join "\n", @out, ''; |
171 push @out, '; do NOT EDIT the SOA records SERIAL number!'; |
|
172 push @out, $print->($_) foreach @zone; |
|
173 return join "\n", @out, ''; |
|
174 } |
|
175 } |
175 } |
176 |
176 |
177 sub delta { |
177 sub delta { |
178 my ($zone1, $zone2) = @_; |
178 my ($zone1, $zone2) = @_; |
179 my %zone1 = map { $_->{id}, $_->{rrset} } @$zone1; |
179 my %zone1 = map { $_->{id}, $_->{rrset} } @$zone1; |