aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2017-08-07 11:46:50 -0400
committerJack Lloyd <[email protected]>2017-08-07 11:46:50 -0400
commit01317855dc2e076050277073ac40c308ad7a4da5 (patch)
treef5b5dcc4589eace863f0cd872f81c0726afb82bf /src
parent453fde9b740754b45b5820e0ad3bf1a836792718 (diff)
parent53d1b0faf2d264e03933b2f1e578ff19c6209aa3 (diff)
Merge GH #1139 Replace --destdir flag with DESTDIR env variable
Diffstat (limited to 'src')
-rw-r--r--src/build-data/makefile/gmake.in2
-rw-r--r--src/build-data/makefile/header.in2
-rw-r--r--src/build-data/makefile/nmake.in2
-rwxr-xr-xsrc/scripts/ci/travis/lint.sh6
-rwxr-xr-xsrc/scripts/install.py90
-rwxr-xr-xsrc/scripts/python_unittests.py (renamed from src/scripts/python_uniitests.py)0
-rwxr-xr-xsrc/scripts/python_unittests_unix.py67
7 files changed, 140 insertions, 29 deletions
diff --git a/src/build-data/makefile/gmake.in b/src/build-data/makefile/gmake.in
index 70959dfa9..22e4ef778 100644
--- a/src/build-data/makefile/gmake.in
+++ b/src/build-data/makefile/gmake.in
@@ -75,4 +75,4 @@ docs:
%{build_doc_commands}
install: $(CLI) docs
- $(SCRIPTS_DIR)/install.py --destdir=%{destdir} --build-dir="%{build_dir}" --bindir=%{bindir} --libdir=%{libdir} --docdir=%{docdir} --includedir=%{includedir}
+ $(SCRIPTS_DIR)/install.py --prefix=%{prefix} --build-dir="%{build_dir}" --bindir=%{bindir} --libdir=%{libdir} --docdir=%{docdir} --includedir=%{includedir}
diff --git a/src/build-data/makefile/header.in b/src/build-data/makefile/header.in
index f62f5ea0d..1114cf2d6 100644
--- a/src/build-data/makefile/header.in
+++ b/src/build-data/makefile/header.in
@@ -19,7 +19,7 @@ CLI_FLAGS = $(CXXFLAGS) $(WARN_FLAGS)
TEST_FLAGS = $(CXXFLAGS) $(WARN_FLAGS)
SCRIPTS_DIR = %{scripts_dir}
-INSTALLED_LIB_DIR = %{destdir}/%{libdir}
+INSTALLED_LIB_DIR = %{prefix}/%{libdir}
CLI_POST_LINK_CMD = %{cli_post_link_cmd}
TEST_POST_LINK_CMD = %{test_post_link_cmd}
diff --git a/src/build-data/makefile/nmake.in b/src/build-data/makefile/nmake.in
index 2fc86e763..83d3e3f2b 100644
--- a/src/build-data/makefile/nmake.in
+++ b/src/build-data/makefile/nmake.in
@@ -100,4 +100,4 @@ distclean: clean
$(RM) Makefile $(LIB_BASENAME).* $(CLI).*
install: $(CLI) docs
- $(SCRIPTS_DIR)\install.py --destdir=%{destdir} --build-dir="%{build_dir}" --bindir=%{bindir} --libdir=%{libdir} --docdir=%{docdir} --includedir=%{includedir}
+ $(SCRIPTS_DIR)\install.py --prefix=%{prefix} --build-dir="%{build_dir}" --bindir=%{bindir} --libdir=%{libdir} --docdir=%{docdir} --includedir=%{includedir}
diff --git a/src/scripts/ci/travis/lint.sh b/src/scripts/ci/travis/lint.sh
index df9288b36..65f885365 100755
--- a/src/scripts/ci/travis/lint.sh
+++ b/src/scripts/ci/travis/lint.sh
@@ -21,9 +21,13 @@ python3_pylint src/scripts/install.py
echo "travis_fold:end:pylint_configure"
echo "travis_fold:start:pylint_python_unittests"
-python3_pylint src/scripts/python_uniitests.py
+python3_pylint src/scripts/python_unittests.py
echo "travis_fold:end:pylint_python_unittests"
+echo "travis_fold:start:pylint_python_unittests_unix"
+python3_pylint src/scripts/python_unittests_unix.py
+echo "travis_fold:end:pylint_python_unittests_unix"
+
echo "travis_fold:start:pylint_botanpy"
python2_pylint src/python/botan2.py
python3_pylint src/python/botan2.py
diff --git a/src/scripts/install.py b/src/scripts/install.py
index 601502657..9f7363a48 100755
--- a/src/scripts/install.py
+++ b/src/scripts/install.py
@@ -33,7 +33,7 @@ def parse_command_line(args):
parser.add_option_group(build_group)
install_group = optparse.OptionGroup(parser, 'Installation options')
- install_group.add_option('--destdir', default='/usr/local',
+ install_group.add_option('--prefix', default='/usr/local',
help='Set output directory (default %default)')
install_group.add_option('--bindir', default='bin', metavar='DIR',
help='Set binary subdir (default %default)')
@@ -63,6 +63,43 @@ def parse_command_line(args):
return (options, args)
+
+class PrependDestdirError(Exception):
+ pass
+
+
+def is_subdir(path, subpath):
+ return os.path.relpath(path, start=subpath).startswith("..")
+
+
+def prepend_destdir(path):
+ """
+ Needed because os.path.join() discards the first path if the
+ second one is absolute, which is usually the case here. Still, we
+ want relative paths to work and leverage the os awareness of
+ os.path.join().
+ """
+ destdir = os.environ.get('DESTDIR', "")
+
+ if destdir:
+ # DESTDIR is non-empty, but we only join absolute paths on UNIX-like file systems
+ if os.path.sep != "/":
+ raise PrependDestdirError("Only UNIX-like file systems using forward slash " \
+ "separator supported when DESTDIR is set.")
+ if not os.path.isabs(path):
+ raise PrependDestdirError("--prefix must be an absolute path when DESTDIR is set.")
+
+ path = os.path.normpath(path)
+ # Remove / or \ prefixes if existent to accomodate for os.path.join()
+ path = path.lstrip(os.path.sep)
+ path = os.path.join(destdir, path)
+
+ if not is_subdir(destdir, path):
+ raise PrependDestdirError("path escapes DESTDIR (path='%s', destdir='%s')" % (path, destdir))
+
+ return path
+
+
def makedirs(dirname, exist_ok=True):
try:
logging.debug('Creating directory %s' % (dirname))
@@ -104,8 +141,8 @@ def main(args):
shutil.copyfile(src, dst)
def copy_executable(src, dst):
- logging.debug('Copying %s to %s' % (src, dst))
copy_file(src, dst)
+ logging.debug('Make %s executable' % dst)
os.chmod(dst, exe_mode)
with open(os.path.join(options.build_dir, 'build_config.json')) as f:
@@ -129,12 +166,12 @@ def main(args):
target_os = cfg['os']
build_shared_lib = bool(cfg['build_shared_lib'])
- bin_dir = os.path.join(options.destdir, options.bindir)
- lib_dir = os.path.join(options.destdir, options.libdir)
- target_doc_dir = os.path.join(options.destdir,
+ bin_dir = os.path.join(options.prefix, options.bindir)
+ lib_dir = os.path.join(options.prefix, options.libdir)
+ target_doc_dir = os.path.join(options.prefix,
options.docdir,
'botan-%d.%d.%d' % (ver_major, ver_minor, ver_patch))
- target_include_dir = os.path.join(options.destdir,
+ target_include_dir = os.path.join(options.prefix,
options.includedir,
'botan-%d' % (ver_major),
'botan')
@@ -145,8 +182,8 @@ def main(args):
else:
app_exe = process_template('botan%{program_suffix}')
- for d in [options.destdir, lib_dir, bin_dir, target_doc_dir, target_include_dir]:
- makedirs(d)
+ for d in [options.prefix, lib_dir, bin_dir, target_doc_dir, target_include_dir]:
+ makedirs(prepend_destdir(d))
build_include_dir = os.path.join(options.build_dir, 'include', 'botan')
@@ -154,42 +191,43 @@ def main(args):
if include == 'internal':
continue
copy_file(os.path.join(build_include_dir, include),
- os.path.join(target_include_dir, include))
+ prepend_destdir(os.path.join(target_include_dir, include)))
build_external_include_dir = os.path.join(options.build_dir, 'include', 'external')
for include in sorted(os.listdir(build_external_include_dir)):
copy_file(os.path.join(build_external_include_dir, include),
- os.path.join(target_include_dir, include))
+ prepend_destdir(os.path.join(target_include_dir, include)))
static_lib = process_template('%{lib_prefix}%{libname}.%{static_suffix}')
copy_file(os.path.join(out_dir, static_lib),
- os.path.join(lib_dir, os.path.basename(static_lib)))
+ prepend_destdir(os.path.join(lib_dir, os.path.basename(static_lib))))
if build_shared_lib:
if target_os == "windows":
libname = process_template('%{libname}')
soname_base = libname + '.dll'
copy_executable(os.path.join(out_dir, soname_base),
- os.path.join(lib_dir, soname_base))
+ prepend_destdir(os.path.join(lib_dir, soname_base)))
else:
soname_patch = process_template('%{soname_patch}')
soname_abi = process_template('%{soname_abi}')
soname_base = process_template('%{soname_base}')
copy_executable(os.path.join(out_dir, soname_patch),
- os.path.join(lib_dir, soname_patch))
+ prepend_destdir(os.path.join(lib_dir, soname_patch)))
if target_os != "openbsd":
prev_cwd = os.getcwd()
try:
- os.chdir(lib_dir)
+ os.chdir(prepend_destdir(lib_dir))
force_symlink(soname_patch, soname_abi)
force_symlink(soname_patch, soname_base)
finally:
os.chdir(prev_cwd)
- copy_executable(os.path.join(out_dir, app_exe), os.path.join(bin_dir, app_exe))
+ copy_executable(os.path.join(out_dir, app_exe),
+ prepend_destdir(os.path.join(bin_dir, app_exe)))
# On Darwin, if we are using shared libraries and we install, we should fix
# up the library name, otherwise the botan command won't work; ironically
@@ -206,29 +244,31 @@ def main(args):
os.path.join(bin_dir, app_exe)])
if 'botan_pkgconfig' in cfg:
- pkgconfig_dir = os.path.join(options.destdir, options.libdir, options.pkgconfigdir)
- makedirs(pkgconfig_dir)
+ pkgconfig_dir = os.path.join(options.prefix, options.libdir, options.pkgconfigdir)
+ makedirs(prepend_destdir(pkgconfig_dir))
copy_file(cfg['botan_pkgconfig'],
- os.path.join(pkgconfig_dir, os.path.basename(cfg['botan_pkgconfig'])))
+ prepend_destdir(os.path.join(pkgconfig_dir, os.path.basename(cfg['botan_pkgconfig']))))
if 'ffi' in cfg['mod_list'].split('\n'):
for ver in cfg['python_version'].split(','):
py_lib_path = os.path.join(lib_dir, 'python%s' % (ver), 'site-packages')
logging.debug('Installing python module to %s' % (py_lib_path))
- makedirs(py_lib_path)
+ makedirs(prepend_destdir(py_lib_path))
py_dir = cfg['python_dir']
for py in os.listdir(py_dir):
- copy_file(os.path.join(py_dir, py), os.path.join(py_lib_path, py))
+ copy_file(os.path.join(py_dir, py), prepend_destdir(os.path.join(py_lib_path, py)))
- shutil.rmtree(target_doc_dir, True)
- shutil.copytree(cfg['doc_output_dir'], target_doc_dir)
+ shutil.rmtree(prepend_destdir(target_doc_dir), True)
+ shutil.copytree(cfg['doc_output_dir'], prepend_destdir(target_doc_dir))
for f in [f for f in os.listdir(cfg['doc_dir']) if f.endswith('.txt')]:
- copy_file(os.path.join(cfg['doc_dir'], f), os.path.join(target_doc_dir, f))
+ copy_file(os.path.join(cfg['doc_dir'], f), prepend_destdir(os.path.join(target_doc_dir, f)))
- copy_file(os.path.join(cfg['base_dir'], 'license.txt'), os.path.join(target_doc_dir, 'license.txt'))
- copy_file(os.path.join(cfg['base_dir'], 'news.rst'), os.path.join(target_doc_dir, 'news.txt'))
+ copy_file(os.path.join(cfg['base_dir'], 'license.txt'),
+ prepend_destdir(os.path.join(target_doc_dir, 'license.txt')))
+ copy_file(os.path.join(cfg['base_dir'], 'news.rst'),
+ prepend_destdir(os.path.join(target_doc_dir, 'news.txt')))
logging.info('Botan %s installation complete', cfg['version'])
return 0
diff --git a/src/scripts/python_uniitests.py b/src/scripts/python_unittests.py
index fff32e03f..fff32e03f 100755
--- a/src/scripts/python_uniitests.py
+++ b/src/scripts/python_unittests.py
diff --git a/src/scripts/python_unittests_unix.py b/src/scripts/python_unittests_unix.py
new file mode 100755
index 000000000..fe9f06a62
--- /dev/null
+++ b/src/scripts/python_unittests_unix.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+
+"""
+Unittests for Botan Python scripts. Those tests only need to pass un UNIX-like
+operating systems.
+
+Requires Python 3.
+
+(C) 2017 Simon Warta (Kullo GmbH)
+
+Botan is released under the Simplified BSD License (see license.txt)
+"""
+
+import os
+import sys
+import unittest
+
+sys.path.append("../..") # Botan repo root
+from install import prepend_destdir # pylint: disable=wrong-import-position
+from install import PrependDestdirError # pylint: disable=wrong-import-position
+
+
+class PrependDestdir(unittest.TestCase):
+ def test_absolute_destdir(self):
+ os.environ["DESTDIR"] = "/"
+ self.assertEqual(prepend_destdir("/home/me"), "/home/me")
+ self.assertEqual(prepend_destdir("/home/me/"), "/home/me")
+ self.assertEqual(prepend_destdir("/home/me/../me2"), "/home/me2")
+
+ os.environ["DESTDIR"] = "/opt"
+ self.assertEqual(prepend_destdir("/home/me"), "/opt/home/me")
+ self.assertEqual(prepend_destdir("/home/me/"), "/opt/home/me")
+ self.assertEqual(prepend_destdir("/home/me/../me2"), "/opt/home/me2")
+
+ def test_relative_destdir(self):
+ os.environ["DESTDIR"] = "."
+ self.assertEqual(prepend_destdir("/home/me"), "./home/me")
+ self.assertEqual(prepend_destdir("/home/me/"), "./home/me")
+ self.assertEqual(prepend_destdir("/home/me/../me2"), "./home/me2")
+
+ os.environ["DESTDIR"] = "bar"
+ self.assertEqual(prepend_destdir("/home/me"), "bar/home/me")
+ self.assertEqual(prepend_destdir("/home/me/"), "bar/home/me")
+ self.assertEqual(prepend_destdir("/home/me/../me2"), "bar/home/me2")
+
+ def test_relative(self):
+ # No destdir set
+ os.environ["DESTDIR"] = ""
+ self.assertEqual(prepend_destdir("foo"), "foo")
+ self.assertEqual(prepend_destdir("../foo"), "../foo")
+
+ # Destdir set
+ os.environ["DESTDIR"] = "/opt"
+ with self.assertRaises(PrependDestdirError):
+ prepend_destdir("foo")
+ with self.assertRaises(PrependDestdirError):
+ prepend_destdir("../foo")
+
+ def test_escaping(self):
+ os.environ["DESTDIR"] = "/opt"
+ with self.assertRaises(PrependDestdirError):
+ prepend_destdir("/foo/../..")
+
+
+if __name__ == '__main__':
+ unittest.TestCase.longMessage = True
+ unittest.main()