view hgext/fsmonitor/state.py @ 29759:e584c6235500

py3: conditionalize the raise statement raise E,V,T is not acceptable in Python 3, thats is conditionalized. Moreover this will result in syntax error so we have to use exec() to execute this. Related PEP- https://www.python.org/dev/peps/pep-3109/#id14 My implementation is motivated from the six implementation except they are defining a new function exec_() to prevent adding an extra frame AFAIK :) https://bitbucket.org/gutworth/six/src/ca4580a5a648/six.py#six.py-680
author Pulkit Goyal <7895pulkit@gmail.com>
date Mon, 08 Aug 2016 23:51:11 +0530
parents a0939666b836
children 29b35dac3b1f
line wrap: on
line source

# state.py - fsmonitor persistent state
#
# Copyright 2013-2016 Facebook, Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.

from __future__ import absolute_import

import errno
import os
import socket
import struct

from mercurial.i18n import _
from mercurial import pathutil

_version = 4
_versionformat = ">I"

class state(object):
    def __init__(self, repo):
        self._opener = repo.opener
        self._ui = repo.ui
        self._rootdir = pathutil.normasprefix(repo.root)
        self._lastclock = None

        self.mode = self._ui.config('fsmonitor', 'mode', default='on')
        self.walk_on_invalidate = self._ui.configbool(
            'fsmonitor', 'walk_on_invalidate', False)
        self.timeout = float(self._ui.config(
            'fsmonitor', 'timeout', default='2'))

    def get(self):
        try:
            file = self._opener('fsmonitor.state', 'rb')
        except IOError as inst:
            if inst.errno != errno.ENOENT:
                raise
            return None, None, None

        versionbytes = file.read(4)
        if len(versionbytes) < 4:
            self._ui.log(
                'fsmonitor', 'fsmonitor: state file only has %d bytes, '
                'nuking state\n' % len(versionbytes))
            self.invalidate()
            return None, None, None
        try:
            diskversion = struct.unpack(_versionformat, versionbytes)[0]
            if diskversion != _version:
                # different version, nuke state and start over
                self._ui.log(
                    'fsmonitor', 'fsmonitor: version switch from %d to '
                    '%d, nuking state\n' % (diskversion, _version))
                self.invalidate()
                return None, None, None

            state = file.read().split('\0')
            # state = hostname\0clock\0ignorehash\0 + list of files, each
            # followed by a \0
            diskhostname = state[0]
            hostname = socket.gethostname()
            if diskhostname != hostname:
                # file got moved to a different host
                self._ui.log('fsmonitor', 'fsmonitor: stored hostname "%s" '
                             'different from current "%s", nuking state\n' %
                             (diskhostname, hostname))
                self.invalidate()
                return None, None, None

            clock = state[1]
            ignorehash = state[2]
            # discard the value after the last \0
            notefiles = state[3:-1]

        finally:
            file.close()

        return clock, ignorehash, notefiles

    def set(self, clock, ignorehash, notefiles):
        if clock is None:
            self.invalidate()
            return

        try:
            file = self._opener('fsmonitor.state', 'wb')
        except (IOError, OSError):
            self._ui.warn(_("warning: unable to write out fsmonitor state\n"))
            return

        try:
            file.write(struct.pack(_versionformat, _version))
            file.write(socket.gethostname() + '\0')
            file.write(clock + '\0')
            file.write(ignorehash + '\0')
            if notefiles:
                file.write('\0'.join(notefiles))
                file.write('\0')
        finally:
            file.close()

    def invalidate(self):
        try:
            os.unlink(os.path.join(self._rootdir, '.hg', 'fsmonitor.state'))
        except OSError as inst:
            if inst.errno != errno.ENOENT:
                raise

    def setlastclock(self, clock):
        self._lastclock = clock

    def getlastclock(self):
        return self._lastclock