I’ve been looking for a simple way to quickly supply some of my applications with easy-access configuration information. Most of the times these are games and smaller utility applications. Enterprise scale applications deserve configuration systems of their own gargantuan proportions, but that’s another story. Thinking back quite a few years, the windows crew had a pretty simple way to supply this sort of information to their running programs, they used the INI file format.
How’s it look?
It’s a pretty basic, plain-text format. Typically you’d see something along the lines of:
You get the idea. The wikipedia link above will give you a more thorough run-down should you need it.
How to make it usable?
The aim is to basically feed an INI file into this process and have some very easy to use C++ objects out the other side. The STL contains some very suitable container style objects that will measure up, so I want something like this:
The map class is a convenient way to manage key-value pairs. Perfect. Looking at the code, the types are very long-winded. All of the namespace declaration actually mixed with the types makes for a very long line. This can be cleaned up by “using” the std namespace, but the whole type definition itself could be cleaned up by just using a typedef. I’ll be writing the types long-hand for the duration of this tutorial, just so we’re clear.
Doing it smart
Thanks to the rigid format of the file, we’ve got a very solid standard set in place as to what we’ll expect when we crack the file open. We can centralise all of our file processing around two regular expressions.
\[(.*?)\]
This first regular expression is our test for the section parts. It tests that the line being interpreted is wrapped in square brackets. When we run this through the regular expression system, it’ll allow us to extract just the name. Nice.
(\w+)=([^\+]+(?!\+{3}))
This second expression will do our key value pair testing. When we use it in extraction with a regular expression, the first match will be the key, the second - the value. Double nice. So, we can fire these regular expressions up using the boost regex library. I’m led to believe that parts of the boost library will be appearing in the newest C++ standard, regular expressions being one of them.
Putting it all together
The block of code in the end is quite simple.
std::stringline,current;// regular expressions to process ini filesboost::regexsection_test("\\[(.*?)\\]");boost::regexvalue_test("(\\w+)=([^\\+]+(?!\\+{3}))");// the result config objectstd::map<std::string,std::map<std::string,std::string>>config;// assuming we've opened the file ok into a// filestream object called "mapfile"while(getline(mapfile,line)){boost::trim(line);if(line.length()>0){boost::smatchmatch;if(boost::regex_search(line,match,section_test)){// any key-value pairs from here to be attributed // to this new namecurrent=match[1];}elseif(boost::regex_search(line,match,value_test)){// set this as a key value pair on the current nameconfig[current][match[1]]=match[2];}}}
So, with a couple of tests to assure us that the values are ok we’ve got a pretty crude implementation here. Erroneous lines are ignored rather than responded to in an exception case. If no initial section is supplied before some key value pairs, those pairs will go into an item section with an empty string.
Anyway, if the user is half-sane about how they treat their INI files, you’ll be just fine.
The best part about technology is the ability to use anything you want. I’ve run across many frameworks all touting their own awesomeness. Sometimes though, you just need to smash a bit of output back to the client. Using the CGI and XHTML libraries available for Haskell, web programming is so simple. Just about every web server known to mankind can run a CGI program and if yours can’t, it may need a trip to the gym.
Show me some code
Excellent. This is where it gets very interesting. I realise at first, when you’re reading this code you’re going to be saying “well, duh - I can knock out a HTML page to be statically served much easier than this B.S.” If this is your train of thought, you may have missed the point. The example I provider here is only to demonstrate to the reader how we can get Haskell closer to the client generation.
moduleMainwhereimportNetwork.CGIimportText.XHtml-- Generates the page contentpage::Htmlpage=body<<h1<<"Served fresh from Haskell!"-- Renders our html document to stringcgiMain::CGICGIResultcgiMain=output$renderHtmlpage-- Handles the CGI action and basic errors alsomain::IO()main=runCGI$handleErrorscgiMain
This should be fairly easy to follow. There’s nothing out of the ordinary and it’s very simple. After reading this document I was impressed that this could be condensed down into the following:
importNetwork.CGIimportText.XHtmlmain=runCGI.output.renderHtml$body<<h1<<"Served fresh from Haskell!"
Damn! Not bad. And, here’s the output that you get from running these CGI programs:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><htmlxmlns="http://www.w3.org/1999/xhtml"><body><h1>Served fresh from Haskell!</h1></body></html>
At the moment, I can see how this looks like a long way around and it certainly is a feathers over steam-train approach to delivering a static page but we’ve now got the power of Haskell behind our CGI program.
Whenever I need to make shell configuration changes in unix land (weather that be on a linux, bsd or osx box), I always find myself scratching around trying to find the “correct place” to put the changes that I want to make. This post is all about the black and white between .bash_profile and .bashrc.
The documented difference
If you were to read the bash man page you’ll get two pretty clear sentences in there.
When bash is invoked as an interactive login shell, or as a non-interactive shell with the –login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable.
When an interactive shell that is not a login shell is started, bash reads and executes commands from ~/.bashrc, if that file exists.
From this, you can see the deciding factor is:
If it’s a login shell, use .bash_profile
If it’s not a login shell, use .bashrc
What’s a login shell?
A login shell is when you’re logging into the machine at the console or over SSH i.e. you haven’t yet logged in. A non-login shell is, for example, when you’ve already logged into your window manager and you fire up your terminal (that is of course, if your terminal is configured to run as a non-login shell!). >Caveats and configurations aside, this is the coarse difference between terms.
Ok, which one do I bloody use then?
Well, to save yourself some administration headaches why not just use one? You then source that configuration file from the other. I know that doesn’t read very well, so here’s the example. I hope this makes it clearer.
So, fill .bashrc with all of your configuration goodies and put the following into .bash_profile
if[-f ~/.bashrc ];then
source ~/.bashrc
fi
So now it doesn’t matter if you use a login or non-login shell, you get the same, consistent configuration experience!
Here are a couple of the common commands I need day-to-day in order to navigate around virtualenv.
# Creating a new virtual envrionment$ virtualenv env# Using a virtual environment$ source env/bin/activate
# Getting out of a virtual environment$ deactivate
# Re-hydrating a requirements file into your environment$ pip install-r requirements.txt
# Serializing all of your environment's packages into a requirements file$ pip freeze > requirements.txt
That’s some basics that will get you up and running.
I like having my specific development environments setup, tailored for the particular project that I’m working on. When I’m working on a python project, virtualenv is my go to tool for the job. It’s great.
We’re going to install this using easy_install so that these instructions should translate pretty well to any linux environment. I am doing this from my Debian workstation though.
First up, we need to install the python-setuptools package so that we get access to easy_install.
As far as the installation is considered, you’re done! It’s that easy. From here you can start to use virtualenv for all of your python based projects. I’ll do a quick cheat-sheet write up shortly on how to use virtualenv at a glance.