mirror of
https://github.com/minio/minio.git
synced 2025-01-11 15:03:22 -05: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…
Reference in New Issue
Block a user