def edit(self, filename): r""" Drop user into editor with filename open. .. SEEALSO:: :meth:`sage.dev.user_interface.UserInterface.edit` TESTS:: sage: tmp = tmp_filename() sage: from sage.dev.test.config import DoctestConfig sage: from sage.dev.cmd_line_interface import CmdLineInterface sage: UI = CmdLineInterface(DoctestConfig()["UI"]) sage: UI.edit(tmp) # not tested sage: print open(tmp,'r').read() # not tested Some lines <BLANKLINE> sage: os.unlink(tmp) """ try: editor = os.environ.get('EDITOR', 'nano') check_call(['sage-native-execute', editor, filename]) except CalledProcessError: from user_interface_error import OperationCancelledError raise OperationCancelledError( "Editor returned non-zero exit value")
def _get_input(self, prompt, options=None, default=None, input_func=raw_input): r""" Helper method for :meth:`switch`, :meth:`get_input`, and :meth:`get_password`. INPUT: - ``prompt`` -- a string - ``options`` -- a list of strings or ``None`` (default: ``None``) - ``default`` -- an integer or ``None`` (deault: ``None``), the default option as an index into ``options`` - ``input_func`` -- a function to get input from user (default: ``raw_input``) TESTS:: sage: from sage.dev.test.config import DoctestConfig sage: from sage.dev.cmd_line_interface import CmdLineInterface sage: UI = CmdLineInterface(DoctestConfig()["UI"]) sage: def input_func(prompt): ....: print(prompt) ....: return "no" sage: UI._get_input("Should I delete your home directory?", ....: ("yes","no","maybe"), default=0, input_func = input_func) Should I delete your home directory? [Yes/no/maybe] 'no' """ try: prompt, options, default = self._std_values(prompt, options, default) while True: s = input_func(prompt) if options is None: return s if len(s.strip()) == 0: if default is None: self.show("Please enter an option.") continue else: return default itr = (opt for opt in options if opt.lower().startswith(s.lower())) try: ret = itr.next() except StopIteration: self.show("Please specify an allowable option.") continue try: ret = itr.next() self.show("Please disambiguate between options.") except StopIteration: return ret except KeyboardInterrupt: from user_interface_error import OperationCancelledError raise OperationCancelledError("cancelled by keyboard interrupt")
def add_comment_interactive(self, ticket, comment=''): r""" Add a comment to ``ticket`` on trac. INPUT: - ``comment`` -- a string (default: ``''``), the default value for the comment to add. EXAMPLES:: sage: from sage.dev.test.config import DoctestConfig sage: from sage.dev.test.user_interface import DoctestUserInterface sage: from sage.dev.test.trac_interface import DoctestTracInterface sage: from sage.dev.test.trac_server import DoctestTracServer sage: config = DoctestConfig() sage: config['trac']['password'] = '******' sage: UI = DoctestUserInterface(config['UI']) sage: trac = DoctestTracInterface(config['trac'], UI, DoctestTracServer()) sage: ticket = trac.create_ticket('Summary', 'Description', {'type':'defect', 'component':'algebra'}) sage: UI.append("# empty comment") sage: trac.add_comment_interactive(ticket) Traceback (most recent call last): ... OperationCancelledError: comment creation aborted sage: UI.append("a comment") sage: trac.add_comment_interactive(ticket) """ ticket = int(ticket) attributes = self._get_attributes(ticket) from sage.dev.misc import tmp_filename filename = tmp_filename() with open(filename, "w") as f: f.write(comment) f.write("\n") f.write(COMMENT_FILE_GUIDE) self._UI.edit(filename) comment = list(open(filename).read().splitlines()) comment = [line for line in comment if not line.startswith("#")] if all([line.strip() == "" for line in comment]): from user_interface_error import OperationCancelledError raise OperationCancelledError("comment creation aborted") comment = "\n".join(comment) url = self._authenticated_server_proxy.ticket.update( ticket, comment, attributes, True) # notification e-mail sent self._UI.debug("Your comment has been recorded: %s" % url)
def edit_ticket_interactive(self, ticket): r""" Edit ``ticket`` on trac. EXAMPLES:: sage: from sage.dev.test.config import DoctestConfig sage: from sage.dev.test.user_interface import DoctestUserInterface sage: from sage.dev.test.trac_interface import DoctestTracInterface sage: from sage.dev.test.trac_server import DoctestTracServer sage: config = DoctestConfig() sage: config['trac']['password'] = '******' sage: UI = DoctestUserInterface(config['UI']) sage: trac = DoctestTracInterface(config['trac'], UI, DoctestTracServer()) sage: ticket = trac.create_ticket('Summary', 'Description', {'type':'defect', 'component':'algebra'}) sage: UI.append("# empty") sage: trac.edit_ticket_interactive(ticket) Traceback (most recent call last): ... OperationCancelledError: ticket edit aborted sage: UI.append("Summary: summary\ndescription\n") sage: trac.edit_ticket_interactive(ticket) """ ticket = int(ticket) attributes = self._get_attributes(ticket) summary = attributes.get('summary', 'No Summary') description = attributes.get('description', 'No Description') ret = self._edit_ticket_interactive(summary, description, attributes) if ret is None: from user_interface_error import OperationCancelledError raise OperationCancelledError("edit aborted") attributes['summary'] = ret[0] attributes['description'] = ret[1] attributes.update(ret[2]) url = self._authenticated_server_proxy.ticket.update( ticket, "", attributes, True) # notification e-mail sent. self._UI.debug("Ticket modified: %s" % url)
def create_ticket_interactive(self): r""" Drop user into an editor for creating a ticket. EXAMPLE:: sage: from sage.dev.test.config import DoctestConfig sage: from sage.dev.test.user_interface import DoctestUserInterface sage: from sage.dev.test.trac_interface import DoctestTracInterface sage: from sage.dev.test.trac_server import DoctestTracServer sage: config = DoctestConfig() sage: config['trac']['password'] = '******' sage: UI = DoctestUserInterface(config['UI']) sage: trac = DoctestTracInterface(config['trac'], UI, DoctestTracServer()) sage: UI.append("Summary: summary\nType: defect\nPriority: minor\nComponent: algebra\ndescription") sage: trac.create_ticket_interactive() 1 """ attributes = { "Type": "defect", "Priority": "major", "Component": "PLEASE CHANGE", "Reporter": self._username } ret = self._edit_ticket_interactive("", None, attributes) if ret is None: from user_interface_error import OperationCancelledError raise OperationCancelledError("ticket creation aborted") ticket = self.create_ticket(*ret) import urlparse from sage.env import TRAC_SERVER_URI ticket_url = urlparse.urljoin( self._config.get('server', TRAC_SERVER_URI), str(ticket)) self._UI.debug("Created ticket #%s (%s)." % (ticket, ticket_url)) return ticket
def _edit_ticket_interactive(self, summary, description, attributes): r""" Helper method for :meth:`edit_ticket_interactive` and :meth:`create_ticket_interactive`. INPUT: - ``summary`` -- a string, summary of ticket - ``description`` -- a string, description of ticket - ``attributes`` -- dictionary containing field, value pairs OUTPUT: A tuple ``(summary, description, attributes)``, the updated version of input after user has edited the ticket. TESTS:: sage: from sage.dev.test.config import DoctestConfig sage: from sage.dev.test.user_interface import DoctestUserInterface sage: from sage.dev.trac_interface import TracInterface sage: config = DoctestConfig() sage: UI = DoctestUserInterface(config['UI']) sage: trac = TracInterface(config['trac'], UI) sage: UI.append("# abort") sage: trac._edit_ticket_interactive('summary', 'description', {'branch':'branch1'}) Traceback (most recent call last): ... OperationCancelledError: ticket edit aborted sage: UI.append("Summary: new summary\nBranch: branch2\nnew description") sage: trac._edit_ticket_interactive('summary', 'description', {'branch':'branch1'}) ('new summary', 'new description', {'branch': 'branch2'}) sage: UI.append("Summary: new summary\nBranch: branch2\nnew description") sage: UI.append("") sage: UI.append("Summary: new summary\nInvalid: branch2\nnew description") sage: trac._edit_ticket_interactive('summary', 'description', {'branch':'branch1'}) Syntax error: field "Invalid" not supported on line 2 Edit ticket file again? [Yes/no] ('new summary', 'new description', {'branch': 'branch2'}) """ from sage.dev.misc import tmp_filename filename = tmp_filename() try: with open(filename, "w") as F: F.write("Summary: %s\n" % summary.encode('utf-8')) for k, v in attributes.items(): k = ALLOWED_FIELDS.get(k.lower()) if k is not None: F.write("%s: %s\n" % (k.encode('utf-8'), v.encode('utf-8'))) if description is None or not description.strip(): description = "\nADD DESCRIPTION\n" F.write("\n" + description.encode('utf-8') + "\n") F.write(TICKET_FILE_GUIDE) while True: try: self._UI.edit(filename) ret = self._parse_ticket_file(filename) break except (RuntimeError, TicketSyntaxError) as error: pass self._UI.error("Syntax error: " + error.message) if not self._UI.confirm("Edit ticket file again?", default=True): ret = None break if ret is None: from user_interface_error import OperationCancelledError raise OperationCancelledError("ticket edit aborted") finally: os.unlink(filename) return ret