259 lines
8.6 KiB
Bash
259 lines
8.6 KiB
Bash
#!/usr/bin/env bash
|
|
# Begin profile
|
|
# ------------------------------------------------------------------------------
|
|
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
|
# Protected by the BSD3 license. Please read bellow for details.
|
|
#
|
|
# * Redistribution and use in source and binary forms,
|
|
# * with or without modification, are permitted provided
|
|
# * that the following conditions are met:
|
|
# *
|
|
# * Redistributions of source code must retain the above
|
|
# * copyright notice, this list of conditions and the
|
|
# * following disclaimer.
|
|
# *
|
|
# * Redistributions in binary form must reproduce the above
|
|
# * copyright notice, this list of conditions and the following
|
|
# * disclaimer in the documentation and/or other materials
|
|
# * provided with the distribution.
|
|
# *
|
|
# * Neither the name of the copyright holder nor the names
|
|
# * of any other contributors may be used to endorse or
|
|
# * promote products derived from this software without
|
|
# * specific prior written permission.
|
|
# *
|
|
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
# * OF SUCH DAMAGE.
|
|
# ------------------------------------------------------------------------------
|
|
|
|
if [[ ! $SHELL =~ bash ]]; then
|
|
echo "That environment script is designed to be used with bash being the shell."
|
|
echo "Please consider using bash to enjoy our features!"
|
|
return 1
|
|
fi
|
|
|
|
# Required for associative arrays (4.0+) and namerefs (4.3+)
|
|
if ((BASH_VERSINFO[0] < 4)) || [[ ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -lt 3 ]]; then
|
|
echo "[ Error ] This profile requires Bash 4.3 or higher."
|
|
echo "Current version: $BASH_VERSION"
|
|
return 1 2>/dev/null || exit 1
|
|
fi
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# path* : private functions for PATH variable management
|
|
pathremove()
|
|
{
|
|
local IFS=':'
|
|
local newpath
|
|
local dir
|
|
local pathvar=${2:-PATH}
|
|
for dir in ${!pathvar}; do
|
|
if [ "$dir" != "$1" ]; then
|
|
newpath=${newpath:+$newpath:}$dir
|
|
fi
|
|
done
|
|
export $pathvar="$newpath"
|
|
}
|
|
|
|
pathprepend()
|
|
{
|
|
pathremove $1 $2
|
|
local pathvar=${2:-PATH}
|
|
export $pathvar="$1${!pathvar:+:${!pathvar}}"
|
|
}
|
|
|
|
pathappend()
|
|
{
|
|
pathremove $1 $2
|
|
local pathvar=${2:-PATH}
|
|
export $pathvar="${!pathvar:+${!pathvar}:}$1"
|
|
}
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Configuration file parser
|
|
parse_conf()
|
|
{
|
|
local config_file="$1"
|
|
local current_section=""
|
|
local line key value
|
|
|
|
[[ ! -f "$config_file" ]] && return 1
|
|
|
|
while IFS='=' read -r key value || [[ -n "$key" ]]; do
|
|
# Internal trimming (removes leading/trailing whitespace & CR)
|
|
key="${key%"${key##*[![:space:]]}"}"
|
|
key="${key#"${key%%[![:space:]]*}"}"
|
|
key="${key%$'\r'}" # Strip potential Windows line endings
|
|
|
|
# Skip comments and empty lines
|
|
[[ -z "$key" || "$key" =~ ^[#\;] ]] && continue
|
|
|
|
# Section Detection: [section_name]
|
|
if [[ "$key" =~ ^\[([a-zA-Z0-9_]+)\]$ ]]; then
|
|
current_section="${BASH_REMATCH[1]}"
|
|
declare -g -A "CONF_$current_section"
|
|
continue
|
|
fi
|
|
|
|
# Secure Assignment (if inside a section)
|
|
if [[ -n "$current_section" ]]; then
|
|
# Clean the value
|
|
value="${value%"${value##*[![:space:]]}"}"
|
|
value="${value#"${value%%[![:space:]]*}"}"
|
|
value="${value%$'\r'}"
|
|
|
|
# Protect against command injection by disallowing certain characters in keys
|
|
value="${value//\`/}"
|
|
value="${value//\$\(/}"
|
|
|
|
# Correctly interpretet internal variables (e.g. $HOME)
|
|
if [[ "$value" == *\$* ]]; then
|
|
value=$(envsubst <<< "$value")
|
|
fi
|
|
|
|
# Strip quotes (handling both " and ')
|
|
value="${value%\"}"; value="${value#\"}"
|
|
value="${value%\'}"; value="${value#\'}"
|
|
|
|
# Use a nameref for safe, eval-free assignment
|
|
local -n current_array="CONF_$current_section"
|
|
current_array["$key"]="$value"
|
|
fi
|
|
done < "$config_file"
|
|
}
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Load command aliases from configuration
|
|
load_alias()
|
|
{
|
|
local section_name="CONF_$1"
|
|
|
|
# Check if the associative array exists using declare -p
|
|
[[ "$(declare -p "$section_name" 2>/dev/null)" != "declare -A"* ]] && return 1
|
|
|
|
# Create a nameref to the section array
|
|
local -n current_aliases="$section_name"
|
|
|
|
# Iterate safely over the keys of the associative array
|
|
for key in "${!current_aliases[@]}"; do
|
|
local cmd="${current_aliases[$key]}"
|
|
|
|
# Extract the base command (first word) safely without awk
|
|
local base_cmd="${cmd%% *}"
|
|
|
|
# Only alias if the base command is executable
|
|
if command -v "$base_cmd" >/dev/null 2>&1; then
|
|
alias "$key"="$cmd"
|
|
fi
|
|
done
|
|
}
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Load configuration values as environment variables
|
|
load_conf()
|
|
{
|
|
local section_name="CONF_$1"
|
|
|
|
[[ "$(declare -p "$section_name" 2>/dev/null)" != "declare -A"* ]] && return 1
|
|
|
|
local -n current_vars="$section_name"
|
|
|
|
for key in "${!current_vars[@]}"; do
|
|
# Export the key/value pair as a standard shell variable
|
|
# We use 'export' directly; Bash handles the assignment safely here
|
|
export "$key"="${current_vars[$key]}"
|
|
done
|
|
}
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# ------------------------------------------------------------------------------
|
|
# ********************************** MAIN PROGRAM ******************************
|
|
# ------------------------------------------------------------------------------
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Store script's path (realpath -s resolve symlinks if profile.sh is a symlink)
|
|
# Because we're more likely to be sourced, we use BASH_SOURCE to get the path
|
|
# of the sourced file instead of $0
|
|
if [[ -z "$PROFILE_PATH" ]]; then
|
|
export MYPATH=$(dirname "$(realpath -s "${BASH_SOURCE[0]}")")
|
|
else
|
|
export MYPATH="$PROFILE_PATH"
|
|
fi
|
|
if [[ ! -e "$MYPATH/profile.sh" ]]; then
|
|
echo "[ Warning ] Path detection failed, trying to use pwd..."
|
|
MYPATH=$(pwd)
|
|
if [[ ! -e "$MYPATH/profile.sh" ]]; then
|
|
echo "[ Error ] Impossible to determine installation path, pretty much nothing will work."
|
|
fi
|
|
fi
|
|
|
|
if [[ ! -s "$MYPATH/version" ]]; then
|
|
echo "[ Warning ] Impossible to determine running version of profile, your installation might be broken."
|
|
fi
|
|
export PROFVERSION=$(cat "$MYPATH"/version)
|
|
|
|
# Build PATH environment variable
|
|
if [[ $EUID -eq 0 ]]; then
|
|
pathappend /sbin:/usr/sbin
|
|
fi
|
|
[[ -d ~/bin ]] && pathappend ~/bin
|
|
[[ -d ~/.local/bin ]] && pathappend ~/.local/bin
|
|
|
|
# Parse and load general configuration
|
|
export PROFILE_CONF="$MYPATH/profile.conf"
|
|
parse_conf "$PROFILE_CONF"
|
|
load_conf system # Load Bash system behavior configuration (history, pager, etc.)
|
|
load_conf general # General purpose configuration (compilation flags, etc.)
|
|
|
|
# Load module scripts
|
|
for script in $MYPATH/profile.d/*.sh; do
|
|
if [[ -r $script ]]; then
|
|
. $script
|
|
fi
|
|
done
|
|
|
|
# Interactive shell detection, two methods available each one of those might have different result
|
|
# depending on distribution
|
|
#shopt -q login_shell && INTERACTIVE=1
|
|
[[ $- == *i* ]] && export INTERACTIVE=1
|
|
|
|
if [[ $INTERACTIVE ]]; then
|
|
# For compiling (as we often compile with LFS/0linux...)
|
|
#Aliases
|
|
load_alias aliases
|
|
|
|
# Define PS1
|
|
trap 'timer_start' DEBUG
|
|
PROMPT_COMMAND='set_prompt'
|
|
|
|
# Set default language
|
|
setfr
|
|
showinfo && printf "\n"
|
|
check_updates -q
|
|
disp I "Profile version $PROFVERSION chargé..."
|
|
fi
|
|
|
|
# Cleanup
|
|
unset pathremove pathprepend pathappend
|
|
|
|
#return 0
|
|
|
|
# End profile.sh
|