OLD | NEW |
| (Empty) |
1 # Copyright (c) 2008 The Chromium Authors. All rights reserved. | |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 import fnmatch | |
6 import os | |
7 import re | |
8 import shutil | |
9 import subprocess | |
10 import utils | |
11 import SCons.Node | |
12 | |
13 Import('env') | |
14 | |
15 env = env.Clone() | |
16 | |
17 if env['OS'] in ['win32', 'wince']: | |
18 env.Append(DATE = 'echo %DATE%.%TIME%') | |
19 else: | |
20 env.Append(DATE = 'date') | |
21 | |
22 def GetInputs(var): return utils.GetInputs(var, env) | |
23 | |
24 def Shell(cmd): | |
25 """Execute a shell command and return the output.""" | |
26 cmd[0] = env.Entry(cmd[0]).abspath | |
27 cmd = env.subst(cmd) | |
28 return subprocess.Popen( | |
29 cmd, shell=True, stdout=subprocess.PIPE).communicate()[0] | |
30 | |
31 if env['OS'] == 'win32': | |
32 def GGUIDGen(value): | |
33 """Generate a GGUID for the given value.""" | |
34 return Shell(['$GGUIDGEN', '$NAMESPACE_GUID', value + '-$VERSION']) | |
35 env.Replace( | |
36 GGUIDGEN = '#/$OPEN_DIR/tools/gguidgen.exe', | |
37 NAMESPACE_GUID = '36F65206-5D4E-4752-9D52-27708E10DA79', | |
38 # MSI version numbers must have the form <major>.<minor>.<build>. To meet this, | |
39 # we combine our build and patch version numbers like so: | |
40 # MSI_VERSION = <major>.<minor>.<BUILD * 100 + PATCH>. | |
41 # Note: This assumes that the BUILD and PATCH variables adhere to the range | |
42 # requirements in version.mk. See comments in version.mk for more details. | |
43 MSI_BUILD = eval(env.subst('$BUILD * 100 + $PATCH')), | |
44 MSI_VERSION = '${MAJOR}.${MINOR}.${MSI_BUILD}', | |
45 ) | |
46 | |
47 # Building wxiobjs with candle | |
48 env.Replace( | |
49 CANDLEDEFPREFIX = '-d', | |
50 CANDLEDEFSUFFIX = '', | |
51 _CANDLEDEFFLAGS = ('${_defines(CANDLEDEFPREFIX, CANDLEDEFINES, ' | |
52 'CANDLEDEFSUFFIX, __env__)}'), | |
53 CANDLECOM = 'candle.exe -out $TARGET $SOURCE ${_CANDLEDEFFLAGS}', | |
54 ) | |
55 env.Append( | |
56 # Note: Since light.exe is run from $OPEN_DIR, candle.exe must generate | |
57 # output with paths relative to that dir. | |
58 SCONS_DIR = '..', # the scons dir relative to OPEN_DIR | |
59 # You can change the names of ProductId vars, but NEVER change their values! | |
60 CANDLEDEFINES = [ | |
61 ('OurWin32ProductId', | |
62 GGUIDGen('OUR_PRODUCT_ID')), | |
63 ('OurComponentGUID_FFComponentsDirFiles', | |
64 GGUIDGen('OUR_COMPONENT_GUID_FF_COMPONENTS_DIR_FILES')), | |
65 ('OurComponentGUID_FFContentDirFiles', | |
66 GGUIDGen('OUR_COMPONENT_GUID_FF_CONTENT_DIR_FILES')), | |
67 ('OurComponentGUID_FFDirFiles', | |
68 GGUIDGen('OUR_COMPONENT_GUID_FF_DIR_FILES')), | |
69 ('OurComponentGUID_FFLibDirFiles', | |
70 GGUIDGen('OUR_COMPONENT_GUID_FF_LIB_DIR_FILES')), | |
71 ('OurComponentGUID_FFRegistry', | |
72 GGUIDGen('OUR_COMPONENT_GUID_FF_REGISTRY')), | |
73 ('OurComponentGUID_IEFiles', | |
74 GGUIDGen('OUR_COMPONENT_GUID_IE_FILES')), | |
75 ('OurComponentGUID_IERegistry', | |
76 GGUIDGen('OUR_COMPONENT_GUID_IE_REGISTRY')), | |
77 ('OurComponentGUID_SharedFiles', | |
78 GGUIDGen('OUR_COMPONENT_GUID_SHARED_FILES')), | |
79 ('OurComponentGUID_SharedVersionedFiles', | |
80 GGUIDGen('OUR_COMPONENT_GUID_SHARED_VERSIONED_FILES')), | |
81 ('OurComponentGUID_SharedRegistry', | |
82 GGUIDGen('OUR_COMPONENT_GUID_SHARED_REGISTRY')), | |
83 ('OurNpapiProductId', | |
84 GGUIDGen('OUR_2ND_PRODUCT_ID')), | |
85 ('OurComponentGUID_NpapiFiles', | |
86 GGUIDGen('OUR_COMPONENT_GUID_NPAPI_FILES')), | |
87 ('OurComponentGUID_NpapiRegistry', | |
88 GGUIDGen('OUR_COMPONENT_GUID_NPAPI_REGISTRY')), | |
89 ('OurMsiVersion', '$MSI_VERSION'), | |
90 ('OurCommonPath', '$COMMON_OUTDIR'), | |
91 ('OurIEPath', '$IE_OUTDIR'), | |
92 ('OurIpcTestPath', '$COMMON_OUTDIR'), | |
93 ('OurFFPath', '$INSTALLER_OUTDIR/$INSTALLER_BASENAME'), | |
94 ('OurNpapiPath', '$NPAPI_OUTDIR'), | |
95 ] | |
96 ) | |
97 wix_langs = [re.sub('-', '_', lang) for lang in env['I18N_LANGS']] | |
98 env.Append( | |
99 CANDLEDEFINES = | |
100 [('OurComponentGUID_FFLang' + lang + 'DirFiles', | |
101 GGUIDGen('OUR_COMPONENT_GUID_FF_' + lang + '_DIR_FILES')) | |
102 for lang in wix_langs], | |
103 ) | |
104 | |
105 def SafeMkdir(dir): | |
106 """Like the builtin Mkdir, but doesn't fail if the dir exists.""" | |
107 def Func(target, source, env): | |
108 dir_subst = env.subst(dir, target=target) | |
109 if not os.path.exists(dir_subst): | |
110 os.makedirs(dir_subst) | |
111 return 0 | |
112 return Action(Func, 'SafeMkdir("' + dir + '")') | |
113 | |
114 def RecursiveDelete(pattern): | |
115 """Recursively deletes directories matching a pattern.""" | |
116 def Func(target, source, env): | |
117 # strip off '.dir' suffix | |
118 target_dir = env.subst('${TARGET.base}', target=target) | |
119 for root, dirs, files in os.walk(target_dir): | |
120 if fnmatch.fnmatch(os.path.normpath(root), pattern): | |
121 print 'Deleting', root | |
122 shutil.rmtree(root) | |
123 return 0 | |
124 return Action(Func, 'RecursiveDelete("' + pattern + '")') | |
125 | |
126 def ToUnixPath(path): | |
127 """Converts windows-style \ to unix-style /.""" | |
128 return re.sub(r'\\', r'/', path) | |
129 | |
130 def DirBuilder(env, dirtarget, dirsrcs): | |
131 """Builder that makes a directory tree by copying source files to | |
132 corresponding locations inside 'dirtarget'. 'dirsrcs' specifies the list of | |
133 mappings from source file/directory to the target location. It's formatted | |
134 like: | |
135 (<target file or dir>, <list of source files>) | |
136 | |
137 Note: source files that come from an output directory must be explicitly | |
138 specified relative to the toplevel dir '#'. | |
139 Note: as shorthand, if the target ends with a '/', then the sources will | |
140 be placed into that dir. Otherwise, source is renamed into the target. | |
141 """ | |
142 | |
143 srcs = [] | |
144 actions = [Delete('${TARGET.base}')] | |
145 for target, sources in dirsrcs: | |
146 target_is_dir = target.endswith('/') | |
147 if target_is_dir: | |
148 actions.append(SafeMkdir('${TARGET.base}/' + target)) | |
149 else: | |
150 actions.append(SafeMkdir('${TARGET.base}/' + os.path.dirname(target))) | |
151 for source in env.Flatten(sources): | |
152 source = env.subst(source, conv=lambda x:x) | |
153 srcs.append(source) | |
154 | |
155 # Special-case for Nodes and Node lists: use their absolute paths for | |
156 # the Copy() action, otherwise it will be relative to our variant dir | |
157 # (not what Copy expects). | |
158 if isinstance(source, list): source = source[0] | |
159 if isinstance(source, SCons.Node.Node): source = source.abspath | |
160 | |
161 # HACK: Compensate for the workaround below. We want the .dir file | |
162 # to be the dependency to the Command() builder, but we want to copy | |
163 # the actual directory - so strip the extension here. | |
164 if source.endswith('.dir'): | |
165 source = source[:-4] | |
166 | |
167 if target_is_dir: | |
168 actions.append( | |
169 Copy('${TARGET.base}/' + target + os.path.basename(source), | |
170 source)) | |
171 else: | |
172 actions.append(Copy('${TARGET.base}/' + target, source)) | |
173 | |
174 # Remove any .svn directories that were copied. | |
175 actions.append(RecursiveDelete('*/.svn')) | |
176 | |
177 # HACK: Workaround for bug in scons where directories aren't checked for | |
178 # dependency changes. Instead, we make a temp file the target, and ensure | |
179 # that that file changes everytime we execute these actions. | |
180 # See http://scons.tigris.org/issues/show_bug.cgi?id=2261 | |
181 actions += ['$DATE > ${TARGET}'] | |
182 return env.Command(env.subst(dirtarget) + '.dir', srcs, actions) | |
183 env.AddMethod(DirBuilder) | |
184 | |
185 def FirefoxInstaller(): | |
186 dirsrcs = [ | |
187 ('/', ['$FF3_OUTDIR/genfiles/install.rdf', | |
188 '$FF3_OUTDIR/genfiles/chrome.manifest']), | |
189 ('lib/', ['$OPEN_DIR/base/firefox/static_files/lib/updater.js']), | |
190 ('chrome/chromeFiles/content/', | |
191 GetInputs('$FF3_RESOURCES $COMMON_RESOURCES')), | |
192 ('chrome/chromeFiles/locale', ['$FF3_OUTDIR/genfiles/i18n']), | |
193 ('components/', | |
194 ['$FF3_MODULE_TYPELIB', | |
195 '$OPEN_DIR/base/firefox/static_files/components/bootstrap.js']), | |
196 ('components/${SHLIBPREFIX}gears${SHLIBSUFFIX}', ['$FF2_MODULE']), | |
197 ('components/${SHLIBPREFIX}gears_ff2${SHLIBSUFFIX}', ['$FF3_MODULE']), | |
198 ] | |
199 | |
200 if env['USING_CCTESTS']: | |
201 dirsrcs += [ | |
202 ('components/', ['$IPC_TEST_EXE']), | |
203 ] | |
204 if env['OS'] != 'win32': | |
205 # TODO(playmobil): Inspector should be located in extensions dir on win32. | |
206 dirsrcs += [ | |
207 ('resources/inspector', [env.Dir('#/$OPEN_DIR/inspector')]), | |
208 ('resources/inspector/common/', ['$OPEN_DIR/sdk/gears_init.js', | |
209 '$OPEN_DIR/sdk/samples/sample.js']), | |
210 ] | |
211 if env['MODE'] == 'dbg' and env['OS'] in ['win32', 'wince']: | |
212 dirsrcs += [ | |
213 ('components/gears_ff2.pdb', ['$FF2_MODULE_PDB']), | |
214 ('components/gears.pdb', ['$FF3_MODULE_PDB']), | |
215 ] | |
216 if env['OS'] == 'osx': | |
217 dirsrcs += [ | |
218 ('resources/', ['$OSX_LAUNCHURL_EXE']), | |
219 ] | |
220 | |
221 dir = env.DirBuilder('$INSTALLER_OUTDIR/$INSTALLER_BASENAME', dirsrcs) | |
222 actions = [ | |
223 # Mark files writeable to allow .xpi rebuilds | |
224 'chmod -R 777 ${SOURCE.base}', | |
225 '(cd ${SOURCE.base} && zip -r ../${TARGET.file} .)' | |
226 ] | |
227 | |
228 return env.Command('$FF_XPI', dir, actions) | |
229 firefox_installer = FirefoxInstaller() | |
230 | |
231 def Win32Installer(): | |
232 wxiobj = env.Command( | |
233 '$COMMON_GENFILES_DIR/win32_msi.wxiobj', | |
234 '$COMMON_GENFILES_DIR/win32_msi.wxs', | |
235 '$CANDLECOM') | |
236 # TODO(mpcomplete): remove this if/when the notifier goes away. This | |
237 # creates fake targets to satisfy the installer build. | |
238 notifier = env.Command( | |
239 [ | |
240 '$COMMON_OUTDIR/notifier.exe', | |
241 '$COMMON_OUTDIR/notifier.dll', | |
242 '$COMMON_OUTDIR/notifier_test.exe' | |
243 ], [], | |
244 'touch $TARGETS') | |
245 # light.exe must be run from $OPEN_DIR | |
246 msi = env.Command( | |
247 '$WIN32_INSTALLER_MSI', | |
248 [wxiobj, notifier, firefox_installer, '$IE_MODULE', '$NPAPI_MODULE'], | |
249 'cd $OPEN_DIR && light.exe -out ${TARGET.abspath} ${SOURCES[0].abspath}') | |
250 return msi | |
251 win32_installer = Win32Installer() | |
252 | |
253 def WinCEInstaller(): | |
254 env['ToUnixPath'] = ToUnixPath | |
255 inf_outdir = ToUnixPath(env.subst('$IE_OUTDIR')) | |
256 inf = env.Command( | |
257 '$COMMON_GENFILES_DIR/wince_cab_fixed.inf', | |
258 '$COMMON_GENFILES_DIR/wince_cab_ie.inf', | |
259 'sed -e "s#bin-....wince-arm.ie.#' + inf_outdir + '#g" $SOURCE > $TARGET') | |
260 cab = env.Command( | |
261 '$WINCE_INSTALLER_CAB', | |
262 [inf, '$IE_MODULE', '$IE_WINCE_SETUP_DLL'], | |
263 ['cabwiz ${ToUnixPath(str(SOURCE))} /compress' | |
264 ' /err ${SOURCES[0].base}.log', | |
265 Copy('$TARGET', '${SOURCE.base}.CAB')]) | |
266 return cab | |
267 wince_installer = WinCEInstaller() | |
268 | |
269 def SafariPluginBundle(): | |
270 """This is the actual gears plugin bundle for Safari.""" | |
271 dirsrcs = [ | |
272 ('Contents/', ['$SF_OUTDIR/genfiles/Info.plist']), | |
273 ('Contents/Resources/English.lproj/InfoPlist.strings', | |
274 ['$OPEN_DIR/tools/osx/English.lproj/InfoPlist.strings']), | |
275 ('Contents/Resources/', env.Glob('#/$OPEN_DIR/ui/safari/*.nib')), | |
276 ('Contents/Resources/', ['$CRASH_SENDER_EXE']), | |
277 ('Contents/Resources/', ['$OSX_CRASH_INSPECTOR_EXE']), | |
278 ('Contents/Resources/', ['$OSX_LAUNCHURL_EXE']), | |
279 ('Contents/MacOS/', ['$SF_MODULE']), | |
280 ] | |
281 | |
282 if env['USING_CCTESTS']: | |
283 dirsrcs += [ | |
284 ('Contents/Resources/', ['$IPC_TEST_EXE']), | |
285 ] | |
286 | |
287 return env.DirBuilder('$SF_PLUGIN_BUNDLE', dirsrcs) | |
288 safari_plugin_bundle = SafariPluginBundle() | |
289 | |
290 def SafariPluginProxyBundle(): | |
291 """This is a proxy plugin which simply loads gears into Safari and keeps | |
292 it in memory. It exists so that gears doesn't unload when Safari wants us | |
293 to, since that causes crashes.""" | |
294 dirsrcs = [ | |
295 ('Contents/', ['$SF_OUTDIR/genfiles/Info.plist']), | |
296 ('Contents/MacOS/${SHLIBPREFIX}gears${SHLIBSUFFIX}', ['$SF_PROXY_DLL']), | |
297 ('Contents/Resources/', [safari_plugin_bundle]), | |
298 ('Contents/Resources/', ['$OPEN_DIR/tools/osx/uninstall.command']), | |
299 ] | |
300 | |
301 return env.DirBuilder('$SF_PLUGIN_PROXY_BUNDLE', dirsrcs) | |
302 safari_plugin_proxy_bundle = SafariPluginProxyBundle() | |
303 | |
304 def SafariInstallerPluginBundle(): | |
305 dirsrcs = [ | |
306 ('Contents/Info.plist', | |
307 ['$OPEN_DIR/base/safari/advanced_stats_sheet.plist']), | |
308 ('Contents/MacOS/InstallerPlugin', ['$SF_INSTALLER_PLUGIN_EXE']), | |
309 ('Contents/Resources/AdvancedStatsSheet.nib', | |
310 [env.Dir('#/$OPEN_DIR/base/safari/advanced_stats_sheet.nib')]), | |
311 ] | |
312 | |
313 return env.DirBuilder('$SF_INSTALLER_PLUGIN_BUNDLE', dirsrcs) | |
314 safari_installer_plugin_bundle = SafariInstallerPluginBundle() | |
315 | |
316 def SafariInputManagerBundle(): | |
317 info = env.Command('$SF_OUTDIR/genfiles/Enabler-Info.plist', | |
318 '$OPEN_DIR/tools/osx/Enabler-Info.plist', | |
319 'cat $SOURCE |' | |
320 'sed \'s/$${EXECUTABLE_NAME}/GearsEnabler/\' |' | |
321 'sed \'s/$${PRODUCT_NAME}/GearsEnabler/\' > $TARGET') | |
322 dirsrcs = [ | |
323 ('GearsEnabler.bundle/Contents/Info.plist', [info]), | |
324 ('GearsEnabler.bundle/Contents/MacOS/', ['$SF_INPUTMANAGER_EXE']), | |
325 ('GearsEnabler.bundle/Contents/Resources/English.lproj/', | |
326 ['$OPEN_DIR/tools/osx/English.lproj/InfoPlist.strings']), | |
327 ('Info', ['$OPEN_DIR/tools/osx/Info']), | |
328 ] | |
329 | |
330 return env.DirBuilder('$SF_INPUTMANAGER_BUNDLE', dirsrcs) | |
331 safari_input_manager_bundle = SafariInputManagerBundle() | |
332 | |
333 def SafariInstallerPackage(): | |
334 pkg = env.Iceberg(env.Dir('${SF_INSTALLER_PKG}'), | |
335 [ | |
336 '$SF_OUTDIR/genfiles/installer.packproj', | |
337 safari_plugin_proxy_bundle, | |
338 safari_input_manager_bundle, | |
339 ]) | |
340 return pkg | |
341 safari_installer_package = SafariInstallerPackage() | |
342 | |
343 def SafariKeystoneInstaller(): | |
344 if not os.path.exists(env.Dir('#/$PRIVATE_DIR').abspath): | |
345 print 'Skipping Safari Keystone installer. Required sources are not public.' | |
346 return [] | |
347 | |
348 env.Append(CREATE_DISK_IMAGE = | |
349 "/usr/bin/hdiutil create -ov -imagekey zlib-level=9 -fs HFS+" | |
350 " -format UDZO -volname '$FRIENDLY_NAME ${VERSION}'" | |
351 " -srcfolder '${INSTALLER_OUTDIR}/Safari/dmg/' -scrub" | |
352 " -nocrossdev '${SF_KEYSTONE_INSTALLER_DMG}'" | |
353 ) | |
354 | |
355 pkg = env.Iceberg(env.Dir('${SF_KEYSTONE_INSTALLER_MPKG}'), | |
356 ['$SF_OUTDIR/genfiles/keystone_installer.packproj']) | |
357 env.Depends(pkg, GetInputs('$SF_M4S')) | |
358 env.Depends(pkg, safari_installer_package) | |
359 | |
360 dirsrcs = [ | |
361 ('/', [pkg]), | |
362 ('/.keystone_install', | |
363 ['$PRIVATE_DIR/tools/osx/installer/keystone_install']), | |
364 ] | |
365 dmg = env.DirBuilder('$INSTALLER_OUTDIR/Safari/dmg', dirsrcs) | |
366 env.AddPostAction(dmg, 'chmod +x ${TARGET.base}/.keystone_install') | |
367 # hdiutil is crashy under leopard, so try twice. | |
368 env.AddPostAction(dmg, '$CREATE_DISK_IMAGE || $CREATE_DISK_IMAGE') | |
369 | |
370 return dmg | |
371 safari_keystone_installer = SafariKeystoneInstaller() | |
372 | |
373 installers = [] | |
374 if 'FF3' in env['VALID_BROWSERS']: | |
375 installers += firefox_installer | |
376 if 'SF' in env['VALID_BROWSERS']: | |
377 installers += [ | |
378 safari_input_manager_bundle, | |
379 safari_plugin_bundle, | |
380 safari_plugin_proxy_bundle, | |
381 safari_installer_plugin_bundle, | |
382 safari_installer_package, | |
383 safari_input_manager_bundle, | |
384 safari_keystone_installer, | |
385 ] | |
386 if env['OS'] == 'win32': | |
387 installers += win32_installer | |
388 if env['OS'] == 'wince': | |
389 installers += wince_installer | |
390 | |
391 env.Alias('gears-installers', installers) | |
OLD | NEW |