diff

package
v0.0.0-...-4a2bce8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 23, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package diff computes structured differences between two sorted record collections, keeping per-type statistics and printable summaries.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Added

type Added bool

Added means an element was added, i.e. appears in a new set but not in the original.

func (Added) String

func (a Added) String() string

type Change

type Change struct {
	// Added is the number of added elements (exist in b but not in a)
	Added uint64
	// Removed is the number of removed elements (exist in a but not in b)
	Removed uint64
	// Total is the total number of elements; added, removed or unchanged
	Total uint64
}

Change is a count of element changes in a diff.

func (*Change) Add

func (c *Change) Add(other Change)

Add adds another Change’s values to this one.

func (Change) Changed

func (c Change) Changed() uint64

Changed returns the number of added and removed elements.

func (Change) LogValue

func (c Change) LogValue() slog.Value

LogValue returns a slog.Value representing the change as a group of attributes.

func (Change) Ratio

func (c Change) Ratio() *Rat

Ratio returns the ratio of change: (added + removed) / total.

func (Change) String

func (c Change) String() string

type Comparable

type Comparable[T any] interface {
	Compare(T) int
}

Comparable is something that can be compared to something else and return an int indicating the order.

type Diff

type Diff[C Comparable[C], T cmp.Ordered] struct {
	Lines []Line[C]
	Types[T]
}

Diff is the difference between two zones.

Example
package main

import (
	"context"
	"fmt"
	"os"
	"strings"

	"gitlab.com/internetstiftelsen-oss/dnse/record"
	"gitlab.com/internetstiftelsen-oss/dnse/zone"
	"gitlab.com/internetstiftelsen-oss/dnse/zone/diff"
)

func main() {
	ctx := context.Background()

	a, b := readRecords(ctx, `
example.com.   3600  IN  NS   a.ns.example.com.
example.com.   3600  IN  NS   b.ns.example.com.
example.com.  86400  IN  MX   0 .
example.com.  86400  IN  TXT  "foo"
`), readRecords(ctx, `
example.com.  86400  IN  TXT   "bar"
example.com.  86400  IN  MX    0 .
example.com.   3600  IN  A     198.51.100.42
example.com.   3600  IN  AAAA  2001:db8::dead:beef
`)

	a.Sort(ctx)
	b.Sort(ctx)

	d, err := diff.New(ctx, a, b, func(_ context.Context, r *record.Record) zone.ClassType {
		return zone.NewClassType(r.Class(), r.Type())
	})
	if err != nil {
		panic(err)
	}

	fmt.Println("diff:")
	d.Print(ctx, os.Stdout)
	fmt.Println("summary:")
	fmt.Println(d)

}

func readRecords(ctx context.Context, str string) (records record.Records) {
	for rr, err := range zone.Read(ctx, strings.NewReader(str), nil, "") {
		if err != nil {
			panic(err)
		}

		records = append(records, record.New(rr))
	}

	return records
}
Output:

diff:
+ example.com.	3600	IN	A	198.51.100.42
- example.com.	3600	IN	NS	a.ns.example.com.
- example.com.	3600	IN	NS	b.ns.example.com.
+ example.com.	86400	IN	TXT	"bar"
- example.com.	86400	IN	TXT	"foo"
+ example.com.	3600	IN	AAAA	2001:db8::dead:beef
summary:
IN	A:	1.000 (+1-0/1)
IN	NS:	1.000 (+0-2/2)
IN	MX:	0.000 (+0-0/1)
IN	TXT:	1.000 (+1-1/2)
IN	AAAA:	1.000 (+1-0/1)
Total:	0.857 (+3-3/7)

func New

func New[C Comparable[C], T cmp.Ordered](
	ctx context.Context,
	sliceA,
	sliceB []C,
	typeFunc func(context.Context, C) T,
) (*Diff[C, T], error)

New compares two Comparable slices that must already be sorted.

func (*Diff[C, T]) Len

func (d *Diff[C, T]) Len() int

Len returns the number of differences in this Diff.

func (*Diff[C, T]) LogValue

func (d *Diff[C, T]) LogValue() slog.Value

LogValue passes to Types.LogValue.

func (*Diff[C, T]) Print

func (d *Diff[C, T]) Print(ctx context.Context, w io.Writer) error

Print prints something like unified diff.

type Line

type Line[C Comparable[C]] struct {
	Added
	OrigLine, NewLine int
	C                 C
}

Line is an added or removed element.

func (*Line[C]) String

func (l *Line[C]) String() string

String returns a short summary of the diff.

type Max

type Max struct {
	// contains filtered or unexported fields
}

Max is an inclusive limit for a change in elements. It‘s either a Rat or a uint64.

func MaxFromRat

func MaxFromRat(r *Rat) *Max

MaxFromRat creates a new Max with a Rat.

func MaxFromUint64

func MaxFromUint64(u uint64) *Max

MaxFromUint64 creates a new Max with a uint64.

func (Max) LogValue

func (m Max) LogValue() slog.Value

LogValue returns a log/slog.Value for a Max: A string for a Rat or a uint64 for a uint64.

func (*Max) MarshalYAML

func (m *Max) MarshalYAML() (any, error)

MarshalYAML encodes the Max‘s inner value, the Rat or uint64, to YAML.

func (*Max) OK

func (m *Max) OK(c Change) bool

OK returns true if a change is below the Max. If the Max is a Rat then the change’s ratio is compared to it. If it is a uint64 then the total change is compared.

func (*Max) String

func (m *Max) String() string

func (*Max) UnmarshalText

func (m *Max) UnmarshalText(text []byte) error

UnmarshalText parses a Max from text. It only allows the ‘N/N’ format.

func (*Max) UnmarshalYAML

func (m *Max) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML decodes a YAML node into a Max. A float is decoded into a Rat, an integer into a uint64 and a string uses Max.UnmarshalText. Any other type results in an error.

func (*Max) ValidateWithContext

func (m *Max) ValidateWithContext(ctx context.Context) error

ValidateWithContext returns an error if the Max is invalid.

type Rat

type Rat big.Rat

Rat wraps big.Rat with some sensible text conversion.

func NewRat

func NewRat(a, b int64) *Rat

NewRat returns a new Rat. See big.NewRat.

func (*Rat) Greater

func (r *Rat) Greater(other *Rat) bool

Greater returns true if this Rat is greater than the other.

func (*Rat) LogValue

func (r *Rat) LogValue() slog.Value

LogValue returns a float64 slog.Value of the Rat.

func (*Rat) MarshalText

func (r *Rat) MarshalText() (text []byte, err error)

MarshalText implements encoding.TextMarshaler using big.Rat.RatString.

func (*Rat) Set

func (r *Rat) Set(other *Rat) *Rat

Set sets the value of this Rat to that of an other, and returns itself.

func (*Rat) String

func (r *Rat) String() string

String returns a strings representation in a d.ddd format.

func (*Rat) UnmarshalText

func (r *Rat) UnmarshalText(text []byte) error

UnmarshalText implements encoding.TextUnmarshaler by delegating to big.Rat.UnmarshalText.

type Types

type Types[T cmp.Ordered] struct {
	// contains filtered or unexported fields
}

Types describes the differences between two slices grouped by their type, as well as the total difference.

func (*Types[T]) Add

func (t *Types[T]) Add(tt T, c Change)

Add adds a change of a type to this Diff and updates the per-type counts.

func (*Types[T]) Each

func (t *Types[T]) Each(f func(T, Change) bool)

Each calls a function with each typed change as long as the function returns true.

func (*Types[T]) LogValue

func (t *Types[T]) LogValue() slog.Value

LogValue returns a group slog.Value with all the types and changes as well as the total.

func (*Types[T]) String

func (t *Types[T]) String() string

func (*Types[T]) Total

func (t *Types[T]) Total() Change

Total returns the total change.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL