Files
SingularityViewer/indra/newview/viewer_manifest.py
2013-08-14 22:41:43 +02:00

914 lines
39 KiB
Python
Executable File

#!/usr/bin/env python
"""\
@file viewer_manifest.py
@author Ryan Williams
@brief Description of all installer viewer files, and methods for packaging
them into installers for all supported platforms.
$LicenseInfo:firstyear=2006&license=viewergpl$
Second Life Viewer Source Code
Copyright (c) 2006-2009, Linden Research, Inc.
The source code in this file ("Source Code") is provided by Linden Lab
to you under the terms of the GNU General Public License, version 2.0
("GPL"), unless you have obtained a separate licensing agreement
("Other License"), formally executed by you and Linden Lab. Terms of
the GPL can be found in doc/GPL-license.txt in this distribution, or
online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
There are special exceptions to the terms and conditions of the GPL as
it is applied to this Source Code. View the full text of the exception
in the file doc/FLOSS-exception.txt in this software distribution, or
online at
http://secondlifegrid.net/programs/open_source/licensing/flossexception
By copying, modifying or distributing this software, you acknowledge
that you have read and understood your obligations described above,
and agree to abide by those obligations.
ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
COMPLETENESS OR PERFORMANCE.
$/LicenseInfo$
"""
import sys
import os.path
import re
import tarfile
viewer_dir = os.path.dirname(__file__)
# add llmanifest library to our path so we don't have to muck with PYTHONPATH
sys.path.append(os.path.join(viewer_dir, '../lib/python/indra/util'))
from llmanifest import LLManifest, main, proper_windows_path, path_ancestors
class ViewerManifest(LLManifest):
def construct(self):
super(ViewerManifest, self).construct()
self.exclude("*.svn*")
self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg")
self.path(src="../../etc/message.xml", dst="app_settings/message.xml")
if self.prefix(src="app_settings"):
self.exclude("logcontrol.xml")
self.exclude("logcontrol-dev.xml")
self.path("*.pem")
self.path("*.ini")
self.path("*.xml")
self.path("*.db2")
# include the entire shaders directory recursively
self.path("shaders")
# ... and the entire windlight directory
self.path("windlight")
# ... and the hunspell dictionaries
self.path("dictionaries")
self.end_prefix("app_settings")
if self.prefix(src="character"):
self.path("*.llm")
self.path("*.xml")
self.path("*.tga")
self.end_prefix("character")
# Include our fonts
if self.prefix(src="fonts"):
self.path("*.ttf")
self.path("*.txt")
self.end_prefix("fonts")
# skins
if self.prefix(src="skins"):
self.path("paths.xml")
# include the entire textures directory recursively
if self.prefix(src="default/textures"):
self.path("*.tga")
self.path("*.j2c")
self.path("*.jpg")
self.path("*.png")
self.path("textures.xml")
self.end_prefix("default/textures")
self.path("default/xui/*/*.xml")
self.path("Default.xml")
self.path("default/*.xml")
if self.prefix(src="dark/textures"):
self.path("*.tga")
self.path("*.j2c")
self.path("*.jpg")
self.path("*.png")
self.path("textures.xml")
self.end_prefix("dark/textures")
self.path("dark.xml")
self.path("dark/*.xml")
# Local HTML files (e.g. loading screen)
if self.prefix(src="*/html"):
self.path("*.png")
self.path("*/*/*.html")
self.path("*/*/*.gif")
self.end_prefix("*/html")
self.end_prefix("skins")
# Files in the newview/ directory
self.path("gpu_table.txt")
def login_channel(self):
"""Channel reported for login and upgrade purposes ONLY;
used for A/B testing"""
# NOTE: Do not return the normal channel if login_channel
# is not specified, as some code may branch depending on
# whether or not this is present
return self.args.get('login_channel')
def buildtype(self):
return self.args['buildtype']
def standalone(self):
return self.args['standalone'] == "ON"
def grid(self):
return self.args['grid']
def channel(self):
return self.args['channel']
def channel_unique(self):
return self.channel().replace("Second Life", "").strip()
def channel_oneword(self):
return "".join(self.channel_unique().split())
def channel_lowerword(self):
return self.channel_oneword().lower()
def viewer_branding_id(self):
return self.args['branding_id']
def installer_prefix(self):
mapping={"secondlife":'SecondLife_',
"snowglobe":'Snowglobe_',
"singularity":'Singularity_'}
return mapping[self.viewer_branding_id()]
def flags_list(self):
""" Convenience function that returns the command-line flags
for the grid"""
# Set command line flags relating to the target grid
grid_flags = ''
if not self.default_grid():
grid_flags = "--grid %(grid)s "\
"--helperuri http://preview-%(grid)s.secondlife.com/helpers/" %\
{'grid':self.grid()}
# set command line flags for channel
channel_flags = ''
if self.login_channel() and self.login_channel() != self.channel():
# Report a special channel during login, but use default
channel_flags = '--channel "%s"' % (self.login_channel())
else:
channel_flags = '--channel "%s"' % self.channel()
# Deal with settings
if self.default_channel() and self.default_grid():
setting_flags = ''
elif self.default_grid():
setting_flags = '--settings settings_%s.xml'\
% self.channel_lowerword()
else:
setting_flags = '--settings settings_%s_%s.xml'\
% (self.grid(), self.channel_lowerword())
return " ".join((channel_flags, grid_flags, setting_flags)).strip()
class WindowsManifest(ViewerManifest):
def final_exe(self):
return self.channel_oneword() + 'Viewer.exe'
def construct(self):
super(WindowsManifest, self).construct()
# the final exe is complicated because we're not sure where it's coming from,
# nor do we have a fixed name for the executable
self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe())
# Plugin host application
self.path(os.path.join(os.pardir,
'llplugin', 'slplugin', self.args['configuration'], "SLPlugin.exe"),
"SLPlugin.exe")
# Plugin volume control
if self.prefix(src=self.args['configuration'], dst=""):
self.path("winmm.dll")
self.end_prefix()
self.path(src="licenses-win32.txt", dst="licenses.txt")
self.path("featuretable.txt")
# For spellchecking
if self.prefix(src=self.args['configuration'], dst=""):
self.path("libhunspell.dll")
self.end_prefix()
# For mesh upload
if self.prefix(src=self.args['configuration'], dst=""):
self.path("libcollada14dom22.dll")
self.path("glod.dll")
self.end_prefix()
# For use in crash reporting (generates minidumps)
#self.path("dbghelp.dll")
#is shipped with windows anyway
# For using FMOD for sound... DJS
#~if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""):
#~try:
#~self.path("fmod.dll")
#~pass
#~except:
#~print "Skipping fmod.dll - not found"
#~ pass
#~self.end_prefix()
# For textures
#if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""):
# self.path("openjpeg.dll")
# self.end_prefix()
# Plugins - FilePicker
if self.prefix(src='../plugins/filepicker/%s' % self.args['configuration'], dst="llplugin"):
self.path("basic_plugin_filepicker.dll")
self.end_prefix()
# Media plugins - QuickTime
if self.prefix(src='../plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"):
self.path("media_plugin_quicktime.dll")
self.end_prefix()
# Media plugins - WebKit/Qt
if self.prefix(src='../plugins/webkit/%s' % self.args['configuration'], dst="llplugin"):
self.path("media_plugin_webkit.dll")
self.end_prefix()
# For WebKit/Qt plugin runtimes
if self.prefix(src="../../libraries/i686-win32/lib/release", dst="llplugin"):
self.path("libeay32.dll")
self.path("qtcore4.dll")
self.path("qtgui4.dll")
self.path("qtnetwork4.dll")
self.path("qtopengl4.dll")
self.path("qtwebkit4.dll")
self.path("qtxmlpatterns4.dll")
self.path("ssleay32.dll")
self.end_prefix()
# For WebKit/Qt plugin runtimes (image format plugins)
if self.prefix(src="../../libraries/i686-win32/lib/release/imageformats", dst="llplugin/imageformats"):
self.path("qgif4.dll")
self.path("qico4.dll")
self.path("qjpeg4.dll")
self.path("qmng4.dll")
self.path("qsvg4.dll")
self.path("qtiff4.dll")
self.end_prefix()
if self.prefix(src="../../libraries/i686-win32/lib/release/codecs", dst="llplugin/codecs"):
self.path("qcncodecs4.dll")
self.path("qjpcodecs4.dll")
self.path("qkrcodecs4.dll")
self.path("qtwcodecs4.dll")
self.end_prefix()
# Get llcommon and deps. If missing assume static linkage and continue.
if self.prefix(src=self.args['configuration'], dst=""):
try:
self.path('llcommon.dll')
except RuntimeError, err:
print err.message
print "Skipping llcommon.dll (assuming llcommon was linked statically)"
self.end_prefix()
if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""):
self.path("libeay32.dll")
self.path("ssleay32.dll")
try:
self.path('libapr-1.dll')
self.path('libaprutil-1.dll')
self.path('libapriconv-1.dll')
except RuntimeError, err:
pass
self.end_prefix()
# For google-perftools tcmalloc allocator.
self.path("../../libraries/i686-win32/lib/release/libtcmalloc_minimal.dll", dst="libtcmalloc_minimal.dll")
try:
if self.prefix("../../libraries/i686-win32/lib/release/msvcrt", dst=""):
self.path("*.dll")
self.path("*.manifest")
self.end_prefix()
except:
pass
# These need to be installed as a SxS assembly, currently a 'private' assembly.
# See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx
#~ if self.prefix(src=self.args['configuration'], dst=""):
#~ if self.args['configuration'] == 'Debug':
#~ self.path("msvcr80d.dll")
#~ self.path("msvcp80d.dll")
#~ self.path("Microsoft.VC80.DebugCRT.manifest")
#~ else:
#~ self.path("msvcr80.dll")
#~ self.path("msvcp80.dll")
#~ self.path("Microsoft.VC80.CRT.manifest")
#~ self.end_prefix()
# The config file name needs to match the exe's name.
#~ self.path(src="%s/secondlife-bin.exe.config" % self.args['configuration'], dst=self.final_exe() + ".config")
# Vivox runtimes
if self.prefix(src="vivox-runtime/i686-win32", dst=""):
self.path("SLVoice.exe")
self.path("alut.dll")
self.path("vivoxsdk.dll")
self.path("ortp.dll")
self.path("wrap_oal.dll")
self.end_prefix()
if 'extra_libraries' in self.args:
print self.args['extra_libraries']
path_list = self.args['extra_libraries'].split('|')
for path in path_list:
path_pair = path.rsplit('/', 1)
if self.prefix(src=path_pair[0], dst=""):
self.path(path_pair[1])
self.end_prefix()
# pull in the crash logger and updater from other projects
self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'], dst="win_crash_logger.exe")
self.path(src='../win_updater/%s/windows-updater.exe' % self.args['configuration'], dst="updater.exe")
def nsi_file_commands(self, install=True):
def wpath(path):
if path.endswith('/') or path.endswith(os.path.sep):
path = path[:-1]
path = path.replace('/', '\\')
return path
result = ""
dest_files = [pair[1] for pair in self.file_list if pair[0] and os.path.isfile(pair[1])]
dest_files = list(set(dest_files)) # remove duplicates
# sort deepest hierarchy first
dest_files.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b))
dest_files.reverse()
out_path = None
for pkg_file in dest_files:
rel_file = os.path.normpath(pkg_file.replace(self.get_dst_prefix()+os.path.sep,''))
installed_dir = wpath(os.path.join('$INSTDIR', os.path.dirname(rel_file)))
pkg_file = wpath(os.path.normpath(pkg_file))
if installed_dir != out_path:
if install:
out_path = installed_dir
result += 'SetOutPath ' + out_path + '\n'
if install:
result += 'File ' + pkg_file + '\n'
else:
result += 'Delete ' + wpath(os.path.join('$INSTDIR', rel_file)) + '\n'
# at the end of a delete, just rmdir all the directories
if not install:
deleted_file_dirs = [os.path.dirname(pair[1].replace(self.get_dst_prefix()+os.path.sep,'')) for pair in self.file_list]
# find all ancestors so that we don't skip any dirs that happened to have no non-dir children
deleted_dirs = []
for d in deleted_file_dirs:
deleted_dirs.extend(path_ancestors(d))
# sort deepest hierarchy first
deleted_dirs.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b))
deleted_dirs.reverse()
prev = None
for d in deleted_dirs:
if d != prev: # skip duplicates
result += 'RMDir ' + wpath(os.path.join('$INSTDIR', os.path.normpath(d))) + '\n'
prev = d
return result
def package_finish(self):
# a standard map of strings for replacing in the templates
substitution_strings = {
'version' : '.'.join(self.args['version']),
'version_short' : '.'.join(self.args['version'][:-1]),
'version_dashes' : '-'.join(self.args['version']),
'final_exe' : self.final_exe(),
'grid':self.args['grid'],
'grid_caps':self.args['grid'].upper(),
# escape quotes becase NSIS doesn't handle them well
'flags':self.flags_list().replace('"', '$\\"'),
'channel':self.channel(),
'channel_oneword':self.channel_oneword(),
'channel_unique':self.channel_unique(),
}
version_vars = """
!define INSTEXE "%(final_exe)s"
!define VERSION "%(version_short)s"
!define VERSION_LONG "%(version)s"
!define VERSION_DASHES "%(version_dashes)s"
""" % substitution_strings
installer_file = "%(channel_oneword)s_%(version_dashes)s_Setup.exe"
grid_vars_template = """
OutFile "%(installer_file)s"
!define VIEWERNAME "%(channel)s"
!define INSTFLAGS "%(flags)s"
!define INSTNAME "%(channel_oneword)s"
!define SHORTCUT "%(channel)s Viewer"
!define URLNAME "secondlife"
!define INSTALL_ICON "install_icon_singularity.ico"
!define UNINSTALL_ICON "install_icon_singularity.ico"
Caption "${VIEWERNAME} ${VERSION_LONG}"
"""
if 'installer_name' in self.args:
installer_file = self.args['installer_name']
else:
installer_file = installer_file % substitution_strings
substitution_strings['installer_file'] = installer_file
tempfile = "secondlife_setup_tmp.nsi"
# the following replaces strings in the nsi template
# it also does python-style % substitution
self.replace_in("installers/windows/installer_template.nsi", tempfile, {
"%%VERSION%%":version_vars,
"%%SOURCE%%":self.get_src_prefix(),
"%%GRID_VARS%%":grid_vars_template % substitution_strings,
"%%INSTALL_FILES%%":self.nsi_file_commands(True),
"%%DELETE_FILES%%":self.nsi_file_commands(False)})
# We use the Unicode version of NSIS, available from
# http://www.scratchpaper.com/
try:
import _winreg as reg
NSIS_path = reg.QueryValue(reg.HKEY_LOCAL_MACHINE, r"SOFTWARE\NSIS\Unicode") + '\\makensis.exe'
self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile))
except:
try:
NSIS_path = os.environ['ProgramFiles'] + '\\NSIS\\Unicode\\makensis.exe'
self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile))
except:
NSIS_path = os.environ['ProgramFiles(X86)'] + '\\NSIS\\Unicode\\makensis.exe'
self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile))
# self.remove(self.dst_path_of(tempfile))
# If we're on a build machine, sign the code using our Authenticode certificate. JC
sign_py = os.path.expandvars("{SIGN_PY}")
if sign_py == "" or sign_py == "{SIGN_PY}":
sign_py = 'C:\\buildscripts\\code-signing\\sign.py'
if os.path.exists(sign_py):
self.run_command('python ' + sign_py + ' ' + self.dst_path_of(installer_file))
else:
print "Skipping code signing,", sign_py, "does not exist"
self.created_path(self.dst_path_of(installer_file))
self.package_file = installer_file
class DarwinManifest(ViewerManifest):
def construct(self):
# copy over the build result (this is a no-op if run within the xcode script)
self.path(self.args['configuration'] + "/" + self.app_name() + ".app", dst="")
if self.prefix(src="", dst="Contents"): # everything goes in Contents
self.path(self.info_plist_name(), dst="Info.plist")
# copy additional libs in <bundle>/Contents/MacOS/
self.path("../../libraries/universal-darwin/lib/release/libndofdev.dylib", dst="Resources/libndofdev.dylib")
self.path("../../libraries/universal-darwin/lib/release/libhunspell-1.3.0.dylib", dst="Resources/libhunspell-1.3.0.dylib")
# most everything goes in the Resources directory
if self.prefix(src="", dst="Resources"):
super(DarwinManifest, self).construct()
if self.prefix("cursors_mac"):
self.path("*.tif")
self.end_prefix("cursors_mac")
self.path("licenses-mac.txt", dst="licenses.txt")
self.path("featuretable_mac.txt")
self.path("SecondLife.nib")
# SG:TODO
self.path("../newview/res/singularity.icns", dst="singularity.icns")
# Translations
self.path("English.lproj")
self.path("German.lproj")
self.path("Japanese.lproj")
self.path("Korean.lproj")
self.path("da.lproj")
self.path("es.lproj")
self.path("fr.lproj")
self.path("hu.lproj")
self.path("it.lproj")
self.path("nl.lproj")
self.path("pl.lproj")
self.path("pt.lproj")
self.path("ru.lproj")
self.path("tr.lproj")
self.path("uk.lproj")
self.path("zh-Hans.lproj")
# SLVoice and vivox lols
self.path("vivox-runtime/universal-darwin/libalut.dylib", "libalut.dylib")
self.path("vivox-runtime/universal-darwin/libopenal.dylib", "libopenal.dylib")
self.path("vivox-runtime/universal-darwin/libortp.dylib", "libortp.dylib")
self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib")
self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice")
self.path("../llcommon/" + self.args['configuration'] + "/libllcommon.dylib", "libllcommon.dylib")
libfile = "lib%s.dylib"
libdir = "../../libraries/universal-darwin/lib/release"
for libfile in ("libapr-1.0.dylib",
"libaprutil-1.0.dylib",
"libcollada14dom.dylib",
"libexpat.1.5.2.dylib",
"libGLOD.dylib"):
self.path(os.path.join(libdir, libfile), libfile)
# For using FMOD for sound...but, fmod is proprietary so some might not use it...
try:
self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib")
pass
except:
print "Skipping libfmodwrapper.dylib - not found"
pass
# And now FMOD Ex!
try:
self.path("libfmodex.dylib", "libfmodex.dylib")
pass
except:
print "Skipping libfmodex.dylib - not found"
pass
# our apps
try:
self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app")
self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app")
except:
pass
# plugin launcher
self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin.app", "SLPlugin.app")
# dependencies on shared libs
mac_crash_logger_res_path = self.dst_path_of("mac-crash-logger.app/Contents/Resources")
slplugin_res_path = self.dst_path_of("SLPlugin.app/Contents/Resources")
for libfile in ("libllcommon.dylib",
"libapr-1.0.dylib",
"libaprutil-1.0.dylib",
"libexpat.1.5.2.dylib"):
target_lib = os.path.join('../../..', libfile)
self.run_command("ln -sf %(target)r %(link)r" %
{'target': target_lib,
'link' : os.path.join(slplugin_res_path, libfile)}
)
#self.run_command("ln -sf %(target)r %(link)r" %
# {'target': target_lib,
# 'link' : os.path.join(mac_crash_logger_res_path, libfile)}
# )
# plugins
if self.prefix(src="", dst="llplugin"):
self.path("../plugins/filepicker/" + self.args['configuration'] + "/basic_plugin_filepicker.dylib", "basic_plugin_filepicker.dylib")
self.path("../plugins/quicktime/" + self.args['configuration'] + "/media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib")
self.path("../plugins/webkit/" + self.args['configuration'] + "/media_plugin_webkit.dylib", "media_plugin_webkit.dylib")
self.path("../../libraries/universal-darwin/lib/release/libllqtwebkit.dylib", "libllqtwebkit.dylib")
self.end_prefix("llplugin")
# command line arguments for connecting to the proper grid
self.put_in_file(self.flags_list(), 'arguments.txt')
self.end_prefix("Resources")
self.end_prefix("Contents")
# NOTE: the -S argument to strip causes it to keep enough info for
# annotated backtraces (i.e. function names in the crash log). 'strip' with no
# arguments yields a slightly smaller binary but makes crash logs mostly useless.
# This may be desirable for the final release. Or not.
if self.buildtype().lower()=='release':
if ("package" in self.args['actions'] or
"unpacked" in self.args['actions']):
self.run_command('strip -S "%(viewer_binary)s"' %
{ 'viewer_binary' : self.dst_path_of('Contents/MacOS/'+self.app_name())})
def app_name(self):
return "Singularity"
def info_plist_name(self):
return "Info-Singularity.plist"
def package_finish(self):
channel_standin = self.app_name()
if not self.default_channel_for_brand():
channel_standin = self.channel()
imagename=self.installer_prefix() + '_'.join(self.args['version'])
# See Ambroff's Hack comment further down if you want to create new bundles and dmg
volname=self.app_name() + " Installer" # DO NOT CHANGE without checking Ambroff's Hack comment further down
if self.default_channel_for_brand():
if not self.default_grid():
# beta case
imagename = imagename + '_' + self.args['grid'].upper()
else:
# first look, etc
imagename = imagename + '_' + self.channel_oneword().upper()
sparsename = imagename + ".sparseimage"
finalname = imagename + ".dmg"
# make sure we don't have stale files laying about
self.remove(sparsename, finalname)
self.run_command('hdiutil create "%(sparse)s" -volname "%(vol)s" -fs HFS+ -type SPARSE -megabytes 700 -layout SPUD' % {
'sparse':sparsename,
'vol':volname})
# mount the image and get the name of the mount point and device node
hdi_output = self.run_command('hdiutil attach -private "' + sparsename + '"')
devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip()
volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip()
# Copy everything in to the mounted .dmg
if self.default_channel_for_brand() and not self.default_grid():
app_name = self.app_name() + " " + self.args['grid']
else:
app_name = channel_standin.strip()
# Hack:
# Because there is no easy way to coerce the Finder into positioning
# the app bundle in the same place with different app names, we are
# adding multiple .DS_Store files to svn. There is one for release,
# one for release candidate and one for first look. Any other channels
# will use the release .DS_Store, and will look broken.
# - Ambroff 2008-08-20
# Added a .DS_Store for snowglobe - Merov 2009-06-17
# We have a single branded installer for all snowglobe channels so snowglobe logic is a bit different
if (self.app_name()=="Snowglobe"):
dmg_template = os.path.join ('installers', 'darwin', 'snowglobe-dmg')
else:
dmg_template = os.path.join(
'installers',
'darwin',
'%s-dmg' % "".join(self.channel_unique().split()).lower())
if not os.path.exists (self.src_path_of(dmg_template)):
dmg_template = os.path.join ('installers', 'darwin', 'release-dmg')
for s,d in {self.get_dst_prefix():app_name + ".app",
os.path.join(dmg_template, "_VolumeIcon.icns"): ".VolumeIcon.icns",
os.path.join(dmg_template, "background.jpg"): "background.jpg",
os.path.join(dmg_template, "_DS_Store"): ".DS_Store"}.items():
print "Copying to dmg", s, d
self.copy_action(self.src_path_of(s), os.path.join(volpath, d))
# Hide the background image, DS_Store file, and volume icon file (set their "visible" bit)
self.run_command('SetFile -a V "' + os.path.join(volpath, ".VolumeIcon.icns") + '"')
self.run_command('SetFile -a V "' + os.path.join(volpath, "background.jpg") + '"')
self.run_command('SetFile -a V "' + os.path.join(volpath, ".DS_Store") + '"')
# Create the alias file (which is a resource file) from the .r
self.run_command('rez "' + self.src_path_of("installers/darwin/release-dmg/Applications-alias.r") + '" -o "' + os.path.join(volpath, "Applications") + '"')
# Set the alias file's alias and custom icon bits
self.run_command('SetFile -a AC "' + os.path.join(volpath, "Applications") + '"')
# Set the disk image root's custom icon bit
self.run_command('SetFile -a C "' + volpath + '"')
# Unmount the image
self.run_command('hdiutil detach -force "' + devfile + '"')
print "Converting temp disk image to final disk image"
self.run_command('hdiutil convert "%(sparse)s" -format UDZO -imagekey zlib-level=9 -o "%(final)s"' % {'sparse':sparsename, 'final':finalname})
# get rid of the temp file
self.package_file = finalname
self.remove(sparsename)
class LinuxManifest(ViewerManifest):
def construct(self):
super(LinuxManifest, self).construct()
self.path("licenses-linux.txt","licenses.txt")
self.path("res/"+self.icon_name(),self.icon_name())
if self.prefix("linux_tools", dst=""):
self.path("client-readme.txt","README-linux.txt")
self.path("client-readme-voice.txt","README-linux-voice.txt")
self.path("client-readme-joystick.txt","README-linux-joystick.txt")
self.path("wrapper.sh",self.wrapper_name())
self.path("handle_secondlifeprotocol.sh")
self.path("register_secondlifeprotocol.sh")
self.path("refresh_desktop_app_entry.sh")
self.path("launch_url.sh")
self.path("install.sh")
self.end_prefix("linux_tools")
# Create an appropriate gridargs.dat for this package, denoting required grid.
self.put_in_file(self.flags_list(), 'gridargs.dat')
if self.buildtype().lower()=='release':
self.path("secondlife-stripped","bin/"+self.binary_name())
self.path("../linux_crash_logger/linux-crash-logger-stripped","linux-crash-logger.bin")
else:
self.path("secondlife-bin","bin/"+self.binary_name())
self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin")
self.path("../llplugin/slplugin/SLPlugin", "bin/SLPlugin")
if self.prefix("res-sdl"):
self.path("*")
# recurse
self.end_prefix("res-sdl")
# plugins
if self.prefix(src="", dst="bin/llplugin"):
self.path("../plugins/filepicker/libbasic_plugin_filepicker.so", "libbasic_plugin_filepicker.so")
self.path("../plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so")
self.path("../plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so")
self.end_prefix("bin/llplugin")
self.path("featuretable_linux.txt")
def wrapper_name(self):
return 'singularity'
def binary_name(self):
return 'singularity-do-not-run-directly'
def icon_name(self):
return "singularity_icon.png"
def package_finish(self):
if 'installer_name' in self.args:
installer_name = self.args['installer_name']
else:
installer_name_components = [self.installer_prefix(), self.args.get('arch')]
installer_name_components.extend(self.args['version'])
installer_name = "_".join(installer_name_components)
if self.default_channel():
if not self.default_grid():
installer_name += '_' + self.args['grid'].upper()
else:
installer_name += '_' + self.channel_oneword().upper()
if self.args['buildtype'].lower() in ['release', 'releasesse2']:
print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build"
# makes some small assumptions about our packaged dir structure
self.run_command("find %(d)r/bin %(d)r/lib* -type f | xargs -d '\n' --no-run-if-empty strip --strip-unneeded" % {'d': self.get_dst_prefix()} )
self.run_command("find %(d)r/bin %(d)r/lib* -type f -not -name \\*.so | xargs -d '\n' --no-run-if-empty strip -s" % {'d': self.get_dst_prefix()} )
# Fix access permissions
self.run_command("""
find '%(dst)s' -type d -print0 | xargs -0 --no-run-if-empty chmod 755;
find '%(dst)s' -type f -perm 0700 -print0 | xargs -0 --no-run-if-empty chmod 0755;
find '%(dst)s' -type f -perm 0500 -print0 | xargs -0 --no-run-if-empty chmod 0555;
find '%(dst)s' -type f -perm 0600 -print0 | xargs -0 --no-run-if-empty chmod 0644;
find '%(dst)s' -type f -perm 0400 -print0 | xargs -0 --no-run-if-empty chmod 0444;
true""" % {'dst':self.get_dst_prefix() })
self.package_file = installer_name + '.tar.bz2'
# temporarily move directory tree so that it has the right
# name in the tarfile
self.run_command("mv '%(dst)s' '%(inst)s'" % {
'dst': self.get_dst_prefix(),
'inst': self.build_path_of(installer_name)})
try:
# --numeric-owner hides the username of the builder for
# security etc.
# I'm leaving this disabled for speed
#self.run_command("tar -C '%(dir)s' --numeric-owner -cjf "
# "'%(inst_path)s.tar.bz2' %(inst_name)s" % {
# 'dir': self.get_build_prefix(),
# 'inst_name': installer_name,
# 'inst_path':self.build_path_of(installer_name)})
print ''
finally:
self.run_command("mv '%(inst)s' '%(dst)s'" % {
'dst': self.get_dst_prefix(),
'inst': self.build_path_of(installer_name)})
class Linux_i686Manifest(LinuxManifest):
def construct(self):
super(Linux_i686Manifest, self).construct()
self.path("../llcommon/libllcommon.so", "lib/libllcommon.so")
if (not self.standalone()) and self.prefix("../../libraries/i686-linux/lib/release", dst="lib"):
try:
self.path("libfmod-3.75.so")
pass
except:
print "Skipping libfmod-3.75.so - not found"
pass
self.path("libELFIO.so")
self.path("libSDL-1.2.so*")
self.path("libapr-1.so*")
self.path("libaprutil-1.so*")
self.path("libcollada14dom.so")
self.path("libcrypto.so*")
self.path("libdb*.so")
self.path("libdirect-1.*.so*")
self.path("libdirectfb-1.*.so*")
self.path("libfusion-1.*.so*")
self.path("libglod.so")
self.path("libminizip.so")
self.path("libexpat.so*")
self.path("libhunspell-*.so.*")
self.path("libssl.so*")
self.path("libuuid.so*")
self.path("libalut.so")
self.path("libopenal.so.1")
self.path("libtcmalloc_minimal.so.0")
self.path("libtcmalloc_minimal.so.0.2.2")
if 'extra_libraries' in self.args:
path_list = self.args['extra_libraries'].split('|')
for path in path_list:
src_path = os.path.realpath(path)
dst_path = os.path.basename(path)
self.path(src_path, dst_path)
self.end_prefix("lib")
# Vivox runtimes
if self.prefix(src="vivox-runtime/i686-linux", dst="bin"):
self.path("SLVoice")
self.end_prefix()
if self.prefix(src="vivox-runtime/i686-linux", dst="lib"):
self.path("libortp.so")
self.path("libvivoxsdk.so")
self.end_prefix("lib")
class Linux_x86_64Manifest(LinuxManifest):
def construct(self):
super(Linux_x86_64Manifest, self).construct()
self.path("../llcommon/libllcommon.so", "lib64/libllcommon.so")
if (not self.standalone()) and self.prefix("../../libraries/x86_64-linux/lib/release", dst="lib64"):
self.path("libapr-1.so*")
self.path("libaprutil-1.so*")
self.path("libcollada14dom.so.2.2", "libcollada14dom.so")
self.path("libdb-*.so*")
self.path("libcrypto.so.*")
self.path("libexpat.so*")
self.path("libglod.so")
self.path("libhunspell-1.3.so*")
self.path("libpcre.so.3");
self.path("libminizip.so.1.2.3", "libminizip.so");
self.path("libssl.so*")
self.path("libuuid.so*")
self.path("libSDL-1.2.so*")
self.path("libELFIO.so")
self.path("libjpeg.so*")
self.path("libpng*.so*")
self.path("libz.so*")
# OpenAL
self.path("libopenal.so*")
self.path("libalut.so*")
if 'extra_libraries' in self.args:
path_list = self.args['extra_libraries'].split('|')
for path in path_list:
src_path = os.path.realpath(path)
dst_path = os.path.basename(path)
self.path(src_path, dst_path)
self.end_prefix("lib64")
# Vivox runtimes and libs
if self.prefix(src="vivox-runtime/i686-linux", dst="bin"):
self.path("SLVoice")
self.end_prefix("bin")
if self.prefix(src="vivox-runtime/i686-linux", dst="lib32"):
#self.path("libalut.so")
self.path("libortp.so")
self.path("libvivoxsdk.so")
self.end_prefix("lib32")
# 32bit libs needed for voice
if self.prefix("../../libraries/x86_64-linux/lib/release/32bit-compat", dst="lib32"):
self.path("libalut.so")
self.path("libidn.so.11")
self.path("libopenal.so.1")
# self.path("libortp.so")
self.path("libuuid.so.1")
self.end_prefix("lib32")
if __name__ == "__main__":
main()