mirror of
https://github.com/audacity/linuxdeploy.git
synced 2026-04-16 21:51:43 -05:00
Support for AppRun hooks installed by plugins, mk. 1
This commit is contained in:
@@ -15,6 +15,9 @@ namespace linuxdeploy {
|
||||
|
||||
|
||||
class AppDirRootSetup::Private {
|
||||
public:
|
||||
static constexpr auto APPRUN_HOOKS_DIRNAME = "apprun-hooks";
|
||||
|
||||
public:
|
||||
const AppDir& appDir;
|
||||
|
||||
@@ -137,6 +140,94 @@ namespace linuxdeploy {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool deployAppRunWrapperIfNecessary() const {
|
||||
const bf::path appRunPath(appDir.path() / "AppRun");
|
||||
const bf::path wrappedAppRunPath(appRunPath.string() + ".wrapped");
|
||||
|
||||
const bf::path appRunHooksPath(appDir.path() / APPRUN_HOOKS_DIRNAME);
|
||||
|
||||
// first, we check whether there's that special directory containing hooks
|
||||
if (!bf::is_directory(appRunHooksPath)) {
|
||||
ldLog() << LD_DEBUG << "Could not find apprun-hooks dir, no need to deploy the AppRun wrapper" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
// if there's no files in there we don't have to do anything
|
||||
bf::directory_iterator firstRegularFile = std::find_if(
|
||||
bf::directory_iterator(appRunHooksPath),
|
||||
bf::directory_iterator{},
|
||||
[](const bf::path& p) {
|
||||
return bf::is_regular_file(p);
|
||||
}
|
||||
);
|
||||
if (firstRegularFile == bf::directory_iterator{}) {
|
||||
ldLog() << LD_WARNING << "Found an empty apprun-hooks directory, assuming there is no need to deploy the AppRun wrapper" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
// any file within that directory is considered to be a script
|
||||
// we can't perform any validity checks, that would be way too much complexity and even tools which
|
||||
// claim they can, like e.g., shellcheck, aren't perfect, they only aid in avoiding bugs but cannot
|
||||
// prevent them completely
|
||||
|
||||
// let's put together the wrapper script's contents
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << "#! /usr/bin/env bash" << std::endl
|
||||
<< std::endl
|
||||
<< "# autogenerated by linuxdeploy" << std::endl
|
||||
<< std::endl
|
||||
<< "export APPDIR=${APPDIR:-$(readlink -f $(dirname \"$0\"))}" << std::endl
|
||||
<< std::endl;
|
||||
|
||||
std::for_each(bf::directory_iterator(appRunHooksPath), bf::directory_iterator{}, [&oss](const bf::path& p) {
|
||||
if (!bf::is_regular_file(p))
|
||||
return;
|
||||
|
||||
oss << "source \"$APPDIR\"/" << APPRUN_HOOKS_DIRNAME << "/" << p.filename();
|
||||
});
|
||||
|
||||
oss << std::endl
|
||||
<< "exec \"$APPDIR\"/AppRun.wrapped" << std::endl;
|
||||
|
||||
// first we need to make sure we're not running this more than once
|
||||
// this might cause more harm than good
|
||||
// we require the user to clean up the mess at first
|
||||
// FIXME: try to find a way how to rewrap AppRun on subsequent runs or, even better, become idempotent
|
||||
if (bf::exists(wrappedAppRunPath)) {
|
||||
ldLog() << LD_WARNING << "Already found wrapped AppRun, using existing file/symlink" << std::endl;
|
||||
}
|
||||
|
||||
// in case the above check triggered a warning, it's possible that there is another AppRun in the AppDir
|
||||
// this one has to be cleaned up in that case
|
||||
if (bf::exists(appRunPath)) {
|
||||
ldLog() << LD_WARNING << "Found an AppRun file/symlink, possibly due to re-run of linuxdeploy, "
|
||||
"overwriting" << std::endl;
|
||||
bf::remove(appRunPath);
|
||||
}
|
||||
|
||||
// backup original AppRun
|
||||
bf::rename(appRunPath, wrappedAppRunPath);
|
||||
|
||||
|
||||
// install new script
|
||||
std::ofstream ofs(appRunPath.string());
|
||||
ofs << oss.str();
|
||||
|
||||
// make sure data is written to disk
|
||||
ofs.flush();
|
||||
ofs.close();
|
||||
|
||||
// make new file executable
|
||||
bf::permissions(appRunPath,
|
||||
bf::perms::owner_all | bf::perms::group_read | bf::perms::others_read |
|
||||
bf::perms::group_exe | bf::perms::others_exe
|
||||
);
|
||||
|
||||
// we're done!
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
AppDirRootSetup::AppDirRootSetup(const AppDir& appDir) : d(new Private(appDir)) {}
|
||||
@@ -160,6 +251,15 @@ namespace linuxdeploy {
|
||||
return false;
|
||||
}
|
||||
|
||||
// plugins might need to run some initializing code to make certain features work
|
||||
// these involve setting environment variables because libraries or frameworks don't support any other
|
||||
// way of pointing them to resources inside the AppDir instead of looking into config files in locations
|
||||
// inside the AppImage, etc.
|
||||
// the linuxdeploy plugin specification states that if plugins put files into a specified directory in
|
||||
// the AppImage, linuxdeploy will make sure they're run before running the regular AppRun
|
||||
if (!d->deployAppRunWrapperIfNecessary())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user