diff --git a/local/dfm/dfm b/local/dfm/dfm index fb49729..2298a54 100755 --- a/local/dfm/dfm +++ b/local/dfm/dfm @@ -6,8 +6,11 @@ set -euo pipefail # define default variables DFM_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" readonly DFM_SCRIPT_DIR +export DFM_SCRIPT_DIR readonly DFM_CMD_DIR="${DFM_SCRIPT_DIR}/cmd" +export DFM_CMD_DIR readonly DFM_LIB_DIR="${DFM_SCRIPT_DIR}/lib" +export DFM_LIB_DIR readonly DFM_DEFAULT_CONFIG_PATH="$HOME/.config" export DFM_DEFAULT_CONFIG_PATH readonly DFM_MAX_RETRIES=3 @@ -17,10 +20,43 @@ export DFM_DEFAULT_VERBOSE=0 TEMP_DIR=$(mktemp -d) export TEMP_DIR +# Clean up temporary directory on exit +trap 'rm -rf "$TEMP_DIR"' EXIT + # Load the common and utility functions from the lib directory. +[[ -f "${DFM_LIB_DIR}/common.sh" ]] || { + echo "Error: Required file ${DFM_LIB_DIR}/common.sh not found" + exit 1 +} +[[ -f "${DFM_LIB_DIR}/utils.sh" ]] || { + echo "Error: Required file ${DFM_LIB_DIR}/utils.sh not found" + exit 1 +} source "${DFM_LIB_DIR}/common.sh" source "${DFM_LIB_DIR}/utils.sh" +# Display help information +# +# @return None +main::show_help() +{ + cat << EOF +Usage: dfm [command] [function] [arguments] + +dotfiles manager utility for installing and configuring dotfiles. + +If no arguments are provided, lists all available commands. +If only a command is provided, lists available functions for that command. +If a command and function are provided, executes the specified function. + +Examples: + dfm # List all available commands + dfm install # List available functions for the install command + dfm install all # Execute the 'all' function from the install command + +EOF +} + # Main function for the dfm script. # # The function checks if any arguments were provided. If no arguments are @@ -40,6 +76,11 @@ main() local cmd="$1" shift + if [[ "$cmd" == "-h" || "$cmd" == "--help" ]]; then + main::show_help + return 0 + fi + if [[ $# -eq 0 ]]; then # Show the available functions for the command local cmd_file="${DFM_CMD_DIR}/${cmd}.sh" diff --git a/local/dfm/lib/utils.sh b/local/dfm/lib/utils.sh index e82cd37..1894b4f 100755 --- a/local/dfm/lib/utils.sh +++ b/local/dfm/lib/utils.sh @@ -109,6 +109,7 @@ list::print_subcommand() list::loop_functions() { + local cmd_file="$1" 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. @@ -282,7 +283,7 @@ 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) + done < <(find "$DFM_CMD_DIR" -type f -name "*.sh" -print0) echo "${cmd_files[@]}" } @@ -297,7 +298,7 @@ main::find_commands() main::get_command_functions() { local cmd_file="$1" - # Etsitään funktiomäärittelyt (function xxx() tai xxx()) + # Find function definitions (function xxx() or xxx()) grep -E '^[[:space:]]*(function[[:space:]]+)?[a-zA-Z0-9_]+\(\)[[:space:]]*{' "$cmd_file" \ | sed -E 's/^[[:space:]]*(function[[:space:]]+)?([a-zA-Z0-9_]+).*/\2/' } @@ -360,12 +361,24 @@ main::execute_command() local func="$1" shift - local cmd_file="${CMD_DIR}/${cmd}.sh" - if [[ ! -f "$cmd_file" ]]; then + # Validate input + if [[ ! "$cmd" =~ ^[a-zA-Z0-9_-]+$ ]] || [[ ! "$func" =~ ^[a-zA-Z0-9_-]+$ ]]; then + lib::error "Invalid command or function name" + return 1 + fi + + local cmd_file="${DFM_CMD_DIR}/${cmd}.sh" + if [[ ! -f "$cmd_file" ]] || [[ ! -r "$cmd_file" ]]; then lib::error "Command '$cmd' not found" return 1 fi + # Validate command file + if ! bash -n "$cmd_file"; then + lib::error "Command file '$cmd' contains syntax errors" + return 1 + fi + # Source the command file # shellcheck source=/dev/null source "$cmd_file"