github.com/koron/hk@v0.0.0-20150303213137-b8aeaa3ab34c/util.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/ioutil"
     7  	"log"
     8  	"net/url"
     9  	"os"
    10  	"os/exec"
    11  	"path/filepath"
    12  	"runtime"
    13  	"strings"
    14  	"time"
    15  
    16  	"github.com/heroku/hk/Godeps/_workspace/src/github.com/bgentry/heroku-go"
    17  	"github.com/heroku/hk/Godeps/_workspace/src/github.com/mgutz/ansi"
    18  	"github.com/heroku/hk/hkclient"
    19  	"github.com/heroku/hk/term"
    20  )
    21  
    22  var nrc *hkclient.NetRc
    23  
    24  func hkHome() string {
    25  	return filepath.Join(hkclient.HomePath(), ".hk")
    26  }
    27  
    28  func netrcPath() string {
    29  	if s := os.Getenv("NETRC_PATH"); s != "" {
    30  		return s
    31  	}
    32  
    33  	return filepath.Join(hkclient.HomePath(), netrcFilename)
    34  }
    35  
    36  func loadNetrc() {
    37  	var err error
    38  
    39  	if nrc == nil {
    40  		if nrc, err = hkclient.LoadNetRc(); err != nil {
    41  			if os.IsNotExist(err) {
    42  				nrc = &hkclient.NetRc{}
    43  				return
    44  			}
    45  			printFatal("loading netrc: " + err.Error())
    46  		}
    47  	}
    48  }
    49  
    50  func getCreds(u string) (user, pass string) {
    51  	loadNetrc()
    52  	if nrc == nil {
    53  		return "", ""
    54  	}
    55  
    56  	apiURL, err := url.Parse(u)
    57  	if err != nil {
    58  		printFatal("invalid API URL: %s", err)
    59  	}
    60  
    61  	user, pass, err = nrc.GetCreds(apiURL)
    62  	if err != nil {
    63  		printError(err.Error())
    64  	}
    65  
    66  	return user, pass
    67  }
    68  
    69  func saveCreds(host, user, pass string) error {
    70  	loadNetrc()
    71  	m := nrc.FindMachine(host)
    72  	if m == nil || m.IsDefault() {
    73  		m = nrc.NewMachine(host, user, pass, "")
    74  	}
    75  	m.UpdateLogin(user)
    76  	m.UpdatePassword(pass)
    77  
    78  	body, err := nrc.MarshalText()
    79  	if err != nil {
    80  		return err
    81  	}
    82  	return ioutil.WriteFile(netrcPath(), body, 0600)
    83  }
    84  
    85  func removeCreds(host string) error {
    86  	loadNetrc()
    87  	nrc.RemoveMachine(host)
    88  
    89  	body, err := nrc.MarshalText()
    90  	if err != nil {
    91  		return err
    92  	}
    93  	return ioutil.WriteFile(netrcPath(), body, 0600)
    94  }
    95  
    96  // exists returns whether the given file or directory exists or not
    97  func fileExists(path string) (bool, error) {
    98  	_, err := os.Stat(path)
    99  	if err == nil {
   100  		return true, nil
   101  	}
   102  	if os.IsNotExist(err) {
   103  		return false, nil
   104  	}
   105  	return false, err
   106  }
   107  
   108  func must(err error) {
   109  	if err != nil {
   110  		if herror, ok := err.(heroku.Error); ok {
   111  			switch herror.Id {
   112  			case "two_factor":
   113  				printError(err.Error() + " Authorize with `hk authorize`.")
   114  				os.Exit(79)
   115  			case "unauthorized":
   116  				printFatal(err.Error() + " Log in with `hk login`.")
   117  			}
   118  		}
   119  		printFatal(err.Error())
   120  	}
   121  }
   122  
   123  func printError(message string, args ...interface{}) {
   124  	log.Println(colorizeMessage("red", "error:", message, args...))
   125  }
   126  
   127  func printFatal(message string, args ...interface{}) {
   128  	log.Fatal(colorizeMessage("red", "error:", message, args...))
   129  }
   130  
   131  func printWarning(message string, args ...interface{}) {
   132  	log.Println(colorizeMessage("yellow", "warning:", message, args...))
   133  }
   134  
   135  func mustConfirm(warning, desired string) {
   136  	if term.IsTerminal(os.Stdin) {
   137  		printWarning(warning)
   138  		fmt.Printf("> ")
   139  	}
   140  	var confirm string
   141  	if _, err := fmt.Scanln(&confirm); err != nil {
   142  		printFatal(err.Error())
   143  	}
   144  
   145  	if confirm != desired {
   146  		printFatal("Confirmation did not match %q.", desired)
   147  	}
   148  }
   149  
   150  func colorizeMessage(color, prefix, message string, args ...interface{}) string {
   151  	prefResult := ""
   152  	if prefix != "" {
   153  		prefResult = ansi.Color(prefix, color+"+b") + " " + ansi.ColorCode("reset")
   154  	}
   155  	return prefResult + ansi.Color(fmt.Sprintf(message, args...), color) + ansi.ColorCode("reset")
   156  }
   157  
   158  func listRec(w io.Writer, a ...interface{}) {
   159  	for i, x := range a {
   160  		fmt.Fprint(w, x)
   161  		if i+1 < len(a) {
   162  			w.Write([]byte{'\t'})
   163  		} else {
   164  			w.Write([]byte{'\n'})
   165  		}
   166  	}
   167  }
   168  
   169  type prettyTime struct {
   170  	time.Time
   171  }
   172  
   173  func (s prettyTime) String() string {
   174  	if time.Now().Sub(s.Time) < 12*30*24*time.Hour {
   175  		return s.Local().Format("Jan _2 15:04")
   176  	}
   177  	return s.Local().Format("Jan _2  2006")
   178  }
   179  
   180  type prettyDuration struct {
   181  	time.Duration
   182  }
   183  
   184  func (a prettyDuration) String() string {
   185  	switch d := a.Duration; {
   186  	case d > 2*24*time.Hour:
   187  		return a.Unit(24*time.Hour, "d")
   188  	case d > 2*time.Hour:
   189  		return a.Unit(time.Hour, "h")
   190  	case d > 2*time.Minute:
   191  		return a.Unit(time.Minute, "m")
   192  	}
   193  	return a.Unit(time.Second, "s")
   194  }
   195  
   196  func (a prettyDuration) Unit(u time.Duration, s string) string {
   197  	return fmt.Sprintf("%2d", roundDur(a.Duration, u)) + s
   198  }
   199  
   200  func roundDur(d, k time.Duration) int {
   201  	return int((d + k/2 - 1) / k)
   202  }
   203  
   204  func abbrev(s string, n int) string {
   205  	if len(s) > n {
   206  		return s[:n-1] + "…"
   207  	}
   208  	return s
   209  }
   210  
   211  func ensurePrefix(val, prefix string) string {
   212  	if !strings.HasPrefix(val, prefix) {
   213  		return prefix + val
   214  	}
   215  	return val
   216  }
   217  
   218  func ensureSuffix(val, suffix string) string {
   219  	if !strings.HasSuffix(val, suffix) {
   220  		return val + suffix
   221  	}
   222  	return val
   223  }
   224  
   225  func openURL(url string) error {
   226  	var command string
   227  	var args []string
   228  	switch runtime.GOOS {
   229  	case "darwin":
   230  		command = "open"
   231  		args = []string{command, url}
   232  	case "windows":
   233  		command = "cmd"
   234  		args = []string{"/c", "start " + strings.Replace(url, "&", "^&", -1)}
   235  	default:
   236  		if _, err := exec.LookPath("xdg-open"); err != nil {
   237  			log.Println("xdg-open is required to open web pages on " + runtime.GOOS)
   238  			os.Exit(2)
   239  		}
   240  		command = "xdg-open"
   241  		args = []string{command, url}
   242  	}
   243  	return runCommand(command, args, os.Environ())
   244  }
   245  
   246  func runCommand(command string, args, env []string) error {
   247  	if runtime.GOOS != "windows" {
   248  		p, err := exec.LookPath(command)
   249  		if err != nil {
   250  			log.Printf("Error finding path to %q: %s\n", command, err)
   251  			os.Exit(2)
   252  		}
   253  		command = p
   254  	}
   255  	return sysExec(command, args, env)
   256  }
   257  
   258  func stringsIndex(s []string, item string) int {
   259  	for i := range s {
   260  		if s[i] == item {
   261  			return i
   262  		}
   263  	}
   264  	return -1
   265  }