<?xml version="1.0" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <atom:link href="http://www.mivok.net/rss.xml" rel="self"
            type="application/rss+xml" />
        <description>mivok.net blog</description>
        <generator>jekyll</generator>
        <title>Mivok.net</title>
        <language>en-US</language>
        <link>http://www.mivok.net</link>
        <ttl>60</ttl>
        
        <item>
            <guid>http://www.mivok.net//2012/04/14/vimcram.html</guid>
            <link>http://www.mivok.net//2012/04/14/vimcram.html</link>
            <title>Vimcram - making testing vim scripts suck less</title>
            <description>&lt;p&gt;A while ago I was reading a blog post with tips on &lt;a href='http://stevelosh.com/blog/2011/09/writing-vim-plugins/'&gt;writing vim plugins&lt;/a&gt;. There&amp;#8217;s lot of good information there, and if you find yourself writing any vim scripts or plugins, it&amp;#8217;s well worth a read. I was surprised by one point though, the section on &lt;a href='http://stevelosh.com/blog/2011/09/writing-vim-plugins/#unit-testing-will-make-you-drink'&gt;testing&lt;/a&gt;. My &lt;a href='https://github.com/mivok/vimtodo'&gt;vimtodo plugin&lt;/a&gt; has a large number of regression tests, and it&amp;#8217;s my safety net to make sure that I&amp;#8217;ve not horribly broken something with my latest change. I don&amp;#8217;t subscribe to the test driven development philosophy of writing a test and coding only until it passes, but I do find it useful to have a few tests to guard against you breaking something.&lt;/p&gt;

&lt;p&gt;So when I read that testing sucks so much in Vim that you should avoid it, I was a little surprised, and certainly disagreed with the sentiment. My tests work fine, and I don&amp;#8217;t recall it being particularly hard to implement the tests. So I took a look at the shell script testing tool mentioned in the blog post, &lt;a href='https://bitheap.org/cram/'&gt;cram&lt;/a&gt;, to see what was so special about it. I looked back at my tests in vimtodo, then at the example of the cram page, and back at my tests. The cram example showed a test that basically looked like a transcript of a shell session, and definitely not like the mess of code that comprised my tests. I thought that it couldn&amp;#8217;t be too hard to implement something like that for vim, and the guy who wrote the blog post offered to buy a nice bottle of scotch for anyone who did so. One can never drink too much scotch (this may or may not be true), and so I got cracking.&lt;/p&gt;

&lt;p&gt;The result is &lt;a href='https://github.com/mivok/vimcram'&gt;vimcram&lt;/a&gt;, which is now up on github. There are still a few features I&amp;#8217;d like to add, but it&amp;#8217;s pretty usable, and I&amp;#8217;m currently converting all of my tests on vimtodo over to using it.&lt;/p&gt;

&lt;p&gt;Tests in vimcram look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Test substituting text:

    &amp;gt; Add some text
    &amp;gt; Add some more text
    :%s/some //
    Add text
    Add more text

Test normal mode commands

    @ggdW
    @jdW
    text
    more text&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which, while not exactly a transcript of a vim session (it&amp;#8217;s kind of hard to do with a visual editor and multiple modes), is pretty straightforward.&lt;/p&gt;

&lt;p&gt;If you have a vim plugin and don&amp;#8217;t have any tests for it, give vimcram a try. It might make test writing easy enough that you actually write them!&lt;/p&gt;</description>
            <pubDate>Sat, 14 Apr 2012 00:00:00 -0700</pubDate>
        </item>
        
        <item>
            <guid>http://www.mivok.net//2012/01/27/site-on-github.html</guid>
            <link>http://www.mivok.net//2012/01/27/site-on-github.html</link>
            <title>Mivok.net is now hosted on github with jekyll</title>
            <description>&lt;p&gt;Ever since I saw Jekyll, I liked the idea of having a statically generated site for something as simple as a blog where you really don&amp;#8217;t need dynamic content (except for comments where, as you can see below, I cheated and used &lt;a href='http://www.intensedebate.com'&gt;intense debate&lt;/a&gt;). But I hadn&amp;#8217;t touched anything in ruby before (at the time it probably wasn&amp;#8217;t even installed on my web server), was suffering from not-invented-here syndrome, and decided to write my own version in Python. It was clunky, but it worked, for the most part. Two years later however, it&amp;#8217;s seen no love, was in dire need of some maintenance/improvement, and I finally realized that pretty much everything I wanted to do was already done in Jekyll.&lt;/p&gt;

&lt;p&gt;The site was simple to convert (the original program being an attempted clone), and it now means that I can punt on hosting and let github deal with things. And if github turns out not to be a good choice, then it&amp;#8217;s simple to host anywhere. It is after all, a static site.&lt;/p&gt;</description>
            <pubDate>Fri, 27 Jan 2012 00:00:00 -0800</pubDate>
        </item>
        
        <item>
            <guid>http://www.mivok.net//2012/01/27/bup.html</guid>
            <link>http://www.mivok.net//2012/01/27/bup.html</link>
            <title>Backups with bup</title>
            <description>&lt;p&gt;I&amp;#8217;m thinking about backups once more, and thought I would take a look at &lt;a href='https://github.com/apenwarr/bup'&gt;bup&lt;/a&gt;. Bup&amp;#8217;s claim to fame (and the reason I first heard about it) is that it&amp;#8217;s a git based backup system, or rather it uses the git repository format, with its own tools to make it deal with large files effectively. The more I looked at it, the more I realized that bup being git-based isn&amp;#8217;t the main feature. Bup has a rolling checksum algorithm similar to rsync and splits up files so that only changes are backed up, even in the case of large files. This also has a nice side effect: you get deduplication of data for free. This includes space efficient backups of VM images, and files across multiple computers (the OS files are almost identical). I have two laptops with the same data (git repositories, photos, other work) on both of them, and multiple VM images used for testing, so the ability to have block level deduplication in backups sounded ideal.&lt;/p&gt;

&lt;p&gt;Bup can also generate &lt;a href='http://en.wikipedia.org/wiki/Parchive'&gt;par2&lt;/a&gt; files for error recovery, and has commands to verify/recover corrupted backups. This is a useful feature given that bup goes to great lengths to ensure that each piece of data is only stored once.&lt;/p&gt;

&lt;p&gt;My old backups were with rsnapshot, and as it happened, bup has a conversion tool for this, so the first step was to move them over to using bup. The command do to this is &lt;code&gt;bup import-rsnapshot&lt;/code&gt;, but this didn&amp;#8217;t quite work for me and gave an error when running bup save. Thankfully there is a dry-run option which prints out the commands that bup uses, and because rsnapshot backups direct copies of the files, what bup does is basically back up the backup. So I ended up running:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;export BUP_DIR=/bup
/usr/bin/bup index -ux -f bupindex.rigel.tmp manual.0/rigel/
/usr/bin/bup save --strip --date=1314714851 -f bupindex.rigel.tmp \
    -n rigel manual.0/rigel/&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The two bup commands were directly output from the &lt;code&gt;import-rsnapshot&lt;/code&gt; command, and I did this multiple times for each backup I had.&lt;/p&gt;

&lt;p&gt;Next was to take the initial backup from my laptop. This was actually a different laptop from the one I took the rsnapshot backups with, but I&amp;#8217;d copied over a lot of the data and wanted to see how well the dedup feature worked. As can be seen with the rsnapshot import, taking a backup is actually two steps, &lt;code&gt;bup index&lt;/code&gt; followed by &lt;code&gt;bup save&lt;/code&gt;. The &lt;code&gt;index&lt;/code&gt; command generates a list of files to back up, while the &lt;code&gt;save&lt;/code&gt; command actually does it. The documentation gives a couple of reasons for splitting this in to two steps, mainly that it allows you to use a different method (such as inotify) to generate and update the index, and it also allows you to only generate the list of files once if you are backing up to multiple locations. This separation of duties appeals to the tinkerer in me, but it would still have been nice to have a shortcut &amp;#8216;just back it up&amp;#8217; command, similar to how &lt;code&gt;git
pull&lt;/code&gt; is a combination of &lt;code&gt;git fetch&lt;/code&gt; and &lt;code&gt;git merge&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The commands to take a backup are:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;export BUP_DIR=/bup
bup index -ux --exclude=/bup /
bup save -n procyon /&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;First, I set the backup directory to /bup. What I&amp;#8217;m doing here is backing up locally (and copying to an external hard drive later), but you can also pass the &lt;code&gt;-r&lt;/code&gt; option to back up directly to a remote server via ssh.&lt;/p&gt;

&lt;p&gt;I also pass the &lt;code&gt;-x&lt;/code&gt; option to &lt;code&gt;bup index&lt;/code&gt; to limit it to one filesystem, and also exclude the backup directory itself from the backup.&lt;/p&gt;

&lt;p&gt;Next, the &lt;code&gt;bup save&lt;/code&gt; command actually performs that backup. I passed in the hostname of my laptop (procyon) as the name of the backup set. Multiple backups can have the same name, and they show up as multiple git commits, so a hostname is a good choice for the name of the backup set.&lt;/p&gt;

&lt;p&gt;As I mentioned above, bup can make use of &lt;code&gt;par2&lt;/code&gt; to generate parity files. This is a separate step, and is done using the &lt;code&gt;bup fsck&lt;/code&gt; command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;bup fsck -g -j4&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;-g&lt;/code&gt; option generates the par2 files, and the &lt;code&gt;-j 4&lt;/code&gt; option means run up to 4 par2 jobs at the same time. Generating parity files is CPU intensive, so I set it to twice the number of CPUs in my system. I have hyperthreading turned on, and it saturated all 4 &amp;#8216;virtual&amp;#8217; CPUs. Once this was done, I ended up with several .par2 files in the &lt;code&gt;/bup/objects/pack&lt;/code&gt; directory (this is a git repository, and all data is stored in the &lt;code&gt;objects/&lt;/code&gt; dir.&lt;/p&gt;

&lt;p&gt;And the results? Bup used 30GB for 2 original backups from rsnapshot (rsnapshot used 26GB and 37GB for the first and second backups, and this was taking into account identical files). Then, when I backed up my 2nd laptop (with approx 40GB used at the time) the size of the bup backup increased by only 4GB. This backup of my laptop included a 5GB ubuntu VM image that didn&amp;#8217;t exist in the previous snapshots, so bup must have been able to deal with the duplicate data from the image and the live OS.&lt;/p&gt;

&lt;p&gt;All of this sounds amazing, but of course there are a few downsides, all of which are spelled out pretty plainly in the bup README:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no metadata - these are backups of my personal laptop, and I&amp;#8217;ll be restoring either single files, or reinstalling and copying over files as I need them, so losing permissions/file ownership etc. isn&amp;#8217;t a big deal for me. However, this feature is supposed to be coming soon.&lt;/li&gt;

&lt;li&gt;no way to prune old backups - this is another feature that is coming soon, but given that I&amp;#8217;m a pack rat, rarely deleting old data, and the dedup feature, I&amp;#8217;m not too concerned for the moment.&lt;/li&gt;

&lt;li&gt;bup is relatively new and immature. This shows both in the possible bugs I encountered above, the lack of what some might consider essential features, and the somewhat low level command usage (separate index, save and fsck commands). This is easily worked around however, and is likely to improve in future.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That said, if you can live with the above limitations, and want incredible space savings for your backups (especially across multiple computers), then I would suggest giving bup a try.&lt;/p&gt;</description>
            <pubDate>Fri, 27 Jan 2012 00:00:00 -0800</pubDate>
        </item>
        
        <item>
            <guid>http://www.mivok.net//2010/03/31/solaris-freebsd.html</guid>
            <link>http://www.mivok.net//2010/03/31/solaris-freebsd.html</link>
            <title>From Solaris to FreeBSD</title>
            <description>&lt;p&gt;Less than one week after I switched my hosting over to Solaris 10, with all its ZFS/dtrace goodness, Oracle quietly makes a &lt;a href='http://arstechnica.com/open-source/news/2010/03/solaris-10-no-longer-free-as-in-beer-now-a-90-day-trial.ars'&gt;license change&lt;/a&gt; that everybody dealing with Solaris is likely now familiar with, and Solaris 10 is no longer free to use. Emails to Sun/Oracle&amp;#8217;s licensing department result only in form letters repeating instructions on the website, and then nothing.&lt;/p&gt;

&lt;p&gt;I can&amp;#8217;t really blame Oracle for this, Sun didn&amp;#8217;t make enough money to survive, and Oracle has this radical idea that you need to actually charge people in order to make money. I can blame them for not providing more clarity regarding the issue (so far they haven&amp;#8217;t announced anything), and for leaving customers unsure about what&amp;#8217;s going to happen next. However, this is mostly besides the point. I now needed to look into a good alternative.&lt;/p&gt;

&lt;p&gt;OpenSolaris is the obvious candidate, and I&amp;#8217;ve played around with it a little previously, but I can&amp;#8217;t make myself like some of the changes made to it. The biggest annoyances being related to the new packaging system and some of the poor choices made in its design (e.g. no &amp;#8211;nodeps option). That is an entire post (or rather, rant) in itself however. In addition to this, I can&amp;#8217;t help but believe that Oracle is going to make some change to OpenSolaris that makes it not a realistic option.&lt;/p&gt;

&lt;p&gt;This is where FreeBSD comes in. With release 8.0, ZFS has become a fully supported filesystem. It has dtrace support, jails (just like zones), even &lt;a href='http://bsdbased.com/2009/11/27/vimage-better-virtualization-in-freebsd-8'&gt;virtual networking&lt;/a&gt; so you can have a full network stack inside the jail.&lt;/p&gt;

&lt;p&gt;For my personal server, the main feature I was interested in was ZFS, specifically ZFS root/boot. With ZFS it is trivial to set up mirrored drives, and I wanted to avoid doing software raid with UFS as well as ZFS. Thankfully there is &lt;a href='http://wiki.freebsd.org/RootOnZFS'&gt;extensive documentation&lt;/a&gt; on how to do this. It isn&amp;#8217;t in the standard install, but if you need a repeatable procedure for many servers, it&amp;#8217;s a (relatively) simple matter to script the installation, and you would probably want to do this anyway for an automated install.&lt;/p&gt;

&lt;p&gt;There were a few gotchas, as with any new system you&amp;#8217;re not familiar with, but so far it looks quite nice. I&amp;#8217;ll be looking further into jails (especially the vimage jails) and other nice features. Hopefully, FreeBSD will turn out to be a good replacement for Solaris.&lt;/p&gt;</description>
            <pubDate>Wed, 31 Mar 2010 00:00:00 -0700</pubDate>
        </item>
        
        <item>
            <guid>http://www.mivok.net//2010/03/05/gitosis.html</guid>
            <link>http://www.mivok.net//2010/03/05/gitosis.html</link>
            <title>Gitosis - manage git repositories sanely</title>
            <description>&lt;p&gt;I&amp;#8217;ve finally made all my projects available publicly via git at http://git.mivok.net/ thanks to &lt;a href='http://eagain.net/gitweb/?p=gitosis.git'&gt;gitosis&lt;/a&gt;. Before that, I kind of just thrown everything in a git directory under my home directory and accessed it over ssh, which worked fine for private repositories, but fell flat whenever I wanted to make something available to somebody else.&lt;/p&gt;

&lt;p&gt;Gitosis promised to make it easy to add new repositories and set up access for new people as needed, and once everything is set up, it is really easy - everything is contained in a config file inside a git repository, so you can make changes locally and push. You also have the benefit that your changes themselves are under version control. However, there were a few hiccups along the way, so I&amp;#8217;m going to describe what I did in case others try and hit the same problems I did.&lt;/p&gt;

&lt;p&gt;Gitosis uses python and setuptools, which I already had available. I&amp;#8217;m running Ubuntu, so installing any requirements is as simple as running:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;aptitude install python python-setuptools&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Of course, git itself is a requirement. For now we&amp;#8217;ll use the Ubuntu package, but it&amp;#8217;s a good idea to build from source if you want the latest version:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;aptitude install git-core&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, get the gitosis source:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git clone git://eagain.net/gitosis.git&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and install:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cd gitosis
sudo python ./setup.py install&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So far, everything is pretty straightforward. Next we need to add a user that everyone will connect as in order to access repositories. The main method gitosis uses for accessing repositories, is to have a single user that everyone connects to over ssh. Logins are only allowed via ssh keys, and anyone who connects is restricted to running gitosis commands, preventing them from accessing anything they shouldn&amp;#8217;t.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo adduser --system --shell /bin/sh --gecos &amp;#39;git user&amp;#39; \
    --group --disabled-password --home /srv/git git&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here I&amp;#8217;ve set the home directory to &lt;code&gt;/srv/git&lt;/code&gt;. This directory will hold all repositories and gitosis files. Next we need to initialize this directory with all of the gitosis configuration files:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo -H -u git gitosis-init &amp;lt; your-ssh-key.pub&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(the -H option to sudo sets the HOME variable to the user you are running commands as. In this case - /srv/git).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;your-ssh-key.pub&lt;/code&gt; file should be your ssh public key for the computer you are working on now. You will use this to access the administration repository and any other repositories you create later. If you don&amp;#8217;t have an ssh key set up already, make one now and copy the &lt;code&gt;id_rsa.pub&lt;/code&gt; file to the server before running the above command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ssh-keygen -t rsa -b 4096&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For more information on ssh-keys, see the ssh-keygen man page.&lt;/p&gt;

&lt;p&gt;Note: by default, gitosis takes the comment field of your ssh key to be your username. In my case, it was mark@laptop, and I would have had to use mark@laptop as my username whenever editing permissions. If you want something nicer, edit the copy of your public key before running the &lt;code&gt;gitosis-init&lt;/code&gt; command and change the comment field to something a little nicer.&lt;/p&gt;

&lt;p&gt;Now you have the basic server set up. To edit the configuration, clone the administration repository:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git clone git@your-server.example.com:gitosis-admin.git&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then you can edit the gitosis.conf file, commit it, and push back to the server.&lt;/p&gt;

&lt;p&gt;At this point I hit my first snag. Any changes pushed back to the server didn&amp;#8217;t take effect. The magic updating of settings wasn&amp;#8217;t working. After some hunting around (read: typing stuff into Google and clicking frantically), I found that all of the magic is done via a hook on the gitosis-admin repository. For some reason, the hook script wasn&amp;#8217;t executable, and so never ran. Before committing any configuration changes, make sure to fix the permissions on the repository hook:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo chmod +x /srv/git/repositories/gitosis-admin.git/hooks/post-update&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The basic gitosis setup at this point is complete. Aside from adding repositories and new users, the other steps are optional. However, we are talking about making repositories publicly accessible, and the other two steps - setting up &lt;code&gt;git://&lt;/code&gt; access via &lt;code&gt;git-daemon&lt;/code&gt; and setting up gitweb will do this.&lt;/p&gt;

&lt;p&gt;First though, here&amp;#8217;s a quick overview on adding users/repositories.&lt;/p&gt;

&lt;p&gt;To add a new user, get a copy of their ssh public key (ssh keys are what makes the whole thing work), and copy it to your gitosis-admin checkout inside the &lt;code&gt;keydir&lt;/code&gt; directory. Name the file &lt;code&gt;USERNAME.pub&lt;/code&gt;, replacing the username with the name of the user you wish to add - this is the username you will use when setting permissions. For example, if you add &lt;code&gt;joe.pub&lt;/code&gt;, then you will use joe as the username in the configuration below.&lt;/p&gt;

&lt;p&gt;To add a repository, you just give somebody permission to access it and then push. This involves editing the gitosis.conf and adding a few lines:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ini'&gt;&lt;span class='k'&gt;[group foo]&lt;/span&gt;
&lt;span class='na'&gt;writable&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;myrepository&lt;/span&gt;
&lt;span class='na'&gt;members&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;joe&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This allows user joe to write to myrepository.git. You then add this as a remote in your local repository and push to create the repository on the server:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cd path/to/my-repository
git remote add origin git@your-server.example.com:myrepository.git
git push&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This assumes you actually have something to push. In practice this isn&amp;#8217;t an issue - you start with a blank local repository (using &lt;code&gt;git init&lt;/code&gt;), commit your first changes, and push. The first person to push actually creates the repository.&lt;/p&gt;

&lt;h2 id='setting_up_git_access'&gt;Setting up git:// access&lt;/h2&gt;

&lt;p&gt;This part allows people to clone a repository without needing to authenticate, and without having to generate ssh keys. You can&amp;#8217;t push to repositories in this way however - you have to use ssh if you want to push back to a repository. Chances are, you don&amp;#8217;t want all repositories to be public, and gitosis allows you to pick and choose which you make public and which you make private using (wait for it&amp;#8230;) the gitosis.conf file.&lt;/p&gt;

&lt;p&gt;Setting up git:// access is as simple as running the git-daemon command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo -u git git-daemon --base-path=/srv/git/repositories/&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you&amp;#8217;re running Ubuntu however, gitosis comes with a nice script that you just drop in to /etc/event.d, edit to change the path, and it will start the git-daemon automatically on boot:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo cp gitosis/etc-event.d-local-git-daemon /etc/event.d/local-git-daemon
sudo sed -i s+/srv/example.com/git+/srv/git+ /etc/event.d/local-git-daemon
sudo initctl start local-git-daemon&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The initctl script starts the daemon without rebooting, which is usually a good thing.&lt;/p&gt;

&lt;p&gt;By default, no repositories are made public. To make them public, you need to add a &lt;code&gt;daemon = yes&lt;/code&gt; option to your gitosis.conf:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ini'&gt;&lt;span class='k'&gt;[repo myrepository]&lt;/span&gt;
&lt;span class='na'&gt;daemon&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Here we have made a new &lt;code&gt;repo&lt;/code&gt; section for myrepository. Save the gitosis.conf file, commit, push, and you should be able to clone myrepository using &lt;code&gt;git://your-server.example.com/myrepository.git&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id='gitweb__making_everything_look_pretty'&gt;Gitweb - making everything look pretty&lt;/h2&gt;

&lt;p&gt;The final step is getting gitweb working. For this you need a copy of gitweb.cgi and associated files. I built git from source, and gitweb.cgi was built as part of this, but if you didn&amp;#8217;t do this, there is an Ubuntu package available called &lt;code&gt;gitweb&lt;/code&gt;. I also use lighttpd on my server, with pages stored under &lt;code&gt;/srv/www/domain.example.com/pages/&lt;/code&gt; so I&amp;#8217;ll be describing a configuration for that server and layout.&lt;/p&gt;

&lt;p&gt;First, copy &lt;code&gt;gitweb.cgi&lt;/code&gt;, &lt;code&gt;gitweb.css&lt;/code&gt;, and all of the images to &lt;code&gt;/srv/www/domain.example.com/&lt;/code&gt;. I put the css files and images inside a &lt;code&gt;pages&lt;/code&gt; subdirectory (the document root), and put &lt;code&gt;gitweb.cgi&lt;/code&gt; inside a separate &lt;code&gt;cgi-bin&lt;/code&gt; directory outside of the document root.&lt;/p&gt;

&lt;p&gt;Next, configure lighttpd. I have simple-vhost set up which sets the document root based on the domain name requested, so we only need to do special set up for the git/cgi parts:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$HTTP[&amp;quot;host&amp;quot;] =~ &amp;quot;^git\.your-server\.example\.com$&amp;quot; {
    url.redirect = (
        &amp;quot;^/$&amp;quot; =&amp;gt; &amp;quot;/gitweb/&amp;quot;,
        &amp;quot;^/gitweb$&amp;quot; =&amp;gt; &amp;quot;/gitweb/&amp;quot;
    )
    alias.url = (
        &amp;quot;/gitweb/&amp;quot; =&amp;gt; &amp;quot;/srv/www/git.your-server.example.com/cgi-bin/gitweb.cgi&amp;quot;,
    )
    setenv.add-environment = (
        &amp;quot;GITWEB_CONFIG&amp;quot; =&amp;gt; &amp;quot;/srv/www/git.your-server.example.com/gitweb.conf&amp;quot;,
    )
    $HTTP[&amp;quot;url&amp;quot;] =~ &amp;quot;^/gitweb/&amp;quot; { cgi.assign = (&amp;quot;&amp;quot; =&amp;gt; &amp;quot;&amp;quot;) }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Gitosis does provide a config file for lighttpd, but it wasn&amp;#8217;t appropriate for my setup. Note that the above needs the following modules loaded: &lt;code&gt;mod_alias&lt;/code&gt;, &lt;code&gt;mod_cgi&lt;/code&gt;, &lt;code&gt;mod_redirect&lt;/code&gt;, &lt;code&gt;mod_setenv&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Gitweb.cgi needs editing slightly in the above configuration, by default it looks for the css file in the same location as the gitweb.cgi file (i.e. in a /gitweb/ dir), but they are stored at the root of the site. Open up gitweb.cgi and search for gitweb.css. Add a slash before the filename and save the file.&lt;/p&gt;

&lt;p&gt;Next is creating a gitweb.conf file. Again, gitosis helps out here, providing a &lt;code&gt;gitweb.conf&lt;/code&gt; file that just needs some tweaking with the right paths. Copy the &lt;code&gt;gitweb.conf&lt;/code&gt; file from the gitosis source distribution to &lt;code&gt;/srv/www/git.your-server.example.com/&lt;/code&gt;, and open it up for editing.&lt;/p&gt;

&lt;p&gt;Edit the &lt;code&gt;$projects_list&lt;/code&gt;, &lt;code&gt;$projectroot&lt;/code&gt;, and the &lt;code&gt;@git_base_url_list&lt;/code&gt; lines and save:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='perl'&gt;&lt;span class='nv'&gt;$projects_list&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;/srv/git/gitosis/projects.list&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='nv'&gt;$projectroot&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;/srv/git/repositories&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='nv'&gt;@git_base_url_list&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;git://your-server.example.com&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;By default, gitosis creates repositories that are only accessible by the git user and users in the git group, so we need to give the web server permissions to access repositories. If this isn&amp;#8217;t done, gitweb will say that there are no repositories available even when you configure web access in gitosis for the repository.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;usermod -G git www-data&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You will need to restart the web server after this in order for the group change to take effect. If your web server is running as someone else other than &lt;code&gt;www-data&lt;/code&gt;, change the above command appropriately.&lt;/p&gt;

&lt;p&gt;Finally, to give access to a repository via gitweb, the process is similar to setting up git:// access. Edit gitosis.conf, and add a &lt;code&gt;gitweb = yes&lt;/code&gt; line next to the &lt;code&gt;daemon = yes&lt;/code&gt; line for the repository. Commit, push, and the repository should now show up in gitweb. In the default configuration, you need to have both &lt;code&gt;daemon = yes&lt;/code&gt; and &lt;code&gt;gitweb = yes&lt;/code&gt; for a repository to be made available via gitweb. See the &lt;code&gt;gitweb.conf&lt;/code&gt; file if you want to change this.&lt;/p&gt;</description>
            <pubDate>Fri, 05 Mar 2010 00:00:00 -0800</pubDate>
        </item>
        
        <item>
            <guid>http://www.mivok.net//2009/09/20/bashfunctionoverrist.html</guid>
            <link>http://www.mivok.net//2009/09/20/bashfunctionoverrist.html</link>
            <title>Bash function renaming and overriding</title>
            <description>&lt;p&gt;One annoyance I found when writing bash scripts is the lack of function references. This became apparent when overriding a function, but when I wanted to change the behavior only slightly. I had a library of functions, and wanted to add some commands before the start of the function, and some cleanup code immediately after it finished.&lt;/p&gt;

&lt;p&gt;This being a library function that was called elsewhere, I couldn&amp;#8217;t edit the function in the library itself. Nor could I edit the calling code and add the steps before and after - the calling code was itself another library function. This left the option of copying and pasting the entire function, and adding my extra code to the beginning and end.&lt;/p&gt;

&lt;p&gt;In python (and many other languages), I would have done something like the following:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='n'&gt;old_foo&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;foo&lt;/span&gt;

&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;foo&lt;/span&gt;&lt;span class='p'&gt;():&lt;/span&gt;
    &lt;span class='n'&gt;initialization_code&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
    &lt;span class='n'&gt;old_foo&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
    &lt;span class='n'&gt;cleanup_code&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;but bash doesn&amp;#8217;t seem to support function references in that manner. After much searching however, I finally found a way to save a function under a new name, which gives the same kind of functionality using bash&amp;#8217;s &lt;code&gt;declare&lt;/code&gt; builtin.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;declare&lt;/code&gt; command prints out the values of declared variables, and more importantly, declared functions - &lt;code&gt;declare -f foo&lt;/code&gt; will print out the code for function &lt;code&gt;foo&lt;/code&gt;. So all you need to do is execute the output of the &lt;code&gt;declare -f&lt;/code&gt; command, after substituting the name of the function. The following bash function does just this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;save_function&lt;span class='o'&gt;()&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
    &lt;span class='nb'&gt;local &lt;/span&gt;&lt;span class='nv'&gt;ORIG_FUNC&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='k'&gt;$(&lt;/span&gt;&lt;span class='nb'&gt;declare&lt;/span&gt; -f &lt;span class='nv'&gt;$1&lt;/span&gt;&lt;span class='k'&gt;)&lt;/span&gt;
    &lt;span class='nb'&gt;local &lt;/span&gt;&lt;span class='nv'&gt;NEWNAME_FUNC&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;$2${ORIG_FUNC#$1}&amp;quot;&lt;/span&gt;
    &lt;span class='nb'&gt;eval&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;$NEWNAME_FUNC&amp;quot;&lt;/span&gt;
&lt;span class='o'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Add that to your scripts, and you have a simple way to copy/rename a function, and a simple way to add a step before/after an existing function. To copy the python example above:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;save_function foo old_foo
foo&lt;span class='o'&gt;()&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
    initialization_code&lt;span class='o'&gt;()&lt;/span&gt;
    old_foo&lt;span class='o'&gt;()&lt;/span&gt;
    cleanup_code&lt;span class='o'&gt;()&lt;/span&gt;
&lt;span class='o'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now any code calling foo in the script will get the new behavior.&lt;/p&gt;</description>
            <pubDate>Sun, 20 Sep 2009 00:00:00 -0700</pubDate>
        </item>
        
        <item>
            <guid>http://www.mivok.net//2009/04/18/bashquoting.html</guid>
            <link>http://www.mivok.net//2009/04/18/bashquoting.html</link>
            <title>Bash quoting and whitespace</title>
            <description>&lt;p&gt;A common thing when writing shell scripts is to allow the user to specify options to commands in a variable. Something like the following:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; &lt;span class='nv'&gt;OPTS&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;--some-option --some-other-option&amp;quot;&lt;/span&gt;
&lt;span class='gp'&gt;$&lt;/span&gt; my_command &lt;span class='nv'&gt;$OPTS&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We can set my_command to the following script to see exactly what gets passed:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='c'&gt;#!/bin/bash&lt;/span&gt;
&lt;span class='k'&gt;for &lt;/span&gt;t; &lt;span class='k'&gt;do&lt;/span&gt;
&lt;span class='k'&gt;    &lt;/span&gt;&lt;span class='nb'&gt;echo&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&amp;#39;$t&amp;#39;&amp;quot;&lt;/span&gt;
&lt;span class='k'&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Running the above prints the following output:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='go'&gt;&amp;#39;--some-option&amp;#39;&lt;/span&gt;
&lt;span class='go'&gt;&amp;#39;--some-other-option&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This works fine, until you want to include options with whitespace in them:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; &lt;span class='nv'&gt;OPTS&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;--libs=&amp;#39;-L/usr/lib -L/usr/local/lib&amp;#39;&amp;quot;&lt;/span&gt;
&lt;span class='gp'&gt;$&lt;/span&gt; my_command &lt;span class='nv'&gt;$OPTS&lt;/span&gt;
&lt;span class='go'&gt;&amp;#39;--libs=&amp;#39;-L/usr/lib&amp;#39;&lt;/span&gt;
&lt;span class='go'&gt;&amp;#39;-L/usr/local/lib&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This output clearly isn&amp;#8217;t what we want. We want a single parameter passed with the entire content of $OPTS. The culprit here is &lt;a href='http://wooledge.org:8000/WordSplitting'&gt;Word Splitting&lt;/a&gt;. Bash will split the value of &lt;code&gt;$OPTS&lt;/code&gt; into individual parameters based on whitespace. One way to get around this is to put &lt;code&gt;$OPTS&lt;/code&gt; in double quotes:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; &lt;span class='nv'&gt;OPTS&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;--libs=&amp;#39;-L/usr/lib -L/usr/local/lib&amp;#39;&amp;quot;&lt;/span&gt;
&lt;span class='gp'&gt;$&lt;/span&gt; my_command &lt;span class='s2'&gt;&amp;quot;$OPTS&amp;quot;&lt;/span&gt;
&lt;span class='go'&gt;&amp;#39;--libs=&amp;#39;-L/usr/lib -L/usr/local/lib&amp;#39;&amp;#39;&lt;/span&gt;

&lt;span class='gp'&gt;$&lt;/span&gt; &lt;span class='nv'&gt;OPTS&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;--libs=-L/usr/lib -L/usr/local/lib&amp;quot;&lt;/span&gt;
&lt;span class='gp'&gt;$&lt;/span&gt; my_command &lt;span class='s2'&gt;&amp;quot;$OPTS&amp;quot;&lt;/span&gt;
&lt;span class='go'&gt;&amp;#39;--libs=-L/usr/lib -L/usr/local/lib&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Putting &lt;code&gt;$OPTS&lt;/code&gt; in double quotes suppresses word expansion. In the above example, that works as expected. The second command has the single quotes removed as they were passed directly to the command, which isn&amp;#8217;t what we wanted. So far, so good. The problem, as you may have spotted by the removal of the single quotes, comes when we want to pass more than one parameter in &lt;code&gt;$OPTS&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; &lt;span class='nv'&gt;OPTS&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;--cflags=O3 --libs=-L/usr/lib -L/usr/local/lib&amp;quot;&lt;/span&gt;
&lt;span class='gp'&gt;$&lt;/span&gt; my_command &lt;span class='s2'&gt;&amp;quot;$OPTS&amp;quot;&lt;/span&gt;
&lt;span class='go'&gt;&amp;#39;--cflags=O3 --libs=-L/usr/lib -L/usr/local/lib&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Here, the entire &lt;code&gt;$OPTS&lt;/code&gt; variable gets passed as a single parameter, which isn&amp;#8217;t what we want. We want &lt;code&gt;--cflags&lt;/code&gt; to be passed as one parameter, and &lt;code&gt;--libs&lt;/code&gt; (and everything that comes with it) to be passed as another parameter. Adding more quotes, backslash escaped or not, does nothing to help.&lt;/p&gt;

&lt;p&gt;The solution? Use bash arrays:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; &lt;span class='nv'&gt;OPTS&lt;/span&gt;&lt;span class='o'&gt;=(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;--cflags=O3&amp;quot;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;--LIBS=-L/usr/lib -L/usr/local/lib&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt;
&lt;span class='gp'&gt;$&lt;/span&gt; my_command &lt;span class='s2'&gt;&amp;quot;${OPTS[@]}&amp;quot;&lt;/span&gt;
&lt;span class='go'&gt;&amp;#39;--cflags=O3&amp;#39;&lt;/span&gt;
&lt;span class='go'&gt;&amp;#39;--LIBS=-L/usr/lib -L/usr/local/lib&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Perfect. But what about backward compatibility? If you have hundreds of scripts that use a string for &lt;code&gt;$OPTS&lt;/code&gt;, how does it work if you change to using arrays? Let&amp;#8217;s try it out:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; &lt;span class='nv'&gt;OPTS&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;--some-option --some-other-option&amp;quot;&lt;/span&gt;
&lt;span class='gp'&gt;$&lt;/span&gt; my_command &lt;span class='s2'&gt;&amp;quot;${OPTS[@]}&amp;quot;&lt;/span&gt;
&lt;span class='go'&gt;&amp;#39;--some-option --some-other-option&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;So it works if your old scripts only have single options, but if multiple scripts are needed, then they will need to be changed to use arrays instead. This however seems to be the best option for passing multiple arguments with whitespace.&lt;/p&gt;</description>
            <pubDate>Sat, 18 Apr 2009 00:00:00 -0700</pubDate>
        </item>
        
    </channel>
</rss>

