mirror of
https://github.com/EnumeratedDev/bpm-utils.git
synced 2026-09-26 15:36:13 +00:00
283 lines
7.9 KiB
Go
283 lines
7.9 KiB
Go
package main
|
|
|
|
import (
|
|
bpmutilsshared "bpm-utils-shared"
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"maps"
|
|
"os"
|
|
"os/exec"
|
|
"path"
|
|
"path/filepath"
|
|
"slices"
|
|
"strings"
|
|
|
|
flag "github.com/spf13/pflag"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
var compile = flag.BoolP("compile", "c", false, "Compile BPM source package")
|
|
var skipCheck = flag.BoolP("skip-checks", "s", false, "Skip 'check' function while compiling")
|
|
var installDepends = flag.BoolP("depends", "d", false, "Install package dependencies for compilation")
|
|
var installPackage = flag.BoolP("install", "i", false, "Install compiled BPM package after compilation finishes")
|
|
var moveToBinaryDir = flag.BoolP("move", "m", false, "Move output packages to the current repository's binary directory")
|
|
var updateChecksums = flag.BoolP("update-checksums", "u", false, "Update the checksums for all download entries")
|
|
var yesAll = flag.BoolP("yes", "y", false, "Accept all confirmation prompts")
|
|
|
|
func main() {
|
|
// Setup flags and help
|
|
setupFlagsAndHelp("bpm-package <options>", "Generates source BPM package from current directory")
|
|
|
|
// Run checks
|
|
runChecks()
|
|
|
|
// Create BPM archive
|
|
outputFile := createArchive()
|
|
|
|
if *compile {
|
|
compilePackage(outputFile)
|
|
}
|
|
}
|
|
|
|
func runChecks() {
|
|
// Check if pkg.info file exists
|
|
if stat, err := os.Stat("pkg.info"); err != nil || !stat.Mode().IsRegular() {
|
|
log.Fatalf("Error: pkg.info does not exist or is not a regular file")
|
|
}
|
|
|
|
// Check if source.sh file exists
|
|
if stat, err := os.Stat("source.sh"); err != nil || !stat.Mode().IsRegular() {
|
|
log.Fatalf("Error: pkg.info does not exist or is not a regular file")
|
|
}
|
|
}
|
|
|
|
func createArchive() string {
|
|
filesToInclude := make([]string, 0)
|
|
|
|
// Include base files
|
|
filesToInclude = append(filesToInclude, "pkg.info", "source.sh")
|
|
|
|
// Check if non-empty source-files directory exists and include it
|
|
if stat, err := os.Stat("source-files"); err == nil && stat.IsDir() {
|
|
dir, err := os.ReadDir("source-files")
|
|
if err == nil && len(dir) != 0 {
|
|
fmt.Println("Non-empty 'source-files' directory found")
|
|
filesToInclude = append(filesToInclude, "source-files")
|
|
}
|
|
}
|
|
|
|
// Check for package scripts and include them
|
|
for _, script := range []string{"pre_install.sh", "post_install.sh", "pre_update.sh", "post_update.sh", "pre_remove.sh", "post_remove.sh"} {
|
|
if stat, err := os.Stat(script); err == nil && stat.Mode().IsRegular() {
|
|
fmt.Printf("Package script '%s' found\n", script)
|
|
filesToInclude = append(filesToInclude, script)
|
|
}
|
|
}
|
|
|
|
// Read pkg.info file
|
|
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromFile("pkg.info")
|
|
if err != nil {
|
|
log.Fatalf("Error: could not read package info: %s", err)
|
|
}
|
|
|
|
// Update checksums
|
|
if *updateChecksums {
|
|
for i, download := range pkgInfo.Downloads {
|
|
if download.Checksum == "skip" {
|
|
continue
|
|
}
|
|
|
|
download.Checksum, err = download.CalculateChecksum(pkgInfo)
|
|
if err != nil {
|
|
log.Fatalf("Could not calculate checksum for download entry %d: %s", i+1, err)
|
|
}
|
|
|
|
pkgInfo.Downloads[i] = download
|
|
}
|
|
|
|
// Save yaml back to file
|
|
var data bytes.Buffer
|
|
encoder := yaml.NewEncoder(&data)
|
|
encoder.SetIndent(2)
|
|
encoder.Encode(pkgInfo)
|
|
if err != nil {
|
|
log.Fatalf("Could not marshal package info: %s", err)
|
|
}
|
|
|
|
// Stat pkg.info
|
|
stat, err := os.Stat("pkg.info")
|
|
if err != nil {
|
|
log.Fatalf("Could not stat pkg.info: %s", err)
|
|
}
|
|
|
|
// Write package info back to file
|
|
err = os.WriteFile("pkg.info", data.Bytes(), stat.Mode().Perm())
|
|
if err != nil {
|
|
log.Fatalf("Could not write package info to pkg.info: %s", err)
|
|
}
|
|
}
|
|
|
|
// Remove old BPM archives in current directory
|
|
oldArchives, err := filepath.Glob("*.bpm")
|
|
if err != nil {
|
|
log.Printf("Warning: could not search for old BPM archives: %s", err)
|
|
}
|
|
for _, bpmArchive := range oldArchives {
|
|
err = os.Remove(bpmArchive)
|
|
if err != nil {
|
|
log.Printf("Warning: could not remove old BPM archive (%s): %s", bpmArchive, err)
|
|
}
|
|
}
|
|
|
|
// Create filename
|
|
filename := fmt.Sprintf("%s-%s-%d-%s-src.bpm", pkgInfo.Name, pkgInfo.Version, pkgInfo.Revision, pkgInfo.Arch)
|
|
|
|
// Create archive using tar
|
|
args := make([]string, 0)
|
|
args = append(args, "-c", "--owner=0", "--group=0", "--no-same-owner", "-f", filename)
|
|
args = append(args, filesToInclude...)
|
|
cmd := exec.Command("tar", args...)
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
err = cmd.Run()
|
|
if err != nil {
|
|
log.Fatalf("Error: failed to create BPM source archive: %s", err)
|
|
}
|
|
|
|
// Get absolute path to filename
|
|
absFilepath, err := filepath.Abs(filename)
|
|
if err != nil {
|
|
log.Fatalf("Error: failed to get absolute path of BPM source archive: %s", err)
|
|
}
|
|
fmt.Printf("BPM source archive created at: %s\n", absFilepath)
|
|
|
|
return absFilepath
|
|
}
|
|
|
|
func compilePackage(archive string) {
|
|
// Setup compile command
|
|
args := make([]string, 0)
|
|
args = append(args, "compile")
|
|
if *skipCheck {
|
|
args = append(args, "-s")
|
|
}
|
|
if *installDepends {
|
|
args = append(args, "-d")
|
|
}
|
|
if *yesAll {
|
|
args = append(args, "-y")
|
|
}
|
|
args = append(args, "--fd=3")
|
|
args = append(args, archive)
|
|
cmd := exec.Command("bpm", args...)
|
|
cmd.Stdin = os.Stdin
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
|
|
// Set output pipe for file descriptor 3
|
|
cmdOutputReader, cmdOutputWriter, err := os.Pipe()
|
|
if err != nil {
|
|
log.Fatalf("Error: failed to create pipe: %s", err)
|
|
}
|
|
defer cmdOutputReader.Close()
|
|
defer cmdOutputWriter.Close()
|
|
cmd.ExtraFiles = append(cmd.ExtraFiles, cmdOutputWriter)
|
|
|
|
// Run command
|
|
err = cmd.Start()
|
|
if err != nil {
|
|
log.Fatalf("Error: failed to compile BPM source package: %s", err)
|
|
}
|
|
|
|
// Wait for process to complete
|
|
err = cmd.Wait()
|
|
if err != nil {
|
|
log.Fatalf("Error: failed to compile BPM source package: %s", err)
|
|
}
|
|
|
|
// Read cmd output
|
|
cmdOutputWriter.Close()
|
|
cmdOutput, err := io.ReadAll(cmdOutputReader)
|
|
if err != nil {
|
|
log.Fatalf("Error: failed to get cmd output: %s", err)
|
|
}
|
|
|
|
// Put output file into slice
|
|
outputPkgs := make(map[string]string)
|
|
for _, line := range strings.Split(strings.TrimSpace(string(cmdOutput)), "\n") {
|
|
// Read generated package info
|
|
pkgInfo, err := bpmutilsshared.ReadPacakgeInfo(line)
|
|
|
|
if repo := bpmutilsshared.GetRepository(); repo != "" && *moveToBinaryDir {
|
|
// Remove old package from binary dir
|
|
if database, err := bpmutilsshared.ReadDatabase(path.Join(repo, "binary/database.bpmdb")); err == nil {
|
|
if entry, ok := database.Entries[pkgInfo.Name]; ok {
|
|
pkgFilepath := path.Join(repo, "binary", entry.Filepath)
|
|
err := os.Remove(pkgFilepath)
|
|
if err != nil {
|
|
log.Printf("Warning: could not remove old binary package (%s): %s", pkgFilepath, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Move package to binary dir
|
|
if err != nil {
|
|
log.Fatalf("Error: could not read package info: %s", err)
|
|
}
|
|
newPath := path.Join(repo, "binary", pkgInfo.Arch, path.Base(line))
|
|
os.MkdirAll(path.Dir(newPath), 0755)
|
|
os.Rename(line, newPath)
|
|
outputPkgs[pkgInfo.Name] = newPath
|
|
|
|
bpmutilsshared.UpdateDatabases(repo)
|
|
} else {
|
|
outputPkgs[pkgInfo.Name] = line
|
|
}
|
|
}
|
|
|
|
// Print out generated packages
|
|
for k, v := range outputPkgs {
|
|
fmt.Printf("Package (%s) was successfully compiled! Binary package generated at: %s\n", k, v)
|
|
}
|
|
|
|
// Install compiled packages
|
|
if *installPackage && len(outputPkgs) != 0 {
|
|
// Read BPM utils config
|
|
config, err := bpmutilsshared.ReadBPMUtilsConfig()
|
|
if err != nil {
|
|
log.Fatalf("Error: failed to read config: %s", err)
|
|
}
|
|
|
|
// Setup install command
|
|
args = make([]string, 0)
|
|
args = append(args, "bpm", "install", "--reinstall")
|
|
if *yesAll {
|
|
args = append(args, "-y")
|
|
}
|
|
|
|
args = append(args, slices.Collect(maps.Values(outputPkgs))...)
|
|
cmd = exec.Command(config.PrivilegeEscalatorCmd, args...)
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
cmd.Stdin = os.Stdin
|
|
|
|
// Run command
|
|
err = cmd.Run()
|
|
if err != nil {
|
|
log.Fatalf("Error: failed to install compiled BPM packages: %s", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func setupFlagsAndHelp(usage, desc string) {
|
|
flag.Usage = func() {
|
|
fmt.Println("Usage: " + usage)
|
|
fmt.Println("Description: " + desc)
|
|
fmt.Println("Options:")
|
|
flag.PrintDefaults()
|
|
}
|
|
flag.Parse()
|
|
}
|