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