peridot/nofussvendor/main.go

169 lines
5.6 KiB
Go

// Copyright (c) All respective contributors to the Peridot Project. All rights reserved.
// Copyright (c) 2021-2022 Rocky Enterprise Software Foundation, Inc. All rights reserved.
// Copyright (c) 2021-2022 Ctrl IQ, Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
package main
import (
bazelbuild "bazel.build/protobuf"
"bytes"
"fmt"
"github.com/sirupsen/logrus"
"google.golang.org/protobuf/proto"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
)
func callBazel(args ...string) []byte {
cmd := exec.Command(
"bazel",
args...,
)
var out bytes.Buffer
cmd.Stdout = &out
var errOut bytes.Buffer
cmd.Stderr = &errOut
err := cmd.Run()
if err != nil {
logrus.Error(errOut.String())
logrus.Fatal(err)
}
return out.Bytes()
}
func main() {
// get bazel workspace
// exit if not invoked with bazel
searchDirectory := os.Getenv("BUILD_WORKING_DIRECTORY")
if searchDirectory == "" {
logrus.Fatal("error: BUILD_WORKING_DIRECTORY not found")
}
// change directory to bazel workspace
err := os.Chdir(searchDirectory)
if err != nil {
logrus.Fatal(err)
}
goModContent, err := ioutil.ReadFile("go.mod")
if err != nil {
logrus.Fatalf("could not read go.mod: %v", err)
}
queryProto := callBazel("query", "kind(go_proto_library, //... except //third_party/...)", "--output", "proto")
var query bazelbuild.QueryResult
err = proto.Unmarshal(queryProto, &query)
if err != nil {
logrus.Fatal(err)
}
var replaceList []string
for _, rule := range query.Target {
if *rule.Rule.RuleClass != "go_proto_library" {
continue
}
fullTarget := *rule.Rule.Name
ruleName := strings.Split(fullTarget, ":")[1]
for _, nstring := range rule.Rule.Attribute {
if *nstring.Name == "importpath" {
origImportPath := *nstring.StringValue
importpath := origImportPath
buildLocation := strings.Replace(*rule.Rule.Location, searchDirectory+"/", "", 1)
buildLocation = filepath.Dir(strings.Split(buildLocation, ":")[0])
buildLocation = fmt.Sprintf("bazel-bin/%s/%s_", buildLocation, ruleName)
modDir := filepath.Join(buildLocation, importpath)
if err := os.MkdirAll(modDir, 0755); err != nil && !os.IsExist(err) {
logrus.Fatalf("could not generate directory for importpath %s", importpath)
}
if strings.HasSuffix(importpath, "/v1") {
importpath = strings.TrimSuffix(importpath, "/v1")
modDir = filepath.Join(modDir, "..")
}
modContent := []byte(fmt.Sprintf("module %s", importpath))
if err := ioutil.WriteFile(filepath.Join(modDir, "go.mod"), modContent, 0644); err != nil {
logrus.Fatalf("could not write go.mod file: %v", err)
}
/*dummyDir := modDir
if strings.HasSuffix(origImportPath, "/v1") {
dummyDir = filepath.Join(dummyDir, "v1")
}*/
/*dummyContent := []byte("// this file is generated for mock purposes. do not check in please\npackage dummy")
if err := ioutil.WriteFile(filepath.Join(dummyDir, "dummy.go"), dummyContent, 0644); err != nil {
logrus.Fatalf("could not write dummy.go file: %v", err)
}*/
replaceListElem := fmt.Sprintf("\t%s => ./%s", importpath, modDir)
replaceList = append(replaceList, replaceListElem)
}
}
}
stringGoMod := string(goModContent)
newContent := []string{"//gen:comment:this file is generated with nofussvendor. DO NOT EDIT"}
inSyncReplaceStart := false
for _, line := range strings.Split(stringGoMod, "\n") {
trimmedLine := strings.TrimSpace(line)
if trimmedLine == "// sync-replace-end" {
newContent = append(newContent, strings.Join(replaceList, "\n"))
newContent = append(newContent, ")")
inSyncReplaceStart = false
}
if !inSyncReplaceStart && !strings.HasPrefix(trimmedLine, "//gen:comment") {
newContent = append(newContent, line)
}
if trimmedLine == "// sync-replace-start" {
inSyncReplaceStart = true
newContent = append(newContent, "replace (")
}
}
if err := ioutil.WriteFile(filepath.Join(searchDirectory, "go.mod"), []byte(strings.Join(newContent, "\n")), 0644); err != nil {
logrus.Fatalf("could not write end file go.mod: %v", err)
}
logrus.Infof("Added %d replace directives pointing to mock modules", len(replaceList))
}