|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2010 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the VCS status monitor thread class for Mercurial. |
|
8 """ |
|
9 |
|
10 from VCS.StatusMonitorThread import VcsStatusMonitorThread |
|
11 |
|
12 |
|
13 class HgStatusMonitorThread(VcsStatusMonitorThread): |
|
14 """ |
|
15 Class implementing the VCS status monitor thread class for Mercurial. |
|
16 """ |
|
17 def __init__(self, interval, project, vcs, parent=None): |
|
18 """ |
|
19 Constructor |
|
20 |
|
21 @param interval new interval in seconds (integer) |
|
22 @param project reference to the project object (Project) |
|
23 @param vcs reference to the version control object |
|
24 @param parent reference to the parent object (QObject) |
|
25 """ |
|
26 VcsStatusMonitorThread.__init__(self, interval, project, vcs, parent) |
|
27 |
|
28 self.__client = None |
|
29 |
|
30 def _performMonitor(self): |
|
31 """ |
|
32 Protected method implementing the monitoring action. |
|
33 |
|
34 This method populates the statusList member variable with a list of |
|
35 strings giving the status in the first column and the path relative |
|
36 to the project directory starting with the third column. The allowed |
|
37 status flags are: |
|
38 <ul> |
|
39 <li>"A" path was added but not yet comitted</li> |
|
40 <li>"M" path has local changes</li> |
|
41 <li>"O" path was removed</li> |
|
42 <li>"R" path was deleted and then re-added</li> |
|
43 <li>"U" path needs an update</li> |
|
44 <li>"Z" path contains a conflict</li> |
|
45 <li>" " path is back at normal</li> |
|
46 </ul> |
|
47 |
|
48 @return tuple of flag indicating successful operation and a status |
|
49 message in case of non successful operation |
|
50 @rtype tuple of (bool, str) |
|
51 """ |
|
52 self.shouldUpdate = False |
|
53 |
|
54 ok, err = self.__initClient() |
|
55 if not ok: |
|
56 return False, err |
|
57 |
|
58 # step 1: get overall status |
|
59 args = self.vcs.initCommand("status") |
|
60 args.append('--noninteractive') |
|
61 args.append('--all') |
|
62 |
|
63 output, error = self.__client.runcommand(args) |
|
64 |
|
65 if error: |
|
66 return False, error |
|
67 |
|
68 states = {} |
|
69 for line in output.splitlines(): |
|
70 if not line.startswith(" "): |
|
71 flag, name = line.split(" ", 1) |
|
72 if flag in "AMR": |
|
73 if flag == "R": |
|
74 status = "O" |
|
75 else: |
|
76 status = flag |
|
77 states[name] = status |
|
78 |
|
79 # step 2: get conflicting changes |
|
80 args = self.vcs.initCommand("resolve") |
|
81 args.append('--list') |
|
82 |
|
83 output, error = self.__client.runcommand(args) |
|
84 |
|
85 for line in output.splitlines(): |
|
86 flag, name = line.split(" ", 1) |
|
87 if flag == "U": |
|
88 states[name] = "Z" # conflict |
|
89 |
|
90 # step 3: collect the status to be reported back |
|
91 for name in states: |
|
92 try: |
|
93 if self.reportedStates[name] != states[name]: |
|
94 self.statusList.append( |
|
95 "{0} {1}".format(states[name], name)) |
|
96 except KeyError: |
|
97 self.statusList.append("{0} {1}".format(states[name], name)) |
|
98 for name in self.reportedStates: |
|
99 if name not in states: |
|
100 self.statusList.append(" {0}".format(name)) |
|
101 self.reportedStates = states |
|
102 |
|
103 return ( |
|
104 True, |
|
105 self.tr("Mercurial status checked successfully") |
|
106 ) |
|
107 |
|
108 def _getInfo(self): |
|
109 """ |
|
110 Protected method implementing the real info action. |
|
111 |
|
112 @return short info message |
|
113 @rtype str |
|
114 """ |
|
115 ok, err = self.__initClient() |
|
116 if not ok: |
|
117 return "" |
|
118 |
|
119 args = self.vcs.initCommand("identify") |
|
120 args.append('--num') |
|
121 args.append('--id') |
|
122 args.append('--branch') |
|
123 |
|
124 output, error = self.__client.runcommand(args) |
|
125 |
|
126 if error: |
|
127 # ignore errors |
|
128 return "" |
|
129 |
|
130 globalRev, localRev, branch = output.splitlines()[0].split(None, 2) |
|
131 if globalRev.endswith("+"): |
|
132 globalRev = globalRev[:-1] |
|
133 if localRev.endswith("+"): |
|
134 localRev = localRev[:-1] |
|
135 |
|
136 return self.tr("{0} / {1}:{2}", "branch, local id, global id").format( |
|
137 branch, localRev, globalRev) |
|
138 |
|
139 def _shutdown(self): |
|
140 """ |
|
141 Protected method performing shutdown actions. |
|
142 """ |
|
143 if self.__client: |
|
144 self.__client.stopServer() |
|
145 |
|
146 def __initClient(self): |
|
147 """ |
|
148 Private method to initialize the Mercurial client. |
|
149 |
|
150 @return tuple containing an OK flag and potentially an error message |
|
151 @rtype tuple of (bool, str) |
|
152 """ |
|
153 if self.__client is None: |
|
154 from .HgClient import HgClient |
|
155 client = HgClient(self.projectDir, "utf-8", self.vcs) |
|
156 ok, err = client.startServer() |
|
157 if ok: |
|
158 self.__client = client |
|
159 else: |
|
160 ok = True |
|
161 err = "" |
|
162 |
|
163 return ok, err |