blob: 0b29d0c4096cf80d0d68816f992143bc405f4d21 [file] [log] [blame]
Dmitry Polukhincbdd21c2013-08-13 10:42:04 -07001#!/usr/bin/python
2# -*- coding: utf-8 -*-
3# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""Generate and upload tarballs for default apps cache.
8
9Run inside the 'files' dir containing 'external_extensions.json' file:
10$ chromite/bin/chrome_update_extension_cache --create --upload \\
11 chromeos-default-apps-1.0.0
12
13Always increment the version when you update an existing package.
14If no new files are added, increment the third version number.
15 e.g. 1.0.0 -> 1.0.1
16If you change list of default extensions, increment the second version number.
17 e.g. 1.0.0 -> 1.1.0
18
19Also you need to regenerate the Manifest with the new tarball digest.
20Run inside the chroot:
21$ ebuild chromeos-default-apps-1.0.0.ebuild manifest --force
22"""
23
24import json
25import os
26import urllib
27import xml.dom.minidom
28
29from chromite.lib import commandline
30from chromite.lib import cros_build_lib
31from chromite.lib import gs
32from chromite.lib import osutils
33
34
35EXTENSIONS_CACHE_PREFIX = '/usr/share/google-chrome/extensions'
36UPLOAD_URL_BASE = 'gs://chromeos-localmirror-private/distfiles'
37
38
39def DownloadCrx(ext, extension, outputdir):
40 """Download .crx file from WebStore and update entry."""
41 cros_build_lib.Info('Extension "%s"(%s)...', extension['name'], ext)
42
43 update_url = '%s?x=id%%3D%s%%26uc' % (extension['external_update_url'], ext)
44 response = urllib.urlopen(update_url)
45 if response.getcode() != 200:
46 cros_build_lib.Error('Cannot get update response, URL: %s, error: %d',
47 update_url, response.getcode())
48 return False
49
50 dom = xml.dom.minidom.parse(response)
51 status = dom.getElementsByTagName('app')[0].getAttribute('status')
52 if status != 'ok':
53 cros_build_lib.Error('Cannot fetch extension, status: %s', status)
54 return False
55
56 node = dom.getElementsByTagName('updatecheck')[0]
57 url = node.getAttribute('codebase')
58 version = node.getAttribute('version')
59 filename = '%s-%s.crx' % (ext, version)
60 response = urllib.urlopen(url)
61 if response.getcode() != 200:
62 cros_build_lib.Error('Cannot download extension, URL: %s, error: %d',
63 url, response.getcode())
64 return False
65
66 osutils.WriteFile(os.path.join(outputdir, 'extensions', filename),
67 response.read())
68
69 # Has to delete because only one of 'external_crx' or
70 # 'external_update_url' should present for the extension.
71 del extension['external_update_url']
72
73 extension['external_crx'] = os.path.join(EXTENSIONS_CACHE_PREFIX, filename)
74 extension['external_version'] = version
75
76 cros_build_lib.Info('Downloaded, current version %s', version)
77 return True
78
79
80def CreateCacheTarball(extensions, outputdir, tarball):
81 """Cache |extensions| in |outputdir| and pack them in |tarball|."""
82 osutils.SafeMakedirs(os.path.join(outputdir, 'extensions', 'managed_users'))
83 was_errors = False
84 for ext in extensions:
85 managed_users = extensions[ext].get('managed_users', 'no')
86 cache_crx = extensions[ext].get('cache_crx', 'yes')
87
88 # Remove fields that shouldn't be in the output file.
89 for key in ('cache_crx', 'managed_users'):
90 extensions[ext].pop(key, None)
91
92 if cache_crx == 'yes':
93 if not DownloadCrx(ext, extensions[ext], outputdir):
94 was_errors = True
95 elif cache_crx == 'no':
96 pass
97 else:
98 cros_build_lib.Die('Unknown value for "cache_crx" %s for %s',
99 cache_crx, ext)
100
101 if managed_users == 'yes':
102 json_file = os.path.join(outputdir,
103 'extensions/managed_users/%s.json' % ext)
104 json.dump(extensions[ext],
105 open(json_file, 'w'),
106 sort_keys=True,
107 indent=2,
108 separators=(',', ': '))
109
110 if managed_users != 'only':
111 json_file = os.path.join(outputdir, 'extensions/%s.json' % ext)
112 json.dump(extensions[ext],
113 open(json_file, 'w'),
114 sort_keys=True,
115 indent=2,
116 separators=(',', ': '))
117
118 if was_errors:
119 cros_build_lib.Die('FAIL to download some extensions')
120
121 cros_build_lib.CreateTarball(tarball, outputdir)
122 cros_build_lib.Info('Tarball created %s', tarball)
123
124
125def main(argv):
126 parser = commandline.ArgumentParser(
127 '%%(prog)s [options] <version>\n\n%s' % __doc__)
128 parser.add_argument('version', nargs=1)
129 parser.add_argument('--path', default=None, type='path',
130 help='Path of files dir with external_extensions.json')
131 parser.add_argument('--create', default=False, action='store_true',
132 help='Create cache tarball with specified name')
133 parser.add_argument('--upload', default=False, action='store_true',
134 help='Upload cache tarball with specified name')
135 options = parser.parse_args(argv)
136
137 if options.path:
138 os.chdir(options.path)
139
140 if not (options.create or options.upload):
141 cros_build_lib.Die('Need at least --create or --upload args')
142
143 if not os.path.exists('external_extensions.json'):
144 cros_build_lib.Die('No external_extensions.json in %s. Did you forget the '
145 '--path option?', os.getcwd())
146
147 tarball = '%s.tar.xz' % options.version[0]
148 if options.create:
149 extensions = json.load(open('external_extensions.json', 'r'))
150 with osutils.TempDir() as tempdir:
151 CreateCacheTarball(extensions, tempdir, os.path.abspath(tarball))
152
153 if options.upload:
154 ctx = gs.GSContext()
155 url = os.path.join(UPLOAD_URL_BASE, tarball)
156 if ctx.Exists(url):
157 cros_build_lib.Die('This version already exists on Google Storage (%s)!\n'
158 'NEVER REWRITE EXISTING FILE. IT WILL BREAK CHROME OS '
159 'BUILD!!!', url)
160 ctx.Copy(os.path.abspath(tarball), url, acl='project-private')
161 cros_build_lib.Info('Tarball uploaded %s', url)
162 osutils.SafeUnlink(os.path.abspath(tarball))