e9dd1e220fa523cbe1d60f758089ff6d800d1c07
[platform/framework/web/crosswalk.git] / src / xwalk / build / android / generate_xwalk_core_library.py
1 #!/usr/bin/env python
2 #
3 # Copyright (c) 2013 Intel Corporation. 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 # pylint: disable=F0401
7
8 import distutils.dir_util
9 import optparse
10 import os
11 import shutil
12 import sys
13 import zipfile
14 from common_function import RemoveUnusedFilesInReleaseMode
15 from xml.dom.minidom import Document
16
17 LIBRARY_PROJECT_NAME = 'xwalk_core_library'
18 XWALK_CORE_SHELL_APK = 'xwalk_core_shell_apk'
19
20 def AddGeneratorOptions(option_parser):
21   option_parser.add_option('-s', dest='source',
22                            help='Source directory of project root.',
23                            type='string')
24   option_parser.add_option('-t', dest='target',
25                            help='Product out target directory.',
26                            type='string')
27
28
29 def CleanLibraryProject(out_dir):
30   out_project_path = os.path.join(out_dir, LIBRARY_PROJECT_NAME)
31   if os.path.exists(out_project_path):
32     for item in os.listdir(out_project_path):
33       sub_path = os.path.join(out_project_path, item)
34       if os.path.isdir(sub_path):
35         shutil.rmtree(sub_path)
36       elif os.path.isfile(sub_path):
37         os.remove(sub_path)
38
39
40 def CopyProjectFiles(project_source, out_dir):
41   """cp xwalk/build/android/xwalkcore_library_template/<file>
42         out/Release/xwalk_core_library/<file>
43   """
44
45   print 'Copying library project files...'
46   template_dir = os.path.join(project_source, 'xwalk', 'build', 'android',
47                               'xwalkcore_library_template')
48   files_to_copy = [
49       # AndroidManifest.xml from template.
50       'AndroidManifest.xml',
51       # Eclipse project properties from template.
52       'project.properties',
53       # Ant build file.
54       'build.xml',
55       # Ant properties file.
56       'ant.properties',
57   ]
58   for f in files_to_copy:
59     source_file = os.path.join(template_dir, f)
60     target_file = os.path.join(out_dir, LIBRARY_PROJECT_NAME, f)
61
62     shutil.copy2(source_file, target_file)
63
64
65 def CopyJSBindingFiles(project_source, out_dir):
66   print 'Copying js binding files...'
67   jsapi_dir = os.path.join(out_dir,
68                            LIBRARY_PROJECT_NAME,
69                            'res',
70                            'raw')
71   if not os.path.exists(jsapi_dir):
72     os.makedirs(jsapi_dir)
73
74   jsfiles_to_copy = [
75       'xwalk/experimental/launch_screen/launch_screen_api.js',
76       'xwalk/experimental/presentation/presentation_api.js',
77       'xwalk/runtime/android/core_internal/src/org/xwalk/core/'
78       + 'internal/extension/api/device_capabilities/device_capabilities_api.js'
79   ]
80
81   # Copy JS binding file to assets/jsapi folder.
82   for jsfile in jsfiles_to_copy:
83     source_file = os.path.join(project_source, jsfile)
84     target_file = os.path.join(jsapi_dir, os.path.basename(source_file))
85     shutil.copyfile(source_file, target_file)
86
87
88 def CopyBinaries(out_dir):
89   """cp out/Release/<pak> out/Release/xwalk_core_library/res/raw/<pak>
90      cp out/Release/lib.java/<lib> out/Release/xwalk_core_library/libs/<lib>
91      cp out/Release/xwalk_core_shell_apk/libs/*
92         out/Release/xwalk_core_library/libs
93   """
94
95   print 'Copying binaries...'
96   # Copy assets.
97   res_raw_dir = os.path.join(
98       out_dir, LIBRARY_PROJECT_NAME, 'res', 'raw')
99   res_value_dir = os.path.join(
100       out_dir, LIBRARY_PROJECT_NAME, 'res', 'values')
101   if not os.path.exists(res_raw_dir):
102     os.mkdir(res_raw_dir)
103   if not os.path.exists(res_value_dir):
104     os.mkdir(res_value_dir)
105
106   paks_to_copy = [
107       'icudtl.dat',
108       'xwalk.pak',
109   ]
110
111   pak_list_xml = Document()
112   resources_node = pak_list_xml.createElement('resources')
113   string_array_node = pak_list_xml.createElement('string-array')
114   string_array_node.setAttribute('name', 'xwalk_resources_list')
115   pak_list_xml.appendChild(resources_node)
116   resources_node.appendChild(string_array_node)
117   for pak in paks_to_copy:
118     source_file = os.path.join(out_dir, pak)
119     target_file = os.path.join(res_raw_dir, pak)
120     shutil.copyfile(source_file, target_file)
121     item_node = pak_list_xml.createElement('item')
122     item_node.appendChild(pak_list_xml.createTextNode(pak))
123     string_array_node.appendChild(item_node)
124   pak_list_file = open(os.path.join(res_value_dir,
125                                     'xwalk_resources_list.xml'), 'w')
126   pak_list_xml.writexml(pak_list_file, newl='\n', encoding='utf-8')
127   pak_list_file.close()
128
129   # Copy jar files to libs.
130   libs_dir = os.path.join(out_dir, LIBRARY_PROJECT_NAME, 'libs')
131   if not os.path.exists(libs_dir):
132     os.mkdir(libs_dir)
133
134   libs_to_copy = [
135       'xwalk_core_library_java.jar',
136   ]
137
138   for lib in libs_to_copy:
139     source_file = os.path.join(out_dir, 'lib.java', lib)
140     target_file = os.path.join(libs_dir, lib)
141     shutil.copyfile(source_file, target_file)
142
143   # Copy native libraries.
144   source_dir = os.path.join(out_dir, XWALK_CORE_SHELL_APK, 'libs')
145   target_dir = libs_dir
146   distutils.dir_util.copy_tree(source_dir, target_dir)
147
148
149 def CopyDirAndPrefixDuplicates(input_dir, output_dir, prefix):
150   """ Copy the files into the output directory. If one file in input_dir folder
151   doesn't exist, copy it directly. If a file exists, copy it and rename the
152   file so that the resources won't be overrided. So all of them could be
153   packaged into the xwalk core library.
154   """
155   for root, _, files in os.walk(input_dir):
156     for f in files:
157       src_file = os.path.join(root, f)
158       relative_path = os.path.relpath(src_file, input_dir)
159       target_file = os.path.join(output_dir, relative_path)
160       target_dir_name = os.path.dirname(target_file)
161       if not os.path.exists(target_dir_name):
162         os.makedirs(target_dir_name)
163       # If the file exists, copy it and rename it with another name to
164       # avoid overwriting the existing one.
165       if os.path.exists(target_file):
166         target_base_name = os.path.basename(target_file)
167         target_base_name = prefix + '_' + target_base_name
168         target_file = os.path.join(target_dir_name, target_base_name)
169       shutil.copyfile(src_file, target_file)
170
171
172 def MoveImagesToNonMdpiFolders(res_root):
173   """Move images from drawable-*-mdpi-* folders to drawable-* folders.
174
175   Why? http://crbug.com/289843
176
177   Copied from build/android/gyp/package_resources.py.
178   """
179   for src_dir_name in os.listdir(res_root):
180     src_components = src_dir_name.split('-')
181     if src_components[0] != 'drawable' or 'mdpi' not in src_components:
182       continue
183     src_dir = os.path.join(res_root, src_dir_name)
184     if not os.path.isdir(src_dir):
185       continue
186     dst_components = [c for c in src_components if c != 'mdpi']
187     assert dst_components != src_components
188     dst_dir_name = '-'.join(dst_components)
189     dst_dir = os.path.join(res_root, dst_dir_name)
190     if not os.path.isdir(dst_dir):
191       os.makedirs(dst_dir)
192     for src_file_name in os.listdir(src_dir):
193       if not src_file_name.endswith('.png'):
194         continue
195       src_file = os.path.join(src_dir, src_file_name)
196       dst_file = os.path.join(dst_dir, src_file_name)
197       assert not os.path.lexists(dst_file)
198       shutil.move(src_file, dst_file)
199
200
201 def CopyResources(out_dir):
202   print 'Copying resources...'
203   res_dir = os.path.join(out_dir, LIBRARY_PROJECT_NAME, 'res')
204   temp_dir = os.path.join(out_dir, LIBRARY_PROJECT_NAME, 'temp')
205   if os.path.exists(res_dir):
206     shutil.rmtree(res_dir)
207   if os.path.exists(temp_dir):
208     shutil.rmtree(temp_dir)
209
210   # All resources should be in specific folders in res_directory.
211   # Since there might be some resource files with same names from
212   # different folders like ui_java, content_java and others,
213   # it's necessary to rename some files to avoid overridding.
214   res_to_copy = [
215       # zip file list
216       'content_java.zip',
217       'content_strings_grd.zip',
218       'ui_java.zip',
219       'ui_strings_grd.zip',
220       'xwalk_core_internal_java.zip',
221       'xwalk_core_strings.zip'
222   ]
223
224   for res_zip in res_to_copy:
225     zip_file = os.path.join(out_dir, 'res.java', res_zip)
226     zip_name = os.path.splitext(res_zip)[0]
227     if not os.path.isfile(zip_file):
228       raise Exception('Resource zip not found: ' + zip_file)
229     subdir = os.path.join(temp_dir, zip_name)
230     if os.path.isdir(subdir):
231       raise Exception('Resource zip name conflict: ' + zip_name)
232     os.makedirs(subdir)
233     with zipfile.ZipFile(zip_file) as z:
234       z.extractall(path=subdir)
235     CopyDirAndPrefixDuplicates(subdir, res_dir, zip_name)
236     MoveImagesToNonMdpiFolders(res_dir)
237
238   if os.path.isdir(temp_dir):
239     shutil.rmtree(temp_dir)
240
241
242 def PostCopyLibraryProject(out_dir):
243   print 'Post Copy Library Project...'
244   aidls_to_remove = [
245       'org/chromium/content/common/common.aidl',
246       'org/chromium/net/IRemoteAndroidKeyStoreInterface.aidl',
247   ]
248   for aidl in aidls_to_remove:
249     aidl_file = os.path.join(out_dir, LIBRARY_PROJECT_NAME, 'src', aidl)
250     if os.path.exists(aidl_file):
251       os.remove(aidl_file)
252
253
254 def main(argv):
255   print 'Generating XWalkCore Library Project...'
256   option_parser = optparse.OptionParser()
257   AddGeneratorOptions(option_parser)
258   options, _ = option_parser.parse_args(argv)
259
260   if not os.path.exists(options.source):
261     print 'Source project does not exist, please provide correct directory.'
262     sys.exit(1)
263   out_dir = options.target
264
265   # Clean directory for project first.
266   CleanLibraryProject(out_dir)
267
268   out_project_dir = os.path.join(out_dir, LIBRARY_PROJECT_NAME)
269   if not os.path.exists(out_project_dir):
270     os.mkdir(out_project_dir)
271
272   # Copy Eclipse project files of library project.
273   CopyProjectFiles(options.source, out_dir)
274   # Copy binaries and resuorces.
275   CopyResources(out_dir)
276   CopyBinaries(out_dir)
277   # Copy JS API binding files.
278   CopyJSBindingFiles(options.source, out_dir)
279   # Post copy library project.
280   PostCopyLibraryProject(out_dir)
281   # Remove unused files.
282   mode = os.path.basename(os.path.normpath(out_dir))
283   RemoveUnusedFilesInReleaseMode(mode,
284       os.path.join(out_dir, LIBRARY_PROJECT_NAME, 'libs'))
285   # Create empty src directory
286   src_dir = os.path.join(out_project_dir, 'src')
287   if not os.path.isdir(src_dir):
288     os.mkdir(src_dir)
289   readme = os.path.join(src_dir, 'README.md')
290   open(readme, 'w').write(
291       "# Source folder for xwalk_core_library\n"
292       "## Why it's empty\n"
293       "xwalk_core_library doesn't contain java sources.\n"
294       "## Why put me here\n"
295       "To make archives keep the folder, "
296       "the src directory is needed to build an apk by ant.")
297   print 'Your Android library project has been created at %s' % (
298       out_project_dir)
299
300 if __name__ == '__main__':
301   sys.exit(main(sys.argv))