Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/add hashing #30

Closed
wants to merge 13 commits into from
4 changes: 3 additions & 1 deletion fsql.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import (
const Version = "0.2.1"

var q *query.Query
var attrs = [4]string{"mode", "size", "time", "name"}

// Should be noted that this slice, is temporaly related to the order of printing
var attrs = [5]string{"mode", "size", "time", "hash", "name"}

// output prints the result value for each SELECTed attribute. Order is based
// on the order the attributes appear in attrs.
Expand Down
1 change: 1 addition & 0 deletions parser/attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
var allAttributes = map[string]bool{
"mode": true,
"name": true,
"hash": true,
"size": true,
"time": true,
}
Expand Down
4 changes: 2 additions & 2 deletions query/modifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ func (q *Query) applyModifiers(path string, info os.FileInfo) map[string]interfa
results := make(map[string]interface{}, len(q.Attributes))

for attribute := range q.Attributes {
value := transform.DefaultFormatValue(attribute, path, info)
var err error
value, err := transform.DefaultFormatValue(attribute, path, info)

if _, ok := q.Modifiers[attribute]; !ok {
results[attribute] = value
continue
}

for _, m := range q.Modifiers[attribute] {
var err error
value, err = transform.Format(&transform.FormatParams{
Attribute: attribute,
Path: path,
Expand Down
11 changes: 11 additions & 0 deletions transform/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,14 @@ func upper(name string) interface{} {
func lower(name string) interface{} {
return strings.ToLower(name)
}

// truncate returns the first n letters of the string str.
// if n is greater than the size of str, return str unaltered.
// if n is < 0, return str unaltered.
func truncate(str string, n int) string {
if len(str) < n || n < 0 {
return str
}

return str[0:n]
}
80 changes: 73 additions & 7 deletions transform/format.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
package transform

import (
"crypto"
_ "crypto/sha1" //Import SHA-1 hashing function
"encoding/hex"
"fmt"
"io/ioutil"
"os"
"reflect"
"strconv"
"strings"
"time"
)
Expand All @@ -18,6 +24,26 @@ type FormatParams struct {
Args []string
}

func (p FormatParams) argAs(index int, kind reflect.Kind) (interface{}, error) {
// return args as an int
asInt := func() (interface{}, error) {
var n int
var err error
if err == nil && len(p.Args) > 0 && p.Args[index] != "" {
if n, err = strconv.Atoi(p.Args[index]); err != nil {
return nil, err
}
}
return n, nil
}
switch kind {
case reflect.Int:
return asInt()
default:
return nil, &ErrNotImplemented{p.Name, p.Attribute}
}
}

// Format runs the respective format function on the provided parameters.
func Format(p *FormatParams) (val interface{}, err error) {
switch strings.ToUpper(p.Name) {
Expand All @@ -31,8 +57,9 @@ func Format(p *FormatParams) (val interface{}, err error) {
val, err = p.fullPath()
case "SHORTPATH":
val, err = p.shortPath()
case "SHA1":
val, err = p.hash(crypto.SHA1)
}

if err != nil {
return nil, err
}
Expand Down Expand Up @@ -109,18 +136,57 @@ func (p *FormatParams) shortPath() (interface{}, error) {
return p.Info.Name(), nil
}

// hash will take the hash function, based on the hasher type supplied.
func (p *FormatParams) hash(hasher crypto.SignerOpts) (interface{}, error) {
var err error
var n interface{}
var h interface{}

n, err = p.argAs(0, reflect.Int)
if err != nil {
return nil, err
}
h, err = hash(p.Info, p.Path, hasher)
return truncate(h.(string), n.(int)), nil
}

func hash(info os.FileInfo, path string, hasher crypto.SignerOpts) (interface{}, error) {
if info.IsDir() {
return strings.Repeat("-", hasher.HashFunc().Size()), nil
}

f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
b, err := ioutil.ReadAll(f)
if err != nil {
return "", err
}

h := hasher.HashFunc().New()
h.Write(b)
return hex.EncodeToString(h.Sum(nil)), nil
}

// DefaultFormatValue returns the default format value for the provided
// attribute attr based on path and info.
func DefaultFormatValue(attr, path string, info os.FileInfo) interface{} {
func DefaultFormatValue(attr, path string, info os.FileInfo) (interface{}, error) {
switch attr {
case "mode":
return info.Mode()
return info.Mode(), nil
case "name":
return info.Name()
return info.Name(), nil
case "size":
return info.Size()
return info.Size(), nil
case "time":
return info.ModTime().Format(time.Stamp)
return info.ModTime().Format(time.Stamp), nil
case "hash":
v, err := hash(info, path, crypto.SHA1)
if err == nil {
return truncate(v.(string), 7), nil
}
}
return nil
return nil, &ErrUnsupportedFormat{"", attr}
}