Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: sitescripts/extensions/bin/createNightlies.py

Issue 5092904657747968: Issue 356 - Update devbuild in the Chrome Web Store (Closed)
Patch Set: Skip CRX header when uploading to CWS Created April 21, 2014, 6:10 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « .sitescripts.example ('k') | sitescripts/extensions/utils.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sitescripts/extensions/bin/createNightlies.py
===================================================================
--- a/sitescripts/extensions/bin/createNightlies.py
+++ b/sitescripts/extensions/bin/createNightlies.py
@@ -26,8 +26,9 @@
"""
import sys, os, os.path, codecs, subprocess, ConfigParser, traceback, json, hashlib
-import tempfile, re, shutil, urlparse, pipes
+import tempfile, re, shutil, urlparse, pipes, time, urllib2, struct
from datetime import datetime
+from urllib import urlencode
from xml.dom.minidom import parse as parseXml
from sitescripts.utils import get_config, setupStderr, get_template
from sitescripts.extensions.utils import compareVersions, Configuration
@@ -286,11 +287,11 @@
if not os.path.exists(baseDir):
os.makedirs(baseDir)
outputFile = "%s-%s%s" % (self.basename, self.version, self.config.packageSuffix)
- outputPath = os.path.join(baseDir, outputFile)
+ self.path = os.path.join(baseDir, outputFile)
self.updateURL = urlparse.urljoin(self.config.nightliesURL, self.basename + '/' + outputFile + '?update')
if self.config.type == 'android':
- apkFile = open(outputPath, 'wb')
+ apkFile = open(self.path, 'wb')
try:
try:
@@ -302,29 +303,29 @@
subprocess.check_call(buildCommand, stdout=apkFile, close_fds=True)
except:
# clear broken output if any
- if os.path.exists(outputPath):
- os.remove(outputPath)
+ if os.path.exists(self.path):
+ os.remove(self.path)
raise
elif self.config.type == 'chrome' or self.config.type == 'opera':
import buildtools.packagerChrome as packager
- packager.createBuild(self.tempdir, type=self.config.type, outFile=outputPath, buildNum=self.revision, keyFile=self.config.keyFile, experimentalAPI=self.config.experimental)
+ packager.createBuild(self.tempdir, type=self.config.type, outFile=self.path, buildNum=self.revision, keyFile=self.config.keyFile, experimentalAPI=self.config.experimental)
elif self.config.type == 'safari':
import buildtools.packagerSafari as packager
- packager.createBuild(self.tempdir, type=self.config.type, outFile=outputPath, buildNum=self.revision, keyFile=self.config.keyFile)
+ packager.createBuild(self.tempdir, type=self.config.type, outFile=self.path, buildNum=self.revision, keyFile=self.config.keyFile)
else:
import buildtools.packagerGecko as packager
- packager.createBuild(self.tempdir, outFile=outputPath, buildNum=self.revision, keyFile=self.config.keyFile)
+ packager.createBuild(self.tempdir, outFile=self.path, buildNum=self.revision, keyFile=self.config.keyFile)
- if not os.path.exists(outputPath):
+ if not os.path.exists(self.path):
raise Exception("Build failed, output file hasn't been created")
linkPath = os.path.join(baseDir, '00latest%s' % self.config.packageSuffix)
if hasattr(os, 'symlink'):
if os.path.exists(linkPath):
os.remove(linkPath)
- os.symlink(os.path.basename(outputPath), linkPath)
+ os.symlink(os.path.basename(self.path), linkPath)
else:
- shutil.copyfile(outputPath, linkPath)
+ shutil.copyfile(self.path, linkPath)
def retireBuilds(self):
"""
@@ -392,6 +393,46 @@
finally:
shutil.rmtree(docsdir, ignore_errors=True)
+ def uploadToChromeWebStore(self):
+ # use refresh token to obtain a valid access token
+ # https://developers.google.com/accounts/docs/OAuth2WebServer#refresh
+
+ response = json.load(urllib2.urlopen(
+ 'https://accounts.google.com/o/oauth2/token',
+
+ urlencode([
+ ('refresh_token', self.config.refreshToken),
+ ('client_id', self.config.clientID),
+ ('client_secret', self.config.clientSecret),
+ ('grant_type', 'refresh_token'),
+ ])
+ ))
+
+ # upload a new version with the Chrome Web Store API
+ # https://developer.chrome.com/webstore/using_webstore_api#uploadexisitng
+
+ request = urllib2.Request('https://www.googleapis.com/upload/chromewebstore/v1.1/items/' + self.config.galleryID)
+ request.get_method = lambda: 'PUT'
+ request.add_header('Authorization', '%s %s' % (response['token_type'], response['access_token']))
+ request.add_header('x-goog-api-version', '2')
+
+ with open(self.path, 'rb') as file:
+ # skip CRX magic and version
+ offset = 8
+ file.seek(offset)
+
+ # skip public key and signature
+ offset += 8 + sum(struct.unpack('<II', file.read(8)))
Wladimir Palant 2014/04/21 20:22:56 Please don't skip magic number and version - read
Sebastian Noack 2014/04/21 20:46:36 Done.
+ file.seek(offset)
Wladimir Palant 2014/04/21 20:22:56 Please use os.SEEK_CUR as second parameter to file
Sebastian Noack 2014/04/21 20:46:36 Done.
+
+ request.add_header('Content-Length', os.fstat(file.fileno()).st_size - offset)
+ request.add_data(file)
+
+ response = json.load(urllib2.urlopen(request))
+
+ if response['uploadState'] == 'FAILURE':
+ raise Exception(response['itemError'])
+
def run(self):
"""
Run the nightly build process for one extension
@@ -438,6 +479,9 @@
# update nightlies config
self.config.latestRevision = self.revision
+
+ if self.config.clientID and self.config.clientSecret and self.config.refreshToken:
Wladimir Palant 2014/04/21 20:22:56 I think it makes sense to keep the type == 'chrome
Sebastian Noack 2014/04/21 20:46:36 Done.
+ self.uploadToChromeWebStore()
finally:
# clean up
if self.tempdir:
« no previous file with comments | « .sitescripts.example ('k') | sitescripts/extensions/utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld