aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/viewer_manifest.py
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/newview/viewer_manifest.py')
-rwxr-xr-xlinden/indra/newview/viewer_manifest.py450
1 files changed, 450 insertions, 0 deletions
diff --git a/linden/indra/newview/viewer_manifest.py b/linden/indra/newview/viewer_manifest.py
new file mode 100755
index 0000000..4c422e4
--- /dev/null
+++ b/linden/indra/newview/viewer_manifest.py
@@ -0,0 +1,450 @@
1#!/usr/bin/python
2# @file viewer_manifest.py
3# @author Ryan Williams
4# @brief Description of all installer viewer files, and methods for packaging
5# them into installers for all supported platforms.
6#
7# Copyright (c) 2006-2007, Linden Research, Inc.
8#
9# The source code in this file ("Source Code") is provided by Linden Lab
10# to you under the terms of the GNU General Public License, version 2.0
11# ("GPL"), unless you have obtained a separate licensing agreement
12# ("Other License"), formally executed by you and Linden Lab. Terms of
13# the GPL can be found in doc/GPL-license.txt in this distribution, or
14# online at http://secondlife.com/developers/opensource/gplv2
15#
16# There are special exceptions to the terms and conditions of the GPL as
17# it is applied to this Source Code. View the full text of the exception
18# in the file doc/FLOSS-exception.txt in this software distribution, or
19# online at http://secondlife.com/developers/opensource/flossexception
20#
21# By copying, modifying or distributing this software, you acknowledge
22# that you have read and understood your obligations described above,
23# and agree to abide by those obligations.
24#
25# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
26# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
27# COMPLETENESS OR PERFORMANCE.
28import sys
29import os.path
30import re
31import tarfile
32viewer_dir = os.path.dirname(__file__)
33# add llmanifest library to our path so we don't have to muck with PYTHONPATH
34sys.path.append(os.path.join(viewer_dir, '../lib/python/indra'))
35from llmanifest import LLManifest, main, proper_windows_path, path_ancestors
36
37class ViewerManifest(LLManifest):
38 def construct(self):
39 super(ViewerManifest, self).construct()
40 self.exclude("*.svn*")
41 self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg")
42
43 if self.prefix(src="app_settings"):
44 self.exclude("logcontrol.xml")
45 self.exclude("logcontrol-dev.xml")
46 self.path("*.pem")
47 self.path("*.ini")
48 self.path("*.xml")
49 self.path("*.vp")
50 self.path("*.db2")
51
52 # include the entire shaders directory recursively
53 self.path("shaders")
54 self.end_prefix("app_settings")
55
56 if self.prefix(src="character"):
57 self.path("*.llm")
58 self.path("*.xml")
59 self.path("*.tga")
60 self.end_prefix("character")
61
62
63 # Include our fonts
64 if self.prefix(src="fonts"):
65 self.path("*.ttf")
66 self.path("*.txt")
67 self.end_prefix("fonts")
68
69 # XUI
70 if self.prefix(src="skins"):
71 # include the entire textures directory recursively
72 self.path("textures")
73 self.path("paths.xml")
74 self.path("xui/*/*.xml")
75 self.path('words.*.txt')
76
77 # Local HTML files (e.g. loading screen)
78 if self.prefix("html/*"):
79 self.path("*.html")
80 self.path("*.gif")
81 self.path("*.jpg")
82 self.path("*.css")
83 self.end_prefix("html/*")
84 self.end_prefix("skins")
85
86 self.path("featuretable.txt")
87 self.path("releasenotes.txt")
88 self.path("lsl_guide.html")
89 self.path("gpu_table.txt")
90
91 def flags_list(self):
92 """ Convenience function that returns the command-line flags for the grid"""
93 if(self.args['grid'] == ''):
94 return ""
95 elif(self.args['grid'] == 'firstlook'):
96 return '-settings settings_firstlook.xml'
97 else:
98 return ("-settings settings_beta.xml --%(grid)s -helperuri http://preview-%(grid)s.secondlife.com/helpers/" % {'grid':self.args['grid']})
99
100 def login_url(self):
101 """ Convenience function that returns the appropriate login url for the grid"""
102 if(self.args.get('login_url')):
103 return self.args['login_url']
104 else:
105 if(self.args['grid'] == ''):
106 return 'http://secondlife.com/app/login/'
107 elif(self.args['grid'] == 'firstlook'):
108 return 'http://secondlife.com/app/login/firstlook/'
109 else:
110 return 'http://secondlife.com/app/login/beta/'
111
112 def replace_login_url(self):
113 # set the login page to point to a url appropriate for the type of client
114 self.replace_in("skins/xui/en-us/panel_login.xml", searchdict={'http://secondlife.com/app/login/':self.login_url()})
115
116
117class WindowsManifest(ViewerManifest):
118 def final_exe(self):
119 # *NOTE: these are the only two executable names that the crash reporter recognizes
120 if self.args['grid'] == '':
121 return "SecondLife.exe"
122 elif self.args['grid'] == 'firstlook':
123 return "SecondLifeFirstLook.exe"
124 else:
125 return "SecondLifePreview.exe"
126 # return "SecondLifePreview%s.exe" % (self.args['grid'], )
127
128 def construct(self):
129 super(WindowsManifest, self).construct()
130 # the final exe is complicated because we're not sure where it's coming from,
131 # nor do we have a fixed name for the executable
132 self.path(self.find_existing_file('ReleaseForDownload/Secondlife.exe', 'Secondlife.exe', 'ReleaseNoOpt/newview_noopt.exe'), dst=self.final_exe())
133 # need to get the kdu dll from any of the build directories as well
134 self.path(self.find_existing_file('ReleaseForDownload/llkdu.dll', 'llkdu.dll', '../../libraries/i686-win32/lib_release/llkdu.dll'), dst='llkdu.dll')
135 self.path(src="licenses-win32.txt", dst="licenses.txt")
136
137 # For use in crash reporting (generates minidumps)
138 self.path("dbghelp.dll")
139
140 # For using FMOD for sound... DJS
141 self.path("fmod.dll")
142
143 # Mozilla appears to force a dependency on these files so we need to ship it (CP)
144 self.path("msvcr71.dll")
145 self.path("msvcp71.dll")
146
147 # Mozilla runtime DLLs (CP)
148 if self.prefix(src="../../libraries/i686-win32/lib_release", dst=""):
149 self.path("gksvggdiplus.dll")
150 self.path("js3250.dll")
151 self.path("nspr4.dll")
152 self.path("nss3.dll")
153 self.path("nssckbi.dll")
154 self.path("plc4.dll")
155 self.path("plds4.dll")
156 self.path("smime3.dll")
157 self.path("softokn3.dll")
158 self.path("ssl3.dll")
159 self.path("xpcom.dll")
160 self.path("xul.dll")
161 self.end_prefix()
162
163 # Mozilla runtime misc files (CP)
164 if self.prefix(src="app_settings/mozilla"):
165 self.path("chrome/*.*")
166 self.path("components/*.*")
167 self.path("greprefs/*.*")
168 self.path("plugins/*.*")
169 self.path("res/*.*")
170 self.path("res/*/*")
171 self.end_prefix()
172
173# # pull in the crash logger and updater from other projects
174# self.path(src="../win_crash_logger/win_crash_logger.exe", dst="win_crash_logger.exe")
175 self.path(src="../win_updater/updater.exe", dst="updater.exe")
176 self.replace_login_url()
177
178 def nsi_file_commands(self, install=True):
179 def wpath(path):
180 if(path.endswith('/') or path.endswith(os.path.sep)):
181 path = path[:-1]
182 path = path.replace('/', '\\')
183 return path
184
185 result = ""
186 dest_files = [pair[1] for pair in self.file_list if pair[0] and os.path.isfile(pair[1])]
187 # sort deepest hierarchy first
188 dest_files.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b))
189 dest_files.reverse()
190 out_path = None
191 for pkg_file in dest_files:
192 rel_file = os.path.normpath(pkg_file.replace(self.get_dst_prefix()+os.path.sep,''))
193 installed_dir = wpath(os.path.join('$INSTDIR', os.path.dirname(rel_file)))
194 pkg_file = wpath(os.path.normpath(pkg_file))
195 if installed_dir != out_path:
196 if(install):
197 out_path = installed_dir
198 result += 'SetOutPath ' + out_path + '\n'
199 if(install):
200 result += 'File ' + pkg_file + '\n'
201 else:
202 result += 'Delete ' + wpath(os.path.join('$INSTDIR', rel_file)) + '\n'
203 # at the end of a delete, just rmdir all the directories
204 if(not install):
205 deleted_file_dirs = [os.path.dirname(pair[1].replace(self.get_dst_prefix()+os.path.sep,'')) for pair in self.file_list]
206 # find all ancestors so that we don't skip any dirs that happened to have no non-dir children
207 deleted_dirs = []
208 for d in deleted_file_dirs:
209 deleted_dirs.extend(path_ancestors(d))
210 # sort deepest hierarchy first
211 deleted_dirs.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b))
212 deleted_dirs.reverse()
213 prev = None
214 for d in deleted_dirs:
215 if d != prev: # skip duplicates
216 result += 'RMDir ' + wpath(os.path.join('$INSTDIR', os.path.normpath(d))) + '\n'
217 prev = d
218
219 return result
220
221 def package_finish(self):
222 version_vars_template = """
223 !define INSTEXE "%(final_exe)s"
224 !define VERSION "%(version_short)s"
225 !define VERSION_LONG "%(version)s"
226 !define VERSION_DASHES "%(version_dashes)s"
227 """
228 if(self.args['grid'] == ''):
229 installer_file = "Second Life %(version_dashes)s Setup.exe"
230 grid_vars_template = """
231 OutFile "%(outfile)s"
232 !define INSTFLAGS "%(flags)s"
233 !define INSTNAME "SecondLife"
234 !define SHORTCUT "Second Life"
235 !define URLNAME "secondlife"
236 Caption "Second Life ${VERSION}"
237 """
238 else:
239 installer_file = "Second Life %(version_dashes)s (%(grid_caps)s) Setup.exe"
240 grid_vars_template = """
241 OutFile "%(outfile)s"
242 !define INSTFLAGS "%(flags)s"
243 !define INSTNAME "SecondLife%(grid_caps)s"
244 !define SHORTCUT "Second Life (%(grid_caps)s)"
245 !define URLNAME "secondlife%(grid)s"
246 !define UNINSTALL_SETTINGS 1
247 Caption "Second Life %(grid)s ${VERSION}"
248 """
249 if(self.args.has_key('installer_name')):
250 installer_file = self.args['installer_name']
251 else:
252 installer_file = installer_file % {'version_dashes' : '-'.join(self.args['version']),
253 'grid_caps' : self.args['grid'].upper()}
254 tempfile = "../secondlife_setup.nsi"
255 # the following is an odd sort of double-string replacement
256 self.replace_in("installers/windows/installer_template.nsi", tempfile, {
257 "%%VERSION%%":version_vars_template%{'version_short' : '.'.join(self.args['version'][:-1]),
258 'version' : '.'.join(self.args['version']),
259 'version_dashes' : '-'.join(self.args['version']),
260 'final_exe' : self.final_exe()},
261 "%%GRID_VARS%%":grid_vars_template%{'grid':self.args['grid'],
262 'grid_caps':self.args['grid'].upper(),
263 'outfile':installer_file,
264 'flags':self.flags_list()},
265 "%%INSTALL_FILES%%":self.nsi_file_commands(True),
266 "%%DELETE_FILES%%":self.nsi_file_commands(False)})
267
268 NSIS_path = 'C:\\Program Files\\NSIS\\makensis.exe'
269 self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile))
270 self.remove(self.dst_path_of(tempfile))
271 self.created_path(installer_file)
272
273
274class DarwinManifest(ViewerManifest):
275 def construct(self):
276 # copy over the build result (this is a no-op if run within the xcode script)
277 self.path("build/" + self.args['configuration'] + "/Second Life.app", dst="")
278
279 if self.prefix(src="", dst="Contents"): # everything goes in Contents
280 # Expand the tar file containing the assorted mozilla bits into
281 # <bundle>/Contents/MacOS/
282 self.contents_of_tar('mozilla-universal-darwin.tgz', 'MacOS')
283
284 # replace the default theme with our custom theme (so scrollbars work).
285 if self.prefix(src="mozilla-theme", dst="MacOS/chrome"):
286 self.path("classic.jar")
287 self.path("classic.manifest")
288 self.end_prefix("MacOS/chrome")
289
290 # most everything goes in the Resources directory
291 if self.prefix(src="", dst="Resources"):
292 super(DarwinManifest, self).construct()
293
294 # the trial directory seems to be not used [rdw]
295 self.path('trial')
296
297 if self.prefix("cursors_mac"):
298 self.path("*.tif")
299 self.end_prefix("cursors_mac")
300
301 self.path("licenses-mac.txt", dst="licenses.txt")
302 self.path("featuretable_mac.txt")
303 self.path("secondlife.icns")
304
305 # llkdu dynamic library
306# self.path("../../libraries/universal-darwin/lib_release/libllkdu.dylib", "libllkdu.dylib")
307
308 # command line arguments for connecting to the proper grid
309 self.put_in_file(self.flags_list(), 'arguments.txt')
310
311 # set the proper login url
312 self.replace_login_url()
313
314 self.end_prefix("Resources")
315
316 self.end_prefix("Contents")
317
318 # NOTE: the -S argument to strip causes it to keep enough info for
319 # annotated backtraces (i.e. function names in the crash log). 'strip' with no
320 # arguments yields a slightly smaller binary but makes crash logs mostly useless.
321 # This may be desirable for the final release. Or not.
322 if("package" in self.args['actions'] or
323 "unpacked" in self.args['actions']):
324 self.run_command('strip -S "%(viewer_binary)s"' %
325 { 'viewer_binary' : self.dst_path_of('Contents/MacOS/Second Life')})
326
327
328 def package_finish(self):
329 imagename="SecondLife_" + '_'.join(self.args['version'])
330 if(self.args['grid'] != ''):
331 imagename = imagename + '_' + self.args['grid'].upper()
332
333 sparsename = imagename + ".sparseimage"
334 finalname = imagename + ".dmg"
335 # make sure we don't have stale files laying about
336 self.remove(sparsename, finalname)
337
338 self.run_command('hdiutil create "%(sparse)s" -volname "Second Life" -fs HFS+ -type SPARSE -megabytes 300' % {'sparse':sparsename})
339
340 # mount the image and get the name of the mount point and device node
341 hdi_output = self.run_command('hdiutil attach -private "' + sparsename + '"')
342 devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip()
343 volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip()
344
345 # Copy everything in to the mounted .dmg
346 # TODO change name of .app once mac_updater can handle it.
347 for s,d in {
348 self.get_dst_prefix():"Second Life.app",
349 "lsl_guide.html":"Linden Scripting Language Guide.html",
350 "releasenotes.txt":"Release Notes.txt",
351 "installers/darwin/mac_image_hidden":".hidden",
352 "installers/darwin/mac_image_background.tga":"background.tga",
353 "installers/darwin/mac_image_DS_Store":".DS_Store"}.items():
354
355 print "Copying to dmg", s, d
356 self.copy_action(self.src_path_of(s), os.path.join(volpath, d))
357
358 # Unmount the image
359 self.run_command('hdiutil detach "' + devfile + '"')
360
361 print "Converting temp disk image to final disk image"
362 self.run_command('hdiutil convert "%(sparse)s" -format UDZO -imagekey zlib-level=9 -o "%(final)s"' % {'sparse':sparsename, 'final':finalname})
363 # get rid of the temp file
364 self.remove(sparsename)
365
366class LinuxManifest(ViewerManifest):
367 def construct(self):
368 super(LinuxManifest, self).construct()
369 self.path("licenses-linux.txt","licenses.txt")
370 self.path("res/ll_icon.ico","secondlife.ico")
371 if self.prefix("linux_tools", ""):
372 self.path("client-readme.txt","README-linux.txt")
373 self.path("wrapper.sh","secondlife")
374 self.path("unicode.ttf","unicode.ttf")
375 self.end_prefix("linux_tools")
376
377 # Create an appropriate gridargs.dat for this package, denoting required grid.
378 self.put_in_file(self.flags_list(), 'gridargs.dat')
379 # set proper login url
380 self.replace_login_url()
381
382 # stripping all the libs removes a few megabytes from the end-user package
383 for s,d in self.file_list:
384 if re.search("lib/lib.+\.so.*", d):
385 self.run_command('strip -S %s' % d)
386
387
388 def package_finish(self):
389 if(self.args.has_key('installer_name')):
390 installer_name = self.args['installer_name']
391 else:
392 installer_name = '_'.join('SecondLife_', self.args.get('arch'), *self.args['version'])
393 if grid != '':
394 installer_name += "_" + grid.upper()
395
396 # temporarily move directory tree so that it has the right name in the tarfile
397 self.run_command("mv %(dst)s %(inst)s" % {'dst':self.get_dst_prefix(),'inst':self.src_path_of(installer_name)})
398 # --numeric-owner hides the username of the builder for security etc.
399 self.run_command('tar -C %(dir)s --numeric-owner -cjf %(inst_path)s.tar.bz2 %(inst_name)s' % {'dir':self.get_src_prefix(), 'inst_name': installer_name, 'inst_path':self.src_path_of(installer_name)})
400 self.run_command("mv %(inst)s %(dst)s" % {'dst':self.get_dst_prefix(),'inst':self.src_path_of(installer_name)})
401
402class Linux_i686Manifest(LinuxManifest):
403 def construct(self):
404 super(Linux_i686Manifest, self).construct()
405 self.path("secondlife-i686-bin-stripped","bin/do-not-directly-run-secondlife-bin")
406# self.path("../linux_crash_logger/linux-crash-logger-i686-bin-stripped","linux-crash-logger.bin")
407 self.path("linux_tools/launch_url.sh","launch_url.sh")
408 if self.prefix("res-sdl"):
409 self.path("*")
410 # recurse
411 self.end_prefix("res-sdl")
412
413 self.path("app_settings/mozilla-runtime-linux-i686")
414
415 if self.prefix("../../libraries/i686-linux/lib_release_client", "lib"):
416# self.path("libkdu_v42R.so")
417 self.path("libfmod-3.75.so")
418 self.path("libapr-1.so.0")
419 self.path("libaprutil-1.so.0")
420 self.path("libdb-4.2.so")
421 self.path("libogg.so.0")
422 self.path("libvorbis.so.0")
423 self.path("libvorbisfile.so.0")
424 self.path("libvorbisenc.so.0")
425 self.path("libcurl.so.4")
426 self.path("libcrypto.so.0.9.7")
427 self.path("libssl.so.0.9.7")
428 self.path("libexpat.so.1")
429# self.path("libstdc++.so.6")
430 self.path("libelfio.so")
431 self.path("libuuid.so", "libuuid.so.1")
432 self.path("libSDL-1.2.so.0")
433# self.path("libllkdu.so", "../bin/libllkdu.so") # llkdu goes in bin for some reason
434 self.end_prefix("lib")
435
436
437class Linux_x86_64Manifest(LinuxManifest):
438 def construct(self):
439 super(Linux_x86_64Manifest, self).construct()
440 self.path("secondlife-x86_64-bin-stripped","bin/secondlife-bin")
441 # TODO: I get the sense that this isn't fully fleshed out
442 if self.prefix("../../libraries/x86_64-linux/lib_release_client", "lib"):
443# self.path("libkdu_v42R.so")
444 self.path("libxmlrpc.so.0")
445# # self.path("libllkdu.so", "../bin/libllkdu.so") # llkdu goes in bin for some reason
446 self.end_prefix("lib")
447
448
449if __name__ == "__main__":
450 main(srctree=viewer_dir, dsttree=os.path.join(viewer_dir, "packaged"))