mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-12-11 00:44:20 -05:00
827c4f548d
bazel-deps-mirror is an internal tools used to upload external dependencies that are referenced in the Bazel WORKSPACE to the Edgeless Systems' mirror. It also normalizes deps rules. * hack: add tool to mirror Bazel dependencies * hack: bazel-deps-mirror tests * bazel: add deps mirror commands * ci: upload Bazel dependencies on renovate PRs * update go mod * run deps_mirror_upload Signed-off-by: Paul Meyer <49727155+katexochen@users.noreply.github.com> Co-authored-by: Paul Meyer <49727155+katexochen@users.noreply.github.com>
159 lines
4.3 KiB
Go
159 lines
4.3 KiB
Go
/*
|
|
Copyright (c) Edgeless Systems GmbH
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
*/
|
|
|
|
// package bazelfiles is used to find and handle Bazel WORKSPACE and bzl files.
|
|
package bazelfiles
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/bazelbuild/buildtools/build"
|
|
"github.com/hexops/gotextdiff"
|
|
"github.com/hexops/gotextdiff/myers"
|
|
"github.com/hexops/gotextdiff/span"
|
|
"github.com/spf13/afero"
|
|
)
|
|
|
|
// Helper is used to find and handle Bazel WORKSPACE and bzl files.
|
|
type Helper struct {
|
|
fs afero.Fs
|
|
workspaceRoot string
|
|
}
|
|
|
|
// New creates a new BazelFilesHelper.
|
|
func New() (*Helper, error) {
|
|
workspaceRoot, err := findWorkspaceRoot(os.LookupEnv)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Helper{
|
|
fs: afero.NewBasePathFs(afero.NewOsFs(), workspaceRoot),
|
|
workspaceRoot: workspaceRoot,
|
|
}, nil
|
|
}
|
|
|
|
// FindFiles returns the paths to all Bazel files in the Bazel workspace.
|
|
func (h *Helper) FindFiles() ([]BazelFile, error) {
|
|
workspaceFile, err := h.findWorkspaceFile()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
bzlFiles, err := h.findBzlFiles()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return append(bzlFiles, workspaceFile), nil
|
|
}
|
|
|
|
// findWorkspaceFile returns the path to the Bazel WORKSPACE.bazel file (or WORKSPACE if the former doesn't exist).
|
|
func (h *Helper) findWorkspaceFile() (BazelFile, error) {
|
|
if _, err := h.fs.Stat("WORKSPACE.bazel"); err == nil {
|
|
return BazelFile{
|
|
RelPath: "WORKSPACE.bazel",
|
|
AbsPath: filepath.Join(h.workspaceRoot, "WORKSPACE.bazel"),
|
|
Type: BazelFileTypeWorkspace,
|
|
}, nil
|
|
}
|
|
if _, err := h.fs.Stat("WORKSPACE"); err == nil {
|
|
return BazelFile{
|
|
RelPath: "WORKSPACE",
|
|
AbsPath: filepath.Join(h.workspaceRoot, "WORKSPACE"),
|
|
Type: BazelFileTypeWorkspace,
|
|
}, nil
|
|
}
|
|
return BazelFile{}, fmt.Errorf("failed to find Bazel WORKSPACE file")
|
|
}
|
|
|
|
// findBzlFiles returns the paths to all .bzl files in the Bazel workspace.
|
|
func (h *Helper) findBzlFiles() ([]BazelFile, error) {
|
|
var bzlFiles []BazelFile
|
|
err := afero.Walk(h.fs, ".", func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if info.IsDir() {
|
|
return nil
|
|
}
|
|
if filepath.Ext(path) != ".bzl" {
|
|
return nil
|
|
}
|
|
bzlFiles = append(bzlFiles, BazelFile{
|
|
RelPath: path,
|
|
AbsPath: filepath.Join(h.workspaceRoot, path),
|
|
Type: BazelFileTypeBzl,
|
|
})
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return bzlFiles, nil
|
|
}
|
|
|
|
// LoadFile loads a Bazel file.
|
|
func (h *Helper) LoadFile(bf BazelFile) (*build.File, error) {
|
|
data, err := afero.ReadFile(h.fs, bf.RelPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
switch bf.Type {
|
|
case BazelFileTypeBzl:
|
|
return build.ParseBzl(bf.AbsPath, data)
|
|
case BazelFileTypeWorkspace:
|
|
return build.ParseWorkspace(bf.AbsPath, data)
|
|
}
|
|
return nil, fmt.Errorf("unknown Bazel file type: %d", bf.Type)
|
|
}
|
|
|
|
// WriteFile writes (updates) a Bazel file.
|
|
func (h *Helper) WriteFile(bf BazelFile, buildfile *build.File) error {
|
|
return afero.WriteFile(h.fs, bf.RelPath, build.Format(buildfile), 0o644)
|
|
}
|
|
|
|
// Diff returns the diff between the saved and the updated (in-memory) version of a Bazel file.
|
|
func (h *Helper) Diff(bf BazelFile, buildfile *build.File) (string, error) {
|
|
savedData, err := afero.ReadFile(h.fs, bf.RelPath)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
updatedData := build.Format(buildfile)
|
|
edits := myers.ComputeEdits(span.URIFromPath(bf.RelPath), string(savedData), string(updatedData))
|
|
diff := fmt.Sprint(gotextdiff.ToUnified("a/"+bf.RelPath, "b/"+bf.RelPath, string(savedData), edits))
|
|
return diff, nil
|
|
}
|
|
|
|
// findWorkspaceRoot returns the path to the Bazel workspace root.
|
|
func findWorkspaceRoot(lookupEnv LookupEnv) (string, error) {
|
|
workspaceRoot, ok := lookupEnv("BUILD_WORKSPACE_DIRECTORY")
|
|
if !ok {
|
|
return "", fmt.Errorf("failed to find Bazel workspace root: not executed via \"bazel run\" and BUILD_WORKSPACE_DIRECTORY not set")
|
|
}
|
|
return workspaceRoot, nil
|
|
}
|
|
|
|
// BazelFile is a reference (path) to a Bazel file.
|
|
type BazelFile struct {
|
|
RelPath string
|
|
AbsPath string
|
|
Type BazelFileType
|
|
}
|
|
|
|
// BazelFileType is the type of a Bazel file.
|
|
type BazelFileType int
|
|
|
|
const (
|
|
BazelFileTypeBzl = iota // BazelFileTypeBzl is a .bzl file
|
|
BazelFileTypeWorkspace // BazelFileTypeWorkspace is a WORKSPACE or WORKSPACE.bazel file
|
|
)
|
|
|
|
// LookupEnv can be the real os.LookupEnv or a mock for testing.
|
|
type LookupEnv func(key string) (string, bool)
|