91c41d33cb
- always go to new copy of the cloned repository after forking it - always set the local repo user config after the fork - always check for spelling mistakes in the forked repo readme files just in case
709 lines
23 KiB
Plaintext
709 lines
23 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" "$@"
|
|
}
|
|
function substring() {
|
|
local _length=${#1}
|
|
local _start=${2}
|
|
local _end=${3}
|
|
echo ${1:_start:_length-_end}
|
|
}
|
|
|
|
|
|
# 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/*/$*"
|
|
}
|
|
function iknowwhatyoudownload() {
|
|
browse "https://iknowwhatyoudownload.com/en/peer/?ip=$*"
|
|
}
|
|
function vimium() {
|
|
browse "chrome-extension://dbepggeogbaibhgnhhndojpepiihcmeb/pages/options.html#"
|
|
}
|
|
function toby() {
|
|
browse "chrome-extension://gfdcgfhkelkdmglklfbndgopaihmoeci/toby.html"
|
|
}
|
|
# 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; }' G --invert-match "./" | column -c3 -s " " -t G "$filter" | sort --numeric-sort --reverse | nl H "-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; }' G "$filter" | sort --numeric-sort --reverse | nl H "-n$max_results"
|
|
}
|
|
# Where is a function defined?
|
|
function whichfunc() {
|
|
whence -v $1
|
|
type -a $1
|
|
}
|
|
|
|
source $HOME/Code/dotfiles/dot_scripts/suggest_readable_parameters.sh
|
|
|
|
# TODO : suggest spelling fixes
|
|
function suggest_code_refactoring() {
|
|
#inspired by : \grep 'awk '\''{$1=$1};1'\' $HOME/Code/dotfiles/dot_zsh*
|
|
header "code refactoring suggestions"
|
|
while read -r line; do
|
|
local short_name=$(echo "$line" | sed -E "s/='.*//g")
|
|
local alias_value=$(echo "$line" | sed -E 's/[a-zA-Z_-]+=//g')
|
|
local alias_value_truncated=${alias_value:1:$((${#alias_value} - 2))}
|
|
\fgrep -d skip $alias_value_truncated "$@" 2>/tmp/error.log | \grep --invert-match "alias $short_name=" 1>/dev/null
|
|
if [ $? -eq 0 ]; then
|
|
success "found $short_name --> $alias_value_truncated"
|
|
\fgrep -d skip "$alias_value_truncated" "$@" --color -n -H --line-buffered | \grep --invert-match "alias $short_name="
|
|
else
|
|
local error_message=$(\cat /tmp/error.log)
|
|
if [ -n "$error_message" ]; then
|
|
error "issue occured when looking for $alias_value_truncated : $error_message"
|
|
fi
|
|
fi
|
|
done < <(alias | awk -v COUNT=1 'NF>COUNT') # list of all aliases, excluding the less interesting ones (where we use one word for another)
|
|
}
|
|
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' H "-$search_input_size")
|
|
}
|
|
|
|
# Sound management
|
|
# Inspired by https://apple.stackexchange.com/a/213048/231885 for switching devices
|
|
# and https://coderwall.com/p/22p0ja/set-get-osx-volume-mute-from-the-command-line for volume management
|
|
function mute_device() {
|
|
local current_device=$(SwitchAudioSource -c)
|
|
local target_device="$1"
|
|
if SwitchAudioSource -a | grep "$target_device" 1>/dev/null; then
|
|
SwitchAudioSource -s "$1" 1>/dev/null
|
|
osascript -e 'set volume output muted true'
|
|
success "device $target_device muted"
|
|
SwitchAudioSource -s "$current_device" 1>/dev/null
|
|
if [ "$current_device" != "$target_device" ]; then
|
|
arrow "switching back to $current_device"
|
|
fi
|
|
arrow "currently using $target_device"
|
|
else
|
|
error "sound device not found : $target_device (maybe it's disconnected ?)"
|
|
fi
|
|
}
|
|
function switch_device() {
|
|
local target_device="$1"
|
|
if SwitchAudioSource -a | grep "$target_device" 1>/dev/null; then
|
|
if SwitchAudioSource -s "$1" 1>/dev/null; then
|
|
success "switched to $target_device"
|
|
unmute
|
|
else
|
|
error "failed to switch to $target_device"
|
|
fi
|
|
else
|
|
error "sound device not found : $target_device (maybe it's disconnected ?)"
|
|
fi
|
|
}
|
|
|
|
# Web Crawling
|
|
function aboutpage() {
|
|
year=$(echo "$*" | egrep --extended-regexp --only-matching '\b[[:digit:]]{4}\b' H -n1)
|
|
if [ -z "$year" ]; then
|
|
year=$(curl --silent --show-error --location "$*" | tr '<' '\r' | \egrep --ignore-case "date|datetime" -A 1 | \grep --extended-regexp --only-matching '\b[[:digit:]]{4}\b' H -n1)
|
|
fi
|
|
author=$(curl --silent --show-error --location "$*" | tr '<' '\r' | \egrep --ignore-case "author" -A 1 | \grep --extended-regexp --only-matching '([A-Z][A-Za-z]+\s([A-Za-z ]+)*)' H -n1)
|
|
title=$(curl --silent -SL "$*" | tr '<' '<\n' | \grep title -A 1 H -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 --unique | 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 --numeric-sort --reverse H -50"
|
|
}
|
|
function historyloc() {
|
|
top_commands_full "" 5000 topshellloc
|
|
}
|
|
function how_in() {
|
|
where="$1"
|
|
shift
|
|
IFS=+ curl "cht.sh/${where}/$*"
|
|
}
|
|
# File name references in file
|
|
function filerefs() {
|
|
FILENAME=${1:-README*)}
|
|
\grep --extended-regexp --only-matching "\b([a-zA-Z.-]+)\.([a-z]{2,4}\b)" $FILENAME \
|
|
| sort --unique \
|
|
| egrep --invert-match --ignore-case "\.com|\.git|\.io|\net|\.org|\.se|\.me|\.fr|contributing\.md"
|
|
}
|
|
function invalid_file_refs() {
|
|
FILENAME=${1:-"README.*"}
|
|
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 G --invert-match "$FILENAME" | 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 "$FILENAME")
|
|
}
|
|
|
|
|
|
# Text search
|
|
# run write-good, proselint, and aspell in non interactive mode, to list all mispelled words found
|
|
function checkenlist() {
|
|
aspell -d en list < "$1" | sort --unique --ignore-case
|
|
write-good --no-passive "$1"
|
|
proselint "$1"
|
|
alex -q --stdin < "$1"
|
|
}
|
|
|
|
function checkenremote() {
|
|
local target_url=$(echo "$1" | sed 's/github.com/raw.githubusercontent.com/g' | sed 's;blob/;;')
|
|
curl --location --insecure --silent "$target_url" > /tmp/file && checkenlist /tmp/file && write-good --no-passive /tmp/file && proselint /tmp/file && \cat /tmp/file > alex -q --stdin
|
|
}
|
|
|
|
# Time management
|
|
function zoomtimeboxed() {
|
|
declare -i total_minutes=$1
|
|
declare -i total_seconds=$total_minutes*60
|
|
echo $total_seconds;
|
|
arrow "will start zoom and leave it after $total_minutes minutes ($total_seconds seconds)"
|
|
zoom; (sleep "$total_seconds" && nozoom) &
|
|
}
|
|
|
|
# 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 --zero-terminated
|
|
}
|
|
# To automatically ls when changing directory
|
|
function cd() {
|
|
builtin cd "$@" && ll -atr
|
|
}
|
|
function mouse() {
|
|
case "$(uname -s)" in
|
|
Darwin)
|
|
sh ~/.scripts/mouse_bluetooth.sh
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Conversion
|
|
function epub2pdf() {
|
|
local output_file_name=$(echo $1 | sed 's/.epub$/.pdf/')
|
|
ebook-convert "$1" "$output_file_name"
|
|
}
|
|
function epub2mobi() {
|
|
local output_file_name=$(echo $1 | sed 's/.epub$/.mobi/')
|
|
ebook-convert "$1" "$output_file_name"
|
|
}
|
|
|
|
# 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 --silent "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 --extended-regexp --only-matching "^[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 --silent --location "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"
|
|
gsh "HEAD:$path_to_file" | colordiff -y - "$path_to_file"
|
|
}
|
|
function gcrb() {
|
|
branch=$1
|
|
gcb $branch origin/$branch
|
|
}
|
|
|
|
function installhooks() {
|
|
pre-commit install --install-hooks --overwrite --allow-missing-config
|
|
}
|
|
function copyhooks() {
|
|
FILENAME=${1:-"$HOME/.git-template/.pre-commit-config.yaml"}
|
|
cp -f "$FILENAME" ./.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"
|
|
success "updated origin to $1"
|
|
arrow "copying pre-commit hooks ..."
|
|
if [[ "$1" =~ "$COMPANY_NAME" ]]; then
|
|
copyhooks
|
|
gitpro
|
|
else
|
|
copyhooks "$HOME/.git-template/.pre-commit-minimal-config.yaml"
|
|
gitperso
|
|
fi
|
|
}
|
|
function gitpushcurrentremote() {
|
|
gitpushallremote "$(git_current_branch)"
|
|
}
|
|
function gitpushallremote() {
|
|
local param_branch="$1"
|
|
grv
|
|
grv G push | awk '{print $1}' | while read -r remote; do
|
|
if [ -z "$param_branch" ]; then
|
|
arrow "pushing all branches to $remote"
|
|
gp --all "$remote"
|
|
else
|
|
arrow "pushing $param_branch to $remote"
|
|
gp "$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
|
|
arrow "copying pre-commit hooks ..."
|
|
if [[ "$1:u" =~ "$COMPANY_NAME:u" ]]; then
|
|
copyhooks
|
|
gitpro
|
|
else
|
|
copyhooks "$HOME/.git-template/.pre-commit-minimal-config.yaml"
|
|
gitperso
|
|
fi
|
|
else
|
|
error "unable to change current directory to : $folder"
|
|
fi
|
|
else
|
|
error "unable to clone repository from url : $1"
|
|
fi
|
|
}
|
|
function fork() {
|
|
code || exit
|
|
local folder=$(basename $1 | sed 's/\.git.*//g')
|
|
gh repo fork "$1" --clone && cd "$folder"
|
|
if [[ "$1:u" =~ "$COMPANY_NAME:u" ]]; then
|
|
gitpro
|
|
else
|
|
gitperso
|
|
fi
|
|
checkenlist README*
|
|
}
|
|
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" H -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 --silent $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() {
|
|
md -p "$@" && cd "${@:$#}"
|
|
}
|
|
|
|
# Date / Time management helpers
|
|
function endofday() {
|
|
local planned_end=$(moro status 2>&1 | \grep --extended-regexp --only-matching "Working until ([0-9:]+) will make.*" | uniq | \grep --extended-regexp --only-matching "([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 --extended-regexp --only-matching "Clock out.*([0-9:]+)" | \grep --extended-regexp --only-matching "([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 --location --insecure --silent https://raw.githubusercontent.com/MorganGeek/bookmarks/master/stopwords.txt -o "$HOME/stopwords.txt"
|
|
}
|
|
function file_getwords() {
|
|
dl_stopwords
|
|
\cat "$1" | tr '[:upper:]' '[:lower:]' | \grep --extended-regexp --only-matching '\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 G "$1" 1>/dev/null && compgen -A function "$1" 1>/dev/null); then
|
|
eval "$1"
|
|
fi
|
|
fi
|
|
}
|