dotfiles/dot_zsh_functions
MorganGeek 56702d74f7 helper to list invalid filenames in manuals/readme
- Helper name is `invalid_file_refs` and can be used like this :
  `invalid_file_refs README.*`
- Given a document (readme, manual...) containing file names, the script
  will attempt to identify what file names are either not referenced in
  the source code, or missing in the project, thus helping to detect
  some potentials issues.
- Example of issue detected by this tool : the README.md
  mentions a `config.yaml` while the application would search for `config.yml`.
  Because of this mistake, the user might struggle to make the application work.
2020-07-13 16:19:08 +02:00

577 lines
18 KiB
Plaintext

# Text formatting utilities
bold=$(tput bold)
underline=$(tput sgr 0 1)
reset=$(tput sgr0)
purple=$(tput setaf 171)
red=$(tput setaf 1)
green=$(tput setaf 76)
tan=$(tput setaf 3)
blue=$(tput setaf 38)
header() {
printf "\n${bold}${purple}========== %s ==========${reset}\n" "$@"
}
arrow() {
printf " ➜ %s\n" "$@"
}
success() {
printf "${green} ✔ %s${reset}\n" "$@"
}
error() {
printf "${red} ✖ %s${reset}\n" "$@"
}
warning() {
printf "${tan} ➜ %s${reset}\n" "$@"
}
underline() {
printf "${underline}${bold}%s${reset}\n" "$@"
}
bold() {
printf "${bold}%s${reset}\n" "$@"
}
note() {
printf "${underline}${bold}${blue}Note:${reset} ${blue}%s${reset}\n" "$@"
}
# Browser interaction utilities
function browse() {
open -na "$DEFAULT_BROWSER" --args "$1"
}
function google() {
browse "https://www.google.com/search?q=$*"
}
function stackoverflow() {
browse "https://www.google.com/search?q=site:stackoverflow.com $*"
}
function github() {
browse "https://github.com/search?q=$*"
}
function hacker() {
browse "https://hn.algolia.com/?sort=byDate&query=$*"
}
function gmail() {
browse "https://mail.google.com/mail/u/0"
}
function gmail2() {
browse "https://mail.google.com/mail/u/1"
}
function cicdboard() {
browse "$JIRA_URL/secure/RapidBoard.jspa?rapidView=457&view=planning.nodetail"
}
function cicddashboard() {
browse "$JIRA_URL/secure/Dashboard.jspa?selectPageId=13131"
}
function calendar() {
browse "https://calendar.google.com/calendar/r?tab=mc"
}
function asana() {
browse "https://app.asana.com"
}
function confluencetasks() {
browse "$CONFLUENCE_URL/plugins/inlinetasks/mytasks.action"
}
function trello_web() {
browse "$TRELLO_BOARD_URL"
}
function bookmarks() {
browse "https://github.com/MorganGeek/bookmarks/blob/master/README.md"
}
function spotify() {
browse "https://open.spotify.com/search/$*"
}
function lob() {
browse "https://lobste.rs"
}
function archive() {
browse "https://web.archive.org/web/*/$*"
}
# Jira utilities
function issues() {
jira issue jql "status = Open AND text ~ \"$*\" ORDER BY Created DESC"
}
function istherenewissues() {
LASTISSUE=$(newissues | sed $'s,\x1b\\[[0-9;]*[a-zA-Z],,g' | awk 'FNR==2{print $2}')
if [[ -f "$HOME/.newjiraissue" ]]; then
previous_jira_issue=$(\cat "$HOME/.newjiraissue" | sed $'s,\x1b\\[[0-9;]*[a-zA-Z],,g') # the sed part is for removing output colors
if [ "$LASTISSUE" != "$previous_jira_issue" ]; then
newissues
else
success "no new issue"
fi
fi
echo "$LASTISSUE" >"$HOME/.newjiraissue"
}
# Prolog / Logtalk
function logtalk() {
path_swilgt=$(find /usr/local/Cellar/logtalk -name "*swilgt.sh" 2>/dev/null)
sh "$path_swilgt"
}
# History / Aliases helpers
function top_commands() {
local filter="$1"
local max_results=${2:-'50'}
history | \cat | awk '{CMD[$2]++;count++;}END { for (a in CMD)print CMD[a] " " CMD[a]/count*100 "% " a; }' | grep -v "./" | column -c3 -s " " -t | grep "$filter" | sort -nr | nl | head "-n$max_results"
}
function top_commands_full() {
local filter="$1"
local max_results=${2:-'50'}
history | \cat | awk '{$1=$1};1' | sed 's/^[0-9 TAB]*//g' | awk '{CMD[$0]++;count++;}END { for (a in CMD)print CMD[a] " " CMD[a]/count*100 "%\t" a; }' | grep "$filter" | sort -nr | nl | head "-n$max_results"
}
# Where is a function defined?
function whichfunc() {
whence -v $1
type -a $1
}
function suggest_aliases() {
local search_input_size=${1:-'50'}
header "alias recommendations"
while read -r line; do
local matching_aliases=$(ag "$line")
if [ ! -z "$matching_aliases" ]; then
success "there is an alias for $line :"
while read -r alias_line; do
arrow "$alias_line"
done < <(echo "$matching_aliases")
echo
else
warning "no alias for $line"
fi
done < <(top_commands_full "" "$search_input_size" | awk '{ $1=""; $2=""; $3=""; print}' | awk 'NF' | awk '{$1=$1};1' | awk -v COUNT=1 'NF>COUNT' | head "-$search_input_size")
}
# Web Crawling
function aboutpage() {
year=$(echo "$*" | egrep -Eo '\b[[:digit:]]{4}\b' | head -n1)
if [ -z "$year" ]; then
year=$(curl -sSL "$*" | tr '<' '\r' | \egrep -i "date|datetime" -A 1 | \grep -Eo '\b[[:digit:]]{4}\b' | head -n1)
fi
author=$(curl -sSL "$*" | tr '<' '\r' | \egrep -i "author" -A 1 | \grep -Eo '([A-Z][A-Za-z]+\s([A-Za-z ]+)*)' | head -n1)
title=$(curl -sSL "$*" | tr '<' '<\n' | \grep title -A 1 | head -n1 | sed -E 's/.*<title>(.*)<\/title>.*/\1/' | sed "s/ [^[:alnum:]]*$author//")
yearint=$(($year + 0))
currentyear=$(echo $(date +"%Y"))
if [ ! -z "$author" ]; then
echo "by $author"
fi
if [ ! -z "$title" ]; then
echo "-> $title"
fi
if [[ $yearint -ge 1970 && $yearint -le $currentyear ]]; then
echo "$yearint"
fi
if [ ! -z "$title" ] && [ ! -z "$author" ] && [[ $yearint -ge 1970 && $yearint -le $currentyear ]]; then
echo "[$author]($*) - ($yearint) $title"
fi
}
# Extract a column from a tabular output
# via https://blog.developer.atlassian.com/ten-tips-for-wonderful-bash-productivity/
function col() {
awk -v col=$1 '{print $col}'
}
# Skip first x words in line
# via https://blog.developer.atlassian.com/ten-tips-for-wonderful-bash-productivity/
function skip() {
n=$(($1 + 1))
cut -d' ' -f$n-
}
# Code search / stats helpers
cmd_loc="find . -type f \( \
-name '*.py' \
-o -name '*.rb' \
-o -name '*.go' \
-o -name '*.java' \
-o -name '*.kt' \
-o -name '*.c' -o -name '*.h' \
-o -name '*.js' \
-o -name '*.tsx' \
-o -name '*.sh' \
-o -name '*.md' \
-o -name '*.xml' \
-o -name '*.yaml' -o -name '*.yml' \
-o -name '*.groovy' \
-o -name '*.gradle' \
-o -name '*.properties' \
\) -exec \cat \{\} \; | LANG=C LC_CTYPE=C sed -e 's/^[ \t]*//;s/[ \t]*$//'"
# Unique lines of code
# Via https://text.causal.agency/004-uloc.txt
function uloc() {
eval "$cmd_loc | LANG=C LC_CTYPE=C sort -u | wc -l"
}
# Top lines of code
function toploc() {
eval "$cmd_loc | LANG=C LC_CTYPE=C cut -c 1-100 | LANG=C LC_CTYPE=C sort | uniq -c | LANG=C LC_CTYPE=C sort -nr | head -50"
}
function how_in() {
where="$1"
shift
IFS=+ curl "cht.sh/${where}/$*"
}
# File name references in file
function filerefs() {
\grep -Eo "\b([a-zA-Z.]+)\.([a-z]{2,4}\b)" "$1" \
| sort -u \
| egrep -vi "\.com|\.git|\.io|\net|\.org|\.se|\.me|\.fr|contributing\.md"
}
function invalid_file_refs() {
while read -r file_ref; do
arrow "processing $file_ref ..."
find . -name "$file_ref" 1>/dev/null
local exit_status=$?
if [ $exit_status -eq 1 ]; then
warning "$file_ref does not exist in the project"
else
success "$file_ref was found in the project"
fi
arrow "checking if $file_ref is present in the source code..."
source_refs=$(\grep "$file_ref" * -r -l | grep -v "$1" | wc -l 2>/dev/null | trim)
if [ "$source_refs" -eq 0 ]; then
error "$file_ref was not found in source code"
else
arrow "searching for $file_ref references in soure code..."
while read -r source_ref; do
success "$file_ref was found in $source_ref"
done < <(\grep "$file_ref" * -r -l)
fi
done < <(filerefs "$1")
}
# File stats helpers
# Find files bigger than X size and sort them by size
function biggerthan() {
find . -size "+$*" -type f -print0 | xargs -0 ls -Ssh | sort -z
}
# To automatically ls when changing directory
function cd() {
builtin cd "$@" && ls -latr
}
function mouse() {
case "$(uname -s)" in
Darwin)
sh ~/.scripts/mouse_bluetooth.sh
;;
esac
}
# Information gathering
function meteo() {
curl "fr.wttr.in/$*"
}
function rate() {
curl "http://rate.sx/$*"
}
# Uploaders
function transfer() {
# check arguments
if [ $# -eq 0 ]; then
warning "No arguments specified. Usage:\necho transfer /tmp/test.md\ncat /tmp/test.md | transfer test.md"
return 1
fi
# get temporarily filename, output is written to this file show progress can be showed
tmpfile=$(mktemp -t transferXXX)
# upload stdin or file
file=$1
if tty -s; then
basefile=$(basename "$file" | sed -e 's/[^a-zA-Z0-9._-]/-/g')
if [ ! -e $file ]; then
error "File $file doesn't exists."
return 1
fi
if [ -d $file ]; then
# zip directory and transfer
zipfile=$(mktemp -t transferXXX.zip)
cd $(dirname $file) && zip -r -q - $(basename $file) >>$zipfile
curl --progress-bar --upload-file "$zipfile" "https://transfer.sh/$basefile.zip" >>$tmpfile
rm -f $zipfile
else
# transfer file
curl --progress-bar --upload-file "$file" "https://transfer.sh/$basefile" >>$tmpfile
fi
else
# transfer pipe
curl --progress-bar --upload-file "-" "https://transfer.sh/$file" >>$tmpfile
fi
# cat output link
cat $tmpfile
# cleanup
rm -f $tmpfile
}
function checkov() { docker run -i --rm -v "$(pwd):/tf" bridgecrew/checkov -d /tf "$@"; }
function vimat() {
vim +/$1 $2
}
function httperr() {
curl -s "https://http.cat/$1" | imgcat
}
# Config / Infra as code
function terraform-compliance() { docker run --rm -v "$(pwd):/target" -i -t eerkunt/terraform-compliance "$@"; }
function terragrunt_color() {
BOLD=$(tput bold)
BLACK=$(tput setaf 0)
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
BLUE=$(tput setaf 4)
CYAN=$(tput setaf 6)
RESET=$(tput sgr0)
REDBOLD=${RED}${BOLD}
REDRESET=${RESET}${RED}
BLUEBOLD=${BLUE}${BOLD}
BLUERESET=${RESET}${BLUE}
terragrunt ${*} 2>&1 | sed \
-e "s/\(\\[terragrunt\\] \\[.*\\]\)\( [0-9\\/]* [0-9:]*\) /${BLUEBOLD}\1${BLUERESET}\2${RESET} /" \
-e "s/\(\\[terragrunt\\]\)\( [0-9\\/]* [0-9:]*\) /${BLUEBOLD}\1${BLUERESET}\2${RESET} /" \
-e "s/\(Error: \)\(.*\)/${REDBOLD}\1${REDRESET}\2${RESET}/" \
-e "s/\(Hit multiple errors:\)/${REDBOLD}\1${RESET}/" \
-e "s/\(exit status 1\)/${RED}\1${RESET}/" \
-e "s/\( WARNING: \)\(.*\)/${YELLOW}${BOLD}\1${RESET}${YELLOW}\2${RESET}/" \
-e "s/\( Running command: \)\(.*\)/\1${CYAN}\2${RESET}/" \
-e "s/\( *.*: *\)\(\".*\"\)\( => \)\(\".*\"\)/${YELLOW}\1${RED}\2${BLACK}\3${GREEN}\4${RESET}/" \
-e "s/\( *.*: *\".*\"\)/${GREEN}\1${RESET}/"
}
function jenkins-cli() {
local script_location=$(find $HOME/code/jenkins-cloudbees-core -name "jenkins-cli.sh")
eval "$script_location $*"
}
# Security / Secrets helpers
function passwords() {
bw list items --search "$1" | jq -c '.[] | .name + " " + .login.username + ":" + .login.password + " " + .login.uris[0].uri'
}
function password() {
bw get password "$1"
}
function vaultgetsecret() {
local secret=$(grep -A 500 "ANSIBLE_VAULT" "$1" | awk '{$1=$1;print}' | \grep -Eo "^[0-9a-z^ ]+$")
local secret_string=$(echo "\$ANSIBLE_VAULT;1.1;AES256\n$secret")
echo "$secret_string" | awk '{$1=$1;print}' | ansible-vault decrypt --vault-password-file=$VAULT_PASSWORD_FILE
}
### Git helpers
function backupgithub() {
cd "$REPO_PATH"
curl -sL "https://api.github.com/users/$1/repos" | jq -r '.[] | .ssh_url' | xargs -n1 git clone --mirror --no-hardlinks
}
function gitydiff() {
local path_to_file="$1"
git show "HEAD:$path_to_file" | colordiff -y - "$path_to_file"
}
function gcrb() {
branch=$1
git checkout -b $branch origin/$branch
}
function installhooks() {
pre-commit install --install-hooks --overwrite --allow-missing-config
}
function copyhooks() {
cp -f ~/.git-template/.pre-commit-config.yaml ./
installhooks
runhooks
}
function git_listobjectsbysize() {
tempFile=$(mktemp)
IFS=$'\n'
for commitSHA1 in $(git rev-list --all); do
git ls-tree -r --long "$commitSHA1" >>"$tempFile"
done
# sort files by SHA1, de-dupe list and finally re-sort by filesize
sort --key 3 "$tempFile" |
uniq |
sort --key 4 --numeric-sort --reverse
# remove temp file
rm -f "$tempFile"
}
function setorigin() {
gra origin "$1" 2>/dev/null
grset origin "$1"
if [[ "$1" =~ *"$COMPANY_NAME"* ]]; then
copyhooks
fi
}
function gitpushcurrentremote() {
gitpushallremote "$(git_current_branch)"
}
function gitpushallremote() {
local param_branch="$1"
grv
grv | grep push | awk '{print $1}' | while read -r remote; do
if [ -z "$param_branch" ]; then
arrow "pushing all branches to $remote"
git push --all "$remote"
else
arrow "pushing $param_branch to $remote"
git push "$remote" "$param_branch"
fi
done
}
function clone() {
local folder=$(basename $1 | sed 's/\.git.*//g')
arrow "git project identified as $folder"
arrow "cloning repository ..."
if gcls "$1"; then
success "repository cloned"
if [[ -n "$folder" ]]; then
cd "$folder" || exit
if [[ "$1:u" =~ *"$COMPANY_NAME:u"* ]]; then
arrow "copying pre-commit hooks ..."
copyhooks
fi
else
error "unable to change current directory to : $folder"
fi
else
error "unable to clone repository url : $1"
fi
}
function git-project() {
if [ -d "$REPO_PATH" ]; then
REPO_PATH="$(pwd)"
fi
local preview='lsd --color always --icon always --group-dirs first {}'
local dir=$(find "$REPO_PATH" -maxdepth 3 -type d -name ".git" | sed 's#.git$##' | fzf --select-1 --query="$*" --preview "$preview")
if [[ -n "$dir" ]]; then
cd "$dir" || exit
fi
}
function gitignorefor() {
local language=${1:-''}
if [ ! -d "$HOME/Code/gitignore" ]; then
arrow "cloning https://github.com/github/gitignore into $REPO_PATH/gitignore"
git clone "https://github.com/github/gitignore $_"
fi
local gitignore_file=$(fd "$language" "$REPO_PATH/gitignore" | head -n1)
if [ ! -z "$gitignore_file" ]; then
success "matched gitignore file : $gitignore_file"
if [ ! -f "$(pwd)/.gitignore" ]; then
arrow "you don't have a $(pwd)/.gitignore file, but that's not an issue :-) ..."
fi
arrow "copying the file content to your $(pwd)/.gitignore file"
adhoc blockinfile -a "block='{{ lookup('file', '$gitignore_file') }}' dest='$(pwd)/.gitignore' create=yes"
else
error "no gitignore file found for $language"
fi
}
# Miscellaneous helpers
function colorpic() {
local picture_url="$1"
arrow "Colorizing $picture_url"
local result_url=$(\curl -F "image=@$picture_url" -H "api-key:$COLORPIC_APIKEY" https://api.deepai.org/api/colorizer -s | jq '.output_url' | strings)
success "Generated $result_url"
arrow "Display in progress..."
eval "\curl -s $result_url | imgcat"
}
function bookmarkadd() {
adhoc lineinfile -a "path=$HOME/Code/bookmarks/README.md insertafter='"$1"' line='* "$2"'"
}
function rssadd() {
adhoc lineinfile -a "path=~/.newsboat/urls line='"$1"'"
newsboat
}
# Via https://stackoverflow.com/a/58598185/2309958
# capture the output of a command so it can be retrieved with ret
function cap () { tee /tmp/capture.out}
# return the output of the most recent command that was captured by cap
function ret () { \cat /tmp/capture.out }
# Package / Dependencies management helpers
function adhocbis() {
local ansible_output=$(adhoc "$*")
echo $ansible_output | sed 's/127.0.0.1.*SUCCESS/WOKE/g'
}
function brewadd() {
brew install "$1"
adhoc lineinfile -a "path=~/Brewfile line='brew \"$1\"'"
}
function pipadd() {
pip install "$1"
pip freeze >"$HOME/requirements.txt"
}
function goadd() {
adhoc lineinfile -a "path=~/.scripts/godeps.sh line='go get -u -v $1'"
go get -u -v "$1"
}
# Make a directory and cd to it
function take() {
mkdir -p "$@" && cd "${@:$#}"
}
# Date / Time management helpers
function endofday() {
local planned_end=$(moro status 2>&1 | \grep -Eo "Working until ([0-9:]+) will make.*" | uniq | \grep -Eo "([0-9]+:[0-9]+)")
local max_hour="$planned_end"
local min_hour=$(current_time)
if [ -z "$planned_end" ]; then
local clockout=$(moro report 2>&1 | \grep -Eo "Clock out.*([0-9:]+)" | \grep -Eo "([0-9]+:[0-9]+)")
max_hour="$clockout"
fi
if is_earlier "$min_hour" "$max_hour"; then
arrow "you should keep working, it's only $min_hour while you should work until $max_hour"
moro status
else
warning "you should stop working now because it's later than $max_hour"
moro report
fi
}
function convtimetodate() {
date -j -f '%H:%M' "$1" +'%Y/%m/%d %H:%M'
}
function convtimetotimestamp() {
date -j -f '%H:%M' "$1" +'%s'
}
function is_earlier() {
local first=$(convtimetotimestamp "$1")
local second=$(convtimetotimestamp "$2")
if [ "$second" -gt "$first" ]; then
true
else
false
fi
}
function dl_stopwords() {
curl -Lks https://raw.githubusercontent.com/MorganGeek/bookmarks/master/stopwords.txt -o "$HOME/stopwords.txt"
}
function file_getwords() {
dl_stopwords
\cat "$1" | tr '[:upper:]' '[:lower:]' | \grep -o -E '\w{3,}' | \grep --invert-match --word-regexp --fixed-strings --file="$HOME/stopwords.txt" | \sed 's/s$//g' | \sed 's/ing$//g' | sort_count
}
function file_getpairs() {
dl_stopwords
\cat "$1" | filter_pairs
}
function file_dups() {
\cat "$1" | sort_count
}
function foreach_run() {
find . -name "$1" -exec "$2" {} \;
}
# input should be something like : 1-10 to generate one number between 1 and 10
function chance() {
[[ $(shuf -i "$1" -n 1) == 1 ]]
}
function runiflucky() {
if chance "1-10"; then
if alias "$1" 2>/dev/null || (compgen -A function | grep "$1" 1>/dev/null && compgen -A function "$1" 1>/dev/null); then
eval "$1"
fi
fi
}