Skip to content

Commit

Permalink
Merge pull request #2 from kellyma2/rpmtree
Browse files Browse the repository at this point in the history
Add support for generating lockfiles to rpmtree
  • Loading branch information
kellyma2 authored Jan 3, 2025
2 parents ce47a60 + f0105bc commit 0904616
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 49 deletions.
169 changes: 131 additions & 38 deletions cmd/rpmtree.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (

"github.com/bazelbuild/buildtools/build"
"github.com/rmohr/bazeldnf/cmd/template"
"github.com/rmohr/bazeldnf/pkg/api"
"github.com/rmohr/bazeldnf/pkg/api/bazeldnf"
"github.com/rmohr/bazeldnf/pkg/bazel"
"github.com/rmohr/bazeldnf/pkg/reducer"
"github.com/rmohr/bazeldnf/pkg/repo"
Expand All @@ -22,22 +24,120 @@ type rpmtreeOpts struct {
workspace string
toMacro string
buildfile string
configname string
lockfile string
name string
public bool
forceIgnoreRegex []string
}

var rpmtreeopts = rpmtreeOpts{}

type Handler interface {
AddRPMs(pkgs []*api.Package, arch string) error
PruneRPMs(buildfile *build.File)
Write() error
}

type MacroHandler struct {
bzl, defName string
bzlfile *build.File
}

func NewMacroHandler(toMacro string) (Handler, error) {
bzl, defName, err := bazel.ParseMacro(rpmtreeopts.toMacro)

if err != nil {
return nil, err
}

bzlfile, err := bazel.LoadBzl(bzl)
if err != nil {
return nil, err
}

return &MacroHandler{
bzl: bzl,
bzlfile: bzlfile,
defName: defName,
}, nil
}

func (h *MacroHandler) AddRPMs(pkgs []*api.Package, arch string) error {
return bazel.AddBzlfileRPMs(h.bzlfile, h.defName, pkgs, arch)
}

func (h *MacroHandler) PruneRPMs(buildfile *build.File) {
bazel.PruneBzlfileRPMs(buildfile, h.bzlfile, h.defName)
}

func (h *MacroHandler) Write() error {
return bazel.WriteBzl(false, h.bzlfile, h.bzl)
}

type WorkspaceHandler struct {
workspace string
workspacefile *build.File
}

func NewWorkspaceHandler(workspace string) (Handler, error) {
workspacefile, err := bazel.LoadWorkspace(workspace)
if err != nil {
return nil, err
}

return &WorkspaceHandler{
workspace: workspace,
workspacefile: workspacefile,
}, nil
}

func (h *WorkspaceHandler) AddRPMs(pkgs []*api.Package, arch string) error {
return bazel.AddWorkspaceRPMs(h.workspacefile, pkgs, arch)
}

func (h *WorkspaceHandler) PruneRPMs(buildfile *build.File) {
bazel.PruneWorkspaceRPMs(buildfile, h.workspacefile)
}

func (h *WorkspaceHandler) Write() error {
return bazel.WriteWorkspace(false, h.workspacefile, h.workspace)
}

type LockFileHandler struct {
filename string
config *bazeldnf.Config
}

func NewLockFileHandler(configname, filename string) (Handler, error) {
return &LockFileHandler{
filename: filename,
config: &bazeldnf.Config{
Name: configname,
RPMs: []bazeldnf.RPM{},
},
}, nil
}

func (h *LockFileHandler) AddRPMs(pkgs []*api.Package, arch string) error {
return bazel.AddConfigRPMs(h.config, pkgs, arch)
}

func (h *LockFileHandler) PruneRPMs(buildfile *build.File) {
// we always generate from scratch and have nothing to prune
}

func (h *LockFileHandler) Write() error {
return bazel.WriteLockFile(h.config, h.filename)
}

func NewRpmTreeCmd() *cobra.Command {

rpmtreeCmd := &cobra.Command{
Use: "rpmtree",
Short: "Writes a rpmtree rule and its rpmdependencies to bazel files",
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, required []string) error {
writeToMacro := rpmtreeopts.toMacro != ""

repos, err := repo.LoadRepoFiles(rpmtreeopts.repofiles)
if err != nil {
return err
Expand Down Expand Up @@ -68,54 +168,45 @@ func NewRpmTreeCmd() *cobra.Command {
if err != nil {
return err
}
workspace, err := bazel.LoadWorkspace(rpmtreeopts.workspace)

var handler Handler
var configname string

if rpmtreeopts.toMacro != "" {
handler, err = NewMacroHandler(rpmtreeopts.toMacro)
} else if rpmtreeopts.lockfile != "" {
configname = rpmtreeopts.configname
handler, err = NewLockFileHandler(
rpmtreeopts.configname,
rpmtreeopts.lockfile,
)
} else {
handler, err = NewWorkspaceHandler(rpmtreeopts.workspace)
}

if err != nil {
return err
}
var bzlfile *build.File
var bzl, defName string
if writeToMacro {
bzl, defName, err = bazel.ParseMacro(rpmtreeopts.toMacro)
if err != nil {
return err
}
bzlfile, err = bazel.LoadBzl(bzl)
if err != nil {
return err
}
}

build, err := bazel.LoadBuild(rpmtreeopts.buildfile)
if err != nil {
return err
}
if writeToMacro {
err = bazel.AddBzlfileRPMs(bzlfile, defName, install, rpmtreeopts.arch)
if err != nil {
return err
}
} else {
err = bazel.AddWorkspaceRPMs(workspace, install, rpmtreeopts.arch)
if err != nil {
return err
}
}
bazel.AddTree(rpmtreeopts.name, build, install, rpmtreeopts.arch, rpmtreeopts.public)
if writeToMacro {
bazel.PruneBzlfileRPMs(build, bzlfile, defName)
} else {
bazel.PruneWorkspaceRPMs(build, workspace)

err = handler.AddRPMs(install, rpmtreeopts.arch)
if err != nil {
return err
}

bazel.AddTree(rpmtreeopts.name, configname, build, install, rpmtreeopts.arch, rpmtreeopts.public)

handler.PruneRPMs(build)
logrus.Info("Writing bazel files.")
err = bazel.WriteWorkspace(false, workspace, rpmtreeopts.workspace)
err = handler.Write()
if err != nil {
return err
}
if writeToMacro {
err = bazel.WriteBzl(false, bzlfile, bzl)
if err != nil {
return err
}
}

err = bazel.WriteBuild(false, build, rpmtreeopts.buildfile)
if err != nil {
return err
Expand All @@ -136,6 +227,8 @@ func NewRpmTreeCmd() *cobra.Command {
rpmtreeCmd.Flags().StringVarP(&rpmtreeopts.workspace, "workspace", "w", "WORKSPACE", "Bazel workspace file")
rpmtreeCmd.Flags().StringVarP(&rpmtreeopts.toMacro, "to-macro", "", "", "Tells bazeldnf to write the RPMs to a macro in the given bzl file instead of the WORKSPACE file. The expected format is: macroFile%defName")
rpmtreeCmd.Flags().StringVarP(&rpmtreeopts.buildfile, "buildfile", "b", "rpm/BUILD.bazel", "Build file for RPMs")
rpmtreeCmd.Flags().StringVar(&rpmtreeopts.configname, "configname", "rpms", "config name to use in lockfile")
rpmtreeCmd.Flags().StringVar(&rpmtreeopts.lockfile, "lockfile", "", "lockfile for RPMs")
rpmtreeCmd.Flags().StringVar(&rpmtreeopts.name, "name", "", "rpmtree rule name")
rpmtreeCmd.Flags().StringArrayVar(&rpmtreeopts.forceIgnoreRegex, "force-ignore-with-dependencies", []string{}, "Packages matching these regex patterns will not be installed. Allows force-removing unwanted dependencies. Be careful, this can lead to hidden missing dependencies.")
rpmtreeCmd.MarkFlagRequired("name")
Expand Down
5 changes: 4 additions & 1 deletion pkg/api/bazeldnf/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ load("@rules_go//go:def.bzl", "go_library")

go_library(
name = "bazeldnf",
srcs = ["repo.go"],
srcs = [
"config.go",
"repo.go",
],
importpath = "github.com/rmohr/bazeldnf/pkg/api/bazeldnf",
visibility = ["//visibility:public"],
)
12 changes: 12 additions & 0 deletions pkg/api/bazeldnf/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package bazeldnf

type RPM struct {
Name string `json:"name"`
SHA256 string `json:"sha256"`
URLs []string `json:"urls"`
}

type Config struct {
Name string `json:"name"`
RPMs []RPM `json:"rpms"`
}
1 change: 1 addition & 0 deletions pkg/bazel/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//pkg/api",
"//pkg/api/bazeldnf",
"@com_github_bazelbuild_buildtools//build:go_default_library",
"@com_github_bazelbuild_buildtools//edit:go_default_library",
],
Expand Down
63 changes: 54 additions & 9 deletions pkg/bazel/bazel.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
package bazel

import (
"encoding/json"
"fmt"
"io/ioutil"
"net/url"
"os"
"path/filepath"
"sort"
"strings"

"github.com/bazelbuild/buildtools/build"
"github.com/bazelbuild/buildtools/edit"
"github.com/rmohr/bazeldnf/pkg/api"
"github.com/rmohr/bazeldnf/pkg/api/bazeldnf"
)

type Artifact struct {
rule *build.Rule
}

func LoadWorkspace(path string) (*build.File, error) {
workspaceData, err := ioutil.ReadFile(path)
workspaceData, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("failed to parse WORSPACE orig: %v", err)
}
Expand All @@ -30,7 +32,7 @@ func LoadWorkspace(path string) (*build.File, error) {
}

func LoadBuild(path string) (*build.File, error) {
buildfileData, err := ioutil.ReadFile(path)
buildfileData, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("failed to parse BUILD.bazel orig: %v", err)
}
Expand All @@ -42,7 +44,7 @@ func LoadBuild(path string) (*build.File, error) {
}

func LoadBzl(path string) (*build.File, error) {
bzlData, err := ioutil.ReadFile(path)
bzlData, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("failed to parse bzl orig: %v", err)
}
Expand All @@ -58,23 +60,31 @@ func WriteBuild(dryRun bool, buildfile *build.File, path string) error {
fmt.Println(build.FormatString(buildfile))
return nil
}
return ioutil.WriteFile(path, build.Format(buildfile), 0666)
return os.WriteFile(path, build.Format(buildfile), 0666)
}

func WriteWorkspace(dryRun bool, workspace *build.File, path string) error {
if dryRun {
fmt.Println(build.FormatString(workspace))
return nil
}
return ioutil.WriteFile(path, build.Format(workspace), 0666)
return os.WriteFile(path, build.Format(workspace), 0666)
}

func WriteBzl(dryRun bool, bzl *build.File, path string) error {
if dryRun {
fmt.Println(build.FormatString(bzl))
return nil
}
return ioutil.WriteFile(path, build.Format(bzl), 0666)
return os.WriteFile(path, build.Format(bzl), 0666)
}

func WriteLockFile(config *bazeldnf.Config, path string) error {
configJson, err := json.Marshal(config)
if err != nil {
return err
}
return os.WriteFile(path, configJson, 0666)
}

// ParseMacro parses a macro expression of the form macroFile%defName and returns the bzl file and the def name.
Expand Down Expand Up @@ -258,7 +268,16 @@ func AddTar2Files(name string, rpmtree string, buildfile *build.File, files []st
}
}

func AddTree(name string, buildfile *build.File, pkgs []*api.Package, arch string, public bool) {
func AddTree(name, configname string, buildfile *build.File, pkgs []*api.Package, arch string, public bool) {
transform := func(n string) string {
return "@"+n+"//rpm"
}
if configname != "" {
transform = func(n string) string {
return "@" + configname + "//" + n
}
}

rpmtrees := map[string]*rpmTree{}

for _, rule := range buildfile.Rules("rpmtree") {
Expand All @@ -269,7 +288,7 @@ func AddTree(name string, buildfile *build.File, pkgs []*api.Package, arch strin
rpms := []string{}
for _, pkg := range pkgs {
pkgName := sanitize(pkg.String() + "." + arch)
rpms = append(rpms, "@"+pkgName+"//rpm")
rpms = append(rpms, transform(pkgName))
}
sort.SliceStable(rpms, func(i, j int) bool {
return rpms[i] < rpms[j]
Expand Down Expand Up @@ -486,6 +505,32 @@ func (r *tar2Files) SetFiles(dirs []string, fileMap map[string][]string) {
r.Rule.SetAttr("files", filesMapExpr)
}

func AddConfigRPMs(config *bazeldnf.Config, pkgs []*api.Package, arch string) error {
for _, pkg := range pkgs {
URLs := []string{}

for _, mirror := range pkg.Repository.Mirrors {
u, err := url.Parse(mirror)
if err != nil {
return err
}
u = u.JoinPath(pkg.Location.Href)
URLs = append(URLs, u.String())
}

config.RPMs = append(
config.RPMs,
bazeldnf.RPM{
Name: sanitize(pkg.String() + "." + arch),
SHA256: pkg.Checksum.Text,
URLs: URLs,
},
)
}

return nil
}

func sanitize(name string) string {
name = strings.ReplaceAll(name, ":", "__")
name = strings.ReplaceAll(name, "+", "__plus__")
Expand Down
Loading

0 comments on commit 0904616

Please sign in to comment.