* Add support for multi-line commit message input by using EOF
authorZac Medico <zmedico@gentoo.org>
Fri, 14 Dec 2007 11:27:52 +0000 (11:27 -0000)
committerZac Medico <zmedico@gentoo.org>
Fri, 14 Dec 2007 11:27:52 +0000 (11:27 -0000)
  as a delimiter (Ctrl-d) instead of a new line.

* Add support for getting a commit message using an editor defined
  by the EDITOR environment variable.

(trunk r8919:8921)

svn path=/main/branches/2.1.2/; revision=8922

bin/repoman

index ee6920f789d000d36718ad3ceba9da9e444292a7..74d64b9c5c7877d70093cdd7cf3a6f263fc2ad29 100755 (executable)
@@ -300,6 +300,77 @@ def help(exitstatus=1,helpfulness=1):
        else:
                print
 
+def editor_is_executable(editor):
+       """
+       Given an EDITOR string, validate that it refers to
+       an executable. This uses shlex.split() to split the
+       first component and do a PATH lookup if necessary.
+
+       @param editor: An EDITOR value from the environment.
+       @type: string
+       @rtype: bool
+       @returns: True if an executable is found, False otherwise.
+       """
+       import shlex
+       editor_split = shlex.split(editor)
+       if not editor_split:
+               return False
+       filename = editor_split[0]
+       if not os.path.isabs(filename):
+               from portage_exec import find_binary
+               return find_binary(filename) is not None
+       return os.access(filename, os.X_OK) and os.path.isfile(filename)
+
+def get_commit_message_with_editor(editor):
+       """
+       Execute editor with a temporary file as it's argument
+       and return the file content afterwards.
+
+       @param editor: An EDITOR value from the environment
+       @type: string
+       @rtype: string or None
+       @returns: A string on success or None if an error occurs.
+       """
+       from tempfile import mkstemp
+       fd, filename = mkstemp()
+       try:
+               os.write(fd, "\n# Please enter the commit message " + \
+                       "for your changes.\n# (Comment lines starting " + \
+                       "with '#' will not be included)\n")
+               os.close(fd)
+               retval = os.system(editor + " '%s'" % filename)
+               if not (os.WIFEXITED(retval) and os.WEXITSTATUS(retval) == os.EX_OK):
+                       return None
+               try:
+                       mylines = open(filename).readlines()
+               except OSError, e:
+                       if e.errno != errno.ENOENT:
+                               raise
+                       del e
+                       return None
+               return "".join(line for line in mylines if not line.startswith("#"))
+       finally:
+               try:
+                       os.unlink(filename)
+               except OSError:
+                       pass
+
+def get_commit_message_with_stdin():
+       """
+       Read a commit message from the user and return it.
+
+       @rtype: string or None
+       @returns: A string on success or None if an error occurs.
+       """
+       print "Please enter a commit message. Use Ctrl-d to finish or Ctrl-c to abort."
+       commitmessage = []
+       while True:
+               commitmessage.append(sys.stdin.readline())
+               if not commitmessage[-1]:
+                       break
+       commitmessage = "".join(commitmessage)
+       return commitmessage
+
 def last():
        try:
                #Retrieve and unpickle stats and fails from saved files
@@ -1900,13 +1971,19 @@ else:
                                raise
                # We've read the content so the file is no longer needed.
                commitmessagefile = None
-       if not commitmessage:
-               print "Please enter a CVS commit message at the prompt:"
-               while not commitmessage:
-                       try:
-                               commitmessage=raw_input(green("> "))
-                       except KeyboardInterrupt: 
-                               exithandler()
+       if not commitmessage or not commitmessage.strip():
+               try:
+                       editor = os.environ.get("EDITOR")
+                       if editor and editor_is_executable(editor):
+                               commitmessage = get_commit_message_with_editor(editor)
+                       else:
+                               commitmessage = get_commit_message_with_stdin()
+               except KeyboardInterrupt:
+                       exithandler()
+               if not commitmessage or not commitmessage.strip():
+                       print "* no commit message?  aborting commit."
+                       sys.exit(1)
+       commitmessage = commitmessage.rstrip()
        portage_version = getattr(portage, "VERSION", None)
        if portage_version is None:
                sys.stderr.write("Failed to insert portage version in message!\n")