mirror of
https://github.com/ivuorinen/dotfiles.git
synced 2026-02-10 23:51:56 +00:00
feat(dfm): modularize dfm, add utils, logger, etc.
This commit is contained in:
@@ -28,7 +28,7 @@ indent_size = 1
|
|||||||
indent_size = 1
|
indent_size = 1
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
|
|
||||||
[{local/bin/*,**/*.sh,**/zshrc,config/*,scripts/*}]
|
[{local/bin/*,local/dfm/*,**/*.sh,**/zshrc,config/*,scripts/*}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
tab_width = 2
|
tab_width = 2
|
||||||
shell_variant = bash # --language-variant
|
shell_variant = bash # --language-variant
|
||||||
|
|||||||
38
local/dfm/cmd/install.sh
Executable file
38
local/dfm/cmd/install.sh
Executable file
@@ -0,0 +1,38 @@
|
|||||||
|
# Installation functions for dfm, the dotfile manager
|
||||||
|
#
|
||||||
|
# @author Ismo Vuorinen <https://github.com/ivuorinen>
|
||||||
|
# @license MIT
|
||||||
|
|
||||||
|
# @description Install all packages in the correct order
|
||||||
|
function all()
|
||||||
|
{
|
||||||
|
lib::log "Installing all packages..."
|
||||||
|
fonts
|
||||||
|
brew
|
||||||
|
asdf
|
||||||
|
}
|
||||||
|
|
||||||
|
# @description Install fonts
|
||||||
|
function fonts()
|
||||||
|
{
|
||||||
|
lib::log "Installing fonts..."
|
||||||
|
# implement fonts installation
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install asdf and set it up.
|
||||||
|
#
|
||||||
|
# @description Install asdf
|
||||||
|
function asdf()
|
||||||
|
{
|
||||||
|
lib::log "Installing asdf..."
|
||||||
|
# implement asdf installation
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install Homebrew and set it up.
|
||||||
|
#
|
||||||
|
# @description Installs Homebrew
|
||||||
|
function brew()
|
||||||
|
{
|
||||||
|
lib::log "Installing Homebrew..."
|
||||||
|
# implement Homebrew installation
|
||||||
|
}
|
||||||
58
local/dfm/dfm
Executable file
58
local/dfm/dfm
Executable file
@@ -0,0 +1,58 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# dfm - dotfiles manager
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# define default variables
|
||||||
|
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
readonly CMD_DIR="${SCRIPT_DIR}/cmd"
|
||||||
|
readonly LIB_DIR="${SCRIPT_DIR}/lib"
|
||||||
|
readonly DEFAULT_CONFIG_PATH="$HOME/.config"
|
||||||
|
readonly MAX_RETRIES=3
|
||||||
|
export DEFAULT_INSTALL_DIR="$HOME/.local"
|
||||||
|
export DEFAULT_VERBOSE=0
|
||||||
|
export TEMP_DIR=$(mktemp -d)
|
||||||
|
|
||||||
|
# Load the common and utility functions from the lib directory.
|
||||||
|
source "${LIB_DIR}/common.sh"
|
||||||
|
source "${LIB_DIR}/utils.sh"
|
||||||
|
|
||||||
|
# Main function for the dfm script.
|
||||||
|
#
|
||||||
|
# The function checks if any arguments were provided. If no arguments are
|
||||||
|
# provided, it lists all available commands. If a command name is provided,
|
||||||
|
# it lists the available functions for that command. If a command and function
|
||||||
|
# name are provided, it executes the function with the provided arguments.
|
||||||
|
#
|
||||||
|
# @param args The command-line arguments.
|
||||||
|
# @return None
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
if [[ $# -eq 0 ]]; then
|
||||||
|
main::list_available_commands
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local cmd="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [[ $# -eq 0 ]]; then
|
||||||
|
# Näytä komennon saatavilla olevat funktiot
|
||||||
|
local cmd_file="${CMD_DIR}/${cmd}.sh"
|
||||||
|
if [[ -f "$cmd_file" ]]; then
|
||||||
|
list::print_group "Available functions for '$cmd'"
|
||||||
|
list::loop_functions "$cmd_file"
|
||||||
|
else
|
||||||
|
lib::error "Command '$cmd' not found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local func="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
main::execute_command "$cmd" "$func" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
236
local/dfm/lib/common.sh
Executable file
236
local/dfm/lib/common.sh
Executable file
@@ -0,0 +1,236 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# dfm common functions for logging and error handling, etc.
|
||||||
|
# Source this file to use the functions in your scripts.
|
||||||
|
#
|
||||||
|
# @author Ismo Vuorinen <https://github.com/ivuorinen>
|
||||||
|
# @license MIT
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
declare -A ERROR_CODES=(
|
||||||
|
[SUCCESS]=0
|
||||||
|
[INVALID_ARGUMENT]=1
|
||||||
|
[COMMAND_NOT_FOUND]=2
|
||||||
|
[FUNCTION_NOT_FOUND]=3
|
||||||
|
[EXECUTION_FAILED]=4
|
||||||
|
)
|
||||||
|
|
||||||
|
declare -A LOG_LEVELS=(
|
||||||
|
[DEBUG]=0
|
||||||
|
[INFO]=1
|
||||||
|
[WARN]=2
|
||||||
|
[ERROR]=3
|
||||||
|
)
|
||||||
|
LOG_LEVEL="${LOG_LEVEL:-INFO}"
|
||||||
|
|
||||||
|
# Simple logging function
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# lib::log "Hello, world!"
|
||||||
|
#
|
||||||
|
# @description Log a message to the console
|
||||||
|
# @param $* Message to log
|
||||||
|
# @return void
|
||||||
|
lib::log()
|
||||||
|
{
|
||||||
|
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Simple error logging function
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# lib::error "Something went wrong"
|
||||||
|
#
|
||||||
|
# @description Log an error message to the console
|
||||||
|
# @param $* Error message
|
||||||
|
# @return void
|
||||||
|
lib::error()
|
||||||
|
{
|
||||||
|
printf '[%s] ERROR: %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Handle an error by logging an error message to the console
|
||||||
|
# and exiting with an error code based on the error type.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# lib::error::handle $LINENO $0
|
||||||
|
#
|
||||||
|
# @description Handle an error
|
||||||
|
# @param $1 Line number
|
||||||
|
# @param $2 Command
|
||||||
|
# @return void
|
||||||
|
lib::error::handle()
|
||||||
|
{
|
||||||
|
local exit_code=$?
|
||||||
|
local line_no=$1
|
||||||
|
local command=$2
|
||||||
|
|
||||||
|
case $exit_code in
|
||||||
|
${ERROR_CODES[INVALID_ARGUMENT]})
|
||||||
|
lib::error "Invalid argument at line $line_no in command '$command'"
|
||||||
|
;;
|
||||||
|
${ERROR_CODES[COMMAND_NOT_FOUND]})
|
||||||
|
lib::error "Command not found at line $line_no"
|
||||||
|
;;
|
||||||
|
${ERROR_CODES[FUNCTION_NOT_FOUND]})
|
||||||
|
lib::error "Function not found at line $line_no in command '$command'"
|
||||||
|
;;
|
||||||
|
${ERROR_CODES[EXECUTION_FAILED]})
|
||||||
|
lib::error "Execution failed at line $line_no in command '$command'"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
lib::error "Unknown error ($exit_code) at line $line_no in command '$command'"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
return $exit_code
|
||||||
|
}
|
||||||
|
|
||||||
|
# Throw an error by logging an error message to the console and exiting
|
||||||
|
# with an error code based on the error type. The error code name is used
|
||||||
|
# to determine the error code from the ERROR_CODES associative array.
|
||||||
|
# The error message is passed as arguments to the function.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# lib::error::throw INVALID_ARGUMENT "Invalid argument"
|
||||||
|
# lib::error::throw COMMAND_NOT_FOUND "Command not found"
|
||||||
|
# lib::error::throw FUNCTION_NOT_FOUND "Function not found"
|
||||||
|
# lib::error::throw EXECUTION_FAILED "Execution failed"
|
||||||
|
#
|
||||||
|
# @description Throw an error
|
||||||
|
# @param $1 Error code name
|
||||||
|
# @param $* Error message
|
||||||
|
# @return void
|
||||||
|
lib::error::throw()
|
||||||
|
{
|
||||||
|
local code_name=$1
|
||||||
|
shift
|
||||||
|
local message=$*
|
||||||
|
|
||||||
|
lib::error "$message"
|
||||||
|
return "${ERROR_CODES[$code_name]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logs a message to the console if the current log level is set so that the
|
||||||
|
# message is displayed. The log level is compared to the log level of the
|
||||||
|
# message and if the message log level is greater than or equal to the current
|
||||||
|
# log level, the message is displayed.
|
||||||
|
# The log levels are defined in the LOG_LEVELS associative array.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# logger::log "INFO" "This is an info message"
|
||||||
|
# logger::log "DEBUG" "This is a debug message"
|
||||||
|
# logger::log "WARN" "This is a warning message"
|
||||||
|
# logger::log "ERROR" "This is an error message"
|
||||||
|
#
|
||||||
|
# @description Log a message to the console based on the log level setting.
|
||||||
|
# @param $1 Log level
|
||||||
|
# @param $2 Message
|
||||||
|
# @return void
|
||||||
|
logger::log()
|
||||||
|
{
|
||||||
|
local level=$1
|
||||||
|
shift
|
||||||
|
local msg=$1
|
||||||
|
|
||||||
|
if [[ ${LOG_LEVELS[$level]} -ge ${LOG_LEVELS[$LOG_LEVEL]} ]]; then
|
||||||
|
printf '[%s] [%s]: %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$level" "$msg" >&2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logs a debug message to the console, if the current log level is set to DEBUG or greater.
|
||||||
|
# The message is passed as arguments to the function.
|
||||||
|
# The function is defined above.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# logger::debug "This is a debug message"
|
||||||
|
#
|
||||||
|
# @description Log a debug message to the console
|
||||||
|
# @param $* Message
|
||||||
|
# @return void
|
||||||
|
logger::debug()
|
||||||
|
{
|
||||||
|
logger::log "DEBUG" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logs an info message to the console, if the current log level is set to INFO or greater.
|
||||||
|
# The message is passed as arguments to the function.
|
||||||
|
# The function is defined above.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# logger::info "This is an info message"
|
||||||
|
#
|
||||||
|
# @description Log an info message to the console
|
||||||
|
# @param $* Message
|
||||||
|
# @return void
|
||||||
|
logger::info()
|
||||||
|
{
|
||||||
|
logger::log "INFO" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logs a warning message to the console, if the current log level is set to WARN or greater.
|
||||||
|
# The message is passed as arguments to the function.
|
||||||
|
# The function is defined above.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# logger::warn "This is a warning message"
|
||||||
|
#
|
||||||
|
# @description Log a warning message to the console
|
||||||
|
# @param $* Message
|
||||||
|
# @return void
|
||||||
|
logger::warn()
|
||||||
|
{
|
||||||
|
logger::log "WARN" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logs an error message to the console, if the current log level is set to ERROR or greater.
|
||||||
|
# The message is passed as arguments to the function.
|
||||||
|
# The function is defined above.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# logger::error "This is an error message"
|
||||||
|
#
|
||||||
|
# @description Log an error message to the console
|
||||||
|
# @param $* Message
|
||||||
|
# @return void
|
||||||
|
logger::error()
|
||||||
|
{
|
||||||
|
logger::log "ERROR" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cleanup function to remove temporary files and directories
|
||||||
|
# when the script exits or is interrupted by a signal (e.g. Ctrl+C).
|
||||||
|
# The function is registered with the `EXIT` trap.
|
||||||
|
#
|
||||||
|
# @description Remove temporary files and directories
|
||||||
|
# @return void
|
||||||
|
cleanup()
|
||||||
|
{
|
||||||
|
local exit_code=$?
|
||||||
|
[ -d "$TEMP_DIR" ] && rm -rf "$TEMP_DIR"
|
||||||
|
exit $exit_code
|
||||||
|
}
|
||||||
|
|
||||||
|
# Register the cleanup function to run on EXIT signal.
|
||||||
|
#
|
||||||
|
# This will ensure that temporary files and directories are removed
|
||||||
|
# when the script exits or is interrupted by a signal (e.g. Ctrl+C).
|
||||||
|
# The cleanup function is defined above.
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
# Handle errors by logging an error message to the console.
|
||||||
|
#
|
||||||
|
# The function is registered with the `ERR` trap.
|
||||||
|
# The line number where the error occurred is passed as an argument to the function.
|
||||||
|
# The function is defined above.
|
||||||
|
#
|
||||||
|
# @description Handle an error
|
||||||
|
# @param $1 Line number
|
||||||
|
# @return void
|
||||||
|
handle_error()
|
||||||
|
{
|
||||||
|
local exit_code=$?
|
||||||
|
local line_no=$1
|
||||||
|
logger::error "Failed at line ${line_no} with exit code ${exit_code}"
|
||||||
|
}
|
||||||
|
|
||||||
|
trap 'handle_error ${LINENO}' ERR
|
||||||
334
local/dfm/lib/utils.sh
Executable file
334
local/dfm/lib/utils.sh
Executable file
@@ -0,0 +1,334 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# dfm utility functions for common tasks
|
||||||
|
# Source this file to use the functions in your scripts.
|
||||||
|
#
|
||||||
|
# @author Ismo Vuorinen <https://github.com/ivuorinen>
|
||||||
|
# @license MIT
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ANSI escape codes
|
||||||
|
readonly RESET="\033[0m"
|
||||||
|
readonly BOLD="\033[1m"
|
||||||
|
readonly DIM="\033[2m"
|
||||||
|
readonly ITALIC="\033[3m"
|
||||||
|
readonly UNDERLINE="\033[4m"
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
readonly BLACK="\033[30m"
|
||||||
|
readonly RED="\033[31m"
|
||||||
|
readonly GREEN="\033[32m"
|
||||||
|
readonly YELLOW="\033[33m"
|
||||||
|
readonly BLUE="\033[34m"
|
||||||
|
readonly MAGENTA="\033[35m"
|
||||||
|
readonly CYAN="\033[36m"
|
||||||
|
readonly WHITE="\033[37m"
|
||||||
|
|
||||||
|
# Function to print formatted line
|
||||||
|
list::print_formatted()
|
||||||
|
{
|
||||||
|
local format=$1
|
||||||
|
shift
|
||||||
|
printf "${format}%s${RESET}\n" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to print a header
|
||||||
|
list::print_header()
|
||||||
|
{
|
||||||
|
printf "\n ${BOLD}${BLUE}%s${RESET}\n" "$1"
|
||||||
|
printf "%s\n" " $(printf '%.s─' {1..60})"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to print a group header
|
||||||
|
list::print_group()
|
||||||
|
{
|
||||||
|
local group=$1
|
||||||
|
printf "\n ${YELLOW}${BOLD}%s${RESET}\n\n" "$group"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to print a command
|
||||||
|
list::print_command()
|
||||||
|
{
|
||||||
|
local cmd=$1
|
||||||
|
local desc=${2:-""}
|
||||||
|
printf " ${BOLD}${CYAN}%-15s${RESET} ${DIM}%s${RESET}\n" "$cmd" "$desc"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to print a subcommand
|
||||||
|
list::print_subcommand()
|
||||||
|
{
|
||||||
|
local cmd=$1
|
||||||
|
local desc=${2:-""}
|
||||||
|
printf " ${GREEN}%-13s${RESET} ${desc}\n" "$cmd"
|
||||||
|
}
|
||||||
|
|
||||||
|
list::loop_functions()
|
||||||
|
{
|
||||||
|
while IFS= read -r func; do
|
||||||
|
# Get the function description from the function definition in the
|
||||||
|
# command file. If no description is found, print only the function name.
|
||||||
|
# The description is printed without the @description prefix.
|
||||||
|
# If the function is not found, print only the function name.
|
||||||
|
# The function name is printed with a bullet point.
|
||||||
|
local doc
|
||||||
|
doc=$(main::get_function_description "$cmd_file" "$func")
|
||||||
|
if [[ -n "$doc" ]]; then
|
||||||
|
list::print_subcommand "$func:" "${doc#*@description}"
|
||||||
|
else
|
||||||
|
list::print_subcommand "$func" ""
|
||||||
|
fi
|
||||||
|
done < <(main::get_command_functions "$cmd_file")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the documentation for a function from a command file.
|
||||||
|
list::get_function_docs()
|
||||||
|
{
|
||||||
|
local cmd_file="$1"
|
||||||
|
local func="$2"
|
||||||
|
|
||||||
|
awk -v func="$func" '
|
||||||
|
# Start collecting documentation when a function is found and the line contains @
|
||||||
|
/^[[:space:]]*#[[:space:]]*@/ {
|
||||||
|
tag = $2
|
||||||
|
sub(/^[[:space:]]*#[[:space:]]*@[[:space:]]*[a-zA-Z]+[[:space:]]*/, "")
|
||||||
|
docs[tag] = $0
|
||||||
|
last_tag = tag
|
||||||
|
}
|
||||||
|
|
||||||
|
# Collect multi-line documentation
|
||||||
|
/^[[:space:]]*#/ && last_tag && !/^[[:space:]]*#[[:space:]]*@/ {
|
||||||
|
sub(/^[[:space:]]*#[[:space:]]*/, "")
|
||||||
|
docs[last_tag] = docs[last_tag] " " $0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Empty line or comment line ends documentation
|
||||||
|
!/^[[:space:]]*#/ {
|
||||||
|
last_tag = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# When the function is found, print the documentation
|
||||||
|
$0 ~ "^[[:space:]]*(function[[:space:]]+)?" func "\\(\\)" {
|
||||||
|
for (tag in docs) {
|
||||||
|
printf "@%s %s\n", tag, docs[tag]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' "$cmd_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if a command exists in the current environment and return 0 if it does.
|
||||||
|
# Otherwise, return 1.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# if utils::is_installed curl; then
|
||||||
|
# echo "curl is installed"
|
||||||
|
# else
|
||||||
|
# echo "curl is not installed"
|
||||||
|
# fi
|
||||||
|
#
|
||||||
|
# @description Check if a command exists
|
||||||
|
# @param $1 Command to check
|
||||||
|
# @return 0 if the command exists, 1 otherwise
|
||||||
|
utils::is_installed()
|
||||||
|
{
|
||||||
|
command -v "$1" > /dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if a directory exists in the current env PATH and return 0 if it does.
|
||||||
|
# Otherwise, return 1.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# if utils::in_path /usr/local/bin; then
|
||||||
|
# echo "/usr/local/bin is in PATH"
|
||||||
|
# else
|
||||||
|
# echo "/usr/local/bin is not in PATH"
|
||||||
|
# fi
|
||||||
|
#
|
||||||
|
# @description Check if a directory is in PATH
|
||||||
|
# @param $1 Directory to check
|
||||||
|
# @return 0 if the directory is in PATH, 1 otherwise
|
||||||
|
utils::in_path()
|
||||||
|
{
|
||||||
|
local cmd=$1
|
||||||
|
local result=1
|
||||||
|
IFS=: read -ra path <<< "$PATH"
|
||||||
|
for p in "${path[@]}"; do
|
||||||
|
if [[ -x "$p/$cmd" ]]; then
|
||||||
|
result=0
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return $result
|
||||||
|
}
|
||||||
|
|
||||||
|
# Retry a command until it succeeds or the maximum number of retries is reached.
|
||||||
|
# Logs a warning message if the command fails and is retried after a short delay.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# if utils::retry 3 curl -sSL https://example.com; then
|
||||||
|
# echo "Success"
|
||||||
|
# else
|
||||||
|
# echo "Failed"
|
||||||
|
# fi
|
||||||
|
#
|
||||||
|
# @description Retry a command
|
||||||
|
# @param $1 Maximum number of retries
|
||||||
|
# @param $2.. Command to run
|
||||||
|
# @return 0 if the command succeeds, 1 otherwise
|
||||||
|
# @dependencies logger::warn
|
||||||
|
utils::retry()
|
||||||
|
{
|
||||||
|
local tries=$1
|
||||||
|
shift
|
||||||
|
local count=1
|
||||||
|
|
||||||
|
until "$@"; do
|
||||||
|
[[ $count -gt $tries ]] && return 1
|
||||||
|
logger::warn "Failed, retry $count/$tries"
|
||||||
|
((count++))
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ask for confirmation before proceeding. The default value is used if the user
|
||||||
|
# presses Enter without providing an answer.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# if utils::interactive::confirm "Are you sure?"; then
|
||||||
|
# echo "Confirmed"
|
||||||
|
# else
|
||||||
|
# echo "Not confirmed"
|
||||||
|
# fi
|
||||||
|
#
|
||||||
|
# @description Confirm an action
|
||||||
|
# @param $1 Prompt message
|
||||||
|
# @param $2 Default value
|
||||||
|
# @return 0 if the user confirms, 1 otherwise
|
||||||
|
utils::interactive::confirm()
|
||||||
|
{
|
||||||
|
local prompt=$1
|
||||||
|
local default=${2:-Y}
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -rp "$prompt [Y/n]: " response
|
||||||
|
case ${response:-$default} in
|
||||||
|
[Yy]*) return 0 ;;
|
||||||
|
[Nn]*) return 1 ;;
|
||||||
|
*) echo "Please answer yes or no" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Find all command files in the cmd directory and return them
|
||||||
|
# as a space-separated string of filenames (e.g. "cmd1.sh cmd2.sh").
|
||||||
|
#
|
||||||
|
# The function uses a while loop to read the output of the find command
|
||||||
|
# line by line. The -print0 option is used to separate the filenames with
|
||||||
|
# a null character (\0) instead of a newline. This is necessary to handle
|
||||||
|
# filenames with spaces correctly.
|
||||||
|
#
|
||||||
|
# The read command reads the null-separated filenames and appends them to
|
||||||
|
# the cmd_files array. Finally, the function prints the array elements
|
||||||
|
# separated by a space.
|
||||||
|
#
|
||||||
|
# @return A space-separated string of command files.
|
||||||
|
main::find_commands()
|
||||||
|
{
|
||||||
|
local cmd_files=()
|
||||||
|
while IFS= read -r -d '' file; do
|
||||||
|
cmd_files+=("$file")
|
||||||
|
done < <(find "$CMD_DIR" -type f -name "*.sh" -print0)
|
||||||
|
echo "${cmd_files[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the function names from a command file.
|
||||||
|
#
|
||||||
|
# The function uses grep to find function definitions (function xxx() or xxx())
|
||||||
|
# and sed to extract the function names. The function names are printed one per
|
||||||
|
# line.
|
||||||
|
#
|
||||||
|
# @param cmd_file The command file to extract function names from.
|
||||||
|
# @return A list of function names.
|
||||||
|
main::get_command_functions()
|
||||||
|
{
|
||||||
|
local cmd_file="$1"
|
||||||
|
# Etsitään funktiomäärittelyt (function xxx() tai xxx())
|
||||||
|
grep -E '^[[:space:]]*(function[[:space:]]+)?[a-zA-Z0-9_]+\(\)[[:space:]]*{' "$cmd_file" \
|
||||||
|
| sed -E 's/^[[:space:]]*(function[[:space:]]+)?([a-zA-Z0-9_]+).*/\2/'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the description of a function from a command file.
|
||||||
|
#
|
||||||
|
# The function uses grep to find the function definition and sed to extract
|
||||||
|
# the description. The description is printed without the @description prefix.
|
||||||
|
#
|
||||||
|
# @param cmd_file The command file to extract the function description from.
|
||||||
|
# @param func The function name.
|
||||||
|
# @return The function description.
|
||||||
|
main::get_function_description()
|
||||||
|
{
|
||||||
|
local cmd_file="$1"
|
||||||
|
local func="$2"
|
||||||
|
|
||||||
|
grep -B1 "^[[:space:]]*\(function[[:space:]]*\)\{0,1\}$func().*{" "$cmd_file" \
|
||||||
|
| grep "@description" \
|
||||||
|
| sed -E 's/^[[:space:]]*#[[:space:]]*@description[[:space:]]*//'
|
||||||
|
}
|
||||||
|
|
||||||
|
# List all available commands and their functions.
|
||||||
|
#
|
||||||
|
# The function uses main::find_commands to get a list of command files.
|
||||||
|
# It then iterates over the files and prints the command name and
|
||||||
|
# its functions.
|
||||||
|
#
|
||||||
|
# @return None
|
||||||
|
main::list_available_commands()
|
||||||
|
{
|
||||||
|
local cmd_files
|
||||||
|
cmd_files=$(main::find_commands)
|
||||||
|
|
||||||
|
list::print_header "dfm - dotfiles manager"
|
||||||
|
list::print_group "Available commands"
|
||||||
|
|
||||||
|
for cmd_file in $cmd_files; do
|
||||||
|
local cmd_name
|
||||||
|
cmd_name=$(basename "$cmd_file" .sh)
|
||||||
|
list::print_command "$cmd_name"
|
||||||
|
|
||||||
|
list::loop_functions "$cmd_file"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Execute a command function.
|
||||||
|
#
|
||||||
|
# The function loads the command file and checks if the function exists.
|
||||||
|
# If the function exists, it executes the function with the provided arguments.
|
||||||
|
#
|
||||||
|
# @param cmd The command name.
|
||||||
|
# @param func The function name.
|
||||||
|
# @param args The function arguments.
|
||||||
|
# @return None
|
||||||
|
main::execute_command()
|
||||||
|
{
|
||||||
|
local cmd="$1"
|
||||||
|
shift
|
||||||
|
local func="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
local cmd_file="${CMD_DIR}/${cmd}.sh"
|
||||||
|
if [[ ! -f "$cmd_file" ]]; then
|
||||||
|
lib::error "Command '$cmd' not found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Source the command file
|
||||||
|
source "$cmd_file"
|
||||||
|
|
||||||
|
# Check if the function exists
|
||||||
|
if ! declare -f "$func" > /dev/null; then
|
||||||
|
lib::error "Function '$func' not found in command '$cmd'"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run the function with the provided arguments
|
||||||
|
"$func" "$@"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user