~emersion/drmdb

680b067f896eb2c76a3d7ce925988615fb38e964 — Simon Ser 2 years ago 1e9820c
cmd/drmdump: split tree formatter
3 files changed, 118 insertions(+), 101 deletions(-)

M cmd/drmdump/main.go
A treefmt/text.go
A treefmt/treefmt.go
M cmd/drmdump/main.go => cmd/drmdump/main.go +83 -101
@@ 4,33 4,15 @@ import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
	"syscall"

	"git.sr.ht/~emersion/go-drm"
	"git.sr.ht/~emersion/drmdb/treefmt"
)

type TreePrinter struct {
	w      io.Writer
	indent int
}

func NewTreePrinter(w io.Writer) *TreePrinter {
	return &TreePrinter{w: w}
}

func (tp *TreePrinter) NewChild() *TreePrinter {
	return &TreePrinter{w: tp.w, indent: tp.indent + 1}
}

func (tp *TreePrinter) Printf(format string, v ...interface{}) {
	fmt.Fprintf(tp.w, strings.Repeat("  ", tp.indent)+format+"\n", v...)
}

type DriverVersion struct {
	Major int32  `json:"major"`
	Minor int32  `json:"minor"`


@@ 117,30 99,30 @@ func driver(n *drm.Node) (*Driver, error) {
	}, nil
}

func printDriver(tp *TreePrinter, drv *Driver) {
	tp.Printf("Driver: %v (%v) version %v", drv.Name, drv.Desc, &drv.Version)
	tpc := tp.NewChild()
func printDriver(tf treefmt.Formatter, drv *Driver) {
	tf.Printf("Driver: %v (%v) version %v", drv.Name, drv.Desc, &drv.Version)
	tfc := tf.NewChild()

	for c, v := range drv.Caps {
		if v != nil {
			if c == "PRIME" {
				tpc.Printf("DRM_CAP_PRIME supported")
				tpcc := tpc.NewChild()
				tpcc.Printf("DRM_CAP_PRIME_IMPORT = %v", *v&drm.CapPrimeImport != 0)
				tpcc.Printf("DRM_CAP_PRIME_EXPORT = %v", *v&drm.CapPrimeExport != 0)
				tfc.Printf("DRM_CAP_PRIME supported")
				tfcc := tfc.NewChild()
				tfcc.Printf("DRM_CAP_PRIME_IMPORT = %v", *v&drm.CapPrimeImport != 0)
				tfcc.Printf("DRM_CAP_PRIME_EXPORT = %v", *v&drm.CapPrimeExport != 0)
			} else {
				tpc.Printf("DRM_CAP_%v = %v", c, *v)
				tfc.Printf("DRM_CAP_%v = %v", c, *v)
			}
		} else {
			tpc.Printf("DRM_CAP_%v unsupported", c)
			tfc.Printf("DRM_CAP_%v unsupported", c)
		}
	}

	for c, ok := range drv.ClientCaps {
		if ok {
			tpc.Printf("DRM_CLIENT_CAP_%v supported", c)
			tfc.Printf("DRM_CLIENT_CAP_%v supported", c)
		} else {
			tpc.Printf("DRM_CLIENT_CAP_%v unsupported", c)
			tfc.Printf("DRM_CLIENT_CAP_%v unsupported", c)
		}
	}
}


@@ 179,13 161,13 @@ func device(n *drm.Node) (*Device, error) {
	}
}

func printDevice(tp *TreePrinter, dev *Device) {
func printDevice(tf treefmt.Formatter, dev *Device) {
	switch dev.BusType {
	case drm.BusPCI:
		pci := dev.DeviceData.(*DevicePCI)
		tp.Printf("Device: %v %04X:%04X", dev.BusType, pci.Vendor, pci.Device)
		tf.Printf("Device: %v %04X:%04X", dev.BusType, pci.Vendor, pci.Device)
	default:
		tp.Printf("Device: %v", dev.BusType)
		tf.Printf("Device: %v", dev.BusType)
	}
}



@@ 411,7 393,7 @@ func properties(n *drm.Node, id drm.AnyID) (map[string]Property, error) {
	return m, nil
}

func printProperties(tp *TreePrinter, props map[string]Property) {
func printProperties(tf treefmt.Formatter, props map[string]Property) {
	for name, prop := range props {
		// TODO: immutable, atomic
		// TODO: type-specific property data


@@ 419,7 401,7 @@ func printProperties(tp *TreePrinter, props map[string]Property) {
		if val == nil {
			val = prop.Value
		}
		tp.Printf("%q: %v = %v", name, prop.Type, val)
		tf.Printf("%q: %v = %v", name, prop.Type, val)
	}
}



@@ 475,30 457,30 @@ func encoderIDsString(encs []drm.EncoderID) string {
	return s
}

func printModes(tp *TreePrinter, modes []Mode) {
func printModes(tf treefmt.Formatter, modes []Mode) {
	for _, mode := range modes {
		tp.Printf("%v", &mode)
		tf.Printf("%v", &mode)
	}
}

func printConnectors(tp *TreePrinter, conns []Connector) {
func printConnectors(tf treefmt.Formatter, conns []Connector) {
	for i, conn := range conns {
		tp.Printf("Connector %v", i)
		tpc := tp.NewChild()

		tpc.Printf("Object ID: %v", conn.ID)
		tpc.Printf("Type: %v", conn.Type)
		tpc.Printf("Status: %v", conn.Status)
		tpc.Printf("Physical size: %vx%v mm", conn.PhyWidth, conn.PhyHeight)
		tpc.Printf("Subpixel: %v", conn.Subpixel)
		tpc.Printf("Encoders: %v", encoderIDsString(conn.Encoders))
		tf.Printf("Connector %v", i)
		tfc := tf.NewChild()

		tfc.Printf("Object ID: %v", conn.ID)
		tfc.Printf("Type: %v", conn.Type)
		tfc.Printf("Status: %v", conn.Status)
		tfc.Printf("Physical size: %vx%v mm", conn.PhyWidth, conn.PhyHeight)
		tfc.Printf("Subpixel: %v", conn.Subpixel)
		tfc.Printf("Encoders: %v", encoderIDsString(conn.Encoders))
		if len(conn.Modes) > 0 {
			tpc.Printf("Modes")
			printModes(tpc.NewChild(), conn.Modes)
			tfc.Printf("Modes")
			printModes(tfc.NewChild(), conn.Modes)
		}
		if len(conn.Properties) > 0 {
			tpc.Printf("Properties")
			printProperties(tpc.NewChild(), conn.Properties)
			tfc.Printf("Properties")
			printProperties(tfc.NewChild(), conn.Properties)
		}
	}
}


@@ 524,15 506,15 @@ func encoders(n *drm.Node, card *drm.ModeCard) ([]Encoder, error) {
	return l, nil
}

func printEncoders(tp *TreePrinter, encs []Encoder) {
func printEncoders(tf treefmt.Formatter, encs []Encoder) {
	for i, enc := range encs {
		tp.Printf("Encoder %v", i)
		tpc := tp.NewChild()
		tf.Printf("Encoder %v", i)
		tfc := tf.NewChild()

		tpc.Printf("Object ID: %v", enc.ID)
		tpc.Printf("Type: %v", enc.Type)
		tpc.Printf("CRTCs: %v", bitfieldString(enc.PossibleCRTCs))
		tpc.Printf("Clones: %v", bitfieldString(enc.PossibleClones))
		tfc.Printf("Object ID: %v", enc.ID)
		tfc.Printf("Type: %v", enc.Type)
		tfc.Printf("CRTCs: %v", bitfieldString(enc.PossibleCRTCs))
		tfc.Printf("Clones: %v", bitfieldString(enc.PossibleClones))
	}
}



@@ 572,21 554,21 @@ func crtcs(n *drm.Node, card *drm.ModeCard) ([]CRTC, error) {
	return l, nil
}

func printCRTCs(tp *TreePrinter, crtcs []CRTC) {
func printCRTCs(tf treefmt.Formatter, crtcs []CRTC) {
	for i, crtc := range crtcs {
		tp.Printf("CRTC %v", i)
		tpc := tp.NewChild()
		tf.Printf("CRTC %v", i)
		tfc := tf.NewChild()

		tpc.Printf("Object ID: %v", crtc.ID)
		tpc.Printf("FB: %v", crtc.FB)
		tpc.Printf("Position: %v, %v", crtc.X, crtc.Y)
		tpc.Printf("Gamma size: %v", crtc.GammaSize)
		tfc.Printf("Object ID: %v", crtc.ID)
		tfc.Printf("FB: %v", crtc.FB)
		tfc.Printf("Position: %v, %v", crtc.X, crtc.Y)
		tfc.Printf("Gamma size: %v", crtc.GammaSize)
		if crtc.Mode != nil {
			tpc.Printf("Mode: %v", crtc.Mode)
			tfc.Printf("Mode: %v", crtc.Mode)
		}
		if len(crtc.Properties) > 0 {
			tpc.Printf("Properties")
			printProperties(tpc.NewChild(), crtc.Properties)
			tfc.Printf("Properties")
			printProperties(tfc.NewChild(), crtc.Properties)
		}
	}
}


@@ 633,29 615,29 @@ func planes(n *drm.Node) ([]Plane, error) {
	return l, nil
}

func printFormats(tp *TreePrinter, formats []drm.Format) {
func printFormats(tf treefmt.Formatter, formats []drm.Format) {
	for _, fmt := range formats {
		tp.Printf("%v", fmt)
		tf.Printf("%v", fmt)
	}
}

func printPlanes(tp *TreePrinter, planes []Plane) {
func printPlanes(tf treefmt.Formatter, planes []Plane) {
	for i, plane := range planes {
		tp.Printf("Plane %v", i)
		tpc := tp.NewChild()

		tpc.Printf("Object ID: %v", plane.ID)
		tpc.Printf("CRTC: %v", plane.CRTC)
		tpc.Printf("FB: %v", plane.FB)
		tpc.Printf("CRTCs: %v", bitfieldString(plane.PossibleCRTCs))
		tpc.Printf("Gamma size: %v", plane.GammaSize)
		tf.Printf("Plane %v", i)
		tfc := tf.NewChild()

		tfc.Printf("Object ID: %v", plane.ID)
		tfc.Printf("CRTC: %v", plane.CRTC)
		tfc.Printf("FB: %v", plane.FB)
		tfc.Printf("CRTCs: %v", bitfieldString(plane.PossibleCRTCs))
		tfc.Printf("Gamma size: %v", plane.GammaSize)
		if len(plane.Formats) > 0 {
			tpc.Printf("Formats")
			printFormats(tpc.NewChild(), plane.Formats)
			tfc.Printf("Formats")
			printFormats(tfc.NewChild(), plane.Formats)
		}
		if len(plane.Properties) > 0 {
			tpc.Printf("Properties")
			printProperties(tpc.NewChild(), plane.Properties)
			tfc.Printf("Properties")
			printProperties(tfc.NewChild(), plane.Properties)
		}
	}
}


@@ 723,31 705,31 @@ func node(nodePath string) (*Node, error) {
	}, nil
}

func printNode(tp *TreePrinter, path string, n *Node) {
	tp.Printf("Node: %s", path)
	tpc := tp.NewChild()
func printNode(tf treefmt.Formatter, path string, n *Node) {
	tf.Printf("Node: %s", path)
	tfc := tf.NewChild()

	printDriver(tpc, n.Driver)
	printDevice(tpc, n.Device)
	printDriver(tfc, n.Driver)
	printDevice(tfc, n.Device)

	tpc.Printf("Connectors")
	printConnectors(tpc.NewChild(), n.Connectors)
	tfc.Printf("Connectors")
	printConnectors(tfc.NewChild(), n.Connectors)

	tpc.Printf("Encoders")
	printEncoders(tpc.NewChild(), n.Encoders)
	tfc.Printf("Encoders")
	printEncoders(tfc.NewChild(), n.Encoders)

	tpc.Printf("CRTCs")
	printCRTCs(tpc.NewChild(), n.CRTCs)
	tfc.Printf("CRTCs")
	printCRTCs(tfc.NewChild(), n.CRTCs)

	tpc.Printf("Planes")
	printPlanes(tpc.NewChild(), n.Planes)
	tfc.Printf("Planes")
	printPlanes(tfc.NewChild(), n.Planes)
}

func main() {
	var (
		outputJSON bool
		outfutJSON bool
	)
	flag.BoolVar(&outputJSON, "j", false, "Enable JSON output")
	flag.BoolVar(&outfutJSON, "j", false, "Enable JSON outfut")
	flag.Parse()

	paths, err := filepath.Glob(drm.NodePatternPrimary)


@@ 764,15 746,15 @@ func main() {
		nodes[p] = n
	}

	if outputJSON {
	if outfutJSON {
		err = json.NewEncoder(os.Stdout).Encode(nodes)
		if err != nil {
			log.Fatalf("Failed to write JSON: %v", err)
		}
	} else {
		tp := NewTreePrinter(os.Stdout)
		tf := treefmt.NewTextFormatter(os.Stdout)
		for path, n := range nodes {
			printNode(tp, path, n)
			printNode(tf, path, n)
		}
	}
}

A treefmt/text.go => treefmt/text.go +25 -0
@@ 0,0 1,25 @@
package treefmt

import (
	"fmt"
	"io"
	"strings"
)

type textFormatter struct {
	w      io.Writer
	indent int
}

// NewTextFormatter pretty-prints a tree in a text format to w.
func NewTextFormatter(w io.Writer) Formatter {
	return &textFormatter{w: w}
}

func (tp *textFormatter) NewChild() Formatter {
	return &textFormatter{w: tp.w, indent: tp.indent + 1}
}

func (tp *textFormatter) Printf(format string, v ...interface{}) {
	fmt.Fprintf(tp.w, strings.Repeat("  ", tp.indent)+format+"\n", v...)
}

A treefmt/treefmt.go => treefmt/treefmt.go +10 -0
@@ 0,0 1,10 @@
// Package treefmt provides tree pretty-printing helpers.
package treefmt

// Formatter pretty-prints tree structures.
type Formatter interface {
	// NewChild creates a new child tree.
	NewChild() Formatter
	// Printf creates a new child leaf.
	Printf(format string, v ...interface{})
}