github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/util/util.go (about)

     1  // Package util implements various utility functions used within ipfs
     2  // that do not currently have a better place to live.
     3  package util
     4  
     5  import (
     6  	"errors"
     7  	"io"
     8  	"math/rand"
     9  	"os"
    10  	"path/filepath"
    11  	"runtime/debug"
    12  	"strings"
    13  	"time"
    14  
    15  	b58 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
    16  	ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
    17  	mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
    18  
    19  	"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir"
    20  )
    21  
    22  // Debug is a global flag for debugging.
    23  var Debug bool
    24  
    25  // ErrNotImplemented signifies a function has not been implemented yet.
    26  var ErrNotImplemented = errors.New("Error: not implemented yet.")
    27  
    28  // ErrTimeout implies that a timeout has been triggered
    29  var ErrTimeout = errors.New("Error: Call timed out.")
    30  
    31  // ErrSeErrSearchIncomplete implies that a search type operation didnt
    32  // find the expected node, but did find 'a' node.
    33  var ErrSearchIncomplete = errors.New("Error: Search Incomplete.")
    34  
    35  // ErrNotFound is returned when a search fails to find anything
    36  var ErrNotFound = ds.ErrNotFound
    37  
    38  // ErrNoSuchLogger is returned when the util pkg is asked for a non existant logger
    39  var ErrNoSuchLogger = errors.New("Error: No such logger")
    40  
    41  // TildeExpansion expands a filename, which may begin with a tilde.
    42  func TildeExpansion(filename string) (string, error) {
    43  	return homedir.Expand(filename)
    44  }
    45  
    46  // ErrCast is returned when a cast fails AND the program should not panic.
    47  func ErrCast() error {
    48  	debug.PrintStack()
    49  	return errCast
    50  }
    51  
    52  var errCast = errors.New("cast error")
    53  
    54  // ExpandPathnames takes a set of paths and turns them into absolute paths
    55  func ExpandPathnames(paths []string) ([]string, error) {
    56  	var out []string
    57  	for _, p := range paths {
    58  		abspath, err := filepath.Abs(p)
    59  		if err != nil {
    60  			return nil, err
    61  		}
    62  		out = append(out, abspath)
    63  	}
    64  	return out, nil
    65  }
    66  
    67  type randGen struct {
    68  	rand.Rand
    69  }
    70  
    71  func NewTimeSeededRand() io.Reader {
    72  	src := rand.NewSource(time.Now().UnixNano())
    73  	return &randGen{
    74  		Rand: *rand.New(src),
    75  	}
    76  }
    77  
    78  func NewSeededRand(seed int64) io.Reader {
    79  	src := rand.NewSource(seed)
    80  	return &randGen{
    81  		Rand: *rand.New(src),
    82  	}
    83  }
    84  
    85  func (r *randGen) Read(p []byte) (n int, err error) {
    86  	for i := 0; i < len(p); i++ {
    87  		p[i] = byte(r.Rand.Intn(255))
    88  	}
    89  	return len(p), nil
    90  }
    91  
    92  // GetenvBool is the way to check an env var as a boolean
    93  func GetenvBool(name string) bool {
    94  	v := strings.ToLower(os.Getenv(name))
    95  	return v == "true" || v == "t" || v == "1"
    96  }
    97  
    98  // MultiErr is a util to return multiple errors
    99  type MultiErr []error
   100  
   101  func (m MultiErr) Error() string {
   102  	if len(m) == 0 {
   103  		return "no errors"
   104  	}
   105  
   106  	s := "Multiple errors: "
   107  	for i, e := range m {
   108  		if i != 0 {
   109  			s += ", "
   110  		}
   111  		s += e.Error()
   112  	}
   113  	return s
   114  }
   115  
   116  func Partition(subject string, sep string) (string, string, string) {
   117  	if i := strings.Index(subject, sep); i != -1 {
   118  		return subject[:i], subject[i : i+len(sep)], subject[i+len(sep):]
   119  	}
   120  	return subject, "", ""
   121  }
   122  
   123  func RPartition(subject string, sep string) (string, string, string) {
   124  	if i := strings.LastIndex(subject, sep); i != -1 {
   125  		return subject[:i], subject[i : i+len(sep)], subject[i+len(sep):]
   126  	}
   127  	return subject, "", ""
   128  }
   129  
   130  // Hash is the global IPFS hash function. uses multihash SHA2_256, 256 bits
   131  func Hash(data []byte) mh.Multihash {
   132  	h, err := mh.Sum(data, mh.SHA2_256, -1)
   133  	if err != nil {
   134  		// this error can be safely ignored (panic) because multihash only fails
   135  		// from the selection of hash function. If the fn + length are valid, it
   136  		// won't error.
   137  		panic("multihash failed to hash using SHA2_256.")
   138  	}
   139  	return h
   140  }
   141  
   142  // IsValidHash checks whether a given hash is valid (b58 decodable, len > 0)
   143  func IsValidHash(s string) bool {
   144  	out := b58.Decode(s)
   145  	if out == nil || len(out) == 0 {
   146  		return false
   147  	}
   148  	_, err := mh.Cast(out)
   149  	if err != nil {
   150  		return false
   151  	}
   152  	return true
   153  }
   154  
   155  // XOR takes two byte slices, XORs them together, returns the resulting slice.
   156  func XOR(a, b []byte) []byte {
   157  	c := make([]byte, len(a))
   158  	for i := 0; i < len(a); i++ {
   159  		c[i] = a[i] ^ b[i]
   160  	}
   161  	return c
   162  }