aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
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/install.py100
-rwxr-xr-xsrc/scripts/python_uniitests.py31
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()