post-install/post-install
Alex A. Naanou a64d76dbd1 added exif manipulation packages...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2024-06-27 16:32:27 +03:00

996 lines
22 KiB
Bash
Executable File

#!/usr/bin/env bash
#----------------------------------------------------------------------
#
# TODO:
# - keyd -- copy config from syncthing...
# - tor (user) + link cfg
# - link config files
# - copy config files
# - edit system config files
# - might be a good idea to add gui/no-gui options...
# - ssh-keygen...
# - add --system and --user flags to only do system/user stuff...
# - profile packager/extractor???
#
# XXX Q: should we do this based on feature or as it is now???
# A: looks like it would be logical to split this in two:
# - general system state and singular tools
# - tasks -- each can consist of configuration and several packages...
#
#
# XXX @ does not work with cat <<EOF | ...
#
#
#----------------------------------------------------------------------
# options...
#FEATURE_DIR=
#DRY_RUN=
#QUIET=
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CMD=$(basename $0)
SYSTEM_RC=${0}rc
USER_RC=~/.${CMD}rc
# XXX do we need to split user and system scripts???
SCRIPT_DIR=${0}.d/
USER_SCRIPT_DIR=${0}.d/user/
# System info...
function systemInfo(){
if ! [ -z "$(type -t dmidecode )" ] ; then
# XXX should we be more specific here and include model number??
PLATFORM=$( sudo dmidecode \
| grep -A3 '^System Information' \
| grep 'Version:' \
| sed 's/\s*Version:\s*//' )
elif ! [ -z "$(type -t uname )" ] ; then
PLATFORM=$(uname -o)
else
PLATFORM=unknown
fi
PLATFORM_SCRIPT_DIR=${SCRIPT_DIR}/platform/${PLATFORM}
}
#----------------------------------------------------------------------
# configuration....
# see: ALL_FEATURES below...
FEATURES=(
dir
dnf-config
rpmfusion
flathub
dnf
flatpak
npm
vim
start-services
start-user-services
bashctrl
syncthing
# these can depend on some services like syncthing...
#user-link
#user-copy
scripts
platform-scripts
user-scripts
)
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DIR=(
~/.bashrc.d
~/bin
~/.config
~/.local/share
~/Sync/ALL
~/work/EXTERNAL
)
# NOTE: $DIR and these are not run in order -- linking may need other
# stuff done before...
# XXX
CFG_USER_SOURCE=~/Sync/CONFIG/Linux/
CFG_USER_LINK=(
.gitconfig
.vimrc .gvimrc .vim
.tmux.conf
.config/mc
.config/ulauncher
)
CFG_USER_COPY=(
)
PKG_DNF=(
# system...
cronie
# graphics...
# install, run vainfo and install the missing driver, e.g. intel-media-driver
# also see: https://github.com/intel/media-driver#known-issues-and-limitations for codec support
libva-utils
# for intel onboard graphics...
# test if needed:
# $ vainfo
#intel-media-driver
# also see: https://github.com/AdnanHodzic/auto-cpufreq
tlp
acpi
smartmontools
# tools and recovery...
gparted gdisk testdisk
# networking...
tor obfs4
yt-dlp qbittorrent
perl-Image-ExifTool
# tools...
openssl gpm
mc ranger vifm tmux bat
btop htop iftop iotop
ncdu cpu-x glances stacer
jdupes
keepassxc
kitty
nextcloud-client
# fonts...
mscore-fonts-all
# tty fonts...
# /etc/vconsole.conf
# FONT="ter-v24n"
# /etc/defaults/grub -- kernel options, add: vconsole.font=...
# GRUB_TERMINAL_OUTPUT="gfxterm"
# # $ sudo grub2-mkfont \
# # --output=/boot/efi/EFI/fedora/fonts/ter-u32n.pf2 \
# # /usr/share/fonts/terminus-fonts/ter-u32n.otb
# GRUB_FONT="/boot/efi/EFI/fedora/fonts/ter-u32n.pf2"
# # XXX this sees to have no effect until /etc/vconsole.conf is
# # loaded...
# GRUB_CMDLINE_LINUX="... vconsole.font=ter-v24n"
# XXX should we also add a feature to set these up???
terminus-fonts
terminus-fonts-console
terminus-fonts-grub2
# dev...
git
p7zip zip unrar
nodejs golang
# media...
vlc mpv
ffmpeg
mkvtoolnix-gui
avidemux
exiftool exiv2 vips-tools
# codecs...
gstreamer1-plugin-openh264
gstreamer1-plugins-bad-free
gstreamer1-plugins-bad-freeworld
gstreamer1-plugins-base
gstreamer1-plugins-good
gstreamer1-plugins-good-gtk
gstreamer1-plugins-good-qt
gstreamer1-plugins-ugly
gstreamer1-plugins-ugly-free
# desktop...
ulauncher
gnome-tweaks
gnome-shell-extension-gsconnect
# apps...
krita
pdftk
# XXX needed for OBS' virtual camera + requires rpmfusion
# $ sudo dnf install \
# https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm
# $ sudo dnf install \
# https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm
# v4l2loopback
# Gnome shell extensions...
gnome-shell-extension-gsconnect
gnome-shell-extension-caffeine
gnome-shell-extension-dash-to-dock
gnome-shell-extension-blur-my-shell
#gnome-shell-extension-just-perfection
)
PKG_NPM=(
tldr
)
PKG_FLATPAK=(
# system...
com.github.tchx84.Flatseal
com.mattjakeman.ExtensionManager
io.github.realmazharhussain.GdmSettings
org.gustavoperedo.FontDownloader
# net...
org.briarproject.Briar
com.github.Eloston.UngoogledChromium
# media...
fr.handbrake.ghb
fr.handbrake.ghb.Plugin.IntelMediaSDK
# tools...
ch.openboard.OpenBoard
org.blender.Blender
)
PKG_SNAP=(
irfanview
foobar2000
snap-store
)
PKG_GO=(
github.com/charmbracelet/gum@latest
)
SERVICES_START=(
crond sshd gpm
)
SERVICES_USER_START=(
)
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SAVE=(
FEATURES
DIR
PKG_DNF PKG_FLATPAK PKG_NPM PKG_SNAP
SERVICES_START SERVICES_USER_START
CFG_USER_SOURCE CFG_USER_LINK CFG_USER_COPY
)
#----------------------------------------------------------------------
# Builtin features...
ALL_FEATURES=($( \
cat $0 \
| grep '^function feature-' \
| sed 's/function feature-\([^(]*\)(.*$/\1/' \
| sort))
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# For more info see:
# https://fedoramagazine.org/hibernation-in-fedora-36-workstation/
function feature-hibernate(){
# dracut configuration...
cat <<-EOF | sudo tee /etc/dracut.conf.d/resume.conf
add_dracutmodules+=" resume "
EOF
@ dracut -f
# a service to disable zram before we hibernate...
# XXX do we need to enable the swap here too???
cat <<-EOF | sudo tee /etc/systemd/system/hibernate-preparation.service
[Unit]
Description=Disable zram before hibernate
Before=systemd-hibernate.service
[Service]
User=root
Type=oneshot
ExecStart=/usr/sbin/swapoff /dev/zram0
[Install]
WantedBy=systemd-hibernate.service
EOF
@ sudo systemctl enable hibernate-preparation.service
# disable some memory checks...
mkdir -p /etc/systemd/system/systemd-logind.service.d/
cat <<-EOF | sudo tee /etc/systemd/system/systemd-logind.service.d/override.conf
[Service]
Environment=SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1
EOF
@ sudo mkdir -p /etc/systemd/system/systemd-hibernate.service.d/
cat <<-EOF | sudo tee /etc/systemd/system/systemd-hibernate.service.d/override.conf
[Service]
Environment=SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1
EOF
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-dnf-config(){
if [ -z "$(grep 'f_lynx/post-install' /etc/dnf/dnf.conf)" ] ; then
echo Updating config
# a bit ugly...
cat <<-EOF | sudo tee -a /etc/dnf/dnf.conf > /dev/null
# added by f_lynx/post-install script...
fastmirror=True
max_parallel_downloads=10
defaultyes=True
EOF
else
echo Already updated.
fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-dir(){
@setupList mkdir -p - ${DIR[@]}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# link user files/dirs (syncthing, ...)...
##function feature-user-link(){
## # XXX
## true
##}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# copy user files/dirs (syncthing, ...)...
##function feature-user-copy(){
## # XXX
## true
##}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-dnf(){
@ sudo dnf update
@setupList sudo dnf install - ${PKG_DNF[@]}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-npm(){
@setupList sudo npm install -g - ${PKG_NPM[@]}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-rpmfusion(){
@ sudo dnf install \
https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm
@ sudo dnf install \
https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-flathub(){
@ sudo flatpak remote-add --if-not-exists flathub \
https://flathub.org/repo/flathub.flatpakrepo
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-flatpak(){
@setupList sudo flatpak install - ${PKG_FLATPAK[@]}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-snap(){
@ sudo dnf install snapd
@ sudo ln -s /var/lib/snapd/snap /snap
# this is here to compensate for snap not being ready right away...
# ...did not dig into why...
@ sleep 5
@setupList sudo snap install - ${PKG_SNAP[@]}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-go(){
@ sudo dnf install golang
@setupList sudo go install - ${PKG_GO[@]}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-start-services(){
@setupList sudo systemctl start - ${SERVICES_START[@]}
@setupList sudo systemctl enable - ${SERVICES_START[@]}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-start-user-services(){
@setupList sudo systemctl --user enable - ${SERVICES_USER_START[@]}
@setupList sudo systemctl --user start - ${SERVICES_USER_START[@]}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-vim(){
@ sudo dnf install vim gvim
# default editor...
@ sudo dnf install vim-default-editor --allowerasing
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# see:
# https://github.com/rvaiya/keyd
# XXX copy config: /etc/keyd/<keyboard-id>.conf...
function feature-keyd-source(){ (
@ mkdir -p ~/work/EXTERNAL
@ cd ~/work/EXTERNAL
if ! [ -d keyd ] ; then
@ git clone https://github.com/rvaiya/keyd
fi
@ cd keyd
@ make \
&& @ sudo make install
@ sudo systemctl enable keyd \
&& @ sudo systemctl start keyd
) }
function feature-keyd(){ (
@ sudo dnf copr enable alternateved/keyd
@ sudo dnf install keyd
) }
# see: https://wayland.freedesktop.org/libinput/doc/latest/palm-detection.html
function feature-keyd-quirk(){ (
local QUIRKS_FILE=/etc/libinput/local-overrides.quirks
# check if already installed...
if [ -e "$QUIRKS_FILE" ] \
&& grep -q '\[keyd\]' "$QUIRKS_FILE" ; then
echo "File \"$QUIRKS_FILE\" already exists and contains \"[keyd]\" section, aborting." 1>&2
return
fi
# install...
@ sudo mkdir -p "$(dirname "$QUIRKS_FILE")"
cat <<-EOF | sudo tee -a "$QUIRKS_FILE" > /dev/null
[keyd]
MatchUdevType=keyboard
MatchName=keyd virtual keyboard
AttrKeyboardIntegration=internal
EOF
) }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# to update:
# $ cd /opt/ventoy && ./VentoyGUI.x86_64
#
# see:
# https://copr.fedorainfracloud.org/coprs/karlisk/ventoy/
function feature-ventoy(){ (
@ sudo dnf copr enable karlisk/ventoy
@ sudo dnf install ventoy
) }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# see:
# https://gitlab.com/warningnonpotablewater/libinput-config
# https://www.reddit.com/r/Fedora/comments/qn0o9w/adjust_touchpad_scroll_speed_enable_mouse_wheel/
function feature-libinput-config(){ (
@ sudo dnf install libinput libinput-devel systemd-devel
@ mkdir -p ~/work/EXTERNAL
@ cd ~/work/EXTERNAL
if ! [ -d libinput-config ] ; then
@ git clone https://gitlab.com/warningnonpotablewater/libinput-config.git
fi
@ cd libinput-config
@ meson build
@ cd build
@ ninja
@ sudo ninja install
# config...
# for more info on options see:
# https://gitlab.com/warningnonpotablewater/libinput-config
cat <<-EOF | sudo tee -a /etc/libinput.conf > /dev/null
dwt=enabled
scroll-factor=0.3
gesture-speed=1.5
EOF
) }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-bashctrl(){ (
@ mkdir -p ~/work/
@ cd ~/work/
if ! [ -d bashctrl ] ; then
@ git clone git@github.com:flynx/bashctrl
fi
@ cd bashctrl
@ ./bashctrl -y setup
) }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-gamma(){
@ mkdir -p ~/work/EXTERNAL/
@ cd ~/work/EXTERNAL/
if ! [ -d bashctrl ] ; then
@ git clone https://github.com/zb3/gnome-gamma-tool
fi
@ cd gnome-gamma-tool/
@ ./gnome-gamma-tool.py -g 1.15
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-far(){
@ sudo dnf copr enable polter/far2l
@ sudo dnf install far2l far2l-tty
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# a disk usage utility...
function feature-dust(){
@ sudo dnf copr enable gourlaysama/dust
@ sudo dnf install dust
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-shadowsocks-rust(){
@ sudo dnf copr enable spyophobia/shadowsocks-rust
@ sudo dnf install shadowsocks-rust
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-gnome(){
# fractional scaling...
@ gsettings set org.gnome.mutter experimental-features "['scale-monitor-framebuffer']"
# disable beeps...
@ gsettings set org.gnome.desktop.sound event-sounds false
# visual bell...
@ gsettings set org.gnome.desktop.wm.preferences visual-bell true
@ gsettings set org.gnome.desktop.wm.preferences visual-bell-type frame-flash
# per window input selection...
@ gsettings set org.gnome.desktop.input-sources.per-window true
# swap language with alt-shift...
# NOTE: with the way the gui is setup not this is not possible to set there...
@ gsettings set org.gnome.desktop.wm.keybindings switch-input-source-backward "['<Alt>Shift_L']"
@ gsettings set org.gnome.desktop.wm.keybindings switch-input-source "['<Shift>Alt_L']"
# custom keys...
# XXX
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-syncthing(){
@ mkdir -p ~/Sync/ALL
@ sudo dnf install syncthing
@ sudo systemctl --user enable --now syncthing
#@ sudo systemctl --user start syncthing
# XXX can we do this from CLI???
# need to:
# - link device
# - share ALL directory
# - wait for sync
echo "Waiting for Syncthing to be connected with other devices manually."
read -p "(press any key when done)"
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# XXX needs a bit more setup...
function feature-snapshots(){ (
@ dnf install snapper python3-dnf-plugin-snapper
@ sudo snapper -c root create-config /
@ sudo snapper -c home create-config /home
@ sudo snapper -c boot create-config /boot
@ cd ~/work/EXTERNAL/
if ! [ -d grub-btrfs ] ; then
@ git clone https://github.com/Antynea/grub-btrfs.git
fi
@ cd grub-btrfs
@ sudo make install
) }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# XXX needs a bit more setup...
function feature-s1yoga-touchpad(){
# XXX detect hardware and abort setup on non-compatible machines...
cat <<EOF | sudo tee /usr/lib/systemd/system-sleep/fix-touchpad
#!/bin/sh
# fixes an issue where the touchpad stops working after suspend/hibernate...
if [ "$${1}" == "post" ] ; then
modprobe -r i2c_i801
sleep 3
modprobe i2c_i801
fi
EOF
@ chmod +x /usr/lib/systemd/system-sleep/fix-touchpad
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# XXX are these the same thing???
# - suspend does not work...
# - hibernate works on the second try only...
function feature-s1yoga-syspend(){
# XXX did not figure this one out yet...
true
}
function feature-s1yoga-hibernate(){
# XXX did not figure this one out yet...
# XXX HACK (will this work?)
# if hibernate fails retry once
# if second try fails beep
true
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# XXX skip scripts starting in "-"
# XXX make the scripts support the same syntax as features...
function feature-scripts(){ (
if ! [ -z "$1" ] ; then
local dir=$1
else
local dir=$SCRIPT_DIR
fi
# no script dir...
[ -d "$dir" ] \
|| return 1
cd "$dir"l
local script
for script in * ; do
# skip README and scripts starting with '-'...
( [ "${script}" == "README" ] \
|| [ "${script:0:1}" == "-" ] )\
&& continue
echo "# $script:"
( @ ./$script )
done
) }
function feature-platform-scripts(){
systemInfo
feature-scripts "$PLATFORM_SCRIPT_DIR"
}
function feature-user-scripts(){
feature-scripts "$USER_SCRIPT_DIR"
}
#----------------------------------------------------------------------
# feature api...
function @feature(){
while ! [ -z "$1" ] ; do
local feauture="$1"
for f in "${FEATURES[@]}" ; do
if [ "$f" == "${feature}" ] ; then
return 0
fi
done
shift
done
false
}
function @feature-add(){
while ! [ -z "$1" ] ; do
if ! @feature "$1" ; then
FEATURES+=("$1")
fi
shift
done
}
function @feature-del(){
while ! [ -z $1 ] ; do
FEATURES=( ${FEATURES[@]/$1} )
shift
done
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# XXX add an interactive list editor???
# XXX
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# command runners...
# Print command and if $DRY_RUN is not set run it...
#
function @(){
# XXX this does not preserve quotes...
[ -z $QUIET ] \
&& echo "## $@"
if [ -z $DRY_RUN ] ; then
$@
# need to exit with true status on dry runs...
else
true
fi
}
# Setup list if not empty...
#
# Usage:
# @setupList CMD - LIST
#
function @setupList(){
local CMD=
local LST=
# get command...
while true ; do
if [ $# == 0 ] || [ $1 == "-" ] ; then
shift
break
fi
CMD="$CMD $1"
shift
done
# list...
LST=("$@")
# run command if list is not empty...
if [ ${#LST[@]} != 0 ] ; then
@ $CMD ${LST[@]}
fi
}
#----------------------------------------------------------------------
# config...
[ -e "${SYSTEM_RC}" ] \
&& source ${SYSTEM_RC}
[ -e "${USER_RC}" ] \
&& source ${USER_RC}
#----------------------------------------------------------------------
# help and arguments...
function listScripts(){
[ -d "$SCRIPT_DIR" ] \
&& echo "-" \
&& return 0
local scripts=( $(ls "$SCRIPT_DIR") )
echo ${scripts/README}
}
function printhelp(){ cat << EOF
Usage: $CMD [OPTIONS]
Options:
-h | --help - print this message and exit.
-d | --dry-run - report the actions but do nothing.
-q | --quiet - run in quiet mode.
-l | --list-features - list enabled features.
-la | --list-all-features
- list supported features.
-ls | --list-scripts - list available scripts.
External configuration:
-s | --source FILE - read config from file.
(this flag can be used multiple times)
-o | --output FILE - write config to file.
Feature list manipulation:
-all - clear features
+all - reset features to \$ALL_FEATURES
-FEATURE - remove FEATURE from list
+FEATURE - add FEATURE to lost
Helpers:
--make-platform-dir - make platform directory for current platform
and exit.
Location:
${SCRIPT_DIR}/platform/NAME
Default features:
${FEATURES[@]}
Supported features:
${ALL_FEATURES[@]}
Available scripts:
$( listScripts )
Examples:
Only create dirs and links (features dir and user-link)...
\$ $CMD -all +dir +user-link
Same as above...
\$ FEATURES=( dir user-link ) $CMD
EOF
}
while ! [ -z "$1" ] ; do
case "$1" in
-h|--help)
printhelp
exit
;;
-d|--dry-run)
DRY_RUN=1
shift
;;
-q|--quiet)
QUIET=1
shift
;;
# introspection...
-l|--list-features)
echo ${FEATURES[@]}
exit
;;
-la|--list-all-features)
echo ${ALL_FEATURES[@]}
exit
;;
-ls|--list-scripts)
listScripts
exit
;;
# config files...
-s|--source)
[ -z "$2" ] \
&& source "$2"
shift
shift
;;
-o|--output)
SAVE=1
SAVE_FILE=$2
shift
shift
;;
# helpers...
--make-platform-dir)
systemInfo
echo "# Patform script dir: $PLATFORM_SCRIPT_DIR"
[ -d "$PLATFORM_SCRIPT_DIR" ] \
|| @ mkdir -p "$PLATFORM_SCRIPT_DIR"
exit
;;
# feature manipulation...
# NOTE: keep these last...
+all)
FEATURES=( ${ALL_FEATURES[@]} )
shift
;;
-all)
FEATURES=()
shift
;;
+*)
@feature-add "${1:1}"
shift
;;
-*)
@feature-del "${1:1}"
shift
;;
esac
done
#----------------------------------------------------------------------
# install/setup stuff...
echo "# FEATURES: ${FEATURES[@]}"
# built-in functions...
# NOTE: order of execution is set by $ALL_FEATURES...
_features=( "${FEATURES[@]}" )
for feature in "${ALL_FEATURES[@]}" ; do
# skip...
@feature "$feature" \
|| continue
# functions...
if [ "$(type -t feature-$feature)" == "function" ] ; then
echo "# $feature:"
_features=( ${_features[@]/$feature} )
feature-$feature
fi
done
# features not in $ALL_FEATURES...
for feature in "${_features[@]}" ; do
echo "# $feature:"
# built-in...
if [ "$(type -t feature-$feature)" == "function" ] ; then
feature-$feature
# feature scripts...
elif [ -d "$FEATURE_DIR" ] ; then
"$FEATURE_DIR"/$feature
# err...
else
echo "$CMD: unknown feature: $feature"
fi
done
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# save...
# XXX
#----------------------------------------------------------------------
# vim:set ts=4 sw=4 nowrap :