Enhanced visual feedback around tar & zsync! (#4194)

* Move Kindle scripts to FBInk
* Proper progress bars around tar invocations
* Spinner during zsync processing
pull/4203/head
NiLuJe 6 years ago committed by GitHub
parent 850be52177
commit ababbd7aad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -31,6 +31,7 @@ INSTALL_DIR=koreader-$(DIST)-$(MACHINE)
# platform directories
PLATFORM_DIR=platform
COMMON_DIR=$(PLATFORM_DIR)/common
KINDLE_DIR=$(PLATFORM_DIR)/kindle
KOBO_DIR=$(PLATFORM_DIR)/kobo
POCKETBOOK_DIR=$(PLATFORM_DIR)/pocketbook
@ -165,8 +166,7 @@ kindleupdate: all
ln -sf ../$(KINDLE_DIR)/launchpad $(INSTALL_DIR)/
ln -sf ../../$(KINDLE_DIR)/koreader.sh $(INSTALL_DIR)/koreader
ln -sf ../../$(KINDLE_DIR)/libkohelper.sh $(INSTALL_DIR)/koreader
ln -sf ../../$(KINDLE_DIR)/kotar_cpoint $(INSTALL_DIR)/koreader
ln -sf ../../$(KINDLE_DIR)/zsync_status.sh $(INSTALL_DIR)/koreader
ln -sf ../../$(COMMON_DIR)/spinning_zsync $(INSTALL_DIR)/koreader
# create new package
cd $(INSTALL_DIR) && pwd && \
zip -9 -r \
@ -198,7 +198,7 @@ koboupdate: all
cp $(KOBO_DIR)/koreader.png $(INSTALL_DIR)/koreader.png
cp $(KOBO_DIR)/fmon/README.txt $(INSTALL_DIR)/README_kobo.txt
cp $(KOBO_DIR)/*.sh $(INSTALL_DIR)/koreader
cp $(KOBO_DIR)/kotar_cpoint $(INSTALL_DIR)/koreader
cp $(COMMON_DIR)/spinning_zsync $(INSTALL_DIR)/koreader
# create new package
cd $(INSTALL_DIR) && \
zip -9 -r \

@ -1 +1 @@
Subproject commit 22d94e931c9f272eca96fbaab389afca6aaff3dc
Subproject commit f436894521f53a1440f40c35315da14d4b2a2894

@ -36,6 +36,7 @@ local OTAManager = {
installed_package = ota_dir .. "koreader.installed.tar",
package_indexfile = "ota/package.index",
updated_package = ota_dir .. "koreader.updated.tar",
can_pretty_print = lfs.attributes("./fbink", "mode") == "file" and true or false,
}
local ota_channels = {
@ -156,12 +157,14 @@ function OTAManager:fetchAndProcessUpdate()
text = _("KOReader will be updated on next restart."),
})
-- Make it clear that zsync is done
if Device:isKindle() then
os.execute("./zsync_status.sh clear")
elseif Device:isKobo() then
os.execute("./fbink -q -y -7 -pm ' ' ' '")
if self.can_pretty_print then
os.execute("./fbink -q -y -7 -pm ' ' ' '")
end
else
-- Make it clear that zsync is done
if self.can_pretty_print then
os.execute("./fbink -q -y -7 -pm ' ' ' '")
end
UIManager:show(ConfirmBox:new{
text = _("Error updating KOReader. Would you like to delete temporary files?"),
ok_callback = function()
@ -191,10 +194,33 @@ function OTAManager:_buildLocalPackage()
self.installed_package, self.package_indexfile))
else
-- With visual feedback if supported...
if lfs.attributes("./kotar_cpoint", "mode") == "file" then
if self.can_pretty_print then
os.execute("./fbink -q -y -7 -pmh 'Preparing local OTA package'")
-- We need a vague idea of how much space the tarball we're creating will take to compute a proper percentage...
-- Get the size from the latest zsync package, which'll be a closer match than anything else we might come up with.
local zsync_file = self:getZsyncFilename()
local local_zsync_file = ota_dir .. zsync_file
local tarball_size = nil
local zsync = io.open(local_zsync_file, "r")
if zsync then
for line in zsync:lines() do
tarball_size = line:match("^Length: (%d*)$")
if tarball_size then break end
end
zsync:close()
end
-- Next, we need to compute the amount of tar blocks that'll take, knowing that tar's default blocksize is 20 * 512 bytes.
-- c.f., https://superuser.com/questions/168749 & http://www.noah.org/wiki/tar_notes
-- Defaults to a sane-ish value as-of now, in case shit happens...
local blocks = 6405
if tarball_size then
blocks = tarball_size / (512 * 20)
end
-- And since we want a percentage, devise the exact value we need for tar to spit out exactly 100 checkpoints ;).
local cpoints = blocks / 100
return os.execute(string.format(
"./tar --no-recursion -cf %s -C .. -T %s --checkpoint=200 --checkpoint-action=exec='./kotar_cpoint $TAR_CHECKPOINT create'",
self.installed_package, self.package_indexfile))
"./tar --no-recursion -cf %s -C .. -T %s --checkpoint=%d --checkpoint-action=exec='./fbink -q -y -6 -P $(($TAR_CHECKPOINT/%d))'",
self.installed_package, self.package_indexfile, cpoints, cpoints))
else
return os.execute(string.format(
"./tar --no-recursion -cf %s -C .. -T %s",
@ -205,19 +231,19 @@ end
function OTAManager:zsync()
if self:_buildLocalPackage() == 0 then
-- Make it clear that it's now zsync churning CPU time, instead of tar churning IO ;).
if Device:isKindle() then
os.execute("./zsync_status.sh")
elseif Device:isKobo() then
os.execute("./fbink -q -y -7 -pmh 'Computing zsync delta . . .'")
local zsync_wrapper = "zsync"
-- With visual feedback if supported...
if self.can_pretty_print then
zsync_wrapper = "spinning_zsync"
end
return os.execute(
("./zsync -i %s -o %s -u %s %s%s"):format(
self.installed_package,
self.updated_package,
self:getOTAServer(),
ota_dir,
self:getZsyncFilename())
("./%s -i '%s' -o '%s' -u '%s' '%s%s'"):format(
zsync_wrapper,
self.installed_package,
self.updated_package,
self:getOTAServer(),
ota_dir,
self:getZsyncFilename())
)
end
end

@ -0,0 +1,42 @@
#!/bin/sh
# Small zsync wrapper so we can get a pretty spinner while it works...
./fbink -q -y -7 -pmh 'Computing zsync delta !'
# Clear any potential leftover from the local OTA tarball creation.
./fbink -q -y -6 -pm ' '
# Spin in the background while we work ;).
(
# See https://stackoverflow.com/questions/2685435 for inspiration
# as well as https://www.npmjs.com/package/cli-spinners
# & https://github.com/swelljoe/spinner
# http://www.fileformat.info/info/unicode/block/block_elements/list.htm
##
# Simple bars, they look better when a bit smoother, with a snappier interval (~250ms)
#SPINNER="<22> ▁ ▂ ▃ ▄ ▅ ▆ ▇ █ ▇ ▆ ▅ ▄ ▃ ▂ ▁"
#SPINNER="<22> ▏ ▎ ▍ ▌ ▋ ▊ ▉ █ ▉ ▊ ▋ ▌ ▍ ▎ ▏"
# Spinning blocks
SPINNER="▖ ▘ ▝ ▗"
#SPINNER="▜ ▟ ▙ ▛"
# Snaking blocks
#SPINNER="▌ ▀ ▐ ▄"
#SPINNER="▌ ▛ ▀ ▜ ▐ ▟ ▄ ▙"
while :; do
for spin in ${SPINNER}; do
usleep 500000
# NOTE: Throw stderr to the void because I'm cheating w/ U+FFFD for a blank character,
# which FBInk replaces by a blank, but not before shouting at us on stderr ;).
./fbink -q -y -7 -pmh "Computing zsync delta ${spin}" 2>/dev/null
done
done
) &
# Launch zsync, and remember its exit code...
./zsync "$@"
rc=$?
# Kill the spinner subshell now that we're done
kill -15 $!
# And return with zsync's exit code, not kill's ;).
exit ${rc}

@ -7,7 +7,7 @@ PROC_FIVEWAY="/proc/fiveway"
[ -e "${PROC_FIVEWAY}" ] && echo unlock >"${PROC_FIVEWAY}"
# KOReader's working directory
KOREADER_DIR="/mnt/us/koreader"
export KOREADER_DIR="/mnt/us/koreader"
# Load our helper functions...
if [ -f "${KOREADER_DIR}/libkohelper.sh" ]; then
@ -99,21 +99,17 @@ ko_update_check() {
NEWUPDATE="${KOREADER_DIR}/ota/koreader.updated.tar"
INSTALLED="${KOREADER_DIR}/ota/koreader.installed.tar"
if [ -f "${NEWUPDATE}" ]; then
logmsg "Updating koreader . . ."
# Look for our own GNU tar build to do a fancy progress tracking...
GNUTAR_BIN="${KOREADER_DIR}/tar"
if [ -x "${GNUTAR_BIN}" ]; then
# Let our checkpoint script handle the detailed visual feedback...
eips_print_bottom_centered "Updating KOReader" 3
# shellcheck disable=SC2016
${GNUTAR_BIN} -C "/mnt/us" --no-same-owner --no-same-permissions --checkpoint=200 --checkpoint-action=exec='./kotar_cpoint $TAR_CHECKPOINT' -xf "${NEWUPDATE}"
fail=$?
else
# Fall back to busybox tar
eips_print_bottom_centered "Updating KOReader . . ." 3
tar -C "/mnt/us" -xf "${NEWUPDATE}"
fail=$?
fi
logmsg "Updating KOReader . . ."
# Let our checkpoint script handle the detailed visual feedback...
eips_print_bottom_centered "Updating KOReader" 3
# NOTE: See frontend/ui/otamanager.lua for a few more details on how we squeeze a percentage out of tar's checkpoint feature
# NOTE: %B should always be 512 in our case, so let stat do part of the maths for us instead of using %s ;).
FILESIZE="$(stat -c %b "${NEWUPDATE}")"
BLOCKS="$((FILESIZE / 20))"
export CPOINTS="$((BLOCKS / 100))"
# shellcheck disable=SC2016
${KOREADER_DIR}/tar -C "/mnt/us" --no-same-owner --no-same-permissions --checkpoint="${CPOINTS}" --checkpoint-action=exec='$KOREADER_DIR/fbink -q -y -6 -P $(($TAR_CHECKPOINT/$CPOINTS))' -xf "${NEWUPDATE}"
fail=$?
# Cleanup behind us...
if [ "${fail}" -eq 0 ]; then
mv "${NEWUPDATE}" "${INSTALLED}"
@ -127,6 +123,7 @@ ko_update_check() {
eips_print_bottom_centered "KOReader may fail to function properly" 1
fi
rm -f "${NEWUPDATE}" # always purge newupdate in all cases to prevent update loop
unset BLOCKS CPOINTS
fi
}
# NOTE: Keep doing an initial update check, in addition to one during the restart loop, so we can pickup potential updates of this very script...

@ -1,44 +0,0 @@
#!/bin/sh
# KOReader's working directory
KOREADER_DIR="/mnt/us/koreader"
# We do NOT want to sleep during eips calls!
export EIPS_NO_SLEEP="true"
# Load our helper functions...
if [ -f "${KOREADER_DIR}/libkohelper.sh" ]; then
# shellcheck source=/dev/null
. "${KOREADER_DIR}/libkohelper.sh"
else
echo "Can't source helper functions, aborting!"
exit 1
fi
## First arg is the checkpoint number, and we get one every 200 checkpoints.
CHECKPOINT_NUM="${1}"
CHECKPOINT_GRANULARITY="200"
# Use that to build a progress bar
PROGRESS_AMOUNT="$((CHECKPOINT_NUM / CHECKPOINT_GRANULARITY))"
# Which text do we want to use?
case "${2}" in
"create")
PROGRESS_BASE_STRING="Preparing local OTA package"
;;
*)
PROGRESS_BASE_STRING="Updating KOReader"
;;
esac
# And start drawing the progress bar...
PROGRESS_STRING=""
for _ in $(seq 1 ${PROGRESS_AMOUNT}); do
# Fill the progress bar...
PROGRESS_STRING="${PROGRESS_STRING}."
done
# Print our progress :)
eips_print_bottom_centered "${PROGRESS_BASE_STRING}" 3
eips_print_bottom_centered "${PROGRESS_STRING}" 2

@ -14,91 +14,10 @@ else
[ -f /etc/rc.d/functions ] && . /etc/rc.d/functions
fi
# We need to get the proper constants for our model...
kmodel="$(cut -c3-4 /proc/usid)"
case "${kmodel}" in
"13" | "54" | "2A" | "4F" | "52" | "53")
# Voyage
SCREEN_X_RES=1088 # NOTE: Yes, 1088, not 1072 or 1080...
SCREEN_Y_RES=1448
EIPS_X_RES=16
EIPS_Y_RES=24 # Manually mesured, should be accurate.
;;
"24" | "1B" | "1D" | "1F" | "1C" | "20" | "D4" | "5A" | "D5" | "D6" | "D7" | "D8" | "F2" | "17" | "60" | "F4" | "F9" | "62" | "61" | "5F")
# PaperWhite & PaperWhite 2
SCREEN_X_RES=768 # NOTE: Yes, 768, not 758...
SCREEN_Y_RES=1024
EIPS_X_RES=16
EIPS_Y_RES=24 # Manually mesured, should be accurate.
;;
"C6" | "DD")
# KT2
SCREEN_X_RES=608
SCREEN_Y_RES=800
EIPS_X_RES=16
EIPS_Y_RES=24
;;
"0F" | "11" | "10" | "12")
# Touch
SCREEN_X_RES=600 # _v_width @ upstart/functions
SCREEN_Y_RES=800 # _v_height @ upstart/functions
EIPS_X_RES=12 # from f_puts @ upstart/functions
EIPS_Y_RES=20 # from f_puts @ upstart/functions
;;
*)
# Handle legacy devices...
if [ -f "/etc/rc.d/functions" ] && grep "EIPS" "/etc/rc.d/functions" >/dev/null 2>&1; then
# Already done...
#. /etc/rc.d/functions
echo "foo" >/dev/null
else
# Try the new device ID scheme...
kmodel="$(cut -c4-6 /proc/usid)"
case "${kmodel}" in
"0G1" | "0G2" | "0G4" | "0G5" | "0G6" | "0G7" | "0KB" | "0KC" | "0KD" | "0KE" | "0KF" | "0KG" | "0LK" | "0LL")
# PW3
SCREEN_X_RES=1088
SCREEN_Y_RES=1448
EIPS_X_RES=16
EIPS_Y_RES=24
;;
"0GC" | "0GD" | "0GR" | "0GS" | "0GT" | "0GU")
# Oasis
SCREEN_X_RES=1088
SCREEN_Y_RES=1448
EIPS_X_RES=16
EIPS_Y_RES=24
;;
"0LM" | "0LN" | "0LP" | "0LQ" | "0P1" | "0P2" | "0P6" | "0P7" | "0P8" | "0S1" | "0S2" | "0S3" | "0S4" | "0S7" | "0SA")
# Oasis 2
SCREEN_X_RES=1280 # NOTE: Yep, line_length/xres_virtual, not xres (1264)
SCREEN_Y_RES=1680
EIPS_X_RES=16 # TBD 19?
EIPS_Y_RES=24 # TBD 28? 25?!
;;
"0DU" | "0K9" | "0KA")
# KT3
SCREEN_X_RES=608
SCREEN_Y_RES=800
EIPS_X_RES=16
EIPS_Y_RES=24
;;
*)
# Fallback... We shouldn't ever hit that.
SCREEN_X_RES=600
SCREEN_Y_RES=800
EIPS_X_RES=12
EIPS_Y_RES=20
;;
esac
fi
;;
esac
# And now we can do the maths ;)
EIPS_MAXCHARS="$((SCREEN_X_RES / EIPS_X_RES))"
EIPS_MAXLINES="$((SCREEN_Y_RES / EIPS_Y_RES))"
# Adapted from libkh[5]
FBINK_BIN="/mnt/us/koreader/fbink"
# NOTE: Yeah, the name becomes a bit of a lie now that we're exclusively using FBInk ;p.
eips_print_bottom_centered() {
# We need at least two args
if [ $# -lt 2 ]; then
@ -109,22 +28,10 @@ eips_print_bottom_centered() {
kh_eips_string="${1}"
kh_eips_y_shift_up="${2}"
# Get the real string length now
kh_eips_strlen="${#kh_eips_string}"
# Add the right amount of left & right padding, since we're centered, and eips doesn't trigger a full refresh,
# so we'll have to padd our string with blank spaces to make sure two consecutive messages don't run into each other
kh_padlen="$(((EIPS_MAXCHARS - kh_eips_strlen) / 2))"
# Left padding...
while [ ${#kh_eips_string} -lt $((kh_eips_strlen + kh_padlen)) ]; do
kh_eips_string=" ${kh_eips_string}"
done
# Right padding (crop to the edge of the screen)
while [ ${#kh_eips_string} -lt ${EIPS_MAXCHARS} ]; do
kh_eips_string="${kh_eips_string} "
done
# Unlike eips, we need at least a single space to even try to print something ;).
if [ "${kh_eips_string}" = "" ]; then
kh_eips_string=" "
fi
# Sleep a tiny bit to workaround the logic in the 'new' (K4+) eInk controllers that tries to bundle updates,
# otherwise it may drop part of our messages because of other screen updates from KUAL...
@ -133,6 +40,7 @@ eips_print_bottom_centered() {
usleep 150000 # 150ms
fi
# And finally, show our formatted message centered on the bottom of the screen (NOTE: Redirect to /dev/null to kill unavailable character & pixel not in range warning messages)
eips 0 $((EIPS_MAXLINES - 2 - kh_eips_y_shift_up)) "${kh_eips_string}" >/dev/null
# NOTE: FBInk will handle the padding. FBInk's default font is square, not tall like eips,
# so we compensate by tweaking the baseline ;). This matches the baseline we use on Kobo, too.
${FBINK_BIN} -qpm -y $((-4 - kh_eips_y_shift_up)) "${kh_eips_string}"
}

@ -1,27 +0,0 @@
#!/bin/sh
# KOReader's working directory
KOREADER_DIR="/mnt/us/koreader"
# We do NOT want to sleep during eips calls!
export EIPS_NO_SLEEP="true"
# Load our helper functions...
if [ -f "${KOREADER_DIR}/libkohelper.sh" ]; then
# shellcheck source=/dev/null
. "${KOREADER_DIR}/libkohelper.sh"
else
echo "Can't source helper functions, aborting!"
exit 1
fi
# What are we printing?
case "${1}" in
"clear")
eips_print_bottom_centered " " 3
eips_print_bottom_centered " " 2
;;
*)
eips_print_bottom_centered "Computing zsync delta . . ." 3
;;
esac

@ -28,8 +28,14 @@ ko_update_check() {
NEWUPDATE="${KOREADER_DIR}/ota/koreader.updated.tar"
INSTALLED="${KOREADER_DIR}/ota/koreader.installed.tar"
if [ -f "${NEWUPDATE}" ]; then
./fbink -q -y -7 -pmh "Updating KOReader"
# NOTE: See frontend/ui/otamanager.lua for a few more details on how we squeeze a percentage out of tar's checkpoint feature
# NOTE: %B should always be 512 in our case, so let stat do part of the maths for us instead of using %s ;).
FILESIZE="$(stat -c %b "${NEWUPDATE}")"
BLOCKS="$((FILESIZE / 20))"
export CPOINTS="$((BLOCKS / 100))"
# shellcheck disable=SC2016
./tar xf "${NEWUPDATE}" --strip-components=1 --no-same-permissions --no-same-owner --checkpoint=200 --checkpoint-action=exec='./kotar_cpoint $TAR_CHECKPOINT'
./tar xf "${NEWUPDATE}" --strip-components=1 --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='./fbink -q -y -6 -P $(($TAR_CHECKPOINT/$CPOINTS))'
fail=$?
# Cleanup behind us...
if [ "${fail}" -eq 0 ]; then
@ -42,6 +48,7 @@ ko_update_check() {
./fbink -q -y -5 -pm "KOReader may fail to function properly!"
fi
rm -f "${NEWUPDATE}" # always purge newupdate in all cases to prevent update loop
unset BLOCKS CPOINTS
fi
}
# NOTE: Keep doing an initial update check, in addition to one during the restart loop, so we can pickup potential updates of this very script...

@ -1,28 +0,0 @@
#!/bin/sh
## First arg is the checkpoint number, and we get one every 200 checkpoints.
CHECKPOINT_NUM="${1}"
CHECKPOINT_GRANULARITY="200"
# Use that to build a progress bar
PROGRESS_AMOUNT="$((CHECKPOINT_NUM / CHECKPOINT_GRANULARITY))"
# Which text do we want to use?
case "${2}" in
"create")
PROGRESS_BASE_STRING="Preparing local OTA package"
;;
*)
PROGRESS_BASE_STRING="Updating KOReader"
;;
esac
# And start drawing the progress bar...
PROGRESS_STRING=""
for _ in $(seq 1 ${PROGRESS_AMOUNT}); do
# Fill the progress bar...
PROGRESS_STRING="${PROGRESS_STRING}."
done
# Print our progress :)
./fbink -q -y -7 -pmh "${PROGRESS_BASE_STRING}" "${PROGRESS_STRING}"
Loading…
Cancel
Save