From aa5fbb82d62cc62191246826a7fc4ded6bdb9061 Mon Sep 17 00:00:00 2001 From: ngn Date: Sun, 11 Aug 2024 17:45:54 +0300 Subject: [PATCH] new: mtsc-common, mp-build and mp-pool --- Makefile | 15 +- README.md | 13 +- matter-base/Makefile | 9 + matter-base/README.md | 2 +- matter-base/main.sh | 115 ++++---- matter-chroot/Makefile | 9 + matter-chroot/main.sh | 91 ++++--- matter-iso/Makefile | 9 + matter-iso/README.md | 2 +- matter-iso/main.sh | 138 ++++------ matter-mirror/.gitignore | 1 - matter-mirror/README.md | 14 - matter-mirror/main.py | 262 ------------------ mp-build/Makefile | 16 ++ mp-build/README.md | 26 ++ mp-build/scripts/mp-build.sh | 452 +++++++++++++++++++++++++++++++ mp-build/scripts/mp-migrate.sh | 94 +++++++ mp-build/scripts/mp-new.sh | 108 ++++++++ mp-build/scripts/mp-wrap.sh | 56 ++++ mp-pool/Makefile | 16 ++ mp-pool/README.md | 12 + mp-pool/scripts/mp-pool-clean.sh | 126 +++++++++ mp-pool/scripts/mp-pool.sh | 293 ++++++++++++++++++++ mtsc-common/Makefile | 9 + mtsc-common/README.md | 3 + mtsc-common/common.sh | 206 ++++++++++++++ 26 files changed, 1619 insertions(+), 478 deletions(-) create mode 100644 matter-base/Makefile mode change 100644 => 100755 matter-base/main.sh create mode 100644 matter-chroot/Makefile mode change 100644 => 100755 matter-chroot/main.sh create mode 100644 matter-iso/Makefile delete mode 100644 matter-mirror/.gitignore delete mode 100644 matter-mirror/README.md delete mode 100644 matter-mirror/main.py create mode 100644 mp-build/Makefile create mode 100644 mp-build/README.md create mode 100755 mp-build/scripts/mp-build.sh create mode 100755 mp-build/scripts/mp-migrate.sh create mode 100755 mp-build/scripts/mp-new.sh create mode 100755 mp-build/scripts/mp-wrap.sh create mode 100644 mp-pool/Makefile create mode 100644 mp-pool/README.md create mode 100755 mp-pool/scripts/mp-pool-clean.sh create mode 100755 mp-pool/scripts/mp-pool.sh create mode 100644 mtsc-common/Makefile create mode 100644 mtsc-common/README.md create mode 100755 mtsc-common/common.sh diff --git a/Makefile b/Makefile index dd42319..e0cf900 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,14 @@ +SUBDIRS := $(wildcard */.) prefix = /usr install: - install -v -m755 matter-mirror/main.py $(DESTDIR)$(prefix)/bin/matter-mirror - install -v -m755 matter-chroot/main.sh $(DESTDIR)$(prefix)/bin/matter-chroot - install -v -m755 matter-base/main.sh $(DESTDIR)$(prefix)/bin/matter-base - install -v -m755 matter-iso/main.sh $(DESTDIR)$(prefix)/bin/matter-iso + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C "$$dir" install ; \ + done uninstall: - rm -v $(DESTDIR)$(prefix)/bin/matter-mirror - rm -v $(DESTDIR)$(prefix)/bin/matter-chroot - rm -v $(DESTDIR)$(prefix)/bin/matter-base - rm -v $(DESTDIR)$(prefix)/bin/matter-iso + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C "$$dir" uninstall ; \ + done .PHONY: install uninstall diff --git a/README.md b/README.md index 480f92e..ab7fe90 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ -# tools | Matterlinux Tools and Scripts Collection -This repository contains different tools and scripts -for general matterlinux installation and configuration. +# mtsc | MatterLinux tools and scripts collection +This repository contains different tools and scripts +for general MatterLinux installation, configuration and +build process. ### Installation All the tools and scripts can be copied to PATH with @@ -8,10 +9,14 @@ the make script: ``` make install ``` +You can also install the mtsc package from the base package +pool. ### Usage All tools/scripts contains usage information in README files: +- [mtsc-common](mtsc-common/README.md) - [matter-chroot](matter-chroot/README.md) -- [matter-mirror](matter-mirror/README.md) - [matter-base](matter-base/README.md) - [matter-iso](matter-iso/README.md) +- [mp-build](mp-build/README.md) +- [mp-pool](mp-pool/README.md) diff --git a/matter-base/Makefile b/matter-base/Makefile new file mode 100644 index 0000000..197bf65 --- /dev/null +++ b/matter-base/Makefile @@ -0,0 +1,9 @@ +PREFIX = /usr + +install: + install -m755 "main.sh" $(DESTDIR)/$(PREFIX)/bin/matter-base + +uninstall: + rm $(DESTDIR)/$(PREFIX)/lib/matter-base + +.PHONY: install uninstall diff --git a/matter-base/README.md b/matter-base/README.md index c19c265..b9c88cb 100644 --- a/matter-base/README.md +++ b/matter-base/README.md @@ -3,7 +3,7 @@ This script is used for building release archives. ### Usage Note that you will need to install and configure -[`mp`](https://git.matterlinux.xyz/matterlinux/mp) before using +[`matt`](https://git.matterlinux.xyz/matterlinux/matt) before using `matter-base`. To use the `matter-base` script, specify a temporary target diff --git a/matter-base/main.sh b/matter-base/main.sh old mode 100644 new mode 100755 index 4eae73f..b1b7240 --- a/matter-base/main.sh +++ b/matter-base/main.sh @@ -1,6 +1,6 @@ #!/bin/bash -# matter-base | Matterlinux Release Archive Build Script +# matter-base | MatterLinux release archive build script # MatterLinux 2023-2024 (https://matterlinux.xyz) # This program is free software: you can redistribute it and/or modify @@ -16,66 +16,54 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -############################ -## logging functions/vars ## -############################ -BOLD="\e[1m" -RESET="\e[0m" -GREEN="\e[32m" -BLUE="\e[34m" -GRAY="\e[37m" -RED="\e[31m" +############################# +## import common functions ## +############################# +location="$(dirname "${0}")" +location="$(realpath "${location}")" +commonsh="$(echo "${location}" | sed 's/\/bin/\/lib/g')/mtsc-common.sh" -success() { - echo -e "$BOLD$GREEN>>>$RESET$BOLD $1$RESET" -} +source "${commonsh}" -info() { - echo -e "$BOLD$BLUE>>>$RESET$BOLD $1$RESET" -} - -error() { - echo -e "$BOLD$RED>>>$RESET$BOLD $1$RESET" +if [ "${?}" != "0" ]; then + echo "Failed to import mtsc-common" exit 1 -} - -#################### -## util functions ## -#################### -check_ret() { - if [ $? -ne 0 ]; then - error "$1" - fi -} +fi ################# ## main script ## ################# if [ "$EUID" -ne 0 ]; then error "You should run this script as root" + exit 1 fi if [ $# -eq 0 ]; then error "Please specify a name for the archive" + exit 1 fi -NAME="$1" -TARGET="$(realpath $1)" -if [ -d $TARGET ]; then +name="${1}" +target="$(realpath "${1}")" + +if [ -d "${target}" ]; then error "A directory with the specified archive name exists" + exit 1 fi -mkdir $TARGET +mkdir "${target}" -if ! type mp > /dev/null; then - error "mp is not installed, please install and configure mp" +if ! type matt > /dev/null; then + error "matt is not installed, please install and configure matt" + exit 1 fi info "Creating directory structure" -pushd $TARGET > /dev/null - mkdir -p {dev,proc,sys,run,tmp,root,home,boot,mnt} - mkdir -p var/{log,mail,lib} - mkdir -p usr/{bin,lib,sbin} - mkdir -p etc/mp +pushd "${target}" > /dev/null + install -Ddm755 {dev,proc,sys,run,tmp,root,home,boot,mnt} + install -Ddm755 var/{log,mail,lib} + install -Ddm755 usr/{bin,lib,sbin} + install -Ddm755 var/lib/matt + install -Ddm755 etc/matt ln -sf usr/lib lib ln -sf usr/lib lib64 @@ -126,25 +114,24 @@ EOF EOF popd > /dev/null -export MP_ROOT="$TARGET" MP_YES=1 - info "Syncing repositories" - mp-sync - check_ret "mp-sync command failed" +info "Syncing repositories" +matt sync --root "${target}" --yes +check_ret "matt command failed" - info "Installing base system packages" - mp-install acl attr coreutils binutils \ - bash e2fsprogs udev file release \ - findutils gawk grep gzip iana-etc \ - inetutils intltool iproute kmod less \ - openssl sed shadow tar tcl mandb \ - man-pages tzdata util-linux which \ - mp gettext iproute procps psmisc \ - mandb kbd dbus vim nano libxml2 - check_ret "mp-install command failed" -unset MP_ROOT MP_YES +info "Installing base system packages" +matt install --root "${target}" --yes \ + acl attr coreutils binutils \ + bash e2fsprogs udev file release \ + findutils gawk grep gzip iana-etc \ + inetutils intltool iproute kmod less \ + openssl sed shadow tar tcl mandb \ + man-pages tzdata util-linux which \ + matt gettext iproute procps psmisc \ + mandb kbd dbus vim nano libxml2 +check_ret "matt command failed" success "Installed the base system" -cat > $TARGET/etc/inputrc << "EOF" +cat > "${target}/etc/inputrc" << "EOF" # do not bell on tab-completion #set bell-style none @@ -183,24 +170,24 @@ $if mode=emacs $endif EOF -cat > $TARGET/etc/shells << "EOF" +cat > "${target}/etc/shells" << "EOF" /bin/sh /bin/bash EOF -cp "$TARGET/etc/skel/."* "$TARGET/root" +cp "${target}/etc/skel/."* "${target}/root" info "Installing certs" -wget -q https://hg.mozilla.org/projects/nss/raw-file/tip/lib/ckfw/builtins/certdata.txt -O "$TARGET/certdata.txt" -matter-chroot $TARGET make-ca > /dev/null +wget --show-progress -q https://hg.mozilla.org/projects/nss/raw-file/tip/lib/ckfw/builtins/certdata.txt -O "${target}/certdata.txt" +matter-chroot "${target}" make-ca > /dev/null check_ret "Failed to run make-ca, install certs manually" -rm -f "$TARGET/certdata.txt" +rm -f "${target}/certdata.txt" info "Setup complete, now creating the archive..." -pushd $TARGET > /dev/null - tar czf ../${NAME}.tar.gz * +pushd "${target}" > /dev/null + tar czf ../${name}.tar.gz * check_ret "Failed to create the archive" popd > /dev/null success "Archive created, now cleaning up" -rm -rf $TARGET && success "Build completed" +rm -rf "${target}" && success "Build completed" diff --git a/matter-chroot/Makefile b/matter-chroot/Makefile new file mode 100644 index 0000000..59d1ab5 --- /dev/null +++ b/matter-chroot/Makefile @@ -0,0 +1,9 @@ +PREFIX = /usr + +install: + install -m755 "main.sh" $(DESTDIR)/$(PREFIX)/bin/matter-chroot + +uninstall: + rm $(DESTDIR)/$(PREFIX)/lib/matter-chroot + +.PHONY: install uninstall diff --git a/matter-chroot/main.sh b/matter-chroot/main.sh old mode 100644 new mode 100755 index 70b2901..754c619 --- a/matter-chroot/main.sh +++ b/matter-chroot/main.sh @@ -1,6 +1,6 @@ #!/bin/bash -# matter-chroot | Matterlinux Chroot Script +# matter-chroot | MatterLinux chroot script # MatterLinux 2023-2024 (https://matterlinux.xyz) # This program is free software: you can redistribute it and/or modify @@ -16,67 +16,71 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -############################ -## logging functions/vars ## -############################ -RED="\e[31m" -BOLD="\e[1m" -RESET="\e[0m" +############################# +## import common functions ## +############################# +location="$(dirname "${0}")" +location="$(realpath "${location}")" +commonsh="$(echo "${location}" | sed 's/\/bin/\/lib/g')/mtsc-common.sh" -error() { - echo -e "$BOLD$RED>>>$RESET$BOLD $1$RESET" +source "${commonsh}" + +if [ "${?}" != "0" ]; then + echo "Failed to import mtsc-common" exit 1 -} +fi #################### ## util functions ## #################### linkresolv(){ - if [ ! -f "$TARGET/etc/resolv.conf" ]; then - ln -sf /run/systemd/resolve/resolv.conf "$TARGET/etc/resolv.conf" + if [ ! -f "${target}/etc/resolv.conf" ]; then + ln -sf /run/systemd/resolve/resolv.conf "${target}/etc/resolv.conf" fi } chrt() { - mount -t proc proc "$TARGET/proc" - mount -t sysfs sysfs "$TARGET/sys" - if [[ -d "$TARGET/sys/firmware/efi/efivars" ]]; then - mount -t efivarfs efivarfs "$TARGET/sys/firmware/efi/efivars" + mount -t proc proc "${target}/proc" + mount -t sysfs sysfs "${target}/sys" + if [[ -d "${target}/sys/firmware/efi/efivars" ]]; then + mount -t efivarfs efivarfs "${target}/sys/firmware/efi/efivars" fi - mount -o bind /dev "$TARGET/dev" - mount -t devpts none "$TARGET/dev/pts" - mount --bind /run "$TARGET/run" + mount -o bind /dev "${target}/dev" + mount -t devpts none "${target}/dev/pts" + mount --bind /run "${target}/run" linkresolv - if [ -h $TARGET/dev/shm ]; then - mkdir -p $TARGET/$(readlink $TARGET/dev/shm) + if [ -h "${target}/dev/shm" ]; then + mkdir -p "${target}/$(readlink "${target}/dev/shm")" else - mount -t tmpfs -o nosuid,nodev tmpfs "$TARGET/dev/shm" + mount -t tmpfs -o nosuid,nodev tmpfs "${target}/dev/shm" fi local prompt='\['$BOLD'\['$RED'(chroot)\['$RESET'\['$BOLD' \u@\h:\w#\['$RESET' ' - chroot "$TARGET" /usr/bin/env -i \ - HOME=/root \ - TERM="$TERM" \ - PS1="$prompt" \ - PATH=/usr/bin:/usr/sbin \ + chroot "${target}" /usr/bin/env -i \ + HOME=/root \ + TERM="${TERM}" \ + PS1="${prompt}" \ + PATH=/usr/bin:/usr/sbin \ "$@" - RET_CODE=$? + local ret_code=$? # kill procs that may prevent umount killall -9 dirmngr 2> /dev/null killall -9 gpg-agent 2> /dev/null - umount "$TARGET/proc" - mountpoint -q "$TARGET/sys/firmware/efi/efivars" && umount "$TARGET/sys/firmware/efi/efivars" - umount "$TARGET/sys" + umount "${target}/proc" + mountpoint -q "${target}/sys/firmware/efi/efivars" && umount "${target}/sys/firmware/efi/efivars" + umount "${target}/sys" - umount "$TARGET/dev/pts" - mountpoint -q "$TARGET/dev/shm" && umount "$TARGET/dev/shm" - umount "$TARGET/dev" - umount "$TARGET/run" + umount "${target}/dev/pts" + mountpoint -q "${target}/dev/shm" && umount "${target}/dev/shm" + umount "${target}/dev" + umount "${target}/run" + + return $ret_code } ################# @@ -84,24 +88,29 @@ chrt() { ################# if [ "$EUID" -ne 0 ]; then error "Cannot chroot without root" + exit 1 fi if [ $# -eq 0 ]; then error "Please specify a directory" + exit 1 fi -TARGET=$(realpath $1) -if [ -f $TARGET ]; then - error "$TARGET is a file" +target="$(realpath "${1}")" + +if [ -f "${target}" ]; then + error "${target} is a file" + exit 1 fi -if [ ! -d $TARGET ]; then - error "$TARGET does not exist" +if [ ! -d "${target}" ]; then + error "${target} does not exist" + exit 1 fi if [ $# -gt 1 ]; then chrt ${@:2} - exit $RET_CODE + exit $? fi chrt bash --noprofile --login diff --git a/matter-iso/Makefile b/matter-iso/Makefile new file mode 100644 index 0000000..ae0aa6d --- /dev/null +++ b/matter-iso/Makefile @@ -0,0 +1,9 @@ +PREFIX = /usr + +install: + install -m755 "main.sh" $(DESTDIR)/$(PREFIX)/bin/matter-iso + +uninstall: + rm $(DESTDIR)/$(PREFIX)/lib/matter-iso + +.PHONY: install uninstall diff --git a/matter-iso/README.md b/matter-iso/README.md index f54ee37..a6f7fa0 100644 --- a/matter-iso/README.md +++ b/matter-iso/README.md @@ -8,4 +8,4 @@ a configuration directory: ``` matter-iso matterlinux_24.00.tar.gz isocfg ``` -To learn more about the configuration, see the [wiki page for releases](/wiki/release). +To learn more about the configuration, see the [wiki page for releases](/wiki/releases). diff --git a/matter-iso/main.sh b/matter-iso/main.sh index 4f25491..0114f6f 100755 --- a/matter-iso/main.sh +++ b/matter-iso/main.sh @@ -1,6 +1,6 @@ #!/bin/bash -# matter-iso | MatterLinux ISO Build Script +# matter-iso | MatterLinux ISO build script # MatterLinux 2023-2024 (https://matterlinux.xyz) # This program is free software: you can redistribute it and/or modify @@ -16,71 +16,35 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -############################ -## logging functions/vars ## -############################ -BOLD="\e[1m" -RESET="\e[0m" -GREEN="\e[32m" -BLUE="\e[34m" -GRAY="\e[37m" -RED="\e[31m" -LOG_PREFIX=">>>" +############################# +## import common functions ## +############################# +location="$(dirname "${0}")" +location="$(realpath "${location}")" +commonsh="$(echo "${location}" | sed 's/\/bin/\/lib/g')/mtsc-common.sh" -echo_color() { - echo -e "${1}" -} +source "${commonsh}" -success() { - echo_color "${BOLD}${GREEN}${LOG_PREFIX}${RESET}${BOLD} $1 ${RESET}" -} - -info() { - echo_color "${BOLD}${BLUE}${LOG_PREFIX}${RESET}${BOLD} $1 ${RESET}" -} - -error() { - echo_color "${BOLD}${RED}${LOG_PREFIX}${RESET}${BOLD} $1 ${RESET}" +if [ "${?}" != "0" ]; then + echo "Failed to import mtsc-common" exit 1 -} - -errorne() { - echo_color "${BOLD}${RED}${LOG_PREFIX}${RESET}${BOLD} $1 ${RESET}" -} - -print() { - echo_color "${BOLD}${GRAY}$1${RESET}" -} - -set_indent() { - LOG_PREFIX="|>" -} - -unset_indent() { - LOG_PREFIX=">>>" -} +fi #################### ## util functions ## #################### -check_ret() { - if [ $? -ne 0 ]; then - error "$1" - fi -} - check_retc() { if [ $? -ne 0 ]; then - errorne "$1" + error "${1}" clean_tmpdir exit 1 fi } clean_tmpdir(){ - if [ -d $TMPDIR ]; then + if [ -d "${tmpdir}" ]; then info "Cleaning up temp directory" - rm -rf $TMPDIR + rm -rf "${tmpdir}" fi } @@ -101,61 +65,71 @@ check_iso_vars() { ################# if [ "$EUID" -ne 0 ]; then error "You should run this script as root" + exit 1 fi if [ $# -ne 2 ]; then error "Please specify a release archive and a config directory" + exit 1 fi -ARCHIVE="$(realpath $1)" -if [ ! -f $ARCHIVE ]; then +archive="$(realpath "${1}")" + +if [ ! -f "${archive}" ]; then error "Archive file not found" + exit 1 fi -if [[ "$(file $ARCHIVE)" != *"gzip compressed data"* ]]; then +if [[ "$(file "${archive}")" != *"gzip compressed data"* ]]; then error "Bad archive format" + exit 1 fi -CONFDIR="$(realpath $2)" -if [ ! -d $CONFDIR ]; then +confdir="$(realpath "${2}")" + +if [ ! -d "${confdir}" ]; then error "Config directory not found" + exit 1 fi -TMPDIR="${CONFDIR}_tmp" -DISTDIR="${CONFDIR}/dist" -ROOTDIR="${DISTDIR}/root" -ISOSH="${TMPDIR}/iso.sh" +tmpdir="${confdir}_tmp" +distdir="${confdir}/dist" +rootdir="${distdir}/root" +isoh="${tmpdir}/iso.sh" -mkdir -p $ROOTDIR +mkdir -p "${rootdir}" success "Created root and dist directory" info "Copying over the config directory" -cp -r $CONFDIR $TMPDIR +cp -r "${confdir}" "${tmpdir}" check_ret "Copy failed" -if [ ! -f $ISOSH ]; then +if [ ! -f "${isoh}" ]; then error "ISO script not found" + exit 1 fi -source $ISOSH +source "${isoh}" check_retc "Cannot source the ISO script" + check_iso_vars check_retc "ISO script is not valid" success "Sourced the ISO script" info "Removing excluded files" -rm -rf "$TMPDIR/dist" +rm -rf "${tmpdir}/dist" set_indent for e in "${EXCLUDE[@]}"; do - info "Removing $e" - rm -rf "$TMPDIR/$e" + info "Removing ${e}" + rm -rf "${tmpdir}/${e}" done - rm -rf "$TMPDIR/.git" + rm -rf "${tmpdir}/.git" unset_indent info "Extracting release archive" SECONDS=0 -tar --skip-old-files -xf "$ARCHIVE" -C "$TMPDIR" + +tar --skip-old-files -xf "${archive}" -C "${tmpdir}" check_retc "Extract failed" success "Extracted in ${SECONDS}s" @@ -184,45 +158,45 @@ for p2 in "${PKGS2[@]}"; do done info "Adding public keys" -matter-chroot "$TMPDIR" gpg --receive-keys $keys_str +matter-chroot "${tmpdir}" gpg --receive-keys $keys_str check_retc "Failed to add public keys" if [ ! -z "${PKGS1}" ]; then info "Installing extra packages (1)" - matter-chroot "$TMPDIR" mp-sync + matter-chroot "${tmpdir}" matt sync check_retc "Sync failed" - matter-chroot "$TMPDIR" MP_YES=1 mp-install $pkgs1_str + matter-chroot "${tmpdir}" matt install --yes $pkgs1_str check_retc "Install failed" fi info "Running build script" -echo "source /iso.sh && build" > "$TMPDIR/stager.sh" -matter-chroot "$TMPDIR" chmod +x /stager.sh -matter-chroot "$TMPDIR" /stager.sh +echo "source /iso.sh && build" > "${tmpdir}/stager.sh" +matter-chroot "${tmpdir}" chmod +x /stager.sh +matter-chroot "${tmpdir}" /stager.sh check_ret "Build script failed" -rm "$TMPDIR/stager.sh" +rm "${tmpdir}/stager.sh" info "Cleaning up and building initrd" -rm "$ISOSH" +rm "${isoh}" pushd "$TMPDIR" > /dev/null - mkdir -p "$ROOTDIR/boot" - find . | cpio --quiet -H newc -o | xz -T0 --check=crc32 > "$ROOTDIR/boot/initrd.img" + mkdir -p "${rootdir}/boot" + find . | cpio --quiet -H newc -o | xz -T0 --check=crc32 > "${rootdir}/boot/initrd.img" check_ret "Failed to build initrd" popd > /dev/null if [ ! -z "${PKGS2}" ]; then info "Installing extra packages (2)" - matter-chroot "$TMPDIR" MP_YES=1 mp-install $pkgs2_str + matter-chroot "${tmpdir}" MP_YES=1 matt install --yes $pkgs2_str check_ret "Install failed" fi info "Copying over the bootdir" -cp -r "$TMPDIR/boot"/* "$ROOTDIR/boot" +cp -r "${tmpdir}/boot"/* "${rootdir}/boot" info "Building the ISO..." -pushd "$DISTDIR" > /dev/null - grub-mkrescue -o "$DISTDIR/${NAME}_${VERSION}.iso" root +pushd "${distdir}" > /dev/null + grub-mkrescue -o "${distdir}/${NAME}_${VERSION}.iso" root check_retc "grub-mkrescue failed" popd > /dev/null diff --git a/matter-mirror/.gitignore b/matter-mirror/.gitignore deleted file mode 100644 index 65e3ba2..0000000 --- a/matter-mirror/.gitignore +++ /dev/null @@ -1 +0,0 @@ -test/ diff --git a/matter-mirror/README.md b/matter-mirror/README.md deleted file mode 100644 index c4919a8..0000000 --- a/matter-mirror/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# matter-mirror -A simple python script to create and manage MatterLinux mirrors. -**Does not support FTP!** - -### Usage -To use the `matter-mirror` script, pass in a URL and a download (output) -directory. For example: -```bash -mkdir base -matter-mirror -u https://pkgs.matterlinux.xyz/base -o base -``` -This will download the repo at `https://pkgs.matterlinux.xyz/base` to the -`base` directory. Running it again, script will only download outdated or -new packages. diff --git a/matter-mirror/main.py b/matter-mirror/main.py deleted file mode 100644 index ac91f66..0000000 --- a/matter-mirror/main.py +++ /dev/null @@ -1,262 +0,0 @@ -#!/bin/python3 - -# matter-mirror | MatterLinux Repo Mirror Tool -# MatterLinux 2023-2024 (https://matterlinux.xyz) - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from os import path, chdir, listdir, remove -from typing import List -import requests as req -import logging as log -import configparser -import argparse -import tarfile -import hashlib - -class BadResponse(Exception): - def __init__(self, msg: str) -> None: - super().__init__(f"Bad response: {msg}") - -class Pkg: - def __init__(self, name: str, version: str, sum: str) -> None: - self.archive = f"{name}_{version}.mpf" - self.sig = f"{name}_{version}.mpf.sig" - - self.version = version - self.name = name - self.sum = sum - - def remove_old(self) -> None: - files = listdir(".") - for f in files: - if f.startswith(f"{self.name}_"): - remove(f) - -class Repo: - def __init__(self, uri: str, out: str) -> None: - self.pkgs: List[Pkg] = [] - self.author: str - self.name: str - self.pub: str - self.uri = uri - self.out = out - - def join_url(self, pth: str) -> str: - if self.uri.endswith("/") and not pth.startswith("/"): - return self.uri+pth - elif self.uri.endswith("/") and pth.startswith("/"): - return self.uri[:-1]+pth - elif not self.uri.endswith("/") and pth.startswith("/"): - return self.uri+pth - - return self.uri+"/"+pth - - def get_repo(self) -> None: - repourl = self.join_url("repo") - res = req.get(repourl) - - if res.status_code != 200: - raise BadResponse(f"{res.status_code} - {repourl}") - - cfg = configparser.ConfigParser() - cfg.read_string(res.content.decode("utf-8")) - - for k in cfg.keys(): - if k == "DEFAULT": - continue - self.name = k - - self.pub = cfg[self.name]["pub"] - self.author = cfg[self.name]["author"] - - f = open("repo", "wb") - f.write(res.content) - f.close() - - def process_pkgs(self, pkgs: str) -> None: - cfg = configparser.ConfigParser() - cfg.read_string(pkgs) - - for k in cfg.keys(): - try: - ver = cfg[k]["version"] - sum = cfg[k]["sum"] - except: - continue - self.pkgs.append(Pkg(k, ver, sum)) - - def check_pkg(self, pkg: Pkg) -> bool: - # true -> package is in the outdir and its up-to-date - # false -> its not ^ - if not path.exists(pkg.archive) or not path.exists(pkg.sig): - return False - - fhash = hashlib.sha256() - f = open(pkg.archive, "rb") - - while chunk := f.read(8192): - fhash.update(chunk) - - f.close() - if pkg.sum != fhash.hexdigest(): - return False - - return True - - def check_pkgs(self) -> None: - pkgcl = [] - for p in self.pkgs: - pkgcl.append(p) - - for p in self.pkgs: - if self.check_pkg(p): - pkgcl.remove(p) - - self.pkgs = pkgcl - - def get_pkglist(self) -> None: - arcname = f"{self.name}.tar.gz" - pkgsurl = self.join_url(arcname) - res = req.get(pkgsurl) - - if res.status_code != 200: - raise BadResponse(f"{res.status_code} - {pkgsurl}") - - f = open(arcname, "wb") - f.write(res.content) - f.close() - - t = tarfile.open(arcname) - for m in t.getmembers(): - if m.name != "pkgs": - continue - - f = t.extractfile(m) - if f == None: continue - self.process_pkgs(f.read().decode("utf-8")) - f.close() - t.close() - - def download_pkg(self, p: Pkg) -> bool: - p.remove_old() - - arcurl = self.join_url(p.archive) - sigurl = self.join_url(p.sig) - - arcres = req.get(arcurl) - sigres = req.get(sigurl) - - if arcres.status_code != 200: - raise BadResponse(f"{arcres.status_code} - {arcurl}") - - if sigres.status_code != 200: - raise BadResponse(f"{sigres.status_code} - {sigurl}") - - arcf = open(p.archive, "wb") - arcf.write(arcres.content) - arcf.close() - - sigf = open(p.sig, "wb") - sigf.write(sigres.content) - sigf.close() - - return True - -if __name__ == "__main__": - log.basicConfig( - format="[%(levelname)s] [%(asctime)s]: %(message)s", - datefmt="%H:%M:%S", - level=log.INFO - ) - - parser = argparse.ArgumentParser( - prog="matter-mirror", - description="Create and manage MatterLinux mirrors", - epilog="Part of matter-tools | https://git.matterlinux.xyz/matter/matter-tools") - - parser.add_argument("-u", help="Repo URI", required=True, dest="uri") - parser.add_argument("-o", help="Download directory", required=True, dest="out") - args = parser.parse_args() - - if not args.uri.startswith("http://") and not args.uri.startswith("https://"): - log.error(f"Bad URI: {args.uri}") - exit(1) - - if not path.exists(args.out): - log.error(f"Out directory not found: {args.out}") - exit(1) - - if not path.isdir(args.out): - log.error(f"Out directory is not a directory: {args.out}") - exit(1) - - try: - chdir(args.out) - except Exception as e: - log.error(f"Cannot change dir: {args.out}") - exit(1) - - try: - repo = Repo(args.uri, args.out) - repo.get_repo() - except Exception as e: - log.error(e) - exit(1) - - log.info(f"Got repo file => {repo.name}:{repo.author}:{repo.pub}") - log.info("Downloading package list") - - try: - repo.get_pkglist() - except Exception as e: - log.error(e) - exit(1) - - all = len(repo.pkgs) - if all == 0: - log.error("Got no valid packages!") - exit(1) - - log.info(f"Got total of {all} packages") - - try: - repo.check_pkgs() - except Exception as e: - log.error(e) - exit(1) - - old = len(repo.pkgs) - if old == 0: - log.info("All packages are up-to-date!") - exit() - - print(f" Up-to-date packages: {all-old} ({int(100*(all-old)/all)}%)") - print(f" New packages: {old} ({int(100*old/all)}%)") - - resc = 0 - for p in repo.pkgs: - try: - log.info(f"({repo.pkgs.index(p)+1}/{len(repo.pkgs)}) Downloading {p.name}") - try: - repo.download_pkg(p) - except KeyboardInterrupt: - log.error("Stopping downloads") - exit(1) - resc += 1 - except Exception as e: - log.error(f"Download failed: {e}") - continue - - log.info(f"Downloaded {resc} out of {old} packages ({int(100*resc/old)}%)") diff --git a/mp-build/Makefile b/mp-build/Makefile new file mode 100644 index 0000000..e83ec97 --- /dev/null +++ b/mp-build/Makefile @@ -0,0 +1,16 @@ +SCRIPTS = $(patsubst scripts/%.sh,%,$(wildcard scripts/*.sh)) +PREFIX = /usr + +install: + @for s in $(SCRIPTS) ; do \ + echo "installing script: $$s" ; \ + install -m755 "scripts/$$s.sh" $(DESTDIR)/$(PREFIX)/bin/$$s ; \ + done + +uninstall: + @for s in $(SCRIPTS) ; do \ + echo "removing script: $$s" ; \ + rm $(DESTDIR)/$(PREFIX)/bin/$$s ; \ + done + +.PHONY: install uninstall diff --git a/mp-build/README.md b/mp-build/README.md new file mode 100644 index 0000000..b896f8a --- /dev/null +++ b/mp-build/README.md @@ -0,0 +1,26 @@ +# mp-build | MatterLinux package build scripts +The package build scripts for MatterLinux package system. These scripts +are used for building and creating packages. + +### Usage +To create an package source directory, you can use the `mp-new` +script: +```bash +mp-new _ +``` +This will create all the required source files, all templated +according to the package name and the version you specify. + +After editing the source files, you can build the package by +using the `mp-build` script: +```bash +mp-build /path/to/package +``` +When the build is completed, the package archive will be created +inside the `/path/to/package/dist` directory. + +You can also specify different build options, to list these +options you can run: +```bash +mp-build --help +``` diff --git a/mp-build/scripts/mp-build.sh b/mp-build/scripts/mp-build.sh new file mode 100755 index 0000000..de85c68 --- /dev/null +++ b/mp-build/scripts/mp-build.sh @@ -0,0 +1,452 @@ +#!/bin/bash + +# mp-build | MatterLinux package build script +# MatterLinux 2023-2024 (https://matterlinux.xyz) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +############################# +## import common functions ## +############################# +location="$(dirname "${0}")" +location="$(realpath "${location}")" +commonsh="$(echo "${location}" | sed 's/\/bin/\/lib/g')/mtsc-common.sh" + +source "${commonsh}" + +if [ "${?}" != "0" ]; then + echo "Failed to import mtsc-common" + exit 1 +fi + +#################### +## util functions ## +#################### +# extracts the filename from an URL +get_fn_url() { + file=$(echo "${1}" | rev | cut -d "/" -f -1 | rev) +} + +# download/copy file, used for obtaning $FILES +get_file() { + if [[ "${1}" == "https://"* || "${1}" == "http://"* || "${1}" == "ftp://"* ]] + then + curl "${1}" --progress-bar -OL + return $? + elif [ -f "${pkgpath}/${1}" ]; then + cp "${pkgpath}/${1}" . + return $? + else + return 1 + fi +} + +# length based hash check function +check_hash() { + if [[ "$2" == "NOHASH" ]]; then + info "Using NOHASH for $1" + return 0 + fi + + local len=${#2} + if [[ $len == 128 ]]; then + local hsh=$(sha512sum "$1" | cut -d " " -f 1) + elif [[ $len == 64 ]]; then + local hsh=$(sha256sum "$1" | cut -d " " -f 1) + elif [[ $len == 64 ]]; then + local hsh=$(sha256sum "$1" | cut -d " " -f 1) + elif [[ $len == 40 ]]; then + local hsh=$(sha1sum "$1" | cut -d " " -f 1) + elif [[ $len == 32 ]]; then + local hsh=$(md5sum "$1" | cut -d " " -f 1) + fi + + if [[ "$hsh" == "$2" ]]; then + success "Hash matches for $1" + return 0 + else + error "Bad hash for $1" + return 1 + fi +} + +# prints the help info +help_cmd() { + info "MatterLinux package build script" + info "Usage: ${0} [package directory]" + info "Options:" + echo_color " $BOLD--no-depend$RESET: don't check depends" + echo_color " $BOLD--no-stdout$RESET: disable stdout for PACKAGE() function" + echo_color " $BOLD--no-cache$RESET: don't check cache" + echo_color " $BOLD--no-opts$RESET: don't show/list options" + echo_color " $BOLD--cores$RESET: how many cores to use for the build" + echo + info "Licensed under GPLv3, see for more information" +} + +# clean the this directory +clean_dist() { + rm -f "${distpath}/DATA" + rm -f "${distpath}/CHANGES" + rm -f "${distpath}/INSTALL" + rm -f "${distpath}/HASHES" + rm -f "${distpath}/files.tar.gz" +} + +# checks/installs a list of depends +check_depends() { + local list=("$@") + + if [ "${#list[@]}" == "0" ]; then + info "Got zero depends, skipping depend check" + return 0 + fi + + if [ "$EUID" -ne 0 ]; then + if type doas > /dev/null; then + DOAS="doas" + elif type sudo > /dev/null; then + DOAS="sudo" + else + error "Failed to find doas or sudo, skipping depend check" + return 0 + fi + fi + + for dep in "${list[@]}"; do + if [ -z "${depends_str}" ]; then + depends_str="${dep}" + else + depends_str="${depends_str} ${dep}" + fi + done + + depends_uniq=$(echo "${depends_str}" | tr ' ' '\n' | sort | uniq) + depends_count=$(echo "${depends_uniq}" | wc -l) + depends_uniq=$(echo "${depends_uniq}" | tr '\n' ' ') + + info "Installing ${depends_count} depends" + $DOAS matt install --yes $depends_uniq + return $? +} + +################# +## main script ## +################# +OPT_NO_DEPEND=0 # checking depends is ENABLED +OPT_NO_STDOUT=0 # PACKAGE() function output is ENABLED +OPT_NO_CACHE=0 # cache is ENABLED +OPT_NO_OPTS=0 # showing/listing options is ENABLED +OPT_CORES=$(nproc) # use ALL CPU cores + +# parses all the options +for arg in "$@"; do + case $arg in + "--help") + help_cmd + exit 0 + ;; + "--no-depend") + OPT_NO_DEPEND=1 ;; + "--no-stdout") + OPT_NO_STDOUT=1 ;; + "--no-cache") + OPT_NO_CACHE=1 ;; + "--no-opts") + OPT_NO_OPTS=1 ;; + "--cores"*) + OPT_CORES=$(echo "${arg}" | cut -d "=" -f2) ;; + --*) + error "Unknown option: ${arg}" + exit 1 ;; + *) + if [ -z "${TARGET}" ]; then + TARGET="${arg}" + else + error "Unknown argument: ${arg}" + exit 1 + fi + ;; + esac +done + +if [ -z "${TARGET}" ]; then + error "Package directory is not specified, run with \"--help\" for more information" + exit 1 +fi + +if [ ! -d "${TARGET}" ]; then + error "Package directory \"${TARGET}\" does not exist" + exit 1 +fi + +if [ $OPT_NO_DEPEND -eq 0 ] && ! command -v matt &> /dev/null; then + error "!!! BUILD ON MATTERLINUX !!!" + error "matt is not installed, please build on a MatterLinux system" + error "Do NOT create bug reports if build fails on non-MatterLinux systems" + info "Auto enabling NO_DEPEND as depend check will fail without matt" + OPT_NO_DEPEND=1 +fi + +# print the options +if [ $OPT_NO_OPTS -eq 0 ]; then + info "Running mp-build with the options:" + print " $BOLD NO_DEPEND = $(itoyn $OPT_NO_DEPEND)" + print " $BOLD NO_SDTOUT = $(itoyn $OPT_NO_STDOUT)" + print " $BOLD NO_CACHE = $(itoyn $OPT_NO_CACHE)" + print " $BOLD NO_OPTS = $(itoyn $OPT_NO_OPTS)" + print " $BOLD CORES = $OPT_CORES" +fi + +cd "${TARGET}" +check_ret "Failed to change directory into \"${TARGET}\"" + +if [ ! -f "pkg.sh" ]; then + error "Package directory does not contain a package script (pkg.sh)" + exit 1 +fi + +# source and verify the package script +source "pkg.sh" +check_ret "Failed to source the package script" + +check_pkg_vars +check_ret + +# check the changes file +if [ ! -f "changes.md" ]; then + warn "Package directory does not contain a changes file (changes.md)" + warn "Creating an empty one, however you should you should create an actual changes file" + echo "# ${VERSION}" > "changes.md" + echo "No changes specified" >> "changes.md" +fi + +# setup package directories +pkgpath="$(realpath .)" +cachepath="$(realpath '.cache')" +distpath="$(realpath 'dist')" +rootpath="$(realpath 'root')" + +mkdir -p "${rootpath}" +check_ret "Failed to create the root directory" + +# check the cache +package_hash=$(md5sum "${pkgpath}/pkg.sh" 2> /dev/null | awk '{print $1}') +changes_hash=$(md5sum "${pkgpath}/changes.md" 2> /dev/null | awk '{print $1}') + +if [ $OPT_NO_CACHE -eq 0 ] && [ -f "${cachepath}/last" ]; then + package_cache=$(sed -n '1p' "${cachepath}/last") + changes_cache=$(sed -n '2p' "${cachepath}/last") + + if [[ "${package_cache}" == "${package_hash}" ]] && [[ "${changes_cache}" == "${changes_hash}" ]]; then + info "Found build in the cache (add --no-cache if you want to rebuild anyway)" + success "Build was successful" + exit 0 + fi +fi + +# check all the depends for the build +all_depends+=("${DEPENDS[@]}") +all_depends+=("${BUILD[@]}") + +if [ $OPT_NO_DEPEND -eq 0 ]; then + check_depends "${all_depends[@]}" + check_ret "Failed to check all the dependencies" +fi + +# make sure file count and the hash count is the same +file_count=${#FILES[@]} +hash_count=${#HASHES[@]} + +if [[ $file_count != $hash_count ]]; then + error "There are ${file_count} files but ${hash_count} hashes" + exit 1 +fi + +# cleanup files from previous builds +info "Cleaning up files from the previous build" +set_indent + +for f in "${rootpath}"/*; do + # do not remove the file if its required for build + for ((i = 0; i < $file_count; i++)) do + get_fn_url "${FILES[i]}" + if [[ "$(realpath "${rootpath}/${file}")" == "$(realpath ${f})" ]]; then + isdownload=1 + break + fi + done + + if [ -z $isdownload ]; then + info "Removing file from previous build: $f" + rm -rf "$f" + fi + + unset isdownload +done + +unset_indent + +cd "${rootpath}" +check_ret "Failed to change directory into the root directory" + +info "Obtaining all the files" +set_indent + +for ((i = 0; i < $file_count; i++)) do + get_fn_url "${FILES[i]}" + + # check if the file is already present + if [ -f "$file" ]; then + check_hash $file ${HASHES[i]} > /dev/null + if [ $? -eq 0 ]; then + success "($(($i+1))/$file_count) Using the file from previous build: $file" + continue + fi + rm -f $file + fi + + info "($(($i+1))/$file_count) Obtaining file: $file" + get_file ${FILES[i]} + check_ret "Failed to obtain the file!" + + check_hash "${file}" ${HASHES[i]} + check_ret "Verification failed for file: $file" +done + +unset_indent + +info "Running the build function" +export CFLAGS="-march=x86-64 -mtune=generic -O2" +export ROOTDIR="${rootpath}" +export MAKEFLAGS="-j${OPT_CORES}" +export MAKEOPTS="-j${OPT_CORES}" +export XORG_PREFIX="/usr" +export XORG_CONFIG="--prefix=${XORG_PREFIX} --sysconfdir=/etc \ + --localstatedir=/var --disable-static" + +SECONDS=0 + +if [ $OPT_NO_STDOUT -eq 0 ]; then + fakeroot "${location}/mp-wrap" "../pkg.sh" + check_ret "Package PACKAGE() function failed" +else + fakeroot "${location}/mp-wrap" "../pkg.sh" > /dev/null + check_ret "Package PACKAGE() function failed" +fi + +unset XORG_CONFIG XORG_PREFIX +unset CFLAGS ROOTDIR +unset MAKEOPTS MAKEFLAGS + +if [ "$SECONDS" != "0" ]; then + success "Completed the build in ${SECONDS}s" +else + success "Completed the build in less than a second" +fi + +# remove all the $FILES +for ((i = 0; i < $file_count; i++)) do + get_fn_url ${FILES[i]} && rm -f $file + success "Removed file: $file" +done + +info "Building the package archive" +set_indent + +# cleanup the dist directory +mkdir -p "${distpath}" +clean_dist + +# build the files archive +find . -printf "%P\n" | fakeroot tar -czf "${distpath}/files.tar.gz" --no-recursion -T - +check_ret "(1/6) Failed to create the files archive (files.tar.gz)" +success "(1/6) Created the files archive (files.tar.gz)" + +# build the DATA file +cat > "${distpath}/DATA" << EOF +[${NAME}] +version = ${VERSION} +desc = ${DESC} +size = $(du -sb "${rootpath}" | awk '{print $1}') +EOF + +for dep in "${DEPENDS[@]}"; do + echo "depends = ${dep}" >> "${distpath}/DATA" +done + +for keep in "${KEEP[@]}"; do + echo "keep = ${keep}" >> "${distpath}/DATA" +done + +success "(2/6) Created the package data file (DATA)" + +# create the changes file +cp "${pkgpath}/changes.md" "${distpath}/CHANGES" +check_ret "(3/6) Failed to create the changes file (CHANGES)" +success "(3/6) Created the changes file (CHANGES)" + +# create the install script +if type INSTALL &>/dev/null; then + echo "$(type INSTALL | tail -n+2)" > "${distpath}/INSTALL" + check_ret "(4/6) Failed to create the install script (INSTALL)" +fi +success "(4/6) Created the install script (INSTALL)" + +# create the HASHES file +find . -type f -exec md5sum {} >> "${distpath}/HASHES" \; +check_ret "(5/6) Failed to create the file hash list (HASHES)" +success "(5/6) Created the file hash list (HASHES)" + +# remove previous build archives +for old in "${distpath}/${NAME}_"*.mpf; do + rm -f $old +done + +# create the final archive +archive="${NAME}_${VERSION}.mpf" +pushd "${distpath}" > /dev/null + find . -printf "%P\n" | fakeroot tar -czf "${archive}" --no-recursion -T - + check_ret "(6/6) Failed to create the package archive (${archive})" +popd > /dev/null +success "(6/6) Created the package archive (${archive})" + +# clean up +cd "${pkgpath}" + +info "Cleaning up the dist directory" +clean_dist + +info "Cleaning the root directory" +rm -rf "${rootpath}" + +# update the cache +unset_indent +info "Updating the package cache" +set_indent + +mkdir -p "${cachepath}" + +echo "${package_hash}" > "${cachepath}/last" +check_ret "(1/2) Failed to add package script to the cache" +success "(1/2) Added package script to the cache" + +echo "${changes_hash}" >> "${cachepath}/last" +check_ret "(2/2) Failed to add changes file to the cache" +success "(2/2) Added changes file to the cache" + +unset_indent + +success "Build was successful" +exit 0 diff --git a/mp-build/scripts/mp-migrate.sh b/mp-build/scripts/mp-migrate.sh new file mode 100755 index 0000000..e12bc7d --- /dev/null +++ b/mp-build/scripts/mp-migrate.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +# mp-migrate | MatterLinux package migration script +# MatterLinux 2023-2024 (https://matterlinux.xyz) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +############################# +## import common functions ## +############################# +location="$(dirname "${0}")" +location="$(realpath "${location}")" +commonsh="$(echo "${location}" | sed 's/\/bin/\/lib/g')/mtsc-common.sh" + +source "${commonsh}" + +if [ "${?}" != "0" ]; then + echo "Failed to import mtsc-common" + exit 1 +fi + +################# +## main script ## +################# +if [ -z "$1" ]; then + error "Please specify a package directory" + exit 1 +fi + +if [ ! -d "$1" ]; then + error "Failed to access to the specified directory" + exit 1 +fi + +target="$(realpath "${1}")" +pkg_script="${target}/pkg.sh" +install_script="${target}/install.sh" + +if [ ! -f "${pkg_script}" ]; then + error "Specified directory does not contain a package script (pkg.sh)" + exit 1 +fi + +info "Sourcing the package script" +source "${pkg_script}" + +if [ -z "${VERSION}" ]; then + error "Required package variable \"\$VERSION\" is not set" + exit 1 +fi + +info "Auto generating the changes file" +cat > "${target}/changes.md" << EOF +# ${VERSION} +First version +EOF + +info "Adding the gitignore file" +cat > "${target}/.gitignore" << EOF +.cache/ +dist/ +root/ +EOF + +sed -i 's/build() {/PACKAGE() {/' "${pkg_script}" +check_ret "Failed to update the build function" + +if [ -f "${install_script}" ]; then + info "Migrating the install script" + echo >> "${pkg_script}" + echo "INSTALL(){" >> "${pkg_script}" + + while read l; do + echo " ${l}" >> "${pkg_script}" + done < "${install_script}" + + echo "}" >> "${pkg_script}" + + rm "${install_script}" + check_ret "Failed to remove the install script" +fi + +success "Migration is completed" diff --git a/mp-build/scripts/mp-new.sh b/mp-build/scripts/mp-new.sh new file mode 100755 index 0000000..435c3f3 --- /dev/null +++ b/mp-build/scripts/mp-new.sh @@ -0,0 +1,108 @@ +#!/bin/bash + +# mp-new | MatterLinux package creation script +# MatterLinux 2023-2024 (https://matterlinux.xyz) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +############################# +## import common functions ## +############################# +location="$(dirname "${0}")" +location="$(realpath "${location}")" +commonsh="$(echo "${location}" | sed 's/\/bin/\/lib/g')/mtsc-common.sh" + +source "${commonsh}" + +if [ "${?}" != "0" ]; then + echo "Failed to import mtsc-common" + exit 1 +fi + +################# +## main script ## +################# +if [ -z "$1" ]; then + error "Please specify a package" + exit 1 +fi + +pkg=$(basename "${1}") +target=$(dirname "${1}") + +case "${1}" in + *_*) + name=$(echo "${pkg}" | cut -d "_" -f1) + version=$(echo "${pkg}" | cut -d "_" -f2) + ;; + *) + warn "Package version is not specified, using \"1\" as version instead" + name="${pkg}" + version="1" + ;; +esac + +if [ -d "${target}/${name}" ]; then + error "There is already a directory for \"${target}/${name}\"" + exit 1 +fi + +info "Creating directory for \"${name}\"" + +mkdir "${target}/${name}" +check_ret "Failed to create package directory for \"${name}\"" + +cd "${target}/${name}" + +cat > pkg.sh << EOF +# general info +NAME="${name}" +DESC="" +VERSION="${version}" + +# required files +FILES=() +HASHES=() + +# install and build depends +DEPENDS=() +BUILD=() + +PACKAGE(){ + tar xf "\${NAME}-\${VERSION}.tar.gz" + cd "\${NAME}-\${VERSION}" + + # build commands + + cd .. && rm -r "\${NAME}-\${VERSION}" +} + +INSTALL(){ + # install script + # remove if not requied +} +EOF + +cat > changes.md << EOF +# ${version} +First version +EOF + +cat > .gitignore << EOF +.cache/ +dist/ +root/ +EOF + +success "Created package directory and files for \"${name}\"" diff --git a/mp-build/scripts/mp-wrap.sh b/mp-build/scripts/mp-wrap.sh new file mode 100755 index 0000000..8716af0 --- /dev/null +++ b/mp-build/scripts/mp-wrap.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# mp-wrap | MatterLinux package build function wrapper +# MatterLinux 2023-2024 (https://matterlinux.xyz) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +############################# +## import common functions ## +############################# +location="$(dirname "${0}")" +location="$(realpath "${location}")" +commonsh="$(echo "${location}" | sed 's/\/bin/\/lib/g')/mtsc-common.sh" + +source "${commonsh}" + +if [ "${?}" != "0" ]; then + echo "Failed to import mtsc-common" + exit 1 +fi + +################# +## main script ## +################# +if [ -z "${1}" ]; then + error "Package script not specified" + exit 1 +fi + +ninja(){ + echo "[ninja wrapper] adding MAKEFLAGS" + /usr/bin/ninja $MAKEFLAGS $@ +} + +echo "running the PACKAGE() function" +set -e + +source "${1}" +PACKAGE +ret="$?" + +set +e +echo "PACKAGE() returned with code $ret" + +exit $ret diff --git a/mp-pool/Makefile b/mp-pool/Makefile new file mode 100644 index 0000000..e83ec97 --- /dev/null +++ b/mp-pool/Makefile @@ -0,0 +1,16 @@ +SCRIPTS = $(patsubst scripts/%.sh,%,$(wildcard scripts/*.sh)) +PREFIX = /usr + +install: + @for s in $(SCRIPTS) ; do \ + echo "installing script: $$s" ; \ + install -m755 "scripts/$$s.sh" $(DESTDIR)/$(PREFIX)/bin/$$s ; \ + done + +uninstall: + @for s in $(SCRIPTS) ; do \ + echo "removing script: $$s" ; \ + rm $(DESTDIR)/$(PREFIX)/bin/$$s ; \ + done + +.PHONY: install uninstall diff --git a/mp-pool/README.md b/mp-pool/README.md new file mode 100644 index 0000000..3c73d36 --- /dev/null +++ b/mp-pool/README.md @@ -0,0 +1,12 @@ +# mp-pool | MatterLinux pool build scripts +The pool build scripts for MatterLinux package system. These scripts +are used for building and creating pools. + +### Usage +To build a pool from the source, you can use the `mp-pool` +script: +```bash +mp-pool /path/to/pool +``` +When the build is completed, the package archives and pool files +will be created inside the `/path/to/pool/dist` directory. diff --git a/mp-pool/scripts/mp-pool-clean.sh b/mp-pool/scripts/mp-pool-clean.sh new file mode 100755 index 0000000..e57f662 --- /dev/null +++ b/mp-pool/scripts/mp-pool-clean.sh @@ -0,0 +1,126 @@ +#!/bin/bash + +# mp-pool-clean | MatterLinux pool cleanup script +# MatterLinux 2023-2024 (https://matterlinux.xyz) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +############################# +## import common functions ## +############################# +location=$(dirname "${0}") +location=$(realpath "${location}") +commonsh="$(echo "${location}" | sed 's/\/bin/\/lib/g')/mtsc-common.sh" + +source "${commonsh}" > /dev/null + +if [ "${?}" != "0" ]; then + echo "Failed to import mtsc-common" + exit 1 +fi + +################# +## main script ## +################# +target="${1}" + +if [ -z "${target}" ]; then + error "Please specify a pool directory" + exit 1 +fi + +if [ ! -d "${target}" ]; then + error "Pool directory \"${target}\" does not exist" + exit 1 +fi + +cd "${target}" +check_ret "Failed to change directory into \"${target}\"" + +if [ ! -f "pool.sh" ]; then + error "Package directory does not contain a pool script (pool.sh)" + exit 1 +fi + +# source and verify the package script +source "pool.sh" +check_ret "Failed to source the pool script" + +check_pool_vars +check_ret + +# setup package directories +pkgpath="$(realpath .)" +distpath="$(realpath 'dist')" +srcpath="$(realpath "${SRCDIR}")" + +if [ ! -d "${srcpath}" ]; then + error "Source path does not exist" + exit 1 +fi + +if [ ! -d "${distpath}" ]; then + info "Nothing to do (dist directory does not exist)" + exit 1 +fi + +# source and store every package +files=("INFO" "LIST") +pc="$(ls -1q "${srcpath}" | wc -l)" +pi=1 + +info "Sourcing all the packages" +set_indent + +for pkg in "${srcpath}/"*; do + package=$(basename "${pkg}") + info "(${pi}/${pc}) Sourcing \"${package}\"" + + source "${pkg}/pkg.sh" + check_ret "(${pi}/${pc}) Failed to import the source script for \"${package}\"" + + check_pkg_vars + check_ret + + files+=("${NAME}_${VERSION}.mpf") + files+=("${NAME}_${VERSION}.mpf.sig") + pi=$((pi+1)) +done + +success "Completed" +unset_indent + +info "Cleaning up old archives and signatures" +pushd "${distpath}" > /dev/null +set_indent + +for file in *; do + found=0 + for f in "${files[@]}"; do + if [ "${file}" == "${f}" ]; then + found=1 + break + fi + done + + if [ $found -eq 0 ]; then + info "Removing ${file}" + rm "${file}" + check_ret "Failed to remove ${file}" + fi +done + +popd > /dev/null +success "Completed" +unset_indent diff --git a/mp-pool/scripts/mp-pool.sh b/mp-pool/scripts/mp-pool.sh new file mode 100755 index 0000000..b45fb9c --- /dev/null +++ b/mp-pool/scripts/mp-pool.sh @@ -0,0 +1,293 @@ +#!/bin/bash + +# mp-pool | MatterLinux pool build script +# MatterLinux 2023-2024 (https://matterlinux.xyz) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +############################# +## import common functions ## +############################# +location=$(dirname "${0}") +location=$(realpath "${location}") +commonsh="$(echo "${location}" | sed 's/\/bin/\/lib/g')/mtsc-common.sh" + +source "${commonsh}" > /dev/null + +if [ "${?}" != "0" ]; then + echo "Failed to import mtsc-common" + exit 1 +fi + +#################### +## util functions ## +#################### +# prints the help info +help_cmd() { + info "MatterLinux pool build script" + info "Usage: ${0} [pool directory]" + info "Options:" + echo_color " $BOLD--skip-fail$RESET: skip if a package build fails" + echo_color " $BOLD--no-depend$RESET: don't check depends" + echo_color " $BOLD--no-stdout$RESET: disable stdout for build() function" + echo_color " $BOLD--no-cache$RESET: don't use cache" + echo_color " $BOLD--no-opts$RESET: don't show/list options" + echo_color " $BOLD--no-sign$RESET: don't sign build packages" + echo_color " $BOLD--cores$RESET: how many cores to use for the build" + echo + info "Licensed under GPLv3, see for more information" +} + +# clean the dist directory +clean_dist() { + rm -f "${distpath}/DATA" + rm -f "${distpath}/CHANGES" + rm -f "${distpath}/INSTALL" + rm -f "${distpath}/HASHES" + rm -f "${distpath}/files.tar.gz" +} + +# convert bash array to newline splitted string +list_to_str(){ + local list=("$@") + for el in "${list[@]}"; do + if [ -z "${str}" ]; then + str="${el}" + else + printf -v str "${str}\n ${el}" + fi + done +} + +# run mp-build with options +mp_build_opts(){ + local opts=("${1}" "--no-opts") + + if [ $OPT_NO_DEPEND -eq 1 ]; then + opts+=("--no-depend") + fi + + if [ $OPT_NO_STDOUT -eq 1 ]; then + opts+=("--no-stdout") + fi + + if [ $OPT_NO_CACHE -eq 1 ]; then + opts+=("--no-cache") + fi + + mp-build ${opts[@]} + return "$?" +} + +################# +## main script ## +################# +OPT_SKIP_FAIL=0 # stop build when a package build fails +OPT_NO_DEPEND=0 # checking depends is ENABLED +OPT_NO_STDOUT=0 # build() function output is ENABLED +OPT_NO_CACHE=0 # cache is ENABLED +OPT_NO_OPTS=0 # showing/listing options is ENABLED +OPT_NO_SIGN=0 # sign all the built packages +OPT_CORES=$(nproc) # use ALL CPU cores + +# parses all the options +for arg in "$@"; do + case $arg in + "--help") + help_cmd + exit 0 + ;; + "--skip-fail") + OPT_SKIP_FAIL=1 ;; + "--no-depend") + OPT_NO_DEPEND=1 ;; + "--no-stdout") + OPT_NO_STDOUT=1 ;; + "--no-cache") + OPT_NO_CACHE=1 ;; + "--no-opts") + OPT_NO_OPTS=1 ;; + "--no-sign") + OPT_NO_SIGN=1 ;; + "--cores"*) + OPT_CORES=$(echo "${arg}" | cut -d "=" -f2) ;; + --*) + error "Unknown option: ${arg}" + exit 1 ;; + *) + if [ -z "${TARGET}" ]; then + TARGET="${arg}" + else + error "Unknown argument: ${arg}" + exit 1 + fi + ;; + esac +done + +if [ -z "${TARGET}" ]; then + error "Pool directory is not specified, run with \"--help\" for more information" + exit 1 +fi + +if [ ! -d "${TARGET}" ]; then + error "Pool directory \"${TARGET}\" does not exist" + exit 1 +fi + +if [ $OPT_NO_DEPEND -eq 0 ] && ! command -v matt &> /dev/null; then + error "!!! BUILD ON MATTERLINUX !!!" + error "matt is not installed, please build on a MatterLinux system" + error "Do NOT create bug reports if build fails on non-MatterLinux systems" + info "Auto enabling NO_DEPEND as depend check will fail without mp" + OPT_NO_DEPEND=1 +fi + +# print the options +if [ $OPT_NO_OPTS -eq 0 ]; then + info "Running mp-pool with the options:" + print " $BOLD SKIP_FAIL = $(itoyn $OPT_SKIP_FAIL)" + print " $BOLD NO_DEPEND = $(itoyn $OPT_NO_DEPEND)" + print " $BOLD NO_SDTOUT = $(itoyn $OPT_NO_STDOUT)" + print " $BOLD NO_CACHE = $(itoyn $OPT_NO_CACHE)" + print " $BOLD NO_OPTS = $(itoyn $OPT_NO_OPTS)" + print " $BOLD NO_SIGN = $(itoyn $OPT_NO_SIGN)" + print " $BOLD CORES = $OPT_CORES" +fi + +cd "${TARGET}" +check_ret "Failed to change directory into \"${TARGET}\"" + +if [ ! -f "pool.sh" ]; then + error "Package directory does not contain a pool script (pool.sh)" + exit 1 +fi + +# source and verify the package script +source "pool.sh" +check_ret "Failed to source the pool script" + +check_pool_vars +check_ret + +# setup package directories +pkgpath="$(realpath .)" +distpath="$(realpath 'dist')" +srcpath="$(realpath "${SRCDIR}")" + +mkdir -p "${distpath}" +check_ret "Failed to create the dist directory" + +if [ ! -d "${srcpath}" ]; then + error "Source path does not exist" + exit 1 +fi + +# build every package +pc="$(ls -1q "${srcpath}" | wc -l)" +pi=1 + +for pkg in "${srcpath}/"*; do + package=$(basename "${pkg}") + info "(${pi}/${pc}) Building \"${package}\"" + + if [ $OPT_SKIP_FAIL -eq 1 ]; then + mp_build_opts "${pkg}" + if [ $? -ne "0" ]; then + error "(${pi}/${pc}) Build failed for \"${package}\", skipping" + pi=$((pi+1)) + continue + fi + else + mp_build_opts "${pkg}" + check_ret "(${pi}/${pc}) Build failed for \"${package}\"" + fi + + archive="$(find "${pkg}/dist" -name "*.mpf" | tail -n1)" + name="$(echo "${archive}" | cut -d _ -f 1)" + + if [ ! -z "${archive}" ]; then + rm -f "${distpath}/${name}_"* + mv "${archive}" "${distpath}" + check_ret "(${pi}/${pc}) Moving package archive failed for \"${package}\"" + fi + + success "(${pi}/${pc}) Build was successful for \"${package}\"" + pi=$((pi+1)) +done + +success "Completed all the package builds" + +# sign packages +if [ "$OPT_NO_SIGN" -eq 0 ]; then + gpg --list-secret-keys "${PUBKEY}" &> /dev/null + check_ret "Package signing is enabled, however you do not have the required private key" + + info "Signing package archives" + set_indent + + for pkg in "${distpath}/"*".mpf"; do + gpg --default-key "${PUBKEY}" --yes --detach-sign "${pkg}" &> /dev/null + check_ret "Failed to sign package archive: \"$(basename "${pkg}")\"" + success "Signed archive: $(basename "${pkg}")" + done + + success "Signing process was completed" + unset_indent +fi + +info "Creating pool files" +set_indent + +# create INFO file +cat > "${distpath}/INFO" << EOF +[${NAME}] +size = $(du -sb "${distpath}" | awk '{print $1}') +maintainer = ${MAINTAINER} +pubkey = ${PUBKEY} +EOF + +check_ret "(1/2) Failed to create pool info file (INFO)" +success "(1/2) Created pool info file (INFO)" + +# create LIST archive +rm -rf "${distpath}/list" +mkdir -p "${distpath}/list" +cd "${distpath}/list" + +check_ret "Failed change directory into temporary list directory" +info "Creating package list archive" + +for pkg in "${distpath}/"*".mpf"; do + archive="$(basename "${pkg}")" + name="${archive::-4}" + + mkdir "${name}" + check_ret "Failed to create list directory for \"${archive}\", is there two packages with the same name?" + + tar xf "${pkg}" -C "${name}" DATA + check_ret "Failed to extract data file from \"${archive}\"" +done + +pushd "${distpath}/list" > /dev/null + tar czf "${distpath}/LIST" * + check_ret "(2/2) Failed to create list archive (LIST)" +popd > /dev/null + +rm -r "${distpath}/list" +check_ret "(2/2) Failed to remove temporary list directory" +success "(2/2) Created package list archive (LIST)" +unset_indent + +success "Pool build was successful" diff --git a/mtsc-common/Makefile b/mtsc-common/Makefile new file mode 100644 index 0000000..312d928 --- /dev/null +++ b/mtsc-common/Makefile @@ -0,0 +1,9 @@ +PREFIX = /usr + +install: + install -m755 "common.sh" $(DESTDIR)/$(PREFIX)/lib/mtsc-common.sh + +uninstall: + rm $(DESTDIR)/$(PREFIX)/lib/mtsc-common.sh + +.PHONY: install uninstall diff --git a/mtsc-common/README.md b/mtsc-common/README.md new file mode 100644 index 0000000..d7d1eb6 --- /dev/null +++ b/mtsc-common/README.md @@ -0,0 +1,3 @@ +# mtsc-common | MatterLinux common script functions +A (bash) shell script that contains common functions used in MatterLinux +build scripts and tools. diff --git a/mtsc-common/common.sh b/mtsc-common/common.sh new file mode 100755 index 0000000..8d26080 --- /dev/null +++ b/mtsc-common/common.sh @@ -0,0 +1,206 @@ +#!/bin/bash + +# mtsc-common | MatterLinux common script functions +# MatterLinux 2023-2024 (https://matterlinux.xyz) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +$(return 0 2>/dev/null) + +if [ $? -eq 1 ]; then + echo "This script contains common functions for MatterLinux tools/scripts" + echo "You are not supposed to directly run it, now exiting to prevent any errors" + exit 1 +fi + +############################ +## logging functions/vars ## +############################ +BOLD="\e[1m" +RESET="\e[0m" +YELLOW="\e[33m" +GREEN="\e[32m" +BLUE="\e[34m" +GRAY="\e[37m" +RED="\e[31m" + +NORMAL_PREFIX=">>>" +INDENT_PREFIX=" |" + +LOG_PREFIX="$NORMAL_PREFIX" + +echo_color() { + echo -e "${1}" +} + +success() { + if [ "$LOG_PREFIX" == "$NORMAL_PREFIX" ]; then + echo_color "${BOLD}${GREEN}${LOG_PREFIX}${RESET}${BOLD} $1 ${RESET}" + else + echo_color "${BOLD}${GREEN}${LOG_PREFIX}${RESET} $1" + fi +} + +info() { + if [ "$LOG_PREFIX" == "$NORMAL_PREFIX" ]; then + echo_color "${BOLD}${BLUE}${LOG_PREFIX}${RESET}${BOLD} $1 ${RESET}" + else + echo_color "${BOLD}${BLUE}${LOG_PREFIX}${RESET} $1" + fi +} + +warn() { + if [ "$LOG_PREFIX" == "$NORMAL_PREFIX" ]; then + echo_color "${BOLD}${YELLOW}${LOG_PREFIX}${RESET}${BOLD} $1 ${RESET}" + else + echo_color "${BOLD}${YELLOW}${LOG_PREFIX}${RESET} $1" + fi +} + +error() { + if [ "$LOG_PREFIX" == "$NORMAL_PREFIX" ]; then + echo_color "${BOLD}${RED}${LOG_PREFIX}${RESET}${BOLD} $1 ${RESET}" + else + echo_color "${BOLD}${RED}${LOG_PREFIX}${RESET} $1" + fi +} + +print() { + echo_color "${BOLD}${GRAY}$1${RESET}" +} + +set_indent() { + LOG_PREFIX="$INDENT_PREFIX" +} + +unset_indent() { + LOG_PREFIX="$NORMAL_PREFIX" +} + +#################### +## util functions ## +#################### +check_ret() { + if [ $? -ne 0 ]; then + if [ ! -z "$1" ]; then + error "$1" + fi + exit 1 + fi +} + +# integer-to-yes-or-no +itoyn() { + if [ $1 -eq 0 ]; then + echo "${RED}no${RESET}" + else + echo "${GREEN}yes${RESET}" + fi +} + +# checks if all the required package vars/functions are set +check_pool_vars() { + if [ ! -n "$NAME" ]; then + error "Failed to load the pool script" + set_indent + + error "Required pool variable is not set: \"\$NAME\"" + unset_indent + + return 1 + elif [ ! -n "$MAINTAINER" ]; then + error "Failed to load the pool script" + set_indent + + error "Required pool variable is not set: \"\$MAINTAINER\"" + unset_indent + + return 1 + elif [ ! -n "$PUBKEY" ]; then + error "Failed to load the pool script" + set_indent + + error "Required pool variable is not set: \"\$PUBKEY\"" + unset_indent + + return 1 + elif [ ! -n "$SRCDIR" ]; then + error "Failed to load the pool script" + set_indent + + error "Required pool variable is not set: \"\$SRCDIR\"" + unset_indent + + return 1 + fi + + case "${NAME}" in + *" "*) + error "Pool name contains an invalid character: \" \"" + unset_indent + return 1 ;; + esac + + return 0 +} + +# checks if all the required package vars/functions are set +check_pkg_vars() { + if [ ! -n "$NAME" ]; then + error "Failed to load the package script" + set_indent + + error "Required package variable is not set: \"\$NAME\"" + unset_indent + + return 1 + elif [ ! -n "$VERSION" ]; then + error "Failed to load the package script" + set_indent + + error "Required package variable is not set: \"\$VERSION\"" + unset_indent + + return 1 + elif [ ! -n "$DESC" ]; then + error "Failed to load the package script" + set_indent + + error "Required package variable is not set: \"\$DESC\"" + unset_indent + + return 1 + elif ! type PACKAGE &>/dev/null; then + error "Failed to load the package script" + set_indent + + error "Required \"PACKAGE()\" function is not defined" + unset_indent + + return 1 + fi + + case "${NAME}" in + *_*) + error "Package name contains an invalid character: \"_\"" + unset_indent + return 1 ;; + *" "*) + error "Package name contains an invalid character: \" \"" + unset_indent + return 1 ;; + esac + + return 0 +}