Using Subversion to Automatically Publish Your Website


Recently at work my co-workers and I have been working on a fairly large and complex website (which will be top secret until early next year 🙂 ), and we have encountered one of the pitfalls associated with group web development: Overwriting each other’s code with FTP. The natural solution was to use Subversion to manage our source code. We created our repository, checked out our local copies, and regularly updated and committed our code. While this greatly reduced the frequency and severity of our FTP mishaps, it did not eliminate them entirely. As tension began to mount (exaggerated greatly for literary value), we decided to seek a better solution… something that would allow for our development server to automatically reflect the contents of our source repository. We eventually settled on the use of a post-commit hook, which for those of you who are new to subversion is simply a script (which can be written in any language your server understands) which is executed every time anyone commits to the repository. Unfortunately for us our Subversion Repository was hosted on a third party server, and we did not have access to the server to write the hook. This meant that we were going to need to create a new repository on a server we could access. We chose to use the Web Server we host our site on, just because it reduces the overall complexity of our setup considerably. The following steps were implemented on an Ubuntu 11.04×64 server, but the steps should be nearly identical (with the exception of possibly the package management) on any modern Linux server.

Using Subversion to Automatically Publish Your Website

Install Subversion and Subversion Apache Support

sudo apt-get install subversion libapache2-svn

Create the SVN Directories

You can place your SVN Root anywhere you would like on the filesystem, but I chose to place mine in /svn, feel free to edit these commands to reflect your desired location. Also, in my example I change the ownership of the svn directory to the user/group www-data. If you are using a different Linux distribution you may need to check to see which user Apache runs as by default, and adjust the commands accordingly.

sudo mkdir /svn
sudo chown www-data:www-data /svn

Creating Your Repository and Configuring Apache to Serve It

We need to configure Apache to know the location of our repository (which I realize we haven’t created yet), so point your favorite text editor (I’m a Nano guy) at /etc/apache2/mods-available/dav_svn.conf:

sudo nano /etc/apache2/mods-available/dav_svn.conf

By default almost everything in the file is commented out. While it is possible to set up your repository to allow anonymous reading (and is in fact the default option), I opted to require authentication for every action on this repository since this source code will most likely end up containing database user credentials. Since an example of setting up anonymous reading is in the configuration file, I will allow you to un-comment it if you would like to use it. Here is an example of the config file I am using:

<Location /svn/repository>
  # Uncomment this to enable the repository
  DAV svn
  # Set this to the path to your repository
  SVNPath /svn/repository

  # Authorization Data
  AuthType Basic
  AuthName "Subversion Repository"
  AuthUserFile /etc/apache2/dav_svn.passwd
  Require valid-user
</Location>

There are a few things to note about the above file. The first is the tag, which needs to point to the location we plan to create the repository in. Also note that SVNPath should point to the same location. The next section contains data about how to authorize users. I used basic .htaccess style authentication, with an auth file located at /etc/apache2/dav_svn.passwd. The last line before the closing tag states that only users with a valid username and password are able to access the repository.

Now that we have Apache pointed at the repository, let’s create it! In order to prevent permissions issues, we need to become the www-data user:

sudo su www-data

when asked for a password, enter your own password. Now that we are the correct user, let’s create the repository at the location we specified above.

svnadmin create /svn/repository
exit

Now that the repository exists and Apache is configured to see it, we need to restart Apache to refresh the configuration:

sudo /etc/init.d/apache2 restart

After a moment, try to point your browser to http://%5Byourdomain%5D.com/svn/repository. If everything is configured correctly you should see a password box pop up. Of course, there are no users authenticated for the repository, so at this point you can’t get in.

Creating Your SVN User Accounts

Now that the repository is set up, we need to have authenticated users to commit to and update from the repository. When creating users, the command to create the first user is slightly different from the command to create all other users. For the first user do:

sudo htpasswd -cm /etc/apache2/dav_svn.passwd username

and for the rest do:

sudo htpasswd -m /etc/apache2/dav_svn.passwd username

After creating a user for yourself, go back to http://%5Byourdomain%5D.com/svn/repository and enter your username and password. If all goes well, you should see a screen indicating that your repository is at revision 0.

Setting Up Your Website to Retrieve Data from the Repository

There are several way to do this next step, and several things to consider before choosing a path. If your website already exists, you may want to set up a new virtual host on your server to hold the new copy until you are satisfied with the performance of the repository, or if you have an up to date local copy you may feel free to simply delete your old directory on the server (as we will be remaking it in a moment). Another thing to consider will be subversion configuration directories inside your website. If your server is configured like mine, it denies access to .svn directories, and an svn checkout command should be an easy way to accomplish our task. Otherwise, you may want to consider using an svn export command instead. Since my server is configured to be safe with .svn directories, I decided to go with the checkout command. Since my website is located at /var/www/mysite, the commands to do a fresh svn checkout is:

sudo rm -rf /var/www/mysite
cd /var/www
sudo svn checkout file:///svn/repository mysite --username yourusername --password yourpassword

You should now have a basically empty directory, which has the distinct advantage of being able to be quickly updated to contain the contents of the repository.

Updating Your Website After SVN Commit

Now that the repository is set up and our website is pointing to a working copy, we can set up our post-commit hook to update the website every time a commit is made. Due to the somewhat complex nature of Linux permissions, we will be performing three main steps to accomplish this goal: Creating a script to update the working copy in our webroot, giving the Apache user (in my case www-data) the ability to run that script as root without a password, and then creating our hook to call that script as root.
First we create the script (Note: this command will open Nano to a blank file for you to edit and as soon as you save the file it will also make that file executable):

sudo nano /usr/local/bin/svn-post-commit-update-mysite && sudo chmod +x /usr/local/bin/svn-post-commit-update-mysite

And inside place:

#!/bin/bash
cd /var/www/mysite && sudo svn update

This code will simply navigate to the working copy we checked out in the last step, and run svn update. This should update the contents of that folder to reflect the contents of the repository.

Next we will give the Apache user the ability to run this script as root without a password by editing /etc/sudoers

sudo nano /etc/sudoers

and adding the following line:

www-data    ALL=(root) NOPASSWD: /usr/local/bin/svn-post-commit-update-mysite

Next we will create and edit the post-commit hook for the repository:

sudo nano /svn/repository/hooks/post-commit && sudo chmod +x /svn/repository/hooks/post-commit

And inside place:

#!/bin/bash
sudo /usr/local/bin/svn-post-commit-update-mysite 1>&2

Testing Your Setup

Now that everything is theoretically set up, all we have left to do is test. The best way to do this would be to do an svn checkout on your local machine, copy the local backup of your website into the folder you performed your checkout into, and then attempt to run a commit on your working copy. If all goes well, you should be able to point your web browser at your Website and see what you just committed.

Ubuntu: Automatically Disable Touchpad when External Mouse Connected


Introduction:

If you’re like me, you hate using your touchpad when you could be using an external mouse. If you’re like me you also have a habit of disabling your touchpad when using a mouse, and forgetting to re-enable it until after you unplug your mouse. If you’re like me, this tutorial is exactly what you need.

What you need to get started:

You will need to make sure that you have xinput and halevt installed. You almost certainly already have xinput, but the following command will make sure you have what you need:

sudo aptitude install xinput halevt

I also recommend that you create a folder for scripts (if you haven’t already), and add it to your $PATH. I created a “bin” folder in my home directory for this. Create the folder with:

mkdir ~/bin

and add it to your path by issuing the following commands:

echo "PATH=\$PATH:~/bin" >> ~/.bashrc
echo "export PATH" >> ~/.bashrc

Configure the script:

First we need to create and configure the script which will actually toggle the touchpad:

cd ~/bin
touch toggleTouchpad
gedit toggleTouchpad

The script should now be open in gedit (feel free to replace gedit with your favorite text editor). Paste the following into the script:

# toggleTouchpad by Brendon Dugan
# Toggles a touchpad on or off depending on it's current state or CLI argument
#
# To configure, run the command 'xinput list' in terminal and identify your touch pad.
# Using the output of the above command, change the touchpadString variable to a substring
# of your touchpad's description that is unique to that device.
#
# To run, simply type 'toggleTouchpad' to toggle your touchpad on or off, or
# 'toggleTouchpad on' to explicitly turn your touchpad on, or
# 'toggleTouchpad off' to explicitly turn it off.
#
# Enjoy!

# A function for logging
safemk () {
if [ ! -d $1 ];
  then mkdir $1;
  chmod +rw $1;
fi
}
logdir=/home/$USER/.toggleTouchpad
touchpadString="TouchPad"
touchpadID=$(xinput list | grep "$touchpadString" | awk -F " " '{print $6}' | awk -F "=" '{print $2}')
touchpadEnabled=$(xinput list-props $touchpadID | grep "Device Enabled" | awk -F ":" '{print $2}')
sleeptime=1

# Create the logging directory
safemk $logdir
touch $logdir/errorLog.txt

# Check for arguments on the command line
if test $# -eq 1
then
	# Change the argument to lowercase
	arg1=$(echo $1 | tr [:upper:] [:lower:])
	cliArg=1
else
	# There is no argument.
	cliArg=0
fi

if [ $cliArg -eq 1 ]
then
	# If there's an argument, check to see whether it is on, off, or junk
	if [ $arg1 = 'on' ]
	then
		# The argument was 'on', so turn the touchpad on
		xinput --set-prop $touchpadID "Device Enabled" 1
		if [ $(xinput list-props $touchpadID | grep "Device Enabled" | awk -F ":" '{print $2}') -eq 0 ]
		then
			echo "Something went wrong\n" >> $logdir/errorLog.txt
		fi
	elif [ $arg1 = 'off' ]
	then
		# Sleep for a short time to fix a bug that re-enabled the touchpad immediately after disabling it
		sleep $sleeptime
		# The argument was 'off', so turn the touchpad off
		xinput --set-prop $touchpadID "Device Enabled" 0
		if [ $(xinput list-props $touchpadID | grep "Device Enabled" | awk -F ":" '{print $2}') -eq 1 ]
		then
			echo "Something went wrong, perhaps \$sleeptime needs to be greater than $sleeptime ?\n" >> $logdir/errorLog.txt
		fi
	else
		# The argument was junk, so log the error and go on
		echo "Invalid argument \""$arg1"\" was supplied\n" >> $logdir/errorLog.txt
	fi
else
	# There was no argument, so just toggle the touchpad to the opposite
	# of the state it has now.
	if [ $touchpadEnabled -eq 1 ]
	then
		xinput --set-prop $touchpadID "Device Enabled" 0
	else
		xinput --set-prop $touchpadID "Device Enabled" 1
	fi
fi

Now make the script executable by running:

 chmod +x ~/bin/toggleTouchpad

Ok, we’re almost configured. We need to make sure that your touchpad will be affected by the script. Run the following command to get a list of all current input devices:

xinput -list

It should have an output something like this:

brendon@brendon-lappy-linux:~$ xinput -list
⎡ Virtual core pointer                    	id=2	[master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer              	id=4	[slave  pointer  (2)]
⎜   ↳ Logitech Logitech BT Mini-Receiver      	id=15	[slave  pointer  (2)]
⎜   ↳ SynPS/2 Synaptics TouchPad              	id=12	[slave  pointer  (2)]
⎣ Virtual core keyboard                   	id=3	[master keyboard (2)]
    ↳ Virtual core XTEST keyboard             	id=5	[slave  keyboard (3)]
    ↳ Power Button                            	id=6	[slave  keyboard (3)]
    ↳ Video Bus                               	id=7	[slave  keyboard (3)]
    ↳ Power Button                            	id=8	[slave  keyboard (3)]
    ↳ Sleep Button                            	id=9	[slave  keyboard (3)]
    ↳ Laptop_Integrated_Webcam_2M             	id=10	[slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard            	id=11	[slave  keyboard (3)]
    ↳ Dell WMI hotkeys                        	id=13	[slave  keyboard (3)]
    ↳ Logitech Logitech BT Mini-Receiver      	id=14	[slave  keyboard (3)]
brendon@brendon-lappy-linux:~$

If your touchpad has the word “TouchPad” (case sensitive) in it, the script is ready to go. If it doesn’t, edit the variable “touchpadString” in the script to match your touchpad… but remember everything is case sensitive. For now, your script is configured. Next step is testing.

Test the script:

Make sure your touchpad is working, and then open a new terminal window. We are going to do four tests. Before and after each test, try your touchpad.

Test 1:

toggleTouchpad

Did your touchpad stop working? Good!

Test 2:

toggleTouchpad

Did your touchpad start working again? Good!

Test 3:

toggleTouchpad off

Wait at least one second…
Did your touchpad stop working? Good!

Test 4:

toggleTouchpad on

Wait at least one second…
Did your touchpad start working again? Good!

Making the magic happen automatically:

We’re almost there! Now we need to set the script to run automatically when your mouse is plugged in. Making sure your mouse is unplugged, run the following command:

halevt -i >>~/connectedDevices.txt

While the command is running, plug in your mouse, and then unplug it. Now press Ctrl +c to kill the process. Open ~/connectedDevices.txt, and you should see something that looks like:

New Device: /org/freedesktop/Hal/devices/usb_device_46d_b02_noserial
New Device: /org/freedesktop/Hal/devices/usb_device_46d_b02_noserial_if0
New Device: /org/freedesktop/Hal/devices/usb_device_46d_c70e_00076142E023
New Device: /org/freedesktop/Hal/devices/usb_device_46d_c70e_00076142E023_if0
New Device: /org/freedesktop/Hal/devices/usb_device_46d_c70e_00076142E023_if0_logicaldev_input
New Device: /org/freedesktop/Hal/devices/usb_device_46d_c70a_00076142E023
New Device: /org/freedesktop/Hal/devices/usb_device_46d_c70a_00076142E023_if0
New Device: /org/freedesktop/Hal/devices/usb_device_46d_c70a_00076142E023_if0_logicaldev_input
Device removed: /org/freedesktop/Hal/devices/usb_device_46d_c70e_00076142E023_if0_logicaldev_input
Device removed: /org/freedesktop/Hal/devices/usb_device_46d_c70e_00076142E023_if0
Device removed: /org/freedesktop/Hal/devices/usb_device_46d_c70e_00076142E023
Device removed: /org/freedesktop/Hal/devices/usb_device_46d_c70a_00076142E023_if0_logicaldev_input
Device removed: /org/freedesktop/Hal/devices/usb_device_46d_b02_noserial_if0
Device removed: /org/freedesktop/Hal/devices/usb_device_46d_c70a_00076142E023_if0
Device removed: /org/freedesktop/Hal/devices/usb_device_46d_c70a_00076142E023
Device removed: /org/freedesktop/Hal/devices/usb_device_46d_b02_noserial

All of those devices are your mouse. Since each of those events will trigger every time you plug in your mouse, we only need to handle one of them. Pick one that ends in seemingly random numbers, and copy and paste everything after the “:” into a text file. We will be using it in a moment. Now, let’s create our halevt config file:

touch ~/.halevt.xml && gedit ~/.halevt.xml

Paste the following into the file:

<?xml version="1.0" encoding="UTF-8"?>
<halevt:Configuration version="0.1" xmlns:halevt="http://www.environnement.ens.fr/perso/dumas/halevt.html">
	<halevt:Device match="hal.info.udi = /org/freedesktop/Hal/devices/usb_device_46d_c70e_00076142E023">
		<halevt:Insertion exec="toggleTouchpad off"/>
		<halevt:Removal exec="toggleTouchpad on"/>
	</halevt:Device>
</halevt:Configuration>

We are almost done! Remember the bit I had you paste into another file?? We are going to use that to identify your device. In the config file, change the line that says:

<halevt:Device match="hal.info.udi = /org/freedesktop/Hal/devices/usb_device_46d_c70e_00076142E023">

to say :

<halevt:Device match="hal.info.udi = /org/freedesktop/Hal/devices/the_rest_of_what_you_copied_into_the_file">

Theoretically, we’re done!

Test the Magic:

From terminal run:

sudo killall halevt
halevt -c ~/.halevt.xml

Now, connect your mouse. If all is going well, about ~1.5 seconds after you plug in your mouse your touchpad should stop working. Now, disconnect your mouse. Your touchpad should start working again.

Making it permanent:

If all went well in the tests, you will want to make this happen automatically forever. Go to “System->Preferences->Startup Applications”, and add a new startup program. Name it something you will remember, and for the command put “halevt -c ~/.halevt.xml”. You’re done!!

Special Thanks:

While writing this script I received a great deal of help from the user Arndt at Ubuntuforums, so you should go leave him lots of love and thanks.

Quickly Toggle Your Touchpad in Linux


For me it is often frustrating trying to use my laptop’s touchpad to do anything that requires even the slightest bit of accuracy, so I use an external mouse whenever possible. Unfortunately, the placement of the touchpad means that I will invariably end up touching it with my palms while I type. Today I finally had enough and decided to take matters into my own hands. The following script will allow you to either toggle your touchpad based upon it’s current setting, or to explicitly turn your touchpad on or off (perhaps as an event to be fired when you plug in or unplug an external mouse). Without further ado:

# toggleTouchpad by Brendon Dugan
# Toggles a touchpad on or off depending on it's current state or CLI argument
#
# To configure, run the command 'xinput list' in terminal and identify your touch pad.
# Using the output of the above command, change the touchpadString variable to a substring
# of your touchpad's description that is unique to that device.
#
# To run, simply type 'toggleTouchpad' to toggle your touchpad on or off, or
# 'toggleTouchpad on' to explicitly turn your touchpad on, or
# 'toggleTouchpad off' to explicitly turn it off.
#
# Enjoy!
touchpadString="TouchPad"
touchpadID=$(xinput list | grep "$touchpadString" | awk -F " " '{print $6}' | awk -F "=" '{print $2}')
touchpadEnabled=$(xinput list-props $touchpadID | grep "Device Enabled" | awk -F ":" '{print $2}')

# Check for arguments on the command line
if test $# -eq 1
then
	# Change the argument to lowercase
	arg1=$(echo $1 | tr [:upper:] [:lower:])
	cliArg=1
else
	# There is no argument.
	cliArg=0
fi

if [ $cliArg -eq 1 ]
then
	# If there's an argument, check to see whether it is on, off, or junk
	if [ $arg1 = 'on' ]
	then
		# The argument was 'on', so turn the touchpad on
		xinput --set-prop $touchpadID "Device Enabled" 1
	elif [ $arg1 = 'off' ]
	then
		# The argument was 'off', so turn the touchpad off
		xinput --set-prop $touchpadID "Device Enabled" 0
	else
		# The argument was junk, so do nothing
		sleep 1
	fi
else
	# There was no argument, so just toggle the touchpad to the opposite
	# of the state it has now.
	if [ $touchpadEnabled -eq 1 ]
	then
		xinput --set-prop $touchpadID "Device Enabled" 0
	else
		xinput --set-prop $touchpadID "Device Enabled" 1
	fi
fi