Show More
@@ -1,119 +1,119 b'' | |||||
1 | # state.py - fsmonitor persistent state |
|
1 | # state.py - fsmonitor persistent state | |
2 | # |
|
2 | # | |
3 | # Copyright 2013-2016 Facebook, Inc. |
|
3 | # Copyright 2013-2016 Facebook, Inc. | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms of the |
|
5 | # This software may be used and distributed according to the terms of the | |
6 | # GNU General Public License version 2 or any later version. |
|
6 | # GNU General Public License version 2 or any later version. | |
7 |
|
7 | |||
8 | from __future__ import absolute_import |
|
8 | from __future__ import absolute_import | |
9 |
|
9 | |||
10 | import errno |
|
10 | import errno | |
11 | import os |
|
11 | import os | |
12 | import socket |
|
12 | import socket | |
13 | import struct |
|
13 | import struct | |
14 |
|
14 | |||
15 | from mercurial.i18n import _ |
|
15 | from mercurial.i18n import _ | |
16 | from mercurial import pathutil |
|
16 | from mercurial import pathutil | |
17 |
|
17 | |||
18 | _version = 4 |
|
18 | _version = 4 | |
19 | _versionformat = ">I" |
|
19 | _versionformat = ">I" | |
20 |
|
20 | |||
21 | class state(object): |
|
21 | class state(object): | |
22 | def __init__(self, repo): |
|
22 | def __init__(self, repo): | |
23 |
self._ |
|
23 | self._vfs = repo.vfs | |
24 | self._ui = repo.ui |
|
24 | self._ui = repo.ui | |
25 | self._rootdir = pathutil.normasprefix(repo.root) |
|
25 | self._rootdir = pathutil.normasprefix(repo.root) | |
26 | self._lastclock = None |
|
26 | self._lastclock = None | |
27 |
|
27 | |||
28 | self.mode = self._ui.config('fsmonitor', 'mode', default='on') |
|
28 | self.mode = self._ui.config('fsmonitor', 'mode', default='on') | |
29 | self.walk_on_invalidate = self._ui.configbool( |
|
29 | self.walk_on_invalidate = self._ui.configbool( | |
30 | 'fsmonitor', 'walk_on_invalidate', False) |
|
30 | 'fsmonitor', 'walk_on_invalidate', False) | |
31 | self.timeout = float(self._ui.config( |
|
31 | self.timeout = float(self._ui.config( | |
32 | 'fsmonitor', 'timeout', default='2')) |
|
32 | 'fsmonitor', 'timeout', default='2')) | |
33 |
|
33 | |||
34 | def get(self): |
|
34 | def get(self): | |
35 | try: |
|
35 | try: | |
36 |
file = self._ |
|
36 | file = self._vfs('fsmonitor.state', 'rb') | |
37 | except IOError as inst: |
|
37 | except IOError as inst: | |
38 | if inst.errno != errno.ENOENT: |
|
38 | if inst.errno != errno.ENOENT: | |
39 | raise |
|
39 | raise | |
40 | return None, None, None |
|
40 | return None, None, None | |
41 |
|
41 | |||
42 | versionbytes = file.read(4) |
|
42 | versionbytes = file.read(4) | |
43 | if len(versionbytes) < 4: |
|
43 | if len(versionbytes) < 4: | |
44 | self._ui.log( |
|
44 | self._ui.log( | |
45 | 'fsmonitor', 'fsmonitor: state file only has %d bytes, ' |
|
45 | 'fsmonitor', 'fsmonitor: state file only has %d bytes, ' | |
46 | 'nuking state\n' % len(versionbytes)) |
|
46 | 'nuking state\n' % len(versionbytes)) | |
47 | self.invalidate() |
|
47 | self.invalidate() | |
48 | return None, None, None |
|
48 | return None, None, None | |
49 | try: |
|
49 | try: | |
50 | diskversion = struct.unpack(_versionformat, versionbytes)[0] |
|
50 | diskversion = struct.unpack(_versionformat, versionbytes)[0] | |
51 | if diskversion != _version: |
|
51 | if diskversion != _version: | |
52 | # different version, nuke state and start over |
|
52 | # different version, nuke state and start over | |
53 | self._ui.log( |
|
53 | self._ui.log( | |
54 | 'fsmonitor', 'fsmonitor: version switch from %d to ' |
|
54 | 'fsmonitor', 'fsmonitor: version switch from %d to ' | |
55 | '%d, nuking state\n' % (diskversion, _version)) |
|
55 | '%d, nuking state\n' % (diskversion, _version)) | |
56 | self.invalidate() |
|
56 | self.invalidate() | |
57 | return None, None, None |
|
57 | return None, None, None | |
58 |
|
58 | |||
59 | state = file.read().split('\0') |
|
59 | state = file.read().split('\0') | |
60 | # state = hostname\0clock\0ignorehash\0 + list of files, each |
|
60 | # state = hostname\0clock\0ignorehash\0 + list of files, each | |
61 | # followed by a \0 |
|
61 | # followed by a \0 | |
62 | if len(state) < 3: |
|
62 | if len(state) < 3: | |
63 | self._ui.log( |
|
63 | self._ui.log( | |
64 | 'fsmonitor', 'fsmonitor: state file truncated (expected ' |
|
64 | 'fsmonitor', 'fsmonitor: state file truncated (expected ' | |
65 | '3 chunks, found %d), nuking state\n', len(state)) |
|
65 | '3 chunks, found %d), nuking state\n', len(state)) | |
66 | self.invalidate() |
|
66 | self.invalidate() | |
67 | return None, None, None |
|
67 | return None, None, None | |
68 | diskhostname = state[0] |
|
68 | diskhostname = state[0] | |
69 | hostname = socket.gethostname() |
|
69 | hostname = socket.gethostname() | |
70 | if diskhostname != hostname: |
|
70 | if diskhostname != hostname: | |
71 | # file got moved to a different host |
|
71 | # file got moved to a different host | |
72 | self._ui.log('fsmonitor', 'fsmonitor: stored hostname "%s" ' |
|
72 | self._ui.log('fsmonitor', 'fsmonitor: stored hostname "%s" ' | |
73 | 'different from current "%s", nuking state\n' % |
|
73 | 'different from current "%s", nuking state\n' % | |
74 | (diskhostname, hostname)) |
|
74 | (diskhostname, hostname)) | |
75 | self.invalidate() |
|
75 | self.invalidate() | |
76 | return None, None, None |
|
76 | return None, None, None | |
77 |
|
77 | |||
78 | clock = state[1] |
|
78 | clock = state[1] | |
79 | ignorehash = state[2] |
|
79 | ignorehash = state[2] | |
80 | # discard the value after the last \0 |
|
80 | # discard the value after the last \0 | |
81 | notefiles = state[3:-1] |
|
81 | notefiles = state[3:-1] | |
82 |
|
82 | |||
83 | finally: |
|
83 | finally: | |
84 | file.close() |
|
84 | file.close() | |
85 |
|
85 | |||
86 | return clock, ignorehash, notefiles |
|
86 | return clock, ignorehash, notefiles | |
87 |
|
87 | |||
88 | def set(self, clock, ignorehash, notefiles): |
|
88 | def set(self, clock, ignorehash, notefiles): | |
89 | if clock is None: |
|
89 | if clock is None: | |
90 | self.invalidate() |
|
90 | self.invalidate() | |
91 | return |
|
91 | return | |
92 |
|
92 | |||
93 | try: |
|
93 | try: | |
94 |
file = self._ |
|
94 | file = self._vfs('fsmonitor.state', 'wb', atomictemp=True) | |
95 | except (IOError, OSError): |
|
95 | except (IOError, OSError): | |
96 | self._ui.warn(_("warning: unable to write out fsmonitor state\n")) |
|
96 | self._ui.warn(_("warning: unable to write out fsmonitor state\n")) | |
97 | return |
|
97 | return | |
98 |
|
98 | |||
99 | with file: |
|
99 | with file: | |
100 | file.write(struct.pack(_versionformat, _version)) |
|
100 | file.write(struct.pack(_versionformat, _version)) | |
101 | file.write(socket.gethostname() + '\0') |
|
101 | file.write(socket.gethostname() + '\0') | |
102 | file.write(clock + '\0') |
|
102 | file.write(clock + '\0') | |
103 | file.write(ignorehash + '\0') |
|
103 | file.write(ignorehash + '\0') | |
104 | if notefiles: |
|
104 | if notefiles: | |
105 | file.write('\0'.join(notefiles)) |
|
105 | file.write('\0'.join(notefiles)) | |
106 | file.write('\0') |
|
106 | file.write('\0') | |
107 |
|
107 | |||
108 | def invalidate(self): |
|
108 | def invalidate(self): | |
109 | try: |
|
109 | try: | |
110 | os.unlink(os.path.join(self._rootdir, '.hg', 'fsmonitor.state')) |
|
110 | os.unlink(os.path.join(self._rootdir, '.hg', 'fsmonitor.state')) | |
111 | except OSError as inst: |
|
111 | except OSError as inst: | |
112 | if inst.errno != errno.ENOENT: |
|
112 | if inst.errno != errno.ENOENT: | |
113 | raise |
|
113 | raise | |
114 |
|
114 | |||
115 | def setlastclock(self, clock): |
|
115 | def setlastclock(self, clock): | |
116 | self._lastclock = clock |
|
116 | self._lastclock = clock | |
117 |
|
117 | |||
118 | def getlastclock(self): |
|
118 | def getlastclock(self): | |
119 | return self._lastclock |
|
119 | return self._lastclock |
General Comments 0
You need to be logged in to leave comments.
Login now