<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>cxreg&apos;s tech blag</title>
    <link rel="alternate" type="text/html" href="http://cxreg.com/blag/" />
    <link rel="self" type="application/atom+xml" href="http://cxreg.com/blag/atom.xml" />
    <id>tag:cxreg.com,2010-06-17:/blag//2</id>
    <updated>2011-06-06T02:48:52Z</updated>
    <subtitle>cxreg plays with open source</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 5.02</generator>

<entry>
    <title>Per-directory environment variables, now safer and better</title>
    <link rel="alternate" type="text/html" href="http://cxreg.com/blag/2011/05/per-directory-environment-variables-now-safer-and-better.html" />
    <id>tag:cxreg.com,2011:/blag//2.6</id>

    <published>2011-05-30T08:03:56Z</published>
    <updated>2011-06-06T02:48:52Z</updated>

    <summary>As I wrote about previously, using bash_varstash and bash_smartcd you can set up your bash shell to set important environment variables without intervention when changing to particular directories, and have it automatically restore them to their previous state when leaving....</summary>
    <author>
        <name>cxreg</name>
        
    </author>
    
        <category term="Shell scripting" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en-us" xml:base="http://cxreg.com/blag/">
        <![CDATA[As I wrote about <a href="/blag/2010/06/bash-arrays-variable-stashing-and-cd-aliasing-magic.html">previously</a>, using bash_varstash and bash_smartcd you can set up your bash shell to set important environment variables without intervention when changing to particular directories, and have it automatically restore them to their previous state when leaving. &nbsp;The library is <a href="https://github.com/cxreg/smartcd">on github</a>.<div><div><br /></div><div>While this library has served me very well, I've now released a new version with several significant and interesting changes.</div><div><br /></div><div><font class="Apple-style-span" style="font-size: 1.25em; "><b>autostash</b></font></div><div><font class="Apple-style-span" style="font-size: 1.25em; "><br /></font></div><div>First is the addition of a new command, called <i>autostash</i>. It will perform the unstash for you, if run from smartcd, when the directory is left, without explicit configuration. &nbsp;This significantly lowers the already fairly low bar for using this feature, and adds a bit more DTRT.</div><div><br /></div><div>An example might now look like this:</div><div><br /></div><div>autostash PATH</div><div>export PATH=/foo:$PATH</div><div><br /></div><div>and that's all you need! &nbsp;Maybe in a later release, these can be combined into a single command, but not today.</div><div><br /></div><div><font class="Apple-style-span" style="font-size: 1.25em; "><b>New script layout</b></font></div><div><br /></div><div>Second is a complete change in structure in how the scripts themselves are located and executed. &nbsp;Previously, files would be co-located with the directory they correspond to. &nbsp;For example, the directory /foo/bar would contain the file /foo/bar/.bash_enter which would be run upon 'cd'ing into it. &nbsp;Now, however, the files are located in a hierarchy under your home directory, primarily for security reasons.</div><div><br /></div><div>To make the transition easier, if a legacy script is found, smartcd will notify you about it and tell you how to migrate it to the proper location. &nbsp;In addition, if you manually run stash, unstash, or autostash, they too will tell you how to create a proper script to automate the action you just ran.</div><div><br /></div><div>Here are some examples of this in action:</div><div><br /></div><div><div>$ cd my-project/</div><div># NOTICE! &nbsp;Deprecated .bash_enter found, please migrate this file to the new</div><div># format using the following (or similar) commands:</div><div>mkdir -p "/home/username/.smartcd/home/username/my-project"</div><div>cat "/home/username/my-project/.bash_enter" &gt;&gt; "/home/username/.smartcd/home/username/my-project/bash_enter"</div><div>rm "/home/username/my-project/.bash_enter"</div></div><div><br /></div><div><div>$ autostash PATH</div><div># You are manually autostashing a variable. &nbsp;To automatically perform this</div><div># whenever you enter this directory, paste the following command(s):</div><div>mkdir -p "/home/username/.smartcd/home/username/my-project"</div><div>echo autostash PATH &gt;&gt; "/home/username/.smartcd/home/username/my-project/bash_enter"</div></div><div><br /></div><div>To turn off these help messages, you can set the variable VARSTASH_QUIET</div><div><br /></div><div><b><font class="Apple-style-span" style="font-size: 1.25em; ">Interactive and automatic configuration</font></b></div><div><b><font class="Apple-style-span" style="font-size: 1.25em; "><br /></font></b></div><div>To additionally simplify configuring things, some additional methods for editing the bash_enter and bash_leave scripts are provided.</div><div><br /></div><div>If you just want the recommended actions listed in the previous section to be performed for you with no questions asked, you can set the variable&nbsp;VARSTASH_AUTOCONFIG</div><div><br /></div><div><div>$ VARSTASH_AUTOCONFIG=1</div></div><div><div>$ autostash foo</div><div>Automatically running echo autostash foo &gt;&gt; "/home/username/.smartcd/home/username/bash_enter"</div></div><div><br /></div><div>If you simply want to open the file in your preferred editor, you can run <i>varstash_edit</i></div><div><br /></div><div><div>$ varstash_edit</div><div>Usage: varstash_edit ( bash_enter | bash_leave )</div><div>$ varstash_edit bash_enter</div><div>[ $EDITOR invoked on the correct bash_enter file ]</div><div><br /></div></div><div>This can also happen automatically when you type stash, unstash, or autostash if you set the variable&nbsp;VARSTASH_AUTOEDIT. &nbsp;This will first add the commands, as with&nbsp;VARSTASH_AUTOCONFIG, then launch your editor</div><div><br /></div><div><div>$ VARSTASH_AUTOEDIT=1</div><div>Automatically running echo autostash foo &gt;&gt; "/home/username/.smartcd/home/username/bash_enter"</div></div><div><div>[ $EDITOR invoked on the correct bash_enter file ]</div></div></div>]]>
        
    </content>
</entry>

<entry>
    <title>Bash arrays, variable stashing, and cd aliasing = magic goodness</title>
    <link rel="alternate" type="text/html" href="http://cxreg.com/blag/2010/06/bash-arrays-variable-stashing-and-cd-aliasing-magic.html" />
    <id>tag:cxreg.com,2010:/blag//2.3</id>

    <published>2010-06-19T04:48:43Z</published>
    <updated>2011-06-06T02:53:25Z</updated>

    <summary><![CDATA[To scratch a few itches that I had, I wrote a number of bash functions.&nbsp; These are published on Github at http://github.com/cxreg/smartcdThis repository is made of 3 components, each of which are separately useful:bash_arraysbash_varstashbash_smartcdAnd with their powers combined, you can.....]]></summary>
    <author>
        <name>cxreg</name>
        
    </author>
    
        <category term="Linux" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Shell scripting" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="bash" label="Bash" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="environmentvariable" label="Environment variable" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="shell" label="Shell" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="shellscript" label="Shell script" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="unix" label="Unix" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://cxreg.com/blag/">
        <![CDATA[To scratch a few itches that I had, I wrote a number of bash functions.&nbsp; These are published on Github at <a href="http://github.com/cxreg/smartcd">http://github.com/cxreg/smartcd</a><br /><br />This repository is made of 3 components, each of which are separately useful:<br /><br /><ul><li>bash_arrays</li><li>bash_varstash</li><li>bash_smartcd</li></ul>And with their powers combined, you can.. well let's not get ahead of ourselves.<br /><br /><font style="font-size: 0.8em;"><b><font style="font-size: 1.25em;">bash_arrays</font></b></font><b><font style="font-size: 1em;"><br /><br /></font></b><font style="font-size: 1em;">Bash is a very featureful shell.&nbsp; It has things that many people aren't even aware of.&nbsp; One such feature, added in 2.0, is the ability for shell variables to be real arrays, instead of just strings.&nbsp; Using string variables and IFS (Internal Field Separator, if you don't know, don't ask) to manage multiple values can be very frustrating.<br /><br />You can initialize array variables with the syntax "name=(value1 ... valuen)", and assign individual elements like "name[subscript]=value".&nbsp; You access them by index like "${name[subscript]}"<br /><br /><i>$ foo=(bar baz biff)<br />$ echo ${foo[2]}<br />biff<br />$ foo[3]=blah<br />$ echo ${foo[3]}<br /></i></font><i><br />$ foo[3]=blah<br />$ echo ${foo[3]}<br />blah</i><br /><br />However, this syntax is pretty awkward, and almost no convenience functions are supplied.&nbsp; If you've worked with any high level dynamic languages, you'll be familiar with things such as push, pop, shift, unshift, and reverse.<br /><br />These missing functions are provided by the included file <i>bash_arrays</i>, and are named <br /><ul><li>apush - add an element to the end of the array<br /></li><li>apop - remove an element from the end of the array<br /></li><li>ashift - remove an element from the beginning of the array<br /></li><li>aunshift - add an element to the beginning of the array<br /></li><li>areverse - reorder the array backwards<br /></li></ul>along with a few others<br /><ul><li>afirst - print the first element but leave it in place<br /></li><li>alast - print the last element but leave it in place<br /></li><li>alen - print the number of elements in the array<br /></li></ul>The "a*" naming convention is to indicate that they work on arrays, and to avoid possible naming conflicts with other functions that might use such common words.<br /><br />Example usage:<br /><br /><i>$ apush foo bar baz biff<br />$ alen foo<br />3<br />$ apop foo<br />biff<br />$ apop foo<br />baz<br />$ apop foo<br />bar</i><br /><br />Unfortunately, there isn't a simple way to both modify a shell variable and "return" a value. The only way to capture a non-numeric return value is by executing a sub-shell, which will modify the value only in the sub-shell.&nbsp; The modification is of course lost when that shell exits.<br /><br /><i>bar=$(apop foo) # $bar has a value, but $foo is unmodified!</i><br /><br />To work around this shortcoming, the mutators (functions which modify the array) that also need to return a value (apop and ashift) set a variable which contains the returned value, $_apop_return and $_ashift_return respectively.<br /><br /><i>apop foo &gt;/dev/null # run in current shell, and quiet output<br />bar=$_apop_return<br /><br /></i><b>bash_varstash</b><i><br /></i><br />This file provides 2 functions, <i>stash</i> and <i>unstash</i>.&nbsp; <i>stash</i> stores the value of a variable to a temporary location.&nbsp; <i>unstash</i> restores its value from the temporary variable and deletes it.&nbsp; The name of the temporary variable is derived from the current working directory of the shell, which means you'll need to be in the directory you stashed from to unstash properly.<br /><br /><i>$ export FOO=bar<br />$ echo $FOO<br />bar<br />$ stash FOO<br />$ export FOO=baz<br />$ echo $FOO<br />baz<br />$ unstash FOO<br />$ echo $FOO<br />bar</i><br /><br />While this might sound a bit arcane, it is specifically useful with...<br /><br /><b>bash_smartcd</b><br /><br />This file provides a replacement for cd.&nbsp; It runs the specially named "<i>.bash_enter</i>" shell script when it enters a directory, and runs "<i>.bash_leave</i>" when it moves away, using the <i>bash_arrays</i> functions to keep track of things.<br /><br />Once loaded, it's enabled by simply adding<br /><br /><i>alias cd=smartcd</i><br /><br />to your shell initialization file.&nbsp; All path differences are incrementally inspected when changing directories, so it will "leave" the necessary path elements before "entering" the new ones.<br /><br />For example:<br /><br /><i>/foo/bar/baz$ cd /foo/biff</i><br /><br />This would "leave" baz, then bar, and then enter biff. /foo is ignored because it is common to both paths.<br /><br />And now for the motivating reason for all of these libraries...<br /><br />*drumroll*<br /><br />When <i>smartcd</i> is combined with <i>stash</i> and <i>unstash</i>, you can achieve something pretty amazing: <b>per-directory environment variables.&nbsp; </b>These can be useful for many things, including automagically modifying PATH, PERL5LIB,
ORACLE_HOME, or any number of other settings you might want to tweak when
you cd into a development directory or some other special environment.&nbsp; If set up properly, they will be restored to their original values when leaving.<br /><br />Let's inspect the scripts:<br /><br /><i>$ cat foo/.bash_enter<br />echo entering `pwd`<br />stash FOO<br />export FOO=baz<br /><br />$ cat foo/.bash_leave<br />unstash FOO<br />echo leaving `pwd`<br /><br />$ cat foo/bar/.bash_enter<br />echo entering `pwd`<br />stash FOO<br />export FOO=biff<br /><br />$ cat foo/bar/.bash_leave<br />unstash FOO<br />echo leaving `pwd`<br /><br /></i>Notice that you can stash the same variable multiple times, at different levels.&nbsp; Now, let's set the variable and try it out.<br /><br /><i>$ export FOO=bar<br /><br />$ cd foo<br />entering /home/count/foo<br /><br />$ echo $FOO<br />baz<br /><br />$ cd bar<br />entering /home/count/foo/bar<br /><br />$ echo $FOO<br />biff<br /><br />$ cd<br />leaving /home/count/foo/bar<br />leaving /home/count/foo<br /><br />$ echo $FOO<br />bar</i><br />


<div style="margin-top: 10px; height: 15px;" class="zemanta-pixie"><a class="zemanta-pixie-a" href="http://www.zemanta.com/" title="Enhanced by Zemanta"><img style="border: medium none ; float: right;" class="zemanta-pixie-img" src="http://img.zemanta.com/zemified_e.png?x-id=31411527-db2e-4f90-b020-f3b8b31b608e" alt="Enhanced by Zemanta" /></a></div>]]>
        
    </content>
</entry>

<entry>
    <title>git only</title>
    <link rel="alternate" type="text/html" href="http://cxreg.com/blag/2010/06/git-only.html" />
    <id>tag:cxreg.com,2010:/blag//2.1</id>

    <published>2010-06-18T03:04:08Z</published>
    <updated>2010-06-18T03:57:10Z</updated>

    <summary><![CDATA[By now, everyone knows that Git is the best source control system since sliced RCS. &nbsp;I don't have to tell you about that.Sometimes, you want to see what commits you have on a branch, but you want to see *only*...]]></summary>
    <author>
        <name>cxreg</name>
        
    </author>
    
    <category term="gitsoftware" label="Git (software)" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://cxreg.com/blag/">
        <![CDATA[By now, everyone knows that <a class="zem_slink" href="http://en.wikipedia.org/wiki/Git_%28software%29" title="Git (software)" rel="wikipedia">Git</a> is the best <a class="zem_slink" href="http://en.wikipedia.org/wiki/Revision_control" title="Revision control" rel="wikipedia">source control</a> system since sliced <a class="zem_slink" href="http://en.wikipedia.org/wiki/Revision_Control_System" title="Revision Control System" rel="wikipedia">RCS</a>. &nbsp;I don't have to tell you about that.<div><br /></div><div>Sometimes, you want to see what commits you have on a branch, but you want to see <b>*only*</b> the commits on that branch, and aren't on any other. &nbsp;If you happen to know which branch it came from, it's simple to do something like this:</div><div><br /></div><div><i>git log starting_branch..new_branch</i></div><div><br /></div><div>But if you don't know or care where it came from, this is more difficult. &nbsp;In order to do this, you might craft a complicated command line that looks something like this:</div><div><br /></div><div><div><i>git log $(git rev-parse --not --branches | grep -v $(git rev-parse &lt;branch&gt;)) &lt;branch&gt;</i></div></div><div><i><br /></i></div><div>but this is impossible to remember, and annoying to type. &nbsp;Fortunately, Git makes it trivial to add commands in several ways:</div><div><br /></div><div><ol><li>Create a program and put it in your $PATH, and name it git-something, which then allows you to run "git something"</li><li>Make an alias, which can simply add arguments to other git commands, or which can shell out to a system command</li></ol></div><div><br /></div><div>For this problem, I chose the second option. &nbsp;However, since the convoluted command I wrote above requires you to pass the &lt;branch&gt; argument twice, an ordinary alias is not sufficient. &nbsp;I decided to use a shell function to help.</div><div><br /></div><div>First, we'll define the function. &nbsp;You can put this in your .bashrc or .bash_profile, or somewhere similar:</div><div><br /></div><div><div><i>git_only() {</i></div><div><i>&nbsp;&nbsp; &nbsp;opts=$(git rev-parse --no-revs "$@" 2&gt;/dev/null)</i></div><div><i>&nbsp;&nbsp; &nbsp;rev=$(git rev-parse --revs-only "$@" 2&gt;/dev/null)</i></div><div><i>&nbsp;&nbsp; &nbsp;if [[ -z $rev ]]; then</i></div><div><i>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;branch=$(git name-rev --name-only HEAD)</i></div><div><i>&nbsp;&nbsp; &nbsp;else</i></div><div><i>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;branch=$rev</i></div><div><i>&nbsp;&nbsp; &nbsp;fi</i></div><div><i>&nbsp;&nbsp; &nbsp;git log $(git rev-parse --not --remotes --branches | grep -v $(git rev-parse $branch)) $branch $opts</i></div><div><i>}</i></div><div><br /></div><div>Note that it uses git's rev-parse command to separate options from revisions, so that you'll be able to pass most arguments to this that you'd normally pass to "git log", including -- pathspecs</div><div><br /></div><div>Then you need to export the function so that sub-shells can also see it</div><div><br /></div><div><i>export -f git_only</i></div></div><div><br /></div><div>Finally, you simply add it to git's config as an alias:</div><div><br /></div><div><i>git config --global alias.only '!git_only'</i></div><div><br /></div><div>And that's it! &nbsp;Now you're ready to try it out:</div><div><br /></div><div><i>$ git only origin/foobar</i></div><div><br /></div><div>As written, this does have a couple of shortcomings:</div><div><br /></div><div><ol><li>Any "revision arguments" will be eaten by rev-parse, so things like --no-merges wont work</li><li>Since refs are parsed to SHA1s before grepping out the one that you want to inspect, if it's exactly identical to another branch, it will still be shown even though it's not actually unique</li></ol></div><div class="zemanta-pixie" style="margin-top:10px;height:15px">If I figure out workaround to those issues, I'll update the post with a new version of the function.</div>]]>
        
    </content>
</entry>

</feed>

