Launch editor for long submit request message. #553
authorHuang Hao <hao.h.huang@intel.com>
Tue, 27 Nov 2012 05:30:36 +0000 (13:30 +0800)
committerHuang Hao <hao.h.huang@intel.com>
Wed, 28 Nov 2012 02:27:32 +0000 (10:27 +0800)
* add functions edit() and edit_files()
* change argument of TempCopy.__init__ from original_path to
    content
* change test_changelog.py to make tests pass

Change-Id: I59b10276db6d5e0fd9843009be01c218c440ece5

gitbuildsys/cmd_changelog.py
gitbuildsys/cmd_submit.py
gitbuildsys/utils.py
tests/test_changelog.py
tools/gbs

index fafc33faec06b946c1b15b7ee8d39de976eecfed..418fb8548ba9fad4a5c1e69e20266069ce4789ec 100644 (file)
 import os
 import datetime
 import glob
-import subprocess
-import shutil
 
-from gitbuildsys import msger, utils
-from gitbuildsys.conf import configmgr
+from gitbuildsys import msger
+from gitbuildsys.utils import guess_spec, edit_file
 from gitbuildsys.cmd_export import get_packaging_dir
 
 from gbp.rpm.git import GitRepositoryError, RpmGitRepository
 
-EDITOR = configmgr.get('editor') or os.getenv('EDITOR') or 'vi'
 
 
-def add_entries(changesfile, new_entries):
-    """Add new entries to the top of changelog."""
+def get_all_entries(changesfile, new_entries):
+    """return all entries including old in changesfile and new_entries"""
     lines = ["%s%s" % (line, os.linesep) for line in new_entries]
     lines.append(os.linesep)
-    with open(changesfile) as chlog:
-        lines.extend(chlog.readlines())
-    with open(changesfile, "w") as chlog:
-        chlog.writelines(lines)
+
+    if os.path.exists(changesfile):
+        with open(changesfile) as chlog:
+            lines.extend(chlog.readlines())
+    return ''.join(lines)
 
 
 def get_latest_rev(changesfile):
@@ -96,8 +94,8 @@ def main(args):
 
     if args.spec or not changes_file_list:
         # Create .changes file with the same name as a spec
-        specfile = os.path.basename(utils.guess_spec(project_root_dir,
-                                                     packaging_dir, args.spec))
+        specfile = os.path.basename(guess_spec(project_root_dir,
+                                               packaging_dir, args.spec))
         fn_changes = os.path.splitext(specfile)[0] + ".changes"
         fn_changes = os.path.join(project_root_dir, packaging_dir, fn_changes)
     else:
@@ -139,18 +137,8 @@ def main(args):
     else:
         new_entries = make_log_entries(commits, repo)
 
-    # create temporary copy and update it with new entries
-    temp = utils.TempCopy(fn_changes)
-    add_entries(temp.name, new_entries)
-    temp.update_stat()
-
-    subprocess.call("%s %s" % (EDITOR, temp.name), shell=True)
-
-    if temp.is_changed():
-        try:
-            shutil.copy2(temp.name, fn_changes)
-        except (IOError, shutil.Error), excobj:
-            msger.error("Can't update %s: %s" % (fn_changes, str(excobj)))
+    content = get_all_entries(fn_changes, new_entries)
+    if edit_file(fn_changes, content):
         msger.info("Change log has been updated.")
     else:
         msger.info("Change log has not been updated")
index 4382d1b7fdd58d4da29add95360d651cd1ec8f46..374eac0ed6a16b0dbcbcc67a4df3daf093d106ca 100644 (file)
@@ -22,17 +22,37 @@ import os
 import time
 
 from gitbuildsys import msger
+from gitbuildsys.utils import edit
 
 from gbp.rpm.git import GitRepositoryError, RpmGitRepository
 
 
+
+def get_message():
+    '''
+    get message from editor
+    '''
+    prompt = '''
+# Please enter the message for your tag. Lines starting with '#'
+# will be ignored, and an empty message aborts the submission.
+#'''
+    raw = edit(prompt)
+    useful = [i for i in raw.splitlines() if not i.startswith('#') ]
+    return os.linesep.join(useful).strip()
+
+
 def main(args):
     """gbs submit entry point."""
 
     workdir = args.gitdir
 
-    if not args.msg:
-        msger.error("argument for -m option can't be empty")
+    if args.msg is None:
+        message = get_message()
+    else:
+        message = args.msg
+
+    if not message:
+        msger.error("tag message is required")
 
     try:
         repo = RpmGitRepository(workdir)
@@ -69,8 +89,8 @@ def main(args):
         tagname = 'submit/%s/%s' % (args.target, time.strftime( \
                                     '%Y%m%d.%H%M%S', time.gmtime()))
         msger.info('creating tag: %s' % tagname)
-        repo.create_tag(tagname, msg=args.msg, commit=commit, sign=args.sign,
-                                                 keyid=args.user_key)
+        repo.create_tag(tagname, msg=message, commit=commit, sign=args.sign,
+                        keyid=args.user_key)
     except GitRepositoryError, err:
         msger.error('failed to create tag %s: %s ' % (tagname, str(err)))
 
index 04a06ed59b0716ba816342c7a85ce0053fe423dd..ac7a77572016d1a3f758de878c5d022eef644e16 100644 (file)
@@ -128,16 +128,13 @@ class TempCopy(object):
        Deletes temporary file when object is destroyed.
     """
 
-    def __init__(self, orig_fpath):
-        self.orig_fpath = orig_fpath
-
-        # create temp file
-        tmpffd, self.name = tempfile.mkstemp(dir=os.path.dirname(orig_fpath))
+    def __init__(self, content=None):
+        tmpffd, self.name = tempfile.mkstemp()
         os.close(tmpffd)
 
-        # copy original file to temp
-        if os.path.exists(orig_fpath):
-            shutil.copy2(orig_fpath, self.name)
+        if content:
+            with open(self.name, 'w') as fobj:
+                fobj.write(content)
 
         self.stat = os.stat(self.name)
 
@@ -507,3 +504,37 @@ def glob_in_rev(git_path, pattern, commit_id):
             pattern, commit_id, str(err)))
 
     return fnmatch.filter(output.splitlines(), pattern)
+
+
+def edit(initial_content=None):
+    '''
+    launch an editor to get input from user. return the content that input.
+    '''
+    from gitbuildsys.conf import configmgr
+    EDITOR = configmgr.get('editor') or os.getenv('EDITOR') or 'vi'
+
+    temp = TempCopy(initial_content)
+    subprocess.call('%s %s' % (EDITOR, temp.name), shell=True)
+
+    if temp.is_changed():
+        with open(temp.name) as fobj:
+            return fobj.read()
+    return ''
+
+
+def edit_file(target_fname, initial_content=None):
+    '''
+    create temporary copy of target_fname with initial_content, then launch an
+        editor, update content back if user do some changes.
+    return True if content has been changed.
+    '''
+    changes = edit(initial_content)
+    if not changes:
+        return False
+
+    try:
+        with open(target_fname, 'w') as fobj:
+            fobj.write(changes)
+    except IOError, err:
+        msger.error("Can't update %s: %s" % (target_fname, str(err)))
+    return True
index c948e43128bd0837cb27c6b62eeb4e47966a186e..a44bcd37bb4a18b20518b2abcd3e4cbf677df3e4 100644 (file)
@@ -30,11 +30,13 @@ from nose.tools import eq_, raises
 
 from gbp.git.repository import GitRepository
 
-from gitbuildsys import cmd_changelog
-
 GBS = imp.load_source("gbs", "./tools/gbs").main
 ENV = {}
 
+def set_editor(editor):
+    '''set editor'''
+    os.environ['EDITOR'] = editor
+
 def setup_module():
     """One setup for all tests."""
 
@@ -87,7 +89,7 @@ class TestChangelog(unittest.TestCase):
         os.mkdir('packaging')
         open("packaging/test.spec", "w").close()
 
-        cmd_changelog.EDITOR = "sleep 1 && touch"
+        set_editor("sleep 1 && touch")
 
     def test_new_changes(self):
         """Test generating new .changes."""
@@ -127,7 +129,7 @@ class TestChangelog(unittest.TestCase):
     @staticmethod
     def test_not_updated():
         """Test normal exit when changelog is not updated."""
-        cmd_changelog.EDITOR = "true"
+        set_editor("true")
         eq_(GBS(argv=["gbs ", "changelog"]), None)
 
     @staticmethod
index ff87077f11284661af72e432ce6e6601ae922105..4f149b8fcd548afaa1538fdfdebb264f7bf40aa0 100755 (executable)
--- a/tools/gbs
+++ b/tools/gbs
@@ -332,8 +332,7 @@ def submit_parser(parser):
                         default=os.getcwd(),
                         help='path to git repository')
 
-    parser.add_argument('-m', '--msg', required=True,
-                        help='specify tag message info')
+    parser.add_argument('-m', '--msg', help='specify tag message info')
     parser.add_argument('-c', '--commit', default='HEAD',
                         help='specify a commit ID to submit')
     parser.add_argument('-s', '--sign', action='store_true',