diff options
author | Jack Lloyd <[email protected]> | 2017-08-07 11:46:50 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2017-08-07 11:46:50 -0400 |
commit | 01317855dc2e076050277073ac40c308ad7a4da5 (patch) | |
tree | f5b5dcc4589eace863f0cd872f81c0726afb82bf /src | |
parent | 453fde9b740754b45b5820e0ad3bf1a836792718 (diff) | |
parent | 53d1b0faf2d264e03933b2f1e578ff19c6209aa3 (diff) |
Merge GH #1139 Replace --destdir flag with DESTDIR env variable
Diffstat (limited to 'src')
-rw-r--r-- | src/build-data/makefile/gmake.in | 2 | ||||
-rw-r--r-- | src/build-data/makefile/header.in | 2 | ||||
-rw-r--r-- | src/build-data/makefile/nmake.in | 2 | ||||
-rwxr-xr-x | src/scripts/ci/travis/lint.sh | 6 | ||||
-rwxr-xr-x | src/scripts/install.py | 90 | ||||
-rwxr-xr-x | src/scripts/python_unittests.py (renamed from src/scripts/python_uniitests.py) | 0 | ||||
-rwxr-xr-x | src/scripts/python_unittests_unix.py | 67 |
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() |