github.com/grafana/tanka@v0.26.1-0.20240506093700-c22cfc35c21a/pkg/tanka/format.go (about)

     1  package tanka
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  
     7  	"github.com/gobwas/glob"
     8  	"github.com/google/go-jsonnet/formatter"
     9  	"github.com/grafana/tanka/pkg/jsonnet"
    10  	"github.com/pkg/errors"
    11  )
    12  
    13  // FormatOpts modify the behaviour of Format
    14  type FormatOpts struct {
    15  	// Excludes are a list of globs to exclude files while searching for Jsonnet
    16  	// files
    17  	Excludes []glob.Glob
    18  
    19  	// OutFn receives the formatted file and it's name. If left nil, the file
    20  	// will be formatted in place.
    21  	OutFn OutFn
    22  
    23  	// PrintNames causes all filenames to be printed
    24  	PrintNames bool
    25  }
    26  
    27  // OutFn is a function that receives the formatted file for further action,
    28  // like persisting to disc
    29  type OutFn func(name, content string) error
    30  
    31  // FormatFiles takes a list of files and directories, processes them and returns
    32  // which files were formatted and perhaps an error.
    33  func FormatFiles(fds []string, opts *FormatOpts) ([]string, error) {
    34  	var paths []string
    35  	for _, f := range fds {
    36  		fs, err := jsonnet.FindFiles(f, opts.Excludes)
    37  		if err != nil {
    38  			return nil, errors.Wrap(err, "finding Jsonnet files")
    39  		}
    40  		paths = append(paths, fs...)
    41  	}
    42  
    43  	// if nothing defined, default to save inplace
    44  	outFn := opts.OutFn
    45  	if outFn == nil {
    46  		outFn = func(name, content string) error {
    47  			return os.WriteFile(name, []byte(content), 0644)
    48  		}
    49  	}
    50  
    51  	// print each file?
    52  	printFn := func(...interface{}) {}
    53  	if opts.PrintNames {
    54  		printFn = func(i ...interface{}) { fmt.Println(i...) }
    55  	}
    56  
    57  	var changed []string
    58  	for _, p := range paths {
    59  		content, err := os.ReadFile(p)
    60  		if err != nil {
    61  			return nil, err
    62  		}
    63  
    64  		formatted, err := Format(p, string(content))
    65  		if err != nil {
    66  			return nil, err
    67  		}
    68  
    69  		if string(content) != formatted {
    70  			printFn("fmt", p)
    71  			changed = append(changed, p)
    72  		} else {
    73  			printFn("ok ", p)
    74  		}
    75  
    76  		if err := outFn(p, formatted); err != nil {
    77  			return nil, err
    78  		}
    79  	}
    80  
    81  	return changed, nil
    82  }
    83  
    84  // Format takes a file's name and contents and returns them in properly
    85  // formatted. The file does not have to exist on disk.
    86  func Format(filename string, content string) (string, error) {
    87  	return formatter.Format(filename, content, formatter.DefaultOptions())
    88  }