3 # Copyright 2015 The Chromium 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.
7 '''Prepares the Google Play services split client libraries before usage by
10 We need to preprocess Google Play services before using it in Chrome
11 builds for 2 main reasons:
13 - Getting rid of unused resources: unsupported languages, unused
16 - Merging the differents jars so that it can be proguarded more
17 easily. This is necessary since debug and test apks get very close
20 The script is supposed to be used with the maven repository that can be
21 obtained by downloading the "extra-google-m2repository" from the Android SDK
22 Manager. It also supports importing from already extracted AAR files using the
23 --is-extracted-repo flag. The expected directory structure in that case would
28 | +-- <content of the first AAR file>
32 The json config (see the -c argument) file should provide the following fields:
34 - lib_version: String. Used when building from the maven repository. It should
35 be the package's version (e.g. "7.3.0"). Unused with extracted repositories.
37 - clients: String array. List of clients to pick. For example, when building
38 from the maven repository, it's the artifactId (e.g. "play-services-base") of
39 each client. With an extracted repository, it's the name of the
42 - locale_whitelist: String array. Locales that should be allowed in the final
43 resources. They are specified the same way they are appended to the `values`
44 directory in android resources (e.g. "us-GB", "it", "fil").
46 The output is a directory with the following structure:
49 +-- google-play-services.jar
58 +-- res/[.git-keep-directory]
59 +-- src/android/UnusedStub.java
61 Requires the `jar` utility in the path.
74 from pylib
import cmd_helper
75 from pylib
import constants
78 os
.path
.join(constants
.DIR_SOURCE_ROOT
, 'build', 'android', 'gyp'))
79 from util
import build_utils
82 M2_PKG_PATH
= os
.path
.join('com', 'google', 'android', 'gms')
86 parser
= argparse
.ArgumentParser(description
=("Prepares the Google Play "
87 "services split client libraries before usage by Chrome's build system. "
88 "See the script's documentation for more a detailed help."))
89 parser
.add_argument('-r',
91 help='The Google Play services repository location',
94 parser
.add_argument('-o',
96 help='The output directory',
99 parser
.add_argument('-c',
101 help='Config file path',
104 parser
.add_argument('-g',
108 help='Add a .gitkeep file to the empty directories')
109 parser
.add_argument('-x',
110 '--is-extracted-repo',
113 help='The provided repository is not made of AAR files.')
115 args
= parser
.parse_args()
117 ProcessGooglePlayServices(args
.repository
,
121 args
.is_extracted_repo
)
124 def ProcessGooglePlayServices(repo
, out_dir
, config_path
, git_friendly
,
126 with
open(config_path
, 'r') as json_file
:
127 config
= json
.load(json_file
)
129 with build_utils
.TempDir() as tmp_root
:
130 tmp_paths
= _SetupTempDir(tmp_root
)
132 if is_extracted_repo
:
133 _ImportFromExtractedRepo(config
, tmp_paths
, repo
)
135 _ImportFromAars(config
, tmp_paths
, repo
)
137 _GenerateCombinedJar(tmp_paths
)
138 _ProcessResources(config
, tmp_paths
)
139 _BuildOutput(config
, tmp_paths
, out_dir
, git_friendly
)
142 def _SetupTempDir(tmp_root
):
145 'imported_clients': os
.path
.join(tmp_root
, 'imported_clients'),
146 'extracted_jars': os
.path
.join(tmp_root
, 'jar'),
147 'combined_jar': os
.path
.join(tmp_root
, 'google-play-services.jar'),
149 os
.mkdir(tmp_paths
['imported_clients'])
150 os
.mkdir(tmp_paths
['extracted_jars'])
155 def _SetupOutputDir(out_dir
):
158 'res': os
.path
.join(out_dir
, 'res'),
159 'jar': os
.path
.join(out_dir
, 'google-play-services.jar'),
160 'stub': os
.path
.join(out_dir
, 'stub'),
163 shutil
.rmtree(out_paths
['jar'], ignore_errors
=True)
164 shutil
.rmtree(out_paths
['res'], ignore_errors
=True)
165 shutil
.rmtree(out_paths
['stub'], ignore_errors
=True)
170 def _MakeWritable(dir_path
):
171 for root
, dirs
, files
in os
.walk(dir_path
):
172 for path
in itertools
.chain(dirs
, files
):
173 st
= os
.stat(os
.path
.join(root
, path
))
174 os
.chmod(os
.path
.join(root
, path
), st
.st_mode | stat
.S_IWUSR
)
177 def _ImportFromAars(config
, tmp_paths
, repo
):
178 for client
in config
['clients']:
179 aar_name
= '%s-%s.aar' % (client
, config
['lib_version'])
180 aar_path
= os
.path
.join(repo
, M2_PKG_PATH
, client
,
181 config
['lib_version'], aar_name
)
182 aar_out_path
= os
.path
.join(tmp_paths
['imported_clients'], client
)
183 build_utils
.ExtractAll(aar_path
, aar_out_path
)
185 client_jar_path
= os
.path
.join(aar_out_path
, 'classes.jar')
186 build_utils
.ExtractAll(client_jar_path
, tmp_paths
['extracted_jars'],
190 def _ImportFromExtractedRepo(config
, tmp_paths
, repo
):
193 for client
in config
['clients']:
194 client_out_dir
= os
.path
.join(tmp_paths
['imported_clients'], client
)
195 shutil
.copytree(os
.path
.join(repo
, client
), client_out_dir
)
197 client_jar_path
= os
.path
.join(client_out_dir
, 'classes.jar')
198 build_utils
.ExtractAll(client_jar_path
, tmp_paths
['extracted_jars'],
201 _MakeWritable(tmp_paths
['imported_clients'])
204 def _GenerateCombinedJar(tmp_paths
):
205 out_file_name
= tmp_paths
['combined_jar']
206 working_dir
= tmp_paths
['extracted_jars']
207 cmd_helper
.Call(['jar', '-cf', out_file_name
, '-C', working_dir
, '.'])
210 def _ProcessResources(config
, tmp_paths
):
211 LOCALIZED_VALUES_BASE_NAME
= 'values-'
212 locale_whitelist
= set(config
['locale_whitelist'])
214 glob_pattern
= os
.path
.join(tmp_paths
['imported_clients'], '*', 'res', '*')
215 for res_dir
in glob
.glob(glob_pattern
):
216 dir_name
= os
.path
.basename(res_dir
)
218 if dir_name
.startswith('drawable'):
219 shutil
.rmtree(res_dir
)
222 if dir_name
.startswith(LOCALIZED_VALUES_BASE_NAME
):
223 dir_locale
= dir_name
[len(LOCALIZED_VALUES_BASE_NAME
):]
224 if dir_locale
not in locale_whitelist
:
225 shutil
.rmtree(res_dir
)
228 def _BuildOutput(config
, tmp_paths
, out_dir
, git_friendly
):
229 out_paths
= _SetupOutputDir(out_dir
)
231 # Copy the resources to the output dir
232 for client
in config
['clients']:
233 res_in_tmp_dir
= os
.path
.join(tmp_paths
['imported_clients'], client
, 'res')
234 if os
.path
.isdir(res_in_tmp_dir
) and os
.listdir(res_in_tmp_dir
):
235 res_in_final_dir
= os
.path
.join(out_paths
['res'], client
)
236 shutil
.copytree(res_in_tmp_dir
, res_in_final_dir
)
239 shutil
.copyfile(tmp_paths
['combined_jar'], out_paths
['jar'])
241 # Write the java dummy stub. Needed for gyp to create the resource jar
242 stub_location
= os
.path
.join(out_paths
['stub'], 'src', 'android')
243 os
.makedirs(stub_location
)
244 with
open(os
.path
.join(stub_location
, 'UnusedStub.java'), 'w') as stub
:
245 stub
.write('package android;'
246 'public final class UnusedStub {'
247 ' private UnusedStub() {}'
250 # Create the main res directory. Will be empty but is needed by gyp
251 stub_res_location
= os
.path
.join(out_paths
['stub'], 'res')
252 os
.makedirs(stub_res_location
)
254 build_utils
.Touch(os
.path
.join(stub_res_location
, '.git-keep-directory'))
257 if __name__
== '__main__':