38 @param parent reference to the parent widget |
38 @param parent reference to the parent widget |
39 @type QWidget |
39 @type QWidget |
40 """ |
40 """ |
41 super().__init__(parent) |
41 super().__init__(parent) |
42 self.setupUi(self) |
42 self.setupUi(self) |
43 |
43 |
44 self.buttonBox.button( |
44 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False) |
45 QDialogButtonBox.StandardButton.Close).setEnabled(False) |
45 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True) |
46 self.buttonBox.button( |
46 |
47 QDialogButtonBox.StandardButton.Cancel).setDefault(True) |
|
48 |
|
49 self.__process = None |
47 self.__process = None |
50 self.__cmd = "" |
48 self.__cmd = "" |
51 |
49 |
52 self.__progs = [] |
50 self.__progs = [] |
53 if interpreter: |
51 if interpreter: |
54 self.__progs.append(interpreter) |
52 self.__progs.append(interpreter) |
55 self.__progs.extend([ |
53 self.__progs.extend( |
56 getPythonExecutable(), |
54 [ |
57 "python3", |
55 getPythonExecutable(), |
58 "python", |
56 "python3", |
59 ]) |
57 "python", |
|
58 ] |
|
59 ) |
60 self.__callIndex = 0 |
60 self.__callIndex = 0 |
61 self.__callArgs = [] |
61 self.__callArgs = [] |
62 |
62 |
63 self.__venvName = venvName |
63 self.__venvName = venvName |
64 self.__venvDirectory = "" |
64 self.__venvDirectory = "" |
65 self.__createLog = createLog |
65 self.__createLog = createLog |
66 self.__manager = venvManager |
66 self.__manager = venvManager |
67 |
67 |
68 def start(self, arguments): |
68 def start(self, arguments): |
69 """ |
69 """ |
70 Public slot to start the virtualenv command. |
70 Public slot to start the virtualenv command. |
71 |
71 |
72 @param arguments commandline arguments for virtualenv/pyvenv program |
72 @param arguments commandline arguments for virtualenv/pyvenv program |
73 (list of strings) |
73 (list of strings) |
74 """ |
74 """ |
75 if self.__callIndex == 0: |
75 if self.__callIndex == 0: |
76 # first attempt, add a given python interpreter and do |
76 # first attempt, add a given python interpreter and do |
77 # some other setup |
77 # some other setup |
78 self.errorGroup.hide() |
78 self.errorGroup.hide() |
79 self.contents.clear() |
79 self.contents.clear() |
80 self.errors.clear() |
80 self.errors.clear() |
81 |
81 |
82 self.__process = QProcess() |
82 self.__process = QProcess() |
83 self.__process.readyReadStandardOutput.connect(self.__readStdout) |
83 self.__process.readyReadStandardOutput.connect(self.__readStdout) |
84 self.__process.readyReadStandardError.connect(self.__readStderr) |
84 self.__process.readyReadStandardError.connect(self.__readStderr) |
85 self.__process.finished.connect(self.__finish) |
85 self.__process.finished.connect(self.__finish) |
86 |
86 |
87 self.__callArgs = arguments |
87 self.__callArgs = arguments |
88 self.__venvDirectory = arguments[-1] |
88 self.__venvDirectory = arguments[-1] |
89 |
89 |
90 prog = self.__progs[self.__callIndex] |
90 prog = self.__progs[self.__callIndex] |
91 self.__cmd = "{0} {1}".format(prog, " ".join(arguments)) |
91 self.__cmd = "{0} {1}".format(prog, " ".join(arguments)) |
92 self.__logOutput(self.tr("Executing: {0}\n").format( |
92 self.__logOutput(self.tr("Executing: {0}\n").format(self.__cmd)) |
93 self.__cmd)) |
|
94 self.__process.start(prog, arguments) |
93 self.__process.start(prog, arguments) |
95 procStarted = self.__process.waitForStarted(5000) |
94 procStarted = self.__process.waitForStarted(5000) |
96 if not procStarted: |
95 if not procStarted: |
97 self.__logOutput(self.tr("Failed\n\n")) |
96 self.__logOutput(self.tr("Failed\n\n")) |
98 self.__nextAttempt() |
97 self.__nextAttempt() |
99 |
98 |
100 def on_buttonBox_clicked(self, button): |
99 def on_buttonBox_clicked(self, button): |
101 """ |
100 """ |
102 Private slot called by a button of the button box clicked. |
101 Private slot called by a button of the button box clicked. |
103 |
102 |
104 @param button button that was clicked (QAbstractButton) |
103 @param button button that was clicked (QAbstractButton) |
105 """ |
104 """ |
106 if button == self.buttonBox.button( |
105 if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close): |
107 QDialogButtonBox.StandardButton.Close |
|
108 ): |
|
109 self.accept() |
106 self.accept() |
110 elif button == self.buttonBox.button( |
107 elif button == self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel): |
111 QDialogButtonBox.StandardButton.Cancel |
|
112 ): |
|
113 self.__finish(0, 0, giveUp=True) |
108 self.__finish(0, 0, giveUp=True) |
114 |
109 |
115 def __finish(self, exitCode, exitStatus, giveUp=False): |
110 def __finish(self, exitCode, exitStatus, giveUp=False): |
116 """ |
111 """ |
117 Private slot called when the process finished. |
112 Private slot called when the process finished. |
118 |
113 |
119 It is called when the process finished or |
114 It is called when the process finished or |
120 the user pressed the button. |
115 the user pressed the button. |
121 |
116 |
122 @param exitCode exit code of the process (integer) |
117 @param exitCode exit code of the process (integer) |
123 @param exitStatus exit status of the process (QProcess.ExitStatus) |
118 @param exitStatus exit status of the process (QProcess.ExitStatus) |
124 @param giveUp flag indicating to not start another attempt (boolean) |
119 @param giveUp flag indicating to not start another attempt (boolean) |
125 """ |
120 """ |
126 if ( |
121 if ( |
127 self.__process is not None and |
122 self.__process is not None |
128 self.__process.state() != QProcess.ProcessState.NotRunning |
123 and self.__process.state() != QProcess.ProcessState.NotRunning |
129 ): |
124 ): |
130 self.__process.terminate() |
125 self.__process.terminate() |
131 QTimer.singleShot(2000, self.__process.kill) |
126 QTimer.singleShot(2000, self.__process.kill) |
132 self.__process.waitForFinished(3000) |
127 self.__process.waitForFinished(3000) |
133 |
128 |
134 self.buttonBox.button( |
129 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True) |
135 QDialogButtonBox.StandardButton.Close).setEnabled(True) |
130 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False) |
136 self.buttonBox.button( |
131 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True) |
137 QDialogButtonBox.StandardButton.Cancel).setEnabled(False) |
132 |
138 self.buttonBox.button( |
|
139 QDialogButtonBox.StandardButton.Close).setDefault(True) |
|
140 |
|
141 if not giveUp: |
133 if not giveUp: |
142 if exitCode != 0: |
134 if exitCode != 0: |
143 self.__logOutput(self.tr("Failed\n\n")) |
135 self.__logOutput(self.tr("Failed\n\n")) |
144 if len(self.errors.toPlainText().splitlines()) == 1: |
136 if len(self.errors.toPlainText().splitlines()) == 1: |
145 self.errors.clear() |
137 self.errors.clear() |
146 self.errorGroup.hide() |
138 self.errorGroup.hide() |
147 self.__nextAttempt() |
139 self.__nextAttempt() |
148 return |
140 return |
149 |
141 |
150 self.__process = None |
142 self.__process = None |
151 |
143 |
152 self.__logOutput(self.tr('\npyvenv finished.\n')) |
144 self.__logOutput(self.tr("\npyvenv finished.\n")) |
153 |
145 |
154 if self.__createLog: |
146 if self.__createLog: |
155 self.__writeLogFile() |
147 self.__writeLogFile() |
156 |
148 |
157 self.__changeVirtualEnvironmentInterpreter() |
149 self.__changeVirtualEnvironmentInterpreter() |
158 |
150 |
159 def __nextAttempt(self): |
151 def __nextAttempt(self): |
160 """ |
152 """ |
161 Private method to start another attempt. |
153 Private method to start another attempt. |
162 """ |
154 """ |
163 self.__callIndex += 1 |
155 self.__callIndex += 1 |
164 if self.__callIndex < len(self.__progs): |
156 if self.__callIndex < len(self.__progs): |
165 self.start(self.__callArgs) |
157 self.start(self.__callArgs) |
166 else: |
158 else: |
167 self.__logError( |
159 self.__logError( |
168 self.tr('No suitable pyvenv program could be' |
160 self.tr("No suitable pyvenv program could be" " started.\n") |
169 ' started.\n')) |
161 ) |
170 self.__cmd = "" |
162 self.__cmd = "" |
171 self.__finish(0, 0, giveUp=True) |
163 self.__finish(0, 0, giveUp=True) |
172 |
164 |
173 def __readStdout(self): |
165 def __readStdout(self): |
174 """ |
166 """ |
175 Private slot to handle the readyReadStandardOutput signal. |
167 Private slot to handle the readyReadStandardOutput signal. |
176 |
168 |
177 It reads the output of the process, formats it and inserts it into |
169 It reads the output of the process, formats it and inserts it into |
178 the contents pane. |
170 the contents pane. |
179 """ |
171 """ |
180 self.__process.setReadChannel(QProcess.ProcessChannel.StandardOutput) |
172 self.__process.setReadChannel(QProcess.ProcessChannel.StandardOutput) |
181 |
173 |
182 while self.__process.canReadLine(): |
174 while self.__process.canReadLine(): |
183 s = str(self.__process.readLine(), |
175 s = str( |
184 Preferences.getSystem("IOEncoding"), |
176 self.__process.readLine(), |
185 'replace') |
177 Preferences.getSystem("IOEncoding"), |
|
178 "replace", |
|
179 ) |
186 self.__logOutput(s) |
180 self.__logOutput(s) |
187 |
181 |
188 def __readStderr(self): |
182 def __readStderr(self): |
189 """ |
183 """ |
190 Private slot to handle the readyReadStandardError signal. |
184 Private slot to handle the readyReadStandardError signal. |
191 |
185 |
192 It reads the error output of the process and inserts it into the |
186 It reads the error output of the process and inserts it into the |
193 error pane. |
187 error pane. |
194 """ |
188 """ |
195 self.__process.setReadChannel(QProcess.ProcessChannel.StandardError) |
189 self.__process.setReadChannel(QProcess.ProcessChannel.StandardError) |
196 |
190 |
197 while self.__process.canReadLine(): |
191 while self.__process.canReadLine(): |
198 s = str(self.__process.readLine(), |
192 s = str( |
199 Preferences.getSystem("IOEncoding"), |
193 self.__process.readLine(), |
200 'replace') |
194 Preferences.getSystem("IOEncoding"), |
|
195 "replace", |
|
196 ) |
201 self.__logError(s) |
197 self.__logError(s) |
202 |
198 |
203 def __logOutput(self, s): |
199 def __logOutput(self, s): |
204 """ |
200 """ |
205 Private method to log some output. |
201 Private method to log some output. |
206 |
202 |
207 @param s output string to log (string) |
203 @param s output string to log (string) |
208 """ |
204 """ |
209 self.contents.insertPlainText(s) |
205 self.contents.insertPlainText(s) |
210 self.contents.ensureCursorVisible() |
206 self.contents.ensureCursorVisible() |
211 |
207 |
212 def __logError(self, s): |
208 def __logError(self, s): |
213 """ |
209 """ |
214 Private method to log an error. |
210 Private method to log an error. |
215 |
211 |
216 @param s error string to log (string) |
212 @param s error string to log (string) |
217 """ |
213 """ |
218 self.errorGroup.show() |
214 self.errorGroup.show() |
219 self.errors.insertPlainText(s) |
215 self.errors.insertPlainText(s) |
220 self.errors.ensureCursorVisible() |
216 self.errors.ensureCursorVisible() |
221 |
217 |
222 def __writeLogFile(self): |
218 def __writeLogFile(self): |
223 """ |
219 """ |
224 Private method to write a log file to the virtualenv directory. |
220 Private method to write a log file to the virtualenv directory. |
225 """ |
221 """ |
226 outtxt = self.contents.toPlainText() |
222 outtxt = self.contents.toPlainText() |
227 logFile = os.path.join(self.__venvDirectory, "pyvenv_upgrade.log") |
223 logFile = os.path.join(self.__venvDirectory, "pyvenv_upgrade.log") |
228 self.__logOutput(self.tr("\nWriting log file '{0}'.\n") |
224 self.__logOutput(self.tr("\nWriting log file '{0}'.\n").format(logFile)) |
229 .format(logFile)) |
225 |
230 |
|
231 try: |
226 try: |
232 with open(logFile, "w", encoding="utf-8") as f: |
227 with open(logFile, "w", encoding="utf-8") as f: |
233 f.write(self.tr("Output:\n")) |
228 f.write(self.tr("Output:\n")) |
234 f.write(outtxt) |
229 f.write(outtxt) |
235 errtxt = self.errors.toPlainText() |
230 errtxt = self.errors.toPlainText() |