hgext/fsmonitor/state.py
author Gregory Szorc <gregory.szorc@gmail.com>
Sat, 08 Apr 2017 11:35:29 -0700
branchstable
changeset 31798 8c9178d647f7
parent 30539 29b35dac3b1f
child 31215 15c998528c36
permissions -rw-r--r--
tests: add test demonstrating buggy path handling `hg debugupgraderepo` is currently buggy with regards to path handling when copying files in .hg/store/. Specifically, it applies the store filename encoding to paths instead of operating on raw files. This commit adds a test demonstrating the buggy behavior.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
28433
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     1
# state.py - fsmonitor persistent state
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     2
#
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     3
# Copyright 2013-2016 Facebook, Inc.
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     4
#
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     5
# This software may be used and distributed according to the terms of the
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     6
# GNU General Public License version 2 or any later version.
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     7
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     8
from __future__ import absolute_import
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     9
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    10
import errno
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    11
import os
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    12
import socket
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    13
import struct
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    14
29205
a0939666b836 py3: move up symbol imports to enforce import-checker rules
Yuya Nishihara <yuya@tcha.org>
parents: 28433
diff changeset
    15
from mercurial.i18n import _
28433
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    16
from mercurial import pathutil
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    17
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    18
_version = 4
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    19
_versionformat = ">I"
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    20
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    21
class state(object):
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    22
    def __init__(self, repo):
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    23
        self._opener = repo.opener
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    24
        self._ui = repo.ui
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    25
        self._rootdir = pathutil.normasprefix(repo.root)
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    26
        self._lastclock = None
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    27
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    28
        self.mode = self._ui.config('fsmonitor', 'mode', default='on')
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    29
        self.walk_on_invalidate = self._ui.configbool(
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    30
            'fsmonitor', 'walk_on_invalidate', False)
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    31
        self.timeout = float(self._ui.config(
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    32
            'fsmonitor', 'timeout', default='2'))
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    33
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    34
    def get(self):
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    35
        try:
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    36
            file = self._opener('fsmonitor.state', 'rb')
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    37
        except IOError as inst:
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    38
            if inst.errno != errno.ENOENT:
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    39
                raise
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    40
            return None, None, None
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    41
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    42
        versionbytes = file.read(4)
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    43
        if len(versionbytes) < 4:
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    44
            self._ui.log(
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    45
                'fsmonitor', 'fsmonitor: state file only has %d bytes, '
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    46
                'nuking state\n' % len(versionbytes))
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    47
            self.invalidate()
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    48
            return None, None, None
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    49
        try:
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    50
            diskversion = struct.unpack(_versionformat, versionbytes)[0]
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    51
            if diskversion != _version:
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    52
                # different version, nuke state and start over
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    53
                self._ui.log(
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    54
                    'fsmonitor', 'fsmonitor: version switch from %d to '
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    55
                    '%d, nuking state\n' % (diskversion, _version))
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    56
                self.invalidate()
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    57
                return None, None, None
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    58
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    59
            state = file.read().split('\0')
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    60
            # state = hostname\0clock\0ignorehash\0 + list of files, each
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    61
            # followed by a \0
30539
29b35dac3b1f fsmonitor: be robust in the face of bad state
Simon Farnsworth <simonfar@fb.com>
parents: 29205
diff changeset
    62
            if len(state) < 3:
29b35dac3b1f fsmonitor: be robust in the face of bad state
Simon Farnsworth <simonfar@fb.com>
parents: 29205
diff changeset
    63
                self._ui.log(
29b35dac3b1f fsmonitor: be robust in the face of bad state
Simon Farnsworth <simonfar@fb.com>
parents: 29205
diff changeset
    64
                    'fsmonitor', 'fsmonitor: state file truncated (expected '
29b35dac3b1f fsmonitor: be robust in the face of bad state
Simon Farnsworth <simonfar@fb.com>
parents: 29205
diff changeset
    65
                    '3 chunks, found %d), nuking state\n', len(state))
29b35dac3b1f fsmonitor: be robust in the face of bad state
Simon Farnsworth <simonfar@fb.com>
parents: 29205
diff changeset
    66
                self.invalidate()
29b35dac3b1f fsmonitor: be robust in the face of bad state
Simon Farnsworth <simonfar@fb.com>
parents: 29205
diff changeset
    67
                return None, None, None
28433
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    68
            diskhostname = state[0]
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    69
            hostname = socket.gethostname()
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    70
            if diskhostname != hostname:
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    71
                # file got moved to a different host
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    72
                self._ui.log('fsmonitor', 'fsmonitor: stored hostname "%s" '
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    73
                             'different from current "%s", nuking state\n' %
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    74
                             (diskhostname, hostname))
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    75
                self.invalidate()
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    76
                return None, None, None
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    77
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    78
            clock = state[1]
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    79
            ignorehash = state[2]
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    80
            # discard the value after the last \0
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    81
            notefiles = state[3:-1]
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    82
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    83
        finally:
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    84
            file.close()
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    85
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    86
        return clock, ignorehash, notefiles
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    87
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    88
    def set(self, clock, ignorehash, notefiles):
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    89
        if clock is None:
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    90
            self.invalidate()
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    91
            return
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    92
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    93
        try:
30539
29b35dac3b1f fsmonitor: be robust in the face of bad state
Simon Farnsworth <simonfar@fb.com>
parents: 29205
diff changeset
    94
            file = self._opener('fsmonitor.state', 'wb', atomictemp=True)
28433
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    95
        except (IOError, OSError):
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    96
            self._ui.warn(_("warning: unable to write out fsmonitor state\n"))
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    97
            return
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    98
30539
29b35dac3b1f fsmonitor: be robust in the face of bad state
Simon Farnsworth <simonfar@fb.com>
parents: 29205
diff changeset
    99
        with file:
28433
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   100
            file.write(struct.pack(_versionformat, _version))
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   101
            file.write(socket.gethostname() + '\0')
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   102
            file.write(clock + '\0')
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   103
            file.write(ignorehash + '\0')
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   104
            if notefiles:
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   105
                file.write('\0'.join(notefiles))
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   106
                file.write('\0')
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   107
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   108
    def invalidate(self):
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   109
        try:
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   110
            os.unlink(os.path.join(self._rootdir, '.hg', 'fsmonitor.state'))
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   111
        except OSError as inst:
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   112
            if inst.errno != errno.ENOENT:
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   113
                raise
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   114
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   115
    def setlastclock(self, clock):
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   116
        self._lastclock = clock
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   117
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   118
    def getlastclock(self):
3b67f27bb908 fsmonitor: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
   119
        return self._lastclock