|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2010 - 2022 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 committed</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 not tracked</li> |
|
46 <li>"!" path is missing</li> |
|
47 <li>" " path is back at normal</li> |
|
48 </ul> |
|
49 |
|
50 @return tuple of flag indicating successful operation and a status |
|
51 message in case of non successful operation |
|
52 @rtype tuple of (bool, str) |
|
53 """ |
|
54 self.shouldUpdate = False |
|
55 |
|
56 ok, err = self.__initClient() |
|
57 if not ok: |
|
58 return False, err |
|
59 |
|
60 # step 1: get overall status |
|
61 args = self.vcs.initCommand("status") |
|
62 args.append('--noninteractive') |
|
63 args.append('--all') |
|
64 if self.vcs.hasSubrepositories(): |
|
65 args.append("--subrepos") |
|
66 |
|
67 output, error = self.__client.runcommand(args) |
|
68 |
|
69 if error: |
|
70 return False, error |
|
71 |
|
72 states = {} |
|
73 for line in output.splitlines(): |
|
74 if not line.startswith(" "): |
|
75 flag, name = line.split(" ", 1) |
|
76 if flag in "AMR?!": |
|
77 if flag == "R": |
|
78 status = "O" |
|
79 else: |
|
80 status = flag |
|
81 states[name] = status |
|
82 |
|
83 # step 2: get conflicting changes |
|
84 args = self.vcs.initCommand("resolve") |
|
85 args.append('--list') |
|
86 |
|
87 output, error = self.__client.runcommand(args) |
|
88 |
|
89 for line in output.splitlines(): |
|
90 flag, name = line.split(" ", 1) |
|
91 if flag == "U": |
|
92 states[name] = "Z" # conflict |
|
93 |
|
94 # step 3: collect the status to be reported back |
|
95 for name in states: |
|
96 try: |
|
97 if self.reportedStates[name] != states[name]: |
|
98 self.statusList.append( |
|
99 "{0} {1}".format(states[name], name)) |
|
100 except KeyError: |
|
101 self.statusList.append("{0} {1}".format(states[name], name)) |
|
102 for name in self.reportedStates: |
|
103 if name not in states: |
|
104 self.statusList.append(" {0}".format(name)) |
|
105 self.reportedStates = states |
|
106 |
|
107 return ( |
|
108 True, |
|
109 self.tr("Mercurial status checked successfully") |
|
110 ) |
|
111 |
|
112 def _getInfo(self): |
|
113 """ |
|
114 Protected method implementing the real info action. |
|
115 |
|
116 @return short info message |
|
117 @rtype str |
|
118 """ |
|
119 ok, err = self.__initClient() |
|
120 if not ok: |
|
121 return "" |
|
122 |
|
123 args = self.vcs.initCommand("identify") |
|
124 args.append('--num') |
|
125 args.append('--id') |
|
126 args.append('--branch') |
|
127 |
|
128 output, error = self.__client.runcommand(args) |
|
129 |
|
130 if error: |
|
131 # ignore errors |
|
132 return "" |
|
133 |
|
134 globalRev, localRev, branch = output.splitlines()[0].split(None, 2) |
|
135 if globalRev.endswith("+"): |
|
136 globalRev = globalRev[:-1] |
|
137 if localRev.endswith("+"): |
|
138 localRev = localRev[:-1] |
|
139 |
|
140 return self.tr("{0} / {1}:{2}", "branch, local id, global id").format( |
|
141 branch, localRev, globalRev) |
|
142 |
|
143 def _shutdown(self): |
|
144 """ |
|
145 Protected method performing shutdown actions. |
|
146 """ |
|
147 if self.__client: |
|
148 self.__client.stopServer() |
|
149 |
|
150 def __initClient(self): |
|
151 """ |
|
152 Private method to initialize the Mercurial client. |
|
153 |
|
154 @return tuple containing an OK flag and potentially an error message |
|
155 @rtype tuple of (bool, str) |
|
156 """ |
|
157 if self.__client is None: |
|
158 from .HgClient import HgClient |
|
159 client = HgClient(self.projectDir, "utf-8", self.vcs) |
|
160 ok, err = client.startServer() |
|
161 if ok: |
|
162 self.__client = client |
|
163 else: |
|
164 ok = True |
|
165 err = "" |
|
166 |
|
167 return ok, err |