Reorganize codebase #10

Merged
EnumDev merged 23 commits from code_reorganization into develop 2025-04-17 11:49:52 +00:00
4 changed files with 7 additions and 494 deletions
Showing only changes of commit c767f26937 - Show all commits

View File

@ -27,9 +27,6 @@ var subcommandArgs []string
var rootDir = "/" var rootDir = "/"
var verbose = false var verbose = false
var yesAll = false var yesAll = false
var buildSource = false
var skipCheck = false
var keepTempDir = false
var force = false var force = false
var pkgListNumbers = false var pkgListNumbers = false
var pkgListNames = false var pkgListNames = false
@ -524,9 +521,6 @@ func printHelp() {
fmt.Println(" -v Show additional information about what BPM is doing") fmt.Println(" -v Show additional information about what BPM is doing")
fmt.Println(" -y skips the confirmation prompt") fmt.Println(" -y skips the confirmation prompt")
fmt.Println(" -f skips dependency, conflict and architecture checking") fmt.Println(" -f skips dependency, conflict and architecture checking")
fmt.Println(" -o=<path> set the binary package output directory (defaults to /var/lib/bpm/compiled)")
fmt.Println(" -c=<path> set the compilation directory (defaults to /var/tmp)")
fmt.Println(" -b creates a binary package from a source package after compilation and saves it in the binary package output directory")
fmt.Println(" -k keeps the compilation directory created by BPM after source package installation") fmt.Println(" -k keeps the compilation directory created by BPM after source package installation")
fmt.Println(" --reinstall Reinstalls packages even if they do not have a newer version available") fmt.Println(" --reinstall Reinstalls packages even if they do not have a newer version available")
fmt.Println(" --reinstall-all Same as --reinstall but also reinstalls dependencies") fmt.Println(" --reinstall-all Same as --reinstall but also reinstalls dependencies")
@ -575,11 +569,6 @@ func resolveFlags() {
installFlagSet.StringVar(&rootDir, "R", "/", "Set the destination root") installFlagSet.StringVar(&rootDir, "R", "/", "Set the destination root")
installFlagSet.BoolVar(&verbose, "v", false, "Show additional information about what BPM is doing") installFlagSet.BoolVar(&verbose, "v", false, "Show additional information about what BPM is doing")
installFlagSet.BoolVar(&yesAll, "y", false, "Skip confirmation prompts") installFlagSet.BoolVar(&yesAll, "y", false, "Skip confirmation prompts")
installFlagSet.StringVar(&bpmlib.BPMConfig.BinaryOutputDir, "o", bpmlib.BPMConfig.BinaryOutputDir, "Set the binary output directory")
installFlagSet.StringVar(&bpmlib.BPMConfig.CompilationDir, "c", bpmlib.BPMConfig.CompilationDir, "Set the compilation directory")
installFlagSet.BoolVar(&buildSource, "b", false, "Build binary package from source package")
installFlagSet.BoolVar(&skipCheck, "s", false, "Skip check function during source compilation")
installFlagSet.BoolVar(&keepTempDir, "k", false, "Keep temporary directory after source compilation")
installFlagSet.BoolVar(&force, "f", false, "Force installation by skipping architecture and dependency resolution") installFlagSet.BoolVar(&force, "f", false, "Force installation by skipping architecture and dependency resolution")
installFlagSet.BoolVar(&reinstall, "reinstall", false, "Reinstalls packages even if they do not have a newer version available") installFlagSet.BoolVar(&reinstall, "reinstall", false, "Reinstalls packages even if they do not have a newer version available")
installFlagSet.BoolVar(&reinstallAll, "reinstall-all", false, "Same as --reinstall but also reinstalls dependencies") installFlagSet.BoolVar(&reinstallAll, "reinstall-all", false, "Same as --reinstall but also reinstalls dependencies")

View File

@ -6,10 +6,6 @@ import (
) )
type BPMConfigStruct struct { type BPMConfigStruct struct {
CompilationEnv []string `yaml:"compilation_env"`
SilentCompilation bool `yaml:"silent_compilation"`
BinaryOutputDir string `yaml:"binary_output_dir"`
CompilationDir string `yaml:"compilation_dir"`
IgnorePackages []string `yaml:"ignore_packages"` IgnorePackages []string `yaml:"ignore_packages"`
Repositories []*Repository `yaml:"repositories"` Repositories []*Repository `yaml:"repositories"`
} }
@ -26,12 +22,7 @@ func ReadConfig() (err error) {
return err return err
} }
BPMConfig = BPMConfigStruct{ BPMConfig = BPMConfigStruct{}
CompilationEnv: make([]string, 0),
SilentCompilation: false,
BinaryOutputDir: "/var/lib/bpm/compiled/",
CompilationDir: "/var/tmp/",
}
err = yaml.Unmarshal(bytes, &BPMConfig) err = yaml.Unmarshal(bytes, &BPMConfig)
if err != nil { if err != nil {
return err return err

View File

@ -465,9 +465,9 @@ func (operation *BPMOperation) Execute(verbose, force bool) error {
isReinstall := IsPackageInstalled(bpmpkg.PkgInfo.Name, operation.RootDir) isReinstall := IsPackageInstalled(bpmpkg.PkgInfo.Name, operation.RootDir)
var err error var err error
if value.IsDependency { if value.IsDependency {
err = installPackage(value.File, operation.RootDir, verbose, true, false, false, false) err = installPackage(value.File, operation.RootDir, verbose, true)
} else { } else {
err = installPackage(value.File, operation.RootDir, verbose, force, false, false, false) err = installPackage(value.File, operation.RootDir, verbose, force)
} }
if err != nil { if err != nil {
return errors.New(fmt.Sprintf("could not install package (%s): %s\n", bpmpkg.PkgInfo.Name, err)) return errors.New(fmt.Sprintf("could not install package (%s): %s\n", bpmpkg.PkgInfo.Name, err))

View File

@ -8,16 +8,13 @@ import (
version "github.com/knqyf263/go-rpm-version" version "github.com/knqyf263/go-rpm-version"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"io" "io"
"io/fs"
"os" "os"
"os/exec" "os/exec"
"path" "path"
"path/filepath"
"slices" "slices"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"syscall"
) )
type BPMPackage struct { type BPMPackage struct {
@ -309,11 +306,6 @@ func executePackageScripts(filename, rootDir string, operation packageOperation,
} }
cmd := exec.Command("/bin/bash", temp.Name()) cmd := exec.Command("/bin/bash", temp.Name())
if !BPMConfig.SilentCompilation {
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
}
cmd.Dir = rootDir cmd.Dir = rootDir
cmd.Env = os.Environ() cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_ROOT=%s", rootDir)) cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_ROOT=%s", rootDir))
@ -433,14 +425,6 @@ func ReadPackageInfo(contents string) (*PackageInfo, error) {
return &pkgInfo, nil return &pkgInfo, nil
} }
func CreateInfoFile(pkgInfo *PackageInfo) string {
b, err := yaml.Marshal(&pkgInfo)
if err != nil {
return ""
}
return string(b)
}
func CreateReadableInfo(showArchitecture, showType, showPackageRelations bool, pkgInfo *PackageInfo, rootDir string) string { func CreateReadableInfo(showArchitecture, showType, showPackageRelations bool, pkgInfo *PackageInfo, rootDir string) string {
ret := make([]string, 0) ret := make([]string, 0)
appendArray := func(label string, array []string) { appendArray := func(label string, array []string) {
@ -611,447 +595,7 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
return nil return nil
} }
func isSplitPackage(filename string) bool { func installPackage(filename, rootDir string, verbose, force bool) error {
pkgInfo, err := ReadPackage(filename)
if err != nil {
return false
}
if pkgInfo.PkgInfo.Type != "source" {
return false
}
cmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("test $(tar -tf %s | grep '^pkg.info' | wc -l) -eq 1", filename))
if err := cmd.Run(); err == nil {
return false
}
return true
}
func compilePackage(bpmpkg *BPMPackage, filename, rootDir string, verbose, binaryPkgFromSrc, skipCheck, keepTempDir bool) (error, []string) {
var files []string
if !IsPackageInstalled(bpmpkg.PkgInfo.Name, rootDir) {
err := executePackageScripts(filename, rootDir, packageOperationInstall, false)
if err != nil {
return err, nil
}
} else {
err := executePackageScripts(filename, rootDir, packageOperationUpdate, false)
if err != nil {
return err, nil
}
}
//seenHardlinks := make(map[string]string)
file, err := os.Open(filename)
if err != nil {
return err, nil
}
tr := tar.NewReader(file)
temp := path.Join(BPMConfig.CompilationDir, "bpm_source-"+bpmpkg.PkgInfo.Name)
err = os.RemoveAll(temp)
if err != nil {
return err, nil
}
if verbose {
fmt.Println("Creating temp directory at: " + temp)
}
err = os.Mkdir(temp, 0755)
if err != nil {
return err, nil
}
err = os.Chown(temp, 65534, 65534)
if err != nil {
return err, nil
}
for {
header, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return err, nil
}
if strings.HasPrefix(header.Name, "source-files/") && header.Name != "source-files/" {
extractFilename := path.Join(temp, strings.TrimPrefix(header.Name, "source-files/"))
switch header.Typeflag {
case tar.TypeDir:
if err := os.Mkdir(extractFilename, 0755); err != nil {
if !os.IsExist(err) {
return err, nil
}
} else {
if verbose {
fmt.Println("Creating Directory: " + extractFilename)
}
err = os.Chown(extractFilename, 65534, 65534)
if err != nil {
return err, nil
}
}
case tar.TypeReg:
err := os.Remove(extractFilename)
if err != nil && !os.IsNotExist(err) {
return err, nil
}
outFile, err := os.Create(extractFilename)
if verbose {
fmt.Println("Creating File: " + extractFilename)
}
if err != nil {
return err, nil
}
err = os.Chown(extractFilename, 65534, 65534)
if err != nil {
return err, nil
}
if _, err := io.Copy(outFile, tr); err != nil {
return err, nil
}
if err := os.Chmod(extractFilename, header.FileInfo().Mode()); err != nil {
return err, nil
}
err = outFile.Close()
if err != nil {
return err, nil
}
case tar.TypeSymlink:
if verbose {
fmt.Println("Skipping symlink (Bundling symlinks in source packages is not supported)")
}
case tar.TypeLink:
if verbose {
fmt.Println("Skipping hard link (Bundling hard links in source packages is not supported)")
}
default:
return errors.New("unknown type (" + strconv.Itoa(int(header.Typeflag)) + ") in " + extractFilename), nil
}
}
if header.Name == "source.sh" {
bs, err := io.ReadAll(tr)
if err != nil {
return err, nil
}
err = os.WriteFile(path.Join(temp, "source.sh"), bs, 0644)
if err != nil {
return err, nil
}
err = os.Chown(path.Join(temp, "source.sh"), 65534, 65534)
if err != nil {
return err, nil
}
}
}
if _, err := os.Stat(path.Join(temp, "source.sh")); os.IsNotExist(err) {
return errors.New("source.sh file could not be found in the temporary build directory"), nil
}
fmt.Println("Running source.sh file...")
if !IsPackageInstalled(bpmpkg.PkgInfo.Name, rootDir) {
err = executePackageScripts(filename, rootDir, packageOperationInstall, false)
if err != nil {
return err, nil
}
} else {
err = executePackageScripts(filename, rootDir, packageOperationUpdate, false)
if err != nil {
return err, nil
}
}
bs, err := os.ReadFile(path.Join(temp, "source.sh"))
if err != nil {
return err, nil
}
if !strings.Contains(string(bs), "package()") {
fmt.Print("This package does not seem to have the required 'package' function\nThe source.sh file may have been created for an older BPM version\nPlease update the source.sh file")
return errors.New("invalid source.sh format"), nil
}
runScript := `
cd "$BPM_WORKDIR"
set -a
source "source.sh"
set +a
if [[ $(type -t prepare) == function ]]; then
echo "Running prepare() function..."
bash -e -c prepare
if [ $? -ne 0 ]; then
echo "Failed to run prepare() function in source.sh"
exit 1
fi
fi
cd "$BPM_SOURCE"
if [[ $(type -t build) == function ]]; then
echo "Running build() function..."
bash -e -c build
if [ $? -ne 0 ]; then
echo "Failed to run build() function in source.sh"
exit 1
fi
fi
cd "$BPM_SOURCE"
if [[ $(type -t check) == function ]] && [ -z "$SKIPCHECK" ]; then
echo "Running check() function..."
bash -e -c check
if [ $? -ne 0 ]; then
echo "Failed to run check() function in source.sh"
exit 1
fi
fi
cd "$BPM_SOURCE"
if ! [[ $(type -t package) == function ]]; then
echo "Failed to locate package() function in source.sh"
exit 1
fi
echo "Running package() function..."
touch "$BPM_WORKDIR"/fakeroot_file
fakeroot -s "$BPM_WORKDIR"/fakeroot_file bash -e -c package
bash -e -c package
if [ $? -ne 0 ]; then
echo "Failed to run package() function in source.sh"
fi
`
err = os.WriteFile(path.Join(temp, "run.sh"), []byte(runScript), 0644)
if err != nil {
return err, nil
}
err = os.Chown(path.Join(temp, "run.sh"), 65534, 65534)
if err != nil {
return err, nil
}
cmd := exec.Command("/bin/bash", "-e", "run.sh")
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: 65534, Gid: 65534}
cmd.Dir = temp
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, "USER=nobody")
cmd.Env = append(cmd.Env, "HOME="+temp)
err = os.Mkdir(path.Join(temp, "source"), 0755)
if err != nil {
return err, nil
}
err = os.Chown(path.Join(temp, "source"), 65534, 65534)
if err != nil {
return err, nil
}
err = os.Mkdir(path.Join(temp, "output"), 0755)
if err != nil {
return err, nil
}
err = os.Chown(path.Join(temp, "output"), 65534, 65534)
if err != nil {
return err, nil
}
cmd.Env = append(cmd.Env, "BPM_WORKDIR="+temp)
cmd.Env = append(cmd.Env, "BPM_SOURCE="+path.Join(temp, "source"))
cmd.Env = append(cmd.Env, "BPM_OUTPUT="+path.Join(temp, "output"))
cmd.Env = append(cmd.Env, "SKIPCHECK="+strconv.FormatBool(skipCheck))
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_ROOT=%s", rootDir))
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_NAME=%s", bpmpkg.PkgInfo.Name))
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_DESC=%s", bpmpkg.PkgInfo.Description))
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_VERSION=%s", bpmpkg.PkgInfo.Version))
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_REVISION=%d", bpmpkg.PkgInfo.Revision))
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_URL=%s", bpmpkg.PkgInfo.Url))
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_ARCH=%s", bpmpkg.PkgInfo.Arch))
depends := make([]string, len(bpmpkg.PkgInfo.Depends))
copy(depends, bpmpkg.PkgInfo.Depends)
for i := 0; i < len(depends); i++ {
depends[i] = fmt.Sprintf("\"%s\"", depends[i])
}
makeDepends := make([]string, len(bpmpkg.PkgInfo.MakeDepends))
copy(makeDepends, bpmpkg.PkgInfo.MakeDepends)
for i := 0; i < len(makeDepends); i++ {
makeDepends[i] = fmt.Sprintf("\"%s\"", makeDepends[i])
}
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_DEPENDS=(%s)", strings.Join(depends, " ")))
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_MAKE_DEPENDS=(%s)", strings.Join(makeDepends, " ")))
for _, value := range BPMConfig.CompilationEnv {
cmd.Env = append(cmd.Env, value)
}
cmd.Env = append(cmd.Env, "BPM_PKG_TYPE=source")
if !BPMConfig.SilentCompilation {
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
}
err = cmd.Run()
if err != nil {
return err, nil
}
if _, err := os.Stat(path.Join(temp, "output/")); err != nil {
if os.IsNotExist(err) {
return errors.New("output directory not be found at " + path.Join(temp, "output/")), nil
}
return err, nil
}
if dir, _ := os.ReadDir(path.Join(temp, "output/")); len(dir) == 0 {
return errors.New("output directory is empty"), nil
}
fmt.Println("Copying all files...")
err = filepath.WalkDir(path.Join(temp, "/output/"), func(fullpath string, d fs.DirEntry, err error) error {
relFilename, err := filepath.Rel(path.Join(temp, "/output/"), fullpath)
if relFilename == "." {
return nil
}
extractFilename := path.Join(rootDir, relFilename)
if err != nil {
return err
}
if d.Type() == os.ModeDir {
files = append(files, relFilename+"/")
if err := os.Mkdir(extractFilename, 0755); err != nil {
if !os.IsExist(err) {
return err
}
} else {
if verbose {
fmt.Println("Creating Directory: " + extractFilename)
}
}
} else if d.Type().IsRegular() {
if _, err := os.Stat(extractFilename); err == nil {
if slices.Contains(bpmpkg.PkgInfo.Keep, relFilename) {
if verbose {
fmt.Println("Skipping File: " + extractFilename + "(File is configured to be kept during installs/updates)")
}
files = append(files, relFilename)
return nil
}
}
err := os.Remove(extractFilename)
if err != nil && !os.IsNotExist(err) {
return err
}
outFile, err := os.Create(extractFilename)
if verbose {
fmt.Println("Creating File: " + extractFilename)
}
files = append(files, relFilename)
if err != nil {
return err
}
f, err := os.Open(fullpath)
if err != nil {
return err
}
if _, err := io.Copy(outFile, f); err != nil {
return err
}
info, err := os.Stat(fullpath)
if err != nil {
return err
}
if err := os.Chmod(extractFilename, info.Mode()); err != nil {
return err
}
err = outFile.Close()
if err != nil {
return err
}
err = f.Close()
if err != nil {
return err
}
} else if d.Type() == os.ModeSymlink {
link, err := os.Readlink(fullpath)
if err != nil {
return err
}
err = os.Remove(extractFilename)
if err != nil && !os.IsNotExist(err) {
return err
}
if verbose {
fmt.Println("Creating Symlink: "+extractFilename, " -> "+link)
}
files = append(files, relFilename)
err = os.Symlink(link, extractFilename)
if err != nil {
return err
}
}
return nil
})
if err != nil {
return err, nil
}
if binaryPkgFromSrc {
compiledDir := path.Join(BPMConfig.BinaryOutputDir)
err = os.MkdirAll(compiledDir, 0755)
compiledInfo := PackageInfo{}
compiledInfo = *bpmpkg.PkgInfo
compiledInfo.Type = "binary"
compiledInfo.Arch = GetArch()
err = os.WriteFile(path.Join(temp, "pkg.info"), []byte(CreateInfoFile(&compiledInfo)), 0644)
if err != nil {
return err, nil
}
err = os.Chown(path.Join(temp, "pkg.info"), 65534, 65534)
if err != nil {
return err, nil
}
scripts, err := ReadPackageScripts(filename)
for key, val := range scripts {
err = os.WriteFile(path.Join(temp, key), []byte(val), 0644)
if err != nil {
return err, nil
}
err = os.Chown(path.Join(temp, key), 65534, 65534)
if err != nil {
return err, nil
}
}
sed := fmt.Sprintf("s/output/files/")
fileName := compiledInfo.Name + "-" + compiledInfo.GetFullVersion() + "-" + compiledInfo.Arch + ".bpm"
cmd := exec.Command("/usr/bin/fakeroot", "-i fakeroot_file", "tar", "-czvpf", fileName, "pkg.info", "output/", "--transform", sed)
if !BPMConfig.SilentCompilation {
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
}
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: 65534, Gid: 65534}
cmd.Dir = temp
cmd.Env = os.Environ()
fmt.Printf("running command: %s\n", strings.Join(cmd.Args, " "))
err = cmd.Run()
if err != nil {
return err, nil
}
err = copyFileContents(path.Join(temp, fileName), path.Join(compiledDir, fileName))
if err != nil {
return err, nil
}
err = os.Chown(path.Join(compiledDir, fileName), 0, 0)
if err != nil {
return err, nil
}
}
if !keepTempDir {
err := os.RemoveAll(temp)
if err != nil {
return err, nil
}
}
if len(files) == 0 {
return errors.New("no output files for source package. Cancelling package installation"), nil
}
defer file.Close()
return nil, files
}
func installPackage(filename, rootDir string, verbose, force, binaryPkgFromSrc, skipCheck, keepTempDir bool) error {
if _, err := os.Stat(filename); os.IsNotExist(err) { if _, err := os.Stat(filename); os.IsNotExist(err) {
return err return err
} }
@ -1170,13 +714,7 @@ func installPackage(filename, rootDir string, verbose, force, binaryPkgFromSrc,
return err return err
} }
} else if bpmpkg.PkgInfo.Type == "source" { } else if bpmpkg.PkgInfo.Type == "source" {
if isSplitPackage(filename) { return errors.New("direct source package compilation in BPM has been temporarily removed and is being reworked on")
return errors.New("BPM is unable to install split source packages")
}
err, _ := compilePackage(bpmpkg, filename, rootDir, verbose, binaryPkgFromSrc, skipCheck, keepTempDir)
if err != nil {
return err
}
} else { } else {
return errors.New("unknown package type: " + bpmpkg.PkgInfo.Type) return errors.New("unknown package type: " + bpmpkg.PkgInfo.Type)
} }
@ -1649,11 +1187,6 @@ func removePackage(pkg string, verbose bool, rootDir string) error {
// Executing post_remove script // Executing post_remove script
if _, err := os.Stat(path.Join(pkgDir, "post_remove.sh")); err == nil { if _, err := os.Stat(path.Join(pkgDir, "post_remove.sh")); err == nil {
cmd := exec.Command("/bin/bash", path.Join(pkgDir, "post_remove.sh")) cmd := exec.Command("/bin/bash", path.Join(pkgDir, "post_remove.sh"))
if !BPMConfig.SilentCompilation {
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
}
cmd.Dir = rootDir cmd.Dir = rootDir
cmd.Env = os.Environ() cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_ROOT=%s", rootDir)) cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_ROOT=%s", rootDir))