<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4312481443349522150</id><updated>2026-07-17T13:55:05.010-04:00</updated><category term="python"/><category term="linux"/><category term="osx"/><category term="bash"/><category term="vim"/><category term="git"/><category term="vi"/><category term="x11"/><category term="ci"/><category term="code coverage"/><category term="code quality"/><category term="continuous integration"/><category term="jenkins"/><category term="mocking"/><category term="nose"/><category term="pylint"/><category term="unit testing"/><category term="alfred"/><category term="gitolite"/><category term="sed"/><category term="source control"/><category term="ubuntu"/><category term="automator"/><category term="awk"/><category term="bash monitoring web notification email"/><category term="bash python"/><category term="center"/><category term="cgi"/><category term="cli"/><category term="clone"/><category term="compile"/><category term="cxFreeze"/><category term="deadsnakes"/><category term="dependency"/><category term="development"/><category term="distribute"/><category term="encryption"/><category term="fetch"/><category term="formatting"/><category term="fuse"/><category term="gitorious"/><category term="gnu"/><category term="guid"/><category term="left justify"/><category term="mac"/><category term="markdown"/><category term="mktemp"/><category term="mock"/><category term="package"/><category term="patch"/><category term="pip"/><category term="plugin"/><category term="ppa"/><category term="preview"/><category term="pull"/><category term="py2app"/><category term="py2exe"/><category term="quicklook"/><category term="right justify"/><category term="screen"/><category term="security"/><category term="sshfs"/><category term="string"/><category term="svn"/><category term="terminal"/><category term="test"/><category term="unittest"/><category term="url"/><category term="variables"/><category term="virtualenv"/><category term="web"/><category term="zenity"/><title type='text'>Steve&#39;s Blog</title><subtitle type='html'>Technical tips</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://bhfsteve.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>29</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-2763214158433271403</id><published>2017-02-23T10:49:00.000-05:00</published><updated>2017-02-24T15:23:30.487-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="python"/><title type='text'>Python streams</title><content type='html'>I&#39;ve become really comfortable with Java 8&#39;s streams over the past couple years. &amp;nbsp;As a result, when I go back and do Python work, I get stream envy. &amp;nbsp;I looked around and found a couple options, but none of them were really what I&#39;m after... something quick and dirty that will just make my syntax a bit more readable.&lt;br /&gt;
&lt;br /&gt;
So I threw this together and find it quite handy. &amp;nbsp;I hope you find it helpful as well. &amp;nbsp;If you save this to a module and name it &#39;streams.py&#39;, you can use it like the following:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; from lazy_streams import stream&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; S = stream(range(250)) \&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; .filter(lambda x: (x%2 == 0))&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; print S.size()&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; print S.take(10).to_string()&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; print S.reverse().take(10).to_list()&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; S1 = S.map(lambda x: &quot;Item %d&quot; % x)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; print S1.first_or_else(&#39;Nothing to see&#39;)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; print stream([&#39;Patty Cake&#39;, &#39;Jim Shoe&#39;, &#39;Justin Case&#39;]) \&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; .sort(lambda x: x.split(&#39; &#39;)[1]) \&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; .to_list()&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; print stream([[1, 2], 3, [4, 5, 6], &#39;seven&#39;]) \&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; .flatten() \&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; .to_list()&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
I&#39;ve tested it on lists as big as 2.5 million items and the lazy evaluation seems to work really great!&lt;br /&gt;
&lt;br /&gt;
Here&#39;s the gist:&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/brettschneider/4b91533e3a43f6b724fd8348eaf5d2ae.js&quot;&gt;&lt;/script&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/2763214158433271403'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/2763214158433271403'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2017/02/python-streams.html' title='Python streams'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-269121105701280590</id><published>2017-02-17T16:06:00.001-05:00</published><updated>2017-02-17T16:07:56.942-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="python"/><title type='text'>Sharing a Python generator across multiple multiprocessing processes.</title><content type='html'>Sometimes I need to do some work on a seemingly endless set of data. &amp;nbsp;I often use generators to create the endless data. &amp;nbsp;Say, for example I were trying to brute-force crack a zip file&#39;s password. &amp;nbsp;I&#39;d create a generator that methodically and continually creates new passwords for the cracking to to use in attempting to unzip the file.&lt;br /&gt;
&lt;br /&gt;
Once I have my generator in place, I have a problem. &amp;nbsp;What if I want to spread this brute-force attack across all the cores in my system to speed up this slow endless effort. &amp;nbsp;One would think that multiprocessing will solve the problem.&lt;br /&gt;
&lt;br /&gt;
Well, no. &amp;nbsp;Generators aren&#39;t natively shared across processes in Python. &amp;nbsp;They&#39;re copied to each process. &amp;nbsp;This means that if you try to use the generator with multiprocessing, each process will get it&#39;s own copy of the generator and each process would get the same values from each copy.&lt;br /&gt;
&lt;br /&gt;
To solve that, I devised a quick and dirty solution: &amp;nbsp;Place the generator in it&#39;s own process and then have each worker process request the next value from it via inter-process communication using the multi-processing Pipe class.&lt;br /&gt;
&lt;br /&gt;
To that end, here&#39;s an example. &amp;nbsp;I post this here mainly to jog my memory next time I need to do this, but if you find it useful, great!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/brettschneider/ff173aad40f5eddca8fc1e56fdd66938.js&quot;&gt;&lt;/script&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/269121105701280590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/269121105701280590'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2017/02/sharing-python-generator-across.html' title='Sharing a Python generator across multiple multiprocessing processes.'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-1370924909882921599</id><published>2017-02-08T13:50:00.001-05:00</published><updated>2017-02-08T13:50:59.149-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bash"/><category scheme="http://www.blogger.com/atom/ns#" term="compile"/><category scheme="http://www.blogger.com/atom/ns#" term="cxFreeze"/><category scheme="http://www.blogger.com/atom/ns#" term="distribute"/><category scheme="http://www.blogger.com/atom/ns#" term="py2app"/><category scheme="http://www.blogger.com/atom/ns#" term="py2exe"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><title type='text'>Non-freeze, single file distribution of your python project</title><content type='html'>In my job, I often have to share/distribute Python code to others on my development team or to others in sibling development teams. &amp;nbsp;These folks are technical and I can easily rely on them to have a reasonably contemporary version of Python already installed. &amp;nbsp;Thus I don&#39;t really want to completely freeze my Python project (via cxFreeze, py2app, py2exe, etc.). &amp;nbsp;Nor do I want to send my coworkers through the &#39;create a virtualenv, pip install -r, etc.).&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I want a middle-ground. &amp;nbsp;I want to just send them a file, knowing that it contains all the required dependencies and will just run, assuming they have Python in their path.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I&#39;ve known for a while that if you zip up a directory full of Python files and so long as the root of the zip file contains a __main__.py file and you can directly run the zip file via &lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;python {filename.zip}&lt;/b&gt;&lt;/span&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
What I didn&#39;t know is that you can concatenate a text file containing the Python shebang (&#39;#!/usr/bin/env python&#39;) and a python zip file and the resulting file is runnable.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;#!/usr/bin/env python&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;PK&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^C^D^T^@^B^@^H^@&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;nLHJb±gL&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;94&amp;gt;^A^@^@&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;Ò&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^B^@^@^K^@^\^@&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;__main__.pyUT&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^@^C&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;¯,&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;9b&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;Xö,&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;9b&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;Xux&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^K^@^A^D&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;«&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;82&amp;gt;&amp;lt;90&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;~&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^D^T^@^@^@&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;u&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;92&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;ÑkÛ0&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^P&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;ÆßýWÜ²&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^G&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;ÙÐ$},&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^E&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;ÃÂ(&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;85&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;2Ú&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;90&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;ìq &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^T&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;ûâ&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;88&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;Z&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;92&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;9&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;9d&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;º&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;95&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;±ÿ}&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;&#39;;ÎJ`Â&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^O&amp;lt;96&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;ôéû~ºÓ&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;ÈY©1&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^F&amp;lt;93&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;9£4@&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^Q&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;81&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;+ü&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;8e&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;O&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^X&amp;lt;88&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;2#tCrÌ&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^N&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;0©¸&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;83&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;ÛÑw°ÌÕÂ#®Ë¾&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^A&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;aÀ&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^P&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;Å &amp;gt;«¼h@&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^P&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;;c6&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;8d&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;^Âý=&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^\&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;AB!ej&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;91&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;nbsp; &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;9e&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;g¦ñ&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;95&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;Vgé&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;87&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;ÌqÏ&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^R&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;C&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;8a&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;9&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;99&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;aq&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^O^O&amp;lt;9f&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;Cv&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^U^A&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;þXQi&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;88&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;ÛÌ®°Üx&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;90&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;µó&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;98&amp;gt;^G&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;l­&amp;nbsp;´Z&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^B&amp;lt;81&amp;gt;^E&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;·¾&amp;amp;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;^B^C&amp;lt;83&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;ÕÚ§&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #c33720; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;,g&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;^L&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;Ã=kW&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;^Y&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;$r­â Æ]HÉ&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;^U&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;Ý5AÂ[V&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;^F&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;C$y&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;80&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;¢a&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;82&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;^V^U&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;{°(Ô&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;9b&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;|Ü&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;^X&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;W}¤h&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;8f&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;aØ}¦&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;^G&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;gt;o&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;96&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;êu&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;9c&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;e?k&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;8e&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;,àbºÔ/ýëh´¶&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;^L&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;Çp&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;^A^Y&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;8b&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;LÕBt&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;85&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;w£hi¿&amp;amp;(&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;^H&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;Ûîä&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;lt;96&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;tÿ.&lt;/span&gt;&lt;span style=&quot;color: #5330e1; font-variant-ligatures: no-common-ligatures;&quot;&gt;^@&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;A&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #c33720; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;dJuëX&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I stumbled upon a tool called &lt;a href=&quot;https://github.com/pantsbuild/pex&quot; target=&quot;_blank&quot;&gt;pex&lt;/a&gt; which will automate generating these shebang/zip files. &amp;nbsp;While I found pex useful, it seems too much for my needs. &amp;nbsp;So I started cobbling together my own shebang/zip files by hand as I needed them.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Ultimately, wanted to automate this some, so I ended up creating a simple bash script (which I named &#39;compile.sh&#39;) to speed things up. &amp;nbsp;Here&#39;s that script. &amp;nbsp;Hope you find this useful.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;#!/bin/bash&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;#&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;# compile.sh&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal; min-height: 15px;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;# Creates a self-runnable, single-file deployable for your python project.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;# Your python project&#39;s main entry point must be in a file named __main__.py.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;# It will embed in the deployable every dependency you&#39;ve pip-installed in&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;# your virtualenv .env directory.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;#&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;# The deployable still requires that python is installed on the target system.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal; min-height: 15px;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;if &lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;[[&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;-d&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; .env/lib/python2.&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;/site-packages &lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;then&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #c33720; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;This script must be run from a virtualenv root.&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;exit&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;1&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #ce7924; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;fi&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal; min-height: 15px;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;if &lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;[[&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;-f&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; __main__.py &lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;then&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #c33720; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;This will only work if you have a __main__.py file.&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;exit&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;1&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #ce7924; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;fi&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal; min-height: 15px;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #ce7924; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;if &lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;[[&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;-z&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;]]&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;then&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #c33720; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;Usage: &lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;$(basename $0)&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; {output_filename}&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;exit&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;1&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #ce7924; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;fi&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal; min-height: 15px;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #d53bd3; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: #34bbc7; font-variant-ligatures: no-common-ligatures;&quot;&gt;TMPDIR&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;$(mktemp -u /tmp/python.compile.XXXXXXX)&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #34bbc7; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;CURDIR&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;pwd&lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #34bbc7; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;TARGET&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal; min-height: 15px;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;# Create payload zip with our code (remove extra junk)&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #d53bd3; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;-p&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;$TMPDIR&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;/deps&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #c33720; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;zip &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;-9&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;$TMPDIR&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;/payload.zip&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; *&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;zip &lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;-d&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;$TMPDIR&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;/payload.zip&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; compile.sh&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;zip &lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;-d&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;$TMPDIR&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;/payload.zip&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; requirements.txt&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;zip &lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;-d&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;$TMPDIR&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;/payload.zip&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;$TARGET&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; /dev/null&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal; min-height: 15px;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;# Gather the virtualenv packages and clean them up&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;cp &lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;-R&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; .env/lib/python2.&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;/site-packages/* &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;$TMPDIR&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;/deps&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #d53bd3; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;find&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;$TMPDIR&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;/deps&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;-iname&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;*.pyc&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;-delete&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #d53bd3; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;find&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;$TMPDIR&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;/deps&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;-ipath&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;*pip*&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;-delete&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #d53bd3; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;find&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;$TMPDIR&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;/deps&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;-ipath&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;*easy_install*&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;-delete&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #d53bd3; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;find&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;$TMPDIR&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;/deps&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;-ipath&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;*dist-info*&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;-delete&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal; min-height: 15px;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;# Add the virtualenv packages to the payload&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #d53bd3; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;$TMPDIR&lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;/deps&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;zip &lt;/span&gt;&lt;span style=&quot;color: #c33720; font-variant-ligatures: no-common-ligatures;&quot;&gt;-9&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;-r&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; ../payload.zip *&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #d53bd3; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;$CURDIR&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal; min-height: 15px;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;# Assemble the payload into a runable&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #c33720; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;#!/usr/bin/env python&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt;| cat - &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;$TMPDIR&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;/payload.zip&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #d53bd3; font-variant-ligatures: no-common-ligatures;&quot;&gt;$TARGET&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #d53bd3; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;+x&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;$TARGET&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: whitesmoke; font-family: Monaco; font-size: 11px; line-height: normal; min-height: 15px;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #5330e1; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;# Cleanup&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: black; color: #d53bd3; font-family: Monaco; font-size: 11px; line-height: normal;&quot;&gt;
&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;rm&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;-r&lt;/span&gt;&lt;span style=&quot;color: whitesmoke; font-variant-ligatures: no-common-ligatures;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-variant-ligatures: no-common-ligatures;&quot;&gt;$TMPDIR&lt;/span&gt;&lt;span style=&quot;color: #ce7924; font-variant-ligatures: no-common-ligatures;&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/1370924909882921599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/1370924909882921599'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2017/02/non-freeze-single-file-distribution-of.html' title='Non-freeze, single file distribution of your python project'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-5491652107907340762</id><published>2015-10-07T11:33:00.001-04:00</published><updated>2015-10-07T11:34:06.442-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="python"/><title type='text'>Python Decorators Examples</title><content type='html'>I often go long stretches between times when I aggressively use python at clients. &amp;nbsp;As a result, I get rusty on what I could consider somewhat advanced topics and have to spend time googling around to jog my memory. &amp;nbsp;Reading my own code usually gets me back up and running quicker than reading others&#39; code. &amp;nbsp;Leaving this here as a breadcrumb to help me remember how to use python decorators.&lt;br /&gt;
&lt;br /&gt;
If you find this helpful, awesome!&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;#!/usr/bin/env python&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&quot;&quot;&quot;Decorator examples&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;def decorator_without_arguments(func):&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; def wrapped_function(*args, **kwargs):&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Reverses the arguments before calling&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; new_args = reversed(args)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return func(*new_args, **kwargs)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; wrapped_function.__name__ = &quot;(%s -&amp;gt; %s)&quot; % \&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (decorator_without_arguments.__name__, func.__name__)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; return wrapped_function&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;def decorator_with_arguments(arg1, arg2=None):&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; def actual_decorator(func):&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; def wrapped_function(*args, **kwargs):&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Wraps results in explanation string&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; result = &quot;(%s: %s) &quot; % (arg1, &#39;, &#39;.join([str(x) for x in args]))&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; result += str(func(*args, **kwargs))&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if arg2 is not None:&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; result += arg2&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return result&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; wrapped_function.__name__ = func.__name__&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return wrapped_function&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; return actual_decorator&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;def undecorated_subtract(number_1, number_2):&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; return number_1 - number_2&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;@decorator_without_arguments&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;def decorated_subtract(number_1, number_2):&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; return number_1 - number_2&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;def undecorated_add(number_1, number_2):&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; return number_1 + number_2&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;@decorator_with_arguments(&#39;ADD&#39;)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;def decorated_add(number_1, number_2):&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; return number_1 + number_2&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;if __name__ == &#39;__main__&#39;:&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; print undecorated_subtract(7, 3)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; print decorated_subtract(7, 3)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; print decorated_subtract&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; print undecorated_add(3, 7)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; print decorated_add(3, 7)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; print decorated_add&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/5491652107907340762'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/5491652107907340762'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2015/10/i-often-go-long-stretches-between-times.html' title='Python Decorators Examples'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-3157020005153065991</id><published>2014-07-23T13:17:00.003-04:00</published><updated>2014-07-23T13:17:43.040-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bash python"/><title type='text'>Embedding python in bash scripts</title><content type='html'>As a software development consultant, I do a lot of bash scripting. &amp;nbsp;I can do a lot of really creative things using nothing but bash and the binutils at my disposal, but sometimes I&#39;ll come across something that&#39;s just easier to do in a higher level scripting language. &amp;nbsp;Enter python.&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Conversely, there are a lot of things that are just easier and more straight forward to do in bash, so writing everything in straight python may be more work than it&#39;s worth.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Here&#39;s a quick posting to describe how you can embed some python code into your bash scripts and get the best of both worlds. &amp;nbsp;&lt;i&gt;Note: just as a heads, up, the examples in this posting are quite contrived.&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Calling python from bash is easy. &amp;nbsp;You simply use python&#39;s &#39;-&#39; argument and pipe in your python code. &amp;nbsp;I typically wrap my python code in a bash function.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;#!/bin/bash&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;function current_datetime {&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;python - &amp;lt;&amp;lt;END&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;import datetime&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;print datetime.datetime.now()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;END&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;}&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;# Call it&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;current_datetime&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;# Call it and capture the output&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;DT=$(current_datetime)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;echo Current date and time: $DT&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
You can also pass data into your embedded python script. &amp;nbsp;I do that using environment variables:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;#!/bin/bash&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;function line {&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;PYTHON_ARG=&quot;$1&quot; python - &amp;lt;&amp;lt;END&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;import os&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;line_len = int(os.environ[&#39;PYTHON_ARG&#39;])&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;print &#39;-&#39; * line_len&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;END&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;}&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;# Do it one way&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;line 80&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;echo &#39;Handy&#39;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;# Do it another way&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;echo $(line 80)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
My usual use-case for doing this is if I&#39;m extending someone else&#39;s bash scripts and have to &#39;go off the reservation&#39; a bit. &amp;nbsp;Sometimes I&#39;m updating an existing &#39;legacy&#39; script and need to look up some data... maybe do a REST call or something. &amp;nbsp;Here&#39;s an example bash script that uses curl to call a REST service to get some weather data. &amp;nbsp;Then is passes the raw JSON response to an embedded python script to interpret and format the results:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;#!/bin/bash&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;function format_weather_data() {&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;PYTHON_ARG=&quot;$1&quot; python - &amp;lt;&amp;lt;END&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;import os&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;import json&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;json_data = os.environ[&#39;PYTHON_ARG&#39;]&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;data =json.loads(json_data)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;lookup = {&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;200&#39;: &#39;thunderstorm with light rain&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;201&#39;: &#39;thunderstorm with rain&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;202&#39;: &#39;thunderstorm with heavy rain&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;210&#39;: &#39;light thunderstorm&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;211&#39;: &#39;thunderstorm&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;212&#39;: &#39;heavy thunderstorm&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;221&#39;: &#39;ragged thunderstorm&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;230&#39;: &#39;thunderstorm with light drizzle&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;231&#39;: &#39;thunderstorm with drizzle&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;232&#39;: &#39;thunderstorm with heavy drizzle&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;300&#39;: &#39;light intensity drizzle&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;301&#39;: &#39;drizzle&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;302&#39;: &#39;heavy intensity drizzle&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;310&#39;: &#39;light intensity drizzle rain&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;311&#39;: &#39;drizzle rain&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;312&#39;: &#39;heavy intensity drizzle rain&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;313&#39;: &#39;shower rain and drizzle&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;314&#39;: &#39;heavy shower rain and drizzle&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;321&#39;: &#39;shower drizzle&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;500&#39;: &#39;light rain&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;501&#39;: &#39;moderate rain&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;502&#39;: &#39;heavy intensity rain&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;503&#39;: &#39;very heavy rain&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;504&#39;: &#39;extreme rain&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;511&#39;: &#39;freezing rain&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;520&#39;: &#39;light intensity shower rain&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;521&#39;: &#39;shower rain&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;522&#39;: &#39;heavy intensity shower rain&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;531&#39;: &#39;ragged shower rain&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;600&#39;: &#39;light snow&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;601&#39;: &#39;snow&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;602&#39;: &#39;heavy snow&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;611&#39;: &#39;sleet&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;612&#39;: &#39;shower sleet&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;615&#39;: &#39;light rain and snow&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;616&#39;: &#39;rain and snow&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;620&#39;: &#39;light shower snow&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;621&#39;: &#39;shower snow&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;622&#39;: &#39;heavy shower snow&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;701&#39;: &#39;mist&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;711&#39;: &#39;smoke&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;721&#39;: &#39;haze&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;731&#39;: &#39;sand, dust whirls&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;741&#39;: &#39;fog&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;751&#39;: &#39;sand&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;761&#39;: &#39;dust&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;762&#39;: &#39;volcanic ash&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;771&#39;: &#39;squalls&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;781&#39;: &#39;tornado&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;800&#39;: &#39;clear sky&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;801&#39;: &#39;few clouds&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;802&#39;: &#39;scattered clouds&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;803&#39;: &#39;broken clouds&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;804&#39;: &#39;overcast clouds&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;900&#39;: &#39;tornado&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;901&#39;: &#39;tropical storm&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;902&#39;: &#39;hurricane&#39;,&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;903&#39;: &#39;cold&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;904&#39;: &#39;hot&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;905&#39;: &#39;windy&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;906&#39;: &#39;hail&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;950&#39;: &#39;setting&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;951&#39;: &#39;calm&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;952&#39;: &#39;light breeze&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;953&#39;: &#39;gentle breeze&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;954&#39;: &#39;moderate breeze&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;955&#39;: &#39;fresh breeze&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;956&#39;: &#39;strong breeze&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;957&#39;: &#39;high wind, near gale&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;958&#39;: &#39;gale&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;959&#39;: &#39;severe gale&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;960&#39;: &#39;storm&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;961&#39;: &#39;violent storm&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &#39;962&#39;: &#39;hurricane&#39;,&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;}&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;print &quot;Current temperature: %g F&quot; % data[&#39;main&#39;][&#39;temp&#39;]&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;print &quot;Today&#39;s high: %g F&quot; % data[&#39;main&#39;][&#39;temp_max&#39;]&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;print &quot;Today&#39;s low: %g F&quot; % data[&#39;main&#39;][&#39;temp_min&#39;]&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;print &quot;Wind speed: %g mi/hr&quot; % data[&#39;wind&#39;][&#39;speed&#39;]&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;weather_descs = [lookup.get(str(i[&#39;id&#39;]), &#39;*error*&#39;) for i in data[&#39;weather&#39;]]&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;print &quot;Weather: %s&quot; % &#39;, &#39;.join(weather_descs)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;END&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;}&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;WEATHER_URL=&quot;http://api.openweathermap.org/data/2.5/weather?q=Cincinnati,OH&amp;amp;units=imperial&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;format_weather_data &quot;$(curl -s $WEATHER_URL)&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Hope you find this information useful.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/3157020005153065991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/3157020005153065991'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2014/07/embedding-python-in-bash-scripts.html' title='Embedding python in bash scripts'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-8102873551923342348</id><published>2014-01-22T16:21:00.002-05:00</published><updated>2014-01-22T16:21:19.080-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bash"/><category scheme="http://www.blogger.com/atom/ns#" term="guid"/><category scheme="http://www.blogger.com/atom/ns#" term="sed"/><title type='text'>Formatting GUIDs with sed</title><content type='html'>At my current client, I&#39;m often given GUIDs for one reason or another. &amp;nbsp;Often they are not in the format that I need them to be. &amp;nbsp;Sometimes they have the dashes and I need them to be dash-free. &amp;nbsp;Other times, the dashes have been removed and I need them back.&lt;br /&gt;
&lt;br /&gt;
Here&#39;s some quick, down and dirty &lt;i&gt;sed &lt;/i&gt;commands to swap them back and forth:&lt;br /&gt;
&lt;br /&gt;
To remove the dashes:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;$ echo&amp;nbsp;8EC60070-685F-41DB-C881-EACF9E74E4BD | sed &#39;s/-//g&#39;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;8EC60070685F41DBC881EACF9E74E4BD&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;$&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
To put them back:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;$ echo&amp;nbsp;8EC60070685F41DBC881EACF9E74E4BD |&amp;nbsp;sed -rn &#39;s/([0-9A-F]{8})([0-9A-F]{4})([0-9A-F]{4})([0-9A-F]{4})([0-9A-F]{12})/\1-\2-\3-\4-\5/p&#39;)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;8EC60070-685F-41DB-C881-EACF9E74E4BD&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;$&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
It goes without saying you can embed this very &lt;i&gt;sed&lt;/i&gt; command in a bash script and run it over many rows in a file.</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/8102873551923342348'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/8102873551923342348'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2014/01/formatting-guids-with-sed.html' title='Formatting GUIDs with sed'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-250003634787894262</id><published>2013-03-14T14:26:00.000-04:00</published><updated>2013-03-14T14:26:28.739-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bash monitoring web notification email"/><title type='text'>Monitoring a web page for changes using bash</title><content type='html'>There&#39;s this conference that I&#39;d like to attend and I&#39;ve heard that it&#39;s a hard-to-get-into type conference. &amp;nbsp;When I go to their site it doesn&#39;t have any new info.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Rather than checking the site every day, I&#39;d like to have it monitored and be alerted when something new DOES appear on it.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Now I know there are services like &lt;a href=&quot;http://changedetection.com/&quot;&gt;ChangeDetection.com&lt;/a&gt; that can monitor it for me, but I was wanting to cobble something together with the tools I already have. &amp;nbsp;I&#39;d also like to have the ability to customize what it consider &quot;a change&quot; at my disposal when/if I need it.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
To that end, I threw together the following bash script. &amp;nbsp;It monitors a URL and if it detects a change, it sends an email to my gmail account letting me know.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Hope you find it useful. &amp;nbsp;BTW, I&#39;m using a program called sendEmail to send the email notification. &amp;nbsp;It&#39;s in apt if you&#39;re using a debian/ubuntu-like distribution.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;#!/bin/bash&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;# monitor.sh - Monitors a web page for changes&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;# sends an email notification if the file change&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;USERNAME=&quot;me@gmail.com&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;PASSWORD=&quot;itzasecret&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;URL=&quot;http://thepage.com/that/I/want/to/monitor&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;for (( ; ; )); do&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; mv new.html old.html 2&amp;gt; /dev/null&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; curl $URL -L --compressed -s &amp;gt; new.html&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; DIFF_OUTPUT=&quot;$(diff new.html old.html)&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; if [ &quot;0&quot; != &quot;${#DIFF_OUTPUT}&quot; ]; then&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; sendEmail -f $USERNAME -s smtp.gmail.com:587 \&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -xu $USERNAME -xp $PASSWORD -t $USERNAME \&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -o tls=yes -u &quot;Web page changed&quot; \&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -m &quot;Visit it at $URL&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; sleep 10&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; fi&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;done&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Then from a bash prompt I run it with the following command:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;nohup ./monitor.sh &amp;amp;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Using nohup and throwing it in the background allows me to log out and have the script continue to run.&lt;/div&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/250003634787894262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/250003634787894262'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2013/03/monitoring-web-page-for-changes-using.html' title='Monitoring a web page for changes using bash'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-431860075552427015</id><published>2013-02-04T22:38:00.000-05:00</published><updated>2013-02-04T22:41:09.595-05:00</updated><title type='text'>Fun with Python&#39;s multiprocessing module</title><content type='html'>At my current client, they asked me to write a Python script to aggregate data from a RESTful web service. &amp;nbsp;Essentially, they have a web service end-point that takes a single customer ID as an argument and it returns some customer profile records as JSON.&lt;br /&gt;
&lt;br /&gt;
They wanted my script to call the web service for each and every customer listed in a text file. &amp;nbsp;The script will be run from a scheduled job (cron, windows scheduled task, etc.). &amp;nbsp;Once productionalized, the text file will contain a large number of customer ID&#39;s (like a million or so). &amp;nbsp;All the results need to be stored in a single text file for the run.&lt;br /&gt;
&lt;br /&gt;
My first thought was to use Python&#39;s threading features, but I came with 2 problems with this:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Python&#39;s threading isn&#39;t &quot;real&quot; threading. &amp;nbsp;A single Python process will run all threads on a single physical core regardless of how many cores the server has. &amp;nbsp;The other cores will not be utilized.&lt;/li&gt;
&lt;li&gt;Python&#39;s urllib and urllib2 packages aren&#39;t even thread safe.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Now I know there&#39;s a third-party thread-safe urllib3 package, but that doesn&#39;t solve the multi-core issue and I wasn&#39;t looking to install anything beyond Python 2.7&#39;s standard library on the server. &amp;nbsp;After doing a little research, I came up with the idea of using Python&#39;s multiprocessing module.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The rest of this blog posting is a walkthrough of what I ended up building.&lt;/div&gt;
&lt;h3&gt;
First things first - configuration&lt;/h3&gt;
&lt;div&gt;
Since this is a script that will be run often and certain configuration settings will need to be updated from time to time by support staff, I decided to extract the configuration out to a separate configuration file. &amp;nbsp;Initially, I had the settings stored in a .ini file, but I later thought why not use Python for settings. &amp;nbsp;To that end, I have a &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;settings.py&lt;/span&gt;&lt;/b&gt; file that holds a class that contains the settings:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;#!/usr/bin/env python&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;Settings file. &amp;nbsp;See job.py for more info.&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;# -----------------------------------------------------------&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;# Edit the values in this Settings class to control settings.&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;# -----------------------------------------------------------&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;class Settings:&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Settings as a class. &amp;nbsp;Why? &amp;nbsp;Because I&#39;m lazy.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; source_file = &#39;TestData.csv&#39;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; profile_data_file = &#39;results.txt&#39;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; log_file = &#39;log.txt&#39;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; failed_customer_file = &#39;failed.txt&#39;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; process_count = 10&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; url =&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: small;&quot;&gt;&#39;http://division-1.internal-server.com/rest-service/endpoint/{0}&#39;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
There is one input file (&lt;b&gt;source_file&lt;/b&gt;). &amp;nbsp;This is the file that contains the list of customer ID&#39;s. &amp;nbsp;Then there are 3 output files: &amp;nbsp;&lt;b&gt;profile_data_file&lt;/b&gt;, &lt;b&gt;log_file&lt;/b&gt; and &lt;b&gt;failed_customer_file&lt;/b&gt;. &amp;nbsp;The &lt;b&gt;profile_data_file&lt;/b&gt; file is where the script will put the customer detail records that it receives from the web service. &amp;nbsp;The &lt;b&gt;log_file&lt;/b&gt; is where the script will write logging messages for debugging problems after the fact. &amp;nbsp;Finally, &lt;b&gt;failed_customer_file&lt;/b&gt; is where the script will write customer ID&#39;s of customers that the script fails to retrieve from the web services.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;process_count&lt;/b&gt; is a setting that will allow you to specify how many parallel processes the script should spawn.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;url&lt;/b&gt; is the url of the web service end-point.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The main job script is called &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;job.py&lt;/span&gt;&lt;/b&gt;. &amp;nbsp;It imports the settings.py module and then creates a new class that inherits from the Settings class.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;class Config(settings.Settings):&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Configuration class&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; _runtime = datetime.datetime.now().strftime(&#39;%Y%m%d-%H%M%S&#39;)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; @staticmethod&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; def timestamp(filename):&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Stamps a filename with the timestamp for this run&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; parts = os.path.splitext(filename)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return &quot;%s-%s%s&quot; % (parts[0], Config._runtime, parts[1])&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This class has a static method called timestamp. &amp;nbsp;In the main job, I will call the timestamp method to add the date/time of the run to the output filenames. &amp;nbsp;So you might see something like:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;outfile = open(Config.timestamp(Config.log_file), &#39;w&#39;)&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This will open a file named &#39;log-20120204-112530.txt&#39; for writing.&lt;/div&gt;
&lt;h3&gt;
The Job class&lt;/h3&gt;
&lt;div&gt;
The Job class is the main class that executes the job and spawns the worker processes. &amp;nbsp;It has the following methods:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;__init__&lt;/b&gt; - constructor, set&#39;s up a multiprocessing Pool and 3 Queue&#39;s&lt;/li&gt;
&lt;li&gt;&lt;b&gt;run&lt;/b&gt; - Kicks off the job&lt;/li&gt;
&lt;li&gt;&lt;b&gt;get_customers&lt;/b&gt; - Reads the customer file&lt;/li&gt;
&lt;li&gt;&lt;b&gt;get_requests&lt;/b&gt; - Transforms the customers list into a list of processes requests&lt;/li&gt;
&lt;li&gt;&lt;b&gt;process_customer_queue&lt;/b&gt; - Deals with responses from the web service&lt;/li&gt;
&lt;li&gt;&lt;b&gt;process_log_queue&lt;/b&gt; - Deals with log messages from the worker processes&lt;/li&gt;
&lt;li&gt;&lt;b&gt;process_exceptions_queue&lt;/b&gt; - Deals with exceptions that occur in the worker processes&lt;/li&gt;
&lt;li&gt;&lt;b&gt;log&lt;/b&gt; - Writes log messages to the log file&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
Here&#39;s a copy of the Job class:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;class Job:&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Job that performs the run.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; def __init__(self):&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self._manager = multiprocessing.Manager()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self._pool = multiprocessing.Pool(Config.process_count)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self._customer_queue = self._manager.Queue()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self._log_queue = self._manager.Queue()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self._exception_queue = self._manager.Queue()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; def run(self):&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Do it.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; start_time = datetime.datetime.now()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.log(&#39;[Run started]&#39;)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; customers = self.get_customers()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; requests = self.get_requests(customers)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; result = self._pool.map_async(get_customer, requests)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; while not result.ready():&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.process_customer_queue()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.process_log_queue()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.process_exceptions_queue()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self._pool.close()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self._pool.join()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.process_customer_queue()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.process_log_queue()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.process_exceptions_queue()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.log(&#39;[Run finished]&#39;)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.log(&#39;[Total runtime: %s]&#39; % (datetime.datetime.now() - start_time))&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; def get_customers(self):&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Read the source file.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; buf = [line.strip() for line in open(Config.source_file).readlines()[1:]]&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return buf&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; def get_requests(self, customers):&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Generate requests from customers.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; requests = [{ \&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &#39;customer&#39;: customer, \&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &#39;data&#39;: self._customer_queue, \&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &#39;log&#39;: self._log_queue, \&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &#39;exceptions&#39;: self._exception_queue, \&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &#39;url&#39;: Config.url, \&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; } for customer in customers]&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return requests&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; def process_customer_queue(self):&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Pull messages off the data queue.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; try:&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; message = self._customer_queue.get_nowait()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; except Queue.Empty:&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; customer = message[&#39;customer&#39;]&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; details = message[&#39;server_response&#39;][&#39;details&#39;]&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; outfile = open(Config.timestamp(Config.profile_data_file), &#39;a&#39;)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; for record in details:&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; buf = &quot;%s, %s, %s, %s\n&quot; % (customer, record[&#39;id&#39;], \&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; record[&#39;relevanceScore&#39;], record[&#39;relevanceRank&#39;])&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; outfile.write(buf)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; outfile.close()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; def process_log_queue(self):&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Pull messages off the log queue.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; try:&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; message = self._log_queue.get_nowait()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; except Queue.Empty:&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.log(message)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; def process_exceptions_queue(self):&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Pull messages off the exceptions queue.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; try:&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; message = self._exception_queue.get_nowait()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; except Queue.Empty:&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; customer = message[&#39;customer&#39;]&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; exception = message[&#39;exception&#39;]&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.log(&quot;EXCEPTION GETTING %s! - %s&quot; % \&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (customer, str(exception)))&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; failed_file = open(Config.timestamp(Config.failed_customer_file), &#39;a&#39;)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; buf = &quot;%s\n&quot; % customer&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; failed_file.write(buf)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; failed_file.close()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; def log(self, message):&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Write message to the log file.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; logfile = open(Config.timestamp(Config.log_file), &#39;a&#39;)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; timestamp = datetime.datetime.now().strftime(&#39;%Y/%m/%d %H:%M:%S&#39;)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; logfile.write(&quot;%s - %s\n&quot; % (timestamp, message))&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; logfile.close()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Some important things to highlight. &amp;nbsp;The constructor creates three queues: &amp;nbsp;customer_queue, log_queue, and exceptions_queue. &amp;nbsp;These queues are used for interprocess communication. &amp;nbsp;The constructor creates a Pool of worker processes. &amp;nbsp;Each process will communicate back to the parent process via these queues. &amp;nbsp;The customer_queue is responsible for holding the results of the web services calls. &amp;nbsp;The log_queue is responsible for holding log messages. &amp;nbsp;The exceptions_queue is responsible for holding exceptions that occur when worker processes have problems talking to the web service.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In the run method, the Job class will call the Pool class&#39; map_async method. &amp;nbsp;The map_async method splits the requests list into multiple lists and passes each list to a separate worker process for processing. Then the run method goes into a loop, waiting for the worker processes to all complete. &amp;nbsp;While it&#39;s waiting, it will continually check the queues to see if any messages have been received.&lt;/div&gt;
&lt;h3&gt;
The stand-alone function&lt;/h3&gt;
&lt;div&gt;
The map_async method&#39;s first argument is the name of the function that each worker process should run the request list items with. &amp;nbsp;In this case, the name of that function is get_customer. &amp;nbsp;get_customer looks like this:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;def get_customer(request):&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Retrieve the customer details from the given request.&quot;&quot;&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; customer = request[&#39;customer&#39;]&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; url = request[&#39;url&#39;]&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; data = request[&#39;data&#39;]&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; log = request[&#39;log&#39;]&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; exceptions = request[&#39;exceptions&#39;]&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; try:&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; log.put(&quot;Requesting details for customer %s&quot; % customer)&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; req_url = url.replace(&#39;{0}&#39;, customer)&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; request = urllib2.Request(req_url)&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; response = urllib2.urlopen(request)&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; buf = response.read()&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; data_records = json.loads(buf)&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; coupons.put({&#39;customer: customer, &#39;server_response&#39;: data_records})&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; log.put(&quot;Successfully retrieved %d details(s) for %s&quot; % \&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (len(data_records), customer))&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; except Exception, exc:&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; exceptions.put({&#39;customer&#39;: customer, &#39;exception&#39;: exc})&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
This function is called for each request in the worker processes. &amp;nbsp;It extracts queues from the request. &amp;nbsp;It uses the put method on each queue to pass information back to the parent process.&lt;/div&gt;
&lt;h3&gt;
Pulling it all together&lt;/h3&gt;
&lt;div&gt;
The last thing in my script file is this:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;if __name__ == &#39;__main__&#39;:&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; # Let&#39;s do this!&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; Job().run()&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
It&#39;s important to embed the Job().run() call inside the &#39;if __main__&#39; branching. &amp;nbsp;This is because of how the multiprocessing internals work. &amp;nbsp;When the Pool.map_async method is executed, Python will create a number of sub processes. &amp;nbsp;When each process starts up, it&#39;s actually spawning a copy of the Python executable. &amp;nbsp;When that process comes up, it imports the job module and then starts calling the get_customer function over and over with the requests. &amp;nbsp;If the Job().run() were not embedded in a &#39;if __main__&#39; branch, every worker process would spawn more Job classes. &amp;nbsp;Nothing good would come of that!&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Hope you find this helpful.&lt;/div&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/431860075552427015'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/431860075552427015'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2013/02/fun-with-pythons-multiprocessing-module.html' title='Fun with Python&#39;s multiprocessing module'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-6437445533121485764</id><published>2013-01-29T11:41:00.002-05:00</published><updated>2013-01-31T09:18:55.099-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="git"/><category scheme="http://www.blogger.com/atom/ns#" term="source control"/><category scheme="http://www.blogger.com/atom/ns#" term="svn"/><title type='text'>Create and track svn branches using git-svn</title><content type='html'>My most recent client is utilizing svn for the source control needs. &amp;nbsp;While I used to be a big svn guy, I&#39;ve more recently been using git and have found the transition back to svn a little awkward.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Enter: git-svn. &amp;nbsp;I love git-svn because I can exist in a svn&amp;nbsp;environment&amp;nbsp;without giving up all the things I love about git. &amp;nbsp;One thing that continually escapes my memory is how to create a svn branch from the git CLI as well as how to associate a git branch with a svn branch.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This blog entry is my own cheat-sheet.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Say, I want to create a svn branch off of the trunk. &amp;nbsp;Here&#39;s what I would do:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;$ git checkout master&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;$ git svn rebase&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;$&amp;nbsp;git svn branch -m &quot;Creating a feature branch&quot; feature_1001&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;$ git svn dcommit&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;$ git checkout -b my_feature_1001 feature_1001&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Another thing that isn&#39;t so intuitive is merging your changes back to trunk when you&#39;re done. &amp;nbsp;Here&#39;s what I would do:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;$ git checkout feature_1001&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;$ git rebase master&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;$ git checkout master&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;$ git merge feature_1001&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;$ git svn dcommit&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;$ git branch -D feature_1001&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Then I have to use a svn client to actually delete the svn branch.&lt;br /&gt;
&lt;br /&gt;
Also, if a svn branch is removed, you need to remove it by hand from git with&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;$ git branch -rd feature_1001&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/6437445533121485764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/6437445533121485764'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2013/01/create-and-track-svn-branches-using-git.html' title='Create and track svn branches using git-svn'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-1160004821664713477</id><published>2012-10-19T10:24:00.003-04:00</published><updated>2012-10-19T10:24:35.844-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="formatting"/><category scheme="http://www.blogger.com/atom/ns#" term="markdown"/><category scheme="http://www.blogger.com/atom/ns#" term="vim"/><title type='text'>Reformatting for 80 characters in vim</title><content type='html'>After reading &lt;a href=&quot;http://www.amazon.com/Pragmatic-Programmer-Journeyman-Master/dp/020161622X&quot; target=&quot;_blank&quot;&gt;The Pragmatic Programmer&lt;/a&gt; and &lt;a href=&quot;http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882&quot; target=&quot;_blank&quot;&gt;Clean Code&lt;/a&gt;, I&#39;ve pretty much settled on using text files (specifically in &lt;a href=&quot;http://daringfireball.net/projects/markdown/&quot; target=&quot;_blank&quot;&gt;markdown&lt;/a&gt; format) for all my personal notes and documentation and editing them with&amp;nbsp;&lt;a href=&quot;http://www.vim.org/&quot; target=&quot;_blank&quot;&gt;vim&lt;/a&gt;. &amp;nbsp;That being said, I like to keep my files limited to 80 columns wide. &amp;nbsp;That way I can look at and review multiple documents&amp;nbsp;simultaneously&amp;nbsp;in splits and vertical split easily.&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In my .vimrc I have the following setting to get the auto wrapping working for me:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;set textwidth=80&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
That way as I type along, vim is keeping track of the file&#39;s column width and when I get to the 80th column it automatically moves me to the next line. &amp;nbsp;Pretty handy.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Here&#39;s my problem though, if I change some text that I&#39;ve already entered and reword it, my paragraph loses it&#39;s nicely formatted set column width. &amp;nbsp;Here&#39;s an example but with the textwidth setting set at 40:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Before my edit change:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;Lorem ipsum dolor sit amet, consectetur&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;adipiscing elit. &amp;nbsp;Proin neque sapien,&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;facilisis eget tincidunt ut, porttitor&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;laoreet lacus. Class aptent taciti&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;sociosqu ad litora torquent per conubia&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;nostra, per inceptos himenaeos. &amp;nbsp;Etiam&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;semper elementum congue.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
After my edit change:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;Lorem ipsum dolor sit amet, consectetur&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;adipiscing elit. &amp;nbsp;Proin neque sapien,&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;facilisis eget tincidunt ut, porttitor&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;laoreet lacus. Class aptent taciti&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;sociosqu ad litora torquent per conubia&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;nostra, per inceptos himenaeos. &amp;nbsp;&lt;b&gt;I&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;forgot some text.&lt;/b&gt; Etiam&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;semper elementum congue.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Notice the problem: &amp;nbsp;After editing the paragraph, &amp;nbsp;the second to last line doesn&#39;t go to the 40th column before wrapping. &amp;nbsp;This is a little&amp;nbsp;annoying&amp;nbsp;to me because I feel the need to reformat the paragraph to get it back to looking like the &quot;before&quot;. &amp;nbsp;It&#39;s not too big of a deal when I only have to reformat a line or two but if I&#39;ve change something high up in a fairly long paragraph, reformatting dozens of lines can get tedious.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Here&#39;s a little tip that I stumbled across that can make that reformatting go a bit quicker:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
1. &amp;nbsp;Select the whole paragraph with &lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;V&lt;/span&gt;&lt;/b&gt;. and then &lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;h&lt;/span&gt;&lt;/b&gt;,&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;j&lt;/span&gt;&lt;/b&gt;,&lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;k&lt;/span&gt;&lt;/b&gt; and/or &lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;l&lt;/span&gt;&lt;/b&gt;.&lt;/div&gt;
&lt;div&gt;
2. &amp;nbsp;Then strip the new-line characters with &lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;J&lt;/span&gt;&lt;/b&gt;.&lt;/div&gt;
&lt;div&gt;
3. &amp;nbsp;Finally reformat it with &lt;b&gt;&lt;span style=&quot;color: blue; font-family: Courier New, Courier, monospace;&quot;&gt;gq&lt;/span&gt;&lt;/b&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Hope you find this helpful!&lt;/div&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/1160004821664713477'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/1160004821664713477'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2012/10/reformatting-for-80-characters-in-vim.html' title='Reformatting for 80 characters in vim'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-5762858374708686038</id><published>2012-07-06T12:32:00.002-04:00</published><updated>2012-07-06T12:47:42.488-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bash"/><category scheme="http://www.blogger.com/atom/ns#" term="cgi"/><category scheme="http://www.blogger.com/atom/ns#" term="clone"/><category scheme="http://www.blogger.com/atom/ns#" term="git"/><category scheme="http://www.blogger.com/atom/ns#" term="gitolite"/><category scheme="http://www.blogger.com/atom/ns#" term="url"/><category scheme="http://www.blogger.com/atom/ns#" term="web"/><title type='text'>CGI Script to display clone urls</title><content type='html'>&lt;br /&gt;
After some discussion, I was able to convince my client to convert from gitorious to gitolite. &amp;nbsp;One nice feature that people like about gitorious is that the web interface provides an easy way to look up urls for cloning repositories.&lt;br /&gt;
&lt;br /&gt;
In my mind, that&#39;s a pretty&amp;nbsp;legitimate&amp;nbsp;need. &amp;nbsp;To that end, I threw together this bash script, which acts as a cgi and dropped it in the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;cgi-bin&lt;/span&gt;&lt;/b&gt; directory of the server that&#39;s running gitolite. &amp;nbsp;Hope you find this helpful.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;#!/bin/bash&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;REPOSITORY_DIR=&quot;/home/git/repositories/&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;URL_PREFIX=&quot;git clone git@internal-build-server:&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;cat &amp;lt;&amp;lt;DONE&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Content-type: text/html&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&amp;lt;title&amp;gt;Repository URLs&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&amp;lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;/index.css&quot; /&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;div id=&quot;page_container&quot;&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;background-color: white; white-space: pre;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;background-color: white;&quot;&gt;Repository URLs&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;Repository URLs on this server follow a specific pattern. &amp;nbsp;The pattern is&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;as follows:&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&amp;lt;center&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;git@&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;internal-build-server&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;:&amp;lt;i&amp;gt;&amp;lt;font color=&quot;darkblue&quot;&amp;gt;{category}&amp;lt;/font&amp;gt;&amp;lt;/i&amp;gt;/&amp;lt;i&amp;gt;&amp;lt;font color=&quot;darkblue&quot;&amp;gt;{project}&amp;lt;/font&amp;gt;&amp;lt;/i&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&amp;lt;/center&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;These URLs are both pull and push URLs. &amp;nbsp;You do not need separate URLs&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;for pulling and pushing. &amp;nbsp;Access control will be handled by a&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;server git update hook that is provided by gitolite.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;In an effort to make life a little easier in locating your URLs, this script&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;enumerates URLs for the repositories located on this machine below.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;DONE&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;CATEGORIES=$(find $REPOSITORY_DIR -type d -maxdepth 1 -mindepth 1 -not \&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;-iname &#39;*.git&#39; | sed -e &quot;s|$REPOSITORY_DIR||g&quot;)&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;for CATEGORY in $CATEGORIES; do&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;echo &quot;&amp;lt;h2&amp;gt;Category: $CATEGORY&amp;lt;/h2&amp;gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;CAT_REPOSITORIES=$(find $REPOSITORY_DIR$CATEGORY -type d -iname \&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&#39;*.git&#39; | sed -e &quot;s|$REPOSITORY_DIR||g&quot; -e &#39;s/.git$//g&#39;)&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;for REPOSITORY in $CAT_REPOSITORIES; do&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;echo &quot;$URL_PREFIX$REPOSITORY&amp;lt;br /&amp;gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;done&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;done&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;ROOT_REPOSITORIES=$(find $REPOSITORY_DIR -type d -maxdepth 1 -mindepth 1 \&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;-iname &#39;*.git&#39; | sed -e &quot;s|$REPOSITORY_DIR||g&quot; -e &#39;s/.git$//g&#39;)&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;echo &quot;&amp;lt;h2&amp;gt;Uncategorized Repositories&amp;lt;/h2&amp;gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;for REPOSITORY in $ROOT_REPOSITORIES; do&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;echo &quot;$URL_PREFIX$REPOSITORY&amp;lt;br /&amp;gt;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;done&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;cat &amp;lt;&amp;lt;DONE&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;DONE&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/5762858374708686038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/5762858374708686038'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2012/07/cgi-script-to-display-clone-urls.html' title='CGI Script to display clone urls'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-4073634363884948527</id><published>2012-06-25T12:11:00.001-04:00</published><updated>2012-06-25T12:16:58.376-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="awk"/><category scheme="http://www.blogger.com/atom/ns#" term="bash"/><category scheme="http://www.blogger.com/atom/ns#" term="fetch"/><category scheme="http://www.blogger.com/atom/ns#" term="git"/><category scheme="http://www.blogger.com/atom/ns#" term="mktemp"/><category scheme="http://www.blogger.com/atom/ns#" term="pull"/><category scheme="http://www.blogger.com/atom/ns#" term="sed"/><category scheme="http://www.blogger.com/atom/ns#" term="zenity"/><title type='text'>Bash script for pulling/fetching multiple git clones</title><content type='html'>&lt;br /&gt;
In my current assignment, I&#39;m acting as the main build guy for a number of projects that use git for source control. &amp;nbsp;As such, I find it very useful to keep all my git clones up to date whether I&#39;m actively developing in them or not. &amp;nbsp;Additionally, I need to review the changes other developers are committing, so I&#39;d like to get a summary of recent git activities.&lt;br /&gt;
&lt;br /&gt;
Over time, I&#39;ve put this little bash script together to help me with that. &amp;nbsp;I&#39;ve included the script in this posting so I can remember later what/why I did this. &amp;nbsp;Disclaimer, I wrote this script and run this script in bash on Linux (not via git-bash in Windows). &amp;nbsp;Also, I&#39;m using Zenity for some nice UI look/feel.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; 1&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; #!/bin/bash&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; 2&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; 3&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; pushd ~/dev/repos &amp;gt; /dev/null&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; 4&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; 5&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; # The log file&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; 6&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; PULL_LOG=&quot;$(mktemp)&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; 7&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; 8&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; # Get a list of all the clones in this directory.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; 9&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; CLONES=$(find -maxdepth 2 -mindepth 2 -type d -name &quot;.git&quot; | sed -e &#39;s|\./||&#39; -e &#39;s|/\.git||&#39;)&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;10&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;11&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; # Get a list of all the branches in clone/branch format&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;12&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; ALL_BRANCHES=$(for clone in $CLONES; do cd $clone; for branch in $(git branch -l | sed &#39;s/\s\|\*//g&#39;); do echo $clone/$branch; done; cd ..; done)&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;13&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;14&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; # Count the branches&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;15&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; BRANCH_COUNT=$(echo $ALL_BRANCHES | sed &#39;s/ /\n/g&#39; | wc -l)&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;16&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;17&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; # Start the log file&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;18&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; echo &quot;Pull log for $(date)&quot; &amp;gt;&amp;gt; $PULL_LOG&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;19&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; echo &quot;--------------------------------------------------------------------------------&quot; &amp;gt;&amp;gt; $PULL_LOG&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;20&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;21&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; # Function for pipping output to zenity progress dialog&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;22&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; function pull_clones() {&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;23&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; clone_counter=0&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;24&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; for clone in $CLONES; do&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;25&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; echo &quot;Pulling branches for clone $clone&quot; &amp;gt;&amp;gt; $PULL_LOG&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;26&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; echo &quot;--------------------------------------------------------------------------------&quot; &amp;gt;&amp;gt; $PULL_LOG&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;27&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; cd $clone&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;28&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; echo &quot;# Fetching changes for clone $clone&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;29&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; git fetch origin 2&amp;gt;&amp;gt; $PULL_LOG&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;30&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; for branch in $(git branch -l | sed &#39;s/\s\|\*//g&#39;); do&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;31&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; echo &quot;# Merging branch $clone/$branch&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;32&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; echo &quot;Merging branch $branch&quot; &amp;gt;&amp;gt; $PULL_LOG&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;33&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; git checkout $branch 2&amp;gt; /dev/null&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;34&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; git merge origin/$branch &amp;gt;&amp;gt; $PULL_LOG&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;35&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; echo | awk &#39;{print count / total * 100}&#39; count=$clone_counter total=$BRANCH_COUNT&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;36&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; let clone_counter=clone_counter+1&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;37&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; done&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;38&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; cd ..&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;39&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; echo &amp;gt;&amp;gt; $PULL_LOG&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;40&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; &amp;nbsp; &amp;nbsp; done&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;41&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; }&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;42&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;43&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; # Do it&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;44&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; pull_clones | zenity --progress --title=&#39;Pulling development clones&#39; --width=512&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;45&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; zenity --text-info --filename=$PULL_LOG --title=&quot;Pull log&quot; --width=500 --height=450&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;46&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;47&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; #Clean up&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;48&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; rm $PULL_LOG&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;49&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: red; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;50&lt;/span&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt; popd &amp;gt; /dev/null&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/4073634363884948527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/4073634363884948527'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2012/06/bash-script-for-pullingfetching.html' title='Bash script for pulling/fetching multiple git clones'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-9007190010059154228</id><published>2012-06-06T10:47:00.003-04:00</published><updated>2012-06-06T10:47:55.013-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="mock"/><category scheme="http://www.blogger.com/atom/ns#" term="patch"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="test"/><category scheme="http://www.blogger.com/atom/ns#" term="unittest"/><title type='text'>Patching tip using mocks in python unit tests</title><content type='html'>I use the &lt;a href=&quot;http://www.voidspace.org.uk/python/mock/&quot; target=&quot;_blank&quot;&gt;mock&lt;/a&gt; library by Michael Foord in my python unit tests and one problem always plagued me. &amp;nbsp;Here&#39;s the problem and the solution.&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Sometimes when I import a package/module in my code I use this pattern (let&#39;s call it pattern &lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;A&lt;/span&gt;&lt;/b&gt;):&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&quot;&quot;&quot;&lt;b&gt;file_module_pattern_a&lt;/b&gt;.py&quot;&quot;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;import &lt;b&gt;os&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;def get_files(path):&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Return list of files&quot;&quot;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; return&amp;nbsp;&lt;b&gt;os.listdir&lt;/b&gt;(path)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;Other times, I use this pattern (let&#39;s call it pattern &lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;B&lt;/span&gt;&lt;/b&gt;):&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&quot;&quot;&quot;&lt;b&gt;file_module_pattern_b&lt;/b&gt;.py&quot;&quot;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;from &lt;b&gt;os&lt;/b&gt; import &lt;b&gt;listdir&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;def get_files(path):&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Return list of files&quot;&quot;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; return&amp;nbsp;&lt;b&gt;listdir&lt;/b&gt;(path_variable)&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Note the differente. &amp;nbsp;In pattern &lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;A&lt;/span&gt;&lt;/b&gt;, I import the whole &lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;os&lt;/b&gt;&lt;/span&gt; package, while in pattern &lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;B&lt;/span&gt;&lt;/b&gt;, I only import the &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;listdir&lt;/span&gt;&lt;/b&gt; function. &amp;nbsp;Now in my unit tests, here&#39;s what I use for pattern &lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;A&lt;/span&gt;&lt;/b&gt;:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&quot;&quot;&quot;Unit tests for module file_module_pattern_a&quot;&quot;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;div&gt;
from file_module_pattern_a import get_files&lt;/div&gt;
&lt;div&gt;
from unittest import TestCase&lt;/div&gt;
&lt;div&gt;
from mock import patch, sentinel&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;class StandloneTests(TestCase):&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Test the standalone functions&quot;&quot;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; @patch(&#39;&lt;b&gt;os.listdir&lt;/b&gt;&#39;)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; def test_get_files(self, mock_listdir):&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Test the get_files function&quot;&quot;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; test_result = get_files(sentinel.PATH)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mock_listdir.assert_called_once_with(sentinel.PATH)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.assertEqual(test_result, mock_listdir.return_value)&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This works great. &amp;nbsp;The only problem is... if I use pattern &lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;B&lt;/span&gt;&lt;/b&gt; with this unit test, the &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;mock_listdir&lt;/span&gt;&lt;/b&gt; never gets called. &amp;nbsp;The unit test tries to use the REAL &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;os.listdir&lt;/span&gt;&lt;/b&gt; function.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Here&#39;s the issue at hand. &amp;nbsp;When I use pattern &lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;B&lt;/span&gt;&lt;/b&gt;, I&#39;m actually adding the function to my module, not the global scope. &amp;nbsp;As a result, the patch directive needs to reference my module, not &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;os&lt;/span&gt;&lt;/b&gt;. &amp;nbsp;Here&#39;s the correct unit test patch syntax:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&quot;&quot;&quot;Unit tests for module file_module_pattern_b&quot;&quot;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;div&gt;
from file_module_pattern_b import get_files&lt;/div&gt;
&lt;div&gt;
from unittest import TestCase&lt;/div&gt;
&lt;div&gt;
from mock import patch, sentinel&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;class StandloneTests(TestCase):&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Test the standalone functions&quot;&quot;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; @patch(&#39;&lt;b&gt;file_module_pattern_b.listdir&lt;/b&gt;&#39;)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; def test_get_files(self, mock_listdir):&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Test the get_files function&quot;&quot;&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; test_result = get_files(sentinel.PATH)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mock_listdir.assert_called_once_with(sentinel.PATH)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.assertEqual(test_result, mock_listdir.return_value)&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/9007190010059154228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/9007190010059154228'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2012/06/patching-tip-using-mocks-in-python-unit.html' title='Patching tip using mocks in python unit tests'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-3338136546673982767</id><published>2012-06-04T11:43:00.000-04:00</published><updated>2012-06-04T11:47:15.719-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="alfred"/><category scheme="http://www.blogger.com/atom/ns#" term="fuse"/><category scheme="http://www.blogger.com/atom/ns#" term="mac"/><category scheme="http://www.blogger.com/atom/ns#" term="osx"/><category scheme="http://www.blogger.com/atom/ns#" term="sshfs"/><title type='text'>Using SSHFS from OSX</title><content type='html'>SSHFS is a FUSE (Filesystem in Userspace) plugin that allows you to mount a drive/filesystem on your systems via SSH. &amp;nbsp;This is a great way to transfer files securely over the public Internet. &amp;nbsp;Best of all, it&#39;s free! &lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
OSX supports FUSE through a program called OSXFUSE (or Fuse for OSX). &amp;nbsp;You can download it at:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;a href=&quot;http://osxfuse.github.com/&quot;&gt;http://osxfuse.github.com/&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Note, you&#39;ll have to download the plugins for OSXFUSE separately. &amp;nbsp;The two most popular are: &amp;nbsp;SSHFS and NTFS-3G (a plugin that allows you to mount NFTS volumes in read/write mode... which I will not be covering in this post).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Computers hosting sshfs directories don&#39;t need to have any special software installed on them. &amp;nbsp;They simply need to be running sshd (the secure shell daemon) and not have file transfers disabled. &amp;nbsp;Usually, sshd is configured by default to have file transfers enabled.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
One thing that often confuses people coming from the Mac world is that SSHFS has no GUI. &amp;nbsp;So how do you mount remote drives? &amp;nbsp;Well, you&#39;d normally do it from a terminal prompt.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In this blog entry, I will go over three ways to mount sshfs drives/filesystems using SSHFS:&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;Using terminal.app and some bash commands&lt;/li&gt;
&lt;li&gt;Using Automator&lt;/li&gt;
&lt;li&gt;By creating an Alfred.app extension&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;

Get the software&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
Before we begin, first make sure you have the OSXFUSE software installed. &amp;nbsp;Download it from the link listed above. &amp;nbsp;You&#39;ll know you have it properly installed when you see it in your System Preferences:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj12jj0lvUAR3Q4gbF98CYllNxNjE-CRJSSMqqS07XGngWjS4PCeuksD0yFomjM-YzJIqtZk0qLpYlfomQXCfb5Vfp6EToyH6jRwcmmSUQk_SAeWxBhyn8mKeZe437ZtZOMQdO-VvR4C_rv/s1600/System+Preferences.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;276&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj12jj0lvUAR3Q4gbF98CYllNxNjE-CRJSSMqqS07XGngWjS4PCeuksD0yFomjM-YzJIqtZk0qLpYlfomQXCfb5Vfp6EToyH6jRwcmmSUQk_SAeWxBhyn8mKeZe437ZtZOMQdO-VvR4C_rv/s320/System+Preferences.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
You&#39;ll also want to ensure that you&#39;ve installed the SSHFS plugin from the same site. &amp;nbsp;To verify that you&#39;ve installed it correctly, you&#39;ll need to run &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;sshfs -h&lt;/span&gt;&lt;/b&gt; from a terminal window:&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWR-Uppd7FDEfeaV5qo0hFOSEhQTpG9rQ5iEFGtXnKPFgwMuNDgQR2D-u3r-g1LHBzZ0XW-OvWvxYPWZOJhGRn7FugBwV5lTS20HzhQX5ZYhjoq6fD5XmlyZvqMq9goAqxmhzqzz4naGM-/s1600/sshfs+-h.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWR-Uppd7FDEfeaV5qo0hFOSEhQTpG9rQ5iEFGtXnKPFgwMuNDgQR2D-u3r-g1LHBzZ0XW-OvWvxYPWZOJhGRn7FugBwV5lTS20HzhQX5ZYhjoq6fD5XmlyZvqMq9goAqxmhzqzz4naGM-/s320/sshfs+-h.png&quot; width=&quot;217&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
If you&#39;ve got these two items installed, you&#39;re ready to go!&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;

First way: From the bash prompt&lt;/h3&gt;
&lt;div&gt;
This method is the most traditional way to mount a sshfs filesystem... and actually the other two methods will be invoking the same commands...we&#39;ll just be hiding them with the graphical interface.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
First start a terminal window and create a directory to house the filesystem. &amp;nbsp;I always put my filesystems in the &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;/Volumes&lt;/span&gt;&lt;/b&gt; directory. &amp;nbsp;You aren&#39;t required to put your directory there. &amp;nbsp;You can put it anywhere you&#39;d like. &amp;nbsp;I just do so out of convention. &amp;nbsp;Here&#39;s the command to do so:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@l00-1nsv01 $ &lt;b&gt;mkdir /Volumes/ssh_fs_mount&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I named my mount &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;ssh_fs_mount&lt;/span&gt;&lt;/b&gt;. &amp;nbsp;You can name yours anything you&#39;d like.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjH5XQFukgxhPBpgJZ9hQXd9JhGkt51aADvdJeoDsD785O2NYKc2Q6dSMHoQ73_2qRV9oSzomdWOCxR0g4uRiWlZrHqYha2uZ1VVCJzcg6Xt_vIKqrb9q5R7zwikm0q3-1Ck1IhhG9bdg-/s1600/mkdir.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;246&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjH5XQFukgxhPBpgJZ9hQXd9JhGkt51aADvdJeoDsD785O2NYKc2Q6dSMHoQ73_2qRV9oSzomdWOCxR0g4uRiWlZrHqYha2uZ1VVCJzcg6Xt_vIKqrb9q5R7zwikm0q3-1Ck1IhhG9bdg-/s320/mkdir.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Then you need to run the &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;sshfs&lt;/span&gt;&lt;/b&gt; command to mount the remote computer&#39;s directory to your hosting directory. The command takes the following format:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;sshfs username@hostname:/path/to/directory /local/directory&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
...where &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;username&lt;/span&gt;&lt;/b&gt; is your username on the remote computer, &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;hostname&lt;/span&gt;&lt;/b&gt; is the name of the remote computer contains the directory that you&#39;d like to mount, &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;/path/to/directory&lt;/span&gt;&lt;/b&gt; is the full path to the directory on the remote computer that you&#39;d like to mount and &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;/local/directory&lt;/span&gt;&lt;/b&gt; is the directory on your local computer that you&#39;d like to house the mount on. &amp;nbsp;Maybe an example will make it more clear.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I have a Linux computer that I do a lot of development on. &amp;nbsp;It&#39;s called &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;ubuntu64.local.&lt;/span&gt;&lt;/b&gt; &amp;nbsp;My username on that computer it &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve&lt;/span&gt;&lt;/b&gt; and my development folder on that computer is at &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;/home/steve/dev&lt;/span&gt;&lt;/b&gt;. &amp;nbsp;Here&#39;s the sshfs command that I would issue to mount my development folder from the Linux computer into the &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;/Volumes/ssh_fs_mount&lt;/span&gt;&lt;/b&gt; folder on my Mac&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;sshfs steve@ubuntu64.local:/home/steve/dev /Volumes/ssh_fs_mount&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Let&#39;s try it real quick:&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipjAC8axzcDxp28SZGc_v__7kKwN0ruHaACksbv9SSP5IX82CCqPT1XypqyRmVH1NCozwUMSCkB1VCoH6JvbFvC9dPyQPJtm7e3JOVb4tq2-WlbYx91HmTM_CoKyBb_lq9ofTG8GJWH9d-/s1600/terminal1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;246&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipjAC8axzcDxp28SZGc_v__7kKwN0ruHaACksbv9SSP5IX82CCqPT1XypqyRmVH1NCozwUMSCkB1VCoH6JvbFvC9dPyQPJtm7e3JOVb4tq2-WlbYx91HmTM_CoKyBb_lq9ofTG8GJWH9d-/s320/terminal1.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
A couple of items to note... &amp;nbsp;First, I&#39;m prompted for a password. &amp;nbsp;This is prompting me for my password on the &lt;b&gt;remote computer&lt;/b&gt; (ubuntu64.local in this instance). &amp;nbsp;It&#39;s &lt;b&gt;not&lt;/b&gt; prompting me for my Mac password. &amp;nbsp;This is the remote computer verifying that I&#39;m indeed steve@ubuntu64.local and not some&amp;nbsp;other&amp;nbsp;impostor. &amp;nbsp; &amp;nbsp;If I have key-based authentication working between my Mac account and my Linux account, I would not be prompted for the password. &amp;nbsp;I normally do have key-based authentication between these two accounts, but I turned it off for this demonstration. &amp;nbsp;If you&#39;re not using key-based authentication when ssh&#39;ing between computers... you should. &amp;nbsp;In fact, the other two methods in this blog entry (using Automator and the Alfred&amp;nbsp;extension) assume you are using key-based authentication and aren&#39;t prompted for a password. You can find out more about setting-up key-based authentication at any of these links:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;a href=&quot;https://www.google.com/#sclient=psy-ab&amp;amp;hl=en&amp;amp;q=ssh+key-based+authentication&amp;amp;oq=ssh+key-based+authentication&amp;amp;aq=f&amp;amp;aqi=g1g-K3&amp;amp;aql=&amp;amp;gs_l=hp.3..0j0i30l3.1071.5243.0.5877.30.29.1.0.0.0.222.3587.10j17j2.29.0...0.0.GCevakOUaRQ&amp;amp;pbx=1&amp;amp;bav=on.2,or.r_gc.r_pw.,cf.osb&amp;amp;fp=89c2cc531d5730ec&amp;amp;biw=1277&amp;amp;bih=1039&quot; target=&quot;_blank&quot;&gt;Google Search&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Second, there&#39;s no other output from the command. &amp;nbsp;No output means that sshfs was able to successfully complete the mount. &amp;nbsp;If there had been a problem, sshfs would have complained with error messages. &amp;nbsp;Once the mount is completed, the drive should appear on the desktop:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHEk_1YJzHZLvDkJCkL2Hvy6iZEdbsB9RM2c6cohhXg9Rh-idzqGCzom7iDBk-bvai4fgMWP1qk0T4a7q0sANLyPFX_gjExtUXzRgEHRi5-hgYoO9iwn7823zoL8_LEW_flMN5oQMn_sLl/s1600/drive+on+desktop.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHEk_1YJzHZLvDkJCkL2Hvy6iZEdbsB9RM2c6cohhXg9Rh-idzqGCzom7iDBk-bvai4fgMWP1qk0T4a7q0sANLyPFX_gjExtUXzRgEHRi5-hgYoO9iwn7823zoL8_LEW_flMN5oQMn_sLl/s1600/drive+on+desktop.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
It should behave like a normal Mac drive. &amp;nbsp;You can get info on it. &amp;nbsp;You can browse it in Finder. &amp;nbsp;You can even add/edit/remote files (assuming your account on the remote computer has the appropriate&amp;nbsp;privileges).&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiebVh8NgjS0wWuDZ-b8oRJAbWpmqIgl-LrA2PhmzPjKjbGmb4J1LYc2jRlbgBtkhnlrTkw7kgOYwKv_uJhif4-D7xgcuQ7tP0BeFE2hWeNJMtP_dQbsgAtefHuaXNl8QPWLWuJ7nF_kR_T/s1600/browse+in+finder.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;199&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiebVh8NgjS0wWuDZ-b8oRJAbWpmqIgl-LrA2PhmzPjKjbGmb4J1LYc2jRlbgBtkhnlrTkw7kgOYwKv_uJhif4-D7xgcuQ7tP0BeFE2hWeNJMtP_dQbsgAtefHuaXNl8QPWLWuJ7nF_kR_T/s320/browse+in+finder.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
When you&#39;re done and want to unmount the drive, simply right-click on it and select &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Eject&lt;/span&gt;&lt;/b&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXcvgk1vhiiahP4klOgVC44zXg3lmHMYpf1DXbQS5lvXt4qL5RmadEOZlfEw4BVq8KlCDcCzaVA_N3UbR93HgyP-lJ6jE-m8Tp6ektwR_sah5yLJExCl3_cs45l4mAaw8Yr4S92cHI_obm/s1600/eject.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXcvgk1vhiiahP4klOgVC44zXg3lmHMYpf1DXbQS5lvXt4qL5RmadEOZlfEw4BVq8KlCDcCzaVA_N3UbR93HgyP-lJ6jE-m8Tp6ektwR_sah5yLJExCl3_cs45l4mAaw8Yr4S92cHI_obm/s320/eject.png&quot; width=&quot;317&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Note, when the SSHSFS volume has been ejected, OSX automatically deletes the &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;/Volumes/ssh_fs_mount&lt;/span&gt;&lt;/b&gt; directory. &amp;nbsp;If you put your mounting directories in &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;/Volumes&lt;/span&gt;&lt;/b&gt;, you&#39;ll always have to recreate them &amp;nbsp;after ejecting.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;

Second Way: Create an Automator task&lt;/h3&gt;
&lt;div&gt;
Using Automator, you can create a workflow to automate the steps you did in the first method. &amp;nbsp;After all, that&#39;s what Automator is for.. automating repetitive things.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
First, start Automator and create a new &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Application&lt;/span&gt;&lt;/b&gt; workflow:&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrV0R3RY3zqni_gqBySqwKCBW-fOKPkLRuqQkYS0JXXgXsULk-nNBOXGt9YT6TJHarSmIJK6UWYZ7P95MGBNC6oIndzgcio7axY00wE6opPJyQ3_3C4CfftPR_Bu1277eoufGGFsRg1lMt/s1600/Automator+New+Workflow.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;274&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrV0R3RY3zqni_gqBySqwKCBW-fOKPkLRuqQkYS0JXXgXsULk-nNBOXGt9YT6TJHarSmIJK6UWYZ7P95MGBNC6oIndzgcio7axY00wE6opPJyQ3_3C4CfftPR_Bu1277eoufGGFsRg1lMt/s320/Automator+New+Workflow.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Next, in the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Text&lt;/span&gt;&lt;/b&gt; Library, drag the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Ask For Text&lt;/span&gt;&lt;/b&gt; action to the workflow.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZLIzqQPzMY1veePRXCEkcNNPU4Rd1z7eA6rJFQrvMifjLfPAi8mOAxx6rho2hJIfubvqyXFIWvDijH1zkDiYhgiREW__tABDprlpk5JsH6FTHPJuQ7wbJy9_YraLNWMwTc7bNu5sZNE1n/s1600/Ask+For+Text.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;274&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZLIzqQPzMY1veePRXCEkcNNPU4Rd1z7eA6rJFQrvMifjLfPAi8mOAxx6rho2hJIfubvqyXFIWvDijH1zkDiYhgiREW__tABDprlpk5JsH6FTHPJuQ7wbJy9_YraLNWMwTc7bNu5sZNE1n/s320/Ask+For+Text.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Check the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Ignore this action&#39;s input&lt;/span&gt;&lt;/b&gt;&amp;nbsp;and &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Require an answer&lt;/span&gt;&lt;/b&gt; checkboxes. &amp;nbsp;Enter &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Enter a remote sshfs url and click OK&lt;/span&gt;&lt;/b&gt; in the question textbox.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZO-C5XQbjW6Z38OfbRD90jAPi2dWMGSqTNqR_1xt6jizl9sHPxXwXr_t5MT8qH9w9yrwR1ZZReTA7xQswDtMwPBlNqqTJpQUtgyzQPcPvu-WEXWCWSZtcbTtU7-cKVzPO9YV0pm4BhJ-s/s1600/Ask+for+Text+2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;274&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZO-C5XQbjW6Z38OfbRD90jAPi2dWMGSqTNqR_1xt6jizl9sHPxXwXr_t5MT8qH9w9yrwR1ZZReTA7xQswDtMwPBlNqqTJpQUtgyzQPcPvu-WEXWCWSZtcbTtU7-cKVzPO9YV0pm4BhJ-s/s320/Ask+for+Text+2.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Now, from the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Utilities&lt;/span&gt;&lt;/b&gt; library, drag the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Run Shell Script&lt;/span&gt;&lt;/b&gt; action to the workflow and drop it below the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Ask for Text&lt;/span&gt;&lt;/b&gt; action.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhO0h5oIJrsyipOEyeDV21eDScSCT1XUPfHxIN1BnQ4okP6sr7fnE1rKjY2hMlFk4vWvXMgvILVkSoswArVrv80e-pG9CQFPSJ5fYH6vKIlAYryd2um1LQ1DVNfgiCGn2-MFEw0SCNJ2tRy/s1600/Run+Shell+Script.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;274&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhO0h5oIJrsyipOEyeDV21eDScSCT1XUPfHxIN1BnQ4okP6sr7fnE1rKjY2hMlFk4vWvXMgvILVkSoswArVrv80e-pG9CQFPSJ5fYH6vKIlAYryd2um1LQ1DVNfgiCGn2-MFEw0SCNJ2tRy/s320/Run+Shell+Script.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Change the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Pass input&lt;/span&gt;&lt;/b&gt; pulldown from &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;to stdin&lt;/span&gt;&lt;/b&gt; to &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;as arguments&lt;/span&gt;&lt;/b&gt;. &amp;nbsp;Then past the following text into the textarea:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;volume_name=/Volumes/sshfs_volume_$$&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;mkdir $volume_name&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;/usr/local/bin/sshfs $1 $volume_name&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;if [ &quot;$?&quot; == &quot;0&quot; ]; then&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;open $volume_name&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;else&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;echo &quot;Unable to mount sshfs volume.&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;rmdir $volume_name&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;fi&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
Save it to your desktop as &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;SSHFS Workflow&lt;/span&gt;&lt;/b&gt;. &amp;nbsp;It should now look like this:&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGgjQmQyERgKhCYyhqveWXXTTqJYS9si7pXqyi4cfs9iyYbOHdk7nA40g0YqFfElCaEtOsRX2glgBBajv_sxHNV430dxGNpwe2LPCihwM2OtvKzJ-WGFU6Fr_N67LVfMaB4YMFcPqAEf1Y/s1600/Final+Workflow.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;274&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGgjQmQyERgKhCYyhqveWXXTTqJYS9si7pXqyi4cfs9iyYbOHdk7nA40g0YqFfElCaEtOsRX2glgBBajv_sxHNV430dxGNpwe2LPCihwM2OtvKzJ-WGFU6Fr_N67LVfMaB4YMFcPqAEf1Y/s320/Final+Workflow.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Now, if you run it from your desktop, it will prompt you for a sshfs url. &amp;nbsp;The format is the same from the bash method. &amp;nbsp;I&#39;ll reuse my example:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;steve@ubuntu64.local:/home/steve/dev&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Again, like I mentioned before, this method assumes that you&#39;ve already set up key-based authentication between your Mac account and your remote account.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7Vyn5uyPU6b-DHpWxzNiIIHuVOaU9meqjV-EVM2QO8ibxJN0dogjbG7zjmqQSQ4pHuoP_Jxgb27EvsbJVTZktzulHaTDA4o4pAKz5Pb3J52OvXtLAdNqqTk9HM05kEBKUIsi1CzKr0ylc/s1600/workflow+running.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;158&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7Vyn5uyPU6b-DHpWxzNiIIHuVOaU9meqjV-EVM2QO8ibxJN0dogjbG7zjmqQSQ4pHuoP_Jxgb27EvsbJVTZktzulHaTDA4o4pAKz5Pb3J52OvXtLAdNqqTk9HM05kEBKUIsi1CzKr0ylc/s320/workflow+running.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
If all goes well, the automator will automatically open the mounted volume. &amp;nbsp;Just like the first method, when you&#39;re done, you simply right-click the volume and eject it via Finder.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;

Third Way: Create an Alfred Extension&lt;/h3&gt;
&lt;div&gt;
Now if you&#39;re running Alfred, you&#39;re probably thinking, &quot;I can just run the automator task from Alfred and be done with it.&quot; &amp;nbsp;Yes. &amp;nbsp;You could. &amp;nbsp;But you can also create an extension. &amp;nbsp;That way you can enter the sshfs url directly into the Alfred window and save yourself one last data-entry step.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
To create the extension go to the&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Extensions&lt;/span&gt;&lt;/b&gt;&amp;nbsp;tab of the Alfred preferences window. &amp;nbsp;Click the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;+&lt;/span&gt;&lt;/b&gt; and select &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Shell Script&lt;/span&gt;&lt;/b&gt;.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmKg1pvqdhdCr2W2ao_OITtk4H9qtwDqE56o9ejBms5__XXWzkwWpC3olLtngFSRRt-k3QkD28m7GZ5hLen706AhQ0Gh4bjz6sqbfSr2KC0R4mWWsGsf1C_toS5AwsaFKDWSJTD7wIySmm/s1600/Alfred+Prefs.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;251&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmKg1pvqdhdCr2W2ao_OITtk4H9qtwDqE56o9ejBms5__XXWzkwWpC3olLtngFSRRt-k3QkD28m7GZ5hLen706AhQ0Gh4bjz6sqbfSr2KC0R4mWWsGsf1C_toS5AwsaFKDWSJTD7wIySmm/s320/Alfred+Prefs.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
In the &lt;b&gt;Extension Name&lt;/b&gt; field, enter &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;SSHFS&lt;/span&gt;&lt;/b&gt; and click &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Create&lt;/span&gt;&lt;/b&gt;.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicJWRTVnoAuHl244U3lXND7yNCh_dk_6lYK3sNhdUppfgQ6x0yKiK6xu-q3mJDr0smLH5hN7RjlDrSVKu-Ibzo72Ogoq11h7M2QTq0cOGW3pUZOg2uaqgeLUUTvQwoPqQ0N5ipMhPBnmy8/s1600/Extension+name.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;251&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicJWRTVnoAuHl244U3lXND7yNCh_dk_6lYK3sNhdUppfgQ6x0yKiK6xu-q3mJDr0smLH5hN7RjlDrSVKu-Ibzo72Ogoq11h7M2QTq0cOGW3pUZOg2uaqgeLUUTvQwoPqQ0N5ipMhPBnmy8/s320/Extension+name.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
In the &lt;b&gt;Title&lt;/b&gt; field, enter &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;SSHFS Mounter&lt;/span&gt;&lt;/b&gt;. &amp;nbsp;In the &lt;b&gt;Description&lt;/b&gt; field, enter &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Mount a sshfs volume&lt;/span&gt;&lt;/b&gt;. &amp;nbsp;Make sure the &lt;b&gt;Keyword&lt;/b&gt; checkbox is checked and the enter &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;sshfs&lt;/span&gt;&lt;/b&gt; in the textbox next to it. &amp;nbsp;Make sure the &lt;b&gt;Silent&lt;/b&gt; checkbox is checked. &amp;nbsp;Finally in the &lt;b&gt;Command&lt;/b&gt; field, enter the following text:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;volume_name=/Volumes/sshfs_volume_$$&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;mkdir $volume_name&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;/usr/local/bin/sshfs {query} $volume_name&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;if [ &quot;$?&quot; == &quot;0&quot; ]; then&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;open $volume_name&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;else&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;echo &quot;Unable to mount sshfs volume.&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;rmdir $volume_name&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;fi&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
If should look like this:&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiA_7Xv0BZE5pCyN_ygVzeMsWgHMUp423GrGHLWv8VDOrosmX5Rnd2eLt1-bjn9jtXzwBOMX2NIW8iLJ6LvUlCMDScUHyz9jYEvg8Ss5SBB2rHtsSnPXgwX83UvSYKsjMaIBJ8BaujzIsr/s1600/extension+settings.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;251&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiA_7Xv0BZE5pCyN_ygVzeMsWgHMUp423GrGHLWv8VDOrosmX5Rnd2eLt1-bjn9jtXzwBOMX2NIW8iLJ6LvUlCMDScUHyz9jYEvg8Ss5SBB2rHtsSnPXgwX83UvSYKsjMaIBJ8BaujzIsr/s320/extension+settings.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
If you have Growl installed on your Mac, click the &lt;b&gt;Advanced&lt;/b&gt; button and check the &lt;b&gt;Display script output in Growl&lt;/b&gt; checkbox.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvRvX7D2mbIVO1KyQMZDsRK08NRqdAC3rBJ_X60xkp_Mivd_9pyLB8CXTcelqLITjs_HcSp_rdlYMHjwN7hjkA7Q0efnEoPYyMKpsU8KpHJmmJ8KekMrsEMwo7FpvijKf-aW3XntMTgVVj/s1600/turn+on+growl.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;251&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvRvX7D2mbIVO1KyQMZDsRK08NRqdAC3rBJ_X60xkp_Mivd_9pyLB8CXTcelqLITjs_HcSp_rdlYMHjwN7hjkA7Q0efnEoPYyMKpsU8KpHJmmJ8KekMrsEMwo7FpvijKf-aW3XntMTgVVj/s320/turn+on+growl.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Save the extension and close the preferences window. &amp;nbsp;Now from the the Alfred prompt, you can enter &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;sshfs your_sshfs_url&lt;/span&gt;&lt;/b&gt; and hit enter, where &lt;b&gt;your_sshfs_url&lt;/b&gt; is an actual sshfs url. &amp;nbsp;Here&#39;s me mounting my ubuntu64.local system&#39;s tmp directory:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAUgkkLV5Ab_T5v2jFGgkXfdzZW7JH_tOdVJN81uvRgebLuOcXUVp6K5pfUmuWjAcWFehDmVIvs321HJ58IY38rAyCUEeZhUojt0zDzn2BLCmTWUhtaq9WImoUY0Yp9rP3OQkflrt-hTTL/s1600/alfred+sshfs.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;133&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAUgkkLV5Ab_T5v2jFGgkXfdzZW7JH_tOdVJN81uvRgebLuOcXUVp6K5pfUmuWjAcWFehDmVIvs321HJ58IY38rAyCUEeZhUojt0zDzn2BLCmTWUhtaq9WImoUY0Yp9rP3OQkflrt-hTTL/s320/alfred+sshfs.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Just like the Automator method, the Alfred method presumes you are using key-based authentication between your Mac account and the remote computer&#39;s account. &amp;nbsp;It should automatically open the folder you mounted. &amp;nbsp;When you&#39;re done, simply right-click on the volume and eject it.&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/3338136546673982767'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/3338136546673982767'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2012/06/using-sshfs-from-osx.html' title='Using SSHFS from OSX'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj12jj0lvUAR3Q4gbF98CYllNxNjE-CRJSSMqqS07XGngWjS4PCeuksD0yFomjM-YzJIqtZk0qLpYlfomQXCfb5Vfp6EToyH6jRwcmmSUQk_SAeWxBhyn8mKeZe437ZtZOMQdO-VvR4C_rv/s72-c/System+Preferences.png" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-1309254608055043775</id><published>2012-05-30T10:53:00.000-04:00</published><updated>2012-05-30T10:53:06.474-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="deadsnakes"/><category scheme="http://www.blogger.com/atom/ns#" term="dependency"/><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="package"/><category scheme="http://www.blogger.com/atom/ns#" term="pip"/><category scheme="http://www.blogger.com/atom/ns#" term="ppa"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="ubuntu"/><category scheme="http://www.blogger.com/atom/ns#" term="virtualenv"/><title type='text'>Run multiple python versions on your system</title><content type='html'>I&#39;m a software development consultant. &amp;nbsp;I write python (as well as other languages) code for many clients and I don&#39;t get to dictate what their environment looks like. &amp;nbsp;I&#39;ve got clients running python as old as 2.4 while others are on the bleeding edge. &amp;nbsp;Additionally, each client may have their own packages installed as well as differing lists of third party packages.&lt;br /&gt;
&lt;br /&gt;
This post is a description of how I went about getting multiple versions of python installed in my ubuntu development machine and how I go about managing different package sets for different clients.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Get multiple pythons installed&lt;/h3&gt;
Ubuntu typically only supports one python 2.x version and one 3.x version at a time. &amp;nbsp;There&#39;s a popular ppa (personal package archive) called deadsnakes that contains older versions of python. &amp;nbsp;You can find it:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;a href=&quot;https://launchpad.net/~fkrull/+archive/deadsnakes&quot;&gt;https://launchpad.net/~fkrull/+archive/deadsnakes&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
To install it (per the instructions in the link above), you do the following:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;steve@ubuntu64 ~ $ &lt;b&gt;sudo add-apt-repository&amp;nbsp;ppa:fkrull/deadsnakes&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Then you need to update your cache:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;steve@ubuntu64 ~ $ &lt;b&gt;sudo apt-get update&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Finally, simply install the other versions (I&#39;m running on ubuntu 12.04 LTS, so I have python 2.7 already):&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;steve@ubuntu64 ~ $ &lt;b&gt;sudo apt-get install python2.4 python2.5 python2.6&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
If you&#39;re following along, we now have python versions 2.4 through 2.7 installed the computer. &amp;nbsp;If you run &#39;python&#39;, you&#39;ll see the default version is still 2.7.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;steve@ubuntu64 ~ $ &lt;b&gt;python&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Python &lt;b&gt;2.7.3&lt;/b&gt; (default, Apr 20 2012, 22:39:59)&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;[GCC 4.6.3] on linux2&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Here&#39;s why: &amp;nbsp;Each python version is stored in &lt;b&gt;/usr/bin&lt;/b&gt; as &lt;b&gt;python2.X&lt;/b&gt; where X is the version. &amp;nbsp;There is a symbolic link named &lt;b&gt;python&lt;/b&gt;&amp;nbsp;that points to the version you want to be the default. &amp;nbsp;Instead of typing &lt;b&gt;python&lt;/b&gt; from the bash prompt, you could just as easily type &lt;b&gt;python2.5&lt;/b&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;steve@ubuntu64 ~ $ &lt;b&gt;ls -l /usr/bin/python*&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;lrwxrwxrwx 1 root root &amp;nbsp; &amp;nbsp; &amp;nbsp; 9 Apr 17 13:20 /usr/bin/python -&amp;gt; python2.7&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;lrwxrwxrwx 1 root root &amp;nbsp; &amp;nbsp; &amp;nbsp; 9 Apr 17 13:20 /usr/bin/python2 -&amp;gt; python2.7&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;-rwxr-xr-x 1 root root 1216520 May 21 12:13 /usr/bin/python2.4&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;-rwxr-xr-x 1 root root 1403624 May &amp;nbsp;3 00:17 /usr/bin/python2.5&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;-rwxr-xr-x 1 root root 2652056 May 12 08:43 /usr/bin/python2.6&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;-rwxr-xr-x 1 root root 2993560 Apr 20 19:37 /usr/bin/python2.7&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;steve@ubuntu64 ~ $ &lt;b&gt;python2.5&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Python &lt;b&gt;2.5.6&lt;/b&gt; (r256:88840, May &amp;nbsp;3 2012, 04:16:14)&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;[GCC 4.6.3] on linux2&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
This is a point of interest. &amp;nbsp;I would not mess with the symbolic link. &amp;nbsp;Ubuntu runs python for many internal maintenance scripts and those scripts are expecting the python version that shipped with ubuntu.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Use virtualenv to manage your python installations and package sets&lt;/h3&gt;
So now that you have multiple versions of python on your system, how to manage them? &amp;nbsp;How do you keep packages installed for one version separate from packages installed for another. &amp;nbsp;What if you want to run one version of django for client X and a different version for client Y?&lt;br /&gt;
&lt;br /&gt;
That&#39;s where virtualenv comes in. &amp;nbsp;If your a ruby programmer, this is analogous to rvm. &amp;nbsp;Virtualenv lets you manage the python versions and package installations separately for different projects or clients.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Installing virtualenv is simple&lt;/h3&gt;
As always, you&#39;re just a single apt-get command away from having virtualenv ready to go:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;steve@ubuntu64 ~ $ &lt;b&gt;sudo apt-get install python-virtualenv&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
That it. &amp;nbsp;Virtualenv is ready to go now.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Quick example&lt;/h3&gt;
Say your starting a new project for a client. &amp;nbsp;They are running python2.5 and want to use the mocks, nose and coverage packages for testing. &amp;nbsp;Here a walkthrough of how to use virtualenv to manage the project.&lt;br /&gt;
&lt;br /&gt;
First, let&#39;s create a directory for the project:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;steve@ubuntu64 ~ $ &lt;b&gt;mkdir -p ~/dev/project1&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;steve@ubuntu64 ~ $ &lt;b&gt;cd ~/dev/project1&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Next, run virtualenv to create the environment for the project:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;steve@ubuntu64 ~/dev/project1 $ &lt;b&gt;virtualenv -p /usr/bin/python2.5 .env&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Running virtualenv with interpreter /usr/bin/python2.5&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;New python executable in .env/bin/python2.5&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Also creating executable in .env/bin/python&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Installing distribute.............................................................................................................................................................................................done.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Installing pip...............done.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;steve@ubuntu64 ~/dev/project1 $&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
This command tells virtualenv to create a &lt;b&gt;.env&lt;/b&gt; directory and to place a copy of the &lt;b&gt;2.5&lt;/b&gt; version of python in it. &amp;nbsp;This copy of the 2.5 python is brand-spankin&#39; new. &amp;nbsp;It doesn&#39;t have any packages (beyond the standard library) installed. &amp;nbsp;You will need to install them yourself. &amp;nbsp;Any packages that you install in this instance of python will not be available to main python installation or other virtualenv instances.&lt;br /&gt;
&lt;br /&gt;
Before your can use this new copy, you need to activate it:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;steve@ubuntu64 ~/dev/project1 $ &lt;b&gt;source .env/bin/activate&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;(.env)steve@ubuntu64 ~/dev/project1 $&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The activate script manipulates your path environment variable, placing the new python instance first in your path. &amp;nbsp;This makes is so that when you run python, it will use the version from your instance:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;(.env)steve@ubuntu64 ~/dev/project1 $ &lt;b&gt;which python&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;/home/steve/dev/project1/.env/bin/python&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;(.env)steve@ubuntu64 ~/dev/project1 $ &lt;b&gt;python&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Python &lt;b&gt;2.5.6&lt;/b&gt; (r256:88840, May &amp;nbsp;3 2012, 04:16:14)&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;[GCC 4.6.3] on linux2&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Also, notice that your prompt starts with &lt;b&gt;(.env)&lt;/b&gt;. &amp;nbsp;This tells you that you&#39;re running with the virtualenv instance activated. &amp;nbsp;To install packages in your instance, use the &lt;b&gt;pip&lt;/b&gt; command:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;(.env)steve@ubuntu64 ~/dev/project1 $ &lt;b&gt;pip install mock nose coverage&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Downloading/unpacking mock&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; Downloading mock-0.8.0.tar.gz (749Kb): 749Kb downloaded&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; Running setup.py egg_info for package mock&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; warning: no files found matching &#39;*.png&#39; under directory &#39;docs&#39;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; warning: no files found matching &#39;*.css&#39; under directory &#39;docs&#39;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; warning: no files found matching &#39;*.html&#39; under directory &#39;docs&#39;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; warning: no files found matching &#39;*.js&#39; under directory &#39;docs&#39;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Downloading/unpacking nose&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; Downloading nose-1.1.2.tar.gz (729Kb): 729Kb downloaded&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; In the tar file /tmp/pip-dH_WYa-unpack/nose-1.1.2.tar.gz the member nose-1.1.2/doc/doc_tests/test_selector_plugin/support/tests/mymodule/my_function$py.class is invalid: &#39;filename None not found&#39;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; In the tar file /tmp/pip-dH_WYa-unpack/nose-1.1.2.tar.gz the member nose-1.1.2/doc/doc_tests/test_restricted_plugin_options/restricted_plugin_options.rst.py3.patch is invalid: &#39;filename None not found&#39;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; Running setup.py egg_info for package nose&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Downloading/unpacking coverage &amp;nbsp;Downloading coverage-3.5.2.tar.gz (115Kb): 115Kb downloaded&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; Running setup.py egg_info for package coverage&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; no previously-included directories found matching &#39;test&#39;Installing collected packages: mock, nose, coverage&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; Running setup.py install for mock&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; warning: no files found matching &#39;*.png&#39; under directory &#39;docs&#39;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; warning: no files found matching &#39;*.css&#39; under directory &#39;docs&#39;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; warning: no files found matching &#39;*.html&#39; under directory &#39;docs&#39;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; warning: no files found matching &#39;*.js&#39; under directory &#39;docs&#39;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; Running setup.py install for nose&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; Installing nosetests script to /home/steve/dev/project1/.env/bin&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; Installing nosetests-2.5 script to /home/steve/dev/project1/.env/bin&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; Running setup.py install for coverage&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; building &#39;coverage.tracer&#39; extension&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.5 -c coverage/tracer.c -o build/temp.linux-x86_64-2.5/coverage/tracer.o&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; coverage/tracer.c:3:20: fatal error: Python.h: No such file or directory&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; compilation terminated.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; **&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; ** Couldn&#39;t install with extension module, trying without it...&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; ** SystemExit: error: command &#39;gcc&#39; failed with exit status 1&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; **&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; no previously-included directories found matching &#39;test&#39;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; Installing coverage script to /home/steve/dev/project1/.env/bin&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Successfully installed mock nose coverage&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Cleaning up...&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;(.env)steve@ubuntu64 ~/dev/project1 $&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
To see that the packages have been installed, simply use them:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;(.env)steve@ubuntu64 ~/dev/project1 $ &lt;b&gt;python&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Python &lt;b&gt;2.5.6&lt;/b&gt; (r256:88840, May &amp;nbsp;3 2012, 04:16:14)&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;[GCC 4.6.3] on linux2&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;b&gt;import mock&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;b&gt;import nose&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;b&gt;import coverage&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
When you&#39;re done working on the project, deactivate it. &amp;nbsp;You can always come back later and activate it again.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;(.env)steve@ubuntu64 ~/dev/project1 $ &lt;b&gt;deactivate&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;steve@ubuntu64 ~/dev/project1 $&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Notice that when you deactivate the environment, your packages are no longer available:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;steve@ubuntu64 ~/dev/project1 $ &lt;b&gt;python&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Python &lt;b&gt;2.7.3&lt;/b&gt; (default, Apr 20 2012, 22:39:59)&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;[GCC 4.6.3] on linux2&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;b&gt;import mock&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Traceback (most recent call last):&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; File &quot;&amp;lt;stdin&amp;gt;&quot;, line 1, in &amp;lt;module&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;ImportError: No module named mock&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;b&gt;import nose&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Traceback (most recent call last):&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; File &quot;&amp;lt;stdin&amp;gt;&quot;, line 1, in &amp;lt;module&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;ImportError: No module named nose&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;b&gt;import coverage&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Traceback (most recent call last):&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; File &quot;&amp;lt;stdin&amp;gt;&quot;, line 1, in &amp;lt;module&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;ImportError: No module named coverage&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
You can create as many virtualenv environments as you like. &amp;nbsp;I create one for each project that I work on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Bonus material&lt;/h3&gt;
&lt;br /&gt;
To make life even easier, here&#39;s a couple additional things I do that you might find helpful!&lt;br /&gt;
&lt;br /&gt;
First, once you&#39;ve started to use virtualenv with some frequency, you start to get tired of downloading and installing the same packages over and over. &amp;nbsp;Pip has the ability to cache your downloaded packages for reuse. &amp;nbsp;To do that, you&#39;ll need to create a directory to store the download packages in:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;steve@ubuntu64 ~ $ &lt;b&gt;mkdir ~/.pip_download_cache&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Then you&#39;ll need to set a variable to inform pip of the new directory. &amp;nbsp;Add the following to your .bashrc file:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;export PIP_DOWNLOAD_CACHE=/home/steve/.pip_download_cache&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Now when you do a pip install, it will keep the downloaded files in the ~/.pip_download_cache directory. &amp;nbsp;The next time you do a pip install of the same package, it will just use the copy from the directory instead of downloading it again.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Second, it can be tedious to always have to type &#39;source .env/bin/activate&#39; every time you want to activate an environment. &amp;nbsp;Since I always put my virtual environments in a .env directory I can count on the command to activate always being the same. &amp;nbsp;So I create an alias for it. &amp;nbsp;I added the the following to my ~/.bash_aliases file:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;alias activate=&#39;source .env/bin/activate&#39;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Now once I &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;cd&lt;/span&gt;&lt;/b&gt; into the projects directory, I simply type &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;activate&lt;/span&gt;&lt;/b&gt; to activate my virtual environment.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/1309254608055043775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/1309254608055043775'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2012/05/run-multiple-python-versions-on-your.html' title='Run multiple python versions on your system'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-7629067542556667544</id><published>2012-05-25T10:05:00.002-04:00</published><updated>2012-05-25T20:41:25.568-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="encryption"/><category scheme="http://www.blogger.com/atom/ns#" term="security"/><category scheme="http://www.blogger.com/atom/ns#" term="vi"/><category scheme="http://www.blogger.com/atom/ns#" term="vim"/><title type='text'>File encryption with vim</title><content type='html'>You may not know it, but you can encrypt your files using vim... and it&#39;s pretty easy to do.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;

Turning encryption on for a file&lt;/h3&gt;
If you&#39;re editing a file, to encrypt it, simply enter &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;X&lt;/span&gt;&lt;/b&gt; at the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;:&lt;/span&gt;&lt;/b&gt; prompt.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXFY-au3fUXTL5iPzzjXbJns4Slw8B23PrGw4VWV8rq2TUdGAZX9Dnu0rO3Ky_aZvzQWwGcpwRpBTwLfUw65GoiBFuktg1RtM11qKhSGIXBPY3ETxoltR_A_IvkiqZYsYDudkf-bjwLTAo/s1600/x_prompt.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;246&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXFY-au3fUXTL5iPzzjXbJns4Slw8B23PrGw4VWV8rq2TUdGAZX9Dnu0rO3Ky_aZvzQWwGcpwRpBTwLfUw65GoiBFuktg1RtM11qKhSGIXBPY3ETxoltR_A_IvkiqZYsYDudkf-bjwLTAo/s320/x_prompt.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Vim will then prompt you for a key. &amp;nbsp;A key is the password for decrypting the file in the future. &amp;nbsp;You&#39;ll have to enter it twice to ensure you typed it correctly.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1eNt-0ouKyBFAZX7OtL8HA_jlnfz1v7Caj-0Bp9xZst545y_pbF-x3lpKqELI0tkjTM_-pzEetNTsVlBHd8hyphenhyphenS-a43iX1_qul2T0UTRAw3slNe2LWaB0-FFIzK7ZAxzwnIX8Px1FFZUxm/s1600/key_prompt.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;246&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1eNt-0ouKyBFAZX7OtL8HA_jlnfz1v7Caj-0Bp9xZst545y_pbF-x3lpKqELI0tkjTM_-pzEetNTsVlBHd8hyphenhyphenS-a43iX1_qul2T0UTRAw3slNe2LWaB0-FFIzK7ZAxzwnIX8Px1FFZUxm/s320/key_prompt.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Once you&#39;ve entered your key, the next time you save/write, the file should be encrypted, see the status text at the bottom to be sure.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_v3VoAy4-n1wrMh7dru5k67WMDnj5Wd6dr3k_ZYkDkxBDFfBqw7zZfhuPeVmerZjFrLuqKaFnppHzdoSeVW-538IY6Td80F_-sr8qaRcLHKgqLp7La_G59ImM4N87KOoT5IJF_5mrpNiX/s1600/crypted.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;236&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_v3VoAy4-n1wrMh7dru5k67WMDnj5Wd6dr3k_ZYkDkxBDFfBqw7zZfhuPeVmerZjFrLuqKaFnppHzdoSeVW-538IY6Td80F_-sr8qaRcLHKgqLp7La_G59ImM4N87KOoT5IJF_5mrpNiX/s320/crypted.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Once the file is encrypted, it will be unreadable to others.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKE5xLk-0PYfQCqckdGlm0WUKcW29t3dEhY0ZMbhkso1KG9ZqFjHPFE5YtJrmfNjEpFUDFIr3mLK6nqxrXEPYuiY6Q2oOcDlwYVrDWDTS2d6iP51iqqT2sVczmH5FmNw7k3yXTYWL3Futt/s1600/encrypted_file.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;246&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKE5xLk-0PYfQCqckdGlm0WUKcW29t3dEhY0ZMbhkso1KG9ZqFjHPFE5YtJrmfNjEpFUDFIr3mLK6nqxrXEPYuiY6Q2oOcDlwYVrDWDTS2d6iP51iqqT2sVczmH5FmNw7k3yXTYWL3Futt/s320/encrypted_file.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Vim auto-detects whether files are encrypted. &amp;nbsp;If you try to open an encrypted file, vim will prompt you for the key.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSeJjZKOFnmPftA_al3skB3Vcjomql1bPJNtLNARtmXNnRMbvXs2yajSiNLKhV1k5MQCP_nAjxeFYzHcGCWTzuf4-qEM5yH3mdeIFxkrBDkVy9eW1QXdgcZLrYRB8Up-7NwzNyUC1ihTBO/s1600/open_key_prompt.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;246&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSeJjZKOFnmPftA_al3skB3Vcjomql1bPJNtLNARtmXNnRMbvXs2yajSiNLKhV1k5MQCP_nAjxeFYzHcGCWTzuf4-qEM5yH3mdeIFxkrBDkVy9eW1QXdgcZLrYRB8Up-7NwzNyUC1ihTBO/s320/open_key_prompt.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Vim uses whatever you enter for the key to decrypt the file. &amp;nbsp;If you enter the correct things will look great. &amp;nbsp;If you enter an invalid key, vim will present you with garbage to edit.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4H37P8IQ7LPqE-mvqKwg8ZX_pnw4geLKTDTY0YAINHfPisb6zB6lRnM_NpN8cEwKmjqgrQqC_wL1jMISDiguS_rQjZNe_Tp414c9_rMtUPHNkKNIIVk36c5Cgk3OSHhpNx410Jrw0Pw1U/s1600/garbage.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;246&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4H37P8IQ7LPqE-mvqKwg8ZX_pnw4geLKTDTY0YAINHfPisb6zB6lRnM_NpN8cEwKmjqgrQqC_wL1jMISDiguS_rQjZNe_Tp414c9_rMtUPHNkKNIIVk36c5Cgk3OSHhpNx410Jrw0Pw1U/s320/garbage.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
The encryption will stay on for the file until you tell vim you&#39;d like to remove it.&lt;br /&gt;
&lt;br /&gt;
Be mindful of your key. &amp;nbsp;If you forget it, you will not be able to retrieve the contents of your file.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;

Turning off encryption for a file&lt;/h3&gt;
Turning encryption off is equally as easy. &amp;nbsp;Simply set the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;key&lt;/span&gt;&lt;/b&gt; setting to nothing. &amp;nbsp;With the command:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;:set key=&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOLqTX2fcTeFdtDEpQvlFh4FBtBWUwMZQBHt6oAu-8G9E1CJYGBX1pYJo-ll-EMHP1V89SsXBPjl7vzw-FO3684XZv6RC2NgDA7_aEpQniEH2B7qZZD38ilkjFlsy0FYplxNQRQew7kXSt/s1600/set_key_blank.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;246&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOLqTX2fcTeFdtDEpQvlFh4FBtBWUwMZQBHt6oAu-8G9E1CJYGBX1pYJo-ll-EMHP1V89SsXBPjl7vzw-FO3684XZv6RC2NgDA7_aEpQniEH2B7qZZD38ilkjFlsy0FYplxNQRQew7kXSt/s320/set_key_blank.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Be sure to write the file. &amp;nbsp;Note that it is no longer encrypted (status text)&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_HD028V8H_GmVX9a0opBdcGmyP6qbnNcBKgEpaW8NoU7YEuRZSWu2pzjN5Fy7KCEWW92PcL7ao8HYkzX888XrO7Za75Q2IXmQX1spZnVVvlDFNtiFeZO9ClwBuG7r7tmGG2Jm5GTi0Nyt/s1600/write_decrypted.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;246&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_HD028V8H_GmVX9a0opBdcGmyP6qbnNcBKgEpaW8NoU7YEuRZSWu2pzjN5Fy7KCEWW92PcL7ao8HYkzX888XrO7Za75Q2IXmQX1spZnVVvlDFNtiFeZO9ClwBuG7r7tmGG2Jm5GTi0Nyt/s320/write_decrypted.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3&gt;

Wait! &amp;nbsp;Before you go&lt;/h3&gt;
As of vim 7.3, vim uses one of two encryption methods: zip and blowfish. &amp;nbsp;Zip is the same encryption that PkZip uses and is somewhat weak (can be cracked). &amp;nbsp;Conversely, blowfish is more&amp;nbsp;contemporary&amp;nbsp;and is much harder to crack. &amp;nbsp;Zip, unfortunately, is the default encryption method in vim. &amp;nbsp;I would strongly suggest that you use blowfish when encrypting your files. &amp;nbsp;To do this is simple enough. &amp;nbsp;Simply enter the command:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;:set cm=blowfish&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
I put it in my .vimrc file so it&#39;s always set.</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/7629067542556667544'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/7629067542556667544'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2012/05/file-encryption-with-vim.html' title='File encryption with vim'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXFY-au3fUXTL5iPzzjXbJns4Slw8B23PrGw4VWV8rq2TUdGAZX9Dnu0rO3Ky_aZvzQWwGcpwRpBTwLfUw65GoiBFuktg1RtM11qKhSGIXBPY3ETxoltR_A_IvkiqZYsYDudkf-bjwLTAo/s72-c/x_prompt.png" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-3510599136426123509</id><published>2012-05-24T11:00:00.001-04:00</published><updated>2012-05-25T20:42:26.633-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bash"/><category scheme="http://www.blogger.com/atom/ns#" term="center"/><category scheme="http://www.blogger.com/atom/ns#" term="left justify"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="right justify"/><category scheme="http://www.blogger.com/atom/ns#" term="string"/><category scheme="http://www.blogger.com/atom/ns#" term="variables"/><title type='text'>Some light string manipulation in bash</title><content type='html'>This post is more for me than you. &amp;nbsp;I had to do a little bash work this morning and thought I&#39;d keep a record of some of the syntax and concepts that I used in case I have to do more in the future.&lt;br /&gt;
&lt;br /&gt;
There are two files here: a function library and a script that consumes it. &amp;nbsp;The function library is used to do different kinds of string justification (left justify, right justify and centering). &amp;nbsp;Kind of like &#39;echo&#39; on&amp;nbsp;steroids. &amp;nbsp;This could have easily been done in python, perl or ruby, but I wanted it to stay in bash this time to keep the calling scripts uniform.&lt;br /&gt;
&lt;br /&gt;
Here&#39;s the sample file that consumes the library:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;#!/bin/bash&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;. echo_helper&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;x=&#39;Steve is here!&#39;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;left_justify &quot;$x&quot; 40 .&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;right_justify &quot;$x&quot; 40 .&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;center_justify &quot;$x&quot; 40 .&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;echo $(pad_string 40 -)&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;x=&#39;Steve was here.&#39;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;left_justify &quot;$x&quot; 40 .&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;right_justify &quot;$x&quot; 40 .&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;echo $(center_justify &quot;$x&quot; 40 .)&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
And here&#39;s what the output should look like:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Steve is here!..........................&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;..........................Steve is here!&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;.............Steve is here!.............&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;----------------------------------------&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Steve was here..........................&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;.........................Steve was here.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;............Steve was here..............&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Finally, here&#39;s the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;echo_helper&lt;/span&gt;&lt;/b&gt; library code:&lt;br /&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; text-align: left;&quot;&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;display: inline !important;&quot;&gt;
&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; text-align: left;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;#!/bin/bash&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;# Syntaxes to remember:&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;#&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;# String length of a variable: &amp;nbsp;${#varname}&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;# String offsetting of a variable: ${varname:offset} or ${varname:offset:length}&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;# Usage: pad_string LENGTH {PADDING_CHARACTER=&#39; &#39;}&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;function pad_string {&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;local line=&#39;&#39;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;local length=$1&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;local padding_character=&#39; &#39;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;if [[ &quot;$2&quot; != &quot;&quot; ]]; then&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;padding_character=$2&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;fi&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;while((${#line} &amp;lt; $length)); do&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;line=&quot;$line$padding_character&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;done&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;echo -n &quot;$line&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;}&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;# Usage: left_justify MESSAGE LENGTH {PADDING_CHARACTER=&#39; &#39;}&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;function left_justify {&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;local message=$1&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;local length=$2&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;local padding_character=&#39; &#39;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;if [[ &quot;$3&quot; != &quot;&quot; ]]; then&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;padding_character=$3&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;fi&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;echo &quot;$message$(pad_string $length-${#message} $padding_character)&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;}&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;# Usage: right_justify MESSAGE LENGTH {PADDING_CHARACTER=&#39; &#39;}&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;function right_justify {&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;local message=$1&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;local length=$2&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;local padding_character=&#39; &#39;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;if [[ &quot;$3&quot; != &quot;&quot; ]]; then&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;padding_character=$3&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;fi&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;echo &quot;$(pad_string $length-${#message} $padding_character)$message&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;}&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;# Usage: center_justify MESSAGE LENGTH {PADDING_CHARACTER=&#39; &#39;}&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;function center_justify {&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;local message=$1&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;local length=$2&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;local padding_character=&#39; &#39;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;if [[ &quot;$3&quot; != &quot;&quot; ]]; then&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;padding_character=$3&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;fi&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;local half_length=$(expr $length / 2)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;local half_message_length=$(expr ${#message} / 2)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;local padding_length=$(expr $half_length - $half_message_length)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;padding=&quot;$(pad_string $padding_length $padding_character)&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;message=&quot;$padding$message$padding&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;if [[ ${#message} &amp;gt; $length ]]; then # handle even/odd length issue&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;echo &quot;${message:1}&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;else&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;  &lt;/span&gt;echo &quot;$message&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;fi&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;}&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/3510599136426123509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/3510599136426123509'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2012/05/some-light-string-manipulation-in-bash.html' title='Some light string manipulation in bash'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-8459111161904778909</id><published>2012-05-23T14:25:00.002-04:00</published><updated>2012-05-23T14:25:10.698-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="osx"/><category scheme="http://www.blogger.com/atom/ns#" term="preview"/><category scheme="http://www.blogger.com/atom/ns#" term="quicklook"/><category scheme="http://www.blogger.com/atom/ns#" term="vi"/><category scheme="http://www.blogger.com/atom/ns#" term="vim"/><title type='text'>QuickLook from vim</title><content type='html'>Here&#39;s another nifty trick I came up with. &amp;nbsp;I&#39;m probably not the first to think of it but I&#39;ll put it out there anyway.&lt;br /&gt;
&lt;br /&gt;
Quicklook is a neat feature of OSX (versions since Leopard) that allows you to preview the contents of a file without having to open it. &amp;nbsp;The way I&#39;ve typically used it is to select a file in finder and hit the spacebar. &amp;nbsp;OSX then opens a nicely formated window with the contents of my selected file displayed.&lt;br /&gt;
&lt;br /&gt;
I keep a lot of my documentation, notes, etc in &lt;a href=&quot;http://daringfireball.net/projects/markdown/&quot; target=&quot;_blank&quot;&gt;markdown&lt;/a&gt; format. &amp;nbsp;Back in January, I attended &lt;a href=&quot;http://codemash.org/&quot; target=&quot;_blank&quot;&gt;CodeMash&lt;/a&gt; in Sandusky, Ohio and someone turned me onto a markdown rendering Quicklook plugin. &amp;nbsp;It&#39;s a great little tool. &amp;nbsp;I can keep writing my docs and notes in markdown, but when I Quicklook them, they are rendered for display nicely. &amp;nbsp;If you have interest in this free plugin, you can download it &lt;a href=&quot;https://github.com/toland/qlmarkdown&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Anyway, I settled into this habit of editing a file in vim, saving it, then pressing spacebar on it from finder to preview it. &amp;nbsp;It got me thinking, wouldn&#39;t it be great if I could just open Quicklook directly from vim?&lt;br /&gt;
&lt;br /&gt;
After some quick googling around, I found a command-line tool in OSX that does just that. &amp;nbsp;It&#39;s called qlmanage. &amp;nbsp;From there it was easy enough to come up with a vim key mapping.&lt;br /&gt;
&lt;br /&gt;
Put this (all one line) in your .vimrc file and you should be able to do Quicklooks of your files right from vim simply by hitting &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;\v&lt;/span&gt;&lt;/b&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;map &amp;lt;Leader&amp;gt;v :write&amp;lt;cr&amp;gt;:sil !/usr/bin/qlmanage -p % &amp;gt; /dev/null &amp;amp;&amp;lt;cr&amp;gt;:redraw!&amp;lt;cr&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
It works from both MacVim as well as the terminal version. &amp;nbsp;You don&#39;t have to use it solely with markdown files. &amp;nbsp;In fact you can use it with any file that Quicklook understands (html for example).</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/8459111161904778909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/8459111161904778909'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2012/05/quicklook-from-vim.html' title='QuickLook from vim'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-1243760100038093701</id><published>2012-05-22T11:29:00.002-04:00</published><updated>2012-05-22T11:29:21.535-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bash"/><category scheme="http://www.blogger.com/atom/ns#" term="cli"/><category scheme="http://www.blogger.com/atom/ns#" term="gnu"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="osx"/><category scheme="http://www.blogger.com/atom/ns#" term="screen"/><category scheme="http://www.blogger.com/atom/ns#" term="terminal"/><category scheme="http://www.blogger.com/atom/ns#" term="ubuntu"/><title type='text'>Fun with gnu screen</title><content type='html'>In my day job, I spend a fair amount of time working on numerous tasks on the command-line in Linux and OSX. &amp;nbsp;Way back in my college days, I used a program called &lt;a href=&quot;http://www.gnu.org/software/screen/&quot; target=&quot;_blank&quot;&gt;gnu screen&lt;/a&gt;&amp;nbsp;(aka &#39;screen&#39;) but&amp;nbsp;recently I&#39;ve &quot;refound&quot; it. &amp;nbsp;I have a new appreciation for screen and now use it every day.&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
What is screen?&lt;/h3&gt;
&lt;div&gt;
Screen let&#39;s you have multiple shell sessions running simultaneously in the same terminal window. &amp;nbsp;Here&#39;s some of the features that I personally find appealing:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;With a little muscle memory, you can switch rapidly between the sessions.&lt;/li&gt;
&lt;li&gt;It has the ability to split up your terminal window into multiple &quot;window-splits&quot; so you can see two or more shells sessions at the same time. &amp;nbsp;The splits are even resizable.&lt;/li&gt;
&lt;li&gt;You can &#39;detach&#39; and &#39;reattach&#39; to a screen session, allowing you to sign-out, leave and come back later, all the while keeping your terminal sessions active and running.&lt;/li&gt;
&lt;li&gt;It&#39;s&amp;nbsp;configurable&amp;nbsp;and scriptable.&lt;/li&gt;
&lt;li&gt;You can copy and paste between sessions with &#39;vi&#39; like keystrokes.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
How do you get screen?&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
Well, if you&#39;re running ubuntu like me, it&#39;s pretty darn easy. &amp;nbsp;You&#39;re one command away from having it:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~ $ &lt;b&gt;sudo apt-get install screen&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Pretty simple.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
Getting started&lt;/h3&gt;
&lt;div&gt;
Once you have screen installed, simply run it.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~ $ &lt;b&gt;screen&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
It will bring you to a welcome screen (I&#39;ll show you how to disable the welcome screen later).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizt6Dxjv6hogAhDqOFB_MRCZQwjCf9fl7W6zqCvfEtbCmcufCvAgb9Jrycf4etUXLL2Ku4rug9x9qrk_iePHvnhn1_Sa_TPu3DYKSBtxgf7oaJDjEjwx4_a8Wts7xcVSCSeNBmVn-M4w_f/s1600/welcome+screen.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;254&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizt6Dxjv6hogAhDqOFB_MRCZQwjCf9fl7W6zqCvfEtbCmcufCvAgb9Jrycf4etUXLL2Ku4rug9x9qrk_iePHvnhn1_Sa_TPu3DYKSBtxgf7oaJDjEjwx4_a8Wts7xcVSCSeNBmVn-M4w_f/s320/welcome+screen.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
At the bottom of the welcome screen, it will say&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;[Press Space or Return to end.]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Go ahead and do that. &amp;nbsp;You&#39;ll be returned to a bash prompt. &amp;nbsp;It&#39;s important to note that screen hasn&#39;t terminated, but rather it&#39;s spawned another shell prompt within itself and you&#39;re sitting at that new prompt. You can now begin using screen via keyboard command sequences. &amp;nbsp;To prove it, press &lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;Ctrl-a&lt;/b&gt;&lt;/span&gt; and then press &lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; font-weight: bold;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt; (double quote)&lt;/span&gt;. &amp;nbsp;You should get a screen that looks like this:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKwWTZyYkbbS9J9AZPhDmcn9uJz2jpn1HJBzrHE1RiQREs4dmJTJv-Vxb7eVT-tvf5uzf-r_J9ICqcOA_m8XBQ5pUxAemByiRkPffNblsP1yCRpKCbjj0Vp41XoG3EexlW6nK789qT7QPk/s1600/session+list.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;254&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKwWTZyYkbbS9J9AZPhDmcn9uJz2jpn1HJBzrHE1RiQREs4dmJTJv-Vxb7eVT-tvf5uzf-r_J9ICqcOA_m8XBQ5pUxAemByiRkPffNblsP1yCRpKCbjj0Vp41XoG3EexlW6nK789qT7QPk/s320/session+list.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
This is the terminal session list. &amp;nbsp;If you have more than one terminal session running, you&#39;d seem them all listed here. &amp;nbsp;Let&#39;s create another terminal session. &amp;nbsp;Press &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a&lt;/span&gt;&lt;/b&gt; and then press &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;c&lt;/span&gt;&lt;/b&gt;. &amp;nbsp;This should take you back to a bash prompt. &amp;nbsp;Your now in a new bash prompt. &amp;nbsp;See see the updated list, press &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a&lt;/span&gt;&lt;/b&gt; and &lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&quot;&lt;/b&gt;&lt;/span&gt; again.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVnEXaMKgM8jXbp2AZERphEiBmdoZSaP_4W-UFCsBnimnR1xhWVEzSUToTvNgPkCHPbtJW6YvATzIwimscGapV7zZOz6dInSEs1rTwbEJqn0V3NYnHVhW4cwyqnZza6LUwNUsyO2-IuAix/s1600/session+list+with+2+sessions.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;254&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVnEXaMKgM8jXbp2AZERphEiBmdoZSaP_4W-UFCsBnimnR1xhWVEzSUToTvNgPkCHPbtJW6YvATzIwimscGapV7zZOz6dInSEs1rTwbEJqn0V3NYnHVhW4cwyqnZza6LUwNUsyO2-IuAix/s320/session+list+with+2+sessions.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Now there&#39;s two bash sessions. &amp;nbsp;You can select the one you&#39;d like to see by using your arrow keys (or vi cursor movement keys) to highlight the one you want and then press enter/return.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
When you want to quit out, simply exit out of all your bash prompts. &amp;nbsp;Once the last bash session ends, screen will automatically terminate, leaving where you were when you initially started it.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEapUgXPV5JGxOIs0uoCUcBwFpdrBmWMHTazn4dindRsdRaQWbdQ1FRsF3QHFHghPNmICLmmFt5B4V0Pex2UeajYvJINlikiaApnWDB1R3x2VLnefTdlW35Hvrgs-5Lc7f_rotm1hyhYiD/s1600/screen+terminates.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;254&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEapUgXPV5JGxOIs0uoCUcBwFpdrBmWMHTazn4dindRsdRaQWbdQ1FRsF3QHFHghPNmICLmmFt5B4V0Pex2UeajYvJINlikiaApnWDB1R3x2VLnefTdlW35Hvrgs-5Lc7f_rotm1hyhYiD/s320/screen+terminates.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3&gt;
My most used key sequences&lt;/h3&gt;
&lt;div&gt;
As you&#39;ve probably realized by now, screen uses &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a&lt;/span&gt;&lt;/b&gt; plus a key to drive it&#39;s functionality. &amp;nbsp;Here&#39;s a list of key sequences that I use most often.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;Ctrl-a Ctrl-a&lt;/b&gt;&lt;/span&gt; - Toggles between two sessions. &amp;nbsp;It&#39;s kind of like the &quot;last&quot; button on your TV remote.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a c&lt;/span&gt;&lt;/b&gt; - Creates a new terminal session.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a A&lt;/span&gt;&lt;/b&gt; - Let&#39;s you set the title of a terminal session. &amp;nbsp;The title is what appears in the session list.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a &quot;&lt;/span&gt;&lt;/b&gt; - Lists the terminal sessions. &amp;nbsp;You can then use arrow keys or vi keys to select which session you wan to go to.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a d&lt;/span&gt;&lt;/b&gt; -&amp;nbsp;Detach&amp;nbsp;screen so you can log off and come back later. &amp;nbsp;Later when you sign back on, just type &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;screen -r&lt;/span&gt;&lt;/b&gt; to reattach to your running screen session.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a :&lt;/span&gt;&lt;/b&gt; - Bring up screen&#39;s colon prompt (similar to vi). &amp;nbsp;From the colon prompt you can issue commands directly to screen. &amp;nbsp;(You&#39;ll probably use it most resizing window splits).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a [&lt;/span&gt;&lt;/b&gt; - Start copy mode (for copy/paste).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a ]&lt;/span&gt;&lt;/b&gt; - Paste what you copied from copy mode.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a S&lt;/span&gt;&lt;/b&gt; - Split the screen horizontally.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a |&lt;/span&gt;&lt;/b&gt; (pipe) - Split the screen vertically.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a {tab}&lt;/span&gt;&lt;/b&gt; - Move focus from window split to window split&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a X&lt;/span&gt;&lt;/b&gt; - Close the current window split.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
Split example&lt;/h3&gt;
&lt;div&gt;
Here a quick example of doing a couple window splits. &amp;nbsp;First, start screen and a few terminal sessions:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; text-align: left;&quot;&gt;steve@ubuntu64 ~ $&amp;nbsp;&lt;/span&gt;&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; text-align: left;&quot;&gt;screen&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; text-align: left;&quot;&gt;{return}&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; text-align: left;&quot;&gt;Ctrl-a c&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; text-align: left;&quot;&gt;Ctrl-a c&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace; text-align: left;&quot;&gt;Ctrl-a &quot;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Your terminal window should look like this:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdFVr_QJllFF9zZEgRwsZXifnLfkID8dqCJK2csHWsphbzip3wh4BIuF9tv8v3Y68ANYRDhCre0J0zYnyz84iBxVGeCw3pLCW9BLEfZe-_wEZFdJBufHpe0WQC2B43wHtPw05hlnMipv8h/s1600/three+sessions.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;254&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdFVr_QJllFF9zZEgRwsZXifnLfkID8dqCJK2csHWsphbzip3wh4BIuF9tv8v3Y68ANYRDhCre0J0zYnyz84iBxVGeCw3pLCW9BLEfZe-_wEZFdJBufHpe0WQC2B43wHtPw05hlnMipv8h/s320/three+sessions.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Now press &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a S&lt;/span&gt;&lt;/b&gt; to split the screen. &amp;nbsp;You should now have an upper split and a lower split. &amp;nbsp;Press &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{return}&lt;/span&gt;&lt;/b&gt; now to select terminal session 2 in the upper split. &amp;nbsp;In that terminal session run the &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;top&lt;/span&gt;&lt;/b&gt; command.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv2KT2zp_UzYEUBPnnV7Zic4PRuK4MkkdvWC0KUBZq24-2kfZSFzo1gW_nKVqmqx6oxCtlGJE0x6Nwh5YY1_giDznWclfX0zVdaLefqKK4KvSusi7K7-o0DKodNMyeMNFuATz9tdv_AlMX/s1600/split+1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;254&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv2KT2zp_UzYEUBPnnV7Zic4PRuK4MkkdvWC0KUBZq24-2kfZSFzo1gW_nKVqmqx6oxCtlGJE0x6Nwh5YY1_giDznWclfX0zVdaLefqKK4KvSusi7K7-o0DKodNMyeMNFuATz9tdv_AlMX/s320/split+1.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Now press &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a {tab}&lt;/span&gt;&lt;/b&gt;. &amp;nbsp;This will move the cursor down to the bottom split. &amp;nbsp;Then press &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a &quot;&lt;/span&gt;&lt;/b&gt; to bring up the session list.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigpH2oMJZvMJPo23eacHiiO9NCloZPmcnOfh3IGasn7VozYgjE96X1Z3qHd5ZJMyhlKhf_royqR29hhZilrhWnDp48mAx2R0znuT09t7DNIVpaU5kgtUMyp5N-RvX68eNMIIx4P7NiUWDr/s1600/split+2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;254&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigpH2oMJZvMJPo23eacHiiO9NCloZPmcnOfh3IGasn7VozYgjE96X1Z3qHd5ZJMyhlKhf_royqR29hhZilrhWnDp48mAx2R0znuT09t7DNIVpaU5kgtUMyp5N-RvX68eNMIIx4P7NiUWDr/s320/split+2.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Select session &lt;b&gt;0&lt;/b&gt; and then issue the following command in the lower split: &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;watch ls&lt;/span&gt;&lt;/b&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcapx7WBuGiVr3xnnrxzdLoWDg9Bc4kyxF0R2cE51x0E3V3rD-p4ct_CoV9FkQ0NqQoe-MUlLaFOqWoKQ8BJwZPvy2-XKkQY3S_0_QZA7paG6gOGqs3Jcoqyj41p_rg9md2p3h6mp_BDto/s1600/split+3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;254&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcapx7WBuGiVr3xnnrxzdLoWDg9Bc4kyxF0R2cE51x0E3V3rD-p4ct_CoV9FkQ0NqQoe-MUlLaFOqWoKQ8BJwZPvy2-XKkQY3S_0_QZA7paG6gOGqs3Jcoqyj41p_rg9md2p3h6mp_BDto/s320/split+3.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Next, let&#39;s split the lower window vertically. &amp;nbsp;Press &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a |&lt;/span&gt;&lt;/b&gt; (pipe), &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a {tab}&lt;/span&gt;&lt;/b&gt;, &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a &quot;&lt;/span&gt;&lt;/b&gt;. &amp;nbsp;Select session 1.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEic-vYHukXTFZ59FYfjZkl3AllVljtCeHnUxCWvPjaYGBqg3defDQW4g6dydzjoDnAuonX_j9c1VPspYfHyIFWAJ3OzZy-5QjNovOUfjw8LkQf9bdwT7ITv0sFbGmQh1YdbcE9bDmKNf7nq/s1600/split+4.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;254&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEic-vYHukXTFZ59FYfjZkl3AllVljtCeHnUxCWvPjaYGBqg3defDQW4g6dydzjoDnAuonX_j9c1VPspYfHyIFWAJ3OzZy-5QjNovOUfjw8LkQf9bdwT7ITv0sFbGmQh1YdbcE9bDmKNf7nq/s320/split+4.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
As you can see, you can keep splitting, sub-splitting, etc. &amp;nbsp;Remember, &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a {tab}&lt;/span&gt;&lt;/b&gt; moves the cursor to the next window split. &amp;nbsp;That&#39;s how you move around.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
When you&#39;re done, you can use &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Ctrl-a X&lt;/span&gt;&lt;/b&gt; to close the window splits. &amp;nbsp;This does not quit/kill the process running in that split. &amp;nbsp;The process stays in the session list until you exit it normally.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
Scripting&lt;/h3&gt;
&lt;div&gt;
Screen reads and processes the &lt;b&gt;~/.screenrc&lt;/b&gt; file at startup. &amp;nbsp;Here&#39;s mine:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;vbell off&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;startup_message off&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;defscrollback 1000&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;bindkey -k k1 colon&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;bindkey -k k2 screen&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;bindkey -k F2 windowlist -b&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;hardstatus off&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;caption always &#39;%{Yb}[%=%t%=]&#39;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;altscreen on&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;shell -${SHELL}&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
You can go through the screen man page for what each line does. &amp;nbsp;You can customize screen however you&#39;d like.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
There are two features that combined make startup processing especially interesting:&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;You can use the &lt;b&gt;-c&lt;/b&gt; command line argument to give screen an alternate rc file to process on startup.&lt;/li&gt;
&lt;li&gt;Using commands, you can do anything in the rc file that you could do interactively.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
Using this notion, I create different screen rc files for different contexts. &amp;nbsp;For example, when I&#39;m working at a certain client, I would like to have screen set up a certain way, with specific terminal sessions setup. &amp;nbsp;I create a bash aliases for each client.&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In my ~/.bash_aliases file I have:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;alias clientX=&#39;screen -c ~/screen_profiles/clientX&#39;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;alias clientY=&#39;screen -c ~/screen_profiles/clientY&#39;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
My ~/screen_profiles/clientX file looks like this:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;altscreen on&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;vbell off&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;attrcolor b &quot;.I&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;termcapinfo xterm &#39;Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm&#39;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;defbce &quot;on&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;defscrollback 1500&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;bindkey -k k1 colon&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;bindkey -k k2 screen&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;bindkey -k F2 windowlist -b&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;screen -t &quot;Home&quot; bash&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;screen -t &quot;Build&quot; ssh &lt;i&gt;my_username@build_server&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;screen -t &quot;Dev2&quot; ssh &lt;i&gt;my_username@dev_server&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;screen -t &quot;WebLogic&quot; &lt;i&gt;my_username@weblogic_server&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;screen -t &quot;Todo/Notes&quot; vi ~/notes/todo.markdown&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;hardstatus off&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;caption always &#39;%{Yb}[%=%t%=]&#39;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;select 0&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;split -v&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;resize +20&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;focus&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;select 5&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;focus&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This rc file does the following:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;Does some normal setup that I do anyway (key bindings, colors, etc.)&lt;/li&gt;
&lt;li&gt;Creates a terminal session titled, &quot;Home&quot; and runs bash in it.&lt;/li&gt;
&lt;li&gt;Creates a terminal session titled, &quot;Build&quot; and ssh&#39;s me into the build server.&lt;/li&gt;
&lt;li&gt;Creates a terminal session titled, &quot;Dev2&quot; and ssh&#39;s me into the dev 2 server.&lt;/li&gt;
&lt;li&gt;Creates a terminal session titled, &quot;WebLogic&quot; and ssh&#39;s me into the weblogic server.&lt;/li&gt;
&lt;li&gt;Creates a terminal session titled, &quot;Todo/Notes&quot; and edits my ~/notes/todo.markdown file using vi in it.&lt;/li&gt;
&lt;li&gt;Splits the window vertically, resizing the left window to be 20 columns bigger.&lt;/li&gt;
&lt;li&gt;Selects the &quot;Home&quot; session for the left window.&lt;/li&gt;
&lt;li&gt;Selects the &quot;Todo/Notes&quot; session for the right window.&lt;/li&gt;
&lt;li&gt;Puts the cursor focus on the left window.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
So when I come into clientX&#39;s office for the day, I simply type &lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;clientX&lt;/span&gt;&lt;/b&gt; at the bash prompt and within a second, I have screen all set up with my splits and automatically logged into all the servers I commonly use. &amp;nbsp;Pretty cool.&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/1243760100038093701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/1243760100038093701'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2012/05/fun-with-gnu-screen.html' title='Fun with gnu screen'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizt6Dxjv6hogAhDqOFB_MRCZQwjCf9fl7W6zqCvfEtbCmcufCvAgb9Jrycf4etUXLL2Ku4rug9x9qrk_iePHvnhn1_Sa_TPu3DYKSBtxgf7oaJDjEjwx4_a8Wts7xcVSCSeNBmVn-M4w_f/s72-c/welcome+screen.png" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-6634997312640949930</id><published>2012-05-17T10:41:00.003-04:00</published><updated>2012-05-18T09:45:46.675-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="git"/><category scheme="http://www.blogger.com/atom/ns#" term="gitolite"/><category scheme="http://www.blogger.com/atom/ns#" term="gitorious"/><category scheme="http://www.blogger.com/atom/ns#" term="source control"/><title type='text'>Gitolite... my new shiny penny</title><content type='html'>At my current client engagement, I&#39;m serving as the build-guy and all around code librarian. &amp;nbsp;I&#39;m managing 35 or so git repositories... keeping them tidy and organized.&lt;br /&gt;
&lt;br /&gt;
Since the client seems to heavily utilize consultant help, they have a veritable revolving door of staff. &amp;nbsp;Before my arrival they decided to purchase and use a tool called &lt;a href=&quot;http://gitorious.org/&quot; target=&quot;_blank&quot;&gt;gitorious&lt;/a&gt;&amp;nbsp;to aid in managing the repositories and access to them. &amp;nbsp;It&#39;s pretty much like a private github. &amp;nbsp;It has all kinds of features including web-based management of users/keys,&amp;nbsp;browse-able&amp;nbsp;git logs, etc. &amp;nbsp;They have it running as an appliance on a virtual server here at the office.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It works pretty well and I&#39;ve embraced it because it&#39;s the &quot;officially-blessed-by-enterprise-architecture&quot; tool.&lt;br /&gt;
&lt;br /&gt;
It&#39;s not without it&#39;s drawbacks though:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;In it&#39;s default configuration, EVERYONE/ANONYMOUS has READ access to ALL repositories.&lt;/li&gt;
&lt;li&gt;Gitorious is heavily integrated with git&#39;s hooks, so if you want to add your own hooks to a repository, you&#39;re pretty much out of luck... unless you like tampering with their code - good luck with that.&lt;/li&gt;
&lt;li&gt;If you don&#39;t want use their appliance and want to install it yourself, it&#39;s not all that straight forward.&lt;/li&gt;
&lt;li&gt;The UI isn&#39;t really that intuitive. &amp;nbsp;For example if you want to see a list of tags for a repository, you have to drill into a branch rather than seeing them at the repository level.&lt;/li&gt;
&lt;li&gt;It costs money if you want to have your own on-site copy.&lt;/li&gt;
&lt;/ul&gt;
All that said, I started looking around for alternatives for managing medium to large numbers of git repositories (more than 5&#39;ish) both for my own stuff as well as for future clients.&lt;br /&gt;
&lt;br /&gt;
In looking around, I found a tool called &lt;a href=&quot;https://github.com/sitaramc/gitolite&quot; target=&quot;_blank&quot;&gt;gitolite&lt;/a&gt;. &amp;nbsp;Gitolite seem to provide all the features that I want/need and has the benefits of being simple/easy to implement as well as being opensource/free.&lt;br /&gt;
&lt;br /&gt;
Gitolite doesn&#39;t have a user interface. &amp;nbsp;You mange it with... what else... git!&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;






Installation is easy&lt;/h3&gt;
If you&#39;re running on Ubuntu, you&#39;re only a command away from installation:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~ $&lt;/span&gt;&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&lt;/b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;sudo apt-get install gitolite&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
That get&#39;s app installed and ready to configure.&lt;br /&gt;
&lt;h3&gt;






Configuration is easy too&lt;/h3&gt;
Instead of housing gitolite on my personal account (which you could easily do... I just choose not to), I created an account for it called git.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~ $ &lt;/span&gt;&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;sudo adduser git&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Adding user `git&#39; ...&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Adding new group `git&#39; (1002) ...&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Adding new user `git&#39; (1002) with group `git&#39; ...&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Creating home directory `/home/git&#39; ...&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Copying files from `/etc/skel&#39; ...&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Enter new UNIX password:&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Retype new UNIX password:&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;passwd: password updated successfully&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Changing the user information for git&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Enter the new value, or press ENTER for the default&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Full Name []: Git Repository Home&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Room Number []:&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Work Phone []:&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Home Phone []:&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Other []:&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Is the information correct? [Y/n] y&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~ $&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
After creating the account, you&#39;ll want to copy your public key to the git account&#39;s home directory for the one and only step of initial gitolite configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~ $&lt;/span&gt;&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt; sudo cp .ssh/id_rsa.pub /home/git/steveb.pub&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~ $&lt;b&gt; sudo chown git.git /home/git/steveb.pub&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~ $&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
Now we&#39;re ready to do the initial configuration. &amp;nbsp;You&#39;ll need to become the git account to do it.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~ $&lt;/span&gt;&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt; su - git&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Password:&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;git@ubuntu64:~$&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
Then you&#39;ll want to issue the command &lt;b&gt;gl-setup&lt;/b&gt; from the bash prompt, passing in the key you just copied.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;git@ubuntu64:~$&lt;/span&gt;&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt; gl-setup steveb.pub&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
It will prompt you to edit the default &lt;b&gt;.gitolite.rc&lt;/b&gt; file, but don&#39;t change anything, it&#39;s fine as it is for now. &amp;nbsp;You may have a need to change it in the future but I haven&#39;t so far. &amp;nbsp;Just save and quit out of your editor without changing anything.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;The default settings in the rc file (/home/git/.gitolite.rc) are fine for most&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;people but if you wish to make any changes, you can do so now.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;hit enter...&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;creating gitolite-admin...&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Initialized empty Git repository in /home/git/repositories/gitolite-admin.git/&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;creating testing...&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Initialized empty Git repository in /home/git/repositories/testing.git/&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;[master (root-commit) 09aad52] start&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;2 files changed, 6 insertions(+)&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;create mode 100644 conf/gitolite.conf&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;create mode 100644 keydir/steveb.pub&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;git@ubuntu64:~$&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
That&#39;s it. &amp;nbsp;Gitolite is all set up and ready to use!&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;git@ubuntu64:~$&lt;/span&gt;&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt; exit&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;logout&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~ $&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h3&gt;






Using gitolite is a piece-o-cake&lt;/h3&gt;
&lt;br /&gt;
Managing your git repositories with gitolite is done entirely by manipulating a git repository called &lt;b&gt;gitolite-admin&lt;/b&gt;. &amp;nbsp;First let&#39;s use gitolite to create a new repository. &amp;nbsp;Step one: &amp;nbsp;clone the &lt;b&gt;gitolite-admin&lt;/b&gt; repository from your system:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~ $&lt;/span&gt;&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt; cd dev&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev $&lt;/span&gt;&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt; git clone git@localhost:gitolite-admin.git&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Cloning into &#39;gitolite-admin&#39;...&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;remote: Counting objects: 6, done.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;remote: Compressing objects: 100% (4/4), done.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;remote: Total 6 (delta 0), reused 0 (delta 0)&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Receiving objects: 100% (6/6), done.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev $&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
You&#39;ll notice that the &lt;b&gt;gitolite-admin&lt;/b&gt; clone has a pretty simple directory structure.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev $&lt;b&gt; cd gitolite-admin&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/gitolite-admin(master) $&lt;b&gt; ls -la&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;total 20&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;drwxr-xr-x &amp;nbsp;5 steve steve 4096 May 17 09:23 .&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;drwxrwxr-x 13 steve steve 4096 May 17 09:23 ..&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;drwxrwxr-x &amp;nbsp;2 steve steve 4096 May 17 09:23 &lt;b&gt;conf&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;drwxrwxr-x &amp;nbsp;8 steve steve 4096 May 17 09:24 .git&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;drwxrwxr-x &amp;nbsp;2 steve steve 4096 May 17 09:23 &lt;b&gt;keydir&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/gitolite-admin(master) $&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
It has two directories: &lt;b&gt;conf&lt;/b&gt; and &lt;b&gt;keydir&lt;/b&gt;. &amp;nbsp;The conf directory contains a file called &lt;b&gt;gitolite.conf&lt;/b&gt;. &amp;nbsp;You edit the &lt;b&gt;gitolite.conf&lt;/b&gt; file to create repositories and manage permissions to those repositories.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/gitolite-admin(master) $&lt;b&gt; ls -l conf&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;total 4&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;-rw-rw-r-- 1 steve steve 92 May 17 09:23 &lt;b&gt;gitolite.conf&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/gitolite-admin(master) $&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
The &lt;b&gt;keydir&lt;/b&gt; directory is where you should place public key files of the users you want to grant access to repositories. &amp;nbsp;You&#39;ll notice that the public key you copied for your self is already there!&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/gitolite-admin(master) $ &lt;b&gt;ls -l keydir&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;total 4&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;-rw-rw-r-- 1 steve steve 391 May 17 09:23 &lt;b&gt;steveb.pub&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/gitolite-admin(master) $&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
Let&#39;s add that new repository. &amp;nbsp;To do so, simply edit the &lt;b&gt;conf/gitolite.conf&lt;/b&gt; file with your favorite text editor.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/gitolite-admin(master) $ vi &lt;b&gt;conf/gitolite.conf&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
Add the following lines to it:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;repo &amp;nbsp; &amp;nbsp;gitolite-admin&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; RW+ &amp;nbsp; &amp;nbsp; = &amp;nbsp; steveb&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;repo &amp;nbsp; &amp;nbsp;testing&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; RW+ &amp;nbsp; &amp;nbsp; = &amp;nbsp; @all&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;repo&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;my_cool_new_repository&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;        &lt;/span&gt;RW+&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;= &amp;nbsp; steveb&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
The two new lines in the file establish that you want to add a new repository named &lt;b&gt;my_cool_new_repository&lt;/b&gt; and that you want to grant the user with the public key file &lt;b&gt;steveb.pub&lt;/b&gt; full &lt;b&gt;READ/WRITE/REFEDIT&lt;/b&gt; permissions.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Save the file. Commit it. &amp;nbsp;Then push it back to the repository origin.&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/gitolite-admin(master) $ &lt;b&gt;git add .&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/gitolite-admin(master) $ &lt;b&gt;git commit -m&quot;Added new repository my_cool_new_repository&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;[master 393ef15] Added new repository my_cool_new_repository&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;1 file changed, 3 insertions(+)&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/gitolite-admin(master) $ &lt;b&gt;git push&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Counting objects: 7, done.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Delta compression using up to 2 threads.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Compressing objects: 100% (3/3), done.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Writing objects: 100% (4/4), 433 bytes, done.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Total 4 (delta 0), reused 0 (delta 0)&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;remote: creating my_cool_new_repository...&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;remote: Initialized empty Git repository in /home/git/repositories/my_cool_new_repository.git/&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;To git@localhost:gitolite-admin.git&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp;09aad52..393ef15 &amp;nbsp;master -&amp;gt; master&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/gitolite-admin(master) $&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
Gitolite sees your change to the &lt;b&gt;conf/gitolite.conf&lt;/b&gt; file. &amp;nbsp;It then creates a new blank, bare git repository called &lt;b&gt;my_cool_new_repository.git&lt;/b&gt;. &amp;nbsp;It also ensures that the &lt;b&gt;steveb.pub&lt;/b&gt; file has the&amp;nbsp;appropriate&amp;nbsp;access to the git account (check out the git account&#39;s ~/.ssh/authorized_keys).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
That&#39;s it. &amp;nbsp;Your new repository is ready to clone!&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/gitolite-admin(master) $ &lt;b&gt;cd ..&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev $ &lt;b&gt;git clone git@localhost:my_cool_new_repository.git&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Cloning into &#39;my_cool_new_repository&#39;...&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;warning: You appear to have cloned an empty repository.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev $ &lt;b&gt;cd my_cool_new_repository/&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/my_cool_new_repository(master) $ &lt;b&gt;date &amp;gt; file1.txt&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/my_cool_new_repository(master) $ &lt;b&gt;git add .&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/my_cool_new_repository(master) $ &lt;b&gt;git commit -m&quot;Added file1.txt&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;[master (root-commit) 90e1635] Added file1.txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;1 file changed, 1 insertion(+)&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;create mode 100644 file1.txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/my_cool_new_repository(master) $ &lt;b&gt;git push origin master&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Counting objects: 3, done.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Writing objects: 100% (3/3), 257 bytes, done.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Total 3 (delta 0), reused 0 (delta 0)&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;To git@localhost:my_cool_new_repository.git&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;* [new branch] &amp;nbsp; &amp;nbsp; &amp;nbsp;master -&amp;gt; master&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;steve@ubuntu64 ~/dev/my_cool_new_repository(master) $&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
Adding/removing user access is as simple as adding/removing key files from the &lt;b&gt;keydir&lt;/b&gt; directory, updating the &lt;b&gt;conf/gitolite.conf&lt;/b&gt; file and pushing.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The gitolife.conf file, while very simple, is incredibly powerful. &amp;nbsp;It supports groups. &amp;nbsp;Also, it will not only allow you to control access to git repositories, but will also allow you to assign permissions to branches and tags with regular expressions. &amp;nbsp;Take a look at the &lt;a href=&quot;https://github.com/sitaramc/gitolite/tree/master/doc&quot; target=&quot;_blank&quot;&gt;documentation&lt;/a&gt; for much more info.&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/6634997312640949930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/6634997312640949930'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2012/05/gitolite-my-new-shiny-penny.html' title='Gitolite... my new shiny penny'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-6813230067355006322</id><published>2012-05-01T11:57:00.002-04:00</published><updated>2012-05-18T09:40:32.296-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="automator"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="osx"/><category scheme="http://www.blogger.com/atom/ns#" term="x11"/><title type='text'>Use automator to create X11 shortcuts in OSX</title><content type='html'>I have a Mac and yet I do a fair amount of work in X11apps on Linux systems. &amp;nbsp;I really like the ssh&#39;s -Y flag that let&#39;s me run my Linux X11 apps and have their display output (and input) sent back to my Mac.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;iframe bordercolor=&quot;#000000&quot; frameborder=&quot;0&quot; height=&quot;150&quot; hspace=&quot;0&quot; marginheight=&quot;0&quot; marginwidth=&quot;0&quot; scrolling=&quot;no&quot; src=&quot;http://ad.doubleclick.net/adi/N7433.148119.BLOGGEREN/B6627866.444;sz=180x150;ord=[timestamp]?;lid=41000000026530730;pid=57365;usg=AFHzDLvO-qX1OMueCN4NvXQW37hlKQgROw;adurl=http%253A%252F%252Fwww.abt.com%252Fproduct%252F57365%252FApple-MD313LLA.html;pubid=543520;price=%241199.00;title=Apple+13.3+Inch+MacBoo...;merc=Abt+Electronics+%26+Appliances;imgsrc=http%3A%2F%2Fcontent.abt.com%2Fmedia%2Fimages%2Fproducts%2FBDP_Images%2Fbig_mbp13blion.jpg;width=110;height=71&quot; vspace=&quot;0&quot; width=&quot;180&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;br /&gt;
I just stumbled onto this in Automator and thought it might be worth sharing.&lt;br /&gt;
&lt;br /&gt;
You can create Automator &quot;Application&quot; workflows that look/feel/behave like local OSX applications, but are actually running on remote Linux servers. &amp;nbsp;In this posting, I will walk through creating an Automator workflow for Synaptic, an application package manager for apt based Linux distributions.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;




Requirements&lt;/h3&gt;
You will need to ensure you have an environment that meets the following&amp;nbsp;requirements&amp;nbsp;in order to follow along:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;A Mac running OSX (I&#39;m using Lion. &amp;nbsp;I&#39;ve not tested this with other versions so if you&#39;re using another version, your milage may vary.)&lt;/li&gt;
&lt;li&gt;You will need X11.app or&lt;a href=&quot;http://xquartz.macosforge.org/landing/&quot; target=&quot;_blank&quot;&gt; XQuartz.app&lt;/a&gt; installed on your Mac. &amp;nbsp;X11.app comes with OSX up to Lion. &amp;nbsp;After Lion, you will need to install XQuartz.app yourself.&lt;/li&gt;
&lt;li&gt;Access to a Linux system that is running SSH with X11 tunneling enabled (a default I believe) and gksudo and synaptic installed.&lt;/li&gt;
&lt;li&gt;You need to have key-based authentication set up with your account so you are not prompted for a password when logging into the Linux machine via ssh.&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;gksudo&lt;/b&gt; is normally not needed. &amp;nbsp;In this case we&#39;re running synaptic, a package manager for Linux, which needs elevated&amp;nbsp;privileges&amp;nbsp;in order to add/remove&amp;nbsp;software&amp;nbsp;packages on the Linux machine. &amp;nbsp;If the X11 app you are wanting to run doesn&#39;t require elevated&amp;nbsp;privileges&amp;nbsp;you won&#39;t need gksudo.&lt;br /&gt;
&lt;h3&gt;




Verify that you can log in without as password prompt&lt;/h3&gt;
&lt;div&gt;
Before we create the Automator workflow, let&#39;s verify that you can log into the Linux system from your Mac without a password prompt. Start a terminal window and issue a command in the following format:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;ssh username@linux_hostname&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
If you are prompted for a password you will still need to set yourself up for key-based authentication. &amp;nbsp;Check out any of &lt;a href=&quot;https://www.google.com/search?sourceid=chrome&amp;amp;ie=UTF-8&amp;amp;q=setting+up+key-based+authentication+in+ssh&quot; target=&quot;_blank&quot;&gt;these links&lt;/a&gt; and then come back. &amp;nbsp;You should be let in without a password as seen below:&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg04Y80TZVXswZNj1lofwzhPz6TCWn2wpTB-ya-evK2jIZnnm8g64I4tBqeqUXkC86h275RKUFBfRR2ehLFqs6tdyGtySSSWwij3lnqks710YWk4LTQe4XlkHXqt3CCSV6611hPnw1N4QHZ/s1600/no+password+prompt.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg04Y80TZVXswZNj1lofwzhPz6TCWn2wpTB-ya-evK2jIZnnm8g64I4tBqeqUXkC86h275RKUFBfRR2ehLFqs6tdyGtySSSWwij3lnqks710YWk4LTQe4XlkHXqt3CCSV6611hPnw1N4QHZ/s320/no+password+prompt.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;




Start a new Automator Workflow&lt;/h3&gt;
&lt;div&gt;
Once you have confirmed that you can ssh from your Mac into your Linux system, you&#39;re ready to get started. &amp;nbsp;Run Automator and start a new &quot;Application&#39; workflow.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNTq5O7oYTKVud2hVZw6sRD8iBEm_0yb0jhHYQozIQlyf3FTriAHeK_CIp-IvH2QJjeW0xyHYOLtH1g-jF9BQoizrLZ6vROLp4FN_-hGtmfaYeVM0rWZLL1QmTL3S-h9OaQW3dsta8EGot/s1600/new+workflow.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;276&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNTq5O7oYTKVud2hVZw6sRD8iBEm_0yb0jhHYQozIQlyf3FTriAHeK_CIp-IvH2QJjeW0xyHYOLtH1g-jF9BQoizrLZ6vROLp4FN_-hGtmfaYeVM0rWZLL1QmTL3S-h9OaQW3dsta8EGot/s320/new+workflow.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Then we&#39;re going to add a single action to the workflow. &amp;nbsp;In the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Actions&lt;/span&gt;&lt;/b&gt; library locate the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Utilities&lt;/span&gt;&lt;/b&gt; group and select it. &amp;nbsp;Then drag the&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt; Run Shell Script&lt;/span&gt;&lt;/b&gt; action to your workflow.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizpzQ2cv3JEPAaa04XFF5tmoPihlGw82PEaOBsBmNTv7ErAs7ClgZlOocIeEPBU4477JadykkAqnvV4G9DPkHxu5nqy-8xJ1fiuvYBkqEcTYk1nqS-jVz-CSj5HDmbG9HrcmaA5z1gnfW2/s1600/run+shell+action.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;276&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizpzQ2cv3JEPAaa04XFF5tmoPihlGw82PEaOBsBmNTv7ErAs7ClgZlOocIeEPBU4477JadykkAqnvV4G9DPkHxu5nqy-8xJ1fiuvYBkqEcTYk1nqS-jVz-CSj5HDmbG9HrcmaA5z1gnfW2/s320/run+shell+action.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Once you&#39;ve done that, click on the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Options&lt;/span&gt;&lt;/b&gt; link at the bottom of the action. &amp;nbsp;It will reveal some options. &amp;nbsp;Check the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Ignore this action&#39;s input&lt;/span&gt;&lt;/b&gt; checkbox.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4x2DQXWAFeImxEh5axDQRMw8VTdorOOwXWUhFMJfZNYs6q062bNqH8rMXtEGBNvCU8Z_StTlgVwLLjLMrUMToc_K3IBoT-hRWjp6YK7mUnuQlJ4jS9wlu8hLei6exA9MB0yuCvxgiOGN-/s1600/ignore+input.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;262&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4x2DQXWAFeImxEh5axDQRMw8VTdorOOwXWUhFMJfZNYs6q062bNqH8rMXtEGBNvCU8Z_StTlgVwLLjLMrUMToc_K3IBoT-hRWjp6YK7mUnuQlJ4jS9wlu8hLei6exA9MB0yuCvxgiOGN-/s320/ignore+input.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Finally, replace the cat command with the following ssh command:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;ssh -Y username@linux_hostname gksudo -g synaptic &amp;amp;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0Kmhss2o6bjIZQX_-KU1FTQztebxUETPMHmz2szf1mQonh8KXfNvd1So9OMmn2562PLtrbr5ZcGm4JHx1T8U-2VQ7wCwlbhJCIW63HjE3CMFVWiVfVW0yNnsNR8uA9d9BnZEdqecVyAq8/s1600/ssh+syntax.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;262&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0Kmhss2o6bjIZQX_-KU1FTQztebxUETPMHmz2szf1mQonh8KXfNvd1So9OMmn2562PLtrbr5ZcGm4JHx1T8U-2VQ7wCwlbhJCIW63HjE3CMFVWiVfVW0yNnsNR8uA9d9BnZEdqecVyAq8/s320/ssh+syntax.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Where &lt;i&gt;username&lt;/i&gt;&amp;nbsp;is your username and &lt;i&gt;linux_hostname&lt;/i&gt; is your Linux host&#39;s hostname. &amp;nbsp;Don&#39;t forget the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&amp;amp;&lt;/span&gt;&lt;/b&gt; at the end. &amp;nbsp;Then save your workflow as &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Synaptic&lt;/span&gt;&lt;/b&gt;. &amp;nbsp;You can click the run button if you&#39;d like to test it out.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-AkV8-uY-vV1ALP6wVBoxzgRy2yFWbuHWG-ZT-US0uD8QVa0fTruXn3DR9D6Vn1kLzBzTkd5REteNCNfuzYOmk5uZwX214dpov5uwvbxC3_lhR20BdJd9-swEvpBYMgc0mn-XyWKGtV16/s1600/save.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;258&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-AkV8-uY-vV1ALP6wVBoxzgRy2yFWbuHWG-ZT-US0uD8QVa0fTruXn3DR9D6Vn1kLzBzTkd5REteNCNfuzYOmk5uZwX214dpov5uwvbxC3_lhR20BdJd9-swEvpBYMgc0mn-XyWKGtV16/s320/save.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Once you&#39;re satisfied with it, quit out of automator. &amp;nbsp;Now you can run the workflow directly from OSX. &amp;nbsp;Locate it in Finder and double-click on it.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: -webkit-auto;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqZUZSqVepcJhMrwVOO9d6lFBSMSFUt1PgEmpTdlmpwOGs47jmwVowjAQEz6sTfk8-6qe9PZVZ3t1l8Epi46hmQ-37UO7mZSreXo1LbK7M8wGlKZUFYV54MDvEC1eGrD59jv22mqt0Ukwv/s1600/icon+on+desktop.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqZUZSqVepcJhMrwVOO9d6lFBSMSFUt1PgEmpTdlmpwOGs47jmwVowjAQEz6sTfk8-6qe9PZVZ3t1l8Epi46hmQ-37UO7mZSreXo1LbK7M8wGlKZUFYV54MDvEC1eGrD59jv22mqt0Ukwv/s1600/icon+on+desktop.png&quot; /&gt;&lt;/a&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuqVunsad_lUfduxNXg3oM9q1AcB1GyEbAR8Z5VYgCWhjT8D83_o-CoeqnIhM2YYRjUZRgddo2rk5I6THHw7b5W3vxse6MsC9y8M2jgjqlmJB-9L90GrQSlUrHm1LmAQuKx3STaigmsbij/s1600/password+prompt.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;204&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuqVunsad_lUfduxNXg3oM9q1AcB1GyEbAR8Z5VYgCWhjT8D83_o-CoeqnIhM2YYRjUZRgddo2rk5I6THHw7b5W3vxse6MsC9y8M2jgjqlmJB-9L90GrQSlUrHm1LmAQuKx3STaigmsbij/s320/password+prompt.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5BwqjOiqxbuGkGFXbjUfFaY2yLaSeg7SHMtHNqTrqBzPDyAyruiWQIK5376uinEpKqdHAelgy8s9tNrVwfMTgvsXM4f4GTvX1YPs8g6EppkdRcEP8zm3FgEbnAaFU3nPGIEV2DdWVJv0H/s1600/synaptic+running+in+X11.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;212&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5BwqjOiqxbuGkGFXbjUfFaY2yLaSeg7SHMtHNqTrqBzPDyAyruiWQIK5376uinEpKqdHAelgy8s9tNrVwfMTgvsXM4f4GTvX1YPs8g6EppkdRcEP8zm3FgEbnAaFU3nPGIEV2DdWVJv0H/s320/synaptic+running+in+X11.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
That&#39;s it. &amp;nbsp;You can create any number of workflows for individual Linux apps. &amp;nbsp;I have one for LibreOffice, one for synaptic, one for Eclipse and one for gnome-system-monitor.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;




Optional - Set icon for your workflow&lt;/h3&gt;
&lt;div&gt;
If you&#39;re like me, the generic Automator icon on my Synaptic workflow is a little annoying. &amp;nbsp;You can set the icon to whatever you&#39;d like. &amp;nbsp;Here&#39;s &lt;i&gt;one way&lt;/i&gt; to do it.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
First, obtain a copy of the synaptic.png file from your Linux machine and place it on your Mac. &amp;nbsp;I use the following command from a terminal:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;scp steve@ubuntu32.local:/usr/share/pixmaps/synaptic.png ~/Desktop&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
This puts the synaptic.png file on my Mac&#39;s desktop. &amp;nbsp;Then I double-click the synaptic.png file. &amp;nbsp;It should open up in Preview. &amp;nbsp;In preview, I select &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Edit-&amp;gt;Select All&lt;/span&gt;&lt;/b&gt;, then &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Edit-&amp;gt;Copy&lt;/span&gt;&lt;/b&gt;.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj01OoAszCairSlggLDLmn18a-aWdehgps1Z74WoyQHUThylmgSAbtUPFJcdNIVnGCyANPNC-0iR1LRNm6ti5Vk-zBNyJ5x0uXYxnpJYy93T-3Iw8hyphenhyphenYoojbe6SNAMe3YRQz7mfuZTyjLaE/s1600/Copying+from+Preview.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj01OoAszCairSlggLDLmn18a-aWdehgps1Z74WoyQHUThylmgSAbtUPFJcdNIVnGCyANPNC-0iR1LRNm6ti5Vk-zBNyJ5x0uXYxnpJYy93T-3Iw8hyphenhyphenYoojbe6SNAMe3YRQz7mfuZTyjLaE/s320/Copying+from+Preview.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Next, I control-click on the Synaptic automator workflow and select &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Get Info&lt;/span&gt;&lt;/b&gt;. &amp;nbsp;This brings up an informational dialog.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3WfahZH4-sJlXSYimS-H9XA0M8PVQ7OBe-YptDWyEssH2kTSnA5ouZmZ9YSTEhOfDDjnZPRTP7fI17HPaHDjNgF7RGY00wmOPO7vUJ2TRE1XoBG1rNffXb-pAM5o9qTczr-q-q3RnAhhd/s1600/Getinfo+before.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3WfahZH4-sJlXSYimS-H9XA0M8PVQ7OBe-YptDWyEssH2kTSnA5ouZmZ9YSTEhOfDDjnZPRTP7fI17HPaHDjNgF7RGY00wmOPO7vUJ2TRE1XoBG1rNffXb-pAM5o9qTczr-q-q3RnAhhd/s320/Getinfo+before.png&quot; width=&quot;140&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
In the top-lefthand corner of the dialog, there is a small Automator icon. &amp;nbsp;I click on it, causing it to glow blue-ish. &amp;nbsp;While it&#39;s glowing, I press &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Command-V&lt;/span&gt;&lt;/b&gt;.&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiWQXYnmHLM14hgpD7vJMjC-XNmSe6tjPditOhog3QtD2vSfpqnYbsB-umrnrXBT1P9_DxEXiU7zKdT67p7eieadFNLDXP4Bx5J6wBuuu2w1m9s6cDXAUWld9uCfWp9saF_uDTvsawHbBO/s1600/get+info+after.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiWQXYnmHLM14hgpD7vJMjC-XNmSe6tjPditOhog3QtD2vSfpqnYbsB-umrnrXBT1P9_DxEXiU7zKdT67p7eieadFNLDXP4Bx5J6wBuuu2w1m9s6cDXAUWld9uCfWp9saF_uDTvsawHbBO/s320/get+info+after.png&quot; width=&quot;140&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&amp;nbsp;Finally I close the dialog. &amp;nbsp;I also delete the synaptic.png file as I no longer need it. &amp;nbsp;Now &amp;nbsp;My synaptic Automator workflow has he official synaptic icon.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvc_wPPLw25DXdnqeEQEP3gdSFEpwabqR75b7Aloti15IfF7kGcA41i4xO3cmGzGeF9Z6pQkY1fOMxlLDlqcT7fO5xUiMmHY2utpF6cbNz_zahceKTeH39c3akm5Q12s3L-Y21goIKDTXK/s1600/new+icon.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvc_wPPLw25DXdnqeEQEP3gdSFEpwabqR75b7Aloti15IfF7kGcA41i4xO3cmGzGeF9Z6pQkY1fOMxlLDlqcT7fO5xUiMmHY2utpF6cbNz_zahceKTeH39c3akm5Q12s3L-Y21goIKDTXK/s1600/new+icon.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I hope you found this posting helpful.&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/6813230067355006322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/6813230067355006322'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2012/05/use-automator-to-create-x11-shortcuts.html' title='Use automator to create X11 shortcuts in OSX'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg04Y80TZVXswZNj1lofwzhPz6TCWn2wpTB-ya-evK2jIZnnm8g64I4tBqeqUXkC86h275RKUFBfRR2ehLFqs6tdyGtySSSWwij3lnqks710YWk4LTQe4XlkHXqt3CCSV6611hPnw1N4QHZ/s72-c/no+password+prompt.png" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-5287792639763092307</id><published>2012-04-27T13:03:00.000-04:00</published><updated>2012-04-27T13:03:01.322-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ci"/><category scheme="http://www.blogger.com/atom/ns#" term="code coverage"/><category scheme="http://www.blogger.com/atom/ns#" term="code quality"/><category scheme="http://www.blogger.com/atom/ns#" term="continuous integration"/><category scheme="http://www.blogger.com/atom/ns#" term="jenkins"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="mocking"/><category scheme="http://www.blogger.com/atom/ns#" term="nose"/><category scheme="http://www.blogger.com/atom/ns#" term="pylint"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="unit testing"/><title type='text'>Automated python unit testing, code coverage and code quality analysis with Jenkins - part 3</title><content type='html'>This is the third and final posting in a series. &amp;nbsp;Check&amp;nbsp;&lt;a href=&quot;http://bhfsteve.blogspot.com/2012/04/automated-python-unit-testing-code.html&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;&amp;nbsp;for the first posting and &lt;a href=&quot;http://bhfsteve.blogspot.com/2012/04/automated-python-unit-testing-code_20.html&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt; for the second posting.&lt;br /&gt;
&lt;br /&gt;
In this posting I will be explaining how to automate the unit testing, code coverage and code quality analysis that we did manually in the first two posts.&lt;br /&gt;
&lt;br /&gt;
As the title of this series suggests, I use Jenkins for this automation (also known as&amp;nbsp;&lt;u&gt;c&lt;/u&gt;ontinuous&amp;nbsp;&lt;u&gt;i&lt;/u&gt;ntegration - ci). &amp;nbsp;In keeping with the theme of using apt for everything, I will install Jenkins via apt. &amp;nbsp;That being said, in my real job, I have downloaded a jenkins.war file from the &lt;a href=&quot;http://jenkins-ci.org/&quot; target=&quot;_blank&quot;&gt;Jenkins web site&lt;/a&gt; and I start it up from the command line.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;









Install and start Jenkins&lt;/h3&gt;
Jenkins appears in the default apt that ships with Ubuntu, but it&#39;s a really old version... so old, in fact, that it won&#39;t run the plugins that we&#39;ll need in order to do the code quality and code coverage analysis. &amp;nbsp;To get around this, refer to &lt;a href=&quot;http://pkg.jenkins-ci.org/debian/&quot; target=&quot;_blank&quot;&gt;these instructions&lt;/a&gt; on the Jenkins web site to update your apt sources and get the latest&amp;nbsp;version Jenkins via apt.&lt;br /&gt;
&lt;br /&gt;
Here&#39;s a quick screen-shot of the instructions you&#39;ll need to follow:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhM2F-KtKmqOt6P5a7AkBIKeCDDtwCvnx9CVtSvrKGrzaovSyyzwH681sQl7EPo-8n3DnpaLtRS0s8T0L42z60QmbW_9y32k-QYixu7jwb_OGBLmGJfLgzxrE1KPk6G1xMJ2fV2IFOiRZnv/s1600/apt+instructions.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;149&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhM2F-KtKmqOt6P5a7AkBIKeCDDtwCvnx9CVtSvrKGrzaovSyyzwH681sQl7EPo-8n3DnpaLtRS0s8T0L42z60QmbW_9y32k-QYixu7jwb_OGBLmGJfLgzxrE1KPk6G1xMJ2fV2IFOiRZnv/s320/apt+instructions.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Once you&#39;ve got Jenkins installed, check to see if Jenkins is running. &amp;nbsp;If it isn&#39;t start it.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;sudo /etc/init.d/jenkins status&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;sudo /etc/init.d/jenkins start&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVV2e_pXB0pK3V0TIBiIX4rq8Z801ZJ3lzeVEcs-tvaXAB4gR1HzFEsSrAHZce6AL7znpnw7xYvweDTid_OKMXhln8k_5UXu3mSFG4AFGq1AIc7uHQbQBxonItEqt5i1Ww7cNJe7Npu26C/s1600/Jenkins+Status+and+Startup.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVV2e_pXB0pK3V0TIBiIX4rq8Z801ZJ3lzeVEcs-tvaXAB4gR1HzFEsSrAHZce6AL7znpnw7xYvweDTid_OKMXhln8k_5UXu3mSFG4AFGq1AIc7uHQbQBxonItEqt5i1Ww7cNJe7Npu26C/s320/Jenkins+Status+and+Startup.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Once Jenkins is up and running, let&#39;s pull it up in a browser. &amp;nbsp;It will be listening on port 8080.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDhG_VwLA7vnqh8aNX0Z2KRH_vE9-0iSxaM61beQe1JqemCvPsKXeYjkOjSdVLGbu_fO0I0XiQ7WNg6gCAWrGMIEjVY3zAkJimjSMfbtowZY3Pw391v1fR6xiegwds97dNsRedeE5TNEcY/s1600/Welcome+to+Jenkins.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;247&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDhG_VwLA7vnqh8aNX0Z2KRH_vE9-0iSxaM61beQe1JqemCvPsKXeYjkOjSdVLGbu_fO0I0XiQ7WNg6gCAWrGMIEjVY3zAkJimjSMfbtowZY3Pw391v1fR6xiegwds97dNsRedeE5TNEcY/s320/Welcome+to+Jenkins.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3&gt;









Install some needed Jenkins plugins&lt;/h3&gt;
Jenkins has lots of plugins that will allow it to do lots of interesting things. &amp;nbsp;We will be needing a few of them. &amp;nbsp;To install plugins, click on the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Manage Jenkins&lt;/span&gt;&lt;/b&gt; link from the list of links on the left-hand side of the page. Next click on the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Manage Plugins&lt;/span&gt;&lt;/b&gt; link from the resulting page. &amp;nbsp;Finally click on the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Available&lt;/span&gt;&lt;/b&gt; tab from the Plugin Manager page.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPTy2D51BX-pC8wqHYPGIaZjSn8XIjwrC848F4J4Kkj7Bmw2O6PNP9MBjYWiZtWmXRvH7VjNdV3IXUkOiEIFlEHhFSOUklv1JNVmcyP41t5NcoeOFtsedAURLmiPPFILiR0GuiKf_P-RjS/s1600/Available+Plugins.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;247&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPTy2D51BX-pC8wqHYPGIaZjSn8XIjwrC848F4J4Kkj7Bmw2O6PNP9MBjYWiZtWmXRvH7VjNdV3IXUkOiEIFlEHhFSOUklv1JNVmcyP41t5NcoeOFtsedAURLmiPPFILiR0GuiKf_P-RjS/s320/Available+Plugins.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
This will show you a list of all the available plugins that Jenkins can use. Find and select (check the checkbox) for the following plugins:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Jenkins Cobertura Plugin&lt;/li&gt;
&lt;li&gt;Jenkins GIT plugin&lt;/li&gt;
&lt;li&gt;Jenkins Violations&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
After you&#39;ve check the checkboxes, click the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Download now and install after restart&lt;/span&gt;&lt;/b&gt; button at the bottom of the page.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: -webkit-auto;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Jenkins will install the selected plugins and then take a moment to restart. &amp;nbsp;After Jenkins restarts we need to make a small configuration change in order for git to work properly. &amp;nbsp;When Jenkins is done restarting, click the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Manage Jenkins&lt;/span&gt;&lt;/b&gt; link from the left-hand list of links. &amp;nbsp;The click &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Configure System&lt;/span&gt;&lt;/b&gt; from the resulting page. &amp;nbsp;This will bring up a global Jenkins configuration page. &amp;nbsp;Scroll down (past the Git section) to the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Git Plugin&lt;/span&gt;&lt;/b&gt; section. &amp;nbsp;Enter values in the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Global Config user.name Value&lt;/span&gt;&lt;/b&gt; and &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Global Config user.email Value&lt;/span&gt;&lt;/b&gt; fields. &amp;nbsp;Finally, click the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Save&lt;/span&gt;&lt;/b&gt; button at the bottom of the page.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhK5EVNF4XRIcxrI4rqEWnmpZdJi6JQxeEPHEPxBbYubotlYsnNh2Bvjt4hTFjRrv88Hm3FuAk66J8GQCgG-ytnZBNzv5c6iRipk3AUXluxCOcVfzL-PVvh3hJ-LD05-ZGWGFUX4Sv1Xm6k/s1600/Git+config.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;247&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhK5EVNF4XRIcxrI4rqEWnmpZdJi6JQxeEPHEPxBbYubotlYsnNh2Bvjt4hTFjRrv88Hm3FuAk66J8GQCgG-ytnZBNzv5c6iRipk3AUXluxCOcVfzL-PVvh3hJ-LD05-ZGWGFUX4Sv1Xm6k/s320/Git+config.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3&gt;









Our first job&lt;/h3&gt;
When Jenkins comes back, click the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;New Job&lt;/span&gt;&lt;/b&gt; link from the left-hand list of links. &amp;nbsp;This will bring you to a page where you can enter a job name and select a job type. &amp;nbsp;Enter &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Project1&lt;/span&gt;&lt;/b&gt;&amp;nbsp;for the job name and select &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Build a free-style software project&lt;/span&gt;&lt;/b&gt;, then click the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;OK&lt;/span&gt;&lt;/b&gt; button.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXbuOJ1i12_RnmEPu1K0OGUyHooRX_DHhuISDbG6wdo1kzBRKHiaDz0eetwu6fIliAHHOfx19HAdZkjIOUqTR0jLI3DAo6X3Z5pinqvSKC4vyz5RPdtE63c7FdUXN15WEa5vqIHL9tNN5q/s1600/Naming+the+first+project.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;247&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXbuOJ1i12_RnmEPu1K0OGUyHooRX_DHhuISDbG6wdo1kzBRKHiaDz0eetwu6fIliAHHOfx19HAdZkjIOUqTR0jLI3DAo6X3Z5pinqvSKC4vyz5RPdtE63c7FdUXN15WEa5vqIHL9tNN5q/s320/Naming+the+first+project.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
This will bring you to the Configure page for your new job. &amp;nbsp;This is where you tell Jenkins WHAT, WHEN and HOW to do. &amp;nbsp;Let&#39;s get started!&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;









1 - Where to get the source&lt;/h4&gt;
Under the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Source Code Management&lt;/span&gt;&lt;/b&gt; section, click the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Git&lt;/span&gt;&lt;/b&gt; radio button. &amp;nbsp;This will expand more options. &amp;nbsp;For this project we&#39;ll be keeping things simple. &amp;nbsp;Simply enter the path to your git repository. &amp;nbsp;Mine&#39;s at &lt;b style=&quot;color: blue;&quot;&gt;/home/steve/dev/project1 &lt;/b&gt;(this presumes your git repo is on the same box that Jenkins is running on).&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRs_NzkgYS6qHCZguGgF9-Td0mGzhxlNBrbk23SBltz7ylyvrxeB2FFyB_tuKu5M32NeKUUx8rhqPcHXZmzoe101tJnFqjwA3IXCGtJj9_Hv_cuHQhyphenhyphenIcK-opAySchCzfXeTIbkfRuBL_C/s1600/Source+code.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;163&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRs_NzkgYS6qHCZguGgF9-Td0mGzhxlNBrbk23SBltz7ylyvrxeB2FFyB_tuKu5M32NeKUUx8rhqPcHXZmzoe101tJnFqjwA3IXCGtJj9_Hv_cuHQhyphenhyphenIcK-opAySchCzfXeTIbkfRuBL_C/s320/Source+code.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;h4&gt;









2 - When to run the job&lt;/h4&gt;
Next go to the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Build Triggers&lt;/span&gt;&lt;/b&gt; section and check the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Poll SCM&lt;/span&gt;&lt;/b&gt; checkbox. &amp;nbsp;In the resulting &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Schedule&lt;/span&gt;&lt;/b&gt; field, enter 5 *&#39;s. &amp;nbsp;(&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;* * * * *&lt;/span&gt;&lt;/b&gt;) &amp;nbsp;This makes Jenkins check the git repository for changes once a minute, every minute of every day. &amp;nbsp;If it finds a change in the repository, it will &quot;do a build&quot;. &amp;nbsp;We&#39;ll be configuring &quot;the build&quot; to run the unit tests and code coverage and quality tests for us.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGlFMX1Jt9ulNp9Od0zEFblmBEu2Tn2xJDAP5FeiiVZJ7iUf_Ozu_FiI1LlM3YwZ7fbT7IuA_W0OsHwRkJ-cS92gzCZCocbqGXOgbyBTC0zGL5JkvWiwOKIAg6ThpaEb7BDsaifO5WKOvl/s1600/Build+triggers.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;91&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGlFMX1Jt9ulNp9Od0zEFblmBEu2Tn2xJDAP5FeiiVZJ7iUf_Ozu_FiI1LlM3YwZ7fbT7IuA_W0OsHwRkJ-cS92gzCZCocbqGXOgbyBTC0zGL5JkvWiwOKIAg6ThpaEb7BDsaifO5WKOvl/s320/Build+triggers.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
BTW, for larger Jenkins implementations (more than 10 or so Jenkins jobs), the&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Poll SCM&lt;/span&gt;&lt;/b&gt;&amp;nbsp;option is a terrible idea. &amp;nbsp;I can show you another way using git hooks if there is interest. &amp;nbsp;For now, though, let&#39;s just use the&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Poll SCM&lt;/span&gt;&lt;/b&gt;&amp;nbsp;option since this is just an example project.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;h4&gt;









3 - What to run&lt;/h4&gt;
Next, let&#39;s configure the job to do what we want it to when it detects a change in the git repository. &amp;nbsp;In the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Build&lt;/span&gt;&lt;/b&gt; section, click the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Add build step&lt;/span&gt;&lt;/b&gt; button and select &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Execute shell&lt;/span&gt;&lt;/b&gt; from the resulting popup. &amp;nbsp;In the resulting &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Command&lt;/span&gt;&lt;/b&gt; field, enter the following text:&lt;br /&gt;
&lt;br /&gt;
&lt;textarea cols=&quot;110&quot; readonly=&quot;readonly&quot; rows=&quot;5&quot; style=&quot;color: blue; font-face: courier; overflow: scroll;&quot;&gt;PYTHONPATH=&#39;&#39;
nosetests --with-xunit --all-modules --traverse-namespace --with-coverage --cover-package=project1 --cover-inclusive
python -m coverage xml --include=project1*
pylint -f parseable -d I0011,R0801 project1 | tee pylint.out
&lt;/textarea&gt;&lt;br /&gt;
&lt;br /&gt;
Let&#39;s review what&#39;s going on here. &amp;nbsp;When the Jenkins job detects that a source code change has occurred in the git repository, it will clone a copy of the repository and then run the above script against the clone.&lt;br /&gt;
&lt;br /&gt;
You&#39;ll notice that the nosetests command has become a little more complex. &amp;nbsp;I&#39;ve added a fair number of command-line arguments to it. This is to make sure that the code coverage runs over all the code, not just the code that&#39;s involved in the unit tests. &amp;nbsp;It also ensures that nosetests write&#39;s it&#39;s output to a file that Jenkins can interpret.&lt;br /&gt;
&lt;br /&gt;
When nosetests runs the code coverage, it generates a .coverage file. &amp;nbsp;Jenkins can&#39;t read that. &amp;nbsp;The third line of the script (python -m coverage xml...) converts the .coverage file to an xml format that Jenkins Cobertura plugin can read.&lt;br /&gt;
&lt;br /&gt;
The last line (pylint...) runs pylint on the project and outputs it in a format that the Violations Jenkins plugin can read. &amp;nbsp;I also have it disabling a couple warnings that I don&#39;t care to know about. &amp;nbsp;(You can customize this all you want BTW).&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJrBks-wYUVEl61ipgBCOhy7rHSI7PR6ILIxloBslWWdEdYDlWr4FUHh4Z9u8jYvkkQUrNvapjQ8YYxpa02E25GAV4WYvmvw6fl0h29HOzzyns_ebT1WP_L4PbDhtJwoO8lSd4cTAHss_q/s1600/The+build.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;98&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJrBks-wYUVEl61ipgBCOhy7rHSI7PR6ILIxloBslWWdEdYDlWr4FUHh4Z9u8jYvkkQUrNvapjQ8YYxpa02E25GAV4WYvmvw6fl0h29HOzzyns_ebT1WP_L4PbDhtJwoO8lSd4cTAHss_q/s320/The+build.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;h4&gt;



4 - Interpret the results&lt;/h4&gt;
Not only can Jenkins detect changes and run our tests. &amp;nbsp;Given the correct plugins are installed (which we did at the beginning), it can interpret the results and display them in charts/trees/etc. &amp;nbsp;For me this is the best part. &amp;nbsp;All the other stuff, I could have done with some clever scripting and cron.&lt;br /&gt;
&lt;br /&gt;
First stop is coverage. &amp;nbsp;In the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Post-build Actions&lt;/span&gt;&lt;/b&gt; section click the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Public Cobertura Coverage Report&lt;/span&gt;&lt;/b&gt; checkbox. &amp;nbsp;Then in the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Cobertura xml report pattern&lt;/span&gt;&lt;/b&gt; field, enter &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;coverage.xml&lt;/span&gt;&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6v7SUdJoXhVpzyldSjIhTDWMtv5W5nd-llT07CLJZYKGDX__y9Ht9hlunl_G9um_xR6ri2LJcPjxpijNfX-2tUWkbQ0jpljCNK-HkMYmRodFPMafZMqSQLmI7O4S3ZwGdoC4HXzzPbdOV/s1600/cobertura+config.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;160&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6v7SUdJoXhVpzyldSjIhTDWMtv5W5nd-llT07CLJZYKGDX__y9Ht9hlunl_G9um_xR6ri2LJcPjxpijNfX-2tUWkbQ0jpljCNK-HkMYmRodFPMafZMqSQLmI7O4S3ZwGdoC4HXzzPbdOV/s320/cobertura+config.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
This tells Jenkins to read a file named coverage.xml that will contain testing code coverage information in it. &amp;nbsp;The line listed below (from the build script in step 3) is what creates this file:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;python -m coverage xml --include=project1*&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Next, click the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Publish JUnit test result report&lt;/span&gt;&lt;/b&gt; checkbox and enter&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;nosetests.xml&lt;/span&gt;&lt;/b&gt; in the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Test report XMLs&lt;/span&gt;&lt;/b&gt; field.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLonXkxsVEoiTCo7gagwfXZqPKFsv9Yk4T_IrzTeAOfSu5jodS3UC2STbQOA3v6FPgrv_BLa0US06ImcNN68ZCpU3-KSBzKCVRokQuAIQkq3v9y70Py1kJVGH-0Di9cEAQHiyaK-HSPgjw/s1600/Junit+setting.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;71&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLonXkxsVEoiTCo7gagwfXZqPKFsv9Yk4T_IrzTeAOfSu5jodS3UC2STbQOA3v6FPgrv_BLa0US06ImcNN68ZCpU3-KSBzKCVRokQuAIQkq3v9y70Py1kJVGH-0Di9cEAQHiyaK-HSPgjw/s320/Junit+setting.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
This instructs Jenkins to interpret the a file named nosetests.xml that the nose command from creates:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;nosetests --with-xunit --all-modules --traverse-namespace --with-coverage --cover-package=project1 --cover-inclusive&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Finally, check the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Report Violations&lt;/span&gt;&lt;/b&gt; checkbox and enter&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;**/pylint.out&lt;/span&gt;&lt;/b&gt; in the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;pylint&lt;/span&gt;&lt;/b&gt; field.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWkp0ZU8gp_Mp_RVY8fFVhKv6i9SI94LUE93AeGeWcTMdUA5h2jV_EvvkGOOxxUjsvxTfMQIjP34unvbbZGMyuzgGQF3ywY7HLMpBh62jU4ONpU-mKhWB0yrvwc-QCVMB-S9x97nh0H8Pn/s1600/Violations.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWkp0ZU8gp_Mp_RVY8fFVhKv6i9SI94LUE93AeGeWcTMdUA5h2jV_EvvkGOOxxUjsvxTfMQIjP34unvbbZGMyuzgGQF3ywY7HLMpBh62jU4ONpU-mKhWB0yrvwc-QCVMB-S9x97nh0H8Pn/s320/Violations.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
This instructs Jenkins to interpret the &lt;b&gt;pylint.out&lt;/b&gt; file that is generated by the pylint command from the build script:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;pylint -f parseable -d I0011,R0801 project1 | tee pylint.out&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
At this point, you&#39;re done configuring the job. &amp;nbsp;Click the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Save&lt;/span&gt;&lt;/b&gt; button. &amp;nbsp;Now you&#39;re ready to give it a go!&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Run the job&lt;/h3&gt;
Click the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;Build Now&lt;/span&gt;&lt;/b&gt; link on the left-hand list of links. &amp;nbsp;This will manually kick off a run of the job. &amp;nbsp;If no errors. &amp;nbsp;You should see a screen that looks like the one below. &amp;nbsp;If not refresh your page.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfGo9XBD3NCM7-08UFJhFibVGWbRul3oxf86qhQdHawrSJHpfoWK6kEx6NuIUeo0PT0dPhYyjDHQDVfnQgazNGObfThBZR42cNWssNuMIQas7jnVV9OsSPWZJt2xDJDTOqmTnqAHleA-P-/s1600/First+run.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;265&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfGo9XBD3NCM7-08UFJhFibVGWbRul3oxf86qhQdHawrSJHpfoWK6kEx6NuIUeo0PT0dPhYyjDHQDVfnQgazNGObfThBZR42cNWssNuMIQas7jnVV9OsSPWZJt2xDJDTOqmTnqAHleA-P-/s320/First+run.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Not very interesting, is it? &amp;nbsp;That&#39;s because we currently have 100% coverage and no test failures! &amp;nbsp;Let&#39;s add some code (without tests) and see what happens.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Update the code&lt;/h4&gt;
Add the following code to your ~/dev/project1/project1/authentication.py file. &amp;nbsp;Then save and commit it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;def logout():&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; print &#39;You are now logged out.&#39;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTVemJk2_qmWO-X4nGykaPzXUIEnCe-cU6PpgzDGZ8MZ_QVyaMJr6LsKjQwSA33wLy_1_drCRvesUX8ndRZrjqHn_q50bZ9gejeL6h_ndq5OMLPQdSCjpiXbgxCTF9KC-aeiOe6gspiRfH/s1600/editing+authentication.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTVemJk2_qmWO-X4nGykaPzXUIEnCe-cU6PpgzDGZ8MZ_QVyaMJr6LsKjQwSA33wLy_1_drCRvesUX8ndRZrjqHn_q50bZ9gejeL6h_ndq5OMLPQdSCjpiXbgxCTF9KC-aeiOe6gspiRfH/s320/editing+authentication.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIcydiZvVLLslTSyW5T7GjNEeHlJjUnSag3TpQb-9_RHBWsLdYDNSnOKIh0mKQCyE7v_5ZwBRCkCO-BAggNIjcXX0vAdKVrLsEAnB3bdnaDH5rMG6RGOfIM-zYVx8ZVbHmUyokMPoUlwGQ/s1600/commit+logout.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIcydiZvVLLslTSyW5T7GjNEeHlJjUnSag3TpQb-9_RHBWsLdYDNSnOKIh0mKQCyE7v_5ZwBRCkCO-BAggNIjcXX0vAdKVrLsEAnB3bdnaDH5rMG6RGOfIM-zYVx8ZVbHmUyokMPoUlwGQ/s320/commit+logout.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
No go back to your Jenkins window and refresh the Project1 page. &amp;nbsp;You may need to wait a minute. &amp;nbsp;Remember, Jenkins only checks the git repository for changes once a minute. &amp;nbsp;You should see some new info. &amp;nbsp;The top graph is your code coverage. &amp;nbsp;It indicates that you&#39;ve dropped from 100% line coverage to 92%. &amp;nbsp;This makes sense because we added function, but no test for it.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The second graph is your unit test pass/fail trend. &amp;nbsp;It&#39;s all blue because all 3 of our tests are still passing. &amp;nbsp;We&#39;ll break that next by adding a test for logout that fails. &amp;nbsp;:-)&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The third graph is your code quality report. &amp;nbsp;It&#39;s indicating that we had 0 issues in the first build, but now have 1 issue in the second build.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSviUNQ7AxQkyIu2S-f8EInam-QVcxgilFZ9-O6kKeM4uAR-PfgHJtualRR7jau-ZUMSJJjJ4UCJOSQYlKamj1nRTnRJTXkiA7py2Lv3biXtYHYjIpizHlkWNHGMsQnhSZRXRGx1Dd9KF0/s1600/jenkins+after+logout+added.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;309&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSviUNQ7AxQkyIu2S-f8EInam-QVcxgilFZ9-O6kKeM4uAR-PfgHJtualRR7jau-ZUMSJJjJ4UCJOSQYlKamj1nRTnRJTXkiA7py2Lv3biXtYHYjIpizHlkWNHGMsQnhSZRXRGx1Dd9KF0/s320/jenkins+after+logout+added.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
You can get more info by clicking on the graphs. &amp;nbsp;For example, let&#39;s drill into the code coverage graph.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg60MKpoQAGASM28MC-f4UrdxTdVNfXa_PyfClFHHl8c7ue-vMP2IXYkbFidHgYSnUsqbM6i1yWVoSc47IZtFp_-SsO_IeYJDlx-xKMS_w5ZhutxkX9EFqTGHLu05OSYOOnrOqSSgwn0K06/s1600/code+coverage+1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;247&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg60MKpoQAGASM28MC-f4UrdxTdVNfXa_PyfClFHHl8c7ue-vMP2IXYkbFidHgYSnUsqbM6i1yWVoSc47IZtFp_-SsO_IeYJDlx-xKMS_w5ZhutxkX9EFqTGHLu05OSYOOnrOqSSgwn0K06/s320/code+coverage+1.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
You can browse even deeper. &amp;nbsp;Click on the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;project1&lt;/span&gt;&lt;/b&gt; link at the bottom.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1vgDg8aZwmR4ArbohNosGOP1YwujCgLl_iHT9V5FzfgK3R3nIt0Szo6g-e3XwUOCw7a8z-zEOE8hYvzSQTAB_D0E1f3RnGlokLwx8GUcOy_oIc_1IyB9aPs6KAYKhROwh9Wai6zvzFEl5/s1600/code+coverage+2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;314&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1vgDg8aZwmR4ArbohNosGOP1YwujCgLl_iHT9V5FzfgK3R3nIt0Szo6g-e3XwUOCw7a8z-zEOE8hYvzSQTAB_D0E1f3RnGlokLwx8GUcOy_oIc_1IyB9aPs6KAYKhROwh9Wai6zvzFEl5/s320/code+coverage+2.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Then click on the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;authentication.py&lt;/span&gt;&lt;/b&gt; link at the bottom.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8E2SXzTA5ECbb2sXUnMOl8CzS2BxNAQX9VcJjJ_arLYteB7AUj4gximyiuHOsJTNeUYcsT-QN2JkocxfkPcDu8bdboRZMtOefoFQOTnEt3O6rSxz8epoCxDtK5NguAZ9Disymnjn_0IBT/s1600/code+coverage+3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;283&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8E2SXzTA5ECbb2sXUnMOl8CzS2BxNAQX9VcJjJ_arLYteB7AUj4gximyiuHOsJTNeUYcsT-QN2JkocxfkPcDu8bdboRZMtOefoFQOTnEt3O6rSxz8epoCxDtK5NguAZ9Disymnjn_0IBT/s320/code+coverage+3.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
As you can see by the red line at the bottom, the print&amp;nbsp;statement&amp;nbsp;at the bottom is never&amp;nbsp;exercised&amp;nbsp;by a unit test. &amp;nbsp;Hmmmm. &amp;nbsp;We&#39;ll need to fix that.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h4&gt;
Add a failing test&lt;/h4&gt;
&lt;div&gt;
Add this code to the ~/dev/project1/tests/authentication_tests.py file and then commit it to git:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; def test_logout(self):&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Test the logout function...badly.&quot;&quot;&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.assertEqual(0, 1)&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZugOkdfIV1mAE0U9OClLjQW34MK4yuW7aFNvPPtseZS8S5hP3zTN5fSROMy6ebuJkfO28g75KGlBheJZycB2fOkOnUasM6Cn5Agv2fZjB1_LWYRopYAUnisBeA2fsbFXkoXlVKJdMTTvO/s1600/add+a+failing+test.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZugOkdfIV1mAE0U9OClLjQW34MK4yuW7aFNvPPtseZS8S5hP3zTN5fSROMy6ebuJkfO28g75KGlBheJZycB2fOkOnUasM6Cn5Agv2fZjB1_LWYRopYAUnisBeA2fsbFXkoXlVKJdMTTvO/s320/add+a+failing+test.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Wait a minute and then go back to the Jenkins Project1 page. &amp;nbsp;It should now have a third build reporting the test failure.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSaldxHXoml1x6Kxy2RNIGZqTTHiTTiUSWA5VyLUuW00aYHfrivDTdJy7qj9v_NfBB3dbt_UCYAjaZ1aHivDXDLGhRGnKe3sJJoswir6GjJE30yk5ukgBGi9P52o50Wr472l-G-0XvsNn3/s1600/jenkins+with+a+failing+test.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;312&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSaldxHXoml1x6Kxy2RNIGZqTTHiTTiUSWA5VyLUuW00aYHfrivDTdJy7qj9v_NfBB3dbt_UCYAjaZ1aHivDXDLGhRGnKe3sJJoswir6GjJE30yk5ukgBGi9P52o50Wr472l-G-0XvsNn3/s320/jenkins+with+a+failing+test.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
That&#39;s it. &amp;nbsp;Hope you found this helpful. &amp;nbsp;Happy coding.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/5287792639763092307'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/5287792639763092307'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2012/04/automated-python-unit-testing-code_27.html' title='Automated python unit testing, code coverage and code quality analysis with Jenkins - part 3'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhM2F-KtKmqOt6P5a7AkBIKeCDDtwCvnx9CVtSvrKGrzaovSyyzwH681sQl7EPo-8n3DnpaLtRS0s8T0L42z60QmbW_9y32k-QYixu7jwb_OGBLmGJfLgzxrE1KPk6G1xMJ2fV2IFOiRZnv/s72-c/apt+instructions.png" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-5494134807836187824</id><published>2012-04-20T12:03:00.000-04:00</published><updated>2012-04-20T13:33:37.468-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ci"/><category scheme="http://www.blogger.com/atom/ns#" term="code coverage"/><category scheme="http://www.blogger.com/atom/ns#" term="code quality"/><category scheme="http://www.blogger.com/atom/ns#" term="continuous integration"/><category scheme="http://www.blogger.com/atom/ns#" term="jenkins"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="mocking"/><category scheme="http://www.blogger.com/atom/ns#" term="nose"/><category scheme="http://www.blogger.com/atom/ns#" term="pylint"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="unit testing"/><title type='text'>Automated python unit testing, code coverage and code quality analysis with Jenkins - part 2</title><content type='html'>This is the second posting in a series. &amp;nbsp;Check &lt;a href=&quot;http://bhfsteve.blogspot.com/2012/04/automated-python-unit-testing-code.html&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt; for the first posting.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;



Where we gonna do this?&lt;/h3&gt;
First let&#39;s create a directory and repository to house the source code. &amp;nbsp; Enter the following commands:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b style=&quot;background-color: white;&quot;&gt;mkdir -p ~/dev/project1&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b style=&quot;background-color: white;&quot;&gt;git init ~/dev/project1&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b style=&quot;background-color: white;&quot;&gt;cd ~/dev/project1&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
It should go something like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRvjlCviCA3T_2FSyJWGnyydWcqY3HlQ1eoAv6MfFOfR4Kqj4fei2TPzT5ZIuQLAKRgwvkC21Temm1HQu_bkWeY7db3kk_ZQqE-nKJmSP3mb-cGCUurCUVSPftRMmaYC3efridnzIL0lWQ/s1600/Create+directory+and+repo.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRvjlCviCA3T_2FSyJWGnyydWcqY3HlQ1eoAv6MfFOfR4Kqj4fei2TPzT5ZIuQLAKRgwvkC21Temm1HQu_bkWeY7db3kk_ZQqE-nKJmSP3mb-cGCUurCUVSPftRMmaYC3efridnzIL0lWQ/s320/Create+directory+and+repo.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Next, I always add a &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;.gitignore&lt;/span&gt;&lt;/b&gt; file to my repository so&amp;nbsp;unrelated files aren&#39;t tracked in source control. &amp;nbsp;Mine contains the following:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;*.swp&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;*.pyc&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;tags&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;.coverage&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Once I&#39;ve created this file, I add it to the git repository with the following commands:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;git add .gitignore&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;git commit -m&quot;Initial commit. &amp;nbsp;Added a .gitignore file.&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
It should look like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfXy2P52FKkhiyk2beLQq2-3CGGVgBWUWbcFuwN4ER_mfbGIMF3LtDwOcYtgZ4Le45vy_T5EcWhG8_ks9Ven7OmSfDY3zxFuO5t-dbCIt6Kt-aHRBkXjnwwfcVf-haEn7GO4ZAZ75AcrVD/s1600/Adding+.gitignore.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfXy2P52FKkhiyk2beLQq2-3CGGVgBWUWbcFuwN4ER_mfbGIMF3LtDwOcYtgZ4Le45vy_T5EcWhG8_ks9Ven7OmSfDY3zxFuO5t-dbCIt6Kt-aHRBkXjnwwfcVf-haEn7GO4ZAZ75AcrVD/s320/Adding+.gitignore.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3&gt;



Let&#39;s get some source code in place&lt;/h3&gt;
Before we get too ahead of ourselves, let&#39;s pause for some quick explanation. &amp;nbsp;I don&#39;t like to mix my application code with my unit test code. &amp;nbsp;I keep them separate. &amp;nbsp;My application code will eventually need to be deployed somewhere, but the unit test code doesn&#39;t. &amp;nbsp;To that end, I put the application code in one python package named after the project and the unit test code in another package called &quot;tests&quot;. &amp;nbsp;So let&#39;s create the two packages with the following commands:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;mkdir project1&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;touch project1/__init__.py&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;mkdir tests&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;touch tests/__init__.py&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
This might not be a bad place to do a quick commit to source control:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;git add .&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;git commit -m&quot;Added two blank packages: project1 and tests&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Again, should look like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLCEmt2egVMIlcZCjU-e9-gWwhWP9-nyXvcJJBSpkirb9tOXG65q1dxvBCdb4feiVeCYa9tSG9GtkNVOyAgViWvD1tr7MlFPJC19xfGwDaX-wRyHiiC3XboaPxF6IzNWCgdyT61gKp2o73/s1600/Added+blank+packages.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLCEmt2egVMIlcZCjU-e9-gWwhWP9-nyXvcJJBSpkirb9tOXG65q1dxvBCdb4feiVeCYa9tSG9GtkNVOyAgViWvD1tr7MlFPJC19xfGwDaX-wRyHiiC3XboaPxF6IzNWCgdyT61gKp2o73/s320/Added+blank+packages.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
You could run the test runner, coverage and code analysis tools now, but the output wouldn&#39;t be very interesting. &amp;nbsp;Instead, let&#39;s move on and add a failing test.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;



The first test&lt;/h3&gt;
If you&#39;re a TDD type developer, this shouldn&#39;t come as a surprise. &amp;nbsp;We&#39;ll write a test first. &amp;nbsp;Then write some code in order to get the test to pass. &amp;nbsp;In the tests directory, create a file named &quot;&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;authentication_tests.py&lt;/span&gt;&lt;/b&gt;&quot; and place the following code in it:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;#!/usr/bin/env python&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&quot;&quot;&quot;Unit tests for the project1.authentcation module.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;from unittest import TestCase&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;from mock import patch&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;import project1.authentication as auth&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;class StandAloneTests(TestCase):&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Test the stand-alone module functions.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; @patch(&#39;__builtin__.open&#39;)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; def test_login(self, mock_open):&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Test the login function.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mock_open.return_value.read.return_value = \&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;george|bosco\n&quot;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.assertTrue(auth.login(&#39;george&#39;, &#39;bosco&#39;))&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This is a test the will test a function named login that will reside project1.authentication module. &amp;nbsp;If you run it now, it should fail because we haven&#39;t created an authentication module yet, much less a login function. &amp;nbsp;To run the tests, simply type &quot;&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;nosetests&lt;/span&gt;&lt;/b&gt;&quot; from the project root directory. &amp;nbsp;Nose will scan your whole directory structure looking for unit tests to run.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3DDZKXjf9FBj6gjSppWcc6M4AMvreWDBQNeStk7o0CcLW6zElHUtghH0Ue2NQteXOKd2RxAKc6sH6cWfjBAgRMjYeiNo6iAL0H4ZU8WExvpPp2N5NVc-uv0nTJZG0MxpkJrMj36wf-G0F/s1600/Miserable+Failure.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3DDZKXjf9FBj6gjSppWcc6M4AMvreWDBQNeStk7o0CcLW6zElHUtghH0Ue2NQteXOKd2RxAKc6sH6cWfjBAgRMjYeiNo6iAL0H4ZU8WExvpPp2N5NVc-uv0nTJZG0MxpkJrMj36wf-G0F/s320/Miserable+Failure.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3&gt;



&lt;/h3&gt;
&lt;h3&gt;



Let&#39;s get the test to pass&lt;/h3&gt;
&lt;div&gt;
Before we can move on to the topics of coverage and quality, we need to get the test to pass. &amp;nbsp;To do this, &amp;nbsp;create a file in the project1 directory named &quot;&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;authentication.py&lt;/span&gt;&lt;/b&gt;&quot; and place the following code in it:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;#!/usr/bin/env python&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&quot;&quot;&quot;This module provides functions for authenticating users.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;def login(username, password):&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; try:&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; user_file = open(&#39;/etc/users.txt&#39;) &amp;nbsp; &amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; user_buf = user_file.read()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; users = [line.split(&quot;|&quot;) for line in user_buf.split(&quot;\n&quot;)]&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if [username, password] in users:&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return True&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; else:&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return False&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; except Exception, exc:&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; print &quot;I can&#39;t authenticate you.&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return False&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Now when you run the test, everything should be hunky-dory.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOiDs06Ta_DkCRyomHZ00MyKQILc9j9DS__hp6JzjZDET224HqFgTpCN1A8p9qjLXdYGu-ZKvJMUMdC041VZaOllpZqkbBTd8GgdFganxlU_KojYNfhV6j2W7IRMMmqL_puhr3vPyybMuM/s1600/Passing+test.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOiDs06Ta_DkCRyomHZ00MyKQILc9j9DS__hp6JzjZDET224HqFgTpCN1A8p9qjLXdYGu-ZKvJMUMdC041VZaOllpZqkbBTd8GgdFganxlU_KojYNfhV6j2W7IRMMmqL_puhr3vPyybMuM/s320/Passing+test.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3&gt;



&lt;/h3&gt;
&lt;h3&gt;



Code Coverage&lt;/h3&gt;
&lt;div&gt;
You&#39;re probably thinking things look pretty good right about now. &amp;nbsp;Let&#39;s run the the code coverage tool to see where we stand. &amp;nbsp;To run a coverage test, use this command: &quot;&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;nosetests --with-coverage --cover-package=project1&lt;/span&gt;&lt;/b&gt;&quot;. &amp;nbsp;You&#39;ll find that we only have 67% coverage and that our test doesn&#39;t&amp;nbsp;exercise&amp;nbsp;lines 12-15 of our login method. Yikes.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzXm9tLIKha1fO641ysEDWR6SkOT8vECzRaAZ3kBbd3xUgqVB62mXXqdH61MZoVHLJJr-wBbzUj9OcKPmlSAz-HviSzbOYVEregFweZsn9v1eSrRGNiQ4pgGFHlXJcdoBDWnd0AzQEynB6/s1600/Coverage+failure.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzXm9tLIKha1fO641ysEDWR6SkOT8vECzRaAZ3kBbd3xUgqVB62mXXqdH61MZoVHLJJr-wBbzUj9OcKPmlSAz-HviSzbOYVEregFweZsn9v1eSrRGNiQ4pgGFHlXJcdoBDWnd0AzQEynB6/s320/Coverage+failure.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
You see... &amp;nbsp;In our single test, we&#39;re only covering the &lt;i&gt;happy path(tm)&lt;/i&gt;. &amp;nbsp;That is, we only check to see what the function does when a user enters a valid username/password. &amp;nbsp;We don&#39;t check what happens when they enter an invalid username/password. &amp;nbsp;Additionally, we don&#39;t check to see what the function does when it can&#39;t read the user file at all. &amp;nbsp;We would need to add more tests for that. &amp;nbsp;Edit the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;tests/authentication_tests.py&lt;/span&gt;&lt;/b&gt; file and make it look like this:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;#!/usr/bin/env python&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&quot;&quot;&quot;Unit tests for the project1.authentication module.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;from unittest import TestCase&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;from mock import patch&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;import project1.authentication as auth&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;class StandAloneTests(TestCase):&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Test the stand-alone module functions.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; @patch(&#39;__builtin__.open&#39;)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; def test_login_success(self, mock_open):&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Test the login function when things go right.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mock_open.return_value.read.return_value = \&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;george|bosco&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.assertTrue(auth.login(&#39;george&#39;, &#39;bosco&#39;))&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; @patch(&#39;__builtin__.open&#39;)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; def test_login_bad_creds(self, mock_open):&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Test the login function when bad creds are passed.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mock_open.return_value.read.return_value = \&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;george|bosco&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.assertFalse(auth.login(&#39;george&#39;, &#39;marbleRye&#39;))&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; @patch(&#39;__builtin__.open&#39;)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; def test_login_error(self, mock_open):&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Test the login function when an error happens.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mock_open.side_effect = IOError()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.assertFalse(auth.login(&#39;george&#39;, &#39;bosco&#39;))&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Notice I&#39;ve added two more tests: &amp;nbsp;one to test invalid creds and one to test an exception&amp;nbsp;occurring. &amp;nbsp;Now we have 100% coverage.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu0t781ImilF87qIDbsvv2p_e1HPYqPxVxhLO3mBct18Kvw-m_NYQBAaegidQTajtyTHDTQQm8Ne1iNYF-nOktZwcWOXIM51NGCX-_5YicFc5AX8lSP1xQdo82vvk2aQSx7NRUT3tIKy3P/s1600/Coverage+success.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu0t781ImilF87qIDbsvv2p_e1HPYqPxVxhLO3mBct18Kvw-m_NYQBAaegidQTajtyTHDTQQm8Ne1iNYF-nOktZwcWOXIM51NGCX-_5YicFc5AX8lSP1xQdo82vvk2aQSx7NRUT3tIKy3P/s320/Coverage+success.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3&gt;



&lt;/h3&gt;
&lt;h3&gt;



Code Quality&lt;/h3&gt;
&lt;div&gt;
So we now have tests that pass and 100% coverage. &amp;nbsp;That&#39;s&amp;nbsp;awesome!&amp;nbsp; Everything&#39;s under control now. &amp;nbsp;What did you say? &amp;nbsp;&quot;How about the quality of that code?&quot; &amp;nbsp;Let&#39;s check it out and see. &amp;nbsp;To take a look at code quality use the following command: &quot;&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;pylint -r n project1&lt;/span&gt;&lt;/b&gt;&quot;. &amp;nbsp;Ah. Well. &amp;nbsp;We have a few things to clean up. &amp;nbsp;Pylint is notoriously whiny. &amp;nbsp;That said, the things it&#39;s&amp;nbsp;complaining&amp;nbsp;about in this case are legitimate if you&#39;re concerned about being a good python developer.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLhFh9opZk2-Xeqi-00RT2pKnceJRPgY63NW1FSdyW70DysGkcm3l_NdYB07hP1B-VxxJiX0yhzYw0uP8VBxaP4rmNlLBPUPUaWU7McpXao2jZ8KAFXp9SE3btRK8IDQQq3fYfLoHYCJQz/s1600/Quality+attempt+1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLhFh9opZk2-Xeqi-00RT2pKnceJRPgY63NW1FSdyW70DysGkcm3l_NdYB07hP1B-VxxJiX0yhzYw0uP8VBxaP4rmNlLBPUPUaWU7McpXao2jZ8KAFXp9SE3btRK8IDQQq3fYfLoHYCJQz/s320/Quality+attempt+1.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
So let&#39;s get ourselves into compliance. &amp;nbsp;First let&#39;s add a docstring to the project1 package. &amp;nbsp;Edit &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;project1/__init__.py&lt;/span&gt;&lt;/b&gt; and make it look like this:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;#!/usr/bin/env python&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;Project1 is Steve&#39;s example project for the blog.&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;It contains sample code here and there.&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
That takes care of the first pylint complaint. &amp;nbsp;Next let&#39;s fix up the &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;project1/authentication.py&lt;/span&gt;&lt;/b&gt; file. &amp;nbsp;Edit it and make it look like this:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;#!/usr/bin/env python&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&quot;&quot;&quot;This module provides functions for authenticating users.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;def login(username, password):&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &quot;&quot;&quot;Log the user in.&quot;&quot;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; try:&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; user_file = open(&#39;/etc/users.txt&#39;) &amp;nbsp; &amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; user_buf = user_file.read()&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; users = [line.split(&quot;|&quot;) for line in user_buf.split(&quot;\n&quot;)]&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return [username, password] in users&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; except IOError:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; print &quot;I can&#39;t authentication you.&quot;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;color: blue; font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return False&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Now when you run pylint, you should have no complaints:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-jcQXLa_rNx-X1gdFYC85J9x3bxFqE27mQhGAB_kJbq7NC9Qw2B5DYMNcSBEEFuvcpHLi1g8BdBI4It-Tia23iPS9xQjKjY9TMazS8UoYv7wGLnvUoWQmVeohFctDAYEf8m29CPkHP6Iz/s1600/Quality+attempt+2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-jcQXLa_rNx-X1gdFYC85J9x3bxFqE27mQhGAB_kJbq7NC9Qw2B5DYMNcSBEEFuvcpHLi1g8BdBI4It-Tia23iPS9xQjKjY9TMazS8UoYv7wGLnvUoWQmVeohFctDAYEf8m29CPkHP6Iz/s320/Quality+attempt+2.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
If you want a more detailed report from pylint, try using the command, &quot;&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;pylint -r y project1&lt;/span&gt;&lt;/b&gt;&quot; instead. &amp;nbsp;Used that way, it&#39;s very much more verbose.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLM4lWrybRYgldPgpPSfThzCAhepFL-D3rmqzjkmBQVg9jTSMZSnFlrXhsVAsjIu_mF_QW4Yppt2KC05uqApfUpUmKx9B4SBCrpwVy2zYpKI9gD5-1slCdUKdU9j3hBLO_xKRK2zzOKFfq/s1600/Quality+verbose.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLM4lWrybRYgldPgpPSfThzCAhepFL-D3rmqzjkmBQVg9jTSMZSnFlrXhsVAsjIu_mF_QW4Yppt2KC05uqApfUpUmKx9B4SBCrpwVy2zYpKI9gD5-1slCdUKdU9j3hBLO_xKRK2zzOKFfq/s320/Quality+verbose.png&quot; width=&quot;178&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;



Let&#39;s clean up&lt;/h3&gt;
&lt;div&gt;
So here&#39;s what we&#39;ve accomplished so far. &amp;nbsp;We created a project and source code repository. &amp;nbsp;We&#39;ve created a sample piece of code and some tests for it. &amp;nbsp;We&#39;ve ensured that we have 100% code coverage and we&#39;ve analysed our code quality and found it to be in good shape. &amp;nbsp;Let&#39;s pause and make sure that all our work is committed to source control.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirqTFgzNh9esvubUJP8-YGp5fk5JGHSZ4Js4vE4rCrqiRBIYwv_yz9cc5_fp4ps_iCnhqMfkFbhCmhdKD87n1G8QsZJVcGc0-hi_7Yu3x5PXxN5mTlaHvnRIENCKKXAh2QAwExV2RGbEeu/s1600/Commit+code+to+git.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirqTFgzNh9esvubUJP8-YGp5fk5JGHSZ4Js4vE4rCrqiRBIYwv_yz9cc5_fp4ps_iCnhqMfkFbhCmhdKD87n1G8QsZJVcGc0-hi_7Yu3x5PXxN5mTlaHvnRIENCKKXAh2QAwExV2RGbEeu/s320/Commit+code+to+git.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
That&#39;s it for now. &amp;nbsp;In the next post, I will walk through installing Jenkins and configuring it to monitor your source code repository. &amp;nbsp;It will notice when you commit new code and automatically run your unit tests, code coverage and code quality analysis. &amp;nbsp;It can be configured to notify you when things don&#39;t look so good. &amp;nbsp;It can also display nice graphs over time of how your code is progressing. &amp;nbsp;Stay tuned.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/5494134807836187824'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/5494134807836187824'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2012/04/automated-python-unit-testing-code_20.html' title='Automated python unit testing, code coverage and code quality analysis with Jenkins - part 2'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRvjlCviCA3T_2FSyJWGnyydWcqY3HlQ1eoAv6MfFOfR4Kqj4fei2TPzT5ZIuQLAKRgwvkC21Temm1HQu_bkWeY7db3kk_ZQqE-nKJmSP3mb-cGCUurCUVSPftRMmaYC3efridnzIL0lWQ/s72-c/Create+directory+and+repo.png" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-1742534590631713650</id><published>2012-04-20T09:11:00.000-04:00</published><updated>2012-04-20T09:12:16.009-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ci"/><category scheme="http://www.blogger.com/atom/ns#" term="code coverage"/><category scheme="http://www.blogger.com/atom/ns#" term="code quality"/><category scheme="http://www.blogger.com/atom/ns#" term="continuous integration"/><category scheme="http://www.blogger.com/atom/ns#" term="jenkins"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="mocking"/><category scheme="http://www.blogger.com/atom/ns#" term="nose"/><category scheme="http://www.blogger.com/atom/ns#" term="pylint"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="unit testing"/><title type='text'>Automated python unit testing, code coverage and code quality analysis with Jenkins - part 1</title><content type='html'>As a software development consultant, I do a fair amount of&amp;nbsp;&lt;a href=&quot;http://www.python.org/&quot; target=&quot;_blank&quot;&gt;python&lt;/a&gt;&amp;nbsp;development and even though python is a scripting language, I feel that it&#39;s still worthy of good coding practices, namely: unit testing, code coverage analysis and code quality analysis. &amp;nbsp;In this series of blog postings I will describe my python development environment and how I engage the tools.&lt;br /&gt;
&lt;br /&gt;
In this specific blog post, I will talk about the tools I use and how to get them installed/configured. &amp;nbsp;In future postings I&#39;ll set up a sample code base with sample unit tests and run the tests manually. &amp;nbsp;Finally in the last posting, I&#39;ll talk about using Jenkins to automate the testing.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Let&#39;s get started&lt;/b&gt;&lt;br /&gt;
I tend to do most of my python development on the Linux platform. &amp;nbsp;I love python&#39;s cross platform features. &amp;nbsp;While most of my client implementations actually run in Microsoft Windows, I still do my development in Linux.&lt;br /&gt;
&lt;br /&gt;
For the purposes of this blog series, I will be using &lt;a href=&quot;http://www.ubuntu.com/&quot; target=&quot;_blank&quot;&gt;Ubuntu&lt;/a&gt; 11.10, the 64 bit version. &amp;nbsp;This distribution/version isn&#39;t necessary, but that what I&#39;m using. &amp;nbsp;Python 2.7 comes with the default installation. &amp;nbsp;If for whatever reason python isn&#39;t installed on your system, just type &quot;&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;sudo apt-get install python&lt;/span&gt;&lt;/b&gt;&quot; from the bash prompt:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_RhMKU7vMvfIiz-hfNiMXG69R4hly1cIrOrwXqkdB6t4_Nj9kSWo60lCna6tyIMcFIdMJWyJDCEHM2zsK5fGkjnhyphenhyphenUTm4nToRl5UEv5BH-TpvABLlqhVOqm39YvR3lScEpbOP_CtG7fUn/s1600/Install+Python.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_RhMKU7vMvfIiz-hfNiMXG69R4hly1cIrOrwXqkdB6t4_Nj9kSWo60lCna6tyIMcFIdMJWyJDCEHM2zsK5fGkjnhyphenhyphenUTm4nToRl5UEv5BH-TpvABLlqhVOqm39YvR3lScEpbOP_CtG7fUn/s320/Install+Python.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;b&gt;Source control&lt;/b&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
When we move on to automating the testing/analysis, you&#39;ll need to have some source control in place. &amp;nbsp;I use git. &amp;nbsp;Even if you aren&#39;t planning on doing the automation part, source control is still a good idea. &amp;nbsp;Again, you can get it with a single command: &quot;&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;sudo apt-get install git&lt;/span&gt;&lt;/b&gt;&quot;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6RzVm5E2pZcsofSBy6okTY05mM6L2tIoPqI0hUkLBPO5p-YuPPQqgIlcAPUXpwzJSikqoaOwSU8GpgAevToXtspvtwfJG0jkN7jNUwnOAM8-KXuJAIcfp8cRgoaVYk61DjTrUrT1ubVv6/s1600/Install+git.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6RzVm5E2pZcsofSBy6okTY05mM6L2tIoPqI0hUkLBPO5p-YuPPQqgIlcAPUXpwzJSikqoaOwSU8GpgAevToXtspvtwfJG0jkN7jNUwnOAM8-KXuJAIcfp8cRgoaVYk61DjTrUrT1ubVv6/s320/Install+git.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;b&gt;Tools of the trade&lt;/b&gt;&lt;br /&gt;
There are a number of testing, quality and coverage tools out there for python. &amp;nbsp;These are the ones I use:&lt;br /&gt;
&lt;br /&gt;
Unit testing: &amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;unittest&lt;/span&gt;&lt;/b&gt; - Comes with python. &amp;nbsp;It&#39;s part of the standard library.&lt;br /&gt;
Mocking: &amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;mock&lt;/span&gt;&lt;/b&gt; by Michael Foord - It&#39;s available in apt.&lt;br /&gt;
Test runner: &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;nose&lt;/span&gt;&lt;/b&gt; - Also available in apt.&lt;br /&gt;
Code coverage: &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;coverage&lt;/span&gt;&lt;/b&gt; - Also, &lt;i&gt;also&lt;/i&gt; available in apt.&lt;br /&gt;
Code quality: &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;pylint &lt;/span&gt;-&lt;/b&gt;&amp;nbsp; Also, &lt;i&gt;also, also&lt;/i&gt; available in apt.&lt;br /&gt;
&lt;br /&gt;
So to get all these great tools you simply need to type one command: &quot;&lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;sudo apt-get install python-mock python-nose python-coverage pylint&lt;/span&gt;&lt;/b&gt;&quot;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfjmA31CpXwPWa31gMf-HjpMhAIbyFjOYNxfSy-F06Pb9QCyJq57nkIVHaZWzfWcPfpLl6s_FeCxTkT3i_zSxGMzLcwdlPi3CMwfepDLKY-0S0qMdNP8iPFgKrel8g0fgoF6ToF4ZDQeko/s1600/Install+tools.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfjmA31CpXwPWa31gMf-HjpMhAIbyFjOYNxfSy-F06Pb9QCyJq57nkIVHaZWzfWcPfpLl6s_FeCxTkT3i_zSxGMzLcwdlPi3CMwfepDLKY-0S0qMdNP8iPFgKrel8g0fgoF6ToF4ZDQeko/s320/Install+tools.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
That&#39;s it. &amp;nbsp;If you&#39;re following along, you should have a fully ready python development environment. &amp;nbsp;Tune in to the next posting where I&#39;ll create a repository, some sample code and sample unit tests. &amp;nbsp;Then I&#39;ll manually run the testing, coverage and quality analysis tools against it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/1742534590631713650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/1742534590631713650'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2012/04/automated-python-unit-testing-code.html' title='Automated python unit testing, code coverage and code quality analysis with Jenkins - part 1'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_RhMKU7vMvfIiz-hfNiMXG69R4hly1cIrOrwXqkdB6t4_Nj9kSWo60lCna6tyIMcFIdMJWyJDCEHM2zsK5fGkjnhyphenhyphenUTm4nToRl5UEv5BH-TpvABLlqhVOqm39YvR3lScEpbOP_CtG7fUn/s72-c/Install+Python.png" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-4312481443349522150.post-5608073548247212153</id><published>2012-04-13T11:19:00.000-04:00</published><updated>2012-04-13T11:19:49.969-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="osx"/><category scheme="http://www.blogger.com/atom/ns#" term="vi"/><category scheme="http://www.blogger.com/atom/ns#" term="vim"/><category scheme="http://www.blogger.com/atom/ns#" term="x11"/><title type='text'>Copy and paste from vim</title><content type='html'>I&#39;ve added the following to my .vimrc:&lt;br /&gt;
&lt;br /&gt;
&lt;textarea cols=&quot;80&quot;&gt;map &amp;lt;Leader&amp;gt;c :w !xclip -sel clip&amp;lt;cr&amp;gt;&amp;lt;cr&amp;gt;
map &amp;lt;Leader&amp;gt;p :r !xclip -o -sel clip&amp;lt;cr&amp;gt;
&lt;/textarea&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
It allows me to&amp;nbsp;highlight&amp;nbsp;text in a file and then hit &#39;\c&#39; to copy the highlighted text to my X11 clipboard in Ubuntu.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
It also allows me to just hit &#39;\p&#39; to paste from the X11 clipboard to the vim buffer.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
My .vimrc in OSX has the following to provide the same functionality when I&#39;m on the Mac:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;textarea cols=&quot;80&quot;&gt;map &amp;lt;Leader&amp;gt;c :w !pbcopy&amp;lt;cr&amp;gt;&amp;lt;cr&amp;gt;
map &amp;lt;Leader&amp;gt;p :r !pbpaste&amp;lt;cr&amp;gt;
&lt;/textarea&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/5608073548247212153'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4312481443349522150/posts/default/5608073548247212153'/><link rel='alternate' type='text/html' href='http://bhfsteve.blogspot.com/2012/04/copy-and-paste-from-vim.html' title='Copy and paste from vim'/><author><name>bhfsteve</name><uri>http://www.blogger.com/profile/07467841231478317132</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI8ha6ujwyRK4_7yPagrysqeTtVweKEwcncfp3Is_OwMZi_dy5KsTQspE7bS6HokJdQ90C7_P5QmBZGG1OtUUq9OQ1SoZn9zkSgAmYeEy7RMvCGRDM_wrkFSwkvxJ5_W4/s220/profile-pic.png'/></author></entry></feed>