fmt/support/bootstrap.py
2015-03-04 08:24:35 -08:00

196 lines
6.6 KiB
Python

# Common bootstrap functionality.
from __future__ import print_function
import glob, os, platform, re, shutil, sys
import tarfile, tempfile, uuid, zipfile
from contextlib import closing
from subprocess import check_call, call
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import timer
from download import Downloader
windows = platform.system() == 'Windows'
opt_dir = r'\Program Files' if windows else '/opt'
# Downloads to a temporary file in the current directory.
# When running in a Vagrant VM, the current directory is in a synced folder so
# this reduces VM growth.
def download(url, cookie=None):
return Downloader('.').download(url, cookie);
# If we are in a VM managed by Vagrant, then do everything in the shared
# /vagrant directory to avoid growth of the VM drive.
vagrant_dir = '/vagrant'
def bootstrap_init():
if os.path.exists(vagrant_dir):
os.chdir(vagrant_dir)
return True
return False
# Returns executable location.
def which(name):
filename = name + '.exe' if windows else name
for path in os.environ['PATH'].split(os.pathsep):
path = os.path.join(path.strip('"'), filename)
if os.path.isfile(path) and os.access(path, os.X_OK):
return path
return None
# Returns true if executable is installed on the path.
def installed(name):
path = which(name)
if path:
print(name, 'is installed in', path)
return path != None
def create_symlink(filename, linkname):
if not os.path.exists(linkname):
print('Creating a symlink from', linkname, 'to', filename)
os.symlink(filename, linkname)
else:
print('File already exists:', linkname)
# Adds path to search paths.
def add_to_path(path, linkname=None, isdir=False):
paths = os.environ['PATH'].split(os.pathsep)
dir = path if isdir else os.path.dirname(path)
print('Adding', dir, 'to PATH')
if isdir:
paths.insert(0, dir)
else:
paths.append(dir)
os.environ['PATH'] = os.pathsep.join(paths)
if windows:
check_call(['setx', '/m', 'PATH', os.environ['PATH']])
if windows or isdir:
return
dir = '/usr/local/bin'
# Create /usr/local/bin directory if it doesn't exist which can happen
# on OS X.
if not os.path.exists(dir):
os.makedirs(dir)
linkname = os.path.join(dir, linkname or os.path.basename(path))
create_symlink(path, linkname)
# Downloads and installs CMake.
# package: The name of a CMake package,
# e.g. 'cmake-2.8.12.2-Linux-i386.tar.gz'.
def install_cmake(package, **kwargs):
if kwargs.get('check_installed', True) and installed('cmake'):
return
dir, version, minor = re.match(
r'(cmake-(\d+\.\d+)\.(\d+).*-[^\.]+)\..*', package).groups()
# extractall overwrites existing files, so no need to prepare the
# destination.
url = 'http://www.cmake.org/files/v{0}/{1}'.format(version, package)
install_dir = kwargs.get('install_dir', opt_dir)
with Downloader(kwargs.get('download_dir', '.')).download(url) as f:
iszip = package.endswith('zip')
with zipfile.ZipFile(f) if iszip \
else closing(tarfile.open(f, 'r:gz')) as archive:
archive.extractall(install_dir)
dir = os.path.join(install_dir, dir)
if platform.system() == 'Darwin':
dir = glob.glob(os.path.join(dir, 'CMake*.app', 'Contents'))[0]
cmake_path = os.path.join(dir, 'bin', 'cmake')
if install_dir != '.':
add_to_path(cmake_path)
return cmake_path
# Install f90cache.
def install_f90cache():
if not installed('f90cache'):
f90cache = 'f90cache-0.95'
tempdir = tempfile.mkdtemp(suffix='f90cache', dir='')
with download(
'http://people.irisa.fr/Edouard.Canot/f90cache/' +
f90cache + '.tar.bz2', False) as f:
with closing(tarfile.open(f, "r:bz2")) as archive:
archive.extractall(tempdir)
f90cache_dir = os.path.join(tempdir, f90cache)
check_call(['sh', 'configure'], cwd=f90cache_dir)
check_call(['make', 'all', 'install'], cwd=f90cache_dir)
shutil.rmtree(tempdir)
# Returns true iff module exists.
def module_exists(module):
try:
__import__(module)
return True
except ImportError:
return False
# Install package using pip if it hasn't been installed already.
def pip_install(package, test_module=None):
if not test_module:
test_module = package
if module_exists(test_module):
return
# If pip doesn't exist install it first.
if not module_exists('pip'):
with download('https://bootstrap.pypa.io/get-pip.py') as f:
check_call(['python', f])
# Install the package.
print('Installing', package)
check_call(['pip', 'install', package])
# Installs buildbot slave.
def install_buildbot_slave(name, path=None, script_dir='', shell=False, **args):
username = 'vagrant'
if platform.system() == 'Linux':
# Create buildbot user if it doesn't exist.
username = 'buildbot'
import pwd
try:
pwd.getpwnam(username)
except KeyError:
check_call(['sudo', 'useradd', '--system', '--home', '/var/lib/buildbot',
'--create-home', '--shell', '/bin/false', 'buildbot'])
path = path or os.path.expanduser('~{0}/slave'.format(username))
if os.path.exists(path):
return
pip_install('buildbot-slave', 'buildbot')
# The password is insecure but it doesn't matter as the buildslaves are
# not publicly accessible.
command = [os.path.join(script_dir, 'buildslave'),
'create-slave', path, args.get('ip', '10.0.2.2'), name, 'pass']
if not windows:
command = ['sudo', '-u', username] + command
check_call(command, shell=shell)
if windows:
return
if args.get('nocron', False):
return
pip_install('python-crontab', 'crontab')
from crontab import CronTab
cron = CronTab(username)
cron.new('PATH={0}:/usr/local/bin buildslave start {1}'.format(
os.environ['PATH'], path)).every_reboot()
cron.write()
# Ignore errors from buildslave as the buildbot may not be accessible.
call(['sudo', '-H', '-u', username, 'buildslave', 'start', path])
# Copies optional dependencies from opt/<platform> to /opt.
def copy_optional_dependencies(platform):
if os.path.exists('opt'):
for src in glob.glob('opt/' + platform + '/*'):
dest = '/opt/' + os.path.basename(src)
if not os.path.exists(dest):
shutil.copytree(src, dest, symlinks=True)
# Installs an OS X package.
def install_pkg(filename):
print('Installing', filename)
check_call(['sudo', 'installer', '-pkg', filename, '-target', '/'])
# Installs a package from a .dmg file.
def install_dmg(filename):
dir = tempfile.mkdtemp()
check_call(['hdiutil', 'attach', filename, '-mountpoint', dir])
install_pkg(glob.glob(dir + '/*pkg')[0])
check_call(['hdiutil', 'detach', dir])
os.rmdir(dir)
LOCALSOLVER_VERSION = '4_5_20140718'