mirror of
https://github.com/peridotbuild/peridot.git
synced 2024-12-03 18:16:25 +00:00
Add more srpm_import tests
This commit is contained in:
parent
ac32c887a7
commit
12ec42f8d0
@ -20,8 +20,13 @@ go_library(
|
||||
importpath = "go.resf.org/peridot/tools/mothership/worker_server/srpm_import",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//base/go",
|
||||
"//base/go/storage",
|
||||
"//vendor/github.com/go-git/go-billy/v5:go-billy",
|
||||
"//vendor/github.com/go-git/go-git/v5:go-git",
|
||||
"//vendor/github.com/go-git/go-git/v5/config",
|
||||
"//vendor/github.com/go-git/go-git/v5/plumbing",
|
||||
"//vendor/github.com/go-git/go-git/v5/plumbing/object",
|
||||
"//vendor/github.com/go-git/go-git/v5/storage",
|
||||
"//vendor/github.com/pkg/errors",
|
||||
"//vendor/github.com/sassoftware/go-rpmutils",
|
||||
"//vendor/golang.org/x/crypto/openpgp",
|
||||
@ -38,6 +43,12 @@ go_test(
|
||||
"//base/go/storage/memory",
|
||||
"//vendor/github.com/go-git/go-billy/v5/memfs",
|
||||
"//vendor/github.com/go-git/go-billy/v5/osfs",
|
||||
"//vendor/github.com/go-git/go-git/v5:go-git",
|
||||
"//vendor/github.com/go-git/go-git/v5/config",
|
||||
"//vendor/github.com/go-git/go-git/v5/plumbing/cache",
|
||||
"//vendor/github.com/go-git/go-git/v5/plumbing/object",
|
||||
"//vendor/github.com/go-git/go-git/v5/storage/filesystem",
|
||||
"//vendor/github.com/go-git/go-git/v5/storage/memory",
|
||||
"//vendor/github.com/stretchr/testify/require",
|
||||
"//vendor/golang.org/x/crypto/openpgp",
|
||||
],
|
||||
|
@ -15,142 +15,487 @@
|
||||
package srpm_import
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sassoftware/go-rpmutils"
|
||||
"go.resf.org/peridot/base/go/storage"
|
||||
"golang.org/x/crypto/openpgp"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/go-git/go-billy/v5"
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/config"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
storage2 "github.com/go-git/go-git/v5/storage"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sassoftware/go-rpmutils"
|
||||
"go.resf.org/peridot/base/go/storage"
|
||||
"golang.org/x/crypto/openpgp"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type State struct {
|
||||
tempDir string
|
||||
var elDistRegex = regexp.MustCompile(`el\d+`)
|
||||
|
||||
// lookasideBlobs is a map of blob names to their SHA256 hashes.
|
||||
lookasideBlobs map[string]string
|
||||
type State struct {
|
||||
tempDir string
|
||||
|
||||
rpm *rpmutils.Rpm
|
||||
|
||||
// lookasideBlobs is a map of blob names to their SHA256 hashes.
|
||||
lookasideBlobs map[string]string
|
||||
}
|
||||
|
||||
// copyFromOS copies specified file from OS filesystem to target filesystem.
|
||||
func copyFromOS(targetFS billy.Filesystem, path string, targetPath string) error {
|
||||
// Open file from OS filesystem.
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to open file")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Create file in target filesystem.
|
||||
targetFile, err := targetFS.Create(targetPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create file")
|
||||
}
|
||||
defer targetFile.Close()
|
||||
|
||||
// Copy contents of file from OS filesystem to target filesystem.
|
||||
_, err = io.Copy(targetFile, f)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to copy file")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FromFile creates a new State from an SRPM file.
|
||||
// The SRPM file is extracted to a temporary directory.
|
||||
func FromFile(path string, keys ...*openpgp.Entity) (*State, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to open file")
|
||||
}
|
||||
defer f.Close()
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to open file")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// If keys is not empty, then verify the RPM signature.
|
||||
if len(keys) > 0 {
|
||||
_, _, err := rpmutils.Verify(f, keys)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to verify RPM")
|
||||
}
|
||||
// If keys is not empty, then verify the RPM signature.
|
||||
if len(keys) > 0 {
|
||||
_, _, err := rpmutils.Verify(f, keys)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to verify RPM")
|
||||
}
|
||||
|
||||
// After verifying the RPM, seek back to the start of the file.
|
||||
_, err = f.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to seek to start of file")
|
||||
}
|
||||
}
|
||||
// After verifying the RPM, seek back to the start of the file.
|
||||
_, err = f.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to seek to start of file")
|
||||
}
|
||||
}
|
||||
|
||||
rpm, err := rpmutils.ReadRpm(f)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to read RPM")
|
||||
}
|
||||
rpm, err := rpmutils.ReadRpm(f)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to read RPM")
|
||||
}
|
||||
|
||||
state := &State{
|
||||
lookasideBlobs: make(map[string]string),
|
||||
}
|
||||
// Create a temporary directory.
|
||||
state.tempDir, err = os.MkdirTemp("", "srpm_import-*")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create temporary directory")
|
||||
}
|
||||
state := &State{
|
||||
rpm: rpm,
|
||||
lookasideBlobs: make(map[string]string),
|
||||
}
|
||||
// Create a temporary directory.
|
||||
state.tempDir, err = os.MkdirTemp("", "srpm_import-*")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create temporary directory")
|
||||
}
|
||||
|
||||
// Extract the SRPM.
|
||||
err = rpm.ExpandPayload(state.tempDir)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to extract SRPM")
|
||||
}
|
||||
// Extract the SRPM.
|
||||
err = rpm.ExpandPayload(state.tempDir)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to extract SRPM")
|
||||
}
|
||||
|
||||
return state, nil
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func (s *State) Close() error {
|
||||
return os.RemoveAll(s.tempDir)
|
||||
return os.RemoveAll(s.tempDir)
|
||||
}
|
||||
|
||||
func (s *State) GetDir() string {
|
||||
return s.tempDir
|
||||
return s.tempDir
|
||||
}
|
||||
|
||||
// determineLookasideBlobs determines which blobs need to be uploaded to the
|
||||
// lookaside cache.
|
||||
// Currently, the rule is that if a file is larger than 5MB, and is binary,
|
||||
// then it should be uploaded to the lookaside cache.
|
||||
// If the file name contains ".tar", then it is assumed to be a tarball, and
|
||||
// is ALWAYS uploaded to the lookaside cache.
|
||||
func (s *State) determineLookasideBlobs() error {
|
||||
// Read all files in tempDir, except for the SPEC file
|
||||
// For each file, if it is larger than 5MB, and is binary, then add it to
|
||||
// the lookasideBlobs map.
|
||||
// If the file is not binary, then skip it.
|
||||
ls, err := os.ReadDir(s.tempDir)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to read directory")
|
||||
}
|
||||
// Read all files in tempDir, except for the SPEC file
|
||||
// For each file, if it is larger than 5MB, and is binary, then add it to
|
||||
// the lookasideBlobs map.
|
||||
// If the file is not binary, then skip it.
|
||||
ls, err := os.ReadDir(s.tempDir)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to read directory")
|
||||
}
|
||||
|
||||
for _, f := range ls {
|
||||
// If file ends with ".spec", then skip it.
|
||||
if f.IsDir() || strings.HasSuffix(f.Name(), ".spec") {
|
||||
continue
|
||||
}
|
||||
for _, f := range ls {
|
||||
// If file ends with ".spec", then skip it.
|
||||
if f.IsDir() || strings.HasSuffix(f.Name(), ".spec") {
|
||||
continue
|
||||
}
|
||||
|
||||
// If file is larger than 5MB, then add it to the lookasideBlobs map.
|
||||
info, err := f.Info()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get file info")
|
||||
}
|
||||
// If file is larger than 5MB, then add it to the lookasideBlobs map.
|
||||
info, err := f.Info()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get file info")
|
||||
}
|
||||
|
||||
if info.Size() > 5*1024*1024 {
|
||||
sum, err := func() (string, error) {
|
||||
hash := sha256.New()
|
||||
file, err := os.Open(filepath.Join(s.tempDir, f.Name()))
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to open file")
|
||||
}
|
||||
defer file.Close()
|
||||
if info.Size() > 5*1024*1024 || strings.Contains(f.Name(), ".tar") {
|
||||
sum, err := func() (string, error) {
|
||||
hash := sha256.New()
|
||||
file, err := os.Open(filepath.Join(s.tempDir, f.Name()))
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to open file")
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
_, err = io.Copy(hash, file)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to copy file")
|
||||
}
|
||||
_, err = io.Copy(hash, file)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to copy file")
|
||||
}
|
||||
|
||||
return hex.EncodeToString(hash.Sum(nil)), nil
|
||||
}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return hex.EncodeToString(hash.Sum(nil)), nil
|
||||
}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.lookasideBlobs[f.Name()] = sum
|
||||
}
|
||||
}
|
||||
s.lookasideBlobs[f.Name()] = sum
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// uploadLookasideBlobs uploads all blobs in the lookasideBlobs map to the
|
||||
// lookaside cache.
|
||||
func (s *State) uploadLookasideBlobs(lookaside storage.Storage) error {
|
||||
// The object name is the SHA256 hash of the file.
|
||||
for path, hash := range s.lookasideBlobs {
|
||||
_, err := lookaside.Put(hash, filepath.Join(s.tempDir, path))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to upload file")
|
||||
}
|
||||
}
|
||||
// The object name is the SHA256 hash of the file.
|
||||
for path, hash := range s.lookasideBlobs {
|
||||
_, err := lookaside.Put(hash, filepath.Join(s.tempDir, path))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to upload file")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeMetadata file writes the metadata map file.
|
||||
// The metadata file contains lines of the format:
|
||||
//
|
||||
// <path to download> <blob hash>
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// SOURCES/bar 1234567890abcdef
|
||||
func (s *State) writeMetadataFile(targetFS billy.Filesystem) error {
|
||||
// Open metadata file for writing.
|
||||
name, err := s.rpm.Header.GetStrings(rpmutils.NAME)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get RPM name")
|
||||
}
|
||||
|
||||
metadataFile := fmt.Sprintf(".%s.metadata", name[0])
|
||||
f, err := targetFS.Create(metadataFile)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to open metadata file")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Write each line to the metadata file.
|
||||
for path, hash := range s.lookasideBlobs {
|
||||
// RPM sources MUST be in SOURCES/ directory
|
||||
_, err = f.Write([]byte(filepath.Join("SOURCES", path) + " " + hash + "\n"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to write line to metadata file")
|
||||
}
|
||||
}
|
||||
|
||||
// Each file in metadata needs to be added to gitignore
|
||||
// Overwrite the gitignore file
|
||||
gitignoreFile := ".gitignore"
|
||||
f, err = targetFS.OpenFile(gitignoreFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to open gitignore file")
|
||||
}
|
||||
|
||||
// Write each line to the gitignore file.
|
||||
for path, _ := range s.lookasideBlobs {
|
||||
_, err = f.Write([]byte(filepath.Join("SOURCES", path) + "\n"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to write line to gitignore file")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// expandLayout expands the layout of the SRPM into the target filesystem.
|
||||
// Moves all sources into SOURCES/ directory.
|
||||
// Spec file is moved to SPECS/ directory.
|
||||
func (s *State) expandLayout(targetFS billy.Filesystem) error {
|
||||
// Create SOURCES/ directory.
|
||||
err := targetFS.MkdirAll("SOURCES", 0755)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create SOURCES directory")
|
||||
}
|
||||
|
||||
// Copy all files from OS filesystem to target filesystem.
|
||||
ls, err := os.ReadDir(s.tempDir)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to read directory")
|
||||
}
|
||||
|
||||
for _, f := range ls {
|
||||
baseName := filepath.Base(f.Name())
|
||||
// If file ends with ".spec", then copy to SPECS/ directory.
|
||||
if strings.HasSuffix(f.Name(), ".spec") {
|
||||
err := copyFromOS(targetFS, filepath.Join(s.tempDir, f.Name()), filepath.Join("SPECS", baseName))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to copy spec file")
|
||||
}
|
||||
} else {
|
||||
// Copy all other files to SOURCES/ directory.
|
||||
// Only if they are not present in lookasideBlobs
|
||||
_, ok := s.lookasideBlobs[f.Name()]
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
err := copyFromOS(targetFS, filepath.Join(s.tempDir, f.Name()), filepath.Join("SOURCES", baseName))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to copy file")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getRepo returns the target repository for the SRPM.
|
||||
// This is where the payload is uploaded to.
|
||||
func (s *State) getRepo(opts *git.CloneOptions, storer storage2.Storer, targetFS billy.Filesystem) (*git.Repository, error) {
|
||||
// Determine dist tag
|
||||
nevra, err := s.rpm.Header.GetNEVRA()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get NEVRA")
|
||||
}
|
||||
|
||||
// The dist tag will be used as the branch
|
||||
dist := elDistRegex.FindString(nevra.Release)
|
||||
if dist == "" {
|
||||
return nil, errors.Wrap(err, "failed to determine dist tag")
|
||||
}
|
||||
|
||||
// Set branch to dist tag
|
||||
opts.ReferenceName = plumbing.NewBranchReferenceName(dist)
|
||||
opts.SingleBranch = true
|
||||
|
||||
// Clone the repository, to the target filesystem.
|
||||
// We do an init, then a fetch, then a checkout
|
||||
// If the repo doesn't exist, then we init only
|
||||
repo, err := git.Init(storer, targetFS)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to init repo")
|
||||
}
|
||||
wt, err := repo.Worktree()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get worktree")
|
||||
}
|
||||
|
||||
// Create a new remote
|
||||
refspec := config.RefSpec(fmt.Sprintf("+refs/heads/%s:refs/remotes/origin/%[1]s", dist))
|
||||
_, err = repo.CreateRemote(&config.RemoteConfig{
|
||||
Name: "origin",
|
||||
URLs: []string{opts.URL},
|
||||
Fetch: []config.RefSpec{refspec},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create remote")
|
||||
}
|
||||
|
||||
// Fetch the remote
|
||||
err = repo.Fetch(&git.FetchOptions{
|
||||
RemoteName: "origin",
|
||||
RefSpecs: []config.RefSpec{refspec},
|
||||
})
|
||||
|
||||
// Checkout the branch
|
||||
refName := plumbing.NewBranchReferenceName(dist)
|
||||
|
||||
if err != nil {
|
||||
h := plumbing.NewSymbolicReference(plumbing.HEAD, refName)
|
||||
if err := repo.Storer.CheckAndSetReference(h, nil); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to checkout branch")
|
||||
}
|
||||
} else {
|
||||
err = wt.Checkout(&git.CheckoutOptions{
|
||||
Branch: plumbing.NewRemoteReferenceName("origin", dist),
|
||||
Force: true,
|
||||
})
|
||||
}
|
||||
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
// cleanTargetRepo deletes all files in the target repository.
|
||||
func (s *State) cleanTargetRepo(wt *git.Worktree, root string) error {
|
||||
// Delete all files in the target repository.
|
||||
ls, err := wt.Filesystem.ReadDir(root)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to read directory")
|
||||
}
|
||||
|
||||
for _, f := range ls {
|
||||
// If it's a directory, then recurse into it.
|
||||
if f.IsDir() {
|
||||
err := s.cleanTargetRepo(wt, filepath.Join(root, f.Name()))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to clean target repo")
|
||||
}
|
||||
} else {
|
||||
// Otherwise, delete the file.
|
||||
_, err := wt.Remove(filepath.Join(root, f.Name()))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to remove file")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// populateTargetRepo runs the following steps:
|
||||
// 1. Clean the target repository.
|
||||
// 2. Determine which blobs need to be uploaded to the lookaside cache.
|
||||
// 3. Upload blobs to the lookaside cache.
|
||||
// 4. Write the metadata file.
|
||||
// 5. Expand the layout of the SRPM.
|
||||
// 6. Commit the changes to the target repository.
|
||||
func (s *State) populateTargetRepo(repo *git.Repository, targetFS billy.Filesystem, lookaside storage.Storage) error {
|
||||
// Clean the target repository.
|
||||
wt, err := repo.Worktree()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get worktree")
|
||||
}
|
||||
|
||||
err = s.cleanTargetRepo(wt, ".")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to clean target repo")
|
||||
}
|
||||
|
||||
// Determine which blobs need to be uploaded to the lookaside cache.
|
||||
err = s.determineLookasideBlobs()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to determine lookaside blobs")
|
||||
}
|
||||
|
||||
// Upload blobs to the lookaside cache.
|
||||
err = s.uploadLookasideBlobs(lookaside)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to upload lookaside blobs")
|
||||
}
|
||||
|
||||
// Write the metadata file.
|
||||
err = s.writeMetadataFile(targetFS)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to write metadata file")
|
||||
}
|
||||
|
||||
// Expand the layout of the SRPM.
|
||||
err = s.expandLayout(targetFS)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to expand layout")
|
||||
}
|
||||
|
||||
// Commit the changes to the target repository.
|
||||
_, err = wt.Add(".")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to add files")
|
||||
}
|
||||
|
||||
nevra, err := s.rpm.Header.GetNEVRA()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get NEVRA")
|
||||
}
|
||||
_, err = wt.Commit("import "+nevra.String(), &git.CommitOptions{
|
||||
Author: &object.Signature{
|
||||
Name: "Mship Bot",
|
||||
Email: "no-reply+mshipbot@resf.org",
|
||||
When: time.Now(),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to commit changes")
|
||||
}
|
||||
|
||||
// Create a tag
|
||||
// The tag should follow the following format:
|
||||
// imports/<branch>/<nvra>
|
||||
dist := elDistRegex.FindString(nevra.Release)
|
||||
if dist == "" {
|
||||
return errors.Wrap(err, "failed to determine dist tag")
|
||||
}
|
||||
tag := fmt.Sprintf("imports/%s/%s-%s-%s", dist, nevra.Name, nevra.Version, nevra.Release)
|
||||
_, err = repo.CreateTag(tag, plumbing.NewHash("HEAD"), &git.CreateTagOptions{
|
||||
Tagger: &object.Signature{
|
||||
Name: "Mship Bot",
|
||||
Email: "no-reply+mshipbot@resf.org",
|
||||
When: time.Now(),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create tag")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// pushTargetRepo pushes the target repository to the upstream repository.
|
||||
func (s *State) pushTargetRepo(repo *git.Repository, opts *git.PushOptions) error {
|
||||
// Push the target repository to the upstream repository.
|
||||
err := repo.Push(opts)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to push repo")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Import imports the SRPM into the target repository.
|
||||
func (s *State) Import(opts *git.CloneOptions, storer storage2.Storer, targetFS billy.Filesystem, lookaside storage.Storage) error {
|
||||
// Get the target repository.
|
||||
repo, err := s.getRepo(opts, storer, targetFS)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get repo")
|
||||
}
|
||||
|
||||
// Populate the target repository.
|
||||
err = s.populateTargetRepo(repo, targetFS, lookaside)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to populate target repo")
|
||||
}
|
||||
|
||||
// Push the target repository.
|
||||
err = s.pushTargetRepo(repo, &git.PushOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to push target repo")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -17,11 +17,19 @@ package srpm_import
|
||||
import (
|
||||
"github.com/go-git/go-billy/v5/memfs"
|
||||
"github.com/go-git/go-billy/v5/osfs"
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/config"
|
||||
"github.com/go-git/go-git/v5/plumbing/cache"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
"github.com/go-git/go-git/v5/storage/filesystem"
|
||||
"github.com/go-git/go-git/v5/storage/memory"
|
||||
"github.com/stretchr/testify/require"
|
||||
storage_memory "go.resf.org/peridot/base/go/storage/memory"
|
||||
"golang.org/x/crypto/openpgp"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestFromFile(t *testing.T) {
|
||||
@ -58,7 +66,7 @@ func TestFromFile_SignatureFail(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDetermineLookasideBlobs_Empty(t *testing.T) {
|
||||
s, err := FromFile("testdata/efi-rpm-macros-3-3.el8.src.rpm")
|
||||
s, err := FromFile("testdata/basesystem-11-5.el8.src.rpm")
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, s)
|
||||
defer func() {
|
||||
@ -68,7 +76,7 @@ func TestDetermineLookasideBlobs_Empty(t *testing.T) {
|
||||
require.Equal(t, 0, len(s.lookasideBlobs))
|
||||
}
|
||||
|
||||
func TestDetermineLookasideBlobs_NotEmpty_Over5MB(t *testing.T) {
|
||||
func TestDetermineLookasideBlobs_NotEmpty_Tarball(t *testing.T) {
|
||||
s, err := FromFile("testdata/bash-4.4.20-4.el8_6.src.rpm")
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, s)
|
||||
@ -80,7 +88,7 @@ func TestDetermineLookasideBlobs_NotEmpty_Over5MB(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUploadLookaside_Empty(t *testing.T) {
|
||||
s, err := FromFile("testdata/efi-rpm-macros-3-3.el8.src.rpm")
|
||||
s, err := FromFile("testdata/basesystem-11-5.el8.src.rpm")
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, s)
|
||||
defer func() {
|
||||
@ -115,3 +123,221 @@ func TestUploadLookaside_NotEmpty(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
require.True(t, ok)
|
||||
}
|
||||
|
||||
func TestWriteMetadataFile(t *testing.T) {
|
||||
s, err := FromFile("testdata/bash-4.4.20-4.el8_6.src.rpm")
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, s)
|
||||
defer func() {
|
||||
require.Nil(t, s.Close())
|
||||
}()
|
||||
require.Nil(t, s.determineLookasideBlobs())
|
||||
|
||||
fs := memfs.New()
|
||||
require.Nil(t, s.writeMetadataFile(fs))
|
||||
|
||||
fi, err := fs.ReadDir(".")
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, 2, len(fi))
|
||||
require.Equal(t, ".bash.metadata", fi[0].Name())
|
||||
require.Equal(t, ".gitignore", fi[1].Name())
|
||||
|
||||
f, err := fs.Open(".bash.metadata")
|
||||
require.Nil(t, err)
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
n, err := f.Read(buf)
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Equal(t, "SOURCES/bash-4.4.tar.gz d86b3392c1202e8ff5a423b302e6284db7f8f435ea9f39b5b1b20fd3ac36dfcb\n", string(buf[:n]))
|
||||
|
||||
f, err = fs.Open(".gitignore")
|
||||
require.Nil(t, err)
|
||||
|
||||
buf = make([]byte, 1024)
|
||||
n, err = f.Read(buf)
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Equal(t, "SOURCES/bash-4.4.tar.gz\n", string(buf[:n]))
|
||||
}
|
||||
|
||||
func TestExpandLayout(t *testing.T) {
|
||||
s, err := FromFile("testdata/efi-rpm-macros-3-3.el8.src.rpm")
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, s)
|
||||
defer func() {
|
||||
require.Nil(t, s.Close())
|
||||
}()
|
||||
|
||||
fs := memfs.New()
|
||||
require.Nil(t, s.expandLayout(fs))
|
||||
|
||||
fi, err := fs.ReadDir(".")
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, 2, len(fi))
|
||||
require.Equal(t, "SOURCES", fi[0].Name())
|
||||
require.Equal(t, "SPECS", fi[1].Name())
|
||||
|
||||
fi, err = fs.ReadDir("SOURCES")
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Equal(t, 2, len(fi))
|
||||
require.Equal(t, "0001-macros.efi-srpm-make-all-of-our-macros-always-expand.patch", fi[0].Name())
|
||||
require.Equal(t, "efi-rpm-macros-3.tar.bz2", fi[1].Name())
|
||||
|
||||
fi, err = fs.ReadDir("SPECS")
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Equal(t, 1, len(fi))
|
||||
require.Equal(t, "efi-rpm-macros.spec", fi[0].Name())
|
||||
}
|
||||
|
||||
func TestWriteMetadataExpandLayout(t *testing.T) {
|
||||
s, err := FromFile("testdata/efi-rpm-macros-3-3.el8.src.rpm")
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, s)
|
||||
defer func() {
|
||||
require.Nil(t, s.Close())
|
||||
}()
|
||||
|
||||
fs := memfs.New()
|
||||
require.Nil(t, s.determineLookasideBlobs())
|
||||
require.Nil(t, s.writeMetadataFile(fs))
|
||||
require.Nil(t, s.expandLayout(fs))
|
||||
|
||||
fi, err := fs.ReadDir(".")
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, 4, len(fi))
|
||||
require.Equal(t, ".efi-rpm-macros.metadata", fi[0].Name())
|
||||
require.Equal(t, ".gitignore", fi[1].Name())
|
||||
require.Equal(t, "SOURCES", fi[2].Name())
|
||||
require.Equal(t, "SPECS", fi[3].Name())
|
||||
|
||||
fi, err = fs.ReadDir("SOURCES")
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Equal(t, 1, len(fi))
|
||||
require.Equal(t, "0001-macros.efi-srpm-make-all-of-our-macros-always-expand.patch", fi[0].Name())
|
||||
|
||||
fi, err = fs.ReadDir("SPECS")
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Equal(t, 1, len(fi))
|
||||
require.Equal(t, "efi-rpm-macros.spec", fi[0].Name())
|
||||
|
||||
f, err := fs.Open(".efi-rpm-macros.metadata")
|
||||
require.Nil(t, err)
|
||||
|
||||
buf, err := io.ReadAll(f)
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Equal(t, "SOURCES/efi-rpm-macros-3.tar.bz2 f002f60baed7a47ca3e98b8dd7ece2f7352dac9ffab7ae3557eb56b481ce2f86\n", string(buf))
|
||||
}
|
||||
|
||||
func TestGetRepo_New(t *testing.T) {
|
||||
s, err := FromFile("testdata/efi-rpm-macros-3-3.el8.src.rpm")
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, s)
|
||||
defer func() {
|
||||
require.Nil(t, s.Close())
|
||||
}()
|
||||
|
||||
tempDir, err := os.MkdirTemp("", "peridot-srpm-import-test-*")
|
||||
require.Nil(t, err)
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
storer := memory.NewStorage()
|
||||
fs := memfs.New()
|
||||
opts := &git.CloneOptions{
|
||||
URL: "file://" + tempDir,
|
||||
}
|
||||
repo, err := s.getRepo(opts, storer, fs)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, repo)
|
||||
|
||||
// Verify empty
|
||||
objIter, err := repo.CommitObjects()
|
||||
require.Nil(t, err)
|
||||
_, err = objIter.Next()
|
||||
require.Equal(t, io.EOF, err)
|
||||
}
|
||||
|
||||
func TestGetRepo_Existing(t *testing.T) {
|
||||
s, err := FromFile("testdata/efi-rpm-macros-3-3.el8.src.rpm")
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, s)
|
||||
defer func() {
|
||||
require.Nil(t, s.Close())
|
||||
}()
|
||||
|
||||
tempDir, err := os.MkdirTemp("", "peridot-srpm-import-test-*")
|
||||
require.Nil(t, err)
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
// Create a bare repo in tempDir
|
||||
osfsTemp := osfs.New(tempDir)
|
||||
dot, err := osfsTemp.Chroot(".git")
|
||||
require.Nil(t, err)
|
||||
filesystemTemp := filesystem.NewStorage(dot, cache.NewObjectLRUDefault())
|
||||
require.Nil(t, filesystemTemp.Init())
|
||||
_, err = git.Init(filesystemTemp, nil)
|
||||
require.Nil(t, err)
|
||||
|
||||
// Push a commit to the bare repo
|
||||
newTempDir, err := os.MkdirTemp("", "peridot-srpm-import-test-*")
|
||||
require.Nil(t, err)
|
||||
defer os.RemoveAll(newTempDir)
|
||||
|
||||
osfs2 := osfs.New(newTempDir)
|
||||
dot2, err := osfs2.Chroot(".git")
|
||||
require.Nil(t, err)
|
||||
filesystemTemp2 := filesystem.NewStorage(dot2, cache.NewObjectLRUDefault())
|
||||
|
||||
repo, err := git.InitWithOptions(filesystemTemp2, osfs2, git.InitOptions{
|
||||
DefaultBranch: "refs/heads/el8",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
_, err = repo.CreateRemote(&config.RemoteConfig{
|
||||
Name: "origin",
|
||||
URLs: []string{tempDir},
|
||||
})
|
||||
require.Nil(t, err)
|
||||
w, err := repo.Worktree()
|
||||
require.Nil(t, err)
|
||||
f, err := w.Filesystem.Create("testfile")
|
||||
require.Nil(t, err)
|
||||
_, err = f.Write([]byte("test"))
|
||||
require.Nil(t, err)
|
||||
err = f.Close()
|
||||
require.Nil(t, err)
|
||||
_, err = w.Add("testfile")
|
||||
require.Nil(t, err)
|
||||
_, err = w.Commit("test commit", &git.CommitOptions{
|
||||
Author: &object.Signature{
|
||||
Name: "test",
|
||||
Email: "test@resf.org",
|
||||
When: time.Now(),
|
||||
},
|
||||
})
|
||||
require.Nil(t, err)
|
||||
err = repo.Push(&git.PushOptions{
|
||||
RefSpecs: []config.RefSpec{"refs/heads/el8:refs/heads/el8"},
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
storer := memory.NewStorage()
|
||||
fs := memfs.New()
|
||||
opts := &git.CloneOptions{
|
||||
URL: "file://" + tempDir,
|
||||
}
|
||||
repo, err = s.getRepo(opts, storer, fs)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, repo)
|
||||
|
||||
// Verify commit
|
||||
objIter, err := repo.CommitObjects()
|
||||
require.Nil(t, err)
|
||||
obj, err := objIter.Next()
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, "test commit", obj.Message)
|
||||
}
|
||||
|
BIN
tools/mothership/worker_server/srpm_import/testdata/basesystem-11-5.el8.src.rpm
vendored
Normal file
BIN
tools/mothership/worker_server/srpm_import/testdata/basesystem-11-5.el8.src.rpm
vendored
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user