LEFT | RIGHT |
1 # This file is part of the Adblock Plus web scripts, | 1 # This file is part of the Adblock Plus web scripts, |
2 # Copyright (C) 2006-present eyeo GmbH | 2 # Copyright (C) 2006-present eyeo GmbH |
3 # | 3 # |
4 # Adblock Plus is free software: you can redistribute it and/or modify | 4 # Adblock Plus is free software: you can redistribute it and/or modify |
5 # it under the terms of the GNU General Public License version 3 as | 5 # it under the terms of the GNU General Public License version 3 as |
6 # published by the Free Software Foundation. | 6 # published by the Free Software Foundation. |
7 # | 7 # |
8 # Adblock Plus is distributed in the hope that it will be useful, | 8 # Adblock Plus is distributed in the hope that it will be useful, |
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 import zipfile | 46 import zipfile |
47 import contextlib | 47 import contextlib |
48 from xml.dom.minidom import parse as parseXml | 48 from xml.dom.minidom import parse as parseXml |
49 | 49 |
50 from Crypto.PublicKey import RSA | 50 from Crypto.PublicKey import RSA |
51 from Crypto.Signature import PKCS1_v1_5 | 51 from Crypto.Signature import PKCS1_v1_5 |
52 import Crypto.Hash.SHA256 | 52 import Crypto.Hash.SHA256 |
53 | 53 |
54 from sitescripts.extensions.utils import ( | 54 from sitescripts.extensions.utils import ( |
55 compareVersions, Configuration, | 55 compareVersions, Configuration, |
56 writeAndroidUpdateManifest | 56 writeAndroidUpdateManifest, |
57 ) | 57 ) |
58 from sitescripts.utils import get_config, get_template | 58 from sitescripts.utils import get_config, get_template |
59 | 59 |
60 MAX_BUILDS = 50 | 60 MAX_BUILDS = 50 |
61 | 61 |
62 | 62 |
63 # Google and Microsoft APIs use HTTP error codes with error message in | 63 # Google and Microsoft APIs use HTTP error codes with error message in |
64 # body. So we add the response body to the HTTPError to get more | 64 # body. So we add the response body to the HTTPError to get more |
65 # meaningful error messages. | 65 # meaningful error messages. |
66 class HTTPErrorBodyHandler(urllib2.HTTPDefaultErrorHandler): | 66 class HTTPErrorBodyHandler(urllib2.HTTPDefaultErrorHandler): |
(...skipping 28 matching lines...) Expand all Loading... |
95 | 95 |
96 def hasChanges(self): | 96 def hasChanges(self): |
97 return self.revision != self.previousRevision | 97 return self.revision != self.previousRevision |
98 | 98 |
99 def getCurrentRevision(self): | 99 def getCurrentRevision(self): |
100 """ | 100 """ |
101 retrieves the current revision ID from the repository | 101 retrieves the current revision ID from the repository |
102 """ | 102 """ |
103 command = [ | 103 command = [ |
104 'hg', 'id', '-i', '-r', self.config.revision, '--config', | 104 'hg', 'id', '-i', '-r', self.config.revision, '--config', |
105 'defaults.id=', self.config.repository | 105 'defaults.id=', self.config.repository, |
106 ] | 106 ] |
107 return subprocess.check_output(command).strip() | 107 return subprocess.check_output(command).strip() |
108 | 108 |
109 def getCurrentBuild(self): | 109 def getCurrentBuild(self): |
110 """ | 110 """ |
111 calculates the (typically numerical) build ID for the current build | 111 calculates the (typically numerical) build ID for the current build |
112 """ | 112 """ |
113 command = ['hg', 'id', '-n', '--config', 'defaults.id=', self.tempdir] | 113 command = ['hg', 'id', '-n', '--config', 'defaults.id=', self.tempdir] |
114 build = subprocess.check_output(command).strip() | 114 build = subprocess.check_output(command).strip() |
115 return build | 115 return build |
116 | 116 |
117 def getChanges(self): | 117 def getChanges(self): |
118 """ | 118 """ |
119 retrieve changes between the current and previous ("first") revision | 119 retrieve changes between the current and previous ("first") revision |
120 """ | 120 """ |
121 command = [ | 121 command = [ |
122 'hg', 'log', '-R', self.tempdir, '-r', | 122 'hg', 'log', '-R', self.tempdir, '-r', |
123 'reverse(ancestors({}))'.format(self.config.revision), '-l', '50', | 123 'reverse(ancestors({}))'.format(self.config.revision), '-l', '50', |
124 '--encoding', 'utf-8', '--template', | 124 '--encoding', 'utf-8', '--template', |
125 '{date|isodate}\\0{author|person}\\0{rev}\\0{desc}\\0\\0', | 125 '{date|isodate}\\0{author|person}\\0{rev}\\0{desc}\\0\\0', |
126 '--config', 'defaults.log=' | 126 '--config', 'defaults.log=', |
127 ] | 127 ] |
128 result = subprocess.check_output(command).decode('utf-8') | 128 result = subprocess.check_output(command).decode('utf-8') |
129 | 129 |
130 for change in result.split('\x00\x00'): | 130 for change in result.split('\x00\x00'): |
131 if change: | 131 if change: |
132 date, author, revision, description = change.split('\x00') | 132 date, author, revision, description = change.split('\x00') |
133 yield {'date': date, 'author': author, 'revision': revision, 'de
scription': description} | 133 yield {'date': date, 'author': author, 'revision': revision, 'de
scription': description} |
134 | 134 |
135 def copyRepository(self): | 135 def copyRepository(self): |
136 """ | 136 """ |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 os.makedirs(baseDir) | 278 os.makedirs(baseDir) |
279 | 279 |
280 # ABP for Android used to have its own update manifest format. We need t
o | 280 # ABP for Android used to have its own update manifest format. We need t
o |
281 # generate both that and the new one in the libadblockplus format as lon
g | 281 # generate both that and the new one in the libadblockplus format as lon
g |
282 # as a significant amount of users is on an old version. | 282 # as a significant amount of users is on an old version. |
283 if self.config.type == 'android': | 283 if self.config.type == 'android': |
284 newManifestPath = os.path.join(baseDir, 'update.json') | 284 newManifestPath = os.path.join(baseDir, 'update.json') |
285 writeAndroidUpdateManifest(newManifestPath, [{ | 285 writeAndroidUpdateManifest(newManifestPath, [{ |
286 'basename': self.basename, | 286 'basename': self.basename, |
287 'version': self.version, | 287 'version': self.version, |
288 'updateURL': self.updateURL | 288 'updateURL': self.updateURL, |
289 }]) | 289 }]) |
290 | 290 |
291 template = get_template(get_config().get('extensions', templateName), | 291 template = get_template(get_config().get('extensions', templateName), |
292 autoescape=autoescape) | 292 autoescape=autoescape) |
293 template.stream({'extensions': [self]}).dump(manifestPath) | 293 template.stream({'extensions': [self]}).dump(manifestPath) |
294 | 294 |
295 def writeIEUpdateManifest(self, versions): | 295 def writeIEUpdateManifest(self, versions): |
296 """ | 296 """ |
297 Writes update.json file for the latest IE build | 297 Writes update.json file for the latest IE build |
298 """ | 298 """ |
299 if len(versions) == 0: | 299 if len(versions) == 0: |
300 return | 300 return |
301 | 301 |
302 version = versions[0] | 302 version = versions[0] |
303 packageName = self.basename + '-' + version + self.config.packageSuffix | 303 packageName = self.basename + '-' + version + self.config.packageSuffix |
304 updateURL = urlparse.urljoin(self.config.nightliesURL, self.basename + '
/' + packageName + '?update') | 304 updateURL = urlparse.urljoin(self.config.nightliesURL, self.basename + '
/' + packageName + '?update') |
305 baseDir = os.path.join(self.config.nightliesDirectory, self.basename) | 305 baseDir = os.path.join(self.config.nightliesDirectory, self.basename) |
306 manifestPath = os.path.join(baseDir, 'update.json') | 306 manifestPath = os.path.join(baseDir, 'update.json') |
307 | 307 |
308 from sitescripts.extensions.utils import writeIEUpdateManifest as doWrit
e | 308 from sitescripts.extensions.utils import writeIEUpdateManifest as doWrit
e |
309 doWrite(manifestPath, [{ | 309 doWrite(manifestPath, [{ |
310 'basename': self.basename, | 310 'basename': self.basename, |
311 'version': version, | 311 'version': version, |
312 'updateURL': updateURL | 312 'updateURL': updateURL, |
313 }]) | 313 }]) |
314 | 314 |
315 for suffix in ['-x86.msi', '-x64.msi', '-gpo-x86.msi', '-gpo-x64.msi']: | 315 for suffix in ['-x86.msi', '-x64.msi', '-gpo-x86.msi', '-gpo-x64.msi']: |
316 linkPath = os.path.join(baseDir, '00latest%s' % suffix) | 316 linkPath = os.path.join(baseDir, '00latest%s' % suffix) |
317 outputPath = os.path.join(baseDir, self.basename + '-' + version + s
uffix) | 317 outputPath = os.path.join(baseDir, self.basename + '-' + version + s
uffix) |
318 self.symlink_or_copy(outputPath, linkPath) | 318 self.symlink_or_copy(outputPath, linkPath) |
319 | 319 |
320 def build(self): | 320 def build(self): |
321 """ | 321 """ |
322 run the build command in the tempdir | 322 run the build command in the tempdir |
323 """ | 323 """ |
324 baseDir = os.path.join(self.config.nightliesDirectory, self.basename) | 324 baseDir = os.path.join(self.config.nightliesDirectory, self.basename) |
325 if not os.path.exists(baseDir): | 325 if not os.path.exists(baseDir): |
326 os.makedirs(baseDir) | 326 os.makedirs(baseDir) |
327 outputFile = '%s-%s%s' % (self.basename, self.version, self.config.packa
geSuffix) | 327 outputFile = '%s-%s%s' % (self.basename, self.version, self.config.packa
geSuffix) |
328 self.path = os.path.join(baseDir, outputFile) | 328 self.path = os.path.join(baseDir, outputFile) |
329 self.updateURL = urlparse.urljoin(self.config.nightliesURL, self.basenam
e + '/' + outputFile + '?update') | 329 self.updateURL = urlparse.urljoin(self.config.nightliesURL, self.basenam
e + '/' + outputFile + '?update') |
330 | 330 |
331 if self.config.type == 'android': | 331 if self.config.type == 'android': |
332 apkFile = open(self.path, 'wb') | 332 apkFile = open(self.path, 'wb') |
333 | 333 |
334 try: | 334 try: |
335 try: | 335 try: |
336 port = get_config().get('extensions', 'androidBuildPort') | 336 port = get_config().get('extensions', 'androidBuildPort') |
337 except ConfigParser.NoOptionError: | 337 except ConfigParser.NoOptionError: |
338 port = '22' | 338 port = '22' |
339 command = ['ssh', '-p', port, get_config().get('extensions', 'an
droidBuildHost')] | 339 command = ['ssh', '-p', port, get_config().get('extensions', 'an
droidBuildHost')] |
340 command.extend(map(pipes.quote, [ | 340 command.extend(map(pipes.quote, [ |
341 '/home/android/bin/makedebugbuild.py', '--revision', | 341 '/home/android/bin/makedebugbuild.py', '--revision', |
342 self.buildNum, '--version', self.version, '--stdout' | 342 self.buildNum, '--version', self.version, '--stdout', |
343 ])) | 343 ])) |
344 subprocess.check_call(command, stdout=apkFile, close_fds=True) | 344 subprocess.check_call(command, stdout=apkFile, close_fds=True) |
345 except: | 345 except: |
346 # clear broken output if any | 346 # clear broken output if any |
347 if os.path.exists(self.path): | 347 if os.path.exists(self.path): |
348 os.remove(self.path) | 348 os.remove(self.path) |
349 raise | 349 raise |
350 else: | 350 else: |
351 env = os.environ | 351 env = os.environ |
352 spiderMonkeyBinary = self.config.spiderMonkeyBinary | 352 spiderMonkeyBinary = self.config.spiderMonkeyBinary |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
406 packageFile = self.basename + '-' + version + self.config.packageSuf
fix | 406 packageFile = self.basename + '-' + version + self.config.packageSuf
fix |
407 changelogFile = self.basename + '-' + version + '.changelog.xhtml' | 407 changelogFile = self.basename + '-' + version + '.changelog.xhtml' |
408 if not os.path.exists(os.path.join(baseDir, packageFile)): | 408 if not os.path.exists(os.path.join(baseDir, packageFile)): |
409 # Oops | 409 # Oops |
410 continue | 410 continue |
411 | 411 |
412 link = { | 412 link = { |
413 'version': version, | 413 'version': version, |
414 'download': packageFile, | 414 'download': packageFile, |
415 'mtime': os.path.getmtime(os.path.join(baseDir, packageFile)), | 415 'mtime': os.path.getmtime(os.path.join(baseDir, packageFile)), |
416 'size': os.path.getsize(os.path.join(baseDir, packageFile)) | 416 'size': os.path.getsize(os.path.join(baseDir, packageFile)), |
417 } | 417 } |
418 if os.path.exists(os.path.join(baseDir, changelogFile)): | 418 if os.path.exists(os.path.join(baseDir, changelogFile)): |
419 link['changelog'] = changelogFile | 419 link['changelog'] = changelogFile |
420 links.append(link) | 420 links.append(link) |
421 template = get_template(get_config().get('extensions', 'nightlyIndexPage
')) | 421 template = get_template(get_config().get('extensions', 'nightlyIndexPage
')) |
422 template.stream({'config': self.config, 'links': links}).dump(outputPath
) | 422 template.stream({'config': self.config, 'links': links}).dump(outputPath
) |
423 | 423 |
424 def read_downloads_lockfile(self): | 424 def read_downloads_lockfile(self): |
425 path = get_config().get('extensions', 'downloadLockFile') | 425 path = get_config().get('extensions', 'downloadLockFile') |
426 try: | 426 try: |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 config = get_config() | 516 config = get_config() |
517 | 517 |
518 upload_url = ('https://addons.mozilla.org/api/v3/addons/{}/' | 518 upload_url = ('https://addons.mozilla.org/api/v3/addons/{}/' |
519 'versions/{}/').format(self.extensionID, self.version) | 519 'versions/{}/').format(self.extensionID, self.version) |
520 | 520 |
521 with open(self.path, 'rb') as file: | 521 with open(self.path, 'rb') as file: |
522 data, content_type = urllib3.filepost.encode_multipart_formdata({ | 522 data, content_type = urllib3.filepost.encode_multipart_formdata({ |
523 'upload': ( | 523 'upload': ( |
524 os.path.basename(self.path), | 524 os.path.basename(self.path), |
525 file.read(), | 525 file.read(), |
526 'application/x-xpinstall' | 526 'application/x-xpinstall', |
527 ) | 527 ), |
528 }) | 528 }) |
529 | 529 |
530 request = self.generate_mozilla_jwt_request( | 530 request = self.generate_mozilla_jwt_request( |
531 config.get('extensions', 'amo_key'), | 531 config.get('extensions', 'amo_key'), |
532 config.get('extensions', 'amo_secret'), | 532 config.get('extensions', 'amo_secret'), |
533 upload_url, | 533 upload_url, |
534 'PUT', | 534 'PUT', |
535 data, | 535 data, |
536 [('Content-Type', content_type)], | 536 [('Content-Type', content_type)], |
537 ) | 537 ) |
538 | 538 |
539 try: | 539 try: |
540 urllib2.urlopen(request).close() | 540 urllib2.urlopen(request).close() |
541 except urllib2.HTTPError as e: | 541 except urllib2.HTTPError as e: |
542 try: | 542 try: |
543 logging.error(e.read()) | 543 logging.error(e.read()) |
544 finally: | 544 finally: |
545 e.close() | 545 e.close() |
546 raise | 546 raise |
547 | 547 |
548 self.add_to_downloads_lockfile( | 548 self.add_to_downloads_lockfile( |
549 self.config.type, | 549 self.config.type, |
550 { | 550 { |
551 'buildtype': 'devbuild', | 551 'buildtype': 'devbuild', |
552 'app_id': self.extensionID, | 552 'app_id': self.extensionID, |
553 'version': self.version, | 553 'version': self.version, |
554 } | 554 }, |
555 ) | 555 ) |
556 os.remove(self.path) | 556 os.remove(self.path) |
557 | 557 |
558 def download_from_mozilla_addons(self, buildtype, version, app_id): | 558 def download_from_mozilla_addons(self, buildtype, version, app_id): |
559 config = get_config() | 559 config = get_config() |
560 iss = config.get('extensions', 'amo_key') | 560 iss = config.get('extensions', 'amo_key') |
561 secret = config.get('extensions', 'amo_secret') | 561 secret = config.get('extensions', 'amo_secret') |
562 | 562 |
563 url = ('https://addons.mozilla.org/api/v3/addons/{}/' | 563 url = ('https://addons.mozilla.org/api/v3/addons/{}/' |
564 'versions/{}/').format(app_id, version) | 564 'versions/{}/').format(app_id, version) |
565 | 565 |
566 request = self.generate_mozilla_jwt_request( | 566 request = self.generate_mozilla_jwt_request( |
567 iss, secret, url, 'GET', | 567 iss, secret, url, 'GET', |
568 ) | 568 ) |
569 response = json.load(urllib2.urlopen(request)) | 569 response = json.load(urllib2.urlopen(request)) |
570 | 570 |
571 filename = '{}-{}.xpi'.format(self.basename, version) | 571 filename = '{}-{}.xpi'.format(self.basename, version) |
572 self.path = os.path.join( | 572 self.path = os.path.join( |
573 config.get('extensions', 'nightliesDirectory'), | 573 config.get('extensions', 'nightliesDirectory'), |
574 self.basename, | 574 self.basename, |
575 filename | 575 filename, |
576 ) | 576 ) |
577 | 577 |
578 necessary = ['passed_review', 'reviewed', 'processed', 'valid'] | 578 necessary = ['passed_review', 'reviewed', 'processed', 'valid'] |
579 if all(response[x] for x in necessary): | 579 if all(response[x] for x in necessary): |
580 download_url = response['files'][0]['download_url'] | 580 download_url = response['files'][0]['download_url'] |
581 checksum = response['files'][0]['hash'] | 581 checksum = response['files'][0]['hash'] |
582 | 582 |
583 request = self.generate_mozilla_jwt_request( | 583 request = self.generate_mozilla_jwt_request( |
584 iss, secret, download_url, 'GET', | 584 iss, secret, download_url, 'GET', |
585 ) | 585 ) |
(...skipping 10 matching lines...) Expand all Loading... |
596 if returned_checksum != checksum: | 596 if returned_checksum != checksum: |
597 logging.error('Checksum could not be verified: {} vs {}' | 597 logging.error('Checksum could not be verified: {} vs {}' |
598 ''.format(checksum, returned_checksum)) | 598 ''.format(checksum, returned_checksum)) |
599 | 599 |
600 with open(self.path, 'w') as fp: | 600 with open(self.path, 'w') as fp: |
601 fp.write(file_content) | 601 fp.write(file_content) |
602 | 602 |
603 self.update_link = os.path.join( | 603 self.update_link = os.path.join( |
604 config.get('extensions', 'nightliesURL'), | 604 config.get('extensions', 'nightliesURL'), |
605 self.basename, | 605 self.basename, |
606 filename | 606 filename, |
607 ) | 607 ) |
608 | 608 |
609 self.remove_from_downloads_lockfile(self.config.type, | 609 self.remove_from_downloads_lockfile(self.config.type, |
610 'version', | 610 'version', |
611 version) | 611 version) |
612 elif not response['passed_review'] or not response['valid']: | 612 elif not response['passed_review'] or not response['valid']: |
613 # When the review failed for any reason, we want to know about it | 613 # When the review failed for any reason, we want to know about it |
614 logging.error(json.dumps(response, indent=4)) | 614 logging.error(json.dumps(response, indent=4)) |
615 self.remove_from_downloads_lockfile(self.config.type, | 615 self.remove_from_downloads_lockfile(self.config.type, |
616 'version', | 616 'version', |
617 version) | 617 version) |
618 | 618 |
619 def uploadToChromeWebStore(self): | 619 def uploadToChromeWebStore(self): |
620 | 620 |
621 opener = urllib2.build_opener(HTTPErrorBodyHandler) | 621 opener = urllib2.build_opener(HTTPErrorBodyHandler) |
622 | 622 |
623 # use refresh token to obtain a valid access token | 623 # use refresh token to obtain a valid access token |
624 # https://developers.google.com/accounts/docs/OAuth2WebServer#refresh | 624 # https://developers.google.com/accounts/docs/OAuth2WebServer#refresh |
625 | 625 |
626 response = json.load(opener.open( | 626 response = json.load(opener.open( |
627 'https://accounts.google.com/o/oauth2/token', | 627 'https://accounts.google.com/o/oauth2/token', |
628 | 628 |
629 urlencode([ | 629 urlencode([ |
630 ('refresh_token', self.config.refreshToken), | 630 ('refresh_token', self.config.refreshToken), |
631 ('client_id', self.config.clientID), | 631 ('client_id', self.config.clientID), |
632 ('client_secret', self.config.clientSecret), | 632 ('client_secret', self.config.clientSecret), |
633 ('grant_type', 'refresh_token'), | 633 ('grant_type', 'refresh_token'), |
634 ]) | 634 ]), |
635 )) | 635 )) |
636 | 636 |
637 auth_token = '%s %s' % (response['token_type'], response['access_token']
) | 637 auth_token = '%s %s' % (response['token_type'], response['access_token']
) |
638 | 638 |
639 # upload a new version with the Chrome Web Store API | 639 # upload a new version with the Chrome Web Store API |
640 # https://developer.chrome.com/webstore/using_webstore_api#uploadexisitn
g | 640 # https://developer.chrome.com/webstore/using_webstore_api#uploadexisitn
g |
641 | 641 |
642 request = urllib2.Request('https://www.googleapis.com/upload/chromewebst
ore/v1.1/items/' + self.config.devbuildGalleryID) | 642 request = urllib2.Request('https://www.googleapis.com/upload/chromewebst
ore/v1.1/items/' + self.config.devbuildGalleryID) |
643 request.get_method = lambda: 'PUT' | 643 request.get_method = lambda: 'PUT' |
644 request.add_header('Authorization', auth_token) | 644 request.add_header('Authorization', auth_token) |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
742 def upload_to_windows_store(self): | 742 def upload_to_windows_store(self): |
743 opener = urllib2.build_opener(HTTPErrorBodyHandler) | 743 opener = urllib2.build_opener(HTTPErrorBodyHandler) |
744 | 744 |
745 headers = {'Authorization': self.get_windows_store_access_token(), | 745 headers = {'Authorization': self.get_windows_store_access_token(), |
746 'Content-type': 'application/json'} | 746 'Content-type': 'application/json'} |
747 | 747 |
748 # Get application | 748 # Get application |
749 # https://docs.microsoft.com/en-us/windows/uwp/monetize/get-an-app | 749 # https://docs.microsoft.com/en-us/windows/uwp/monetize/get-an-app |
750 api_path = '{}/v1.0/my/applications/{}'.format( | 750 api_path = '{}/v1.0/my/applications/{}'.format( |
751 'https://manage.devcenter.microsoft.com', | 751 'https://manage.devcenter.microsoft.com', |
752 self.config.devbuildGalleryID | 752 self.config.devbuildGalleryID, |
753 ) | 753 ) |
754 | 754 |
755 request = urllib2.Request(api_path, None, headers) | 755 request = urllib2.Request(api_path, None, headers) |
756 with contextlib.closing(opener.open(request)) as response: | 756 with contextlib.closing(opener.open(request)) as response: |
757 app_obj = json.load(response) | 757 app_obj = json.load(response) |
758 | 758 |
759 # Delete existing in-progress submission | 759 # Delete existing in-progress submission |
760 # https://docs.microsoft.com/en-us/windows/uwp/monetize/delete-an-app-su
bmission | 760 # https://docs.microsoft.com/en-us/windows/uwp/monetize/delete-an-app-su
bmission |
761 submissions_path = api_path + '/submissions' | 761 submissions_path = api_path + '/submissions' |
762 if 'pendingApplicationSubmission' in app_obj: | 762 if 'pendingApplicationSubmission' in app_obj: |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
889 # write update manifest | 889 # write update manifest |
890 self.writeUpdateManifest() | 890 self.writeUpdateManifest() |
891 | 891 |
892 # retire old builds | 892 # retire old builds |
893 versions = self.retireBuilds() | 893 versions = self.retireBuilds() |
894 # update index page | 894 # update index page |
895 self.updateIndex(versions) | 895 self.updateIndex(versions) |
896 | 896 |
897 # Update soft link to latest build | 897 # Update soft link to latest build |
898 baseDir = os.path.join( | 898 baseDir = os.path.join( |
899 self.config.nightliesDirectory, self.basename | 899 self.config.nightliesDirectory, self.basename, |
900 ) | 900 ) |
901 linkPath = os.path.join( | 901 linkPath = os.path.join( |
902 baseDir, '00latest' + self.config.packageSuffix | 902 baseDir, '00latest' + self.config.packageSuffix, |
903 ) | 903 ) |
904 | 904 |
905 self.symlink_or_copy(self.path, linkPath) | 905 self.symlink_or_copy(self.path, linkPath) |
906 finally: | 906 finally: |
907 # clean up | 907 # clean up |
908 if self.tempdir: | 908 if self.tempdir: |
909 shutil.rmtree(self.tempdir, ignore_errors=True) | 909 shutil.rmtree(self.tempdir, ignore_errors=True) |
910 | 910 |
911 | 911 |
912 def main(download=False): | 912 def main(download=False): |
(...skipping 23 matching lines...) Expand all Loading... |
936 | 936 |
937 file = open(nightlyConfigFile, 'wb') | 937 file = open(nightlyConfigFile, 'wb') |
938 nightlyConfig.write(file) | 938 nightlyConfig.write(file) |
939 | 939 |
940 | 940 |
941 if __name__ == '__main__': | 941 if __name__ == '__main__': |
942 parser = argparse.ArgumentParser() | 942 parser = argparse.ArgumentParser() |
943 parser.add_argument('--download', action='store_true', default=False) | 943 parser.add_argument('--download', action='store_true', default=False) |
944 args = parser.parse_args() | 944 args = parser.parse_args() |
945 main(args.download) | 945 main(args.download) |
LEFT | RIGHT |