mirror of
				https://github.com/minio/minio.git
				synced 2025-10-29 15:55:00 -04:00 
			
		
		
		
	Implement custom date command for cross platform portability
This commit is contained in:
		
							parent
							
								
									23861fa6a7
								
							
						
					
					
						commit
						5d484e2770
					
				
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @ -49,7 +49,7 @@ minio: pre-build build-all test-all | ||||
| 
 | ||||
| install: minio | ||||
| 	@echo "Installing minio:" | ||||
| 	@godep go install -a -ldflags "-X main.BuildDate `date -u '+%FT%T.%N%:z'`" github.com/minio/minio | ||||
| 	@godep go install -a -ldflags "-X main.BuildDate `go run buildscripts/date.go`" github.com/minio/minio | ||||
| 
 | ||||
| save: restore | ||||
| 	@godep save ./... | ||||
|  | ||||
							
								
								
									
										26
									
								
								buildscripts/date.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								buildscripts/date.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| /* | ||||
|  * Minio Client (C) 2014, 2015 Minio, Inc. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| func main() { | ||||
| 	fmt.Println(time.Now().UTC().Format(time.RFC3339Nano)) | ||||
| } | ||||
| @ -1,247 +0,0 @@ | ||||
| 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) | ||||
| } | ||||
| 
 | ||||
| // error formats the error to standard error, adding program | ||||
| // identification and a newline | ||||
| func errorf(format string, args ...interface{}) { | ||||
| 	fmt.Fprintf(os.Stderr, "verifier: "+format+"\n", args...) | ||||
| 	exitCode = 2 | ||||
| } | ||||
| 
 | ||||
| type goPackage struct { | ||||
| 	p               *ast.Package | ||||
| 	fs              *token.FileSet | ||||
| 	decl            map[string]ast.Node | ||||
| 	missingcomments map[string]ast.Node | ||||
| 	used            map[string]bool | ||||
| } | ||||
| 
 | ||||
| type usedWalker goPackage | ||||
| 
 | ||||
| // 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 | ||||
| } | ||||
| 
 | ||||
| type report struct { | ||||
| 	pos  token.Pos | ||||
| 	name string | ||||
| } | ||||
| type reports []report | ||||
| 
 | ||||
| // Len | ||||
| func (l reports) Len() int { return len(l) } | ||||
| 
 | ||||
| // Less | ||||
| func (l reports) Less(i, j int) bool { return l[i].pos < l[j].pos } | ||||
| 
 | ||||
| // Swap | ||||
| func (l reports) Swap(i, j int) { l[i], l[j] = l[j], l[i] } | ||||
| 
 | ||||
| // Visits files for used nodes. | ||||
| func (p *goPackage) 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 | ||||
| } | ||||
| 
 | ||||
| func getAllMinioPkgs(path string, fl os.FileInfo, err error) error { | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if fl.IsDir() { | ||||
| 		// Skip godeps | ||||
| 		if strings.Contains(path, "Godeps") { | ||||
| 			return nil | ||||
| 		} | ||||
| 		dirs = appendUniq(dirs, path) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| 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.ParseComments|parser.Mode(0)) | ||||
| 	if err != nil { | ||||
| 		errorf("%s", err) | ||||
| 		return | ||||
| 	} | ||||
| 	for _, pkg := range pkgs { | ||||
| 		doPackage(fs, pkg) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func doDecl(p *goPackage, decl interface{}, cmap ast.CommentMap) bool { | ||||
| 	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: | ||||
| 		// if function is 'main', never check | ||||
| 		if n.Name.Name == "main" { | ||||
| 			return true | ||||
| 		} | ||||
| 		// Do not be strict on non-exported functions | ||||
| 		if !ast.IsExported(n.Name.Name) { | ||||
| 			return true | ||||
| 		} | ||||
| 		// Do not be strict for field list functions | ||||
| 		// if n.Recv != nil { | ||||
| 		// continue | ||||
| 		//} | ||||
| 		// Be strict for global functions | ||||
| 		_, ok := cmap[n] | ||||
| 		if ok == false { | ||||
| 			p.missingcomments[n.Name.Name] = n | ||||
| 		} | ||||
| 
 | ||||
| 		// function declarations | ||||
| 		// TODO(remy): do methods | ||||
| 		if n.Recv == nil { | ||||
| 			p.decl[n.Name.Name] = n | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func doPackage(fs *token.FileSet, pkg *ast.Package) { | ||||
| 	p := &goPackage{ | ||||
| 		p:               pkg, | ||||
| 		fs:              fs, | ||||
| 		decl:            make(map[string]ast.Node), | ||||
| 		missingcomments: make(map[string]ast.Node), | ||||
| 		used:            make(map[string]bool), | ||||
| 	} | ||||
| 	for _, file := range pkg.Files { | ||||
| 		cmap := ast.NewCommentMap(fs, file, file.Comments) | ||||
| 		for _, decl := range file.Decls { | ||||
| 			if doDecl(p, decl, cmap) { | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	// 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) | ||||
| 	} | ||||
| 
 | ||||
| 	for name, node := range p.missingcomments { | ||||
| 		errorf("%s: comment is missing for 'func %s'", fs.Position(node.Pos()), name) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 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, getAllMinioPkgs) | ||||
| 				if err != nil { | ||||
| 					errorf(err.Error()) | ||||
| 				} | ||||
| 				for _, dir := range dirs { | ||||
| 					doDir(dir) | ||||
| 				} | ||||
| 			} else { | ||||
| 				errorf("not a directory: %s", name) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	os.Exit(exitCode) | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user