mirror of
https://github.com/truenas/core-build.git
synced 2026-02-15 07:36:18 +00:00
226 lines
5.8 KiB
Python
226 lines
5.8 KiB
Python
#+
|
|
# Copyright 2015 iXsystems, Inc.
|
|
# All rights reserved
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted providing that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
#####################################################################
|
|
|
|
import os
|
|
import sys
|
|
import time
|
|
import datetime
|
|
import subprocess
|
|
import atexit
|
|
import string
|
|
import signal
|
|
import inspect
|
|
from collections import defaultdict
|
|
from dsl import load_file
|
|
|
|
|
|
def interrupt(signal, frame):
|
|
error('Build interrupted by SIGINT')
|
|
|
|
|
|
def sh(*args, **kwargs):
|
|
logfile = kwargs.pop('log', None)
|
|
mode = kwargs.pop('mode', 'w')
|
|
nofail = kwargs.pop('nofail', False)
|
|
cmd = e(' '.join(args), **get_caller_vars())
|
|
if logfile:
|
|
sh('mkdir -p', os.path.dirname(logfile))
|
|
f = open(logfile, mode)
|
|
|
|
debug('sh: {0}', cmd)
|
|
ret = subprocess.call(cmd, stdout=f if logfile else None, stderr=subprocess.STDOUT, shell=True)
|
|
if ret != 0 and not nofail:
|
|
info('Failed command: {0}', cmd)
|
|
info('Returned value: {0}', ret)
|
|
error('Build failed')
|
|
|
|
return ret
|
|
|
|
|
|
def sh_str(*args, **kwargs):
|
|
logfile = kwargs.pop('log', None)
|
|
mode = kwargs.pop('mode', 'w')
|
|
cmd = e(' '.join(args), **get_caller_vars())
|
|
if logfile:
|
|
f = open(logfile, mode)
|
|
|
|
try:
|
|
return subprocess.check_output(cmd, shell=True).strip()
|
|
except subprocess.CalledProcessError:
|
|
return ''
|
|
|
|
|
|
def chroot(root, *args, **kwargs):
|
|
root = e(root, **get_caller_vars())
|
|
cmd = e(' '.join(args), **get_caller_vars())
|
|
return sh("chroot ${root} /bin/sh -c '${cmd}'", **kwargs)
|
|
|
|
|
|
def setup_env():
|
|
signal.signal(signal.SIGINT, interrupt)
|
|
dsl = load_file('${BUILD_CONFIG}/env.pyd', os.environ)
|
|
for k, v in dsl.items():
|
|
if k.isupper():
|
|
os.environ[k] = v
|
|
|
|
|
|
def env(name, default=None):
|
|
return os.getenv(name, default)
|
|
|
|
|
|
def readfile(filename):
|
|
filename = e(filename, **get_caller_vars())
|
|
with open(filename, 'r') as f:
|
|
return f.read().strip()
|
|
|
|
|
|
def setfile(filename, contents):
|
|
filename = e(filename, **get_caller_vars())
|
|
debug('setfile: {0}', filename)
|
|
|
|
if not os.path.isdir(os.path.dirname(filename)):
|
|
sh('mkdir -p', os.path.dirname(filename))
|
|
|
|
f = open(filename, 'w')
|
|
f.write(contents)
|
|
f.write('\n')
|
|
f.close()
|
|
|
|
|
|
def appendfile(filename, contents):
|
|
filename = e(filename, **get_caller_vars())
|
|
debug('appendfile: {0}', filename)
|
|
|
|
if not os.path.isdir(os.path.dirname(filename)):
|
|
sh('mkdir -p', os.path.dirname(filename))
|
|
|
|
f = open(filename, 'a')
|
|
f.write(contents)
|
|
f.write('\n')
|
|
|
|
|
|
def on_exit(func):
|
|
def abort():
|
|
info('Build aborted, cleaning up')
|
|
func()
|
|
|
|
atexit.register(abort)
|
|
|
|
|
|
def get_caller_vars():
|
|
frame = inspect.currentframe()
|
|
try:
|
|
parent = frame.f_back.f_back
|
|
kwargs = parent.f_locals
|
|
kwargs.update(parent.f_globals)
|
|
finally:
|
|
del frame
|
|
|
|
return kwargs
|
|
|
|
|
|
def e(s, **kwargs):
|
|
s = os.path.expandvars(s)
|
|
if not kwargs:
|
|
kwargs = get_caller_vars()
|
|
|
|
t = string.Template(s)
|
|
d = defaultdict(lambda: '')
|
|
d.update(kwargs)
|
|
return t.safe_substitute(d)
|
|
|
|
|
|
def pathjoin(*args):
|
|
return os.path.join(*[os.path.expandvars(i) for i in args])
|
|
|
|
|
|
def objdir(path):
|
|
return os.path.join(e('${OBJDIR}'), path)
|
|
|
|
|
|
def template(filename, variables=None):
|
|
f = open(e(filename), 'r')
|
|
t = string.Template(f.read())
|
|
variables = variables or {}
|
|
variables.update(os.environ)
|
|
result = t.safe_substitute(**variables)
|
|
f.close()
|
|
return result
|
|
|
|
|
|
def glob(path):
|
|
import glob as g
|
|
return g.glob(e(path, **get_caller_vars()))
|
|
|
|
|
|
def walk(path):
|
|
path = e(path, **get_caller_vars())
|
|
for root, dirs, files in os.walk(path):
|
|
for name in files:
|
|
yield os.path.relpath(os.path.join(root, name), path)
|
|
|
|
for name in dirs:
|
|
yield os.path.relpath(os.path.join(root, name), path)
|
|
|
|
|
|
def sha256(filename, output=None):
|
|
filename = e(filename, **get_caller_vars())
|
|
if not output:
|
|
output = filename + '.sha256'
|
|
else:
|
|
output = e(output, **get_caller_vars())
|
|
|
|
setfile(output, sh_str("sha256 ${filename}"))
|
|
|
|
|
|
def import_function(filename, fname):
|
|
module = __import__(filename)
|
|
return getattr(module, fname)
|
|
|
|
|
|
def elapsed():
|
|
timestamp = env('BUILD_STARTED', str(int(time.time())))
|
|
td = int(timestamp)
|
|
return str(datetime.timedelta(seconds=time.time() - td)).split('.')[0] # XXX
|
|
|
|
|
|
def info(fmt, *args):
|
|
print '[{0}] ==> '.format(elapsed()) + e(fmt.format(*args))
|
|
|
|
|
|
def debug(fmt, *args):
|
|
if env('BUILD_LOGLEVEL') == 'DEBUG':
|
|
log(fmt, *args)
|
|
|
|
|
|
def log(fmt, *args):
|
|
print e(fmt.format(*args))
|
|
|
|
|
|
def error(fmt, *args):
|
|
print '[{0}] ==> ERROR: '.format(elapsed()) + e(fmt.format(*args))
|
|
sys.exit(1) |