Skip to content

Commit

Permalink
feat: refactor SSH configuration functions and add new features
Browse files Browse the repository at this point in the history
- Add check for required commands "gum" and "argc"
- Modify the `select_many` function to use custom prefixes for selected and unselected items
- Add a new function `select_all`
- Modify the `add` function to include a check for existing hostnames in $sshfile and to edit the hostname if it exists
- Modify the `remove` function to include a check for existing hostnames in $sshfile and to remove the hostname from $sshfile if it exists
- Add a new function `edit` to edit a hostname
- Add a new function `choose` to select one/many/all hostnames
- Modify the `list` function to display a formatted table of hostnames
- Add a new function `ssh` to create a ssh config from hosts
- Modify the `.profile` file to export new environment variables for gum confirm color settings
  • Loading branch information
bresilla committed Apr 30, 2024
1 parent d3eda0a commit f4467eb
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 110 deletions.
235 changes: 126 additions & 109 deletions .func/cli/hos
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#!/bin/bash

#check if some commands are available
[ ! command -v gum &> /dev/null ] && { echo "gum [https://github.com/charmbracelet/gum] is required to run this script, please install it"; exit 1; }
[ ! command -v argc &> /dev/null ] && { echo "argc [https://github.com/sigoden/argc/] is required to run this script, please install it"; exit 1; }

hostnames=/etc/hosts
sshfile=~/.ssh/config

Expand All @@ -8,7 +12,7 @@ select_one() {
}

select_many() {
cat $hostnames | awk '$1 ~ /^[^;#]/' | tail -n +4 | gum choose --no-limit --height=20
cat $hostnames | awk '$1 ~ /^[^;#]/' | tail -n +4 | gum choose --no-limit --height=20 --selected-prefix="" --unselected-prefix="" --cursor-prefix=""
}

select_all() {
Expand All @@ -21,7 +25,9 @@ select_all() {
# @option --username Username to use
# @option --port Port to use
# @option --key Key to use / IdentityFile
# @flag -q --quiet Do not ask for confirmation
add() {
# -------- HOSTNAME --------
if [ -z $argc_name ]; then
name=$(gum input --placeholder "Name?")
else
Expand All @@ -31,10 +37,13 @@ add() {
gum log --structured --level error "Invalid name, must be alphanumeric with dots"
exit 1
elif grep -q "$name" $hostnames; then
gum log --structured --level error "Name already exists"
gum log --structured --level error "Name already exists in $hostnames"
exit 1
elif grep -q "Host $name" $sshfile; then
gum log --structured --level info "Host $name already exists in $sshfile"
edit 1
fi

# -------- IP --------
if [ -z $argc_ip ]; then
ip=$(gum input --placeholder "IP?")
else
Expand All @@ -44,151 +53,159 @@ add() {
gum log --structured --level error "Invalid IP address, must be in the form of x.x.x.x"
exit 1
elif grep -q "$ip" $hostnames; then
gum log --structured --level error "IP already exists"
gum log --structured --level error "IP already exists in $hostnames"
exit 1
fi
new_object="$ip $name"
if gum confirm "are you sure you want to add $new_object"; then
echo $new_object | doas tee -a $hostnames
fi
gum log --structured --level info "added $new_object to $hostnames"

if gum confirm "do you want to add $name to $sshfile too"; then
if grep -q "Host $name" $sshfile; then
gum log --structured --level info "Host $name already exists in $sshfile"
continue
fi

string="\n\nHost $name\n\t# $ip\n\thostname $name\n"
if [ -z $argc_username ]; then
if gum confirm "use current user"; then
username=$(whoami)
else
username=$(gum input --placeholder "Username?")
fi
# -------- USERNAME --------
if [ -z $argc_username ]; then
if gum confirm "use current user"; then
username=$(whoami)
else
username=$argc_username
username=$(gum input --placeholder "Username?")
fi
string+="\tuser $username\n"

if [ -z $argc_port ]; then
port=22
else
username=$argc_username
fi
# -------- KEY --------
if [ -z $argc_key ]; then
if gum confirm "add a key"; then
key=$(gum file ~/.ssh/)
else
port=$argc_port
fi
string+="\tport $port\n"

if [ ! -z $argc_key ]; then
string+="\tidentityFile $argc_key\n"
elif gum confirm "do you want to add a key for $name"; then
key=$(gum input --placeholder "Key?")
[ ! -f $key ] && { gum log --structured --level error "Key not found"; exit 1; }
string+="\tidentityFile $key\n"
key="0"
fi
else
key=$argc_key
fi
# -------- PORT --------
if [ -z $argc_port ]; then
port=$(gum input --placeholder "Port?")
else
port=$argc_port
fi

new_object="$ip $name #$username #$port #$key"

echo -e $string | doas tee -a $sshfile
if [ "$argc_quiet" = 1 ]; then
add_host=true
add_ssh=true
else
add_host=false
add_ssh=false
gum confirm "are you sure you want to add $new_object" && add_host=true
gum confirm "do you want to add $name to $sshfile too" && add_ssh=true
fi

# echo "added successfully"
exit 0
}
if [ "$add_host" = true ]; then
echo $new_object | sudo tee -a $hostnames
gum log --structured --level info "added $new_object to $hostnames"
fi

# @cmd Edit a hostname
edit() {
echo edit "$@"
}
if [ "$add_ssh" = true ]; then
string="\nHost $name\n\t# $ip\n\tport $port\n\thostname $name\n\tuser $username"
[ -f $key ] && string+="\n\tidentityFile $key\n\tidentitiesonly yes"
echo -e $string | sudo tee -a $sshfile
gum log --structured --level info "added $name to $sshfile"
fi

# @cmd List all hostnames
list() {
select_one
exit 0
}

# @cmd Remove a hostname from the list
# @option --name Name of the host
# @option --ip IP address of the host
# @flag -q --quiet Do not ask for confirmation
remove() {
if [ -z $argc_name ] && [ -z $argc_ip ]; then
selected=$(select_many)
[ -z "$selected" ] && gum log --structured --level error "No host selected" && exit 1
while IFS= read -r line; do
if gum confirm "are you sure you want to remove $line"; then
doas sed -i "/$line/d" $hostnames
gum log --structured --level info "host $line removed"
fi
done <<< "$selected"
exit 0
fi

if [ -z $argc_ip ]; then
grep -q "$argc_name" $hostnames || { gum log --structured --level error "Name not found"; exit 1; }
line=$(grep "$argc_name" $hostnames)
elif [ -z $argc_ip ]; then
grep -q "$argc_name" $hostnames || { gum log --structured --level error "Name not found in $hostnames"; exit 1; }
grep -q "Host $name" $sshfile || { gum log --structured --level error "Host not found in $sshfile"; exit 1; }
selected=$(grep "$argc_name" $hostnames)
elif [ -z $argc_name ]; then
grep -q "$argc_ip" $hostnames || { gum log --structured --level error "IP not found"; exit 1; }
line=$(grep "$argc_ip" $hostnames)
grep -q "$argc_ip" $hostnames || { gum log --structured --level error "IP not found in $hostnames"; exit 1; }
selected=$(grep "$argc_ip" $hostnames)
else
gum log --structured --level error "Invalid arguments"
exit 1
fi
echo
if gum confirm "are you sure you want to remove $line"; then
doas sed -i "/$line/d" $hostnames
gum log --structured --level info "host $line removed"
fi

[ -z "$selected" ] && gum log --structured --level error "No host selected" && exit 1
while IFS= read -r line; do
name=$(echo $line | awk '{print $2}')

if [ "$argc_quiet" = 1 ]; then
remove_host=true
remove_ssh=true
else
remove_host=false
remove_ssh=false
gum confirm "are you sure you want to remove $line" && remove_host=true
gum confirm "do you want to remove $name from $sshfile" && remove_ssh=true
fi

if [ $remove_host = true ]; then
sudo sed -i "\|$line|d" $hostnames
gum log --structured --level info "$line removed from $hostnames"
fi
if [ $remove_ssh = true ]; then
sudo sed -i "/Host $name/,/^$/d" $sshfile
sed -i '$ d' $sshfile
gum log --structured --level info "$name removed from $sshfile"
fi
done <<< "$selected"
}

# @cmd SSH into a hostname
# @option --name Name of the host
# @option --ip IP address of the host
# @option --username Username to use
# @option --port Port to use
# @option --key Key to use / IdentityFile
ssh() {
if [ $argc_num == "all" ]; then
selected=$(select_all)
keytrigger=false
elif [ ! -z $argc_name ] && [ ! -z $argc_ip ]; then
selected="$argc_ip $argc_name"
else
selected=$(select_many)
fi
# @cmd Edit a hostname
# @flag -q --quiet Do not ask for confirmation
edit() {
selected=$(select_one)
ARRAY=($selected)
[ -z "$selected" ] && gum log --structured --level error "No host selected" && exit 1
$0 remove --ip ${ARRAY[0]} --quiet
name=$(gum input --placeholder "Name?" --value ${ARRAY[1]})
ip=$(gum input --placeholder "IP?" --value ${ARRAY[0]})
user=$(gum input --placeholder "Username?" --value ${ARRAY[2]:1})
port=$(gum input --placeholder "Port?" --value ${ARRAY[3]:1})
key=$(gum input --placeholder "Key?" --value ${ARRAY[4]:1})
$0 add --name $name --ip $ip --username $user --port $port --key $key --quiet
}

# @cmd Select one/many/all hostnames
choose() {
select_many
}

# @cmd List all hostnames
# @meta default-subcommand
list() {
selected=$(select_all)
printf "┌───────────────────┬───────────────────────────┬────────────┬──────┬─────────────────────────────────────┐\n"
printf "│ IP │ Name │ Username │ Port │ Key │\n"
printf "├───────────────────┼───────────────────────────┼────────────┼──────┼─────────────────────────────────────┤\n"
while IFS= read -r line; do
words=($line)
printf "│ %-17s │ %-25s │ %-10s │ %-4s │ %-35s │\n" ${words[0]} ${words[1]} ${words[2]:1} ${words[3]:1} ${words[4]:1}
done <<< "$selected"
printf "└───────────────────┴───────────────────────────┴────────────┴──────┴─────────────────────────────────────┘\n"
}

# @cmd Create a ssh config from hosts
ssh() {
selected=$(select_all)
[ -z "$selected" ] && gum log --structured --level error "No host selected" && exit 1

while IFS= read -r line; do
ip=$(echo $line | awk '{print $1}')
name=$(echo $line | awk '{print $2}')
string="Host $name\n\t# $ip\n\thostname $name\n"

if grep -q "Host $name" $sshfile; then
gum log --structured --level info "Host $name already exists in $sshfile"
continue
fi

if [ -z $argc_username ]; then
username=$(whoami)
else
username=$argc_username
fi
username=$(whoami)
string+="\tuser $username\n"

if [ -z $argc_port ]; then
port=22
else
port=$argc_port
fi
string+="\tport $port\n"

if [ ! -z $argc_key ]; then
string+="\tidentityFile $argc_key\n"
elif $keytrigger; then
if gum confirm "do you want to add a key for $name"; then
key=$(gum input --placeholder "Key?")
[ ! -f $key ] && { gum log --structured --level error "Key not found"; exit 1; }
string+="\tidentityFile $key\n"
fi
fi

echo -e $string | doas tee -a $sshfile
echo -e $string | sudo tee -a $sshfile
done <<< "$selected"
exit 0

Expand Down
3 changes: 2 additions & 1 deletion .profile
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ export LULE_S="/env/dot/.func/wm/lule_colors"
export LULE_C="/home/bresilla/.config/lule/configs.json"
export GUM_CHOOSE_CURSOR_FOREGROUND="1"
export GUM_CHOOSE_SELECTED_FOREGROUND="9"

export GUM_CONFIRM_SELECTED_FOREGROUND="15"
export GUM_CONFIRM_UNSELECTED_FOREGROUND="7"

#--------------------------- LOCALE --------------------------
export TZ='Europe/Berlin'
Expand Down

0 comments on commit f4467eb

Please sign in to comment.