Example #1
0
    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")
Example #2
0
    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