xref: /aosp_15_r20/external/bazelbuild-rules_go/go/runfiles/global.go (revision 9bb1b549b6a84214c53be0924760be030e66b93a)
1*9bb1b549SSpandan Das// Copyright 2020, 2021 Google LLC
2*9bb1b549SSpandan Das//
3*9bb1b549SSpandan Das// Licensed under the Apache License, Version 2.0 (the "License");
4*9bb1b549SSpandan Das// you may not use this file except in compliance with the License.
5*9bb1b549SSpandan Das// You may obtain a copy of the License at
6*9bb1b549SSpandan Das//
7*9bb1b549SSpandan Das//     https://www.apache.org/licenses/LICENSE-2.0
8*9bb1b549SSpandan Das//
9*9bb1b549SSpandan Das// Unless required by applicable law or agreed to in writing, software
10*9bb1b549SSpandan Das// distributed under the License is distributed on an "AS IS" BASIS,
11*9bb1b549SSpandan Das// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9bb1b549SSpandan Das// See the License for the specific language governing permissions and
13*9bb1b549SSpandan Das// limitations under the License.
14*9bb1b549SSpandan Das
15*9bb1b549SSpandan Daspackage runfiles
16*9bb1b549SSpandan Das
17*9bb1b549SSpandan Dasimport (
18*9bb1b549SSpandan Das	"regexp"
19*9bb1b549SSpandan Das	"runtime"
20*9bb1b549SSpandan Das	"sync"
21*9bb1b549SSpandan Das)
22*9bb1b549SSpandan Das
23*9bb1b549SSpandan Das// Rlocation returns the absolute path name of a runfile.  The runfile name must be
24*9bb1b549SSpandan Das// a relative path, using the slash (not backslash) as directory separator.  If
25*9bb1b549SSpandan Das// the runfiles manifest maps s to an empty name (indicating an empty runfile
26*9bb1b549SSpandan Das// not present in the filesystem), Rlocation returns an error that wraps ErrEmpty.
27*9bb1b549SSpandan Dasfunc Rlocation(path string) (string, error) {
28*9bb1b549SSpandan Das	return RlocationFrom(path, CallerRepository())
29*9bb1b549SSpandan Das}
30*9bb1b549SSpandan Das
31*9bb1b549SSpandan Dasfunc RlocationFrom(path string, sourceRepo string) (string, error) {
32*9bb1b549SSpandan Das	r, err := g.get()
33*9bb1b549SSpandan Das	if err != nil {
34*9bb1b549SSpandan Das		return "", err
35*9bb1b549SSpandan Das	}
36*9bb1b549SSpandan Das	return r.WithSourceRepo(sourceRepo).Rlocation(path)
37*9bb1b549SSpandan Das}
38*9bb1b549SSpandan Das
39*9bb1b549SSpandan Das// Env returns additional environmental variables to pass to subprocesses.
40*9bb1b549SSpandan Das// Each element is of the form “key=value”.  Pass these variables to
41*9bb1b549SSpandan Das// Bazel-built binaries so they can find their runfiles as well.  See the
42*9bb1b549SSpandan Das// Runfiles example for an illustration of this.
43*9bb1b549SSpandan Das//
44*9bb1b549SSpandan Das// The return value is a newly-allocated slice; you can modify it at will.
45*9bb1b549SSpandan Dasfunc Env() ([]string, error) {
46*9bb1b549SSpandan Das	r, err := g.get()
47*9bb1b549SSpandan Das	if err != nil {
48*9bb1b549SSpandan Das		return nil, err
49*9bb1b549SSpandan Das	}
50*9bb1b549SSpandan Das	return r.Env(), nil
51*9bb1b549SSpandan Das}
52*9bb1b549SSpandan Das
53*9bb1b549SSpandan Dasvar legacyExternalGeneratedFile = regexp.MustCompile(`^bazel-out[/][^/]+/bin/external/([^/]+)/`)
54*9bb1b549SSpandan Dasvar legacyExternalFile = regexp.MustCompile(`^external/([^/]+)/`)
55*9bb1b549SSpandan Das
56*9bb1b549SSpandan Das// CurrentRepository returns the canonical name of the Bazel repository that
57*9bb1b549SSpandan Das// contains the source file of the caller of CurrentRepository.
58*9bb1b549SSpandan Dasfunc CurrentRepository() string {
59*9bb1b549SSpandan Das	return callerRepository(1)
60*9bb1b549SSpandan Das}
61*9bb1b549SSpandan Das
62*9bb1b549SSpandan Das// CallerRepository returns the canonical name of the Bazel repository that
63*9bb1b549SSpandan Das// contains the source file of the caller of the function that itself calls
64*9bb1b549SSpandan Das// CallerRepository.
65*9bb1b549SSpandan Dasfunc CallerRepository() string {
66*9bb1b549SSpandan Das	return callerRepository(2)
67*9bb1b549SSpandan Das}
68*9bb1b549SSpandan Das
69*9bb1b549SSpandan Dasfunc callerRepository(skip int) string {
70*9bb1b549SSpandan Das	_, file, _, _ := runtime.Caller(skip + 1)
71*9bb1b549SSpandan Das	if match := legacyExternalGeneratedFile.FindStringSubmatch(file); match != nil {
72*9bb1b549SSpandan Das		return match[1]
73*9bb1b549SSpandan Das	}
74*9bb1b549SSpandan Das	if match := legacyExternalFile.FindStringSubmatch(file); match != nil {
75*9bb1b549SSpandan Das		return match[1]
76*9bb1b549SSpandan Das	}
77*9bb1b549SSpandan Das	// If a file is not in an external repository, it is in the main repository,
78*9bb1b549SSpandan Das	// which has the empty string as its canonical name.
79*9bb1b549SSpandan Das	return ""
80*9bb1b549SSpandan Das}
81*9bb1b549SSpandan Das
82*9bb1b549SSpandan Dastype global struct {
83*9bb1b549SSpandan Das	once     sync.Once
84*9bb1b549SSpandan Das	runfiles *Runfiles
85*9bb1b549SSpandan Das	err      error
86*9bb1b549SSpandan Das}
87*9bb1b549SSpandan Das
88*9bb1b549SSpandan Dasfunc (g *global) get() (*Runfiles, error) {
89*9bb1b549SSpandan Das	g.once.Do(g.init)
90*9bb1b549SSpandan Das	return g.runfiles, g.err
91*9bb1b549SSpandan Das}
92*9bb1b549SSpandan Das
93*9bb1b549SSpandan Dasfunc (g *global) init() {
94*9bb1b549SSpandan Das	g.runfiles, g.err = New()
95*9bb1b549SSpandan Das}
96*9bb1b549SSpandan Das
97*9bb1b549SSpandan Dasvar g global
98