mirror of
https://github.com/audacity/linuxdeploy.git
synced 2026-04-13 15:19:49 -05:00
Merge pull request #87 from linuxdeploy/apprun-hooks
AppRun hooks for plugins
This commit is contained in:
@@ -39,7 +39,7 @@ namespace linuxdeploy {
|
||||
explicit AppDir(const std::string& path);
|
||||
|
||||
// creates basic directory structure of an AppDir in "FHS" mode
|
||||
bool createBasicStructure();
|
||||
bool createBasicStructure() const;
|
||||
|
||||
// deploy shared library
|
||||
//
|
||||
@@ -66,39 +66,42 @@ namespace linuxdeploy {
|
||||
// deploy arbitrary file
|
||||
boost::filesystem::path deployFile(const boost::filesystem::path& from, const boost::filesystem::path& to);
|
||||
|
||||
// copy arbitrary file (immediately)
|
||||
bool copyFile(const boost::filesystem::path& from, const boost::filesystem::path& to, bool overwrite = false) const;
|
||||
|
||||
// create an <AppDir> relative symlink to <target> at <symlink>.
|
||||
bool createRelativeSymlink(const boost::filesystem::path& target, const boost::filesystem::path& symlink);
|
||||
bool createRelativeSymlink(const boost::filesystem::path& target, const boost::filesystem::path& symlink) const;
|
||||
|
||||
// execute deferred copy operations
|
||||
bool executeDeferredOperations();
|
||||
|
||||
// return path to AppDir
|
||||
boost::filesystem::path path();
|
||||
boost::filesystem::path path() const;
|
||||
|
||||
// create a list of all icon paths in the AppDir
|
||||
std::vector<boost::filesystem::path> deployedIconPaths();
|
||||
std::vector<boost::filesystem::path> deployedIconPaths() const;
|
||||
|
||||
// create a list of all executable paths in the AppDir
|
||||
std::vector<boost::filesystem::path> deployedExecutablePaths();
|
||||
std::vector<boost::filesystem::path> deployedExecutablePaths() const;
|
||||
|
||||
// create a list of all desktop file paths in the AppDir
|
||||
std::vector<desktopfile::DesktopFile> deployedDesktopFiles();
|
||||
std::vector<desktopfile::DesktopFile> deployedDesktopFiles() const;
|
||||
|
||||
// create symlinks for AppRun, desktop file and icon in the AppDir root directory
|
||||
bool createLinksInAppDirRoot(const desktopfile::DesktopFile& desktopFile, boost::filesystem::path customAppRunPath = "");
|
||||
bool setUpAppDirRoot(const desktopfile::DesktopFile& desktopFile, boost::filesystem::path customAppRunPath = "");
|
||||
|
||||
// list all executables in <AppDir>/usr/bin
|
||||
// this function does not perform a recursive search, but only searches the bin directory
|
||||
std::vector<boost::filesystem::path> listExecutables();
|
||||
std::vector<boost::filesystem::path> listExecutables() const;
|
||||
|
||||
// list all shared libraries in <AppDir>/usr/lib
|
||||
// this function recursively searches the entire lib directory for shared libraries
|
||||
std::vector<boost::filesystem::path> listSharedLibraries();
|
||||
std::vector<boost::filesystem::path> listSharedLibraries() const;
|
||||
|
||||
// search for executables and libraries and deploy their dependencies
|
||||
// calling this function can turn sure file trees created by make install commands into working
|
||||
// AppDirs
|
||||
bool deployDependenciesForExistingFiles();
|
||||
bool deployDependenciesForExistingFiles() const;
|
||||
|
||||
// disable deployment of copyright files for this instance
|
||||
void setDisableCopyrightFilesDeployment(bool disable);
|
||||
|
||||
@@ -79,8 +79,8 @@ namespace linuxdeploy {
|
||||
|
||||
try {
|
||||
desktopfile::DesktopFile desktopFile = getMainDesktopFile(desktopFilePaths, deployedDesktopFiles);
|
||||
ldLog() << "Deploying desktop file:" << desktopFile.path() << std::endl;
|
||||
return appDir.createLinksInAppDirRoot(desktopFile, customAppRunPath);
|
||||
ldLog() << "Deploying files to AppDir root using desktop file:" << desktopFile.path() << std::endl;
|
||||
return appDir.setUpAppDirRoot(desktopFile, customAppRunPath);
|
||||
} catch (const DeployError& er) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ target_link_libraries(linuxdeploy_core_log PUBLIC ${BOOST_LIBS})
|
||||
|
||||
add_subdirectory(copyright)
|
||||
|
||||
add_library(linuxdeploy_core STATIC elf.cpp appdir.cpp ${HEADERS})
|
||||
add_library(linuxdeploy_core STATIC elf.cpp appdir.cpp ${HEADERS} appdir_root_setup.cpp)
|
||||
target_link_libraries(linuxdeploy_core PUBLIC
|
||||
linuxdeploy_plugin linuxdeploy_core_log linuxdeploy_util linuxdeploy_desktopfile_static
|
||||
${BOOST_LIBS} CImg ${CMAKE_THREAD_LIBS_INIT}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
// auto-generated headers
|
||||
#include "excludelist.h"
|
||||
#include "appdir_root_setup.h"
|
||||
|
||||
using namespace linuxdeploy::core;
|
||||
using namespace linuxdeploy::desktopfile;
|
||||
@@ -81,7 +82,7 @@ namespace linuxdeploy {
|
||||
|
||||
// actually copy file
|
||||
// mimics cp command behavior
|
||||
bool copyFile(const bf::path& from, bf::path to, bool overwrite = false) {
|
||||
static bool copyFile(const bf::path& from, bf::path to, bool overwrite = false) {
|
||||
ldLog() << "Copying file" << from << "to" << to << std::endl;
|
||||
|
||||
try {
|
||||
@@ -559,7 +560,7 @@ namespace linuxdeploy {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isInDebugSymbolsLocation(const bf::path& path) {
|
||||
static bool isInDebugSymbolsLocation(const bf::path& path) {
|
||||
// TODO: check if there's more potential locations for debug symbol files
|
||||
for (const std::string& dbgSymbolsPrefix : {".debug/"}) {
|
||||
if (path.string().substr(0, dbgSymbolsPrefix.size()) == dbgSymbolsPrefix)
|
||||
@@ -578,7 +579,7 @@ namespace linuxdeploy {
|
||||
|
||||
AppDir::AppDir(const std::string& path) : AppDir(bf::path(path)) {}
|
||||
|
||||
bool AppDir::createBasicStructure() {
|
||||
bool AppDir::createBasicStructure() const {
|
||||
std::vector<std::string> dirPaths = {
|
||||
"usr/bin/",
|
||||
"usr/lib/",
|
||||
@@ -635,7 +636,7 @@ namespace linuxdeploy {
|
||||
return d->executeDeferredOperations();
|
||||
}
|
||||
|
||||
boost::filesystem::path AppDir::path() {
|
||||
boost::filesystem::path AppDir::path() const {
|
||||
return d->appDirPath;
|
||||
}
|
||||
|
||||
@@ -665,7 +666,7 @@ namespace linuxdeploy {
|
||||
return foundPaths;
|
||||
}
|
||||
|
||||
std::vector<bf::path> AppDir::deployedIconPaths() {
|
||||
std::vector<bf::path> AppDir::deployedIconPaths() const {
|
||||
auto icons = listFilesInDirectory(path() / "usr/share/icons/");
|
||||
auto pixmaps = listFilesInDirectory(path() / "usr/share/pixmaps/", false);
|
||||
icons.reserve(pixmaps.size());
|
||||
@@ -673,11 +674,11 @@ namespace linuxdeploy {
|
||||
return icons;
|
||||
}
|
||||
|
||||
std::vector<bf::path> AppDir::deployedExecutablePaths() {
|
||||
std::vector<bf::path> AppDir::deployedExecutablePaths() const {
|
||||
return listFilesInDirectory(path() / "usr/bin/", false);
|
||||
}
|
||||
|
||||
std::vector<DesktopFile> AppDir::deployedDesktopFiles() {
|
||||
std::vector<DesktopFile> AppDir::deployedDesktopFiles() const {
|
||||
std::vector<DesktopFile> desktopFiles;
|
||||
|
||||
auto paths = listFilesInDirectory(path() / "usr/share/applications/", false);
|
||||
@@ -692,131 +693,24 @@ namespace linuxdeploy {
|
||||
return desktopFiles;
|
||||
}
|
||||
|
||||
bool AppDir::createLinksInAppDirRoot(const DesktopFile& desktopFile, boost::filesystem::path customAppRunPath) {
|
||||
ldLog() << "Deploying desktop file to AppDir root:" << desktopFile.path() << std::endl;
|
||||
|
||||
// copy desktop file to root directory
|
||||
if (!d->symlinkFile(desktopFile.path(), path())) {
|
||||
ldLog() << LD_ERROR << "Failed to create link to desktop file in AppDir root:" << desktopFile.path() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// look for suitable icon
|
||||
DesktopFileEntry iconEntry;
|
||||
|
||||
if (!desktopFile.getEntry("Desktop Entry", "Icon", iconEntry)) {
|
||||
ldLog() << LD_ERROR << "Icon entry missing in desktop file:" << desktopFile.path() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool iconDeployed = false;
|
||||
|
||||
const auto foundIconPaths = deployedIconPaths();
|
||||
|
||||
if (foundIconPaths.empty()) {
|
||||
ldLog() << LD_ERROR << "Could not find icon executable for Icon entry:" << iconEntry.value() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& iconPath : foundIconPaths) {
|
||||
ldLog() << LD_DEBUG << "Icon found:" << iconPath << std::endl;
|
||||
|
||||
const bool matchesFilenameWithExtension = iconPath.filename() == iconEntry.value();
|
||||
|
||||
if (iconPath.stem() == iconEntry.value() || matchesFilenameWithExtension) {
|
||||
if (matchesFilenameWithExtension) {
|
||||
ldLog() << LD_WARNING << "Icon= entry filename contains extension" << std::endl;
|
||||
}
|
||||
|
||||
ldLog() << "Deploying icon to AppDir root:" << iconPath << std::endl;
|
||||
|
||||
if (!d->symlinkFile(iconPath, path())) {
|
||||
ldLog() << LD_ERROR << "Failed to create symlink for icon in AppDir root:" << iconPath << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
iconDeployed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!iconDeployed) {
|
||||
ldLog() << LD_ERROR << "Could not find suitable icon for Icon entry:" << iconEntry.value() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!customAppRunPath.empty()) {
|
||||
// copy custom AppRun executable
|
||||
// FIXME: make sure this file is executable
|
||||
ldLog() << "Deploying custom AppRun:" << customAppRunPath;
|
||||
|
||||
if (!d->copyFile(customAppRunPath, path() / "AppRun"))
|
||||
return false;
|
||||
} else {
|
||||
// check if there is a custom AppRun already
|
||||
// in that case, skip deployment of symlink
|
||||
if (bf::exists(path() / "AppRun")) {
|
||||
ldLog() << LD_WARNING << "Custom AppRun detected, skipping deployment of symlink" << std::endl;
|
||||
} else {
|
||||
// look for suitable binary to create AppRun symlink
|
||||
DesktopFileEntry executableEntry;
|
||||
|
||||
if (!desktopFile.getEntry("Desktop Entry", "Exec", executableEntry)) {
|
||||
ldLog() << LD_ERROR << "Exec entry missing in desktop file:" << desktopFile.path()
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto executableName = util::split(executableEntry.value())[0];
|
||||
|
||||
const auto foundExecutablePaths = deployedExecutablePaths();
|
||||
|
||||
if (foundExecutablePaths.empty()) {
|
||||
ldLog() << LD_ERROR << "Could not find suitable executable for Exec entry:" << executableName
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool deployedExecutable = false;
|
||||
|
||||
for (const auto& executablePath : foundExecutablePaths) {
|
||||
ldLog() << LD_DEBUG << "Executable found:" << executablePath << std::endl;
|
||||
|
||||
if (executablePath.filename() == executableName) {
|
||||
ldLog() << "Deploying AppRun symlink for executable in AppDir root:" << executablePath
|
||||
<< std::endl;
|
||||
|
||||
if (!d->symlinkFile(executablePath, path() / "AppRun")) {
|
||||
ldLog() << LD_ERROR
|
||||
<< "Failed to create AppRun symlink for executable in AppDir root:"
|
||||
<< executablePath << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
deployedExecutable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!deployedExecutable) {
|
||||
ldLog() << LD_ERROR << "Could not deploy symlink for executable: could not find suitable executable for Exec entry:" << executableName << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
bool AppDir::setUpAppDirRoot(const DesktopFile& desktopFile, boost::filesystem::path customAppRunPath) {
|
||||
AppDirRootSetup setup(*this);
|
||||
setup.run(desktopFile, customAppRunPath);
|
||||
}
|
||||
|
||||
bf::path AppDir::deployFile(const boost::filesystem::path& from, const boost::filesystem::path& to) {
|
||||
return d->deployFile(from, to, true);
|
||||
}
|
||||
|
||||
bool AppDir::createRelativeSymlink(const bf::path& target, const bf::path& symlink) {
|
||||
bool AppDir::copyFile(const bf::path& from, const bf::path& to, bool overwrite) const {
|
||||
return d->copyFile(from, to, overwrite);
|
||||
}
|
||||
|
||||
bool AppDir::createRelativeSymlink(const bf::path& target, const bf::path& symlink) const {
|
||||
return d->symlinkFile(target, symlink, true);
|
||||
}
|
||||
|
||||
std::vector<bf::path> AppDir::listExecutables() {
|
||||
std::vector<bf::path> AppDir::listExecutables() const {
|
||||
std::vector<bf::path> executables;
|
||||
|
||||
for (const auto& file : listFilesInDirectory(path() / "usr" / "bin", false)) {
|
||||
@@ -834,7 +728,7 @@ namespace linuxdeploy {
|
||||
return executables;
|
||||
}
|
||||
|
||||
std::vector<bf::path> AppDir::listSharedLibraries() {
|
||||
std::vector<bf::path> AppDir::listSharedLibraries() const {
|
||||
std::vector<bf::path> sharedLibraries;
|
||||
|
||||
for (const auto& file : listFilesInDirectory(path() / "usr" / "lib", true)) {
|
||||
@@ -856,7 +750,7 @@ namespace linuxdeploy {
|
||||
return sharedLibraries;
|
||||
}
|
||||
|
||||
bool AppDir::deployDependenciesForExistingFiles() {
|
||||
bool AppDir::deployDependenciesForExistingFiles() const {
|
||||
for (const auto& executable : listExecutables()) {
|
||||
if (bf::is_symlink(executable))
|
||||
continue;
|
||||
|
||||
272
src/core/appdir_root_setup.cpp
Normal file
272
src/core/appdir_root_setup.cpp
Normal file
@@ -0,0 +1,272 @@
|
||||
// local headers
|
||||
#include <linuxdeploy/util/util.h>
|
||||
#include <linuxdeploy/core/log.h>
|
||||
#include "appdir_root_setup.h"
|
||||
|
||||
|
||||
namespace bf = boost::filesystem;
|
||||
|
||||
namespace linuxdeploy {
|
||||
using namespace desktopfile;
|
||||
|
||||
namespace core {
|
||||
using namespace appdir;
|
||||
using namespace log;
|
||||
|
||||
|
||||
class AppDirRootSetup::Private {
|
||||
public:
|
||||
static constexpr auto APPRUN_HOOKS_DIRNAME = "apprun-hooks";
|
||||
|
||||
public:
|
||||
const AppDir& appDir;
|
||||
|
||||
public:
|
||||
explicit Private(const AppDir& appDir) : appDir(appDir) {}
|
||||
|
||||
public:
|
||||
bool deployDesktopFileAndIcon(const DesktopFile& desktopFile) const {
|
||||
ldLog() << "Deploying desktop file to AppDir root:" << desktopFile.path() << std::endl;
|
||||
|
||||
// copy desktop file to root directory
|
||||
if (!appDir.createRelativeSymlink(desktopFile.path(), appDir.path())) {
|
||||
ldLog() << LD_ERROR << "Failed to create link to desktop file in AppDir root:" << desktopFile.path() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// look for suitable icon
|
||||
DesktopFileEntry iconEntry;
|
||||
|
||||
if (!desktopFile.getEntry("Desktop Entry", "Icon", iconEntry)) {
|
||||
ldLog() << LD_ERROR << "Icon entry missing in desktop file:" << desktopFile.path() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool iconDeployed = false;
|
||||
|
||||
const auto foundIconPaths = appDir.deployedIconPaths();
|
||||
|
||||
if (foundIconPaths.empty()) {
|
||||
ldLog() << LD_ERROR << "Could not find icon executable for Icon entry:" << iconEntry.value() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& iconPath : foundIconPaths) {
|
||||
ldLog() << LD_DEBUG << "Icon found:" << iconPath << std::endl;
|
||||
|
||||
const bool matchesFilenameWithExtension = iconPath.filename() == iconEntry.value();
|
||||
|
||||
if (iconPath.stem() == iconEntry.value() || matchesFilenameWithExtension) {
|
||||
if (matchesFilenameWithExtension) {
|
||||
ldLog() << LD_WARNING << "Icon= entry filename contains extension" << std::endl;
|
||||
}
|
||||
|
||||
ldLog() << "Deploying icon to AppDir root:" << iconPath << std::endl;
|
||||
|
||||
if (!appDir.createRelativeSymlink(iconPath, appDir.path())) {
|
||||
ldLog() << LD_ERROR << "Failed to create symlink for icon in AppDir root:" << iconPath << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
iconDeployed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!iconDeployed) {
|
||||
ldLog() << LD_ERROR << "Could not find suitable icon for Icon entry:" << iconEntry.value() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool deployCustomAppRunFile(const bf::path& customAppRunPath) const {
|
||||
// copy custom AppRun executable
|
||||
// FIXME: make sure this file is executable
|
||||
ldLog() << "Deploying custom AppRun:" << customAppRunPath;
|
||||
|
||||
if (!appDir.copyFile(customAppRunPath, appDir.path() / "AppRun"))
|
||||
return false;
|
||||
}
|
||||
|
||||
bool deployStandardAppRunFromDesktopFile(const DesktopFile& desktopFile, const bf::path& customAppRunPath) const {
|
||||
// check if there is a custom AppRun already
|
||||
// in that case, skip deployment of symlink
|
||||
if (bf::exists(appDir.path() / "AppRun")) {
|
||||
ldLog() << LD_WARNING << "Existing AppRun detected, skipping deployment of symlink" << std::endl;
|
||||
} else {
|
||||
// look for suitable binary to create AppRun symlink
|
||||
DesktopFileEntry executableEntry;
|
||||
|
||||
if (!desktopFile.getEntry("Desktop Entry", "Exec", executableEntry)) {
|
||||
ldLog() << LD_ERROR << "Exec entry missing in desktop file:" << desktopFile.path()
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto executableName = util::split(executableEntry.value())[0];
|
||||
|
||||
const auto foundExecutablePaths = appDir.deployedExecutablePaths();
|
||||
|
||||
if (foundExecutablePaths.empty()) {
|
||||
ldLog() << LD_ERROR << "Could not find suitable executable for Exec entry:" << executableName
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool deployedExecutable = false;
|
||||
|
||||
for (const auto& executablePath : foundExecutablePaths) {
|
||||
ldLog() << LD_DEBUG << "Executable found:" << executablePath << std::endl;
|
||||
|
||||
if (executablePath.filename() == executableName) {
|
||||
ldLog() << "Deploying AppRun symlink for executable in AppDir root:" << executablePath
|
||||
<< std::endl;
|
||||
|
||||
if (!appDir.createRelativeSymlink(executablePath, appDir.path() / "AppRun")) {
|
||||
ldLog() << LD_ERROR
|
||||
<< "Failed to create AppRun symlink for executable in AppDir root:"
|
||||
<< executablePath << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
deployedExecutable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!deployedExecutable) {
|
||||
ldLog() << LD_ERROR << "Could not deploy symlink for executable: could not find suitable executable for Exec entry:" << executableName << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
<< "# make sure errors in sourced scripts will cause this script to stop" << std::endl
|
||||
<< "set -e" << std::endl
|
||||
<< std::endl
|
||||
<< "this_dir=$(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 \"$this_dir\"/" << APPRUN_HOOKS_DIRNAME << "/" << p.filename();
|
||||
});
|
||||
|
||||
oss << std::endl
|
||||
<< "exec \"$this_dir\"/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;
|
||||
} else {
|
||||
// backup original AppRun
|
||||
bf::rename(appRunPath, wrappedAppRunPath);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
// 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)) {}
|
||||
|
||||
bool AppDirRootSetup::run(const DesktopFile& desktopFile, const bf::path& customAppRunPath) const {
|
||||
// first step that is always required is to deploy the desktop file and the corresponding icon
|
||||
if (!d->deployDesktopFileAndIcon(desktopFile))
|
||||
return false;
|
||||
|
||||
// the algorithm depends on whether the user wishes to deploy their own AppRun file
|
||||
// in case they do, the algorithm shall deploy that file
|
||||
// otherwise, the standard algorithm shall be run which takes information from the desktop file to
|
||||
// deploy a symlink pointing to the AppImage's main binary
|
||||
// this allows power users to define their own AppImage initialization steps or run different binaries
|
||||
// based on parameters etc.
|
||||
if (!customAppRunPath.empty()) {
|
||||
if (!d->deployCustomAppRunFile(customAppRunPath))
|
||||
return false;
|
||||
} else {
|
||||
if (!d->deployStandardAppRunFromDesktopFile(desktopFile, customAppRunPath))
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
36
src/core/appdir_root_setup.h
Normal file
36
src/core/appdir_root_setup.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
// system headers
|
||||
#include <memory>
|
||||
|
||||
// local headers
|
||||
#include "linuxdeploy/core/appdir.h"
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace core {
|
||||
/**
|
||||
* Wrapper for an AppDir that encapsulates all functionality to set up the AppDir root directory.
|
||||
*/
|
||||
class AppDirRootSetup {
|
||||
private:
|
||||
// PImpl
|
||||
class Private;
|
||||
std::shared_ptr<Private> d;
|
||||
|
||||
public:
|
||||
explicit AppDirRootSetup(const appdir::AppDir& appdir);
|
||||
|
||||
/**
|
||||
* Deploy files to the AppDir root directory using the provided desktop file and the information within it.
|
||||
* Optionally, a custom AppRun path can be provided which is deployed instead of following the internal
|
||||
* default mechanism, which usually just places a symlink to the main binary as AppRun.
|
||||
*
|
||||
* @param desktopFile
|
||||
* @param customAppRunPath
|
||||
* @return
|
||||
*/
|
||||
bool run(const desktopfile::DesktopFile& desktopFile, const boost::filesystem::path& customAppRunPath = "") const;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user