A basic shell for pelican
Posted on 2015-01-09 in Programmation
My blog uses Pelican a static website generator. All my articles are under version control. To generate after each modification the new html version of the pages, you must use the make regenerate. To launch the test web server, you use make serve. Finally to synchronize the content on the server, you use make rsync_upload. Each time I do this, I also push my modifications to my server and to Bitbucket in order to have a backup.
Until now, I managed all that in a standard terminal. I already had a bash function to switch to the proper directory and enable python's venv. However, I did not find that very practical. make serve and make regenerate must always stay in background, I have to push to two different repositories and synchronize with the server. So I decided to create a script to improve that.
Since I need to launch the same commands in the same folder without leaving the venv and since I want to easily interact with the background commands, I decided to create a small shell. I am very happy with it.
Some explanations on the script (available below):
- Everything is in an infinite loop to simulate a true shell. echo -ne "> " print a prompt and let the cursor on the same line.
- exec 3< <(make serve)
- <(make serve) is replaced by a path to a virtual file connected to the standard output of the command.
- Since we want the process to be in background, we launch it with exec.
- Finally, since we want to fetch the output of the command, we connect the file to a new output named 3. We then read its content with cat <&3. While the file is not closed, this command won't stop.
- Got to this thread for more details.
- Additional output: I tried to store the name of the ouputs in variables. That would have allowed me to refactor and clarify the code. However, that makes exec "${var}"< <(make serve) and cat <&"${var}" crash.
- [ -n "${serve_pid}" ] && has_died "${serve_pid}": has_died must not be surrounded by brackets (that means it must not be pass to the test command) in order for the script to work properly.
- echo ${pid}: you can only send error code with return. For everything else, you must use echo.
You will find the whole script below. You can also download it ou le see it on github if you want the latest version
1 #!/usr/bin/bash 2 3 stop_command() { 4 if [ "$1" ]; then 5 kill "$1" 6 fi 7 } 8 9 has_died() { 10 if kill -0 "$1" > /dev/null 2>&1; then 11 return 1 12 else 13 return 0 14 fi 15 } 16 17 find_pid() { 18 echo $(ps -elf | grep "$1" | grep -v '&&' | grep -v 'grep' | awk '{print $4}') 19 } 20 21 get_pid() { 22 pid=$(find_pid "$1") 23 until [ -n "${pid}" ]; do 24 pid=$(find_pid "$1") 25 done 26 echo "${pid}" 27 } 28 29 # Activate venv 30 cd ~/server/blog/ 31 source bin/activate 32 cd pelican/jujens.eu 33 34 regenerate_pid='' 35 serve_pid='' 36 # These variables cannot be used. If you try to use them, you will get an error like 3< not found. 37 #regenerate_output=3 38 #serve_output=4 39 40 while true; do 41 # Print errors for regenerate 42 if [ -n "${regenerate_pid}" ] && has_died "${regenerate_pid}"; then 43 echo -e "Regenerate has died with ouput:\n" 44 cat <&3 45 fi 46 # Print errors for serve 47 if [ -n "${serve_pid}" ] && has_died "${serve_pid}"; then 48 echo -e "Serve has died with ouput:\n" 49 cat <&4 50 fi 51 52 echo -en "(blog) > " 53 read command 54 55 case "${command}" in 56 deploy) 57 hg push > /dev/null 58 hg push bitbucket >/dev/null 59 stop_command "${serve_pid}" 60 stop_command "${regenerate_pid}" 61 serve_pid='' 62 regenerate_pid='' 63 cat <&3 > /dev/null 2>&1 64 cat <&4 > /dev/null 2>&1 65 make rsync_upload > /dev/null 66 ;; 67 push) 68 hg push > /dev/null 69 hg push bitbucket > /dev/null 70 ;; 71 st|status) 72 hg st 73 ;; 74 add) 75 echo "Enter the filename to add (. for all files)" 76 read file_name 77 hg add "${file_name}" 78 ;; 79 ci|commit) 80 echo "Please enter the commit message:" 81 read commit_msg 82 hg ci -m "${commit_msg}" 83 ;; 84 serve) 85 if [ -n "${serve_pid}" ] && ! has_died "${serve_pid}"; then 86 echo "Serve is already running." 87 else 88 exec 4< <(make serve 2>&1) 89 serve_pid=$(get_pid 'python3 -m pelican.server') 90 fi 91 ;; 92 regenerate) 93 if [ -n "${regenerate_pid}" ] && ! has_died "${regenerate_pid}"; then 94 echo "Regenerate is already running." 95 else 96 exec 3< <(make regenerate 2>&1) 97 regenerate_pid=$(get_pid 'make regenerate') 98 fi 99 ;; 100 "stop serve") 101 stop_command "${serve_pid}" > /dev/null 102 serve_pid='' 103 cat <&4 > /dev/null 104 ;; 105 "stop regenerate") 106 stop_command "${regenerate_pid}" > /dev/null 107 regenerate_pid='' 108 cat <&3 > /dev/null 109 ;; 110 stop) 111 echo "Stop requires an argument: serve or regenerate" 112 ;; 113 quit) 114 break 115 ;; 116 help) 117 echo "Available commands:" 118 echo -e "\tdeploy" 119 echo -e "\tpush" 120 echo -e "\tserve" 121 echo -e "\tregenerate" 122 echo -e "\tstop serve" 123 echo -e "\tstop regenerate" 124 echo -e "\thelp" 125 ;; 126 *) 127 if [ -n "${command}" ]; then 128 echo -e "${command} is invalid." 129 fi 130 esac 131 done 132 133 echo "Done"