From f06bc5b3751b79792c08e6b18be7d362e84c7695 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Sun, 13 Nov 2011 20:14:55 +0200 Subject: [PATCH] Add generic file-editing support to ubuntutools.question --- ubuntutools/question.py | 112 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/ubuntutools/question.py b/ubuntutools/question.py index 522b236..124f66e 100644 --- a/ubuntutools/question.py +++ b/ubuntutools/question.py @@ -1,7 +1,8 @@ # # question.py - Helper class for asking questions # -# Copyright (C) 2010, Benjamin Drung +# Copyright (C) 2010, Benjamin Drung , +# 2011, Stefano Rivera # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -15,6 +16,13 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +import tempfile +import os +import re +import sys + +import ubuntutools.subprocess + class Question(object): def __init__(self, options, show_help=True): @@ -86,3 +94,105 @@ def input_number(question, min_number, max_number, default=None): print "Please input a number." assert type(selected) == int return selected + + +def confirmation_prompt(message=None, action=None): + '''Display message, or a stock message including action, and wait for the + user to press Enter + ''' + if message is None: + if action is None: + action = 'continue' + message = 'Press [Enter] to %s. Press [Ctrl-C] to abort now.' % action + try: + raw_input(message) + except KeyboardInterrupt: + print '\nAborting as requested.' + sys.exit(1) + + +class EditFile(object): + def __init__(self, filename, description, placeholders=None): + self.filename = filename + self.description = description + if placeholders is None: + placeholders = (re.compile(r'^<<<.*>>>$', re.UNICODE),) + self.placeholders = placeholders + + def optional_edit(self): + '''Prompt the user to decide if the file needs editing''' + print "Currently the %s looks like:" % self.description + with open(self.filename, 'r') as f: + print f.read() + if YesNoQuestion().ask("Edit", "no") == "yes": + self.edit() + + def edit(self): + done = False + while not done: + old_mtime = os.stat(self.filename).st_mtime + ubuntutools.subprocess.check_call(['sensible-editor', + self.filename]) + modified = old_mtime != os.stat(self.filename).st_mtime + placeholders_present = False + if self.placeholders: + with open(self.filename, 'r') as f: + for line in f: + for placeholder in self.placeholders: + if placeholder.search(line.strip()): + placeholders_present = True + + if placeholders_present: + print ("Placeholders still present in the %s. " + "Please replace them with useful information." + % self.description) + confirmation_prompt('edit again') + elif not modified: + print "The %s was not modified" % self.description + if YesNoQuestion().ask("Edit again", "yes") == "no": + done = True + elif self.check_edit(): + done = True + + def check_edit(self): + '''Override this to implement extra checks on the edited report. + Should return False if another round of editing is needed, + and should prompt the user to confirm that, if necessary. + ''' + return True + + +class EditBugReport(EditFile): + split_re = re.compile(r'^Summary.*?:\s+(.*)\s+' + r'Description:\s+(.*)$', + re.DOTALL | re.UNICODE) + + def __init__(self, subject, body, placeholders=None): + tmpfile = tempfile.NamedTemporaryFile(prefix=sys.argv[0] + '_', + suffix='.txt', + delete=False) + tmpfile.write((u'Summary (one line):\n%s\n\nDescription:\n%s' + % (subject, body)).encode('utf-8')) + tmpfile.close() + super(EditBugReport, self).__init__(tmpfile.name, 'bug report', + placeholders) + + def check_edit(self): + with open(self.filename, 'r') as f: + report = f.read().decode('utf-8') + + if self.split_re.match(report) is None: + print ("The %s doesn't start with 'Summary:' and 'Description:' " + "blocks" % self.description) + confirmation_prompt('edit again') + return False + return True + + def get_report(self): + with open(self.filename, 'r') as f: + report = f.read().decode('utf-8') + + m = self.split_re.match(report) + report = (m.group(1), m.group(2)) + os.unlink(self.filename) + return report