|
| 1 | +#!/bin/bash |
| 2 | +# SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | + |
| 4 | +function spdlog() { |
| 5 | + local level="${1}" messages=("${@:2}") |
| 6 | + |
| 7 | + case "${level}" in |
| 8 | + info) |
| 9 | + level="$(printf "%s%s%s" "\033[32m" "info" "\e[0m")" |
| 10 | + ;; |
| 11 | + warn) |
| 12 | + level="$(printf "%s%s%s" "\033[33m\033[1m" "warning" "\e[0m")" |
| 13 | + ;; |
| 14 | + error) |
| 15 | + level="$(printf "%s%s%s" "\033[31m\033[1m" "error" "\e[0m")" |
| 16 | + ;; |
| 17 | + esac |
| 18 | + |
| 19 | + echo -e "[$(date '+%H:%M:%S.%3N')] [${level}]" "${messages[@]}" >&2 |
| 20 | +} |
| 21 | + |
| 22 | +function print-if-executable() { |
| 23 | + local file="${1}" |
| 24 | + |
| 25 | + if [ -x "${file}" ]; then |
| 26 | + echo "${file}" |
| 27 | + return 0 |
| 28 | + fi |
| 29 | + |
| 30 | + return 1 |
| 31 | +} |
| 32 | + |
| 33 | +function find-program() { |
| 34 | + local name="${1}" script_dir="${2}" project_dir="${3:-}" |
| 35 | + |
| 36 | + # If the calling script is installed to /usr, the program should be right next to it |
| 37 | + if print-if-executable "${script_dir}/${name}"; then |
| 38 | + return 0 |
| 39 | + fi |
| 40 | + |
| 41 | + # Otherwise the script might be called from the cloned git repository |
| 42 | + if [ -n "${project_dir}" ] && [ -f "${project_dir}/meson_options.txt" ]; then |
| 43 | + local -r file="$(find "${project_dir}" -type f -executable -name "${name}" | head -n1)" |
| 44 | + |
| 45 | + if print-if-executable "${file}"; then |
| 46 | + spdlog info "Located ${name} at ./$(realpath --relative-to="${PWD}" "${file}")" |
| 47 | + return 0 |
| 48 | + fi |
| 49 | + fi |
| 50 | + |
| 51 | + # Fall back to looking in PATH |
| 52 | + if print-if-executable "$(command -v "${name}" || true)"; then |
| 53 | + spdlog warn "Located ${name} using PATH" |
| 54 | + spdlog warn "This script is designed to not use PATH, something might be wrong" |
| 55 | + return 0 |
| 56 | + fi |
| 57 | + |
| 58 | + return 1 |
| 59 | +} |
| 60 | + |
| 61 | +function run-iptsd-foreach() { |
| 62 | + local -r script_dir="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" |
| 63 | + local -r project_dir="$(realpath "${script_dir}/../..")" |
| 64 | + |
| 65 | + local device_index="" |
| 66 | + local device_type="any" |
| 67 | + local xargs_procs="1" |
| 68 | + local tmux_socket="" |
| 69 | + local show_help="" |
| 70 | + |
| 71 | + while getopts ":t:i:pmh" args; do |
| 72 | + case "${args}" in |
| 73 | + i) |
| 74 | + device_index="${OPTARG}" |
| 75 | + ;; |
| 76 | + t) |
| 77 | + device_type="${OPTARG}" |
| 78 | + ;; |
| 79 | + p) |
| 80 | + xargs_procs="0" |
| 81 | + ;; |
| 82 | + m) |
| 83 | + xargs_procs="0" |
| 84 | + tmux_socket="$(mktemp -u)" |
| 85 | + ;; |
| 86 | + *) |
| 87 | + show_help="1" |
| 88 | + ;; |
| 89 | + esac |
| 90 | + done |
| 91 | + |
| 92 | + shift $((OPTIND - 1)) |
| 93 | + |
| 94 | + if [ -n "${show_help}" ]; then |
| 95 | + echo "Usage: iptsd-foreach [OPTIONS] -- COMMAND" |
| 96 | + echo "Run commands on one or many IPTS devices" |
| 97 | + echo "" |
| 98 | + echo "Options:" |
| 99 | + echo " -h Print this help message and exit" |
| 100 | + echo " -t TEXT:{any,touchscreen,touchpad} Selects all devices with the given type" |
| 101 | + echo " -i INTEGER Selects a single device by its index" |
| 102 | + echo " -p Run all commands in parallel" |
| 103 | + echo " -m Like -p, but runs every instance in seperate tmux windows" |
| 104 | + |
| 105 | + return 0 |
| 106 | + fi |
| 107 | + |
| 108 | + if [ -n "${tmux_socket}" ] && [ ! -x "$(command -v tmux)" ]; then |
| 109 | + spdlog error "tmux is not installed" |
| 110 | + return 1 |
| 111 | + fi |
| 112 | + |
| 113 | + local -r check_device="$(find-program "iptsd-check-device" "${script_dir}" "${project_dir}")" |
| 114 | + |
| 115 | + if [ -z "${check_device}" ]; then |
| 116 | + spdlog error "Could not locate iptsd-check-device" |
| 117 | + return 1 |
| 118 | + fi |
| 119 | + |
| 120 | + local devices=() |
| 121 | + |
| 122 | + while read -rd $'\n' device; do |
| 123 | + if [ ! -r "${device}" ]; then |
| 124 | + spdlog warn "Can't read from ${device}, is the program running as root?" |
| 125 | + continue |
| 126 | + fi |
| 127 | + |
| 128 | + if ! "${check_device}" --quiet --type="${device_type}" "${device}"; then |
| 129 | + continue |
| 130 | + fi |
| 131 | + |
| 132 | + devices+=("${device}") |
| 133 | + done <<<"$(find "/dev" -maxdepth 1 | grep -E "hidraw[0-9]+" | sort)" |
| 134 | + |
| 135 | + # If no devices were found, exit |
| 136 | + if (("${#devices[@]}" == 0)); then |
| 137 | + spdlog info "No devices found" |
| 138 | + return 0 |
| 139 | + fi |
| 140 | + |
| 141 | + if [ -n "${device_index}" ]; then |
| 142 | + if (("${#devices[@]}" <= "${device_index}")) || (("${device_index}" < 0)); then |
| 143 | + spdlog error "Device index is out of range" |
| 144 | + return 1 |
| 145 | + fi |
| 146 | + |
| 147 | + devices=("${devices[${device_index}]}") |
| 148 | + fi |
| 149 | + |
| 150 | + # Ignore the tmux option if there is only one device |
| 151 | + if (("${#devices[@]}" == 1)); then |
| 152 | + tmux_socket="" |
| 153 | + fi |
| 154 | + |
| 155 | + local xargs_cmd=("bash" "-c" "$*") |
| 156 | + |
| 157 | + if [ -n "${tmux_socket}" ]; then |
| 158 | + xargs_cmd=("tmux" "-S" "${tmux_socket}" "new-window" "-n" "{}" "${xargs_cmd[@]}") |
| 159 | + tmux -S "${tmux_socket}" new-session -d -n iptsd |
| 160 | + fi |
| 161 | + |
| 162 | + # Run the supplied commands on all devices |
| 163 | + echo -n "${devices[@]}" | xargs -d ' ' -P "${xargs_procs}" -i "${xargs_cmd[@]}" |
| 164 | + |
| 165 | + if [ -n "${tmux_socket}" ]; then |
| 166 | + tmux -S "${tmux_socket}" kill-window -t 0 |
| 167 | + tmux -S "${tmux_socket}" attach |
| 168 | + fi |
| 169 | + |
| 170 | + return 0 |
| 171 | +} |
| 172 | + |
| 173 | +if [ "${BASH_SOURCE[0]}" = "${0}" ]; then |
| 174 | + run-iptsd-foreach "$@" |
| 175 | +fi |
0 commit comments