CxFreeze/CxfreezeExecDialog.py

changeset 56
c8a47a8536b0
parent 47
986f27beaad4
child 60
8bf1407ebc46
equal deleted inserted replaced
55:f8f333fffe81 56:c8a47a8536b0
11 try: 11 try:
12 str = unicode # __IGNORE_WARNING__ 12 str = unicode # __IGNORE_WARNING__
13 except (NameError): 13 except (NameError):
14 pass 14 pass
15 15
16 import shutil
17 import errno
18 import fnmatch
16 import os.path 19 import os.path
17 20
18 from PyQt4.QtCore import pyqtSlot, QProcess, QTimer 21 from PyQt4.QtCore import pyqtSlot, QProcess, QTimer, QThread, pyqtSignal
19 from PyQt4.QtGui import QDialog, QDialogButtonBox, QAbstractButton 22 from PyQt4.QtGui import QDialog, QDialogButtonBox, QAbstractButton
20 23
21 from E5Gui import E5MessageBox 24 from E5Gui import E5MessageBox
22 25
23 from .Ui_CxfreezeExecDialog import Ui_CxfreezeExecDialog 26 from .Ui_CxfreezeExecDialog import Ui_CxfreezeExecDialog
43 46
44 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False) 47 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
45 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) 48 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
46 49
47 self.process = None 50 self.process = None
51 self.copyProcess = None
48 self.cmdname = cmdname 52 self.cmdname = cmdname
49 53
50 def start(self, args, script): 54 def start(self, args, parms, ppath, mainscript):
51 """ 55 """
52 Public slot to start the packager command. 56 Public slot to start the packager command.
53 57
54 @param args commandline arguments for packager program (list of strings) 58 @param args commandline arguments for packager program (list of strings)
59 @param parms parameters got from the config dialog (dict)
60 @param ppath project path (string)
55 @param script main script name to be processed by by the packager (string) 61 @param script main script name to be processed by by the packager (string)
56 @return flag indicating the successful start of the process 62 @return flag indicating the successful start of the process
57 """ 63 """
58 self.errorGroup.hide() 64 self.errorGroup.hide()
59 65 script = os.path.join(ppath, mainscript)
60 dname = os.path.dirname(script) 66 dname = os.path.dirname(script)
61 script = os.path.basename(script) 67 script = os.path.basename(script)
62 68
69 self.ppath = ppath
70 self.additionalFiles = parms.get('additionalFiles', [])
71 self.targetDirectory = os.path.join(parms.get('targetDirectory', 'dist'))
72
63 self.contents.clear() 73 self.contents.clear()
64 self.errors.clear() 74 self.errors.clear()
65 75
66 args.append(script) 76 args.append(script)
67 77
68 self.process = QProcess() 78 self.process = QProcess()
69 self.process.setWorkingDirectory(dname) 79 self.process.setWorkingDirectory(dname)
70 80
71 self.process.readyReadStandardOutput.connect(self.__readStdout) 81 self.process.readyReadStandardOutput.connect(self.__readStdout)
72 self.process.readyReadStandardError.connect(self.__readStderr) 82 self.process.readyReadStandardError.connect(self.__readStderr)
73 self.process.finished.connect(self.__finish) 83 self.process.finished.connect(self.__finishedFreeze)
74 84
75 self.setWindowTitle(self.trUtf8('{0} - {1}').format(self.cmdname, script)) 85 self.setWindowTitle(self.trUtf8('{0} - {1}').format(self.cmdname, script))
76 self.contents.insertPlainText(' '.join(args) + '\n\n') 86 self.contents.insertPlainText(' '.join(args) + '\n\n')
77 self.contents.ensureCursorVisible() 87 self.contents.ensureCursorVisible()
78 88
96 @param button button that was clicked (QAbstractButton) 106 @param button button that was clicked (QAbstractButton)
97 """ 107 """
98 if button == self.buttonBox.button(QDialogButtonBox.Close): 108 if button == self.buttonBox.button(QDialogButtonBox.Close):
99 self.accept() 109 self.accept()
100 elif button == self.buttonBox.button(QDialogButtonBox.Cancel): 110 elif button == self.buttonBox.button(QDialogButtonBox.Cancel):
111 self.additionalFiles = [] # Skip copying additional files
101 self.__finish() 112 self.__finish()
102 113
103 def __finish(self): 114 def __finish(self):
104 """ 115 """
105 Private slot called when the process finished. 116 Private slot called when the process finished.
106 117
107 It is called when the process finished or 118 It is called when the process finished or
108 the user pressed the cancel button. 119 the user pressed the cancel button.
109 """ 120 """
110 if self.process is not None and \ 121 if self.process is not None:
111 self.process.state() != QProcess.NotRunning: 122 self.process.disconnect(self.__finishedFreeze)
112 self.process.terminate() 123 self.process.terminate()
113 QTimer.singleShot(2000, self.process.kill) 124 QTimer.singleShot(2000, self.process.kill)
114 self.process.waitForFinished(3000) 125 self.process.waitForFinished(3000)
115 126 self.process = None
127
128 if self.copyProcess is not None:
129 self.copyProcess.terminate()
130 self.copyProcess = None
131
132 self.contents.insertPlainText(
133 self.trUtf8('\n{0} aborted.\n').format(self.cmdname))
134
135 self.__enableButtons()
136
137 def __finishedFreeze(self):
138 """
139 Private slot called when the process finished.
140
141 It is called when the process finished or
142 the user pressed the cancel button.
143 """
144 self.process = None
145
146 self.contents.insertPlainText(
147 self.trUtf8('\n{0} finished.\n').format(self.cmdname))
148
149 self.copyProcess = copyAdditionalFiles(self)
150 self.copyProcess.insertPlainText.connect(self.contents.insertPlainText)
151 self.copyProcess.finished.connect(self.__enableButtons)
152 self.copyProcess.start()
153
154 def __enableButtons(self):
155 """
156 Private slot called when all processes finished.
157
158 It is called when the process finished or
159 the user pressed the cancel button.
160 """
161 self.copyProcess = None
116 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) 162 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
117 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) 163 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
118 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) 164 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
119
120 self.process = None
121
122 self.contents.insertPlainText(
123 self.trUtf8('\n{0} finished.\n').format(self.cmdname))
124 self.contents.ensureCursorVisible() 165 self.contents.ensureCursorVisible()
125 166
126 def __readStdout(self): 167 def __readStdout(self):
127 """ 168 """
128 Private slot to handle the readyReadStandardOutput signal. 169 Private slot to handle the readyReadStandardOutput signal.
129 170
130 It reads the output of the process, formats it and inserts it into 171 It reads the output of the process, formats it and inserts it into
153 s = str(self.process.readAllStandardError(), 194 s = str(self.process.readAllStandardError(),
154 Preferences.getSystem("IOEncoding"), 195 Preferences.getSystem("IOEncoding"),
155 'replace') 196 'replace')
156 self.errors.insertPlainText(s) 197 self.errors.insertPlainText(s)
157 self.errors.ensureCursorVisible() 198 self.errors.ensureCursorVisible()
199
200
201 class copyAdditionalFiles(QThread):
202 """
203 Thread to copy the distribution dependend files.
204
205 @signal insertPlainText(text) emitted to inform user about the copy progress
206 """
207 insertPlainText = pyqtSignal(str)
208
209 def __init__(self, main):
210 """
211 Constructor, which stores the needed variables.
212
213 @param main self-object of the caller
214 """
215 super(copyAdditionalFiles, self).__init__()
216
217 self.ppath = main.ppath
218 self.additionalFiles = main.additionalFiles
219 self.targetDirectory = main.targetDirectory
220
221 def __copytree(self, src, dst):
222 """
223 Copies a file or folder. Wildcards allowed. Existing files are overwitten.
224
225 @param src source file or folder to copy. Wildcards allowed. (str)
226 @param dst destination (str)
227 """
228 def src2dst(srcname, base, dst):
229 """
230 Combines the relativ path of the source (srcname) with the
231 destination folder.
232
233 @param srcname actual file or folder to copy
234 @param base basename of the source folder
235 @param dst basename of the destination folder
236 @return destination path
237 """
238 delta = srcname.split(base)[1]
239 return os.path.join(dst, delta[1:])
240
241 base, fileOrFolderName = os.path.split(src)
242 initDone = False
243 for root, dirs, files in os.walk(base):
244 copied = False
245 # remove all none matching directorynames, create all others
246 for dir in dirs[:]:
247 pathname = os.path.join(root, dir)
248 if initDone or fnmatch.fnmatch(pathname, src):
249 newDir = src2dst(pathname, base, dst)
250 # avoid infinit loop
251 if fnmatch.fnmatch(newDir, src):
252 dirs.remove(dir)
253 continue
254 try:
255 copied = True
256 os.makedirs(newDir)
257 except OSError as err:
258 if err.errno != errno.EEXIST: # it's ok if directory already exists
259 raise err
260 else:
261 dirs.remove(dir)
262
263 for file in files:
264 fn = os.path.join(root, file)
265 if initDone or fnmatch.fnmatch(fn, src):
266 newFile = src2dst(fn, base, dst)
267 # copy files, give errors to caller
268 shutil.copy2(fn, newFile)
269 copied = True
270
271 # check if file was found and copied
272 if len(files) and not copied:
273 raise IOError(errno.ENOENT,
274 self.trUtf8("No such file or directory: '{0}'").format(src))
275
276 initDone = True
277
278 def run(self):
279 """
280 QThread entry point to copy the selected additional files and folders.
281 """
282 self.insertPlainText.emit('----\n')
283 os.chdir(self.ppath)
284 for fn in self.additionalFiles:
285 self.insertPlainText.emit(
286 self.trUtf8('\nCopying {0}: ').format(fn))
287
288 # on linux normpath doesn't replace backslashes to slashes.
289 fn = fn.replace('\\', '/')
290 fn = os.path.abspath(os.path.normpath(fn))
291 dst = os.path.join(self.ppath, self.targetDirectory)
292 if fn.startswith(os.path.normpath(self.ppath)):
293 dirname = fn.split(self.ppath+os.sep)[1]
294 dst = os.path.join(dst, os.path.dirname(dirname))
295 try:
296 os.makedirs(dst)
297 except OSError as err:
298 if err.errno != errno.EEXIST: # it's ok if directory already exists
299 raise err
300
301 try:
302 self.__copytree(fn, dst)
303 self.insertPlainText.emit(self.trUtf8('ok'))
304 except IOError as err:
305 self.insertPlainText.emit(self.trUtf8('failed: {0}').format(err.strerror))

eric ide

mercurial