Use virt-install to fully automate the install for Devuan with preseed

I recently discovered how to use a Debian preseed file while building a VM in kvm. After hand-crafting my Devuan preseed file, here it is in all my customized and I’m sure duplicate-filled and bogus-answer-encrusted glory.

How I use this

I define a variable, and plug it into the important parts.

vm=d2-04a ; time sudo virt-install -n "${vm}" --memory 2048 \
   --vcpus=1 --os-variant=debiantesting -v \
   --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=20 \
   -l /mnt/public/Support/SetupsBig/Linux/devuan_ascii_2.0.0-beta_amd64_DVD.iso \
   --initrd-inject=/mnt/public/Support/Platforms/devuan/preseed/preseed.cfg \
   --extra-args "hostname=${vm} NOTIFYEMAIL=bgstack15@gmail.com interface=auto" \
   --debug --network type=bridge,source=br0 --noautoconsole

Some thoughts

For some reason I was unable to get the preseed to work with the non-beta Ascii iso. When I started the preseed vm activity, I already had the beta disc so I was using it first before I downloaded the release disc, which didn’t even work. So I reverted to the beta disc. Please share any results, working or otherwise, you have when trying this with the release disc.
I do some tricky stuff in here with grub and the ceres release. Apparently consolekit messes with some of the files grub wants to lay down in /boot (having to do with locales), so I had to create this complex solution. I don’t even care that it’s “grub-legacy.” It seems a little simpler for a simpler time, and also works, so why bother doing anything different?

The preseed file

# File: /mnt/public/Support/Platforms/devuan/devuan-preseed1.txt
# Locations:
#    /mnt/public/Support/Platforms/devuan/devuan-preseed1.txt
# Author: bgstack15
# Startdate: 2019-06-25
# Title: Kickstart for CentOS 7 for ipa.smith122.com
# Purpose: To provide an easy installation for VMs and other systems in the Mersey network
# History:
#    2017-06 I learned how to use kickstart files for the RHCSA EX-200 exam
#    2017-08-08 Added notifyemail to --extra-args
#    2017-10-29 major revision to use local repository
#    2019-06-25 fork from centos7-ks.cfg
# Usage with virt-install:
#    vm=d2-04a ; time sudo virt-install -n "${vm}" --memory 2048 --vcpus=1 --os-variant=debiantesting -v --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=20 -l /mnt/public/Support/SetupsBig/Linux/devuan_ascii_2.0.0-beta_amd64_DVD.iso --initrd-inject=/mnt/public/Support/Platforms/devuan/preseed/preseed.cfg --extra-args "hostname=${vm} NOTIFYEMAIL=bgstack15@gmail.com interface=auto" --debug --network type=bridge,source=br0 --noautoconsole
#    vm=d2-04a; sudo virsh destroy "${vm}"; sudo virsh undefine --remove-all-storage "${vm}";
# Reference:
#    https://sysadmin.compxtreme.ro/automatically-set-the-hostname-during-kickstart-installation/
#    /mnt/public/Support/Platforms/CentOS7/install-vm.txt
#    https://serverfault.com/questions/481244/preseed-command-string-fail-with-newline-character-using-virt-install-initrd-inj
#    https://www.debian.org/releases/stable/i386/apbs01.html.en
#    https://github.com/jameswthorne/preseeds/blob/master/debian-7-wheezy-unattended.seed
#    syntax for --location https://www.queryxchange.com/q/1_908324/virt-install-preseed-not-working/
#    example preseed https://www.debian.org/releases/stable/example-preseed.txt
#    skip next dvd question https://unix.stackexchange.com/questions/409212/preseed-directive-to-skip-another-cd-dvd-scanning
#    grub problem caused by consolekit:amd64 https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=915947#10
#    https://stackoverflow.com/questions/39861614/how-to-fully-automate-unattended-virt-install
#    https://www.debian.org/releases/stable/i386/apbs03.html.en
#    https://dev1galaxy.org/viewtopic.php?id=1853
#    https://www.cyberciti.biz/faq/howto-setup-serial-console-on-debian-linux/
# Improve:
#    discover how to send email, using postfix or sendmail. Don't care which, but exclude exim4.
#    echo "$( hostname ) has IP $( ip -4 -o a s eth0 | awk '{print $4}' | sed -r -e 's/\/.*$//' )" | 
#    add the kernel lines: console=ttyS0 console=tty1. Get this to work; tried manually but perhaps devuan doesn't use console the same way?

d-i debian-installer/country string US
d-i debian-installer/keymap select us
d-i debian-installer/language string en
d-i debian-installer/locale string en_US
d-i localechooser/supported-locales string en_US.UTF-8

d-i keyboard-configuration/layoutcode string us
d-i keyboard-configuration/variantcode string
d-i keyboard-configuration/xkb-keymap select us

d-i netcfg/disable_autoconfig boolean false
d-i netcfg/get_domain string ipa.smith122.com
d-i netcfg/wireless_wep string
# disable asking for non-free firmware, because this is a vm and has none
d-i hw-detect/load_firmware boolean false

#d-i apt-setup/enable-source-repositories boolean false
# ORIGINAL d-i apt-setup/services-select multiselect security updates, release updates, backported software
d-i apt-setup/contrib boolean true
d-i apt-setup/disable-cdrom-entries boolean true
d-i apt-setup/non-free boolean true
d-i apt-setup/use_mirror boolean true
d-i mirror/country string manual
d-i mirror/http/directory string /devuan
d-i mirror/http/hostname string deb.devuan.org
d-i mirror/http/proxy string
d-i mirror/protocol string http
d-i mirror/suite string testing

d-i apt-setup/cdrom/set-failed boolean false
d-i apt-setup/cdrom/set-first boolean false
d-i apt-setup/cdrom/set-next boolean false

# my repos and ceres
d-i apt-setup/local0/comment string smith122deb
d-i apt-setup/local0/key string http://albion320.no-ip.biz/smith122/repo/deb/smith122deb.gpg
d-i apt-setup/local0/repository string http://albion320.no-ip.biz/smith122/repo/deb/ /
d-i apt-setup/local1/comment string devuan-deb
d-i apt-setup/local1/key string http://albion320.no-ip.biz/smith122/repo/deb/smith122deb.gpg
d-i apt-setup/local1/repository string http://albion320.no-ip.biz/smith122/repo/devuan-deb/ /
d-i apt-setup/local2/comment string ceres
d-i apt-setup/local2/key string https://pkgmaster.devuan.org/merged/dists/ceres/Release.gpg
d-i apt-setup/local2/repository string http://pkgmaster.devuan.org/merged ceres main contrib non-free
# if for some reason I really need to turn off the gpg key check:
#d-i debian-installer/allow_unauthenticated boolean false

tasksel tasksel/first multiselect standard, ssh-server

# adapted from /mnt/public/Support/Platforms/devuan/devuan.txt, main fluxbox desktop, but for a vm
# no xscreensaver, for a vm.
d-i pkgsel/include string \
   alsamixergui alttab apt-transport-https bgconf bgscripts bgscripts-core \
   cifs-utils curl fluxbox freeipa-client git grub lightdm lightdm-gtk-greeter \
   mlocate net-tools nfs-common ntpdate oddjob-mkhomedir=0.1-1 openssh-server \
   p7zip palemoon palemoon-ublock-origin parted qemu-guest-agent rsync scite \
   screen spice-vdagent strace sudo tcpdump vim vlc volumeicon-alsa waterfox \
   xfce4-terminal xfe xserver-xorg-video-qxl

d-i pkgsel/upgrade select none

popularity-contest popularity-contest/participate boolean true

d-i clock-setup/ntp boolean true
d-i clock-setup/ntp-server string dns1.ipa.smith122.com
d-i time/zone string America/New_York

# skip grub during main part, because we will do it in late_command
d-i grub-installer/skip boolean true
# these next 2 are experimental
d-i grub-installer/skip-again boolean true
d-i grub-installer/skip-confirm boolean true
d-i grub-installer/confirm_skip boolean true
d-i nobootloader/confirmation_common boolean true

d-i lilo-installer/skip boolean true
#d-i grub-installer/with_other_os boolean true
#d-i grub-installer/only_debian boolean true
#d-i grub-installer/grub2_instead_of_grub_legacy boolean true
#d-i grub-installer/bootdev string /dev/vda
#d-i grub-installer/choose_bootdev select /dev/vda
#grub-installer grub-installer/force-efi-extra-removable boolean false

d-i passwd/root-password password f0rg3tkickstart&
d-i passwd/root-password-again password f0rg3tkickstart&

d-i partman-auto/choose_recipe select home
d-i partman-auto-crypto/erase_disks boolean false
d-i partman-auto/disk string /dev/vda
d-i partman-auto/init_automatically_partition select biggest_free
d-i partman-auto/method string lvm
d-i partman/choose_label string gpt
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
d-i partman/confirm_write_new_label boolean true
d-i partman/default_label string gpt
#d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-md/confirm_nooverwrite boolean true
#d-i partman/mount_style select uuid
d-i partman-partitioning/confirm_write_new_label boolean true

# Uncomment this to add multiarch configuration for i386
#d-i apt-setup/multiarch string i386

d-i passwd/make-user boolean true
d-i passwd/user-fullname string bgstack15
d-i passwd/username string bgstack15
d-i passwd/user-password-crypted password $6$85aKM2DkiD5g9r3D$zkbcVES1Bzu.b5dBJxklSggEJzswZBlVAyc9LUUIzMA2OLRH2PD2ZWE9Q40Wtw/3OOxDM2nF031hfD4s5LGuG1
d-i passwd/user-default-groups string audio cdrom video

d-i finish-install/reboot_in_progress note
d-i cdrom-detect/eject boolean true

# additional application stuff just in case it works and is useful
# LDAP server URI:
d-i shared/ldapns/ldap-server	string	ldapi:///ipa.smith122.com

d-i openssh-server/password-authentication	boolean	true
d-i openssh-server/permit-root-login	boolean	false

# Remove consolekit from ceres, which disrupts /boot/grub/local/*mo files, that grub-install wants.
d-i preseed/late_command string in-target apt-get purge -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" consolekit exim4\* ; \
   apt-get install -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" postfix ; \
   in-target grub-install /dev/vda ; in-target update-grub ; \
   in-target wget http://albion320.no-ip.biz/smith122/certs/ca-ipa.smith122.com.crt -O /usr/local/share/ca-certificates/ca-ipa.smith122.com.crt && update-ca-certificates || : ; \
   in-target su bgstack15 -c "sudo /usr/bin/bgconf.py" 1>/root/clone.log 2>&1 ; \
   in-target sed -i -r -e '/^kernel/s/(\s*console=.{1,7}[0-9])*\s*$/ console=tty0 console=ttyS0/;' /boot/grub/menu.lst ; \
   in-target sed -i -r -e '$aT0:23:respawn:/sbin/getty -L ttyS0 9600 vt100' /etc/inittab

Use virt-install to fully automate the install for CentOS/Fedora with kickstart

Here is my kickstart file for CentOS 7. I deploy VMs into my kvm environment with a oneliner, using this kickstart file.

How I use this

I define a variable, and plug it into the important parts.

vm=c7-04a ; time sudo virt-install -n "${vm}" --memory 2048 \
   --vcpus=1 --os-variant=centos7.0 --accelerate -v \
   --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=20 \
   -l /mnt/public/Support/SetupsBig/Linux/CentOS-7-x86_64-Minimal-1810.iso \
   --initrd-inject=/mnt/public/Support/Platforms/CentOS7/centos7-ks.cfg \
   --extra-args "ks=file:/centos7-ks.cfg SERVERNAME=${vm} NOTIFYEMAIL=bgstack15@gmail.com" \
   --debug --network type=bridge,source=br0 --noautoconsole

Some thoughts

I had to download the 1810 release of the iso, because there was something wrong with the repos or perhaps files in the previous isos, with how they interacted with either the virtual environment or the network or something. But the CentOS-7-x86_64-minimal-1810.iso was important.
I found the SERVERNAME trick on the Internet. You can iterate over /proc/cmdline and react to values you find there, in the %pre or %post scripts.
You will see that I use my own local repositories for the regular CentOS repos, and I add my own internal one (smith122/repo/rpm). Obviously you should find a suitable set of repos for your own.
You will also see that I attempt to download my CA certificates at various points. I’m pretty sure the %pre effort fails, because the system is not on the network yet.

Dependencies

The kickstart file

# File: /mnt/public/Support/Platforms/CentOS7/centos7-ks.cfg
# Locations:
#    /mnt/public/Support/Platforms/CentOS7/centos7-ks.cfg
# Author: bgstack15
# Startdate: 2017-06-02
# Title: Kickstart for CentOS 7 for ipa.smith122.com
# Purpose: To provide an easy installation for VMs and other systems in the Mersey network
# History:
#    2017-06 I learned how to use kickstart files for the RHCSA EX-200 exam
#    2017-08-08 Added notifyemail to --extra-args
#    2017-10-29 major revision to use local repository
#
#
#
#
# Usage with virt-install:
#    vm=c7-04a ; time sudo virt-install -n "${vm}" --memory 2048 --vcpus=1 --os-variant=centos7.0 --accelerate -v --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=20 -l /mnt/public/Support/SetupsBig/Linux/CentOS-7-x86_64-Minimal-1810.iso --initrd-inject=/mnt/public/Support/Platforms/CentOS7/centos7-ks.cfg --extra-args "ks=file:/centos7-ks.cfg SERVERNAME=${vm} NOTIFYEMAIL=bgstack15@gmail.com" --debug --network type=bridge,source=br0 --noautoconsole
#    vm=c7-04a; sudo virsh destroy "${vm}"; sudo virsh undefine --remove-all-storage "${vm}";
# Reference:
#    https://sysadmin.compxtreme.ro/automatically-set-the-hostname-during-kickstart-installation/
#    /mnt/public/Support/Platforms/CentOS7/install-vm.txt

#platform=x86, AMD64, or Intel EM64T
#version=DEVEL
# Install OS instead of upgrade
install
# Keyboard layouts
keyboard 'us'
# Root password
rootpw --plaintext SOMETHINGSTRONGHERE
# my user
user --groups=wheel --name=bgstack15-local --password=$6$.gh0u7vg2HDPJPX/$g4Y1l.q76fs7i0UK8t6h83bDIo2YnGGj/1DGeUzzbMTd0pBh4of6jNYWxxws/937sUiPgETqPsYFI5XNrkAle. --iscrypted --gecos="bgstack15-local"

# System language
lang en_US.UTF-8
# Firewall configuration
firewall --enabled --ssh
# Reboot after installation
reboot
# Network information
#attempting to put it in the included ks file that accepts hostname from the virsh command.
#network  --bootproto=dhcp --device=eth0 --ipv6=auto --activate
%include /tmp/network.ks
# System timezone
timezone America/New_York --utc
# System authorization information
auth  --useshadow  --passalgo=sha512
# Use network installation instead of CDROM installation media
url --url="http://www.ipa.smith122.com/mirror/centos/7/os/x86_64/"

# Use text mode install
text
# SELinux configuration
selinux --enforcing
# Do not configure the X Window System
skipx

# Use all local repositories
# Online repos
repo --name=smith122rpm --baseurl=https://www.ipa.smith122.com/smith122/repo/rpm/
repo --name=base --baseurl=https://www.ipa.smith122.com/mirror/centos/$releasever/os/$basearch/
repo --name=updates --baseurl=https://www.ipa.smith122.com/mirror/centos/$releasever/updates/$basearch/
repo --name=extras --baseurl=https://www.ipa.smith122.com/mirror/centos/$releasever/extras/$basearch/
repo --name=epel --baseurl=https://www.ipa.smith122.com/mirror/fedora/epel/$releasever/$basearch

# Offline repos
#
#
#
#
#

firstboot --disabled

# System bootloader configuration
bootloader --location=mbr
# Partition clearing information
clearpart --all --initlabel
# Disk partitioning information
autopart --type=lvm

%pre
echo "network  --bootproto=dhcp --device=eth0 --ipv6=auto --activate --hostname renameme.ipa.smith122.com" > /tmp/network.ks
for x in $( cat /proc/cmdline );
do
   case $x in
      SERVERNAME*)
         eval $x
         echo "network  --bootproto=dhcp --device=eth0 --ipv6=auto --activate --hostname ${SERVERNAME}.ipa.smith122.com" > /tmp/network.ks
         ;;
      NOTIFYEMAIL*)
         eval $x
         echo "${NOTIFYEMAIL}" > /mnt/sysroot/root/notifyemail.txt
         ;;
   esac
done
cp -p /run/install/repo/ca-ipa.smith122.com.crt /etc/pki/ca-trust/source/anchors/ 2>/dev/null || :
wget http://www.ipa.smith122.com/smith122/certs/ca-ipa.smith122.com.crt -O /etc/pki/ca-trust/source/anchors/ca-ipa.smith122-wget.com.crt || :
update-ca-trust || :
%end

%post
(
   # Set temporary hostname
   #hostnamectl set-hostname renameme.ipa.smith122.com;

   # Get local mirror root ca certificate
   wget http://www.ipa.smith122.com/smith122/certs/ca-ipa.smith122.com.crt -O /etc/pki/ca-trust/source/anchors/ca-ipa.smith122.com.crt && update-ca-trust

   # Get local mirror repositories
   wget https://www.ipa.smith122.com/smith122/repo/rpm/smith122rpm.repo -O /etc/yum.repos.d/smith122rpm.repo;
   wget http://www.ipa.smith122.com/smith122/repo/rpm/smith122rpm.mirrorlist -O /etc/yum.repos.d/smith122rpm.mirrorlist
   distro=centos7 ; wget https://www.ipa.smith122.com/smith122/repo/mirror/smith122-bundle-${distro}.repo -O /etc/yum.repos.d/smith122-bundle-${distro}.repo && grep -oP "(? /boot/grub2/grub.cfg

   # postfix is already started by default on centos7
   # Send IP address to myself
   thisip="$( ifconfig 2>/dev/null | awk '/Bcast|broadcast/{print $2}' | tr -cd '[^0-9\.\n]' | head -n1 )"
   {
      echo "${SERVER} has IP ${thisip}."
      echo "system finished kickstart at $( date "+%Y-%m-%d %T" )";
   } | /usr/share/bgscripts/send.sh -f "root@$( hostname --fqdn )" \
      -h -s "${SERVER} is ${thisip}" $( cat /root/notifyemail.txt 2>/dev/null )

   # No changes to graphical boot
   #

   # fix the mkhomedir problem
   systemctl enable oddjobd.service && systemctl start oddjobd.service

   # Personal customizations
   mkdir -p /mnt/bgstack15 /mnt/public
   su bgstack15-local -c "sudo /usr/share/bgconf/bgconf.py"

) >> /root/install.log 2>&1
%end

%packages
@core
@^minimal
autossh
bc
bgconf
bgscripts-core
bind-utils
cifs-utils
cryptsetup
dosfstools
epel-release
expect
firewalld
git
iotop
ipa-client
-iwl*-firmware
mailx
man
mlocate
net-tools
nfs-utils
ntp
p7zip
parted
policycoreutils-python
rpm-build
rsync
screen
strace
sysstat
tcpdump
telnet
vim
wget
yum-utils
%end

Convert vhs video tape to mkv file in Linux

Last updated 2019-09-11

I still own video tapes (VHS) and I have finally gotten around to getting a nice setup for saving them down to hard disk so I can clear out the old video tape collection. This is how I did it.
First of all, I knew I needed an RCA-to-something adapter. I found an “AV to USB converter” [amazon.com] that does the trick. When attached to a Ubuntu 16.04 system, it shows up as /dev/video0. No additional steps required! To quote one of my role models [thealaskalinuxuser.com] on the Internet: “Linux — keep it simple.”
Now, I discovered over time that the audio input just didn’t work. But the video comes in perfectly! I was using vlc [videolan.org] for the input capture. To get the audio to work, I had to find an RCA to mini-phono cable which I already owned. An example product is on monoprice.com [monoprice.com].
I also had to fiddle with the audio input settings to get the input to work right. I had to poke around with pulseaudio, alsa, and vlc to get the audio input to work the way I needed it.
For my setup (pictured below), I needed to make sure my input source was mic (the front jack on my desktop computer) and not line, which is probably the input in the back. I chose to set my mic boost (akin to gain) really low, and capture volume really high.

screenshot of alsa mixer on capture settings screen
I needed to set pulseaudio to allow the stereo input. I have discovered that pulseaudio is fragile, and also never remembers the settings I choose for it, so for every reboot or login or pulseaudio –start command, I have to go readjust the “profile.” I am starting to understand why people smarter (and more verbose) than me tend to dislike pulseaudio.
pavucontrol showing configuration
With alsa and pulse set up correctly, it is now a matter of getting vlc to accept the audio input while accepting the video input. I had to discover how my system identifies the audio jack.

$ arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: PCH [HDA Intel PCH], device 0: CX20641 Analog [CX20641 Analog]
  Subdevices: 0/1
  Subdevice #0: subdevice #0
card 0: PCH [HDA Intel PCH], device 2: CX20641 Alt Analog [CX20641 Alt Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: USB20 [AV TO USB2.0], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

By trial and error, I learned the mic input is card 0, device 2. In alsa terms, that’s alsa://0,2.
So, to put it all together, I had to set VLC to open a “capture device” of /dev/video0, with audio device of hw:0,2. To get the audio and video to both be output by VLC, I had to go into advanced optiosn and se audio input = 0.
screenshot of vlc with /dev/video0, hw:0,2 and audio input=0 VLC always defaults to audio input=-1, so no audio will come through.
When I selected the Play button, it presents both audio and video from the VCR!
So, with the video on the screen that I want, I pressed the record button (from the toolbar visible when you select View -> Advanced controls). VLC records by default to avi format, which is not my preferred method, even though it is a temporary format.
So, I had to set all the settings again, and then select the drop-down arrow beside the Play button, and select “Convert.” A new window appears, and I select the file format I want and the output file.

With all the options set, I now return to the first options screen and select the “Convert” button.
After running through the whole video, I come back and hit stop in VLC.
I use HandBrake [handbrake.fr] to convert the file to the format I want. The details of that are beyond the scope of this post.
For a bonus, I discovered that killing vlc safely closes the written file, so it is still viewable. So I just run a command in a terminal to kill vlc after the published length of the videotape:

$ sleep $(( 60 * 120 )) ; killall vlc

I could have done something fancier with xdotool to select the “stop” button, but why bother?

Addendum

For some reason, when I capture video (possibly because of the NTSC framerate conversation), the audio gets a little bit out of sync with the video. Thankfully, there is a tool that can change the scale of the audio to video: mkvmerge, which is a part of mkvtoolnix suite. After much experimentation, I am satisfied that a safe number to use to scale the audio perfectly from my VCR for all content is in this command:

mkvmerge -y '1:0,100.060552/100' -o new.mkv old.mkv

That is take stream 1 (zero-indexed, and usually the audio in a simple captured video file) and stretch it with an anchor point of zero to 100.060552% of the original speed. So it slows down the audio, and then the audio syncs perfectly with the video, for a 2-hour movie.

Display svg in tkinter python3

The Internet has a guide for displaying svgs in Tkinter in Python 2: http://code.activestate.com/lists/python-list/595078/
However, I have not found any guides for the process for python3. And since I don’t want to move backwards, I had to come up with something.

Here is my solution. (link)
Screenshot of tkinter window with svgs rendered as the images on buttons, one scaled and one unscaled.

#!/usr/bin/env python3
# File: svgs-tkinter-python3.py
# License: CC-BY-SA 4.0
# Author: bgstack15
# Startdate: 2019-06-21 10:09
# Title: 
# Purpose: 
# History:
# Usage:
# References:
#    http://effbot.org/tkinterbook/button.htm
#    http://effbot.org/tkinterbook/tkinter-application-windows.htm
#    http://effbot.org/tkinterbook/
#    https://stackoverflow.com/questions/18537918/set-window-icon#18538416
#    https://pillow.readthedocs.io/en/stable/reference/ImageTk.html
# Improve:
# Dependencies:
#    devuan: python3-tk python3-pil.imagetk python3-cairosvg
#    el7: python36-tkinter python36-pillow-tk ( pip3 install cairosvg )

import re
import tkinter as tk
from PIL import Image, ImageTk, PngImagePlugin

LM_USE_SVG = 0
try:
   from cairosvg import svg2png
   LM_USE_SVG = 1
except:
   print("WARNING: Unable to import cairosvg. No svg images will be displayed.")
   LM_USE_SVG = 0

# graphical classes and functions
print("Loading graphics...")

def photoimage_from_svg(filename = "",size = "48"):
   # this one works, but does not allow me to set the size.
   # this is kept as an example of how to open a svg without saving to a file.
   # open svg
   item = svg2png(url=filename, parent_width = size, parent_height = size)
   return ImageTk.PhotoImage(data=item)

def empty_photoimage(size=24):
   photo = Image.new("RGBA",[size,size])
   return ImageTk.PhotoImage(image=photo)

def image_from_svg(filename = "",size = 0):
   # open svg
   if LM_USE_SVG == 1:
      if size == 0:
         # unscaled
         svg2png(url=filename,write_to="/tmp/example_temp_image.png")
      else:
         svg2png(url=filename,write_to="/tmp/example_temp_image.png",parent_width = size,parent_height = size)
      photo = Image.open("/tmp/example_temp_image.png")
   else:
      photo = Image.new("RGBA",[size,size])
   return photo

def get_scaled_icon(iconfilename, size = 0):

   try:
      print("Opening icon file",iconfilename)
      # try an svg
      if re.compile(".*\.svg").match(iconfilename):
         photo = image_from_svg(filename=iconfilename, size=size)
      else:
         photo = Image.open(iconfilename)
   except Exception as f:
      print("Error with icon file:", f)
      return empty_photoimage()

   if size != 0 and (type(photo) is Image or type(photo) is PngImagePlugin.PngImageFile):
      photo.thumbnail(size=[size, size])

   if not type(photo) is ImageTk.PhotoImage:
      try:
         photo = ImageTk.PhotoImage(photo)
      except Exception as e:
         print("Error was ",e)
   return photo

class App:
   def __init__(self, master):
      frame = tk.Frame(master)
      frame.grid(row=0)

      self.photo1 = get_scaled_icon("/usr/share/icons/Numix/128/actions/system-log-out.svg", 20)
      self.button1 = tk.Button(frame, text="Scaled to 24x24", image=self.photo1, compound=tk.LEFT)
      self.button1.grid(row=0,column=0)

      self.photo2 = get_scaled_icon("/usr/share/icons/Numix/128/actions/system-log-out.svg")
      self.button2 = tk.Button(frame, text="Unscaled", image=self.photo2, compound=tk.LEFT)
      self.button2.grid(row=0,column=1)

      self.buttonCancel = tk.Button(frame, text="Cancel", underline=0, command=self.quitaction)
      self.buttonCancel.grid(row=1,columnspan=8,sticky=tk.W+tk.E)

   def quitaction(self,b=None):
      print("Closing the window...")
      root.destroy()

root = tk.Tk()

# MAIN LOOP
root.title("SVG examples")
imgicon = get_scaled_icon("/usr/share/icons/Numix/128/actions/system-log-out.svg", 24)
root.tk.call('wm','iconphoto', root._w, imgicon)
app = App(root)
root.mainloop()
try:
   root.destroy()
except:
   pass

Install cairosvg for python3 on el7

I wanted to install cairosvg on my CentOS 7 terminal server.
Come to find out, I had to install in using pip, because el7 only has cairosvg for the python2.

# yum list python-cairosvg
Loaded plugins: ulninfo
Installed Packages
python-cairosvg.noarch                                             1.0.7-3.el7                                             @epel

So, I had to go get pip3.
Enable the correct repos when installing pip3 and the dependencies for cairosvg.

yum --enablerepo=epel,updates install python36-pip cairo python36-devel libffi-devel

Use the http proxy when calling pip3 to update itself.

$ sudo https_proxy=http://10.123.456.789:3128 pip3 install --upgrade pip

And then, installing cairosvg failed.

# https_proxy=http://10.123.456.789:3128 pip3 install cairosvg
Collecting cairosvg
  Using cached https://files.pythonhosted.org/packages/fd/97/d0f51b1022aecdc3b77385daea0292f3978ec26fee31e65e8a1592ebeff1/CairoSVG-2.4.0-py3-none-any.whl
Collecting defusedxml (from cairosvg)
  Using cached https://files.pythonhosted.org/packages/06/74/9b387472866358ebc08732de3da6dc48e44b0aacd2ddaa5cb85ab7e986a2/defusedxml-0.6.0-py2.py3-none-any.whl
Collecting cairocffi (from cairosvg)
  Using cached https://files.pythonhosted.org/packages/0f/0f/7e21b5ddd31b610e46a879c0d21e222dd0fef428c1fc86bbd2bd57fed8a7/cairocffi-1.0.2.tar.gz
    ERROR: Complete output from command python setup.py egg_info:
    ERROR: warning: no previously-included files found matching 'setup.pyc'
    warning: no previously-included files matching 'yacctab.*' found under directory 'tests'
    warning: no previously-included files matching 'lextab.*' found under directory 'tests'
    warning: no previously-included files matching 'yacctab.*' found under directory 'examples'
    warning: no previously-included files matching 'lextab.*' found under directory 'examples'
    zip_safe flag not set; analyzing archive contents...
    pycparser.ply.__pycache__.lex.cpython-36: module references __file__
    pycparser.ply.__pycache__.lex.cpython-36: module MAY be using inspect.getsourcefile
    pycparser.ply.__pycache__.yacc.cpython-36: module references __file__
    pycparser.ply.__pycache__.yacc.cpython-36: module MAY be using inspect.getsourcefile
    pycparser.ply.__pycache__.yacc.cpython-36: module MAY be using inspect.stack
    pycparser.ply.__pycache__.ygen.cpython-36: module references __file__
    
    Installed /tmp/pip-install-lxiyvrgx/cairocffi/.eggs/pycparser-2.19-py3.6.egg
    Traceback (most recent call last):
      File "", line 1, in 
      File "/tmp/pip-install-lxiyvrgx/cairocffi/setup.py", line 13, in 
        'cairocffi/ffi_build.py:ffi_pixbuf']
      File "/usr/lib/python3.6/site-packages/setuptools/__init__.py", line 129, in setup
        return distutils.core.setup(**attrs)
      File "/usr/lib64/python3.6/distutils/core.py", line 108, in setup
        _setup_distribution = dist = klass(attrs)
      File "/usr/lib/python3.6/site-packages/setuptools/dist.py", line 370, in __init__
        k: v for k, v in attrs.items()
      File "/usr/lib64/python3.6/distutils/dist.py", line 281, in __init__
        self.finalize_options()
      File "/usr/lib/python3.6/site-packages/setuptools/dist.py", line 529, in finalize_options
        ep.load()(self, ep.name, value)
      File "/tmp/pip-install-lxiyvrgx/cairocffi/.eggs/cffi-1.12.3-py3.6-linux-x86_64.egg/cffi/setuptools_ext.py", line 217, in cffi_modules
        add_cffi_module(dist, cffi_module)
      File "/tmp/pip-install-lxiyvrgx/cairocffi/.eggs/cffi-1.12.3-py3.6-linux-x86_64.egg/cffi/setuptools_ext.py", line 49, in add_cffi_module
        execfile(build_file_name, mod_vars)
      File "/tmp/pip-install-lxiyvrgx/cairocffi/.eggs/cffi-1.12.3-py3.6-linux-x86_64.egg/cffi/setuptools_ext.py", line 25, in execfile
        exec(code, glob, glob)
      File "cairocffi/ffi_build.py", line 26, in 
        ffi = FFI()
      File "/tmp/pip-install-lxiyvrgx/cairocffi/.eggs/cffi-1.12.3-py3.6-linux-x86_64.egg/cffi/api.py", line 48, in __init__
        import _cffi_backend as backend
    ImportError: /tmp/pip-install-lxiyvrgx/cairocffi/.eggs/cffi-1.12.3-py3.6-linux-x86_64.egg/_cffi_backend.cpython-36m-x86_64-linux-gnu.so: failed to map segment from shared object: Operation not permitted
    ----------------------------------------
ERROR: Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-lxiyvrgx/cairocffi/

So I had to remount /tmp temporarily with exec, because I know it was mounted with noexec.

mount -o rw,remount,exec /tmp

And after I reran the install command, it worked!

# https_proxy=http://10.123.456.789:3128 pip3 install cairosvg
[ TRUNCATED ]
Installing collected packages: pycparser, cffi, cairocffi, webencodings, tinycss2, cssselect2, defusedxml, cairosvg
  Running setup.py install for pycparser ... done
  Running setup.py install for cairocffi ... done

References

  1. https://cairosvg.org/documentation/
  2. Original research

Firefox disable a ping

What is an html a ping

An html “a ping” is a characteristic of an <a> tag that is used to track when a link is followed.
An example: the following link to the front page of this blog has an A ping characteristic:
https://bgstack15.wordpress.com

The characteristic looks like:

<a href="https://bgstack15.wordpress.com" ping="https://bgstack15.wordpress.com/ping">https://bgstack15.wordpress.com</a>

Disable html ping in Firefox

In about:config, set:

browser.send_pings = false

References

Weblinks

  1. https://www.thewindowsclub.com/ping-hyperlink-auditing-in-chrome-firefox