305 lines
8.4 KiB
Go
305 lines
8.4 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"regexp"
|
||
|
|
||
|
"git.oreonproject.org/oreonproject/eternity/common"
|
||
|
"git.oreonproject.org/oreonproject/eternity/lib"
|
||
|
|
||
|
"math/big"
|
||
|
"os/signal"
|
||
|
"path/filepath"
|
||
|
|
||
|
"github.com/Masterminds/semver"
|
||
|
"github.com/sassoftware/go-rpmutils"
|
||
|
)
|
||
|
|
||
|
func main() {
|
||
|
if len(os.Args) < 2 {
|
||
|
fmt.Println("Usage: eternity <build/generate/convert/repo/package>")
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
|
||
|
logger := &common.DefaultLogger
|
||
|
|
||
|
for i, arg := range os.Args {
|
||
|
if arg == "--help" || arg == "-h" || (i != 1 && arg == "help") {
|
||
|
logger.LogFunc(lib.Log{
|
||
|
Level: "FATAL",
|
||
|
Content: "To ask for help, use 'eternity help <build/generate/convert/repo/package>, not --help, -h, or eternity <command> help.",
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
switch os.Args[1] {
|
||
|
case "build":
|
||
|
inMemory := true
|
||
|
if len(os.Args) > 2 {
|
||
|
if os.Args[2] == "-d" || os.Args[2] == "--disk" {
|
||
|
inMemory = false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
privateKey, err, vagueError := common.LoadPrivateKey(logger)
|
||
|
if err != nil || vagueError != nil {
|
||
|
common.LoadPrivateKeyHandleError(err, vagueError, logger)
|
||
|
}
|
||
|
|
||
|
config, err, vagueError := lib.ParseConfig("eternity.json", logger)
|
||
|
if err != nil || vagueError != nil {
|
||
|
common.EternityJsonHandleError(err, vagueError, logger)
|
||
|
} else {
|
||
|
var tempDir string
|
||
|
c := make(chan os.Signal, 1)
|
||
|
signal.Notify(c, os.Interrupt)
|
||
|
go func() {
|
||
|
for sig := range c {
|
||
|
fmt.Println("\nCaught", sig, "signal, exiting...")
|
||
|
if tempDir != "" {
|
||
|
common.BuildEPKRemoveTemporaryDirectory(tempDir, logger)
|
||
|
}
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
}()
|
||
|
var size big.Int
|
||
|
size, tempDir, err, vagueError = lib.BuildEPK("./", inMemory, config.Build, logger)
|
||
|
if err != nil || vagueError != nil {
|
||
|
common.BuildEPKHandleError(tempDir, err, vagueError, logger)
|
||
|
} else {
|
||
|
filePath := filepath.Join("./", config.Metadata.Name+"-"+config.Metadata.Version.String())
|
||
|
config.Metadata.DecompressedSize = size
|
||
|
err, vagueError := lib.PackageEPK(config.Metadata, config.Build, tempDir, filePath+".epk", privateKey, logger)
|
||
|
if err != nil || vagueError != nil {
|
||
|
common.PackageEPKHandleError(err, vagueError, logger)
|
||
|
} else {
|
||
|
common.BuildEPKRemoveTemporaryDirectory(tempDir, logger)
|
||
|
logger.LogFunc(lib.Log{
|
||
|
Level: "INFO",
|
||
|
Content: "Successfully built and packaged EPK at " + filePath + ".epk",
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
case "repo":
|
||
|
if len(os.Args) < 4 {
|
||
|
fmt.Println("Usage: eternity repo <build/generate> <directory>")
|
||
|
fmt.Println("See 'eternity help repo' for more information.")
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
privateKey, err, vagueError := common.LoadPrivateKey(logger)
|
||
|
if err != nil || vagueError != nil {
|
||
|
common.LoadPrivateKeyHandleError(err, vagueError, logger)
|
||
|
}
|
||
|
switch os.Args[2] {
|
||
|
case "generate":
|
||
|
err, vagueError := lib.GenerateRepository(os.Args[3], privateKey, logger)
|
||
|
if err != nil || vagueError != nil {
|
||
|
common.GenerateRepositoryHandleError(err, vagueError, logger)
|
||
|
}
|
||
|
}
|
||
|
case "convert":
|
||
|
if len(os.Args) < 4 {
|
||
|
fmt.Println("Usage: eternity convert </path/to/rpm> [</path/to/output/epk>]")
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
|
||
|
privateKey, err, vagueError := common.LoadPrivateKey(logger)
|
||
|
if err != nil || vagueError != nil {
|
||
|
common.LoadPrivateKeyHandleError(err, vagueError, logger)
|
||
|
}
|
||
|
|
||
|
rpmFile, err := os.Open(os.Args[2])
|
||
|
if err != nil {
|
||
|
logger.LogFunc(lib.Log{
|
||
|
Level: "FATAL",
|
||
|
Content: "Error opening RPM: " + err.Error(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
rpm, err := rpmutils.ReadRpm(rpmFile)
|
||
|
if err != nil {
|
||
|
logger.LogFunc(lib.Log{
|
||
|
Level: "FATAL",
|
||
|
Content: "Error reading RPM: " + err.Error(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
name, err := rpm.Header.GetString(rpmutils.NAME)
|
||
|
if err != nil {
|
||
|
logger.LogFunc(lib.Log{
|
||
|
Level: "FATAL",
|
||
|
Content: "Error getting RPM name: " + err.Error(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
description, err := rpm.Header.GetString(rpmutils.DESCRIPTION)
|
||
|
if err != nil {
|
||
|
logger.LogFunc(lib.Log{
|
||
|
Level: "FATAL",
|
||
|
Content: "Error getting RPM description: " + err.Error(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
longDescription := logger.LogFunc(lib.Log{
|
||
|
Level: "INFO",
|
||
|
Content: "Enter a long description for the package: ",
|
||
|
Prompt: true,
|
||
|
})
|
||
|
|
||
|
version, err := rpm.Header.GetString(rpmutils.VERSION)
|
||
|
if err != nil {
|
||
|
logger.LogFunc(lib.Log{
|
||
|
Level: "FATAL",
|
||
|
Content: "Error getting RPM version: " + err.Error(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
release, err := rpm.Header.GetString(rpmutils.RELEASE)
|
||
|
if err != nil {
|
||
|
logger.LogFunc(lib.Log{
|
||
|
Level: "FATAL",
|
||
|
Content: "Error getting RPM release: " + err.Error(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
semanticVersion, err := semver.NewVersion(version + "-" + release)
|
||
|
if err != nil {
|
||
|
logger.LogFunc(lib.Log{
|
||
|
Level: "FATAL",
|
||
|
Content: "Error parsing RPM version and release: " + err.Error(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
author := logger.LogFunc(lib.Log{
|
||
|
Level: "PROMPT",
|
||
|
Content: "Enter your preferred author name. This must be the same as the author name used in " +
|
||
|
"eternity.json and associated with your keypair, otherwise it will cause issues with EPK" +
|
||
|
" verification and your repository will be rejected by Eon and cannot be trusted.",
|
||
|
Prompt: true,
|
||
|
})
|
||
|
|
||
|
license, err := rpm.Header.GetString(rpmutils.LICENSE)
|
||
|
if err != nil {
|
||
|
logger.LogFunc(lib.Log{
|
||
|
Level: "FATAL",
|
||
|
Content: "Error getting RPM license: " + err.Error(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
decompressedSize, err := rpm.Header.GetUint64s(rpmutils.SIZE)
|
||
|
if err != nil {
|
||
|
logger.LogFunc(lib.Log{
|
||
|
Level: "FATAL",
|
||
|
Content: "Error getting RPM size: " + err.Error(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
dependenciesRpm, err := rpm.Header.GetStrings(rpmutils.REQUIRENAME)
|
||
|
if err != nil {
|
||
|
logger.LogFunc(lib.Log{
|
||
|
Level: "FATAL",
|
||
|
Content: "Error getting RPM dependencies: " + err.Error(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
libRegex := regexp.MustCompile(`^([a-z]+)`)
|
||
|
var dependencies []string
|
||
|
|
||
|
for _, dependency := range dependenciesRpm {
|
||
|
dependencyMatch := libRegex.FindStringSubmatch(dependency)
|
||
|
if len(dependencyMatch) > 1 {
|
||
|
match := dependencyMatch[1]
|
||
|
if match != "rpmlib" && match != "rtld" {
|
||
|
var exists bool
|
||
|
for _, dep := range dependencies {
|
||
|
if dep == match {
|
||
|
exists = true
|
||
|
}
|
||
|
}
|
||
|
if !exists {
|
||
|
dependencies = append(dependencies, match)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fmt.Println(dependencies)
|
||
|
|
||
|
architecture, err := rpm.Header.GetString(rpmutils.ARCH)
|
||
|
if err != nil {
|
||
|
logger.LogFunc(lib.Log{
|
||
|
Level: "FATAL",
|
||
|
Content: "Error getting RPM architecture: " + err.Error(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
metadata := lib.Metadata{
|
||
|
Name: name,
|
||
|
Description: description,
|
||
|
LongDescription: longDescription,
|
||
|
Version: *semanticVersion,
|
||
|
Author: author,
|
||
|
License: license,
|
||
|
Architecture: architecture,
|
||
|
Dependencies: dependencies,
|
||
|
DecompressedSize: *big.NewInt(int64(decompressedSize[0])),
|
||
|
SpecialFiles: lib.SpecialFiles{},
|
||
|
}
|
||
|
|
||
|
// Output the RPM data to a temporary directory
|
||
|
tempDir, err := os.MkdirTemp("", "eternity-convert-")
|
||
|
if err != nil {
|
||
|
logger.LogFunc(lib.Log{
|
||
|
Level: "FATAL",
|
||
|
Content: "Error creating temporary directory: " + err.Error(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
err = rpm.ExpandPayload(filepath.Join(tempDir, "payload"))
|
||
|
if err != nil {
|
||
|
logger.LogFunc(lib.Log{
|
||
|
Level: "FATAL",
|
||
|
Content: "Error expanding RPM payload: " + err.Error(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Package the EPK
|
||
|
err, vagueError = lib.PackageEPK(metadata, lib.Build{
|
||
|
TargetRoot: "payload",
|
||
|
HooksFolder: lib.PotentiallyNullString{
|
||
|
Null: true,
|
||
|
},
|
||
|
}, tempDir, os.Args[3], privateKey, logger)
|
||
|
if err != nil || vagueError != nil {
|
||
|
common.PackageEPKHandleError(err, vagueError, logger)
|
||
|
} else {
|
||
|
logger.LogFunc(lib.Log{
|
||
|
Level: "INFO",
|
||
|
Content: "Successfully converted RPM to EPK at " + os.Args[3],
|
||
|
})
|
||
|
}
|
||
|
case "help":
|
||
|
if len(os.Args) > 2 {
|
||
|
switch os.Args[2] {
|
||
|
case "build":
|
||
|
fmt.Println("Usage: eternity build [-d/--disk]")
|
||
|
fmt.Println(" -d, --disk Build EPK on disk instead of in memory. This is useful for large EPKs.")
|
||
|
case "convert":
|
||
|
fmt.Println("Usage: eternity convert </path/to/rpm> </path/to/output/epk>")
|
||
|
case "repo":
|
||
|
fmt.Println("Usage: eternity repo <build/generate> <directory>")
|
||
|
fmt.Println(" build Build a repository from a directory containing EPK project directories.")
|
||
|
fmt.Println(" generate Generate a repository from a directory containing EPKs.")
|
||
|
case "package":
|
||
|
fmt.Println("Usage: eternity package <epk>")
|
||
|
default:
|
||
|
fmt.Println("Usage: eternity help <build/generate/convert/repo/package>")
|
||
|
}
|
||
|
} else {
|
||
|
fmt.Println("Usage: eternity help <build/generate/convert/repo/package>")
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|