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 |