<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -147,24 +147,25 @@ def invoke_code_swarm(code_swarm_jar, proj_cfg, options):
 def code_swarm_dir(repo):
     &quot;&quot;&quot;Returns a directory within the current working directory that
     we can use for storage within the given repository directory.&quot;&quot;&quot;
-    if repo[0] == '.':
-        repo = repo[1:]
-    return os.path.join(os.getcwd(), &quot;.&quot; + repo, &quot;.code_swarm&quot;)
+    return os.path.join(os.getcwd(), repo, &quot;.code_swarm&quot;)
 
 
 def autogenerate_files(options):
     &quot;&quot;&quot;docstring for autogenerate_files&quot;&quot;&quot;
     if os.path.exists(&quot;.git&quot;):
-        dir = code_swarm_dir(&quot;git&quot;)
+        dir = code_swarm_dir(&quot;.git&quot;)
         generate_log = do_git
     elif os.path.exists(&quot;.svn&quot;):
-        dir = code_swarm_dir(&quot;svn&quot;)
+        dir = code_swarm_dir(&quot;.svn&quot;)
         generate_log = do_svn
     elif os.path.exists(&quot;.hg&quot;):
-        dir = code_swarm_dir(&quot;hg&quot;)
+        dir = code_swarm_dir(&quot;.hg&quot;)
         generate_log = do_hg
+    elif os.path.exists(&quot;_darcs&quot;):
+        dir = code_swarm_dir(&quot;_darcs&quot;)
+        generate_log = do_darcs
     else:
-        msg  = &quot;This directory isn't an svn, git, or hg project. &quot;
+        msg  = &quot;This directory isn't an svn, git, hg, or darcs project. &quot;
         msg += &quot;Run in the base directory of a source-controlled project.&quot;
         print &gt;&gt;sys.stderr, msg
         sys.exit(2)
@@ -198,7 +199,7 @@ def do_git(dir):
 
     return do_cmds('git log --name-status --pretty=format:&quot;%s&quot; &gt; &quot;%s&quot;'%(fmt, tmp)
                   ,&quot;convert_logs.py -g '%s' -o '%s'&quot; % (tmp, xml)
-                  ,&quot;rm %s&quot; % tmp)
+                  ,&quot;rm -f '%s'&quot; % tmp)
 
 
 def do_svn(dir):
@@ -207,7 +208,7 @@ def do_svn(dir):
 
     return do_cmds(&quot;svn log -v &gt; '%s'&quot; % tmp
                   ,&quot;convert_logs.py -s '%s' -o '%s'&quot; % (tmp, xml)
-                  ,&quot;rm '%s'&quot; % tmp)
+                  ,&quot;rm -f '%s'&quot; % tmp)
 
 
 def do_hg(dir):
@@ -218,6 +219,14 @@ def do_hg(dir):
                   ,&quot;sort_code_swarm_input.py &lt; '%s' &gt; '%s'&quot; % (tmp, xml)
                   ,&quot;rm '%s'&quot; % tmp)
 
+def do_darcs(dir):
+    tmp = os.path.join(dir, &quot;darcs.xml&quot;)
+    xml = os.path.join(dir, &quot;log.xml&quot;)
+    
+    return do_cmds(&quot;darcs changes -s --xml-output &gt; '%s'&quot; % tmp
+                  ,&quot;convert_logs.py -d '%s' -o '%s'&quot; % (tmp, xml)
+                  ,&quot;rm -f '%s'&quot; % tmp)
+
 def do_freebase(domain):
     dir = os.path.abspath(tempfile.gettempdir())
     xml = os.path.join(dir, md5.new(str(random())).hexdigest() + &quot;.xml&quot;)</diff>
      <filename>bin/code_swarm</filename>
    </modified>
    <modified>
      <diff>@@ -6,6 +6,9 @@ import os
 import sys
 import time
 from xml.sax.saxutils import escape as h
+from xml.sax import make_parser
+from xml.sax.handler import ContentHandler
+from xml.sax._exceptions import SAXParseException
 from sys import stderr
 import re
 import sre_constants
@@ -51,6 +54,10 @@ def parse_args(argv):
         metavar=&quot;&lt;log file&gt;&quot;,
         help=&quot;input mercurial log to convert to standard event xml&quot;)
 
+    p.add_option(&quot;-d&quot;, &quot;--darcs-log&quot;, dest=&quot;darcs_xml&quot;,
+        metavar=&quot;&lt;log file&gt;&quot;,
+        help=&quot;output of 'darcs changes -s --xml-output'&quot;)
+
     p.add_option(&quot;-l&quot;, &quot;--gnu-changelog&quot;, dest=&quot;gnu_log&quot;,
         metavar=&quot;&lt;log file&gt;&quot;,
         help=&quot;input GNU Changelog to convert to standard event xml&quot;)
@@ -108,6 +115,9 @@ def main(argv):
     elif opts.mercurial_log:
         log_file = opts.mercurial_log
         parser = parse_mercurial_log
+    elif opts.darcs_xml:
+        log_file = opts.darcs_xml
+        parser = parse_darcs_xml
     elif opts.gnu_log:
         log_file = opts.gnu_log
         parser = parse_gnu_changelog
@@ -399,6 +409,57 @@ def parse_gnu_changelog(file_handle, opts):
                 line = file_handle.next()
             continue
 
+def parse_darcs_xml(file_handle, opts):
+    class DarcsParser(ContentHandler):
+        def __init__(self):
+            self.events = []
+            self.author = None
+            self.date = None
+            self.getFilename = False
+            self.filename = &quot;&quot;
+            self.capture_events = [&quot;add_file&quot;, &quot;modify_file&quot;, &quot;remove_file&quot;]
+
+        def startElement(self, name, attrs):
+            if name in self.capture_events:
+                self.getFilename = True
+                self.filename = &quot;&quot;
+                return
+            if name == &quot;patch&quot;:
+                self.author = attrs[&quot;author&quot;].strip()
+                date = re.sub(&quot;[A-Za-z ]+ (\d\d\d\d)$&quot;, &quot; \\1&quot;, attrs[&quot;date&quot;])
+                date = re.sub(&quot;\s+&quot;,&quot; &quot;,date).strip() # normalize whitespace
+                try:
+                    date = time.strptime(date,&quot;%Y%m%d%H%M%S&quot;)
+                except ValueError, e:
+                    date = time.strptime(date,&quot;%a %b %d %H:%M:%S  %Y&quot;)
+                
+                self.date = int(time.mktime(date))*1000
+            elif name == &quot;move&quot;:
+                self.newEvent(attrs[&quot;from&quot;])
+                self.newEvent(attrs[&quot;to&quot;])
+            elif name not in [&quot;summary&quot;,&quot;name&quot;,&quot;changelog&quot;,&quot;added_lines&quot;
+                             ,&quot;removed_lines&quot;, &quot;add_directory&quot;, &quot;remove_directory&quot;
+                             ,&quot;comment&quot;, &quot;replaced_tokens&quot;]:
+                print &gt;&gt; stderr, &quot;warning: unknown tag '%s'&quot; % name 
+            
+        def characters(self,str):
+            if self.getFilename:
+                self.filename += str
+        
+        def endElement(self, name):
+            if name in self.capture_events:
+                self.newEvent(self.filename)
+                self.getFilename = False
+        
+        def newEvent(self, name):
+            self.events.append(Event(name.strip(),self.date,self.author))
+    
+    parser = make_parser()
+    dp = DarcsParser()
+    parser.setContentHandler(dp)
+    parser.parse(file_handle)
+    return dp.events
+
 def parse_perforce_path(file_handle, opts):
     changelists = run_marshal('p4 -G changelists &quot;' + opts.perforce_path + '&quot;')
     file_key_re = re.compile(&quot;^depotFile&quot;)</diff>
      <filename>bin/convert_logs.py</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>e491173bdc417b84c39b2c37d42d6c4680bb97b9</id>
    </parent>
  </parents>
  <author>
    <name>Peter Burns</name>
    <email>peter@metaweb.com</email>
  </author>
  <url>http://github.com/rictic/code_swarm/commit/fc54cc6d2de5480b71543c40c7b62bad7f16f01f</url>
  <id>fc54cc6d2de5480b71543c40c7b62bad7f16f01f</id>
  <committed-date>2009-03-29T17:19:44-07:00</committed-date>
  <authored-date>2009-03-29T17:19:44-07:00</authored-date>
  <message>Added full support for darcs, including autodiscovery

Unfortunately darcs sometimes will produce invalid XML when asked.  This is a known bug, and related to character encoding issues that they seem unwilling to fix.  I might take the performance hit and rewrite this using BeautifulSoup at some point.  I've only seen the bug in the darcs repo itself, it comes up
when there are authors with non-ascii names.</message>
  <tree>751b35132395a4e6123f2574aed01ed6ca364c96</tree>
  <committer>
    <name>Peter Burns</name>
    <email>peter@metaweb.com</email>
  </committer>
</commit>
