PacUI: Bash script providing advanced Pacman and Yay/Pikaur/Aurman/Pakku/Trizen/Pacaur functionality in a simple UI

cli
pacui
aur
pacman
yay

#443

this is already the case.

when no AUR helper is present, pacui still works but does not offer options, for which an AUR helper is required.

if somebody does not want to use any AUR packages, (s)he can still use pacui.


#444

clicking on the links works just fine in termite


#445

i have just added this to pacui in commit: https://github.com/excalibur1234/pacui/commit/597092f91734235f9487679194adc8f7516babc7


#446

Thank you for writing and maintaining this great piece of software. I haven’t spent much time playing with pacui yet, so I’m not very familiar with all its features. One feature that I really like is the “edit config files” option. Would it be possible to add a feature to this submenu to en masse create backups of all those config files with a .bak extension. That would be a super handy feature to have in case you ever needed to restore a config file that was altered. If it is a lot effort to implement then don’t bother, (but if it’ can easily be done) it would be a nice feature to have. Thanks again for this great piece of coding.


#447

for inspiration (if required),
I have a script of this type, saved in a.gz archive all .conf (if different date from the original package = I modified them) and files in xxx.d/ plus some home files

#!/usr/bin/env bash
pkgname='config-save'
version=0.1.0-1

# test in asset function
unset DEVELOPER PARAMS ADMIN CONFIG VERBOSE LOCAL DIR PACKAGES
#PARAMS=1
DEVELOPER=1
PACKAGES=1
DIR=1
LOCAL=1

#general install directories
declare -A DIRS=()
DIRS[local]="$HOME/.config/${pkgname}.conf"
DIRS[save]="/tmp/$pkgname"
error_file="/tmp/$pkgname.err"

#########################

function usage()
{
   echo -e "Usage: $pkgname
   -g --git : save in repo git
   -z --gz : save in archive\n
   -p --package : only packages
   -l --local : only locale config ~/.config/${pkgname}.conf
   -d --dir : only files /etc/*.d/*\n
   -v --verbose : show more information\n"
   echo -e "output in : ${DIRS[save]}/"
} 


# call one error : cp zozoleb 2> $error_file
#(( $? )) && error "oops"
function error() 
{
   local msg=$1
   [[ -f "$error_file" ]] && { 
      msg="${msg}: $(head -n1 $error_file)"
      rm $error_file
   }
   echo "${msg}" >&2
}

function asset()
{
   local E_PARAM_ERR=98
   local E_ASSERT_FAILED=99
  
   ((PARAMS)) && {
      (( $# < 1 )) && {
         error "expected argument"
         usage
         exit $E_PARAM_ERR
      }
   }

   ((ADMIN)) && {
      (($EUID != 0)) && {
         error "you cannot perform this operation unless you are root."
         exit $E_ASSERT_FAILED
      }
   }

   ((CONFIG)) && {
      [ -r "${DIRS[conf]}" ] || {
         error "config file not found \"${DIRS[conf]}\""
         exit $E_ASSERT_FAILED
      }
   }
}

function init_paths()
{
   DIRS[local]="$HOME/.config/${pkgname}.conf"
   DIRS[path]=''
   DIRS[conf]="/etc/${pkgname}.conf"
   DIRS[lib]="/usr/lib/${pkgname}"
   DIRS[doc]="/usr/share/doc/${pkgname}"
   local lg=$(locale 2>/dev/null | awk -F'=' '/^LANG/ {print $2}')
   DIRS[conf.lang]=${lg:0:2}
   DIRS[dico]="/usr/share/locale/${DIRS[conf.lang]}/LC_MESSAGES/$pkgname"      
}

##########################################################
#   PROJECT FUNCTIONS
##########################################################

function packages.save()
{
   pacman -Qqen > "${DIRS[save]}/pkglist-repo.txt"
   pacman -Qqem > "${DIRS[save]}/pkglist-aur.txt"
   printf "saved in %s\n" ${DIRS[save]}
}

function package.findconf()
{
   #find all conf file in one package
   local package="${1-:'pacman'}"
   local f
   date_p=$(date -d "$(LANG=C pacman -Qi ${package} | awk -F':' '/Install Date/ {print $2}')" +%s)
   ((VERBOSE)) && echo "package $package installed le : ${date_p} : $(LANG=C pacman -Qi ${package} | awk -F':' '/Install Date/ {print $2}')"
   for f in $(pacman -Qlq "${package}" | grep "/etc/" | grep -v "/$"); do
      [ -f "$f" ] || continue
      #echo  "get date for ${f}"
      local date_m=$(stat -c %Y "${f}")
      #date_f=$(/usr/bin/date -r "$f" +%s) bug :(
      if (( $date_m - $date_p > 500 )); then
         echo -e "\t-- $f is to save .... $date_p <> $date_m"
         echo "$f" >> ${DIRS[save.diff]}
      else
         ((VERBOSE)) && echo -e "\t-- $date_p == $date_m , $f is original !"
      fi
   done
}

function packages.findconf()
{
   local pkg
   echo "------------------------------"
   echo "-- all packages"   
   while read pkg
   do
      package.findconf "$pkg"
   done < "${DIRS[save]}/pkglist-repo.txt"
}

function add_diff() {
   local f="$1"
   if [ -f "$f" ]; then
      echo "$f" >> ${DIRS[save.diff]}
      echo -e "\t\t$f (add)"
   fi
}

function d.findconf()
{
   local dir="${1-:'/etc/systemd/journald.conf.d'}"
   local f
   ((VERBOSE)) && echo -e "\t${dir} (DIR)"
   for f in ${dir}/*; do
      [ -d "$f" ] && continue
      [ -f "$f" ] || continue
      ((VERBOSE)) && echo -e "\t\t$f"
      #local pkg=$(pacman -Qoq "$f" 2>/dev/null)
      # if file not in one package SAVE
      if (! pacman -Qoq "$f" &>/dev/null); then
         add_diff "$f"
      fi
   done
}

function ds.findconf()
{
   echo "------------------------------"
   echo "-- all .d directories"
   for d in $(find /etc/ -type d -iname "*.d" -readable 2>/dev/null); do
      d.findconf "$d"
   done
}

function list.findconf()
{
   local dir="${1-:'/etc/systemd/journald.conf.d'}"
   local f
   if [ -d "$dir" ]; then
      ((VERBOSE)) && echo -e "\t$dir DIR"
      for f in ${dir}/*; do
         [ -d "$f" ] &&  list.findconf "$f"  # continue
         [ -f "$f" ] || continue
         add_diff "$f"
      done
   else
      add_diff "$dir"
   fi
}

function lists.findconf()
{
   echo "------------------------------"
   list.findconf "/etc/issue"
   list.findconf "/etc/locale.conf"
   list.findconf "/etc/pacman.conf"
   list.findconf "$HOME/.bashrc"
   list.findconf "$HOME/.bash_profile"
   list.findconf "$HOME/.zshrc"
   list.findconf "$HOME/.yaourtrc"
   list.findconf "$HOME/.nanorc"
   list.findconf "$HOME/.gitconfig"
   list.findconf "$HOME/.config/user-dirs.dirs"
   list.findconf "$HOME/.config/autostart"
   echo "-- all files and directories in ~/.config/${pkgname}.conf"
   while read f
   do
      list.findconf "$f"
   done < "${DIRS[local]}"
}

function git.create()
{
   local url=${1:-'https://gitlab.com/$LOGIN/arch-save.git'}
   git init
   git remote add origin $url
}

function git.save()
{
   # git add, commit, git push NEXT
   echo "------------------------------" 
}

function save.create()
{
   local f
   # lire fichier "${DIRS[save]}/etc.list"
   # copier les fichiers dans "${DIRS[save.diff]}"
   echo "------------------------------"
   #cat "${DIRS[save.diff]}"
   echo "-- cp all files in ${DIRS[save.diff]}"
   while read f
   do
      [ -f "$f" ] || continue
      [ -r "$f" ] || continue # pas les droits en lecture !
      ((VERBOSE)) && echo "copy of $f in\t${DIRS[save]}${f}"
      install -pD "$f" "${DIRS[save]}$f"
   done < "${DIRS[save.diff]}"
}

function save.gz()
{
   # gzip directory "${DIRS[save]}"
   echo "------------------------------"
   echo "-- create archive in ${DIRS[save]}"
   local namef="$(hostname -s)-$(lsb_release -i | awk '{print $3}')-$(date +%F).tar.gz"
   namef=${namef,,}
   cd "${DIRS[save]}"
   rm "${DIRS[save]}/${namef}" 2>/dev/null
   tar -czf "/tmp/${namef}" -C "${DIRS[save]}" "."
   mv "/tmp/${namef}" "${DIRS[save]}/${namef}"
   echo "archive: ${DIRS[save]}/${namef}"
}


##########################################################
#   RUN
##########################################################

run()
{
   rm -rf "${DIRS[save]}" &>/dev/null
   [ -d "${DIRS[save]}" ] || mkdir "${DIRS[save]}"
   DIRS[save.diff]="${DIRS[save]}/etc.list"
   echo ''> "${DIRS[save.diff]}"
   
   packages.save
   ((PACKAGES)) && packages.findconf
   ((DIR)) && ds.findconf
   ((LOCAL)) && lists.findconf
   
   save.create
   #((GIT)) && git.save
   ((GZ)) && save.gz
}


main()
{
   # load home conf
   init_paths


   SHORT=hvgzldpu:
   LONG=help,verbose,git,gz,local,dir,packages,url
   PARSED=$(getopt --options $SHORT --longoptions $LONG --name "$0" -- "$@")
   (( $? != 0 )) && exit 1
   eval set -- "$PARSED"

   while true; do
      case "$1" in
         -g|--git)
            GIT=1
            shift 
            ;;
         -z|--gz)
            GZ=1
            shift 
            ;;            
         -v|--verbose)
            VERBOSE=1
            shift 
            ;;
         -u|--url)
            URL="$2"
            shift 
            ;;
         -d|--dir)
            unset PACKAGES LOCAL
            shift
            ;;  
         -p|--package)
            unset LOCAL DIR
            shift
            ;;
         -l|--local)
            unset PACKAGES DIR
            shift
            ;;            
         -h|--help)
            usage
            exit 0
            ;; 
         --)
            shift
            break
            ;;
         *)
            echo "Programming error"
            exit 3
            ;;
      esac
   done
   #ARGS=("$@")
   unset LONG SHORT PARSED

   # tests
   asset "$@"

   #run
   run "$@"
}

if [ "${BASH_SOURCE[0]}" == "$0" ]; then
   main "$@"
   exit 0
else
   export -f packages.save
fi

BUT
old script :-1: (with dates compare) ; best way its to use pacman -kk

sudo LANG=C pacman -Qkk 2>1| grep -oE '\/.*Modification time ' | cut -d'(' -f1
sudo tar -cvzf my-system-config.tar.gz $( LANG=C pacman -Qkk 2>1| grep -oE '\/.*Modification time ' | cut -d'(' -f1)

#448

Very nice. :+1:


#449

if you want to create a backup of your config files, i recommend to create a git repository like this:

  • sudo pacman -S git
  • <go to the directory you want to create your git repo, e.g. to /etc/ >
  • git init
  • git add . (add all files to be tracked by git. alternatively, you can only track individual files or track all files except for some (google for “.gitignore”))
  • git commit -m "first backup"

every time you want to save your config files, you can do another commit.

if you want to get rid of all git backups simply delete the .git folder.

git is much more flexible than all the stuff i could integrate in pacui.


#450

I use fix-pacman-errors to update mirrors, but the last time I used it, it deleted my user configurations, so I couldn’t log to Manjaro anymore, and I had to do a fresh install.

Thank you for that!


#451

the only commands, which can remove files from your system in the “fix pacman errors” option are:

  • sudo rm -r /tmp/pacui*
  • sudo unlink "/var/lib/pacman/db.lck
  • sudo rm -r /etc/pacman.d/gnupg

as you can see, your configuration files in your user (i.e. home) directory are untouched. therefore, i conclude that your following statement is false:

the only case, in which people were not be able to login into manjaro anymore after using pacui, is when the “maintain system” option was used. here an exemplary case:

tl;dr: It is highly likely you have experienced the same. In this case, you have to thank your (probably) unknowing past self for deleting your /etc/shadow, /etc/passed, and /etc/group files (which included your login password and other essential stuff) and replacing them with *.pacnew files, despite a nice diff view of what you were going to delete.

you likely meant these thanks in an ironic way, but i take them literally.
pacui does not stop you from breaking your system - but it let’s you do it efficiently.


#452

This is why I love pacui :sweat_smile:

I think it is very much within the spirit of manjaro and arch based Linux in general


#453

I couldn’t even use advanced options in boot menu to be able to use maintain-system option.

I just don’t know how deleting the current user could be a good way to fix errors!

I didn’t pay too much attention to the message, and I chose overwrite, but I didn’t think that it could break my system, because I used Pacui a lot of times, and it is supposed to be user friendly application for beginner but I was mistaken.

It’s partially my fault but I learned my lesson, and I will never use Pacui ever again, and I may never use Manjaro either because it’s different with each update, and it’s a little bit frustrating :expressionless:


#454

You owe me some screen wipes :smiley:


#455

I posted a while back how to recover the /etc files mentioned if they get trashed, there are backups in /etc ending in a “-” (minus sign) that do not get hosed.

ls -la *-  
-rw-r--r-- 1 root root 1053 May 28 21:26 group-
-rw------- 1 root root  892 May 28 21:26 gshadow-
-rw-r--r-- 1 root root 1824 May 28 21:26 passwd-
-rw------- 1 root root 1025 May 28 21:26 shadow-

Just copy them back!


#456

you were indeed mistaken.

the second and third sentence of the first post in this topic / the github page:


#457

thanks for your suggestion!
i will add it to pacui’s help page.


#458

i have just released version 1.10.3. changelog is available here: https://github.com/excalibur1234/pacui/releases/tag/1.10.3


#459

PacUI is now able to read more alternate Pacman paths from its configuration file. Reading the Pacman configuration file should be reliable, too.
PacUI is now fully compatible with Pacman 5.1

Now pacman 5.1 recommends ? to use pacman-conf command and not grep pacman.conf
in annonce :

implement pacman-conf, a new tool to safely parse pacman.conf, and use it in internal scripts


#460

i have read this announcement, too. i was excited and immediately tried it.

unfortunately, i was not able to query pacman.conf (using pacman-conf) for anything else than repository names.

“pacman-conf -h” only mentions repositories. no word or example how to query file or directory paths…


#461

yes limited , is just a copy of pacconf in pacutils package


#462

with the latest commit, i have just added support for pakku.