diff options
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/install.py | 100 | ||||
-rwxr-xr-x | src/scripts/python_uniitests.py | 31 |
5 files changed, 108 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/install.py b/src/scripts/install.py index 601502657..1875bd62d 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,53 @@ def parse_command_line(args): return (options, args) + +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 cannot join all prefix paths. + + #These will be rejected via an exception: + # C:/foo + # C:foo + # \\foo (Python >3.1 only) + # \\foo\bar (Python >3.1 only) + # ../somewhere/else + + #These will be normalized to a relative path and joined with DESTDIR: + # /absolute/dir + # relative/dir + # /dir/with/../inside + # ./relative/to/me + # ~/botan-install-test + + # ".." makes no sense, as it would certainly escape the DESTDIR prefix + if path.startswith(".."): + raise Exception('With DESTDIR set, a prefix starting in ".." would escape the destdir. Aborting.') + + # Will only trigger on Windows, see the splitdrive() doc for details + drive, _ = os.path.splitdrive(path) + if drive != "": + raise Exception('DESTDIR set, but drive or UNC detected in prefix path. Aborting.') + + # resolved ~, ~user + path = os.path.expanduser(path) + # native slashes, ".." inside (not in front of) pathes normalized + 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) + + return path + + def makedirs(dirname, exist_ok=True): try: logging.debug('Creating directory %s' % (dirname)) @@ -104,8 +151,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 +176,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 +192,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 +201,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 +254,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_uniitests.py index fff32e03f..c804fae83 100755 --- a/src/scripts/python_uniitests.py +++ b/src/scripts/python_uniitests.py @@ -10,13 +10,14 @@ Requires Python 3. Botan is released under the Simplified BSD License (see license.txt) """ +import os import sys import unittest sys.path.append("../..") # Botan repo root from configure import CompilerDetector # pylint: disable=wrong-import-position from configure import ModulesChooser # pylint: disable=wrong-import-position - +from install import prepend_destdir # pylint: disable=wrong-import-position class CompilerDetection(unittest.TestCase): @@ -269,6 +270,34 @@ class ModulesChooserResolveDependencies(unittest.TestCase): self.assertEqual(modules, set(["G", "A", "C", "E"])) +class PrependDestdir(unittest.TestCase): + def test_base(self): + os.environ["DESTDIR"] = "/" + self.assertEqual(prepend_destdir("/home/me"), "/home/me") + self.assertEqual(prepend_destdir("relative_path"), "/relative_path") + self.assertEqual(prepend_destdir("./relative_path"), "/relative_path") + self.assertEqual(prepend_destdir("relative/sub"), "/relative/sub") + + self.assertEqual(prepend_destdir("/home/me/"), "/home/me") + self.assertEqual(prepend_destdir("relative_path/"), "/relative_path") + + self.assertEqual(prepend_destdir("/home/me/../me2"), "/home/me2") + self.assertEqual(prepend_destdir("relative/sub/../sub2"), "/relative/sub2") + + os.environ["DESTDIR"] = "/opt" + self.assertEqual(prepend_destdir("/home/me"), "/opt/home/me") + self.assertEqual(prepend_destdir("relative_path"), "/opt/relative_path") + self.assertEqual(prepend_destdir("./relative_path"), "/opt/relative_path") + self.assertEqual(prepend_destdir("relative/sub"), "/opt/relative/sub") + + self.assertEqual(prepend_destdir("/home/me/"), "/opt/home/me") + self.assertEqual(prepend_destdir("relative_path/"), "/opt/relative_path") + + self.assertEqual(prepend_destdir("/home/me/../me2"), "/opt/home/me2") + self.assertEqual(prepend_destdir("relative/sub/../sub2"), "/opt/relative/sub2") + + + if __name__ == '__main__': unittest.TestCase.longMessage = True unittest.main() |