sterlinganderson.net

-  you probably got here by mistake. seriously.
Sep 18

Automatic Web Site Deployment with SVN and Ruby

I was setting up a new test server and production server for our web sites at work. I had finally persuaded my manager that we needed to mandate the use of a SCM system for the site source. I wanted to make deploying the sites drop dead simple as well. The last thing I wanted was to force people to check changes into Subversion, then have them upload those changes to the test server, then when the changes are approved, upload them to the production server. Too much shifting, and too much opportunity for files to get out of sync. I created a couple Ruby scripts that sit on the test server and production server. On the test server the script checks out the latest revision of the test web sites. The script is run via a cron job, so very shortly after changes are checked in to the repository they are exported out to the version of the site running on the test server.

#!/usr/bin/env ruby

# The path to the directory where your site folders sit
web_root = "/path/to/document/root/"

# A hash of sites. Folder name and SVN repository name
websites = { "site_folder" => "repo_name",
  "site2_folder" => "repo2_name"}

websites.each do |site, repo|
  # First we check for a file named "revision" in the site
  # folder. If that's not there we quit. This is a just in
  # case safety measure, you have to create the revision
  # file for the script to work. Initially it can be a file
  # with just a single "0" in it (no quotes).
  if File.exist?(web_root + site + "/revision")
    local_revision = File.open(web_root + site + "/revision").gets.chomp
  else
    exit
  end
  # Get the current revision in subversion
  svn_revision = `/usr/bin/svn info http://svn.server.com/#{repo}/ | grep '^Revision' | sed -e 's/Revision: *//'`.chomp
  # The the Subversion revision is greater than the number in the revision file
  # then we need to update the site.
  if svn_revision.to_i > local_revision.to_i then
    `/usr/bin/svn export --revision #{svn_revision} --force --username USERNAME --password PASSWORD http://svn.server.com/#{repo}/trunk #{web_root}#{site}`
    # After the export make sure the update the revision number in the revision file
    `echo "#{svn_revision}" > #{web_root}#{site}/revision`
  end
end

In order to get a site on the test server we need to create a folder for it in the web_root, add the revision file to the empty folder, set up the virtual host, and finally add the information to the websites hash in the script. I have this script running every thirty minutes on the test server. Once the site script runs the site is there. It will always be up to date, and the developer does not have to touch the test server. The most important rule you need if you are going to do things this way is don't check broken code into Subversion. If you do then your test site will very shortly break as well. The production server is pretty much the same, except I have a second file called deploy_revision that tells the script exactly what revision to check out. In production we may not always want the freshest code. Other than checking the deploy_revision file, the script on the production site is pretty much the same as the script on the test server.

#!/usr/bin/env ruby

# The path to the directory where your site folders sit
web_root = "/path/to/document/root/"

# A hash of sites. Folder name and SVN repository name
websites = { "site_folder" => "repo_name",
  "site2_folder" => "repo2_name"}

websites.each do |site, repo|
  # If deploy_revision file isn't there just quit.
  if !File.exist?(web_root + site + "/deploy_revision")
    exit
  else
    deploy_revision = File.open(web_root + site + "/deploy_revision").gets.chomp
    # Check for the revision file, it's okay if it's not there, in that
    # case just set the revision to 0
    if File.exist?(web_root + site + "/revision")
      local_revision = File.open(web_root + site + "/revision").gets.chomp
    else
      local_revision = 0
    end
    # Check the SVN revision
    svn_revision = `/usr/bin/svn info http://svn.server.com/#{repo}/ | grep '^Revision' | sed -e 's/Revision: *//'`.chomp
    # if the SVN revision is less than the deployed revision quite, that's not right...
    if svn_revision.to_i  local_revision.to_i then
        `/usr/bin/svn export --revision #{deploy_revision} --force --username USERNAME --password PASSWORD http://svn.server.com/#{repo}/trunk #{web_root}#{site}`
        `echo "#{svn_revision}" > #{web_root}#{site}/revision`
      end
    end
  end
end

I don't have the production script running under a cron job just because I want to be really careful about what gets deployed. You could easily do that thought. We've only got half a dozen sites getting updated this way right now, but eventually as changes are made to sites they are being added into Subversion and rolled into this setup.

Loading mentions Retweet

0 Comments

Jun 4

Timed iSight Shots, or Narcissism on the Cheap

Since most recent Macs are shipping with built-in iSights I thought it might be fun to put together a way to snap a picture at a certain time and then send it off somewhere. Downloading the Requirements Using two great free utilities, isightcapture, and sendEmail, in combination with a little script, and launchd I'm going to show you how I got this done. To get started you will need to download isightcapture, and sendEmail.

Installing the Tools After you have downloaded both applications you need someplace to put them. I recommend /usr/local/bin/. This is a common location for programs installed by users. You don't want to put stuff where OSX puts its files. Assuming you downloaded the applications to your Downloads folder do the following in a terminal (the first line may be unnecessary if the directory already exists):

$ sudo mkdir /usr/local/bin
$ cd ~/Downloads
$ hdiutil attach isightcapture1_1.dmg
$ sudo cp /Volumes/isightcapture1_1/isightcapture /usr/local/bin/
$ hdiutil detach /Volumes/isightcapture1_1/
$ tar zxvf sendEmail-v1.55.tar.gz
$ sudo cp sendEmail-v1.55/sendEmail /usr/local/bin/

Now you have the tools installed, you need to create the script that pulls them together. Writing Your Script I use the following BASH shell script to take the picture, and them email it. The email address I am sending it to is for a Web Gallery of my .Mac account. When the email is received it is automatically added to the gallery. While I use my .Mac account accout, Flickr allows you to post pictures via email, and Blogger allows you to post to your blog via email as well. These are just a couple examples, there are many more.

#!/bin/bash

SERVER="mail server here"
USER="username"
PASS="password"
FROM="from@address.com"
TO="to@address.com"

DATE=`date "+%Y-%m-%d %H:%M:%S"`
SUBJECT="$DATE"
MESSAGE=" "
FILE1="/tmp/$DATE.jpg"
FILE2=$(echo -n $FILE1 | sed -e "s/\:/qq/g")

/usr/local/bin/isightcapture "$FILE2"

/bin/mv "$FILE2" "$FILE1"

/usr/local/bin/sendEmail \
-f $FROM \
-t $TO \
-u "$SUBJECT" \
-m "$MESSAGE" \
-a "$FILE1" \
-s $SERVER \
-xu $USER \
-xp $PASS

rm "$FILE1"

So what's going on here? Okay, the first five variables, SERVER, USER, PASS, FROM, and TO need to be set by you. SERVER is your outgoing mail server. The easiest way to get this is to look at your mail settings in Mail, or whatever you use for email. For .Mac it would be smtp.mac.com:587. USER and PASSWORD are just that, what you need to connect to the server. The FROM address should be something, I use my real email address so if for some reason the email bounces it will hopefully make it back to me and I will know it happened. TO is where you want the email to end up. You do not need to edit anything else. Save this file as isightcam.sh somewhere, /usr/local/bin/ is a good choice. You want to make sure the file is executable so from a terminal run the following:

$ sudo chmod +x /usr/local/bin/isightcam.sh

Testing Your Script Now you want to make sure it worked. Again from a terminal, run your script:

$ /usr/local/bin/isightcam.sh

You should see the camera light go on as it takes your picture, then a notification that the email was sent successfully should appear. Assuming all is well edit your script and change the line with the sendEmail command: From:

/usr/local/bin/sendEmail \

To (this just makes sendEmail not produce any output):

/usr/local/bin/sendEmail -q \

Automating the iSight Now that our script is working the way we want let's set up some automation. My choice is launchd. Its a bit more confusing than using a simple cron job, but one thing I really like about launchd is if my laptop is sleeping when the event is supposed to occur launchd will fire it off as soon as it can once my Mac wakes. The following plist file needs to be created for our agent:

Disabled

Label
net.sterlinganderson.isightcam
ProgramArguments

/usr/local/bin/isightcam.sh

StartCalendarInterval


Hour
9
Minute
0


Hour
16
Minute
0

Save this file as net.sterlinganderson.net.plist in ~/Library/LaunchAgents/. Note the following about this file.

  • The string for the command is currently set to /usr/local/bin/isightcam.sh, make sure you have that set to whatever path your isightcam script is at.
  • Look at the <array></array> tags after StartCalendarInterval. Currently it is set to run at 9:00 AM and 4:00 PM. If you want to run the script only once remove one of the <dict></dict> tag sets and also the <array></array> tag set that enclose the two <dict></dict> tag sets. When you only have one set of <dict></dict> tags you don't need them wrapped in the <array></array> tags.

To load it run the following:

$ launchctl load ~/Library/LaunchAgents/net.sterlinganderson.net.plist

Unloading:

$ launchctl unload ~/Library/LaunchAgents/net.sterlinganderson.net.plist

Finishing Up That's it. If you have any issues please feel free to comment.

Loading mentions Retweet

0 Comments

About Sterling Anderson



 

Search Blog

Get Updates

Tags