Partial refactoring to isolate git stuff.
authorEric S. Raymond <esr@thyrsus.com>
Thu, 27 Sep 2012 06:42:50 +0000 (02:42 -0400)
committerEric S. Raymond <esr@thyrsus.com>
Thu, 27 Sep 2012 06:42:50 +0000 (02:42 -0400)
git-irkbot.py

index 4f7c0527d7baa34493a0ade3f5205cdfbfefdde6..f6ccb8be1e57ca2cf029e63f215d9fc8651d7cb4 100755 (executable)
@@ -22,7 +22,7 @@
 #
 # /path/to/git-irkbot.py ${refname} $(git rev-list ${oldhead}..${newhead} | tac)
 #
-# Configuration variables affecting this script:
+# git configuration variables affecting this script:
 #
 # irker.project = name of the project
 # irker.channels = list of IRC URLs corresponding to channels
@@ -79,59 +79,67 @@ version = "1.0"
 def do(command):
     return commands.getstatusoutput(command)[1]
 
-def extract(refname, merged):
-    "Extract metadata to be reported to CIA."
-
-    # Try to tinyfy a reference to a web view for this commit.
-    try:
-        url = open(urllib.urlretrieve(tinyifier + urlprefix + merged)[0]).read()
-    except:
-        url = urlprefix + merged
-
-    branch = os.path.basename(refname)
-
-    # Compute a description for the revision
-    if revformat == 'raw':
-        rev = merged
-    elif revformat == 'short':
-        rev = ''
-    else: # revformat == 'describe'
-        rev = do("git describe %s 2>/dev/null" % merged)
-    if not rev:
-        rev = merged[:12]
-
-    # Extract the meta-information for the commit
-    files = do("git diff-tree -r --name-only '"+ merged +"' | sed -e '1d' -e 's-.*-&-'")
-    metainfo = do("git log -1 '--pretty=format:%an <%ae>%n%at%n%s' " + merged)
-    (author, ts, logmsg) = metainfo.split("\n")
-
-    # This discards the part of the author's address after @.
-    # Might be be nice to ship the full email address, if not
-    # for spammers' address harvesters - getting this wrong
-    # would make the freenode #commits channel into harvester heaven.
-    author = author.replace("<", "").split("@")[0].split()[-1]
-
-    # This ignores the timezone.  Not clear what to do with it...
-    ts = ts.strip().split()[0]
-
-    context = locals()
-    context.update(globals())
-
-    return context
+class GitExtractor:
+    "Metadata extraction for the git version control system."
+    def __init__(self, project=None):
+        # Get all global config variables
+        self.revformat = do("git config --get irker.revformat")
+        self.project = project or do("git config --get irker.project")
+        self.repo = do("git config --get irker.repo")
+        self.server = do("git config --get irker.server")
+        self.channels = do("git config --get irker.channels")
+        self.tcp = do("git config --get irker.tcp")
+        # The project variable defaults to the name of the repository toplevel. 
+        if not self.project:
+            here = os.getcwd()
+            while True:
+                if os.path.exists(os.path.join(here, ".git")):
+                    self.project = os.path.basename(here)
+                    break
+                elif here == '/':
+                    sys.stderr.write("git-irkbot.py: no .git below root!\n")
+                    sys.exit(1)
+                here = os.path.dirname(here)
+        if not self.repo:
+            self.repo = self.project.lower()
+        self.host = socket.getfqdn()            
+    def extract(self, refname, merged):
+        "Extract metadata to be reported to CIA."
+        # Try to tinyfy a reference to a web view for this commit.
+        try:
+            self.url = open(urllib.urlretrieve(tinyifier + urlprefix + merged)[0]).read()
+        except:
+            self.url = urlprefix + merged
+
+        self.branch = os.path.basename(refname)
+
+        # Compute a description for the revision
+        if self.revformat == 'raw':
+            self.rev = merged
+        elif self.revformat == 'short':
+            self.rev = ''
+        else: # self.revformat == 'describe'
+            self.rev = do("git describe %s 2>/dev/null" % merged)
+        if not self.rev:
+            self.rev = merged[:12]
+
+        # Extract the meta-information for the commit
+        self.files = do("git diff-tree -r --name-only '"+ merged +"' | sed -e '1d' -e 's-.*-&-'")
+        metainfo = do("git log -1 '--pretty=format:%an <%ae>%n%at%n%s' " + merged)
+        (self.author, self.ts, self.logmsg) = metainfo.split("\n")
+
+        # This discards the part of the author's address after @.
+        # Might be be nice to ship the full email address, if not
+        # for spammers' address harvesters - getting this wrong
+        # would make the freenode #commits channel into harvester heaven.
+        self.author = self.author.replace("<", "").split("@")[0].split()[-1]
+
+        # This ignores the timezone.  Not clear what to do with it...
+        self.ts = self.ts.strip().split()[0]
 
 if __name__ == "__main__":
     import getopt
 
-    # Get all config variables
-    revformat = do("git config --get irker.revformat")
-    project = do("git config --get irker.project")
-    repo = do("git config --get irker.repo")
-    server = do("git config --get irker.server")
-    channels = do("git config --get irker.channels")
-    tcp = do("git config --get irker.tcp")
-
-    host = socket.getfqdn()
-
     try:
         (options, arguments) = getopt.getopt(sys.argv[1:], "np:V")
     except getopt.GetoptError, msg:
@@ -139,6 +147,8 @@ if __name__ == "__main__":
         raise SystemExit, 1
 
     notify = True
+    project = None
+    channels = ""
     for (switch, val) in options:
         if switch == '-p':
             project = val
@@ -148,29 +158,17 @@ if __name__ == "__main__":
             print "git-irkbot.py: version", version
             sys.exit(0)
 
-    # The project variable defaults to the name of the repository toplevel. 
-    if not project:
-        here = os.getcwd()
-        while True:
-            if os.path.exists(os.path.join(here, ".git")):
-                project = os.path.basename(here)
-                break
-            elif here == '/':
-                sys.stderr.write("git-irkbot.py: no .git below root!\n")
-                sys.exit(1)
-            here = os.path.dirname(here)
+    # Someday we'll have extractors for several version-control systems
+    extractor = GitExtractor(project)
 
     # By default, the channel list includes the freenode #commits list 
-    if not channels:
-        channels = "irc://chat.freenode.net/%s,irc://chat.freenode.net/#commits" % project
-
-    if not repo:
-        repo = project.lower()
+    if not extractor.channels:
+        extractor.channels = "irc://chat.freenode.net/%s,irc://chat.freenode.net/#commits" % extractor.project
 
-    urlprefix = urlprefix % globals()
+    urlprefix = urlprefix % extractor.__dict__
 
     # The script wants a reference to head followed by the list of
-    # commit ID to report about.
+    # commit IDs to report about.
     if len(arguments) == 0:
         refname = do("git symbolic-ref HEAD 2>/dev/null")
         merges = [do("git rev-parse HEAD")]
@@ -179,8 +177,9 @@ if __name__ == "__main__":
         merges = arguments[1:]
 
     for merged in merges:
-        privmsg = template % extract(refname, merged)
-        channel_list = channels.split(",")
+        extractor.extract(refname, merged)
+        privmsg = template % extractor.__dict__
+        channel_list = extractor.channels.split(",")
         structure = {"to":channel_list, "privmsg":privmsg}
         message = json.dumps(structure)
         if not notify: