mirror of
https://github.com/encounter/linuxdeploy.git
synced 2026-07-10 12:18:44 -07:00
Initial commit
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
cmake-build-*/
|
||||||
|
*build*/
|
||||||
|
.idea/
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[submodule "lib/cpp-subprocess"]
|
||||||
|
path = lib/cpp-subprocess
|
||||||
|
url = https://github.com/arun11299/cpp-subprocess.git
|
||||||
|
[submodule "lib/args"]
|
||||||
|
path = lib/args
|
||||||
|
url = https://github.com/Taywee/args.git
|
||||||
|
[submodule "lib/cpp-feather-ini-parser"]
|
||||||
|
path = lib/cpp-feather-ini-parser
|
||||||
|
url = https://github.com/Turbine1991/cpp-feather-ini-parser.git
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.2)
|
||||||
|
|
||||||
|
project(linuxdeploy C CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
set(LINUXDEPLOY_VERSION 0.1-alpha-1)
|
||||||
|
add_definitions(-DLINUXDEPLOY_VERSION="${LINUXDEPLOY_VERSION}")
|
||||||
|
|
||||||
|
add_subdirectory(lib)
|
||||||
|
|
||||||
|
add_subdirectory(src)
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
Copyright 2018 TheAssassin
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# linuxdeploy
|
||||||
|
|
||||||
|
AppDir creation and maintenance tool.
|
||||||
|
|
||||||
|
**More info will follow soon!**
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
// system includes
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// library includes
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "linuxdeploy/core/desktopfile.h"
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace linuxdeploy {
|
||||||
|
namespace core {
|
||||||
|
namespace appdir {
|
||||||
|
/*
|
||||||
|
* Base class for AppDirs.
|
||||||
|
*/
|
||||||
|
class AppDir {
|
||||||
|
private:
|
||||||
|
// private data class pattern
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData* d;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// default constructor
|
||||||
|
// construct AppDir from given path
|
||||||
|
// the directory will be created if it doesn't exist
|
||||||
|
explicit AppDir(const boost::filesystem::path& path);
|
||||||
|
|
||||||
|
~AppDir();
|
||||||
|
|
||||||
|
// alternative constructor
|
||||||
|
// shortcut for using a normal string instead of a path
|
||||||
|
explicit AppDir(const std::string& path);
|
||||||
|
|
||||||
|
// creates basic directory structure of an AppDir in "FHS" mode
|
||||||
|
bool createBasicStructure();
|
||||||
|
|
||||||
|
// deploy shared library
|
||||||
|
bool deployLibrary(const boost::filesystem::path& path);
|
||||||
|
|
||||||
|
// deploy executable
|
||||||
|
bool deployExecutable(const boost::filesystem::path& path);
|
||||||
|
|
||||||
|
// deploy desktop file
|
||||||
|
bool deployDesktopFile(const desktopfile::DesktopFile& desktopFile);
|
||||||
|
|
||||||
|
// deploy icon
|
||||||
|
bool deployIcon(const boost::filesystem::path& path);
|
||||||
|
|
||||||
|
// execute deferred copy operations
|
||||||
|
bool executeDeferredOperations();
|
||||||
|
|
||||||
|
// return path to AppDir
|
||||||
|
boost::filesystem::path path();
|
||||||
|
|
||||||
|
// create a list of all icon paths in the AppDir
|
||||||
|
std::vector<boost::filesystem::path> deployedIconPaths();
|
||||||
|
|
||||||
|
// create a list of all executable paths in the AppDir
|
||||||
|
std::vector<boost::filesystem::path> deployedExecutablePaths();
|
||||||
|
|
||||||
|
// create a list of all desktop file paths in the AppDir
|
||||||
|
std::vector<desktopfile::DesktopFile> deployedDesktopFiles();
|
||||||
|
|
||||||
|
// create symlinks for AppRun, desktop file and icon in the AppDir root directory
|
||||||
|
bool createLinksInAppDirRoot(const desktopfile::DesktopFile& desktopFile);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
// system includes
|
||||||
|
|
||||||
|
// library includes
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace linuxdeploy {
|
||||||
|
namespace core {
|
||||||
|
namespace desktopfile {
|
||||||
|
/*
|
||||||
|
* Parse and read desktop files.
|
||||||
|
*/
|
||||||
|
class DesktopFile {
|
||||||
|
private:
|
||||||
|
// private data class pattern
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData* d;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// default constructor
|
||||||
|
DesktopFile();
|
||||||
|
|
||||||
|
// construct from existing desktop file
|
||||||
|
// file must exist
|
||||||
|
explicit DesktopFile(const boost::filesystem::path& path);
|
||||||
|
|
||||||
|
// read desktop file
|
||||||
|
// sets path associated with this file
|
||||||
|
bool read(const boost::filesystem::path& path);
|
||||||
|
|
||||||
|
// get path associated with this file
|
||||||
|
boost::filesystem::path path() const;
|
||||||
|
|
||||||
|
// sets the path associated with this desktop file
|
||||||
|
// used to e.g., save the desktop file
|
||||||
|
void setPath(const boost::filesystem::path& path);
|
||||||
|
|
||||||
|
// clear contents of desktop file
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
// save desktop file
|
||||||
|
bool save() const;
|
||||||
|
|
||||||
|
// save desktop file to path
|
||||||
|
// does not change path associated with desktop file
|
||||||
|
bool save(const boost::filesystem::path& path) const;
|
||||||
|
|
||||||
|
// check if entry exists in given section and key
|
||||||
|
bool entryExists(const std::string& section, const std::string& key) const;
|
||||||
|
|
||||||
|
// get key from desktop file
|
||||||
|
// an std::string passed as value parameter will be populated with the contents
|
||||||
|
// returns true (and populates value) if the key exists, false otherwise
|
||||||
|
bool getEntry(const std::string& section, const std::string& key, std::string& value) const;
|
||||||
|
|
||||||
|
// add key to section in desktop file
|
||||||
|
// the section will be created if it doesn't exist already
|
||||||
|
// returns true if an existing key was overwritten, false otherwise
|
||||||
|
bool setEntry(const std::string& section, const std::string& key, const std::string& value);
|
||||||
|
|
||||||
|
// create common application entries in desktop file
|
||||||
|
// returns false if one of the keys exists and was left unmodified
|
||||||
|
bool addDefaultKeys(const std::string& executableFileName);
|
||||||
|
|
||||||
|
// validate desktop file
|
||||||
|
bool validate() const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
// system includes
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// library includes
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace linuxdeploy {
|
||||||
|
namespace core {
|
||||||
|
namespace elf {
|
||||||
|
class ElfFile {
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData* d;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ElfFile(const boost::filesystem::path& path);
|
||||||
|
~ElfFile();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// recursively trace dynamic library dependencies of a given ELF file
|
||||||
|
// this works for both libraries and executables
|
||||||
|
// the resulting vector consists of absolute paths to the libraries determined by the same methods a system's
|
||||||
|
// linker would use
|
||||||
|
std::vector<boost::filesystem::path> traceDynamicDependencies();
|
||||||
|
|
||||||
|
// fetch rpath stored in binary
|
||||||
|
// it appears that according to the ELF standard, the rpath is ignored in libraries, therefore if the path
|
||||||
|
// points to an executable, an empty string is returned
|
||||||
|
std::string getRPath();
|
||||||
|
|
||||||
|
// set rpath in ELF file
|
||||||
|
// returns true on success, false otherwise
|
||||||
|
bool setRPath(const std::string& value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
// system includes
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// library includes
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace linuxdeploy {
|
||||||
|
namespace core {
|
||||||
|
namespace log {
|
||||||
|
enum LD_LOGLEVEL {
|
||||||
|
LD_DEBUG = 0,
|
||||||
|
LD_INFO,
|
||||||
|
LD_WARNING,
|
||||||
|
LD_ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
enum LD_STREAM_CONTROL {
|
||||||
|
LD_NOOP = 0,
|
||||||
|
LD_NO_SPACE,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ldLog {
|
||||||
|
private:
|
||||||
|
// this is the type of std::cout
|
||||||
|
typedef std::basic_ostream<char, std::char_traits<char> > CoutType;
|
||||||
|
|
||||||
|
// this is the function signature of std::endl
|
||||||
|
typedef CoutType& (* stdEndlType)(CoutType&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static LD_LOGLEVEL verbosity;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool prependSpace;
|
||||||
|
bool logLevelSet;
|
||||||
|
CoutType& stream = std::cout;
|
||||||
|
|
||||||
|
LD_LOGLEVEL currentLogLevel;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// advanced behavior
|
||||||
|
ldLog(bool prependSpace, bool logLevelSet, LD_LOGLEVEL logLevel);
|
||||||
|
|
||||||
|
void checkPrependSpace();
|
||||||
|
|
||||||
|
bool checkVerbosity();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void setVerbosity(LD_LOGLEVEL verbosity);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// public constructor
|
||||||
|
// does not implement the advanced behavior -- see private constructors for that
|
||||||
|
ldLog();
|
||||||
|
|
||||||
|
public:
|
||||||
|
ldLog operator<<(const std::string& message);
|
||||||
|
ldLog operator<<(const char* message);
|
||||||
|
ldLog operator<<(const boost::filesystem::path& path);
|
||||||
|
ldLog operator<<(const double val);
|
||||||
|
ldLog operator<<(stdEndlType strm);
|
||||||
|
ldLog operator<<(const LD_LOGLEVEL logLevel);
|
||||||
|
ldLog operator<<(const LD_STREAM_CONTROL streamControl);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace linuxdeploy {
|
||||||
|
namespace core {
|
||||||
|
namespace util {
|
||||||
|
static inline bool ltrim(std::string& s, char to_trim = ' ') {
|
||||||
|
// TODO: find more efficient way to check whether elements have been removed
|
||||||
|
size_t initialLength = s.length();
|
||||||
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [to_trim](int ch) {
|
||||||
|
return ch != to_trim;
|
||||||
|
}));
|
||||||
|
return s.length() < initialLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool rtrim(std::string& s, char to_trim = ' ') {
|
||||||
|
// TODO: find more efficient way to check whether elements have been removed
|
||||||
|
auto initialLength = s.length();
|
||||||
|
s.erase(std::find_if(s.rbegin(), s.rend(), [to_trim](int ch) {
|
||||||
|
return ch != to_trim;
|
||||||
|
}).base(), s.end());
|
||||||
|
return s.length() < initialLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool trim(std::string& s, char to_trim = ' ') {
|
||||||
|
// returns true if either modifies s
|
||||||
|
auto ltrim_result = ltrim(s, to_trim);
|
||||||
|
return rtrim(s, to_trim) && ltrim_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> split(const std::string& s, char delim = ' ') {
|
||||||
|
std::vector<std::string> result;
|
||||||
|
|
||||||
|
std::stringstream ss(s);
|
||||||
|
std::string item;
|
||||||
|
|
||||||
|
while (std::getline(ss, item, delim)) {
|
||||||
|
result.push_back(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> splitLines(const std::string& s) {
|
||||||
|
return split(s, '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline std::string strLower(std::string s) {
|
||||||
|
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::tolower(c); });
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
add_library(subprocess INTERFACE)
|
||||||
|
target_sources(subprocess INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/cpp-subprocess/subprocess.hpp)
|
||||||
|
target_include_directories(subprocess INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/cpp-subprocess)
|
||||||
|
|
||||||
|
add_library(args INTERFACE)
|
||||||
|
target_sources(args INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/args/args.hxx)
|
||||||
|
target_include_directories(args INTERFACE args)
|
||||||
|
|
||||||
|
add_library(cpp-feather-ini-parser INTERFACE)
|
||||||
|
target_sources(cpp-feather-ini-parser INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/cpp-feather-ini-parser/INI.h)
|
||||||
|
target_include_directories(cpp-feather-ini-parser INTERFACE cpp-feather-ini-parser)
|
||||||
|
|
||||||
|
add_executable(test_cpp_feather_ini_parser EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/cpp-feather-ini-parser/example/example.cpp)
|
||||||
|
target_link_libraries(test_cpp_feather_ini_parser PRIVATE cpp-feather-ini-parser)
|
||||||
|
add_test(test_cpp_feather_ini_parser test_cpp_feather_ini_parser)
|
||||||
Submodule
+1
Submodule lib/args added at bd0429e91f
Submodule
+1
Submodule lib/cpp-feather-ini-parser added at 2dff628f92
Submodule
+1
Submodule lib/cpp-subprocess added at 05c76a5311
@@ -0,0 +1,4 @@
|
|||||||
|
# globally include own includes
|
||||||
|
include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
|
add_subdirectory(core)
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# 3.5 is required for imported boost targets
|
||||||
|
# 3.6 is required for the PkgConfig module's IMPORTED_TARGET library feature
|
||||||
|
cmake_minimum_required(VERSION 3.6)
|
||||||
|
|
||||||
|
# include headers to make CLion happy
|
||||||
|
file(GLOB HEADERS ${PROJECT_SOURCE_DIR}/include/linuxdeploy/core/*.h)
|
||||||
|
|
||||||
|
find_package(Boost REQUIRED COMPONENTS filesystem regex)
|
||||||
|
find_package(Threads)
|
||||||
|
|
||||||
|
find_package(PkgConfig)
|
||||||
|
pkg_check_modules(magick++ REQUIRED IMPORTED_TARGET Magick++)
|
||||||
|
|
||||||
|
message(STATUS "Generating excludelist")
|
||||||
|
execute_process(
|
||||||
|
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/generate-excludelist.sh
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(core elf.cpp log.cpp appdir.cpp desktopfile.cpp ${HEADERS})
|
||||||
|
target_link_libraries(core Boost::filesystem Boost::regex subprocess cpp-feather-ini-parser PkgConfig::magick++ ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
target_include_directories(core PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
add_executable(linuxdeploy main.cpp)
|
||||||
|
target_link_libraries(linuxdeploy core args)
|
||||||
|
|
||||||
|
set_target_properties(linuxdeploy PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,130 @@
|
|||||||
|
// library headers
|
||||||
|
#include <INI.h>
|
||||||
|
|
||||||
|
// local headers
|
||||||
|
#include "linuxdeploy/core/desktopfile.h"
|
||||||
|
#include "linuxdeploy/core/log.h"
|
||||||
|
|
||||||
|
using namespace linuxdeploy::core;
|
||||||
|
using namespace linuxdeploy::core::log;
|
||||||
|
|
||||||
|
namespace bf = boost::filesystem;
|
||||||
|
|
||||||
|
namespace linuxdeploy {
|
||||||
|
namespace core {
|
||||||
|
namespace desktopfile {
|
||||||
|
class DesktopFile::PrivateData {
|
||||||
|
public:
|
||||||
|
bf::path path;
|
||||||
|
INI<> ini;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PrivateData() : path(), ini("", false) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
DesktopFile::DesktopFile() {
|
||||||
|
d = new PrivateData();
|
||||||
|
}
|
||||||
|
|
||||||
|
DesktopFile::DesktopFile(const bf::path& path) : DesktopFile() {
|
||||||
|
if (!read(path))
|
||||||
|
throw std::runtime_error("Failed to read desktop file");
|
||||||
|
};
|
||||||
|
|
||||||
|
bool DesktopFile::read(const boost::filesystem::path& path) {
|
||||||
|
setPath(path);
|
||||||
|
|
||||||
|
clear();
|
||||||
|
|
||||||
|
// nothing to do
|
||||||
|
if (!bf::exists(path))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
std::ifstream ifs(path.string());
|
||||||
|
if (!ifs)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
d->ini.parse(ifs);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::filesystem::path DesktopFile::path() const {
|
||||||
|
return d->path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopFile::setPath(const boost::filesystem::path& path) {
|
||||||
|
d->path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopFile::clear() {
|
||||||
|
d->ini.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopFile::save() const {
|
||||||
|
return save(d->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopFile::save(const boost::filesystem::path& path) const {
|
||||||
|
return d->ini.save(path.string());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopFile::entryExists(const std::string& section, const std::string& key) const {
|
||||||
|
if (!d->ini.select(section))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::string absolutelyUnlikeValue = "<>!§$%&/()=?+'#-.,_:;'*¹²³½¬{[]}^°|";
|
||||||
|
|
||||||
|
auto value = d->ini.get<std::string, std::string, std::string>(section, key, absolutelyUnlikeValue);
|
||||||
|
|
||||||
|
return value != absolutelyUnlikeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopFile::setEntry(const std::string& section, const std::string& key, const std::string& value) {
|
||||||
|
// check if value exists -- used for return value
|
||||||
|
auto rv = entryExists(section, key);
|
||||||
|
|
||||||
|
// set key
|
||||||
|
d->ini[section][key] = value;
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopFile::getEntry(const std::string& section, const std::string& key, std::string& value) const {
|
||||||
|
if (!entryExists(section, key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!d->ini.select(section))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
value = d->ini.get(key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopFile::addDefaultKeys(const std::string& executableFileName) {
|
||||||
|
auto rv = true;
|
||||||
|
|
||||||
|
auto setDefault = [&rv, this](const std::string& section, const std::string& key, const std::string& value) {
|
||||||
|
if (setEntry(section, key, value)) {
|
||||||
|
rv = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
setDefault("Desktop Entry", "Name", executableFileName);
|
||||||
|
setDefault("Desktop Entry", "Exec", executableFileName);
|
||||||
|
setDefault("Desktop Entry", "Icon", executableFileName);
|
||||||
|
setDefault("Desktop Entry", "Type", "Application");
|
||||||
|
setDefault("Desktop Entry", "Categories", "Utility;");
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopFile::validate() const {
|
||||||
|
// FIXME: call desktop-file-validate
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
// library includes
|
||||||
|
#include <boost/regex.hpp>
|
||||||
|
#include <subprocess.hpp>
|
||||||
|
|
||||||
|
// local headers
|
||||||
|
#include "linuxdeploy/core/elf.h"
|
||||||
|
#include "linuxdeploy/core/log.h"
|
||||||
|
#include "linuxdeploy/core/util.h"
|
||||||
|
|
||||||
|
using namespace linuxdeploy::core::log;
|
||||||
|
|
||||||
|
namespace bf = boost::filesystem;
|
||||||
|
|
||||||
|
namespace linuxdeploy {
|
||||||
|
namespace core {
|
||||||
|
namespace elf {
|
||||||
|
class ElfFile::PrivateData {
|
||||||
|
public:
|
||||||
|
const bf::path path;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PrivateData(const bf::path& path) : path(path) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
ElfFile::ElfFile(const boost::filesystem::path& path) {
|
||||||
|
d = new PrivateData(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
ElfFile::~ElfFile() {
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<bf::path> ElfFile::traceDynamicDependencies() {
|
||||||
|
// this method's purpose is to abstract this process
|
||||||
|
// the caller doesn't care _how_ it's done, after all
|
||||||
|
|
||||||
|
// for now, we use the same ldd based method linuxdeployqt uses
|
||||||
|
|
||||||
|
std::vector<bf::path> paths;
|
||||||
|
|
||||||
|
subprocess::Popen lddProc(
|
||||||
|
{"ldd", d->path.string().c_str()},
|
||||||
|
subprocess::output{subprocess::PIPE},
|
||||||
|
subprocess::error{subprocess::PIPE}
|
||||||
|
);
|
||||||
|
|
||||||
|
auto lddOutput = lddProc.communicate();
|
||||||
|
auto& lddStdout = lddOutput.first;
|
||||||
|
auto& lddStderr = lddOutput.second;
|
||||||
|
|
||||||
|
if (lddProc.retcode() != 0) {
|
||||||
|
ldLog() << LD_ERROR << "Call to ldd failed:" << std::endl << lddStderr.buf.data() << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string lddStdoutContents(lddStdout.buf.data());
|
||||||
|
|
||||||
|
const boost::regex expr(R"(\s*(.+)\s+\=>\s+(.+)\s+\((.+)\)\s*)");
|
||||||
|
boost::smatch what;
|
||||||
|
|
||||||
|
for (const auto& line : util::splitLines(lddStdoutContents)) {
|
||||||
|
if (boost::regex_search(line, what, expr)) {
|
||||||
|
auto libraryPath = what[2].str();
|
||||||
|
util::trim(libraryPath);
|
||||||
|
paths.push_back(bf::absolute(libraryPath));
|
||||||
|
} else {
|
||||||
|
ldLog() << LD_DEBUG << "Invalid ldd output: " << line << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ElfFile::getRPath() {
|
||||||
|
subprocess::Popen patchelfProc(
|
||||||
|
{"patchelf", "--print-rpath", d->path.c_str()},
|
||||||
|
subprocess::output(subprocess::PIPE),
|
||||||
|
subprocess::error(subprocess::PIPE)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto patchelfOutput = patchelfProc.communicate();
|
||||||
|
auto& patchelfStdout = patchelfOutput.first;
|
||||||
|
auto& patchelfStderr = patchelfOutput.second;
|
||||||
|
|
||||||
|
if (patchelfProc.retcode() != 0) {
|
||||||
|
std::string errStr(patchelfStderr.buf.data());
|
||||||
|
|
||||||
|
// if file is not an ELF executable, there is no need for a detailed error message
|
||||||
|
if (patchelfProc.retcode() == 1 && errStr.find("not an ELF executable")) {
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
ldLog() << LD_ERROR << "Call to patchelf failed:" << std::endl << errStr;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string retval = patchelfStdout.buf.data();
|
||||||
|
util::trim(retval, '\n');
|
||||||
|
util::trim(retval);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ElfFile::setRPath(const std::string& value) {
|
||||||
|
subprocess::Popen patchelfProc(
|
||||||
|
{"patchelf", "--set-rpath", value.c_str(), d->path.c_str()},
|
||||||
|
subprocess::output(subprocess::PIPE),
|
||||||
|
subprocess::error(subprocess::PIPE)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto patchelfOutput = patchelfProc.communicate();
|
||||||
|
auto& patchelfStdout = patchelfOutput.first;
|
||||||
|
auto& patchelfStderr = patchelfOutput.second;
|
||||||
|
|
||||||
|
if (patchelfProc.retcode() != 0) {
|
||||||
|
ldLog() << LD_ERROR << "Call to patchelf failed:" << std::endl << patchelfStderr.buf;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright 2018 Alexander Gottwald (https://github.com/ago1024)
|
||||||
|
# Copyright 2018 TheAssassin (https://github.com/TheAssassin)
|
||||||
|
#
|
||||||
|
# Dual-licensed under the terms of the GPLv3 and LGPL v3 licenses as part of
|
||||||
|
# linuxdeployqt (https://github.com/probonopd/linuxdeployqt).
|
||||||
|
#
|
||||||
|
# Changed to use C++ standard library containers instead of Qt ones.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# download excludelist
|
||||||
|
blacklisted=($(wget --quiet https://raw.githubusercontent.com/probonopd/AppImages/master/excludelist -O - | sort | uniq | grep -v "^#.*" | grep "[^-\s]"))
|
||||||
|
|
||||||
|
# sanity check
|
||||||
|
if [ "$blacklisted" == "" ]; then
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
filename=excludelist.h
|
||||||
|
|
||||||
|
# overwrite existing source file
|
||||||
|
cat > "$filename" <<EOF
|
||||||
|
/*
|
||||||
|
* List of libraries to exclude for different reasons.
|
||||||
|
*
|
||||||
|
* Automatically generated from
|
||||||
|
* https://raw.githubusercontent.com/probonopd/AppImages/master/excludelist
|
||||||
|
*
|
||||||
|
* This file shall be committed by the developers occassionally,
|
||||||
|
* otherwise systems without access to the internet won't be able to build
|
||||||
|
* fully working versions of linuxdeployqt.
|
||||||
|
*
|
||||||
|
* See https://github.com/probonopd/linuxdeployqt/issues/274 for more
|
||||||
|
* information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
static const std::vector<std::string> generatedExcludelist = {
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Create array
|
||||||
|
for item in ${blacklisted[@]:0:${#blacklisted[@]}-1}; do
|
||||||
|
echo -e ' "'"$item"'",' >> "$filename"
|
||||||
|
done
|
||||||
|
echo -e ' "'"${blacklisted[$((${#blacklisted[@]}-1))]}"'"' >> "$filename"
|
||||||
|
|
||||||
|
echo "};" >> "$filename"
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user