#!/bin/bash # devctl is an utility script for automating some development tasks and actions. # To find out what options are available, run it without any arguments. # Text styles RED='\033[0;31m' BOLD=$(tput bold) NORMAL=$(tput sgr0) # Define dev paths # Those are paths to dirs and files created for dev project dev_paths=( "./avatargallery" "./devproject" "./media" "./static" "./theme" "./userdata" "./cron.txt" "./manage.py" ) # Required ports # Some tasks test for those ports before continuing port_django=8000 port_postgresql=5432 required_ports=($port_postgresql) # Default superuser username="Admin" password="password" # Some commond shorthands error() { echo -e "${RED}Error:${NORMAL} $1" } docker_stop() { docker-compose stop } docker_rebuild() { docker_stop docker-compose build --no-cache } docker_down() { docker_stop docker-compose down --remove-orphans } require_docker() { if [[ ! $IN_DOCKER = 1 ]]; then error "This command can only be ran inside the running Misago container." exit 1 fi } wait_for_db() { require_docker export PGPASSWORD=$POSTGRES_PASSWORD RETRIES=10 until psql -h $POSTGRES_HOST -U $POSTGRES_USER -d $POSTGRES_DB -c "select 1" > /dev/null 2>&1 || [ $RETRIES -eq 0 ]; do echo "Waiting for postgres server, $((RETRIES--)) remaining attempts..." sleep 3 done } # Commands intro() { echo "Usage: ./dev [arg] ..." echo "Arguments grouped by type:" echo echo "Development project:" echo echo " ${BOLD}init${NORMAL} initialize new dev project for development, do nothing if project already exists." echo " ${BOLD}clear${NORMAL} if dev project exists, delete it's files and destroy docker containers." echo " ${BOLD}rebuild${NORMAL} rebuild docker containers (uses --no-cache)." echo echo "Testing:" echo echo " ${BOLD}test${NORMAL} run tests suite." echo " ${BOLD}test module${NORMAL} run tests suite in specified python module, eg. misago.users." echo echo "Translations:" echo echo " ${BOLD}makemessages${NORMAL} update translation files for \"en\" language." echo " ${BOLD}makemessages lang${NORMAL} update translation files for \"lang\" language." echo " ${BOLD}compilemessages${NORMAL} compile translation files to \"mo\" format." echo " ${BOLD}txpull${NORMAL} pull translations from Transifex." echo " ${BOLD}txpush${NORMAL} push new source files to Transifex." echo } # Handle invalid option message invalid_argument() { echo -e "Invalid argument: ${RED}$1${NORMAL}" echo "Please run this script without any arguments to see the list of available arguments." exit 1 } # Initialize new dev project init() { for dev_path in "${dev_paths[@]}"; do if [ -e $dev_path ]; then error "Dev project already exists, or was not deleted completely." echo echo "Please use \"clear\" option to clear any pissible remaining files and try again." exit 1 fi done for port in "${required_ports[@]}"; do nc "127.0.0.1" "$port" < /dev/null if [[ $? = "0" ]]; then if [[ $port = $port_django ]]; then error "Django application appears to already be running on http://127.0.0.1:8000" elif [[ $port = $port_postgresql ]]; then error "PostgreSQL appears to already be running on port $port." fi exit 1 fi done docker_rebuild docker-compose run --rm misago ./dev init_in_docker } # Initialization step that has to occur inside docker init_in_docker() { require_docker wait_for_db # initialize django project python misago/bin/misago-start-devproject.py # move items of interest up one level mv devproject/devproject devproject_tmp mv devproject/avatargallery ./avatargallery mv devproject/media ./media mv devproject/userdata ./userdata mv devproject/manage.py ./manage.py rm -rf devproject mv devproject_tmp devproject # migrate the DB python manage.py migrate # create superuser Admin with password "password" python manage.py createsuperuser --username $username --email admin@example.com --password $password echo echo "================================================================================" echo echo "You can now start the development server using:" echo echo " docker-compose up" echo echo "Running server will be available in the browser under the http://127.0.0.1:8000 address." echo echo "Default superuser has been created with following credentials:" echo echo "Username: $username" echo "Password: $password" echo echo "For development project configuration see files in the \"devproject\" directory." echo } # Clear existing dev project clear() { echo -e "${RED}Warning:${NORMAL} You are going clear current development project." echo will_delete_files=false for dev_path in "${dev_paths[@]}"; do if [ -e $dev_path ]; then will_delete_files=true fi done if [[ $will_delete_files = true ]]; then echo "Following files and directories will be deleted:" for dev_path in "${dev_paths[@]}"; do if [ -e $dev_path ]; then echo " $dev_path" fi done echo fi echo "This will also stop and remove docker containers used by this project." echo echo "Enter \"y\" to confirm:" read confirmation if [[ $confirmation = "y" ]]; then for dev_path in "${dev_paths[@]}"; do if [ -e $dev_path ]; then echo "Removing $dev_path" rm -rf $dev_path fi done docker_down exit 0 else echo "Operation canceled." exit 0 fi } # Rebuild docker containers rebuild() { docker_rebuild exit 0 } # Run tests suite test() { docker-compose run --rm misago runtests.py $1 docker_stop exit 0 } # Make messages makemessages() { docker-compose run --rm --no-deps misago ./dev makemessages_in_docker $1 } # Docker part of makemessages makemessages_in_docker() { require_docker echo "Extracting messages for $1 language:" cd ./misago echo "Processing .py and .html files..." django-admin.py makemessages -l $1 -e html,txt,py > /dev/null echo "Processing .js files..." django-admin.py makemessages -l $1 -d djangojs > /dev/null } # Compile messages compilemessages() { docker-compose run --rm --no-deps misago ./dev compilemessages_in_docker } # Docker part of compile messages compilemessages_in_docker() { require_docker cd ./misago django-admin.py compilemessages } # Command dispatcher if [[ $1 ]]; then if [[ $1 = "init" ]]; then init elif [[ $1 = "init_in_docker" ]]; then init_in_docker elif [[ $1 = "clear" ]]; then clear elif [[ $1 = "rebuild" ]]; then rebuild elif [[ $1 = "test" ]]; then test $2 elif [[ $1 = "makemessages" ]]; then makemessages ${2:-en} elif [[ $1 = "makemessages_in_docker" ]]; then makemessages_in_docker $2 elif [[ $1 = "compilemessages" ]]; then compilemessages elif [[ $1 = "compilemessages_in_docker" ]]; then compilemessages_in_docker else invalid_argument $1 fi else intro fi