Update Mar 2021 - This blog now uses Fossil's newer hook mechanism. The HOWTO described in this post is obsolete.
I've migrated this site to Pharo 5 from Pharo 3. One notable behind-the-scene change is that content is now deployed using Fossil, the "simple, high-reliability, distributed software configuration management system". Fossil is usually compared with DVCS such as Git and Mercurial.
This server runs the published version of this site. (Of course.) The development version is on my laptop. Now, when I wish to publish changes from my development version, say, when I have written a new blog post, I 'fossil commit', then 'fossil push', whereupon the new blog post and associated artefacts such as images are deployed into the published version on this server.
There are any number of articles on the web describing using Git hooks to automate deploying web content. In this post, I describe using Fossil to do the same. Some familiarity with Fossil is assumed.
To begin, build Fossil with TH1 hooks and Tcl integration. Deploy it both locally and on the server, by copying the single Fossil executable to appropriate directories.
Create a new repostory locally. Take note of the admin user ID and generated password. Let's assume that the admin user ID is 'laptop-user'. Be aware that Fossil has its own user IDs, passwords and roles, distinct from the underlying operating system's.
laptop% mkdir ~/repo laptop% cd ~/repo laptop% fossil init webtree.fossil project-id: 3c05c3016eeabf8e87816ee218c6a86d3c87b950 server-id: ff42bc86dba1a26b1d94b64685f7c09d02581617 admin-user: laptop-user (initial password is "1fe2ff")
Check out the repository locally:
laptop% mkdir ~/webtree laptop% cd ~/webtree laptop% fossil open ~/repo/webtree.fossil
Add new content:
laptop% cd ~/webtree laptop% echo "Hello, world, from Fossil." > helloworld.txt laptop% fossil add helloworld.txt laptop% fossil commit -m "First commit."
Upon commit, the repository, ~/repo/webtree.fossil, is updated. Note that the repository is a single file that can be copied, renamed, moved to other computers, etc. Let's scp it to our server and set up the following directory structure there. Here I use /x to keep path names short for this post.
/x/ bin/ fossil <= The Fossil executable. fossilupdate <= Shell script, described below. webtree/ <= Checked out tree of webtree.fossil. repo/ webtree.fossil <= The repository.
To populate /x/webtree:
server% cd /x/webtree server% fossil open /x/repo/webtree.fossil server% ls -a ./ ../ .fslckout helloworld.txt
The file .fslckout is Fossil's checkout database.
Create the shell script /x/bin/fossilupdate:
server% cd /x/bin server% cat > fossilupdate #!/bin/sh cd /x/webtree /x/bin/fossil update ^D server% chmod 755 fossilupdate
Run the Fossil server. Here I use port 8081.
server% cd /x/webtree server% /x/bin/fossil server --port 8081 Listening for HTTP requests on TCP port 8081
With your web browser, navigate to the Fossil server and login using the admin user ID and password you noted down earlier. Go to Admin > Settings. Disable autosync, enable tcl, enable th1-hooks, and click 'Apply Changes'. Go to Admin > Transfers > Push. Enter below command into the text box and click 'Apply Changes'.
tclInvoke exec /x/bin/fossilupdate &
This sets up the Fossil transfer hook, which will fire after your Fossil server processes a 'fossil push' request.
Back on the laptop, commit another file:
laptop% cd ~/webtree laptop% echo "Hello again." > take2.txt laptop% fossil add take2.txt laptop% fossil commit -m "Take 2." laptop% fossil push http://laptop-user@server:8081/ password for laptop-user: remember password (Y/n)? n Round-trips: 2 Artifacts sent: 2 received: 0 Push done, send: 1075 received: 1199 ip: <server>
The push from the laptop will trigger the abovementioned transfer hook configured in the server's Fossil server instance, which will update /x/webtree on the server. Viola!
It is often desirable to start the Fossil server automatically upon server startup. On my server, I use daemontools. However, for some reason daemontools' setuidgid program is unable to run 'fossil server' in the correct directory. So I use Ubuntu's start-stop-daemon instead, and this is the daemontools run file:
#!/bin/sh exec /sbin/start-stop-daemon --start \ -c cms:cms -d /x/webtree \ --exec /x/bin/fossil \ -- server --port 8081
Create a new user, say, 'cms', and set up ownership of /x:
User:Group Dir/File --------------------- root:root /x/ root:root bin/ root:root fossil root:root fossilupdate cms:cms webtree/ cms:cms repo/ cms:cms webtree.fossil root:root run <= daemontools run file
Link /x/repo into daemontools, and 'fossil server' runs as the 'cms' user in /x/webtree.
/x/webtree/.fslckout is Fossil's checkout database. If your web server serves content directly from /x/webtree, you should configure it to not serve the .fslckout file.
An alternate practice (according to those Git hook articles) is to rsync the content of /x/webtree to another directory, and it is this second directory that the web server reads from. In such a case, it is still necessary to avoid rsync'ing the .fslckout file.
As mentioned, Fossil maintains its own user IDs, passwords, and roles. In this post, I assumed that the Fossil admin user is called 'laptop-user' and used it for 'fossil push'. It is preferable to set up a separate lower privileged Fossil user and use that instead.