mirror of
https://github.com/EnumeratedDev/bpm-utils.git
synced 2026-09-16 02:56:11 +00:00
Merge pull request #1 from EnumeratedDev/go_rewrite
Rewrite bpm-utils in go
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
# IDE Directories
|
||||
.idea
|
||||
|
||||
# Build directory
|
||||
build
|
||||
@@ -0,0 +1,35 @@
|
||||
# Installation paths
|
||||
PREFIX ?= /usr/local
|
||||
BINDIR ?= $(PREFIX)/bin
|
||||
SYSCONFDIR := $(PREFIX)/etc
|
||||
|
||||
# Compilers and tools
|
||||
GO ?= go
|
||||
|
||||
build:
|
||||
mkdir -p build
|
||||
cd src/bpm-package; $(GO) build -ldflags "-w" -o ../../build/bpm-package git.enumerated.dev/bubble-package-manager/bpm-utils/src/bpm-package
|
||||
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:
|
||||
# Create directory
|
||||
install -dm755 $(DESTDIR)$(BINDIR)
|
||||
# Install binary
|
||||
install -Dm755 build/bpm-* -t $(DESTDIR)$(BINDIR)/
|
||||
|
||||
install-config:
|
||||
# Create directory
|
||||
install -dm755 $(DESTDIR)$(SYSCONFDIR)
|
||||
# Install files
|
||||
install -dm755 $(DESTDIR)$(SYSCONFDIR)/bpm-utils/
|
||||
cp -r config/* -t $(DESTDIR)$(SYSCONFDIR)/bpm-utils/
|
||||
|
||||
uninstall:
|
||||
-rm -f $(DESTDIR)$(BINDIR)/bpm-{package,repo,setup}
|
||||
-rm -rf $(DESTDIR)$(SYSCONFDIR)/bpm-utils/
|
||||
|
||||
clean:
|
||||
rm -r build/
|
||||
|
||||
.PHONY: build install install-config uninstall clean
|
||||
@@ -1,56 +1,70 @@
|
||||
|
||||
# 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)
|
||||
- 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)
|
||||
## 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 source package directory into a .bpm archive)
|
||||
|
||||
## 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
|
||||
```
|
||||
- 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
|
||||
make install-config 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 metedata file inside the newly created directory to include dependencies or add/change other information. Here's an example of what a metedata 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>
|
||||
depends: ["dependency1","dependency2"] (Optional)
|
||||
optional_depends: ["optional_depend1","optional_depend2"]
|
||||
make_depends: ["make_depend1","make_depend2"] (Optional)
|
||||
architecture: x86_64
|
||||
type: source
|
||||
depends:
|
||||
- dependency1
|
||||
- dependency2
|
||||
optional_depends:
|
||||
- optional_depend1
|
||||
- optional_depend2
|
||||
make_depends:
|
||||
- make_depend1
|
||||
- make_depend2
|
||||
keep:
|
||||
- etc/my_config.conf
|
||||
downloads:
|
||||
- url: https://wwww.my-url.com/file.tar.gz
|
||||
extract_strip_components: 1
|
||||
extract_to_bpm_source: true
|
||||
checksum: 9d19c8884cb22a594ba06a4caa6a3088e15ddfd4f3ede8c3b9e8f5cbb5a4a7a8
|
||||
```
|
||||
### 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 source 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
|
||||
```
|
||||
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 source bpm archive (and binary if passed the '-c' flag) 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
|
||||
|
||||
-217
@@ -1,217 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -f .compilation-options ]; then
|
||||
source ./.compilation-options
|
||||
fi
|
||||
|
||||
echo "$ARCH"
|
||||
|
||||
while getopts "ksfa:" o; do
|
||||
case "${o}" in
|
||||
a) ARCH="$OPTARG";;
|
||||
k) KEEP=true;;
|
||||
s) SKIPCHECK=true;;
|
||||
f) FORCE=true;;
|
||||
*) exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
PACKAGE="${@:$OPTIND:1}"
|
||||
|
||||
DIR="$PWD"
|
||||
if [ -z "$ARCH" ]; then
|
||||
ARCH=$(uname -m)
|
||||
fi
|
||||
|
||||
if ! [ -f "$PACKAGE" ]; then
|
||||
echo "$PACKAGE is not a path to a file"
|
||||
exit 1
|
||||
fi
|
||||
if ! file "$PACKAGE" | grep -q 'POSIX tar archive'; then
|
||||
echo "$PACKAGE is not a BPM package"
|
||||
exit 1
|
||||
fi
|
||||
if ! tar -tf "$PACKAGE" | grep -q 'source.sh'; then
|
||||
echo "$PACKAGE is not a BPM source package"
|
||||
exit 1
|
||||
fi
|
||||
echo "$Converting $PACKAGE..."
|
||||
|
||||
declare -A PKGINFO
|
||||
# Declare and run Read Package Information function
|
||||
function ReadPkgInfo() {
|
||||
local BACK="$PWD"
|
||||
cd "$DIR"
|
||||
if [ $# -eq 0 ]; then
|
||||
FILE=pkg.info
|
||||
PKGINFO_FILE=$(tar -xf "$PACKAGE" pkg.info -O)
|
||||
else
|
||||
FILE=pkg.info."$1"
|
||||
fi
|
||||
|
||||
if ! tar -tf "$PACKAGE" "$FILE"; then
|
||||
echo "Could not find $FILE in $PACKAGE"
|
||||
exit 1
|
||||
fi
|
||||
PKGINFO_FILE=$(tar -xf "$PACKAGE" "$FILE" -O)
|
||||
|
||||
while read line; do
|
||||
PKGINFO[$(echo -n "$line" | cut -d":" -f1 | xargs)]=$(echo -n "$line" | cut -d":" -f2 | xargs)
|
||||
done < <(tar -xf "$PACKAGE" "$FILE" -O)
|
||||
cd "$BACK"
|
||||
}
|
||||
ReadPkgInfo
|
||||
|
||||
if [ -z "$FORCE" ] && command -v bpm &> /dev/null && [ -n "$PKGINFO[depends]" ]; then
|
||||
MISSING=()
|
||||
for depend in $(echo "${PKGINFO[depends]}" | tr -d '[]' | tr ',' '\n' ); do
|
||||
if ! bpm info "$depend" &> /dev/null; then
|
||||
MISSING+=("$depend")
|
||||
fi
|
||||
done
|
||||
if [ "${#MISSING[@]}" -ne 0 ]; then
|
||||
echo "The following dependencies could not be resolved: ${MISSING[@]}"
|
||||
EXIT=true
|
||||
fi
|
||||
elif ! command -v bpm &> /dev/null; then
|
||||
echo "BPM not in PATH. Skipping dependency resolution"
|
||||
elif [ -n "$FORCE" ]; then
|
||||
echo "Force compilation enabled. Skipping dependency resolution"
|
||||
fi
|
||||
|
||||
if [ -z "$FORCE" ] && command -v bpm &> /dev/null && [ -n "$PKGINFO[make_depends]" ]; then
|
||||
MISSING=()
|
||||
for depend in $(echo "${PKGINFO[make_depends]}" | tr -d '[]' | tr ',' '\n' ); do
|
||||
if ! bpm info "$depend" &> /dev/null; then
|
||||
MISSING+=("$depend")
|
||||
fi
|
||||
done
|
||||
if [ "${#MISSING[@]}" -ne 0 ]; then
|
||||
echo "The following make dependencies could not be resolved: ${MISSING[@]}"
|
||||
EXIT=true
|
||||
fi
|
||||
elif ! command -v bpm &> /dev/null; then
|
||||
echo "BPM not in PATH. Skipping make dependency resolution"
|
||||
elif [ -n "$FORCE" ]; then
|
||||
echo "Force compilation enabled. Skipping make dependency resolution"
|
||||
fi
|
||||
|
||||
if [ -n "$EXIT" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Creating temporary compilation directory structure
|
||||
TEMPDIR="/var/tmp/bpm_source_${PKGINFO[name]}"
|
||||
if [ -d "$TEMPDIR" ] && [ -z "$KEEP" ]; then
|
||||
rm -rf "$TEMPDIR"
|
||||
fi
|
||||
mkdir -p "$TEMPDIR"
|
||||
mkdir -p "$TEMPDIR"/source
|
||||
[ -d "$TEMPDIR"/output ] && rm -rf "$TEMPDIR"/output
|
||||
mkdir -p "$TEMPDIR"/output
|
||||
tar -xf "$PACKAGE" -C "$TEMPDIR" source.sh
|
||||
if tar -xf "$PACKAGE" -C "$TEMPDIR" source-files &> /dev/null; then
|
||||
mv "$TEMPDIR"/source-files/* "$TEMPDIR"/
|
||||
rm -d "$TEMPDIR"/source-files
|
||||
fi
|
||||
PACKAGE_SCRIPTS=()
|
||||
while read line; do
|
||||
PACKAGE_SCRIPTS+=("$line")
|
||||
done < <(tar -tf "$PACKAGE" | grep -v -E 'source.sh|pkg.info|source-files')
|
||||
tar -xf "$PACKAGE" -C "$TEMPDIR" ${PACKAGE_SCRIPTS[@]} &> /dev/null
|
||||
cd "$TEMPDIR"
|
||||
|
||||
# Declare and run Set Variables function
|
||||
function SetVariables() {
|
||||
export BPM_PKG_NAME="${PKGINFO[name]}"
|
||||
export BPM_PKG_DESC="${PKGINFO[description]}"
|
||||
export BPM_PKG_VERSION="${PKGINFO[version]}"
|
||||
export BPM_PKG_REVISION="${PKGINFO[revision]}"
|
||||
[ -z "$BPM_PKG_REVISION" ] && export BPM_PKG_REVISION=1
|
||||
export BPM_PKG_URL="${PKGINFO[url]}"
|
||||
export BPM_PKG_ARCH="${PKGINFO[architecture]}"
|
||||
IFS=',' read -r -a BPM_PKG_DEPENDS <<< "${PKGINFO[depends]}"
|
||||
IFS=',' read -r -a BPM_PKG_MAKE_DEPENDS <<< "${PKGINFO[make_depends]}"
|
||||
export BPM_PKG_DEPENDS
|
||||
export BPM_PKG_MAKE_DEPENDS
|
||||
export BPM_WORKDIR="$TEMPDIR"
|
||||
export BPM_SOURCE="$TEMPDIR"/source
|
||||
export BPM_OUTPUT="$TEMPDIR"/output
|
||||
}
|
||||
SetVariables
|
||||
|
||||
# Declare Run Package Function function
|
||||
function RunPkgFunction() {
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "No function name given"
|
||||
exit 1
|
||||
fi
|
||||
func="$1"
|
||||
|
||||
if [[ $(type -t "$func") == function ]]; then
|
||||
echo "Running ${func}() function..."
|
||||
bash -e -c "$func"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to run ${func}() function in source.sh"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Read source.sh file and source functions
|
||||
set -a
|
||||
source source.sh
|
||||
set +a
|
||||
|
||||
cd "$BPM_WORKDIR"
|
||||
RunPkgFunction prepare
|
||||
|
||||
cd "$BPM_SOURCE"
|
||||
RunPkgFunction build
|
||||
|
||||
cd "$BPM_SOURCE"
|
||||
if [ -z "$SKIPCHECK" ]; then
|
||||
RunPkgFunction check
|
||||
fi
|
||||
|
||||
# Packaging all packages
|
||||
for func in $(typeset -F | awk '{print $3}' | grep '^package'); do
|
||||
cd "$BPM_SOURCE"
|
||||
if [[ "$func" == "package" ]]; then
|
||||
pkgname="$BPM_PKG_NAME"
|
||||
ReadPkgInfo
|
||||
else
|
||||
pkgname="${func##package-}"
|
||||
ReadPkgInfo "$pkgname"
|
||||
fi
|
||||
SetVariables
|
||||
echo "Running ${func}() function..."
|
||||
touch "$TEMPDIR"/fakeroot_file_"$pkgname"
|
||||
fakeroot -s "$TEMPDIR"/fakeroot_file_"$pkgname" bash -e -c "$func"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to run ${func}() function in source.sh"
|
||||
exit 1
|
||||
fi
|
||||
cd "$BPM_WORKDIR"
|
||||
touch pkg.info
|
||||
if [[ "$pkgname" == "$BPM_PKG_NAME" ]]; then
|
||||
echo "${PKGINFO_FILE}" > pkg.info
|
||||
else
|
||||
echo "${PKGINFO_FILE}" > pkg.info
|
||||
fi
|
||||
echo "${PKGINFO_FILE}" > pkg.info
|
||||
sed -i "s/architecture:.*/architecture: ${ARCH}/g" pkg.info
|
||||
sed -i 's/type:.*/type: binary/g' pkg.info
|
||||
fakeroot -i "$TEMPDIR"/fakeroot_file_"$pkgname" find "$TEMPDIR"/output -mindepth 1 -printf "%P %#m %U %G %s\n" > "$TEMPDIR"/pkg.files
|
||||
find output -printf "%P\n" | fakeroot -i "$TEMPDIR"/fakeroot_file_"$pkgname" tar -czf files.tar.gz --no-recursion -C output -T -
|
||||
tar -cf "$DIR"/"$pkgname"-"$BPM_PKG_VERSION"-"$BPM_PKG_REVISION"-"$ARCH".bpm --owner=0 --group=0 -C "$TEMPDIR" pkg.info pkg.files ${PACKAGE_SCRIPTS[@]} files.tar.gz
|
||||
echo "Packaged ${pkgname} successfully!"
|
||||
rm "$TEMPDIR"/fakeroot_file_"$pkgname"
|
||||
rm -r output/
|
||||
mkdir output
|
||||
rm pkg.info
|
||||
done
|
||||
|
||||
if [ -z "$KEEP" ]; then
|
||||
rm -rf "$TEMPDIR"
|
||||
fi
|
||||
-99
@@ -1,99 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -f .compilation-options ]; then
|
||||
source ./.compilation-options
|
||||
fi
|
||||
|
||||
while getopts "cskfa:" flag; do
|
||||
case "$flag" in
|
||||
c) CONVERT=true;;
|
||||
k) KEEP=true;;
|
||||
s) SKIPCHECK=true;;
|
||||
f) FORCE=true;;
|
||||
a) ARCH="${OPTARG}";;
|
||||
*) exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -f pkg.info ]; then
|
||||
echo "pkg.info file found"
|
||||
else
|
||||
echo "pkg.info file not found in $PWD"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
output="${@:$OPTIND:1}"
|
||||
if [ -z "$output" ]; then
|
||||
pkgname=$(grep "^name: " pkg.info)
|
||||
output=$(echo "$pkgname" | cut -d' ' -f2)"-src.bpm"
|
||||
fi
|
||||
if [ -z "$output" ] || [[ ! "$output" =~ ^[a-z.A-Z0-9_-]{1,}$ ]]; then
|
||||
echo "Invalid output name! The name must only contain letters, numbers, hyphens or underscores!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
type="binary"
|
||||
toCompress=()
|
||||
|
||||
echo "Creating package with the name $output..."
|
||||
|
||||
if [ -d files ]; then
|
||||
echo "files/ directory found"
|
||||
toCompress+=("files/")
|
||||
else
|
||||
if [ -f source.sh ]; then
|
||||
type="source"
|
||||
echo "source.sh file found"
|
||||
toCompress+=("source.sh")
|
||||
if [ -f pre_update.sh ]; then
|
||||
echo "pre_update.sh file found"
|
||||
toCompress+=("pre_update.sh")
|
||||
fi
|
||||
if [ -f post_update.sh ]; then
|
||||
echo "post_update.sh file found"
|
||||
toCompress+=("post_update.sh")
|
||||
fi
|
||||
if [ -f pre_install.sh ]; then
|
||||
echo "pre_install.sh file found"
|
||||
toCompress+=("pre_install.sh")
|
||||
fi
|
||||
if [ -f post_install.sh ]; then
|
||||
echo "post_install.sh file found"
|
||||
toCompress+=("post_install.sh")
|
||||
fi
|
||||
if [ -f pre_remove.sh ]; then
|
||||
echo "pre_remove.sh file found"
|
||||
toCompress+=("pre_remove.sh")
|
||||
fi
|
||||
if [ -f post_remove.sh ]; then
|
||||
echo "post_remove.sh file found"
|
||||
toCompress+=("post_remove.sh")
|
||||
fi
|
||||
if [ -d source-files ]; then
|
||||
if [ ! -z "$(ls -A source-files)" ]; then
|
||||
echo "source-files/ directory found"
|
||||
toCompress+=("source-files/")
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "files/ directory or source.sh file not found in $PWD"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
for pkginfo in ./pkg.inf*; do
|
||||
pkginfo=$(basename "$pkginfo")
|
||||
echo "${pkginfo} file found"
|
||||
toCompress+=("$pkginfo")
|
||||
done
|
||||
|
||||
echo "Creating $type package as $output"
|
||||
tar -c --owner=0 --group=0 --no-same-owner -f "$output" "${toCompress[@]}"
|
||||
|
||||
if [ ! -z "$CONVERT" ] && "$CONVERT" && [[ "$type" == "source" ]]; then
|
||||
args=()
|
||||
[ -n "$KEEP" ] && args+=("-k")
|
||||
[ -n "$SKIPCHECK" ] && args+=("-s")
|
||||
[ -n "$FORCE" ] && args+=("-f")
|
||||
bpm-convert "${args[@]}" -a "$ARCH" "$output"
|
||||
fi
|
||||
@@ -1,176 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
usage () {
|
||||
echo "------BPM-Setup options------"
|
||||
echo "bpm-setup -D <directory> | Path to package directory"
|
||||
echo "bpm-setup -y | Skips confirmation prompt"
|
||||
echo "bpm-setup -n <name> | Set the package name (Defaults to \"package-name\")"
|
||||
echo "bpm-setup -d <description> | Set the package description (Defaults to \"Default package description\")"
|
||||
echo "bpm-setup -v <version> | Set the package version (Defaults to \"1.0\")"
|
||||
echo "bpm-setup -u <url> | Set the package URL (Optional)"
|
||||
echo "bpm-setup -l <licenses> | Set the package licenses (Optional)"
|
||||
echo "bpm-setup -t <binary/source> | Set the package type to binary or source (Defaults to binary)"
|
||||
echo "bpm-setup -s <source template file> | Use a default template file (Defaults to /etc/bpm-utils/source.default)"
|
||||
echo "bpm-setup -g <true/false> | Create git repository (Defaults to true)"
|
||||
}
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
usage
|
||||
exit
|
||||
fi
|
||||
|
||||
DESCRIPTION="Default package description"
|
||||
VERSION="1.0"
|
||||
#URL="https://my.project.url/ (Optional)"
|
||||
#LICENSE="Your project's license (Optional)"
|
||||
TYPE="binary"
|
||||
SOURCE_FILE="/etc/bpm-utils/source.default"
|
||||
GIT=true
|
||||
|
||||
while getopts "D:n:d:v:u:l:t:s:g:y" o; do
|
||||
case "${o}" in
|
||||
D)
|
||||
DIRECTORY="${OPTARG}"
|
||||
;;
|
||||
y)
|
||||
CONFIRM=yes
|
||||
;;
|
||||
n)
|
||||
NAME="${OPTARG}"
|
||||
;;
|
||||
d)
|
||||
DESCRIPTION="${OPTARG}"
|
||||
;;
|
||||
v)
|
||||
VERSION="${OPTARG}"
|
||||
;;
|
||||
u)
|
||||
URL="${OPTARG}"
|
||||
;;
|
||||
l)
|
||||
LICENSE="${OPTARG}"
|
||||
;;
|
||||
t)
|
||||
TYPE="${OPTARG}"
|
||||
;;
|
||||
s)
|
||||
SOURCE_FILE="$(realpath ${OPTARG})"
|
||||
;;
|
||||
g)
|
||||
if [[ "${OPTARG}" == true ]]; then
|
||||
GIT=TRUE
|
||||
elif [[ "${OPTARG}" == false ]]; then
|
||||
GIT=false
|
||||
else
|
||||
echo "${OPTARG} is not a true or false value!"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "${DIRECTORY}" ]; then
|
||||
echo "Required directory argument missing. Try 'bpm-setup -D <directory> [other options...]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${NAME}" ]; then
|
||||
NAME="${DIRECTORY}"
|
||||
fi
|
||||
|
||||
if [[ ! "${DIRECTORY}" == "/"* ]]; then
|
||||
DIRECTORY="${PWD}/${DIRECTORY}"
|
||||
fi
|
||||
|
||||
if [ -e "${DIRECTORY}" ]; then
|
||||
echo "This path already exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$TYPE" != "binary" ]] && [[ "$TYPE" != "source" ]]; then
|
||||
echo "Invalid package type! Package type must be either 'binary' or 'source'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
if [ -z "${CONFIRM}" ]; then
|
||||
echo "Setting up package working directory at ${DIRECTORY} with the following information:"
|
||||
echo "Package name: $NAME"
|
||||
echo "Package description: $DESCRIPTION"
|
||||
echo "Package version: $VERSION"
|
||||
if [ -z "${URL}" ]; then
|
||||
echo "Package URL: Not set"
|
||||
else
|
||||
echo "Package URL: $URL"
|
||||
fi
|
||||
if [ -z "${LICENSE}" ]; then
|
||||
echo "Package license: Not set"
|
||||
else
|
||||
echo "Package license: $LICENSE"
|
||||
fi
|
||||
|
||||
echo "Package type: $TYPE"
|
||||
if [[ "$TYPE" == "source" ]]; then
|
||||
echo "Create Git repository: $GIT"
|
||||
fi
|
||||
read -p "Create package directory? [y/N]: " CREATE
|
||||
case $CREATE in
|
||||
[Yy]* )
|
||||
;;
|
||||
*)
|
||||
echo "Exiting bpm-setup..."
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if ! mkdir -pv $DIRECTORY; then
|
||||
echo "Could not create $DIRECTORY!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd $DIRECTORY
|
||||
|
||||
touch pkg.info
|
||||
echo "name: ${NAME}" >> pkg.info
|
||||
echo "description: ${DESCRIPTION}" >> pkg.info
|
||||
echo "version: ${VERSION}" >> pkg.info
|
||||
if [ ! -z "${URL}" ]; then echo "url: ${URL}" >> pkg.info; fi
|
||||
if [ ! -z "${LICENSE}" ]; then echo "license: ${LICENSE}" >> pkg.info; fi
|
||||
|
||||
if [[ "$TYPE" == "binary" ]]; then
|
||||
echo "architecture: $(uname -m)" >> pkg.info
|
||||
echo "type: binary" >> pkg.info
|
||||
mkdir -pv files
|
||||
echo "Package directory created successfully!"
|
||||
echo "Make sure to edit the pkg.info file with the appropriate information for your package"
|
||||
echo "Add your binaries under the 'files' directory. For example a binary called 'my_binary' should go under files/usr/bin/my_binary"
|
||||
echo "You can turn your package into a .bpm file use the 'bpm-create <name>' command"
|
||||
else
|
||||
echo "architecture: any" >> pkg.info
|
||||
echo "type: source" >> pkg.info
|
||||
mkdir -pv source-files
|
||||
if [ -f "${SOURCE_FILE}" ]; then
|
||||
touch source.temp
|
||||
cat "${SOURCE_FILE}" > source.temp
|
||||
export NAME DESCRIPTION VERSION URL LICENSE TYPE
|
||||
envsubst '$NAME:$DESCRIPTION:$VERSION:$URL:$LICENSE:$TYPE' < source.temp > source.sh
|
||||
rm source.temp
|
||||
else
|
||||
echo "Source file at ${SOURCE_FILE} does not exist! Creating empty source.sh instead..."
|
||||
touch source.sh
|
||||
fi
|
||||
if $GIT ; then
|
||||
git init
|
||||
echo -e "*.bpm\n.gitignore" > .gitignore
|
||||
fi
|
||||
echo "Package directory created successfully!"
|
||||
echo "Make sure to edit the pkg.info file with the appropriate information for your package"
|
||||
echo "Add your compilation code in the source.sh file. Follow the instructions on the template file on how to properly create your compilation script"
|
||||
echo "You can add additional files that will be used during compilation to the 'source-files' directory"
|
||||
echo "You can turn your package into a .bpm file use the 'bpm-package <filename>' command"
|
||||
fi
|
||||
@@ -0,0 +1 @@
|
||||
privilege_escalator_cmd: "sudo"
|
||||
@@ -0,0 +1,2 @@
|
||||
# Exclude bpm archives
|
||||
*.bpm
|
||||
@@ -0,0 +1,32 @@
|
||||
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package
|
||||
# BPM Expects the source code to be extracted into the automatically created 'source' directory which can be accessed using $BPM_SOURCE
|
||||
# BPM Expects the output files to be present in the automatically created 'output' directory which can be accessed using $BPM_OUTPUT
|
||||
|
||||
# The prepare function is executed in the root of the temp directory
|
||||
# This function is used for putting downloaded files to the correct location or applying patches
|
||||
prepare() {
|
||||
cd "$BPM_SOURCE"
|
||||
# Fetch cargo dependencies
|
||||
cargo fetch --locked --target "$(rustc -vV | sed -n 's/host: //p')"
|
||||
}
|
||||
|
||||
# The build function is executed in the source directory
|
||||
# This function is used to compile the source code
|
||||
build() {
|
||||
cargo build --release --frozen --workspace
|
||||
}
|
||||
|
||||
# The check function is executed in the source directory
|
||||
# This function is used to run tests to verify the package has been compiled correctly
|
||||
check() {
|
||||
cargo test --frozen
|
||||
}
|
||||
|
||||
# The package function is executed in the source directory
|
||||
# This function is used to move the compiled files into the output directory
|
||||
package() {
|
||||
find target/release -maxdepth 1 -type f -executable -exec install -Dm755 -t "$BPM_OUTPUT"/usr/bin {} +
|
||||
|
||||
# Install package license
|
||||
install -Dm644 "$BPM_SOURCE"/LICENSE "$BPM_OUTPUT"/usr/share/licenses/$NAME/LICENSE
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package
|
||||
# BPM Expects the source code to be extracted into the automatically created 'source' directory which can be accessed using $BPM_SOURCE
|
||||
# BPM Expects the output files to be present in the automatically created 'output' directory which can be accessed using $BPM_OUTPUT
|
||||
|
||||
# The prepare function is executed in the root of the temp directory
|
||||
# This function is used for putting downloaded files to the correct location or applying patches
|
||||
prepare() {
|
||||
echo "You may remove this function if you do not intend to use it"
|
||||
}
|
||||
|
||||
# The build function is executed in the source directory
|
||||
# This function is used to compile the source code
|
||||
build() {
|
||||
cmake -B build -DCMAKE_INSTALL_PREFIX=/usr
|
||||
cmake --build build
|
||||
}
|
||||
|
||||
# The check function is executed in the source directory
|
||||
# This function is used to run tests to verify the package has been compiled correctly
|
||||
check() {
|
||||
ctest --test-dir build
|
||||
}
|
||||
|
||||
# The package function is executed in the source directory
|
||||
# This function is used to move the compiled files into the output directory
|
||||
package() {
|
||||
DESTDIR="$BPM_OUTPUT" cmake --install build
|
||||
|
||||
# Install package license
|
||||
install -Dm644 "$BPM_SOURCE"/LICENSE "$BPM_OUTPUT"/usr/share/licenses/$NAME/LICENSE
|
||||
}
|
||||
@@ -2,14 +2,10 @@
|
||||
# BPM Expects the source code to be extracted into the automatically created 'source' directory which can be accessed using $BPM_SOURCE
|
||||
# BPM Expects the output files to be present in the automatically created 'output' directory which can be accessed using $BPM_OUTPUT
|
||||
|
||||
DOWNLOAD="https://wwww.my-url.com/file.tar.gz"
|
||||
FILENAME="${DOWNLOAD##*/}"
|
||||
|
||||
# The prepare function is executed in the root of the temp directory
|
||||
# This function is used for downloading files and putting them into the correct location
|
||||
# This function is used for putting downloaded files to the correct location or applying patches
|
||||
prepare() {
|
||||
wget "$DOWNLOAD"
|
||||
tar -xvf "$FILENAME" --strip-components=1 -C "$BPM_SOURCE"
|
||||
echo "You may remove this function if you do not intend to use it"
|
||||
}
|
||||
|
||||
# The build function is executed in the source directory
|
||||
@@ -29,4 +25,7 @@ check() {
|
||||
# This function is used to move the compiled files into the output directory
|
||||
package() {
|
||||
make DESTDIR="$BPM_OUTPUT" install
|
||||
|
||||
# Install package license
|
||||
install -Dm644 "$BPM_SOURCE"/LICENSE "$BPM_OUTPUT"/usr/share/licenses/$NAME/LICENSE
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package
|
||||
# BPM Expects the source code to be extracted into the automatically created 'source' directory which can be accessed using $BPM_SOURCE
|
||||
# BPM Expects the output files to be present in the automatically created 'output' directory which can be accessed using $BPM_OUTPUT
|
||||
|
||||
# The prepare function is executed in the root of the temp directory
|
||||
# This function is used for putting downloaded files to the correct location or applying patches
|
||||
prepare() {
|
||||
echo "You may remove this function if you do not intend to use it"
|
||||
}
|
||||
|
||||
# The build function is executed in the source directory
|
||||
# This function is used to compile the source code
|
||||
build() {
|
||||
make PREFIX=/usr
|
||||
}
|
||||
|
||||
# The check function is executed in the source directory
|
||||
# This function is used to run tests to verify the package has been compiled correctly
|
||||
check() {
|
||||
make check
|
||||
}
|
||||
|
||||
# The package function is executed in the source directory
|
||||
# This function is used to move the compiled files into the output directory
|
||||
package() {
|
||||
make DESTDIR="$BPM_OUTPUT" PREFIX=/usr install
|
||||
|
||||
# Install package license
|
||||
install -Dm644 "$BPM_SOURCE"/LICENSE "$BPM_OUTPUT"/usr/share/licenses/$NAME/LICENSE
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package
|
||||
# BPM Expects the source code to be extracted into the automatically created 'source' directory which can be accessed using $BPM_SOURCE
|
||||
# BPM Expects the output files to be present in the automatically created 'output' directory which can be accessed using $BPM_OUTPUT
|
||||
|
||||
# The prepare function is executed in the root of the temp directory
|
||||
# This function is used for putting downloaded files to the correct location or applying patches
|
||||
prepare() {
|
||||
echo "You may remove this function if you do not intend to use it"
|
||||
}
|
||||
|
||||
# The build function is executed in the source directory
|
||||
# This function is used to compile the source code
|
||||
build() {
|
||||
meson setup build --prefix=/usr
|
||||
meson compile -C build
|
||||
}
|
||||
|
||||
# The check function is executed in the source directory
|
||||
# This function is used to run tests to verify the package has been compiled correctly
|
||||
check() {
|
||||
meson test -C build --print-errorlogs
|
||||
}
|
||||
|
||||
# The package function is executed in the source directory
|
||||
# This function is used to move the compiled files into the output directory
|
||||
package() {
|
||||
meson install -C build --destdir="$BPM_OUTPUT"
|
||||
|
||||
# Install package license
|
||||
install -Dm644 "$BPM_SOURCE"/LICENSE "$BPM_OUTPUT"/usr/share/licenses/$NAME/LICENSE
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package
|
||||
# BPM Expects the source code to be extracted into the automatically created 'source' directory which can be accessed using $BPM_SOURCE
|
||||
# BPM Expects the output files to be present in the automatically created 'output' directory which can be accessed using $BPM_OUTPUT
|
||||
|
||||
# The prepare function is executed in the root of the temp directory
|
||||
# This function is used for putting downloaded files to the correct location or applying patches
|
||||
prepare() {
|
||||
echo "You may remove this function if you do not intend to use it"
|
||||
}
|
||||
|
||||
# The build function is executed in the source directory
|
||||
# This function is used to compile the source code
|
||||
build() {
|
||||
python3 -m build --wheel --no-isolation .
|
||||
}
|
||||
|
||||
# The check function is executed in the source directory
|
||||
# This function is used to run tests to verify the package has been compiled correctly
|
||||
check() {
|
||||
# Python module testing command varies from module to module
|
||||
}
|
||||
|
||||
# The package function is executed in the source directory
|
||||
# This function is used to move the compiled files into the output directory
|
||||
package() {
|
||||
python3 -m installer --destdir="$BPM_OUTPUT" dist/*.whl
|
||||
|
||||
# Install package license
|
||||
install -Dm644 "$BPM_SOURCE"/LICENSE "$BPM_OUTPUT"/usr/share/licenses/$NAME/LICENSE
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
containsElement () {
|
||||
local e match="$1"
|
||||
shift
|
||||
for e; do [[ "$e" == "$match" ]] && return 0; done
|
||||
return 1
|
||||
}
|
||||
|
||||
SCRIPT_PATH=$(realpath "$0")
|
||||
SCRIPT_DIR=$(dirname "$SCRIPT_PATH")
|
||||
|
||||
DEEP=false
|
||||
PKGS=()
|
||||
|
||||
while getopts "d" flag; do
|
||||
case "$flag" in
|
||||
d) DEEP=true
|
||||
shopt -s globstar;;
|
||||
*) >&2 echo "Unknown flag ${flag}"
|
||||
exit 2;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "${@:$OPTIND:1}" ]; then
|
||||
echo "You have not specified a repository"
|
||||
exit 1
|
||||
fi
|
||||
if ! [ -d "${@:$OPTIND:1}" ]; then
|
||||
>&2 echo "The given path is not a directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if realpath "${@:$OPTIND:1}" &> /dev/null; then
|
||||
REPO=$(realpath "${@:$OPTIND:1}")
|
||||
fi
|
||||
|
||||
shopt -s nullglob
|
||||
|
||||
create_entry() {
|
||||
if [ $# -eq 0 ]; then
|
||||
return 0
|
||||
fi
|
||||
if ! [ -f "$1" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
info="info:"$'\n'
|
||||
info+=$(tar -xf "$pkg" pkg.info -O | sed 's/^/ /g')
|
||||
package=$(echo "$info" | grep 'name: ' | xargs | awk '{print $2}')
|
||||
if ! echo "$info" | grep -q '^ type: binary'; then
|
||||
>&2 echo "The following package is not a binary package: ${package}"
|
||||
exit 1
|
||||
fi
|
||||
if containsElement "$package" "${PKGS[@]}"; then
|
||||
>&2 echo "The following package was found in more than 1 package archives: ${package}"
|
||||
exit 1
|
||||
fi
|
||||
PKGS+=("$package")
|
||||
file="$(realpath -s --relative-to="$REPO" "$pkg")"
|
||||
info+=$'\n'"download: ${file}"
|
||||
info+=$'\n'"download_size: "$(cat "$pkg" | wc -c)
|
||||
info+=$'\n'"installed_size: "$(tar -xf "$pkg" files.tar.gz -O | zcat | wc -c)
|
||||
info+=$'\n---'
|
||||
echo "$info"
|
||||
}
|
||||
|
||||
if ! $DEEP; then
|
||||
for arch in "$REPO"/*/; do
|
||||
for pkg in "$arch"/*.bpm; do
|
||||
create_entry "$pkg"
|
||||
done
|
||||
done
|
||||
else
|
||||
for arch in "$REPO"/*/; do
|
||||
for pkg in "$arch"/**/*.bpm; do
|
||||
create_entry "$pkg"
|
||||
done
|
||||
done
|
||||
fi
|
||||
@@ -0,0 +1,13 @@
|
||||
module git.enumerated.dev/bubble-package-manager/bpm-utils/src/bpm-package
|
||||
|
||||
go 1.23
|
||||
|
||||
require (
|
||||
bpm-utils-shared v1.0.0
|
||||
github.com/spf13/pflag v1.0.10
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require github.com/drone/envsubst v1.0.3 // indirect
|
||||
|
||||
replace bpm-utils-shared => ../bpm-utils-shared
|
||||
@@ -0,0 +1,10 @@
|
||||
github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
|
||||
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
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=
|
||||
@@ -0,0 +1,282 @@
|
||||
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.ReadPacakgeInfoFromTarball(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()
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
module git.enumerated.dev/bubble-package-manager/bpm-utils/src/bpm-repo
|
||||
|
||||
go 1.23
|
||||
|
||||
require (
|
||||
bpm-utils-shared v1.0.0
|
||||
github.com/spf13/pflag v1.0.10
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require github.com/drone/envsubst v1.0.3 // indirect
|
||||
|
||||
replace bpm-utils-shared => ../bpm-utils-shared
|
||||
@@ -0,0 +1,10 @@
|
||||
github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
|
||||
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
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=
|
||||
@@ -0,0 +1,375 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
bpmutilsshared "bpm-utils-shared"
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log"
|
||||
"maps"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var currentFlagSet *flag.FlagSet
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
log.Println("Error: no subcommand")
|
||||
listSubcommands()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
subcommand := os.Args[1]
|
||||
|
||||
switch subcommand {
|
||||
case "create-repo", "c":
|
||||
// Setup flags and help
|
||||
flagset := flag.NewFlagSet("create-repo", flag.ExitOnError)
|
||||
setupFlagsAndHelp(flagset, fmt.Sprintf("bpm-repo %s <options>", subcommand), "Create a new BPM repository", os.Args[:1])
|
||||
|
||||
// Get current database
|
||||
repo := bpmutilsshared.GetRepository()
|
||||
if repo != "" {
|
||||
log.Fatal("Error: this command cannot be run inside a BPM repository")
|
||||
}
|
||||
|
||||
scanner := bufio.NewReader(os.Stdin)
|
||||
fmt.Print("Repository name: ")
|
||||
name, err := scanner.ReadString('\n')
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not read user input: %s", err)
|
||||
}
|
||||
fmt.Print("Repository description: ")
|
||||
desc, err := scanner.ReadString('\n')
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not read user input: %s", err)
|
||||
}
|
||||
|
||||
createRepository(strings.TrimSpace(name), strings.TrimSpace(desc))
|
||||
case "update-db", "u":
|
||||
// Setup flags and help
|
||||
flagset := flag.NewFlagSet("update-db", flag.ExitOnError)
|
||||
setupFlagsAndHelp(flagset, fmt.Sprintf("bpm-repo %s <options>", subcommand), "Update update source and binary databases in current repository", os.Args[:1])
|
||||
|
||||
// Get current database
|
||||
repo := bpmutilsshared.GetRepository()
|
||||
if repo == "" {
|
||||
log.Fatal("Error: this command may only be run inside a BPM repository")
|
||||
}
|
||||
|
||||
bpmutilsshared.UpdateDatabases(repo)
|
||||
case "list", "l":
|
||||
flagset := flag.NewFlagSet("list", flag.ExitOnError)
|
||||
setupFlagsAndHelp(flagset, fmt.Sprintf("bpm-repo %s <options>", subcommand), "List packages", os.Args[:1])
|
||||
|
||||
// Get current database
|
||||
repo := bpmutilsshared.GetRepository()
|
||||
if repo == "" {
|
||||
log.Fatal("Error: this command may only be run inside a BPM repository")
|
||||
}
|
||||
|
||||
listPackagesFunc(repo)
|
||||
case "check-versions", "v":
|
||||
// Setup flags and help
|
||||
flagset := flag.NewFlagSet("check-versions", flag.ExitOnError)
|
||||
flagset.BoolP("verbose", "v", false, "Show additional information about the current operation")
|
||||
flagset.BoolP("force", "f", false, "Force current operation to bypass certain conditions")
|
||||
setupFlagsAndHelp(flagset, fmt.Sprintf("bpm-repo %s <options>", subcommand), "Manage BPM repositories and databases", os.Args[2:])
|
||||
currentFlagSet = flagset
|
||||
|
||||
// Get current database
|
||||
repo := bpmutilsshared.GetRepository()
|
||||
if repo == "" {
|
||||
log.Fatal("Error: this command may only be run inside a BPM repository")
|
||||
}
|
||||
|
||||
checkVersionsFunc(repo)
|
||||
default:
|
||||
log.Println("Error: unknown subcommand")
|
||||
listSubcommands()
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func createRepository(name, description string) {
|
||||
err := os.Mkdir(name, 0755)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not create directory: %s", err)
|
||||
}
|
||||
|
||||
contents := fmt.Sprintf("name: %s\ndescription: %s\n", name, description)
|
||||
err = os.WriteFile(path.Join(name, "bpm-repo.conf"), []byte(contents), 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not write to file: %s", err)
|
||||
}
|
||||
|
||||
fmt.Println("Repository created successfully!")
|
||||
}
|
||||
|
||||
func checkVersionsFunc(repo string) {
|
||||
// Get flags
|
||||
verbose, _ := currentFlagSet.GetBool("verbose")
|
||||
force, _ := currentFlagSet.GetBool("force")
|
||||
|
||||
// Read environment files
|
||||
err := readEnvFile(repo)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not read environment file: %s", err)
|
||||
}
|
||||
|
||||
// Read version cache
|
||||
type CachedVersionEntry struct {
|
||||
LatestVersion string `yaml:"latest_version"`
|
||||
Timestamp int64 `yaml:"timestamp"`
|
||||
}
|
||||
cachedVersions := make(map[string]CachedVersionEntry)
|
||||
data, err := os.ReadFile(path.Join(repo, ".version-cache"))
|
||||
if err == nil {
|
||||
err := yaml.Unmarshal(data, &cachedVersions)
|
||||
if err != nil {
|
||||
cachedVersions = make(map[string]CachedVersionEntry)
|
||||
}
|
||||
}
|
||||
|
||||
directories := make([]string, 0)
|
||||
if currentFlagSet.NArg() > 0 {
|
||||
for _, dir := range currentFlagSet.Args() {
|
||||
if _, err := os.Stat(path.Join(repo, "source", dir, "pkg.info")); err != nil {
|
||||
log.Fatalf("Error: could not find pkg.info file in directory (%s): %s", dir, err)
|
||||
}
|
||||
directories = append(directories, path.Join(repo, "source", dir))
|
||||
}
|
||||
} else {
|
||||
// Loop through each directory with a 'pkg.info' file
|
||||
err := filepath.Walk(path.Join(repo, "source"), func(path string, info fs.FileInfo, err error) error {
|
||||
if filepath.Base(path) == "pkg.info" {
|
||||
directories = append(directories, filepath.Dir(path))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not loop through all packages: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
pkgsWithoutScript := make([]string, 0)
|
||||
pkgsIgnored := make([]string, 0)
|
||||
pkgsWithError := make(map[string]error)
|
||||
pkgsWithUpdates := make(map[string]struct {
|
||||
OldVersion string
|
||||
NewVersion string
|
||||
}, 0)
|
||||
pkgsUpToDate := 0
|
||||
for _, dir := range directories {
|
||||
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromFile(path.Join(dir, "pkg.info"))
|
||||
if err != nil {
|
||||
log.Fatalf("Could not read package info: %s", err)
|
||||
}
|
||||
|
||||
if verbose {
|
||||
fmt.Printf("Checking version for package (%s)...\n", pkgInfo.Name)
|
||||
}
|
||||
|
||||
// Check cached latest version
|
||||
latestVersion := ""
|
||||
if cachedVersion, ok := cachedVersions[pkgInfo.Name]; ok && !force && time.Since(time.UnixMilli(cachedVersion.Timestamp)).Milliseconds() < 604800000 {
|
||||
latestVersion = cachedVersion.LatestVersion
|
||||
} else {
|
||||
// Check whether check-version.sh script exists
|
||||
if _, err := os.Stat(path.Join(dir, "check-version.sh")); err != nil {
|
||||
pkgsWithoutScript = append(pkgsWithoutScript, pkgInfo.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
// Execute check-version.sh script
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
cmd := exec.CommandContext(ctx, "bash", "-e", path.Join(dir, "check-version.sh"))
|
||||
cmd.Environ()
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
pkgsWithError[pkgInfo.Name] = err
|
||||
continue
|
||||
}
|
||||
latestVersion = strings.TrimSpace(string(output))
|
||||
|
||||
// Check if package should be ignored
|
||||
if latestVersion == "ignore" {
|
||||
pkgsIgnored = append(pkgsIgnored, pkgInfo.Name)
|
||||
|
||||
// Remove cached status
|
||||
delete(cachedVersions, pkgInfo.Name)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure latest version is valid
|
||||
if latestVersion == "" || latestVersion == "null" {
|
||||
pkgsWithError[pkgInfo.Name] = fmt.Errorf("invalid version number \"%s\"", latestVersion)
|
||||
continue
|
||||
}
|
||||
|
||||
// Cache latest version
|
||||
cachedVersions[pkgInfo.Name] = CachedVersionEntry{
|
||||
LatestVersion: latestVersion,
|
||||
Timestamp: time.Now().UnixMilli(),
|
||||
}
|
||||
}
|
||||
|
||||
// Compare versions
|
||||
if pkgInfo.Version != latestVersion {
|
||||
pkgsWithUpdates[pkgInfo.Name] = struct {
|
||||
OldVersion string
|
||||
NewVersion string
|
||||
}{
|
||||
OldVersion: pkgInfo.Version,
|
||||
NewVersion: latestVersion,
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
pkgsUpToDate++
|
||||
}
|
||||
|
||||
// Save cached versions to file
|
||||
data, err = yaml.Marshal(cachedVersions)
|
||||
if err == nil {
|
||||
err := os.WriteFile(path.Join(repo, ".version-cache"), data, 0644)
|
||||
if err != nil {
|
||||
log.Printf("Warning: could not write cached versions to file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Print updates
|
||||
keys := slices.Collect(maps.Keys(pkgsWithUpdates))
|
||||
sort.Strings(keys)
|
||||
for _, pkg := range keys {
|
||||
fmt.Printf("Update available for package (%s): %s -> %s\n", pkg, pkgsWithUpdates[pkg].OldVersion, pkgsWithUpdates[pkg].NewVersion)
|
||||
}
|
||||
|
||||
if verbose {
|
||||
// Print ignored packages
|
||||
for _, pkg := range pkgsIgnored {
|
||||
log.Printf("Warning: package (%s) was ignored\n", pkg)
|
||||
}
|
||||
|
||||
// Print packages without check-version.sh script
|
||||
for _, pkg := range pkgsWithoutScript {
|
||||
log.Printf("Warning: package (%s) has no check-version.sh script\n", pkg)
|
||||
}
|
||||
}
|
||||
|
||||
// Print errors
|
||||
keys = slices.Collect(maps.Keys(pkgsWithError))
|
||||
sort.Strings(keys)
|
||||
for _, pkg := range keys {
|
||||
log.Printf("Error: check-version.sh script for package (%s) failed: %s", pkg, pkgsWithError[pkg])
|
||||
}
|
||||
|
||||
// Print summary
|
||||
fmt.Println("----- Summary -----")
|
||||
fmt.Println("Available updates:", len(pkgsWithUpdates))
|
||||
fmt.Println("Up to date:", pkgsUpToDate)
|
||||
fmt.Println("Missing script:", len(pkgsWithoutScript))
|
||||
fmt.Println("Ignored: ", len(pkgsIgnored))
|
||||
fmt.Println("Errors:", len(pkgsWithError))
|
||||
}
|
||||
|
||||
func listPackagesFunc(repo string) {
|
||||
// Read databases
|
||||
sourceDatabase, err := bpmutilsshared.ReadDatabase(path.Join(repo, "source/database.bpmdb"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
binaryDatabase, err := bpmutilsshared.ReadDatabase(path.Join(repo, "binary/database.bpmdb"))
|
||||
if err != nil {
|
||||
binaryDatabase = &bpmutilsshared.BPMDatabase{}
|
||||
}
|
||||
|
||||
// Sort database entries
|
||||
entriesSorted := slices.Collect(maps.Values(sourceDatabase.Entries))
|
||||
sort.Slice(entriesSorted, func(i, j int) bool {
|
||||
return entriesSorted[i].PackageInfo.Name < entriesSorted[j].PackageInfo.Name
|
||||
})
|
||||
|
||||
// Loop through each entry
|
||||
for _, entry := range entriesSorted {
|
||||
if len(entry.PackageInfo.SplitPackages) > 0 {
|
||||
for _, splitPkg := range entry.PackageInfo.SplitPackages {
|
||||
// Handle split packages
|
||||
additionalText := ""
|
||||
if binaryEntry, ok := binaryDatabase.Entries[splitPkg.Name]; !ok {
|
||||
additionalText += "(Binary package missing) "
|
||||
} else if fmt.Sprintf("%s-%d", binaryEntry.PackageInfo.Version, binaryEntry.PackageInfo.Revision) != fmt.Sprintf("%s-%d", entry.PackageInfo.Version, entry.PackageInfo.Revision) {
|
||||
additionalText += "(Binary package version mismatch) "
|
||||
}
|
||||
fmt.Printf("%s %s-%d %s\n", splitPkg.Name, entry.PackageInfo.Version, entry.PackageInfo.Revision, additionalText)
|
||||
}
|
||||
} else {
|
||||
additionalText := ""
|
||||
if binaryEntry, ok := binaryDatabase.Entries[entry.PackageInfo.Name]; !ok {
|
||||
additionalText += "(Binary package missing) "
|
||||
} else if fmt.Sprintf("%s-%d", binaryEntry.PackageInfo.Version, binaryEntry.PackageInfo.Revision) != fmt.Sprintf("%s-%d", entry.PackageInfo.Version, entry.PackageInfo.Revision) {
|
||||
additionalText += "(Binary package version mismatch) "
|
||||
}
|
||||
fmt.Printf("%s %s-%d %s\n", entry.PackageInfo.Name, entry.PackageInfo.Version, entry.PackageInfo.Revision, additionalText)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readEnvFile(repo string) error {
|
||||
data, err := os.ReadFile(path.Join(repo, ".env"))
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" || line[0] == '#' {
|
||||
continue
|
||||
}
|
||||
|
||||
splitLine := strings.Split(line, "=")
|
||||
if len(splitLine) != 2 {
|
||||
return fmt.Errorf("invalid format")
|
||||
}
|
||||
|
||||
os.Setenv(splitLine[0], splitLine[1])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func listSubcommands() {
|
||||
fmt.Println("Usage: bpm-repo <subcommand> <options>")
|
||||
fmt.Println("Description: Manage BPM repositories and databases")
|
||||
fmt.Println("Subcommands:")
|
||||
fmt.Println(" c, create-repo Create a new BPM repository")
|
||||
fmt.Println(" u, update-db Update update source and binary databases in current repositor")
|
||||
fmt.Println(" v, check-versions Manage BPM repositories and databases")
|
||||
fmt.Println(" l, list List packages")
|
||||
}
|
||||
|
||||
func setupFlagsAndHelp(flagset *flag.FlagSet, usage, desc string, args []string) {
|
||||
flagset.Usage = func() {
|
||||
fmt.Println("Usage: " + usage)
|
||||
fmt.Println("Description: " + desc)
|
||||
fmt.Println("Options:")
|
||||
flagset.PrintDefaults()
|
||||
}
|
||||
flagset.Parse(args)
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
module git.enumerated.dev/bubble-package-manager/bpm-utils/src/bpm-setup
|
||||
|
||||
go 1.23
|
||||
|
||||
require (
|
||||
bpm-utils-shared v1.0.0
|
||||
github.com/spf13/pflag v1.0.10
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require github.com/drone/envsubst v1.0.3 // indirect
|
||||
|
||||
replace bpm-utils-shared => ../bpm-utils-shared
|
||||
@@ -0,0 +1,10 @@
|
||||
github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
|
||||
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
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=
|
||||
@@ -0,0 +1,206 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
bpmutilsshared "bpm-utils-shared"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var directory = flag.StringP("directory", "D", "", "Path to package directory")
|
||||
var name = flag.StringP("name", "n", "", "Set the package name")
|
||||
var description = flag.StringP("description", "d", "Default Package Description", "Set the description")
|
||||
var version = flag.StringP("version", "v", "1.0", "Set the package version")
|
||||
var url = flag.StringP("url", "u", "", "Set the package URL")
|
||||
var license = flag.StringP("license", "l", "", "Set the package licenses")
|
||||
var template = flag.StringP("template", "t", "gnu-configure", "Set the package template")
|
||||
var git = flag.BoolP("git", "g", true, "Create git repository")
|
||||
|
||||
func main() {
|
||||
// Setup flags and help
|
||||
setupFlagsAndHelp("bpm-setup <options>", "Sets up files and directories for BPM source package creation")
|
||||
|
||||
// Show command help if no directory name is given
|
||||
if *directory == "" {
|
||||
log.Println("Error: directory flag is required")
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Set package name to directory name if empty
|
||||
if *name == "" {
|
||||
*name = filepath.Base(*directory)
|
||||
}
|
||||
|
||||
// run checks
|
||||
runChecks()
|
||||
|
||||
// Show summary
|
||||
showSummary()
|
||||
|
||||
// Confirmation prompt
|
||||
fmt.Printf("Create package directory? [y\\N]: ")
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
text, _ := reader.ReadString('\n')
|
||||
if strings.TrimSpace(strings.ToLower(text)) != "y" && strings.TrimSpace(strings.ToLower(text)) != "yes" {
|
||||
fmt.Println("Cancelling package directory creation...")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Create package directory
|
||||
createDirectory()
|
||||
}
|
||||
|
||||
func runChecks() {
|
||||
if strings.TrimSpace(*directory) == "" {
|
||||
log.Fatalf("No directory was specified!")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(*name) == "" {
|
||||
log.Fatalf("No package name was specified!")
|
||||
}
|
||||
|
||||
if stat, err := os.Stat(path.Join("/etc/bpm-utils/templates/", *template)); err != nil || stat.IsDir() {
|
||||
log.Fatalf("%s is not a valid template file!", *template)
|
||||
}
|
||||
}
|
||||
|
||||
func showSummary() {
|
||||
absPath, err := filepath.Abs(strings.TrimSpace(*directory))
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to determine absolute path: %s", err)
|
||||
}
|
||||
fmt.Printf("Setting up package directory at %s with the following information:\n", absPath)
|
||||
fmt.Printf("Package name: %s\n", strings.TrimSpace(*name))
|
||||
fmt.Printf("Package description: %s\n", *description)
|
||||
fmt.Printf("Package version: %s\n", *version)
|
||||
if url != nil && *url != "" {
|
||||
fmt.Printf("Package URL: %s\n", *url)
|
||||
} else {
|
||||
fmt.Printf("Package URL: Not Set\n")
|
||||
}
|
||||
if license != nil && *license != "" {
|
||||
fmt.Printf("Package license: %s\n", *license)
|
||||
} else {
|
||||
fmt.Printf("Package license: Not Set\n")
|
||||
}
|
||||
fmt.Printf("Template file: %s\n", *template)
|
||||
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)
|
||||
*name = strings.TrimSpace(*name)
|
||||
|
||||
// Create directory
|
||||
err := os.Mkdir(*directory, 0755)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not create directory: %s", err)
|
||||
}
|
||||
|
||||
// Create package info struct
|
||||
pkgInfo := bpmutilsshared.PackageInfo{
|
||||
Name: *name,
|
||||
Description: *description,
|
||||
Version: *version,
|
||||
Url: *url,
|
||||
License: *license,
|
||||
Arch: "any",
|
||||
Type: "source",
|
||||
Downloads: []bpmutilsshared.PackageDownload{
|
||||
{
|
||||
Url: "https://wwww.my-url.com/file.tar.gz",
|
||||
ExtractTo: "${BPM_SOURCE}",
|
||||
ExtractStripComponents: 1,
|
||||
Checksum: "replaceme",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var buffer bytes.Buffer
|
||||
encoder := yaml.NewEncoder(&buffer)
|
||||
encoder.SetIndent(2)
|
||||
encoder.Encode(&pkgInfo)
|
||||
|
||||
// Write package info to file
|
||||
err = os.WriteFile(path.Join(*directory, "pkg.info"), buffer.Bytes(), 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not write to pkg.info: %s", err)
|
||||
}
|
||||
|
||||
// Create source-files directory
|
||||
err = os.Mkdir(path.Join(*directory, "source-files"), 0755)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not create directory: %s", err)
|
||||
}
|
||||
|
||||
// Copy source template file
|
||||
input, err := os.ReadFile(path.Join("/etc/bpm-utils/templates", *template))
|
||||
if err != nil {
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
||||
// Create git repository
|
||||
if git != nil && *git {
|
||||
err = exec.Command("git", "init", *directory).Run()
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not initialize git repository: %s", err)
|
||||
}
|
||||
|
||||
// Copy default gitignore
|
||||
defaultGitignoreFile, err := os.Open("/etc/bpm-utils/gitignore.default")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer defaultGitignoreFile.Close()
|
||||
newGitignoreFile, err := os.OpenFile(path.Join(*directory, ".gitignore"), os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not create .gitignore file: %s", err)
|
||||
}
|
||||
|
||||
_, err = io.Copy(newGitignoreFile, defaultGitignoreFile)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not copy data to .gitignore file: %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()
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package bpm_utils_shared
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type BPMDatabase struct {
|
||||
DatabaseVersion int `yaml:"database_version"`
|
||||
Entries map[string]BPMDatabaseEntry `yaml:"entries"`
|
||||
}
|
||||
|
||||
type BPMDatabaseEntry struct {
|
||||
PackageInfo *PackageInfo `yaml:"info"`
|
||||
Filepath string `yaml:"filepath"`
|
||||
DownloadSize int64 `yaml:"download_size"`
|
||||
InstalledSize int64 `yaml:"installed_size"`
|
||||
}
|
||||
|
||||
func ReadDatabase(path string) (*BPMDatabase, error) {
|
||||
// Read database file
|
||||
output, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
database := &BPMDatabase{}
|
||||
|
||||
// Unmarshal yaml
|
||||
err = yaml.Unmarshal(output, &database)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return database, nil
|
||||
}
|
||||
|
||||
func GenerateDatabase(path string) error {
|
||||
database := BPMDatabase{
|
||||
DatabaseVersion: 2,
|
||||
Entries: make(map[string]BPMDatabaseEntry),
|
||||
}
|
||||
|
||||
err := filepath.Walk(path, func(packagePath string, info fs.FileInfo, err error) error {
|
||||
if !strings.HasSuffix(packagePath, ".bpm") {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Initialize database entry
|
||||
entry := BPMDatabaseEntry{}
|
||||
entry.DownloadSize = info.Size()
|
||||
entry.Filepath, err = filepath.Rel(path, packagePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get package installed size
|
||||
cmd := exec.Command("tar", "-t", "-v", "-f", packagePath, "files.tar.gz")
|
||||
output, err := cmd.Output()
|
||||
if err == nil {
|
||||
entry.InstalledSize, err = strconv.ParseInt(strings.Fields(string(output))[2], 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err.(*exec.ExitError).ExitCode() == 2 {
|
||||
entry.InstalledSize = 0
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get package info
|
||||
entry.PackageInfo, err = ReadPacakgeInfoFromTarball(packagePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Add entry to database
|
||||
if _, ok := database.Entries[entry.PackageInfo.Name]; ok {
|
||||
return fmt.Errorf("package (%s) has already been added to the database", entry.PackageInfo.Name)
|
||||
}
|
||||
database.Entries[entry.PackageInfo.Name] = entry
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := yaml.Marshal(&database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.WriteFile(filepath.Join(path, "database.bpmdb"), data, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateDatabases(repo string) {
|
||||
if _, err := os.Stat(path.Join(repo, "source")); err == nil {
|
||||
err = GenerateDatabase(path.Join(repo, "source"))
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not generate source directory database: %s", err)
|
||||
}
|
||||
fmt.Println("Source directory database was generated successfully!")
|
||||
}
|
||||
|
||||
if _, err := os.Stat(path.Join(repo, "binary")); err == nil {
|
||||
err = GenerateDatabase(path.Join(repo, "binary"))
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not generate binary directory database: %s", err)
|
||||
}
|
||||
fmt.Println("Binary directory database was generated successfully!")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
module bpm-utils-shared
|
||||
|
||||
go 1.23
|
||||
|
||||
require gopkg.in/yaml.v3 v3.0.1
|
||||
|
||||
require github.com/drone/envsubst v1.0.3
|
||||
@@ -0,0 +1,8 @@
|
||||
github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
|
||||
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
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=
|
||||
@@ -0,0 +1,26 @@
|
||||
package bpm_utils_shared
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package bpm_utils_shared
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/drone/envsubst"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type PackageInfo struct {
|
||||
Name string `yaml:"name"`
|
||||
Description string `yaml:"description,omitempty"`
|
||||
Version string `yaml:"version,omitempty"`
|
||||
Revision int `yaml:"revision,omitempty"`
|
||||
Url string `yaml:"url,omitempty"`
|
||||
License string `yaml:"license,omitempty"`
|
||||
Arch string `yaml:"architecture,omitempty"`
|
||||
OutputArch string `yaml:"output_architecture,omitempty"`
|
||||
Type string `yaml:"type,omitempty"`
|
||||
Keep []string `yaml:"keep,omitempty"`
|
||||
Depends []string `yaml:"depends,omitempty"`
|
||||
OptionalDepends []string `yaml:"optional_depends,omitempty"`
|
||||
MakeDepends []string `yaml:"make_depends,omitempty"`
|
||||
Conflicts []string `yaml:"conflicts,omitempty"`
|
||||
Replaces []string `yaml:"replaces,omitempty"`
|
||||
Provides []string `yaml:"provides,omitempty"`
|
||||
Downloads []PackageDownload `yaml:"downloads,omitempty"`
|
||||
SplitPackages []*PackageInfo `yaml:"split_packages,omitempty"`
|
||||
}
|
||||
|
||||
type PackageDownload struct {
|
||||
Url string `yaml:"url"`
|
||||
Type string `yaml:"type,omitempty"`
|
||||
Filepath string `yaml:"filepath,omitempty,omitempty"`
|
||||
|
||||
// Archive options
|
||||
NoExtract bool `yaml:"no_extract,omitempty"`
|
||||
ExtractTo string `yaml:"extract_to,omitempty"`
|
||||
ExtractStripComponents int `yaml:"extract_strip_components,omitempty"`
|
||||
|
||||
// Git options
|
||||
CloneTo string `yaml:"clone_to,omitempty"`
|
||||
GitBranch string `yaml:"git_branch,omitempty"`
|
||||
|
||||
Checksum string `yaml:"checksum,omitempty"`
|
||||
}
|
||||
|
||||
func ReadPackageInfo(data []byte) (*PackageInfo, error) {
|
||||
pkgInfo := &PackageInfo{
|
||||
Revision: 1,
|
||||
Keep: make([]string, 0),
|
||||
Depends: make([]string, 0),
|
||||
MakeDepends: make([]string, 0),
|
||||
OptionalDepends: make([]string, 0),
|
||||
Conflicts: make([]string, 0),
|
||||
Replaces: make([]string, 0),
|
||||
Provides: make([]string, 0),
|
||||
Downloads: make([]PackageDownload, 0),
|
||||
SplitPackages: make([]*PackageInfo, 0),
|
||||
}
|
||||
|
||||
// Unmarshal yaml
|
||||
err := yaml.Unmarshal(data, pkgInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pkgInfo, nil
|
||||
}
|
||||
|
||||
func ReadPacakgeInfoFromTarball(path string) (*PackageInfo, error) {
|
||||
// Extract package info using tar
|
||||
cmd := exec.Command("tar", "-x", "-f", path, "pkg.info", "-O")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkgInfo, err := ReadPackageInfo(output)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pkgInfo, nil
|
||||
}
|
||||
|
||||
func ReadPacakgeInfoFromFile(path string) (*PackageInfo, error) {
|
||||
// Read data from file
|
||||
output, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkgInfo, err := ReadPackageInfo(output)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pkgInfo, nil
|
||||
}
|
||||
|
||||
func (pkgDownload *PackageDownload) CalculateChecksum(pkgInfo *PackageInfo) (string, error) {
|
||||
switch pkgDownload.Type {
|
||||
case "", "file":
|
||||
fmt.Println("Downloading and calculating checksum for file...")
|
||||
|
||||
// Replace variables in download url
|
||||
downloadUrl := pkgDownload.Url
|
||||
downloadUrl, err := envsubst.Eval(downloadUrl, func(s string) string {
|
||||
switch s {
|
||||
case "BPM_PKG_VERSION":
|
||||
return pkgInfo.Version
|
||||
case "BPM_PKG_NAME":
|
||||
return pkgInfo.Name
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cmd := exec.Command("sh", "-c", fmt.Sprintf("curl -s -L %s | sha256sum | awk '{print $1}'", downloadUrl))
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
checksum, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return strings.TrimSpace(string(checksum)), err
|
||||
case "git":
|
||||
fmt.Println("Calculating checksum for git branch...")
|
||||
|
||||
// Replace variables in git branch
|
||||
gitBranch := pkgDownload.GitBranch
|
||||
gitBranch, err := envsubst.Eval(gitBranch, func(s string) string {
|
||||
switch s {
|
||||
case "BPM_PKG_VERSION":
|
||||
return pkgInfo.Version
|
||||
case "BPM_PKG_NAME":
|
||||
return pkgInfo.Name
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if pkgDownload.GitBranch == "" {
|
||||
return "", fmt.Errorf("'git_branch' field cannot be empty")
|
||||
}
|
||||
|
||||
cmd := exec.Command("sh", "-c", fmt.Sprintf("git ls-remote -bt %s | grep -E 'refs/.*/%s(\\^\\{\\})?$' | tail -n1 | awk '{print $1}'", pkgDownload.Url, gitBranch))
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
checksum, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return strings.TrimSpace(string(checksum)), err
|
||||
default:
|
||||
return "", fmt.Errorf("unknown download type (%s)", pkgDownload.Type)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package bpm_utils_shared
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
func GetRepository() string {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
for dir != "/" {
|
||||
if _, err := os.Stat(path.Join(dir, "bpm-repo.conf")); err == nil {
|
||||
return dir
|
||||
}
|
||||
dir = path.Dir(dir)
|
||||
}
|
||||
|
||||
if dir == "/" {
|
||||
return ""
|
||||
}
|
||||
return dir
|
||||
}
|
||||
Reference in New Issue
Block a user