runfiles

package
v0.51.0-rc2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 2, 2024 License: Apache-2.0 Imports: 15 Imported by: 19

Documentation

Overview

Package runfiles provides access to Bazel runfiles.

Usage

This package has two main entry points, the global functions Rlocation, Env and New, as well as the Runfiles type.

Global functions

Most users should use the Rlocation and Env functions directly to access individual runfiles. Use Rlocation to find the filesystem location of a runfile, and use Env to obtain environmental variables to pass on to subprocesses that themselves may need to access runfiles.

The New function returns a Runfiles object that implements fs.FS. This allows more complex operations on runfiles, such as iterating over all runfiles in a certain directory or evaluating glob patterns, consistently across all platforms.

All of these functions follow the standard runfiles discovery process, which works uniformly across Bazel build actions, `bazel test`, and `bazel run`. It does rely on cooperation between processes (see Env for details).

Custom runfiles discovery and lookup

If you need to look up runfiles in a custom way (e.g., you use them for a packaged application or one that is available on PATH), you can pass Option values to New to force a specific runfiles location.

## Restrictions

Functions in this package may not observe changes to the environment or os.Args after the first call to any of them. Pass Option values to New to customize runfiles discovery instead.

Example

Read a runfile.

package main

import (
	"os"

	"github.com/bazelbuild/rules_go/go/runfiles"
)

func main() {
	p, err := runfiles.Rlocation("my_module/path/to/pkg/file.txt")
	if err != nil {
		panic(err)
	}
	content, _ := os.ReadFile(p)
	println(string(content))
}
Output:

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrEmpty = errors.New("empty runfile")

ErrEmpty indicates that a runfile isn’t present in the filesystem, but should be created as an empty file if necessary.

Functions

func CallerRepository added in v0.37.0

func CallerRepository() string

CallerRepository returns the canonical name of the Bazel repository that contains the source file of the caller of the function that itself calls CallerRepository.

Example

Implement a custom wrapper around runfiles.Rlocation that accepts paths relative to the repository of the caller.

package main

import (
	"os"
	"path"

	"github.com/bazelbuild/rules_go/go/runfiles"
)

// MyRepoRelativeRlocation behaves like runfiles.Rlocation, but accepts a path
// relative to the repository of the caller rather than a path prefixed with a
// repository name.
func MyRepoRelativeRlocation(relativePath string) (string, error) {
	var runfilesDirectory string
	callerRepository := runfiles.CallerRepository()
	if callerRepository == "" {
		// The runfiles directory of the main repository has a special name
		// with Bzlmod.
		runfilesDirectory = "_main"
	} else {
		runfilesDirectory = callerRepository
	}
	rlocationPath := path.Join(runfilesDirectory, relativePath)
	// runfiles.CallerRepository always returns a canonical repository name,
	// but we still specify the correct source repo here in case the caller
	// specifies a path such as "../other_repo/file.txt".
	return runfiles.RlocationFrom(rlocationPath, callerRepository)
}

// Implement a custom wrapper around runfiles.Rlocation that accepts paths
// relative to the repository of the caller.
func main() {
	p, err := MyRepoRelativeRlocation("path/to/pkg/file.txt")
	if err != nil {
		panic(err)
	}
	content, _ := os.ReadFile(p)
	println(string(content))
}
Output:

func CurrentRepository added in v0.37.0

func CurrentRepository() string

CurrentRepository returns the canonical name of the Bazel repository that contains the source file of the caller of CurrentRepository.

func Env

func Env() ([]string, error)

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.

Example

Execute a tool from runfiles that itself uses runfiles.

package main

import (
	"os"
	"os/exec"

	"github.com/bazelbuild/rules_go/go/runfiles"
)

func main() {
	tool, err := runfiles.Rlocation("my_module/path/to/pkg/some_tool")
	if err != nil {
		panic(err)
	}
	runfilesEnv, err := runfiles.Env()
	if err != nil {
		panic(err)
	}
	cmd := exec.Command(tool, "arg1", "arg2")
	cmd.Env = append(os.Environ(), runfilesEnv...)
	_ = cmd.Run()
}
Output:

func Rlocation

func Rlocation(path string) (string, error)

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.

Example

Read a runfile.

package main

import (
	"os"

	"github.com/bazelbuild/rules_go/go/runfiles"
)

func main() {
	p, err := runfiles.Rlocation("my_module/path/to/pkg/file.txt")
	if err != nil {
		panic(err)
	}
	content, _ := os.ReadFile(p)
	println(string(content))
}
Output:

Example (InjectedPath)

Read a runfile at a path injected by Bazel at build time.

package main

import (
	"os"

	"github.com/bazelbuild/rules_go/go/runfiles"
)

// Injected by Bazel by adding the following attribute on the target
// (supported by go_binary, go_test, and go_library):
//
//	x_defs = {
//	    "example.com/pkg.fileTxtRlocationpath": "$(rlocationpath file.txt)",
//	},
var fileTxtRlocationpath string

// Read a runfile at a path injected by Bazel at build time.
func main() {
	p, err := runfiles.Rlocation(fileTxtRlocationpath)
	if err != nil {
		panic(err)
	}
	content, _ := os.ReadFile(p)
	println(string(content))
}
Output:

func RlocationFrom added in v0.37.0

func RlocationFrom(path string, sourceRepo string) (string, error)

Types

type Directory

type Directory string

Directory specifies the location of the runfiles directory. You can pass this as an option to New. If unset or empty, use the value of the environmental variable RUNFILES_DIR.

type Error

type Error struct {
	// Runfile name that caused the failure.
	Name string

	// Underlying error.
	Err error
}

Error represents a failure to look up a runfile.

func (Error) Error

func (e Error) Error() string

Error implements error.Error.

func (Error) Unwrap

func (e Error) Unwrap() error

Unwrap returns the underlying error, for errors.Unwrap.

type ManifestFile

type ManifestFile string

ManifestFile specifies the location of the runfile manifest file. You can pass this as an option to New. If unset or empty, use the value of the environmental variable RUNFILES_MANIFEST_FILE.

type Option

type Option interface {
	// contains filtered or unexported methods
}

Option is an option for the New function to override runfiles discovery.

type ProgramName

type ProgramName string

ProgramName is an Option that sets the program name. If not set, New uses os.Args[0].

type Runfiles

type Runfiles struct {
	// contains filtered or unexported fields
}

Runfiles allows access to Bazel runfiles. Use New to create Runfiles objects; the zero Runfiles object always returns errors. See https://docs.bazel.build/skylark/rules.html#runfiles for some information on Bazel runfiles.

Runfiles implements fs.FS regardless of the type of runfiles that backs it. This is the preferred way to interact with runfiles in a platform-agnostic way. For example, to find all runfiles beneath a directory, use fs.Glob or fs.WalkDir.

func New

func New(opts ...Option) (*Runfiles, error)

New creates a given Runfiles object. By default, it uses os.Args and the RUNFILES_MANIFEST_FILE and RUNFILES_DIR environmental variables to find the runfiles location. This can be overwritten by passing some options.

See section “Runfiles discovery” in https://docs.google.com/document/d/e/2PACX-1vSDIrFnFvEYhKsCMdGdD40wZRBX3m3aZ5HhVj4CtHPmiXKDCxioTUbYsDydjKtFDAzER5eg7OjJWs3V/pub.

Example (Copy)

Copy a subdirectory of the runfiles to a temporary directory.

package main

import (
	"io/fs"
	"os"

	"github.com/bazelbuild/rules_go/go/runfiles"
)

func main() {
	r, err := runfiles.New()
	if err != nil {
		panic(err)
	}
	tmpDir, _ := os.MkdirTemp("", "example")
	defer os.RemoveAll(tmpDir)
	testdataFS, _ := fs.Sub(r, "my_module/path/to/pkg/testdata")
	_ = os.CopyFS(tmpDir, testdataFS)
}
Output:

Example (Glob)

Iterate over all ".txt" files in a runfiles subdirectory.

package main

import (
	"io/fs"

	"github.com/bazelbuild/rules_go/go/runfiles"
)

func main() {
	r, err := runfiles.New()
	if err != nil {
		panic(err)
	}
	textFiles, _ := fs.Glob(r, "my_module/path/to/pkg/testdata/*.txt")
	for _, f := range textFiles {
		content, _ := fs.ReadFile(r, f)
		println(string(content))
	}
}
Output:

func (*Runfiles) Env

func (r *Runfiles) Env() []string

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. If r is the zero Runfiles object, the return value is nil.

func (*Runfiles) Open

func (r *Runfiles) Open(name string) (fs.File, error)

Open implements fs.FS for a Runfiles instance.

Rlocation-style paths are supported with both apparent and canonical repo names. The root directory of the filesystem (".") additionally lists the apparent repo names that are visible to the current source repo (with --enable_bzlmod).

func (*Runfiles) Rlocation

func (r *Runfiles) Rlocation(path string) (string, error)

Rlocation returns the (relative or absolute) path name of a runfile. The runfile name must be a runfile-root relative path, using the slash (not backslash) as directory separator. It is typically of the form "repo/path/to/pkg/file".

If r is the zero Runfiles object, Rlocation always returns an error. 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.

See section “Library interface” in https://docs.google.com/document/d/e/2PACX-1vSDIrFnFvEYhKsCMdGdD40wZRBX3m3aZ5HhVj4CtHPmiXKDCxioTUbYsDydjKtFDAzER5eg7OjJWs3V/pub.

func (*Runfiles) WithSourceRepo added in v0.37.0

func (r *Runfiles) WithSourceRepo(sourceRepo string) *Runfiles

WithSourceRepo returns a Runfiles instance identical to the current one, except that it uses the given repository's repository mapping when resolving runfiles paths.

type SourceRepo added in v0.37.0

type SourceRepo string

SourceRepo is an Option that sets the canonical name of the repository whose repository mapping should be used to resolve runfiles paths. If not set, New uses the repository containing the source file from which New is called. Use CurrentRepository to get the name of the current repository.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL