dev 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. #!/bin/bash
  2. # "dev" is an utility script speeding up different development tasks and actions.
  3. # To find out what options are available, run it without any arguments.
  4. # Text styles
  5. RED='\033[0;31m'
  6. BOLD=$(tput bold)
  7. NORMAL=$(tput sgr0)
  8. # Required ports
  9. # Some tasks test for those ports before continuing
  10. port_django=${MISAGO_DEVSERVER_PORT:-8000}
  11. port_postgresql=5432
  12. required_ports=($port_postgresql $port_django)
  13. # Default superuser
  14. username="Admin"
  15. password="password"
  16. email="admin@example.com"
  17. # Utility functions used by action commands
  18. error() {
  19. echo -e "${RED}Error:${NORMAL} $1"
  20. }
  21. require_in_docker() {
  22. if [[ ! $IN_MISAGO_DOCKER = 1 ]]; then
  23. error "This command can only be ran inside the running Misago docker container."
  24. exit 1
  25. fi
  26. }
  27. wait_for_db() {
  28. require_in_docker
  29. export PGPASSWORD=$POSTGRES_PASSWORD
  30. RETRIES=10
  31. until psql -h $POSTGRES_HOST -U $POSTGRES_USER -d $POSTGRES_DB -c "select 1" > /dev/null 2>&1 || [ $RETRIES -eq 0 ]; do
  32. echo "Waiting for PostgreSQL to start, $((RETRIES--)) remaining attempts..."
  33. sleep 2
  34. done
  35. }
  36. # Check if user has docker-compose
  37. if [[ ! $IN_MISAGO_DOCKER = 1 ]]; then
  38. if ! command -v docker >/dev/null 2>&1; then
  39. error "You need to have Docker installed to use this tool."
  40. echo
  41. echo "Docker release for your system can be downloaded for free from this page:"
  42. echo "https://www.docker.com/get-started"
  43. echo
  44. exit 1
  45. fi
  46. if ! command -v docker-compose >/dev/null 2>&1; then
  47. error "You need to have Docker Compose installed to use this tool."
  48. echo
  49. echo "Docker release for your system can be downloaded for free from this page:"
  50. echo "https://www.docker.com/get-started"
  51. echo
  52. exit 1
  53. fi
  54. fi
  55. # Commands
  56. intro() {
  57. echo "Usage: ./dev [arg] ..."
  58. echo "Arguments grouped by type:"
  59. echo
  60. echo "Development project:"
  61. echo
  62. echo " ${BOLD}init${NORMAL} initialize dev database for development."
  63. echo " ${BOLD}afterinit${NORMAL} repeat help message displayed after init command is complete."
  64. echo " ${BOLD}clear${NORMAL} clear media and userdata dirs and destroy docker containers."
  65. echo " ${BOLD}rebuild${NORMAL} rebuild docker containers."
  66. echo " ${BOLD}reset${NORMAL} run clear followed by init."
  67. echo
  68. echo " Both init and rebuild args can be followed with any number of extra args and options that should be appended to docker-compose build."
  69. echo
  70. echo "Testing:"
  71. echo
  72. echo " ${BOLD}test${NORMAL} run tests suite using pytest."
  73. echo
  74. echo "Translations:"
  75. echo
  76. echo " ${BOLD}makemessages${NORMAL} update translation files for \"en\" language."
  77. echo " ${BOLD}makemessages lang${NORMAL} update translation files for \"lang\" language."
  78. echo " ${BOLD}compilemessages${NORMAL} compile translation files to \"mo\" format."
  79. echo " ${BOLD}txpull${NORMAL} pull translations from Transifex."
  80. echo " ${BOLD}txpush${NORMAL} push new source files to Transifex."
  81. echo " ${BOLD}txsync${NORMAL} runs entire process of syncing translations with Transifex."
  82. echo
  83. echo "Shortcuts:"
  84. echo
  85. echo " ${BOLD}manage.py${NORMAL} runs \"python manage.py\" inside docker."
  86. echo " ${BOLD}bash${NORMAL} starts bash session inside running Misago container."
  87. echo " ${BOLD}run${NORMAL} runs \"docker-compose run --rm misago\"."
  88. echo " ${BOLD}psql${NORMAL} runs psql connected to development database."
  89. echo " ${BOLD}pyfmt${NORMAL} runs isort + black on python code."
  90. echo " ${BOLD}fakedata${NORMAL} populates database with testing data."
  91. echo " ${BOLD}fakebigdata${NORMAL} populates database with LARGE amount of testing data."
  92. echo
  93. }
  94. # Handle invalid argument
  95. invalid_argument() {
  96. echo -e "Invalid argument: ${RED}$1${NORMAL}"
  97. echo "Please run this script without any arguments to see the list of available arguments."
  98. exit 1
  99. }
  100. # Initialize new dev project
  101. init() {
  102. for port in "${required_ports[@]}"; do
  103. nc "127.0.0.1" "$port" < /dev/null
  104. if [[ $? = "0" ]]; then
  105. if [[ $port = $port_django ]]; then
  106. error "Other application appears to already be running on http://127.0.0.1:${port_django}"
  107. elif [[ $port = $port_postgresql ]]; then
  108. error "PostgreSQL appears to already be running on the port $port."
  109. echo
  110. echo "Misago runs its own PostgreSQL instance in the docker container and uses port $port to expose it to other programs."
  111. echo "Please stop your PostgreSQL server and try again."
  112. echo
  113. fi
  114. exit 1
  115. fi
  116. done
  117. docker-compose stop
  118. docker-compose build --pull --force-rm "${@:2}"
  119. docker-compose run --rm misago ./dev init_in_docker
  120. }
  121. # Initialization step that has to occur inside docker
  122. init_in_docker() {
  123. require_in_docker
  124. wait_for_db
  125. # migrate the database
  126. python manage.py migrate
  127. # create superuser Admin with password "password"
  128. python manage.py createsuperuser --username $username --email $email --password $password
  129. # display after init message
  130. echo
  131. echo "================================================================================"
  132. after_init_message
  133. }
  134. # After-init message
  135. after_init_message() {
  136. echo
  137. echo "You can now start the development server using:"
  138. echo
  139. echo " docker-compose up"
  140. echo
  141. echo "Running server will be available in the browser under the http://127.0.0.1:${port_django} address."
  142. echo
  143. echo "Default superuser has been created with this username and password:"
  144. echo
  145. echo "Username: $username"
  146. echo "Password: $password"
  147. echo
  148. echo "To connect to development database use following credentials:"
  149. echo
  150. echo "User: misago"
  151. echo "Password: misago"
  152. echo "Database: misago"
  153. echo "Host: postgres"
  154. echo "Port: 5432"
  155. echo
  156. echo "Note: development server must be running for connection to be possible."
  157. echo
  158. }
  159. # Clear existing dev project
  160. clear() {
  161. echo -e "${RED}Warning:${NORMAL} You are going to delete media files created during development and destroy docker containers."
  162. echo
  163. devproject_path="$(pwd)/devproject"
  164. echo "Enter \"y\" to confirm:"
  165. read confirmation
  166. if [[ $confirmation = "y" ]]; then
  167. docker-compose stop
  168. docker-compose down --remove-orphans
  169. find $devproject_path/media -mindepth 1 ! -name '.gitignore' -delete
  170. find $devproject_path/userdata -mindepth 1 ! -name '.gitignore' -delete
  171. else
  172. echo "Operation canceled."
  173. fi
  174. }
  175. # Rebuild docker containers
  176. rebuild() {
  177. docker-compose stop
  178. docker-compose build --pull --force-rm "${@:2}"
  179. }
  180. # Run tests suite
  181. test() {
  182. docker-compose run --rm misago pytest "${@:2}"
  183. }
  184. # Make messages
  185. makemessages() {
  186. docker-compose run --rm --no-deps misago ./dev makemessages_in_docker $1
  187. }
  188. # Docker part of makemessages
  189. makemessages_in_docker() {
  190. require_in_docker
  191. cd ./misago
  192. if [[ $1 ]]; then
  193. echo "Extracting messages for $1 language:"
  194. echo "Processing .py and .html files..."
  195. django-admin makemessages -l $1 --no-obsolete -e html,txt,py > /dev/null
  196. echo "Processing .js files..."
  197. django-admin makemessages -l $1 --no-obsolete -d djangojs > /dev/null
  198. else
  199. echo "Extracting messages for all languages:"
  200. django-admin makemessages --all --no-obsolete -e html,txt,py > /dev/null
  201. django-admin makemessages --all --no-obsolete -d djangojs > /dev/null
  202. fi
  203. }
  204. # Compile messages
  205. compilemessages() {
  206. docker-compose run --rm --no-deps misago ./dev compilemessages_in_docker
  207. }
  208. # Docker part of compile messages
  209. compilemessages_in_docker() {
  210. require_in_docker
  211. cd ./misago
  212. django-admin compilemessages
  213. }
  214. # Pull translation files from transifex
  215. txpull() {
  216. tx pull -a
  217. compilemessages
  218. }
  219. # Push translation sources to transifex
  220. txpush() {
  221. tx push --source
  222. }
  223. # Shortcut for starting bash session in running container
  224. run_bash() {
  225. docker exec -it misago_misago_1 bash
  226. }
  227. # Shortcut for docker-compose run --rm misago python manage.py
  228. run_managepy() {
  229. docker-compose run --rm misago python manage.py "${@:2}"
  230. }
  231. # Shortcut for docker-compose run --rm misago...
  232. docker_run() {
  233. docker-compose run --rm misago "${@:2}"
  234. }
  235. # Shortcut for psql
  236. run_psql() {
  237. docker-compose run --rm misago ./dev psql_in_docker
  238. }
  239. # Docker part of psql shortcut
  240. psql_in_docker() {
  241. wait_for_db
  242. PGPASSWORD=$POSTGRES_PASSWORD psql --username $POSTGRES_USER --host $POSTGRES_HOST $POSTGRES_DB
  243. }
  244. # Shortcut for creating small dev forum
  245. create_fake_data() {
  246. docker-compose run --rm misago python manage.py createfakecategories 7
  247. docker-compose run --rm misago python manage.py createfakecategories 12 1
  248. docker-compose run --rm misago python manage.py createfakehistory 600
  249. }
  250. # Shortcut for creating big dev forum
  251. create_fake_bigdata() {
  252. docker-compose run --rm misago python manage.py createfakecategories 48
  253. docker-compose run --rm misago python manage.py createfakecategories 24 1
  254. docker-compose run --rm misago python manage.py createfakehistory 2190 120
  255. }
  256. # Command dispatcher
  257. if [[ $1 ]]; then
  258. if [[ $1 = "init" ]]; then
  259. init $@
  260. elif [[ $1 = "init_in_docker" ]]; then
  261. init_in_docker
  262. elif [[ $1 = "afterinit" ]]; then
  263. after_init_message
  264. elif [[ $1 = "clear" ]]; then
  265. clear
  266. elif [[ $1 = "reset" ]]; then
  267. clear
  268. init $@
  269. elif [[ $1 = "rebuild" ]]; then
  270. rebuild $@
  271. elif [[ $1 = "test" ]]; then
  272. test $@
  273. elif [[ $1 = "makemessages" ]]; then
  274. makemessages $2
  275. elif [[ $1 = "makemessages_in_docker" ]]; then
  276. makemessages_in_docker $2
  277. elif [[ $1 = "compilemessages" ]]; then
  278. compilemessages
  279. elif [[ $1 = "compilemessages_in_docker" ]]; then
  280. compilemessages_in_docker
  281. elif [[ $1 = "txpull" ]]; then
  282. txpull
  283. elif [[ $1 = "txpush" ]]; then
  284. txpush
  285. elif [[ $1 = "txsync" ]]; then
  286. rm -rf ./misago/locale/en
  287. makemessages en
  288. txpush
  289. txpull
  290. compilemessages
  291. elif [[ $1 = "bash" ]]; then
  292. run_bash
  293. elif [[ $1 = "manage.py" ]]; then
  294. run_managepy $@
  295. elif [[ $1 = "run" ]]; then
  296. docker_run $@
  297. elif [[ $1 = "psql" ]]; then
  298. run_psql
  299. elif [[ $1 = "psql_in_docker" ]]; then
  300. psql_in_docker
  301. elif [[ $1 = "pyfmt" ]]; then
  302. isort -rc misago
  303. black devproject misago
  304. elif [[ $1 = "fakedata" ]]; then
  305. create_fake_data
  306. elif [[ $1 = "fakebigdata" ]]; then
  307. create_fake_bigdata
  308. else
  309. invalid_argument $1
  310. fi
  311. else
  312. intro
  313. fi