<?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>chris' random ramblings &#187; Python</title>
	<atom:link href="http://atlee.ca/blog/category/technology/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://atlee.ca/blog</link>
	<description>programming, photography, media, and anything else that strikes my fancy</description>
	<lastBuildDate>Tue, 11 May 2010 15:15:46 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>A year in RelEng</title>
		<link>http://atlee.ca/blog/2010/05/11/a-year-in-releng/</link>
		<comments>http://atlee.ca/blog/2010/05/11/a-year-in-releng/#comments</comments>
		<pubDate>Tue, 11 May 2010 15:15:46 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[buildbot]]></category>
		<category><![CDATA[talos]]></category>
		<category><![CDATA[unittests]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=719</guid>
		<description><![CDATA[Something prompted me to look at the size of our codebase here in RelEng, and how much it changes over time.  This is the code that drives all the build, test and release automation for Firefox, project branches, and Try, as well as configuration management for the various build and test machines that we [...]]]></description>
			<content:encoded><![CDATA[<p>Something prompted me to look at the size of our codebase here in RelEng, and how much it changes over time.  This is the code that drives all the build, test and release automation for Firefox, project branches, and Try, as well as configuration management for the various build and test machines that we have.</p>
<p>Here are some simple stats:</p>
<p>2,193 changesets across 5 repositories&#8230;that&#8217;s about 6 changes a day on average.</p>
<p>We grew from 43,294 lines of code last year to 73,549 lines of code as of today.  That&#8217;s 70% more code today than we had last year.</p>
<p>We added 88,154 lines to our code base, and removed 51,957.  I&#8217;m not sure what this means, but it seems like a pretty high rate of change!</p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2010/05/11/a-year-in-releng/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting free diskspace in python, on Windows</title>
		<link>http://atlee.ca/blog/2010/05/10/getting-free-diskspace-in-python-on-windows/</link>
		<comments>http://atlee.ca/blog/2010/05/10/getting-free-diskspace-in-python-on-windows/#comments</comments>
		<pubDate>Tue, 11 May 2010 03:00:53 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=747</guid>
		<description><![CDATA[Amazingly, one of the most popular links on this site is the quick tip, Getting free diskspace in python.
One of the comments shows that this method doesn&#8217;t work on Windows.  Here&#8217;s a version that does:

import win32file
def freespace&#40;p&#41;:
    &#34;&#34;&#34;
    Returns the number of free bytes on the drive that [...]]]></description>
			<content:encoded><![CDATA[<p>Amazingly, one of the most popular links on this site is the quick tip, <a href="http://atlee.ca/blog/2008/02/23/getting-free-diskspace-in-python/">Getting free diskspace in python.</a></p>
<p>One of the comments shows that this method doesn&#8217;t work on Windows.  Here&#8217;s a version that does:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> win32file
<span style="color: #ff7700;font-weight:bold;">def</span> freespace<span style="color: black;">&#40;</span>p<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;
    Returns the number of free bytes on the drive that ``p`` is on
    &quot;&quot;&quot;</span>
    secsPerClus, bytesPerSec, nFreeClus, totClus = win32file.<span style="color: black;">GetDiskFreeSpace</span><span style="color: black;">&#40;</span>p<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> secsPerClus <span style="color: #66cc66;">*</span> bytesPerSec <span style="color: #66cc66;">*</span> nFreeClus</pre></div></div>

<p>The win32file module is part of the <a href="http://sourceforge.net/projects/pywin32/">pywin32</a> extension module.</p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2010/05/10/getting-free-diskspace-in-python-on-windows/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>poster 0.6.0 released</title>
		<link>http://atlee.ca/blog/2010/05/10/poster-0-6-0-released/</link>
		<comments>http://atlee.ca/blog/2010/05/10/poster-0-6-0-released/#comments</comments>
		<pubDate>Tue, 11 May 2010 02:23:36 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[package]]></category>
		<category><![CDATA[poster]]></category>
		<category><![CDATA[utilities]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=740</guid>
		<description><![CDATA[I&#8217;ve just pushed poster 0.6.0 to the cheeseshop.
Thanks again to everybody who sent in bug reports, and for letting me know how you&#8217;re using poster!  It&#8217;s really great to hear from users.
poster 0.6.0 fixes a few problems with 0.5, most notably:

Documentation updates to clarify some common use cases.
Added a poster.version attribute.  Thanks to [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just pushed poster 0.6.0 to the <a href="http://pypi.python.org/pypi/poster/0.6.0">cheeseshop</a>.</p>
<p>Thanks again to everybody who sent in bug reports, and for letting me know how you&#8217;re using poster!  It&#8217;s really great to hear from users.</p>
<p>poster 0.6.0 fixes a few problems with 0.5, most notably:</p>
<ul>
<li>Documentation updates to clarify some common use cases.</li>
<li>Added a poster.version attribute.  Thanks to <a href="http://jcalderone.livejournal.com/54911.html">JP!</a></li>
<li>Fix for unicode filenames. Thanks to Zed Shaw.</li>
<li>Handle StringIO file objects. Thanks to Christophe Combelles.</li>
</ul>
<p>poster 0.6.0 can be downloaded from the <a href="http://pypi.python.org/pypi/poster/0.6.0">cheeseshop</a>, or from <a href="http://atlee.ca/software/poster/dist/0.6.0/">my website</a>.  Documentation can be found at <a href="http://atlee.ca/software/poster/">http://atlee.ca/software/poster/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2010/05/10/poster-0-6-0-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>What do you want to know about builds?</title>
		<link>http://atlee.ca/blog/2010/05/04/what-do-you-want-to-know-about-builds/</link>
		<comments>http://atlee.ca/blog/2010/05/04/what-do-you-want-to-know-about-builds/#comments</comments>
		<pubDate>Tue, 04 May 2010 22:44:14 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[buildbot]]></category>
		<category><![CDATA[end-to-end]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[talos]]></category>
		<category><![CDATA[unittests]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=722</guid>
		<description><![CDATA[Mozilla has been quite involved in recent buildbot development, in particular, helping to make it scale across multiple machines.  More on this in another post!
Once deployed, these changes will give us the ability to give real time access to various information about our build queue: the list of jobs waiting to start, and which [...]]]></description>
			<content:encoded><![CDATA[<p>Mozilla has been quite involved in recent <a href="http://buildbot.net/trac">buildbot</a> development, in particular, helping to make it scale across multiple machines.  More on this in another post!</p>
<p>Once deployed, these changes will give us the ability to give real time access to various information about our build queue: the list of jobs waiting to start, and which jobs are in progress.  This should help other tools like <a href="http://tests.themasta.com/tinderboxpushlog/">Tinderboxpushlog</a> show more accurate information.  One limitation of the upstream work so far is that it only captures a very coarse level of detail about builds: start/end time, and result code is pretty much it.  No further detail about the build is captured, like which slave it executed on, what properties it generated (which could include useful information like the URL to the generated binaries), etc.</p>
<p>We&#8217;ve also been exporting a <a href="http://build.mozilla.org/builds/">json dump</a> of our build status for <a href="http://atlee.ca/blog/2010/03/04/byo-build-dashboard/">many months now</a>.  It&#8217;s been useful for some analysis, but it also has limitations: the data is always at least 5 minutes old by the time you look, and in-progress builds are not represented at all.</p>
<p>We&#8217;re starting to look at ways of exporting all this detail in a way that&#8217;s useful to more people.  You want to get notified when your try builds are done?  You want to look at which test suites are taking the most time?  You want to determine how our build times change over time?  You want to find out what the last all-green revision was on trunk?  We want to make this data available, so anybody can write these tools.</p>
<h2>Just how big is that firehose?</h2>
<p>I think we have one of the largest buildbot setups out there and we generate a non-trivial amount of data:</p>
<ul>
<li>6-10 buildbot master processes generating updates, on different machines in 2 or 3 data centers</li>
<li>around 130 jobs per hour composed of 4,773 individual steps total per hour.  That works out to about 1.4 updates per second that are generated</li>
</ul>
<h2>How you can help</h2>
<p>This is where you come in.</p>
<p>I can think of two main classes of interfaces we could set up: a query-type interface where you poll for information that you are interested in, and a notification system where you register a listener for certain types (or all!) events.</p>
<p>What would be the best way for us to make this data available to you?  Some kind of REST API?  A message or event brokering system?  <a href="http://code.google.com/p/pubsubhubbub/">pubsubhubbub</a>?</p>
<p>Is there some type of data or filtering that would be super helpful to you?</p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2010/05/04/what-do-you-want-to-know-about-builds/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Buildbot performance and scaling</title>
		<link>http://atlee.ca/blog/2010/03/31/buildbot-performance-and-scaling/</link>
		<comments>http://atlee.ca/blog/2010/03/31/buildbot-performance-and-scaling/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 20:47:08 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[buildbot]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=703</guid>
		<description><![CDATA[It seems like it was ages ago when I posted about profiling buildbot.
One of the hot spots identified there was the dataReceived call.  This has been sped up a little bit in recent versions of twisted, but our buildbot masters were still severely overloaded.
It turns out that the buildbot slaves make a lot of [...]]]></description>
			<content:encoded><![CDATA[<p>It seems like it was ages ago when I posted about <a href="http://atlee.ca/blog/2009/07/28/profiling-buildbot/">profiling buildbot</a>.</p>
<p>One of the hot spots identified there was the dataReceived call.  This has been sped up a little bit in recent versions of twisted, but our buildbot masters were still severely overloaded.</p>
<p>It turns out that the buildbot slaves make a <strong>lot</strong> of RPC calls when sending log data, which results in tens of thousands of dataReceived calls.  Multiply that by several dozen build slaves sending log data peaking at a combined throughput of 10 megabits/s and you&#8217;ve got an awful lot of data to handle.</p>
<p>By adding a small slave-side buffer, the number of RPC calls to send log data is drastically reduced by an order of magnitude in some tests, resulting in a much better load situation on the master.  This is good for us, because it means the masters are much more responsive, and it&#8217;s good for everybody else because it means we have fewer failures and wasted time due to the master being too busy to handle everything.  It also means we can throw more build slaves onto the masters!</p>
<p>The new code was deployed towards the end of the day on the 26th, or the end of the 12th week.</p>
<p><img src="http://atlee.ca/blog/wp-content/uploads/123f0df3.png" alt="" title="Buildbot master weekly CPU usage" width="512" height="355" class="alignnone size-full wp-image-702" /><img src="http://atlee.ca/blog/wp-content/uploads/d9c1a2ee.png" alt="" title="Buildbot master monthly CPU usage" width="511" height="352" class="alignnone size-full wp-image-701" /></p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2010/03/31/buildbot-performance-and-scaling/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>poster 0.5 released</title>
		<link>http://atlee.ca/blog/2009/10/07/poster-0-5-released/</link>
		<comments>http://atlee.ca/blog/2009/10/07/poster-0-5-released/#comments</comments>
		<pubDate>Wed, 07 Oct 2009 12:54:47 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[poster]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=555</guid>
		<description><![CDATA[I&#8217;ve just released version 0.5 of poster, the streaming http upload library for python.  It&#8217;s easy_installable or downloadable directly from the cheeseshop.
Thanks again to everybody who&#8217;s written in with bug fixes and suggestions!
]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just released version 0.5 of <a href="http://atlee.ca/software/poster/">poster</a>, the streaming http upload library for python.  It&#8217;s easy_installable or downloadable directly from the <a href="http://pypi.python.org/pypi/poster/">cheeseshop</a>.</p>
<p>Thanks again to everybody who&#8217;s written in with bug fixes and suggestions!</p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2009/10/07/poster-0-5-released/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Profiling Buildbot</title>
		<link>http://atlee.ca/blog/2009/07/28/profiling-buildbot/</link>
		<comments>http://atlee.ca/blog/2009/07/28/profiling-buildbot/#comments</comments>
		<pubDate>Tue, 28 Jul 2009 16:13:12 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[buildbot]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=450</guid>
		<description><![CDATA[Buildbot is a critical part of our build infrastructure at Mozilla.  We use it to manage builds on 5 different platforms (Linux, Mac, Windows, Maemo and Windows Mobile), and 5 different branches (mozilla-1.9.1, mozilla-central, TraceMonkey, Electrolysis, and Places).  All in all we have 80 machines doing builds across 150 different build types (not [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://buildbot.net">Buildbot</a> is a critical part of our build infrastructure at Mozilla.  We use it to manage builds on 5 different platforms (Linux, Mac, Windows, Maemo and Windows Mobile), and 5 different branches (mozilla-1.9.1, mozilla-central, TraceMonkey, Electrolysis, and Places).  All in all we have 80 machines doing builds across 150 different build types (not counting Talos; all the Talos test runs and slaves are managed by a different master).</p>
<p>And buildbot is at the center of it all.</p>
<p>The load on our machine running buildbot is normally fairly high, and occasionally spikes so that the buildbot process is unresponsive.  It normally restores itself within a few minutes, but I&#8217;d really like to know why it&#8217;s doing this!</p>
<p>Running our staging buildbot master with python&#8217;s <a href="http://docs.python.org/library/profile.html#module-cProfile">cProfile</a> module for almost two hours yields the following profile:</p>
<pre>
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
   416377 4771.188    0.011 4796.749    0.012 {select.select}
       52  526.891   10.133  651.043   12.520 /tools/buildbot/lib/python2.5/site-packages/buildbot-0.7.10p1-py2.5.egg/buildbot/status/web/waterfall.py:834(phase2)
     6518  355.370    0.055  355.370    0.055 {posix.fsync}
   232582  238.943    0.001 1112.039    0.005 /tools/twisted-8.0.1/lib/python2.5/site-packages/twisted/spread/banana.py:150(dataReceived)
 10089681  104.395    0.000  130.089    0.000 /tools/twisted-8.0.1/lib/python2.5/site-packages/twisted/spread/banana.py:36(b1282int)
36798140/36797962   83.536    0.000   83.537    0.000 {len}
 29913653   70.458    0.000   70.458    0.000 {method 'append' of 'list' objects}
      311   63.775    0.205   63.775    0.205 {bz2.compress}
 10088987   56.581    0.000  665.982    0.000 /tools/twisted-8.0.1/lib/python2.5/site-packages/twisted/spread/banana.py:141(gotItem)
4010792/1014652   56.079    0.000  176.693    0.000 /tools/twisted-8.0.1/lib/python2.5/site-packages/twisted/spread/jelly.py:639(unjelly)
2343910/512709   47.954    0.000  112.446    0.000 /tools/twisted-8.0.1/lib/python2.5/site-packages/twisted/spread/banana.py:281(_encode)
</pre>
<h1>Interpreting the results</h1>
<p><code>select</code> shows up in the profile because we&#8217;re profiling wall clock time, not cpu time.  So the more time we&#8217;re spending in <code>select</code>, the better, since that means we&#8217;re just waiting for data.  The overall run time for this profile was 7,532 seconds, so <code>select</code> is taking around 63% of our total time.  I believe the more time spent here, the better.  Time spent inside <code>select</code> is idle time.</p>
<p>We already knew that the buildbot waterfall was slow (the second line in profile).</p>
<p><code>fsync</code> isn&#8217;t too surprising either.  buildbot calls <code>fsync</code> after writing log files to disk.  We&#8217;ve considered removing this call, and this profile lends support to our original guess.</p>
<p>The next entries really surprised me, twisted&#8217;s <code>dataReceived</code> and a decoding function, <code>b1282int</code>.  These are called when processing data received from the slaves.  If I&#8217;m reading this correctly, this means that <code>dataReceived</code> and children account for around 40% of our total time after you remove the time spent in <code>select</code>.  <code>1112 / (7532-4796) = 40%</code>.</p>
<p>These results are from our staging buildbot master, which doesn&#8217;t have anywhere near the same load as the production buildbot master.  I would expect that the time spent waiting in <code>select</code> would go down on the production master (there&#8217;s more data being received, more often), and that time spent in <code>fsync</code> and <code>dataReceived</code> would go up.</p>
<h1>What to do about it?</h1>
<p>A few ideas&#8230;.</p>
<ul>
<li>Use <a href="http://psyco.sourceforge.net/">psyco</a> to get some JIT goodness applied to some of the slower python functions.</li>
<li>Remove the <code>fsync</code> call after saving logs.</li>
<li>Use the cpu-time to profile rather than wallclock time.  This will give a different perspective on the performance of buildbot, which should give better information about where we&#8217;re spending time processing data.</li>
<li>Implement slow pieces in C (or cython).  Twisted&#8217;s Banana library looks do-able in C, and also is high up in the profile.</li>
<li>Send less data from the slaves.  We&#8217;re currently logging all stdout/stderr produced by the slaves.  All of this data is processed by the master process and then saved to disk.</li>
<li>Rearchitect buildbot to handle this kind of load.</li>
<li>Have more than one buildbot master, each one handling fewer slaves.  We&#8217;re actively looking into this approach, since it also allows us to have some redundancy for this critical piece of our infrastructure.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2009/07/28/profiling-buildbot/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>poster 0.4 released</title>
		<link>http://atlee.ca/blog/2009/04/05/poster-04-released/</link>
		<comments>http://atlee.ca/blog/2009/04/05/poster-04-released/#comments</comments>
		<pubDate>Sun, 05 Apr 2009 19:23:53 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[My Software]]></category>
		<category><![CDATA[opensource]]></category>
		<category><![CDATA[poster]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=365</guid>
		<description><![CDATA[I&#8217;m happy to announce the release of poster version 0.4.
This is a bug fix release, which fixes problems when trying to use poster over a secure connection (with https).
I&#8217;ve also reworked some of the code so that it can hopefully work with python 2.4.  It passes all the unit tests that I have under [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m happy to announce the release of <a href="http://atlee.ca/software/poster">poster</a> version 0.4.</p>
<p>This is a bug fix release, which fixes problems when trying to use poster over a secure connection (with https).</p>
<p>I&#8217;ve also reworked some of the code so that it can hopefully work with python 2.4.  It passes all the unit tests that I have under python 2.4 now, but since I don&#8217;t normally use python 2.4, I&#8217;d be interested to hear other people&#8217;s experience using it.</p>
<p>One of the things that I love about working on poster, and about open source software in general, is hearing from users all over the world who have found it helpful in some way.  It&#8217;s always encouraging to hear about how poster is being used, so thank you to all who have e-mailed me!</p>
<p>poster can be downloaded from my <a href="http://atlee.ca/software/poster/dist/0.4/">website</a>, or from the <a href="http://pypi.python.org/pypi/poster/0.4">cheeseshop</a>. </p>
<p>As always, bug reports, comments, and questions are always welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2009/04/05/poster-04-released/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Exporting MQ patches</title>
		<link>http://atlee.ca/blog/2009/03/23/exporting-mq-patches/</link>
		<comments>http://atlee.ca/blog/2009/03/23/exporting-mq-patches/#comments</comments>
		<pubDate>Mon, 23 Mar 2009 17:30:52 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[hg]]></category>
		<category><![CDATA[mercurial]]></category>
		<category><![CDATA[mq]]></category>
		<category><![CDATA[patch]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=328</guid>
		<description><![CDATA[I&#8217;ve been trying to use Mercurial Queues to manage my work on different tasks in several repositories.  I try to name all my patches with the name of the bug it&#8217;s related to; so for my recent work on getting Talos not skipping builds, I would call my patch &#8216;bug468731&#8242;.
I noticed that I was [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been trying to use <a href="http://hgbook.red-bean.com/hgbookch12.html#x16-26700012">Mercurial Queues</a> to manage my work on different tasks in several repositories.  I try to name all my patches with the name of the bug it&#8217;s related to; so for my recent work on getting Talos not skipping builds, I would call my patch &#8216;bug468731&#8242;.</p>
<p>I noticed that I was running this series of steps a lot:<br />
<code>cd ~/mozilla/buildbot-configs<br />
hg qdiff > ~/patches/bug468731-buildbot-configs.patch<br />
cd ~/mozilla/buildbotcustom<br />
hg qdiff > ~/patches/bug468731-buildbotcustom.patch<br />
</code><br />
&#8230;and then uploading the resulting patch files as attachments to the bug.  There&#8217;s a lot of repetition and extra mental work in those steps:</p>
<ul>
<li>I have to type the bug number manually <em>twice</em>.  This is annoying, and error-prone.  I&#8217;ve made a typo on more than one occasion and then wasted a few minutes trying to track down where the file went.</li>
<li>I have to type the correct repository name for each patch.  Again, I&#8217;ve managed to screw this up in the past.  Often I have several terminals open, one for each repository, and I can get mixed up as to which repository I&#8217;ve currently got active.</li>
<li>mercurial already knows the bug number, since I&#8217;ve used it in the name of my patch.</li>
<li>mercurial already knows which repository I&#8217;m in.</li>
</ul>
<p>I wrote the mercurial extension below to help with this.  It will take the current patch name, and the basename of the current repository, and save a patch in ~/patches called [patch_name]-[repo_name].patch.  It will also compare the current patch to any previous ones in the patches directory, and save a new file if the patches are different, or tell you that you&#8217;ve already saved this patch.</p>
<p>To enable this extension, save the code below somewhere like ~/.hgext/mkpatch.py, and then add &#8220;mkpatch = ~/.hgext/mkpatch.py&#8221; to your .hgrc&#8217;s extensions section.  Then you can run &#8216;hg mkpatch&#8217; to automatically create a patch for you in your ~/patches directory!</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>, hashlib
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> mercurial <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">commands</span>, util
<span style="color: #ff7700;font-weight:bold;">from</span> hgext <span style="color: #ff7700;font-weight:bold;">import</span> mq
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> mkpatch<span style="color: black;">&#40;</span>ui, repo, <span style="color: #66cc66;">*</span>pats, <span style="color: #66cc66;">**</span>opts<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Saves the current patch to a file called &lt;patch_name&gt;-&lt;repo_name&gt;.patch
    in your patch directory (defaults to ~/patches)
    &quot;&quot;&quot;</span>
    repo_name = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">basename</span><span style="color: black;">&#40;</span>ui.<span style="color: black;">config</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'paths'</span>, <span style="color: #483d8b;">'default'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> opts.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'patchdir'</span><span style="color: black;">&#41;</span>:
        patch_dir = opts.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'patchdir'</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">del</span> opts<span style="color: black;">&#91;</span><span style="color: #483d8b;">'patchdir'</span><span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        patch_dir = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">expanduser</span><span style="color: black;">&#40;</span>ui.<span style="color: black;">config</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'mkpatch'</span>, <span style="color: #483d8b;">'patchdir'</span>, <span style="color: #483d8b;">&quot;~/patches&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    ui.<span style="color: black;">pushbuffer</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    mq.<span style="color: black;">top</span><span style="color: black;">&#40;</span>ui, repo<span style="color: black;">&#41;</span>
    patch_name = ui.<span style="color: black;">popbuffer</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">exists</span><span style="color: black;">&#40;</span>patch_dir<span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">os</span>.<span style="color: black;">makedirs</span><span style="color: black;">&#40;</span>patch_dir<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">elif</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">isdir</span><span style="color: black;">&#40;</span>patch_dir<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">raise</span> util.<span style="color: black;">Abort</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;%s is not a directory&quot;</span> <span style="color: #66cc66;">%</span> patch_dir<span style="color: black;">&#41;</span>
&nbsp;
    ui.<span style="color: black;">pushbuffer</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    mq.<span style="color: black;">diff</span><span style="color: black;">&#40;</span>ui, repo, <span style="color: #66cc66;">*</span>pats, <span style="color: #66cc66;">**</span>opts<span style="color: black;">&#41;</span>
    patch_data = ui.<span style="color: black;">popbuffer</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    patch_hash = hashlib.<span style="color: #dc143c;">new</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'sha1'</span>, patch_data<span style="color: black;">&#41;</span>.<span style="color: black;">digest</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    full_name = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>patch_dir, <span style="color: #483d8b;">&quot;%s-%s.patch&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>patch_name, repo_name<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    i = <span style="color: #ff4500;">0</span>
    <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">exists</span><span style="color: black;">&#40;</span>full_name<span style="color: black;">&#41;</span>:
        file_hash = hashlib.<span style="color: #dc143c;">new</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'sha1'</span>, <span style="color: #008000;">open</span><span style="color: black;">&#40;</span>full_name<span style="color: black;">&#41;</span>.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>.<span style="color: black;">digest</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> file_hash == patch_hash:
            ui.<span style="color: black;">status</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Patch is identical to &quot;</span>, full_name, <span style="color: #483d8b;">&quot;; not saving&quot;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span>
        full_name = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>patch_dir, <span style="color: #483d8b;">&quot;%s-%s.patch.%i&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>patch_name, repo_name, i<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        i += <span style="color: #ff4500;">1</span>
&nbsp;
    <span style="color: #008000;">open</span><span style="color: black;">&#40;</span>full_name, <span style="color: #483d8b;">&quot;w&quot;</span><span style="color: black;">&#41;</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span>patch_data<span style="color: black;">&#41;</span>
    ui.<span style="color: black;">status</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Patch saved to &quot;</span>, full_name<span style="color: black;">&#41;</span>
&nbsp;
mkpatch_options = <span style="color: black;">&#91;</span>
        <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;&quot;</span>, <span style="color: #483d8b;">&quot;patchdir&quot;</span>, <span style="color: #483d8b;">''</span>, <span style="color: #483d8b;">&quot;patch directory&quot;</span><span style="color: black;">&#41;</span>,
        <span style="color: black;">&#93;</span>
cmdtable = <span style="color: black;">&#123;</span>
    <span style="color: #483d8b;">&quot;mkpatch&quot;</span>: <span style="color: black;">&#40;</span>mkpatch, mkpatch_options + mq.<span style="color: black;">cmdtable</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'^qdiff'</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>, <span style="color: #483d8b;">&quot;hg mkpatch [OPTION]... [FILE]...&quot;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#125;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2009/03/23/exporting-mq-patches/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>poster 0.2 is out</title>
		<link>http://atlee.ca/blog/2008/12/05/poster-02-is-out/</link>
		<comments>http://atlee.ca/blog/2008/12/05/poster-02-is-out/#comments</comments>
		<pubDate>Fri, 05 Dec 2008 15:36:28 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[poster]]></category>

		<guid isPermaLink="false">http://atlee.ca/blog/?p=234</guid>
		<description><![CDATA[I&#8217;ve fixed a few bugs with poster, and released the next version, 0.2.  It&#8217;s available from the cheeseshop, or from my web page.
Documentation can also be found here.
]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve fixed a few bugs with <a href="http://atlee.ca/software/poster">poster</a>, and released the next version, 0.2.  It&#8217;s available from the <a href="http://pypi.python.org/pypi/poster/0.2">cheeseshop</a>, or from my <a href="http://atlee.ca/software/poster/dist/0.2/">web page</a>.</p>
<p>Documentation can also be found <a href="http://atlee.ca/software/poster">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://atlee.ca/blog/2008/12/05/poster-02-is-out/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
