Compare commits

...

6 Commits

12 changed files with 340 additions and 80 deletions

View File

@ -1,17 +1,10 @@
SHELL = /bin/bash
# Installation paths
PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin
SYSCONFDIR := $(PREFIX)/etc
ifeq ($(PREFIX),)
PREFIX := /usr/local
endif
ifeq ($(BINDIR),)
BINDIR := $(PREFIX)/bin
endif
ifeq ($(SYSCONFDIR),)
SYSCONFDIR := $(PREFIX)/etc
endif
ifeq ($(GO),)
GO := $(shell type -a -P go | head -n 1)
endif
# Compilers and tools
GO ?= $(shell which go)
build:
mkdir -p build
@ -20,7 +13,7 @@ build:
cd src/bpm-repo; $(GO) build -ldflags "-w" -o ../../build/bpm-repo git.enumerated.dev/bubble-package-manager/bpm-utils/src/bpm-repo
cd src/bpm-setup; $(GO) build -ldflags "-w" -o ../../build/bpm-setup git.enumerated.dev/bubble-package-manager/bpm-utils/src/bpm-setup
install: build config/
install: build/ config/
# Create directories
install -dm755 $(DESTDIR)$(BINDIR)
install -dm755 $(DESTDIR)$(SYSCONFDIR)

View File

@ -1,56 +1,58 @@
# BPM Utils
### _Package creation and editing utilities for BPM_ ###
### _Creation and maintenance utilities for BPM packages and repositories_ ###
## Information
BPM Utils provides a number of different helper commands for creating and maintaining BPM packages or repositories
BPM Utils is a package providing a number of different helper scripts for setting up and archiving BPM packages
## Provided Scripts
- bpm-setup (Creates a directory with the required files for a BPM package)
## Provided utilities
- bpm-setup (Sets up directories for BPM source package creation)
- bpm-repo (Allows for easy management of multiple-package repositories)
- bpm-package (Turns a BPM package directory into a .bpm archive)
- bpm-convert (Converts source packages to binary ones)
- create-repository-data (Generates a repository package data list for unpac)
## Installation
Currently all BPM Utilities are simple bash scripts. This means you are able to simply clone this repository and place these scripts wherever you would like
#### Using a package manager
- Tide Linux: Tide linux provides a `bpm-utils` package which can be installed using `bpm install bpm-utils`
#### Building from source
- Download `go` from your package manager or from the go website
- Download `make` from your package manager
- Run the following command to compile the project
```
make SYSCONFDIR=/etc
```
- Run the following command to install bpm-utils to your system. You may also append a DESTDIR variable at the end of this line if you wish to install the files to a different location
```
make install PREFIX=/usr SYSCONFDIR=/etc
```
## Package Creation using BPM Utils
Creating a package for BPM with these utilities is simple
2) Run the following command (You can run the comamnd with no arguments to see available options)
1) Run the following command (You can run the command with no arguments to see all available options)
```
bpm-setup -D my_package -t <binary/source>
```
3) This will create a directory named 'my_bpm_package' under the current directory with all the required files for the chosen package type
4) You are able to edit the pkg.info descriptor file inside the newly created directory to your liking. Here's an example of what a descriptor file could look like
bpm-setup -D my_package
```
2) This will create a directory named `my_package` containing all files required for bpm package creation
3) You may wish to edit the pkg.info descriptor file inside the newly created directory to include dependencies or add/change other information. Here's an example of what a descriptor file could look like
```yaml
name: my_package
description: My package's description
version: 1.0
revision: 2 (Optional)
architecture: x86_64
url: https://www.my-website.com/ (Optional)
license: MyLicense (Optional)
type: <binary/source>
architecture: x86_64
depends: ["dependency1","dependency2"] (Optional)
optional_depends: ["optional_depend1","optional_depend2"]
optional_depends: ["optional_depend1","optional_depend2"] (Optional)
make_depends: ["make_depend1","make_depend2"] (Optional)
keep: ["etc/my_config.conf"] (Optional)
type: source
```
### Binary Packages
3) If you are making a binary package, copy all your binaries along with the directories they reside in (i.e files/usr/bin/my_binary)
6) Run the following to create a package archive
4) If you would like to bundle patches or other files with your package place them in the 'source-files' directory. They will be extracted to the same location as the source.sh file during compilation
5) You now need to edit your source.sh file which contains the compilation instructions for your package, the default source template comments should explain the basic process of compiling your program and how to edit it
6) When you are done editing your source.sh script run the following command to create a BPM package archive. You may run the `bpm-package` command with no arguments to get an explanation of what each flag does
```
bpm-package <filename.bpm>
bpm-package -d
```
7) It's done! You now hopefully have a working BPM package!
### Source Packages
3) If you would like to bundle patches or other files with your source package place them in the 'source-files' directory. They will be extracted to the same location as the source.sh file during compilation
4) You need to edit your 'source.sh' file, the default source.sh template should explain the basic process of compiling your program
5) Your goal is to download your program's source code with either git, wget, curl, etc. and put the binaries under a folder called 'output' in the root of the temp directory. There is a simple example script with helpful comments in the htop-src test package
6) When you are done making your source.sh script run the following to create a package archive. You may also append the -c flag to compile the package and create a binary package as well
```
bpm-package <filename.bpm>
```
7) That's it! Your source package should now be compiling correctly!
7) The `bpm-package` command will output a binary bpm archive which can be installed by BPM using `bpm install <file.bpm>`. If you are operating inside a BPM repository created using `bpm-repo` the file will automatically be moved to the binary subdirectory of your package repository

1
config/bpm-utils.conf Normal file
View File

@ -0,0 +1 @@
privilege_escalator_cmd: "sudo"

View File

@ -1,3 +1,8 @@
module git.enumerated.dev/bubble-package-manager/bpm-utils/src/bpm-package
go 1.23
require gopkg.in/yaml.v3 v3.0.1 // indirect
require bpm-utils-shared v1.0.0
replace bpm-utils-shared => ../bpm-utils-shared

3
src/bpm-package/go.sum Normal file
View File

@ -0,0 +1,3 @@
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,7 +1,202 @@
package main
import "fmt"
import (
bpmutilsshared "bpm-utils-shared"
"bufio"
"flag"
"fmt"
"gopkg.in/yaml.v3"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
)
var compile = flag.Bool("c", false, "Compile BPM source package")
var skipCheck = flag.Bool("s", false, "Skip 'check' function while compiling")
var installDepends = flag.Bool("d", false, "Install package dependencies for compilation")
var installPackage = flag.Bool("i", false, "Install compiled BPM package after compilation finishes")
var yesAll = flag.Bool("y", false, "Accept all confirmation prompts")
func main() {
fmt.Println("bpm-package")
// Setup flags and help
bpmutilsshared.SetupHelp("bpm-package <options>", "Generates source BPM package from current directory")
bpmutilsshared.SetupFlags()
// 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", script)
filesToInclude = append(filesToInclude, script)
}
}
// Read pkg.info file into basic struct
pkgInfo := struct {
Name string `yaml:"name"`
Version string `yaml:"version"`
Revision int `yaml:"revision"`
Arch string `yaml:"architecture"`
}{
Revision: 1,
}
data, err := os.ReadFile("pkg.info")
if err != nil {
log.Fatalf("Error: could not read pkg.info file")
}
err = yaml.Unmarshal(data, &pkgInfo)
if err != nil {
log.Fatalf("Error: could not unmarshal pkg.info file")
}
// 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, archive)
cmd := exec.Command("bpm", args...)
cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr
pipe, err := cmd.StdoutPipe()
if err != nil {
log.Fatalf("Error: could not setup stdout pipe: %s", err)
}
// Run command
err = cmd.Start()
if err != nil {
log.Fatalf("Error: failed to compile BPM source package: %s", err)
}
// Print command output and store it in variable
pipeOutput := ""
buf := bufio.NewReader(pipe)
for {
b, err := buf.ReadByte()
if err == io.EOF {
break
} else if err != nil {
log.Fatalf("Error: failed to read byte from command: %s", err)
}
pipeOutput += string(b)
fmt.Print(string(b))
}
fmt.Println()
// Put output file into slice
outputFiles := make([]string, 0)
for _, line := range strings.Split(pipeOutput, "\n") {
if strings.Contains(line, "Binary package generated at: ") {
path := strings.TrimSpace(strings.SplitN(line, ":", 2)[1])
outputFiles = append(outputFiles, path)
}
}
// Wait for process to complete
err = cmd.Wait()
if err != nil {
log.Fatalf("Error: failed to compile BPM source package: %s", err)
}
// Install compiled packages
if *installPackage && len(outputFiles) != 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, outputFiles...)
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)
}
}
}

View File

@ -1,3 +1,8 @@
module git.enumerated.dev/bubble-package-manager/bpm-utils/src/bpm-setup
go 1.23
require bpm-utils-shared v1.0.0
require gopkg.in/yaml.v3 v3.0.1 // indirect
replace bpm-utils-shared => ../bpm-utils-shared

3
src/bpm-setup/go.sum Normal file
View File

@ -0,0 +1,3 @@
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,6 +1,7 @@
package main
import (
bpmutilsshared "bpm-utils-shared"
"bufio"
"flag"
"fmt"
@ -12,25 +13,31 @@ import (
"strings"
)
var directory = flag.String("D", "", "Path to package directory")
var name = flag.String("n", "", "Set the package name (Defaults to \"package-name\")")
var description = flag.String("d", "Default Package Description", "Set the description (Defaults to \"package-description\")")
var version = flag.String("v", "1.0", "Set the package version (Defaults to \"1.0\")")
var url = flag.String("u", "", "Set the package URL (Optional)")
var license = flag.String("l", "", "Set the package licenses (Optional)")
var template = flag.String("t", "gnu-configure", "Set the package template (Defaults to \"gnu-configure\")")
var git = flag.Bool("g", true, "Create git repository (Defaults to true)")
var directory = flag.String("D", "", "Path to package directory (required)")
var name = flag.String("n", "", "Set the package name")
var description = flag.String("d", "Default Package Description", "Set the description")
var version = flag.String("v", "1.0", "Set the package version")
var url = flag.String("u", "", "Set the package URL")
var license = flag.String("l", "", "Set the package licenses")
var template = flag.String("t", "gnu-configure", "Set the package template")
var git = flag.Bool("g", true, "Create git repository")
func main() {
// Setup flags
setupFlags()
// Setup flags and help
bpmutilsshared.SetupHelp("bpm-setup <options>", "Sets up files and directories for BPM source package creation")
bpmutilsshared.SetupFlags()
// Show command help if no directory name is given
if *directory == "" {
help()
bpmutilsshared.ShowHelp()
os.Exit(1)
}
// Set package name to directory name if empty
if *name == "" {
*name = filepath.Base(*directory)
}
// run checks
runChecks()
@ -50,28 +57,6 @@ func main() {
createDirectory()
}
func setupFlags() {
flag.Usage = help
flag.Parse()
if *name == "" {
*name = *directory
}
}
func help() {
fmt.Println("Usage: bpm-setup <options>")
fmt.Println("Description: bpm-setup sets up directories for BPM source package creation")
fmt.Println("Options:")
fmt.Println(" -D=<directory> | Path to package directory")
fmt.Println(" -n=<name> | Set the package name (Defaults to \"package-name\")")
fmt.Println(" -d=<description> | Set the package description (Defaults to \"Default package description\")")
fmt.Println(" -v=<version> | Set the package version (Defaults to \"1.0\")")
fmt.Println(" -u=<url> | Set the package URL (Optional)")
fmt.Println(" -l=<licenses> | Set the package licenses (Optional)")
fmt.Println(" -t=<template file> | Use a template file (Defaults to gnu-configure)")
fmt.Println(" -g=<true/false> | Create git repository (Defaults to true)")
}
func runChecks() {
if strings.TrimSpace(*directory) == "" {
log.Fatalf("No directory was specified!")
@ -109,6 +94,15 @@ func showSummary() {
fmt.Printf("Create git repository: %t\n", *git)
}
func replaceVariables(templateContents string) string {
templateContents = strings.ReplaceAll(templateContents, "$NAME", *name)
templateContents = strings.ReplaceAll(templateContents, "$DESCRIPTION", *description)
templateContents = strings.ReplaceAll(templateContents, "$VERSION", *version)
templateContents = strings.ReplaceAll(templateContents, "$URL", *url)
return templateContents
}
func createDirectory() {
// Trim spaces
*directory = strings.TrimSpace(*directory)
@ -151,6 +145,10 @@ func createDirectory() {
log.Fatalf("Error: could not read template file: %s", err)
return
}
// Replace variables in template file
input = []byte(replaceVariables(string(input)))
err = os.WriteFile(path.Join(*directory, "source.sh"), input, 0644)
if err != nil {
log.Fatalf("Error: could not write to source file: %s", err)

View File

@ -0,0 +1,5 @@
module bpm-utils-shared
go 1.23
require gopkg.in/yaml.v3 v3.0.1 // indirect

View File

@ -0,0 +1,3 @@
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -0,0 +1,47 @@
package bpm_utils_shared
import (
"flag"
"fmt"
"gopkg.in/yaml.v3"
"os"
)
var usageMsg string
var description string
type BPMUtilsConfig struct {
PrivilegeEscalatorCmd string `yaml:"privilege_escalator_cmd"`
}
func ReadBPMUtilsConfig() (*BPMUtilsConfig, error) {
data, err := os.ReadFile("/etc/bpm-utils/bpm-utils.conf")
if err != nil {
return nil, err
}
config := &BPMUtilsConfig{}
err = yaml.Unmarshal(data, config)
if err != nil {
return nil, err
}
return config, nil
}
func SetupFlags() {
flag.Usage = ShowHelp
flag.Parse()
}
func SetupHelp(usage, desc string) {
usageMsg = usage
description = desc
}
func ShowHelp() {
fmt.Println("Usage: " + usageMsg)
fmt.Println("Description: " + description)
fmt.Println("Options:")
flag.PrintDefaults()
}