<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>The Daily Build &#187; howto</title>
	<atom:link href="http://blog.bstpierre.org/tag/howto/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.bstpierre.org</link>
	<description>Software Development, version 3.0</description>
	<lastBuildDate>Fri, 03 Feb 2012 02:59:01 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>My First Android Adventure</title>
		<link>http://blog.bstpierre.org/my-first-android-adventure</link>
		<comments>http://blog.bstpierre.org/my-first-android-adventure#comments</comments>
		<pubDate>Tue, 27 Sep 2011 02:43:37 +0000</pubDate>
		<dc:creator>Brian St. Pierre</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[sdk]]></category>

		<guid isPermaLink="false">http://blog.bstpierre.org/?p=342</guid>
		<description><![CDATA[Here are my notes about getting the Android SDK up and running using only the command line tools that come in the SDK. The following worked for me on Ubuntu 10.04 LTS as of September 2011. I find Eclipse to be an excruciating form of torture, so I&#8217;m not following the Eclipse-based instructions. Everything below [...]]]></description>
			<content:encoded><![CDATA[<p>Here are my notes about getting the Android SDK up and running using only the command line tools that come in the SDK.</p>
<p>The following worked for me on Ubuntu 10.04 LTS as of September 2011. I find Eclipse to be an excruciating form of torture, so I&#8217;m not following the Eclipse-based instructions. Everything below can be done from vi or emacs and the command line.</p>
<h3>Installation</h3>
<ol>
<li>Download the SDK from http://developer.android.com/sdk/index.html.</li>
<li>Unpack the SDK.</li>
<li>Run <code>android-sdk-linux_x86/tools/android</code> to bring up the AVD Manager. (AVD is &#8220;Android Virtual Device&#8221; &#8212; it will run in the emulator.)</li>
<li>Select &#8220;Available Packages&#8221;, and expand &#8220;Android Repository&#8221;. It will fetch a list of packages.</li>
<li>Select &#8220;Android SDK Platform-Tools, Version 7&#8243;. (You need this.)</li>
<li>Select &#8220;SDK Platform Android 2.2, API 8, revision 3&#8243;. (You need at least one platform. My development phone has Android 2.2, so that&#8217;s what I&#8217;m initially targeting. You can add more platforms later.)</li>
<li>I also selected Documentation and Samples, for convenience.</li>
<li>Install the packages you selected. Restart ADB when prompted.</li>
<li>Then create a new virtual device. In the AVD Manager, click &#8220;Virtual Devices&#8221;, then &#8220;New&#8230;&#8221;. Give your device a name, choose the platform, click Create.</li>
<li>Install the ubuntu package &#8220;ant1.8&#8243;. Don&#8217;t install &#8220;ant&#8221; &#8212; this is version 1.7, which won&#8217;t work with the android SDK.</li>
</ol>
<h3>Create a New Project</h3>
<p>I unpacked the tools under ~/projects/android.</p>
<p>From that directory, I can give this command:</p>
<pre style="padding-left: 30px;">./android-sdk-linux_x86/tools/android create project \
   -p ./hello_android -t android-8 -a HelloAndroid \
   -k "com.blakitasoftware.hello_android"</pre>
<p>This creates ~/projects/android/hello_android/ containing the new project.</p>
<h3>Build the Project</h3>
<p>Change into the hello_android directory. Run <code>ant debug</code>.</p>
<p>(Info on package signing and building in debug mode: <a href="http://developer.android.com/guide/developing/building/building-cmdline.html#DebugMode">http://developer.android.com/guide/developing/building/building-cmdline.html#DebugMode</a>.)</p>
<h3>Run the Application</h3>
<p>Since we built in debug mode, we don&#8217;t need to worry about signing &#8212; we can run it in the emulator right away.</p>
<p>First start the virtual device: run android with no arguments, find your device, click &#8220;Start&#8230;&#8221;, &#8220;Launch&#8221;.</p>
<p>Install the application by running (assuming you&#8217;re still in the hello_android directory):</p>
<pre style="padding-left: 30px;">../android-sdk-linux_x86/platform-tools/adb \
   install ./bin/HelloAndroid-debug.apk</pre>
<p>Then go to the emulator, click the Launcher. (This is the grid of little gray squares in the bottom of the screen. Yeah, it took me a few seconds to figure this out &#8212; I&#8217;ve never even used an Android phone, this really is an adventure&#8230;) Find your HelloAndroid app, click it, and you&#8217;ll see the greeting (&#8220;Hello World, HelloAndroid&#8221;).</p>
<h3>Make a Change</h3>
<p>To change that greeting, edit res/layout/main.xml.</p>
<p>Assuming you only have one emulator running, the build and install sequence given above can be abbreviated to <code>ant install</code>. This reinstalls your app with the new greeting, find your app in the launcher again and rerun it to see the change.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.bstpierre.org/my-first-android-adventure/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Use Linux to build win32 installers for Python apps</title>
		<link>http://blog.bstpierre.org/linux-win32-python-installer</link>
		<comments>http://blog.bstpierre.org/linux-win32-python-installer#comments</comments>
		<pubDate>Wed, 20 Jul 2011 15:00:36 +0000</pubDate>
		<dc:creator>Brian St. Pierre</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[howto]]></category>

		<guid isPermaLink="false">http://blog.bstpierre.org/?p=319</guid>
		<description><![CDATA[A python-based project I&#8217;m working on has a win32 user that I need to support. Until yesterday I&#8217;ve been moving to a win32 laptop in order to run python setup.py bdist_wininst so I can produce a self-installing executable. Then I discovered how trivial it is to use wine to do the job: Install wine. (sudo [...]]]></description>
			<content:encoded><![CDATA[<p>A python-based project I&#8217;m working on has a win32 user that I need to support. Until yesterday I&#8217;ve been moving to a win32 laptop in order to run <code>python setup.py bdist_wininst</code> so I can produce a self-installing executable. Then I discovered how trivial it is to use wine to do the job:</p>
<ol>
<li>Install wine. (<code>sudo aptitude install wine</code>)</li>
<li>Install python into the wine environment. (Download an msi from python.org and run <code>msiexec /i python-x.x.x.msi</code>.)</li>
<li>Install whatever prerequisite packages you need (e.g. wxPython) using <code>wine</code> or <code>msiexec</code>.</li>
<li>When you&#8217;ve got everything ready to build, just do <code>wine c:/Python27/python.exe setup.py bdist_wininst</code> and look in ./dist/ for your exe!</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://blog.bstpierre.org/linux-win32-python-installer/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Use SSH to Forward Multiple Protocols to Multiple Machines</title>
		<link>http://blog.bstpierre.org/ssh-forward-multiple-protocols-to-multiple-machines</link>
		<comments>http://blog.bstpierre.org/ssh-forward-multiple-protocols-to-multiple-machines#comments</comments>
		<pubDate>Fri, 04 Dec 2009 16:03:33 +0000</pubDate>
		<dc:creator>Brian St. Pierre</dc:creator>
				<category><![CDATA[ssh]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[tool]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://blog.bstpierre.org/?p=239</guid>
		<description><![CDATA[Let's say you have a half-dozen machines at work you want to log into. Instead of setting up a remote forwarding connection from each of those machines, you can have the connection from your main machine perform multiple forwardings instead of just one. This even works if some of the machines don't support ssh.]]></description>
			<content:encoded><![CDATA[<p><em>(This is part five in a <a href="../category/tools/ssh">series of posts on ssh</a>.)</em></p>
<p>Let&#8217;s say you have a half-dozen machines at work you want to log into. Instead of setting up a <a href="http://blog.bstpierre.org/ssh-remote-port-forwarding-tunnels">remote forwarding connection</a> from each of those machines, you can have the connection from your main machine perform multiple forwardings instead of just one. This even works if some of the machines don&#8217;t support ssh.</p>
<p>It shouldn&#8217;t surprise you at this point that you can do this with your config file. On your work machine, you might have something like:</p>
<pre>Host tunnel
  HostName cloud.example.com
  User mycloudusername
  IdentityFile ~/.ssh/id_dsa
  Port 22
  RSAAuthentication yes
  PubkeyAuthentication yes
  ExitOnForwardFailure yes
  # tunnel ssh to myworkmachine
  RemoteForward 4022 localhost:22
  # tunnel remote desktop to mywindowsbox via myworkmachine
  RemoteForward 5389 192.168.4.10:3389
  # tunnel http to mywindowsbox via myworkmachine
  RemoteForward 5080 192.168.4.10:80
  # tunnel remote desktop to otherwindowsbox via myworkmachine
  RemoteForward 6389 192.168.4.11:3389
  # tunnel ssh to workserver via myworkmachine
  RemoteForward 7022 192.168.4.2:22</pre>
<p>You can add a bunch of forwardings as shown above. Each entry will open the given port on cloud and forward it to the specified port on the specified machine. Now when you run &#8220;ssh tunnel&#8221; on your work machine, it will connect to cloud and set up the five port forwardings specified in your config file.</p>
<p>Then when logged in to cloud.example.com, you can do, for example, &#8220;ssh -p 7022 myserverlogin@localhost&#8221; to log into the machine called workserver.</p>
<p>If you mirror the remote forwardings in your home config file as local forwardings, then when you &#8220;ssh work&#8221; from home you can remote desktop to a windows machine from your home pc by doing &#8220;rdesktop -u myworkwinuser localhost:5389&#8243; and it will use the tunnel. (The connection will go from your home pc to cloud, to myworkmachine, to mywindowsbox.) The windows machine does not need to know anything about ssh.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.bstpierre.org/ssh-forward-multiple-protocols-to-multiple-machines/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Open an SSH Tunnel in Four Seconds or Less</title>
		<link>http://blog.bstpierre.org/open-an-ssh-tunnel-in-four-seconds-or-less</link>
		<comments>http://blog.bstpierre.org/open-an-ssh-tunnel-in-four-seconds-or-less#comments</comments>
		<pubDate>Thu, 03 Dec 2009 15:28:47 +0000</pubDate>
		<dc:creator>Brian St. Pierre</dc:creator>
				<category><![CDATA[ssh]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[tool]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://blog.bstpierre.org/?p=233</guid>
		<description><![CDATA[As I mentioned in a previous post on ssh configuration, your config file can specify a variety settings for each server. In fact, the Hosts you use don't even have to exist! Consider the following snippet in your ~/.ssh/config.]]></description>
			<content:encoded><![CDATA[<p><em>(This is part four in a <a href="../category/tools/ssh">series of posts on ssh</a>.)</em></p>
<p>As I mentioned in a previous post on <a href="http://blog.bstpierre.org/configure-ssh-username">ssh configuration</a>, your config file can specify a variety settings for each server.</p>
<p>In fact, the Hosts you use don&#8217;t even have to exist! (The HostName is the important part.) Consider the following snippet in your ~/.ssh/config.</p>
<pre>#
Host work
  HostName localhost
  User myworklogin
  IdentityFile ~/.ssh/id_dsa
  Port 4022
  RSAAuthentication yes
  PubkeyAuthentication yes
  LocalForward 4022 localhost:4022</pre>
<p>I&#8217;m going to assume remote forwarding is set up and the connection is open from work to cloud as described in <a href="http://blog.bstpierre.org/ssh-remote-port-forwarding-tunnels">this post on remote forwarding</a>; and you&#8217;ve got local forwarding set up from home to cloud as described in this post on <a href="http://blog.bstpierre.org/local-ssh-forwarding">local port forwarding</a>.</p>
<p>Now you can do &#8220;ssh work&#8221; from your home pc, and it will automatically log you into your work pc with the right credentials using the tunnel on cloud.example.com. And the scp example above simplifies to &#8220;scp work:/tmp/foo.txt ~/foo.txt&#8221; &#8212; you don&#8217;t have to remember the forwarded port numbers.</p>
<p>Typing &#8220;ssh work&#8221; is nine keystrokes (eight letters plus enter). If you can type 40 wpm, that&#8217;s 200 keystrokes per minute, or 3.33 keystrokes per second, which means you can open the tunnel in four seconds!</p>
<p>If you add &#8220;alias ssw=&#8217;ssh work&#8217;&#8221; to your ~/.bashrc, you&#8217;re down to four keystrokes.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.bstpierre.org/open-an-ssh-tunnel-in-four-seconds-or-less/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Use Local SSH Forwarding to Reduce the Number of Manual Hops</title>
		<link>http://blog.bstpierre.org/local-ssh-forwarding</link>
		<comments>http://blog.bstpierre.org/local-ssh-forwarding#comments</comments>
		<pubDate>Wed, 02 Dec 2009 15:12:19 +0000</pubDate>
		<dc:creator>Brian St. Pierre</dc:creator>
				<category><![CDATA[ssh]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[tool]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://blog.bstpierre.org/?p=219</guid>
		<description><![CDATA[Local port forwarding is the same as remote port forwarding but works in the opposite direction. An example is the clearest way to explain...]]></description>
			<content:encoded><![CDATA[<p><em>(This is part three in a <a href="../category/tools/ssh">series of posts on ssh</a>.)</em></p>
<p>Local port forwarding is the same as <a title="How to Use SSH Remote Port Forwarding to Set Up Secure Tunnels" href="http://blog.bstpierre.org/ssh-remote-port-forwarding-tunnels">remote port forwarding</a> but works in the opposite direction. An example is the clearest way to explain.</p>
<p>Assuming you&#8217;ve done the steps in the previous posts, then at home you can run &#8220;ssh -L 4022:localhost:4022 me@cloud.example.com&#8221;. This listens on TCP port 4022 on your home machine. Any connections there will be forwarded through the ssh connection to port 4022 on cloud&#8230; which, as we recall, gets forwarded to port 22 (ssh) at work. If you leave this connection open, you can run &#8220;ssh -p 4022 localhost&#8221; on your home machine and it will connect to work in just one hop. This means that you can use scp to copy files from home to work or vice versa. For example, &#8220;scp -P 4022 localhost:/tmp/foo.txt ~/foo.txt&#8221; will copy a file from work to home. (<em>Note: scp needs capital &#8220;-P&#8221; to give the port. I got it wrong the first time.</em>)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.bstpierre.org/local-ssh-forwarding/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How to Use SSH Remote Port Forwarding to Set Up Secure Tunnels</title>
		<link>http://blog.bstpierre.org/ssh-remote-port-forwarding-tunnels</link>
		<comments>http://blog.bstpierre.org/ssh-remote-port-forwarding-tunnels#comments</comments>
		<pubDate>Tue, 01 Dec 2009 14:35:17 +0000</pubDate>
		<dc:creator>Brian St. Pierre</dc:creator>
				<category><![CDATA[ssh]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[tool]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://blog.bstpierre.org/?p=215</guid>
		<description><![CDATA[Ssh tunneling can be a bit mind bending at first, but it's simple when you get used to it.]]></description>
			<content:encoded><![CDATA[<p><em>(This is part two in a <a href="http://blog.bstpierre.org/category/tools/ssh">series of posts on ssh</a>.)</em></p>
<p>Ssh tunneling can be a bit mind bending at first, but it&#8217;s simple when you get used to it. Assume that you&#8217;re trying to ssh between two sites that do not allow incoming ssh. Maybe your IT at work is unenlightened and doesn&#8217;t have an ssh gateway. And your ISP has braindead configuration rules that don&#8217;t allow incoming ssh or they make it difficult.</p>
<p>What you need to get around this is a server &#8220;in the cloud&#8221; that permits ssh logins. This could be a hosting server that you pay for, or even a friend with an enlightened ISP who will give you a login account.</p>
<p>On your work PC, use ssh to login to the &#8220;cloud&#8221; server. Using the &#8220;-R&#8221; argument, you tell ssh to listen on a TCP port on the cloud server. Any connection coming in to this server will be forwarded back through the ssh connection to the TCP port you specify. For example, on mymachine.work.com, &#8220;ssh -R 4022:localhost:22 me@cloud.example.com&#8221; tells ssh to listen on cloud&#8217;s port 4022. Incoming connections to that port on cloud will be forwarded to port 22 (ssh) on mymachine.</p>
<p>By default, ssh will only listen to port 4022 on cloud&#8217;s localhost interface. So to log in to work, you will first need to log into cloud, and then use &#8220;ssh -p 4022 myworklogin@localhost&#8221; to log into work.</p>
<p>We&#8217;ll work around this limitation in the next post in this series.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.bstpierre.org/ssh-remote-port-forwarding-tunnels/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to Tell SSH Who You Are</title>
		<link>http://blog.bstpierre.org/configure-ssh-username</link>
		<comments>http://blog.bstpierre.org/configure-ssh-username#comments</comments>
		<pubDate>Mon, 30 Nov 2009 15:11:10 +0000</pubDate>
		<dc:creator>Brian St. Pierre</dc:creator>
				<category><![CDATA[ssh]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[tool]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://blog.bstpierre.org/?p=222</guid>
		<description><![CDATA[Do you log in to several servers with different usernames via ssh? Save typing by telling ssh which username to use on each server.]]></description>
			<content:encoded><![CDATA[<p>Ssh has amazing capabilities that you probably aren&#8217;t using on a daily basis.</p>
<p>The capability that you probably aren&#8217;t using, and the easiest to use, is customizing your config file (in ~/.ssh/config) for the various servers you log into.</p>
<p>For example, I frequently log into about ten different servers using at least four different usernames. By default, if I type &#8220;ssh server&#8221; the client will use my login name on the client machine to try to log into the server &#8212; which is usually wrong. Instead you can <a href="http://superuser.com/questions/64996/how-to-make-ssh-log-in-as-the-right-user">tell your ssh client which username to use on each server</a>. (Thanks to <a href="http://wblinks.com/">Rich Adams</a> for the tip.)</p>
<p>You can customize a variety of settings &#8212; not just the username. For example, I specify a different identity file for a couple of servers.</p>
<p>This saves a bunch of typing and occasional confusion. (By avoiding login errrors as I try to log into a server using the wrong username and can&#8217;t figure out why my password isn&#8217;t working&#8230;)</p>
<p><em>(This is the first post in <a href="../category/tools/ssh">series of posts about how to get the most out of ssh</a>. Make sure you don&#8217;t miss the rest of the series: <a href="http://feeds2.feedburner.com/TheDailyBuild">subscribe to my feed</a> or <a href="http://twitter.com/bstpierre">follow me on twitter</a>.)</em></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.bstpierre.org/configure-ssh-username/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Python&#8217;s ctypes to Call Into C Libraries</title>
		<link>http://blog.bstpierre.org/using-pythons-ctypes-to-make-system-calls</link>
		<comments>http://blog.bstpierre.org/using-pythons-ctypes-to-make-system-calls#comments</comments>
		<pubDate>Wed, 05 Aug 2009 10:35:55 +0000</pubDate>
		<dc:creator>Brian St. Pierre</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://blog.bstpierre.org/?p=185</guid>
		<description><![CDATA[The ctypes module makes loading and calling into a dynamic library incredibly easy.]]></description>
			<content:encoded><![CDATA[<p>The ctypes module makes loading and calling into a dynamic library incredibly easy:</p>
<pre>&gt;&gt;&gt; from ctypes import CDLL
&gt;&gt;&gt; libc = CDLL('libc.so.6')
&gt;&gt;&gt; print libc.strlen('abcde')
5</pre>
<p>As with everything else in python, it gets even better when you scratch the surface. In the example above, CDLL returns an object that represents the dynamic library. You can access the functions in that library by attribute access (&#8220;libc.strlen&#8221;) or item access (&#8220;libc['strlen']&#8220;). Both access mechanisms return a callable object.</p>
<p>This callable object has an &#8220;errcheck&#8221; attribute that can be assigned a callable. We can use this for error-checking our calls into the library. Let&#8217;s write a simple version of the &#8220;kill&#8221; command that uses the kill(2) system call.</p>
<pre>import sys
from ctypes import *

# Load the library.
libc = CDLL('libc.so.6')

# Our error checking function. This will receive the
# return value of the library function, the function that
# was called, and the arguments passed to the function as a
# tuple.
def kill_errcheck(retval, func, funcargs):
    '''Check for error -- retval == -1.'''
    if retval &lt; 0:
        raise Exception('kill%s failed' % (funcargs, ))
    return True

# Get the kill function from the standard library.
kill = libc.kill

# Set the error checker for kill().
kill.errcheck = kill_errcheck

# Pass the command line argument as a pid to kill, with
# SIGSEGV (11).
pid = int(sys.argv[1])
kill(pid, 11)</pre>
<p>Save this as kill.py. Then, in your shell, try something like this:</p>
<pre># Notice that the 3401 is the pid of the process
# we're putting into the background. Yours will
# be different.
bash$ sleep 120&amp;
[1] 3401
bash$ python kill.py 3401
[1]+ Segmentation Fault         sleep 120
bash$ python kill.py 3401
Traceback (most recent call last):
  File "kill.py", line 17, in
    kill(pid, 11)
  File "kill.py", line 10, in kill_errcheck
    raise Exception('kill%s failed' % (funcargs, ))
Exception: kill(3401, 11) failed</pre>
<p>At line 4 of the output we run sleep in the background. At line 5 we learn the pid of this process. At line 6 we run our kill program, giving it the pid we just spawned, and we see the notification from bash that the process was killed (with signal 11, segmentation fault). At line 8 we run our kill program again on pid 3401, but it doesn&#8217;t exist, the kill system call returns -1, and our error checker raises an exception when it detects the system call failure.</p>
<p>But wait, there&#8217;s more&#8230; I&#8217;m working on a follow up post that combines ctypes.Structure with calls into a linux system call.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.bstpierre.org/using-pythons-ctypes-to-make-system-calls/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python Exception Handling: Cleanup and Reraise</title>
		<link>http://blog.bstpierre.org/python-exception-handling-cleanup-and-reraise</link>
		<comments>http://blog.bstpierre.org/python-exception-handling-cleanup-and-reraise#comments</comments>
		<pubDate>Thu, 16 Jul 2009 03:35:49 +0000</pubDate>
		<dc:creator>Brian St. Pierre</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://blog.bstpierre.org/python-exception-handling-cleanup-and-reraise</guid>
		<description><![CDATA[I&#8217;ve had this code around for a while and had an opportunity to drag it out the other day and dust it off. The problem: Every now and again there&#8217;s a situation where you don&#8217;t really want to catch an exception, but you do want to perform some cleanup and let the exception propagate up [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve had <a href="http://gist.github.com/148135">this code</a> around for a while and had an opportunity to drag it out the other day and dust it off. The problem: Every now and again there&#8217;s a situation where you don&#8217;t really want to catch an exception, but you do want to perform some cleanup and let the exception propagate up the stack. Sometimes there&#8217;s an extra wrinkle in that the cleanup code may itself throw an exception (that I&#8217;m simply going to assume we can ignore).</p>
<p><script src="http://gist.github.com/148135.js"></script></p>
<p>You can run the file to see the behavior. Simply provide an integer 1-5 as a command line argument and you&#8217;ll run the selected scenario and see the output. The goal in this case is for cleanup to occur and an exception to be reported as having occurred at line 10.</p>
<p>The code in reraiser1 is wrong because this behaves as if a brand new exception were thrown at line 27. That may not seem so bad, but this code is pretty simple. If this happens and the stack trace is deep, it will be almost impossible to diagnose what went wrong.</p>
<p>The code in reraiser2 shows what happens when a second exception occurs in the except block. A bare raise statement here might be an attempt to re-raise the original exception, but python&#8217;s rules about re-raising specify that the most recent exception in the scope is what is reraised. In this case, that&#8217;s the exception thrown from the cleanup function. Again, this makes troubleshooting difficult.</p>
<p>In reraiser3 I worked around the problem in reraiser2 by moving the cleanup function&#8217;s exception into a separate scope by defining a local cleanup function and calling it from within the except block. This prevents the cleanup function&#8217;s exception from polluting the scope with an irrelevant exception and we can re-raise the original exception. This results in a stack trace rooted at line 10.</p>
<p>Reraiser4 takes a different approach. Instead of moving the cleanup function&#8217;s exception into a separate scope, it captures the traceback information from the original exception and then passes it back to the raise statement so that the reported traceback is accurate.</p>
<p>The cleanest way to handle this is to use a finally block as shown in reraiser5. This situation is what &#8220;finally&#8221; is meant for: it does not trap the exception, it just gives you a chance to clean up before control moves back up the stack to the caller. The presence of finally clues readers in to the fact that you aren&#8217;t messing with the exception, and that the point of the block is to perform cleanup.</p>
<p>Kindly drop me a note if I&#8217;ve got something wrong above, or if I&#8217;m missing a technique (or a common anti-pattern!). Thanks.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.bstpierre.org/python-exception-handling-cleanup-and-reraise/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Five Days to a Django Web App: Day Four, Deployment</title>
		<link>http://blog.bstpierre.org/five-days-to-a-django-web-app-day-four-deployment</link>
		<comments>http://blog.bstpierre.org/five-days-to-a-django-web-app-day-four-deployment#comments</comments>
		<pubDate>Mon, 02 Mar 2009 16:48:20 +0000</pubDate>
		<dc:creator>Brian St. Pierre</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://blog.bstpierre.org/?p=169</guid>
		<description><![CDATA[Thanks for your patience, and for coming back for a discussion of deploying our Django web app. In case you missed any of the previous posts in this series, here they are: Day One, Get Ready (Concept and prep) Day Two, Mockups (Creating a design) Day Three, Coding (Coding tests, views, templates, and models) Pre-Deployment [...]]]></description>
			<content:encoded><![CDATA[<p>Thanks for your patience, and for coming back for a discussion of deploying our Django web app.</p>
<p>In case you missed any of the previous posts in this series, here they are:</p>
<ol>
<li><a href="/five-days-to-a-django-web-app-day-one-get-ready">Day One, Get Ready</a> (Concept and prep)</li>
<li><a href="/five-days-to-a-django-web-app-day-two-mockups">Day Two, Mockups</a> (Creating a design)</li>
<li><a href="/five-days-to-a-django-web-app-day-three-coding">Day Three, Coding</a> (Coding tests, views, templates, and models)</li>
</ol>
<h2>Pre-Deployment</h2>
<p>First, we need to make a couple of decisions:</p>
<ul>
<li>How are we going to push updates to the live site: FTP, git, svn?</li>
<li>How are we going to handle backups?</li>
</ul>
<h3>Version Control as Distribution System</h3>
<p>In my case, I&#8217;m using svn+ssh to push updates. Notice that this does not require special setup on your server &#8212; you do not need to install the svn stuff that DreamHost or your host may provide. Just do svn init to create a repository on the server (<em>outside</em> the DocumentRoot!). Then point your development pc to svn+ssh://USERNAME@host.example.com/home/USERNAME/svn/PROJECT. (Git works similarly, no support from your host required except the binaries.)</p>
<p>In the directory on the host where you&#8217;re going to store your project files, point to the same URL. (You could use the file:///&#8230;/ url, but I prefer to avoid accessing the repo directly. Superstition?)</p>
<p>Now, whenever you make a change on your development system, just &quot;svn ci&quot; and then on the host &#8220;svn up&#8221; and restart your fcgi to pick up the new code. Presto! The live site is updated with your change.</p>
<h3>Backups</h3>
<p>You must have a backup strategy: Your app will have users. Your host&#8217;s disk will burp. Your users will hate you when the disk burps and you don&#8217;t have a good backup.</p>
<p>There are probably 374 different ways of backing up your Django app. The two major things you need to capture are the database and your code. If you are storing objects (e.g. uploaded files) outside the database, you&#8217;ll need to back these up too. The option I&#8217;m using is <a href="http://code.google.com/p/django-backup/">django-backup</a>.</p>
<p>Pull the code from subversion into your project. Rename the directory to &quot;django_backup&quot;. Add django_backup to your INSTALLED_APPS. Verify it works by running <code>./manage.py backup -c</code>. Sanity check the backup by doing <code>zless backups/*.gz</code>. We&#8217;ll set up a cron job on the host to run this regularly when we deploy.</p>
<h2>Deploy</h2>
<p>I&#8217;ve previously written about <a href="/deploying-django-apps-on-dreamhost">deploying Django apps on DreamHost</a>, so I&#8217;m not going to duplicate that here. Keep in mind that you want to use the version control strategy outlined above. Read that article, deploy your app and come back here when you&#8217;re done.</p>
<h2>Post-Deployment</h2>
<h3>Backup</h3>
<p>Let&#8217;s add that cron job we previously mentioned. On the host, run <code>crontab -e</code>. If you&#8217;re on DreamHost and this if the first time you&#8217;ve used cron, it will prompt you for an email address to send output to. Then it will dump you into an editor. (Side note: &quot;joe&quot; is the default. If you want something different, like vim, be sure that EDITOR=/usr/bin/vim is set in your environment.)</p>
<p>Set up a job something similar to the following:</p>
<pre><code>
MAILTO="YOU@EXAMPLE.com"

# m h  dom mon dow   command
4 2 * * * (cd /home/PATH/TO/PROJECT; ./manage.py backup -c --email=YOU@EXAMPLE.com)
</code></pre>
<p>This will run a backup every day at 02:04 (AM). You will get two emails: one with the output from the job, and one with the compressed backup file. (When you get to the point where your database backups are too big for email, you&#8217;ll need to find another strategy.)</p>
<p>Now we&#8217;ve got another problem to solve: we&#8217;re going to accumulate a bunch of backups on the disk. Let&#8217;s get rid of the old backups. This is pretty safe, since we&#8217;re receiving backup files via email. Add a cron job like this:</p>
<pre><code>
14 2 * * * (cd /home/PATH/TO/PROJECT;
    touch --date=`date --iso --date='10 days ago'` .backup.oldest;
    find ./backups/ -mindepth 1 \! -newer .backup.oldest -execdir rm '{}' +)
</code></pre>
<p>(Formatted here for readability &mdash; you need to put that all on one line.)</p>
<p>This will remove backup files older than 10 days. You could do this more concisely with a tool like tmpwatch or tmpreaper, but neither is installed on my host and this incantation should work on pretty much any flavor and installation of linux.</p>
<p>At this point we&#8217;re deployed and the majority of the work is done. Tomorrow we&#8217;ll take a look at some maintenance issues.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.bstpierre.org/five-days-to-a-django-web-app-day-four-deployment/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

