view hgext/fsmonitor/state.py @ 28639:64ed9f904532

tests: fix for failure of test-convert-p4-filetypes.t Before this patch, test-convert-p4-filetypes.t fails (at least with 2015.2/1366233 version of p4/p4d), because some files below are omitted in expected output for revision 1. - file_tempobj - file_xtempobj These files are: - add-ed at revision 0, and - edit-ed at revision 1 According to perforce command reference below, file type 'tempobj' and 'xtempobj' imply '+S' modifier, which indicates that "Only the head revision is stored". This means that these files should appear only in the most recent revision (= revision 1). https://www.perforce.com/perforce/doc.current/manuals/cmdref/file.types.html BTW, test-convert-p4-filetypes.t with 2015.2/1366233 version of p4/p4d fails similarly also at recent revisions for hgext/convert/p4.py in 2015. Therefore, this patch should be reviewed by perforce guru, to examine whether this failure depends on version (and/or configuration) of p4/p4d or not.
author FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
date Sat, 26 Mar 2016 12:55:52 +0900
parents 3b67f27bb908
children a0939666b836
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 import pathutil
from mercurial.i18n import _

_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