| // 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 |