enhancement: make it a real library and drop srpm mode

This commit is contained in:
Mustafa Gezen 2021-09-03 23:07:02 +02:00
parent 7d84156a4b
commit 23bea74126
Signed by: mustafa
GPG Key ID: DCDF010D946438C1
11 changed files with 376 additions and 480 deletions

View File

@ -21,23 +21,8 @@
package main package main
import ( import (
"fmt"
"github.com/rocky-linux/srpmproc/pkg/srpmproc" "github.com/rocky-linux/srpmproc/pkg/srpmproc"
"log" "log"
"os"
"os/user"
"path/filepath"
"strings"
"github.com/go-git/go-billy/v5"
"github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-billy/v5/osfs"
"github.com/go-git/go-git/v5/plumbing/transport/ssh"
"github.com/rocky-linux/srpmproc/pkg/blob"
"github.com/rocky-linux/srpmproc/pkg/blob/file"
"github.com/rocky-linux/srpmproc/pkg/blob/gcs"
"github.com/rocky-linux/srpmproc/pkg/blob/s3"
"github.com/rocky-linux/srpmproc/pkg/data"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -62,7 +47,6 @@ var (
noStorageDownload bool noStorageDownload bool
noStorageUpload bool noStorageUpload bool
manualCommits string manualCommits string
upstreamPrefixHttps string
moduleFallbackStream string moduleFallbackStream string
allowStreamBranches bool allowStreamBranches bool
) )
@ -73,104 +57,37 @@ var root = &cobra.Command{
} }
func mn(_ *cobra.Command, _ []string) { func mn(_ *cobra.Command, _ []string) {
switch version { pd, err := srpmproc.NewProcessData(&srpmproc.ProcessDataRequest{
case 8:
break
default:
log.Fatalf("unsupported upstream version %d", version)
}
var importer data.ImportMode
var blobStorage blob.Storage
if strings.HasPrefix(storageAddr, "gs://") {
blobStorage = gcs.New(strings.Replace(storageAddr, "gs://", "", 1))
} else if strings.HasPrefix(storageAddr, "s3://") {
blobStorage = s3.New(strings.Replace(storageAddr, "s3://", "", 1))
} else if strings.HasPrefix(storageAddr, "file://") {
blobStorage = file.New(strings.Replace(storageAddr, "file://", "", 1))
} else {
log.Fatalf("invalid blob storage")
}
sourceRpmLocation := ""
if strings.HasPrefix(sourceRpm, "file://") {
sourceRpmLocation = strings.TrimPrefix(sourceRpm, "file://")
importer = &srpmproc.SrpmMode{}
} else {
if moduleMode {
sourceRpmLocation = fmt.Sprintf("%s/%s", modulePrefix, sourceRpm)
} else {
sourceRpmLocation = fmt.Sprintf("%s/%s", rpmPrefix, sourceRpm)
}
importer = &srpmproc.GitMode{}
}
lastKeyLocation := sshKeyLocation
if lastKeyLocation == "" {
usr, err := user.Current()
if err != nil {
log.Fatalf("could not get user: %v", err)
}
lastKeyLocation = filepath.Join(usr.HomeDir, ".ssh/id_rsa")
}
var authenticator *ssh.PublicKeys
var err error
// create ssh key authenticator
authenticator, err = ssh.NewPublicKeysFromFile(sshUser, lastKeyLocation, "")
if err != nil {
log.Fatalf("could not get git authenticator: %v", err)
}
fsCreator := func(branch string) billy.Filesystem {
return memfs.New()
}
if tmpFsMode != "" {
log.Printf("using tmpfs dir: %s", tmpFsMode)
fsCreator = func(branch string) billy.Filesystem {
tmpDir := filepath.Join(tmpFsMode, branch)
err := os.MkdirAll(tmpDir, 0755)
if err != nil {
log.Fatalf("could not create tmpfs dir: %v", err)
}
return osfs.New(tmpDir)
}
}
var manualCs []string
if strings.TrimSpace(manualCommits) != "" {
manualCs = strings.Split(manualCommits, ",")
}
srpmproc.ProcessRPM(&data.ProcessData{
Importer: importer,
RpmLocation: sourceRpmLocation,
UpstreamPrefix: upstreamPrefix,
SshKeyLocation: sshKeyLocation,
SshUser: sshUser,
Version: version, Version: version,
BlobStorage: blobStorage, StorageAddr: storageAddr,
GitCommitterName: gitCommitterName, Package: sourceRpm,
GitCommitterEmail: gitCommitterEmail,
ModulePrefix: modulePrefix,
ImportBranchPrefix: importBranchPrefix,
BranchPrefix: branchPrefix,
SingleTag: singleTag,
Authenticator: authenticator,
NoDupMode: noDupMode,
ModuleMode: moduleMode, ModuleMode: moduleMode,
TmpFsMode: tmpFsMode, TmpFsMode: tmpFsMode,
NoStorageDownload: noStorageDownload, ModulePrefix: modulePrefix,
NoStorageUpload: noStorageUpload, RpmPrefix: rpmPrefix,
ManualCommits: manualCs, SshKeyLocation: sshKeyLocation,
UpstreamPrefixHttps: upstreamPrefixHttps, SshUser: sshUser,
ModuleFallbackStream: moduleFallbackStream, ManualCommits: manualCommits,
UpstreamPrefix: upstreamPrefix,
GitCommitterName: gitCommitterName,
GitCommitterEmail: gitCommitterEmail,
ImportBranchPrefix: importBranchPrefix,
BranchPrefix: branchPrefix,
NoDupMode: noDupMode,
AllowStreamBranches: allowStreamBranches, AllowStreamBranches: allowStreamBranches,
FsCreator: fsCreator, ModuleFallbackStream: moduleFallbackStream,
NoStorageUpload: noStorageUpload,
NoStorageDownload: noStorageDownload,
SingleTag: singleTag,
}) })
if err != nil {
log.Fatal(err)
}
err = srpmproc.ProcessRPM(pd)
if err != nil {
log.Fatal(err)
}
} }
func main() { func main() {
@ -198,7 +115,6 @@ func main() {
root.Flags().BoolVar(&noStorageDownload, "no-storage-download", false, "If enabled, blobs are always downloaded from upstream") root.Flags().BoolVar(&noStorageDownload, "no-storage-download", false, "If enabled, blobs are always downloaded from upstream")
root.Flags().BoolVar(&noStorageUpload, "no-storage-upload", false, "If enabled, blobs are not uploaded to blob storage") root.Flags().BoolVar(&noStorageUpload, "no-storage-upload", false, "If enabled, blobs are not uploaded to blob storage")
root.Flags().StringVar(&manualCommits, "manual-commits", "", "Comma separated branch and commit list for packages with broken release tags (Format: BRANCH:HASH)") root.Flags().StringVar(&manualCommits, "manual-commits", "", "Comma separated branch and commit list for packages with broken release tags (Format: BRANCH:HASH)")
root.Flags().StringVar(&upstreamPrefixHttps, "upstream-prefix-https", "", "Web version of upstream prefix. Required if module-mode")
root.Flags().StringVar(&moduleFallbackStream, "module-fallback-stream", "", "Override fallback stream. Some module packages are published as collections and mostly use the same stream name, some of them deviate from the main stream") root.Flags().StringVar(&moduleFallbackStream, "module-fallback-stream", "", "Override fallback stream. Some module packages are published as collections and mostly use the same stream name, some of them deviate from the main stream")
root.Flags().BoolVar(&allowStreamBranches, "allow-stream-branches", false, "Allow import from stream branches") root.Flags().BoolVar(&allowStreamBranches, "allow-stream-branches", false, "Allow import from stream branches")

View File

@ -21,22 +21,21 @@
package data package data
import ( import (
"github.com/cavaliercoder/go-rpm"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"hash" "hash"
) )
type ImportMode interface { type ImportMode interface {
RetrieveSource(pd *ProcessData) *ModeData RetrieveSource(pd *ProcessData) (*ModeData, error)
WriteSource(pd *ProcessData, md *ModeData) WriteSource(pd *ProcessData, md *ModeData) error
PostProcess(md *ModeData) PostProcess(md *ModeData) error
ImportName(pd *ProcessData, md *ModeData) string ImportName(pd *ProcessData, md *ModeData) string
} }
type ModeData struct { type ModeData struct {
Name string
Repo *git.Repository Repo *git.Repository
Worktree *git.Worktree Worktree *git.Worktree
RpmFile *rpm.PackageFile
FileWrites map[string][]byte FileWrites map[string][]byte
TagBranch string TagBranch string
PushBranch string PushBranch string

View File

@ -26,6 +26,8 @@ import (
"github.com/rocky-linux/srpmproc/pkg/blob" "github.com/rocky-linux/srpmproc/pkg/blob"
) )
type FsCreatorFunc func(branch string) (billy.Filesystem, error)
type ProcessData struct { type ProcessData struct {
RpmLocation string RpmLocation string
UpstreamPrefix string UpstreamPrefix string
@ -48,8 +50,7 @@ type ProcessData struct {
NoStorageDownload bool NoStorageDownload bool
NoStorageUpload bool NoStorageUpload bool
ManualCommits []string ManualCommits []string
UpstreamPrefixHttps string
ModuleFallbackStream string ModuleFallbackStream string
AllowStreamBranches bool AllowStreamBranches bool
FsCreator func(branch string) billy.Filesystem FsCreator FsCreatorFunc
} }

View File

@ -234,7 +234,7 @@ func specChange(cfg *srpmprocpb.Cfg, pd *data.ProcessData, md *data.ModeData, _
hasPatch := false hasPatch := false
version := "" version := ""
importName := strings.Replace(pd.Importer.ImportName(pd, md), md.RpmFile.Name(), "1", 1) importName := strings.Replace(pd.Importer.ImportName(pd, md), md.Name, "1", 1)
importNameSplit := strings.SplitN(importName, "-", 2) importNameSplit := strings.SplitN(importName, "-", 2)
if len(importNameSplit) == 2 { if len(importNameSplit) == 2 {
versionSplit := strings.SplitN(importNameSplit[1], ".el", 2) versionSplit := strings.SplitN(importNameSplit[1], ".el", 2)

14
pkg/misc/regex.go Normal file
View File

@ -0,0 +1,14 @@
package misc
import (
"fmt"
"regexp"
)
func GetTagImportRegex(importBranchPrefix string, allowStreamBranches bool) *regexp.Regexp {
if allowStreamBranches {
return regexp.MustCompile(fmt.Sprintf("refs/tags/(imports/(%s(?:.s|.)|%s(?:|s).+)/(.*))", importBranchPrefix, importBranchPrefix))
} else {
return regexp.MustCompile(fmt.Sprintf("refs/tags/(imports/(%s.|%s.-.+)/(.*))", importBranchPrefix, importBranchPrefix))
}
}

View File

@ -18,10 +18,11 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE. // SOFTWARE.
package srpmproc package modes
import ( import (
"fmt" "fmt"
"github.com/rocky-linux/srpmproc/pkg/misc"
"io/ioutil" "io/ioutil"
"log" "log"
"net/http" "net/http"
@ -60,15 +61,15 @@ func (p remoteTargetSlice) Swap(i, j int) {
type GitMode struct{} type GitMode struct{}
func (g *GitMode) RetrieveSource(pd *data.ProcessData) *data.ModeData { func (g *GitMode) RetrieveSource(pd *data.ProcessData) (*data.ModeData, error) {
repo, err := git.Init(memory.NewStorage(), memfs.New()) repo, err := git.Init(memory.NewStorage(), memfs.New())
if err != nil { if err != nil {
log.Fatalf("could not init git Repo: %v", err) return nil, fmt.Errorf("could not init git Repo: %v", err)
} }
w, err := repo.Worktree() w, err := repo.Worktree()
if err != nil { if err != nil {
log.Fatalf("could not get Worktree: %v", err) return nil, fmt.Errorf("could not get Worktree: %v", err)
} }
refspec := config.RefSpec("+refs/heads/*:refs/remotes/*") refspec := config.RefSpec("+refs/heads/*:refs/remotes/*")
@ -78,7 +79,7 @@ func (g *GitMode) RetrieveSource(pd *data.ProcessData) *data.ModeData {
Fetch: []config.RefSpec{refspec}, Fetch: []config.RefSpec{refspec},
}) })
if err != nil { if err != nil {
log.Fatalf("could not create remote: %v", err) return nil, fmt.Errorf("could not create remote: %v", err)
} }
err = remote.Fetch(&git.FetchOptions{ err = remote.Fetch(&git.FetchOptions{
@ -87,7 +88,7 @@ func (g *GitMode) RetrieveSource(pd *data.ProcessData) *data.ModeData {
Force: true, Force: true,
}) })
if err != nil { if err != nil {
log.Fatalf("could not fetch upstream: %v", err) return nil, fmt.Errorf("could not fetch upstream: %v", err)
} }
var branches remoteTargetSlice var branches remoteTargetSlice
@ -97,8 +98,8 @@ func (g *GitMode) RetrieveSource(pd *data.ProcessData) *data.ModeData {
tagAdd := func(tag *object.Tag) error { tagAdd := func(tag *object.Tag) error {
if strings.HasPrefix(tag.Name, fmt.Sprintf("imports/%s%d", pd.ImportBranchPrefix, pd.Version)) { if strings.HasPrefix(tag.Name, fmt.Sprintf("imports/%s%d", pd.ImportBranchPrefix, pd.Version)) {
refSpec := fmt.Sprintf("refs/tags/%s", tag.Name) refSpec := fmt.Sprintf("refs/tags/%s", tag.Name)
if tagImportRegex.MatchString(refSpec) { if misc.GetTagImportRegex(pd.ImportBranchPrefix, pd.AllowStreamBranches).MatchString(refSpec) {
match := tagImportRegex.FindStringSubmatch(refSpec) match := misc.GetTagImportRegex(pd.ImportBranchPrefix, pd.AllowStreamBranches).FindStringSubmatch(refSpec)
exists := latestTags[match[2]] exists := latestTags[match[2]]
if exists != nil && exists.when.After(tag.Tagger.When) { if exists != nil && exists.when.After(tag.Tagger.When) {
@ -116,13 +117,13 @@ func (g *GitMode) RetrieveSource(pd *data.ProcessData) *data.ModeData {
tagIter, err := repo.TagObjects() tagIter, err := repo.TagObjects()
if err != nil { if err != nil {
log.Fatalf("could not get tag objects: %v", err) return nil, fmt.Errorf("could not get tag objects: %v", err)
} }
_ = tagIter.ForEach(tagAdd) _ = tagIter.ForEach(tagAdd)
list, err := remote.List(&git.ListOptions{}) list, err := remote.List(&git.ListOptions{})
if err != nil { if err != nil {
log.Fatalf("could not list upstream: %v", err) return nil, fmt.Errorf("could not list upstream: %v", err)
} }
for _, ref := range list { for _, ref := range list {
@ -153,18 +154,18 @@ func (g *GitMode) RetrieveSource(pd *data.ProcessData) *data.ModeData {
} }
return &data.ModeData{ return &data.ModeData{
Name: filepath.Base(pd.RpmLocation),
Repo: repo, Repo: repo,
Worktree: w, Worktree: w,
RpmFile: createPackageFile(filepath.Base(pd.RpmLocation)),
FileWrites: nil, FileWrites: nil,
Branches: sortedBranches, Branches: sortedBranches,
} }, nil
} }
func (g *GitMode) WriteSource(pd *data.ProcessData, md *data.ModeData) { func (g *GitMode) WriteSource(pd *data.ProcessData, md *data.ModeData) error {
remote, err := md.Repo.Remote("upstream") remote, err := md.Repo.Remote("upstream")
if err != nil { if err != nil {
log.Fatalf("could not get upstream remote: %v", err) return fmt.Errorf("could not get upstream remote: %v", err)
} }
var refspec config.RefSpec var refspec config.RefSpec
@ -174,7 +175,7 @@ func (g *GitMode) WriteSource(pd *data.ProcessData, md *data.ModeData) {
refspec = config.RefSpec(fmt.Sprintf("+%s:%s", md.TagBranch, md.TagBranch)) refspec = config.RefSpec(fmt.Sprintf("+%s:%s", md.TagBranch, md.TagBranch))
branchName = strings.TrimPrefix(md.TagBranch, "refs/heads/") branchName = strings.TrimPrefix(md.TagBranch, "refs/heads/")
} else { } else {
match := tagImportRegex.FindStringSubmatch(md.TagBranch) match := misc.GetTagImportRegex(pd.ImportBranchPrefix, pd.AllowStreamBranches).FindStringSubmatch(md.TagBranch)
branchName = match[2] branchName = match[2]
refspec = config.RefSpec(fmt.Sprintf("+refs/heads/%s:%s", branchName, md.TagBranch)) refspec = config.RefSpec(fmt.Sprintf("+refs/heads/%s:%s", branchName, md.TagBranch))
} }
@ -186,7 +187,7 @@ func (g *GitMode) WriteSource(pd *data.ProcessData, md *data.ModeData) {
Force: true, Force: true,
}) })
if err != nil && err != git.NoErrAlreadyUpToDate { if err != nil && err != git.NoErrAlreadyUpToDate {
log.Fatalf("could not fetch upstream: %v", err) return fmt.Errorf("could not fetch upstream: %v", err)
} }
err = md.Worktree.Checkout(&git.CheckoutOptions{ err = md.Worktree.Checkout(&git.CheckoutOptions{
@ -194,23 +195,23 @@ func (g *GitMode) WriteSource(pd *data.ProcessData, md *data.ModeData) {
Force: true, Force: true,
}) })
if err != nil { if err != nil {
log.Fatalf("could not checkout source from git: %v", err) return fmt.Errorf("could not checkout source from git: %v", err)
} }
_, err = md.Worktree.Add(".") _, err = md.Worktree.Add(".")
if err != nil { if err != nil {
log.Fatalf("could not add Worktree: %v", err) return fmt.Errorf("could not add Worktree: %v", err)
} }
metadataFile, err := md.Worktree.Filesystem.Open(fmt.Sprintf(".%s.metadata", md.RpmFile.Name())) metadataFile, err := md.Worktree.Filesystem.Open(fmt.Sprintf(".%s.metadata", md.Name))
if err != nil { if err != nil {
log.Printf("warn: could not open metadata file, so skipping: %v", err) log.Printf("warn: could not open metadata file, so skipping: %v", err)
return return nil
} }
fileBytes, err := ioutil.ReadAll(metadataFile) fileBytes, err := ioutil.ReadAll(metadataFile)
if err != nil { if err != nil {
log.Fatalf("could not read metadata file: %v", err) return fmt.Errorf("could not read metadata file: %v", err)
} }
client := &http.Client{ client := &http.Client{
@ -239,27 +240,27 @@ func (g *GitMode) WriteSource(pd *data.ProcessData, md *data.ModeData) {
body = fromBlobStorage body = fromBlobStorage
log.Printf("downloading %s from blob storage", hash) log.Printf("downloading %s from blob storage", hash)
} else { } else {
url := fmt.Sprintf("https://git.centos.org/sources/%s/%s/%s", md.RpmFile.Name(), branchName, hash) url := fmt.Sprintf("https://git.centos.org/sources/%s/%s/%s", md.Name, branchName, hash)
log.Printf("downloading %s", url) log.Printf("downloading %s", url)
req, err := http.NewRequest("GET", url, nil) req, err := http.NewRequest("GET", url, nil)
if err != nil { if err != nil {
log.Fatalf("could not create new http request: %v", err) return fmt.Errorf("could not create new http request: %v", err)
} }
req.Header.Set("Accept-Encoding", "*") req.Header.Set("Accept-Encoding", "*")
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
log.Fatalf("could not download dist-git file: %v", err) return fmt.Errorf("could not download dist-git file: %v", err)
} }
body, err = ioutil.ReadAll(resp.Body) body, err = ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
log.Fatalf("could not read the whole dist-git file: %v", err) return fmt.Errorf("could not read the whole dist-git file: %v", err)
} }
err = resp.Body.Close() err = resp.Body.Close()
if err != nil { if err != nil {
log.Fatalf("could not close body handle: %v", err) return fmt.Errorf("could not close body handle: %v", err)
} }
} }
@ -268,7 +269,7 @@ func (g *GitMode) WriteSource(pd *data.ProcessData, md *data.ModeData) {
f, err := md.Worktree.Filesystem.Create(path) f, err := md.Worktree.Filesystem.Create(path)
if err != nil { if err != nil {
log.Fatalf("could not open file pointer: %v", err) return fmt.Errorf("could not open file pointer: %v", err)
} }
hasher := data.CompareHash(body, hash) hasher := data.CompareHash(body, hash)
@ -283,32 +284,36 @@ func (g *GitMode) WriteSource(pd *data.ProcessData, md *data.ModeData) {
_, err = f.Write(body) _, err = f.Write(body)
if err != nil { if err != nil {
log.Fatalf("could not copy dist-git file to in-tree: %v", err) return fmt.Errorf("could not copy dist-git file to in-tree: %v", err)
} }
_ = f.Close() _ = f.Close()
} }
return nil
} }
func (g *GitMode) PostProcess(md *data.ModeData) { func (g *GitMode) PostProcess(md *data.ModeData) error {
for _, source := range md.SourcesToIgnore { for _, source := range md.SourcesToIgnore {
_, err := md.Worktree.Filesystem.Stat(source.Name) _, err := md.Worktree.Filesystem.Stat(source.Name)
if err == nil { if err == nil {
err := md.Worktree.Filesystem.Remove(source.Name) err := md.Worktree.Filesystem.Remove(source.Name)
if err != nil { if err != nil {
log.Fatalf("could not remove dist-git file: %v", err) return fmt.Errorf("could not remove dist-git file: %v", err)
} }
} }
} }
_, err := md.Worktree.Add(".") _, err := md.Worktree.Add(".")
if err != nil { if err != nil {
log.Fatalf("could not add git sources: %v", err) return fmt.Errorf("could not add git sources: %v", err)
} }
return nil
} }
func (g *GitMode) ImportName(_ *data.ProcessData, md *data.ModeData) string { func (g *GitMode) ImportName(pd *data.ProcessData, md *data.ModeData) string {
if tagImportRegex.MatchString(md.TagBranch) { if misc.GetTagImportRegex(pd.ImportBranchPrefix, pd.AllowStreamBranches).MatchString(md.TagBranch) {
match := tagImportRegex.FindStringSubmatch(md.TagBranch) match := misc.GetTagImportRegex(pd.ImportBranchPrefix, pd.AllowStreamBranches).FindStringSubmatch(md.TagBranch)
return match[3] return match[3]
} }

View File

@ -1,51 +0,0 @@
// Copyright (c) 2021 The Srpmproc Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package srpmproc
import (
"github.com/cavaliercoder/go-rpm"
)
// TODO: ugly hack, should create an interface
// since GitMode does not parse an RPM file, we just mimick
// the headers of an actual file to reuse RpmFile.Name()
func createPackageFile(name string) *rpm.PackageFile {
return &rpm.PackageFile{
Lead: rpm.Lead{},
Headers: []rpm.Header{
{},
{
Version: 0,
IndexCount: 1,
Length: 1,
Indexes: []rpm.IndexEntry{
{
Tag: 1000,
Type: rpm.IndexDataTypeStringArray,
Offset: 0,
ItemCount: 1,
Value: []string{name},
},
},
},
},
}
}

View File

@ -1,21 +0,0 @@
// Copyright (c) 2021 The Srpmproc Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package srpmproc

View File

@ -40,14 +40,14 @@ import (
"google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/encoding/prototext"
) )
func cfgPatches(pd *data.ProcessData, md *data.ModeData, patchTree *git.Worktree, pushTree *git.Worktree) { func cfgPatches(pd *data.ProcessData, md *data.ModeData, patchTree *git.Worktree, pushTree *git.Worktree) error {
// check CFG patches // check CFG patches
_, err := patchTree.Filesystem.Stat("ROCKY/CFG") _, err := patchTree.Filesystem.Stat("ROCKY/CFG")
if err == nil { if err == nil {
// iterate through patches // iterate through patches
infos, err := patchTree.Filesystem.ReadDir("ROCKY/CFG") infos, err := patchTree.Filesystem.ReadDir("ROCKY/CFG")
if err != nil { if err != nil {
log.Fatalf("could not walk patches: %v", err) return fmt.Errorf("could not walk patches: %v", err)
} }
for _, info := range infos { for _, info := range infos {
@ -60,44 +60,51 @@ func cfgPatches(pd *data.ProcessData, md *data.ModeData, patchTree *git.Worktree
filePath := filepath.Join("ROCKY/CFG", info.Name()) filePath := filepath.Join("ROCKY/CFG", info.Name())
directive, err := patchTree.Filesystem.Open(filePath) directive, err := patchTree.Filesystem.Open(filePath)
if err != nil { if err != nil {
log.Fatalf("could not open directive file %s: %v", info.Name(), err) return fmt.Errorf("could not open directive file %s: %v", info.Name(), err)
} }
directiveBytes, err := ioutil.ReadAll(directive) directiveBytes, err := ioutil.ReadAll(directive)
if err != nil { if err != nil {
log.Fatalf("could not read directive file: %v", err) return fmt.Errorf("could not read directive file: %v", err)
} }
var cfg srpmprocpb.Cfg var cfg srpmprocpb.Cfg
err = prototext.Unmarshal(directiveBytes, &cfg) err = prototext.Unmarshal(directiveBytes, &cfg)
if err != nil { if err != nil {
log.Fatalf("could not unmarshal cfg file: %v", err) return fmt.Errorf("could not unmarshal cfg file: %v", err)
} }
directives.Apply(&cfg, pd, md, patchTree, pushTree) directives.Apply(&cfg, pd, md, patchTree, pushTree)
} }
} }
return nil
} }
func applyPatches(pd *data.ProcessData, md *data.ModeData, patchTree *git.Worktree, pushTree *git.Worktree) { func applyPatches(pd *data.ProcessData, md *data.ModeData, patchTree *git.Worktree, pushTree *git.Worktree) error {
// check if patches exist // check if patches exist
_, err := patchTree.Filesystem.Stat("ROCKY") _, err := patchTree.Filesystem.Stat("ROCKY")
if err == nil { if err == nil {
cfgPatches(pd, md, patchTree, pushTree) err := cfgPatches(pd, md, patchTree, pushTree)
if err != nil {
return err
} }
}
return nil
} }
func executePatchesRpm(pd *data.ProcessData, md *data.ModeData) { func executePatchesRpm(pd *data.ProcessData, md *data.ModeData) error {
// fetch patch repository // fetch patch repository
repo, err := git.Init(memory.NewStorage(), memfs.New()) repo, err := git.Init(memory.NewStorage(), memfs.New())
if err != nil { if err != nil {
log.Fatalf("could not create new dist Repo: %v", err) return fmt.Errorf("could not create new dist Repo: %v", err)
} }
w, err := repo.Worktree() w, err := repo.Worktree()
if err != nil { if err != nil {
log.Fatalf("could not get dist Worktree: %v", err) return fmt.Errorf("could not get dist Worktree: %v", err)
} }
remoteUrl := fmt.Sprintf("%s/patch/%s.git", pd.UpstreamPrefix, gitlabify(md.RpmFile.Name())) remoteUrl := fmt.Sprintf("%s/patch/%s.git", pd.UpstreamPrefix, gitlabify(md.Name))
refspec := config.RefSpec(fmt.Sprintf("+refs/heads/*:refs/remotes/origin/*")) refspec := config.RefSpec(fmt.Sprintf("+refs/heads/*:refs/remotes/origin/*"))
_, err = repo.CreateRemote(&config.RemoteConfig{ _, err = repo.CreateRemote(&config.RemoteConfig{
@ -106,7 +113,7 @@ func executePatchesRpm(pd *data.ProcessData, md *data.ModeData) {
Fetch: []config.RefSpec{refspec}, Fetch: []config.RefSpec{refspec},
}) })
if err != nil { if err != nil {
log.Fatalf("could not create remote: %v", err) return fmt.Errorf("could not create remote: %v", err)
} }
fetchOptions := &git.FetchOptions{ fetchOptions := &git.FetchOptions{
@ -124,7 +131,7 @@ func executePatchesRpm(pd *data.ProcessData, md *data.ModeData) {
if err != nil { if err != nil {
// no patches active // no patches active
log.Println("info: patch repo not found") log.Println("info: patch repo not found")
return return nil
} else { } else {
err = w.Checkout(&git.CheckoutOptions{ err = w.Checkout(&git.CheckoutOptions{
Branch: plumbing.NewRemoteReferenceName("origin", "main"), Branch: plumbing.NewRemoteReferenceName("origin", "main"),
@ -132,7 +139,10 @@ func executePatchesRpm(pd *data.ProcessData, md *data.ModeData) {
}) })
// common patches found, apply them // common patches found, apply them
if err == nil { if err == nil {
applyPatches(pd, md, w, md.Worktree) err := applyPatches(pd, md, w, md.Worktree)
if err != nil {
return err
}
} else { } else {
log.Println("info: no common patches found") log.Println("info: no common patches found")
} }
@ -143,17 +153,22 @@ func executePatchesRpm(pd *data.ProcessData, md *data.ModeData) {
}) })
// branch specific patches found, apply them // branch specific patches found, apply them
if err == nil { if err == nil {
applyPatches(pd, md, w, md.Worktree) err := applyPatches(pd, md, w, md.Worktree)
if err != nil {
return err
}
} else { } else {
log.Println("info: no branch specific patches found") log.Println("info: no branch specific patches found")
} }
} }
return nil
} }
func getTipStream(pd *data.ProcessData, module string, pushBranch string, origPushBranch string, tries int) string { func getTipStream(pd *data.ProcessData, module string, pushBranch string, origPushBranch string, tries int) (string, error) {
repo, err := git.Init(memory.NewStorage(), memfs.New()) repo, err := git.Init(memory.NewStorage(), memfs.New())
if err != nil { if err != nil {
log.Fatalf("could not init git Repo: %v", err) return "", fmt.Errorf("could not init git Repo: %v", err)
} }
remoteUrl := fmt.Sprintf("%s/rpms/%s.git", pd.UpstreamPrefix, gitlabify(module)) remoteUrl := fmt.Sprintf("%s/rpms/%s.git", pd.UpstreamPrefix, gitlabify(module))
@ -164,7 +179,7 @@ func getTipStream(pd *data.ProcessData, module string, pushBranch string, origPu
Fetch: []config.RefSpec{refspec}, Fetch: []config.RefSpec{refspec},
}) })
if err != nil { if err != nil {
log.Fatalf("could not create remote: %v", err) return "", fmt.Errorf("could not create remote: %v", err)
} }
list, err := remote.List(&git.ListOptions{ list, err := remote.List(&git.ListOptions{
@ -178,7 +193,7 @@ func getTipStream(pd *data.ProcessData, module string, pushBranch string, origPu
return getTipStream(pd, module, pushBranch, origPushBranch, tries+1) return getTipStream(pd, module, pushBranch, origPushBranch, tries+1)
} }
log.Fatalf("could not get rpm refs. import the rpm before the module: %v", err) return "", fmt.Errorf("could not get rpm refs. import the rpm before the module: %v", err)
} }
var tipHash string var tipHash string
@ -238,14 +253,14 @@ func getTipStream(pd *data.ProcessData, module string, pushBranch string, origPu
log.Fatal("could not find tip hash") log.Fatal("could not find tip hash")
} }
return strings.TrimSpace(tipHash) return strings.TrimSpace(tipHash), nil
} }
func patchModuleYaml(pd *data.ProcessData, md *data.ModeData) { func patchModuleYaml(pd *data.ProcessData, md *data.ModeData) error {
// special case for platform.yaml // special case for platform.yaml
_, err := md.Worktree.Filesystem.Open("platform.yaml") _, err := md.Worktree.Filesystem.Open("platform.yaml")
if err == nil { if err == nil {
return return nil
} }
mdTxtPath := "SOURCES/modulemd.src.txt" mdTxtPath := "SOURCES/modulemd.src.txt"
@ -254,18 +269,18 @@ func patchModuleYaml(pd *data.ProcessData, md *data.ModeData) {
mdTxtPath = "SOURCES/modulemd.txt" mdTxtPath = "SOURCES/modulemd.txt"
f, err = md.Worktree.Filesystem.Open(mdTxtPath) f, err = md.Worktree.Filesystem.Open(mdTxtPath)
if err != nil { if err != nil {
log.Fatalf("could not open modulemd file: %v", err) return fmt.Errorf("could not open modulemd file: %v", err)
} }
} }
content, err := ioutil.ReadAll(f) content, err := ioutil.ReadAll(f)
if err != nil { if err != nil {
log.Fatalf("could not read modulemd file: %v", err) return fmt.Errorf("could not read modulemd file: %v", err)
} }
module, err := modulemd.Parse(content) module, err := modulemd.Parse(content)
if err != nil { if err != nil {
log.Fatalf("could not parse modulemd file: %v", err) return fmt.Errorf("could not parse modulemd file: %v", err)
} }
// Get stream branch from tag // Get stream branch from tag
@ -311,23 +326,31 @@ func patchModuleYaml(pd *data.ProcessData, md *data.ModeData) {
log.Fatal("could not recognize modulemd ref") log.Fatal("could not recognize modulemd ref")
} }
tipHash = getTipStream(pd, name, pushBranch, md.PushBranch, 0) tipHash, err = getTipStream(pd, name, pushBranch, md.PushBranch, 0)
if err != nil {
return err
}
if tipHash == "0000000000000000000000000000000000000000" { if tipHash == "0000000000000000000000000000000000000000" {
pushBranch = defaultBranch pushBranch = defaultBranch
tipHash = getTipStream(pd, name, pushBranch, md.PushBranch, 0) tipHash, err = getTipStream(pd, name, pushBranch, md.PushBranch, 0)
if err != nil {
return err
}
} }
rpm.Ref = tipHash rpm.Ref = tipHash
} }
rootModule := fmt.Sprintf("%s.yaml", md.RpmFile.Name()) rootModule := fmt.Sprintf("%s.yaml", md.Name)
err = module.Marshal(md.Worktree.Filesystem, rootModule) err = module.Marshal(md.Worktree.Filesystem, rootModule)
if err != nil { if err != nil {
log.Fatalf("could not marshal root modulemd: %v", err) return fmt.Errorf("could not marshal root modulemd: %v", err)
} }
_, err = md.Worktree.Add(rootModule) _, err = md.Worktree.Add(rootModule)
if err != nil { if err != nil {
log.Fatalf("could not add root modulemd: %v", err) return fmt.Errorf("could not add root modulemd: %v", err)
} }
return nil
} }

View File

@ -24,9 +24,17 @@ import (
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/go-git/go-billy/v5"
"github.com/go-git/go-git/v5/plumbing/transport/ssh"
"github.com/rocky-linux/srpmproc/pkg/blob"
"github.com/rocky-linux/srpmproc/pkg/blob/file"
"github.com/rocky-linux/srpmproc/pkg/blob/gcs"
"github.com/rocky-linux/srpmproc/pkg/blob/s3"
"github.com/rocky-linux/srpmproc/pkg/modes"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"os/user"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings" "strings"
@ -41,8 +49,44 @@ import (
"github.com/rocky-linux/srpmproc/pkg/data" "github.com/rocky-linux/srpmproc/pkg/data"
) )
const (
RpmPrefixCentOS = "https://git.centos.org/rpms"
ModulePrefixCentOS = "https://git.centos.org/modules"
RpmPrefixRocky = "https://git.rockylinux.org/staging/rpms"
ModulePrefixRocky = "https://git.rockylinux.org/staging/modules"
UpstreamPrefixRocky = "https://git.rockylinux.org/staging"
)
var tagImportRegex *regexp.Regexp var tagImportRegex *regexp.Regexp
type ProcessDataRequest struct {
// Required
Version int
StorageAddr string
Package string
// Optional
ModuleMode bool
TmpFsMode string
ModulePrefix string
RpmPrefix string
SshKeyLocation string
SshUser string
ManualCommits string
UpstreamPrefix string
GitCommitterName string
GitCommitterEmail string
ImportBranchPrefix string
BranchPrefix string
FsCreator data.FsCreatorFunc
NoDupMode bool
AllowStreamBranches bool
ModuleFallbackStream string
NoStorageUpload bool
NoStorageDownload bool
SingleTag string
}
func gitlabify(str string) string { func gitlabify(str string) string {
if str == "tree" { if str == "tree" {
return "treepkg" return "treepkg"
@ -51,6 +95,144 @@ func gitlabify(str string) string {
return strings.Replace(str, "+", "plus", -1) return strings.Replace(str, "+", "plus", -1)
} }
func NewProcessData(req *ProcessDataRequest) (*data.ProcessData, error) {
switch req.Version {
case 8:
break
default:
return nil, fmt.Errorf("unsupported upstream version %d", req.Version)
}
// Set defaults
if req.ModulePrefix == "" {
req.ModulePrefix = ModulePrefixCentOS
}
if req.RpmPrefix == "" {
req.RpmPrefix = RpmPrefixCentOS
}
if req.SshUser == "" {
req.SshUser = "git"
}
if req.UpstreamPrefix == "" {
req.UpstreamPrefix = UpstreamPrefixRocky
}
if req.GitCommitterName == "" {
req.GitCommitterName = "rockyautomation"
}
if req.GitCommitterEmail == "" {
req.GitCommitterEmail = "rockyautomation@rockylinux.org"
}
if req.ImportBranchPrefix == "" {
req.ImportBranchPrefix = "c"
}
if req.BranchPrefix == "" {
req.BranchPrefix = "r"
}
// Validate required
if req.Package == "" {
return nil, fmt.Errorf("package cannot be empty")
}
var importer data.ImportMode
var blobStorage blob.Storage
if strings.HasPrefix(req.StorageAddr, "gs://") {
blobStorage = gcs.New(strings.Replace(req.StorageAddr, "gs://", "", 1))
} else if strings.HasPrefix(req.StorageAddr, "s3://") {
blobStorage = s3.New(strings.Replace(req.StorageAddr, "s3://", "", 1))
} else if strings.HasPrefix(req.StorageAddr, "file://") {
blobStorage = file.New(strings.Replace(req.StorageAddr, "file://", "", 1))
} else {
log.Fatalf("invalid blob storage")
}
sourceRpmLocation := ""
if req.ModuleMode {
sourceRpmLocation = fmt.Sprintf("%s/%s", req.ModulePrefix, req.Package)
} else {
sourceRpmLocation = fmt.Sprintf("%s/%s", req.RpmPrefix, req.Package)
}
importer = &modes.GitMode{}
lastKeyLocation := req.SshKeyLocation
if lastKeyLocation == "" {
usr, err := user.Current()
if err != nil {
log.Fatalf("could not get user: %v", err)
}
lastKeyLocation = filepath.Join(usr.HomeDir, ".ssh/id_rsa")
}
var authenticator *ssh.PublicKeys
var err error
// create ssh key authenticator
authenticator, err = ssh.NewPublicKeysFromFile(req.SshUser, lastKeyLocation, "")
if err != nil {
log.Fatalf("could not get git authenticator: %v", err)
}
fsCreator := func(branch string) (billy.Filesystem, error) {
return memfs.New(), nil
}
if req.FsCreator != nil {
fsCreator = req.FsCreator
}
if req.TmpFsMode != "" {
log.Printf("using tmpfs dir: %s", req.TmpFsMode)
fsCreator = func(branch string) (billy.Filesystem, error) {
fs, err := fsCreator(branch)
if err != nil {
return nil, err
}
tmpDir := filepath.Join(req.TmpFsMode, branch)
err = fs.MkdirAll(tmpDir, 0755)
if err != nil {
log.Fatalf("could not create tmpfs dir: %v", err)
}
nFs, err := fs.Chroot(tmpDir)
if err != nil {
return nil, err
}
return nFs, nil
}
}
var manualCs []string
if strings.TrimSpace(req.ManualCommits) != "" {
manualCs = strings.Split(req.ManualCommits, ",")
}
return &data.ProcessData{
Importer: importer,
RpmLocation: sourceRpmLocation,
UpstreamPrefix: req.UpstreamPrefix,
SshKeyLocation: lastKeyLocation,
SshUser: req.SshUser,
Version: req.Version,
BlobStorage: blobStorage,
GitCommitterName: req.GitCommitterName,
GitCommitterEmail: req.GitCommitterEmail,
ModulePrefix: req.ModulePrefix,
ImportBranchPrefix: req.ImportBranchPrefix,
BranchPrefix: req.BranchPrefix,
SingleTag: req.SingleTag,
Authenticator: authenticator,
NoDupMode: req.NoDupMode,
ModuleMode: req.ModuleMode,
TmpFsMode: req.TmpFsMode,
NoStorageDownload: req.NoStorageDownload,
NoStorageUpload: req.NoStorageUpload,
ManualCommits: manualCs,
ModuleFallbackStream: req.ModuleFallbackStream,
AllowStreamBranches: req.AllowStreamBranches,
FsCreator: fsCreator,
}, nil
}
// ProcessRPM checks the RPM specs and discards any remote files // ProcessRPM checks the RPM specs and discards any remote files
// This functions also sorts files into directories // This functions also sorts files into directories
// .spec files goes into -> SPECS // .spec files goes into -> SPECS
@ -58,14 +240,11 @@ func gitlabify(str string) string {
// source files goes into -> SOURCES // source files goes into -> SOURCES
// all files that are remote goes into .gitignore // all files that are remote goes into .gitignore
// all ignored files' hash goes into .{Name}.metadata // all ignored files' hash goes into .{Name}.metadata
func ProcessRPM(pd *data.ProcessData) { func ProcessRPM(pd *data.ProcessData) error {
if pd.AllowStreamBranches { md, err := pd.Importer.RetrieveSource(pd)
tagImportRegex = regexp.MustCompile(fmt.Sprintf("refs/tags/(imports/(%s(?:.s|.)|%s(?:|s).+)/(.*))", pd.ImportBranchPrefix, pd.ImportBranchPrefix)) if err != nil {
} else { return err
tagImportRegex = regexp.MustCompile(fmt.Sprintf("refs/tags/(imports/(%s.|%s.-.+)/(.*))", pd.ImportBranchPrefix, pd.ImportBranchPrefix))
} }
md := pd.Importer.RetrieveSource(pd)
md.BlobCache = map[string][]byte{} md.BlobCache = map[string][]byte{}
remotePrefix := "rpms" remotePrefix := "rpms"
@ -83,9 +262,9 @@ func ProcessRPM(pd *data.ProcessData) {
if pd.NoDupMode { if pd.NoDupMode {
repo, err := git.Init(memory.NewStorage(), memfs.New()) repo, err := git.Init(memory.NewStorage(), memfs.New())
if err != nil { if err != nil {
log.Fatalf("could not init git repo: %v", err) return fmt.Errorf("could not init git repo: %v", err)
} }
remoteUrl := fmt.Sprintf("%s/%s/%s.git", pd.UpstreamPrefix, remotePrefix, gitlabify(md.RpmFile.Name())) remoteUrl := fmt.Sprintf("%s/%s/%s.git", pd.UpstreamPrefix, remotePrefix, gitlabify(md.Name))
refspec := config.RefSpec("+refs/heads/*:refs/remotes/origin/*") refspec := config.RefSpec("+refs/heads/*:refs/remotes/origin/*")
remote, err := repo.CreateRemote(&config.RemoteConfig{ remote, err := repo.CreateRemote(&config.RemoteConfig{
@ -94,7 +273,7 @@ func ProcessRPM(pd *data.ProcessData) {
Fetch: []config.RefSpec{refspec}, Fetch: []config.RefSpec{refspec},
}) })
if err != nil { if err != nil {
log.Fatalf("could not create remote: %v", err) return fmt.Errorf("could not create remote: %v", err)
} }
list, err := remote.List(&git.ListOptions{ list, err := remote.List(&git.ListOptions{
@ -127,7 +306,7 @@ func ProcessRPM(pd *data.ProcessData) {
log.Fatalln("invalid manual commit list") log.Fatalln("invalid manual commit list")
} }
head := fmt.Sprintf("refs/tags/imports/%s/%s-%s", branchCommit[0], md.RpmFile.Name(), branchCommit[1]) head := fmt.Sprintf("refs/tags/imports/%s/%s-%s", branchCommit[0], md.Name, branchCommit[1])
md.Branches = append(md.Branches, head) md.Branches = append(md.Branches, head)
commitPin[head] = branchCommit[1] commitPin[head] = branchCommit[1]
} }
@ -167,15 +346,19 @@ func ProcessRPM(pd *data.ProcessData) {
newTag := "imports/" + pd.BranchPrefix + strings.TrimPrefix(match[1], "imports/"+pd.ImportBranchPrefix) newTag := "imports/" + pd.BranchPrefix + strings.TrimPrefix(match[1], "imports/"+pd.ImportBranchPrefix)
newTag = strings.Replace(newTag, "%", "_", -1) newTag = strings.Replace(newTag, "%", "_", -1)
rpmFile := md.RpmFile createdFs, err := pd.FsCreator(md.PushBranch)
// create new Repo for final dist
repo, err := git.Init(memory.NewStorage(), pd.FsCreator(md.PushBranch))
if err != nil { if err != nil {
log.Fatalf("could not create new dist Repo: %v", err) return err
}
// create new Repo for final dist
repo, err := git.Init(memory.NewStorage(), createdFs)
if err != nil {
return fmt.Errorf("could not create new dist Repo: %v", err)
} }
w, err := repo.Worktree() w, err := repo.Worktree()
if err != nil { if err != nil {
log.Fatalf("could not get dist Worktree: %v", err) return fmt.Errorf("could not get dist Worktree: %v", err)
} }
shouldContinue := true shouldContinue := true
@ -190,7 +373,7 @@ func ProcessRPM(pd *data.ProcessData) {
} }
// create a new remote // create a new remote
remoteUrl := fmt.Sprintf("%s/%s/%s.git", pd.UpstreamPrefix, remotePrefix, gitlabify(rpmFile.Name())) remoteUrl := fmt.Sprintf("%s/%s/%s.git", pd.UpstreamPrefix, remotePrefix, gitlabify(md.Name))
log.Printf("using remote: %s", remoteUrl) log.Printf("using remote: %s", remoteUrl)
refspec := config.RefSpec(fmt.Sprintf("+refs/heads/%s:refs/remotes/origin/%s", md.PushBranch, md.PushBranch)) refspec := config.RefSpec(fmt.Sprintf("+refs/heads/%s:refs/remotes/origin/%s", md.PushBranch, md.PushBranch))
log.Printf("using refspec: %s", refspec) log.Printf("using refspec: %s", refspec)
@ -201,7 +384,7 @@ func ProcessRPM(pd *data.ProcessData) {
Fetch: []config.RefSpec{refspec}, Fetch: []config.RefSpec{refspec},
}) })
if err != nil { if err != nil {
log.Fatalf("could not create remote: %v", err) return fmt.Errorf("could not create remote: %v", err)
} }
err = repo.Fetch(&git.FetchOptions{ err = repo.Fetch(&git.FetchOptions{
@ -221,7 +404,7 @@ func ProcessRPM(pd *data.ProcessData) {
if err != nil { if err != nil {
h := plumbing.NewSymbolicReference(plumbing.HEAD, refName) h := plumbing.NewSymbolicReference(plumbing.HEAD, refName)
if err := repo.Storer.CheckAndSetReference(h, nil); err != nil { if err := repo.Storer.CheckAndSetReference(h, nil); err != nil {
log.Fatalf("could not set reference: %v", err) return fmt.Errorf("could not set reference: %v", err)
} }
} else { } else {
err = w.Checkout(&git.CheckoutOptions{ err = w.Checkout(&git.CheckoutOptions{
@ -230,27 +413,36 @@ func ProcessRPM(pd *data.ProcessData) {
Force: true, Force: true,
}) })
if err != nil { if err != nil {
log.Fatalf("could not checkout: %v", err) return fmt.Errorf("could not checkout: %v", err)
} }
} }
pd.Importer.WriteSource(pd, md) err = pd.Importer.WriteSource(pd, md)
if err != nil {
return err
}
data.CopyFromFs(md.Worktree.Filesystem, w.Filesystem, ".") data.CopyFromFs(md.Worktree.Filesystem, w.Filesystem, ".")
md.Repo = repo md.Repo = repo
md.Worktree = w md.Worktree = w
if pd.ModuleMode { if pd.ModuleMode {
patchModuleYaml(pd, md) err := patchModuleYaml(pd, md)
if err != nil {
return err
}
} else { } else {
executePatchesRpm(pd, md) err := executePatchesRpm(pd, md)
if err != nil {
return err
}
} }
// get ignored files hash and add to .{Name}.metadata // get ignored files hash and add to .{Name}.metadata
metadataFile := fmt.Sprintf(".%s.metadata", rpmFile.Name()) metadataFile := fmt.Sprintf(".%s.metadata", md.Name)
metadata, err := w.Filesystem.Create(metadataFile) metadata, err := w.Filesystem.Create(metadataFile)
if err != nil { if err != nil {
log.Fatalf("could not create metadata file: %v", err) return fmt.Errorf("could not create metadata file: %v", err)
} }
for _, source := range md.SourcesToIgnore { for _, source := range md.SourcesToIgnore {
sourcePath := source.Name sourcePath := source.Name
@ -262,23 +454,23 @@ func ProcessRPM(pd *data.ProcessData) {
sourceFile, err := w.Filesystem.Open(sourcePath) sourceFile, err := w.Filesystem.Open(sourcePath)
if err != nil { if err != nil {
log.Fatalf("could not open ignored source file %s: %v", sourcePath, err) return fmt.Errorf("could not open ignored source file %s: %v", sourcePath, err)
} }
sourceFileBts, err := ioutil.ReadAll(sourceFile) sourceFileBts, err := ioutil.ReadAll(sourceFile)
if err != nil { if err != nil {
log.Fatalf("could not read the whole of ignored source file: %v", err) return fmt.Errorf("could not read the whole of ignored source file: %v", err)
} }
source.HashFunction.Reset() source.HashFunction.Reset()
_, err = source.HashFunction.Write(sourceFileBts) _, err = source.HashFunction.Write(sourceFileBts)
if err != nil { if err != nil {
log.Fatalf("could not write bytes to hash function: %v", err) return fmt.Errorf("could not write bytes to hash function: %v", err)
} }
checksum := hex.EncodeToString(source.HashFunction.Sum(nil)) checksum := hex.EncodeToString(source.HashFunction.Sum(nil))
checksumLine := fmt.Sprintf("%s %s\n", checksum, sourcePath) checksumLine := fmt.Sprintf("%s %s\n", checksum, sourcePath)
_, err = metadata.Write([]byte(checksumLine)) _, err = metadata.Write([]byte(checksumLine))
if err != nil { if err != nil {
log.Fatalf("could not write to metadata file: %v", err) return fmt.Errorf("could not write to metadata file: %v", err)
} }
if data.StrContains(alreadyUploadedBlobs, checksum) { if data.StrContains(alreadyUploadedBlobs, checksum) {
@ -293,7 +485,7 @@ func ProcessRPM(pd *data.ProcessData) {
_, err = w.Add(metadataFile) _, err = w.Add(metadataFile)
if err != nil { if err != nil {
log.Fatalf("could not add metadata file: %v", err) return fmt.Errorf("could not add metadata file: %v", err)
} }
lastFilesToAdd := []string{".gitignore", "SPECS"} lastFilesToAdd := []string{".gitignore", "SPECS"}
@ -302,7 +494,7 @@ func ProcessRPM(pd *data.ProcessData) {
if err == nil { if err == nil {
_, err := w.Add(f) _, err := w.Add(f)
if err != nil { if err != nil {
log.Fatalf("could not add %s: %v", f, err) return fmt.Errorf("could not add %s: %v", f, err)
} }
} }
} }
@ -311,7 +503,10 @@ func ProcessRPM(pd *data.ProcessData) {
continue continue
} }
pd.Importer.PostProcess(md) err = pd.Importer.PostProcess(md)
if err != nil {
return err
}
// show status // show status
status, _ := w.Status() status, _ := w.Status()
@ -324,7 +519,7 @@ func ProcessRPM(pd *data.ProcessData) {
path := strings.TrimPrefix(trimmed, "D ") path := strings.TrimPrefix(trimmed, "D ")
_, err := w.Remove(path) _, err := w.Remove(path)
if err != nil { if err != nil {
log.Fatalf("could not delete extra file %s: %v", path, err) return fmt.Errorf("could not delete extra file %s: %v", path, err)
} }
} }
} }
@ -354,12 +549,12 @@ func ProcessRPM(pd *data.ProcessData) {
Parents: hashes, Parents: hashes,
}) })
if err != nil { if err != nil {
log.Fatalf("could not commit object: %v", err) return fmt.Errorf("could not commit object: %v", err)
} }
obj, err := repo.CommitObject(commit) obj, err := repo.CommitObject(commit)
if err != nil { if err != nil {
log.Fatalf("could not get commit object: %v", err) return fmt.Errorf("could not get commit object: %v", err)
} }
log.Printf("committed:\n%s", obj.String()) log.Printf("committed:\n%s", obj.String())
@ -374,7 +569,7 @@ func ProcessRPM(pd *data.ProcessData) {
SignKey: nil, SignKey: nil,
}) })
if err != nil { if err != nil {
log.Fatalf("could not create tag: %v", err) return fmt.Errorf("could not create tag: %v", err)
} }
pushRefspecs = append(pushRefspecs, config.RefSpec("HEAD:"+plumbing.NewTagReferenceName(newTag))) pushRefspecs = append(pushRefspecs, config.RefSpec("HEAD:"+plumbing.NewTagReferenceName(newTag)))
@ -386,15 +581,17 @@ func ProcessRPM(pd *data.ProcessData) {
Force: true, Force: true,
}) })
if err != nil { if err != nil {
log.Fatalf("could not push to remote: %v", err) return fmt.Errorf("could not push to remote: %v", err)
} }
hashString := obj.Hash.String() hashString := obj.Hash.String()
latestHashForBranch[md.PushBranch] = hashString latestHashForBranch[md.PushBranch] = hashString
} }
err := json.NewEncoder(os.Stdout).Encode(latestHashForBranch) err = json.NewEncoder(os.Stdout).Encode(latestHashForBranch)
if err != nil { if err != nil {
log.Fatalf("could not print hashes") return fmt.Errorf("could not print hashes")
} }
return nil
} }

View File

@ -1,187 +0,0 @@
// Copyright (c) 2021 The Srpmproc Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package srpmproc
import (
"bytes"
"crypto/sha256"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/cavaliercoder/go-cpio"
"github.com/cavaliercoder/go-rpm"
"github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/storage/memory"
"github.com/rocky-linux/srpmproc/pkg/data"
)
type SrpmMode struct{}
func (s *SrpmMode) RetrieveSource(pd *data.ProcessData) *data.ModeData {
cmd := exec.Command("rpm2cpio", pd.RpmLocation)
cpioBytes, err := cmd.Output()
if err != nil {
log.Fatalf("could not convert to cpio (maybe rpm2cpio is missing): %v", err)
}
// create in memory git repository
repo, err := git.Init(memory.NewStorage(), memfs.New())
if err != nil {
log.Fatalf("could not init git Repo: %v", err)
}
// read the rpm in cpio format
buf := bytes.NewReader(cpioBytes)
r := cpio.NewReader(buf)
fileWrites := map[string][]byte{}
for {
hdr, err := r.Next()
if err == io.EOF {
// end of cpio archive
break
}
if err != nil {
log.Fatalln(err)
}
bts, err := ioutil.ReadAll(r)
if err != nil {
log.Fatalf("could not copy file to virtual filesystem: %v", err)
}
fileWrites[hdr.Name] = bts
}
w, err := repo.Worktree()
if err != nil {
log.Fatalf("could not get Worktree: %v", err)
}
// create structure
err = w.Filesystem.MkdirAll("SPECS", 0755)
if err != nil {
log.Fatalf("could not create SPECS dir in vfs: %v", err)
}
err = w.Filesystem.MkdirAll("SOURCES", 0755)
if err != nil {
log.Fatalf("could not create SOURCES dir in vfs: %v", err)
}
f, err := os.Open(pd.RpmLocation)
if err != nil {
log.Fatalf("could not open the file again: %v", err)
}
rpmFile, err := rpm.ReadPackageFile(f)
if err != nil {
log.Fatalf("could not read package, invalid?: %v", err)
}
var sourcesToIgnore []*data.IgnoredSource
for _, source := range rpmFile.Source() {
if strings.Contains(source, ".tar") {
sourcesToIgnore = append(sourcesToIgnore, &data.IgnoredSource{
Name: source,
HashFunction: sha256.New(),
})
}
}
branch := fmt.Sprintf("%s%d", pd.BranchPrefix, pd.Version)
return &data.ModeData{
Repo: repo,
Worktree: w,
RpmFile: rpmFile,
FileWrites: fileWrites,
Branches: []string{branch},
SourcesToIgnore: sourcesToIgnore,
}
}
func (s *SrpmMode) WriteSource(_ *data.ProcessData, md *data.ModeData) {
for fileName, contents := range md.FileWrites {
var newPath string
if filepath.Ext(fileName) == ".spec" {
newPath = filepath.Join("SPECS", fileName)
} else {
newPath = filepath.Join("SOURCES", fileName)
}
mode := os.FileMode(0666)
for _, file := range md.RpmFile.Files() {
if file.Name() == fileName {
mode = file.Mode()
}
}
// add the file to the virtual filesystem
// we will move it to correct destination later
f, err := md.Worktree.Filesystem.OpenFile(newPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode)
if err != nil {
log.Fatalf("could not create file %s: %v", fileName, err)
}
_, err = f.Write(contents)
if err != nil {
log.Fatalf("could not write to file %s: %v", fileName, err)
}
_ = f.Close()
// don't add ignored file to git
if data.IgnoredContains(md.SourcesToIgnore, fileName) {
continue
}
_, err = md.Worktree.Add(newPath)
if err != nil {
log.Fatalf("could not add source file: %v", err)
}
}
// add sources to ignore (remote sources)
gitIgnore, err := md.Worktree.Filesystem.Create(".gitignore")
if err != nil {
log.Fatalf("could not create .gitignore: %v", err)
}
for _, ignore := range md.SourcesToIgnore {
line := fmt.Sprintf("SOURCES/%s\n", ignore)
_, err := gitIgnore.Write([]byte(line))
if err != nil {
log.Fatalf("could not write line to .gitignore: %v", err)
}
}
err = gitIgnore.Close()
if err != nil {
log.Fatalf("could not close .gitignore: %v", err)
}
}
func (s *SrpmMode) PostProcess(_ *data.ModeData) {}
func (s *SrpmMode) ImportName(pd *data.ProcessData, _ *data.ModeData) string {
return filepath.Base(pd.RpmLocation)
}