giffer

Create .gif images from sites like youtube.com
Log | Files | Refs | LICENSE

hash.go (1790B)


      1 package main
      2 
      3 import (
      4 	"io/ioutil"
      5 	"os"
      6 	"path/filepath"
      7 	"sort"
      8 	"sync"
      9 	"unicode"
     10 
     11 	"github.com/OneOfOne/xxhash"
     12 	"github.com/pkg/errors"
     13 )
     14 
     15 // Hash recusively and concurrently hashes a fileEntry or directory.
     16 func Hash(path string) (uint64, error) {
     17 	var (
     18 		found = make(chan fileEntry)
     19 		wg    = &sync.WaitGroup{}
     20 	)
     21 	walk := func(path string, info os.FileInfo, err error) error {
     22 		if err != nil {
     23 			return err
     24 		}
     25 		if info.IsDir() {
     26 			return nil
     27 		}
     28 		wg.Add(1)
     29 		go func() {
     30 			defer wg.Done()
     31 			by, err := ioutil.ReadFile(path)
     32 			found <- fileEntry{
     33 				Path:    path,
     34 				Content: by,
     35 				Err:     err,
     36 			}
     37 		}()
     38 		return nil
     39 	}
     40 	if err := filepath.Walk(path, walk); err != nil {
     41 		return 0, err
     42 	}
     43 	go func() {
     44 		wg.Wait()
     45 		close(found)
     46 	}()
     47 	var files []fileEntry
     48 	for f := range found {
     49 		if f.Err != nil {
     50 			return 0, f.Err
     51 		}
     52 		files = append(files, f)
     53 	}
     54 	sort.Sort(alphabetical(files))
     55 	hash := xxhash.New64()
     56 	for _, f := range files {
     57 		if _, err := hash.Write(f.Content); err != nil {
     58 			return 0, errors.Wrap(err, "hashing")
     59 		}
     60 	}
     61 	return hash.Sum64(), nil
     62 }
     63 
     64 type fileEntry struct {
     65 	Path    string
     66 	Content []byte
     67 	Err     error
     68 }
     69 
     70 type alphabetical []fileEntry
     71 
     72 func (a alphabetical) Len() int {
     73 	return len(a)
     74 }
     75 
     76 func (a alphabetical) Swap(ii, jj int) {
     77 	a[ii], a[jj] = a[jj], a[ii]
     78 }
     79 
     80 func (a alphabetical) Less(ii, jj int) bool {
     81 	iRunes := []rune(a[ii].Path)
     82 	jRunes := []rune(a[jj].Path)
     83 	max := len(iRunes)
     84 	if max > len(jRunes) {
     85 		max = len(jRunes)
     86 	}
     87 	for idx := 0; idx < max; idx++ {
     88 		ir := iRunes[idx]
     89 		jr := jRunes[idx]
     90 		lir := unicode.ToLower(ir)
     91 		ljr := unicode.ToLower(jr)
     92 		if lir != ljr {
     93 			return lir < ljr
     94 		}
     95 		// the lowercase runes are the same, so compare the original
     96 		if ir != jr {
     97 			return ir < jr
     98 		}
     99 	}
    100 	return false
    101 }