From b5eaaead9bf30dd06fae111f456f29ea59ef387c Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Tue, 9 Jan 2024 16:48:11 +0100
Subject: [PATCH] Add autoinstall command

---
 autoinstall/archive_command.sh     |  18 +++++
 autoinstall/bashly.yml             | 107 +++++++++++++++++++++++++++++
 autoinstall/before.sh              |  20 ++++++
 autoinstall/completions_command.sh |   3 +
 autoinstall/env_command.sh         |  17 +++++
 autoinstall/file_command.sh        |  33 +++++++++
 autoinstall/git_command.sh         |  15 ++++
 autoinstall/lib/colors.sh          |  42 +++++++++++
 autoinstall/lib/common.sh          |  20 ++++++
 autoinstall/run_command.sh         |  40 +++++++++++
 autoinstall/text_command.sh        |  16 +++++
 autostart-manage/bashly.yml        |   5 +-
 autostart-manage/lib/common.sh     |   3 +-
 run.sh                             |   9 +++
 14 files changed, 344 insertions(+), 4 deletions(-)
 create mode 100644 autoinstall/archive_command.sh
 create mode 100644 autoinstall/bashly.yml
 create mode 100644 autoinstall/before.sh
 create mode 100644 autoinstall/completions_command.sh
 create mode 100644 autoinstall/env_command.sh
 create mode 100644 autoinstall/file_command.sh
 create mode 100644 autoinstall/git_command.sh
 create mode 100644 autoinstall/lib/colors.sh
 create mode 100644 autoinstall/lib/common.sh
 create mode 100644 autoinstall/run_command.sh
 create mode 100644 autoinstall/text_command.sh
 create mode 100755 run.sh

diff --git a/autoinstall/archive_command.sh b/autoinstall/archive_command.sh
new file mode 100644
index 0000000..6019708
--- /dev/null
+++ b/autoinstall/archive_command.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+
+target=${args[target]:?}
+url=${args[url]:?}
+
+if [ ! -f "$target" ]
+then
+	echo "Installing archive $url to $target"
+
+	target_dir=$(dirname "$target")
+	mkdir -p "$target_dir"
+	cd "$target_dir" || exit 1
+
+	_http_client "$url" > "$target"
+	tar xaf "$target"
+
+	_run_hook
+fi
diff --git a/autoinstall/bashly.yml b/autoinstall/bashly.yml
new file mode 100644
index 0000000..fec3458
--- /dev/null
+++ b/autoinstall/bashly.yml
@@ -0,0 +1,107 @@
+name: autoinstall
+help: Install files, repository and else
+version: 0.1.0
+
+flags:
+  - long: --clean
+    short: -c
+    help: Clean exisiting targets
+  - long: --hook
+    short: -h
+    help: Hook to run if something changed
+    arg: hook
+
+environment_variables:
+  - name: AUTOINSTALL_CLEAN
+    help: Clean exisiting targets
+
+dependencies:
+  http_client:
+    command: [curl, wget]
+    help: Please install either curl or wget
+
+commands:
+  - name: completions
+    help: Generate bash completions
+
+  - name: run
+    help: Autoinstall from file
+    args:
+      - name: group
+        required: true
+        help: The group to install
+
+  - name: git
+    help: Install a git repository
+    args:
+      - name: repo
+        required: true
+        help: The url of the git repository
+      - name: target
+        required: true
+        help: The path to clone the repository into
+
+  - name: file
+    help: Install a file
+    args:
+      - name: url
+        required: true
+        help: The url of the file
+      - name: target
+        required: true
+        help: The file-path to download the file into
+    flags:
+      - long: --pipe
+        short: -p
+        help: Pipe file through command (e.g. "tar xzO")
+        arg: pipe
+        default: cat
+
+  - name: exe
+    help: Install an executable
+    args:
+      - name: url
+        required: true
+        help: The url of the file
+      - name: target
+        required: true
+        help: The file-path to download the file into
+    filename: file_command.sh
+    flags:
+      - long: --pipe
+        short: -f
+        help: Pipe file through command (e.g. "tar xzO")
+        arg: pipe
+        default: cat
+
+  - name: archive
+    help: Install an archive
+    args:
+      - name: url
+        required: true
+        help: The url of the arhive
+      - name: target
+        required: true
+        help: The path to clone the repository into
+
+  - name: env
+    help: Create a file with envsubst
+    args:
+      - name: template
+        required: true
+        help: The path to the template
+      - name: target
+        required: true
+        help: The path to write the result to
+    dependencies:
+      envsubst: This tool is usually part of the gettext package
+
+  - name: text
+    help: Create a file from text
+    args:
+      - name: text
+        required: true
+        help: The text to write to the file
+      - name: target
+        required: true
+        help: The path to write the result to
diff --git a/autoinstall/before.sh b/autoinstall/before.sh
new file mode 100644
index 0000000..c0e639e
--- /dev/null
+++ b/autoinstall/before.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+if [ "${action:?}" = "run" ]
+then
+	return
+fi
+
+clean=${args[--clean]:-}
+target=${args[target]:?}
+
+if [ "${action:?}" = "exe" ]
+then
+	target="$HOME/.local/bin/$target"
+fi
+
+if [ -n "$clean" ] || [ -n "${AUTOINSTALL_CLEAN:-}" ]
+then
+	echo "Cleaning $target"
+	rm -rf "$target"
+fi
diff --git a/autoinstall/completions_command.sh b/autoinstall/completions_command.sh
new file mode 100644
index 0000000..0d10993
--- /dev/null
+++ b/autoinstall/completions_command.sh
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+
+send_completions
diff --git a/autoinstall/env_command.sh b/autoinstall/env_command.sh
new file mode 100644
index 0000000..74d65d7
--- /dev/null
+++ b/autoinstall/env_command.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+target=${args[target]:?}
+template=${args[template]:?}
+
+if [ ! -f "$target" ]
+then
+	echo "Installing env-template $template to $target"
+
+	target_dir=$(dirname "$target")
+	mkdir -p "$target_dir"
+	cd "$target_dir" || exit 1
+
+	envsubst < "$template" > "$target"
+
+	_run_hook
+fi
diff --git a/autoinstall/file_command.sh b/autoinstall/file_command.sh
new file mode 100644
index 0000000..2faa2dd
--- /dev/null
+++ b/autoinstall/file_command.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+
+pipe=${args[--pipe]:?}
+target=${args[target]:?}
+url=${args[url]:?}
+
+if [ "${action:-file}" = "exe" ]
+then
+	if [ -x "$(command -v "$target")" ]
+	then
+		return
+	fi
+	target="$HOME/.local/bin/$target"
+fi
+
+
+if [ ! -f "$target" ]
+then
+	echo "Installing file $url to $target"
+
+	target_dir=$(dirname "$target")
+	mkdir -p "$target_dir"
+	cd "$target_dir" || exit 1
+
+	_http_client "$url" | eval "$pipe" > "$target"
+
+	if [ "${action:-file}" = "exe" ]
+	then
+		chmod +x "$target"
+	fi
+
+	_run_hook
+fi
diff --git a/autoinstall/git_command.sh b/autoinstall/git_command.sh
new file mode 100644
index 0000000..33faf65
--- /dev/null
+++ b/autoinstall/git_command.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+target=${args[target]:?}
+repo=${args[repo]:?}
+
+if [ ! -d "$target" ]
+then
+	echo "Installing repo $repo to $target"
+
+	mkdir -p "$target"
+
+	git clone --depth=1 "$repo" "$target" >/dev/null 2>&1
+
+	_run_hook
+fi
diff --git a/autoinstall/lib/colors.sh b/autoinstall/lib/colors.sh
new file mode 100644
index 0000000..cbdc015
--- /dev/null
+++ b/autoinstall/lib/colors.sh
@@ -0,0 +1,42 @@
+## Color functions [@bashly-upgrade colors]
+## This file is a part of Bashly standard library
+##
+## Usage:
+## Use any of the functions below to color or format a portion of a string.
+##
+##   echo "before $(red this is red) after"
+##   echo "before $(green_bold this is green_bold) after"
+##
+## Color output will be disabled if `NO_COLOR` environment variable is set
+## in compliance with https://no-color.org/
+##
+print_in_color() {
+  local color="$1"
+  shift
+  if [[ -z ${NO_COLOR+x} ]]; then
+    printf "$color%b\e[0m\n" "$*"
+  else
+    printf "%b\n" "$*"
+  fi
+}
+
+red() { print_in_color "\e[31m" "$*"; }
+green() { print_in_color "\e[32m" "$*"; }
+yellow() { print_in_color "\e[33m" "$*"; }
+blue() { print_in_color "\e[34m" "$*"; }
+magenta() { print_in_color "\e[35m" "$*"; }
+cyan() { print_in_color "\e[36m" "$*"; }
+bold() { print_in_color "\e[1m" "$*"; }
+underlined() { print_in_color "\e[4m" "$*"; }
+red_bold() { print_in_color "\e[1;31m" "$*"; }
+green_bold() { print_in_color "\e[1;32m" "$*"; }
+yellow_bold() { print_in_color "\e[1;33m" "$*"; }
+blue_bold() { print_in_color "\e[1;34m" "$*"; }
+magenta_bold() { print_in_color "\e[1;35m" "$*"; }
+cyan_bold() { print_in_color "\e[1;36m" "$*"; }
+red_underlined() { print_in_color "\e[4;31m" "$*"; }
+green_underlined() { print_in_color "\e[4;32m" "$*"; }
+yellow_underlined() { print_in_color "\e[4;33m" "$*"; }
+blue_underlined() { print_in_color "\e[4;34m" "$*"; }
+magenta_underlined() { print_in_color "\e[4;35m" "$*"; }
+cyan_underlined() { print_in_color "\e[4;36m" "$*"; }
diff --git a/autoinstall/lib/common.sh b/autoinstall/lib/common.sh
new file mode 100644
index 0000000..584603a
--- /dev/null
+++ b/autoinstall/lib/common.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+_http_client() {
+	if [ -x "$(command -v curl)" ]
+	then
+		curl -fsSL "$1"
+	elif [ -x "$(command -v wget)" ]
+	then
+		wget -qO - "$1"
+	fi
+}
+
+_run_hook() {
+	hook=${args[--hook]:-}
+	if [ -n "$hook" ]
+	then
+		yellow "Running hook: $hook"
+		bash -c "$hook"
+	fi
+}
diff --git a/autoinstall/run_command.sh b/autoinstall/run_command.sh
new file mode 100644
index 0000000..c585ce2
--- /dev/null
+++ b/autoinstall/run_command.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+
+group=${args[group]:?}
+
+_config_query() {
+	tomlq -c --arg group "$group" \
+		'.autoinstall | map(select(.group == $group)) | '"$1" \
+		"$XDG_CONFIG_HOME/autoinstall.toml"
+}
+
+#length=$(_config_query "length")
+_config_query ".[]" | while read -r entry; do
+	install_args=()
+
+	type=$(echo "$entry" | jq -r '.type')
+	source=$(echo "$entry" | jq -r '.source')
+	target=$(echo "$entry" | jq -r '.target')
+	hook=$(echo "$entry" | jq -r '.hook // ""')
+	pipe=$(echo "$entry" | jq -r '.pipe // ""')
+
+	if [[ -n "$hook" ]]; then
+		install_args+=("--hook=$hook")
+	fi
+
+	install_args+=("$type")
+
+	if [[ -n "$pipe" ]]; then
+		install_args+=("--pipe=$pipe")
+	fi
+
+	if [[ $source = \$* ]]
+	then
+		source=$(eval "echo $source")
+	fi
+	install_args+=("$source")
+
+	install_args+=("$(eval "echo $target")")
+
+	autoinstall "${install_args[@]}"
+done
diff --git a/autoinstall/text_command.sh b/autoinstall/text_command.sh
new file mode 100644
index 0000000..4fcd486
--- /dev/null
+++ b/autoinstall/text_command.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+target=${args[target]:?}
+text=${args[text]:?}
+
+if [ ! -f "$target" ]
+then
+	echo "Installing text '$text' to $target"
+
+	target_dir=$(dirname "$target")
+	mkdir -p "$target_dir"
+
+	echo "$text" > "$target"
+
+	_run_hook
+fi
diff --git a/autostart-manage/bashly.yml b/autostart-manage/bashly.yml
index e65abd6..853529d 100644
--- a/autostart-manage/bashly.yml
+++ b/autostart-manage/bashly.yml
@@ -3,9 +3,7 @@ help: Manage autostart
 version: 0.1.0
 
 dependencies:
-  yq:
-    command: [tomlq]
-    help: please install yq (https://github.com/kislyuk/yq)
+  tomlq: please install yq (https://github.com/kislyuk/yq)
 
 environment_variables:
 - name: HOSTNAME
@@ -76,6 +74,7 @@ commands:
       - $(autostart-manage list)
     filename: systemctl.sh
   - name: log
+    alias: logs
     help: Show the log for a single program from autostart
     args:
       - name: program
diff --git a/autostart-manage/lib/common.sh b/autostart-manage/lib/common.sh
index 758403e..dfbbb1c 100644
--- a/autostart-manage/lib/common.sh
+++ b/autostart-manage/lib/common.sh
@@ -18,6 +18,7 @@ _list () {
 }
 
 _autostart_run_graphical () {
+	set +e
 	pass x # Try to unlock yubikey asap
 
 	start-audio pipewire
@@ -33,7 +34,7 @@ _autostart_run_graphical () {
 		fi
 	fi
 
-	autoinstall graphical
+	autoinstall run graphical
 	autostart-manage run
 }
 
diff --git a/run.sh b/run.sh
new file mode 100755
index 0000000..67177b3
--- /dev/null
+++ b/run.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env sh
+
+target=$(cat .target)
+
+[ -n "$target" ] || exit 1
+
+make generate
+
+"./output/$target" "$@"