Newer
Older
from collections import OrderedDict
from textwrap import dedent
from ..util import is_installed, get_installed_build
def __init__(self, build, script, config, from_binary_archives=False):
name = "install" if not from_binary_archives else "install from binary archives"
super().__init__(name, build, script, config)
self.from_binary_archives = from_binary_archives
def _run(self, show_output=False, args=None):
environment = self.config.global_env()
tmp_root = environment["TMP_ROOT"]
orchestra_root = environment['ORCHESTRA_ROOT']
logging.info("Preparing temporary root directory")
pre_file_list = self._index_directory(tmp_root + orchestra_root, strip_prefix=tmp_root + orchestra_root)
if self.from_binary_archives:
self._install_from_binary_archives()
else:
self._install(show_output)
self._post_install(show_output)
post_file_list = self._index_directory(tmp_root + orchestra_root, strip_prefix=tmp_root + orchestra_root)
new_files = [f for f in post_file_list if f not in pre_file_list]
archive_name = self.build.binary_archive_filename
archive_path = os.path.join(self.environment["BINARY_ARCHIVES"], archive_name)
if args.create_binary_archives and not os.path.exists(archive_path):
logging.info("Creating binary archive")
self._create_binary_archive()
if not args.no_merge:
self._uninstall_currently_installed_build(show_output)
logging.info("Merging installation into Orchestra root directory")
self._merge(show_output)
# Write file index
os.makedirs(self.config.component_index_dir(), exist_ok=True)
installed_component_path = self.config.component_index_path(self.build.component.name)
with open(installed_component_path, "w") as f:
f.truncate(0)
f.write(self.build.qualified_name + "\n")
f.write("\n".join(new_files))
def _is_satisfied(self):
return is_installed(self.config, self.build.component.name, wanted_build=self.build.name)
rm -rf "$TMP_ROOT"
mkdir -p "$TMP_ROOT"
mkdir -p "${TMP_ROOT}${ORCHESTRA_ROOT}/include"
mkdir -p "${TMP_ROOT}${ORCHESTRA_ROOT}/lib64"{,/include,/pkgconfig}
test -e "${TMP_ROOT}${ORCHESTRA_ROOT}/lib" || ln -s lib64 "${TMP_ROOT}${ORCHESTRA_ROOT}/lib"
test -L "${TMP_ROOT}${ORCHESTRA_ROOT}/lib"
mkdir -p "${TMP_ROOT}${ORCHESTRA_ROOT}/bin"
mkdir -p "${TMP_ROOT}${ORCHESTRA_ROOT}/usr/"{lib,include}
mkdir -p "${TMP_ROOT}${ORCHESTRA_ROOT}/share/"{info,doc,man}
touch "${TMP_ROOT}${ORCHESTRA_ROOT}/share/info/dir"
mkdir -p "${TMP_ROOT}${ORCHESTRA_ROOT}/libexec"
""")
run_script(script, environment=self.environment)
def _install(self, show_output):
logging.info("Executing install script")
run_script(self.script, show_output=show_output, environment=self.environment)
def _post_install(self, show_output):
# TODO: maybe this should be put into the configuration and not in Orchestra itself
logging.info("Converting hardlinks to symbolic")
self._hard_to_symbolic(show_output)
# TODO: maybe this should be put into the configuration and not in Orchestra itself
logging.info("Fixing RPATHs")
self._fix_rpath(show_output)
# TODO: this should be put into the configuration and not in Orchestra itself
logging.info("Replacing NDEBUG preprocessor statements")
self._replace_ndebug(True, show_output)
def _hard_to_symbolic(self, show_output):
hard_to_symbolic = """hard-to-symbolic.py "${TMP_ROOT}${ORCHESTRA_ROOT}" """
run_script(hard_to_symbolic, show_output=show_output, environment=self.environment)
def _fix_rpath(self, show_output):
fix_rpath_script = dedent(f"""
cd "$TMP_ROOT$ORCHESTRA_ROOT"
# Fix rpath
find . -type f -executable | while read EXECUTABLE; do
if head -c 4 "$EXECUTABLE" | grep '^.ELF' > /dev/null &&
file "$EXECUTABLE" | grep x86-64 | grep -E '(shared|dynamic)' > /dev/null;
then
REPLACE='$'ORIGIN/$(realpath --relative-to="$(dirname "$EXECUTABLE")" ".")
echo "Setting rpath of $EXECUTABLE to $REPLACE"
elf-replace-dynstr.py "$EXECUTABLE" "$RPATH_PLACEHOLDER" "$REPLACE" /
elf-replace-dynstr.py "$EXECUTABLE" "$ORCHESTRA_ROOT" "$REPLACE" /
fi
done
""")
run_script(fix_rpath_script, show_output=show_output, environment=self.environment)
def _replace_ndebug(self, enable_debugging, show_output):
debug, ndebug = ("1", "0") if enable_debugging else ("0", "1")
patch_ndebug_script = dedent(rf"""
cd "$TMP_ROOT$ORCHESTRA_ROOT"
find include/ -name "*.h" \
-exec \
sed -i \
-e 's|^\s*#\s*ifndef\s\+NDEBUG|#if {debug}|' \
-e 's|^\s*#\s*ifdef\s\+NDEBUG|#if {ndebug}|' \
-e 's|^\(\s*#\s*if\s\+.*\)!defined(NDEBUG)|\1{debug}|' \
-e 's|^\(\s*#\s*if\s\+.*\)defined(NDEBUG)|\1{ndebug}|' \
{"{}"} ';'
run_script(patch_ndebug_script, show_output=show_output, environment=self.environment)
def _uninstall_currently_installed_build(self, show_output):
installed_build = get_installed_build(self.build.component.name, self.config)
if installed_build is None:
logging.info("Uninstalling previously installed build")
uninstall(self.build.component.name, self.config)
copy_command = f'cp -farl "$TMP_ROOT/$ORCHESTRA_ROOT/." "$ORCHESTRA_ROOT"'
run_script(copy_command, show_output=show_output, environment=self.environment)
def _create_binary_archive(self):
archive_name = self.build.binary_archive_filename
script = dedent(f"""
mkdir -p "$BINARY_ARCHIVES"
cd "$TMP_ROOT$ORCHESTRA_ROOT"
tar caf "$BINARY_ARCHIVES/{archive_name}" --owner=0 --group=0 "."
""")
run_script(script, show_output=True, environment=self.environment)
def _install_from_binary_archives(self):
archives_dir = self.environment["BINARY_ARCHIVES"]
archive_filepath = os.path.join(archives_dir, self.build.binary_archive_filename)
if not os.path.exists(archive_filepath):
raise Exception("Binary archive not found!")
script = dedent(f"""
mkdir -p "$TMP_ROOT$ORCHESTRA_ROOT"
cd "$TMP_ROOT$ORCHESTRA_ROOT"
tar xaf "{archive_filepath}"
""")
run_script(script, environment=self.environment)
@staticmethod
def _index_directory(dirpath, strip_prefix=None):
paths = list(glob.glob(f"{dirpath}/**", recursive=True))
if strip_prefix:
paths = [remove_prefix(p, strip_prefix) for p in paths]
@property
def environment(self) -> OrderedDict:
env = super().environment
env["DESTDIR"] = env["TMP_ROOT"]
return env
def _implicit_dependencies(self):
if self.from_binary_archives:
return set()
else:
return {self.build.configure}
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
class InstallAnyBuildAction(Action):
def __init__(self, build, config):
installed_build_name = get_installed_build(build.component.name, config)
if installed_build_name:
chosen_build = build.component.builds[installed_build_name]
else:
chosen_build = build
super().__init__("install any", chosen_build, None, config)
self._original_build = build
def _implicit_dependencies(self):
return {self.build.install}
def _run(self, show_output=False, args=None):
return
def is_satisfied(self, recursively=False, already_checked=None):
return self.build.install.is_satisfied(recursively=recursively, already_checked=already_checked)
def _is_satisfied(self):
raise NotImplementedError("This method should not be called!")
@property
def name_for_graph(self):
if self.build == self._original_build:
return f"install {self.build.component.name} (prefer {self._original_build.name})"
else:
return f"install {self.build.component.name} (prefer {self._original_build.name}, chosen {self.build.name})"
@property
def name_for_components(self):
return f"{self._original_build.component.name}~{self._original_build.name}"
def remove_prefix(string, prefix):
if string.startswith(prefix):
return string[len(prefix):]
else:
return string[:]
def uninstall(component_name, config):
index_path = config.component_index_path(component_name)
with open(index_path) as f:
f.readline()
paths = f.readlines()
# Ensure depth first visit by reverse-sorting
paths.sort(reverse=True)
paths = [path.strip() for path in paths]
for path in paths:
path = path.lstrip("/")
path_to_delete = os.path.join(config.global_env()['ORCHESTRA_ROOT'], path)
if os.path.isfile(path_to_delete) or os.path.islink(path_to_delete):
logging.debug(f"Deleting {path_to_delete}")
os.remove(path_to_delete)
elif os.path.isdir(path_to_delete):
if os.listdir(path_to_delete):
logging.debug(f"Not removing directory {path_to_delete} as it is not empty")
else:
logging.debug(f"Deleting directory {path_to_delete}")
os.rmdir(path_to_delete)
logging.debug(f"Deleting index file {index_path}")
os.remove(index_path)