1import os 2import sys 3import hashlib 4import re 5import subprocess 6import time 7import glob 8import zipfile 9import shutil 10import requests 11import json 12 13# Timeout socket handling 14import socket 15import threading 16import errno 17 18from util import * 19 20try: 21 import zlib 22 compression = zipfile.ZIP_DEFLATED 23except: 24 compression = zipfile.ZIP_STORED 25 26modes = { zipfile.ZIP_DEFLATED: 'deflated', 27 zipfile.ZIP_STORED: 'stored', 28 } 29 30try: 31 # Python 3 32 from urllib.request import urlopen, Request 33 from urllib.error import HTTPError, URLError 34 from urllib.parse import urlparse 35 from http.client import HTTPException 36except ImportError: 37 # Python 2 38 from urllib2 import urlopen, Request, HTTPError, URLError 39 from urlparse import urlparse 40 from httplib import HTTPException 41 42BINTRAY_SNAPSHOT_SERVER_PATH = "https://oss.jfrog.org/artifactory/oss-snapshot-local" 43BINTRAY_RELEASE_SERVER_PATH = "https://oss.jfrog.org/artifactory/oss-release-local" 44BINTRAY_MAVEN_GROUP_PATH = "/org/github/alberthdev/cemu/" 45MAX_ATTEMPTS = 5 46SHA256_STRICT = False 47 48# Solution from Anppa @ StackOverflow 49# http://stackoverflow.com/a/18468750/1094484 50def timeout_http_body_read_to_file(response, fh, timeout = 60): 51 def murha(resp): 52 os.close(resp.fileno()) 53 resp.close() 54 55 # set a timer to yank the carpet underneath the blocking read() by closing the os file descriptor 56 t = threading.Timer(timeout, murha, (response,)) 57 58 t.start() 59 fh.write(response.read()) 60 t.cancel() 61 62def truncate_url(url): 63 if len(url) > 70: 64 truncated_url = url[:34] + ".." + url[len(url) - 34:] 65 else: 66 truncated_url = url 67 68 return truncated_url 69 70def check_file(path): 71 try: 72 test_fh = open(path) 73 test_fh.close() 74 return True 75 except IOError: 76 return False 77 78# Note: suppress_errors will only work on HTTP errors 79# Other errors will be forcefully displayed 80def check_url(url, suppress_errors = True): 81 check_attempts = 0 82 found = False 83 84 while check_attempts <= MAX_ATTEMPTS: 85 # If we aren't on our first download attempt, wait a bit. 86 if check_attempts > 0: 87 print(" !! Download attempt failed, waiting 10s before retry...") 88 print(" (attempt %i/%i)" % (check_attempts + 1, MAX_ATTEMPTS)) 89 90 # Wait... 91 time.sleep(10) 92 93 # Open the url 94 try: 95 f = urlopen(url) 96 97 # Everything good! 98 found = True 99 break 100 101 # Error handling... 102 except HTTPError: 103 if not suppress_errors: 104 _, e, _ = sys.exc_info() 105 print(" !! HTTP Error: %i (%s)" % (e.code, url)) 106 print(" !! Server said:") 107 err = e.read().decode("utf-8") 108 err = " !! " + "\n !! ".join(err.split("\n")).strip() 109 print(err) 110 111 found = False 112 break 113 except URLError: 114 _, e, _ = sys.exc_info() 115 print(" !! URL Error: %s (%s)" % (e.reason, url)) 116 117 found = False 118 break 119 except HTTPException: 120 _, e, _ = sys.exc_info() 121 print(" !! HTTP Exception: %s (%s)" % (str(e), url)) 122 except socket.error: 123 _, e, _ = sys.exc_info() 124 if e.errno == errno.EBADF: 125 print(" !! Timeout reached: %s (%s)" % (str(e), url)) 126 else: 127 print(" !! Socket Exception: %s (%s)" % (str(e), url)) 128 129 # Increment attempts 130 check_attempts += 1 131 132 if check_attempts > MAX_ATTEMPTS: 133 print(" !! ERROR: URL check failed, assuming not found!") 134 135 return found 136 137def dlfile(url, dest = None): 138 dl_attempts = 0 139 dest = dest or os.path.basename(url) 140 141 while dl_attempts <= MAX_ATTEMPTS: 142 # If we aren't on our first download attempt, wait a bit. 143 if dl_attempts > 0: 144 print(" !! Download attempt failed, waiting 10s before retry...") 145 print(" (attempt %i/%i)" % (dl_attempts + 1, MAX_ATTEMPTS)) 146 147 # Wait... 148 time.sleep(10) 149 150 # Open the url 151 try: 152 f = urlopen(url) 153 print(" -> Downloading:") 154 print(" %s" % truncate_url(url)) 155 156 # Open our local file for writing 157 with open(dest, "wb") as local_file: 158 timeout_http_body_read_to_file(f, local_file, timeout = 300) 159 #local_file.write(f.read()) 160 161 # Everything good! 162 break 163 164 # Error handling... 165 except HTTPError: 166 _, e, _ = sys.exc_info() 167 print(" !! HTTP Error: %i (%s)" % (e.code, url)) 168 print(" !! Server said:") 169 err = e.read().decode("utf-8") 170 err = " !! " + "\n !! ".join(err.split("\n")).strip() 171 print(err) 172 except URLError: 173 _, e, _ = sys.exc_info() 174 print(" !! URL Error: %s (%s)" % (e.reason, url)) 175 except HTTPException: 176 _, e, _ = sys.exc_info() 177 print(" !! HTTP Exception: %s (%s)" % (str(e), url)) 178 except socket.error: 179 _, e, _ = sys.exc_info() 180 if e.errno == errno.EBADF: 181 print(" !! Timeout reached: %s (%s)" % (str(e), url)) 182 else: 183 print(" !! Socket Exception: %s (%s)" % (str(e), url)) 184 185 # Increment attempts 186 dl_attempts += 1 187 188 if dl_attempts > MAX_ATTEMPTS: 189 print(" !! ERROR: Download failed, exiting!") 190 sys.exit(1) 191 192def generate_file_md5(filename, blocksize=2**20): 193 m = hashlib.md5() 194 with open( filename , "rb" ) as f: 195 while True: 196 buf = f.read(blocksize) 197 if not buf: 198 break 199 m.update( buf ) 200 return m.hexdigest() 201 202def generate_file_sha1(filename, blocksize=2**20): 203 m = hashlib.sha1() 204 with open( filename , "rb" ) as f: 205 while True: 206 buf = f.read(blocksize) 207 if not buf: 208 break 209 m.update( buf ) 210 return m.hexdigest() 211 212def generate_file_sha256(filename, blocksize=2**20): 213 m = hashlib.sha256() 214 with open( filename , "rb" ) as f: 215 while True: 216 buf = f.read(blocksize) 217 if not buf: 218 break 219 m.update( buf ) 220 return m.hexdigest() 221 222def output_md5(filename): 223 md5_result = "%s %s" % (filename, generate_file_md5(filename)) 224 print(md5_result) 225 return md5_result 226 227def output_sha1(filename): 228 sha1_result = "%s %s" % (filename, generate_file_sha1(filename)) 229 print(sha1_result) 230 return sha1_result 231 232def output_sha256(filename): 233 sha256_result = "%s %s" % (filename, generate_file_sha256(filename)) 234 print(sha256_result) 235 return sha256_result 236 237# True if valid, False otherwise 238# Generalized validation function 239# filename - file to check 240# chksum_file - checksum file to verify against 241# hash_name - name of hash function used 242# hash_regex - regex to validate the hash format 243# hash_func - function to create hash from file 244def validate_gen(filename, chksum_file, hash_name, hash_regex, hash_func): 245 print(" -> Validating file with %s: %s" % (hash_name, filename)) 246 try: 247 hash_fh = open(chksum_file) 248 correct_hash = hash_fh.read().strip() 249 hash_fh.close() 250 except IOError: 251 print(" !! ERROR: Could not open checksum file '%s' for opening!" % chksum_file) 252 print(" !! Exact error follows...") 253 raise 254 255 # Ensure hash is a valid checksum 256 hash_match = re.match(hash_regex, correct_hash) 257 258 if not hash_match: 259 print(" !! ERROR: Invalid %s checksum!" % hash_name) 260 print(" !! Extracted %s (invalid): %s" % (hash_name, correct_hash)) 261 sys.exit(1) 262 263 # One more thing - check to make sure the file exists! 264 try: 265 test_fh = open(filename, "rb") 266 test_fh.close() 267 except IOError: 268 print(" !! ERROR: Can't check %s checksum - could not open file!" % hash_name) 269 print(" !! File: %s" % filename) 270 print(" !! Traceback follows:") 271 traceback.print_exc() 272 return False 273 274 # Alright, let's compute the checksum! 275 cur_hash = hash_func(filename) 276 277 # Check the checksum... 278 if cur_hash != correct_hash: 279 print(" !! ERROR: %s checksums do not match!" % hash_name) 280 print(" !! File: %s" % filename) 281 print(" !! Current %s: %s" % (hash_name, cur_hash)) 282 print(" !! Correct %s: %s" % (hash_name, correct_hash)) 283 return False 284 285 # Otherwise, everything is good! 286 return True 287 288def validate(filename): 289 valid_md5 = validate_gen(filename, filename + ".md5", "MD5", r'^[0-9a-f]{32}$', generate_file_md5) 290 291 if valid_md5: 292 valid_sha1 = validate_gen(filename, filename + ".sha1", "SHA1", r'^[0-9a-f]{40}$', generate_file_sha1) 293 294 if valid_sha1: 295 # Special case: SHA256. 296 # Check its existence before attempting to validate. 297 if check_file(filename + ".sha256") or SHA256_STRICT: 298 valid_sha256 = validate_gen(filename, filename + ".sha256", "SHA256", r'^[0-9a-f]{64}$', generate_file_sha256) 299 300 return valid_sha256 301 else: 302 print(" !! **********************************************************") 303 print(" !! WARNING: SHA256 checksum was not found for file:") 304 print(" %s" % filename) 305 print(" SHA256 checksum is strongly suggested for file integrity") 306 print(" checking due to the weakness of other hashing algorithms.") 307 print(" Continuing for now.") 308 print(" !! **********************************************************") 309 return True 310 else: 311 return False # alternatively, valid_sha1 312 else: 313 return False # alternatively, valid_md5 314 315def dl_and_validate(url): 316 validation_attempts = 0 317 local_fn = os.path.basename(url) 318 319 print(" -> Downloading + validating:") 320 print(" %s" % truncate_url(url)) 321 322 # Download checksums... 323 print(" -> Downloading checksums for file: %s" % (local_fn)) 324 dlfile(url + ".md5") 325 dlfile(url + ".sha1") 326 327 # SHA256 support was recently added, so do some careful checking 328 # here. 329 if check_url(url + ".sha256"): 330 dlfile(url + ".sha256") 331 else: 332 # https://oss.jfrog.org/artifactory/oss-snapshot-local/org/github/alberthdev/cemu/appveyor-qt/Qt5.12.0_Rel_Static_Win32_DevDeploy.7z 333 # https://oss.jfrog.org/api/storage/oss-snapshot-local/org/github/alberthdev/cemu/appveyor-qt/Qt5.12.0_Rel_Static_Win32_DevDeploy.7z 334 url_parsed = urlparse(url) 335 if url_parsed.netloc == "oss.jfrog.org" and url_parsed.path.startswith("/artifactory"): 336 file_info_json_url = url.replace("://oss.jfrog.org/artifactory/", "://oss.jfrog.org/api/storage/") 337 338 if check_url(file_info_json_url): 339 dlfile(file_info_json_url, local_fn + ".info.json") 340 341 file_info_json_fh = open(local_fn + ".info.json") 342 file_info_json = json.loads(file_info_json_fh.read()) 343 file_info_json_fh.close() 344 345 if "checksums" in file_info_json and "sha256" in file_info_json["checksums"]: 346 print(" -- Found SHA256 checksum from file JSON info.") 347 print(" SHA256: %s" % file_info_json["checksums"]["sha256"]) 348 sha256_fh = open(local_fn + ".sha256", "w") 349 sha256_fh.write("%s" % file_info_json["checksums"]["sha256"]) 350 sha256_fh.close() 351 else: 352 print(" !! Could not find SHA256 checksum in JSON info.") 353 else: 354 print(" !! JSON info does not seem to work or exist:") 355 print(" %s" % file_info_json_url) 356 print(" Will not be able to locate SHA256 checksum.") 357 else: 358 print(" !! Could not detect a OSS JFrog URL. Will not be able") 359 print(" to find SHA256 checksum.") 360 361 while validation_attempts < MAX_ATTEMPTS: 362 # If we aren't on our first download attempt, wait a bit. 363 if validation_attempts > 0: 364 print(" !! Download + validation attempt failed, waiting 10s before retry...") 365 print(" (attempt %i/%i)" % (validation_attempts + 1, MAX_ATTEMPTS)) 366 # Wait... 367 time.sleep(10) 368 369 print(" -> Downloading file: %s" % (local_fn)) 370 371 # Download file... 372 dlfile(url) 373 374 # ...and attempt to validate it! 375 if validate(local_fn): 376 break 377 378 # Validation failed... looping back around. 379 # Increment validation attempt counter 380 validation_attempts += 1 381 382 if validation_attempts > MAX_ATTEMPTS: 383 print(" !! ERROR: Download and validation failed, exiting!") 384 sys.exit(1) 385 386 print(" -> Downloaded + validated successfully:") 387 print(" %s" % truncate_url(url)) 388 389def extract(filename): 390 print(" -> Extracting file: %s" % filename) 391 if not silent_exec(["7z", "x", "-y", "-oC:\\", filename]): 392 print(" !! ERROR: Failed to extract file: " % filename) 393 print(" !! See above output for details.") 394 sys.exit(1) 395 396def install_deps(): 397 print(" * Attempting to download dependencies...") 398 dl_and_validate('https://oss.jfrog.org/artifactory/oss-snapshot-local/org/github/alberthdev/cemu/appveyor-qt/Qt5.12.0_Rel_Static_Win32_DevDeploy.7z.001') 399 dl_and_validate('https://oss.jfrog.org/artifactory/oss-snapshot-local/org/github/alberthdev/cemu/appveyor-qt/Qt5.12.0_Rel_Static_Win32_DevDeploy.7z.002') 400 dl_and_validate('https://oss.jfrog.org/artifactory/oss-snapshot-local/org/github/alberthdev/cemu/appveyor-qt/Qt5.12.0_Rel_Static_Win64_DevDeploy.7z.001') 401 dl_and_validate('https://oss.jfrog.org/artifactory/oss-snapshot-local/org/github/alberthdev/cemu/appveyor-qt/Qt5.12.0_Rel_Static_Win64_DevDeploy.7z.002') 402 403 print(" * Attempting to install dependencies...") 404 extract('Qt5.12.0_Rel_Static_Win32_DevDeploy.7z.001') 405 extract('Qt5.12.0_Rel_Static_Win64_DevDeploy.7z.001') 406 407 print(" * Successfully installed build dependencies!") 408 409def overwrite_copy(src, dest): 410 src_bn = os.path.basename(src) 411 dest_path = os.path.join(dest, src_bn) 412 413 src_fh = open(src, "rb") 414 dest_fh = open(dest_path, "wb") 415 416 dest_fh.write(src_fh.read()) 417 418 src_fh.close() 419 dest_fh.close() 420 421def collect_static_main_files(arch, build_path, dest, extra_wc = None): 422 file_list = [] 423 424 if extra_wc: 425 for copy_type in extra_wc: 426 print(" -> Copying %s files (%s)..." % (copy_type, arch)) 427 copy_wc = extra_wc[copy_type] 428 429 for file in glob.glob(copy_wc): 430 print(" -> Copying %s (%s, %s)..." % (os.path.basename(file), arch, copy_type)) 431 overwrite_copy(file, dest) 432 433 434 # Finally, add our binary! 435 print(" -> Copying main executable (%s)..." % (arch)) 436 exec_path = os.path.join(build_path, "CEmu.exe") 437 overwrite_copy(exec_path, dest) 438 439 # No manifest needed - already embedded into exe. 440 441# wc = wildcard 442# extra_wc: dictionary of extra wildcard paths to copy in! 443# example: { "More DLLs" : "C:\MoreDLLs\*.dll"} 444def collect_main_files(arch, vcredist_wc_path, ucrt_wc_path, build_path, dest, extra_wc = None): 445 file_list = [] 446 447 print(" -> Searching VCRedist for DLL files to include (%s)..." % (arch)) 448 449 for file in glob.glob(vcredist_wc_path): 450 print(" -> Copying %s (%s, VCRedist)..." % (os.path.basename(file), arch)) 451 overwrite_copy(file, dest) 452 453 for file in glob.glob(ucrt_wc_path): 454 print(" -> Copying %s (%s, UCRT)..." % (os.path.basename(file), arch)) 455 overwrite_copy(file, dest) 456 457 if extra_wc: 458 for copy_type in extra_wc: 459 print(" -> Copying %s files (%s)..." % (copy_type, arch)) 460 copy_wc = extra_wc[copy_type] 461 462 for file in glob.glob(copy_wc): 463 print(" -> Copying %s (%s, %s)..." % (os.path.basename(file), arch, copy_type)) 464 overwrite_copy(file, dest) 465 466 467 # Finally, add our binary! 468 print(" -> Copying main executable (%s)..." % (arch)) 469 exec_path = os.path.join(build_path, "CEmu.exe") 470 overwrite_copy(exec_path, dest) 471 472 # No manifest needed - already embedded into exe. 473 474def collect_qt_files_with_qml(arch, deploy_tool, dest, exe_file, qmldir = "qml"): 475 os.environ.pop("VCINSTALLDIR", None) 476 print(" -> Collecting all Qt dependencies (%s)..." % (arch)) 477 if not simple_exec([deploy_tool, "--qmldir", qmldir, "--dir", dest, exe_file]): 478 print(" !! ERROR: Failed to collect Qt dependencies!") 479 print(" !! See above output for details.") 480 sys.exit(1) 481 482def collect_qt_files(arch, deploy_tool, dest, exe_file): 483 os.environ.pop("VCINSTALLDIR", None) 484 print(" -> Collecting all Qt dependencies (%s)..." % (arch)) 485 if not simple_exec([deploy_tool, "--no-angle", "--no-opengl-sw", "--no-system-d3d-compiler", "--dir", dest, exe_file]): 486 print(" !! ERROR: Failed to collect Qt dependencies!") 487 print(" !! See above output for details.") 488 sys.exit(1) 489 490def build_file_list(arch, dest): 491 file_list = [] 492 root_parts = len(dest.split(os.sep)) 493 494 print(" -> Finalizing file list for release (%s)..." % (arch)) 495 496 for root, dirnames, filenames in os.walk(dest): 497 for filename in filenames: 498 full_path = os.path.join(root, filename) 499 # Delete root folder from path to form archive path! 500 arc_path = os.sep.join(full_path.split(os.sep)[root_parts:]) 501 file_list.append([full_path, arc_path]) 502 503 return file_list 504 505def make_zip(arch, filename, file_list): 506 print(" * Building ZIP file %s (%s)..." % (filename, arch)) 507 508 if compression == zipfile.ZIP_DEFLATED: 509 print(" (Compression is enabled!)") 510 else: 511 print(" (Compression is DISABLED!)") 512 513 zf = zipfile.ZipFile(filename, mode='w') 514 try: 515 for file_entry in file_list: 516 if len(file_entry) == 1: 517 full_path = file_entry[0] 518 arc_path = full_path 519 elif len(file_entry) == 2: 520 full_path = file_entry[0] 521 arc_path = file_entry[1] 522 else: 523 print(" !! ERROR: Bug - invalid number of file elements in file_entry!") 524 print(" file_entry is %s" % (str(file_entry))) 525 sys.exit(1) 526 527 print(" -> Adding %s -> %s..." % (full_path, arc_path)) 528 zf.write(full_path, compress_type=compression, arcname=arc_path) 529 finally: 530 print(" -> Closing ZIP file %s (%s)..." % (filename, arch)) 531 zf.close() 532 533 print(" * Successfully built ZIP file %s (%s)!" % (filename, arch)) 534 535def upload_snapshot(filename, cur_timestamp, snap_base_fn, bintray_api_username, bintray_api_key, extra_path = None): 536 cur_date = cur_timestamp.split("_")[0] 537 cur_date_ym = cur_date[:6] 538 539 full_path = BINTRAY_SNAPSHOT_SERVER_PATH + BINTRAY_MAVEN_GROUP_PATH + "git/" + cur_date_ym + "/" + cur_date + "/" + snap_base_fn + "/" 540 541 base_fn = os.path.basename(filename) 542 543 print(" * Preparing to deploy snapshot: %s" % base_fn) 544 545 if extra_path: 546 full_path += extra_path 547 548 # Compute MD5, SHA1, and SHA256 549 print(" -> Computing checksums before uploading...") 550 file_md5sum = generate_file_md5(filename) 551 file_sha1sum = generate_file_sha1(filename) 552 file_sha256sum = generate_file_sha256(filename) 553 554 print(" -> MD5 = %s" % file_md5sum) 555 print(" -> SHA1 = %s" % file_sha1sum) 556 print(" -> SHA256 = %s" % file_sha256sum) 557 558 headers = { 559 'X-Checksum-Md5' : file_md5sum, 560 'X-Checksum-Sha1' : file_sha1sum, 561 'X-Checksum-Sha256' : file_sha256sum, 562 } 563 564 #files = {base_fn: open(filename, 'rb')} 565 fh = open(filename, 'rb') 566 file_data = fh.read() 567 fh.close() 568 569 print(" * Uploading/deploying snapshot: %s" % base_fn) 570 r = requests.put(full_path + base_fn, headers = headers, data = file_data, \ 571 auth = (bintray_api_username, bintray_api_key)) 572 573 print(" * Resulting status code: %i" % r.status_code) 574 print(" * Resulting response:\n%s" % r.content) 575 576 if r.status_code != 201: 577 print(" ! ERROR: Upload/deployment of snapshot failed!") 578 579def deploy_snapshots(): 580 print(" * Preparing to deploy...") 581 582 # Check for our needed environment variables! 583 # First up? Bintray! 584 bintray_api_username = os.environ.get("BINTRAY_API_USERNAME") 585 bintray_api_key = os.environ.get("BINTRAY_API_KEY") 586 587 if (bintray_api_username == None) or (bintray_api_key == None): 588 print(" ! ERROR: Authentication environmental variables not found!") 589 print(" ! BINTRAY_API_USERNAME defined? %s" % ("Yes" if bintray_api_username else "No")) 590 print(" ! BINTRAY_API_KEY defined? %s" % ("Yes" if bintray_api_key else "No")) 591 sys.exit(1) 592 593 # One more - are the Qt5 dynamic directories defined? 594 qt5_bin_dir_dynamic_32 = os.environ.get("QT5_BIN_DIR_DYNAMIC_32") 595 qt5_bin_dir_dynamic_64 = os.environ.get("QT5_BIN_DIR_DYNAMIC_64") 596 597 if (qt5_bin_dir_dynamic_32 == None) or (qt5_bin_dir_dynamic_64 == None): 598 print(" ! ERROR: Qt5 dynamic location environmental variables not found!") 599 print(" ! QT5_BIN_DIR_DYNAMIC_32 defined? %s" % ("Yes" if QT5_BIN_DIR_DYNAMIC_32 else "No")) 600 print(" ! QT5_BIN_DIR_DYNAMIC_64 defined? %s" % ("Yes" if QT5_BIN_DIR_DYNAMIC_64 else "No")) 601 sys.exit(1) 602 603 # Make a directory for our deploy ZIPs 604 mkdir_p("deploy") 605 mkdir_p(os.path.join("deploy", "release32")) 606 mkdir_p(os.path.join("deploy", "release64")) 607 mkdir_p(os.path.join("deploy", "release32_debug")) 608 mkdir_p(os.path.join("deploy", "release64_debug")) 609 610 mkdir_p(os.path.join("deploy_static", "release32")) 611 mkdir_p(os.path.join("deploy_static", "release64")) 612 mkdir_p(os.path.join("deploy_static", "release32_debug")) 613 mkdir_p(os.path.join("deploy_static", "release64_debug")) 614 615 # git rev-parse --short HEAD 616 git_rev = output_exec(["git", "rev-parse", "--short", "HEAD"]) 617 618 if git_rev == None: 619 sys.exit(1) 620 621 git_rev = git_rev.decode("utf-8").strip() 622 623 # Snapshot filename - based on http://zeranoe1.rssing.com/chan-5973786/latest.php 624 cur_timestamp = time.strftime("%Y%m%d_%H%M%S") 625 snap_base_fn = "cemu-%s-git-%s" % (cur_timestamp, git_rev) 626 snap_base_path = os.path.join("deploy", snap_base_fn) 627 628 # Locate files that we need! 629 print(" * Collecting all dependencies for deployment...") 630 631 collect_main_files("x86", r"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x86\Microsoft.VC140.CRT\*.dll", 632 r"C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x86\*.dll", 633 os.path.join("build_32", "release"), 634 os.path.join("deploy", "release32"), 635 extra_wc = { 636 "vcpkg provided DLLs" : os.path.join("build_32", "release") + r"\*.dll" 637 } 638 ) 639 collect_main_files("x64", r"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x64\Microsoft.VC140.CRT\*.dll", 640 r"C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x64\*.dll", 641 os.path.join("build_64", "release"), 642 os.path.join("deploy", "release64"), 643 extra_wc = { 644 "vcpkg provided DLLs" : os.path.join("build_64", "release") + r"\*.dll" 645 } 646 ) 647 648 # For debug builds, only copy api*.dll for UCRT redist, then copy 649 # the specific ucrt debug DLL in the extra copy arg. 650 collect_main_files("x86 Debug", r"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\debug_nonredist\x86\Microsoft.VC140.DebugCRT\*.dll", 651 r"C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x86\api*.dll", 652 os.path.join("build_32", "debug"), 653 os.path.join("deploy", "release32_debug"), 654 extra_wc = { 655 "UCRT Debug" : r"C:\Program Files (x86)\Windows Kits\10\bin\x86\ucrt\*.dll", 656 "vcpkg provided DLLs" : os.path.join("build_32", "debug") + r"\*.dll" 657 } 658 ) 659 collect_main_files("x64 Debug", r"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\debug_nonredist\x64\Microsoft.VC140.DebugCRT\*.dll", 660 r"C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x64\api*.dll", 661 os.path.join("build_64", "debug"), 662 os.path.join("deploy", "release64_debug"), 663 extra_wc = { 664 "UCRT Debug" : r"C:\Program Files (x86)\Windows Kits\10\bin\x64\ucrt\*.dll", 665 "vcpkg provided DLLs" : os.path.join("build_64", "debug") + r"\*.dll" 666 } 667 ) 668 669 # Static builds 670 # Release 671 collect_static_main_files("x86 Static", os.path.join("build_static_32", "release"), os.path.join("deploy_static", "release32"), 672 #extra_wc = { 673 # "EGL Library" : r"C:\Qt\Qt5.12.0-static\bin\libEGL.dll", 674 # "GLESv2 Library" : r"C:\Qt\Qt5.12.0-static\bin\libGLESv2.dll", 675 # "DirectX Compiler Library" : r"C:\Qt\5.12.0\msvc2015\bin\d3dcompiler_*.dll", 676 # "Mesa OpenGL Software Rendering Library" : r"C:\Qt\5.12.0\msvc2015\bin\opengl32sw.dll", 677 # } 678 ) 679 collect_static_main_files("x64 Static", os.path.join("build_static_64", "release"), os.path.join("deploy_static", "release64"), 680 #extra_wc = { 681 # "EGL Library" : r"C:\Qt\Qt5.12.0x64-static\bin\libEGL.dll", 682 # "GLESv2 Library" : r"C:\Qt\Qt5.12.0x64-static\bin\libGLESv2.dll", 683 # "DirectX Compiler Library" : r"C:\Qt\5.12.0\msvc2015_64\bin\d3dcompiler_*.dll", 684 # "Mesa OpenGL Software Rendering Library" : r"C:\Qt\5.12.0\msvc2015_64\bin\opengl32sw.dll", 685 # } 686 ) 687 688 # Debug 689 collect_static_main_files("x86 Static Debug", os.path.join("build_static_32", "debug"), os.path.join("deploy_static", "release32_debug"), 690 #extra_wc = { 691 # "EGL Library" : r"C:\Qt\Qt5.12.0-static\bin\libEGLd.dll", 692 # "GLESv2 Library" : r"C:\Qt\Qt5.12.0-static\bin\libGLESv2d.dll", 693 # "DirectX Compiler Library" : r"C:\Qt\5.12.0\msvc2015\bin\d3dcompiler_*.dll", 694 # "Mesa OpenGL Software Rendering Library" : r"C:\Qt\5.12.0\msvc2015\bin\opengl32sw.dll", 695 # } 696 ) 697 collect_static_main_files("x64 Static Debug", os.path.join("build_static_64", "debug"), os.path.join("deploy_static", "release64_debug"), 698 #extra_wc = { 699 # "EGL Library" : r"C:\Qt\Qt5.12.0x64-static\bin\libEGLd.dll", 700 # "GLESv2 Library" : r"C:\Qt\Qt5.12.0x64-static\bin\libGLESv2d.dll", 701 # "DirectX Compiler Library" : r"C:\Qt\5.12.0\msvc2015_64\bin\d3dcompiler_*.dll", 702 # "Mesa OpenGL Software Rendering Library" : r"C:\Qt\5.12.0\msvc2015_64\bin\opengl32sw.dll", 703 # } 704 ) 705 706 # Qt files only needed for dynamic builds 707 collect_qt_files("x86", qt5_bin_dir_dynamic_32 + r"\windeployqt.exe", r"deploy\release32", r'build_32\release\CEmu.exe') 708 collect_qt_files("x64", qt5_bin_dir_dynamic_64 + r"\windeployqt.exe", r"deploy\release64", r'build_64\release\CEmu.exe') 709 710 collect_qt_files("x86 Debug", qt5_bin_dir_dynamic_32 + r"\windeployqt.exe", r"deploy\release32_debug", r'build_32\debug\CEmu.exe') 711 collect_qt_files("x64 Debug", qt5_bin_dir_dynamic_64 + r"\windeployqt.exe", r"deploy\release64_debug", r'build_64\debug\CEmu.exe') 712 713 file_list_32 = build_file_list("x86", r"deploy\release32") 714 file_list_64 = build_file_list("x64", r"deploy\release64") 715 716 file_list_32_debug = build_file_list("x86 Debug", r"deploy\release32_debug") 717 file_list_64_debug = build_file_list("x64 Debug", r"deploy\release64_debug") 718 719 file_list_32_static = build_file_list("x86", r"deploy_static\release32") 720 file_list_64_static = build_file_list("x64", r"deploy_static\release64") 721 722 file_list_32_static_debug = build_file_list("x86 Debug", r"deploy_static\release32_debug") 723 file_list_64_static_debug = build_file_list("x64 Debug", r"deploy_static\release64_debug") 724 725 # Build our ZIPs! 726 cemu_win32_zip_fn = snap_base_path + "-win32-release-shared.zip" 727 cemu_win64_zip_fn = snap_base_path + "-win64-release-shared.zip" 728 729 cemu_win32_debug_zip_fn = snap_base_path + "-win32-debug-shared.zip" 730 cemu_win64_debug_zip_fn = snap_base_path + "-win64-debug-shared.zip" 731 732 cemu_win32_static_zip_fn = snap_base_path + "-win32-release-static.zip" 733 cemu_win64_static_zip_fn = snap_base_path + "-win64-release-static.zip" 734 735 cemu_win32_static_debug_zip_fn = snap_base_path + "-win32-debug-static.zip" 736 cemu_win64_static_debug_zip_fn = snap_base_path + "-win64-debug-static.zip" 737 738 make_zip("x86", cemu_win32_zip_fn, file_list_32) 739 make_zip("x64", cemu_win64_zip_fn, file_list_64) 740 741 make_zip("x86 Debug", cemu_win32_debug_zip_fn, file_list_32_debug) 742 make_zip("x64 Debug", cemu_win64_debug_zip_fn, file_list_64_debug) 743 744 make_zip("x86 Static", cemu_win32_static_zip_fn, file_list_32_static) 745 make_zip("x64 Static", cemu_win64_static_zip_fn, file_list_64_static) 746 747 make_zip("x86 Static Debug", cemu_win32_static_debug_zip_fn, file_list_32_static_debug) 748 make_zip("x64 Static Debug", cemu_win64_static_debug_zip_fn, file_list_64_static_debug) 749 750 # Upload everything! 751 upload_snapshot(cemu_win32_zip_fn, cur_timestamp, snap_base_fn, bintray_api_username, bintray_api_key) 752 upload_snapshot(cemu_win64_zip_fn, cur_timestamp, snap_base_fn, bintray_api_username, bintray_api_key) 753 754 upload_snapshot(cemu_win32_debug_zip_fn, cur_timestamp, snap_base_fn, bintray_api_username, bintray_api_key) 755 upload_snapshot(cemu_win64_debug_zip_fn, cur_timestamp, snap_base_fn, bintray_api_username, bintray_api_key) 756 757 upload_snapshot(cemu_win32_static_zip_fn, cur_timestamp, snap_base_fn, bintray_api_username, bintray_api_key) 758 upload_snapshot(cemu_win64_static_zip_fn, cur_timestamp, snap_base_fn, bintray_api_username, bintray_api_key) 759 760 upload_snapshot(cemu_win32_static_debug_zip_fn, cur_timestamp, snap_base_fn, bintray_api_username, bintray_api_key) 761 upload_snapshot(cemu_win64_static_debug_zip_fn, cur_timestamp, snap_base_fn, bintray_api_username, bintray_api_key) 762 763 print(" * Snapshot deployment complete!") 764 765def usage(msg = None): 766 if msg: 767 print(msg) 768 769 print("Usage: %s [make_checksum|install|deploy]" % sys.argv[0]) 770 sys.exit(1) 771 772if __name__ == "__main__": 773 if len(sys.argv) != 2: 774 usage() 775 sys.exit(1) 776 777 if sys.argv[1] == "make_checksum": 778 make_checksum() 779 elif sys.argv[1] == "install": 780 install_deps() 781 elif sys.argv[1] == "deploy": 782 deploy_snapshots() 783 else: 784 usage("ERROR: Invalid command!") 785