61 Commits

Author SHA1 Message Date
TheAssassin 8e0fdc80b0 Fix linking issues, mk. 2 2018-11-28 11:07:20 +01:00
TheAssassin 3a96c5e880 Fix linking issues 2018-11-28 11:03:08 +01:00
TheAssassin 0bc12dfd95 Use std::regex library instead of boost one
Works equally fine for us, and allows for removing a dependency.
2018-11-28 10:59:09 +01:00
TheAssassin b7faefdc56 Merge pull request #60 from linuxdeploy/issue-59
Ship 32-bit strip binary
2018-11-24 00:44:39 +01:00
TheAssassin 4585cb1a28 Download known working version of strip for i386, mk. 2 2018-11-24 00:34:38 +01:00
TheAssassin 23c85c732a Download known working version of strip for i386 2018-11-24 00:04:40 +01:00
TheAssassin b3e259bda1 Merge branch 'master' into issue-59 2018-11-23 22:08:37 +01:00
TheAssassin d42abe363c Merge pull request #61 from linuxdeploy/debug-desktopfile-unit-tests-in-release-builds
Fix desktop file parser unit test failures
2018-11-23 22:08:03 +01:00
TheAssassin ef90b09c79 Fix remaining issues with usage of assert 2018-11-23 20:52:54 +01:00
TheAssassin ce097235f2 Note for self: -O1+ strips out expressions surrounded by assert() 2018-11-23 18:05:56 +01:00
TheAssassin d65574544f Ship 32-bit strip binary, mk. 3 2018-11-23 17:55:53 +01:00
TheAssassin b38612d07e Ship 32-bit strip binary, mk. 2 2018-11-23 17:17:38 +01:00
TheAssassin 9cddf75449 Ship 32-bit strip binary 2018-11-23 16:32:43 +01:00
TheAssassin b974f44ffd Debug desktop file unit tests, mk.1
They're only broken on non-debug builds, so it's quite likely the
optimizations break the code.
2018-11-21 00:03:20 +01:00
TheAssassin ecaeda4533 Deactivate unit tests that fail for no apparent reason on Travis CI
Will re-enable and debug them eventually. Right now, they prevent
binaries from being published, which is really a problem.
2018-11-19 22:25:20 +01:00
TheAssassin ccfd05b5e0 Improve DesktopFile's comparison operators 2018-11-19 22:12:14 +01:00
TheAssassin 6cf9bc55a7 Fix comparison editor 2018-11-19 22:06:29 +01:00
TheAssassin 1e3e074f35 Properly copy desktop file reader 2018-11-19 22:06:08 +01:00
TheAssassin 7b16864dbe Add missing return statement 2018-11-19 21:51:26 +01:00
TheAssassin 0b5ab2fc36 Fix return type of setter 2018-11-19 21:51:26 +01:00
TheAssassin b3d0e7f20f Merge pull request #57 from linuxdeploy/fix-plugin-detection
Fix plugin detection
2018-11-19 21:09:23 +01:00
TheAssassin 132931772c Fix directory check 2018-11-19 20:52:45 +01:00
TheAssassin 6f7a2fd54a Reduce verbosity of debug logging related to plugin detection 2018-11-19 20:50:09 +01:00
TheAssassin c4258759b4 Make sure directories aren't falsely recognized as plugins 2018-11-19 20:48:04 +01:00
TheAssassin 786a24cb25 Fix CMake syntax 2018-11-16 00:25:27 +01:00
TheAssassin 35f1acf00d Cleaning up coverage data after creating them makes no sense
The cleanup shall take place before running the test binaries which
create the new data, not afterwards.
2018-11-16 00:23:03 +01:00
TheAssassin be0a891770 Improve test fixture names 2018-11-15 23:45:42 +01:00
TheAssassin 92a1370b30 Be able to use EXPECT_EQ with DesktopFile objects
GoogleTest internally uses operator==(first, second) instead of
first.operator==(second). By implementing the operators outside the
classes, GoogleTest can be made happy.
2018-11-15 23:36:04 +01:00
TheAssassin 541da1b573 Test (in)equality operators 2018-11-15 23:32:36 +01:00
TheAssassin f274de8045 Make sure default keys don't overwrite existing ones 2018-11-15 21:24:08 +01:00
TheAssassin 6a951558ce Use assert to check for impossible scenarios 2018-11-15 21:23:43 +01:00
TheAssassin a4b13a1916 Clean up coverage data before new run
This makes sure that reports on subsequent runs are accurate.
2018-11-15 21:19:22 +01:00
TheAssassin 1c4e4a3888 Remove redundant setters/getters 2018-11-15 20:53:16 +01:00
TheAssassin e4bf795211 No need for a string conversion operator
Doesn't make sense here anyway.
2018-11-15 20:44:43 +01:00
TheAssassin e994eacfa0 Prevent unnecessary log messages in unit tests 2018-11-15 19:08:03 +01:00
TheAssassin beb2ee15be Don't use exceptions to detect abnormal behavior
https://isocpp.org/wiki/faq/exceptions#why-not-exceptions
2018-11-15 18:48:58 +01:00
TheAssassin 2e1a37ccf5 Fix path to test data 2018-11-15 18:05:08 +01:00
TheAssassin 520ac6de9b Reduce amount of implicit behavior in desktop file parser 2018-11-15 18:03:46 +01:00
TheAssassin 1bcdcab057 Restructure desktop file tests, build single binary 2018-11-15 17:58:02 +01:00
TheAssassin 1d9c907ec3 Merge pull request #55 from linuxdeploy/test_desktopfile_parser_conformance
Test desktopfile parser conformance
2018-11-15 17:51:06 +01:00
TheAssassin 3e584f5551 Merge branch 'master' into test_desktopfile_parser_conformance 2018-11-15 17:21:23 +01:00
TheAssassin f7975f1b80 Use return types with guaranteed sizes
This will ensure the conversions work equally on both 32-bit platforms
(int == long on 32-bit Linux systems, on 64 bit long > int).
2018-11-15 17:19:42 +01:00
TheAssassin 4af76a92c5 Fix duplicate key detection 2018-11-15 13:41:53 +01:00
TheAssassin b6f5f371b6 Avoid copying data more often than necessary c 2018-11-15 13:40:22 +01:00
TheAssassin d10e0614a1 Increase build speed of tests 2018-11-15 13:39:17 +01:00
TheAssassin 4ffa1a66ae Improve code style 2018-11-15 13:22:41 +01:00
TheAssassin 9707b81931 Fix basic format header checks 2018-11-15 13:14:31 +01:00
TheAssassin 21b12cc6b6 Use EXPECT instead of ASSERT 2018-11-15 13:01:10 +01:00
TheAssassin ae61f6b9d8 Update README.md 2018-11-15 01:35:09 +01:00
TheAssassin b43b04f693 Check for valid and invalid keys (spec/basic format) 2018-11-15 01:29:14 +01:00
TheAssassin 61fb8bebdb Fix execution of desktop file tests 2018-11-15 00:58:56 +01:00
TheAssassin 002ba4a496 Split two checks to make sure they're tested separately
Otherwise, one test case is always uncovered (either the first one
passes and the second one triggers, or the first one triggers and the
second one is never tested).
2018-11-14 11:22:38 +01:00
TheAssassin 244d82fede Test behavior on lines with multiple = characters 2018-11-14 11:19:02 +01:00
TheAssassin 9f8121ebff Check whether invalid lines are recognized 2018-11-14 11:16:35 +01:00
TheAssassin 80adfa8872 Recognize broken section headings, mk. 4 2018-11-14 11:14:24 +01:00
TheAssassin 4a07c8151e Make sure errors are recognized in all sections, not just the first one 2018-11-14 11:10:34 +01:00
TheAssassin ded20c162d Recognize broken section headings, mk. 3 2018-11-14 10:59:17 +01:00
TheAssassin bf152a509b Recognize broken section headings, mk. 2 2018-11-14 10:46:48 +01:00
TheAssassin dc8f446ca4 Recognize broken section headings, mk. 1 2018-11-14 10:41:47 +01:00
TheAssassin fbc1d78122 Use custom exceptions for error handling 2018-11-14 10:31:41 +01:00
TheAssassin 9b2ff305e0 Merge pull request #52 from linuxdeploy/generate-coverage-reports
Generate coverage reports
2018-11-10 19:54:05 +01:00
31 changed files with 832 additions and 425 deletions
-3
View File
@@ -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
+4
View File
@@ -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).
+12 -3
View File
@@ -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}
+1 -1
View File
@@ -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) {};
};
}
}
}
+2 -2
View File
@@ -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();
};
+2 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
}
+28 -36
View File
@@ -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);
}
}
}
+4 -8
View File
@@ -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();
}
}
}
};
+44 -13
View File
@@ -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;
}
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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();
}
}
}
+1 -2
View File
@@ -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