Posts Tagged ‘code’

The Smallest Carbon Emacs Installer Ever.

Wednesday, January 9th, 2008

As noted on several other blogs posts the /usr/bin/emacs in MacOS X Leopard is built with carbon support, it simply lacks the .app wrapper. You can easily download the .app wrapper and create a symlink and away you go. So here is a shell script that does that.emacs-installer.shUsage:

  1. Download emacs-installer.sh
  2. chmod a+x emacs-installer.sh
  3. sudo ./emacs-installer.sh /Applications

Technorati Tags: ,

iRate.py v2007-06-29

Friday, June 29th, 2007

The Problem:iTunes keeps song ratings, play and skip counts in a proprietary database format.The Solution:iTunes exposes song ratins, play and skip counts via AppleScript, and I have a python->AppleScript bridge.My solution of course is not a particularly original one, Doug’s AppleScripts for iTunes includes a Tags to File Comments script. Which uses AppleScript to take ratings, play counts, skip counts, and more out of iTunes and shove it into the Spotlight comment field in the extended attributes. This was a fine, perfectly well functioning script. However the performance characteristics of both AppleScript and extended attributes makes it very very slow. On my Core 2 Duo MacBook Pro it took roughly 8 hours (I don’t actually know, I fell asleep while waiting) to export the data for ~4,430 tracks, with iTunes using 100% CPU. I don’t know how long it takes to import the data because I figured I could write something else in less than 8 hours.So after about 4 hours of coding and debugging I present to you iRate.pyIt uses AppleScript to export the the ratings, played count, played date, skipped count, skipped date to an SQLite database. It will also import the same data from the SQLite database.  It also manages to be significantly faster than Doug’s script.  The export of my library takes about 44 seconds, and another 22 seconds to import.To run it requires:

  • MacOS X 10.4 (tested on 10.4.10)
  • iTunes 7.2+ (tested on 7.2 and 7.3)
  • Python 2.5 (Universal binary available here)
  • appscript 0.17.2 (Fancy installer available here)

So there we have a simple solution to a simple problem. Here is hoping someone else finds it as useful as I did.-David

Technorati Tags: ,

very actual information about skulls

Tuesday, June 5th, 2007

WWDC2007 is in just 5 days. I’m very much looking forward to seeing people’s reactions to Leopard Server since last year. It’s been really fun to work on, and not just because my stuff is almost all Python + Twisted. I’ve just had to work on some really interesting problems. It’s also very nice to take a break from doing a lot of framework work and never getting to really use the framework. Now I am, now I thinking I’m understanding much better what it’s actual problems are, and why some of our design decisions have been good and some have been bad. (Mostly mine have been bad I think.) I really look forward to correcting some of those mistakes in the near future once we’ve shipped. I’m also looking forward to seeing what comes of the Twisted.web2 summer of code project. James and Valentino are both very smart people and I’m sure some amazing things will get done.On a web2 related note. I’ve never been very happy with static.File. For a variety of reasons that I haven’t really documented anywhere. So here is a short list.

  • It’s poorly factored, it contains code to handle both files and directories, and it is difficult to seperate the code that does the directory listings from the files. (Even though it’s in defined on another class, it’s still weird and difficult to substitute.)
  • It doesn’t take advantage of one of web2’s most useful features over twisted.web, the ability to consume an arbitrary number of path segments during resource traversal. In theory you could join all the segments passed to locateChild and try to treat it as a file, falling back to child_ methods or children that were added with putChild if the file didn’t exist, and if that failed returning a 404. (a non-existent static.Directory class could do this, since static.File instances shouldn’t have children.)
  • There were also some things that bothered me about overriding mimetypes
  • I’m also not fond of it’s ignoredExts or processors __init__ arguments. They’re useful for executing such as CGI scripts but I don’t really think you should mix scripts you want executed with files you want served statically. Perhaps that is just an asthetic issue. We also have a CGIDirectory which acts as a general purpose cgi-bin resource.

And now, just like I promised, som every actual information about skulls. “In humans, the adult skull is normally made up of 29 bones.”P.S. If you’re confused about the title of this post, it came from a spam comment that got caught in moderation (and made it past akismet,) it amused me greatly and I at the time of this writing nothing came up on google for it.

Technorati Tags: , ,

Twitter + Quicksilver + Growl = Tweet+Growl

Wednesday, March 21st, 2007

A while ago after much discussion of Twitter by Leo Laporte and Merlin Mann on MacBreak Weekly I decided to sign up. I like it, I can’t explain why, I just do. It satisfies my urge to talk to noone in particular.Shortly after discovering Twitter I immediately went looking for the best way to post to Twitter. Where I found the Tweet = Twitter + Quicksilver which is a great little script, but it never told me when it was successful. (and during twitters recent downtime I Tweet’d several times.)So in the spirit of open source I decided to improve it by adding Growl support. So without further ado I present to you Tweet+Growl

tell application "GrowlHelperApp"	set the allNotificationsList to {"Success Notification", "Failure Notification"}	set the enabledNotificationsList to {"Success Notification", "Failure Notification"}	register as application ¬		"Tweet" all notifications allNotificationsList ¬		default notifications enabledNotificationsListend tellusing terms from application "Quicksilver"	on process text tweet		tell application "Keychain Scripting"			set twitter_key to first Internet key of current keychain whose server is "twitter.com"			set twitter_login to quoted form of (account of twitter_key & ":" & password of twitter_key)		end tell		set twitter_status to quoted form of ("status=" & tweet)		set results to do shell script "curl --user " & twitter_login & "-D - --data-binary " & twitter_status & " http://twitter.com/statuses/update.json"		set code to word 3 of results		if code = "200" then			tell application "GrowlHelperApp"				notify with name ¬					"Success Notification" title ¬					"Tweet Success" description ¬					"Successfully twittered \"" & tweet & ¬					"\"" application name "Tweet"			end tell		else			tell application "GrowlHelperApp"				notify with name ¬					"Failure Notification" title ¬					"Tweet Failure:" & code description ¬					"Failed to twitter \"" & tweet & ¬					"\"" application name "Tweet"			end tell		end if		return nothing	end process textend using terms from

Technorati Tags: ,

svnpurge

Sunday, November 12th, 2006

This deletes all unknown files in an svn working copy.

alias svnpurge="svn st | awk '/^?/ {print \\$2}' | xargs rm -rvf | awk '{print \\"Purging \\" \\$1}'"

Technorati Tags: , ,

ctypes number of cpus

Tuesday, November 7th, 2006
#!/usr/bin/env pythonfrom ctypes import *import ctypes.utillibc = cdll.LoadLibrary(ctypes.util.find_library('libc'))def getCPUnums():    counts = {'logicalcpu': c_int(0),              'ncpu': c_int(0),              'physicalcpu': c_int(0)}    for k, v in counts.iteritems():        size = c_int(sizeof(v))        libc.sysctlbyname('hw.%s' % (k,),                          c_voidp(addressof(v)),                          addressof(size),                          None, 0)    return (int(counts['ncpu'].value),            int(counts['physicalcpu'].value),            int(counts['logicalcpu'].value))if __name__ == “__main__”:    print “”"CPU Counts:N:\t\t%dPhysical:\t%dLogical:\t%d”"” % getCPUnums()

Of course my Intel Core 2 Duo gives me the following.

sabrina dreid:~> python cpun.pyCPU Counts:N:              2Physical:       2Logical:        2

You could have just as easily done sysctl hw.ncpu hw.physicalcpu hw.logicalcpu with commands.getoutput. But ctypes is cooler and almost certainly several times faster.

Technorati Tags: , , ,

imapfilter and magical archives

Thursday, September 14th, 2006

After figuring out how to filter my mail I set about figuring out howto use imapfilter to archive old mail in my INBOX. This is actuallyquite simple.

oldmail = {    'old',    'not_since ' .. date_before(7)}results = match(myAccount, 'INBOX', oldmail)move(myAccount, 'INBOX', myAccount, 'INBOX-archive', results)

First off this code matches any old mail (read, seen, whatever) thatarrived more than 7 days ago. Then it moves this mail off to the sideto a folder called ‘INBOX-archive’. It’s put off to the side becauseof some deficiencies with mutt. But I don’t sync -archive foldersanyway so it’s not a big deal, it’s just there if I ever need it.Of course, this still lets the mail in my local folders for all mymailing lists (which constitute most of my mail) pile up. Thesolution? Well I’m subscribed to all the mailing list mailboxes, andit turns out that imapfilter gives me a really nice list of all mysubscribed mailboxes.

print("Archiving mail recieved before " .. date_before(7) .. ".")subscriptions = lsub(myAccount, '')for n in subscriptionsdo   print('Archiving in ' .. subscriptions[n])   mailbox = subscriptions[n]   results = match(myAccount, mailbox, oldmail)   move(myAccount, mailbox, myAccount, mailbox .. ‘-archive’, results)end

Of course this doesn’t work. Atleast not out of the box on imapfilter1.2.2. At one point the following essentially occurs

prefix = NULL;/* read a bunch of stuff off of the network */strlen(prefix);EXC_BAD_ACCESS

Apparently imapfilter doesn’t exactly know how to do deal with myimap server, and prefix stays NULL, causing a not very nice Bus Error.The below patch fixes the problem, though not in the nicest waypossible. It merely does what the original author did and sprinklternary operators liberally.

--- old-namespace.c     2006-09-13 22:41:20.000000000 -0700+++ namespace.c 2006-09-13 22:42:15.000000000 -0700@@ -60,8 +60,8 @@        buffer_reset(&nbuf);        o = 0;-       if (!strncasecmp(mbox, prefix, strlen(prefix)))-               o = strlen(prefix);+       if (!strncasecmp(mbox, prefix, strlen((prefix ? prefix : ""))))+          o = strlen((prefix ? prefix : ""));        n = snprintf(nbuf.data, nbuf.size + 1, "%s", mbox + o);        if (n > (int)nbuf.size) {

I’ll probably submit this patch to the upstream, or at the very leastnotify them of the bug. imapfilter is a pretty handy little app. Sohandy that it got me to actualy debug C code for the first time inyears.

Technorati Tags: , ,

imapfilter and mailinglists with a list-id header

Wednesday, September 13th, 2006

When I switched to my minimalist mail environment (which takes noless than 4 command lines to read my mail) I suddenly found myselfwith a filtering problem. First some background on my environmentI read my mail in mutt. It doesn’t suck, very much. It alsosatisfies my absolute biggest requirement in a mail reader which isthe exact same behavior on Linux as on OS X. Being able to read mymail over SSH isn’t a requirement it’s just a perk. However I do_not_ use mutt’s built in IMAP support, to actually download mymail I use offlineimap to sync my remote mailboxes with a localMaildir format directory. So now I have all my email in~/Mail/dreid.org/INBOX but having all my mail in one place is notreally an optimal solution, and so this brings me to my filteringproblem. I’d used procmail in the past, but frankly at this pointafter so many years of staring at nice clean python code for avariety of purposes I’d rather eat my own excrement than writeanother .procmailrc. Luckily for me there is a nice little toolcalled imapfilter. Written in C but scriptable in Lua so installedit then immediately set about writing a filter for my mailinglists.

The typical List-Id header

My Lua code handles the two most common List-Id headers that I’veseen, and works across all the mailing lists I’mcurrently subscribed to.First there is the domain only header:

    List-Id: baypiggies.python.org

Then there is the Description header:

    List-Id: Twisted Python Discussion     

In my case I wanted to use the first segment of the domain as themailbox name. I use a very simple algorithm that makes thefollowing assumptions:

  • Periods only appear in the domain name
  • Left Angle brackets only appear around the domain name
  • There are no spaces in the domain name

Given the 5 or 6 mailing lists I’m subscribed to and that they allfollow these rules, the obvious deficiencies in the code don’t bother meall that much, however your mileage may vary.

The Code

So without further ado here is the code so you too can be on yourway to mailing list filtering goodness

function parseListId(header)   baseheader = string.sub(header,                           string.find(header, ':')+1, nil)   destname = ''   for i=1,string.len(baseheader)   do      c = string.sub(baseheader, i, i)      if c == '<'      then         -- reset destname on any < brackets         destname = ''      elseif c == '.'      then         -- stop on the first .         return destname      elseif c ~= ' '      then         -- add any non-space character to the destination name         destname = destname .. c      end   endend

The rest of the config.lua for mailing lists

mailinglist = {   'header "list-id" ""'}results = match(myAccount, 'INBOX', mailinglist)listids = fetchfields(myAccount, 'INBOX', {'list-id'}, results) or {}mailboxes = {}for message, header in pairs(listids)do   mailbox = parseListId(header)   if not mailboxes[mailbox]   then      mailboxes[mailbox] = {}   end   table.insert(mailboxes[mailbox], message)endfor mailbox, messages in pairs(mailboxes)do   move(myAccount, ‘INBOX’, myAccount, mailbox, messages)end

Posting this I can see some room for improvement, I could cache andcompare the actual unparsed header (it shouldn’t vary from message tomessage) which would reduce the number of calls to parseListId (I’mnot sure it’s slow enough to worry about though.So now you have what I think is a pretty decent solution, eventuallyimapfilter will get run by a cronjob on my server (cron seems to notactually work on OS X tiger, which is another blog post all together.)Then I’ll only have to run 3 commands to check my mail. Next timeI’ll teach you how to create archives for all subscribed mailboxes.Which is a ridiculously easy bit of lua though I had to patchimapfilter to not get an EXC_BAD_ACCESS when reading folder lists frommy server.

Technorati Tags: , ,