|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2006 - 2009 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the VCS status monitor thread base class. |
|
8 """ |
|
9 |
|
10 import os |
|
11 |
|
12 from PyQt4.QtCore import QThread, QMutex, QMutexLocker, QWaitCondition, SIGNAL |
|
13 |
|
14 class VcsStatusMonitorThread(QThread): |
|
15 """ |
|
16 Class implementing the VCS status monitor thread base class. |
|
17 |
|
18 @signal vcsStatusMonitorData(QStringList) emitted to update the VCS status |
|
19 @signal vcsStatusMonitorStatus(QString, QString) emitted to signal the status of the |
|
20 monitoring thread (ok, nok, op) and a status message |
|
21 """ |
|
22 def __init__(self, interval, projectDir, vcs, parent = None): |
|
23 """ |
|
24 Constructor |
|
25 |
|
26 @param interval new interval in seconds (integer) |
|
27 @param projectDir project directory to monitor (string) |
|
28 @param vcs reference to the version control object |
|
29 @param parent reference to the parent object (QObject) |
|
30 """ |
|
31 QThread.__init__(self, parent) |
|
32 self.setObjectName("VcsStatusMonitorThread") |
|
33 |
|
34 self.setTerminationEnabled(True) |
|
35 |
|
36 self.projectDir = projectDir |
|
37 self.vcs = vcs |
|
38 |
|
39 self.interval = interval |
|
40 self.autoUpdate = False |
|
41 |
|
42 self.statusList = [] |
|
43 self.reportedStates = {} |
|
44 self.shouldUpdate = False |
|
45 |
|
46 self.monitorMutex = QMutex() |
|
47 self.monitorCondition = QWaitCondition() |
|
48 self.__stopIt = False |
|
49 |
|
50 def run(self): |
|
51 """ |
|
52 Protected method implementing the tasks action. |
|
53 """ |
|
54 while not self.__stopIt: |
|
55 # perform the checking task |
|
56 self.statusList = [] |
|
57 self.emit(SIGNAL("vcsStatusMonitorStatus(QString, QString)"), |
|
58 "wait", self.trUtf8("Waiting for lock")) |
|
59 try: |
|
60 locked = self.vcs.vcsExecutionMutex.tryLock(5000) |
|
61 except TypeError: |
|
62 locked = self.vcs.vcsExecutionMutex.tryLock() |
|
63 if locked: |
|
64 try: |
|
65 self.emit(SIGNAL("vcsStatusMonitorStatus(QString, QString)"), |
|
66 "op", self.trUtf8("Checking repository status")) |
|
67 res, statusMsg = self._performMonitor() |
|
68 finally: |
|
69 self.vcs.vcsExecutionMutex.unlock() |
|
70 if res: |
|
71 status = "ok" |
|
72 else: |
|
73 status = "nok" |
|
74 self.emit(SIGNAL("vcsStatusMonitorStatus(QString, QString)"), |
|
75 "send", self.trUtf8("Sending data")) |
|
76 self.emit(SIGNAL("vcsStatusMonitorData(QStringList)"), |
|
77 self.statusList) |
|
78 self.emit(SIGNAL("vcsStatusMonitorStatus(QString, QString)"), |
|
79 status, statusMsg) |
|
80 else: |
|
81 self.emit(SIGNAL("vcsStatusMonitorStatus(QString, QString)"), |
|
82 "timeout", self.trUtf8("Timed out waiting for lock")) |
|
83 |
|
84 if self.autoUpdate and self.shouldUpdate: |
|
85 try: |
|
86 self.vcs.vcsUpdate(self.projectDir, True) |
|
87 continue # check again |
|
88 except TypeError: |
|
89 pass # compatibility for older VCS plugins |
|
90 self.shouldUpdate = False |
|
91 |
|
92 # wait until interval has expired checking for a stop condition |
|
93 self.monitorMutex.lock() |
|
94 if not self.__stopIt: |
|
95 self.monitorCondition.wait(self.monitorMutex, self.interval * 1000) |
|
96 self.monitorMutex.unlock() |
|
97 |
|
98 self.exit() |
|
99 |
|
100 def setInterval(self, interval): |
|
101 """ |
|
102 Public method to change the monitor interval. |
|
103 |
|
104 @param interval new interval in seconds (integer) |
|
105 """ |
|
106 locked = self.monitorMutex.tryLock() |
|
107 self.interval = interval |
|
108 self.monitorCondition.wakeAll() |
|
109 if locked: |
|
110 self.monitorMutex.unlock() |
|
111 |
|
112 def getInterval(self): |
|
113 """ |
|
114 Public method to get the monitor interval. |
|
115 |
|
116 @return interval in seconds (integer) |
|
117 """ |
|
118 return self.interval |
|
119 |
|
120 def setAutoUpdate(self, auto): |
|
121 """ |
|
122 Public method to enable the auto update function. |
|
123 |
|
124 @param auto status of the auto update function (boolean) |
|
125 """ |
|
126 self.autoUpdate = auto |
|
127 |
|
128 def getAutoUpdate(self): |
|
129 """ |
|
130 Public method to retrieve the status of the auto update function. |
|
131 |
|
132 @return status of the auto update function (boolean) |
|
133 """ |
|
134 return self.autoUpdate |
|
135 |
|
136 def checkStatus(self): |
|
137 """ |
|
138 Public method to wake up the status monitor thread. |
|
139 """ |
|
140 locked = self.monitorMutex.tryLock() |
|
141 self.monitorCondition.wakeAll() |
|
142 if locked: |
|
143 self.monitorMutex.unlock() |
|
144 |
|
145 def stop(self): |
|
146 """ |
|
147 Public method to stop the monitor thread. |
|
148 """ |
|
149 locked = self.monitorMutex.tryLock() |
|
150 self.__stopIt = True |
|
151 self.monitorCondition.wakeAll() |
|
152 if locked: |
|
153 self.monitorMutex.unlock() |
|
154 |
|
155 def clearCachedState(self, name): |
|
156 """ |
|
157 Public method to clear the cached VCS state of a file/directory. |
|
158 |
|
159 @param name name of the entry to be cleared (string) |
|
160 """ |
|
161 key = name.replace(self.projectDir + os.sep, '') |
|
162 try: |
|
163 del self.reportedStates[key] |
|
164 except KeyError: |
|
165 pass |
|
166 |
|
167 def _performMonitor(self): |
|
168 """ |
|
169 Protected method implementing the real monitoring action. |
|
170 |
|
171 This method must be overridden and populate the statusList member variable |
|
172 with a list of strings giving the status in the first column and the |
|
173 path relative to the project directory starting with the third column. |
|
174 The allowed status flags are: |
|
175 <ul> |
|
176 <li>"A" path was added but not yet comitted</li> |
|
177 <li>"M" path has local changes</li> |
|
178 <li>"R" path was deleted and then re-added</li> |
|
179 <li>"U" path needs an update</li> |
|
180 <li>"Z" path contains a conflict</li> |
|
181 <li>" " path is back at normal</li> |
|
182 </ul> |
|
183 |
|
184 @return tuple of flag indicating successful operation (boolean) and |
|
185 a status message in case of non successful operation (QString) |
|
186 """ |
|
187 raise RuntimeError('Not implemented') |