Index: mergebot/trunk/mergebot/RebranchActor.py
===================================================================
--- mergebot/trunk/mergebot/RebranchActor.py	(revision 16)
+++ mergebot/trunk/mergebot/RebranchActor.py	(revision 17)
@@ -1,177 +1,176 @@
 #!/usr/bin/env python
 """
-Syntax: RebranchActor.py ticketnum component version requestor
-
 Rebranch a branch from its trunk, pulling in the changes made on the branch if
 possible.
 """
 
+import shutil
+import time
 import os
-import sys
-import time
-import trac.env
 
-import SvnOps
-from WorkQueue import MergeBotActor, VersionToDir
-from TrackerTools import GetRepositoryPublicUrl, GetRepositoryLocalUrl, Task, \
-    GetWorkDir, GetLogFile
+from mergebot import SvnOps
+from mergebot.Actor import Actor
 
-def rebranch_action(trac_env, ticketnum, component, version, requestor):
+class RebranchActor(Actor):
+    """Rebranches a ticket from its baseline.
     """
-    To rebranch from the baseline, you have to do these steps:
-        delete the branch.
-        recreate the branch.
-        merge in the changes from the deleted branch.
-        if there are no conflicts, commit those changes to the branch.
-    """
-    # FIXME: This desparately needs to be refactored.
-    # Do as much work as we can before affecting the repository so we have as
-    # little cleanup as possible and the fewest cases where we leave a broken
-    # branch.
-    task_obj = Task(trac_env, ticketnum)
-    summary = task_obj.GetSummary()
+    def execute(self):
+        """
+        To rebranch from the baseline, you have to do these steps:
+            delete the branch.
+            recreate the branch.
+            merge in the changes from the deleted branch.
+            if there are no conflicts, commit those changes to the branch.
+        """
+        # FIXME: This desparately needs to be refactored.
+        # Do as much work as we can before affecting the repository so we have
+        # as little cleanup as possible and the fewest cases where we leave a
+        # broken branch.
 
-    # We need to improve the logging of the rebranch stuff.
-    logfile = GetLogFile(trac_env, ticketnum)
-    open(logfile, "a").write("%s rebranching ticket %s\n" % (time.asctime(),
-        ticketnum))
+        results = {}
 
-    baserepositoryurl = str(GetRepositoryLocalUrl(trac_env))
-    branchurl = os.path.join(baserepositoryurl, component, "branches",
-        "ticket-%s" % ticketnum)
-    baselineurl = os.path.join(baserepositoryurl, component,
-        VersionToDir(version))
-    publicbranchurl = os.path.join(GetRepositoryPublicUrl(trac_env), component,
-        "branches", "ticket-%s" % ticketnum)
+        # We need to improve the logging of the rebranch stuff.
+        logfile = self.logfilename()
+        open(logfile, "a").write("%s rebranching ticket %s\n" %
+            (time.asctime(), self.ticket))
 
-    # Determine the revision range for the branch: startrev:endrev
-    branchinfo = SvnOps.get_branch_info(branchurl, logfile)
-    if not branchinfo:
-        open(logfile, "a").write(
-            "Unable to get %s branch revision information.\n" % (branchurl))
-        return "rebranchfailed", task_obj
-    startrev, endrev = branchinfo
+        # Make sure the various urls we require do exist
+        if not SvnOps.get_branch_info(self.local_url(), logfile):
+            comment = 'Component %s does not exist in the repository.' \
+                % self.component
+            return results, comment, False
+        if not SvnOps.get_branch_info(self.local_url() + '/branches', logfile):
+            comment = 'No directory in which to create branches for ' \
+                'component %s in the repository.' % self.component
+            return results, comment, False
+        if not SvnOps.get_branch_info(self.baseline_local_url(), logfile):
+            comment = 'Version %s for component %s does not exist in the ' \
+                'repository.' % (self.version, self.component)
+            return results, comment, False
 
-    workingcopy = GetWorkDir(trac_env, ticketnum, __name__)
+        rev_info = SvnOps.get_branch_info(self.branch_local_url(), logfile)
+        if not rev_info:
+            comment = \
+                'Branch for ticket %s does not exist in the repository.' % \
+                (self.ticket)
+            return results, comment, False
+        startrev, endrev = rev_info
 
-    svnmergecommand = "svn merge -r %s:%s %s@%s" % (startrev, endrev,
-        branchurl, startrev)
-    publicsvnmergecommand = "svn merge -r %s:%s %s@%s" % (startrev, endrev,
-        publicbranchurl, startrev)
-    # This is used in the ticket comments.
-    instructioncomment = "\n".join([
-            "You will need to fix this manually by creating the branch and "
-                "then doing the merge with this command:",
-            "{{{",
-            publicsvnmergecommand,
-            "}}}",
-    ])
-    # These are used in the commit messages.
-    rmmessage = "\n".join([
-        "Ticket #%s: %s" % (ticketnum, summary),
-        "    Remove the branch to rebranch from %s for %s." % \
-            (version, requestor),
-    ])
-    copymessage = "\n".join([
-        "Ticket #%s: %s" % (ticketnum, summary),
-        "    Recreate branch from %s for %s." % (version, requestor),
-        "[log:%s/branches/ticket-%s@%s Previous log]." % \
-            (component, ticketnum, endrev),
-    ])
-    # This is a list of commands.  Each of these must complete successfully, in
-    # this order, to complete the rebranch.  On failure, the given comment
-    # needs to be added to the ticket log.
-    commanderrors = (
-        (lambda x: SvnOps.logcmd("rm -rf \"%s\"" % (workingcopy), x),
-            "Rebranch internal error: Unable to cleanup work area."),
-        (lambda x: SvnOps.delete_branch(branchurl, rmmessage, x) == -1,
-            "Rebranch internal error: Unable to delete the old branch."),
-        (lambda x: SvnOps.create_branch(baselineurl, branchurl, copymessage, x),
-            "Rebranch internal error: Unable to recreate the branch.  %s" % \
-                (instructioncomment, )),
-        (lambda x: SvnOps.checkout(branchurl, workingcopy, x),
-            "Rebranch internal error: Unable to get working copy.  %s" % \
-                (instructioncomment, )),
-    )
-    for cmd, errorcomment in commanderrors:
-        retval = cmd(logfile)
-        if retval:
-            task_obj.AddComment(errorcomment)
-            os.system("rm -rf \"%s\"" % (workingcopy, ))
-            return "rebranchfailed", task_obj
+        workingcopy = self.work_dir
+        if os.path.exists(workingcopy):
+            shutil.rmtree(workingcopy)
 
-    # On success, we're in the same state as if we had just branched.
-    status = "branched"
-    # Go ahead and try to do the merge.  If we got lucky and there are no
-    # conflicts, commit the changes.
-    # Put a full update on the ticket.
-    results = SvnOps.merge("%s@%s" % (branchurl, startrev), workingcopy,
-        (startrev, endrev), logfile)
-    conflicts = SvnOps.conflicts_from_merge_results(results)
-    if conflicts:
-        ticketmessage = "\n".join([
-            "There were conflicts on rebranching.",
-            "Files in conflict:",
-            "{{{",
-            "\n".join(conflicts),
-            "}}}",
-            "You will need to resolve the conflicts manually.",
-            "To do so, update a working copy to the branch, "
-                "and run this merge command:",
-            "{{{",
-            publicsvnmergecommand,
-            "}}}",
-            "Once you have resolved the conflicts, "
-                "commit your work to the branch.",
-        ]) 
-    else: # No conflicts, do the commit.
-        mergemessage = "\n".join([
-            "Ticket #%s: %s" % (ticketnum, summary),
-            "    Merge in changes from old branch for %s." % (requestor),
-            "    %s" % (svnmergecommand),
-        ])
-        newrev = SvnOps.commit(workingcopy, mergemessage, logfile)
-        if newrev == None:
-            ticketmessage = "\n".join([
-                "Rebranched from %s for %s." % (version, requestor),
-                "There were no changes to commit to the branch.",
-                "You will need to update your working copy.",
-            ])
-        elif newrev < 0:
-            ticketmessage = "\n".join([
-                "Rebranch internal error:  Unable to commit merged changes.",
-                "You will need to fix this manually by doing the merge with "
-                    "this command:",
+        svnmergecommand = "svn merge -r %s:%s %s@%s" % (startrev, endrev,
+            self.branch_local_url(), startrev)
+        publicsvnmergecommand = "svn merge -r %s:%s %s@%s" % (startrev, endrev,
+            self.branch_public_url(), startrev)
+        # This is used in the ticket comments when there are conflicts.
+        instructioncomment = "\n".join([
+                "You will need to fix this manually by creating the branch and "
+                    "then doing the merge with this command:",
                 "{{{",
                 publicsvnmergecommand,
                 "}}}",
+        ])
+        # These are used in the commit messages.
+        rmmessage = "\n".join([
+            "Ticket #%s: %s" % (self.ticket, self.summary),
+            "    Remove the branch to rebranch from %s for %s." % \
+                (self.version, self.requestor),
+        ])
+        copymessage = "\n".join([
+            "Ticket #%s: %s" % (self.ticket, self.summary),
+            "    Recreate branch from %s for %s." % (self.version,
+                                                     self.requestor),
+            "[log:%s/branches/ticket-%s@%s Previous log]." % \
+                (self.component, self.ticket, endrev),
+        ])
+        # This is a list of commands.  Each of these must complete
+        # successfully, in this order, to complete the rebranch.  On failure,
+        # the given comment needs to be added to the ticket log.
+        commanderrors = (
+            (lambda x: SvnOps.delete_branch(self.branch_local_url(), rmmessage,
+                                            x) == -1,
+                "Rebranch internal error: Unable to delete the old branch."),
+            (lambda x: SvnOps.create_branch(self.baseline_local_url(),
+                    self.branch_local_url(), copymessage, x),
+                "Rebranch internal error: Unable to recreate the branch.  %s" \
+                    % (instructioncomment, )),
+            (lambda x: SvnOps.checkout(self.branch_local_url(), workingcopy, x),
+                "Rebranch internal error: Unable to get working copy.  %s" % \
+                    (instructioncomment, )),
+        )
+        for cmd, error_comment in commanderrors:
+            retval = cmd(logfile)
+            if retval:
+                if os.path.exists(workingcopy):
+                    shutil.rmtree(workingcopy)
+                results['mergebotstate'] = 'rebranchfailed'
+                return results, error_comment, False
+
+        # On success, we're in the same state as if we had just branched.
+        results['mergebotstate'] = 'branched'
+        success = True
+
+        # Go ahead and try to do the merge.  If we got lucky and there are no
+        # conflicts, commit the changes.
+        # Put a full update on the ticket.
+        merge_results = SvnOps.merge("%s@%s" % (self.branch_local_url(),
+            startrev), workingcopy, (startrev, endrev), logfile)
+        conflicts = SvnOps.conflicts_from_merge_results(merge_results)
+        if conflicts:
+            ticketmessage = "\n".join([
+                "There were conflicts on rebranching.",
+                "Files in conflict:",
+                "{{{",
+                "\n".join(conflicts),
+                "}}}",
+                "You will need to resolve the conflicts manually.",
+                "To do so, update a working copy to the branch, "
+                    "and run this merge command:",
+                "{{{",
+                publicsvnmergecommand,
+                "}}}",
+                "Once you have resolved the conflicts, "
+                    "commit your work to the branch.",
+            ]) 
+        else: # No conflicts, do the commit.
+            mergemessage = "\n".join([
+                "Ticket #%s: %s" % (self.ticket, self.summary),
+                "    Merge in changes from old branch for %s." % self.requestor,
+                "    %s" % svnmergecommand,
             ])
-            status = "rebranchfailed"
-        else:
-            ticketmessage = "\n".join([
-                "Rebranched from %s for %s." % (version, requestor),
-                "There were no conflicts, so the changes were automatically "
-                    "merged and committed to the branch.",
-                "You will need to update your working copy.",
-            ])
+            newrev = SvnOps.commit(workingcopy, mergemessage, logfile)
+            if newrev == None:
+                ticketmessage = "\n".join([
+                    "Rebranched from %s for %s." % (self.version,
+                                                    self.requestor),
+                    "There were no changes to commit to the branch.",
+                    "You will need to update your working copy.",
+                ])
+            elif newrev < 0:
+                ticketmessage = "\n".join([
+                    "Rebranch internal error:  Unable to commit merged "
+                        "changes.",
+                    "You will need to fix this manually by doing the merge "
+                        "with this command:",
+                    "{{{",
+                    publicsvnmergecommand,
+                    "}}}",
+                ])
+                results['mergebotstate'] = 'rebranchfailed'
+                success = False
+            else:
+                ticketmessage = "\n".join([
+                    "Rebranched from %s for %s." % (self.version,
+                                                    self.requestor),
+                    "There were no conflicts, so the changes were "
+                        "automatically merged and committed to the branch.",
+                    "You will need to update your working copy.",
+                ])
 
-    task_obj.AddComment( ticketmessage )
-    os.system("rm -rf \"%s\"" % (workingcopy, ))
-    return status, task_obj
-
-class RebranchActor(MergeBotActor):
-    "Actor wrapper for rebranch_action"
-    def __init__(self, trac_env):
-        MergeBotActor.__init__(self, trac_env, "rebranch", rebranch_action)
-
-def main():
-    tracdir = sys.argv[1]
-    trac_env = trac.env.open_environment(tracdir)
-    rebranchingActor = RebranchActor(trac_env)
-    rebranchingActor.AddTask(sys.argv[2:])
-    rebranchingActor.Run()
-
-if __name__ == "__main__":
-    main()
+        if os.path.exists(workingcopy):
+            shutil.rmtree(workingcopy)
+        return results, ticketmessage, success
 
 # vim:foldcolumn=4 foldmethod=indent
