Author Topic: apt-get upgrade and yad  (Read 1070 times)

misko_2083

  • Posts: 70
    • View Profile
apt-get upgrade and yad
« on: January 12, 2016, 07:54:41 PM »
I've been playing with a little script to update packages.
So here is the thing. When a package manager has an exclusive lock and this script tries to start the update, it calls a function to check wheather there is a lock or not.
If there is a lock it opens a Yad progress dialog which waits until the package manager (synaptic, gdebi-gtk, aptitude, apt...) releases the lock.
Now, when I click on Cancel on that same dialog Yad kills the parent process but there is still a child process that is checking the lock.
It eventualy closes when the package manager is closed, but I wonder if there is a way to kill it along with the parent.

The problem is in function checklock. When the synaptic is running and you select the 'Update Packages' from the main dialog, click the Cancel and look for the process with htop.
Any suggestions are welcome.  :)
Code: [Select]
#!/bin/bash
# Licensed under the GNU GPLv3.
#.%%...%%..%%%%%%...%%%%...%%..%%...%%%%.._.
#.%%%.%%%....%%....%%......%%.%%...%%..%%.2.
#.%%.%.%%....%%.....%%%%...%%%%....%%..%%.0.
#.%%...%%....%%........%%..%%.%%...%%..%%.8.
#.%%...%%..%%%%%%...%%%%...%%..%%...%%%%..3.
# Bash/YAD Debian Package Updater based on Linux Lite update tool
# ------- Change log ------
# Switched to YAD and adapted to Debian
# Added: a main dialog loop, log, option to purge the lists, about dialog
# Added: a check for exclusive lock
# -----------------------------------
# Note:  function checklock -> if Cancel is selected while the package manager (synaptic) is open
#        Yad progress kills the parent but will not kill the child process running the exclusive lock check
#        Subshell will be running until the package manager releases the lock
# -----------------------------------
# Milos Pavlovic
#

APPNAME="Update Tool"
LOGFILE=/var/log/misko-update.log
UPDATELOG=/var/log/last-update-log.log
# dist-upgrade or upgrade, change next line
COMMAND=dist-upgrade
# Yad window icon
ic=/usr/local/bin/images/vsidoorb_80.png

# Make sure only root can run our script
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root!" 1>&2
echo "TIP: Use gksudo or a similar tool." 1>&2
exit 1
fi

function log(){
message="$@"
echo '['$(date +%D\ %H:%M:%S)'] '$message | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})*)?m//g" | fold -sw 76 >>$LOGFILE
}

function checklock () {
# Checks for exclusive lock and wait until package managers are closed
while  fuser /var/lib/dpkg/lock 2>&1 >/dev/null  ; do
echo "# Waiting for other software managers to finish..." $"\n"
if [ "$(pidof synaptic)" ]; then
echo "# Waiting for other software managers to finish..." $"\nsynaptic"
fi
echo 1
sleep 1
echo 30
sleep 1
echo 60
sleep 1
if [ ! -z "$(pgrep gdebi-gtk)" ]; then
echo "# Waiting for other software managers to finish..." $"\ngdebi-gtk"
fi
echo 95
sleep 1
done | yad --progress --title="$APPNAME - close any open package managers" --percentage=20 --auto-close --auto-kill --button="Cancel:1"
if [[ $? -eq 1 ]];then
sleep 1
exit
fi
}


function showlog () {
if [[ ! -f $LOGFILE ]]; then
yad --info --title="$APPNAME Info" --text="No log file."
elif  [[  -z "$(cat $LOGFILE)"  ]]; then
yad --info --title="$APPNAME Info" --text="Log is empty."
else
yad --text-info  --button="Open log in Medit:0" --button="Close:1" --title="$APPNAME log file -> $log" --height=600 --width=800 --filename="$LOGFILE"
if [ "${PIPESTATUS[0]}" -eq "0" ]; then
medit "$LOGFILE" &
fi
fi
return
}

function about () {
yad --info --title="About $APPNAME " --height=20 --width=300 --text="$APPNAME is a small update GUI, fork of Linux Lite Upgrade tool and very easy to use.\n\nLicence GPL v3.\n\n Milos Pavlovic 2016"
return
}

function update() {

# Temporary file for error tracking
TMPLIST=$(mktemp /tmp/repos.XXXXXX)

APTUPDATE=$(grep '^deb' -c /etc/apt/sources.list) # Total number of repositories registered, this is approximated

apt-get update 2>&1 | tee $TMPLIST | awk -v total=$APTUPDATE '/^Ign|^Get/{count++;$1=""} FNR { if (total != 0){percentage=int (100*count/total);print (percentage < 90?percentage:90),"\n#",substr($0, 0, 128) }; fflush(stdout)}' \
| yad --progress --text="Updating package lists..." --window-icon="$ic" --title="Updating Software Sources - please wait..." --percentage=0 --auto-close --width=600

if [ "${PIPESTATUS[0]}" -ne "0" ]; then
err_msg=$(awk '/^(W:|E:)/{$1=""; print $0}' $TMPLIST | tail -n 1 ) #Get errors/warnings
log "ERROR: $err_msg"
unset APTUPDATE
rm -f $TMPLIST
unset TMPLIST
yad --error \
--title="Error" --text="$APPNAME couldn't fetch the package cache information lists.\nCheck the log for details"

return
fi

log "INFO: Software sources were updated."

unset APTUPDATE
rm -f $TMPLIST
unset TMPLIST

#  Temporary list of available updates
UPDATES=$(mktemp /tmp/updateslist.XXXXXX)

# Creates a list in /tmp/updateslist
apt-get --just-print $COMMAND 2>&1 | perl -ne 'if (/Inst\s([\w,\-,\d,\.,~,:,\+]+)\s\[([\w,\-,\d,\.,~,:,\+]+)\]\s\(([\w,\-,\d,\.,~,:,\+]+)\)? /i) {print "Name: $1 INSTALLED: $2 AVAILABLE: $3\n"}' | awk '{print NR,":\t"$0}' \
| tee $UPDATES  | yad --progress --window-icon="$ic" --pulsate --title="Calculating Updates" --text="Please wait..." --auto-close

# Check if any updates are available, if there are none, script pops up dialog box saying 'No Updates Available', removes /tmp/updateslist.XXXXXX
if [  -z "$(cat $UPDATES)"  ]; then
log "INFO: No updates are available."
rm -f $UPDATES
unset UPDATES
yad --info --window-icon=$ic --title="$APPNAME" \
--text="No Updates Available"

return
fi
# Log available updates
    lst_upgrades=$(awk 'BEGIN { FS = "[ ]" } { print $3 }' $UPDATES)
    log "INFO: Updates available: $lst_upgrades"
    unset lst_upgrades

# Insert text into  /tmp/updateslist.XXXXXX
sed -i -e '1 i\List of available Updates' -e '1 i\Click Update to continue or Cancel to stop the update process\n'  $UPDATES

# Erase existing available info
sudo dpkg --clear-avail

# Call the yad dialog to show update list
yad --text-info --window-icon="$ic" --ok-label="Update" --cancel-label="Cancel" --title="Available Updates" --width=780 --height=300 --filename="$UPDATES"

# Continue script if no halt
if [ "$?" -eq "0" ];then


# Write log
log "INFO: Update started."

# Remove tmp file and unset variable
rm -f $UPDATES
unset UPDATES

# Begin upgrade
DEBIAN_FRONTEND=noninteractive apt-get  -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" $COMMAND --show-progress -y  2>&1 | tee $UPDATELOG | awk ' BEGIN { FS=" "; total=1;end_download=0} /upgraded/ {total= $1 + $3;FS="[ :]" } /^Get:[[:digit:]]+/ {printf "#Downloading %s %s %s\n",$5,$(NF-1),$NF;print int(($2 - 1) * 100 / total); fflush(stdout)} /^\(Reading / {if (end_download==0){print 100;fflush(stdout);end_download=1}} /^(Preparing|Unpacking|Selecting|Processing|Setting|Download)/ {print "#", $0; fflush(stdout)}  /^Progress/ {print  match($0, /([0-9]+)/, arr); if(arr[1] != "") print arr[1] ; fflush(stdout)}' \
| ( yad --window-icon=$ic --progress --width=600 --text="Downloading package(s)...\nThis may take a while." --title="Downloading - please wait..." --percentage=0 --auto-close ; yad --progress --window-icon=$ic --width=600 --text="Installing and configuring packages...\nThis may take a while." --title="Installing - please wait..." --auto-close )

if [ "${PIPESTATUS[0]}" -ne "0" ]; then
err_msg=$(awk '/^(W:|E:)/{$1=""; print $0}' $UPDATELOG | tail -n 1)
log "ERROR:$err_msg"
yad --error \
--title="Error" --window-icon="$ic" --text="Updates have failed.\nCheck the log for details."
return
fi

# Halt updates script if user selects Cancel
else
log "INFO: User has canceled software upgrades."
rm -f $UPDATES
unset UPDATES
return
fi

log "INFO: Updates successfully installed."

PROCEED=$(yad --question --title="$APPNAME" --text="Updates have finished installing.\n\nWould you like to view the $APPNAME log?"; echo $?)

if [ ${PROCEED} -eq 1 ]; then
yad --info --title="$APPNAME" --text="Updates Complete."
return;
else
yad --text-info --ok-label="Quit" --cancel-label="Cancel" --title="Updates Log" --width=700 --height=300 --filename="$UPDATELOG"
fi

return
}


# Start the main loop
while (true); do
selection=$(yad --list --radiolist --title="$APPNAME" --window-icon="$ic" --text="Pick a task" --height=310 --width=350 --hide-column=2 --button="Exit:1" --button="Select:0" --column="Pick" --column="Function" --column="Task" \
"TRUE" "update" "Update Packages" "FALSE" "showlog" "Show log" "FALSE" "purgecache" "Purge the old cache" "FALSE" "about" "About this application" "FALSE" "exit" "Exit" --print-column=2) || exit
selection=$(echo $selection | cut -d '|' -f 1)

case "$selection" in
update) checklock; update
;;
showlog) showlog
;;
purgecache) checklock; sudo rm -vfd /var/lib/apt/lists/*  || yad --error --text="Error while purging the cache\nTry doing it manualy\nsudo rm -vfd /var/lib/apt/lists/* "
;;
about) about
;;
exit) exit 0
;;
esac
done

VastOne

  •      v-ger
  • Posts: 3931
    • View Profile
    • VSIDO Community
Re: apt-get upgrade and yad
« Reply #1 on: January 13, 2016, 12:58:40 AM »
Have you seen this discussion?

Will take a look at the script and try to debug as well

What do you name it?  I know I can use any, just wanting to know your naming convention

Thanks
VSIDO      VSIDO Twitter     VSIDO FB     VSIDO Google+   

I dev VSIDO

misko_2083

  • Posts: 70
    • View Profile
Re: apt-get upgrade and yad
« Reply #2 on: January 13, 2016, 06:39:10 AM »
Have you seen this discussion?

Will take a look at the script and try to debug as well

What do you name it?  I know I can use any, just wanting to know your naming convention

Thanks
Thank you.
I haven't came up with a name. Might as well be updater.sh as I named it here.  :D

I've come up with a solution. Killing all the processes with the name from basename.
Using the basename means the script name can be anything.
Code: [Select]
function checklock () {
# Checks for exclusive lock and wait until package managers are closed
while  fuser /var/lib/dpkg/lock 2>&1 >/dev/null  ; do
echo "# Waiting for other software managers to finish..." $"\n"
if [ "$(pidof synaptic)" ]; then
echo "# Waiting for other software managers to finish..." $"\nsynaptic"
fi
echo 1
sleep 1
echo 30
sleep 1
echo 60
sleep 1
if [ ! -z "$(pgrep gdebi-gtk)" ]; then
echo "# Waiting for other software managers to finish..." $"\ngdebi-gtk"
fi
echo 95
sleep 1
done | (if ! yad --progress --title="$APPNAME - close any open package managers" --percentage=20 --auto-close --button="Cancel:1";then killall $(basename $0); exit; fi)

}

misko_2083

  • Posts: 70
    • View Profile
Re: apt-get upgrade and yad
« Reply #3 on: January 13, 2016, 07:08:43 AM »
Hmm, yad-updater.sh would be a good name.  ;D
Fixed the text in the progress when downloading packages. It should display the package name when downloading, but not tested yet.
So here is the whole thing
Code: [Select]
#!/bin/bash
# Licensed under the GNU GPLv3.
#.%%...%%..%%%%%%...%%%%...%%..%%...%%%%.._.
#.%%%.%%%....%%....%%......%%.%%...%%..%%.2.
#.%%.%.%%....%%.....%%%%...%%%%....%%..%%.0.
#.%%...%%....%%........%%..%%.%%...%%..%%.8.
#.%%...%%..%%%%%%...%%%%...%%..%%...%%%%..3.
# Bash/YAD Debian Package Updater based on Linux Lite update tool
# ------- Change log ------
# Switched to YAD and adapted to Debian
# Added: a main dialog loop, log, option to purge the lists, about dialog
# Added: a check for exclusive lock
# -----------------------------------
# Note:
# -----------------------------------
# Milos Pavlovic
#

APPNAME="Update Tool"
LOGFILE=/var/log/misko-update.log
UPDATELOG=/var/log/last-update-log.log
# dist-upgrade or upgrade, change next line
COMMAND=dist-upgrade
# Yad window icon
ic=/usr/local/bin/images/vsidoorb_80.png

# Make sure only root can run our script
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root!" 1>&2
echo "TIP: Use gksudo or a similar tool." 1>&2
exit 1
fi

function log(){
message="$@"
echo '['$(date +%D\ %H:%M:%S)'] '$message | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})*)?m//g" | fold -sw 76 >>$LOGFILE
}

function checklock () {
# Checks for exclusive lock and wait until package managers are closed
while  fuser /var/lib/dpkg/lock 2>&1 >/dev/null  ; do
echo "# Waiting for other software managers to finish..." $"\n"
if [ "$(pidof synaptic)" ]; then
echo "# Waiting for other software managers to finish..." $"\nsynaptic"
fi
echo 1
sleep 1
echo 30
sleep 1
echo 60
sleep 1
if [ ! -z "$(pgrep gdebi-gtk)" ]; then
echo "# Waiting for other software managers to finish..." $"\ngdebi-gtk"
fi
echo 95
sleep 1
done | (if ! yad --progress --title="$APPNAME - close any open package managers" --percentage=20 --auto-close --button="Cancel:1";then killall $(basename $0); exit; fi)

}


function showlog () {
if [[ ! -f $LOGFILE ]]; then
yad --info --title="$APPNAME Info" --text="No log file."
elif  [[  -z "$(cat $LOGFILE)"  ]]; then
yad --info --title="$APPNAME Info" --text="Log is empty."
else
yad --text-info  --button="Open log in Medit:0" --button="Close:1" --title="$APPNAME log file -> $log" --height=600 --width=800 --filename="$LOGFILE"
if [ "${PIPESTATUS[0]}" -eq "0" ]; then
medit "$LOGFILE" &
fi
fi
return
}

function about () {
yad --info --title="About $APPNAME " --height=20 --width=300 --text="$APPNAME is a small update GUI, fork of Linux Lite Upgrade tool and very easy to use.\n\nLicence GPL v3.\n\n Milos Pavlovic 2016"
return
}

function update() {

# Temporary file for error tracking
TMPLIST=$(mktemp /tmp/repos.XXXXXX)

APTUPDATE=$(grep '^deb' -c /etc/apt/sources.list) # Total number of repositories registered, this is approximated

apt-get update 2>&1 | tee $TMPLIST | awk -v total=$APTUPDATE '/^Ign|^Get/{count++;$1=""} FNR { if (total != 0){percentage=int (100*count/total);print (percentage < 90?percentage:90),"\n#",substr($0, 0, 128) }; fflush(stdout)}' \
| yad --progress --text="Updating package lists..." --window-icon="$ic" --title="Updating Software Sources - please wait..." --percentage=0 --auto-close --width=600

if [ "${PIPESTATUS[0]}" -ne "0" ]; then
err_msg=$(awk '/^(W:|E:)/{$1=""; print $0}' $TMPLIST | tail -n 1 ) #Get errors/warnings
log "ERROR: $err_msg"
unset APTUPDATE
rm -f $TMPLIST
unset TMPLIST
yad --error \
--title="Error" --text="$APPNAME couldn't fetch the package cache information lists.\nCheck the log for details"

return
fi

log "INFO: Software sources were updated."

unset APTUPDATE
rm -f $TMPLIST
unset TMPLIST

#  Temporary list of available updates
UPDATES=$(mktemp /tmp/updateslist.XXXXXX)

# Creates a list in /tmp/updateslist
apt-get --just-print $COMMAND 2>&1 | perl -ne 'if (/Inst\s([\w,\-,\d,\.,~,:,\+]+)\s\[([\w,\-,\d,\.,~,:,\+]+)\]\s\(([\w,\-,\d,\.,~,:,\+]+)\)? /i) {print "Name: $1 INSTALLED: $2 AVAILABLE: $3\n"}' | awk '{print NR,":\t"$0}' \
| tee $UPDATES  | yad --progress --window-icon="$ic" --pulsate --title="Calculating Updates" --text="Please wait..." --auto-close

# Check if any updates are available, if there are none, script pops up dialog box saying 'No Updates Available', removes /tmp/updateslist.XXXXXX
if [  -z "$(cat $UPDATES)"  ]; then
log "INFO: No updates are available."
rm -f $UPDATES
unset UPDATES
yad --info --window-icon=$ic --title="$APPNAME" \
--text="No Updates Available"

return
fi
# Log available updates
    lst_upgrades=$(awk 'BEGIN { FS = "[ ]" } { print $3 }' $UPDATES)
    log "INFO: Updates available: $lst_upgrades"
    unset lst_upgrades

# Insert text into  /tmp/updateslist.XXXXXX
sed -i -e '1 i\List of available Updates' -e '1 i\Click Update to continue or Cancel to stop the update process\n'  $UPDATES

# Erase existing available info
sudo dpkg --clear-avail

# Call the yad dialog to show update list
yad --text-info --window-icon="$ic" --button="Update:0" --button="Cancel:1" --title="Available Updates" --width=780 --height=300 --filename="$UPDATES"

# Continue script if no halt
if [ "$?" -eq "0" ];then


# Write log
log "INFO: Update started."

# Remove tmp file and unset variable
rm -f $UPDATES
unset UPDATES

# Begin upgrade
DEBIAN_FRONTEND=noninteractive apt-get  -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" $COMMAND --show-progress -y  2>&1 | tee $UPDATELOG | awk ' BEGIN { FS=" "; total=1;end_download=0} /upgraded/ {total= $1 + $3;FS="[ :]" } /^Get:[[:digit:]]+/ {printf "#Downloading %s %s %s\n",$7,$(NF-1),$NF;print int(($2 - 1) * 100 / total); fflush(stdout)} /^\(Reading / {if (end_download==0){print 100;fflush(stdout);end_download=1}} /^(Preparing|Unpacking|Selecting|Processing|Setting|Download)/ {print "#", $0; fflush(stdout)}  /^Progress/ {print  match($0, /([0-9]+)/, arr); if(arr[1] != "") print arr[1] ; fflush(stdout)}' \
| ( yad --window-icon=$ic --progress --width=600 --text="Downloading package(s)...\nThis may take a while." --title="Downloading - please wait..." --percentage=0 --auto-close ; yad --progress --window-icon=$ic --width=600 --text="Installing and configuring packages...\nThis may take a while." --title="Installing - please wait..." --auto-close )

if [ "${PIPESTATUS[0]}" -ne "0" ]; then
err_msg=$(awk '/^(W:|E:)/{$1=""; print $0}' $UPDATELOG | tail -n 1)
log "ERROR:$err_msg"
yad --error \
--title="Error" --window-icon="$ic" --text="Updates have failed.\nCheck the log for details."
return
fi

# Halt updates script if user selects Cancel
else
log "INFO: User has canceled software upgrades."
rm -f $UPDATES
unset UPDATES
return
fi

log "INFO: Updates successfully installed."

PROCEED=$(yad --question --title="$APPNAME" --text="Updates have finished installing.\n\nWould you like to view the $APPNAME log?"; echo $?)

if [ ${PROCEED} -eq 1 ]; then
yad --info --title="$APPNAME" --text="Updates Complete."
return;
else
yad --text-info --ok-label="Quit" --cancel-label="Cancel" --title="Updates Log" --width=700 --height=300 --filename="$UPDATELOG"
fi

return
}


# Start the main loop
while (true); do
selection=$(yad --list --radiolist --title="$APPNAME" --window-icon="$ic" --text="Pick a task" --height=310 --width=350 --hide-column=2 --button="Exit:1" --button="Select:0" --column="Pick" --column="Function" --column="Task" \
"TRUE" "update" "Update Packages" "FALSE" "showlog" "Show log" "FALSE" "purgecache" "Purge the old cache" "FALSE" "about" "About this application" "FALSE" "exit" "Exit" --print-column=2) || exit
selection=$(echo $selection | cut -d '|' -f 1)

case "$selection" in
update) checklock; update
;;
showlog) showlog
;;
purgecache) checklock; sudo rm -vfd /var/lib/apt/lists/*  || yad --error --text="Error while purging the cache\nTry doing it manualy sudo rm /var/lib/apt/lists/* -vf"
;;
about) about
;;
exit) exit 0
;;
esac
done
Also fixed the button name here.

Could be an issue here and there but it's updating packages.
Having an option to select which package to update appears too complicated right now. I'll skip that one because it look's like a dependancy hell to me. :D