hack/update-vendor.sh

This commit is contained in:
Jordan Liggitt
2019-11-05 14:11:10 -05:00
parent 9a5b7c24ad
commit 297570e06a
932 changed files with 77190 additions and 28219 deletions

View File

@@ -75,7 +75,7 @@ func ShortenLabel(label string, pkg string) string {
if !ShortenLabelsFlag {
return label
}
if !strings.HasPrefix(label, "//") {
if !strings.Contains(label, "//") {
// It doesn't look like a long label, so we preserve it.
return label
}
@@ -85,7 +85,13 @@ func ShortenLabel(label string, pkg string) string {
}
slash := strings.LastIndex(labelPkg, "/")
if (slash >= 0 && labelPkg[slash+1:] == rule) || labelPkg == rule {
return "//" + labelPkg
if repo == "" {
return "//" + labelPkg
}
return "@" + repo + "//" + labelPkg
}
if strings.HasPrefix(label, "@") && repo == rule && labelPkg == "" {
return "@" + repo
}
return label
}
@@ -162,8 +168,8 @@ func ExprToRule(expr build.Expr, kind string) (*build.Rule, bool) {
if !ok {
return nil, false
}
k, ok := call.X.(*build.LiteralExpr)
if !ok || k.Token != kind {
k, ok := call.X.(*build.Ident)
if !ok || k.Name != kind {
return nil, false
}
return &build.Rule{call, ""}, true
@@ -180,21 +186,25 @@ func ExistingPackageDeclaration(f *build.File) *build.Rule {
}
// PackageDeclaration returns the package declaration. If it doesn't
// exist, it is created at the top of the BUILD file, after leading
// comments.
// exist, it is created at the top of the BUILD file, after optional
// docstring, comments, and load statements.
func PackageDeclaration(f *build.File) *build.Rule {
if pkg := ExistingPackageDeclaration(f); pkg != nil {
return pkg
}
all := []build.Expr{}
added := false
call := &build.CallExpr{X: &build.LiteralExpr{Token: "package"}}
// Skip CommentBlocks and find a place to insert the package declaration.
call := &build.CallExpr{X: &build.Ident{Name: "package"}}
for _, stmt := range f.Stmt {
_, ok := stmt.(*build.CommentBlock)
if !ok && !added {
all = append(all, call)
added = true
switch stmt.(type) {
case *build.CommentBlock, *build.LoadStmt, *build.StringExpr:
// Skip docstring, comments, and load statements to
// find a place to insert the package declaration.
default:
if !added {
all = append(all, call)
added = true
}
}
all = append(all, stmt)
}
@@ -213,14 +223,14 @@ func RemoveEmptyPackage(f *build.File) *build.File {
var all []build.Expr
for _, stmt := range f.Stmt {
if call, ok := stmt.(*build.CallExpr); ok {
functionName, ok := call.X.(*build.LiteralExpr)
if ok && functionName.Token == "package" && len(call.List) == 0 {
functionName, ok := call.X.(*build.Ident)
if ok && functionName.Name == "package" && len(call.List) == 0 {
continue
}
}
all = append(all, stmt)
}
return &build.File{Path: f.Path, Comments: f.Comments, Stmt: all}
return &build.File{Path: f.Path, Comments: f.Comments, Stmt: all, Type: build.TypeBuild}
}
// InsertAfter inserts an expression after index i.
@@ -241,8 +251,8 @@ func IndexOfLast(stmt []build.Expr, Kind string) int {
if !ok {
continue
}
literal, ok := sAsCallExpr.X.(*build.LiteralExpr)
if ok && literal.Token == Kind {
literal, ok := sAsCallExpr.X.(*build.Ident)
if ok && literal.Name == Kind {
lastIndex = i
}
}
@@ -251,7 +261,7 @@ func IndexOfLast(stmt []build.Expr, Kind string) int {
// InsertAfterLastOfSameKind inserts an expression after the last expression of the same kind.
func InsertAfterLastOfSameKind(stmt []build.Expr, expr *build.CallExpr) []build.Expr {
index := IndexOfLast(stmt, expr.X.(*build.LiteralExpr).Token)
index := IndexOfLast(stmt, expr.X.(*build.Ident).Name)
if index == -1 {
return InsertAtEnd(stmt, expr)
}
@@ -329,7 +339,7 @@ func DeleteRule(f *build.File, rule *build.Rule) *build.File {
}
all = append(all, stmt)
}
return &build.File{Path: f.Path, Comments: f.Comments, Stmt: all}
return &build.File{Path: f.Path, Comments: f.Comments, Stmt: all, Type: build.TypeBuild}
}
// DeleteRuleByName returns the AST without the rules that have the
@@ -347,7 +357,7 @@ func DeleteRuleByName(f *build.File, name string) *build.File {
all = append(all, stmt)
}
}
return &build.File{Path: f.Path, Comments: f.Comments, Stmt: all}
return &build.File{Path: f.Path, Comments: f.Comments, Stmt: all, Type: build.TypeBuild}
}
// DeleteRuleByKind removes the rules of the specified kind from the AST.
@@ -360,12 +370,12 @@ func DeleteRuleByKind(f *build.File, kind string) *build.File {
all = append(all, stmt)
continue
}
k, ok := call.X.(*build.LiteralExpr)
if !ok || k.Token != kind {
k, ok := call.X.(*build.Ident)
if !ok || k.Name != kind {
all = append(all, stmt)
}
}
return &build.File{Path: f.Path, Comments: f.Comments, Stmt: all}
return &build.File{Path: f.Path, Comments: f.Comments, Stmt: all, Type: build.TypeBuild}
}
// AllLists returns all the lists concatenated in an expression.
@@ -383,6 +393,21 @@ func AllLists(e build.Expr) []*build.ListExpr {
return nil
}
// AllSelects returns all the selects concatenated in an expression.
func AllSelects(e build.Expr) []*build.CallExpr {
switch e := e.(type) {
case *build.BinaryExpr:
if e.Op == "+" {
return append(AllSelects(e.X), AllSelects(e.Y)...)
}
case *build.CallExpr:
if x, ok := e.X.(*build.Ident); ok && x.Name == "select" {
return []*build.CallExpr{e}
}
}
return nil
}
// FirstList works in the same way as AllLists, except that it
// returns only one list, or nil.
func FirstList(e build.Expr) *build.ListExpr {
@@ -451,24 +476,208 @@ func ContainsComments(expr build.Expr, str string) bool {
return false
}
// RemoveEmptySelectsAndConcatLists iterates the tree in order to turn
// empty selects into empty lists and adjacent lists are concatenated
func RemoveEmptySelectsAndConcatLists(e build.Expr) build.Expr {
switch e := e.(type) {
case *build.BinaryExpr:
if e.Op == "+" {
e.X = RemoveEmptySelectsAndConcatLists(e.X)
e.Y = RemoveEmptySelectsAndConcatLists(e.Y)
x, xIsList := e.X.(*build.ListExpr)
y, yIsList := e.Y.(*build.ListExpr)
if xIsList && yIsList {
return &build.ListExpr{List: append(x.List, y.List...)}
}
if xIsList && len(x.List) == 0 {
return e.Y
}
if yIsList && len(y.List) == 0 {
return e.X
}
}
case *build.CallExpr:
if x, ok := e.X.(*build.Ident); ok && x.Name == "select" {
if len(e.List) == 0 {
return &build.ListExpr{List: []build.Expr{}}
}
if dict, ok := e.List[0].(*build.DictExpr); ok {
for _, keyVal := range dict.List {
if keyVal, ok := keyVal.(*build.KeyValueExpr); ok {
val, ok := keyVal.Value.(*build.ListExpr)
if !ok || len(val.List) > 0 {
return e
}
} else {
return e
}
}
return &build.ListExpr{List: []build.Expr{}}
}
}
}
return e
}
// ComputeIntersection returns the intersection of the two lists given as parameters;
// if the containing elements are not build.StringExpr, the result will be nil.
func ComputeIntersection(list1, list2 []build.Expr) []build.Expr {
if list1 == nil || list2 == nil {
return nil
}
if len(list2) == 0 {
return []build.Expr{}
}
i := 0
for j, common := range list1 {
if common, ok := common.(*build.StringExpr); ok {
found := false
for _, elem := range list2 {
if str, ok := elem.(*build.StringExpr); ok {
if str.Value == common.Value {
found = true
break
}
} else {
return nil
}
}
if found {
list1[i] = list1[j]
i++
}
} else {
return nil
}
}
return list1[:i]
}
// SelectListsIntersection returns the intersection of the lists of strings inside
// the dictionary argument of the select expression given as a parameter
func SelectListsIntersection(sel *build.CallExpr, pkg string) (intersection []build.Expr) {
if len(sel.List) == 0 || len(sel.List) > 1 {
return nil
}
dict, ok := sel.List[0].(*build.DictExpr)
if !ok || len(dict.List) == 0 {
return nil
}
if keyVal, ok := dict.List[0].(*build.KeyValueExpr); ok {
if val, ok := keyVal.Value.(*build.ListExpr); ok {
intersection = make([]build.Expr, len(val.List))
copy(intersection, val.List)
}
}
for _, keyVal := range dict.List[1:] {
if keyVal, ok := keyVal.(*build.KeyValueExpr); ok {
if val, ok := keyVal.Value.(*build.ListExpr); ok {
intersection = ComputeIntersection(intersection, val.List)
if len(intersection) == 0 {
return intersection
}
} else {
return nil
}
} else {
return nil
}
}
return intersection
}
// ResolveAttr extracts common elements of the lists inside select dictionaries
// and adds them at attribute level rather than select level, as well as turns
// empty selects into empty lists and concatenates adjacent lists
func ResolveAttr(r *build.Rule, attr, pkg string) {
var toExtract []build.Expr
e := r.Attr(attr)
if e == nil {
return
}
for _, sel := range AllSelects(e) {
intersection := SelectListsIntersection(sel, pkg)
if intersection != nil {
toExtract = append(toExtract, intersection...)
}
}
for _, common := range toExtract {
e = AddValueToList(e, pkg, common, false) // this will also remove them from selects
}
r.SetAttr(attr, RemoveEmptySelectsAndConcatLists(e))
}
// SelectDelete removes the item from all the lists which are values
// in the dictionary of every select
func SelectDelete(e build.Expr, item, pkg string, deleted **build.StringExpr) {
for _, sel := range AllSelects(e) {
if len(sel.List) == 0 {
continue
}
if dict, ok := sel.List[0].(*build.DictExpr); ok {
for _, keyVal := range dict.List {
if keyVal, ok := keyVal.(*build.KeyValueExpr); ok {
if val, ok := keyVal.Value.(*build.ListExpr); ok {
RemoveFromList(val, item, pkg, deleted)
}
}
}
}
}
}
// RemoveFromList removes one element from a ListExpr and stores
// the deleted StringExpr at the address pointed by the last parameter
func RemoveFromList(li *build.ListExpr, item, pkg string, deleted **build.StringExpr) {
var all []build.Expr
for _, elem := range li.List {
if str, ok := elem.(*build.StringExpr); ok {
if LabelsEqual(str.Value, item, pkg) && (DeleteWithComments || !hasComments(str)) {
if deleted != nil {
*deleted = str
}
continue
}
}
all = append(all, elem)
}
li.List = all
}
// ListDelete deletes the item from a list expression in e and returns
// the StringExpr deleted, or nil otherwise.
func ListDelete(e build.Expr, item, pkg string) (deleted *build.StringExpr) {
if unquoted, _, err := build.Unquote(item); err == nil {
item = unquoted
}
deleted = nil
item = ShortenLabel(item, pkg)
for _, li := range AllLists(e) {
var all []build.Expr
for _, elem := range li.List {
if str, ok := elem.(*build.StringExpr); ok {
if LabelsEqual(str.Value, item, pkg) && (DeleteWithComments || !hasComments(str)) {
deleted = str
continue
}
}
all = append(all, elem)
}
li.List = all
RemoveFromList(li, item, pkg, &deleted)
}
SelectDelete(e, item, pkg, &deleted)
return deleted
}
@@ -582,13 +791,13 @@ func attributeMustNotBeSorted(rule, attr string) bool {
// getVariable returns the binary expression that assignes a variable to expr, if expr is
// an identifier of a variable that vars contains a mapping for.
func getVariable(expr build.Expr, vars *map[string]*build.BinaryExpr) (varAssignment *build.BinaryExpr) {
func getVariable(expr build.Expr, vars *map[string]*build.AssignExpr) (varAssignment *build.AssignExpr) {
if vars == nil {
return nil
}
if literal, ok := expr.(*build.LiteralExpr); ok {
if varAssignment = (*vars)[literal.Token]; varAssignment != nil {
if literal, ok := expr.(*build.Ident); ok {
if varAssignment = (*vars)[literal.Name]; varAssignment != nil {
return varAssignment
}
}
@@ -604,10 +813,14 @@ func AddValueToList(oldList build.Expr, pkg string, item build.Expr, sorted bool
}
str, ok := item.(*build.StringExpr)
if ok && ListFind(oldList, str.Value, pkg) != nil {
// The value is already in the list.
return oldList
if ok {
if ListFind(oldList, str.Value, pkg) != nil {
// The value is already in the list.
return oldList
}
SelectDelete(oldList, str.Value, pkg, nil)
}
li := FirstList(oldList)
if li != nil {
if sorted {
@@ -623,11 +836,11 @@ func AddValueToList(oldList build.Expr, pkg string, item build.Expr, sorted bool
}
// AddValueToListAttribute adds the given item to the list attribute identified by name and pkg.
func AddValueToListAttribute(r *build.Rule, name string, pkg string, item build.Expr, vars *map[string]*build.BinaryExpr) {
func AddValueToListAttribute(r *build.Rule, name string, pkg string, item build.Expr, vars *map[string]*build.AssignExpr) {
old := r.Attr(name)
sorted := !attributeMustNotBeSorted(r.Kind(), name)
if varAssignment := getVariable(old, vars); varAssignment != nil {
varAssignment.Y = AddValueToList(varAssignment.Y, pkg, item, sorted)
varAssignment.RHS = AddValueToList(varAssignment.RHS, pkg, item, sorted)
} else {
r.SetAttr(name, AddValueToList(old, pkg, item, sorted))
}
@@ -635,7 +848,7 @@ func AddValueToListAttribute(r *build.Rule, name string, pkg string, item build.
// MoveAllListAttributeValues moves all values from list attribute oldAttr to newAttr,
// and deletes oldAttr.
func MoveAllListAttributeValues(rule *build.Rule, oldAttr, newAttr, pkg string, vars *map[string]*build.BinaryExpr) error {
func MoveAllListAttributeValues(rule *build.Rule, oldAttr, newAttr, pkg string, vars *map[string]*build.AssignExpr) error {
if rule.Attr(oldAttr) == nil {
return fmt.Errorf("no attribute %s found in %s", oldAttr, rule.Name())
}
@@ -672,21 +885,58 @@ func DictionarySet(dict *build.DictExpr, key string, value build.Expr) build.Exp
return nil
}
// DictionaryGet looks for the key in the dictionary expression, and returns the
// current value. If it is unset, it returns nil.
func DictionaryGet(dict *build.DictExpr, key string) build.Expr {
for _, e := range dict.List {
kv, ok := e.(*build.KeyValueExpr)
if !ok {
continue
}
if k, ok := kv.Key.(*build.StringExpr); ok && k.Value == key {
return kv.Value
}
}
return nil
}
// DictionaryDelete looks for the key in the dictionary expression. If the key exists,
// it removes the key-value pair and returns it. Otherwise it returns nil.
func DictionaryDelete(dict *build.DictExpr, key string) (deleted build.Expr) {
if unquoted, _, err := build.Unquote(key); err == nil {
key = unquoted
}
deleted = nil
var all []build.Expr
for _, e := range dict.List {
kv, _ := e.(*build.KeyValueExpr)
if k, ok := kv.Key.(*build.StringExpr); ok {
if k.Value == key {
deleted = kv
} else {
all = append(all, e)
}
}
}
dict.List = all
return deleted
}
// RenameAttribute renames an attribute in a rule.
func RenameAttribute(r *build.Rule, oldName, newName string) error {
if r.Attr(newName) != nil {
return fmt.Errorf("attribute %s already exists in rule %s", newName, r.Name())
}
for _, kv := range r.Call.List {
as, ok := kv.(*build.BinaryExpr)
if !ok || as.Op != "=" {
as, ok := kv.(*build.AssignExpr)
if !ok {
continue
}
k, ok := as.X.(*build.LiteralExpr)
if !ok || k.Token != oldName {
k, ok := as.LHS.(*build.Ident)
if !ok || k.Name != oldName {
continue
}
k.Token = newName
k.Name = newName
return nil
}
return fmt.Errorf("no attribute %s found in rule %s", oldName, r.Name())
@@ -700,8 +950,8 @@ func EditFunction(v build.Expr, name string, f func(x *build.CallExpr, stk []bui
if !ok {
return nil
}
fct, ok := call.X.(*build.LiteralExpr)
if !ok || fct.Token != name {
fct, ok := call.X.(*build.Ident)
if !ok || fct.Name != name {
return nil
}
return f(call, stk)
@@ -709,107 +959,137 @@ func EditFunction(v build.Expr, name string, f func(x *build.CallExpr, stk []bui
}
// UsedSymbols returns the set of symbols used in the BUILD file (variables, function names).
func UsedSymbols(f *build.File) map[string]bool {
func UsedSymbols(stmt build.Expr) map[string]bool {
symbols := make(map[string]bool)
build.Walk(f, func(expr build.Expr, stack []build.Expr) {
literal, ok := expr.(*build.LiteralExpr)
build.Walk(stmt, func(expr build.Expr, stack []build.Expr) {
// Don't traverse inside load statements
if len(stack) > 0 {
if _, ok := stack[len(stack)-1].(*build.LoadStmt); ok {
return
}
}
literal, ok := expr.(*build.Ident)
if !ok {
return
}
// Check if we are on the left-side of an assignment
for _, e := range stack {
if as, ok := e.(*build.BinaryExpr); ok {
if as.Op == "=" && as.X == expr {
if as, ok := e.(*build.AssignExpr); ok {
if as.LHS == expr {
return
}
}
}
symbols[literal.Token] = true
symbols[literal.Name] = true
})
return symbols
}
func newLoad(args []string) *build.CallExpr {
load := &build.CallExpr{
X: &build.LiteralExpr{
Token: "load",
// NewLoad creates a new LoadStmt node
func NewLoad(location string, from, to []string) *build.LoadStmt {
load := &build.LoadStmt{
Module: &build.StringExpr{
Value: location,
},
List: []build.Expr{},
ForceCompact: true,
}
for _, a := range args {
load.List = append(load.List, &build.StringExpr{Value: a})
for i := range from {
load.From = append(load.From, &build.Ident{Name: from[i]})
load.To = append(load.To, &build.Ident{Name: to[i]})
}
return load
}
// appendLoad tries to find an existing load location and append symbols to it.
func appendLoad(stmts []build.Expr, args []string) bool {
if len(args) == 0 {
return false
// AppendToLoad appends symbols to an existing load statement
// Returns true if the statement was acually edited (if the required symbols haven't been
// loaded yet)
func AppendToLoad(load *build.LoadStmt, from, to []string) bool {
symbolsToLoad := make(map[string]string)
for i, s := range to {
symbolsToLoad[s] = from[i]
}
location := args[0]
symbolsToLoad := make(map[string]bool)
for _, s := range args[1:] {
symbolsToLoad[s] = true
}
var lastLoad *build.CallExpr
for _, s := range stmts {
call, ok := s.(*build.CallExpr)
if !ok {
continue
}
if l, ok := call.X.(*build.LiteralExpr); !ok || l.Token != "load" {
continue
}
if len(call.List) < 2 {
continue
}
if s, ok := call.List[0].(*build.StringExpr); !ok || s.Value != location {
continue // Loads a different file.
}
for _, arg := range call.List[1:] {
if s, ok := arg.(*build.StringExpr); ok {
delete(symbolsToLoad, s.Value) // Already loaded.
}
}
// Remember the last insert location, but potentially remove more symbols
// that are already loaded in other subsequent calls.
lastLoad = call
for _, ident := range load.To {
delete(symbolsToLoad, ident.Name) // Already loaded.
}
if lastLoad == nil {
if len(symbolsToLoad) == 0 {
return false
}
// Append the remaining loads to the last load location.
// Append the remaining loads to the load statement.
sortedSymbols := []string{}
for s := range symbolsToLoad {
sortedSymbols = append(sortedSymbols, s)
}
sort.Strings(sortedSymbols)
for _, s := range sortedSymbols {
lastLoad.List = append(lastLoad.List, &build.StringExpr{Value: s})
load.From = append(load.From, &build.Ident{Name: symbolsToLoad[s]})
load.To = append(load.To, &build.Ident{Name: s})
}
return true
}
// appendLoad tries to find an existing load location and append symbols to it.
func appendLoad(stmts []build.Expr, location string, from, to []string) bool {
symbolsToLoad := make(map[string]string)
for i, s := range to {
symbolsToLoad[s] = from[i]
}
var lastLoad *build.LoadStmt
for _, s := range stmts {
load, ok := s.(*build.LoadStmt)
if !ok {
continue
}
if load.Module.Value != location {
continue // Loads a different file.
}
for _, ident := range load.To {
delete(symbolsToLoad, ident.Name) // Already loaded.
}
// Remember the last insert location, but potentially remove more symbols
// that are already loaded in other subsequent calls.
lastLoad = load
}
if lastLoad == nil {
return false
}
// Append the remaining loads to the last load location.
from = []string{}
to = []string{}
for t, f := range symbolsToLoad {
from = append(from, f)
to = append(to, t)
}
AppendToLoad(lastLoad, from, to)
return true
}
// InsertLoad inserts a load statement at the top of the list of statements.
// The load statement is constructed using args. Symbols that are already loaded
// The load statement is constructed using a string location and two slices of from- and to-symbols.
// The function panics if the slices aren't of the same lentgh. Symbols that are already loaded
// from the given filepath are ignored. If stmts already contains a load for the
// location in arguments, appends the symbols to load to it.
func InsertLoad(stmts []build.Expr, args []string) []build.Expr {
if appendLoad(stmts, args) {
func InsertLoad(stmts []build.Expr, location string, from, to []string) []build.Expr {
if len(from) != len(to) {
panic(fmt.Errorf("length mismatch: %v (from) and %v (to)", len(from), len(to)))
}
if appendLoad(stmts, location, from, to) {
return stmts
}
load := newLoad(args)
load := NewLoad(location, from, to)
var all []build.Expr
added := false
for _, stmt := range stmts {
for i, stmt := range stmts {
_, isComment := stmt.(*build.CommentBlock)
if isComment || added {
_, isString := stmt.(*build.StringExpr)
isDocString := isString && i == 0
if isComment || isDocString || added {
all = append(all, stmt)
continue
}