6.6 KiB
layout
| layout |
|---|
| layouts/base.njk |
Patterns
The task file from the specification is very basic. Commands can also have parameters and call each other.
The following is a collection of more complex task file patterns.
Set default parameter
Fallback to a default value for a parameter.
build() {
local platform="amd64"
if [[ -n "$1" ]]; then
platform="$1"
fi
Ensure parameter is not empty
Check the first param and exit if it is empty.
deploy() {
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
Prompt for input
Use read to ask for inputs.
if [[ -z "$2" ]]; then
read -p "Enter the task description: " task_description
else
task_description="$2"
fi
Setup local env vars
Define env vars at the beginning of the task file.
CONFIGURATION_FILE="file.conf"
GIT_BRANCH=$(git symbolic-ref --short -q HEAD)
Template with env vars
Create a parameterized file from a template. Requires envsubst.
template-with-env() {
echo "Template $CONFIGURATION_FILE"
export CONFIGURATION_1
export CONFIGURATION_2=${CONFIGURATION_2:="value"}
envsubst < "file.conf.template" > "$CONFIGURATION_FILE"
}
Create Python virtual env
Initialize Python virtual env with uv.
init-venv() {
if [[ ! -d "venv$GIT_BRANCH" ]]; then
echo "Init venv$GIT_BRANCH with $(uv --version)."
uv venv "venv$GIT_BRANCH"
fi
}
Activate Python virtual env
Activate the virtual env.
activate-venv() {
if [[ -f ".venv/bin/activate" ]]; then
source ".venv/bin/activate"
else
echo "Could not find .venv/bin/active. Use init-venv to initalize."
fi
}
Call a Python script
Run a Python script.
generate-password-hash() {
activate-venv
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
export PASSWORD_PLAIN="$1"
bin/password-hash
}
The Python script: bin/password-hash
#!/usr/bin/env python3
import os
from passlib.context import CryptContext
crypt_context = CryptContext(schemes=['pbkdf2_sha512', 'plaintext'], deprecated=['plaintext'])
password = os.environ.get('PASSWORD_PLAIN')
print(crypt_context.hash(password))
Command with named parameters
Assuming you have a docker-compose.yml and would like to start selected or all containers.
start() {
if [[ "$1" =~ "db" ]]; then
docker compose up -d db
fi
if [[ "$1" =~ "admin" ]]; then
docker compose up -d admin
echo "Open http://localhost:8000 url in your browser."
fi
if [[ "$1" =~ "odoo" ]]; then
docker compose up -d odoo
echo "Open http://localhost:8069 url in your browser."
fi
if [[ "$1" =~ "mail" ]]; then
docker compose up -d mail
echo "Open http://localhost:8025 url in your browser."
fi
}
Start all containers with task start and selected with task start db,admin.
Run commands in container
Use docker exec -i to run commands in a container.
drop-db() {
local database="$1"
if [[ -z "$database" ]]; then
database="example"
fi
docker exec -i db psql "postgres://odoo:odoo@localhost:5432/postgres" -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '$database';"
docker exec -i db psql "postgres://odoo:odoo@localhost:5432/postgres" -c "DROP DATABASE \"$database\";"
}
Loop over files and folders
Use for to loop over file, folders or arrays.
render() {
echo "Update index.html for all folders"
for folder in ./*; do
if [[ -f "$folder/README.md" ]]; then
cd "$folder" || exit
md2html README.md _site/index.html
cd .. || exit
fi
done
}
Parse and convert a file
With this function you can split a file into multiple parts whenever a specific keyword is matching. In this example the keyword is !vault.
convert-vault-file() {
local file_path="$1"
local temp_file=$(mktemp)
local temp_part_file=$(mktemp)
local write_finished=false
local current_key=""
while IFS= read -r line; do
# Check for keyword
if [[ "$line" =~ "!vault" ]]; then
# Process previous vault entry if it exists
if [[ "$write_finished" = true ]] && [[ -n "$current_key" ]] && [[ -s "$temp_part_file" ]]; then
# Decrypt part file and write to assemble file
ansible-vault decrypt "$temp_part_file"
local value=$(cat "$temp_part_file")
echo "$current_key: $value" >> "$temp_file"
fi
# Set up for new vault entry
current_key=$(echo "$line" | cut -d':' -f1)
# Clear the file
: > "$temp_part_file"
# Flag as ready to write
write_finished=true
else
if [[ "$write_finished" = true ]]; then
# Pipe into part file
echo "$line" >> "$temp_part_file"
fi
done
done < "$file_path"
# Process the final vault entry
if [[ "$write_finished" = true ]] && [[ -n "$current_key" ]] && [[ -s "$temp_part_file" ]]; then
ansible-vault decrypt "$temp_part_file"
local value=$(cat "$temp_part_file")
echo "$current_key: $value" >> "$temp_file"
fi
# Output assembled file
cat "$temp_file"
# Cleanup temp files
rm -f "$temp_file"
rm -f "$temp_part_file"
}
Process data
This pattern tries to match the worklow of a jupyter notebook. Create a folder with the data processing scripts:
scripts
├── 01_import-mail-data
├── 02_transform-mail-data
└── 03_export-mail-data
The following function lists the scripts and asks for the number of scripts to run. Every script until the entered number is concatenated and executed.
process-data() {
while true; do
local scripts=($(ls scripts))
echo -e "Available scripts:\n"
for index in "${!scripts[@]}"; do
echo "$((index+1)): ${scripts[$index]}"
done
echo ""
read -p "Enter the number of scripts to run (or 'q' to quit): " user_input
if [[ "$user_input" = "q" ]]; then
break
fi
local temp_file=$(mktemp)
for index in "${!scripts[@]}"; do
if (( $user_input >= $((index+1)) )); then
cat "scripts/${scripts[$index]}" >> "$temp_file"
echo >> "$temp_file"
fi
done
clear
echo -e "\nPython Output:\n\n---"
python "$temp_file"
local exit_code=$?
echo -e "---\n"
echo -e "Exit code: $exit_code\n"
rm "$temp_file"
done
}