diff options
Diffstat (limited to 'utils/common/deploy.py')
-rwxr-xr-x | utils/common/deploy.py | 110 |
1 files changed, 97 insertions, 13 deletions
diff --git a/utils/common/deploy.py b/utils/common/deploy.py index 662a104e34..9912bfc2ca 100755 --- a/utils/common/deploy.py +++ b/utils/common/deploy.py | |||
@@ -82,6 +82,25 @@ useupx = False | |||
82 | # OS X: files to copy into the bundle. Workaround for out-of-tree builds. | 82 | # OS X: files to copy into the bundle. Workaround for out-of-tree builds. |
83 | bundlecopy = { } | 83 | bundlecopy = { } |
84 | 84 | ||
85 | # DLL files to ignore when searching for required DLL files. | ||
86 | systemdlls = ['advapi32.dll', | ||
87 | 'comdlg32.dll', | ||
88 | 'gdi32.dll', | ||
89 | 'imm32.dll', | ||
90 | 'kernel32.dll', | ||
91 | 'msvcrt.dll', | ||
92 | 'msvcrt.dll', | ||
93 | 'netapi32.dll', | ||
94 | 'ole32.dll', | ||
95 | 'oleaut32.dll', | ||
96 | 'setupapi.dll', | ||
97 | 'shell32.dll', | ||
98 | 'user32.dll', | ||
99 | 'winmm.dll', | ||
100 | 'winspool.drv', | ||
101 | 'ws2_32.dll'] | ||
102 | |||
103 | |||
85 | # == Functions == | 104 | # == Functions == |
86 | def usage(myself): | 105 | def usage(myself): |
87 | print "Usage: %s [options]" % myself | 106 | print "Usage: %s [options]" % myself |
@@ -238,19 +257,22 @@ def upxfile(wd="."): | |||
238 | return 0 | 257 | return 0 |
239 | 258 | ||
240 | 259 | ||
241 | def runnsis(versionstring, nsis, srcfolder): | 260 | def runnsis(versionstring, nsis, script, srcfolder): |
242 | # run script through nsis to create installer. | 261 | # run script through nsis to create installer. |
243 | print "Running NSIS ..." | 262 | print "Running NSIS ..." |
263 | |||
244 | # Assume the generated installer gets placed in the same folder the nsi | 264 | # Assume the generated installer gets placed in the same folder the nsi |
245 | # script lives in. This seems to be a valid assumption unless the nsi | 265 | # script lives in. This seems to be a valid assumption unless the nsi |
246 | # script specifies a path. NSIS expects files relative to source folder so | 266 | # script specifies a path. NSIS expects files relative to source folder so |
247 | # copy the relevant binaries. | 267 | # copy progexe. Additional files are injected into the nsis script. |
248 | for f in programfiles: | 268 | |
249 | b = srcfolder + "/" + os.path.dirname(nsisscript) + "/" + os.path.dirname(f) | 269 | # FIXME: instead of copying binaries around copy the NSI file and inject |
250 | if not os.path.exists(b): | 270 | # the correct paths. |
251 | os.mkdir(b) | 271 | b = srcfolder + "/" + os.path.dirname(script) + "/" + os.path.dirname(progexe) |
252 | shutil.copy(srcfolder + "/" + f, b) | 272 | if not os.path.exists(b): |
253 | output = subprocess.Popen([nsis, srcfolder + "/" + nsisscript], stdout=subprocess.PIPE) | 273 | os.mkdir(b) |
274 | shutil.copy(srcfolder + "/" + progexe, b) | ||
275 | output = subprocess.Popen([nsis, srcfolder + "/" + script], stdout=subprocess.PIPE) | ||
254 | output.communicate() | 276 | output.communicate() |
255 | if not output.returncode == 0: | 277 | if not output.returncode == 0: |
256 | print "NSIS failed!" | 278 | print "NSIS failed!" |
@@ -258,16 +280,70 @@ def runnsis(versionstring, nsis, srcfolder): | |||
258 | setupfile = program + "-" + versionstring + "-setup.exe" | 280 | setupfile = program + "-" + versionstring + "-setup.exe" |
259 | # find output filename in nsis script file | 281 | # find output filename in nsis script file |
260 | nsissetup = "" | 282 | nsissetup = "" |
261 | for line in open(srcfolder + "/" + nsisscript): | 283 | for line in open(srcfolder + "/" + script): |
262 | if re.match(r'^[^;]*OutFile\s+', line) != None: | 284 | if re.match(r'^[^;]*OutFile\s+', line) != None: |
263 | nsissetup = re.sub(r'^[^;]*OutFile\s+"(.+)"', r'\1', line).rstrip() | 285 | nsissetup = re.sub(r'^[^;]*OutFile\s+"(.+)"', r'\1', line).rstrip() |
264 | if nsissetup == "": | 286 | if nsissetup == "": |
265 | print "Could not retrieve output file name!" | 287 | print "Could not retrieve output file name!" |
266 | return -1 | 288 | return -1 |
267 | shutil.copy(srcfolder + "/" + os.path.dirname(nsisscript) + "/" + nsissetup, setupfile) | 289 | shutil.copy(srcfolder + "/" + os.path.dirname(script) + "/" + nsissetup, setupfile) |
268 | return 0 | 290 | return 0 |
269 | 291 | ||
270 | 292 | ||
293 | def nsisfileinject(nsis, outscript, filelist): | ||
294 | '''Inject files in filelist into NSIS script file after the File line | ||
295 | containing the main binary. This assumes that the main binary is present | ||
296 | in the NSIS script and that all additiona files (dlls etc) to get placed | ||
297 | into $INSTDIR.''' | ||
298 | output = open(outscript, "w") | ||
299 | for line in open(nsis, "r"): | ||
300 | output.write(line) | ||
301 | # inject files after the progexe binary. Match the basename only to avoid path mismatches. | ||
302 | if re.match(r'^\s*File\s*.*' + os.path.basename(progexe), line, re.IGNORECASE): | ||
303 | for f in filelist: | ||
304 | injection = " File /oname=$INSTDIR\\" + os.path.basename(f) + " " + os.path.normcase(f) + "\n" | ||
305 | output.write(injection) | ||
306 | output.write(" ; end of injected files\n") | ||
307 | output.close() | ||
308 | |||
309 | |||
310 | def finddlls(program, extrapaths = []): | ||
311 | '''Check program for required DLLs. Find all required DLLs except ignored | ||
312 | ones and return a list of DLL filenames (including path).''' | ||
313 | # ask objdump about dependencies. | ||
314 | output = subprocess.Popen(["objdump", "-x", program], stdout=subprocess.PIPE) | ||
315 | cmdout = output.communicate() | ||
316 | |||
317 | # create list of used DLLs. Store as lower case as W32 is case-insensitive. | ||
318 | dlls = [] | ||
319 | for line in cmdout[0].split('\n'): | ||
320 | if re.match(r'\s*DLL Name', line) != None: | ||
321 | dll = re.sub(r'^\s*DLL Name:\s+([a-zA-Z_\-0-9\.]+).*$', r'\1', line) | ||
322 | dlls.append(dll.lower()) | ||
323 | |||
324 | # find DLLs in extrapaths and PATH environment variable. | ||
325 | dllpaths = [] | ||
326 | for file in dlls: | ||
327 | if file in systemdlls: | ||
328 | print file + ": System DLL" | ||
329 | continue | ||
330 | dllpath = "" | ||
331 | for path in extrapaths: | ||
332 | if os.path.exists(path + "/" + file): | ||
333 | dllpath = re.sub(r"\\", r"/", path + "/" + file) | ||
334 | print file + ": found at " + dllpath | ||
335 | dllpaths.append(dllpath) | ||
336 | break | ||
337 | if dllpath == "": | ||
338 | try: | ||
339 | dllpath = re.sub(r"\\", r"/", which.which(file)) | ||
340 | print file + ": found at " + dllpath | ||
341 | dllpaths.append(dllpath) | ||
342 | except: | ||
343 | print file + ": NOT FOUND." | ||
344 | return dllpaths | ||
345 | |||
346 | |||
271 | def zipball(versionstring, buildfolder): | 347 | def zipball(versionstring, buildfolder): |
272 | '''package created binary''' | 348 | '''package created binary''' |
273 | print "Creating binary zipball." | 349 | print "Creating binary zipball." |
@@ -278,7 +354,10 @@ def zipball(versionstring, buildfolder): | |||
278 | os.mkdir(outfolder) | 354 | os.mkdir(outfolder) |
279 | # move program files to output folder | 355 | # move program files to output folder |
280 | for f in programfiles: | 356 | for f in programfiles: |
281 | shutil.copy(buildfolder + "/" + f, outfolder) | 357 | if re.match(r'^(/|[a-zA-Z]:)', f) != None: |
358 | shutil.copy(f, outfolder) | ||
359 | else: | ||
360 | shutil.copy(buildfolder + "/" + f, outfolder) | ||
282 | # create zipball from output folder | 361 | # create zipball from output folder |
283 | zf = zipfile.ZipFile(archivename, mode='w', compression=zipfile.ZIP_DEFLATED) | 362 | zf = zipfile.ZipFile(archivename, mode='w', compression=zipfile.ZIP_DEFLATED) |
284 | for root, dirs, files in os.walk(outfolder): | 363 | for root, dirs, files in os.walk(outfolder): |
@@ -503,15 +582,20 @@ def deploy(): | |||
503 | if not upxfile(sourcefolder) == 0: | 582 | if not upxfile(sourcefolder) == 0: |
504 | tempclean(workfolder, cleanup and not keeptemp) | 583 | tempclean(workfolder, cleanup and not keeptemp) |
505 | sys.exit(1) | 584 | sys.exit(1) |
585 | dllfiles = finddlls(sourcefolder + "/" + progexe, [os.path.dirname(qm)]) | ||
586 | if dllfiles.count > 0: | ||
587 | programfiles.extend(dllfiles) | ||
506 | archive = zipball(ver, sourcefolder) | 588 | archive = zipball(ver, sourcefolder) |
589 | # only when running native right now. | ||
590 | if nsisscript != "" and makensis != "": | ||
591 | nsisfileinject(sourcefolder + "/" + nsisscript, sourcefolder + "/" + nsisscript + ".tmp", dllfiles) | ||
592 | runnsis(ver, makensis, nsisscript + ".tmp", sourcefolder) | ||
507 | elif sys.platform == "darwin": | 593 | elif sys.platform == "darwin": |
508 | archive = macdeploy(ver, sourcefolder) | 594 | archive = macdeploy(ver, sourcefolder) |
509 | else: | 595 | else: |
510 | if os.uname()[4].endswith("64"): | 596 | if os.uname()[4].endswith("64"): |
511 | ver += "-64bit" | 597 | ver += "-64bit" |
512 | archive = tarball(ver, sourcefolder) | 598 | archive = tarball(ver, sourcefolder) |
513 | if nsisscript != "" and makensis != "": | ||
514 | runnsis(ver, makensis, sourcefolder) | ||
515 | 599 | ||
516 | # remove temporary files | 600 | # remove temporary files |
517 | tempclean(workfolder, cleanup) | 601 | tempclean(workfolder, cleanup) |