281 lines
9.6 KiB
Python
Executable File
281 lines
9.6 KiB
Python
Executable File
#!/usr/bin/python
|
|
"""\
|
|
@file public_fetch_tarballs.py
|
|
@author Rob Lanphier
|
|
@date 2009-05-30
|
|
@brief Fetch + extract tarballs and zipfiles listed in doc/asset_urls.txt
|
|
|
|
$LicenseInfo:firstyear=2009&license=viewergpl$
|
|
Copyright (c) 2009, Linden Research, Inc.
|
|
|
|
Second Life Viewer Source Code
|
|
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
|
|
|
|
# Look for indra/lib/python in all possible parent directories ...
|
|
# This is an improvement over the setup-path.py method used previously:
|
|
# * the script may blocated anywhere inside the source tree
|
|
# * it doesn't depend on the current directory
|
|
# * it doesn't depend on another file being present.
|
|
|
|
def add_indra_lib_path():
|
|
root = os.path.realpath(__file__)
|
|
# always insert the directory of the script in the search path
|
|
dir = os.path.dirname(root)
|
|
if dir not in sys.path:
|
|
sys.path.insert(0, dir)
|
|
|
|
# Now go look for indra/lib/python in the parent dies
|
|
while root != os.path.sep:
|
|
root = os.path.dirname(root)
|
|
dir = os.path.join(root, 'indra', 'lib', 'python')
|
|
if os.path.isdir(dir):
|
|
if dir not in sys.path:
|
|
sys.path.insert(0, dir)
|
|
return root
|
|
else:
|
|
print >>sys.stderr, "This script is not inside a valid installation."
|
|
sys.exit(1)
|
|
|
|
base_dir = add_indra_lib_path()
|
|
print base_dir
|
|
|
|
import os
|
|
import sys
|
|
import re
|
|
import urllib
|
|
import zipfile
|
|
import tarfile
|
|
import optparse
|
|
import tempfile
|
|
|
|
import indra.util.helpformatter
|
|
|
|
# load + parse doc/asset_urls.txt
|
|
def get_asset_urls():
|
|
asset_urls={}
|
|
f = open(os.path.join(base_dir,"doc", "asset_urls.txt"))
|
|
for line in f:
|
|
line=line.strip()
|
|
(name, value)=re.split("=", line, 1)
|
|
asset_urls[name]=value
|
|
return asset_urls
|
|
|
|
# Filename from a URL
|
|
def get_asset_filename_from_url(asseturl, targetdir):
|
|
i = asseturl.rfind('/')
|
|
filename = os.path.join(targetdir, asseturl[i+1:])
|
|
return filename
|
|
|
|
|
|
# Extract .zip file to targetdir. Called by extract_archive_sans_linden.
|
|
def extract_zipfile_sans_linden(filename, targetdir):
|
|
archive = zipfile.ZipFile(filename, 'r')
|
|
names = archive.namelist()
|
|
for path in names:
|
|
if(path=="linden/"):
|
|
pass
|
|
target = os.path.join(targetdir, re.sub("linden/", "", path))
|
|
subdir = os.path.dirname(target)
|
|
if not os.path.exists(subdir):
|
|
os.makedirs(subdir)
|
|
if not os.path.exists(target):
|
|
fp = open(target, 'wb')
|
|
fp.write(archive.read(path))
|
|
fp.close()
|
|
archive.close()
|
|
|
|
|
|
# Extract .tar.gz file to targetdir. Called by extract_archive_sans_linden.
|
|
def extract_tarball_sans_linden(filename, targetdir):
|
|
archive = tarfile.TarFile.open(filename, 'r')
|
|
# get a series of TarInfo objects
|
|
tarentries=archive.getmembers()
|
|
for tarentry in tarentries:
|
|
target = re.sub(r'^(\./)?(linden/?)?', "", tarentry.name)
|
|
if(target==""):
|
|
continue
|
|
fulltarget=os.path.join(targetdir, target)
|
|
subdir = os.path.dirname(fulltarget)
|
|
if not os.path.exists(subdir):
|
|
os.makedirs(subdir)
|
|
if not os.path.exists(fulltarget):
|
|
# Reset the name property on the TarInfo object, so it writes the
|
|
# file exactly where we want it. It's hard telling for sure if this
|
|
# property is intended to be written to, but it works for now.
|
|
tarentry.name=fulltarget
|
|
# Calling TarFile.extract with the "path" parameter doesn't work as
|
|
# we might hope, because the path components in the tarball get
|
|
# appended to the "path" parameter. Hence the reason for passing in
|
|
# the TarInfo object with the munged name property
|
|
archive.extract(tarentry)
|
|
archive.close()
|
|
|
|
# Extract either .tar.gz file or .zip file to targetdir, stripping off the
|
|
# leading "linden" directory, but leaving the directory structure otherwise
|
|
# intact.
|
|
def extract_archive_sans_linden(filename, targetdir):
|
|
if(filename.endswith('.tar.gz')):
|
|
extract_tarball_sans_linden(filename, targetdir)
|
|
elif(filename.endswith('.zip')):
|
|
extract_zipfile_sans_linden(filename, targetdir)
|
|
else:
|
|
raise Exception, "Unhandled archive type"
|
|
|
|
def get_assetnames_by_platform(platform):
|
|
assetnames=['SLASSET_ART']
|
|
if(platform=='linux' or platform=='all'):
|
|
assetnames.append('SLASSET_LIBS_LINUXI386')
|
|
if(platform=='darwin' or platform=='all'):
|
|
assetnames.append('SLASSET_LIBS_DARWIN')
|
|
if(platform=='windows' or platform=='all'):
|
|
assetnames.append('SLASSET_LIBS_WIN32')
|
|
return assetnames
|
|
|
|
# adapted from install.py
|
|
def _get_platform():
|
|
"Return appropriate platform packages for the environment."
|
|
platform_map = {
|
|
'darwin': 'darwin',
|
|
'linux2': 'linux',
|
|
'win32' : 'windows',
|
|
'cygwin' : 'windows',
|
|
'solaris' : 'solaris'
|
|
}
|
|
this_platform = platform_map[sys.platform]
|
|
return this_platform
|
|
|
|
# copied from install.py
|
|
def _default_installable_cache():
|
|
"""In general, the installable files do not change much, so find a
|
|
host/user specific location to cache files."""
|
|
user = _getuser()
|
|
cache_dir = "/var/tmp/%s/install.cache" % user
|
|
if _get_platform() == 'windows':
|
|
cache_dir = os.path.join(tempfile.gettempdir(), \
|
|
'install.cache.%s' % user)
|
|
return cache_dir
|
|
|
|
# For status messages (e.g. "Loading..."). May come in handy if
|
|
# we implement a "quiet" mode.
|
|
def _report(string):
|
|
print string
|
|
|
|
|
|
# copied from install.py
|
|
def _getuser():
|
|
"Get the user"
|
|
try:
|
|
# Unix-only.
|
|
import getpass
|
|
return getpass.getuser()
|
|
except ImportError:
|
|
import win32api
|
|
return win32api.GetUserName()
|
|
|
|
# adapted from install.py
|
|
def _parse_args():
|
|
parser = optparse.OptionParser(
|
|
usage="usage: %prog [options]",
|
|
formatter = indra.util.helpformatter.Formatter(),
|
|
description="""This script fetches and installs tarballs and \
|
|
zipfiles ("asset bundles") listed in doc/asset_urls.txt
|
|
|
|
If no asset bundles are specified on the command line, then the default \
|
|
behavior is to install all known asset bundles appropriate for the platform \
|
|
specified. You can specify more than one asset bundle on the command line.
|
|
|
|
Example:
|
|
%prog SLASSET_ART
|
|
|
|
This looks for the "SLASSET_ART" entry in doc/asset_urls.txt, and extracts
|
|
the corresponding asset bundle into your source tree.
|
|
""")
|
|
parser.add_option(
|
|
'-p', '--platform',
|
|
type='choice',
|
|
default=_get_platform(),
|
|
dest='platform',
|
|
choices=['windows', 'darwin', 'linux', 'solaris', 'all'],
|
|
help="""Override the automatically determined platform. \
|
|
You can specify 'all' to get assets for all platforms. Choices: windows, \
|
|
darwin, linux, solaris, or all. Default: autodetected (%s)""" % \
|
|
_get_platform())
|
|
parser.add_option(
|
|
'--cache-dir',
|
|
type='string',
|
|
default=_default_installable_cache(),
|
|
dest='cache_dir',
|
|
help='Where to download files. Default: %s'% \
|
|
(_default_installable_cache()))
|
|
parser.add_option(
|
|
'--install-dir',
|
|
type='string',
|
|
default=base_dir,
|
|
dest='install_dir',
|
|
help='Where to unpack the installed files. Default: %s' % base_dir)
|
|
|
|
return parser.parse_args()
|
|
|
|
def main(argv):
|
|
options, args = _parse_args()
|
|
# 1. prepare cache dir
|
|
if not os.path.exists(options.cache_dir):
|
|
os.makedirs(options.cache_dir)
|
|
|
|
# 2. read doc/asset_urls.txt
|
|
asseturls=get_asset_urls()
|
|
|
|
# 3. figure out which asset bundles we'll be downloading
|
|
if len(args)>0:
|
|
assetnames=args
|
|
else:
|
|
assetnames=get_assetnames_by_platform(options.platform)
|
|
|
|
# 4. download and extract each asset bundle
|
|
for asset in assetnames:
|
|
# 4a. get the URL for the asset bundle
|
|
try:
|
|
asseturl=asseturls[asset]
|
|
except:
|
|
print "No asset in doc/asset_urls.txt named %s" % asset
|
|
sys.exit(2)
|
|
# 4b. figure out where to put the downloaded asset bundle
|
|
filename=get_asset_filename_from_url(asseturl, options.cache_dir)
|
|
|
|
# 4c. see if we have it, and if not, get it
|
|
if os.path.exists(filename):
|
|
_report("Using already downloaded "+filename+" ...")
|
|
else:
|
|
_report("Downloading "+filename+" ...")
|
|
urllib.urlretrieve(asseturl, filename)
|
|
# 4d. extract it into the tree
|
|
extract_archive_sans_linden(filename, options.install_dir)
|
|
|
|
# execute main() only if invoked directly:
|
|
if __name__ == "__main__":
|
|
sys.exit(main(sys.argv))
|