You've already forked linuxdeploy
mirror of
https://github.com/encounter/linuxdeploy.git
synced 2026-07-10 12:18:44 -07:00
Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8e0fdc80b0 | |||
| 3a96c5e880 | |||
| 0bc12dfd95 | |||
| b7faefdc56 | |||
| 4585cb1a28 | |||
| 23c85c732a | |||
| b3e259bda1 | |||
| d42abe363c | |||
| ef90b09c79 | |||
| ce097235f2 | |||
| d65574544f | |||
| b38612d07e | |||
| 9cddf75449 | |||
| b974f44ffd | |||
| ecaeda4533 | |||
| ccfd05b5e0 | |||
| 6cf9bc55a7 | |||
| 1e3e074f35 | |||
| 7b16864dbe | |||
| 0b5ab2fc36 | |||
| b3d0e7f20f | |||
| 132931772c | |||
| 6f7a2fd54a | |||
| c4258759b4 | |||
| 786a24cb25 | |||
| 35f1acf00d | |||
| be0a891770 | |||
| 92a1370b30 | |||
| 541da1b573 | |||
| f274de8045 | |||
| 6a951558ce | |||
| a4b13a1916 | |||
| 1c4e4a3888 | |||
| e4bf795211 | |||
| e994eacfa0 | |||
| beb2ee15be | |||
| 2e1a37ccf5 | |||
| 520ac6de9b | |||
| 1bcdcab057 | |||
| 1d9c907ec3 | |||
| 3e584f5551 | |||
| f7975f1b80 | |||
| 4af76a92c5 | |||
| b6f5f371b6 | |||
| d10e0614a1 | |||
| 4ffa1a66ae | |||
| 9707b81931 | |||
| 21b12cc6b6 | |||
| ae61f6b9d8 | |||
| b43b04f693 | |||
| 61fb8bebdb | |||
| 002ba4a496 | |||
| 244d82fede | |||
| 9f8121ebff | |||
| 80adfa8872 | |||
| 4a07c8151e | |||
| ded20c162d | |||
| bf152a509b | |||
| dc8f446ca4 | |||
| fbc1d78122 | |||
| 9b2ff305e0 |
@@ -7,9 +7,6 @@
|
||||
[submodule "lib/boost-filesystem"]
|
||||
path = lib/boost-filesystem
|
||||
url = https://github.com/boostorg/filesystem.git
|
||||
[submodule "lib/boost-regex"]
|
||||
path = lib/boost-regex
|
||||
url = https://github.com/boostorg/regex.git
|
||||
[submodule "lib/boost-system"]
|
||||
path = lib/boost-system
|
||||
url = https://github.com/boostorg/system.git
|
||||
|
||||
@@ -37,6 +37,8 @@ qmake CONFIG+=release PREFIX=/usr .
|
||||
make install INSTALL_ROOT=AppDir
|
||||
```
|
||||
|
||||
Next, download the latest linuxdeploy AppImage. It's available on the [release page](https://github.com/linuxdeploy/linuxdeploy/releases). Make sure to pick the right one for your (target) architecture.
|
||||
|
||||
Now, simply run linuxdeploy like `./linuxdeploy*.AppImage --appdir AppDir`.
|
||||
|
||||
Please use `./linuxdeploy*.AppImage --help` to get a list of options supported by linuxdeploy.
|
||||
@@ -86,6 +88,8 @@ linuxdeploy currently ships with some plugins. These are likely out of date. In
|
||||
|
||||
If you want to use a plugin to bundle additional resources, please add `./linuxdeploy*.AppImage --plugin <name>` to your linuxdeploy command. Output plugins can be activated using `./linuxdeploy*.AppImage --output <name>`.
|
||||
|
||||
**A list of official and community plugins can be found in the [awesome-linuxdeploy](http://github.com/linuxdeploy/awesome-linuxdeploy) project.**
|
||||
|
||||
**Note:** If you want to suggest a plugin for a specific framework, language etc., please feel free to [create a new issue](https://github.com/linuxdeploy/linuxdeploy/issues/new). Current plugin requests can be found [here](https://github.com/linuxdeploy/linuxdeploy/issues?utf8=%E2%9C%93&q=label%3A%22plugin+request%22).
|
||||
|
||||
|
||||
|
||||
@@ -218,8 +218,11 @@ function(SETUP_TARGET_FOR_COVERAGE_GCOVR_XML)
|
||||
endforeach()
|
||||
|
||||
add_custom_target(${Coverage_NAME}
|
||||
# Clean old coverage data
|
||||
COMMAND find ${PROJECT_BINARY_DIR} -type f -iname '*.gcno' -delete
|
||||
|
||||
# Run tests
|
||||
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||
COMMAND ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||
|
||||
# Running gcovr
|
||||
COMMAND ${GCOVR_PATH} --xml
|
||||
@@ -272,8 +275,11 @@ function(SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML)
|
||||
endforeach()
|
||||
|
||||
add_custom_target(${Coverage_NAME}
|
||||
# Clean old coverage data
|
||||
COMMAND find ${PROJECT_BINARY_DIR} -type f -iname '*.gcno' -delete
|
||||
|
||||
# Run tests
|
||||
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||
COMMAND ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||
|
||||
# Create folder
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
|
||||
@@ -329,8 +335,11 @@ function(SETUP_TARGET_FOR_COVERAGE_GCOVR_TEXT)
|
||||
endforeach()
|
||||
|
||||
add_custom_target(${Coverage_NAME}
|
||||
# Clean old coverage data
|
||||
COMMAND find ${PROJECT_BINARY_DIR} -type f -iname '*.gcno' -delete
|
||||
|
||||
# Run tests
|
||||
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||
COMMAND ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||
|
||||
# Create folder
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace linuxdeploy {
|
||||
bool deployDependenciesForExistingFiles();
|
||||
|
||||
// disable deployment of copyright files for this instance
|
||||
bool setDisableCopyrightFilesDeployment(bool disable);
|
||||
void setDisableCopyrightFilesDeployment(bool disable);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,10 @@ namespace linuxdeploy {
|
||||
class PrivateData;
|
||||
std::shared_ptr<PrivateData> d;
|
||||
|
||||
// (in)equality operators are implemented outside this class
|
||||
friend bool operator==(const DesktopFile& first, const DesktopFile& second);
|
||||
friend bool operator!=(const DesktopFile& first, const DesktopFile& second);
|
||||
|
||||
public:
|
||||
// default constructor
|
||||
DesktopFile();
|
||||
@@ -50,12 +54,6 @@ namespace linuxdeploy {
|
||||
// move assignment operator
|
||||
DesktopFile& operator=(DesktopFile&& other) noexcept;
|
||||
|
||||
// equality operator
|
||||
bool operator==(const DesktopFile& other);
|
||||
|
||||
// inequality operator
|
||||
bool operator!=(const DesktopFile& other);
|
||||
|
||||
public:
|
||||
// returns true if a file has been loaded, false otherwise
|
||||
bool isEmpty() const;
|
||||
@@ -95,21 +93,11 @@ namespace linuxdeploy {
|
||||
// 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;
|
||||
|
||||
// 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, DesktopFileEntry& 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);
|
||||
|
||||
// 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
|
||||
@@ -118,7 +106,7 @@ namespace linuxdeploy {
|
||||
// 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 DesktopFileEntry&& entry);
|
||||
bool setEntry(const std::string& section, DesktopFileEntry&& entry);
|
||||
|
||||
// create common application entries in desktop file
|
||||
// returns false if one of the keys exists and was left unmodified
|
||||
@@ -127,6 +115,12 @@ namespace linuxdeploy {
|
||||
// validate desktop file
|
||||
bool validate() const;
|
||||
};
|
||||
|
||||
// DesktopFile equality operator
|
||||
bool operator==(const DesktopFile& first, const DesktopFile& second);
|
||||
|
||||
// DesktopFile inequality operator
|
||||
bool operator!=(const DesktopFile& first, const DesktopFile& second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,17 +50,13 @@ namespace linuxdeploy {
|
||||
const std::string& value() const;
|
||||
|
||||
public:
|
||||
// allow conversion of entry to string
|
||||
// returns value
|
||||
explicit operator std::string() const;
|
||||
|
||||
// convert value to integer
|
||||
// throws boost::bad_lexical_cast in case of type errors
|
||||
int asInt() const;
|
||||
int32_t asInt() const;
|
||||
|
||||
// convert value to long
|
||||
// throws boost::bad_lexical_cast in case of type errors
|
||||
long asLong() const;
|
||||
int64_t asLong() const;
|
||||
|
||||
// convert value to double
|
||||
// throws boost::bad_lexical_cast in case of type errors
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace core {
|
||||
namespace desktopfile {
|
||||
/**
|
||||
* Desktop file library's base exception.
|
||||
*/
|
||||
class DesktopFileError : public std::runtime_error {
|
||||
public:
|
||||
explicit DesktopFileError(const std::string& message = "unknown desktop file error") : runtime_error(message) {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Exception thrown by DesktopFileReader on parsing errors.
|
||||
*/
|
||||
class ParseError : public DesktopFileError {
|
||||
public:
|
||||
explicit ParseError(const std::string& message = "unknown parse error") : DesktopFileError(message) {};
|
||||
};
|
||||
|
||||
/**
|
||||
* I/O exception, thrown if files cannot be opened, reading or writing fails etc.
|
||||
*/
|
||||
class IOError : public DesktopFileError {
|
||||
public:
|
||||
explicit IOError(const std::string& message = "unknown I/O error") : DesktopFileError(message) {};
|
||||
};
|
||||
|
||||
class UnknownSectionError : public DesktopFileError {
|
||||
public:
|
||||
explicit UnknownSectionError(const std::string& section) : DesktopFileError("unknown section: " + section) {};
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,8 +38,8 @@ namespace linuxdeploy {
|
||||
apiLevel = getApiLevelFromExecutable();
|
||||
pluginType = getPluginTypeFromExecutable();
|
||||
|
||||
boost::cmatch res;
|
||||
boost::regex_match(path.filename().c_str(), res, PLUGIN_EXPR);
|
||||
std::smatch res;
|
||||
std::regex_match(path.filename().string(), res, PLUGIN_EXPR);
|
||||
name = res[1].str();
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
// system includes
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
// library includes
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <regex>
|
||||
|
||||
// local includes
|
||||
#include "linuxdeploy/core/log.h"
|
||||
@@ -22,7 +19,7 @@ namespace linuxdeploy {
|
||||
/*
|
||||
* Official regular expression to check filenames for plugins
|
||||
*/
|
||||
static const boost::regex PLUGIN_EXPR(R"(^linuxdeploy-plugin-([^\s\.-]+)(?:-[^\.]+)?(?:\..+)?$)");
|
||||
static const std::regex PLUGIN_EXPR(R"(^linuxdeploy-plugin-([^\s\.-]+)(?:-[^\.]+)?(?:\..+)?$)");
|
||||
|
||||
/*
|
||||
* Plugin interface.
|
||||
|
||||
+1
-9
@@ -94,14 +94,6 @@ if(NOT USE_SYSTEM_BOOST)
|
||||
target_include_directories(boost_filesystem PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/boost-filesystem/include)
|
||||
target_link_libraries(boost_filesystem PUBLIC boost_config boost_utility boost_system)
|
||||
|
||||
file(GLOB boost_regex_srcs ${CMAKE_CURRENT_SOURCE_DIR}/boost-regex/src/*.cpp)
|
||||
add_library(boost_regex STATIC ${boost_regex_srcs})
|
||||
target_include_directories(boost_regex PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/boost-regex/include)
|
||||
target_link_libraries(boost_regex PUBLIC
|
||||
boost_config boost_predef boost_assert boost_throw_exception boost_smart_ptr boost_core boost_mpl
|
||||
boost_type_traits boost_static_assert boost_integer boost_preprocessor boost_functional boost_detail
|
||||
)
|
||||
|
||||
add_library(boost_numeric_conversion INTERFACE)
|
||||
set_property(TARGET boost_numeric_conversion PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-numeric_conversion/include>")
|
||||
set_property(TARGET boost_numeric_conversion PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
|
||||
@@ -130,7 +122,7 @@ if(NOT USE_SYSTEM_BOOST)
|
||||
add_library(boost_lexical_cast INTERFACE)
|
||||
set_property(TARGET boost_lexical_cast PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-lexical_cast/include>")
|
||||
set_property(TARGET boost_lexical_cast PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
|
||||
target_link_libraries(boost_lexical_cast INTERFACE boost_concept_check boost_numeric_conversion boost_array boost_container boost_math)
|
||||
target_link_libraries(boost_lexical_cast INTERFACE boost_concept_check boost_numeric_conversion boost_array boost_container boost_math boost_integer)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
|
||||
Submodule lib/boost-regex deleted from a9fc8fb5de
+2
-2
@@ -7,10 +7,10 @@ include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||
if(USE_SYSTEM_BOOST)
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
find_package(Boost REQUIRED COMPONENTS filesystem regex)
|
||||
set(BOOST_LIBS Boost::filesystem Boost::regex)
|
||||
set(BOOST_LIBS Boost::filesystem)
|
||||
else()
|
||||
# use custom built libs
|
||||
set(BOOST_LIBS boost_system boost_filesystem boost_regex boost_lexical_cast)
|
||||
set(BOOST_LIBS boost_system boost_filesystem boost_lexical_cast)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
+18
-16
@@ -12,6 +12,7 @@
|
||||
|
||||
// local headers
|
||||
#include "linuxdeploy/core/appdir.h"
|
||||
#include "linuxdeploy/core/desktopfile/desktopfileentry.h"
|
||||
#include "linuxdeploy/core/elf.h"
|
||||
#include "linuxdeploy/core/log.h"
|
||||
#include "linuxdeploy/util/util.h"
|
||||
@@ -21,6 +22,7 @@
|
||||
#include "excludelist.h"
|
||||
|
||||
using namespace linuxdeploy::core;
|
||||
using namespace linuxdeploy::core::desktopfile;
|
||||
using namespace linuxdeploy::core::log;
|
||||
|
||||
using namespace cimg_library;
|
||||
@@ -441,7 +443,7 @@ namespace linuxdeploy {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool deployDesktopFile(const desktopfile::DesktopFile& desktopFile) {
|
||||
bool deployDesktopFile(const DesktopFile& desktopFile) {
|
||||
if (hasBeenVisitedAlready(desktopFile.path())) {
|
||||
ldLog() << LD_DEBUG << "File has been visited already:" << desktopFile.path() << std::endl;
|
||||
return true;
|
||||
@@ -586,7 +588,7 @@ namespace linuxdeploy {
|
||||
return d->deployExecutable(path, destination);
|
||||
}
|
||||
|
||||
bool AppDir::deployDesktopFile(const desktopfile::DesktopFile& desktopFile) {
|
||||
bool AppDir::deployDesktopFile(const DesktopFile& desktopFile) {
|
||||
return d->deployDesktopFile(desktopFile);
|
||||
}
|
||||
|
||||
@@ -640,8 +642,8 @@ namespace linuxdeploy {
|
||||
return listFilesInDirectory(path() / "usr/bin/", false);
|
||||
}
|
||||
|
||||
std::vector<desktopfile::DesktopFile> AppDir::deployedDesktopFiles() {
|
||||
std::vector<desktopfile::DesktopFile> desktopFiles;
|
||||
std::vector<DesktopFile> AppDir::deployedDesktopFiles() {
|
||||
std::vector<DesktopFile> desktopFiles;
|
||||
|
||||
auto paths = listFilesInDirectory(path() / "usr/share/applications/", false);
|
||||
paths.erase(std::remove_if(paths.begin(), paths.end(), [](const bf::path& path) {
|
||||
@@ -655,7 +657,7 @@ namespace linuxdeploy {
|
||||
return desktopFiles;
|
||||
}
|
||||
|
||||
bool AppDir::createLinksInAppDirRoot(const desktopfile::DesktopFile& desktopFile, boost::filesystem::path customAppRunPath) {
|
||||
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
|
||||
@@ -665,9 +667,9 @@ namespace linuxdeploy {
|
||||
}
|
||||
|
||||
// look for suitable icon
|
||||
std::string iconName;
|
||||
DesktopFileEntry iconEntry;
|
||||
|
||||
if (!desktopFile.getEntry("Desktop Entry", "Icon", iconName)) {
|
||||
if (!desktopFile.getEntry("Desktop Entry", "Icon", iconEntry)) {
|
||||
ldLog() << LD_ERROR << "Icon entry missing in desktop file:" << desktopFile.path() << std::endl;
|
||||
return false;
|
||||
}
|
||||
@@ -677,16 +679,16 @@ namespace linuxdeploy {
|
||||
const auto foundIconPaths = deployedIconPaths();
|
||||
|
||||
if (foundIconPaths.empty()) {
|
||||
ldLog() << LD_ERROR << "Could not find icon executable for Icon entry:" << iconName << std::endl;
|
||||
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() == iconName;
|
||||
const bool matchesFilenameWithExtension = iconPath.filename() == iconEntry.value();
|
||||
|
||||
if (iconPath.stem() == iconName || matchesFilenameWithExtension) {
|
||||
if (iconPath.stem() == iconEntry.value() || matchesFilenameWithExtension) {
|
||||
if (matchesFilenameWithExtension) {
|
||||
ldLog() << LD_WARNING << "Icon= entry filename contains extension" << std::endl;
|
||||
}
|
||||
@@ -704,7 +706,7 @@ namespace linuxdeploy {
|
||||
}
|
||||
|
||||
if (!iconDeployed) {
|
||||
ldLog() << LD_ERROR << "Could not find suitable icon for Icon entry:" << iconName << std::endl;
|
||||
ldLog() << LD_ERROR << "Could not find suitable icon for Icon entry:" << iconEntry.value() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -722,15 +724,15 @@ namespace linuxdeploy {
|
||||
ldLog() << LD_WARNING << "Custom AppRun detected, skipping deployment of symlink" << std::endl;
|
||||
} else {
|
||||
// look for suitable binary to create AppRun symlink
|
||||
std::string executableName;
|
||||
DesktopFileEntry executableEntry;
|
||||
|
||||
if (!desktopFile.getEntry("Desktop Entry", "Exec", executableName)) {
|
||||
if (!desktopFile.getEntry("Desktop Entry", "Exec", executableEntry)) {
|
||||
ldLog() << LD_ERROR << "Exec entry missing in desktop file:" << desktopFile.path()
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
executableName = util::split(executableName)[0];
|
||||
auto executableName = util::split(executableEntry.value())[0];
|
||||
|
||||
const auto foundExecutablePaths = deployedExecutablePaths();
|
||||
|
||||
@@ -776,7 +778,7 @@ namespace linuxdeploy {
|
||||
}
|
||||
|
||||
bool AppDir::createRelativeSymlink(const bf::path& target, const bf::path& symlink) {
|
||||
d->symlinkFile(target, symlink, true);
|
||||
return d->symlinkFile(target, symlink, true);
|
||||
}
|
||||
|
||||
std::vector<bf::path> AppDir::listExecutables() {
|
||||
@@ -841,7 +843,7 @@ namespace linuxdeploy {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AppDir::setDisableCopyrightFilesDeployment(bool disable) {
|
||||
void AppDir::setDisableCopyrightFilesDeployment(bool disable) {
|
||||
d->disableCopyrightFilesDeployment = disable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// local headers
|
||||
#include "linuxdeploy/core/desktopfile/exceptions.h"
|
||||
#include "linuxdeploy/core/desktopfile/desktopfile.h"
|
||||
#include "linuxdeploy/core/log.h"
|
||||
#include "desktopfilereader.h"
|
||||
@@ -34,10 +35,15 @@ namespace linuxdeploy {
|
||||
DesktopFile::DesktopFile() : d(std::make_shared<PrivateData>()) {}
|
||||
|
||||
DesktopFile::DesktopFile(const bf::path& path) : DesktopFile() {
|
||||
if (bf::exists(path)) {
|
||||
// will throw exceptions in case of issues
|
||||
read(path);
|
||||
// if the file doesn't exist, an exception shall be thrown
|
||||
// otherwise, a user cannot know for sure whether a file was actually read (would need to check this
|
||||
// manually beforehand
|
||||
if (!bf::exists(path)) {
|
||||
throw IOError("Could not find file " + path.string());
|
||||
}
|
||||
|
||||
// will throw exceptions in case of issues
|
||||
read(path);
|
||||
};
|
||||
|
||||
DesktopFile::DesktopFile(std::istream& is) : DesktopFile() {
|
||||
@@ -75,7 +81,7 @@ namespace linuxdeploy {
|
||||
clear();
|
||||
|
||||
DesktopFileReader reader(path);
|
||||
d->data = reader.data();
|
||||
d->data = std::move(reader.data());
|
||||
}
|
||||
|
||||
void DesktopFile::read(std::istream& is) {
|
||||
@@ -128,15 +134,6 @@ namespace linuxdeploy {
|
||||
return (it->second.find(key) != it->second.end());
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
d->data[section][key] = std::move(DesktopFileEntry(key, value));
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool DesktopFile::setEntry(const std::string& section, const DesktopFileEntry& entry) {
|
||||
// check if value exists -- used for return value
|
||||
auto rv = entryExists(section, entry.key());
|
||||
@@ -146,8 +143,8 @@ namespace linuxdeploy {
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool DesktopFile::setEntry(const std::string& section, const DesktopFileEntry&& entry) {
|
||||
// check if value exists -- used for return value
|
||||
bool DesktopFile::setEntry(const std::string& section, DesktopFileEntry&& entry) {
|
||||
// check if value exists -- used for return value
|
||||
auto rv = entryExists(section, entry.key());
|
||||
|
||||
d->data[section][entry.key()] = entry;
|
||||
@@ -155,20 +152,15 @@ namespace linuxdeploy {
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool DesktopFile::getEntry(const std::string& section, const std::string& key, std::string& value) const {
|
||||
if (!entryExists(section, key))
|
||||
return false;
|
||||
|
||||
value = d->data[section][key].value();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DesktopFile::getEntry(const std::string& section, const std::string& key, DesktopFileEntry& entry) const {
|
||||
if (!entryExists(section, key))
|
||||
return false;
|
||||
|
||||
entry = d->data[section][key];
|
||||
|
||||
// make sure keys are equal
|
||||
assert(key == entry.key());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -179,17 +171,17 @@ namespace linuxdeploy {
|
||||
|
||||
auto setDefault = [&rv, this](const std::string& section, const std::string& key, const std::string& value) {
|
||||
if (entryExists(section, key)) {
|
||||
std::string currentValue;
|
||||
if (!getEntry(section, key, currentValue))
|
||||
ldLog() << LD_ERROR << "This should never happen" << std::endl;
|
||||
DesktopFileEntry entry;
|
||||
|
||||
ldLog() << LD_WARNING << "Key exists, not modified:" << key << "(current value:" << currentValue << LD_NO_SPACE << ")" << std::endl;
|
||||
// this should never return false
|
||||
auto entryExists = getEntry(section, key, entry);
|
||||
assert(entryExists);
|
||||
|
||||
ldLog() << LD_WARNING << "Key exists, not modified:" << key << "(current value:" << entry.value() << LD_NO_SPACE << ")" << std::endl;
|
||||
rv = false;
|
||||
} else {
|
||||
if (setEntry(section, key, value)) {
|
||||
// *should* be unreachable
|
||||
rv = false;
|
||||
}
|
||||
auto entryOverwritten = setEntry(section, DesktopFileEntry(key, value));
|
||||
assert(!entryOverwritten);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -207,12 +199,12 @@ namespace linuxdeploy {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DesktopFile::operator==(const DesktopFile& other) {
|
||||
return d->data == other.d->data;
|
||||
bool operator==(const DesktopFile& first, const DesktopFile& second) {
|
||||
return first.d->path == second.d->path && first.d->data == second.d->data;
|
||||
}
|
||||
|
||||
bool DesktopFile::operator!=(const DesktopFile& other) {
|
||||
return !operator==(other);
|
||||
bool operator !=(const DesktopFile& first, const DesktopFile& second) {
|
||||
return !operator==(first, second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,16 +78,16 @@ namespace linuxdeploy {
|
||||
return d->value;
|
||||
}
|
||||
|
||||
int DesktopFileEntry::asInt() const {
|
||||
int32_t DesktopFileEntry::asInt() const {
|
||||
d->assertValueNotEmpty();
|
||||
|
||||
return lexical_cast<int>(value());
|
||||
return lexical_cast<int32_t>(value());
|
||||
}
|
||||
|
||||
long DesktopFileEntry::asLong() const {
|
||||
int64_t DesktopFileEntry::asLong() const {
|
||||
d->assertValueNotEmpty();
|
||||
|
||||
return lexical_cast<long>(value());
|
||||
return lexical_cast<int64_t>(value());
|
||||
}
|
||||
|
||||
double DesktopFileEntry::asDouble() const {
|
||||
@@ -120,10 +120,6 @@ namespace linuxdeploy {
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
DesktopFileEntry::operator std::string() const {
|
||||
return value();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
// local headers
|
||||
#include "linuxdeploy/util/util.h"
|
||||
#include "linuxdeploy/core/desktopfile/desktopfileentry.h"
|
||||
#include "linuxdeploy/core/desktopfile/exceptions.h"
|
||||
#include "desktopfilereader.h"
|
||||
|
||||
namespace bf = boost::filesystem;
|
||||
@@ -26,11 +27,12 @@ namespace linuxdeploy {
|
||||
|
||||
void assertPathIsNotEmptyAndFileExists() {
|
||||
if (path.empty())
|
||||
throw std::invalid_argument("empty path is not permitted");
|
||||
throw IOError("empty path is not permitted");
|
||||
}
|
||||
|
||||
void copyData(const std::shared_ptr<PrivateData>& other) {
|
||||
path = other->path;
|
||||
sections = other->sections;
|
||||
}
|
||||
|
||||
void parse(std::istream& file) {
|
||||
@@ -54,9 +56,20 @@ namespace linuxdeploy {
|
||||
if (len > 0 &&
|
||||
!((len >= 2 && (line[0] == '/' && line[1] == '/')) || (len >= 1 && line[0] == '#'))) {
|
||||
if (line[0] == '[') {
|
||||
if (line.find_last_of('[') != 0)
|
||||
throw ParseError("Multiple opening [ brackets");
|
||||
|
||||
// this line apparently introduces a new section
|
||||
auto closingBracketPos = line.find(']');
|
||||
auto lastClosingBracketPos = line.find_last_of(']');
|
||||
|
||||
if (closingBracketPos == std::string::npos)
|
||||
throw ParseError("No closing ] bracket in section header");
|
||||
else if (closingBracketPos != lastClosingBracketPos)
|
||||
throw ParseError("Two or more closing ] brackets in section header");
|
||||
|
||||
size_t length = len - 2;
|
||||
auto title = line.substr(1, line.find(']') - 1);
|
||||
auto title = line.substr(1, closingBracketPos - 1);
|
||||
|
||||
// set up the new section
|
||||
sections.insert(std::make_pair(title, DesktopFile::section_t()));
|
||||
@@ -64,11 +77,15 @@ namespace linuxdeploy {
|
||||
} else {
|
||||
// we require at least one section to be present in the desktop file
|
||||
if (currentSectionName.empty())
|
||||
throw std::invalid_argument("No section in desktop file");
|
||||
throw ParseError("No section in desktop file");
|
||||
|
||||
auto delimiterPos = line.find('=');
|
||||
if (delimiterPos == std::string::npos)
|
||||
throw ParseError("No = key/value delimiter found");
|
||||
|
||||
// this line should be a normal key-value pair
|
||||
std::string key = line.substr(0, line.find('='));
|
||||
std::string value = line.substr(line.find('=') + 1, line.size());
|
||||
std::string key = line.substr(0, delimiterPos);
|
||||
std::string value = line.substr(delimiterPos + 1, line.size());
|
||||
|
||||
// we can strip away any sort of leading or trailing whitespace safely
|
||||
linuxdeploy::util::trim(key);
|
||||
@@ -76,12 +93,26 @@ namespace linuxdeploy {
|
||||
|
||||
// empty keys are not allowed for obvious reasons
|
||||
if (key.empty())
|
||||
throw std::invalid_argument("Empty keys are not allowed");
|
||||
throw ParseError("Empty keys are not allowed");
|
||||
|
||||
// who are we to judge whether empty values are an issue
|
||||
// that'd require checking the key names and implementing checks per key according to the
|
||||
// freedesktop.org spec
|
||||
sections[currentSectionName][key] = DesktopFileEntry(key, value);
|
||||
// keys may only contain A-Za-z- characters according to specification
|
||||
for (const char c : key) {
|
||||
if (!(
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
(c >= 'a' && c <= 'z') ||
|
||||
(c >= '0' && c <= '9') ||
|
||||
(c == '-')
|
||||
))
|
||||
throw ParseError("Key contains invalid character " + std::string{c});
|
||||
}
|
||||
|
||||
auto& section = sections[currentSectionName];
|
||||
|
||||
// keys must be unique in the same section
|
||||
if (section.find(key) != section.end())
|
||||
throw ParseError("Key " + key + " found more than once");
|
||||
|
||||
section[key] = DesktopFileEntry(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,7 +128,7 @@ namespace linuxdeploy {
|
||||
|
||||
std::ifstream ifs(d->path.string());
|
||||
if (!ifs)
|
||||
throw std::invalid_argument("could not open file: " + d->path.string());
|
||||
throw IOError("could not open file: " + d->path.string());
|
||||
|
||||
d->parse(ifs);
|
||||
}
|
||||
@@ -135,7 +166,7 @@ namespace linuxdeploy {
|
||||
}
|
||||
|
||||
bool DesktopFileReader::operator==(const DesktopFileReader& other) const {
|
||||
return d->path == other.d->path;
|
||||
return d->path == other.d->path && d->sections == other.d->sections;
|
||||
}
|
||||
|
||||
bool DesktopFileReader::operator!=(const DesktopFileReader& other) const {
|
||||
@@ -156,7 +187,7 @@ namespace linuxdeploy {
|
||||
// the map would lazy-initialize a new entry in case the section doesn't exist
|
||||
// therefore explicitly checking whether the section exists, throwing an exception in case it does not
|
||||
if (it == d->sections.end())
|
||||
throw std::range_error("could not find section " + name);
|
||||
throw UnknownSectionError(name);
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
// local headers
|
||||
#include "linuxdeploy/util/util.h"
|
||||
#include "linuxdeploy/core/desktopfile/exceptions.h"
|
||||
#include "desktopfilewriter.h"
|
||||
|
||||
namespace bf = boost::filesystem;
|
||||
@@ -88,7 +89,7 @@ namespace linuxdeploy {
|
||||
std::ofstream ofs(path.string());
|
||||
|
||||
if (!ofs)
|
||||
throw std::runtime_error("could not open file for writing: " + path.string());
|
||||
throw IOError("could not open file for writing: " + path.string());
|
||||
|
||||
save(ofs);
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
// system includes
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
#include <utility>
|
||||
|
||||
// library includes
|
||||
#include <boost/regex.hpp>
|
||||
#include <subprocess.hpp>
|
||||
#include <sys/mman.h>
|
||||
|
||||
@@ -134,11 +134,11 @@ namespace linuxdeploy {
|
||||
|
||||
auto outputAndError = util::subprocess::check_output_error(lddProc);
|
||||
|
||||
const boost::regex expr(R"(\s*(.+)\s+\=>\s+(.+)\s+\((.+)\)\s*)");
|
||||
boost::smatch what;
|
||||
const std::regex expr(R"(\s*(.+)\s+\=>\s+(.+)\s+\((.+)\)\s*)");
|
||||
std::smatch what;
|
||||
|
||||
for (const auto& line : util::splitLines(outputAndError.first)) {
|
||||
if (boost::regex_search(line, what, expr)) {
|
||||
if (std::regex_search(line, what, expr)) {
|
||||
auto libraryPath = what[2].str();
|
||||
util::trim(libraryPath);
|
||||
paths.push_back(bf::absolute(libraryPath));
|
||||
|
||||
+41
-22
@@ -1,11 +1,11 @@
|
||||
// system headers
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// library headers
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <fnmatch.h>
|
||||
#include <subprocess.hpp>
|
||||
|
||||
@@ -64,30 +64,49 @@ namespace linuxdeploy {
|
||||
|
||||
ldLog() << LD_DEBUG << "Searching for plugins in directory" << dir << std::endl;
|
||||
|
||||
for (bf::directory_iterator i(dir); i != bf::directory_iterator(); ++i) {
|
||||
// file must be executable...
|
||||
if (bf::status(*i).permissions() & (bf::owner_exe | bf::group_exe | bf::others_exe)) {
|
||||
// ... and filename must match regular expression
|
||||
boost::cmatch res;
|
||||
if (boost::regex_match(i->path().filename().string().c_str(), res, PLUGIN_EXPR)) {
|
||||
try {
|
||||
auto name = res[1].str();
|
||||
auto* plugin = createPluginInstance(*i);
|
||||
if (plugin == nullptr) {
|
||||
ldLog() << LD_DEBUG << "Failed to create instance for plugin" << i->path();
|
||||
} else {
|
||||
ldLog() << LD_DEBUG << "Found plugin '" << LD_NO_SPACE << name << LD_NO_SPACE << "':" << plugin->path() << std::endl;
|
||||
bool extendedDebugLoggingEnabled = (getenv("DEBUG_PLUGIN_DETECTION") != nullptr);
|
||||
|
||||
if (foundPlugins.find(name) != foundPlugins.end()) {
|
||||
ldLog() << LD_DEBUG << "Already found" << name << "plugin in" << foundPlugins[name]->path() << std::endl;
|
||||
} else {
|
||||
foundPlugins[name] = plugin;
|
||||
}
|
||||
}
|
||||
} catch (const PluginError& e) {
|
||||
ldLog() << LD_WARNING << "Could not load plugin" << i->path() << LD_NO_SPACE << ": " << e.what();
|
||||
for (bf::directory_iterator i(dir); i != bf::directory_iterator(); ++i) {
|
||||
// must be a file, and not a directory
|
||||
if (bf::is_directory(bf::absolute(*i))) {
|
||||
if (extendedDebugLoggingEnabled)
|
||||
ldLog() << LD_DEBUG << "Entry is a directory, skipping:" << i->path() << std::endl;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// file must be executable...
|
||||
if (!(bf::status(*i).permissions() & (bf::owner_exe | bf::group_exe | bf::others_exe))) {
|
||||
if (extendedDebugLoggingEnabled)
|
||||
ldLog() << LD_DEBUG << "File/symlink is not executable, skipping:" << i->path() << std::endl;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// entry name must match regular expression
|
||||
std::smatch res;
|
||||
|
||||
if (!std::regex_match(i->path().filename().string(), res, PLUGIN_EXPR)) {
|
||||
ldLog() << LD_DEBUG << "Doesn't match plugin regex, skipping:" << i->path() << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
auto name = res[1].str();
|
||||
auto* plugin = createPluginInstance(*i);
|
||||
if (plugin == nullptr) {
|
||||
ldLog() << LD_DEBUG << "Failed to create instance for plugin" << i->path() << std::endl;;
|
||||
} else {
|
||||
ldLog() << LD_DEBUG << "Found plugin '" << LD_NO_SPACE << name << LD_NO_SPACE << "':" << plugin->path() << std::endl;
|
||||
|
||||
if (foundPlugins.find(name) != foundPlugins.end()) {
|
||||
ldLog() << LD_DEBUG << "Already found" << name << "plugin in" << foundPlugins[name]->path() << std::endl;
|
||||
} else {
|
||||
foundPlugins[name] = plugin;
|
||||
}
|
||||
}
|
||||
} catch (const PluginError& e) {
|
||||
ldLog() << LD_WARNING << "Could not load plugin" << i->path() << LD_NO_SPACE << ": " << e.what();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,8 +34,7 @@ namespace linuxdeploy {
|
||||
if (size == 0)
|
||||
continue;
|
||||
|
||||
if (size > buf.size())
|
||||
throw std::runtime_error("Read more bytes than buffer size");
|
||||
assert(size <= buf.size());
|
||||
|
||||
auto outBufSize = outBuf.size();
|
||||
outBuf.reserve(outBufSize + size + 1);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user