I endeavor to work with dynamic, agile teams building and operating applications and services at large scale, with a progressive view of the importance of web operations in their business.
I have engineered and maintained web applications with scalable, fault-tolerant infrastructures, integrated render farms and shared storage for post-production facilities, and trained and supported users. I am indebted to the open-source community and strive to contribute back to it.
An articulate communicator, I collaborate diplomatically with team members and can professionally interface with clients and stakeholders.
Software engineering and operations consulting for web applications and services, preferring dynamic languages such as Ruby and Python. Design, implement and automate sophisticated, scalable and resilient architectures. Project management and team workflow guidance.
Web operations, development, and application support for leading managed hosting provider focused on Ruby on Rails applications.
- Progressive dev/ops culture and practice
- Systems Automation / Configuration Management with Puppet
- Xen virtualization and bare-metal
- Continual improvement of end-to-end monitoring and metrics
- Analysis and optimization of customer application performance and architecture
- Deployment and migration of managed customer applications, using Moonshine to integrate Puppet modeling of an apps' architecture needs into the deployment process
- Responded to critical incidents as part of on-call rotation
- Refinement and documentation of operations and support processes through company expansion
Re-architected a load-balanced, high-availability web cluster for LexBlog's customer-facing services, and performed migration from hardware in a colocation facility to cloud infrastructure. Administration of this cluster -- which serves over 500 weblogs for high-profile law firms across the US and internationally -- built on Apache, haproxy, and MySQL. Migrated version control from Subversion to git.
Maintained customized Movable Type installation and customer support portal, merging upstream vendor releases. Liaised with front end developers and customer support staff, and fervently wrote and updated internal and customer-facing documentation.
Contributed to the planning, development and lifecycle management of a large-scale magazine-style legal news aggregation site built with Ruby on Rails and deployed on Amazon Web Services cloud platforms.
Spec, build and integrate workstations, storage and network solutions for digital content creation and delivery. Optimization and testing of most major tools for nonlinear video editing, motion graphics, compositing and 3D animation. Hardware-accelerated systems for realtime editing, VFX and color correction, backed by high-throughput DAS and SAN RAID configurations. Implement distributed network rendering solutions for a variety of 3D and compositing applications. End-user and internal technical support.
I had the pleasure of visiting Japan for RubyKaigi 2010 and a week's vacation at the end of August, squeezing a rich microcosm of the country's electric energy, serene grace, warm mirth and artful cuisine into my short time there. I enjoyed myself immensely, but I felt compelled to share this particular little nugget of social calamity, for whatever reason.
I was self-conscious before even arriving to spend a night in Hakone in a lovely traditional Japanese inn (Mikawaya Ryokan, recommended if you find yourself in the area), as a foreigner not speaking Japanese, traveling alone -- usually not accepted in luxury ryokan -- unfamiliar with the highly refined etiquette and customs of the setting, bearing tattoos in the public bath. A hostess showed me around upon arrival, taking care to try to explain things to me and give subtle warnings of faux pas to avoid, and I changed into my yukata and read a book in excited anticipation of kaiseki to be served sharply at 6:00. At some point, I left my phone sitting atop a door frame running LCD Clock, as practically no one had the number of my rented SIM card in Japan.
Naturally, in the midst of being privately served my elaborate multi-course dinner, all of the elements of which I still cannot identify but savored without prejudice, one of the only people who knew my phone number in Japan, well, called. The forgotten phone vibrated and fell to the tatami-covered floor in an unceremonious cacophony, the dreadfully out-of-place artifact of technology sending the decorous old woman in care of me into momentary panic as I profusely sumimasened and gomen nasaied. Seconds lingered like uninvited in-laws as she picked it up and handed it to me, holding it as if it were a dead animal, as though pleading for me to just make it stop. After I snuffed it out and we both had a moment to collect our wits, smirks grew on both our faces, turning to laughter and bringing great relief as the only language common between us.
I try hard to be considerate and culturally sensitive. I can relate pretty well with the Japanese value of not causing inconvenience for others. What can you do but laugh when it all just caves in?
The Japanese in general are as kind to foreign strangers as locals of any place I've been, even in oft-prim Tokyo, and I never felt unwelcome. Going to Tsukuba for RubyKaigi added a third dynamic to the trip: beyond bustling, image-conscious Tokyo and the mountain getaway of Hakone, Tsukuba felt like regular people letting their guard down, a science center and college town with punk teenager hangouts and boisterous locals not hesitant to roll drunkenly into the yakitori place on their way home and be tacky. I dare say a tinge of Japanese redneck.
RubyKaigi was an outstanding tech conference. Bright, quality community without a load of hot air. I was blown away by the dedication of the organizers and the fine job that they did running a bilingual conference, for a pittance of a fee. Getting away from the duties of work, and then escaping to a mountain spot lost in time set the stage perfectly to think freshly at RubyKaigi and be inspired by the spirit of open-source camaraderie and innovation. I do increasingly miss strong tech community in Bangkok.
My first real vacation in at least a couple of years has given me some perspective, and it's time for some realignment.
Finally getting this posted a week late. I'm looking forward to returning to Chiang Mai for awhile next year, staying longer and taking some time off from work. There's a lot more to see than the comforts of boutique hotels :-)
Today I cooked breakfast as the Bangkok sunrise bathed my condo in its glow. Gathering my things for two weeks' wandering and a visa run, I took to the property management office an assortment of fruit that I was gifted with and had to leave behind, and set off to catch my flight to Chiang Mai.
Arriving around lunchtime, I had a pleasant conversation over coffee with some European travelers who gathered as strangers around the available table at an airport shop. Already the different vibe here was apparent -- a maturity and calm contentedness without the posturing often seen in foreigners and Thais alike in cosmopolitan Bangkok. As we all fanned out from our fleeting encounter, I hailed a cab to reach my fine accommodations. Rubbing my eyes from too little sleep or perhaps a distrust for the immediate sensation of comfort I felt as I stepped inside, I was graciously welcomed by the staff of U Chiang Mai and shown to my room.
Wearily I stepped into a shower that seemed to wash away hours. I donned a robe and cracked open my laptop to check in on the afternoon of work ahead. Seizing the "anytime, anywhere" breakfast as opportunity for a convenient meal, I received a delectable spread of eggs benedict, sauteed mushrooms, a croissant and toast, yogurt, fresh fruits and orange juice. Best Western breakfast I've been served in Thailand hands down.
Eventually I dressed, in order to move outside and round out the day's work from the spacious daybed on my balcony. Opening a beer as the evening sun's last rays glinted upon the surface of the slate-black pool below, I closed the laptop, opened a guidebook, and waited for my friend to arrive with the night's plans.
Adventurous first day in Northern Thailand? No. Rejuvenating to pamper oneself with a boutique hotel once in awhile? Oh, yes.
Bitbucket is a new social code hosting site for Mercurial (Hg) users, allowing them to view and interact with one another’s distributed revision control repositories. It’s no stretch to say that it’s inspired by the excellent GitHub site for the Git SCM. Being a fan of the simplicity and elegance of Hg, I’ve been waiting for someone to do this for awhile.
Bitbucket is quite young and still in public beta, and they’re working rapidly to make improvements and squash bugs, but they already have plenty of novel features working. One of the coolest ones that caught my eye is support for patch queues a lá Mercurial Queues. I had a little trouble figuring out how Bitbucket handles patch queues at first, at it’s not documented in their help yet, but with the help of developer Jesper Noehr I was able to work it out. So until those official docs are published, I hope this guide can help some folks.
h3. Briefly, What’s a Patch Queue?
I should write an article on mq itself, but the basic idea is that you can maintain a stack of patches against a main repository. This means that you could, for example, work on a few features that build on one another in concise patches instead of a giant one that isn’t cohesive (commit early and often!). If you find while working on UI that there’s a problem with the core feature, you refresh your current UI patch, then pop patches until you’re at the core patch. Fix the problem, refresh the core patch, and push the stack back up to the UI to continue working. In a sense, the patches are like “floating” commits that don’t have to truly committed until you know they’re working, or that you’re not chasing an experimental path. This keeps others on a project from having to sift through excessive, confusing changesets in the version history.
Another case is in projects where patches may be maintained against a changing code base until they can be reviewed (or just finished!). Mercurial’s patch queues allow you to pop all patches, pull in new changes to the underlying repository, and push all the patches back on, with the option to merge them if adjustments are needed. This is called rebasing.
By default, Mercurial Queues just works with a set of patches locally, but it’s possible to actually version control it so others can contribute to work-in-progress patches.
All of this begs for some examples, but I’m going to save that for another article or for the book. From here on, we’ll be looking at how to use patch queues on Bitbucket, assuming you’ve gotten acquainted with mq already.
Whether you have an existing patch queue to import or you’re starting afresh, this is the shortest path to having your queue set up in Bitbucket:
project-repo for this example.project-repo-patches. Be sure to check the ‘Omit Series’ box if you already have an existing set of patches you plan to start tracking revisions on.hg qclone the URL of the new patch repo, something like this:$ hg qclone https://user [at] bitbucket [dot] org/user/project-repo-patchesqclone command checks out a repository and it’s versioned patch queue. If you’ve worked with this before, though, you might be thinking this is backward: normally you’d qclone the project-repo, not the patch queue repo! More on that in a bit.`hg qnew` and start working on a patch. `hg qref` when finished with the patch for now, and `hg qcommit -m "your message"` to commit the work on your patches. To push out your changes for others, `cd .hg/patches` from the root of the repo you qclone’d and `hg push`. You should see your changesets and patches show up when browsing the patch queue on Bitbucket.
If you want to use an existing set of patches, `cd .hg/patches` while in project-repo-patches and copy your patches and series file in from the same location in the branch repo you’ve worked on locally. You should not copy the status file that lives in the patches directory — it can cause mq to get confused about which patches have been applied, and it will be regenerated when you apply the newly copied patches to project-repo-patches as you work with it. Now just run `hg add` in the patches directory, and you’re ready to commit and push. From now on, you can use mq normally: `hg qnew` will take care of `hg add`’ing new patches, and you can use qcommit instead of changing to the patches directory to commit.
You might notice that the patches directory has an .hgignore file pre-defined that will keep some files, like status, from being pushed out to your shared patch queue repo. This is exactly what gets set up if you run `hg qinit -c` to start a versioned patch queue on a local repo — Bitbucket has taken these steps for you, as well as setting the path in the patch queue’s hgrc that Bb needs, so you’re ready to push right out of the box. Note: the .hgignore isn’t actually being generated right now, which I believe to be a bug and have reported it.
If you’ve worked with Mercurial Queues and versioned patch queues before, some things about using them on Bitbucket may seem a little odd at first. I’ll try to explain a little bit about what’s going on. Keep in mind that Bitbucket is still very new and it’s possible that things could change, so do a little poking before following me blindly.
The departures from normal behavior — like the fact that to get a full project-repo checkout and its versioned patch queue, you qclone the patch repo instead of the project-repo — stem from the fact that Bitbucket allows multiple patch queues to be associated with the project-repo, a feature with tremendous coolness potential. Because of this, Bb doesn’t actually store your patch queue inside of the main project repo as you might do normally for sharing a single patch queue. So, if you were to qclone the project-repo, how is Hg going to know which patch queue you want to pull in with it?
Bitbucket approaches this with a little bit of magic, and we can get some insight into it by peeking at hgrc files after qclone’ing a patch repo. So continuing with our example, if we qclone project-repo-patches, you’d see something like this in project-repo-patches/.hg/patches/.hg/hgrc:
[paths]
default = https://bitbucket.org/user/project-repo-patches/.hg/patches
.hg/patches, which seems kind of like a patch queue within a patch queue. Why? Let’s take a look at project-repo-patches/.hg/hgrc, the main repo’s config file:[paths]
default = https://bitbucket.org/user/project-repo-patches/
project-repo-patches, commit, and push, you’ll find that the changes end up correctly in the main repo, project-repo, on Bitbucket. Bb is doing some magic to redirect pushes to the root of a patch repo to the “parent” project repo. So, that’s why the patch repo pushes to .hg/patches. Whew. Sorry if you have to read that a few times.
So far I’ve been using HTTP in the examples, and there’s a good reason for that. Part of my confusion in intially trying to use patch queues on Bitbucket stemmed from my use of SSH, and Jesper realized that was the problem: the magic described above for qclone’ing a patch repo to get a full repo and the patches, and having pushes go back to the main repo, is not implemented yet for SSH on Bitbucket. This would lead to a lot of confusion if, like me, you were trying to figure all this out on your own before it’s documented. Thanks to Jesper for his enthusiastic help with this.
SSH is nice because once you’ve given Bitbucket your public key, you don’t need to type your password all the time. It can also be speedier because of compression in the SSH protocol. Armed with the information above, we might try steps like these expecting everything to work over SSH (please note that this does not currently work in my experience):
project-repo.project-repo-patches.$ hg clone ssh://hg [at] bitbucket [dot] org/user/project-repo
.hg directory and clone from your patch repository’s special structure:
$ cd .hg
$ hg clone ssh://hg [at] bitbucket [dot] org/user/project-repo-patches/.hg/patches
This basically leaves you with a main repo and patch queue with their hgrc files set up for the same paths that you’d get from the workflow described previously, except this time using SSH. You also get the main repo in a directory named project-repo as you’d expect, instead of project-repo-patches after the qclone approach, which is a bit counter-intuitive. In fairness, there’s no reason you can’t rename the top project directory after the qclone, once you understand what’s going on.
At least for now, this does not work. You’ll probably get a permissions error when trying to push your patch queue over SSH after setting this up. Jesper noted that he’ll try to get the magic fixed for SSH so that it will work just like HTTP. Hopefully this will one day work as an alternative approach, since SSH is nice, and to me this feels more like a natural Mercurial way to handle multiple patch queues for a project repository than the backwards qclone.
All in all, I’m finding Bitbucket really cool so far, and I can see that they’re working hard to improve it every day. A wiki system is in the works (driven by what else but Mercurial versioning), so alongside the already present issue tracker, it should soon provide a worthy and trouble-free alternative for teams thinking about setting up a server to host Trac and a shared Mercurial repository.
Of course, Github has already shown how the social nature of forking and pulling with the help of a web app can make distributed version control more powerful and more fun for individuals, as well as facilitating community in the open source world. It’s fantastic to see the same opportunities come along for Mercurial fans, and I wish the Bitbucket folks best of luck.
By the way, you can find me here on Bitbucket!
So I’m using Mercurial for version control on a Ruby on Rails project, along with Capistrano for automating deployment and running remote tasks. These are great tools and I’m finding that they work well together with the Mercurial SCM module by Matthew Elder introduced in Cap 2.0.
I came across one problem though: my repository is hosted over HTTP because I don’t want to give everyone access to a shell account for SSH, and the hg SCM module didn’t support prompting for passwords (whether you’re using HTTP authentication or SSH without a public key). This effectively meant that if you wanted Cap to deploy from a repo served in either of these ways, you’d need to put your password in plain text in your Cap recipes.
I don’t like the idea of that, so I created a patch to fix it, along with another minor point or two that I found, and added some unit tests. You can get more details and take a look at the patch on the ticket I submitted. It’s been committed, so if you’re using Capistrano from SVN, you’re set, just svn up.
If you’ve installed Cap from a gem and want a quick fix, you can replace mercurial.rb in your installation with the one attached to this post. On my system, it lives at this directory path:
/usr/local/lib/ruby/gems/1.8/gems/capistrano-2.1.0/lib/capistrano/recipes/deploy/scm/
This will probably work with Cap 2.0, though I’ve only tried with 2.1. The Mercurial module hasn’t changed much.
I should note that on my systems I’ve had to set the option for requesting pseudo-ttys in my recipes, or else Mercurial tries to run non-interactively and password prompting won’t work. If you have that problem, use this:
default_run_options[:pty] = true
If anyone comes up with a nice way to load the new stuff as a monkeypatch in a project, I’d love to hear about it. I’ve been unsuccessful at trying to hook it in through recipes or the Capfile, and it’d be nice to have some way of doing that while waiting for the next gem release. I’d rather not ask my team to check out Capistrano from SVN or run around modifying their installation if I can avoid it.
Update:
And, in short order, Cap 2.2.0 has been released. The fix below is rolled in, so just gem install capistrano and you can forget about the rest!
| Attachment | Size |
|---|---|
| mercurial.rb | 4.57 KB |
I’m a little late in posting this here, but I’m giving a talk on Pylons, a rapid-development web applications framework, for the local Python users group this Wednesday evening.
The talk will primarily be comprised of an overview of the framework and the components that it brings together. Pylons’ use of existing libraries is great for code reuse, flexibility, and simply using the best tools out there, but it can make the initial learning curve a bit steep.
So, if you’re curious about Pylons or are looking for a MVC framework for building web apps and services in Python, come check it out.
You can find a full description and RSVP at the official Meetup page, or on Upcoming if you’re into that sort of thing:
http://python.meetup.com/181/
http://upcoming.yahoo.com/event/407810
The slides for the presentation, as well as an HTML export of the outline (with lots of reference links) are attached to this post. I’ve now embedded the presentation from Slideshare behind the cut. You can download the complete Keynote file with presentation notes there.
| Attachment | Size |
|---|---|
| Pylons Presentation for CPMG.pdf | 387.44 KB |
| Pylons Presentation Outline - HTML.zip | 9.77 KB |
Apologies for taking so long to post Part II. I had hoped that the templates for the Tags Plugin would be ported to Genshi, or that I’d have time to do so myself, before finishing. Unfortunately neither of those things has happened, and in fact the entirety of trac-hacks.org was down for several weeks. That would have been rather annoying when trying to work through this article…
In Part I, we covered the installation of Trac on a shared host at TextDrive by setting up a user-local Python environment. That, along with PEAK‘s setuptools, made it trivial to install a spanking new version of Trac and its prerequisites (along with a few optional niceties). We also saw a simple authentication set-up, and how to make sure tracd and its HTTP server get restarted if a system reboot is necessary.
Now in Part II we’re going to look at administering and extending Trac with some plug-ins, ranging from small and simple to large, complex tools. Some serve utility functions such as providing attractive web-based frontends for various aspects of Trac configuration, while others add wholly new capabilities to the system. Fortunately, thanks to our preparations in the last article, installing plug-ins is quite easy.
h5. Contents
If you haven’t installed Trac yet, what are you waiting for?! Go! The steps in Part I should help you. Even if you’re not using TextDrive for hosting, Trac installation should be largely the same. If you use another shared host, where it may be desirable or altogether necessary to set up your own Python environment, those steps may apply to you too. Just make sure your host’s system Python version is at least 2.3 if you opt to go the virtual-python route, and preferably 2.4 or above. If you have a VPS or some other set up where you have root access, you can just install Trac with the system Python, and be up and running in no time.
Installing most plug-ins is dead simple, so before you go off and get a dozen of them, let’s take a minute to do some housekeeping before there’s any extra clutter that might lead to confusion. You may remember me mentioning in the last article that the WebAdmin plug-in is integrated into the core product for Trac 0.11. That saves us the trouble of what would probably be the first additional installation that most people would want to make. There is another component, though, that integrates with WebAdmin and one would almost expect it to be a part of it: the AccountManager plug-in. Let’s go ahead and install it, and then we’ll be ready to take care of the most important configuration steps from the web interface.
$ easy_install http://trac-hacks.org/svn/accountmanagerplugin/trunk
Yep, that’s it. . We just need to enable the plug-in now that it’s installed… but first we need a privileged user.
In the last article, I left you hanging a bit on the subject of user account management, because I intended to show you the AccountManager plug-in here. We’ll have to set up the first user the hard way, but I’ll show you how to make it easier from then on.
This first bit is a quick review of the simple authentication setup from last time. If you’ve already created your htdigest passwd file with an initial user or two, you’ll just need to add your user(s) to the Trac environment and assign permissions. If not, here’s a quick summary. Use this command to create a password file and add the first user:
$ htdigest -c /home/<youruser>/etc/trac.digest.passwd yourdomain.tld username
Make sure you have an etc directory in $HOME — use mkdir ~/etc first if necessary (or you can use /etc if you have root access on your server). username is arbitrary, but if you’re limiting access to a development team, it’d be sensible to match with svn users. Omit the -c switch on subsequent calls to htdigest for the file.
We’ll now add this user to the Trac environment and give him full admin privileges (consider this the Trac equivalent of root):
$ trac-admin /path/to/your/env permission add <username> TRAC_ADMIN
By default, anonymous users browsing your Trac site will be able to view all the standard components (including your source code!), but they won’t be able to modify anything. We’ll see how to change these settings shortly.
Just one more step before we can leave the command-line world for awhile — restarting tracd so that it picks up our new plug-in and user account. The command to launch tracd is just like the one used for the cron job if you set up authentication in Part I.
$ killall python
$ tracd -d -p XXXX --auth \
yourenv,/home/<youruser>/etc/trac.digest.passwd,yourdomain.tld \
/home/<youruser>/trac/<yourenv>
The first command is a bit reckless — I’m assuming that you’re not running any other long-running Python processes on your web host (besides tracd). If you are, I probably don’t need to point this out to you, and you probably know how to use the ps command to find which Python process you should kill. Replace the Xs with the port where you’re running tracd. .
Now when you visit your Trac in a browser, you should be prompted for login credentials. Log in with a user that you gave the TRAC_ADMIN privilege to just a moment ago, and you should see a new ‘Admin’ button on the far side of the navigation bar. Congrats, most of the hard work is behind you!
At this point I’d suggest that you browse the admin interface on your own to get acquainted with the settings available there. These cover a great number of configuration options that used to require trac-admin commands or editing of the trac.ini file. Don’t get overzealous and enable anything from the AccountManager plug-in just yet — we’ll do that in a sec, and I’ll explain it as we go.
You can always consult the TracGuide if you want to learn more about a particular option or part of Trac, and you have your own copy on your Trac wiki as well. Of particular interest is the ‘Permissions’ link under the ‘General’ menu, where you can configure permissions as we did before at the command line. Full explanation of the permission settings is available at TracPermissions, and you’ll see how to add users in the next section.
Under the General >> Plugins section of the Admin tab, you should see the TracAccountManager plug-in listed with a disclosure triangle. Click the triangle to list the components of the plug-in, and enable the following:
The homepage for AccountManager at trac-hacks.org gives a breakdown of what each component does. You can also hover over the items for tooltips. To quickly summarize, the AccountManager component is the plug-in core and is required for use. The AdminPage component naturally provides a configuration page in the web interface. The others relate to password management: SessionStore interfaces with Trac’s database for session management and is required for any of AccountManager’s password mechanisms. Similarly, AbstractPasswordFileStore allows the plug-in to work with htpasswd or htdigest password files. Since we’re already working with htdigest, we’ve enabled the components to support this, and we don’t need the others. We’ll revisit a few of them in a little while.
Now it’s time to restart tracd again: use the killall and tracd launch commands described previously, and refresh your browser. You can use the up arrow key or CTRL+P to recall your command history, or in Bash you can type CTRL+R and type ‘tracd’ to search for your last launch command. Don’t forget to kill the old process first.
Go to Accounts >> Configuration and click the HtDigestStore radio button. In the filename field, enter the full path to your password file (e.g. /users/home/youruser/etc/trac.digest.passwd). For realm, enter your domain name as specified when you ran the htdigest command. Click Save, and you can now view and add users in Accounts >> Users. Unfortunately the interface doesn’t allow you to edit users at this time — full name and email are set on each user’s individual Preferences page.
AccountManager has a few more nice features that we’ll take advantage of: using an HTML login form instead of the pop-up you’ve seen thus far, and allowing users to change their password or delete their account. To use these features, we’ll need to enable two more components for TracAccountManager under General >> Plugins:
Then expand the entry for Trac itself, disable the LoginModule there, and click Apply. We’re supplanting the built-in login module with AccountManager’s. If you wish, you can also enable AccountManager’s RegistrationModule, which will allow anyone to register for an account by visiting the Login page. If you elect to do so, you should definitely read on for info about the SpamFilter plug-in!
Since we’ve added plug-in components, it’s time to restart tracd once more. But now that AccountManager is handling the authentication, we don’t need to tell tracd about our auth config anymore. Instead, you can simply run with a command like this, substituting your port:
$ tracd -d -p XXXX /users/home/<youruser>/trac/test
Important Note!: At this point, you should also change the command in your restart cron job to leave out the authentication information. Remember the crontab -e command? Check that section of Part I if you’ve forgotten, or need a refresher on how to navigate vi for editing the file.
Now users will be presented with a nice login form instead of the pop-up, and an Account tab will appear on their Preferences page for password changes and account deletions. Finally, once we configure Trac’s SMTP settings in a few moments, a ‘Forgot Your Password?’ link will show up on the login page allowing users to reset their passwords.
You’ll probably want to take care of a few more configuration tasks before moving on to fun times using Trac in full swing. The main config file for your Trac instances will be located at $HOME/trac/<yourenv>/conf/trac.ini if you’ve followed my guides so far. There are a large number of directives that can be specified in this file, and plug-in documentation will often instruct you to make changes as well.
It can become tiresome to log in through a shell and modify this file to make changes, so fortunately there is an IniAdmin plug-in which exposes most, if not all, of the fields from the ini file through the WebAdmin plugin (built-in to Trac 0.11). The [components] section, which is used for plug-in configuration, is already handled by WebAdmin for most cases. You may occasionally find that a plug-in can’t be correctly set up through WebAdmin/IniAdmin, and some changes still require you to restart tracd to take effect, but generally you won’t need to log in over SSH nearly as often. Here’s how I installed IniAdmin:
$ cd ~/trac
$ mkdir src; cd src
$ svn co http://trac-hacks.org/svn/iniadminplugin/0.11 IniAdmin
$ cd IniAdmin
$ python setup.py install
This will install an egg in your local Python environment, and you should be able to enable the plug-in through the admin area of your Trac site. You may need to restart tracd as described previously in this guide. Once it’s up and running, you’ll see all the sections of your trac.ini file listed as links in the admin navigation of your site. Most of the options are explained in the wiki section for TracIni.
With the IniAdmin plug-in installed, we can comfortably take care of SMTP settings for getting notifications working. The instructions here are pretty specific to TextDrive — you’ll need to adapt them as required if you’re setting this up elsewhere.
First, I recommend that you set up a dedicated auto-mail user for your domain through webmin at TextDrive. You can also use this for anything in addition to Trac where you might want to send automated emails. I’ll cover this in brief, so consult the E-mail section of the TextDrive knowledgebase if you’re not sure how to do something.
no-reply (or whatever you like).Write to file.. and enter /dev/null in the field. This might change to indicate “Delete mail” after you submit the form for the first time — that’s what we’re doing here. Any mail sent to no-replyyourdomain.com@ will disappear into oblivion.postmaster-abbrev (use some unique abbreviation of your choosing) and set the ‘Real name’ to something like ‘Automailer’ so you can easily recognize it.Now on to Trac. Click the ‘notification’ link under ‘trac.ini’ in your site’s admin. You can mostly set these options as you see fit. Here are the ones you’ll probably want to make sure to set:
smtp_enabled should be true for this whole deal to worksmtp_user and smtp_pass should be set accordingly for the user you created abovesmtp_server to ‘localhost’ and smtp_port to ‘587’ (this will use TextDrive’s secure SMTP)use_tls to trueno-reply address for smtp_from and smtp_replytosmtp_from_nameuse_public_cc to false to protect users’ privacy as much as possible.That should do it. Again, you may need to restart tracd, then try a test ticket to see if your notifications are working as expected.
This part is optional but highly recommended. You may know that Subversion features hooks to trigger scripts when certain actions occur (see the SVN Book to learn more). The Trac repository contains a user-contributed script that will automatically respond to text in commit messages like “closes #13” or “references #53” by creating links to the referenced tickets by number, and closing them if appropriate. You can read the detailed comment at the beginning of the script itself for further info.
Here’s what you’ll need to get this working with our setup:
$ cd ~/svn/<your-repo>/hooks
$ svn co http://svn.edgewall.org/repos/trac/trunk/contrib/trac-post-commit-hook
$ nano trac-post-commit-hook
... change the top line as follows ...
#!/users/home/<youruser>/python/bin/python
... save and exit with CTRL-O then CTRL-X ...
$ chmod 770 trac-post-commit-hook
Then, edit the file post-commit in the same directory, so that the body of the script looks something like this, edited appropriately:
REPOS=”$1”
REV=”$2”
#
- Trac post-commit hook to close tickets from the commit message and stuff
#
export PYTHONPATH=’/users/home//python/lib/python2.4:/users/home/samwise97/python/lib/python2.4/site-packages’
TRAC_ENV=”/users/home//trac/“
/users/home//python/bin/python /users/home//svn//hooks/trac-post-commit-hook \
-p “$TRAC_ENV” -r “$REV”
Be sure to leave the shebang line at the top. The last step for getting this to work will require you to submit a ticket to TextDrive support. The trac-post-commit-hook file needs to be owned by the ‘www’ user in order for it to get executed correctly.
One of the nice things about the way Trac project environments are set up is that back-ups are easy as py (nyuck nyuck!). The directory containing the environment contains everything that you’d want to back up for a project: configuration, customized templates, attached files, and the project database. Just create a tarball of the environment directory and copy it elsewhere. You can create a script to do this, and use cron to run it periodically. The TextDrive knowledgebase article for database back-ups can give you an idea of how to get started.
By now, you should have quite a nice Trac site for your software projects. We’ve seen how to install Trac with a custom Python environment, how to configure it, and how to extend it with plug-ins.
There are numerous other useful plug-ins, such as a SpamFilter, a simple Pastebin (which needs a tiny edit for 0.11 that I submitted here), or the versatile TagsPlugin. Installing these should be much the same as those that we’ve seen already, and you’ll find instructions at the links given. You might also like to customize your site templates and CSS — the Elixir project’s site is a nice example.
Recent versions of Trac also have expanded support for alternate versioning systems in place of Subversion. I’ve written another article concerning the use of the Mercurial distributed VCS and using it with Trac.
Another ambitious project (by the creator of Trac) is Bitten, a distributed continuous integration and build system integrated with and built heavily around Trac. I’m keen to play with this in the future, and I’ll surely chronicle my experiences when I have the chance.
I hope you’ve found these guides useful, and that Trac serves you well.
The TextDrive theme continues! Trac-hacks.org has been down for a couple of weeks — apparently the maintainer went out of town shortly before the server tanked — so I’m stalling on Part II of my Trac on TextDrive article. Sorry! Plug-in installation is the focus of the article, so it would be rather frustrating to try to follow along when most of the resources are unavailable…
In the mean time, I’ve been trying out Mercurial and really digging it. Mercurial is a distributed version control system, and we’ll talk a little about why you may want such a thing. Also, it’s written (mostly) in Python, and has a very functional Trac plug-in (that incidentally is not hosted on Trac-hacks currently!), so it seems to fit pretty well into our current theme.
Bill de hOra has written a couple of useful articles on Mercurial set-up that are specific to TextDrive, but they’re “terse” by his own words, and the user-local Python environment that we set up earlier affords us a more straightforward procedure. I’ll also try to pick up where Bill left off by briefly covering Mercurial set-up and use with SSH.
But what is this all about, really? There’s been a lot of chatter recently on the rise of distributed VCSes like Bazaar, git, darcs, etc., and I’m not going to go into detail about opting for one tool over another (Wikipedia has a big comparison matrix if you’re looking for a place to start your own research). Rather than sweating the minutiae that separate these tools, readers here would probably be better served by some discussion of why one may want a distributed SCM in the first place. While I haven’t explicitly covered the use of a VCS in the past, the depth of my Trac articles probably appeals more to the beginner than the seasoned (read: impatient) version control user, and someone just starting with Subversion may wonder why he or she should think about throwing it out and starting over. Read on for more, or you can just jump ahead to the set-up details if you like.
h5. Contents
First off, what’s wrong with Subversion? Well, it is by no means a terrible system, and as an answer to CVS it was an undisputed blessing. Many of its shortcomings become apparent in projects with numerous developers committing, or when you are the lucky one tasked with resolving conflicts. Still, I believe that distributed systems also offer advantages for smaller teams and even individuals, and I’ll try to make light of them.
The preeminent feature of a DVCS, as the name implies, is that every working copy has a complete copy of the project’s revision history — in reality, a “working copy” is no different from the “canonical” repository. This means that team members can easily work offline, and as a bonus you’ll likely have multiple isolated back-ups of your full history. Of course this is no substitute for a proper back-up scheme, but it also means that any unavailability of your central VCS server doesn’t predicate a grinding halt in a team’s productivity.
For project maintainers in particular, as I alluded to previously, most of the distributed systems have significantly better branch and merge capabilities, and Mercurial is fully ready for 3-way merge tools. Branching in Subversion is particularly limited. There are also some very sophisticated extensions, such as Mercurial Queues, which gives maintainers a powerful means of juggling patches. These things are really beyond the scope of this article, though.
I haven’t rigorously evaluated the competition — I’ve chosen Mercurial based on others’ accounts, speed and convenience, and generally liking the “feel” of the commands and usage patterns after trying it for a bit. It doesn’t hurt that there are excellent resources available, like Bryan O’Sullivan’s Google Tech Talk, and his comprehensive and free reference book. For icing on the cake, there’s a very good TextMate Bundle, useful tools like hgsvn, and a high level of extensibility. You may find that another DVCS works better for you, but nonetheless the principles here should apply.
To me, the most compelling reasons for individuals and small teams to try Mercurial are speed, flexibility, and a more natural workflow that encourages experimentation and frequent commits. It’s possible to use Mercurial in almost exactly the same way as you would use Subversion, but some acknowledged best practices suggest another approach something like this:
clone a copy from the “authoritative” repository, and designate it as a “pristine” branch for regularly pulling the latest updates.commit in Mercurial is a local operation, and you will push updates back to the authoritative repo once you’ve got working code, or simply export a patch for emailing.The official Mercurial wiki has more info on common working practices. I’ll offer a very brief run-through of common commands after the installation procedures, along with a link to the official tutorial for more detail. Mercurial’s command set is small and intuitive, and it is thoroughly self-documenting, as we’ll see shortly. Many of the commands parallel their svn counterparts, so you can learn quickly.
The last note that I’ll make about the value of Mercurial for a small team is to point out the facilities for ad-hoc collaboration. The distribution contains a built-in web server, and a user can publish his repository on demand with one quick command (Mercurial supports push and pull across SSH or HTTP/HTTP">HTTPS). I can imagine this being very useful and flexible for groups practicing agile development methods, pair programming, or impromptu sprints at user group meetings or conferences.
Alright, enough filibustering, let’s take some action already!
Once again, assuming that you followed my instructions for setting up a user-local Python environment, then installing Mercurial is a cakewalk:
$ easy_install mercurial
This should be run over a shell connection to your shared host. Of course, you’ll want Mercurial installed on your own machine to work with it. First, get Python if you don’t already have it. The steps for installation will differ depending on your platform. Once you have Python up and running, you can grab easy_install and just use the same command as above. Alternatively, you can install from source, which should be a simple build. The easy_install method may not install the man pages, but otherwise it is plainly simple to install and upgrade (via easy_install -U mercurial). You’ll probably find that all the help you need is built in anyhow. Finally, if you have any trouble, check the official Mercurial tutorial, which gives detailed installation instructions.
We’ll soon be serving up your repo(s) on the web (that’s why you’re reading this, right?), but we need a repo first! That’s pretty easy. You can start with an empty directory and add to it, or if you have a project you wish to use you can turn an existing directory into a repository. From your home directory:
$ mkdir hg; cd hg
# if you have a project already:
$ cp -R your/project/dirname . # note the dot!
$ hg init dirname
# or if you want to start with a clean slate, just:
$ hg init spiffyname
The ‘spiffyname’ dir would be created for you if it didn’t already exist. ‘hg‘, the atomic symbol for Mercury, is the Mercurial command-line tool. We’re intentionally creating the hg directory outside of your web/public so that there’s no danger of someone snooping it out should you elect not to serve your repository via HTTP. You can have multiple repositories, and we’ll see how to add files soon.
Before we go any further, take a second to add your name and email address to Mercurial’s config file:
$ nano ~/.hgrc
... add the following ...
[ui]
username = Your Name <your [at] email [dot] com>
... close and save with CTRL-O, CTRL-X ...
This is the customary format, but use what you’d like. This will identify you in all of Mercurial’s records. Your email address will automatically appear obfuscated to users who aren’t logged in, to protect you from spam.
hgwebdir is a CGI script — included with the source distribution of Mercurial — that allows you to serve one or multiple repositories over HTTP/HTTPS. It provides a simple web interface to browse the source code and changesets, and also allows you to push and pull revisions. You only need to follow these steps if you wish to allow others to have access to the repository; if you want a private set up, just use SSH as detailed in the next subsection.
WARNING! The steps I’m going to show you will result in an insecure repository, in that your transactions with the server will cross the wires in clear text. I don’t have an SSL certificate at TextDrive, so if you do, feel free to skip the step we’ll take to explicitly allow plain HTTP. More info is here. This doesn’t mean that you can’t restrict access for viewing and altering the repo on the web, but it does mean that you shouldn’t use plain HTTP if you intend to work with sensitive data. If your project is open source, this probably doesn’t matter at all.
Since we installed Mercurial as an egg, we need to fetch the CGI script, and make a directory for it in your web document root:
$ cd ~/web/public
$ mkdir hg; cd hg
$ wget http://www.selenic.com/repo/hg/raw-file/tip/hgwebdir.cgi
You can really name this directory whatever you want. Unless you’ve changed defaults at TextDrive, this will be accessible at both http://yourdomain.com/hg and http://hg.yourdomain.com when configuration is complete. Next, we need to create and edit a few files and assure that the script file is executable.
# First edit the CGI and set an absolute path to your python executable:
$ nano hgwebdir.cgi
… replace top line with #!/users/home//python/bin/python …
… CTRL-O, CTRL-X to save and exit …
# make the file executable:
$ chmod a+x hgwebdir.cgi
# now we’ll create a config file
$ nano hgweb.config
… enter the following: …
[paths]
spiffyname = /users/home/<you>/hg/spiffyname
… CTRL-O, CTRL-X to save and exit …
# finally, a local .htaccess file for custom Apache options:
$ nano .htaccess
… enter the following: …
Options +ExecCGI
RewriteEngine On
RewriteBase /hg
RewriteRule ^$ hgwebdir.cgi [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) hgwebdir.cgi/$1 [QSA,L]
AuthType Digest
AuthName “yourdomain.com”
AuthDigestDomain /hg/
AuthDigestProvider file
AuthUserFile /users/home//etc/hg.digest.passwd
<LimitExcept GET>
Require valid-user
</LimitExcept>
… CTRL-O, CTRL-X to save and exit …
In the hgweb.config file, whatever you enter on the left will be shown in the URL, i.e. http://yourdomain.com/hg/spiffyname. The right side of course must point to a valid repository. If you have multiple repos, enter them all here in the same fashion. The .htaccess file tells the Apache to allow CGI scripts in the current directory, does some mod_rewrite tricks to give you nicer URLs, and defines some authentication settings. <LimitExcept GET> allows browsing without a password, but will prevent unauthorized push attempts. See the Apache docs to customize this further. Now we just need to create the password file referenced there:
$ htdigest -c /users/home/<you>/etc/hg.digest.passwd yourdomain.tld username
You’ll be prompted for a password. Omit the -c switch for future calls, such as adding and updating users.
One more file to edit and things should be ready to go. Use nano again to open ~/hg/<your_repo>/.hg/hgrc and add the following:
[web]
allow_push = user1, user2
push_ssl = false
contact = Your Name <your [at] email [dot] com>
description = Describe your project.
name = Site Title
style = gitweb
Note: the push_ssl setting is what makes this set up insecure, but without it you must have an SSL certificate or only use SSH. You can use an asterisk (*) if you would like to give push access to everyone who has a password configured. Also, it appears that an email address in the contact field here does not get obfuscated on the site. Finally, the gitweb style is optional — it’s a clone of the git DVCS’ web interface, and in my opinion looks much better than Mercurial’s default.
That should do it! Fire up your browser, point it it http://yourdomain.com/hg/ and you should see a list of your repositories. In the next part, I’ll show you the basic commands for working with hg, including how to push and pull over HTTP.
Alright, this is pretty lengthy already, so I’m going to save the usage summary, SSH access, the TracMercurial plug-in and the Mercurial TextMate bundle for a second installment. We’ll also enable a handy feature that makes tarballs of the tip of your repository available as a link all the time. Until then, check out the official tutorial!
I’m working on a new blog that I’ll actually attempt to publicize, but here’s something to get me moving in the mean time.
In this article, I’m going to present a comprehensive primer for installing and configuring Trac on a TextDrive account, though a lot of the information could be useful to anyone getting started with Trac, or running Python applications on a shared host. In Part II, we’ll extend Trac’s capabilities with some useful plug-ins.
Trac is a web-based tool for simplifying software project management — it’s grown to be rather popular these days, and even if you’re not familiar with it already, chances are pretty good that you’ve surfed across a Trac site at some point. If you use a version control system like Subversion for software or web development projects, Trac can provide you (or a team) with syntax-highlighted browsing of the code in your repository, diff file comparisons between arbitrary revisions, a flexible bug-tracking system, and an integrated wiki to document your project. It’s also highly extensible.
Trac is built with Python, and really, much of the set up in this article centers around setting up your own Python environment. Python is a dynamic, interpreted programming language a lot like Ruby in its elegance and efficiency, but with rather different philosophies. This setup will also set you on your way if you’re interested in web development with Python, with frameworks like Pylons, Django or Turbogears. Python is the bee’s knees, and I’ll be covering a lot more of it in the future.
h3. The State of Affairs at TextDrive
I’ve seen a good number of questions from people out there who’ve followed TextDrive’s guide for running Trac on their shared hosting accounts, and want to get more from it. Everything here should work just fine if you’ve already set things up the TextDrive way, and I’ll cover the painless commands for upgrading your Trac environments.
You might be asking, “What’s wrong with using the instructions that TextDrive provides? Most of the work is done for you!” And you’d be right. But the version of Trac pre-installed on TextDrive’s servers is currently 0.9.6, which is beginning to show it’s age. The Trac team has been adding some really cool stuff in the 0.10 and 0.11dev branches, plus there’s a plethora of plug-ins out there that are often difficult to get working without full control over the Trac installation. So, we’re going to get to the bleeding edge!
One of the first such plug-ins that you’re likely to yearn for is WebAdmin — let’s face it, constantly logging in over SSH to modify your trac.ini or messing around with trac-admin commands to set a lot of user privileges gets old quickly. I tried in vain to get WebAdmin working on my 0.9.6 setup at TxD, and eventually scrapped it in favor rolling my own. Don’t let the length of this article fool you — it’s really not so tough, and in the end we’ll have a hot and fresh version of Trac, along with a self-contained Python environment that will make things much easier to maintain than if you were to take the pre-installed route.
There are several good reasons for opting for the development version of Trac right now: first, that aforementioned WebAdmin plug-in isn’t needed — it’s there out of the box in Trac 0.11. Second, Genshi is used as the templating system rather than ClearSilver, which was found in earlier versions. You don’t need to know anything about those at this point, except that Genshi is much easier to install. Finally, Trac 0.11 installs with Python setuptools, making it much easier to maintain, and if the final release version is out by the time you read this, Trac installation should literally be a one-liner. Let’s get started.
I’m assuming that you’re already using Subversion to manage source code revisions on some projects. Trac can currently only operate with repositories stored on the same local system, so if you haven’t yet set it up at TextDrive, do so now using the knowledgebase articles. It’s also possible to use other version control systems with Trac, and I may cover Mercurial setup in a future article.
One other thing. The setup shown here, like that in TextDrive’s knowledgebase article, proxies tracd with Apache to publish the site. You’ll need to request a port assignment by submitting a request ticket to TextDrive support. Go do that now, so you can work on the setup while you’re waiting for a response!
Now, without further ado…
We can do all of our work over an SSH connection, so the process moves pretty quickly:
First SSH into your shell account, make a new directory for your Python environment, and fetch the virtual-python script:
$ ssh primarytxduser [at] yourhostserver [dot] com
...enter password...
$ mkdir python; cd python
$ wget http://peak.telecommunity.com/dist/virtual-python.py
This script will create a directory structure, then copy and symlink files from the existing TextDrive Python installation into your own. We won’t include the site-packages directory (where 3rd party Python libraries are stored) since TextDrive’s install contains a great many of them that we don’t need.
Then, just update some path environment variables in your shell’s config file, source it to set the values now, and you’re running with your own Python.
$ python virtual-python.py --prefix=~/python --no-site-packages
$ echo "export PYTHONPATH=$HOME/python/lib/python2.4" >> ~/.bash_profile
$ echo "export PATH=/users/home/youruser/python/bin:$PATH" >> ~/.bash_profile
$ source ~/.bash_profile
$ which python
/users/home/<yourusuer>/python/bin/python
You could just use your home directory for the prefix, but I think the python subdirectory is cleaner.
Now we’ll copy a few libraries from the system Python into our environment: bindings for TextDrive’s version of svn, and for the SQLite database engine (I couldn’t get my own version of pysqlite2 to build easily on FreeBSD…):
$ cd python/lib/python2.4/site-packages
$ cp -R /usr/local/lib/python2.4/site-packages/svn .
$ cp -R /usr/local/lib/python2.4/site-packages/libsvn .
$ cp -R /usr/local/lib/python2.4/site-packages/pysqlite2 .
Don’t miss the dots on each line! Symlinking instead of copying will also probably work, and save you headache if the system packages get upgraded. Now on to setuptools, which you’ll surely love for its easy_install utility. You can learn more than you ever wanted to know about setuptools and easy_install over at PEAK.
$ cd ~/python
$ wget http://peak.telecommunity.com/dist/ez_setup.py
$ python ./ez_setup.py
This will build setuptools for you and install it in your local site-packages directory. Now we can use it for the rest of the components (you don’t need to go download these!):
Only Genshi, the template language mentioned earlier, is required — the others are optional but highly recommended (and a cinch to install). Pygments is used for rendering your code as syntax-highlighted XHTML. The last two allow additional markup languages to be used for Trac’s wiki and ticketing systems. You’re probably familiar with Textile — you can use it for comments on this blog! — and docutils allows reStructuredText, an expressive wiki-like syntax commonly used in Python documentation. If you’re interested in learning more with Python, you’ll probably end up wanting docutils somewhere down the road anyway. No set-up is required for these optional components — Trac just finds them automagically. So here’s all you need to do:
$ easy_install Genshi
$ easy_install Pygments
$ easy_install docutils
$ easy_install textile
Not bad, eh? Each of these commands will produce some output as it downloads the packages, builds them as Python Eggs (a lot like Ruby’s Gems), and installs them into site-packages. Skim for any errors, but all should be OK.
Now we’re ready for Trac! At the time of this writing, Trac 0.11 is still in development, so we’ll need to install from an svn checkout. If the final release is out by the time you read this, you should just be able to do easy_install Trac. Yes, really. This is because Trac 0.11 is built to use our old friend setuptools, so even though we currently have to start the build manually, it’ll still produce an Egg that is easy to upgrade.
Create directories for your Trac environment(s) and the source checkout, then check out Trac trunk, build it, and install it to site-packages.
$ cd ~
$ mkdir -p trac/src; cd trac/src
$ svn co http://svn.edgewall.org/repos/trac/trunk trac-0.11dev
...checkout ouput...
$ cd trac-011dev
$ python setup.py install # build and install Egg to site-packages
That’s it! Now you just need to create an environment associated with your svn repository. If you have an existing Trac environment from following TextDrive’s setup, you can upgrade it instead.
$ cd ~/trac
$ trac-admin <name> initenv
Use a short name. The command will run an interactive setup script to walk you through creating the environment — name your project, accept the default choices for database and repository type (just hit Return), and be sure to specify an absolute path for your repo, i.e. /users/home/youruser/svn/<repo-name>. Of course, modify appropriately if your repo is a secondary domain for your account.
For an existing Trac environment, just run these two upgrade commands in the parent directory:
$ trac-admin <yourenv> upgrade
$ trac-admin <yourenv> wiki upgrade
And that’s it! All that’s left to do is some web server configuration, but we can play with our new toy first.
By now, I’d imagine you’re eager to see this thing work. As long as you’ve gotten your port assignment from TextDrive, we have all we need to test at this point. tracd runs the Trac daemon with a lightweight web server. Fire it up!
# XXXX is your assigned port. Use tracd -h for more details.
$ tracd -p XXXX /users/home/<youruser>/trac/<yourenv>
Again, use an absolute path as shown. This runs tracd in the foreground, so you can hit CTRL+C to kill it when you’ve finished playing. Visit http://yourdomain.tld:XXXX in your browser and you should see a link with the project name you selected. It takes you to the promised land.
At this point, you could use trac-admin -h to see how to configure users and permissions, set up a cron job like the one explained below, and call it a day. But this isn’t very nice yet.
You probably don’t want to force everyone to type in that port number to reach your site, and you may want to customize the URL. We’ll also look briefly at a simple authentication set-up, in case you want to password-protect your site (like my current set-up that includes code from client projects, which is why I haven’t linked you to my own sexy spread yet).
We’ll address the URL first, because we’re going to set up a nicer authentication scheme in the next article anyway. This is done by proxying tracd as explained by TextDrive. To summarize the easy way, we’ll direct requests for trac.yoursite.tld to tracd using Apache mod_rewrite directives in a local .htaccess file. Basically, this is a way to give the web server specific instructions on a per-directory basis — the site root in this case. I’ll use the nano editor, ‘cause it’s friendly
$ cd ~/web/public # or the web/public dir of a secondary domain
$ nano .htaccess # will create the file if it doesn't exist
...file opens in nano; enter the following in the file...
RewriteEngine On
RewriteCond %{HTTP_HOST} ^trac\.
RewriteRule (.*) http://127.0.0.1:XXXX/$1 [P]
...type CTRL-O, RETURN, CTRL-X to save and quit...
Feel free to substitute 'trac' with anything of your choosing — I use 'dev'. If you have existing rewrite rules in the file, you probably don’t need the RewriteEngine On directive, and you may want to put the other two lines above any other rules.
If you want a more sophisticated URL scheme, see the linked TextDrive document, or read up on mod_rewrite.
We’ll again refer to TextDrive’s instructions for a simple authentication setup. You can skip this for now if you can wait for Part II of this article, where I’ll show you how to set up the near-essential AccountManager plugin for Trac.
Use this command to create a password file and add the first user:
$ htdigest -c /home/<youruser>/etc/trac.digest.passwd yourdomain.tld username
Make sure you have an etc directory in $HOME — use mkdir ~/etc if necessary. username is arbitrary, but if you’re limiting access to a development team, it’d be sensible to match them with svn passwords. Omit the -c switch on subsequent calls to htdigest for the file.
You’ll need to add your users and set their permissions in the Trac environment. This is covered in Part II, but if you’re in a hurry, check tracd -h to get started, or the documentation in the wiki on your new Trac site (the manual is built in!).
To use this auth setup, you’ll need to augment the command you use to launch tracd. We’ll cover this in the next section.
The last step for today is to make sure that tracd is run automatically when the physical server has to be restarted. For that, we need cron, the handy UNIX utility for running scheduled tasks. I’m going to use the crontab command from our login shell, which might be a little scary to some because it uses the vi text editor. vi can be a little cryptic for the uninitiated, but I’ll try to make this simple edit as painless as possible. Alternatively, you can configure cron jobs through the Webmin interface for your TextDrive account. I’ll leave that route as an exercise for the reader — it’s actually covered in the Trac setup guide I’ve linked to throughout this article. You can ignore the backslashes in these listings — just wanted to indicate the linebreaks.
$ crontab -e
...vi loads your crontab file, which might be empty...
# Press 'i' for insert mode and enter these lines
SHELL=/usr/local/bin/bash
@reboot /users/home/<youruser>/python/bin/tracd -d -p XXXX \
/users/home/<youruser>/trac/<yourenv> #run tracd after reboot
# To save and exit, press ESC to enter command mode.
# Type ':wq' (for 'write quit') and hit RETURN
Be sure to replace XXXX with your port number. We set the SHELL so that cron tasks use your shell configuration, i.e. it will use your custom PYTHONPATH. It’s otherwise best to use absolute paths thoughout. The -d switch runs tracd as a daemon in the background. If you’ve set up authentication, change the reboot line above as follows. Again, see tracd -h for additional details.
/users/home/python/bin/tracd -d -p XXXX \
--auth yourenv,/users/home/username/etc/trac.digest.passwd,yourdomain.tld \
/users/home/<youruser>/trac/<yourenv>
You’re all set! Just remember to actually start tracd now using whichever command you used for the cron job. Treat yourself to your beverage of choice, you’ve earned it!
It’s possible use some sophisticated set-ups for multiple Trac environments, which are beyond the scope of this article, but there is a really simple way. You can set up additional Trac environments just as we’ve done in this article, probably for separate Subversion repositories, and serve them all up in a single tracd instance. To do this, simply specify multiple environments—separated by spaces—when you launch tracd, like this:
$ /users/home/<youruser>/python/bin/tracd -d -p XXXX \
/path/to/environ1 /path/to/environ2
Now, when you visit trac.yourdomain.tld (or whatever URL you configured), you’ll see a listing of the projects. Obviously each is an independent Trac environment, so each can have its own configuration, plug-ins, authentication, and so on.
A whole slew of plug-ins and other add-ons for Trac are available at Trac-hacks.org. These range from simple extensions like a Pastebin, to more complex ones like a spam filter and an extensive continuous integration system (perhaps the subject of a future article).
We’ll take a look at installing a few of those in Part II. We’ll also look at some basic environment configuration for trac.ini. Thanks for sticking it out this long!
The site has been upgraded to Drupal 5.1 and modules have been brought up to date. In theory, this is part of a movement to stop neglecting my blog.
I’m also working on setting up some new modules, including integration of video functionality into the site, so that I can share some recently completed projects. I hope to write how-tos for some of those module configurations, as well as a spam-proofing article I’ve had in mind for awhile now. And I’ll continue updating the audio module tutorial, which I’ve amended with some info for Drupal 5.1.
In other not-so-late-breaking news, Jesse is “about to get married”:http://newligan.com.
Yes, we are actually working on our own company site. Slowly. As we flesh out some copy, we're looking into an identity package so that we can style the site when the content is ready, plus get business cards and all that.
I've implemented a quick-and-dirty issue tracking system for ACS as a proof-of-concept, because I think it's badly needed there. It's built on the drupal casetracker module and is being tested on a current customer project. We're (patiently) waiting on an official sign-off to commence full-on development for them. In the meantime, we've implemented CCK and Views on the staging site, to unlock some of the real meat and potatoes of what Drupal can do.
Jesse has completed work for the launch of paidContent.org, which looks great. He wishes to express his joy to all of you about the migration of their 27,000+ existing entries ;-) He also recently contributed a patch to the Radiant CMS, which powers the new official Ruby site. I think the jury's still out on that patch making it into HEAD...
I had a pretty successful yard sale. Let me know if you need a grill or a dining table. Since then I've been fighting off illness, edumacatin' myself on Ruby over at why's (poignant) guide, and familiarizing myself with the Rails API, in addition to the daily grind. Stay tuned for more... I know you're thrilled.
Opera Mini is pretty awesome.
I found out about it when searching the Salling Clicker forums to see if I could get that app working with my mediocre Motorola V551 mobile phone (more on that another day). I think I'm about to be paying more for my data plan...
The Subversion Applescripts included with Growl are a great little timesaver. For that matter, browsing the other included scripts inspired me to consider some repetitive tasks that I should script myself.
Jesse turned me on to VirtueDesktops, a long-needed replacement for DesktopManager, which I've been using I think since Jaguar. Sadly the graphics card in my ancient Powerbook isn't Core Image capable and I don't get the spiffy animations when switching desktops. Until we have Spaces, though (and/or I get a new Powerbook), it's an indispensable app.
Last but not least, Google Browser Sync allows me to pick up where I left off between home and work. Firefox bookmarks and session info are synced through your Google account (with encryption) so you can get right back to those 16 tabs spread across 5 windows...
Now I just wish the Adium plug-in for Quicksilver would work again...
Updated for Drupal 5.1! See the bottom of the article.
I have a growing backlog of stories that I've been meaning to type up here, including several articles of interest for folks getting started with drupal, but I've just finished setting up the audio module, so I thought I'd share my experience while it's fresh on the mind.
You'll notice that you can now play the "two out of three" mp3 from my last post direct from the site without the need to download, and this is thanks to the audio module. Since it utilizes drupal's node model for content types, this module is able to harness much of the power and flexibility inherent in the CMS, including the taxonomy system and automatic RSS/podcast feed generation. It can also be readily extended through modules like the playlist toolkit for sites with sophisticated audio needs.
My intent here, though, is just to offer a quick step-by-step guide for a simpler application: a blog or some other site seeking to include audio files attached to other content types (pages and stories, for instance). Still, this should be helpful for anyone getting started with the audio module.
> tar xzvf audio-4.7.0.tar.gz
> unzip getid3-1.7.7.zip -d <yoursitepath>/modules/audio/
Version 1.7.7 of getid3 is recommended in the audio module's documentation.
Of course, if audio plays a more prominent role at your site, there's much more that you can do with the audio module, incorporating taxonomy, changing the look of the player, and so on. Here are some links to get you started.
For the most part, updating my audio module for use as outlined above was intuitive, with one exception: the audio_attach module has just been contributed to CVS for 5.x by zirafa. He's also contributed a new audio_playlist module, but I haven't tried that out yet. To get audio_attach (and get my existing nodes with attached audio back to working order), I checked out the audio module from CVS with the following commands:
> cd <yoursitepath>/modules
> cvs -z6 -d:pserver:anonymous:anonymous [at] cvs [dot] drupal [dot] org:/cvs/drupal-contrib checkout -d audio contributions/modules/audio
I installed the modules as normal and ran update.php. At this point I received an SQL error as the script attempted to set multiple primary keys for the audio_attach table. I manually set nid, aid and weight as primary keys using phpMyAdmin, and I was back in business. I've found that my Flash players are not visible when using the handy admin_menu module, but that probably shouldn't effect many of your users.
I'll try to update all of these instructions soon. In the meantime, comment if you have questions!
Welcome to my little corner of nausicaamedia.com. Please pardon the dust (and canned drupal theme) until design and development settles!
This will consist of the blog that you're reading, my résumé, photos, and other personal stuff. It will mostly be a chronicle of what's going on at NMS, but will also include my own random musings about technologies, media, and life in general.
Nausicaa Media Services is the company, right now in its infancy, founded as an umbrella for my freelance work in video post-production and web development. I am partnering with my childhood friend Jesse to offer development and consulting services with an emphasis on web standards, OSS, and web applications built on MVC architecture. We will soon seek to hire freelance designers, with an eventual goal of providing end-to-end branding and information design for web, broadcast and print media.
While Jesse has graduated to Ruby on Rails, I'm still wrangling PHP and am presently evaluating drupal as a content management system. Hence, this blog and the initial NMS site as a whole will be built on drupal. Jesse has extensive experience with Movable Type and others, and we will strive to stay abreast of emerging CMS and framework offerings in order to offer the right choices to clients.
Our first projects are for Atlanta CAD Services, Inc., my full-time employer, and Atlantic Coast Customs, friends of mine from Georgia Tech who are starting an automotive customs shop. It seems like there's no shortage of work out there, and I'm excited to have these two as early case studies, since we'll go through a corporate redesign and a from-scratch showcase site.
Stay tuned for updates on development work-in-progress and first-timers' forays into small business!
It turns out that Vim ships with a pretty sweet man page plugin included, which you’d discover if you edited man pages very often, but most of us don’t so it’s probably a lot more useful to us as a viewer.
Some of you Vim wise guys are saying, “But Vim already has a handy man page viewer, just press K in normal mode for the word under the cursor.” Sure. If you type ‘sh’ a lot in your code and docs maybe that’s great. I can count the number of times I’ve actually used it on one hand (except with plugins that remap it to language-specific doc lookups). Plus it just loads the page in a crummy pager.
Behold:
runtime ftplugin/man.vim
Run that in command mode and observe that you now have a :Man command available. Think up some fun man page to browse and BOOM, you’re reading it in a split window just like :Man sh — that. Yeah, whoa.
This, my friends, is a bonafide Vim buffer. It’s pretty. It’s got syntax highlighting. But best of all, references to other man pages are tags. So when you’re reading that bash page and you’re like, “WTF isatty(3)?” you just put your cursor over that reference and with Ctrl-] you reach enlightenment.[1] When you see it’s libc and you tremble, Ctrl-t and you’re back to bash.
“This is swell!” you say. “It’d be cool if K used this for those five times in my life.”
nmap K :Man <cword><CR>
Put that in your .vimrc and smoke it.[2] Don’t forget to first runtime the plugin as above while you’re in there, to make it persistent.
Some folks like this so much they want to use it when they invoke man on the command line. I’m not drinking that kool aid yet but you might dig it.
[1] Or not. What a buzzkill. If you’re on a Mac or perhaps other platform and get an error, there’s this bug where a well-intentioned fellow fixed a problem but introduced a new one for others. Do `:e $VIMRUNTIME/ftplugin/man.vim` and comment out the `let $MANPAGER =”“` line about 20 lines in, and you should be sitting pretty.
[2] The plugin actually maps `<Leader>K` for you to do the same thing, if you want to just commit that to memory instead.
Rails 3 and Mongoid are just peachy. Here are a couple of development conveniences for using them together.
Pop this snippet in your ~/.irbrc to show the raw JavaScript queries that Mongoid is running as you play with your app in the Rails console (and/or SQL, when you’re using ActiveRecord). Formatting isn’t great for Mongo queries, but it’s helpful nonetheless.
Setting autocreate_indexes to false will spare you some log noise. It’s also worth noting that Hirb works nicely out of the box for Mongoid documents, and I heartily recommend it.
And here’s a db:console Rake task to stand in for the rails dbconsole command that won’t work with Mongoid:
This problem is well-documented around the web, this is just my personal reminder. Others have crafted various solutions varying in complexity. I like this one for the simplicity and easy portability—I don’t remember who to credit for it, unfortunately.
Without getting too deeply into the gory details, if you connect to a remote shell and run GNU screen there, then detach the screen and come back to it in a later SSH session, environment variables that SSH agent forwarding requires to function will have changed and your screen session is none the wiser. This is rather annoying if you frequently connect to a gateway server and use screen to do work on other servers inside of it—your public key will not be forwarded to the internal servers on subsequent connections.
Enter wrapper script to save new SSH variables when you connect again and resume your screen session:
#!/bin/bash
# Wrapper script to set SSH env vars so agent forwarding works when
# resuming screen sessions. Place at ~/bin/screen and make sure
# your personal bin directory has priority in your PATH
for SSHVAR in SSH_CLIENT SSH_TTY SSH_AUTH_SOCK SSH_CONNECTION DISPLAY; do
echo "export ${SSHVAR}=\"${!SSHVAR}\""
done > ~/.sshvars
/usr/bin/screen $*
Then, a simple alias for your .bashrc, to run once you’ve resumed screen:
# After reconnecting to a screen session, this restores env vars
# to allow agent forwarding to work again
alias fixssh='source ~/.sshvars'
Off you go to now to connect to those internal servers needing your forwarded key.
For Leopard, at least:
You might possibly still need to restart applications, log out and back in, or restart completely.
Thanks to the fine people on this thread.
# Clear user font caches
$ atsutil databases -removeUser
# And system cache
$ sudo atsutil databases -remove
# Restart the ATS server
$ atsutil server -shutdown
ATSServer shutdown
$ atsutil server -ping
ATSServer is running
# Check for filesystem activity (this is just generally cool)
$ sudo fs_usage | grep ATS
I’m no good at those “guess how many jelly beans are in the jar” things though. Usually you just win the jar anyway, and who wants that many jelly beans?
‘clean blood stain’ is probably one of those Web History moments where you want to make certain that you’re logged out of your Google account.
Get the Ruby mysql gem to build with MySQL installed from 64-bit binary installer:
sudo env ARCHFLAGS=”-Os -arch x86_64 -fno-common” \
gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
Courtesy of synth @ Chris Cruft » Blog Archive » Ruby, Rails and MySQL with Leopard 10.5.2 and XCode 3.0In the keyboard section of xorg.conf:
Option "XkbOptions" "ctrl:swapcaps"
export PS1="\n\[\033[0;32m\]\w\[\033[0m\]\n[\u@\h]\$ "
Produces a prompt that looks something like this, with that initial newline giving some space from the output of the previous command:
~/src/lexblog/lexcode
[ches@porco]$
Scrivener is a word processor and project management tool created specifically for writers of long texts such as novels and research papers. Has a screenplay mode, WriteRoom-like fullscreen edit,…
finding that just about everything in the Rails Recipes book is useful and pertinent