1// Copyright 2019 The Bazel Authors. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package check 16 17import ( 18 "fmt" 19 "os" 20 "path/filepath" 21 "runtime" 22 "sort" 23 "strings" 24 25 "github.com/bazelbuild/rules_go/go/tools/bazel" 26) 27 28type TestFile struct { 29 Workspace, ShortPath, Path string 30 Binary bool 31} 32 33var DefaultTestFiles = []TestFile{ 34 {Workspace: "io_bazel_rules_go", Path: "tests/core/runfiles/local_file.txt"}, 35 {Workspace: "io_bazel_rules_go", Path: "tests/core/runfiles/local_group.txt"}, 36 {Workspace: "io_bazel_rules_go", Path: "tests/core/runfiles/local_bin", Binary: true}, 37 {Workspace: "runfiles_remote_test", Path: "remote_file.txt"}, 38 {Workspace: "runfiles_remote_test", Path: "remote_group.txt"}, 39 {Workspace: "runfiles_remote_test", Path: "remote_bin", Binary: true}, 40} 41 42func CheckRunfiles(files []TestFile) error { 43 // Check that the runfiles directory matches the current workspace. 44 // There is no runfiles directory on Windows. 45 if runtime.GOOS != "windows" { 46 dir, err := bazel.RunfilesPath() 47 if err != nil { 48 return err 49 } 50 root, base := filepath.Dir(dir), filepath.Base(dir) 51 if !strings.HasSuffix(root, ".runfiles") { 52 return fmt.Errorf("RunfilesPath: %q is not a .runfiles directory", dir) 53 } 54 workspace := os.Getenv("TEST_WORKSPACE") 55 if workspace != "" && workspace != base { 56 return fmt.Errorf("RunfilesPath: %q does not match test workspace %s", dir, workspace) 57 } 58 if srcDir := os.Getenv("TEST_SRCDIR"); srcDir != "" && filepath.Join(srcDir, workspace) != dir { 59 return fmt.Errorf("RunfilesPath: %q does not match TEST_SRCDIR %q", dir, srcDir) 60 } 61 } 62 63 // Check that files can be found with Runfile or FindBinary. 64 // Make sure the paths returned are absolute paths to actual files. 65 seen := make(map[string]string) 66 for _, f := range files { 67 var got string 68 var err error 69 if !f.Binary { 70 if got, err = bazel.Runfile(f.Path); err != nil { 71 return err 72 } 73 if !filepath.IsAbs(got) { 74 return fmt.Errorf("Runfile %s: got a relative path %q; want absolute", f.Path, got) 75 } 76 seen[f.Path] = got 77 } else { 78 var pkg, name string 79 if i := strings.LastIndex(f.Path, "/"); i < 0 { 80 name = f.Path 81 } else { 82 pkg = f.Path[:i] 83 name = f.Path[i+1:] 84 } 85 var ok bool 86 if got, ok = bazel.FindBinary(pkg, name); !ok { 87 return fmt.Errorf("FindBinary %s %s: could not find binary", pkg, name) 88 } 89 if !filepath.IsAbs(got) { 90 return fmt.Errorf("FindBinary %s %s: got a relative path %q; want absolute", pkg, name, got) 91 } 92 } 93 94 if _, err := os.Stat(got); err != nil { 95 return fmt.Errorf("%s: could not stat: %v", f.Path, err) 96 } 97 } 98 99 // Check that the files can be listed. 100 entries, err := bazel.ListRunfiles() 101 if err != nil { 102 return err 103 } 104 for _, e := range entries { 105 if want, ok := seen[e.ShortPath]; ok && want != e.Path { 106 return err 107 } 108 delete(seen, e.ShortPath) 109 } 110 111 if len(seen) > 0 { 112 unseen := make([]string, 0, len(seen)) 113 for short := range seen { 114 unseen = append(unseen, short) 115 } 116 sort.Strings(unseen) 117 return fmt.Errorf("ListRunfiles did not include files:\n\t%s", strings.Join(unseen, "\n\t")) 118 } 119 120 return nil 121} 122