Example #1
0
    def execute(self):
        if not super().execute():
            return False

        self._backup = ChangeSet()
        archive_path = config().archive()
        if archive_path:
            self._archive_file = TodoFile.TodoFile(config().archive())
            self._archive = TodoList.TodoList(self._archive_file.read())

        if len(self.args) > 1:
            self.error(self.usage())
        else:
            try:
                arg = self.argument(0)
                self._handle_args(arg)
            except InvalidCommandArgument:
                try:
                    self._revert_last()
                except (ValueError, KeyError):
                    self.error(
                        'No backup was found for the current state of ' +
                        config().todotxt())

        self._backup.close()
Example #2
0
    def test_revert02(self):
        backup = ChangeSet(self.todolist, self.archive, ['do 1'])
        backup.timestamp = '1'
        command1 = DoCommand(["1"], self.todolist, self.out, self.error, None)
        command1.execute()
        archive_command1 = ArchiveCommand(self.todolist, self.archive)
        archive_command1.execute()
        self.archive_file.write(self.archive.print_todos())
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['do Bar'])
        backup.timestamp = '2'
        command2 = DoCommand(["Bar"], self.todolist, self.out, self.error,
                             None)
        command2.execute()
        archive_command2 = ArchiveCommand(self.todolist, self.archive)
        archive_command2.execute()
        self.archive_file.write(self.archive.print_todos())
        backup.save(self.todolist)

        self.assertEqual(self.archive.print_todos(),
                         "x {t} Foo\nx {t} Bar".format(t=self.today))
        self.assertEqual(self.todolist.print_todos(), "Baz")

        revert_command = RevertCommand([], self.todolist, self.out, self.error,
                                       None)
        revert_command.execute()

        result = TodoList(self.archive_file.read()).print_todos()

        self.assertEqual(self.errors, "")
        self.assertTrue(
            self.output.endswith("Successfully reverted: do Bar\n"))
        self.assertEqual(result, "x {} Foo".format(self.today))
        self.assertEqual(self.todolist.print_todos(), "Bar\nBaz")
Example #3
0
    def _backup(self, p_command, p_args=[], p_label=None):
        if config().backup_count() > 0 and p_command and not self.is_read_only(p_command):
            call = [p_command.name()]+ p_args

            from topydo.lib.ChangeSet import ChangeSet
            label = p_label if p_label else call
            self.backup = ChangeSet(self.todolist, p_label=label)
Example #4
0
class BackupSimulator(object):
    def __init__(self, p_todolist, p_archive, p_timestamp, p_label):
        self.backup = ChangeSet(p_todolist, p_archive, p_label)
        self.backup.timestamp = p_timestamp

    def save(self, p_todolist):
        self.backup.save(p_todolist)
Example #5
0
    def test_revert07(self):
        """ Test backup when no archive file is set """
        backup = ChangeSet(self.todolist, None, ['add One'])
        backup.timestamp = '1'
        command1 = AddCommand(["One"], self.todolist, self.out, self.error, None)
        command1.execute()
        backup.save(self.todolist)

        changesets = list(backup.backup_dict.keys())
        changesets.remove('index')

        self.assertEqual(len(changesets), 1)
        self.assertEqual(self.errors, "")
Example #6
0
    def test_revert07(self):
        """ Test backup when no archive file is set """
        backup = ChangeSet(self.todolist, None, ['add One'])
        backup.timestamp = '1'
        command_executer(AddCommand, ["One"], self.todolist, None, self.out,
                         self.error, None)
        backup.save(self.todolist)

        changesets = list(backup.backup_dict.keys())
        changesets.remove('index')

        self.assertEqual(len(changesets), 1)
        self.assertEqual(self.errors, "")
Example #7
0
    def test_revert02(self):
        backup = ChangeSet(self.todolist, self.archive, ['do 1'])
        backup.timestamp = '1'
        command1 = DoCommand(["1"], self.todolist, self.out, self.error, None)
        command1.execute()
        archive_command1 = ArchiveCommand(self.todolist, self.archive)
        archive_command1.execute()
        self.archive_file.write(self.archive.print_todos())
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['do Bar'])
        backup.timestamp = '2'
        command2 = DoCommand(["Bar"], self.todolist, self.out, self.error, None)
        command2.execute()
        archive_command2 = ArchiveCommand(self.todolist, self.archive)
        archive_command2.execute()
        self.archive_file.write(self.archive.print_todos())
        backup.save(self.todolist)

        self.assertEqual(self.archive.print_todos(), "x {t} Foo\nx {t} Bar".format(t=self.today))
        self.assertEqual(self.todolist.print_todos(), "Baz")

        revert_command = RevertCommand([], self.todolist, self.out, self.error, None)
        revert_command.execute()

        result = TodoList(self.archive_file.read()).print_todos()

        self.assertEqual(self.errors, "")
        self.assertTrue(self.output.endswith("Successfully reverted: do Bar\n"))
        self.assertEqual(result, "x {} Foo".format(self.today))
        self.assertEqual(self.todolist.print_todos(), "Bar\nBaz")
Example #8
0
    def test_revert_no_todolist(self):
        """ Test attempt of revert with todolist missing """
        backup = BackupSimulator(self.todolist, self.archive, '1', ['add One'])
        command_executer(AddCommand, ["One"], self.todolist, None, self.out,
                         self.error, None)
        backup.save(self.todolist)

        backup = BackupSimulator(self.todolist, self.archive, '2', ['add Two'])
        command_executer(AddCommand, ["Two"], self.todolist, None, self.out,
                         self.error, None)
        backup.save(self.todolist)

        backup = BackupSimulator(self.todolist, self.archive, '3',
                                 ['add Three'])
        command_executer(AddCommand, ["Three"], self.todolist, None, self.out,
                         self.error, None)
        backup.save(self.todolist)

        backup = BackupSimulator(self.todolist, self.archive, '4',
                                 ['delete Three'])
        command_executer(DeleteCommand, ["Three"], self.todolist, None,
                         self.out, self.error, None)
        backup.save(self.todolist)

        command_executer(RevertCommand, ['1'], None, None, self.out,
                         self.error, None)

        result = len(ChangeSet().backup_dict.keys())
        self.assertEqual(result, 4)
Example #9
0
    def test_revert06(self):
        """ Test attempt of deletion with non-existing backup key"""
        backup = BackupSimulator(self.todolist, self.archive, '1', ['add One'])
        command_executer(AddCommand, ["One"], self.todolist, None, self.out,
                         self.error, None)
        backup.save(self.todolist)

        backup = BackupSimulator(self.todolist, self.archive, '2', ['add Two'])
        command_executer(AddCommand, ["Two"], self.todolist, None, self.out,
                         self.error, None)
        backup.save(self.todolist)

        backup = BackupSimulator(self.todolist, self.archive, '3',
                                 ['add Three'])
        command_executer(AddCommand, ["Three"], self.todolist, None, self.out,
                         self.error, None)
        backup.save(self.todolist)

        backup = BackupSimulator(self.todolist, self.archive, '4',
                                 ['delete Three'])
        command_executer(DeleteCommand, ["Three"], self.todolist, None,
                         self.out, self.error, None)
        backup.save(self.todolist)

        backup = ChangeSet()
        backup.delete('Foo')

        changesets = list(backup.backup_dict.keys())
        changesets.remove('index')
        index_timestamps = [change[0] for change in backup._get_index()]
        result = list(set(index_timestamps) - set(changesets))

        self.assertEqual(len(changesets), 4)
        self.assertEqual(result, [])
        self.assertEqual(self.errors, "")
Example #10
0
    def test_revert02(self):
        backup = BackupSimulator(self.todolist, self.archive, '1', ['do 1'])
        command_executer(DoCommand, ["1"], self.todolist, self.archive,
                         self.out, self.error, None)
        self.archive_file.write(self.archive.print_todos())
        backup.save(self.todolist)

        # Use add_todolist and add_archive to also cover them
        backup = ChangeSet(p_label=['do Bar'])
        backup.add_todolist(self.todolist)
        backup.add_archive(self.archive)
        backup.timestamp = '2'
        command_executer(DoCommand, ["Bar"], self.todolist, self.archive,
                         self.out, self.error, None)
        self.archive_file.write(self.archive.print_todos())
        backup.save(self.todolist)

        self.assertEqual(self.archive.print_todos(),
                         "x {t} Foo\nx {t} Bar".format(t=self.today))
        self.assertEqual(self.todolist.print_todos(), "Baz")

        revert_command = RevertCommand([], self.todolist, self.out, self.error,
                                       None)
        revert_command.execute()

        result = TodoList(self.archive_file.read()).print_todos()

        self.assertEqual(self.errors, "")
        self.assertTrue(
            self.output.endswith("Reverted to state before: do Bar\n"))
        self.assertEqual(result, "x {} Foo".format(self.today))
        self.assertEqual(self.todolist.print_todos(), "Bar\nBaz")
Example #11
0
    def _backup(self, p_command, p_args=None, p_label=None):
        if config().backup_count() > 0 and p_command and not CLIApplicationBase.is_read_only(p_command):
            p_args = p_args if p_args else []
            call = [p_command.name()] + p_args

            from topydo.lib.ChangeSet import ChangeSet
            label = p_label if p_label else call
            self.backup = ChangeSet(self.todolist, p_label=label)
Example #12
0
    def execute(self):
        if not super().execute():
            return False

        archive_file = TodoFile.TodoFile(config().archive())
        archive = TodoList.TodoList(archive_file.read())

        last_change = ChangeSet()

        try:
            last_change.get_backup(self.todolist)
            last_change.apply(self.todolist, archive)
            archive_file.write(archive.print_todos())
            last_change.delete()

            self.out("Successfully reverted: " + last_change.label)
        except (ValueError, KeyError):
            self.error('No backup was found for the current state of ' +
                       config().todotxt())

        last_change.close()
Example #13
0
    def execute(self):
        if not super().execute():
            return False

        archive_file = TodoFile.TodoFile(config().archive())
        archive = TodoList.TodoList(archive_file.read())

        last_change = ChangeSet()

        try:
            last_change.get_backup(self.todolist)
            last_change.apply(self.todolist, archive)
            archive_file.write(archive.print_todos())
            last_change.delete()

            self.out("Successfully reverted: " + last_change.label)
        except (ValueError, KeyError):
            self.error('No backup was found for the current state of ' + config().todotxt())

        last_change.close()
Example #14
0
    def _execute(self, p_command, p_args):
        """
        Execute a subcommand with arguments. p_command is a class (not an
        object).
        """
        if config().backup_count() > 0 and p_command and not self.is_read_only(p_command):
            call = [p_command.__module__.lower()[16:-7]] + p_args # strip "topydo.commands" and "Command"

            from topydo.lib.ChangeSet import ChangeSet
            self.backup = ChangeSet(self.todolist, p_call=call)

        command = p_command(
            p_args,
            self.todolist,
            lambda o: write(sys.stdout, o),
            error,
            input)

        if command.execute() != False:
            return True

        return False
Example #15
0
    def execute(self):
        if not super().execute():
            return False

        self._backup = ChangeSet()
        archive_path = config().archive()
        if archive_path:
            self._archive_file = TodoFile.TodoFile(config().archive())
            self._archive = TodoList.TodoList(self._archive_file.read())

        if len(self.args) > 1:
            self.error(self.usage())
        else:
            try:
                arg = self.argument(0)
                self._handle_args(arg)
            except InvalidCommandArgument:
                try:
                    self._revert_last()
                except (ValueError, KeyError):
                    self.error('No backup was found for the current state of '
                               + config().todotxt())

        self._backup.close()
Example #16
0
    def test_revert05(self):
        """ Test for possible backup collisions """
        backup = ChangeSet(self.todolist, self.archive, ['add One'])
        backup.timestamp = '1'
        command1 = AddCommand(["One"], self.todolist, self.out, self.error, None)
        command1.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Two'])
        backup.timestamp = '2'
        command2 = AddCommand(["Two"], self.todolist, self.out, self.error, None)
        command2.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Three'])
        backup.timestamp = '3'
        command3 = AddCommand(["Three"], self.todolist, self.out, self.error, None)
        command3.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['delete Three'])
        backup.timestamp = '4'
        command4 = DeleteCommand(["Three"], self.todolist, self.out, self.error, None)
        command4.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Four'])
        backup.timestamp = '5'
        command4 = AddCommand(["Four"], self.todolist, self.out, self.error, None)
        command4.execute()
        backup.save(self.todolist)

        revert_command = RevertCommand([], self.todolist, self.out, self.error, None)
        revert_command.execute()
        self.assertEqual(self.errors, "")
        self.assertTrue(self.output.endswith("Successfully reverted: add Four\n"))
        self.assertEqual(self.todolist.print_todos(), "Foo\nBar\nBaz\n{t} One\n{t} Two".format(t=self.today))

        revert_command = RevertCommand([], self.todolist, self.out, self.error, None)
        revert_command.execute()
        self.assertEqual(self.errors, "")
        self.assertTrue(self.output.endswith("Successfully reverted: delete Three\n"))
        self.assertEqual(self.todolist.print_todos(), "Foo\nBar\nBaz\n{t} One\n{t} Two\n{t} Three".format(t=self.today))

        revert_command = RevertCommand([], self.todolist, self.out, self.error, None)
        revert_command.execute()
        self.assertEqual(self.errors, "")
        self.assertTrue(self.output.endswith("Successfully reverted: add Three\n"))
        self.assertEqual(self.todolist.print_todos(), "Foo\nBar\nBaz\n{t} One\n{t} Two".format(t=self.today))

        revert_command = RevertCommand([], self.todolist, self.out, self.error, None)
        revert_command.execute()
        self.assertEqual(self.errors, "")
        self.assertTrue(self.output.endswith("Successfully reverted: add Two\n"))
        self.assertEqual(self.todolist.print_todos(), "Foo\nBar\nBaz\n{t} One".format(t=self.today))

        revert_command = RevertCommand([], self.todolist, self.out, self.error, None)
        revert_command.execute()
        self.assertEqual(self.errors, "")
        self.assertTrue(self.output.endswith("Successfully reverted: add One\n"))
        self.assertEqual(self.todolist.print_todos(), "Foo\nBar\nBaz")
Example #17
0
    def test_revert04(self):
        """ Test trimming of the backup_file """
        backup = ChangeSet(self.todolist, self.archive, ['add One'])
        backup.timestamp = '1'
        command1 = AddCommand(["One"], self.todolist, self.out, self.error, None)
        command1.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Two'])
        backup.timestamp = '2'
        command2 = AddCommand(["Two"], self.todolist, self.out, self.error, None)
        command2.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Three'])
        backup.timestamp = '3'
        command3 = AddCommand(["Three"], self.todolist, self.out, self.error, None)
        command3.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Four'])
        backup.timestamp = '4'
        command4 = AddCommand(["Four"], self.todolist, self.out, self.error, None)
        command4.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Five'])
        backup.timestamp = '5'
        command5 = AddCommand(["Five"], self.todolist, self.out, self.error, None)
        command5.execute()
        backup.save(self.todolist)

        result = len(ChangeSet().backup_dict.keys())
        self.assertEqual(result, 6)

        backup = ChangeSet(self.todolist, self.archive, ['add Six'])
        backup.timestamp = '6'
        command6 = AddCommand(["Six"], self.todolist, self.out, self.error, None)
        command6.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Seven'])
        backup.timestamp = '7'
        command7 = AddCommand(["Seven"], self.todolist, self.out, self.error, None)
        command7.execute()
        backup.save(self.todolist)

        result = len(ChangeSet().backup_dict.keys())
        self.assertEqual(result, 6)

        revert_command = RevertCommand([], self.todolist, self.out, self.error, None)
        revert_command.execute()

        backup = ChangeSet()
        changesets = list(backup.backup_dict.keys())
        changesets.remove('index')
        index_timestamps = [change[0] for change in backup._get_index()]
        result = list(set(index_timestamps) - set(changesets))

        self.assertEqual(len(changesets), 4)
        self.assertEqual(result, [])
        self.assertEqual(self.errors, "")
        self.assertTrue(self.output.endswith("Successfully reverted: add Seven\n"))
Example #18
0
    def test_revert04(self, mock_archive):
        """ Test trimming of the backup_file """
        mock_archive.return_value = ''  # test for empty archive setting
        backup = BackupSimulator(self.todolist, self.archive, '1', ['add One'])
        command_executer(AddCommand, ["One"], self.todolist, None, self.out,
                         self.error, None)
        backup.save(self.todolist)

        backup = BackupSimulator(self.todolist, self.archive, '2', ['add Two'])
        command_executer(AddCommand, ["Two"], self.todolist, None, self.out,
                         self.error, None)
        backup.save(self.todolist)

        backup = BackupSimulator(self.todolist, self.archive, '3',
                                 ['add Three'])
        command_executer(AddCommand, ["Three"], self.todolist, None, self.out,
                         self.error, None)
        backup.save(self.todolist)

        backup = BackupSimulator(self.todolist, self.archive, '4',
                                 ['add Four'])
        command_executer(AddCommand, ["Four"], self.todolist, None, self.out,
                         self.error, None)
        backup.save(self.todolist)

        backup = BackupSimulator(self.todolist, self.archive, '5',
                                 ['add Five'])
        command_executer(AddCommand, ["Five"], self.todolist, None, self.out,
                         self.error, None)
        backup.save(self.todolist)

        result = len(ChangeSet().backup_dict.keys())
        self.assertEqual(result, 6)

        backup = BackupSimulator(self.todolist, self.archive, '6', ['add Six'])
        command_executer(AddCommand, ["Six"], self.todolist, None, self.out,
                         self.error, None)
        backup.save(self.todolist)

        backup = BackupSimulator(self.todolist, self.archive, '7',
                                 ['add Seven'])
        command_executer(AddCommand, ["Seven"], self.todolist, None, self.out,
                         self.error, None)
        backup.save(self.todolist)

        result = len(ChangeSet().backup_dict.keys())
        self.assertEqual(result, 6)

        revert_command = RevertCommand([], self.todolist, self.out, self.error,
                                       None)
        revert_command.execute()

        backup = ChangeSet()
        changesets = list(backup.backup_dict.keys())
        changesets.remove('index')
        index_timestamps = [change[0] for change in backup._get_index()]
        result = list(set(index_timestamps) - set(changesets))

        self.assertEqual(len(changesets), 4)
        self.assertEqual(result, [])
        self.assertEqual(self.errors, "")
        self.assertTrue(
            self.output.endswith("Reverted to state before: add Seven\n"))
Example #19
0
class RevertCommand(Command):
    def __init__(self, p_args, p_todolist,  # pragma: no branch
                 p_out=lambda a: None,
                 p_err=lambda a: None,
                 p_prompt=lambda a: None):
        super().__init__(p_args, p_todolist, p_out, p_err, p_prompt)

        self._backup = None
        self._archive_file = None
        self._archive = None

    def execute(self):
        if not super().execute():
            return False

        self._backup = ChangeSet()
        archive_path = config().archive()
        if archive_path:
            self._archive_file = TodoFile.TodoFile(config().archive())
            self._archive = TodoList.TodoList(self._archive_file.read())

        if len(self.args) > 1:
            self.error(self.usage())
        else:
            try:
                arg = self.argument(0)
                self._handle_args(arg)
            except InvalidCommandArgument:
                try:
                    self._revert_last()
                except (ValueError, KeyError):
                    self.error('No backup was found for the current state of '
                               + config().todotxt())

        self._backup.close()

    def _revert(self, p_timestamp=None):
        self._backup.read_backup(self.todolist, p_timestamp)
        self._backup.apply(self.todolist, self._archive)

        if self._archive:
            self._archive_file.write(self._archive.print_todos())

        self.out("Reverted to state before: " + self._backup.label)

    def _revert_last(self):
        self._revert()
        self._backup.delete()

    def _revert_to_specific(self, p_position):
        timestamps = [timestamp for timestamp, _ in self._backup]
        position = int(p_position) - 1  # numbering in UI starts with 1
        try:
            timestamp = timestamps[position]
            self._revert(timestamp)
            for timestamp in timestamps[:position + 1]:
                self._backup.read_backup(p_timestamp=timestamp)
                self._backup.delete()
        except IndexError:
            self.error('Specified index is out range')

    def _handle_args(self, p_arg):
        try:
            if p_arg == 'ls':
                self._handle_ls()
            elif p_arg.isdigit():
                self._revert_to_specific(p_arg)
            else:
                raise InvalidCommandArgument
        except InvalidCommandArgument:
            self.error(self.usage())

    def _handle_ls(self):
        num = 1
        for timestamp, change in self._backup:
            label = change[2]
            time = arrow.get(timestamp).format('YYYY-MM-DD HH:mm:ss')

            self.out('{0: >3}| {1} | {2}'.format(str(num), time, label))
            num += 1

    def usage(self):
        return """Synopsis:
  revert [ls]
  revert [NUMBER]"""

    def help(self):
        return """\
Example #20
0
    def test_revert05(self):
        """ Test for possible backup collisions """
        backup = ChangeSet(self.todolist, self.archive, ['add One'])
        backup.timestamp = '1'
        command1 = AddCommand(["One"], self.todolist, self.out, self.error,
                              None)
        command1.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Two'])
        backup.timestamp = '2'
        command2 = AddCommand(["Two"], self.todolist, self.out, self.error,
                              None)
        command2.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Three'])
        backup.timestamp = '3'
        command3 = AddCommand(["Three"], self.todolist, self.out, self.error,
                              None)
        command3.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['delete Three'])
        backup.timestamp = '4'
        command4 = DeleteCommand(["Three"], self.todolist, self.out,
                                 self.error, None)
        command4.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Four'])
        backup.timestamp = '5'
        command4 = AddCommand(["Four"], self.todolist, self.out, self.error,
                              None)
        command4.execute()
        backup.save(self.todolist)

        revert_command = RevertCommand([], self.todolist, self.out, self.error,
                                       None)
        revert_command.execute()
        self.assertEqual(self.errors, "")
        self.assertTrue(
            self.output.endswith("Successfully reverted: add Four\n"))
        self.assertEqual(
            self.todolist.print_todos(),
            "Foo\nBar\nBaz\n{t} One\n{t} Two".format(t=self.today))

        revert_command = RevertCommand([], self.todolist, self.out, self.error,
                                       None)
        revert_command.execute()
        self.assertEqual(self.errors, "")
        self.assertTrue(
            self.output.endswith("Successfully reverted: delete Three\n"))
        self.assertEqual(
            self.todolist.print_todos(),
            "Foo\nBar\nBaz\n{t} One\n{t} Two\n{t} Three".format(t=self.today))

        revert_command = RevertCommand([], self.todolist, self.out, self.error,
                                       None)
        revert_command.execute()
        self.assertEqual(self.errors, "")
        self.assertTrue(
            self.output.endswith("Successfully reverted: add Three\n"))
        self.assertEqual(
            self.todolist.print_todos(),
            "Foo\nBar\nBaz\n{t} One\n{t} Two".format(t=self.today))

        revert_command = RevertCommand([], self.todolist, self.out, self.error,
                                       None)
        revert_command.execute()
        self.assertEqual(self.errors, "")
        self.assertTrue(
            self.output.endswith("Successfully reverted: add Two\n"))
        self.assertEqual(self.todolist.print_todos(),
                         "Foo\nBar\nBaz\n{t} One".format(t=self.today))

        revert_command = RevertCommand([], self.todolist, self.out, self.error,
                                       None)
        revert_command.execute()
        self.assertEqual(self.errors, "")
        self.assertTrue(
            self.output.endswith("Successfully reverted: add One\n"))
        self.assertEqual(self.todolist.print_todos(), "Foo\nBar\nBaz")
Example #21
0
class CLIApplicationBase(object):
    """
    Base class for a Command Line Interfaces (CLI) for topydo. Examples are the
    original CLI and the Prompt interface.

    Handles input/output of the various subcommands.
    """

    def __init__(self):
        self.todolist = TodoList.TodoList([])
        self.todofile = None
        self.do_archive = True
        self._post_archive_action = None
        self.backup = None

    @staticmethod
    def _usage():
        usage()
        sys.exit(0)

    def _process_flags(self):
        args = sys.argv[1:]

        try:
            opts, args = getopt.getopt(args, MAIN_OPTS, MAIN_LONG_OPTS)
        except getopt.GetoptError as e:
            error(str(e))
            sys.exit(1)

        alt_config_path = None
        overrides = {}

        for opt, value in opts:
            if opt == "-a":
                self.do_archive = False
            elif opt == "-c":
                alt_config_path = value
            elif opt == "-C":
                overrides[('topydo', 'force_colors')] = '1'
                overrides[('topydo', 'colors')] = value
            elif opt == "-t":
                overrides[('topydo', 'filename')] = value
            elif opt == "-d":
                overrides[('topydo', 'archive_filename')] = value
            elif opt in ("-v", "--version"):
                version()
            else:
                CLIApplicationBase._usage()

        if alt_config_path:
            config(alt_config_path, overrides)
        elif len(overrides):
            config(p_overrides=overrides)

        return args

    def _archive(self):
        """
        Performs an archive action on the todolist.

        This means that all completed tasks are moved to the archive file
        (defaults to done.txt).
        """
        archive, archive_file = _retrieve_archive()

        if self.backup:
            self.backup.add_archive(archive)

        if archive:
            from topydo.commands.ArchiveCommand import ArchiveCommand
            command = ArchiveCommand(self.todolist, archive)
            command.execute()

            if archive.dirty:
                archive_file.write(archive.print_todos())

    @staticmethod
    def is_read_only(p_command):
        """ Returns True when the given command class is read-only. """
        read_only_commands = tuple(cmd for cmd
                                   in ('revert', ) + READ_ONLY_COMMANDS)
        return p_command.name() in read_only_commands

    def _backup(self, p_command, p_args=None, p_label=None):
        if config().backup_count() > 0 and p_command and not CLIApplicationBase.is_read_only(p_command):
            p_args = p_args if p_args else []
            call = [p_command.name()] + p_args

            from topydo.lib.ChangeSet import ChangeSet
            label = p_label if p_label else call
            self.backup = ChangeSet(self.todolist, p_label=label)

    def _execute(self, p_command, p_args):
        """
        Execute a subcommand with arguments. p_command is a class (not an
        object).
        """
        self._backup(p_command, p_args)

        command = p_command(
            p_args,
            self.todolist,
            output,
            error,
            input)

        if command.execute() != False:
            self._post_archive_action = command.execute_post_archive_actions
            return True

        return False

    def _post_execute(self):
        """
        Should be called when executing the user requested command has been
        completed. It will do some maintenance and write out the final result
        to the todo.txt file.
        """

        if self.todolist.dirty:
            # do not archive when the value of the filename is an empty string
            # (i.e. explicitly left empty in the configuration
            if self.do_archive and config().archive():
                self._archive()
            elif config().archive() and self.backup:
                archive = _retrieve_archive()[0]
                self.backup.add_archive(archive)

            self._post_archive_action()

            if config().keep_sorted():
                from topydo.commands.SortCommand import SortCommand
                self._execute(SortCommand, [])

            if self.backup:
                self.backup.save(self.todolist)

            self.todofile.write(self.todolist.print_todos())
            self.todolist.dirty = False

        self.backup = None

    def run(self):
        raise NotImplementedError
Example #22
0
    def _backup(self, p_command, p_args):
        if config().backup_count() > 0 and p_command and not self.is_read_only(p_command):
            call = [p_command.__module__.lower()[16:-7]] + p_args # strip "topydo.commands" and "Command"

            from topydo.lib.ChangeSet import ChangeSet
            self.backup = ChangeSet(self.todolist, p_call=call)
Example #23
0
    def test_revert06(self):
        """ Test attempt of deletion with non-existing backup key"""
        backup = ChangeSet(self.todolist, self.archive, ['add One'])
        backup.timestamp = '1'
        command1 = AddCommand(["One"], self.todolist, self.out, self.error, None)
        command1.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Two'])
        backup.timestamp = '2'
        command2 = AddCommand(["Two"], self.todolist, self.out, self.error, None)
        command2.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Three'])
        backup.timestamp = '3'
        command3 = AddCommand(["Three"], self.todolist, self.out, self.error, None)
        command3.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['delete Three'])
        backup.timestamp = '4'
        command4 = DeleteCommand(["Three"], self.todolist, self.out, self.error, None)
        command4.execute()
        backup.save(self.todolist)

        backup = ChangeSet()
        backup.delete('Foo')

        changesets = list(backup.backup_dict.keys())
        changesets.remove('index')
        index_timestamps = [change[0] for change in backup._get_index()]
        result = list(set(index_timestamps) - set(changesets))

        self.assertEqual(len(changesets), 4)
        self.assertEqual(result, [])
        self.assertEqual(self.errors, "")
Example #24
0
    def test_revert04(self):
        """ Test trimming of the backup_file """
        backup = ChangeSet(self.todolist, self.archive, ['add One'])
        backup.timestamp = '1'
        command1 = AddCommand(["One"], self.todolist, self.out, self.error,
                              None)
        command1.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Two'])
        backup.timestamp = '2'
        command2 = AddCommand(["Two"], self.todolist, self.out, self.error,
                              None)
        command2.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Three'])
        backup.timestamp = '3'
        command3 = AddCommand(["Three"], self.todolist, self.out, self.error,
                              None)
        command3.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Four'])
        backup.timestamp = '4'
        command4 = AddCommand(["Four"], self.todolist, self.out, self.error,
                              None)
        command4.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Five'])
        backup.timestamp = '5'
        command5 = AddCommand(["Five"], self.todolist, self.out, self.error,
                              None)
        command5.execute()
        backup.save(self.todolist)

        result = len(ChangeSet().backup_dict.keys())
        self.assertEqual(result, 6)

        backup = ChangeSet(self.todolist, self.archive, ['add Six'])
        backup.timestamp = '6'
        command6 = AddCommand(["Six"], self.todolist, self.out, self.error,
                              None)
        command6.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Seven'])
        backup.timestamp = '7'
        command7 = AddCommand(["Seven"], self.todolist, self.out, self.error,
                              None)
        command7.execute()
        backup.save(self.todolist)

        result = len(ChangeSet().backup_dict.keys())
        self.assertEqual(result, 6)

        revert_command = RevertCommand([], self.todolist, self.out, self.error,
                                       None)
        revert_command.execute()

        backup = ChangeSet()
        changesets = list(backup.backup_dict.keys())
        changesets.remove('index')
        index_timestamps = [change[0] for change in backup._get_index()]
        result = list(set(index_timestamps) - set(changesets))

        self.assertEqual(len(changesets), 4)
        self.assertEqual(result, [])
        self.assertEqual(self.errors, "")
        self.assertTrue(
            self.output.endswith("Successfully reverted: add Seven\n"))
Example #25
0
    def test_revert06(self):
        """ Test attempt of deletion with non-existing backup key"""
        backup = ChangeSet(self.todolist, self.archive, ['add One'])
        backup.timestamp = '1'
        command1 = AddCommand(["One"], self.todolist, self.out, self.error,
                              None)
        command1.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Two'])
        backup.timestamp = '2'
        command2 = AddCommand(["Two"], self.todolist, self.out, self.error,
                              None)
        command2.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['add Three'])
        backup.timestamp = '3'
        command3 = AddCommand(["Three"], self.todolist, self.out, self.error,
                              None)
        command3.execute()
        backup.save(self.todolist)

        backup = ChangeSet(self.todolist, self.archive, ['delete Three'])
        backup.timestamp = '4'
        command4 = DeleteCommand(["Three"], self.todolist, self.out,
                                 self.error, None)
        command4.execute()
        backup.save(self.todolist)

        backup = ChangeSet()
        backup.delete('Foo')

        changesets = list(backup.backup_dict.keys())
        changesets.remove('index')
        index_timestamps = [change[0] for change in backup._get_index()]
        result = list(set(index_timestamps) - set(changesets))

        self.assertEqual(len(changesets), 4)
        self.assertEqual(result, [])
        self.assertEqual(self.errors, "")
Example #26
0
class RevertCommand(Command):
    def __init__(
            self,
            p_args,
            p_todolist,  # pragma: no branch
            p_out=lambda a: None,
            p_err=lambda a: None,
            p_prompt=lambda a: None):
        super().__init__(p_args, p_todolist, p_out, p_err, p_prompt)

        self._backup = None
        self._archive_file = None
        self._archive = None

    def execute(self):
        if not super().execute():
            return False

        self._backup = ChangeSet()
        archive_path = config().archive()
        if archive_path:
            self._archive_file = TodoFile.TodoFile(config().archive())
            self._archive = TodoList.TodoList(self._archive_file.read())

        if len(self.args) > 1:
            self.error(self.usage())
        else:
            try:
                arg = self.argument(0)
                self._handle_args(arg)
            except InvalidCommandArgument:
                try:
                    self._revert_last()
                except (ValueError, KeyError):
                    self.error(
                        'No backup was found for the current state of ' +
                        config().todotxt())

        self._backup.close()

    def _revert(self, p_timestamp=None):
        self._backup.read_backup(self.todolist, p_timestamp)
        self._backup.apply(self.todolist, self._archive)

        if self._archive:
            self._archive_file.write(self._archive.print_todos())

        self.out("Reverted to state before: " + self._backup.label)

    def _revert_last(self):
        self._revert()
        self._backup.delete()

    def _revert_to_specific(self, p_position):
        timestamps = [timestamp for timestamp, _ in self._backup]
        position = int(p_position) - 1  # numbering in UI starts with 1
        try:
            timestamp = timestamps[position]
            self._revert(timestamp)
            for timestamp in timestamps[:position + 1]:
                self._backup.read_backup(p_timestamp=timestamp)
                self._backup.delete()
        except IndexError:
            self.error('Specified index is out range')

    def _handle_args(self, p_arg):
        try:
            if p_arg == 'ls':
                self._handle_ls()
            elif p_arg.isdigit():
                self._revert_to_specific(p_arg)
            else:
                raise InvalidCommandArgument
        except InvalidCommandArgument:
            self.error(self.usage())

    def _handle_ls(self):
        num = 1
        for timestamp, change in self._backup:
            label = change[2]
            time = arrow.get(float(timestamp)).format('YYYY-MM-DD HH:mm:ss')

            self.out('{0: >3}| {1} | {2}'.format(str(num), time, label))
            num += 1

    def usage(self):
        return """Synopsis:
  revert [ls]
  revert [NUMBER]"""

    def help(self):
        return """\
Example #27
0
 def __init__(self, p_todolist, p_archive, p_timestamp, p_label):
     self.backup = ChangeSet(p_todolist, p_archive, p_label)
     self.backup.timestamp = p_timestamp
Example #28
0
class CLIApplicationBase(object):
    """
    Base class for a Command Line Interfaces (CLI) for topydo. Examples are the
    original CLI and the Prompt interface.

    Handles input/output of the various subcommands.
    """
    def __init__(self):
        self.todolist = TodoList.TodoList([])
        self.todofile = None
        self.do_archive = True
        self._post_archive_action = None
        self.backup = None

    @staticmethod
    def _usage():
        usage()
        sys.exit(0)

    def _process_flags(self):
        args = sys.argv[1:]

        try:
            opts, args = getopt.getopt(args, MAIN_OPTS, MAIN_LONG_OPTS)
        except getopt.GetoptError as e:
            error(str(e))
            sys.exit(1)

        alt_config_path = None
        overrides = {}

        for opt, value in opts:
            if opt == "-a":
                self.do_archive = False
            elif opt == "-c":
                alt_config_path = value
            elif opt == "-C":
                overrides[('topydo', 'force_colors')] = '1'
                overrides[('topydo', 'colors')] = value
            elif opt == "-t":
                overrides[('topydo', 'filename')] = value
            elif opt == "-d":
                overrides[('topydo', 'archive_filename')] = value
            elif opt in ("-v", "--version"):
                version()
            else:
                CLIApplicationBase._usage()

        if alt_config_path:
            config(alt_config_path, overrides)
        elif len(overrides):
            config(p_overrides=overrides)

        return args

    def _archive(self):
        """
        Performs an archive action on the todolist.

        This means that all completed tasks are moved to the archive file
        (defaults to done.txt).
        """
        archive, archive_file = _retrieve_archive()

        if self.backup:
            self.backup.add_archive(archive)

        if archive:
            command = ArchiveCommand(self.todolist, archive)
            command.execute()

            if archive.dirty:
                archive_file.write(archive.print_todos())

    @staticmethod
    def is_read_only(p_command):
        """ Returns True when the given command class is read-only. """
        read_only_commands = tuple(
            cmd for cmd in ('revert', ) + READ_ONLY_COMMANDS)
        return p_command.name() in read_only_commands

    def _backup(self, p_command, p_args=None, p_label=None):
        if config().backup_count(
        ) > 0 and p_command and not CLIApplicationBase.is_read_only(p_command):
            p_args = p_args if p_args else []
            call = [p_command.name()] + p_args

            from topydo.lib.ChangeSet import ChangeSet
            label = p_label if p_label else call
            self.backup = ChangeSet(self.todolist, p_label=label)

    def _execute(self, p_command, p_args):
        """
        Execute a subcommand with arguments. p_command is a class (not an
        object).
        """
        self._backup(p_command, p_args)

        if p_command == None:
            usage()
            return False
        if p_command.name() != 'archive':
            command = p_command(p_args, self.todolist, output, error, input)

            if command.execute() != False:
                self._post_archive_action = command.execute_post_archive_actions
                return True
        else:
            self.todolist.dirty = True
            self.do_archive = True
            return True

        return False

    def _post_execute(self):
        """
        Should be called when executing the user requested command has been
        completed. It will do some maintenance and write out the final result
        to the todo.txt file.
        """

        if self.todolist.dirty:
            # do not archive when the value of the filename is an empty string
            # (i.e. explicitly left empty in the configuration
            if self.do_archive and config().archive():
                self._archive()
            elif config().archive() and self.backup:
                archive = _retrieve_archive()[0]
                self.backup.add_archive(archive)

            try:
                self._post_archive_action()
            except TypeError:
                pass

            if config().keep_sorted():
                from topydo.commands.SortCommand import SortCommand
                self._execute(SortCommand, [])

            if self.backup:
                self.backup.save(self.todolist)

            self.todofile.write(self.todolist.print_todos())
            self.todolist.dirty = False

        self.backup = None

    def run(self):
        raise NotImplementedError
Example #29
0
class CLIApplicationBase(object):
    """
    Base class for a Command Line Interfaces (CLI) for topydo. Examples are the
    original CLI and the Prompt interface.

    Handles input/output of the various subcommands.
    """

    def __init__(self):
        self.todolist = TodoList.TodoList([])
        self.todofile = None
        self.do_archive = True
        self.backup = None

    def _usage(self):
        usage()
        sys.exit(0)

    def _process_flags(self):
        args = sys.argv[1:]

        try:
            opts, args = getopt.getopt(args, MAIN_OPTS)
        except getopt.GetoptError as e:
            error(str(e))
            sys.exit(1)

        alt_config_path = None
        overrides = {}

        for opt, value in opts:
            if opt == "-a":
                self.do_archive = False
            elif opt == "-c":
                alt_config_path = value
            elif opt == "-t":
                overrides[('topydo', 'filename')] = value
            elif opt == "-d":
                overrides[('topydo', 'archive_filename')] = value
            elif opt == "-v":
                version()
            else:
                self._usage()

        if alt_config_path:
            config(alt_config_path, overrides)
        elif len(overrides):
            config(p_overrides=overrides)

        return args

    def _archive(self):
        """
        Performs an archive action on the todolist.

        This means that all completed tasks are moved to the archive file
        (defaults to done.txt).
        """
        archive_file = TodoFile.TodoFile(config().archive())
        archive = TodoListBase.TodoListBase(archive_file.read())

        if self.backup:
            self.backup.add_archive(archive)

        if archive:
            from topydo.commands.ArchiveCommand import ArchiveCommand
            command = ArchiveCommand(self.todolist, archive)
            command.execute()

            if archive.is_dirty():
                archive_file.write(archive.print_todos())

    def _help(self, args):
        if args is None:
            pass  # TODO
        else:
            pass  # TODO

    def is_read_only(self, p_command):
        """ Returns True when the given command class is read-only. """
        read_only_commands = tuple(cmd + 'Command' for cmd in ('Revert', ) +
                READ_ONLY_COMMANDS)
        return p_command.__module__.endswith(read_only_commands)

    def _execute(self, p_command, p_args):
        """
        Execute a subcommand with arguments. p_command is a class (not an
        object).
        """
        if config().backup_count() > 0 and p_command and not self.is_read_only(p_command):
            call = [p_command.__module__.lower()[16:-7]] + p_args # strip "topydo.commands" and "Command"

            from topydo.lib.ChangeSet import ChangeSet
            self.backup = ChangeSet(self.todolist, p_call=call)

        command = p_command(
            p_args,
            self.todolist,
            lambda o: write(sys.stdout, o),
            error,
            input)

        if command.execute() != False:
            return True

        return False

    def _post_execute(self):
        """
        Should be called when executing the user requested command has been
        completed. It will do some maintenance and write out the final result
        to the todo.txt file.
        """

        if self.todolist.is_dirty():
            # do not archive when the value of the filename is an empty string
            # (i.e. explicitly left empty in the configuration
            if self.do_archive and config().archive():
                self._archive()

            if config().keep_sorted():
                from topydo.commands.SortCommand import SortCommand
                self._execute(SortCommand, [])

            if self.backup:
                self.backup.save(self.todolist)

            self.todofile.write(self.todolist.print_todos())

        self.backup = None

    def run(self):
        raise NotImplementedError