#!/bin/sh # brick - a simple userspace package manager for blek!OS # also built on top of pacman # # made by alice # also it is GPL3 only uwu # settings set -e start_time=$(date +%s) version=1.1 # functions errcho() { # now this was stolen from https://stackoverflow.com/a/2990533 # uwu echo "$@" 1>&2; } err() { printf "\x1b[1;31m[!]\x1b[0m $@\n" 1>&2; } inf() { printf " $@\n" } getbrick() { echo $BRICKS_DIR/$1.brick } brickdb() { mkdir -p $BRICKS_DIR/.db if ! [ -f $BRICKS_DIR/.db/installed ]; then touch $BRICKS_DIR/.db/installed fi echo $BRICKS_DIR/.db } pkg_installed() { if [ ! -z $(echo "$BRICKS_INSTALLED" | grep -E "^$1 \\\\d") ]; then return 0 fi return 1 } user_confirm() { # base function was stolen from https://stackoverflow.com/a/32708121 if [ "$AUTOMATIC" == "true" ]; then return 0 fi while true; do read -r -n 1 -p "$(inf "- ${1:-Continue?} [Y/n]: ")" REPLY case $REPLY in [yY]) echo ; return 0 ;; [nN]) echo ; return 1 ;; *) return 0 ;; esac done } bricksenv() { echo "export BRICKS_DIR=$BRICKS_DIR" echo "export BRICKS_DB=$BRICKS_DB" echo "export AUTOMATIC=$AUTOMATIC" } tmpdir() { if ! [ -f $BRICKS_DIR/.tmp ]; then mkdir -p $BRICKS_DB/.tmp fi echo $BRICKS_DB/.tmp } exec_brick() { echo -e "$(bricksenv)\n$*" | bash } print_long_list() { list=($@) i=0 printf '%s' "$(inf)$(inf)" for el in ${list[@]}; do printf '%s ' $el if [ "$i" == "2" ]; then if ! [ "$(( "${#list[@]}" % 3 ))" == "0" ]; then printf '\n%s' "$(inf)$(inf)" fi fi i=$(( i + 1 )) done echo } # checking that brick's dependencies are installed BRICK_DEPS=(curl) NO_DEPS=() for dep in ${BRICK_DEPS[@]}; do if ! command -v $dep > /dev/null; then NO_DEPS=(${NO_DEPS[@]} $dep) fi done if ! [ "${#NO_DEPS[@]}" == "0" ]; then errcho 'Error!' errcho 'brick itself depends on some stuff, which you dont have installed:' errcho "${NO_DEPS[@]}" fi # some vars BRICKS_DIR=${BRICKS_DIR:-} PKGS=() ERRORED=false AUTOMATIC=false # setting the BRICKS_DIR var BRICKS_PWD=$(pwd) while :; do # lets jump to the parent dir until we find the bricks dir if [ -d $BRICKS_PWD/bricks ]; then # yay we found it ^^ BRICKS_DIR=$BRICKS_PWD/bricks break fi if [ $BRICKS_PWD = "/" ]; then err "Didnt find the bricksdir in this or any parent directory (excluding root)" exit 1 fi done unset BRICKS_PWD BRICKS_DB=$(brickdb) BRICKS_INSTALLED=$(cat $BRICKS_DB/installed) # settings the PKGS var # lets grab those from argv while [[ $# -gt 0 ]]; do case $1 in -y|--noconfirm) AUTOMATIC=true shift;; -L) inf "listing packages" for pkg in $(find $BRICKS_DIR -maxdepth 1 -type f -printf "%f\n" | grep -E \\.brick$ | sed 's/.brick//'); do SCRIPT="\n source $(getbrick $pkg)\n if [ \"\$(command -v info)\" == \"info\" ]; then\n echo \$(info)\n else\n echo 'no info provided'\n fi\n " # exec_brick $SCRIPT inf "$(inf "$pkg - $(exec_brick $SCRIPT)")" done inf 'done' exit 0 ;; -v|--version) echo "brick $version (gpl 3 only)" echo "made by alice with <3" echo "https://git.blek.codes/blek/os" exit 0 ;; -h|--help) echo "brick $version (gpl 3 only)" inf "Usage: $0 [PACKAGES]" inf "$(inf "-h --help \t - Display this message")" inf "$(inf "-v --version \t - Print version and exit")" inf "$(inf "-L \t - List all packages")" exit 0 ;; -*) # meh domt need unkonw args shift;; *) # everything else is a package name however PKGS+=("$1") shift;; esac done PPKGS=() # now step 1 is to check that all packages are there for pkg in "${PKGS[@]}"; do if ! [ -f $(getbrick $pkg) ]; then err "Oh no! Brick $pkg is not found in $BRICKS_DIR" ERRORED=true fi if pkg_installed "$pkg"; then echo $pkg is installed, skipping else PPKGS=("${PPKGS[@]}" $pkg) fi done PKGS=("${PPKGS[@]}") if [ "$ERRORED" == "true" ]; then exit 1 fi # lets resolve the dependencies huh find_deps_for() { brick=$1 deps=() SCRIPT=" source $(getbrick $brick)\n if ! [ \"\$dependencies\" == \"\" ]; then\n echo \"\${dependencies[@]}\"\n fi\n " deps=$(exec_brick $SCRIPT) deps=(${deps[@]}) if ! [ "${#deps[@]}" == "0" ]; then for dep in "${deps[@]}"; do if ! [ -f "$(getbrick $dep)" ]; then err "$brick depends on $dep, which is not an available package" ERRORED=true fi ndeps=$(find_deps_for $dep) deps=(${deps[@]} ${ndeps[@]}) done fi echo ${deps[@]} } for pkg in "${PKGS[@]}"; do PKGS=(${PKGS[@]} $(find_deps_for $pkg)) done if [ "$ERRORED" == "true" ]; then exit 1 fi if [ "${#PKGS[@]}" == "0" ]; then inf "nothing to do" exit else inf "packages to install:" print_long_list "${PKGS[@]}" if ! user_confirm; then inf "canceled" exit fi fi PACDEPS=() # lets first collect the packages for pkg in "${PKGS[@]}"; do source $(getbrick $pkg) IFS=' ' read -ra DEPS <<< $(pkgs) PACDEPS=("${PACDEPS[@]}" "${DEPS[@]}") done # so yeah lets do it if [ "${#PACDEPS[@]}" != "0" ]; then # first, gotta filter out the ones that are already installed INSTALLED=$(pacman -Qe) TO_INSTALL='' removed=0 for pkg in $PACDEPS; do if [[ -z $(echo $INSTALLED | grep $pkg) ]]; then TO_INSTALL="$TO_INSTALL $pkg" else removed=$(($removed + 1)) fi done if ! [ "$removed" == "0" ]; then inf "removed $removed installed pacman deps" fi # then there might actually be no work to be done if [ "$TO_INSTALL" != "" ]; then if [ -f /var/lib/pacman/db.lck ]; then errcho "pacman is running now; can't install pacman deps" errcho "if you are sure that pacman is not running, delete /var/lib/pacman/db.lck manually" fi inf "installing pacman packages:" inf "$TO_INSTALL" # welp lets install those sudo pacman -S --needed --noconfirm $TO_INSTALL &> $BRICKS_DB/.pacman-log PACCODE="$?" if ! [ "$PACCODE" == "0" ]; then err "pacman exited with code $PACCODE" err "pacman's output log is in $BRICKS_DB/.pacman-log" exit fi inf "installed all pacman deps" else inf "no pacman deps to install" fi else inf "no pacman deps to install" fi DOWNLOADED_FILES=() i=1 # pacman deps installed, lets install the actual shit for pkg in "${PKGS[@]}"; do # first check if there is stuff we need to download for that brick SCRIPT=" source $(getbrick $pkg) if [ -z ${var+x} ]; then echo \${downloads[@]} fi " DOWNLOADS=$(exec_brick "$SCRIPT") DOWNLOADS_MAP=() if ! [ "$DOWNLOADS" == "" ]; then DOWNLOADS=($DOWNLOADS) inf "$(inf "downloading files for $pkg...")" ii=1 for download in $DOWNLOADS; do curl -s $download > $(tmpdir)/$pkg-file-$i & DOWNLOADS_MAP=(${DOWNLOADS_MAP[@]} $(tmpdir)/$pkg-file-$i) ii=$(($ii + 1)) done wait inf "$(inf "downloaded")" fi DOWNLOADED_FILES=(${DOWNLOADED_FILES[@]} ${DOWNLOADS_MAP[@]}) SCRIPT=" source $(getbrick $pkg)\n downloads=(${DOWNLOADS_MAP[@]})\n install " inf "installing $pkg [$i/${#PKGS[@]}]" exec_brick "$SCRIPT" > $BRICKS_DB/.$pkg-install-log i=$(($i + 1)) done if ! [ "${#DOWNLOADED_FILES[@]}" == "0" ]; then inf 'cleaning up downloaded files' for file in $DOWNLOADED_FILES; do rm $file & done wait fi inf "done in $(($(date +%s) - $start_time)) seconds"