Beispiel #1
0
    def get_files_to_recover(self):
        """
        Get list of files to recover from pid files in autosave dir.

        This returns a tuple `(files_to_recover, pid_files)`. In this tuple,
        `files_to_recover` is a list of tuples containing the original file
        names and the corresponding autosave file names, as recorded in the
        pid files in the autosave directory. Any files in the autosave
        directory which are not listed in a pid file, are also included, with
        the original file name set to `None`. The second entry, `pid_files`,
        is a list with the names of the pid files.
        """
        autosave_dir = get_conf_path('autosave')
        if not os.access(autosave_dir, os.R_OK):
            return [], []

        files_to_recover = []
        files_mentioned = []
        pid_files = []
        non_pid_files = []

        # In Python 3, easier to use os.scandir()
        for name in os.listdir(autosave_dir):
            full_name = osp.join(autosave_dir, name)
            match = re.match(r'pid([0-9]*)\.txt\Z', name)
            if match:
                pid_files.append(full_name)
                logger.debug('Reading pid file: {}'.format(full_name))
                with open(full_name) as pidfile:
                    txt = pidfile.read()
                    try:
                        txt_as_dict = ast.literal_eval(txt)
                    except (SyntaxError, ValueError):
                        # Pid file got corrupted, see spyder-ide/spyder#11375
                        logger.error(
                            'Error parsing pid file {}'.format(full_name))
                        logger.error('Contents: {}'.format(repr(txt)))
                        txt_as_dict = {}
                    files_mentioned += [
                        autosave for (orig, autosave) in txt_as_dict.items()
                    ]
                pid = int(match.group(1))
                if is_spyder_process(pid):
                    logger.debug('Ignoring files in {}'.format(full_name))
                else:
                    files_to_recover += list(txt_as_dict.items())
            else:
                non_pid_files.append(full_name)

        # Add all files not mentioned in any pid file. This can only happen if
        # the pid file somehow got corrupted.
        for filename in set(non_pid_files) - set(files_mentioned):
            files_to_recover.append((None, filename))
            logger.debug('Added unmentioned file: {}'.format(filename))

        return files_to_recover, pid_files
Beispiel #2
0
    def lock(self):
        """
        Acquire this lock.

        @rtype: C{bool}
        @return: True if the lock is acquired, false otherwise.

        @raise: Any exception os.symlink() may raise, other than
        EEXIST.
        """
        clean = True
        while True:
            try:
                symlink(str(os.getpid()), self.name)
            except OSError as e:
                if _windows and e.errno in (errno.EACCES, errno.EIO):
                    # The lock is in the middle of being deleted because we're
                    # on Windows where lock removal isn't atomic.  Give up, we
                    # don't know how long this is going to take.
                    return False
                if e.errno == errno.EEXIST:
                    try:
                        pid = readlink(self.name)
                    except OSError as e:
                        if e.errno == errno.ENOENT:
                            # The lock has vanished, try to claim it in the
                            # next iteration through the loop.
                            continue
                        raise
                    except IOError as e:
                        if _windows and e.errno == errno.EACCES:
                            # The lock is in the middle of being
                            # deleted because we're on Windows where
                            # lock removal isn't atomic.  Give up, we
                            # don't know how long this is going to
                            # take.
                            return False
                        raise
                    try:
                        if kill is not None:
                            kill(int(pid), 0)
                        if not is_spyder_process(int(pid)):
                            raise (OSError(errno.ESRCH, 'No such process'))
                    except OSError as e:
                        if e.errno == errno.ESRCH:
                            # The owner has vanished, try to claim it in the
                            # next iteration through the loop.
                            try:
                                rmlink(self.name)
                            except OSError as e:
                                if e.errno == errno.ENOENT:
                                    # Another process cleaned up the lock.
                                    # Race them to acquire it in the next
                                    # iteration through the loop.
                                    continue
                                raise
                            clean = False
                            continue
                        raise
                    return False
                raise
            self.locked = True
            self.clean = clean
            return True