From c3ad0906e0b27964a496edd2d3aa249c82e5576a Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Mon, 2 Mar 2015 18:03:01 -0800 Subject: [PATCH] Add deadcode code which recursivley goes into all directories and verifies dangling variables. --- .gitignore | 1 + Makefile | 5 +- buildscripts/deadcode.go | 205 ++++++++++++++++++++ pkg/api/minioapi/bucket_handlers.go | 4 + pkg/api/minioapi/definitions.go | 2 +- pkg/storage/donut/data/data_v1/data.go | 4 +- pkg/storage/donut/data/data_v1/data_test.go | 2 +- pkg/storage/erasure/cauchy_test.go | 2 +- pkg/storage/erasure/doc.go | 6 +- pkg/storage/erasure/erasure_encode.go | 10 +- pkg/storage/erasure/stdint.go | 10 - pkg/storage/erasure/vandermonde_test.go | 2 +- 12 files changed, 228 insertions(+), 25 deletions(-) create mode 100644 buildscripts/deadcode.go diff --git a/.gitignore b/.gitignore index 48dcf2b02..f369d7cc4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ cover.out minio **/*.test **/*.sublime-workspace +deadcode \ No newline at end of file diff --git a/Makefile b/Makefile index 9a97c21df..039c225bc 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,10 @@ checkgopath: getdeps: checkdeps checkgopath @go get github.com/tools/godep && echo "Installed godep" -build-all: getdeps +deadcode: getdeps + @go run buildscripts/deadcode.go . + +build-all: getdeps deadcode @echo "Building Libraries" @godep go generate ./... @godep go build ./... diff --git a/buildscripts/deadcode.go b/buildscripts/deadcode.go new file mode 100644 index 000000000..bcb40e211 --- /dev/null +++ b/buildscripts/deadcode.go @@ -0,0 +1,205 @@ +package main + +import ( + "flag" + "fmt" + "go/ast" + "go/parser" + "go/token" + "os" + "path/filepath" + "sort" + "strings" +) + +var exitCode int +var dirs []string + +func appendUniq(slice []string, i string) []string { + for _, ele := range slice { + if ele == i { + return slice + } + } + return append(slice, i) +} + +func getAllFiles(path string, fl os.FileInfo, err error) error { + if err != nil { + return err + } + if fl.IsDir() { + dirs = appendUniq(dirs, path) + } + return nil +} + +func main() { + flag.Parse() + if flag.NArg() == 0 { + doDir(".") + } else { + for _, name := range flag.Args() { + // Is it a directory? + if fi, err := os.Stat(name); err == nil && fi.IsDir() { + err := filepath.Walk(name, getAllFiles) + if err != nil { + errorf(err.Error()) + } + for _, dir := range dirs { + doDir(dir) + } + } else { + errorf("not a directory: %s", name) + } + } + } + os.Exit(exitCode) +} + +// error formats the error to standard error, adding program +// identification and a newline +func errorf(format string, args ...interface{}) { + fmt.Fprintf(os.Stderr, "deadcode: "+format+"\n", args...) + exitCode = 2 +} + +func doDir(name string) { + notests := func(info os.FileInfo) bool { + if !info.IsDir() && strings.HasSuffix(info.Name(), ".go") && + !strings.HasSuffix(info.Name(), "_test.go") { + return true + } + return false + } + fs := token.NewFileSet() + pkgs, err := parser.ParseDir(fs, name, notests, parser.Mode(0)) + if err != nil { + errorf("%s", err) + return + } + for _, pkg := range pkgs { + doPackage(fs, pkg) + } +} + +type Package struct { + p *ast.Package + fs *token.FileSet + decl map[string]ast.Node + used map[string]bool +} + +func doPackage(fs *token.FileSet, pkg *ast.Package) { + p := &Package{ + p: pkg, + fs: fs, + decl: make(map[string]ast.Node), + used: make(map[string]bool), + } + for _, file := range pkg.Files { + for _, decl := range file.Decls { + switch n := decl.(type) { + case *ast.GenDecl: + // var, const, types + for _, spec := range n.Specs { + switch s := spec.(type) { + case *ast.ValueSpec: + // constants and variables. + for _, name := range s.Names { + p.decl[name.Name] = n + } + case *ast.TypeSpec: + // type definitions. + p.decl[s.Name.Name] = n + } + } + case *ast.FuncDecl: + // function declarations + // TODO(remy): do methods + if n.Recv == nil { + p.decl[n.Name.Name] = n + } + } + } + } + // init() is always used + p.used["init"] = true + if pkg.Name != "main" { + // exported names are marked used for non-main packages. + for name := range p.decl { + if ast.IsExported(name) { + p.used[name] = true + } + } + } else { + // in main programs, main() is called. + p.used["main"] = true + } + for _, file := range pkg.Files { + // walk file looking for used nodes. + ast.Walk(p, file) + } + // reports. + reports := Reports(nil) + for name, node := range p.decl { + if !p.used[name] { + reports = append(reports, Report{node.Pos(), name}) + } + } + sort.Sort(reports) + for _, report := range reports { + errorf("%s: %s is unused", fs.Position(report.pos), report.name) + } +} + +type Report struct { + pos token.Pos + name string +} +type Reports []Report + +func (l Reports) Len() int { return len(l) } +func (l Reports) Less(i, j int) bool { return l[i].pos < l[j].pos } +func (l Reports) Swap(i, j int) { l[i], l[j] = l[j], l[i] } + +// Visits files for used nodes. +func (p *Package) Visit(node ast.Node) ast.Visitor { + u := usedWalker(*p) // hopefully p fields are references. + switch n := node.(type) { + // don't walk whole file, but only: + case *ast.ValueSpec: + // - variable initializers + for _, value := range n.Values { + ast.Walk(&u, value) + } + // variable types. + if n.Type != nil { + ast.Walk(&u, n.Type) + } + case *ast.BlockStmt: + // - function bodies + for _, stmt := range n.List { + ast.Walk(&u, stmt) + } + case *ast.FuncDecl: + // - function signatures + ast.Walk(&u, n.Type) + case *ast.TypeSpec: + // - type declarations + ast.Walk(&u, n.Type) + } + return p +} + +type usedWalker Package + +// Walks through the AST marking used identifiers. +func (p *usedWalker) Visit(node ast.Node) ast.Visitor { + // just be stupid and mark all *ast.Ident + switch n := node.(type) { + case *ast.Ident: + p.used[n.Name] = true + } + return p +} diff --git a/pkg/api/minioapi/bucket_handlers.go b/pkg/api/minioapi/bucket_handlers.go index f98ad6e3d..ef7a743bc 100644 --- a/pkg/api/minioapi/bucket_handlers.go +++ b/pkg/api/minioapi/bucket_handlers.go @@ -40,6 +40,10 @@ func (server *minioApi) listObjectsHandler(w http.ResponseWriter, req *http.Requ return } + if resources.Maxkeys == 0 { + resources.Maxkeys = maxObjectList + } + acceptsContentType := getContentType(req) objects, resources, err := server.storage.ListObjects(bucket, resources) switch err := err.(type) { diff --git a/pkg/api/minioapi/definitions.go b/pkg/api/minioapi/definitions.go index 1c35dc989..6f495a9b3 100644 --- a/pkg/api/minioapi/definitions.go +++ b/pkg/api/minioapi/definitions.go @@ -22,7 +22,7 @@ import ( // Limit number of objects in a given response const ( - MAX_OBJECT_LIST = 1000 + maxObjectList = 1000 ) // Object list response format diff --git a/pkg/storage/donut/data/data_v1/data.go b/pkg/storage/donut/data/data_v1/data.go index 4c3e6e148..3e4e7b269 100644 --- a/pkg/storage/donut/data/data_v1/data.go +++ b/pkg/storage/donut/data/data_v1/data.go @@ -36,8 +36,8 @@ type DataHeader struct { type EncoderTechnique int const ( - VANDERMONDE EncoderTechnique = iota - CAUCHY + Vandermonde EncoderTechnique = iota + Cauchy ) type EncoderParams struct { diff --git a/pkg/storage/donut/data/data_v1/data_test.go b/pkg/storage/donut/data/data_v1/data_test.go index d07fbdf59..6e6d69d1c 100644 --- a/pkg/storage/donut/data/data_v1/data_test.go +++ b/pkg/storage/donut/data/data_v1/data_test.go @@ -39,7 +39,7 @@ func (s *MySuite) TestSingleWrite(c *C) { Length: uint32(len(testData)), K: 8, M: 8, - Technique: CAUCHY, + Technique: Cauchy, } metadata := make(Metadata) metadata["Content-Type"] = "application/octet-stream" diff --git a/pkg/storage/erasure/cauchy_test.go b/pkg/storage/erasure/cauchy_test.go index 5136446f8..a12f8eb4d 100644 --- a/pkg/storage/erasure/cauchy_test.go +++ b/pkg/storage/erasure/cauchy_test.go @@ -29,7 +29,7 @@ var _ = Suite(&MySuite{}) func Test(t *testing.T) { TestingT(t) } func (s *MySuite) TestCauchyDecode(c *C) { - ep, _ := ParseEncoderParams(10, 5, CAUCHY) + ep, _ := ParseEncoderParams(10, 5, Cauchy) data := []byte("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.") diff --git a/pkg/storage/erasure/doc.go b/pkg/storage/erasure/doc.go index e56801a52..8e8e3c9db 100644 --- a/pkg/storage/erasure/doc.go +++ b/pkg/storage/erasure/doc.go @@ -32,7 +32,7 @@ // ParseEncoderParams(k, m, technique int) (EncoderParams, error) // k - Number of rows in matrix // m - Number of colums in matrix -// technique - Matrix type, can be either CAUCHY (recommended) or VANDERMONDE +// technique - Matrix type, can be either Cauchy (recommended) or Vandermonde // constraints: k + m < Galois Field (2^8) // // Choosing right parity and matrix technique is left for application to decide. @@ -53,14 +53,14 @@ // // Creating and using an encoder // var bytes []byte -// params := erasure.ParseEncoderParams(10, 5, erasure.CAUCHY) +// params := erasure.ParseEncoderParams(10, 5, erasure.Cauchy) // encoder := erasure.NewEncoder(params) // encodedData, length := encoder.Encode(bytes) // // Creating and using a decoder // var encodedData [][]byte // var length int -// params := erasure.ParseEncoderParams(10, 5, erasure.CAUCHY) +// params := erasure.ParseEncoderParams(10, 5, erasure.Cauchy) // encoder := erasure.NewEncoder(params) // originalData, err := encoder.Decode(encodedData, length) // diff --git a/pkg/storage/erasure/erasure_encode.go b/pkg/storage/erasure/erasure_encode.go index 4dc9f7c32..96bf7f99b 100644 --- a/pkg/storage/erasure/erasure_encode.go +++ b/pkg/storage/erasure/erasure_encode.go @@ -29,8 +29,8 @@ import ( type Technique int const ( - VANDERMONDE Technique = iota - CAUCHY + Vandermonde Technique = iota + Cauchy ) const ( @@ -59,7 +59,7 @@ type Encoder struct { // ParseEncoderParams creates an EncoderParams object. // // k and m represent the matrix size, which corresponds to the protection level -// technique is the matrix type. Valid inputs are CAUCHY (recommended) or VANDERMONDE. +// technique is the matrix type. Valid inputs are Cauchy (recommended) or Vandermonde. // func ParseEncoderParams(k, m uint8, technique Technique) (*EncoderParams, error) { if k < 1 { @@ -75,9 +75,9 @@ func ParseEncoderParams(k, m uint8, technique Technique) (*EncoderParams, error) } switch technique { - case VANDERMONDE: + case Vandermonde: break - case CAUCHY: + case Cauchy: break default: return nil, errors.New("Technique can be either vandermonde or cauchy") diff --git a/pkg/storage/erasure/stdint.go b/pkg/storage/erasure/stdint.go index 76bf352a3..e23d41a3c 100644 --- a/pkg/storage/erasure/stdint.go +++ b/pkg/storage/erasure/stdint.go @@ -26,16 +26,6 @@ import "unsafe" var ( // See http://golang.org/ref/spec#Numeric_types - - // SizeUint8 is the byte size of a uint8. - sizeUint8 = int(unsafe.Sizeof(uint8(0))) - // SizeUint16 is the byte size of a uint16. - sizeUint16 = int(unsafe.Sizeof(uint16(0))) - // SizeUint32 is the byte size of a uint32. - sizeUint32 = int(unsafe.Sizeof(uint32(0))) - // SizeUint64 is the byte size of a uint64. - sizeUint64 = int(unsafe.Sizeof(uint64(0))) - sizeInt = int(C.sizeInt()) // SizeInt8 is the byte size of a int8. sizeInt8 = int(unsafe.Sizeof(int8(0))) diff --git a/pkg/storage/erasure/vandermonde_test.go b/pkg/storage/erasure/vandermonde_test.go index 750533a18..2fa77df5e 100644 --- a/pkg/storage/erasure/vandermonde_test.go +++ b/pkg/storage/erasure/vandermonde_test.go @@ -22,7 +22,7 @@ import ( ) func (s *MySuite) TestVanderMondeDecode(c *C) { - ep, _ := ParseEncoderParams(10, 5, VANDERMONDE) + ep, _ := ParseEncoderParams(10, 5, Vandermonde) data := []byte("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.")