From 2d1456353a592dbb0a01505abe0c100b853ec399 Mon Sep 17 00:00:00 2001 From: Brian Jones Date: Sun, 4 Jun 2017 23:39:11 -0500 Subject: [PATCH 01/12] base for hashes as an attribute, and SHA-1 as a format for Hash --- parser/attribute.go | 1 + transform/format.go | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/parser/attribute.go b/parser/attribute.go index f6ab17b..5ea93f4 100644 --- a/parser/attribute.go +++ b/parser/attribute.go @@ -12,6 +12,7 @@ var allAttributes = map[string]bool{ "name": true, "size": true, "time": true, + "hash": true, } // parseAttrList parses the list of attributes passed to the SELECT clause. diff --git a/transform/format.go b/transform/format.go index 1625448..0a24d48 100644 --- a/transform/format.go +++ b/transform/format.go @@ -1,7 +1,9 @@ package transform import ( + "crypto" "fmt" + "io/ioutil" "os" "strings" "time" @@ -31,6 +33,8 @@ 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 { @@ -109,6 +113,24 @@ func (p *FormatParams) shortPath() (interface{}, error) { return p.Info.Name(), nil } +func (p *FormatParams) hash(hasher crypto.SignerOpts) (interface{}, error) { + var err error + if err != nil { + panic(err.Error()) + } + f, err := os.Open(p.Path) + if err != nil { + return nil, err + } + defer f.Close() + b, err := ioutil.ReadAll(f) + if err != nil { + return nil, err + } + sum := hasher.HashFunc().New().Sum(b) + return string(sum), 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{} { From 07a80cdef8d9548383eec3009e3697bf8182f4e8 Mon Sep 17 00:00:00 2001 From: Brian Jones Date: Mon, 5 Jun 2017 19:26:43 -0500 Subject: [PATCH 02/12] return _DIR_ for directories, instead of nil. --- fsql.go | 2 +- transform/format.go | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/fsql.go b/fsql.go index 3ef12ad..5aebe04 100644 --- a/fsql.go +++ b/fsql.go @@ -13,7 +13,7 @@ import ( const Version = "0.2.0" var q *query.Query -var attrs = [4]string{"mode", "size", "time", "name"} +var attrs = [5]string{"mode", "size", "time", "name", "hash"} // output prints the result value for each SELECTed attribute. Order is based // on the order the attributes appear in attrs. diff --git a/transform/format.go b/transform/format.go index 0a24d48..0528eef 100644 --- a/transform/format.go +++ b/transform/format.go @@ -2,6 +2,8 @@ package transform import ( "crypto" + _ "crypto/sha1" //Import SHA-1 hashing function + "encoding/hex" "fmt" "io/ioutil" "os" @@ -115,9 +117,11 @@ func (p *FormatParams) shortPath() (interface{}, error) { func (p *FormatParams) hash(hasher crypto.SignerOpts) (interface{}, error) { var err error - if err != nil { - panic(err.Error()) + + if p.Info.IsDir() { + return "_Dir_", nil } + f, err := os.Open(p.Path) if err != nil { return nil, err @@ -127,8 +131,10 @@ func (p *FormatParams) hash(hasher crypto.SignerOpts) (interface{}, error) { if err != nil { return nil, err } - sum := hasher.HashFunc().New().Sum(b) - return string(sum), nil + + h := hasher.HashFunc().New() + h.Write(b) + return hex.EncodeToString(h.Sum(nil)), nil } // DefaultFormatValue returns the default format value for the provided From 8e702912441032c043e6764f01459374a4e79f2d Mon Sep 17 00:00:00 2001 From: Brian Jones Date: Mon, 5 Jun 2017 19:38:38 -0500 Subject: [PATCH 03/12] add default hash impl --- transform/format.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/transform/format.go b/transform/format.go index 0528eef..5252966 100644 --- a/transform/format.go +++ b/transform/format.go @@ -116,13 +116,15 @@ func (p *FormatParams) shortPath() (interface{}, error) { } func (p *FormatParams) hash(hasher crypto.SignerOpts) (interface{}, error) { - var err error + return hash(p.Info, p.Path, hasher) +} - if p.Info.IsDir() { - return "_Dir_", nil +func hash(info os.FileInfo, path string, hasher crypto.SignerOpts) (interface{}, error) { + if info.IsDir() { + return "_DIR_", nil } - f, err := os.Open(p.Path) + f, err := os.Open(path) if err != nil { return nil, err } @@ -149,6 +151,9 @@ func DefaultFormatValue(attr, path string, info os.FileInfo) interface{} { return info.Size() case "time": return info.ModTime().Format(time.Stamp) + case "hash": + v, _ := hash(info, path, crypto.SHA1) + return v } return nil } From 1e500ba9dcb5d86d69973c7c37e5561f6f3cd32a Mon Sep 17 00:00:00 2001 From: Brian Jones Date: Mon, 5 Jun 2017 19:55:13 -0500 Subject: [PATCH 04/12] change order of output --- fsql.go | 4 +++- parser/attribute.go | 2 +- transform/format.go | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fsql.go b/fsql.go index 5aebe04..d3f58df 100644 --- a/fsql.go +++ b/fsql.go @@ -13,7 +13,9 @@ import ( const Version = "0.2.0" var q *query.Query -var attrs = [5]string{"mode", "size", "time", "name", "hash"} + +//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. diff --git a/parser/attribute.go b/parser/attribute.go index 5ea93f4..86e459f 100644 --- a/parser/attribute.go +++ b/parser/attribute.go @@ -10,9 +10,9 @@ import ( var allAttributes = map[string]bool{ "mode": true, "name": true, + "hash": true, "size": true, "time": true, - "hash": true, } // parseAttrList parses the list of attributes passed to the SELECT clause. diff --git a/transform/format.go b/transform/format.go index 5252966..5b77b0e 100644 --- a/transform/format.go +++ b/transform/format.go @@ -121,7 +121,7 @@ func (p *FormatParams) hash(hasher crypto.SignerOpts) (interface{}, error) { func hash(info os.FileInfo, path string, hasher crypto.SignerOpts) (interface{}, error) { if info.IsDir() { - return "_DIR_", nil + return "----------------------------------------", nil } f, err := os.Open(path) From f432c7bce60f9c5348cf701667d96a72081bf474 Mon Sep 17 00:00:00 2001 From: Brian Jones Date: Sun, 11 Jun 2017 11:45:47 -0500 Subject: [PATCH 05/12] use truncate to decide length of hash --- transform/common.go | 8 ++++++++ transform/format.go | 24 +++++++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/transform/common.go b/transform/common.go index 289ddbd..170310c 100644 --- a/transform/common.go +++ b/transform/common.go @@ -24,3 +24,11 @@ func upper(name string) interface{} { func lower(name string) interface{} { return strings.ToLower(name) } + +func truncate(str string, n int) string { + if len(str) < n || n > len(str) { + return str + } + + return str[0:n] +} diff --git a/transform/format.go b/transform/format.go index 5b77b0e..2c7a211 100644 --- a/transform/format.go +++ b/transform/format.go @@ -7,6 +7,7 @@ import ( "fmt" "io/ioutil" "os" + "strconv" "strings" "time" ) @@ -36,7 +37,13 @@ func Format(p *FormatParams) (val interface{}, err error) { case "SHORTPATH": val, err = p.shortPath() case "SHA1": - val, err = p.hash(crypto.SHA1) + var hash string + hash, err = p.hash(crypto.SHA1) + if err == nil && len(p.Args) > 0 && p.Args[0] != "" { + if n, err := strconv.Atoi(p.Args[0]); err == nil { + val = truncate(hash, n) + } + } } if err != nil { @@ -115,23 +122,23 @@ func (p *FormatParams) shortPath() (interface{}, error) { return p.Info.Name(), nil } -func (p *FormatParams) hash(hasher crypto.SignerOpts) (interface{}, error) { +func (p *FormatParams) hash(hasher crypto.SignerOpts) (string, error) { return hash(p.Info, p.Path, hasher) } -func hash(info os.FileInfo, path string, hasher crypto.SignerOpts) (interface{}, error) { +func hash(info os.FileInfo, path string, hasher crypto.SignerOpts) (string, error) { if info.IsDir() { return "----------------------------------------", nil } f, err := os.Open(path) if err != nil { - return nil, err + return "", err } defer f.Close() b, err := ioutil.ReadAll(f) if err != nil { - return nil, err + return "", err } h := hasher.HashFunc().New() @@ -152,8 +159,11 @@ func DefaultFormatValue(attr, path string, info os.FileInfo) interface{} { case "time": return info.ModTime().Format(time.Stamp) case "hash": - v, _ := hash(info, path, crypto.SHA1) - return v + v, err := hash(info, path, crypto.SHA1) + if err != nil { + panic(err.Error()) + } + return truncate(v, 7) } return nil } From 3708162ffaf035cfef62fbea2dda0890113afddb Mon Sep 17 00:00:00 2001 From: Brian Jones Date: Sun, 11 Jun 2017 15:26:55 -0500 Subject: [PATCH 06/12] refactor from string -> interface{} --- transform/format.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/transform/format.go b/transform/format.go index 2c7a211..8bab341 100644 --- a/transform/format.go +++ b/transform/format.go @@ -37,11 +37,12 @@ func Format(p *FormatParams) (val interface{}, err error) { case "SHORTPATH": val, err = p.shortPath() case "SHA1": - var hash string + var hash interface{} hash, err = p.hash(crypto.SHA1) if err == nil && len(p.Args) > 0 && p.Args[0] != "" { - if n, err := strconv.Atoi(p.Args[0]); err == nil { - val = truncate(hash, n) + var n int + if n, err = strconv.Atoi(p.Args[0]); err == nil { + val = truncate(hash.(string), n) } } } @@ -122,18 +123,18 @@ func (p *FormatParams) shortPath() (interface{}, error) { return p.Info.Name(), nil } -func (p *FormatParams) hash(hasher crypto.SignerOpts) (string, error) { +func (p *FormatParams) hash(hasher crypto.SignerOpts) (interface{}, error) { return hash(p.Info, p.Path, hasher) } -func hash(info os.FileInfo, path string, hasher crypto.SignerOpts) (string, error) { +func hash(info os.FileInfo, path string, hasher crypto.SignerOpts) (interface{}, error) { if info.IsDir() { - return "----------------------------------------", nil + return strings.Repeat("-", hasher.HashFunc().Size()), nil } f, err := os.Open(path) if err != nil { - return "", err + return nil, err } defer f.Close() b, err := ioutil.ReadAll(f) @@ -163,7 +164,7 @@ func DefaultFormatValue(attr, path string, info os.FileInfo) interface{} { if err != nil { panic(err.Error()) } - return truncate(v, 7) + return truncate(v.(string), 7) } return nil } From 45e163d2bc9e26b875d0b036b2bd34ee918e4c10 Mon Sep 17 00:00:00 2001 From: Brian Jones Date: Sun, 11 Jun 2017 16:06:37 -0500 Subject: [PATCH 07/12] add comments and refactor pulling out arg as int --- fsql.go | 2 +- transform/common.go | 5 ++++- transform/format.go | 25 ++++++++++++++++++------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/fsql.go b/fsql.go index d3f58df..637ec15 100644 --- a/fsql.go +++ b/fsql.go @@ -14,7 +14,7 @@ const Version = "0.2.0" var q *query.Query -//Should be noted that this slice, is temporaly related to the order of printing +// 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 diff --git a/transform/common.go b/transform/common.go index 170310c..5664fe5 100644 --- a/transform/common.go +++ b/transform/common.go @@ -25,8 +25,11 @@ 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 > len(str) { + if len(str) < n || n < 0 { return str } diff --git a/transform/format.go b/transform/format.go index 8bab341..e075d46 100644 --- a/transform/format.go +++ b/transform/format.go @@ -25,6 +25,16 @@ type FormatParams struct { // Format runs the respective format function on the provided parameters. func Format(p *FormatParams) (val interface{}, err error) { + argAsInt := func(arg []string, index int) (interface{}, error) { + var n int + 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 strings.ToUpper(p.Name) { case "FORMAT": val, err = p.format() @@ -38,15 +48,15 @@ func Format(p *FormatParams) (val interface{}, err error) { val, err = p.shortPath() case "SHA1": var hash interface{} - hash, err = p.hash(crypto.SHA1) - if err == nil && len(p.Args) > 0 && p.Args[0] != "" { - var n int - if n, err = strconv.Atoi(p.Args[0]); err == nil { - val = truncate(hash.(string), n) - } + var n interface{} + n, err = argAsInt(p.Args, 0) + if err != nil { + hash, err = p.hash(crypto.SHA1) + } + if err != nil { + val = truncate(hash.(string), n.(int)) } } - if err != nil { return nil, err } @@ -123,6 +133,7 @@ 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) { return hash(p.Info, p.Path, hasher) } From 9e51d40ac19e9494af14fc7ebcf4f52797e68623 Mon Sep 17 00:00:00 2001 From: Brian Jones Date: Sun, 11 Jun 2017 17:59:14 -0500 Subject: [PATCH 08/12] abstract away argAsInt function --- transform/format.go | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/transform/format.go b/transform/format.go index e075d46..f01ca46 100644 --- a/transform/format.go +++ b/transform/format.go @@ -7,6 +7,7 @@ import ( "fmt" "io/ioutil" "os" + "reflect" "strconv" "strings" "time" @@ -23,10 +24,10 @@ type FormatParams struct { Args []string } -// Format runs the respective format function on the provided parameters. -func Format(p *FormatParams) (val interface{}, err error) { - argAsInt := func(arg []string, index int) (interface{}, error) { +func (p FormatParams) argAs(index int, kind reflect.Kind) (interface{}, error) { + 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 @@ -34,6 +35,16 @@ func Format(p *FormatParams) (val interface{}, err error) { } 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) { case "FORMAT": @@ -49,11 +60,11 @@ func Format(p *FormatParams) (val interface{}, err error) { case "SHA1": var hash interface{} var n interface{} - n, err = argAsInt(p.Args, 0) - if err != nil { + n, err = p.argAs(0, reflect.Int) + if err == nil { hash, err = p.hash(crypto.SHA1) } - if err != nil { + if err == nil { val = truncate(hash.(string), n.(int)) } } From caf43d970226c3dddcf558e27b545523c6a1dee6 Mon Sep 17 00:00:00 2001 From: Brian Jones Date: Sun, 11 Jun 2017 18:04:18 -0500 Subject: [PATCH 09/12] refactor hash truncation --- transform/format.go | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/transform/format.go b/transform/format.go index f01ca46..201111f 100644 --- a/transform/format.go +++ b/transform/format.go @@ -58,15 +58,7 @@ func Format(p *FormatParams) (val interface{}, err error) { case "SHORTPATH": val, err = p.shortPath() case "SHA1": - var hash interface{} - var n interface{} - n, err = p.argAs(0, reflect.Int) - if err == nil { - hash, err = p.hash(crypto.SHA1) - } - if err == nil { - val = truncate(hash.(string), n.(int)) - } + val, err = p.hash(crypto.SHA1) } if err != nil { return nil, err @@ -146,7 +138,16 @@ func (p *FormatParams) shortPath() (interface{}, error) { // hash will take the hash function, based on the hasher type supplied. func (p *FormatParams) hash(hasher crypto.SignerOpts) (interface{}, error) { - return hash(p.Info, p.Path, hasher) + 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) { From 6bf4ac67f8daf3a8bcfdcc285069708144804cd5 Mon Sep 17 00:00:00 2001 From: Brian Jones Date: Sun, 11 Jun 2017 18:05:31 -0500 Subject: [PATCH 10/12] add asInt comment --- transform/format.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/transform/format.go b/transform/format.go index 201111f..7fbb16f 100644 --- a/transform/format.go +++ b/transform/format.go @@ -25,6 +25,8 @@ type FormatParams struct { } 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 From 66e0850f997aa31d8f079504c81b1c36b77bdb85 Mon Sep 17 00:00:00 2001 From: Brian Jones Date: Sun, 11 Jun 2017 18:15:12 -0500 Subject: [PATCH 11/12] refactor Default behavior --- query/modifier.go | 4 ++-- transform/format.go | 17 ++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/query/modifier.go b/query/modifier.go index d8d336a..7c86266 100644 --- a/query/modifier.go +++ b/query/modifier.go @@ -25,7 +25,8 @@ 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 @@ -33,7 +34,6 @@ func (q *Query) applyModifiers(path string, info os.FileInfo) map[string]interfa } for _, m := range q.Modifiers[attribute] { - var err error value, err = transform.Format(&transform.FormatParams{ Attribute: attribute, Path: path, diff --git a/transform/format.go b/transform/format.go index 7fbb16f..517cb4b 100644 --- a/transform/format.go +++ b/transform/format.go @@ -174,22 +174,21 @@ func hash(info os.FileInfo, path string, hasher crypto.SignerOpts) (interface{}, // 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 { - panic(err.Error()) + if err == nil { + return truncate(v.(string), 7), nil } - return truncate(v.(string), 7) } - return nil + return nil, &ErrUnsupportedFormat{"", attr} } From 59c547a35fc049b08701a33922ce9edbfe032436 Mon Sep 17 00:00:00 2001 From: Brian Jones Date: Sun, 11 Jun 2017 18:18:20 -0500 Subject: [PATCH 12/12] fix spacing --- transform/format.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/transform/format.go b/transform/format.go index 517cb4b..9837199 100644 --- a/transform/format.go +++ b/transform/format.go @@ -25,7 +25,6 @@ type FormatParams struct { } func (p FormatParams) argAs(index int, kind reflect.Kind) (interface{}, error) { - // return args as an int asInt := func() (interface{}, error) { var n int @@ -47,7 +46,6 @@ func (p FormatParams) argAs(index int, kind reflect.Kind) (interface{}, error) { // Format runs the respective format function on the provided parameters. func Format(p *FormatParams) (val interface{}, err error) { - switch strings.ToUpper(p.Name) { case "FORMAT": val, err = p.format()