You've already forked linuxdeploy
mirror of
https://github.com/encounter/linuxdeploy.git
synced 2026-07-10 12:18:44 -07:00
Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b7a2e39ba2 | |||
| d9acb6b244 | |||
| 891359edf4 | |||
| f68f8b94e0 | |||
| 1bd5453c61 | |||
| 9783db602e | |||
| 6cfa741f40 | |||
| 1be3327a11 | |||
| cca5ad2e07 | |||
| 058832615c | |||
| cf5927c521 | |||
| 103b637944 | |||
| 58189efba6 | |||
| 019f902b17 | |||
| f97d1e9a01 | |||
| 543078c11e | |||
| 9ddb0d7650 | |||
| 8252503d97 | |||
| d312ba07d0 | |||
| d3853e961b | |||
| ef7b397d4a | |||
| 330f8a393f | |||
| 77ad746c5d | |||
| cd04cc260e | |||
| 3c4580a325 | |||
| f20af7dc67 | |||
| 0ba33879b0 | |||
| f3b7c5ab73 | |||
| 6bc354bacb | |||
| d26947985d | |||
| 2cc962a344 | |||
| 612bf962a3 | |||
| 19d958d30f | |||
| fc82028af4 | |||
| 2d45ef4c72 | |||
| 470caa3db1 | |||
| d24e6dac56 | |||
| 913f5bc6cc | |||
| 4746fd0e87 | |||
| de363bc90b | |||
| 8e9114b7c5 | |||
| 72e4fb49e0 | |||
| abdefbc0ff | |||
| 58845cee8f | |||
| 5bc8840003 | |||
| 1cb5a742db | |||
| 142facd986 | |||
| aced62378a | |||
| 3fd595a63b | |||
| 9dc10fc0fc | |||
| 3183ee2f4f | |||
| 374e17b5e3 | |||
| d9681ccf5c | |||
| 57dbdc6933 | |||
| 3d766446d9 | |||
| e24b46d291 | |||
| 47b8370751 | |||
| 0d055ebb81 | |||
| ce5aecead5 | |||
| f01ae51f58 | |||
| 0e95f19a75 | |||
| 94bb814d69 | |||
| 159b082658 |
+79
-72
@@ -3,87 +3,94 @@ sudo: required
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- env: ARCH=x86_64
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libmagic-dev
|
||||
- libjpeg-dev
|
||||
- libpng-dev
|
||||
- cimg-dev
|
||||
- automake # required for patchelf
|
||||
- env: ARCH=i386
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libmagic-dev:i386
|
||||
- libjpeg-dev:i386
|
||||
- libpng-dev:i386
|
||||
- gcc-multilib
|
||||
- g++-multilib
|
||||
- automake # required for patchelf
|
||||
- libfuse2:i386
|
||||
- libcairo2:i386
|
||||
- env: ARCH=x86_64 BUILD_TYPE=coverage
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libmagic-dev
|
||||
- libjpeg-dev
|
||||
- libpng-dev
|
||||
- cimg-dev
|
||||
before_script:
|
||||
- sudo pip install gcovr
|
||||
script: travis/test-coverage.sh
|
||||
after_success: true # also, we don't intend to upload release binaries
|
||||
- env: ARCH=i386 BUILD_TYPE=coverage
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libmagic-dev:i386
|
||||
- libjpeg-dev:i386
|
||||
- libpng-dev:i386
|
||||
- gcc-multilib
|
||||
- g++-multilib
|
||||
- libfuse2:i386
|
||||
- libcairo2:i386
|
||||
before_script:
|
||||
- sudo pip install gcovr
|
||||
script: travis/test-coverage.sh
|
||||
after_success: true # also, we don't intend to upload release binaries
|
||||
- env: ARCH=x86_64 BUILD_TYPE=centos6
|
||||
- name: CentOS 6 x86_64 build
|
||||
env: ARCH=x86_64 BUILD_TYPE=centos6
|
||||
install: true
|
||||
services:
|
||||
- docker
|
||||
script: travis/build-centos6-docker.sh
|
||||
after_success:
|
||||
- if [ "$TRAVIS_BRANCH" != "$TRAVIS_TAG" ] && [ "$TRAVIS_BRANCH" != "master" ]; then export TRAVIS_EVENT_TYPE=pull_request; fi
|
||||
- wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
|
||||
- bash upload.sh linuxdeploy-centos6-"$ARCH".AppImage*
|
||||
- bash upload.sh linuxdeploy-"$ARCH".AppImage*
|
||||
|
||||
install:
|
||||
- git clone https://github.com/NixOS/patchelf.git -b 0.8
|
||||
- cd patchelf
|
||||
- ./bootstrap.sh
|
||||
- if [ "$ARCH" == "i386" ]; then ./configure --prefix=/usr --build=i686-pc-linux-gnu CFLAGS=-m32 CXXFLAGS=-m32 LDFLAGS=-m32; fi
|
||||
- if [ "$ARCH" == "x86_64" ]; then ./configure --prefix=/usr; fi
|
||||
- make -j$(nproc)
|
||||
- sudo make install
|
||||
- cd ..
|
||||
- rm -rf patchelf
|
||||
- name: CentOS 6 i386 build
|
||||
env: ARCH=i386 BUILD_TYPE=centos6
|
||||
install: true
|
||||
services:
|
||||
- docker
|
||||
script: travis/build-centos6-docker.sh
|
||||
after_success:
|
||||
- if [ "$TRAVIS_BRANCH" != "$TRAVIS_TAG" ] && [ "$TRAVIS_BRANCH" != "master" ]; then export TRAVIS_EVENT_TYPE=pull_request; fi
|
||||
- wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
|
||||
- bash upload.sh linuxdeploy-"$ARCH".AppImage*
|
||||
|
||||
script:
|
||||
- travis/build.sh
|
||||
- name: Ubuntu bionic arm64 build
|
||||
env: ARCH=arm64 BUILD_TYPE=arm64-native
|
||||
dist: bionic
|
||||
arch: arm64
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libmagic-dev
|
||||
- libjpeg-dev
|
||||
- libpng-dev
|
||||
- cimg-dev
|
||||
- patchelf
|
||||
before_script:
|
||||
- git clone https://github.com/NixOS/patchelf.git && \
|
||||
- pushd patchelf && \
|
||||
- # cannot use -b since it's not supported in really old versions of git
|
||||
- git checkout 0.8 && \
|
||||
- ./bootstrap.sh && \
|
||||
- ./configure --prefix=/usr && \
|
||||
- make -j $(nproc) && \
|
||||
- make install && \
|
||||
- popd && \
|
||||
- rm -r patchelf/
|
||||
|
||||
script: travis/build.sh
|
||||
after_success:
|
||||
- if [ "$TRAVIS_BRANCH" != "$TRAVIS_TAG" ] && [ "$TRAVIS_BRANCH" != "master" ]; then export TRAVIS_EVENT_TYPE=pull_request; fi
|
||||
- wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
|
||||
- bash upload.sh linuxdeploy-"$ARCH".AppImage*
|
||||
|
||||
- name: Ubuntu xenial x86_64 coverage build (no binaries uploaded)
|
||||
env: ARCH=x86_64 BUILD_TYPE=coverage
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libmagic-dev
|
||||
- libjpeg-dev
|
||||
- libpng-dev
|
||||
- cimg-dev
|
||||
before_script:
|
||||
- sudo pip install gcovr
|
||||
script: travis/test-coverage.sh
|
||||
after_success: true # also, we don't intend to upload release binaries
|
||||
|
||||
- name: Ubuntu xenial i386 coverage build (no binaries uploaded)
|
||||
env: ARCH=i386 BUILD_TYPE=coverage
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libmagic-dev:i386
|
||||
- libjpeg-dev:i386
|
||||
- libpng-dev:i386
|
||||
- gcc-multilib
|
||||
- g++-multilib
|
||||
- libfuse2:i386
|
||||
- libcairo2:i386
|
||||
before_script:
|
||||
- sudo pip install gcovr
|
||||
script: travis/test-coverage.sh
|
||||
after_success: true # also, we don't intend to upload release binaries
|
||||
|
||||
after_success:
|
||||
- ls -lh
|
||||
# make sure only pushes to rewrite create a new release, otherwise pretend PR and upload to transfer.sh
|
||||
- if [ "$TRAVIS_BRANCH" != "$TRAVIS_TAG" ] && [ "$TRAVIS_BRANCH" != "master" ]; then export TRAVIS_EVENT_TYPE=pull_request; fi
|
||||
- wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
|
||||
- bash upload.sh linuxdeploy-"$ARCH".AppImage*
|
||||
|
||||
branches:
|
||||
except:
|
||||
|
||||
@@ -28,6 +28,7 @@ This is an incomplete list of projects using linuxdeploy. You might want to read
|
||||
- [OpenRCT2](https://github.com/OpenRCT2/OpenRCT2)
|
||||
- [AppImageUpdate](https://github.com/AppImage/AppImageUpdate)
|
||||
- [appimaged](https://github.com/AppImage/appimaged)
|
||||
- [MediaElch](https://github.com/Komet/MediaElch/)
|
||||
|
||||
|
||||
## Plugins
|
||||
|
||||
@@ -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);
|
||||
|
||||
+1
-1
Submodule lib/cpp-subprocess updated: 05c76a5311...6931e3d69f
Submodule lib/linuxdeploy-desktopfile updated: 9ecdcdda3f...5e7a8b1085
@@ -6,3 +6,4 @@ NoDisplay=true
|
||||
Exec=linuxdeploy
|
||||
Icon=linuxdeploy
|
||||
Categories=Development;
|
||||
X-AppImage-Integrate=false
|
||||
|
||||
+2
-2
@@ -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}
|
||||
|
||||
+126
-196
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,286 @@
|
||||
// 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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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() << std::endl;
|
||||
});
|
||||
|
||||
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)) {
|
||||
ldLog() << LD_DEBUG << "deployDesktopFileAndIcon returned false" << std::endl;
|
||||
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)) {
|
||||
ldLog() << LD_DEBUG << "deployCustomAppRunFile returned false" << std::endl;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!d->deployStandardAppRunFromDesktopFile(desktopFile, customAppRunPath)) {
|
||||
ldLog() << LD_DEBUG << "deployStandardAppRunFromDesktopFile returned false" << std::endl;
|
||||
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()) {
|
||||
ldLog() << LD_DEBUG << "deployAppRunWrapperIfNecessary returned false" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -11,17 +11,36 @@ namespace linuxdeploy {
|
||||
using namespace log;
|
||||
|
||||
std::shared_ptr<ICopyrightFilesManager> ICopyrightFilesManager::getInstance() {
|
||||
auto check_command = [](const std::string& command) {
|
||||
auto p = subprocess::Popen(
|
||||
command,
|
||||
subprocess::output(subprocess::PIPE),
|
||||
subprocess::error(subprocess::PIPE)
|
||||
);
|
||||
// very simple but for our purposes good enough which like algorithm to find binaries in $PATH
|
||||
// TODO: move into separate function to be used in the entire code base
|
||||
// FIXME: remove dependency on subprocess library
|
||||
static const auto which = [](const std::string& name) -> bf::path {
|
||||
const auto* path = getenv("PATH");
|
||||
|
||||
return p.wait();
|
||||
if (path == nullptr)
|
||||
return "";
|
||||
|
||||
for (const auto& binDir : subprocess::util::split(path, ":")) {
|
||||
if (!bf::is_directory(binDir)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (bf::directory_iterator it(binDir); it != bf::directory_iterator{}; ++it) {
|
||||
const auto binary = it->path();
|
||||
|
||||
std::cout << binary << std::endl;
|
||||
|
||||
if (binary.filename() == name) {
|
||||
// TODO: check if file is executable (skip otherwise)
|
||||
return binary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
||||
|
||||
if (check_command("which dpkg-query") == 0) {
|
||||
if (!which("dpkg-query").empty()) {
|
||||
ldLog() << LD_DEBUG << "Using dpkg-query to search for copyright files" << std::endl;
|
||||
return std::make_shared<DpkgQueryCopyrightFilesManager>();
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ log_prefix="-- [$(basename $0)]"
|
||||
|
||||
echo "$log_prefix downloading excludelist from GitHub"
|
||||
url="https://raw.githubusercontent.com/probonopd/AppImages/master/excludelist"
|
||||
blacklisted=($(wget --quiet "$url" -O - | sort | uniq | grep -v "^#.*" | grep "[^-\s]"))
|
||||
blacklisted=($(wget --quiet "$url" -O - | sed 's|#.*||g' | sort | uniq))
|
||||
|
||||
# sanity check
|
||||
if [ "$blacklisted" == "" ]; then
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
set(TEST_DATA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/data)
|
||||
|
||||
# common CMake macro for linuxdeploy, adding tests only if they are supposed to be built
|
||||
# otherwise if you try to run CTest the tests aren't build and CTest can't find them
|
||||
if(NOT COMMAND ld_add_test)
|
||||
function(ld_add_test TARGET_NAME)
|
||||
get_target_property(${TARGET_NAME}_EFA ${TARGET_NAME} EXCLUDE_FROM_ALL)
|
||||
if(NOT ${${TARGET_NAME}_EXCLUDE_FROM_ALL})
|
||||
message(STATUS "[${PROJECT_NAME}] Adding test ${TARGET_NAME}")
|
||||
add_test(${TARGET_NAME} ${TARGET_NAME})
|
||||
else()
|
||||
message(STATUS "[${PROJECT_NAME}] Test ${TARGET_NAME} is excluded from ALL, not adding as test")
|
||||
endif()
|
||||
endfunction()
|
||||
endif()
|
||||
|
||||
# first build dependencies for tests
|
||||
add_subdirectory(simple_library)
|
||||
add_subdirectory(simple_executable)
|
||||
|
||||
@@ -12,7 +12,7 @@ target_compile_definitions(test_appdir PRIVATE
|
||||
)
|
||||
|
||||
# register in CTest
|
||||
add_test(test_appdir test_appdir)
|
||||
ld_add_test(test_appdir)
|
||||
|
||||
# make sure library and executable are built before test_appdir
|
||||
add_dependencies(test_appdir simple_library simple_executable)
|
||||
@@ -33,7 +33,7 @@ target_compile_definitions(test_linuxdeploy PRIVATE
|
||||
)
|
||||
|
||||
# register in CTest
|
||||
add_test(test_linuxdeploy test_linuxdeploy)
|
||||
ld_add_test(test_linuxdeploy)
|
||||
|
||||
# make sure library and executable are built before test_appdir
|
||||
add_dependencies(test_linuxdeploy simple_library simple_executable)
|
||||
|
||||
@@ -1,10 +1,24 @@
|
||||
FROM centos:6
|
||||
|
||||
RUN yum install -y centos-release-scl-rh && \
|
||||
yum install -y devtoolset-6 wget curl patchelf vim-common fuse libfuse2 libtool autoconf automake zlib-devel libjpeg-devel libpng-devel nano git && \
|
||||
wget https://github.com/Kitware/CMake/releases/download/v3.13.4/cmake-3.13.4-Linux-x86_64.tar.gz -O- | tar xz --strip-components=1 -C/usr/local
|
||||
yum install -y devtoolset-7 wget curl patchelf vim-common fuse libfuse2 libtool autoconf automake zlib-devel libjpeg-devel libpng-devel nano git && \
|
||||
wget https://artifacts.assassinate-you.net/artifactory/cmake-centos6/cmake-v3.15.3-x86_64.tar.gz -O- | tar xz --strip-components=1 -C/usr/local
|
||||
|
||||
RUN wget http://springdale.math.ias.edu/data/puias/computational/6/x86_64//patchelf-0.8-2.sdl6.x86_64.rpm && \
|
||||
echo "3d746306f5f7958b9487e6d08f53bb13 patchelf-0.8-2.sdl6.x86_64.rpm" || md5sum -c && \
|
||||
rpm -i patchelf-0.8-2.sdl6.x86_64.rpm
|
||||
ENV ARCH=x86_64
|
||||
COPY entrypoint.sh /
|
||||
SHELL ["/entrypoint.sh", "bash", "-x", "-c"]
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
||||
RUN yum install -y gcc-c++ && \
|
||||
git clone https://github.com/NixOS/patchelf.git && \
|
||||
pushd patchelf && \
|
||||
# cannot use -b since it's not supported in really old versions of git
|
||||
git checkout 0.8 && \
|
||||
./bootstrap.sh && \
|
||||
./configure --prefix=/usr/local && \
|
||||
make -j $(nproc) && \
|
||||
make install && \
|
||||
popd && \
|
||||
rm -r patchelf/
|
||||
|
||||
CMD ["bash"]
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
FROM i386/centos:6
|
||||
|
||||
SHELL ["/bin/bash", "-x", "-c"]
|
||||
|
||||
# during Docker build, yum doesn't detect it's an i386 environment on x86_64 machines, and tries to install x86_64 packages, which can't work
|
||||
# this little command fixes this
|
||||
RUN sed -i 's/$basearch/i386/g' /etc/yum.repos.d/CentOS-Base.repo
|
||||
|
||||
# thanks CloudLinux, you're really helping us poor AppImage creators seeking for maximum compatibility by providing devtoolset i386 builds
|
||||
RUN yum install -y yum-utils && \
|
||||
rpm --import https://repo.cloudlinux.com/cloudlinux/security/RPM-GPG-KEY-CloudLinux && \
|
||||
yum-config-manager --add-repo https://www.repo.cloudlinux.com/cloudlinux/6/sclo/devtoolset-7/i386/ && \
|
||||
yum install -y devtoolset-7 wget curl patchelf vim-common fuse libfuse2 libtool autoconf automake zlib-devel libjpeg-devel libpng-devel nano git
|
||||
|
||||
# the shell wrapper takes care of enabling devtoolset and running a shell properly
|
||||
# unfortunately this is the easiest and most solid workaround to the limitations of the scl command
|
||||
COPY entrypoint.sh /
|
||||
ENV ARCH=i386
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
SHELL ["/entrypoint.sh", "bash", "-x", "-c"]
|
||||
|
||||
RUN wget https://artifacts.assassinate-you.net/artifactory/cmake-centos6/cmake-v3.15.3-i386.tar.gz -O- | tar xz --strip-components=1 -C/usr/local
|
||||
|
||||
RUN git clone https://github.com/NixOS/patchelf.git && \
|
||||
pushd patchelf && \
|
||||
# cannot use -b since it's not supported in really old versions of git
|
||||
git checkout 0.8 && \
|
||||
./bootstrap.sh && \
|
||||
./configure --prefix=/usr/local && \
|
||||
make -j $(nproc) && \
|
||||
make install && \
|
||||
popd && \
|
||||
rm -r patchelf/
|
||||
|
||||
CMD ["bash"]
|
||||
@@ -8,6 +8,11 @@ here=$(readlink -f $(dirname "$0"))
|
||||
DOCKERFILE="$here"/Dockerfile.centos6
|
||||
IMAGE=linuxdeploy-build-centos6
|
||||
|
||||
if [ "$ARCH" == "i386" ]; then
|
||||
DOCKERFILE="$DOCKERFILE"-i386
|
||||
IMAGE="$IMAGE"-i386
|
||||
fi
|
||||
|
||||
(cd "$here" && docker build -f "$DOCKERFILE" -t "$IMAGE" .)
|
||||
|
||||
docker run --rm -i -v "$here"/..:/ws:ro -v "$old_cwd":/out -e OUTDIR_OWNER=$(id -u) "$IMAGE" /bin/bash -xe /ws/travis/build-centos6.sh
|
||||
docker run --rm -it -v "$here"/..:/ws:ro -v "$old_cwd":/out -e CI=1 -e OUTDIR_OWNER=$(id -u) "$IMAGE" /bin/bash -xe -c "cd /out && /ws/travis/build-centos6.sh"
|
||||
|
||||
+52
-22
@@ -1,19 +1,34 @@
|
||||
#! /bin/bash
|
||||
|
||||
set -xe
|
||||
set -e
|
||||
set -x
|
||||
|
||||
# get a compiler that allows for using modern-ish C++ (>= 11) on a distro that doesn't normally support it
|
||||
# before you ask: yes, the binaries will work on CentOS 6 even without devtoolset (they somehow partially link C++
|
||||
# things statically while using others from the system...)
|
||||
# so, basically, it's magic!
|
||||
. /opt/rh/devtoolset-6/enable
|
||||
# use RAM disk if possible
|
||||
if [ "$CI" == "" ] && [ -d /dev/shm ]; then
|
||||
TEMP_BASE=/dev/shm
|
||||
else
|
||||
TEMP_BASE=/tmp
|
||||
fi
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
BUILD_DIR=$(mktemp -d -p "$TEMP_BASE" linuxdeploy-build-XXXXXX)
|
||||
|
||||
cmake /ws -DCMAKE_INSTALL_PREFIX=/usr -DUSE_SYSTEM_CIMG=Off
|
||||
cleanup () {
|
||||
if [ -d "$BUILD_DIR" ]; then
|
||||
rm -rf "$BUILD_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
make -j8
|
||||
trap cleanup EXIT
|
||||
|
||||
# store repo root as variable
|
||||
REPO_ROOT=$(readlink -f $(dirname $(dirname "$0")))
|
||||
OLD_CWD=$(readlink -f .)
|
||||
|
||||
pushd "$BUILD_DIR"
|
||||
|
||||
cmake "$REPO_ROOT" -DCMAKE_INSTALL_PREFIX=/usr -DUSE_SYSTEM_CIMG=Off -DUSE_CCACHE=Off
|
||||
|
||||
make -j$(nproc)
|
||||
|
||||
ctest -V
|
||||
|
||||
@@ -23,20 +38,35 @@ LINUXDEPLOY_ARGS=("--appdir" "AppDir" "-e" "bin/linuxdeploy" "-i" "/ws/resources
|
||||
# deploy patchelf which is a dependency of linuxdeploy
|
||||
bin/linuxdeploy "${LINUXDEPLOY_ARGS[@]}"
|
||||
|
||||
tar cfvz /out/appdir.tgz AppDir
|
||||
# bundle AppImage plugin
|
||||
mkdir -p AppDir/plugins
|
||||
|
||||
# cannot add appimage plugin yet, since it won't work on CentOS 6 (at least for now)
|
||||
# therefore we also need to use appimagetool directly to build an AppImage
|
||||
# but we can still prepare the AppDir
|
||||
wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||
chmod +x appimagetool-x86_64.AppImage
|
||||
sed -i 's/AI\x02/\x00\x00\x00/' appimagetool*.AppImage
|
||||
wget https://github.com/TheAssassin/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-"$ARCH".AppImage
|
||||
chmod +x linuxdeploy-plugin-appimage-"$ARCH".AppImage
|
||||
sed -i 's|AI\x02|\x00\x00\x00|' linuxdeploy*.AppImage
|
||||
./linuxdeploy-plugin-appimage-"$ARCH".AppImage --appimage-extract
|
||||
mv squashfs-root/ AppDir/plugins/linuxdeploy-plugin-appimage
|
||||
|
||||
appimage=linuxdeploy-centos6-x86_64.AppImage
|
||||
./appimagetool-x86_64.AppImage --appimage-extract
|
||||
squashfs-root/AppRun AppDir "$appimage" 2>&1
|
||||
ln -s ../../plugins/linuxdeploy-plugin-appimage/AppRun AppDir/usr/bin/linuxdeploy-plugin-appimage
|
||||
|
||||
chown "$OUTDIR_OWNER" "$appimage"
|
||||
export UPD_INFO="gh-releases-zsync|linuxdeploy|linuxdeploy|continuous|linuxdeploy-$ARCH.AppImage"
|
||||
export OUTPUT=linuxdeploy-"$ARCH".AppImage
|
||||
|
||||
mv "$appimage" /out
|
||||
# build AppImage using plugin
|
||||
AppDir/usr/bin/linuxdeploy-plugin-appimage --appdir AppDir/
|
||||
|
||||
# rename AppImage to avoid "Text file busy" issues when using it to create another one
|
||||
mv "$OUTPUT" test.AppImage
|
||||
# also have to patch our test AppImage, but we can leave the newly produced one untouched
|
||||
sed -i 's|AI\x02|\x00\x00\x00|' test.AppImage
|
||||
|
||||
# verify that the resulting AppImage works
|
||||
./test.AppImage --appimage-extract-and-run "${LINUXDEPLOY_ARGS[@]}"
|
||||
|
||||
# check whether AppImage plugin is found and works
|
||||
./test.AppImage --appimage-extract-and-run "${LINUXDEPLOY_ARGS[@]}" --output appimage
|
||||
|
||||
chown "$OUTDIR_OWNER" "$OUTPUT"
|
||||
|
||||
mv "$OUTPUT"* "$OLD_CWD"/
|
||||
|
||||
|
||||
+5
-2
@@ -30,6 +30,8 @@ if [ "$ARCH" == "x86_64" ]; then
|
||||
EXTRA_CMAKE_ARGS=()
|
||||
elif [ "$ARCH" == "i386" ]; then
|
||||
EXTRA_CMAKE_ARGS=("-DCMAKE_TOOLCHAIN_FILE=$REPO_ROOT/cmake/toolchains/i386-linux-gnu.cmake" "-DUSE_SYSTEM_CIMG=OFF")
|
||||
elif [ "$ARCH" == "arm64" ] && [ "$BUILD_TYPE" == "arm64-native" ]; then
|
||||
EXTRA_CMAKE_ARGS=()
|
||||
else
|
||||
echo "Architecture not supported: $ARCH" 1>&2
|
||||
exit 1
|
||||
@@ -75,12 +77,13 @@ mv squashfs-root/ AppDir/plugins/linuxdeploy-plugin-appimage
|
||||
ln -s ../../plugins/linuxdeploy-plugin-appimage/AppRun AppDir/usr/bin/linuxdeploy-plugin-appimage
|
||||
|
||||
export UPD_INFO="gh-releases-zsync|linuxdeploy|linuxdeploy|continuous|linuxdeploy-$ARCH.AppImage"
|
||||
export OUTPUT="linuxdeploy-devbuild-$ARCH.AppImage"
|
||||
|
||||
# build AppImage using plugin
|
||||
AppDir/usr/bin/linuxdeploy-plugin-appimage --appdir AppDir/
|
||||
|
||||
# rename AppImage to avoid "Text file busy" issues when using it to create another one
|
||||
mv ./linuxdeploy-"$ARCH".AppImage test.AppImage
|
||||
mv "$OUTPUT" test.AppImage
|
||||
|
||||
# verify that the resulting AppImage works
|
||||
./test.AppImage "${LINUXDEPLOY_ARGS[@]}"
|
||||
@@ -88,4 +91,4 @@ mv ./linuxdeploy-"$ARCH".AppImage test.AppImage
|
||||
# check whether AppImage plugin is found and works
|
||||
./test.AppImage "${LINUXDEPLOY_ARGS[@]}" --output appimage
|
||||
|
||||
mv linuxdeploy-"$ARCH".AppImage* "$OLD_CWD"
|
||||
mv "$OUTPUT"* "$OLD_CWD"/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user