| OLD | NEW | 
|---|
| 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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 42 from urllib import urlencode | 42 from urllib import urlencode | 
| 43 import urllib2 | 43 import urllib2 | 
| 44 import urlparse | 44 import urlparse | 
| 45 import zipfile | 45 import zipfile | 
| 46 import contextlib | 46 import contextlib | 
| 47 | 47 | 
| 48 from xml.dom.minidom import parse as parseXml | 48 from xml.dom.minidom import parse as parseXml | 
| 49 | 49 | 
| 50 from sitescripts.extensions.utils import ( | 50 from sitescripts.extensions.utils import ( | 
| 51     compareVersions, Configuration, | 51     compareVersions, Configuration, | 
| 52     writeAndroidUpdateManifest | 52     writeAndroidUpdateManifest, | 
| 53 ) | 53 ) | 
| 54 from sitescripts.utils import get_config, get_template | 54 from sitescripts.utils import get_config, get_template | 
| 55 | 55 | 
| 56 MAX_BUILDS = 50 | 56 MAX_BUILDS = 50 | 
| 57 | 57 | 
| 58 | 58 | 
| 59 # Google and Microsoft APIs use HTTP error codes with error message in | 59 # Google and Microsoft APIs use HTTP error codes with error message in | 
| 60 # body. So we add the response body to the HTTPError to get more | 60 # body. So we add the response body to the HTTPError to get more | 
| 61 # meaningful error messages. | 61 # meaningful error messages. | 
| 62 class HTTPErrorBodyHandler(urllib2.HTTPDefaultErrorHandler): | 62 class HTTPErrorBodyHandler(urllib2.HTTPDefaultErrorHandler): | 
| (...skipping 28 matching lines...) Expand all  Loading... | 
| 91 | 91 | 
| 92     def hasChanges(self): | 92     def hasChanges(self): | 
| 93         return self.revision != self.previousRevision | 93         return self.revision != self.previousRevision | 
| 94 | 94 | 
| 95     def getCurrentRevision(self): | 95     def getCurrentRevision(self): | 
| 96         """ | 96         """ | 
| 97             retrieves the current revision ID from the repository | 97             retrieves the current revision ID from the repository | 
| 98         """ | 98         """ | 
| 99         command = [ | 99         command = [ | 
| 100             'hg', 'id', '-i', '-r', self.config.revision, '--config', | 100             'hg', 'id', '-i', '-r', self.config.revision, '--config', | 
| 101             'defaults.id=', self.config.repository | 101             'defaults.id=', self.config.repository, | 
| 102         ] | 102         ] | 
| 103         return subprocess.check_output(command).strip() | 103         return subprocess.check_output(command).strip() | 
| 104 | 104 | 
| 105     def getCurrentBuild(self): | 105     def getCurrentBuild(self): | 
| 106         """ | 106         """ | 
| 107             calculates the (typically numerical) build ID for the current build | 107             calculates the (typically numerical) build ID for the current build | 
| 108         """ | 108         """ | 
| 109         command = ['hg', 'id', '-n', '--config', 'defaults.id=', self.tempdir] | 109         command = ['hg', 'id', '-n', '--config', 'defaults.id=', self.tempdir] | 
| 110         build = subprocess.check_output(command).strip() | 110         build = subprocess.check_output(command).strip() | 
| 111         return build | 111         return build | 
| 112 | 112 | 
| 113     def getChanges(self): | 113     def getChanges(self): | 
| 114         """ | 114         """ | 
| 115           retrieve changes between the current and previous ("first") revision | 115           retrieve changes between the current and previous ("first") revision | 
| 116         """ | 116         """ | 
| 117         command = [ | 117         command = [ | 
| 118             'hg', 'log', '-R', self.tempdir, '-r', | 118             'hg', 'log', '-R', self.tempdir, '-r', | 
| 119             'reverse(ancestors({}))'.format(self.config.revision), '-l', '50', | 119             'reverse(ancestors({}))'.format(self.config.revision), '-l', '50', | 
| 120             '--encoding', 'utf-8', '--template', | 120             '--encoding', 'utf-8', '--template', | 
| 121             '{date|isodate}\\0{author|person}\\0{rev}\\0{desc}\\0\\0', | 121             '{date|isodate}\\0{author|person}\\0{rev}\\0{desc}\\0\\0', | 
| 122             '--config', 'defaults.log=' | 122             '--config', 'defaults.log=', | 
| 123         ] | 123         ] | 
| 124         result = subprocess.check_output(command).decode('utf-8') | 124         result = subprocess.check_output(command).decode('utf-8') | 
| 125 | 125 | 
| 126         for change in result.split('\x00\x00'): | 126         for change in result.split('\x00\x00'): | 
| 127             if change: | 127             if change: | 
| 128                 date, author, revision, description = change.split('\x00') | 128                 date, author, revision, description = change.split('\x00') | 
| 129                 yield {'date': date, 'author': author, 'revision': revision, 'de
     scription': description} | 129                 yield {'date': date, 'author': author, 'revision': revision, 'de
     scription': description} | 
| 130 | 130 | 
| 131     def copyRepository(self): | 131     def copyRepository(self): | 
| 132         """ | 132         """ | 
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 274             os.makedirs(baseDir) | 274             os.makedirs(baseDir) | 
| 275 | 275 | 
| 276         # ABP for Android used to have its own update manifest format. We need t
     o | 276         # ABP for Android used to have its own update manifest format. We need t
     o | 
| 277         # generate both that and the new one in the libadblockplus format as lon
     g | 277         # generate both that and the new one in the libadblockplus format as lon
     g | 
| 278         # as a significant amount of users is on an old version. | 278         # as a significant amount of users is on an old version. | 
| 279         if self.config.type == 'android': | 279         if self.config.type == 'android': | 
| 280             newManifestPath = os.path.join(baseDir, 'update.json') | 280             newManifestPath = os.path.join(baseDir, 'update.json') | 
| 281             writeAndroidUpdateManifest(newManifestPath, [{ | 281             writeAndroidUpdateManifest(newManifestPath, [{ | 
| 282                 'basename': self.basename, | 282                 'basename': self.basename, | 
| 283                 'version': self.version, | 283                 'version': self.version, | 
| 284                 'updateURL': self.updateURL | 284                 'updateURL': self.updateURL, | 
| 285             }]) | 285             }]) | 
| 286 | 286 | 
| 287         template = get_template(get_config().get('extensions', templateName), | 287         template = get_template(get_config().get('extensions', templateName), | 
| 288                                 autoescape=autoescape) | 288                                 autoescape=autoescape) | 
| 289         template.stream({'extensions': [self]}).dump(manifestPath) | 289         template.stream({'extensions': [self]}).dump(manifestPath) | 
| 290 | 290 | 
| 291     def writeIEUpdateManifest(self, versions): | 291     def writeIEUpdateManifest(self, versions): | 
| 292         """ | 292         """ | 
| 293           Writes update.json file for the latest IE build | 293           Writes update.json file for the latest IE build | 
| 294         """ | 294         """ | 
| 295         if len(versions) == 0: | 295         if len(versions) == 0: | 
| 296             return | 296             return | 
| 297 | 297 | 
| 298         version = versions[0] | 298         version = versions[0] | 
| 299         packageName = self.basename + '-' + version + self.config.packageSuffix | 299         packageName = self.basename + '-' + version + self.config.packageSuffix | 
| 300         updateURL = urlparse.urljoin(self.config.nightliesURL, self.basename + '
     /' + packageName + '?update') | 300         updateURL = urlparse.urljoin(self.config.nightliesURL, self.basename + '
     /' + packageName + '?update') | 
| 301         baseDir = os.path.join(self.config.nightliesDirectory, self.basename) | 301         baseDir = os.path.join(self.config.nightliesDirectory, self.basename) | 
| 302         manifestPath = os.path.join(baseDir, 'update.json') | 302         manifestPath = os.path.join(baseDir, 'update.json') | 
| 303 | 303 | 
| 304         from sitescripts.extensions.utils import writeIEUpdateManifest as doWrit
     e | 304         from sitescripts.extensions.utils import writeIEUpdateManifest as doWrit
     e | 
| 305         doWrite(manifestPath, [{ | 305         doWrite(manifestPath, [{ | 
| 306             'basename': self.basename, | 306             'basename': self.basename, | 
| 307             'version': version, | 307             'version': version, | 
| 308             'updateURL': updateURL | 308             'updateURL': updateURL, | 
| 309         }]) | 309         }]) | 
| 310 | 310 | 
| 311         for suffix in ['-x86.msi', '-x64.msi', '-gpo-x86.msi', '-gpo-x64.msi']: | 311         for suffix in ['-x86.msi', '-x64.msi', '-gpo-x86.msi', '-gpo-x64.msi']: | 
| 312             linkPath = os.path.join(baseDir, '00latest%s' % suffix) | 312             linkPath = os.path.join(baseDir, '00latest%s' % suffix) | 
| 313             outputPath = os.path.join(baseDir, self.basename + '-' + version + s
     uffix) | 313             outputPath = os.path.join(baseDir, self.basename + '-' + version + s
     uffix) | 
| 314             self.symlink_or_copy(outputPath, linkPath) | 314             self.symlink_or_copy(outputPath, linkPath) | 
| 315 | 315 | 
| 316     def build(self): | 316     def build(self): | 
| 317         """ | 317         """ | 
| 318           run the build command in the tempdir | 318           run the build command in the tempdir | 
| 319         """ | 319         """ | 
| 320         baseDir = os.path.join(self.config.nightliesDirectory, self.basename) | 320         baseDir = os.path.join(self.config.nightliesDirectory, self.basename) | 
| 321         if not os.path.exists(baseDir): | 321         if not os.path.exists(baseDir): | 
| 322             os.makedirs(baseDir) | 322             os.makedirs(baseDir) | 
| 323         outputFile = '%s-%s%s' % (self.basename, self.version, self.config.packa
     geSuffix) | 323         outputFile = '%s-%s%s' % (self.basename, self.version, self.config.packa
     geSuffix) | 
| 324         self.path = os.path.join(baseDir, outputFile) | 324         self.path = os.path.join(baseDir, outputFile) | 
| 325         self.updateURL = urlparse.urljoin(self.config.nightliesURL, self.basenam
     e + '/' + outputFile + '?update') | 325         self.updateURL = urlparse.urljoin(self.config.nightliesURL, self.basenam
     e + '/' + outputFile + '?update') | 
| 326 | 326 | 
| 327         if self.config.type == 'android': | 327         if self.config.type == 'android': | 
| 328             apkFile = open(self.path, 'wb') | 328             apkFile = open(self.path, 'wb') | 
| 329 | 329 | 
| 330             try: | 330             try: | 
| 331                 try: | 331                 try: | 
| 332                     port = get_config().get('extensions', 'androidBuildPort') | 332                     port = get_config().get('extensions', 'androidBuildPort') | 
| 333                 except ConfigParser.NoOptionError: | 333                 except ConfigParser.NoOptionError: | 
| 334                     port = '22' | 334                     port = '22' | 
| 335                 command = ['ssh', '-p', port, get_config().get('extensions', 'an
     droidBuildHost')] | 335                 command = ['ssh', '-p', port, get_config().get('extensions', 'an
     droidBuildHost')] | 
| 336                 command.extend(map(pipes.quote, [ | 336                 command.extend(map(pipes.quote, [ | 
| 337                     '/home/android/bin/makedebugbuild.py', '--revision', | 337                     '/home/android/bin/makedebugbuild.py', '--revision', | 
| 338                     self.buildNum, '--version', self.version, '--stdout' | 338                     self.buildNum, '--version', self.version, '--stdout', | 
| 339                 ])) | 339                 ])) | 
| 340                 subprocess.check_call(command, stdout=apkFile, close_fds=True) | 340                 subprocess.check_call(command, stdout=apkFile, close_fds=True) | 
| 341             except: | 341             except: | 
| 342                 # clear broken output if any | 342                 # clear broken output if any | 
| 343                 if os.path.exists(self.path): | 343                 if os.path.exists(self.path): | 
| 344                     os.remove(self.path) | 344                     os.remove(self.path) | 
| 345                 raise | 345                 raise | 
| 346         else: | 346         else: | 
| 347             env = os.environ | 347             env = os.environ | 
| 348             spiderMonkeyBinary = self.config.spiderMonkeyBinary | 348             spiderMonkeyBinary = self.config.spiderMonkeyBinary | 
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 402             packageFile = self.basename + '-' + version + self.config.packageSuf
     fix | 402             packageFile = self.basename + '-' + version + self.config.packageSuf
     fix | 
| 403             changelogFile = self.basename + '-' + version + '.changelog.xhtml' | 403             changelogFile = self.basename + '-' + version + '.changelog.xhtml' | 
| 404             if not os.path.exists(os.path.join(baseDir, packageFile)): | 404             if not os.path.exists(os.path.join(baseDir, packageFile)): | 
| 405                 # Oops | 405                 # Oops | 
| 406                 continue | 406                 continue | 
| 407 | 407 | 
| 408             link = { | 408             link = { | 
| 409                 'version': version, | 409                 'version': version, | 
| 410                 'download': packageFile, | 410                 'download': packageFile, | 
| 411                 'mtime': os.path.getmtime(os.path.join(baseDir, packageFile)), | 411                 'mtime': os.path.getmtime(os.path.join(baseDir, packageFile)), | 
| 412                 'size': os.path.getsize(os.path.join(baseDir, packageFile)) | 412                 'size': os.path.getsize(os.path.join(baseDir, packageFile)), | 
| 413             } | 413             } | 
| 414             if os.path.exists(os.path.join(baseDir, changelogFile)): | 414             if os.path.exists(os.path.join(baseDir, changelogFile)): | 
| 415                 link['changelog'] = changelogFile | 415                 link['changelog'] = changelogFile | 
| 416             links.append(link) | 416             links.append(link) | 
| 417         template = get_template(get_config().get('extensions', 'nightlyIndexPage
     ')) | 417         template = get_template(get_config().get('extensions', 'nightlyIndexPage
     ')) | 
| 418         template.stream({'config': self.config, 'links': links}).dump(outputPath
     ) | 418         template.stream({'config': self.config, 'links': links}).dump(outputPath
     ) | 
| 419 | 419 | 
| 420     def read_downloads_lockfile(self): | 420     def read_downloads_lockfile(self): | 
| 421         path = get_config().get('extensions', 'downloadLockFile') | 421         path = get_config().get('extensions', 'downloadLockFile') | 
| 422         try: | 422         try: | 
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 464         issued = int(time.time()) | 464         issued = int(time.time()) | 
| 465         payload = { | 465         payload = { | 
| 466             'iss': issuer, | 466             'iss': issuer, | 
| 467             'jti': random.random(), | 467             'jti': random.random(), | 
| 468             'iat': issued, | 468             'iat': issued, | 
| 469             'exp': issued + 60, | 469             'exp': issued + 60, | 
| 470         } | 470         } | 
| 471 | 471 | 
| 472         hmac_data = '{}.{}'.format( | 472         hmac_data = '{}.{}'.format( | 
| 473             base64.b64encode(json.dumps(header)), | 473             base64.b64encode(json.dumps(header)), | 
| 474             base64.b64encode(json.dumps(payload)) | 474             base64.b64encode(json.dumps(payload)), | 
| 475         ) | 475         ) | 
| 476 | 476 | 
| 477         signature = hmac.new(secret, msg=hmac_data, | 477         signature = hmac.new(secret, msg=hmac_data, | 
| 478                              digestmod=hashlib.sha256).digest() | 478                              digestmod=hashlib.sha256).digest() | 
| 479         token = '{}.{}'.format(hmac_data, base64.b64encode(signature)) | 479         token = '{}.{}'.format(hmac_data, base64.b64encode(signature)) | 
| 480 | 480 | 
| 481         request = urllib2.Request(url, data) | 481         request = urllib2.Request(url, data) | 
| 482         request.add_header('Authorization', 'JWT ' + token) | 482         request.add_header('Authorization', 'JWT ' + token) | 
| 483         for header in add_headers: | 483         for header in add_headers: | 
| 484             request.add_header(*header) | 484             request.add_header(*header) | 
| 485         request.get_method = lambda: method | 485         request.get_method = lambda: method | 
| 486 | 486 | 
| 487         return request | 487         return request | 
| 488 | 488 | 
| 489     def uploadToMozillaAddons(self): | 489     def uploadToMozillaAddons(self): | 
| 490         import urllib3 | 490         import urllib3 | 
| 491 | 491 | 
| 492         config = get_config() | 492         config = get_config() | 
| 493 | 493 | 
| 494         upload_url = ('https://addons.mozilla.org/api/v3/addons/{}/' | 494         upload_url = ('https://addons.mozilla.org/api/v3/addons/{}/' | 
| 495                       'versions/{}/').format(self.extensionID, self.version) | 495                       'versions/{}/').format(self.extensionID, self.version) | 
| 496 | 496 | 
| 497         with open(self.path, 'rb') as file: | 497         with open(self.path, 'rb') as file: | 
| 498             data, content_type = urllib3.filepost.encode_multipart_formdata({ | 498             data, content_type = urllib3.filepost.encode_multipart_formdata({ | 
| 499                 'upload': ( | 499                 'upload': ( | 
| 500                     os.path.basename(self.path), | 500                     os.path.basename(self.path), | 
| 501                     file.read(), | 501                     file.read(), | 
| 502                     'application/x-xpinstall' | 502                     'application/x-xpinstall', | 
| 503                 ) | 503                 ), | 
| 504             }) | 504             }) | 
| 505 | 505 | 
| 506         request = self.generate_jwt_request( | 506         request = self.generate_jwt_request( | 
| 507             config.get('extensions', 'amo_key'), | 507             config.get('extensions', 'amo_key'), | 
| 508             config.get('extensions', 'amo_secret'), | 508             config.get('extensions', 'amo_secret'), | 
| 509             upload_url, | 509             upload_url, | 
| 510             'PUT', | 510             'PUT', | 
| 511             data, | 511             data, | 
| 512             [('Content-Type', content_type)] | 512             [('Content-Type', content_type)], | 
| 513         ) | 513         ) | 
| 514 | 514 | 
| 515         try: | 515         try: | 
| 516             urllib2.urlopen(request).close() | 516             urllib2.urlopen(request).close() | 
| 517         except urllib2.HTTPError as e: | 517         except urllib2.HTTPError as e: | 
| 518             try: | 518             try: | 
| 519                 logging.error(e.read()) | 519                 logging.error(e.read()) | 
| 520             finally: | 520             finally: | 
| 521                 e.close() | 521                 e.close() | 
| 522             raise | 522             raise | 
| 523 | 523 | 
| 524         self.add_to_downloads_lockfile( | 524         self.add_to_downloads_lockfile( | 
| 525             self.config.type, | 525             self.config.type, | 
| 526             { | 526             { | 
| 527                 'buildtype': 'devbuild', | 527                 'buildtype': 'devbuild', | 
| 528                 'app_id': self.extensionID, | 528                 'app_id': self.extensionID, | 
| 529                 'version': self.version, | 529                 'version': self.version, | 
| 530             } | 530             }, | 
| 531         ) | 531         ) | 
| 532         os.remove(self.path) | 532         os.remove(self.path) | 
| 533 | 533 | 
| 534     def download_from_mozilla_addons(self, buildtype, version, app_id): | 534     def download_from_mozilla_addons(self, buildtype, version, app_id): | 
| 535         config = get_config() | 535         config = get_config() | 
| 536         iss = config.get('extensions', 'amo_key') | 536         iss = config.get('extensions', 'amo_key') | 
| 537         secret = config.get('extensions', 'amo_secret') | 537         secret = config.get('extensions', 'amo_secret') | 
| 538 | 538 | 
| 539         url = ('https://addons.mozilla.org/api/v3/addons/{}/' | 539         url = ('https://addons.mozilla.org/api/v3/addons/{}/' | 
| 540                'versions/{}/').format(app_id, version) | 540                'versions/{}/').format(app_id, version) | 
| 541 | 541 | 
| 542         request = self.generate_jwt_request(iss, secret, url, 'GET') | 542         request = self.generate_jwt_request(iss, secret, url, 'GET') | 
| 543         response = json.load(urllib2.urlopen(request)) | 543         response = json.load(urllib2.urlopen(request)) | 
| 544 | 544 | 
| 545         filename = '{}-{}.xpi'.format(self.basename, version) | 545         filename = '{}-{}.xpi'.format(self.basename, version) | 
| 546         self.path = os.path.join( | 546         self.path = os.path.join( | 
| 547             config.get('extensions', 'nightliesDirectory'), | 547             config.get('extensions', 'nightliesDirectory'), | 
| 548             self.basename, | 548             self.basename, | 
| 549             filename | 549             filename, | 
| 550         ) | 550         ) | 
| 551 | 551 | 
| 552         necessary = ['passed_review', 'reviewed', 'processed', 'valid'] | 552         necessary = ['passed_review', 'reviewed', 'processed', 'valid'] | 
| 553         if all(response[x] for x in necessary): | 553         if all(response[x] for x in necessary): | 
| 554             download_url = response['files'][0]['download_url'] | 554             download_url = response['files'][0]['download_url'] | 
| 555             checksum = response['files'][0]['hash'] | 555             checksum = response['files'][0]['hash'] | 
| 556 | 556 | 
| 557             request = self.generate_jwt_request(iss, secret, download_url, | 557             request = self.generate_jwt_request(iss, secret, download_url, | 
| 558                                                 'GET') | 558                                                 'GET') | 
| 559             try: | 559             try: | 
| 560                 response = urllib2.urlopen(request) | 560                 response = urllib2.urlopen(request) | 
| 561             except urllib2.HTTPError as e: | 561             except urllib2.HTTPError as e: | 
| 562                 logging.error(e.read()) | 562                 logging.error(e.read()) | 
| 563 | 563 | 
| 564             # Verify the extension's integrity | 564             # Verify the extension's integrity | 
| 565             file_content = response.read() | 565             file_content = response.read() | 
| 566             sha256 = hashlib.sha256(file_content) | 566             sha256 = hashlib.sha256(file_content) | 
| 567             returned_checksum = '{}:{}'.format(sha256.name, sha256.hexdigest()) | 567             returned_checksum = '{}:{}'.format(sha256.name, sha256.hexdigest()) | 
| 568 | 568 | 
| 569             if returned_checksum != checksum: | 569             if returned_checksum != checksum: | 
| 570                 logging.error('Checksum could not be verified: {} vs {}' | 570                 logging.error('Checksum could not be verified: {} vs {}' | 
| 571                               ''.format(checksum, returned_checksum)) | 571                               ''.format(checksum, returned_checksum)) | 
| 572 | 572 | 
| 573             with open(self.path, 'w') as fp: | 573             with open(self.path, 'w') as fp: | 
| 574                 fp.write(file_content) | 574                 fp.write(file_content) | 
| 575 | 575 | 
| 576             self.update_link = os.path.join( | 576             self.update_link = os.path.join( | 
| 577                 config.get('extensions', 'nightliesURL'), | 577                 config.get('extensions', 'nightliesURL'), | 
| 578                 self.basename, | 578                 self.basename, | 
| 579                 filename | 579                 filename, | 
| 580             ) | 580             ) | 
| 581 | 581 | 
| 582             self.remove_from_downloads_lockfile(self.config.type, | 582             self.remove_from_downloads_lockfile(self.config.type, | 
| 583                                                 'version', | 583                                                 'version', | 
| 584                                                 version) | 584                                                 version) | 
| 585         elif not response['passed_review'] or not response['valid']: | 585         elif not response['passed_review'] or not response['valid']: | 
| 586             # When the review failed for any reason, we want to know about it | 586             # When the review failed for any reason, we want to know about it | 
| 587             logging.error(json.dumps(response, indent=4)) | 587             logging.error(json.dumps(response, indent=4)) | 
| 588             self.remove_from_downloads_lockfile(self.config.type, | 588             self.remove_from_downloads_lockfile(self.config.type, | 
| 589                                                 'version', | 589                                                 'version', | 
| 590                                                 version) | 590                                                 version) | 
| 591 | 591 | 
| 592     def uploadToChromeWebStore(self): | 592     def uploadToChromeWebStore(self): | 
| 593 | 593 | 
| 594         opener = urllib2.build_opener(HTTPErrorBodyHandler) | 594         opener = urllib2.build_opener(HTTPErrorBodyHandler) | 
| 595 | 595 | 
| 596         # use refresh token to obtain a valid access token | 596         # use refresh token to obtain a valid access token | 
| 597         # https://developers.google.com/accounts/docs/OAuth2WebServer#refresh | 597         # https://developers.google.com/accounts/docs/OAuth2WebServer#refresh | 
| 598 | 598 | 
| 599         response = json.load(opener.open( | 599         response = json.load(opener.open( | 
| 600             'https://accounts.google.com/o/oauth2/token', | 600             'https://accounts.google.com/o/oauth2/token', | 
| 601 | 601 | 
| 602             urlencode([ | 602             urlencode([ | 
| 603                 ('refresh_token', self.config.refreshToken), | 603                 ('refresh_token', self.config.refreshToken), | 
| 604                 ('client_id', self.config.clientID), | 604                 ('client_id', self.config.clientID), | 
| 605                 ('client_secret', self.config.clientSecret), | 605                 ('client_secret', self.config.clientSecret), | 
| 606                 ('grant_type', 'refresh_token'), | 606                 ('grant_type', 'refresh_token'), | 
| 607             ]) | 607             ]), | 
| 608         )) | 608         )) | 
| 609 | 609 | 
| 610         auth_token = '%s %s' % (response['token_type'], response['access_token']
     ) | 610         auth_token = '%s %s' % (response['token_type'], response['access_token']
     ) | 
| 611 | 611 | 
| 612         # upload a new version with the Chrome Web Store API | 612         # upload a new version with the Chrome Web Store API | 
| 613         # https://developer.chrome.com/webstore/using_webstore_api#uploadexisitn
     g | 613         # https://developer.chrome.com/webstore/using_webstore_api#uploadexisitn
     g | 
| 614 | 614 | 
| 615         request = urllib2.Request('https://www.googleapis.com/upload/chromewebst
     ore/v1.1/items/' + self.config.devbuildGalleryID) | 615         request = urllib2.Request('https://www.googleapis.com/upload/chromewebst
     ore/v1.1/items/' + self.config.devbuildGalleryID) | 
| 616         request.get_method = lambda: 'PUT' | 616         request.get_method = lambda: 'PUT' | 
| 617         request.add_header('Authorization', auth_token) | 617         request.add_header('Authorization', auth_token) | 
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 651         # https://docs.microsoft.com/en-us/azure/active-directory/active-directo
     ry-protocols-oauth-code#refreshing-the-access-tokens | 651         # https://docs.microsoft.com/en-us/azure/active-directory/active-directo
     ry-protocols-oauth-code#refreshing-the-access-tokens | 
| 652         server = 'https://login.microsoftonline.com' | 652         server = 'https://login.microsoftonline.com' | 
| 653         token_path = '{}/{}/oauth2/token'.format(server, self.config.tenantID) | 653         token_path = '{}/{}/oauth2/token'.format(server, self.config.tenantID) | 
| 654 | 654 | 
| 655         opener = urllib2.build_opener(HTTPErrorBodyHandler) | 655         opener = urllib2.build_opener(HTTPErrorBodyHandler) | 
| 656         post_data = urlencode([ | 656         post_data = urlencode([ | 
| 657             ('refresh_token', self.config.refreshToken), | 657             ('refresh_token', self.config.refreshToken), | 
| 658             ('client_id', self.config.clientID), | 658             ('client_id', self.config.clientID), | 
| 659             ('client_secret', self.config.clientSecret), | 659             ('client_secret', self.config.clientSecret), | 
| 660             ('grant_type', 'refresh_token'), | 660             ('grant_type', 'refresh_token'), | 
| 661             ('resource', 'https://graph.windows.net') | 661             ('resource', 'https://graph.windows.net'), | 
| 662         ]) | 662         ]) | 
| 663         request = urllib2.Request(token_path, post_data) | 663         request = urllib2.Request(token_path, post_data) | 
| 664         with contextlib.closing(opener.open(request)) as response: | 664         with contextlib.closing(opener.open(request)) as response: | 
| 665             data = json.load(response) | 665             data = json.load(response) | 
| 666             auth_token = '{0[token_type]} {0[access_token]}'.format(data) | 666             auth_token = '{0[token_type]} {0[access_token]}'.format(data) | 
| 667 | 667 | 
| 668         return auth_token | 668         return auth_token | 
| 669 | 669 | 
| 670     def upload_appx_file_to_windows_store(self, file_upload_url): | 670     def upload_appx_file_to_windows_store(self, file_upload_url): | 
| 671         # Add .appx file to a .zip file | 671         # Add .appx file to a .zip file | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
| 692     def upload_to_windows_store(self): | 692     def upload_to_windows_store(self): | 
| 693         opener = urllib2.build_opener(HTTPErrorBodyHandler) | 693         opener = urllib2.build_opener(HTTPErrorBodyHandler) | 
| 694 | 694 | 
| 695         headers = {'Authorization': self.get_windows_store_access_token(), | 695         headers = {'Authorization': self.get_windows_store_access_token(), | 
| 696                    'Content-type': 'application/json'} | 696                    'Content-type': 'application/json'} | 
| 697 | 697 | 
| 698         # Get application | 698         # Get application | 
| 699         # https://docs.microsoft.com/en-us/windows/uwp/monetize/get-an-app | 699         # https://docs.microsoft.com/en-us/windows/uwp/monetize/get-an-app | 
| 700         api_path = '{}/v1.0/my/applications/{}'.format( | 700         api_path = '{}/v1.0/my/applications/{}'.format( | 
| 701             'https://manage.devcenter.microsoft.com', | 701             'https://manage.devcenter.microsoft.com', | 
| 702             self.config.devbuildGalleryID | 702             self.config.devbuildGalleryID, | 
| 703         ) | 703         ) | 
| 704 | 704 | 
| 705         request = urllib2.Request(api_path, None, headers) | 705         request = urllib2.Request(api_path, None, headers) | 
| 706         with contextlib.closing(opener.open(request)) as response: | 706         with contextlib.closing(opener.open(request)) as response: | 
| 707             app_obj = json.load(response) | 707             app_obj = json.load(response) | 
| 708 | 708 | 
| 709         # Delete existing in-progress submission | 709         # Delete existing in-progress submission | 
| 710         # https://docs.microsoft.com/en-us/windows/uwp/monetize/delete-an-app-su
     bmission | 710         # https://docs.microsoft.com/en-us/windows/uwp/monetize/delete-an-app-su
     bmission | 
| 711         submissions_path = api_path + '/submissions' | 711         submissions_path = api_path + '/submissions' | 
| 712         if 'pendingApplicationSubmission' in app_obj: | 712         if 'pendingApplicationSubmission' in app_obj: | 
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 839                         # write update manifest | 839                         # write update manifest | 
| 840                         self.writeUpdateManifest() | 840                         self.writeUpdateManifest() | 
| 841 | 841 | 
| 842                         # retire old builds | 842                         # retire old builds | 
| 843                         versions = self.retireBuilds() | 843                         versions = self.retireBuilds() | 
| 844                         # update index page | 844                         # update index page | 
| 845                         self.updateIndex(versions) | 845                         self.updateIndex(versions) | 
| 846 | 846 | 
| 847                         # Update soft link to latest build | 847                         # Update soft link to latest build | 
| 848                         baseDir = os.path.join( | 848                         baseDir = os.path.join( | 
| 849                             self.config.nightliesDirectory, self.basename | 849                             self.config.nightliesDirectory, self.basename, | 
| 850                         ) | 850                         ) | 
| 851                         linkPath = os.path.join( | 851                         linkPath = os.path.join( | 
| 852                             baseDir, '00latest' + self.config.packageSuffix | 852                             baseDir, '00latest' + self.config.packageSuffix, | 
| 853                         ) | 853                         ) | 
| 854 | 854 | 
| 855                         self.symlink_or_copy(self.path, linkPath) | 855                         self.symlink_or_copy(self.path, linkPath) | 
| 856             finally: | 856             finally: | 
| 857                 # clean up | 857                 # clean up | 
| 858                 if self.tempdir: | 858                 if self.tempdir: | 
| 859                     shutil.rmtree(self.tempdir, ignore_errors=True) | 859                     shutil.rmtree(self.tempdir, ignore_errors=True) | 
| 860 | 860 | 
| 861 | 861 | 
| 862 def main(download=False): | 862 def main(download=False): | 
| (...skipping 23 matching lines...) Expand all  Loading... | 
| 886 | 886 | 
| 887     file = open(nightlyConfigFile, 'wb') | 887     file = open(nightlyConfigFile, 'wb') | 
| 888     nightlyConfig.write(file) | 888     nightlyConfig.write(file) | 
| 889 | 889 | 
| 890 | 890 | 
| 891 if __name__ == '__main__': | 891 if __name__ == '__main__': | 
| 892     parser = argparse.ArgumentParser() | 892     parser = argparse.ArgumentParser() | 
| 893     parser.add_argument('--download', action='store_true', default=False) | 893     parser.add_argument('--download', action='store_true', default=False) | 
| 894     args = parser.parse_args() | 894     args = parser.parse_args() | 
| 895     main(args.download) | 895     main(args.download) | 
| OLD | NEW | 
|---|