00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 import sys
00033 import os.path
00034 import re
00035 import tarfile
00036 viewer_dir = os.path.dirname(__file__)
00037
00038 sys.path.append(os.path.join(viewer_dir, '../lib/python/indra/util'))
00039 from llmanifest import LLManifest, main, proper_windows_path, path_ancestors
00040
00041 class ViewerManifest(LLManifest):
00042 def construct(self):
00043 super(ViewerManifest, self).construct()
00044 self.exclude("*.svn*")
00045 self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg")
00046 self.path(src="../../etc/message.xml", dst="app_settings/message.xml")
00047
00048 if self.prefix(src="app_settings"):
00049 self.exclude("logcontrol.xml")
00050 self.exclude("logcontrol-dev.xml")
00051 self.path("*.pem")
00052 self.path("*.ini")
00053 self.path("*.xml")
00054 self.path("*.vp")
00055 self.path("*.db2")
00056
00057
00058 self.path("shaders")
00059
00060 self.path("windlight")
00061 self.end_prefix("app_settings")
00062
00063 if self.prefix(src="character"):
00064 self.path("*.llm")
00065 self.path("*.xml")
00066 self.path("*.tga")
00067 self.end_prefix("character")
00068
00069
00070
00071 if self.prefix(src="fonts"):
00072 self.path("*.ttf")
00073 self.path("*.txt")
00074 self.end_prefix("fonts")
00075
00076
00077 if self.prefix(src="skins"):
00078
00079 self.path("textures")
00080 self.path("paths.xml")
00081 self.path("xui/*/*.xml")
00082 self.path('words.*.txt')
00083
00084
00085 if self.prefix(src="html"):
00086 self.path("*.png")
00087 self.path("*/*/*.html")
00088 self.path("*/*/*.gif")
00089 self.end_prefix("html")
00090 self.end_prefix("skins")
00091
00092 self.path("releasenotes.txt")
00093 self.path("lsl_guide.html")
00094 self.path("gpu_table.txt")
00095
00096 def login_channel(self):
00097 """Channel reported for login and upgrade purposes ONLY; used for A/B testing"""
00098
00099
00100 return self.args.get('login_channel')
00101
00102 def channel(self):
00103 return self.args['channel']
00104 def channel_unique(self):
00105 return self.channel().replace("Second Life", "").strip()
00106 def channel_oneword(self):
00107 return "".join(self.channel_unique().split())
00108 def channel_lowerword(self):
00109 return self.channel_oneword().lower()
00110
00111 def flags_list(self):
00112 """ Convenience function that returns the command-line flags for the grid"""
00113 channel_flags = ''
00114 grid_flags = ''
00115 if not self.default_grid():
00116 if self.default_channel():
00117
00118 channel_flags = '--settings settings_beta.xml'
00119 grid_flags = "--grid %(grid)s --helperuri http://preview-%(grid)s.secondlife.com/helpers/" % {'grid':self.args['grid']}
00120
00121 if not self.default_channel():
00122
00123 channel_flags = '--settings settings_%s.xml --channel "%s"' % (self.channel_lowerword(), self.channel())
00124 elif self.login_channel():
00125
00126 channel_flags = '--channel "%s"' % (self.login_channel())
00127
00128 return " ".join((channel_flags, grid_flags)).strip()
00129
00130
00131 class WindowsManifest(ViewerManifest):
00132 def final_exe(self):
00133 if self.default_channel():
00134 if self.default_grid():
00135 return "SecondLife.exe"
00136 else:
00137 return "SecondLifePreview.exe"
00138 else:
00139 return ''.join(self.channel().split()) + '.exe'
00140
00141
00142 def construct(self):
00143 super(WindowsManifest, self).construct()
00144
00145
00146 self.path(self.find_existing_file('ReleaseForDownload/Secondlife.exe', 'Secondlife.exe', 'ReleaseNoOpt/newview_noopt.exe'), dst=self.final_exe())
00147
00148 self.path(self.find_existing_file('ReleaseForDownload/llkdu.dll', 'llkdu.dll', '../../libraries/i686-win32/lib_release/llkdu.dll'), dst='llkdu.dll')
00149 self.path(src="licenses-win32.txt", dst="licenses.txt")
00150
00151 self.path("featuretable.txt")
00152
00153
00154 self.path("dbghelp.dll")
00155
00156
00157 self.path("fmod.dll")
00158
00159
00160 if self.prefix(src="../../libraries/i686-win32/lib_release", dst=""):
00161 self.path("openjpeg.dll")
00162 self.end_prefix()
00163
00164
00165 self.path("msvcr71.dll")
00166 self.path("msvcp71.dll")
00167
00168
00169 if self.prefix(src="../../libraries/i686-win32/lib_release", dst=""):
00170 self.path("freebl3.dll")
00171 self.path("gksvggdiplus.dll")
00172 self.path("js3250.dll")
00173 self.path("nspr4.dll")
00174 self.path("nss3.dll")
00175 self.path("nssckbi.dll")
00176 self.path("plc4.dll")
00177 self.path("plds4.dll")
00178 self.path("smime3.dll")
00179 self.path("softokn3.dll")
00180 self.path("ssl3.dll")
00181 self.path("xpcom.dll")
00182 self.path("xul.dll")
00183 self.end_prefix()
00184
00185
00186 if self.prefix(src="app_settings/mozilla"):
00187 self.path("chrome/*.*")
00188 self.path("components/*.*")
00189 self.path("greprefs/*.*")
00190 self.path("plugins/*.*")
00191 self.path("res/*.*")
00192 self.path("res/*/*")
00193 self.end_prefix()
00194
00195
00196 if self.prefix(src="vivox-runtime/i686-win32", dst=""):
00197 self.path("SLVoice.exe")
00198 self.path("SLVoiceAgent.exe")
00199 self.path("libeay32.dll")
00200 self.path("srtp.dll")
00201 self.path("ssleay32.dll")
00202 self.path("tntk.dll")
00203 self.path("alut.dll")
00204 self.path("vivoxsdk.dll")
00205 self.path("ortp.dll")
00206 self.path("wrap_oal.dll")
00207 self.end_prefix()
00208
00209
00210
00211 self.path(src="../win_updater/updater.exe", dst="updater.exe")
00212
00213 def nsi_file_commands(self, install=True):
00214 def wpath(path):
00215 if(path.endswith('/') or path.endswith(os.path.sep)):
00216 path = path[:-1]
00217 path = path.replace('/', '\\')
00218 return path
00219
00220 result = ""
00221 dest_files = [pair[1] for pair in self.file_list if pair[0] and os.path.isfile(pair[1])]
00222
00223 dest_files.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b))
00224 dest_files.reverse()
00225 out_path = None
00226 for pkg_file in dest_files:
00227 rel_file = os.path.normpath(pkg_file.replace(self.get_dst_prefix()+os.path.sep,''))
00228 installed_dir = wpath(os.path.join('$INSTDIR', os.path.dirname(rel_file)))
00229 pkg_file = wpath(os.path.normpath(pkg_file))
00230 if installed_dir != out_path:
00231 if(install):
00232 out_path = installed_dir
00233 result += 'SetOutPath ' + out_path + '\n'
00234 if(install):
00235 result += 'File ' + pkg_file + '\n'
00236 else:
00237 result += 'Delete ' + wpath(os.path.join('$INSTDIR', rel_file)) + '\n'
00238
00239 if(not install):
00240 deleted_file_dirs = [os.path.dirname(pair[1].replace(self.get_dst_prefix()+os.path.sep,'')) for pair in self.file_list]
00241
00242 deleted_dirs = []
00243 for d in deleted_file_dirs:
00244 deleted_dirs.extend(path_ancestors(d))
00245
00246 deleted_dirs.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b))
00247 deleted_dirs.reverse()
00248 prev = None
00249 for d in deleted_dirs:
00250 if d != prev:
00251 result += 'RMDir ' + wpath(os.path.join('$INSTDIR', os.path.normpath(d))) + '\n'
00252 prev = d
00253
00254 return result
00255
00256 def package_finish(self):
00257
00258 substitution_strings = {
00259 'version' : '.'.join(self.args['version']),
00260 'version_short' : '.'.join(self.args['version'][:-1]),
00261 'version_dashes' : '-'.join(self.args['version']),
00262 'final_exe' : self.final_exe(),
00263 'grid':self.args['grid'],
00264 'grid_caps':self.args['grid'].upper(),
00265
00266 'flags':self.flags_list().replace('"', '$\\"'),
00267 'channel':self.channel(),
00268 'channel_oneword':self.channel_oneword(),
00269 'channel_unique':self.channel_unique(),
00270 }
00271
00272 version_vars = """
00273 !define INSTEXE "%(final_exe)s"
00274 !define VERSION "%(version_short)s"
00275 !define VERSION_LONG "%(version)s"
00276 !define VERSION_DASHES "%(version_dashes)s"
00277 """ % substitution_strings
00278 if self.default_channel():
00279 if self.default_grid():
00280
00281 installer_file = "Second_Life_%(version_dashes)s_Setup.exe"
00282 grid_vars_template = """
00283 OutFile "%(installer_file)s"
00284 !define INSTFLAGS "%(flags)s"
00285 !define INSTNAME "SecondLife"
00286 !define SHORTCUT "Second Life"
00287 !define URLNAME "secondlife"
00288 Caption "Second Life ${VERSION}"
00289 """
00290 else:
00291
00292 installer_file = "Second_Life_%(version_dashes)s_(%(grid_caps)s)_Setup.exe"
00293 grid_vars_template = """
00294 OutFile "%(installer_file)s"
00295 !define INSTFLAGS "%(flags)s"
00296 !define INSTNAME "SecondLife%(grid_caps)s"
00297 !define SHORTCUT "Second Life (%(grid_caps)s)"
00298 !define URLNAME "secondlife%(grid)s"
00299 !define UNINSTALL_SETTINGS 1
00300 Caption "Second Life %(grid)s ${VERSION}"
00301 """
00302 else:
00303
00304 installer_file = "Second_Life_%(version_dashes)s_%(channel_oneword)s_Setup.exe"
00305 grid_vars_template = """
00306 OutFile "%(installer_file)s"
00307 !define INSTFLAGS "%(flags)s"
00308 !define INSTNAME "SecondLife%(channel_oneword)s"
00309 !define SHORTCUT "%(channel)s"
00310 !define URLNAME "secondlife"
00311 !define UNINSTALL_SETTINGS 1
00312 Caption "%(channel)s ${VERSION}"
00313 """
00314 if(self.args.has_key('installer_name')):
00315 installer_file = self.args['installer_name']
00316 else:
00317 installer_file = installer_file % substitution_strings
00318 substitution_strings['installer_file'] = installer_file
00319
00320 tempfile = "../secondlife_setup_tmp.nsi"
00321
00322
00323 self.replace_in("installers/windows/installer_template.nsi", tempfile, {
00324 "%%VERSION%%":version_vars,
00325 "%%GRID_VARS%%":grid_vars_template % substitution_strings,
00326 "%%INSTALL_FILES%%":self.nsi_file_commands(True),
00327 "%%DELETE_FILES%%":self.nsi_file_commands(False)})
00328
00329 NSIS_path = 'C:\\Program Files\\NSIS\\makensis.exe'
00330 self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile))
00331
00332 self.created_path(installer_file)
00333
00334
00335 class DarwinManifest(ViewerManifest):
00336 def construct(self):
00337
00338 self.path("build/" + self.args['configuration'] + "/Second Life.app", dst="")
00339
00340 if self.prefix(src="", dst="Contents"):
00341
00342
00343 self.contents_of_tar('mozilla-universal-darwin.tgz', 'MacOS')
00344
00345
00346 self.path("../../libraries/universal-darwin/lib_release/libndofdev.dylib", dst="MacOS/libndofdev.dylib")
00347
00348
00349 if self.prefix(src="mozilla-theme", dst="MacOS/chrome"):
00350 self.path("classic.jar")
00351 self.path("classic.manifest")
00352 self.end_prefix("MacOS/chrome")
00353
00354
00355 if self.prefix(src="", dst="Resources"):
00356 super(DarwinManifest, self).construct()
00357
00358 if self.prefix("cursors_mac"):
00359 self.path("*.tif")
00360 self.end_prefix("cursors_mac")
00361
00362 self.path("licenses-mac.txt", dst="licenses.txt")
00363 self.path("featuretable_mac.txt")
00364 self.path("secondlife.icns")
00365
00366
00367
00368
00369
00370 self.put_in_file(self.flags_list(), 'arguments.txt')
00371
00372 self.end_prefix("Resources")
00373
00374 self.end_prefix("Contents")
00375
00376
00377
00378
00379
00380 if("package" in self.args['actions'] or
00381 "unpacked" in self.args['actions']):
00382 self.run_command('strip -S "%(viewer_binary)s"' %
00383 { 'viewer_binary' : self.dst_path_of('Contents/MacOS/Second Life')})
00384
00385
00386 def package_finish(self):
00387 channel_standin = 'Second Life'
00388 if not self.default_channel():
00389 channel_standin = self.channel()
00390
00391 imagename="SecondLife_" + '_'.join(self.args['version'])
00392 if self.default_channel():
00393 if not self.default_grid():
00394
00395 imagename = imagename + '_' + self.args['grid'].upper()
00396 else:
00397
00398 imagename = imagename + '_' + self.channel_oneword().upper()
00399
00400 sparsename = imagename + ".sparseimage"
00401 finalname = imagename + ".dmg"
00402
00403 self.remove(sparsename, finalname)
00404
00405 self.run_command('hdiutil create "%(sparse)s" -volname "%(channel)s" -fs HFS+ -type SPARSE -megabytes 300 -layout SPUD' % {
00406 'sparse':sparsename,
00407 'channel':channel_standin})
00408
00409
00410 hdi_output = self.run_command('hdiutil attach -private "' + sparsename + '"')
00411 devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip()
00412 volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip()
00413
00414
00415 if self.default_channel() and not self.default_grid():
00416 app_name = "Second Life " + self.args['grid']
00417 else:
00418 app_name = channel_standin.strip()
00419
00420 for s,d in {self.get_dst_prefix():app_name + ".app",
00421 "lsl_guide.html":"Linden Scripting Language Guide.html",
00422 "releasenotes.txt":"Release Notes.txt",
00423 "installers/darwin/mac_image_hidden":".hidden",
00424 "installers/darwin/mac_image_background.tga":"background.tga",
00425 "installers/darwin/mac_image_DS_Store":".DS_Store"}.items():
00426 print "Copying to dmg", s, d
00427 self.copy_action(self.src_path_of(s), os.path.join(volpath, d))
00428
00429
00430 self.run_command('hdiutil detach -force "' + devfile + '"')
00431
00432 print "Converting temp disk image to final disk image"
00433 self.run_command('hdiutil convert "%(sparse)s" -format UDZO -imagekey zlib-level=9 -o "%(final)s"' % {'sparse':sparsename, 'final':finalname})
00434
00435 self.remove(sparsename)
00436
00437 class LinuxManifest(ViewerManifest):
00438 def construct(self):
00439 super(LinuxManifest, self).construct()
00440 self.path("licenses-linux.txt","licenses.txt")
00441 self.path("res/ll_icon.png","secondlife_icon.png")
00442 if self.prefix("linux_tools", ""):
00443 self.path("client-readme.txt","README-linux.txt")
00444 self.path("client-readme-voice.txt","README-linux-voice.txt")
00445 self.path("wrapper.sh","secondlife")
00446 self.path("handle_secondlifeprotocol.sh")
00447 self.path("register_secondlifeprotocol.sh")
00448 self.end_prefix("linux_tools")
00449
00450
00451 self.put_in_file(self.flags_list(), 'gridargs.dat')
00452
00453
00454 def package_finish(self):
00455
00456 for s,d in self.file_list:
00457 if re.search("lib/lib.+\.so.*", d):
00458 self.run_command('strip -S %s' % d)
00459 if re.search("app_settings/mozilla-runtime-.*/lib.+\.so.*", d):
00460 self.run_command('strip %s' % d)
00461
00462 if(self.args.has_key('installer_name')):
00463 installer_name = self.args['installer_name']
00464 else:
00465 installer_name = '_'.join('SecondLife_', self.args.get('arch'), *self.args['version'])
00466 if self.default_channel():
00467 if not self.default_grid():
00468 installer_name += '_' + self.args['grid'].upper()
00469 else:
00470 installer_name += '_' + self.channel_oneword().upper()
00471
00472
00473 self.run_command("""
00474 find %(dst)s -type d | xargs chmod 755;
00475 find %(dst)s -type f -perm 0700 | xargs chmod 0755;
00476 find %(dst)s -type f -perm 0500 | xargs chmod 0555;
00477 find %(dst)s -type f -perm 0600 | xargs chmod 0644;
00478 find %(dst)s -type f -perm 0400 | xargs chmod 0444;
00479 true""" % {'dst':self.get_dst_prefix() })
00480
00481
00482 self.run_command("mv %(dst)s %(inst)s" % {'dst':self.get_dst_prefix(),'inst':self.src_path_of(installer_name)})
00483
00484 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)})
00485 self.run_command("mv %(inst)s %(dst)s" % {'dst':self.get_dst_prefix(),'inst':self.src_path_of(installer_name)})
00486
00487 class Linux_i686Manifest(LinuxManifest):
00488 def construct(self):
00489 super(Linux_i686Manifest, self).construct()
00490 self.path("secondlife-i686-bin-stripped","bin/do-not-directly-run-secondlife-bin")
00491
00492 self.path("linux_tools/launch_url.sh","launch_url.sh")
00493 if self.prefix("res-sdl"):
00494 self.path("*")
00495
00496 self.end_prefix("res-sdl")
00497
00498 self.path("featuretable_linux.txt")
00499
00500
00501 self.path("app_settings/mozilla-runtime-linux-i686")
00502
00503 if self.prefix("../../libraries/i686-linux/lib_release_client", "lib"):
00504
00505 self.path("libfmod-3.75.so")
00506 self.path("libapr-1.so.0")
00507 self.path("libaprutil-1.so.0")
00508 self.path("libdb-4.2.so")
00509 self.path("libcrypto.so.0.9.7")
00510 self.path("libssl.so.0.9.7")
00511
00512 self.path("libuuid.so", "libuuid.so.1")
00513 self.path("libSDL-1.2.so.0")
00514 self.path("libELFIO.so")
00515 self.path("libopenjpeg.so.2")
00516
00517
00518
00519 self.end_prefix("lib")
00520
00521
00522 if self.prefix(src="vivox-runtime/i686-linux", dst=""):
00523 self.path("SLVoice")
00524 self.end_prefix()
00525 if self.prefix(src="vivox-runtime/i686-linux", dst="lib"):
00526 self.path("libopenal.so.1")
00527 self.path("libortp.so")
00528 self.path("libvivoxsdk.so")
00529 self.path("libalut.so")
00530 self.end_prefix("lib")
00531
00532 class Linux_x86_64Manifest(LinuxManifest):
00533 def construct(self):
00534 super(Linux_x86_64Manifest, self).construct()
00535 self.path("secondlife-x86_64-bin-stripped","bin/do-not-directly-run-secondlife-bin")
00536
00537 self.path("linux_tools/launch_url.sh","launch_url.sh")
00538 if self.prefix("res-sdl"):
00539 self.path("*")
00540
00541 self.end_prefix("res-sdl")
00542
00543 self.path("featuretable_linux.txt")
00544 self.path("secondlife-i686.supp")
00545
00546 if __name__ == "__main__":
00547 main(srctree=viewer_dir, dsttree=os.path.join(viewer_dir, "packaged"))