Fix up icon copying and make manifest actually start to kinda work again

This commit is contained in:
Drake Arconis
2016-01-16 11:18:40 -05:00
parent 13666ac62a
commit e9f4b917d1
14 changed files with 586 additions and 473 deletions

2
.gitignore vendored
View File

@@ -10,6 +10,8 @@
/indra/viewer-*
/indra/newview/vivox-runtime/
/indra/newview/dbghelp.dll
indra/newview/res/viewer_icon.*
indra/newview/res-sdl/viewer_icon.*
/libraries/
/lib/
*.pyc

View File

@@ -24,9 +24,10 @@ set(LIBS_OPEN_PREFIX)
set(SCRIPTS_PREFIX ../scripts)
set(VIEWER_PREFIX)
set(INTEGRATION_TESTS_PREFIX)
set(DISABLE_TCMALLOC OFF CACHE BOOL "Disable linkage of TCMalloc. (64bit builds automatically disable TCMalloc)")
set(LL_TESTS OFF CACHE BOOL "Build and run unit and integration tests (disable for build timing runs to reduce variation)")
# Compiler and toolchain options
set(DISABLE_TCMALLOC OFF CACHE BOOL "Disable linkage of TCMalloc. (64bit builds automatically disable TCMalloc)")
set(DISABLE_FATAL_WARNINGS TRUE CACHE BOOL "Set this to FALSE to enable fatal warnings.")
if(LIBS_CLOSED_DIR)
@@ -168,15 +169,10 @@ endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# Default deploy grid
set(GRID agni CACHE STRING "Target Grid")
set(VIEWER_CHANNEL "Singularity" CACHE STRING "Viewer Channel Name")
set(VIEWER_CHANNEL "Singularity Test" CACHE STRING "Viewer Channel Name")
set(VIEWER_LOGIN_CHANNEL "${VIEWER_CHANNEL}" CACHE STRING "Fake login channel for A/B Testing")
set(VIEWER_BRANDING_ID "singularity" CACHE STRING "Viewer branding id (currently secondlife|snowglobe)")
# *TODO: break out proper Branding-secondlife.cmake, Branding-snowglobe.cmake, etc
string(REGEX REPLACE " +" "" VIEWER_CHANNEL_ONE_WORD "${VIEWER_CHANNEL}")
set(VIEWER_BRANDING_NAME "${VIEWER_CHANNEL_ONE_WORD}")
set(VIEWER_BRANDING_NAME_CAMELCASE "${VIEWER_CHANNEL_ONE_WORD}")
set(ENABLE_SIGNING OFF CACHE BOOL "Enable signing the viewer")
set(SIGNING_IDENTITY "" CACHE STRING "Specifies the signing identity to use, if necessary.")
set(VERSION_BUILD "0" CACHE STRING "Revision number passed in from the outside")
set(STANDALONE OFF CACHE BOOL "Do not use Linden-supplied prebuilt libraries.")

View File

@@ -41,6 +41,14 @@ import tarfile
import errno
import subprocess
class ManifestError(RuntimeError):
"""Use an exception more specific than generic Python RuntimeError"""
pass
class MissingError(ManifestError):
"""You specified a file that doesn't exist"""
pass
def path_ancestors(path):
drive, path = os.path.splitdrive(os.path.normpath(path))
result = []
@@ -76,31 +84,9 @@ def get_default_platform(dummy):
'darwin':'darwin'
}[sys.platform]
def get_default_version(srctree):
# look up llversion.h and parse out the version info
paths = [os.path.join(srctree, x, 'llversionviewer.h') for x in ['llcommon', '../llcommon', '../../indra/llcommon.h']]
for p in paths:
if os.path.exists(p):
contents = open(p, 'r').read()
major = re.search("LL_VERSION_MAJOR\s=\s([0-9]+)", contents).group(1)
minor = re.search("LL_VERSION_MINOR\s=\s([0-9]+)", contents).group(1)
patch = re.search("LL_VERSION_PATCH\s=\s([0-9]+)", contents).group(1)
build = re.search("LL_VERSION_BUILD\s=\s([0-9]+)", contents).group(1)
return major, minor, patch, build
def get_channel(srctree):
# look up llversionserver.h and parse out the version info
paths = [os.path.join(srctree, x, 'llversionviewer.h') for x in ['llcommon', '../llcommon', '../../indra/llcommon.h']]
for p in paths:
if os.path.exists(p):
contents = open(p, 'r').read()
channel = re.search("LL_CHANNEL\s=\s\"(.+)\";\s*$", contents, flags = re.M).group(1)
return channel
DEFAULT_SRCTREE = os.path.dirname(sys.argv[0])
DEFAULT_CHANNEL = 'Second Life Release'
DEFAULT_CHANNEL_SNOWGLOBE = 'Snowglobe Release'
CHANNEL_VENDOR_BASE = 'Singularity'
RELEASE_CHANNEL = CHANNEL_VENDOR_BASE + ' Release'
ARGUMENTS=[
dict(name='actions',
@@ -121,27 +107,19 @@ ARGUMENTS=[
On Linux this would try to use Linux_i686Manifest.""",
default=""),
dict(name='build', description='Build directory.', default=DEFAULT_SRCTREE),
dict(name='buildtype', description="""The build type used. ('Debug', 'Release', or 'RelWithDebInfo')
Default is Release """,
default="Release"),
dict(name='branding_id', description="""Identifier for the branding set to
use. Currently, 'secondlife' or 'snowglobe')""",
default='secondlife'),
dict(name='buildtype', description='Build type (i.e. Debug, Release, RelWithDebInfo).', default=None),
dict(name='configuration',
description="""The build configuration used. Only used on OS X for
now, but it could be used for other platforms as well.""",
default="Universal"),
description="""The build configuration used.""",
default="Release"),
dict(name='dest', description='Destination directory.', default=DEFAULT_SRCTREE),
dict(name='grid',
description="""Which grid the client will try to connect to. Even
though it's not strictly a grid, 'firstlook' is also an acceptable
value for this parameter.""",
default=""),
description="""Which grid the client will try to connect to.""",
default=None),
dict(name='channel',
description="""The channel to use for updates, packaging, settings name, etc.""",
default=get_channel),
dict(name='login_channel',
description="""The channel to use for login handshake/updates only.""",
default='CHANNEL UNSET'),
dict(name='channel_suffix',
description="""Addition to the channel for packaging and channel value, but not application name (used internally)""",
default=None),
dict(name='installer_name',
description=""" The name of the file that the installer should be
@@ -166,12 +144,12 @@ ARGUMENTS=[
contain the name of the final package in a form suitable
for use by a .bat file.""",
default=None),
dict(name='version',
description="""This specifies the version of Second Life that is
being packaged up.""",
default=get_default_version),
dict(name='extra_libraries',
description="""List of extra libraries to include in package""",
dict(name='versionfile',
description="""The name of a file containing the full version number."""),
dict(name='signature',
description="""This specifies an identity to sign the viewer with, if any.
If no value is supplied, the default signature will be used, if any. Currently
only used on Mac OS X.""",
default=None)
]
@@ -193,8 +171,9 @@ def usage(srctree=""):
arg['description'] % nd)
def main():
print "cwd:", os.getcwd()
print " ".join(sys.argv)
## import itertools
## print ' '.join((("'%s'" % item) if ' ' in item else item)
## for item in itertools.chain([sys.executable], sys.argv))
option_names = [arg['name'] + '=' for arg in ARGUMENTS]
option_names.append('help')
options, remainder = getopt.getopt(sys.argv[1:], "", option_names)
@@ -231,12 +210,17 @@ def main():
args[arg['name']] = default
# fix up version
if isinstance(args.get('version'), str):
args['version'] = args['version'].split('.')
# default and agni are default
if args['grid'] in ['default', 'agni']:
args['grid'] = ''
if isinstance(args.get('versionfile'), str):
try: # read in the version string
vf = open(args['versionfile'], 'r')
args['version'] = vf.read().strip().split('.')
except:
print "Unable to read versionfile '%s'" % args['versionfile']
raise
# unspecified, default, and agni are default
if args['grid'] in ['', 'default', 'agni']:
args['grid'] = None
if 'actions' in args:
args['actions'] = args['actions'].split()
@@ -245,15 +229,101 @@ def main():
for opt in args:
print "Option:", opt, "=", args[opt]
# pass in sourceid as an argument now instead of an environment variable
try:
args['sourceid'] = os.environ["sourceid"]
except KeyError:
args['sourceid'] = ""
# Build base package.
touch = args.get('touch')
if touch:
print 'Creating base package'
args['package_id'] = "" # base package has no package ID
wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args)
wm.do(*args['actions'])
# Store package file for later if making touched file.
base_package_file = ""
if touch:
print 'Created base package ', wm.package_file
base_package_file = "" + wm.package_file
# handle multiple packages if set
try:
additional_packages = os.environ["additional_packages"]
except KeyError:
additional_packages = ""
if additional_packages:
# Determine destination prefix / suffix for additional packages.
base_dest_postfix = args['dest']
base_dest_prefix = ""
base_dest_parts = args['dest'].split(os.sep)
if len(base_dest_parts) > 1:
base_dest_postfix = base_dest_parts[len(base_dest_parts) - 1]
base_dest_prefix = base_dest_parts[0]
i = 1
while i < len(base_dest_parts) - 1:
base_dest_prefix = base_dest_prefix + os.sep + base_dest_parts[i]
i = i + 1
# Determine touched prefix / suffix for additional packages.
base_touch_postfix = ""
base_touch_prefix = ""
if touch:
base_touch_postfix = touch
base_touch_parts = touch.split('/')
if "arwin" in args['platform']:
if len(base_touch_parts) > 1:
base_touch_postfix = base_touch_parts[len(base_touch_parts) - 1]
base_touch_prefix = base_touch_parts[0]
i = 1
while i < len(base_touch_parts) - 1:
base_touch_prefix = base_touch_prefix + '/' + base_touch_parts[i]
i = i + 1
else:
if len(base_touch_parts) > 2:
base_touch_postfix = base_touch_parts[len(base_touch_parts) - 2] + '/' + base_touch_parts[len(base_touch_parts) - 1]
base_touch_prefix = base_touch_parts[0]
i = 1
while i < len(base_touch_parts) - 2:
base_touch_prefix = base_touch_prefix + '/' + base_touch_parts[i]
i = i + 1
# Store base channel name.
base_channel_name = args['channel']
# Build each additional package.
package_id_list = additional_packages.split(" ")
args['channel'] = base_channel_name
for package_id in package_id_list:
try:
if package_id + "_viewer_channel_suffix" in os.environ:
args['channel_suffix'] = os.environ[package_id + "_viewer_channel_suffix"]
else:
args['channel_suffix'] = None
if package_id + "_sourceid" in os.environ:
args['sourceid'] = os.environ[package_id + "_sourceid"]
else:
args['sourceid'] = None
args['dest'] = base_dest_prefix + os.sep + package_id + os.sep + base_dest_postfix
except KeyError:
sys.stderr.write("Failed to create package for package_id: %s" % package_id)
sys.stderr.flush()
continue
if touch:
print 'Creating additional package for "', package_id, '" in ', args['dest']
wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args)
wm.do(*args['actions'])
if touch:
print 'Created additional package ', wm.package_file, ' for ', package_id
faketouch = base_touch_prefix + '/' + package_id + '/' + base_touch_postfix
fp = open(faketouch, 'w')
fp.write('set package_file=%s\n' % wm.package_file)
fp.close()
# Write out the package file in this format, so that it can easily be called
# and used in a .bat file - yeah, it sucks, but this is the simplest...
touch = args.get('touch')
if touch:
fp = open(touch, 'w')
fp.write('set package_file=%s\n' % wm.package_file)
fp.write('set package_file=%s\n' % base_package_file)
fp.close()
print 'touched', touch
return 0
@@ -269,8 +339,8 @@ class LLManifest(object):
__metaclass__ = LLManifestRegistry
manifests = {}
def for_platform(self, platform, arch = None):
if arch and platform != "windows":
platform = platform + '_' + arch
if arch:
platform = platform + '_' + arch + '_'
return self.manifests[platform.lower()]
for_platform = classmethod(for_platform)
@@ -280,26 +350,15 @@ class LLManifest(object):
self.file_list = []
self.excludes = []
self.actions = []
self.src_prefix = list([args['source']])
self.artwork_prefix = list([args['artwork']])
self.build_prefix = list([args['build']])
self.alt_build_prefix = list([args['build']])
self.dst_prefix = list([args['dest']])
self.src_prefix = [args['source']]
self.artwork_prefix = [args['artwork']]
self.build_prefix = [args['build']]
self.dst_prefix = [args['dest']]
self.created_paths = []
self.package_name = "Unknown"
def default_grid(self):
return self.args.get('grid', None) == ''
def default_channel(self):
return self.args.get('channel', None) == DEFAULT_CHANNEL
def default_channel_for_brand(self):
if self.viewer_branding_id()=='secondlife':
return self.args.get('channel', None) == DEFAULT_CHANNEL
elif self.viewer_branding_id()=="snowglobe":
return self.args.get('channel', None) == DEFAULT_CHANNEL_SNOWGLOBE
else:
return True
return self.args.get('channel', None) == RELEASE_CHANNEL
def construct(self):
""" Meant to be overriden by LLManifest implementors with code that
@@ -311,7 +370,7 @@ class LLManifest(object):
in the file list by path()."""
self.excludes.append(glob)
def prefix(self, src='', build=None, dst=None, alt_build=None):
def prefix(self, src='', build=None, dst=None):
""" Pushes a prefix onto the stack. Until end_prefix is
called, all relevant method calls (esp. to path()) will prefix
paths with the entire prefix stack. Source and destination
@@ -322,15 +381,10 @@ class LLManifest(object):
dst = src
if build is None:
build = src
if alt_build is None:
alt_build = build
self.src_prefix.append(src)
self.artwork_prefix.append(src)
self.build_prefix.append(build)
self.dst_prefix.append(dst)
self.alt_build_prefix.append(alt_build)
return True # so that you can wrap it in an if to get indentation
def end_prefix(self, descr=None):
@@ -343,30 +397,25 @@ class LLManifest(object):
src = self.src_prefix.pop()
artwork = self.artwork_prefix.pop()
build = self.build_prefix.pop()
alt_build_prefix = self.alt_build_prefix.pop()
dst = self.dst_prefix.pop()
if descr and not(src == descr or build == descr or dst == descr):
raise ValueError, "End prefix '" + descr + "' didn't match '" +src+ "' or '" +dst + "'"
def get_src_prefix(self):
""" Returns the current source prefix."""
return os.path.relpath(os.path.normpath(os.path.join(*self.src_prefix)))
return os.path.join(*self.src_prefix)
def get_artwork_prefix(self):
""" Returns the current artwork prefix."""
return os.path.relpath(os.path.normpath(os.path.join(*self.artwork_prefix)))
return os.path.join(*self.artwork_prefix)
def get_build_prefix(self):
""" Returns the current build prefix."""
return os.path.relpath(os.path.normpath(os.path.join(*self.build_prefix)))
def get_alt_build_prefix(self):
""" Returns the current alternate source prefix."""
return os.path.relpath(os.path.normpath(os.path.join(*self.alt_build_prefix)))
return os.path.join(*self.build_prefix)
def get_dst_prefix(self):
""" Returns the current destination prefix."""
return os.path.relpath(os.path.normpath(os.path.join(*self.dst_prefix)))
return os.path.join(*self.dst_prefix)
def src_path_of(self, relpath):
"""Returns the full path to a file or directory specified
@@ -383,25 +432,45 @@ class LLManifest(object):
relative to the destination directory."""
return os.path.join(self.get_dst_prefix(), relpath)
def ensure_src_dir(self, reldir):
"""Construct the path for a directory relative to the
source path, and ensures that it exists. Returns the
full path."""
path = os.path.join(self.get_src_prefix(), reldir)
self.cmakedirs(path)
return path
def ensure_dst_dir(self, reldir):
"""Construct the path for a directory relative to the
destination path, and ensures that it exists. Returns the
full path."""
path = os.path.join(self.get_dst_prefix(), reldir)
self.cmakedirs(path)
return path
def run_command(self, command):
""" Runs an external command, and returns the output. Raises
an exception if the command reurns a nonzero status code. For
debugging/informational purpoases, prints out the command's
an exception if the command returns a nonzero status code. For
debugging/informational purposes, prints out the command's
output as it is received."""
print "Running command:", command
fd = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
sys.stdout.flush()
child = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
shell=True)
lines = []
while True:
lines.append(fd.stdout.readline())
lines.append(child.stdout.readline())
if lines[-1] == '':
break
else:
print lines[-1].rstrip('\n'),
print lines[-1],
output = ''.join(lines)
if fd.returncode:
raise RuntimeError(
child.stdout.close()
status = child.wait()
if status:
raise ManifestError(
"Command %s returned non-zero status (%s) \noutput:\n%s"
% (command, fd.returncode, output) )
% (command, status, output) )
return output
def created_path(self, path):
@@ -409,14 +478,24 @@ class LLManifest(object):
a) verify that you really have created it
b) schedule it for cleanup"""
if not os.path.exists(path):
raise RuntimeError, "Should be something at path " + path
raise ManifestError, "Should be something at path " + path
self.created_paths.append(path)
def put_in_file(self, contents, dst):
def put_in_file(self, contents, dst, src=None):
# write contents as dst
f = open(self.dst_path_of(dst), "wb")
f.write(contents)
f.close()
dst_path = self.dst_path_of(dst)
f = open(dst_path, "wb")
try:
f.write(contents)
finally:
f.close()
# Why would we create a file in the destination tree if not to include
# it in the installer? The default src=None (plus the fact that the
# src param is last) is to preserve backwards compatibility.
if src:
self.file_list.append([src, dst_path])
return dst_path
def replace_in(self, src, dst=None, searchdict={}):
if dst == None:
@@ -436,11 +515,7 @@ class LLManifest(object):
# ensure that destination path exists
self.cmakedirs(os.path.dirname(dst))
self.created_paths.append(dst)
if not os.path.isdir(src):
self.ccopy(src,dst)
else:
# src is a dir
self.ccopytree(src,dst)
self.ccopymumble(src, dst)
else:
print "Doesn't exist:", src
@@ -479,30 +554,29 @@ class LLManifest(object):
if method is not None:
method(src, dst)
self.file_list.append([src, dst])
return [dst]
return 1
else:
sys.stdout.write(" (excluding %r, %r)" % (src, dst))
sys.stdout.flush()
return []
return 0
def process_directory(self, src, dst):
if not self.includes(src, dst):
sys.stdout.write(" (excluding %r, %r)" % (src, dst))
sys.stdout.flush()
return []
return 0
names = os.listdir(src)
self.cmakedirs(dst)
errors = []
found_files = []
count = 0
for name in names:
srcname = os.path.join(src, name)
dstname = os.path.join(dst, name)
if os.path.isdir(srcname):
found_files.extend(self.process_directory(srcname, dstname))
count += self.process_directory(srcname, dstname)
else:
found_files.extend(self.process_file(srcname, dstname))
return found_files
count += self.process_file(srcname, dstname)
return count
def includes(self, src, dst):
if src:
@@ -520,28 +594,38 @@ class LLManifest(object):
else:
os.remove(path)
def ccopy(self, src, dst):
""" Copy a single file or symlink. Uses filecmp to skip copying for existing files."""
def ccopymumble(self, src, dst):
"""Copy a single symlink, file or directory."""
if os.path.islink(src):
linkto = os.readlink(src)
if os.path.islink(dst) or os.path.exists(dst):
if os.path.islink(dst) or os.path.isfile(dst):
os.remove(dst) # because symlinking over an existing link fails
elif os.path.isdir(dst):
shutil.rmtree(dst)
os.symlink(linkto, dst)
elif os.path.isdir(src):
self.ccopytree(src, dst)
else:
# Don't recopy file if it's up-to-date.
# If we seem to be not not overwriting files that have been
# updated, set the last arg to False, but it will take longer.
if os.path.exists(dst) and filecmp.cmp(src, dst, True):
return
# only copy if it's not excluded
if self.includes(src, dst):
try:
os.unlink(dst)
except OSError, err:
if err.errno != errno.ENOENT:
raise
self.ccopyfile(src, dst)
# XXX What about devices, sockets etc.?
# YYY would we put such things into a viewer package?!
shutil.copy2(src, dst)
def ccopyfile(self, src, dst):
""" Copy a single file. Uses filecmp to skip copying for existing files."""
# Don't recopy file if it's up-to-date.
# If we seem to be not not overwriting files that have been
# updated, set the last arg to False, but it will take longer.
if os.path.exists(dst) and filecmp.cmp(src, dst, True):
return
# only copy if it's not excluded
if self.includes(src, dst):
try:
os.unlink(dst)
except OSError, err:
if err.errno != errno.ENOENT:
raise
shutil.copy2(src, dst)
def ccopytree(self, src, dst):
"""Direct copy of shutil.copytree with the additional
@@ -557,15 +641,11 @@ class LLManifest(object):
srcname = os.path.join(src, name)
dstname = os.path.join(dst, name)
try:
if os.path.isdir(srcname):
self.ccopytree(srcname, dstname)
else:
self.ccopy(srcname, dstname)
# XXX What about devices, sockets etc.?
self.ccopymumble(srcname, dstname)
except (IOError, os.error), why:
errors.append((srcname, dstname, why))
if errors:
raise RuntimeError, errors
raise ManifestError, errors
def cmakedirs(self, path):
@@ -582,11 +662,25 @@ class LLManifest(object):
if os.path.exists(f):
return f
# didn't find it, return last item in list
if list:
if len(list) > 0:
return list[-1]
else:
return None
def contents_of_tar(self, src_tar, dst_dir):
""" Extracts the contents of the tarfile (specified
relative to the source prefix) into the directory
specified relative to the destination directory."""
self.check_file_exists(src_tar)
tf = tarfile.open(self.src_path_of(src_tar), 'r')
for member in tf.getmembers():
tf.extract(member, self.ensure_dst_dir(dst_dir))
# TODO get actions working on these dudes, perhaps we should extract to a temporary directory and then process_directory on it?
self.file_list.append([src_tar,
self.dst_path_of(os.path.join(dst_dir,member.name))])
tf.close()
def wildcard_regex(self, src_glob, dst_glob):
src_re = re.escape(src_glob)
src_re = src_re.replace('\*', '([-a-zA-Z0-9._ ]*)')
@@ -597,7 +691,12 @@ class LLManifest(object):
i = i+1
return re.compile(src_re), dst_temp
wildcard_pattern = re.compile('\*')
def check_file_exists(self, path):
if not os.path.exists(path) and not os.path.islink(path):
raise MissingError("Path %s doesn't exist" % (os.path.abspath(path),))
wildcard_pattern = re.compile(r'\*')
def expand_globs(self, src, dst):
src_list = glob.glob(src)
src_re, d_template = self.wildcard_regex(src.replace('\\', '/'),
@@ -624,43 +723,53 @@ class LLManifest(object):
return self.path(os.path.join(path, file), file)
def path(self, src, dst=None):
sys.stdout.write("Processing %s => %s ... " % (src, dst))
sys.stdout.flush()
if src == None:
raise RuntimeError("No source file, dst is " + dst)
raise ManifestError("No source file, dst is " + dst)
if dst == None:
dst = src
dst = os.path.join(self.get_dst_prefix(), dst)
sys.stdout.write("Processing %s => %s ... " % (src, dst))
count = 0
is_glob = False
found_files = []
# look under each prefix for matching paths. Paths are normalized so './../blah' will match '../blah/../blah/'
paths = set([os.path.normpath(os.path.join(self.get_src_prefix(), src)),
os.path.normpath(os.path.join(self.get_artwork_prefix(), src)),
os.path.normpath(os.path.join(self.get_build_prefix(), src)),
os.path.normpath(os.path.join(self.get_alt_build_prefix(), src))]
)
for path in paths:
if self.wildcard_pattern.search(path):
is_glob = True
for s,d in self.expand_globs(path, dst):
def try_path(src):
# expand globs
count = 0
if self.wildcard_pattern.search(src):
for s,d in self.expand_globs(src, dst):
assert(s != d)
found_files.extend(self.process_file(s, d))
count += self.process_file(s, d)
else:
# if we're specifying a single path (not a glob),
# we should error out if it doesn't exist
self.check_file_exists(src)
# if it's a directory, recurse through it
if os.path.isdir(path):
found_files.extend(self.process_directory(path, dst))
elif os.path.exists(path):
found_files.extend(self.process_file(path, dst))
if os.path.isdir(src):
count += self.process_directory(src, dst)
else:
count += self.process_file(src, dst)
return count
# if we're specifying a single path (not a glob),
# we should error out if it doesn't exist
if not found_files and not is_glob:
raise RuntimeError("No files match %s\n" % str(paths))
for pfx in self.get_src_prefix(), self.get_artwork_prefix(), self.get_build_prefix():
try:
count = try_path(os.path.join(pfx, src))
except MissingError:
# If src isn't a wildcard, and if that file doesn't exist in
# this pfx, try next pfx.
count = 0
continue
print "%d files" % len(found_files)
return found_files
# Here try_path() didn't raise MissingError. Did it process any files?
if count:
break
# Even though try_path() didn't raise MissingError, it returned 0
# files. src is probably a wildcard meant for some other pfx. Loop
# back to try the next.
print "%d files" % count
# Let caller check whether we processed as many files as expected. In
# particular, let caller notice 0.
return count
def do(self, *actions):
self.actions = actions

Binary file not shown.

View File

@@ -1178,7 +1178,6 @@ if (DARWIN)
# Add resource files to the project.
set(viewer_RESOURCE_FILES
${VIEWER_BRANDING_ID}_icon.icns
macview.r
gpu_table.txt
SecondLife.nib/
@@ -1233,6 +1232,27 @@ if (WINDOWS)
list(APPEND viewer_SOURCE_FILES llviewerprecompiledheaders.cpp)
endif(USE_PRECOMPILED_HEADERS)
# Replace the icons with the appropriate ones for the channel
# ('test' is the default)
set(ICON_PATH "default")
set(VIEWER_MACOSX_PHASE "d")
message("Copying icons for ${ICON_PATH}")
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/icons/${ICON_PATH}/viewer.ico"
"${CMAKE_CURRENT_SOURCE_DIR}/res/viewer_icon.ico"
)
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/icons/${ICON_PATH}/viewer_256.BMP"
"${CMAKE_CURRENT_SOURCE_DIR}/res/viewer_icon.BMP"
)
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/icons/${ICON_PATH}/viewer_256.BMP"
"${CMAKE_CURRENT_SOURCE_DIR}/res-sdl/viewer_icon.BMP"
)
# Add resource files to the project.
# viewerRes.rc is the only buildable file, but
# the rest are all dependencies of it.
@@ -1261,7 +1281,9 @@ if (WINDOWS)
res/lltooltranslate.cur
res/lltoolzoomin.cur
res/lltoolzoomout.cur
res/${VIEWER_BRANDING_ID}_icon.ico
res-sdl/viewer_icon.BMP
res/viewer_icon.BMP
res/viewer_icon.ico
res/resource.h
res/toolpickobject.cur
res/toolpickobject2.cur
@@ -1513,16 +1535,15 @@ if (WINDOWS)
--actions=copy
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
--branding_id=${VIEWER_BRANDING_ID}
--build=${CMAKE_CURRENT_BINARY_DIR}
--channel=${VIEWER_CHANNEL}
--buildtype=${CMAKE_BUILD_TYPE}
--configuration=${CMAKE_CFG_INTDIR}
--dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
--grid=${GRID}
--login_channel=${VIEWER_LOGIN_CHANNEL}
--channel=${VIEWER_CHANNEL}
--versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt
--source=${CMAKE_CURRENT_SOURCE_DIR}
--touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/copy_touched.bat
--extra_libraries="${MANIFEST_LIBRARIES}"
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
stage_third_party_libs
@@ -1537,6 +1558,10 @@ if (WINDOWS)
if (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts)
add_dependencies(${VIEWER_BINARY_NAME} copy_win_scripts)
endif (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts)
add_dependencies(${VIEWER_BINARY_NAME}
SLPlugin
)
# sets the 'working directory' for debugging from visual studio.
if (NOT UNATTENDED)
add_custom_command(
@@ -1551,6 +1576,7 @@ if (WINDOWS)
COMMENT "Setting the ${VIEWER_BINARY_NAME} working directory for debugging."
)
endif (NOT UNATTENDED)
if (PACKAGE)
add_custom_command(
OUTPUT ${CMAKE_CFG_INTDIR}/touched.bat
@@ -1559,16 +1585,15 @@ if (WINDOWS)
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
--branding_id=${VIEWER_BRANDING_ID}
--build=${CMAKE_CURRENT_BINARY_DIR}
--buildtype=${CMAKE_BUILD_TYPE}
--channel=${VIEWER_CHANNEL}
--versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt
--configuration=${CMAKE_CFG_INTDIR}
--dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
--grid=${GRID}
--login_channel=${VIEWER_LOGIN_CHANNEL}
--source=${CMAKE_CURRENT_SOURCE_DIR}
--touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/touched.bat
--extra_libraries="${MANIFEST_LIBRARIES}"
DEPENDS
${VIEWER_BINARY_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
@@ -1576,7 +1601,6 @@ if (WINDOWS)
${COPY_INPUT_DEPENDENCIES}
)
if (PACKAGE)
add_custom_target(llpackage ALL DEPENDS
${CMAKE_CFG_INTDIR}/touched.bat
windows-setup-build-all
@@ -1709,7 +1733,7 @@ endif (LINUX)
if (DARWIN)
set(product ${VIEWER_BRANDING_NAME})
set(MACOSX_BUNDLE_INFO_STRING "A stable third-party Second Life viewer.")
set(MACOSX_BUNDLE_ICON_FILE "${VIEWER_BRANDING_ID}_icon.icns")
set(MACOSX_BUNDLE_ICON_FILE "viewer.icns")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "${VIEWER_BRANDING_NAME}")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${VIEWER_CHANNEL} ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}")
set(MACOSX_BUNDLE_BUNDLE_NAME "${VIEWER_BRANDING_NAME}")

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

View File

@@ -222,10 +222,6 @@ void LLUserAuth::authenticate(
// * We append "64" to channel name on 64-bit for systems for the LL stats system to be able to produce independent
// crash statistics depending on the architecture
std::string chan(LLVersionInfo::getChannel());
if (chan == "Singularity")
{
chan += " Release";
}
#if defined(_WIN64) || defined(__x86_64__)
chan += " 64";
#endif

View File

@@ -60,8 +60,8 @@ END
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_LL_ICON ICON "singularity_icon.ico"
IDI_LCD_LL_ICON ICON "singularity_icon.ico"
IDI_LL_ICON ICON "viewer_icon.ico"
IDI_LCD_LL_ICON ICON "viewer_icon.ico"
/////////////////////////////////////////////////////////////////////////////
//

Binary file not shown.

Binary file not shown.

View File

@@ -33,254 +33,248 @@ $/LicenseInfo$
"""
import sys
import os.path
import errno
import re
import tarfile
import time
import subprocess
import errno
import random
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
# Add indra/lib/python to our path so we don't have to muck with PYTHONPATH.
# Put it FIRST because some of our build hosts have an ancient install of
# indra.util.llmanifest under their system Python!
sys.path.insert(0, os.path.join(viewer_dir, os.pardir, "lib", "python"))
from indra.util.llmanifest import LLManifest, main, path_ancestors, CHANNEL_VENDOR_BASE, RELEASE_CHANNEL, ManifestError
try:
from llbase import llsd
except ImportError:
from indra.base import llsd
class ViewerManifest(LLManifest):
def is_packaging_viewer(self):
# Some commands, files will only be included
# if we are packaging the viewer on windows.
# This manifest is also used to copy
# files during the build (see copy_w_viewer_manifest
# and copy_l_viewer_manifest targets)
return 'package' in self.args['actions']
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")
if self.is_packaging_viewer():
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")
# include the entire shaders directory recursively
self.path("shaders")
# ... and the entire windlight directory
self.path("windlight")
# ... and the entire windlight directory
self.path("windlight")
# ... and the hunspell dictionaries
self.path("dictionaries")
# ... and the hunspell dictionaries
self.path("dictionaries")
self.end_prefix("app_settings")
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"):
if self.prefix(src="character"):
self.path("*.llm")
self.path("*.xml")
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")
self.end_prefix("character")
# 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")
# Include our fonts
if self.prefix(src="fonts"):
self.path("*.ttf")
self.path("*.txt")
self.end_prefix("fonts")
self.end_prefix("skins")
# skins
if self.prefix(src="skins"):
self.path("paths.xml")
self.path("default/xui/*/*.xml")
self.path("Default.xml")
self.path("default/*.xml")
self.path("dark.xml")
self.path("dark/*.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")
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")
# 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')
# 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")
# The summary.json file gets left in the build directory by newview/CMakeLists.txt.
if not self.path2basename(os.pardir, "summary.json"):
print "No summary.json file"
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):
return self.channel_oneword() + "_"
def flags_list(self):
""" Convenience function that returns the command-line flags
for the grid"""
def channel_with_pkg_suffix(self):
fullchannel=self.channel()
if 'channel_suffix' in self.args and self.args['channel_suffix']:
fullchannel+=' '+self.args['channel_suffix']
return fullchannel
# 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()}
def channel_variant(self):
global CHANNEL_VENDOR_BASE
return self.channel().replace(CHANNEL_VENDOR_BASE, "").strip()
# 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())
def channel_type(self): # returns 'release', 'beta', 'project', or 'test'
global CHANNEL_VENDOR_BASE
channel_qualifier=self.channel().replace(CHANNEL_VENDOR_BASE, "").lower().strip()
if channel_qualifier.startswith('release'):
channel_type='release'
elif channel_qualifier.startswith('beta'):
channel_type='beta'
elif channel_qualifier.startswith('project'):
channel_type='project'
else:
channel_flags = '--channel "%s"' % self.channel()
channel_type='test'
return channel_type
# 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()
def channel_variant_app_suffix(self):
# get any part of the compiled channel name after the CHANNEL_VENDOR_BASE
suffix=self.channel_variant()
# by ancient convention, we don't use Release in the app name
if self.channel_type() == 'release':
suffix=suffix.replace('Release', '').strip()
# for the base release viewer, suffix will now be null - for any other, append what remains
if len(suffix) > 0:
suffix = "_"+ ("_".join(suffix.split()))
# the additional_packages mechanism adds more to the installer name (but not to the app name itself)
if 'channel_suffix' in self.args and self.args['channel_suffix']:
suffix+='_'+("_".join(self.args['channel_suffix'].split()))
return suffix
def installer_base_name(self):
global CHANNEL_VENDOR_BASE
# a standard map of strings for replacing in the templates
substitution_strings = {
'channel_vendor_base' : '_'.join(CHANNEL_VENDOR_BASE.split()),
'channel_variant_underscores':self.channel_variant_app_suffix(),
'version_underscores' : '_'.join(self.args['version']),
'arch':self.args['arch']
}
return "%(channel_vendor_base)s%(channel_variant_underscores)s_%(version_underscores)s_%(arch)s" % substitution_strings
def app_name(self):
global CHANNEL_VENDOR_BASE
channel_type=self.channel_type()
if channel_type == 'release':
app_suffix='Viewer'
else:
setting_flags = '--settings settings_%s_%s.xml'\
% (self.grid(), self.channel_lowerword())
app_suffix=self.channel_variant()
return CHANNEL_VENDOR_BASE + ' ' + app_suffix
return " ".join((channel_flags, grid_flags, setting_flags)).strip()
def app_name_oneword(self):
return ''.join(self.app_name().split())
def icon_path(self):
return "../../indra/newview/res/"
return "icons/default"
def path_optional(self, src, dst=None):
"""
For a number of our self.path() calls, not only do we want
to deal with the absence of src, we also want to remember
which were present. Return either an empty list (absent)
or a list containing dst (present). Concatenate these
return values to get a list of all libs that are present.
"""
found_files = []
def extract_names(self,src):
try:
found_files = self.path(src, dst)
except RuntimeError, err:
pass
if not found_files:
print "Skipping %s" % dst
return found_files
contrib_file = open(src,'r')
except IOError:
print "Failed to open '%s'" % src
raise
lines = contrib_file.readlines()
contrib_file.close()
def add_extra_libraries(self):
found_libs = []
config_arg = self.args['configuration'].lower()
if(config_arg == '.'):
config_arg = self.buildtype().lower()
if 'extra_libraries' in self.args and self.args['extra_libraries'] != '':
try:
path_list = self.args['extra_libraries'].strip('"').split('|')
except:
return None
for cur_path in path_list:
if cur_path is None or cur_path == '':
continue
try:
config, file = cur_path.split(' ', 1)
except:
config, file = (None, None)
if(config == 'optimized'):
if(config_arg != 'release' and config_arg != 'relwithdebinfo' and config_arg != 'universal'):
continue
cur_path = file
if(config == 'debug'):
if(config_arg != 'debug'):
continue
cur_path = file
if(cur_path != ''):
if sys.platform == "linux" or sys.platform == "linux2":
found_libs += self.path_optional(cur_path+"*")
else:
found_libs += self.path_optional(cur_path)
return found_libs
# All lines up to and including the first blank line are the file header; skip them
lines.reverse() # so that pop will pull from first to last line
while not re.match("\s*$", lines.pop()) :
pass # do nothing
# A line that starts with a non-whitespace character is a name; all others describe contributions, so collect the names
names = []
for line in lines :
if re.match("\S", line) :
names.append(line.rstrip())
# It's not fair to always put the same people at the head of the list
random.shuffle(names)
return ', '.join(names)
class WindowsManifest(ViewerManifest):
def is_win64(self):
return self.args.get('arch') == "x86_64"
def final_exe(self):
return self.channel_oneword() + 'Viewer.exe'
return self.app_name_oneword()+".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())
pkgdir = os.path.join(self.args['build'], os.pardir, 'packages')
relpkgdir = os.path.join(pkgdir, "lib", "release")
debpkgdir = os.path.join(pkgdir, "lib", "debug")
if self.is_packaging_viewer():
# Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe.
self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe())
# Plugin host application
self.path2basename(os.path.join(os.pardir,
'llplugin', 'slplugin', self.args['configuration']),
"SLplugin.exe")
# Get shared libs from the shared libs staging directory
if self.prefix(src=os.path.join(os.pardir, 'sharedlibs', self.args['configuration']),
dst=""):
# Get llcommon and deps. If missing assume static linkage and continue.
if self.prefix(src=self.args['configuration'], dst=""):
# Get llcommon and deps. If missing assume static linkage and continue.
try:
self.path('llcommon.dll')
self.path('libapr-1.dll')
self.path('libaprutil-1.dll')
self.path('libapriconv-1.dll')
except RuntimeError, err:
print err.message
print "Skipping llcommon.dll (assuming llcommon was linked statically)"
# Mesh 3rd party libs needed for auto LOD and collada reading
try:
self.path('libapr-1.dll')
self.path('libaprutil-1.dll')
self.path('libapriconv-1.dll')
self.path("glod.dll")
except RuntimeError, err:
pass
# For mesh upload
if not self.is_win64():
self.path("libcollada14dom22.dll")
self.path("glod.dll")
self.add_extra_libraries()
if(self.prefix(src="..", dst="")):
found_files = self.path("msvc*.dll")
self.end_prefix()
if(not found_files):
try:
if self.prefix(src="msvcrt", dst=""):
self.path("*.dll")
self.path("*.manifest")
self.end_prefix()
except:
pass
print err.message
print "Skipping GLOD library (assumming linked statically)"
# Vivox runtimes
self.path("SLVoice.exe")
@@ -296,15 +290,18 @@ class WindowsManifest(ViewerManifest):
self.path("ssleay32.dll")
self.path("libeay32.dll")
# For spellchecking
# Hunspell
self.path("libhunspell.dll")
# For google-perftools tcmalloc allocator.
if not self.is_win64():
try:
try:
if self.args['configuration'].lower() == 'debug':
self.path('libtcmalloc_minimal-debug.dll')
else:
self.path('libtcmalloc_minimal.dll')
except:
print "Skipping libtcmalloc_minimal.dll"
except:
print "Skipping libtcmalloc_minimal.dll"
self.end_prefix()
self.path(src="licenses-win32.txt", dst="licenses.txt")
@@ -361,7 +358,8 @@ class WindowsManifest(ViewerManifest):
self.end_prefix()
self.package_file = 'none'
if not self.is_packaging_viewer():
self.package_file = "copied_deps"
def nsi_file_commands(self, install=True):
def wpath(path):
@@ -372,7 +370,6 @@ class WindowsManifest(ViewerManifest):
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()
@@ -380,15 +377,15 @@ class WindowsManifest(ViewerManifest):
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.join(os.pardir,os.path.normpath(pkg_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'
result += 'SetOutPath ' + out_path + '\n'
if install:
result += 'File "' + pkg_file + '"\n'
result += 'File ' + pkg_file + '\n'
else:
result += 'Delete "' + wpath(os.path.join('$INSTDIR', rel_file)) + '"\n'
result += 'Delete ' + wpath(os.path.join('$INSTDIR', rel_file)) + '\n'
# at the end of a delete, just rmdir all the directories
if not install:
@@ -407,28 +404,6 @@ class WindowsManifest(ViewerManifest):
prev = d
return result
def installer_file(self):
if self.is_win64():
mask = "%s_%s_x86-64_Setup.exe"
else:
mask = "%s_%s_Setup.exe"
return mask % (self.channel_oneword(), '-'.join(self.args['version']))
def sign_command(self, *argv):
return [
"signtool.exe",
"sign", "/v",
"/f",os.environ['VIEWER_SIGNING_KEY'],
"/p",os.environ['VIEWER_SIGNING_PASSWORD'],
"/d","%s" % self.channel(),
"/du",os.environ['VIEWER_SIGNING_URL'],
"/t","http://timestamp.comodoca.com/authenticode"
] + list(argv)
def sign(self, *argv):
subprocess.check_call(self.sign_command(*argv))
def package_finish(self):
# a standard map of strings for replacing in the templates
@@ -437,66 +412,43 @@ class WindowsManifest(ViewerManifest):
'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(),
'inst_name':self.channel_oneword() + ' (64 bit)' if self.is_win64() else self.channel_oneword(),
'installer_file':self.installer_file(),
'viewer_name': "%s%s" % (self.channel(), " (64 bit)" if self.is_win64() else "" ),
'install_icon': "install_icon_%s.ico" % self.viewer_branding_id(),
'uninstall_icon': "uninstall_icon_%s.ico" % self.viewer_branding_id(),
'flags':'',
'app_name':self.app_name(),
'app_name_oneword':self.app_name_oneword()
}
installer_file = self.installer_base_name() + '_Setup.exe'
substitution_strings['installer_file'] = installer_file
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 = "%(installer_file)s"
grid_vars_template = """
OutFile "%(installer_file)s"
!define VIEWERNAME "%(viewer_name)s"
!define INSTFLAGS "%(flags)s"
!define INSTNAME "%(inst_name)s"
!define SHORTCUT "%(viewer_name)s Viewer"
!define URLNAME "secondlife"
!define INSTALL_ICON "%(install_icon)s"
!define UNINSTALL_ICON "%(uninstall_icon)s"
!define AUTHOR "Linden Research, Inc." #TODO: Hook this up to cmake et al for easier branding.
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
# Sign the binaries
if 'VIEWER_SIGNING_PASSWORD' in os.environ:
try:
self.sign(self.args['configuration']+"\\"+self.final_exe())
self.sign(self.args['configuration']+"\\SLPlugin.exe")
self.sign(self.args['configuration']+"\\SLVoice.exe")
except Exception, e:
print "Couldn't sign binaries. Tried to sign %s" % self.args['configuration'] + "\\" + self.final_exe() + "\nException: %s" % e
if self.channel_type() == 'release':
substitution_strings['caption'] = CHANNEL_VENDOR_BASE
else:
substitution_strings['caption'] = self.app_name() + ' ${VERSION}'
inst_vars_template = """
OutFile "%(installer_file)s"
!define INSTNAME "%(app_name_oneword)s"
!define SHORTCUT "%(app_name)s"
!define URLNAME "secondlife"
Caption "%(caption)s"
"""
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%%":os.path.abspath(self.get_src_prefix()),
"%%GRID_VARS%%":grid_vars_template % substitution_strings,
"%%SOURCE%%":self.get_src_prefix(),
"%%INST_VARS%%":inst_vars_template % substitution_strings,
"%%INSTALL_FILES%%":self.nsi_file_commands(True),
"%%DELETE_FILES%%":self.nsi_file_commands(False),
"%%INSTALLDIR%%":"%s\\%s" % ('$PROGRAMFILES64' if self.is_win64() else '$PROGRAMFILES', self.channel_oneword()),
"%%WIN64_BIN_BUILD%%":"!define WIN64_BIN_BUILD 1" if self.is_win64() else "",
})
"%%DELETE_FILES%%":self.nsi_file_commands(False)})
# We use the Unicode version of NSIS, available from
# http://www.scratchpaper.com/
@@ -511,29 +463,63 @@ class WindowsManifest(ViewerManifest):
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))
# Sign the installer
# We're probably not on a build machine, but maybe we want to sign
if 'VIEWER_SIGNING_PASSWORD' in os.environ:
try:
self.sign(self.args['configuration'] + "\\" + substitution_strings['installer_file'])
except Exception, e:
print "Couldn't sign windows installer. Tried to sign %s" % self.args['configuration'] + "\\" + substitution_strings['installer_file'] + "\nException: %s" % e
# If we're on a build machine, sign the code using our Authenticode certificate. JC
sign_py = os.path.expandvars("${SIGN}")
if not sign_py or sign_py == "${SIGN}":
sign_py = 'C:\\buildscripts\\code-signing\\sign.py'
else:
# 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"
sign_py = sign_py.replace('\\', '\\\\\\\\')
python = os.path.expandvars("${PYTHON}")
if not python or python == "${PYTHON}":
python = 'python'
if os.path.exists(sign_py):
self.run_command("%s %s %s" % (python, sign_py, self.dst_path_of(installer_file).replace('\\', '\\\\\\\\')))
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 Windows_i686_Manifest(WindowsManifest):
def construct(self):
super(Windows_i686_Manifest, self).construct()
# Get shared libs from the shared libs staging directory
if self.prefix(src=os.path.join(os.pardir, 'sharedlibs', self.args['configuration']),
dst=""):
# Get fmod studio dll, continue if missing
try:
if self.args['configuration'].lower() == 'debug':
self.path("fmodL.dll")
else:
self.path("fmod.dll")
except:
print "Skipping fmodstudio audio library(assuming other audio engine)"
self.end_prefix()
class Windows_x86_64_Manifest(WindowsManifest):
def construct(self):
super(Windows_x86_64_Manifest, self).construct()
# Get shared libs from the shared libs staging directory
if self.prefix(src=os.path.join(os.pardir, 'sharedlibs', self.args['configuration']),
dst=""):
# Get fmodstudio dll, continue if missing
try:
if self.args['configuration'].lower() == 'debug':
self.path("fmodL64.dll")
else:
self.path("fmod64.dll")
except:
print "Skipping fmodstudio audio library(assuming other audio engine)"
self.end_prefix()
class DarwinManifest(ViewerManifest):
def construct(self):
# copy over the build result (this is a no-op if run within the xcode script)
@@ -906,9 +892,9 @@ class LinuxManifest(ViewerManifest):
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()} )
class Linux_i686Manifest(LinuxManifest):
class Linux_i686_Manifest(LinuxManifest):
def construct(self):
super(Linux_i686Manifest, self).construct()
super(Linux_i686_Manifest, self).construct()
# llcommon
if not self.path("../llcommon/libllcommon.so", "lib/libllcommon.so"):
@@ -964,9 +950,9 @@ class Linux_i686Manifest(LinuxManifest):
self.path("libvivoxsdk.so")
self.end_prefix("lib")
class Linux_x86_64Manifest(LinuxManifest):
class Linux_x86_64_Manifest(LinuxManifest):
def construct(self):
super(Linux_x86_64Manifest, self).construct()
super(Linux_x86_64_Manifest, self).construct()
# llcommon
if not self.path("../llcommon/libllcommon.so", "lib64/libllcommon.so"):