mirror of
https://github.com/minio/minio.git
synced 2024-12-28 08:05:55 -05:00
61175ef091
- over the course of a project history every maintainer needs to update its dependency packages, the problem essentially with godep is manipulating GOPATH - this manipulation leads to static objects created at different locations which end up conflicting with the overall functionality of golang. This also leads to broken builds. There is no easier way out of this other than asking developers to do 'godep restore' all the time. Which perhaps as a practice doesn't sound like a clean solution. On the other hand 'godep restore' has its own set of problems. - govendor is a right tool but a stop gap tool until we wait for golangs official 1.5 version which fixes this vendoring issue once and for all. - govendor provides consistency in terms of how import paths should be handled unlike manipulation GOPATH. This has advantages - no more compiled objects being referenced in GOPATH and build time GOPATH manging which leads to conflicts. - proper import paths referencing the exact package a project is dependent on. govendor is simple and provides the minimal necessary tooling to achieve this. For now this is the right solution.
169 lines
3.7 KiB
Go
169 lines
3.7 KiB
Go
package check
|
|
|
|
import (
|
|
"bytes"
|
|
"go/ast"
|
|
"go/parser"
|
|
"go/printer"
|
|
"go/token"
|
|
"os"
|
|
)
|
|
|
|
func indent(s, with string) (r string) {
|
|
eol := true
|
|
for i := 0; i != len(s); i++ {
|
|
c := s[i]
|
|
switch {
|
|
case eol && c == '\n' || c == '\r':
|
|
case c == '\n' || c == '\r':
|
|
eol = true
|
|
case eol:
|
|
eol = false
|
|
s = s[:i] + with + s[i:]
|
|
i += len(with)
|
|
}
|
|
}
|
|
return s
|
|
}
|
|
|
|
func printLine(filename string, line int) (string, error) {
|
|
fset := token.NewFileSet()
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
fnode, err := parser.ParseFile(fset, filename, file, parser.ParseComments)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
config := &printer.Config{Mode: printer.UseSpaces, Tabwidth: 4}
|
|
lp := &linePrinter{fset: fset, fnode: fnode, line: line, config: config}
|
|
ast.Walk(lp, fnode)
|
|
result := lp.output.Bytes()
|
|
// Comments leave \n at the end.
|
|
n := len(result)
|
|
for n > 0 && result[n-1] == '\n' {
|
|
n--
|
|
}
|
|
return string(result[:n]), nil
|
|
}
|
|
|
|
type linePrinter struct {
|
|
config *printer.Config
|
|
fset *token.FileSet
|
|
fnode *ast.File
|
|
line int
|
|
output bytes.Buffer
|
|
stmt ast.Stmt
|
|
}
|
|
|
|
func (lp *linePrinter) emit() bool {
|
|
if lp.stmt != nil {
|
|
lp.trim(lp.stmt)
|
|
lp.printWithComments(lp.stmt)
|
|
lp.stmt = nil
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (lp *linePrinter) printWithComments(n ast.Node) {
|
|
nfirst := lp.fset.Position(n.Pos()).Line
|
|
nlast := lp.fset.Position(n.End()).Line
|
|
for _, g := range lp.fnode.Comments {
|
|
cfirst := lp.fset.Position(g.Pos()).Line
|
|
clast := lp.fset.Position(g.End()).Line
|
|
if clast == nfirst-1 && lp.fset.Position(n.Pos()).Column == lp.fset.Position(g.Pos()).Column {
|
|
for _, c := range g.List {
|
|
lp.output.WriteString(c.Text)
|
|
lp.output.WriteByte('\n')
|
|
}
|
|
}
|
|
if cfirst >= nfirst && cfirst <= nlast && n.End() <= g.List[0].Slash {
|
|
// The printer will not include the comment if it starts past
|
|
// the node itself. Trick it into printing by overlapping the
|
|
// slash with the end of the statement.
|
|
g.List[0].Slash = n.End() - 1
|
|
}
|
|
}
|
|
node := &printer.CommentedNode{n, lp.fnode.Comments}
|
|
lp.config.Fprint(&lp.output, lp.fset, node)
|
|
}
|
|
|
|
func (lp *linePrinter) Visit(n ast.Node) (w ast.Visitor) {
|
|
if n == nil {
|
|
if lp.output.Len() == 0 {
|
|
lp.emit()
|
|
}
|
|
return nil
|
|
}
|
|
first := lp.fset.Position(n.Pos()).Line
|
|
last := lp.fset.Position(n.End()).Line
|
|
if first <= lp.line && last >= lp.line {
|
|
// Print the innermost statement containing the line.
|
|
if stmt, ok := n.(ast.Stmt); ok {
|
|
if _, ok := n.(*ast.BlockStmt); !ok {
|
|
lp.stmt = stmt
|
|
}
|
|
}
|
|
if first == lp.line && lp.emit() {
|
|
return nil
|
|
}
|
|
return lp
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (lp *linePrinter) trim(n ast.Node) bool {
|
|
stmt, ok := n.(ast.Stmt)
|
|
if !ok {
|
|
return true
|
|
}
|
|
line := lp.fset.Position(n.Pos()).Line
|
|
if line != lp.line {
|
|
return false
|
|
}
|
|
switch stmt := stmt.(type) {
|
|
case *ast.IfStmt:
|
|
stmt.Body = lp.trimBlock(stmt.Body)
|
|
case *ast.SwitchStmt:
|
|
stmt.Body = lp.trimBlock(stmt.Body)
|
|
case *ast.TypeSwitchStmt:
|
|
stmt.Body = lp.trimBlock(stmt.Body)
|
|
case *ast.CaseClause:
|
|
stmt.Body = lp.trimList(stmt.Body)
|
|
case *ast.CommClause:
|
|
stmt.Body = lp.trimList(stmt.Body)
|
|
case *ast.BlockStmt:
|
|
stmt.List = lp.trimList(stmt.List)
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (lp *linePrinter) trimBlock(stmt *ast.BlockStmt) *ast.BlockStmt {
|
|
if !lp.trim(stmt) {
|
|
return lp.emptyBlock(stmt)
|
|
}
|
|
stmt.Rbrace = stmt.Lbrace
|
|
return stmt
|
|
}
|
|
|
|
func (lp *linePrinter) trimList(stmts []ast.Stmt) []ast.Stmt {
|
|
for i := 0; i != len(stmts); i++ {
|
|
if !lp.trim(stmts[i]) {
|
|
stmts[i] = lp.emptyStmt(stmts[i])
|
|
break
|
|
}
|
|
}
|
|
return stmts
|
|
}
|
|
|
|
func (lp *linePrinter) emptyStmt(n ast.Node) *ast.ExprStmt {
|
|
return &ast.ExprStmt{&ast.Ellipsis{n.Pos(), nil}}
|
|
}
|
|
|
|
func (lp *linePrinter) emptyBlock(n ast.Node) *ast.BlockStmt {
|
|
p := n.Pos()
|
|
return &ast.BlockStmt{p, []ast.Stmt{lp.emptyStmt(n)}, p}
|
|
}
|