printer/templateprinter.go
author Mikael Berthe <mikael@lilotux.net>
Mon, 01 May 2017 12:42:37 +0200
changeset 50 c6adf9d9e996
parent 49 d6b4e3b7c6c6
child 51 300ac09051a7
permissions -rw-r--r--
Disable ANSI sequences when stdout is not a TTY
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
0
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     1
// Copyright © 2017 Mikael Berthe <mikael@lilotux.net>
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     2
//
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     3
// Licensed under the MIT license.
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     4
// Please see the LICENSE file is this directory.
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     5
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     6
package printer
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     7
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     8
import (
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     9
	"encoding/json"
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    10
	"fmt"
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    11
	"io"
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    12
	"os"
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    13
	"reflect"
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    14
	"text/template"
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    15
40
ad148f60dc87 TemplatePrinter: Handle InstanceStatus lists
Mikael Berthe <mikael@lilotux.net>
parents: 14
diff changeset
    16
	"github.com/m0t0k1ch1/gomif"
50
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
    17
	"github.com/mattn/go-isatty"
40
ad148f60dc87 TemplatePrinter: Handle InstanceStatus lists
Mikael Berthe <mikael@lilotux.net>
parents: 14
diff changeset
    18
0
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    19
	"github.com/McKael/madon"
49
d6b4e3b7c6c6 Add ANSI color support to templates (function "color")
Mikael Berthe <mikael@lilotux.net>
parents: 41
diff changeset
    20
	"github.com/McKael/madonctl/printer/colors"
0
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    21
)
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    22
50
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
    23
// DisableColors can be set to true to disable the color template function
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
    24
var DisableColors bool
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
    25
0
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    26
// TemplatePrinter represents a Template printer
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    27
type TemplatePrinter struct {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    28
	rawTemplate string
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    29
	template    *template.Template
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    30
}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    31
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    32
// NewPrinterTemplate returns a Template ResourcePrinter
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    33
// For TemplatePrinter, the option parameter contains the template string.
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    34
func NewPrinterTemplate(option string) (*TemplatePrinter, error) {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    35
	tmpl := option
41
909c3ddd83f6 Add fromunix filter to templates (converts date from UNIX timestamp)
Mikael Berthe <mikael@lilotux.net>
parents: 40
diff changeset
    36
	t, err := template.New("output").Funcs(template.FuncMap{
909c3ddd83f6 Add fromunix filter to templates (converts date from UNIX timestamp)
Mikael Berthe <mikael@lilotux.net>
parents: 40
diff changeset
    37
		"fromhtml": html2string,
909c3ddd83f6 Add fromunix filter to templates (converts date from UNIX timestamp)
Mikael Berthe <mikael@lilotux.net>
parents: 40
diff changeset
    38
		"fromunix": unix2string,
50
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
    39
		"color":    ansiColor,
41
909c3ddd83f6 Add fromunix filter to templates (converts date from UNIX timestamp)
Mikael Berthe <mikael@lilotux.net>
parents: 40
diff changeset
    40
	}).Parse(tmpl)
0
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    41
	if err != nil {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    42
		return nil, err
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    43
	}
50
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
    44
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
    45
	// Check if stdout is a TTY
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
    46
	if !isatty.IsTerminal(os.Stdout.Fd()) {
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
    47
		DisableColors = true
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
    48
	}
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
    49
0
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    50
	return &TemplatePrinter{
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    51
		rawTemplate: tmpl,
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    52
		template:    t,
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    53
	}, nil
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    54
}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    55
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    56
// PrintObj sends the object as text to the writer
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    57
// If the writer w is nil, standard output will be used.
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    58
func (p *TemplatePrinter) PrintObj(obj interface{}, w io.Writer, tmpl string) error {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    59
	if w == nil {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    60
		w = os.Stdout
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    61
	}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    62
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    63
	if p.template == nil {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    64
		return fmt.Errorf("template not built")
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    65
	}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    66
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    67
	switch ot := obj.(type) { // I wish I knew a better way...
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    68
	case []madon.Account, []madon.Application, []madon.Attachment, []madon.Card,
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    69
		[]madon.Client, []madon.Context, []madon.Instance, []madon.Mention,
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    70
		[]madon.Notification, []madon.Relationship, []madon.Report,
40
ad148f60dc87 TemplatePrinter: Handle InstanceStatus lists
Mikael Berthe <mikael@lilotux.net>
parents: 14
diff changeset
    71
		[]madon.Results, []madon.Status, []madon.StreamEvent, []madon.Tag,
ad148f60dc87 TemplatePrinter: Handle InstanceStatus lists
Mikael Berthe <mikael@lilotux.net>
parents: 14
diff changeset
    72
		[]*gomif.InstanceStatus:
0
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    73
		return p.templateForeach(ot, w)
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    74
	}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    75
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    76
	return p.templatePrintSingleObj(obj, w)
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    77
}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    78
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    79
func (p *TemplatePrinter) templatePrintSingleObj(obj interface{}, w io.Writer) error {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    80
	// This code comes from Kubernetes.
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    81
	data, err := json.Marshal(obj)
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    82
	if err != nil {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    83
		return err
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    84
	}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    85
	out := map[string]interface{}{}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    86
	if err := json.Unmarshal(data, &out); err != nil {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    87
		return err
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    88
	}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    89
	if err = p.safeExecute(w, out); err != nil {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    90
		return fmt.Errorf("error executing template %q: %v", p.rawTemplate, err)
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    91
	}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    92
	return nil
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    93
}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    94
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    95
// safeExecute tries to execute the template, but catches panics and returns an error
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    96
// should the template engine panic.
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    97
// This code comes from Kubernetes.
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    98
func (p *TemplatePrinter) safeExecute(w io.Writer, obj interface{}) error {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    99
	var panicErr error
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   100
	// Sorry for the double anonymous function. There's probably a clever way
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   101
	// to do this that has the defer'd func setting the value to be returned, but
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   102
	// that would be even less obvious.
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   103
	retErr := func() error {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   104
		defer func() {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   105
			if x := recover(); x != nil {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   106
				panicErr = fmt.Errorf("caught panic: %+v", x)
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   107
			}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   108
		}()
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   109
		return p.template.Execute(w, obj)
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   110
	}()
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   111
	if panicErr != nil {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   112
		return panicErr
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   113
	}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   114
	return retErr
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   115
}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   116
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   117
func (p *TemplatePrinter) templateForeach(ol interface{}, w io.Writer) error {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   118
	switch reflect.TypeOf(ol).Kind() {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   119
	case reflect.Slice:
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   120
		s := reflect.ValueOf(ol)
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   121
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   122
		for i := 0; i < s.Len(); i++ {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   123
			o := s.Index(i).Interface()
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   124
			if err := p.templatePrintSingleObj(o, w); err != nil {
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   125
				return err
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   126
			}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   127
		}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   128
	}
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   129
	return nil
5abace724584 Initial public release
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   130
}
50
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
   131
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
   132
func ansiColor(desc string) (string, error) {
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
   133
	if DisableColors {
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
   134
		return "", nil
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
   135
	}
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
   136
	return colors.ANSICodeString(desc)
c6adf9d9e996 Disable ANSI sequences when stdout is not a TTY
Mikael Berthe <mikael@lilotux.net>
parents: 49
diff changeset
   137
}