diff options
Diffstat (limited to 'go/runfiles/global.go')
-rw-r--r-- | go/runfiles/global.go | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/go/runfiles/global.go b/go/runfiles/global.go new file mode 100644 index 00000000..52ec3569 --- /dev/null +++ b/go/runfiles/global.go @@ -0,0 +1,97 @@ +// Copyright 2020, 2021 Google LLC +// +// 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 +// +// https://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 runfiles + +import ( + "regexp" + "runtime" + "sync" +) + +// Rlocation returns the absolute path name of a runfile. The runfile name must be +// a relative path, using the slash (not backslash) as directory separator. If +// the runfiles manifest maps s to an empty name (indicating an empty runfile +// not present in the filesystem), Rlocation returns an error that wraps ErrEmpty. +func Rlocation(path string) (string, error) { + return RlocationFrom(path, CallerRepository()) +} + +func RlocationFrom(path string, sourceRepo string) (string, error) { + r, err := g.get() + if err != nil { + return "", err + } + return r.WithSourceRepo(sourceRepo).Rlocation(path) +} + +// Env returns additional environmental variables to pass to subprocesses. +// Each element is of the form “key=value”. Pass these variables to +// Bazel-built binaries so they can find their runfiles as well. See the +// Runfiles example for an illustration of this. +// +// The return value is a newly-allocated slice; you can modify it at will. +func Env() ([]string, error) { + r, err := g.get() + if err != nil { + return nil, err + } + return r.Env(), nil +} + +var legacyExternalGeneratedFile = regexp.MustCompile(`^bazel-out[/][^/]+/bin/external/([^/]+)/`) +var legacyExternalFile = regexp.MustCompile(`^external/([^/]+)/`) + +// CurrentRepository returns the canonical name of the Bazel repository that +// contains the source file of the caller of CurrentRepository. +func CurrentRepository() string { + return callerRepository(1) +} + +// CallerRepository returns the canonical name of the Bazel repository that +// contains the source file of the caller of the function that itself calls +// CallerRepository. +func CallerRepository() string { + return callerRepository(2) +} + +func callerRepository(skip int) string { + _, file, _, _ := runtime.Caller(skip + 1) + if match := legacyExternalGeneratedFile.FindStringSubmatch(file); match != nil { + return match[1] + } + if match := legacyExternalFile.FindStringSubmatch(file); match != nil { + return match[1] + } + // If a file is not in an external repository, it is in the main repository, + // which has the empty string as its canonical name. + return "" +} + +type global struct { + once sync.Once + runfiles *Runfiles + err error +} + +func (g *global) get() (*Runfiles, error) { + g.once.Do(g.init) + return g.runfiles, g.err +} + +func (g *global) init() { + g.runfiles, g.err = New() +} + +var g global |