2
0
mirror of https://gitlab.com/ita1024/waf.git synced 2024-11-22 01:46:15 +01:00
waf/wscript

425 lines
13 KiB
Plaintext
Raw Normal View History

2011-09-10 11:13:51 +02:00
#! /usr/bin/env python
# encoding: utf-8
2018-01-01 20:53:49 +01:00
# Thomas Nagy, 2005-2018
2011-09-10 11:13:51 +02:00
"""
to make a custom waf file use the option --tools
To add a tool that does not exist in the folder compat15, pass an absolute path:
./waf-light --tools=compat15,/comp/waf/aba.py --prelude=$'\tfrom waflib.extras import aba\n\taba.foo()'
2011-09-10 11:13:51 +02:00
"""
from __future__ import with_statement
2024-07-15 01:32:34 +02:00
VERSION="2.1.2"
2011-09-10 11:13:51 +02:00
APPNAME='waf'
REVISION=''
top = '.'
out = 'build'
2015-02-24 21:20:15 +01:00
zip_types = ['bz2', 'gz', 'xz']
2011-09-10 11:13:51 +02:00
PRELUDE = ''
2011-09-10 11:13:51 +02:00
import os, sys, re, io, optparse, tokenize
2011-09-10 11:13:51 +02:00
from hashlib import md5
from waflib import Errors, Utils, Options, Logs, Scripting
2011-09-10 11:13:51 +02:00
from waflib import Configure
Configure.autoconfig = 1
def sub_file(fname, lst):
2019-01-16 06:51:14 +01:00
with open(fname, 'r') as f:
2012-05-19 09:45:57 +02:00
txt = f.read()
2011-09-10 11:13:51 +02:00
for (key, val) in lst:
re_pat = re.compile(key, re.M)
txt = re_pat.sub(val, txt)
with open(fname, 'w') as f:
2012-05-19 09:45:57 +02:00
f.write(txt)
2011-09-10 11:13:51 +02:00
def to_bytes(x):
if sys.hexversion>0x300000f:
return x.encode()
return x
2016-06-24 13:21:32 +02:00
Logs.warn('------> Executing code from the top-level wscript <-----')
2011-12-17 16:28:30 +01:00
def init(ctx):
2011-09-10 11:13:51 +02:00
if Options.options.setver: # maintainer only (ita)
ver = Options.options.setver
hexver = Utils.num2ver(ver)
hexver = '0x%x'%hexver
sub_file('wscript', (('^VERSION=(.*)', 'VERSION="%s"' % ver), ))
sub_file('waf-light', (('^VERSION=(.*)', 'VERSION="%s"' % ver), ))
pats = []
pats.append(('^WAFVERSION=(.*)', 'WAFVERSION="%s"' % ver))
pats.append(('^HEXVERSION(.*)', 'HEXVERSION=%s' % hexver))
try:
2012-10-31 02:00:01 +01:00
rev = ctx.cmd_and_log("git rev-parse HEAD").strip()
except Errors.WafError:
rev = ''
else:
pats.append(('^WAFREVISION(.*)', 'WAFREVISION="%s"' % rev))
2011-09-10 11:13:51 +02:00
sub_file('waflib/Context.py', pats)
sys.exit(0)
2011-12-31 13:49:34 +01:00
def check(ctx):
Logs.warn('Nothing to do')
2011-09-10 11:13:51 +02:00
# this function is called before any other for parsing the command-line
def options(opt):
# generate waf
opt.add_option('--make-waf', action='store_true', default=True,
2011-09-10 11:13:51 +02:00
help='creates the waf script', dest='waf')
opt.add_option('--interpreter', action='store', default=None,
help='specify the #! line on top of the waf file', dest='interpreter')
opt.add_option('--sign', action='store_true', default=False, help='make a signed file', dest='signed')
default_zip = 'bz2'
if os.name == 'java':
default_zip = 'gz'
opt.add_option('--zip-type', action='store', default=default_zip,
2011-09-10 11:13:51 +02:00
help='specify the zip type [Allowed values: %s]' % ' '.join(zip_types), dest='zip')
opt.add_option('--make-batch', action='store_true', default=False,
help='creates a convenience waf.bat file (done automatically on win32 systems)',
dest='make_batch')
opt.add_option('--yes', action='store_true', default=False,
help=optparse.SUPPRESS_HELP,
dest='yes')
# those ones are not too interesting
opt.add_option('--set-version', default='',
help='sets the version number for waf releases (for the maintainer)', dest='setver')
opt.add_option('--set-name', default='waf', help=optparse.SUPPRESS_HELP, dest='wafname')
2011-09-10 11:13:51 +02:00
opt.add_option('--strip', action='store_true', default=True,
help='shrinks waf (strip docstrings, saves 33kb)',
dest='strip_comments')
opt.add_option('--nostrip', action='store_false', help='no shrinking',
dest='strip_comments')
opt.add_option('--tools', action='store', help='Comma-separated 3rd party tools to add, eg: "compat,ocaml" [Default: "compat15"]',
dest='add3rdparty', default='compat15')
opt.add_option('--coretools', action='store', help='Comma-separated core tools to add, eg: "vala,tex" [Default: all of them]',
dest='coretools', default='default')
2011-09-10 11:13:51 +02:00
opt.add_option('--prelude', action='store', help='Code to execute before calling waf', dest='prelude', default=PRELUDE)
opt.add_option('--namesfrom', action='store', help='Obtain the file names from a model archive', dest='namesfrom', default=None)
2011-09-10 11:13:51 +02:00
opt.load('python')
def process_tokens(tokens):
accu = []
prev = tokenize.NEWLINE
indent = 0
line_buf = []
for (type, token, start, end, line) in tokens:
token = token.replace('\r\n', '\n')
if type == tokenize.NEWLINE:
if line_buf:
accu.append(indent * '\t')
ln = "".join(line_buf)
if ln == 'if __name__=="__main__":': break
#ln = ln.replace('\n', '')
accu.append(ln)
accu.append('\n')
line_buf = []
prev = tokenize.NEWLINE
elif type == tokenize.INDENT:
indent += 1
elif type == tokenize.DEDENT:
indent -= 1
elif type == tokenize.NAME:
if prev == tokenize.NAME or prev == tokenize.NUMBER: line_buf.append(' ')
line_buf.append(token)
elif type == tokenize.NUMBER:
if prev == tokenize.NAME or prev == tokenize.NUMBER: line_buf.append(' ')
line_buf.append(token)
elif type == tokenize.STRING:
if not line_buf and token.startswith('"'): pass
else: line_buf.append(token)
elif type == tokenize.COMMENT:
pass
elif type == tokenize.OP:
line_buf.append(token)
else:
if token != "\n": line_buf.append(token)
if token != '\n':
prev = type
2016-06-24 13:21:32 +02:00
body = ''.join(accu)
2011-09-10 11:13:51 +02:00
return body
2019-01-16 06:51:14 +01:00
deco_re = re.compile('(def|class)\\s+(\\w+)\\(.*')
2011-09-10 11:13:51 +02:00
def process_decorators(body):
2015-03-03 12:19:25 +01:00
lst = body.splitlines()
2011-09-10 11:13:51 +02:00
accu = []
all_deco = []
buf = [] # put the decorator lines
for line in lst:
if line.startswith('@'):
buf.append(line[1:])
elif buf:
name = deco_re.sub('\\2', line)
if not name:
raise IOError("decorator not followed by a function!" + line)
for x in buf:
2016-06-24 13:21:32 +02:00
all_deco.append('%s(%s)' % (x, name))
2011-09-10 11:13:51 +02:00
accu.append(line)
buf = []
else:
accu.append(line)
2016-06-24 13:21:32 +02:00
return '\n'.join(accu+all_deco)
2011-09-10 11:13:51 +02:00
def sfilter(path):
if path.endswith('.py') :
if Options.options.strip_comments:
if sys.version_info[0] >= 3:
with open(path, 'rb') as f:
tk = tokenize.tokenize(f.readline)
next(tk) # the first one is always tokenize.ENCODING for Python 3, ignore it
cnt = process_tokens(tk)
else:
with open(path, 'r') as f:
cnt = process_tokens(tokenize.generate_tokens(f.readline))
else:
with open(path, 'r') as f:
cnt = f.read()
2016-03-08 21:28:20 +01:00
# WARNING: since python >= 2.5 is required, decorators are not processed anymore
# uncomment the following to enable decorator replacement:
2012-02-06 01:39:25 +01:00
#cnt = process_decorators(cnt)
#if cnt.find('set(') > -1:
# cnt = 'import sys\nif sys.hexversion < 0x020400f0: from sets import Set as set\n' + cnt
2015-04-06 14:46:55 +02:00
cnt = '#! /usr/bin/env python\n# encoding: utf-8\n# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file\n\n' + cnt
2011-09-10 11:13:51 +02:00
else:
with open(path, 'r') as f:
cnt = f.read()
2012-06-07 17:57:13 +02:00
if sys.hexversion > 0x030000f0:
2014-08-03 17:34:18 +02:00
return (io.BytesIO(cnt.encode('utf-8')), len(cnt.encode('utf-8')), cnt)
2012-06-07 17:57:13 +02:00
return (io.BytesIO(cnt), len(cnt), cnt)
2011-09-10 11:13:51 +02:00
2015-02-14 12:07:13 +01:00
def create_waf(self, *k, **kw):
2011-09-10 11:13:51 +02:00
mw = 'tmp-waf-'+VERSION
2016-06-24 13:21:32 +02:00
print('-> preparing %r' % mw)
2011-09-10 11:13:51 +02:00
2016-04-15 18:17:26 +02:00
import tarfile, zipfile
2011-09-10 11:13:51 +02:00
zipType = Options.options.zip.strip().lower()
if zipType not in zip_types:
zipType = zip_types[0]
directory_files = {}
2011-09-10 11:13:51 +02:00
files = []
add3rdparty = []
for x in Options.options.add3rdparty.split(','):
if os.path.isdir(x):
# Create mapping from files absolute path to path in module
# directory (for module mylib):
#
# {"/home/path/mylib/__init__.py": "mylib/__init__.py",
# "/home/path/mylib/lib.py": "mylib/lib.py",
# "/home/path/mylib/sub/sub.py": "mylib/sub/lib.py"
# }
#
x_dir = self.generator.bld.root.find_dir(
os.path.abspath(os.path.expanduser(x)))
file_list = x_dir.ant_glob('**/*.py')
for f in file_list:
file_from = f.abspath()
file_to = os.path.join(x_dir.name, f.path_from(x_dir))
# If this is executed on Windows, then file_to will contain
# '\' path separators. These should be changed to '/', otherwise
# the added tools will not be accessible on Unix systems.
directory_files[file_from] = file_to.replace('\\', '/')
files.append(file_from)
elif os.path.isabs(x):
2011-09-10 11:13:51 +02:00
files.append(x)
else:
add3rdparty.append(x + '.py')
coretools = []
for x in Options.options.coretools.split(','):
coretools.append(x + '.py')
up_node = self.generator.bld.path
for node in up_node.find_dir('waflib').ant_glob(incl=['*.py', 'Tools/*.py', 'extras/*.py']):
relpath = node.path_from(up_node)
if node.name == '__init__.py':
files.append(relpath)
continue
if node.parent.name == 'Tools' and Options.options.coretools != 'default':
if node.name not in coretools:
2011-09-10 11:13:51 +02:00
continue
if node.parent.name == 'extras':
if node.name not in add3rdparty:
continue
files.append(relpath)
2011-09-10 11:13:51 +02:00
if Options.options.namesfrom:
with tarfile.open(Options.options.namesfrom) as tar:
oldfiles = files
files = [x.name for x in tar.getmembers()]
if set(files) ^ set(oldfiles):
Logs.warn('The archive model has differences:')
Logs.warn('- Added %r', list(set(files) - set(oldfiles)))
Logs.warn('- Removed %r', list(set(oldfiles) - set(files)))
#open a file as tar.[extension] for writing
tar = tarfile.open('%s.tar.%s' % (mw, zipType), "w:%s" % zipType)
z = zipfile.ZipFile("zip/waflib.zip", "w", compression=zipfile.ZIP_DEFLATED)
2011-09-10 11:13:51 +02:00
for x in files:
2015-10-06 22:06:19 +02:00
try:
tarinfo = tar.gettarinfo(x, x)
except NotImplementedError:
# jython 2.7.0 workaround
tarinfo = tarfile.TarInfo(x)
2011-09-10 11:13:51 +02:00
tarinfo.uid = tarinfo.gid = 0
tarinfo.uname = tarinfo.gname = 'root'
if os.environ.get('SOURCE_DATE_EPOCH'):
tarinfo.mtime = int(os.environ.get('SOURCE_DATE_EPOCH'))
2011-09-10 11:13:51 +02:00
(code, size, cnt) = sfilter(x)
tarinfo.size = size
if x in directory_files:
tarinfo.name = 'waflib/extras/' + directory_files[x]
elif os.path.isabs(x):
2011-09-10 11:13:51 +02:00
tarinfo.name = 'waflib/extras/' + os.path.split(x)[1]
2016-06-24 13:21:32 +02:00
print(' adding %s as %s' % (x, tarinfo.name))
def dest(x):
if x in directory_files:
return os.path.join('waflib', 'extras', directory_files[x])
elif os.path.isabs(x):
return os.path.join('waflib', 'extras', os.path.basename(x))
else:
return os.path.normpath(os.path.relpath(x, "."))
z.write(x, dest(x))
2011-09-10 11:13:51 +02:00
tar.addfile(tarinfo, code)
tar.close()
z.close()
2011-09-10 11:13:51 +02:00
2019-01-16 06:51:14 +01:00
with open('waf-light', 'r') as f:
2012-05-19 09:45:57 +02:00
code1 = f.read()
2011-09-10 11:13:51 +02:00
# tune the application name if necessary
if Options.options.wafname != 'waf':
Options.options.prelude = '\tfrom waflib import Context\n\tContext.WAFNAME=%r\n' % Options.options.wafname + Options.options.prelude
2011-09-10 11:13:51 +02:00
# now store the revision unique number in waf
code1 = code1.replace("if sys.hexversion<0x206000f:\n\traise ImportError('Python >= 2.6 is required to create the waf file')\n", '')
code1 = code1.replace('\t#import waflib.extras.compat15#PRELUDE', Options.options.prelude)
2011-09-10 11:13:51 +02:00
2015-02-14 12:07:13 +01:00
# when possible, set the git revision in the waf file
bld = self.generator.bld
try:
2016-06-24 13:21:32 +02:00
rev = bld.cmd_and_log('git rev-parse HEAD', quiet=0).strip()
except Errors.WafError:
rev = ''
2015-02-14 12:07:13 +01:00
else:
reg = re.compile('^GIT(.*)', re.M)
code1 = reg.sub('GIT="%s"' % rev, code1)
# if the waf file is installed somewhere... but do not do that
2011-09-10 11:13:51 +02:00
prefix = ''
reg = re.compile('^INSTALL=(.*)', re.M)
code1 = reg.sub(r'INSTALL=%r' % prefix, code1)
#change the tarfile extension in the waf script
reg = re.compile('bz2', re.M)
code1 = reg.sub(zipType, code1)
if zipType == 'gz':
code1 = code1.replace('bunzip2', 'gzip -d')
2015-02-24 21:20:15 +01:00
elif zipType == 'xz':
code1 = code1.replace('bunzip2', 'xz -d')
2011-09-10 11:13:51 +02:00
with open('%s.tar.%s' % (mw, zipType), 'rb') as f:
2012-05-19 09:45:57 +02:00
cnt = f.read()
2011-09-10 11:13:51 +02:00
2016-03-08 21:28:20 +01:00
# the REVISION value is the md5 sum of the compressed data (facilitate audits)
2011-09-10 11:13:51 +02:00
m = md5()
m.update(cnt)
REVISION = m.hexdigest()
reg = re.compile('^REVISION=(.*)', re.M)
code1 = reg.sub(r'REVISION="%s"' % REVISION, code1)
def find_unused(kd, ch):
for i in range(35, 125):
for j in range(35, 125):
if i==j: continue
if i == 39 or j == 39: continue
if i == 92 or j == 92: continue
s = chr(i) + chr(j)
if -1 == kd.find(s.encode()):
return (kd.replace(ch.encode(), s.encode()), s)
raise ValueError('Could not find a proper encoding')
2011-09-10 11:13:51 +02:00
2015-03-12 19:24:02 +01:00
# The reverse order prevents collisions
(cnt, C3) = find_unused(cnt, '\x00')
2011-09-10 11:13:51 +02:00
(cnt, C2) = find_unused(cnt, '\r')
(cnt, C1) = find_unused(cnt, '\n')
ccc = code1.replace("C1='x'", "C1='%s'" % C1).replace("C2='x'", "C2='%s'" % C2).replace("C3='x'", "C3='%s'" % C3)
2011-09-10 11:13:51 +02:00
if getattr(Options.options, 'interpreter', None):
ccc = ccc.replace('#!/usr/bin/env python', Options.options.interpreter)
with open('waf', 'wb') as f:
2012-05-19 09:45:57 +02:00
f.write(ccc.encode())
f.write(to_bytes('#==>\n#'))
2012-05-19 09:45:57 +02:00
f.write(cnt)
f.write(to_bytes('\n#<==\n'))
if Options.options.signed:
f.flush()
try:
os.remove('waf.asc')
except OSError:
pass
ret = Utils.subprocess.Popen('gpg -bass waf', shell=True).wait()
if ret:
raise ValueError('Could not sign the waf file!')
sig = Utils.readf('waf.asc')
sig = sig.replace('\r', '').replace('\n', '\\n')
f.write(to_bytes('#'))
f.write(to_bytes(sig))
f.write(to_bytes('\n'))
os.remove('waf.asc')
2011-09-10 11:13:51 +02:00
2011-09-10 11:13:51 +02:00
if sys.platform == 'win32' or Options.options.make_batch:
with open('waf.bat', 'w') as f:
f.write('@setlocal\n@set PYEXE=python\n@where %PYEXE% 1>NUL 2>NUL\n@if %ERRORLEVEL% neq 0 set PYEXE=py\n@%PYEXE% -x "%~dp0waf" %*\n@exit /b %ERRORLEVEL%\n')
2011-09-10 11:13:51 +02:00
if sys.platform != 'win32':
os.chmod('waf', Utils.O755)
os.remove('%s.tar.%s' % (mw, zipType))
2011-09-10 11:13:51 +02:00
def configure(conf):
conf.load('python')
2011-09-10 11:13:51 +02:00
def build(bld):
2016-03-08 21:28:20 +01:00
waf = bld.path.make_node('waf') # do not use a build directory for this file
2016-03-08 19:18:18 +01:00
bld(name='create_waf', rule=create_waf, target=waf, always=True, color='PINK')
2011-12-17 16:28:30 +01:00
class Dist(Scripting.Dist):
def get_excl(self):
return super(self.__class__, self).get_excl() + ' **/waflib.zip'