...

Source file src/golang.conradwood.net/go-easyops/utils/utils.go

Documentation: golang.conradwood.net/go-easyops/utils

     1  /*
     2  Package utils provides a lot of utilities for files, strings, numbers, printing data, formatting and parsing time, rate calculation, sliding average calculation, (linux) console pretty printing and so on.
     3  */
     4  package utils
     5  
     6  import (
     7  	"fmt"
     8  	"math/rand"
     9  	"os"
    10  	"sync"
    11  	"syscall"
    12  	"time"
    13  	"unsafe"
    14  
    15  	"github.com/dustin/go-humanize"
    16  	"golang.conradwood.net/go-easyops/errors/shared"
    17  
    18  	_ "golang.conradwood.net/apis/autodeployer"
    19  	_ "golang.conradwood.net/apis/deploymonkey"
    20  	_ "golang.conradwood.net/apis/grafanadata"
    21  
    22  	//	_ "golang.conradwood.net/apis/h2gproxy"
    23  	_ "golang.yacloud.eu/apis/fscache"
    24  	_ "golang.yacloud.eu/apis/unixipc"
    25  )
    26  
    27  var (
    28  	randlock sync.Mutex
    29  	randsrc  = rand.New(rand.NewSource(time.Now().UnixNano()))
    30  )
    31  
    32  // return random integer between 0 and n
    33  func RandomInt(max int64) int {
    34  	randlock.Lock()
    35  	t := randsrc.Int63n(max)
    36  	randlock.Unlock()
    37  	return int(t)
    38  }
    39  
    40  func RandomString(n int) string {
    41  	const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    42  	const (
    43  		letterIdxBits = 6                    // 6 bits to represent a letter index
    44  		letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
    45  		letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
    46  
    47  	)
    48  
    49  	b := make([]byte, n)
    50  	// A randsrc.Int63() generates 63 random bits, enough for letterIdxMax characters!
    51  	randlock.Lock()
    52  	defer randlock.Unlock()
    53  	for i, cache, remain := n-1, randsrc.Int63(), letterIdxMax; i >= 0; {
    54  		if remain == 0 {
    55  			cache, remain = randsrc.Int63(), letterIdxMax
    56  		}
    57  		if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
    58  			b[i] = letterBytes[idx]
    59  			i--
    60  		}
    61  		cache >>= letterIdxBits
    62  		remain--
    63  	}
    64  
    65  	return string(b)
    66  }
    67  
    68  // never returns - if error != nil, print it and exit
    69  func Bail(txt string, err error) {
    70  	if err == nil {
    71  		return
    72  	}
    73  	fmt.Printf("%s: %s\n", txt, shared.ErrorStringWithStackTrace(err))
    74  	os.Exit(10)
    75  }
    76  
    77  // return true if string has letters only
    78  func IsLettersOnly(txt string) bool {
    79  	return IsOnlyChars(txt, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
    80  }
    81  
    82  // true only if string "txt" is made up exclusively of characters in "valid"
    83  func IsOnlyChars(txt string, valid string) bool {
    84  	for _, x := range txt {
    85  		b := false
    86  		for _, y := range valid {
    87  			if x == y {
    88  				b = true
    89  			}
    90  		}
    91  		if !b {
    92  			return false
    93  		}
    94  	}
    95  	return true
    96  }
    97  
    98  // stall for a random amount of "upto" minutes
    99  func RandomStall(minutes int) {
   100  	if minutes == 0 {
   101  		return
   102  	}
   103  	randlock.Lock()
   104  	t := randsrc.Int63n(int64(minutes * 60))
   105  	randlock.Unlock()
   106  	time.Sleep(time.Duration(t) * time.Second)
   107  }
   108  
   109  func MinInt(x, y int) int {
   110  	if x < y {
   111  		return x
   112  	}
   113  	return y
   114  }
   115  
   116  func MaxInt(x, y int) int {
   117  	if x > y {
   118  		return x
   119  	}
   120  	return y
   121  }
   122  
   123  func MinInt32(x, y int32) int32 {
   124  	if x < y {
   125  		return x
   126  	}
   127  	return y
   128  }
   129  
   130  func MaxInt32(x, y int32) int32 {
   131  	if x > y {
   132  		return x
   133  	}
   134  	return y
   135  }
   136  
   137  func MinInt64(x, y int64) int64 {
   138  	if x < y {
   139  		return x
   140  	}
   141  	return y
   142  }
   143  
   144  func MaxInt64(x, y int64) int64 {
   145  	if x > y {
   146  		return x
   147  	}
   148  	return y
   149  }
   150  
   151  func PrettyNumber(number uint64) string {
   152  	return humanize.Bytes(number)
   153  }
   154  
   155  type TerminalDimensions struct {
   156  	width  int
   157  	height int
   158  }
   159  
   160  func (td *TerminalDimensions) Columns() int {
   161  	return td.width
   162  }
   163  func (td *TerminalDimensions) Rows() int {
   164  	return td.height
   165  }
   166  
   167  // get the size of the current xterm
   168  func TerminalSize() (*TerminalDimensions, error) {
   169  	type winsize struct {
   170  		Row    uint16
   171  		Col    uint16
   172  		Xpixel uint16
   173  		Ypixel uint16
   174  	}
   175  
   176  	ws := &winsize{}
   177  	retCode, _, errno := syscall.Syscall(syscall.SYS_IOCTL,
   178  		uintptr(syscall.Stdout),
   179  		uintptr(syscall.TIOCGWINSZ),
   180  		uintptr(unsafe.Pointer(ws)))
   181  
   182  	if int(retCode) == -1 {
   183  		return nil, fmt.Errorf("failed to get terminalsize: %d", errno)
   184  	}
   185  	ts := &TerminalDimensions{
   186  		width:  int(ws.Col),
   187  		height: int(ws.Row),
   188  	}
   189  	return ts, nil
   190  }
   191  

View as plain text