diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,8 @@ pkg_check_modules(FLATPAK flatpak>=0.6.12) +find_package(LIBFWUPD 1.0.7 REQUIRED) + if(NOT CMAKE_VERSION VERSION_LESS "3.10.0") # CMake 3.9+ warns about automoc on files without Q_OBJECT, and doesn't know about other macros. # 3.10+ lets us provide more macro names that require automoc. @@ -77,5 +79,10 @@ URL "http://www.freedesktop.org" PURPOSE "Required to build the Flatpak backend" TYPE OPTIONAL) +set_package_properties(LIBFWUPD PROPERTIES + DESCRIPTION "Library that exposes fwupd" + URL "http://www.fwupd.org" + PURPOSE "Required to build the Fwupd backend" + TYPE OPTIONAL) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/cmake/FindGIO.cmake b/cmake/FindGIO.cmake new file mode 100644 --- /dev/null +++ b/cmake/FindGIO.cmake @@ -0,0 +1,198 @@ +# FindGIO.cmake +# +# +# CMake support for GIO. +# +# License: +# +# Copyright (c) 2016 Evan Nemerson +# +# 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. + +find_package(PkgConfig) + +set(GIO_DEPS + GObject) + +if(PKG_CONFIG_FOUND) + pkg_search_module(GIO_PKG gio-2.0) +endif() + +find_library(GIO_LIBRARY gio-2.0 HINTS ${GIO_PKG_LIBRARY_DIRS}) +set(GIO "gio-2.0") + +if(GIO_LIBRARY AND NOT GIO_FOUND) + add_library(${GIO} SHARED IMPORTED) + set_property(TARGET ${GIO} PROPERTY IMPORTED_LOCATION "${GIO_LIBRARY}") + set_property(TARGET ${GIO} PROPERTY INTERFACE_COMPILE_OPTIONS "${GIO_PKG_CFLAGS_OTHER}") + + find_path(GIO_INCLUDE_DIR "gio/gio.h" + HINTS ${GIO_PKG_INCLUDE_DIRS}) + + find_package(GLib) + find_package(GObject) + set(GIO_VERSION "${GLib_VERSION}") + + list(APPEND GIO_DEPS_FOUND_VARS "GObject_FOUND") + list(APPEND GIO_INCLUDE_DIRS ${GObject_INCLUDE_DIRS}) + + set_property (TARGET "${GIO}" APPEND PROPERTY INTERFACE_LINK_LIBRARIES "gobject-2.0") + set_property(TARGET ${GIO} PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${GIO_INCLUDE_DIR}") +endif() + +find_program(GLib_COMPILE_SCHEMAS glib-compile-schemas) +if(GLib_COMPILE_SCHEMAS AND NOT GLib_FOUND) + add_executable(glib-compile-schemas IMPORTED) + set_property(TARGET glib-compile-schemas PROPERTY IMPORTED_LOCATION "${GLib_COMPILE_SCHEMAS}") +endif() + +# glib_install_schemas( +# [DESTINATION directory] +# schemas…) +# +# Validate and install the listed schemas. +function(glib_install_schemas) + set (options) + set (oneValueArgs DESTINATION) + set (multiValueArgs) + cmake_parse_arguments(GSCHEMA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + unset (options) + unset (oneValueArgs) + unset (multiValueArgs) + + foreach(schema ${GSCHEMA_UNPARSED_ARGUMENTS}) + get_filename_component(schema_name "${schema}" NAME) + string(REGEX REPLACE "^(.+)\.gschema.xml$" "\\1" schema_name "${schema_name}") + set(schema_output "${CMAKE_CURRENT_BINARY_DIR}/${schema_name}.gschema.xml.valid") + + add_custom_command( + OUTPUT "${schema_output}" + COMMAND glib-compile-schemas + --strict + --dry-run + --schema-file="${schema}" + COMMAND "${CMAKE_COMMAND}" ARGS -E touch "${schema_output}" + DEPENDS "${schema}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT "Validating ${schema}") + + add_custom_target("gsettings-schema-${schema_name}" ALL + DEPENDS "${schema_output}") + + if(CMAKE_INSTALL_FULL_DATADIR) + set(SCHEMADIR "${CMAKE_INSTALL_FULL_DATADIR}/glib-2.0/schemas") + else() + set(SCHEMADIR "${CMAKE_INSTALL_PREFIX}/share/glib-2.0/schemas") + endif() + install(FILES "${schema}" + DESTINATION "${SCHEMADIR}") + install(CODE "execute_process(COMMAND \"${GLib_COMPILE_SCHEMAS}\" \"${SCHEMADIR}\")") + endforeach() +endfunction() + +find_program(GLib_COMPILE_RESOURCES glib-compile-resources) +if(GLib_COMPILE_RESOURCES AND NOT GLib_FOUND) + add_executable(glib-compile-resources IMPORTED) + set_property(TARGET glib-compile-resources PROPERTY IMPORTED_LOCATION "${GLib_COMPILE_RESOURCES}") +endif() + +function(glib_compile_resources SPEC_FILE) + set (options INTERNAL) + set (oneValueArgs TARGET SOURCE_DIR HEADER SOURCE C_NAME) + set (multiValueArgs) + cmake_parse_arguments(GLib_COMPILE_RESOURCES "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + unset (options) + unset (oneValueArgs) + unset (multiValueArgs) + + if(NOT GLib_COMPILE_RESOURCES_SOURCE_DIR) + set(GLib_COMPILE_RESOURCES_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + endif() + + set(FLAGS) + + if(GLib_COMPILE_RESOURCES_INTERNAL) + list(APPEND FLAGS "--internal") + endif() + + if(GLib_COMPILE_RESOURCES_C_NAME) + list(APPEND FLAGS "--c-name" "${GLib_COMPILE_RESOURCES_C_NAME}") + endif() + + get_filename_component(SPEC_FILE "${SPEC_FILE}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + + execute_process( + COMMAND glib-compile-resources + --generate-dependencies + --sourcedir "${GLib_COMPILE_RESOURCES_SOURCE_DIR}" + "${SPEC_FILE}" + OUTPUT_VARIABLE deps + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REPLACE "\n" ";" deps ${deps}) + + if(GLib_COMPILE_RESOURCES_HEADER) + get_filename_component(GLib_COMPILE_RESOURCES_HEADER "${GLib_COMPILE_RESOURCES_HEADER}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}") + + add_custom_command( + OUTPUT "${GLib_COMPILE_RESOURCES_HEADER}" + COMMAND glib-compile-resources + --sourcedir "${GLib_COMPILE_RESOURCES_SOURCE_DIR}" + --generate-header + --target "${GLib_COMPILE_RESOURCES_HEADER}" + ${FLAGS} + "${SPEC_FILE}" + DEPENDS "${SPEC_FILE}" ${deps} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") + endif() + + if(GLib_COMPILE_RESOURCES_SOURCE) + get_filename_component(GLib_COMPILE_RESOURCES_SOURCE "${GLib_COMPILE_RESOURCES_SOURCE}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}") + + add_custom_command( + OUTPUT "${GLib_COMPILE_RESOURCES_SOURCE}" + COMMAND glib-compile-resources + --sourcedir "${GLib_COMPILE_RESOURCES_SOURCE_DIR}" + --generate-source + --target "${GLib_COMPILE_RESOURCES_SOURCE}" + ${FLAGS} + "${SPEC_FILE}" + DEPENDS "${SPEC_FILE}" ${deps} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") + endif() +endfunction() + +find_program(GDBUS_CODEGEN gdbus-codegen) +if(GDBUS_CODEGEN AND NOT GLib_FOUND) + add_executable(gdbus-codegen IMPORTED) + set_property(TARGET gdbus-codegen PROPERTY IMPORTED_LOCATION "${GDBUS_CODEGEN}") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GIO + REQUIRED_VARS + GIO_LIBRARY + GIO_INCLUDE_DIRS + ${GIO_DEPS_FOUND_VARS} + VERSION_VAR + GIO_VERSION) + +unset(GIO_DEPS_FOUND_VARS) diff --git a/cmake/FindGLib.cmake b/cmake/FindGLib.cmake new file mode 100644 --- /dev/null +++ b/cmake/FindGLib.cmake @@ -0,0 +1,83 @@ +# FindGLib.cmake +# +# +# CMake support for GLib/GObject/GIO. +# +# License: +# +# Copyright (c) 2016 Evan Nemerson +# +# 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. + +find_package(PkgConfig) + +if(PKG_CONFIG_FOUND) + pkg_search_module(GLib_PKG glib-2.0) +endif() + +find_library(GLib_LIBRARY glib-2.0 HINTS ${GLib_PKG_LIBRARY_DIRS}) +set(GLib glib-2.0) + +if(GLib_LIBRARY AND NOT GLib_FOUND) + add_library(${GLib} SHARED IMPORTED) + set_property(TARGET ${GLib} PROPERTY IMPORTED_LOCATION "${GLib_LIBRARY}") + set_property(TARGET ${GLib} PROPERTY INTERFACE_COMPILE_OPTIONS "${GLib_PKG_CFLAGS_OTHER}") + + find_path(GLib_INCLUDE_DIRS "glib.h" + HINTS ${GLib_PKG_INCLUDE_DIRS} + PATH_SUFFIXES "glib-2.0") + + get_filename_component(GLib_LIBDIR "${GLib}" DIRECTORY) + find_path(GLib_CONFIG_INCLUDE_DIR "glibconfig.h" + HINTS + ${GLib_LIBDIR} + ${GLib_PKG_INCLUDE_DIRS} + PATHS + "${CMAKE_LIBRARY_PATH}" + PATH_SUFFIXES + "glib-2.0/include" + "glib-2.0") + unset(GLib_LIBDIR) + + if(GLib_CONFIG_INCLUDE_DIR) + file(STRINGS "${GLib_CONFIG_INCLUDE_DIR}/glibconfig.h" GLib_MAJOR_VERSION REGEX "^#define GLIB_MAJOR_VERSION +([0-9]+)") + string(REGEX REPLACE "^#define GLIB_MAJOR_VERSION ([0-9]+)$" "\\1" GLib_MAJOR_VERSION "${GLib_MAJOR_VERSION}") + file(STRINGS "${GLib_CONFIG_INCLUDE_DIR}/glibconfig.h" GLib_MINOR_VERSION REGEX "^#define GLIB_MINOR_VERSION +([0-9]+)") + string(REGEX REPLACE "^#define GLIB_MINOR_VERSION ([0-9]+)$" "\\1" GLib_MINOR_VERSION "${GLib_MINOR_VERSION}") + file(STRINGS "${GLib_CONFIG_INCLUDE_DIR}/glibconfig.h" GLib_MICRO_VERSION REGEX "^#define GLIB_MICRO_VERSION +([0-9]+)") + string(REGEX REPLACE "^#define GLIB_MICRO_VERSION ([0-9]+)$" "\\1" GLib_MICRO_VERSION "${GLib_MICRO_VERSION}") + set(GLib_VERSION "${GLib_MAJOR_VERSION}.${GLib_MINOR_VERSION}.${GLib_MICRO_VERSION}") + unset(GLib_MAJOR_VERSION) + unset(GLib_MINOR_VERSION) + unset(GLib_MICRO_VERSION) + + list(APPEND GLib_INCLUDE_DIRS ${GLib_CONFIG_INCLUDE_DIR}) + set_property(TARGET ${GLib} PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${GLib_INCLUDE_DIRS}") + endif() +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GLib + REQUIRED_VARS + GLib_LIBRARY + GLib_INCLUDE_DIRS + VERSION_VAR + GLib_VERSION) diff --git a/cmake/FindGObject.cmake b/cmake/FindGObject.cmake new file mode 100644 --- /dev/null +++ b/cmake/FindGObject.cmake @@ -0,0 +1,81 @@ +# FindGObject.cmake +# +# +# CMake support for GObject. +# +# License: +# +# Copyright (c) 2016 Evan Nemerson +# +# 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. + +find_package(PkgConfig) + +set(GObject_DEPS + GLib) + +if(PKG_CONFIG_FOUND) + pkg_search_module(GObject_PKG gobject-2.0) +endif() + +find_library(GObject_LIBRARY gobject-2.0 HINTS ${GObject_PKG_LIBRARY_DIRS}) +set(GObject gobject-2.0) + +if(GObject_LIBRARY AND NOT GObject_FOUND) + add_library(${GObject} SHARED IMPORTED) + set_property(TARGET ${GObject} PROPERTY IMPORTED_LOCATION "${GObject_LIBRARY}") + set_property(TARGET ${GObject} PROPERTY INTERFACE_COMPILE_OPTIONS "${GObject_PKG_CFLAGS_OTHER}") + + find_path(GObject_INCLUDE_DIR "gobject/gobject.h" + HINTS ${GObject_PKG_INCLUDE_DIRS}) + + find_package(GLib) + set(GObject_VERSION "${GLib_VERSION}") + + list(APPEND GObject_DEPS_FOUND_VARS "GLib_FOUND") + list(APPEND GObject_INCLUDE_DIRS ${GLib_INCLUDE_DIRS}) + set_property(TARGET ${GObject} PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${GObject_INCLUDE_DIR}") + + set_property (TARGET "${GObject}" APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${GLib}") +endif() + +find_program(GLib_GENMARSHAL glib-genmarshal) +if(GLib_GENMARSHAL AND NOT GLib_FOUND) + add_executable(glib-genmarshal IMPORTED) + set_property(TARGET glib-genmarshal PROPERTY IMPORTED_LOCATION "${GLib_GENMARSHAL}") +endif() + +find_program(GLib_MKENUMS glib-mkenums) +if(GLib_MKENUMS AND NOT GLib_FOUND) + add_executable(glib-mkenums IMPORTED) + set_property(TARGET glib-mkenums PROPERTY IMPORTED_LOCATION "${GLib_MKENUMS}") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GObject + REQUIRED_VARS + GObject_LIBRARY + GObject_INCLUDE_DIRS + ${GObject_DEPS_FOUND_VARS} + VERSION_VAR + GObject_VERSION) + +unset(GObject_DEPS_FOUND_VARS) diff --git a/cmake/FindGObjectIntrospection.cmake b/cmake/FindGObjectIntrospection.cmake new file mode 100644 --- /dev/null +++ b/cmake/FindGObjectIntrospection.cmake @@ -0,0 +1,98 @@ +# FindGObjectIntrospection.cmake +# +# +# License: +# +# Copyright (c) 2016 Evan Nemerson +# +# 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. + +find_program(GObjectIntrospection_COMPILER_EXECUTABLE g-ir-compiler) +find_program(GObjectIntrospection_SCANNER_EXECUTABLE g-ir-scanner) + +if(CMAKE_INSTALL_FULL_DATADIR) + set(GObjectIntrospection_REPOSITORY_DIR "${CMAKE_INSTALL_FULL_DATADIR}/gir-1.0") +else() + set(GObjectIntrospection_REPOSITORY_DIR "${CMAKE_INSTALL_PREFIX}/share/gir-1.0") +endif() + +if(CMAKE_INSTALL_FULL_LIBDIR) + set(GObjectIntrospection_TYPELIB_DIR "${CMAKE_INSTALL_FULL_LIBDIR}/girepository-1.0") +else() + set(GObjectIntrospection_TYPELIB_DIR "${CMAKE_INSTALL_LIBDIR}/girepository-1.0") +endif() + +if(GObjectIntrospection_COMPILER_EXECUTABLE) + # Imported target + add_executable(g-ir-compiler IMPORTED) + set_property(TARGET g-ir-compiler PROPERTY IMPORTED_LOCATION "${GObjectIntrospection_COMPILER_EXECUTABLE}") +endif() + +if(GObjectIntrospection_SCANNER_EXECUTABLE) + # Imported target + add_executable(g-ir-scanner IMPORTED) + set_property(TARGET g-ir-scanner PROPERTY IMPORTED_LOCATION "${GObjectIntrospection_SCANNER_EXECUTABLE}") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GObjectIntrospection + REQUIRED_VARS + GObjectIntrospection_COMPILER_EXECUTABLE + GObjectIntrospection_SCANNER_EXECUTABLE) + +function(gobject_introspection_compile TYPELIB) + set (options DEBUG VERBOSE) + set (oneValueArgs MODULE SHARED_LIBRARY) + set (multiValueArgs FLAGS INCLUDE_DIRS) + cmake_parse_arguments(GObjectIntrospection_COMPILER "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + unset (options) + unset (oneValueArgs) + unset (multiValueArgs) + + get_filename_component(TYPELIB "${TYPELIB}" ABSOLUTE + BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}") + + if(GObjectIntrospection_COMPILER_DEBUG) + list(APPEND GObjectIntrospection_COMPILER_FLAGS "--debug") + endif() + + if(GObjectIntrospection_COMPILER_VERBOSE) + list(APPEND GObjectIntrospection_COMPILER_FLAGS "--verbose") + endif() + + if(GObjectIntrospection_SHARED_LIBRARY) + list(APPEND GObjectIntrospection_COMPILER_FLAGS "--shared-library" "${GObjectIntrospection_SHARED_LIBRARY}") + endif() + + foreach(include_dir ${GObjectIntrospection_COMPILER_INCLUDE_DIRS}) + list(APPEND GObjectIntrospection_COMPILER_FLAGS "--includedir" "${include_dir}") + endforeach() + + add_custom_command( + OUTPUT "${TYPELIB}" + COMMAND g-ir-compiler + ARGS + "-o" "${TYPELIB}" + ${GObjectIntrospection_COMPILER_FLAGS} + ${GObjectIntrospection_COMPILER_UNPARSED_ARGUMENTS} + DEPENDS + ${GObjectIntrospection_COMPILER_UNPARSED_ARGUMENTS}) +endfunction() diff --git a/cmake/FindLIBFWUPD.cmake b/cmake/FindLIBFWUPD.cmake new file mode 100644 --- /dev/null +++ b/cmake/FindLIBFWUPD.cmake @@ -0,0 +1,63 @@ +# - Try to find the Fwupd library +# Once done this will define +# +# LIBFWUPD_FOUND - system has the fwupd library +# LIBFWUPD_INCLUDE_DIR - the Fwupd include directory +# LIBFWUPD_LIBRARY - Link this to use the fwupd +# +# Copyright © 2018, Abhijeet Sharma +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +if(LIBFWUPD_INCLUDE_DIRS AND LIBFWUPD_LIBRARIES) + set(LIBFWUPD_FOUND TRUE) + +else (LIBFWUPD_INCLUDE_DIRS AND LIBFWUPD_LIBRARIES) + + find_library (LIBFWUPD_LIBRARIES + NAMES fwupd libfwupd + ) + + find_path (LIBFWUPD_INCLUDE_DIRS + NAMES fwupd.h + PATH_SUFFIXES fwupd-1 + HINTS fwupd-1/libfwupd + ) + set(LIBFWUPD_FOUND TRUE) + find_package(GIO) + find_package(Soup) + find_package(GLib) + + +endif (LIBFWUPD_INCLUDE_DIRS AND LIBFWUPD_LIBRARIES) + +if (LIBFWUPD_FOUND) + add_library(LIBFWUPD SHARED IMPORTED) + set_target_properties(LIBFWUPD PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${LIBFWUPD_INCLUDE_DIRS} + IMPORTED_LOCATION ${LIBFWUPD_LIBRARIES} + ) + add_dependencies(LIBFWUPD GIO Soup GLib) +endif() diff --git a/cmake/FindSoup.cmake b/cmake/FindSoup.cmake new file mode 100644 --- /dev/null +++ b/cmake/FindSoup.cmake @@ -0,0 +1,86 @@ +# FindSoup.cmake +# +# +# CMake support for libsoup. +# +# License: +# +# Copyright (c) 2016 Evan Nemerson +# +# 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. + +find_package(PkgConfig) + +set(Soup_DEPS + GIO) + +if(PKG_CONFIG_FOUND) + pkg_search_module(Soup_PKG libsoup-2.4) +endif() + +find_library(Soup_LIBRARY soup-2.4 HINTS ${Soup_PKG_LIBRARY_DIRS}) +set(Soup soup-2.4) + +if(Soup_LIBRARY AND NOT Soup_FOUND) + add_library(${Soup} SHARED IMPORTED) + set_property(TARGET ${Soup} PROPERTY IMPORTED_LOCATION "${Soup_LIBRARY}") + set_property(TARGET ${Soup} PROPERTY INTERFACE_COMPILE_OPTIONS "${Soup_PKG_CFLAGS_OTHER}") + + find_path(Soup_INCLUDE_DIR "libsoup/soup.h" + HINTS ${Soup_PKG_INCLUDE_DIRS}) + + if(Soup_INCLUDE_DIR) + file(STRINGS "${Soup_INCLUDE_DIR}/libsoup/soup-version.h" Soup_MAJOR_VERSION REGEX "^#define SOUP_MAJOR_VERSION +\\(?([0-9]+)\\)?$") + string(REGEX REPLACE "^#define SOUP_MAJOR_VERSION \\(([0-9]+)\\)$" "\\1" Soup_MAJOR_VERSION "${Soup_MAJOR_VERSION}") + file(STRINGS "${Soup_INCLUDE_DIR}/libsoup/soup-version.h" Soup_MINOR_VERSION REGEX "^#define SOUP_MINOR_VERSION +\\(?([0-9]+)\\)?$") + string(REGEX REPLACE "^#define SOUP_MINOR_VERSION \\(([0-9]+)\\)$" "\\1" Soup_MINOR_VERSION "${Soup_MINOR_VERSION}") + file(STRINGS "${Soup_INCLUDE_DIR}/libsoup/soup-version.h" Soup_MICRO_VERSION REGEX "^#define SOUP_MICRO_VERSION +\\(?([0-9]+)\\)?$") + string(REGEX REPLACE "^#define SOUP_MICRO_VERSION \\(([0-9]+)\\)$" "\\1" Soup_MICRO_VERSION "${Soup_MICRO_VERSION}") + set(Soup_VERSION "${Soup_MAJOR_VERSION}.${Soup_MINOR_VERSION}.${Soup_MICRO_VERSION}") + unset(Soup_MAJOR_VERSION) + unset(Soup_MINOR_VERSION) + unset(Soup_MICRO_VERSION) + + list(APPEND Soup_INCLUDE_DIRS ${Soup_INCLUDE_DIR}) + set_property(TARGET ${Soup} PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${Soup_INCLUDE_DIR}") + endif() +endif() + +set(Soup_DEPS_FOUND_VARS) +foreach(soup_dep ${Soup_DEPS}) + find_package(${soup_dep}) + + list(APPEND Soup_DEPS_FOUND_VARS "${soup_dep}_FOUND") + list(APPEND Soup_INCLUDE_DIRS ${${soup_dep}_INCLUDE_DIRS}) + + set_property (TARGET "${Soup}" APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${${soup_dep}}") +endforeach(soup_dep) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Soup + REQUIRED_VARS + Soup_LIBRARY + Soup_INCLUDE_DIRS + ${Soup_DEPS_FOUND_VARS} + VERSION_VAR + Soup_VERSION) + +unset(Soup_DEPS_FOUND_VARS) diff --git a/discover/qml/SourcesPage.qml b/discover/qml/SourcesPage.qml --- a/discover/qml/SourcesPage.qml +++ b/discover/qml/SourcesPage.qml @@ -45,6 +45,10 @@ Connections { target: backendItem.backend onPassiveMessage: window.showPassiveNotification(message) + onProceedRequest: { + var dialog = sourceProceedDialog.createObject(window, {sourcesBackend: sourcesBackend, title: title, description: description}) + dialog.open() + } } anchors { @@ -106,6 +110,7 @@ action: modelData.action } } + onObjectAdded: { settingsMenu.insertItem(index, object) } @@ -137,6 +142,56 @@ componentTrue: sourceBackendDelegate componentFalse: sourceDelegate } + Component { + id: sourceProceedDialog + Kirigami.OverlaySheet { + id: sheet + showCloseButton: false + property QtObject sourcesBackend + property alias title: heading.text + property alias description: desc.text + property bool acted: false + ColumnLayout { + Kirigami.Heading { + id: heading + } + Label { + id: desc + Layout.fillWidth: true + textFormat: Text.StyledText + wrapMode: Text.WordWrap + } + RowLayout { + Layout.alignment: Qt.AlignRight + Button { + text: i18n("Proceed") + icon.name: "dialog-ok" + onClicked: { + sourcesBackend.proceed() + sheet.acted = true + sheet.close() + } + } + Button { + Layout.alignment: Qt.AlignRight + text: i18n("Cancel") + icon.name: "dialog-cancel" + onClicked: { + sourcesBackend.cancel() + sheet.acted = true + sheet.close() + } + } + } + } + onSheetOpenChanged: if(!sheetOpen) { + sheet.destroy(1000) + if (!sheet.acted) + sourcesBackend.cancel() + } + } + } + Component { id: sourceDelegate @@ -188,7 +243,7 @@ checked: modelChecked != Qt.Unchecked enabled: modelChecked !== undefined onClicked: { - sourcesView.model.setData(modelIndex, checkedState, Qt.CheckStateRole) + sourcesView.model.setData(modelIndex, checkState, Qt.CheckStateRole) } } Label { diff --git a/libdiscover/backends/CMakeLists.txt b/libdiscover/backends/CMakeLists.txt --- a/libdiscover/backends/CMakeLists.txt +++ b/libdiscover/backends/CMakeLists.txt @@ -39,3 +39,8 @@ if(BUILD_SnapBackend AND Snapd_FOUND) add_subdirectory(SnapBackend) endif() + +option(BUILD_FwupdBackend "Build Fwupd support." "ON") +if(BUILD_FwupdBackend AND LIBFWUPD_FOUND) + add_subdirectory(FwupdBackend) +endif() \ No newline at end of file diff --git a/libdiscover/backends/FwupdBackend/CMakeLists.txt b/libdiscover/backends/FwupdBackend/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/CMakeLists.txt @@ -0,0 +1,27 @@ +add_subdirectory(tests) +add_definitions( -DPROJECT_NAME=${PROJECT_NAME} -DPROJECT_VERSION=${PROJECT_VERSION}) + +set(fwupd-backend_SRCS + FwupdResource.cpp + FwupdBackend.cpp + FwupdTransaction.cpp + FwupdSourcesBackend.cpp + FwupdUpdater.cpp +) + +find_package(GIO) + +include_directories(${LIBFWUPD_INCLUDE_DIRS} ) +add_library(fwupd-backend MODULE ${fwupd-backend_SRCS}) +target_link_libraries(fwupd-backend Qt5::Core Qt5::Widgets KF5::CoreAddons KF5::ConfigCore Discover::Common LIBFWUPD ${Soup} ${GIO} ${GLib} ) + +install(TARGETS fwupd-backend DESTINATION ${PLUGIN_INSTALL_DIR}/discover) +#install(FILES fwupd-backend-categories.xml DESTINATION ${DATA_INSTALL_DIR}/libdiscover/categories) + +add_library(FwupdNotifier MODULE FwupdNotifier.cpp ) +target_link_libraries(FwupdNotifier Discover::Notifiers) +set_target_properties(FwupdNotifier PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}/plasma-discover) + +install(TARGETS FwupdNotifier DESTINATION ${PLUGIN_INSTALL_DIR}/discover-notifier) + + diff --git a/libdiscover/backends/FwupdBackend/FwupdBackend.h b/libdiscover/backends/FwupdBackend/FwupdBackend.h new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/FwupdBackend.h @@ -0,0 +1,117 @@ +/*************************************************************************** + * Copyright © 2013 Aleix Pol Gonzalez * + * Copyright © 2018 Abhijeet Sharma * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License or (at your option) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifndef FWUPDBACKEND_H +#define FWUPDBACKEND_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +extern "C" { +#include +} +#include + +#define FWUPD_DEBUG // UnComment This to see all debug messages + +class QAction; +class FwupdUpdater; +class FwupdResource; +class FwupdBackend : public AbstractResourcesBackend +{ +Q_OBJECT +Q_PROPERTY(int startElements MEMBER m_startElements) +public: + explicit FwupdBackend(QObject* parent = NULL); + ~FwupdBackend(); + + int updatesCount() const override; + AbstractBackendUpdater* backendUpdater() const override; + AbstractReviewsBackend* reviewsBackend() const override; + ResultsStream* search(const AbstractResourcesBackend::Filters & search) override; + ResultsStream * findResourceByPackageName(const QUrl& search) ; + QHash resources() const { return m_resources; } + bool isValid() const override { return true; } // No external file dependencies that could cause runtime errors + + Transaction* installApplication(AbstractResource* app) override; + Transaction* installApplication(AbstractResource* app, const AddonList& addons) override; + Transaction* removeApplication(AbstractResource* app) override; + bool isFetching() const override { return m_fetching; } + AbstractResource * resourceForFile(const QUrl & ) override; + void checkForUpdates() override; + QString displayName() const override; + bool hasApplications() const override; + FwupdClient *client; + QList toDownload; + QList toIgnore; + + bool FwupdDownloadFile(const QUrl &uri,const QString &filename); + bool FwupdRefreshRemotes(uint cacheAge); + bool FwupdRefreshRemote(FwupdRemote *remote,uint cacheAge); + const QUrl FwupdCacheFile(const QString &kind,const QFileInfo &resource); + bool FwupdDownloadAllScheduled(uint cacheAge); + bool FwupdAddToScheduleForDownload(const QUrl uri); + FwupdResource * FwupdCreateDevice(FwupdDevice *device); + FwupdResource * FwupdCreateRelease(FwupdDevice *device); + bool FwupdAddToSchedule(FwupdDevice *device); + QByteArray FwupdGetChecksum(const QUrl filename,QCryptographicHash::Algorithm hashAlgorithm); + QString FwupdBuildDeviceID(FwupdDevice* device); + void FwupdAddUpdates(); + void FwupdSetReleaseDetails(FwupdResource *res,FwupdRelease *rel); + void FwupdSetDeviceDetails(FwupdResource *res,FwupdDevice *device); + void FwupdHandleError(GError **perror); + QSet FwupdGetAllUpdates(); + QString FwupdGetAppName(QString ID); + QMap initHashMap(); + + +public Q_SLOTS: + void toggleFetching(); + +private: + void populate(const QString& name); + + QHash m_resources; + FwupdUpdater* m_updater; + //FwupdReviewsBackend* m_reviews; + bool m_fetching; + int m_startElements; + QList m_toUpdate; +}; + +#endif // FWUPDBACKEND_H diff --git a/libdiscover/backends/FwupdBackend/FwupdBackend.cpp b/libdiscover/backends/FwupdBackend/FwupdBackend.cpp new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/FwupdBackend.cpp @@ -0,0 +1,758 @@ +/*************************************************************************** + * Copyright © 2013 Aleix Pol Gonzalez * + * Copyright © 2018 Abhijeet Sharma * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License or (at your option) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#include "FwupdBackend.h" +#include "FwupdResource.h" +#include "FwupdTransaction.h" +#include "FwupdSourcesBackend.h" +#include +#include +#include + +#include +#include +#include +#include +#include + +DISCOVER_BACKEND_PLUGIN(FwupdBackend) + +FwupdBackend::FwupdBackend(QObject* parent) + : AbstractResourcesBackend(parent) + , m_updater(new FwupdUpdater(this)) + , m_fetching(true) +{ + + QTimer::singleShot(500, this, &FwupdBackend::toggleFetching); + //connect(m_reviews, &FwupdReviewsBackend::ratingsReady, this, &AbstractResourcesBackend::emitRatingsReady); + connect(m_updater, &FwupdUpdater::updatesCountChanged, this, &FwupdBackend::updatesCountChanged); + + client = fwupd_client_new (); + + populate(QStringLiteral("Releases")); + SourcesModel::global()->addSourcesBackend(new FwupdSourcesBackend(this)); +} + +QMap FwupdBackend::initHashMap() +{ + QMap map; + + map.insert(G_CHECKSUM_SHA1,QCryptographicHash::Sha1); + map.insert(G_CHECKSUM_SHA256,QCryptographicHash::Sha256); + map.insert(G_CHECKSUM_SHA512,QCryptographicHash::Sha512); + map.insert(G_CHECKSUM_MD5,QCryptographicHash::Md5); + + return map; +} + +FwupdBackend::~FwupdBackend() +{ + g_object_unref (client); + toDownload.clear(); + toIgnore.clear(); +} + +QString FwupdBackend::FwupdBuildDeviceID(FwupdDevice* device) +{ + QString DeviceID = QLatin1String(fwupd_device_get_id (device)); + DeviceID.replace(QLatin1Char('/'),QLatin1Char('_')); + return QStringLiteral("org.fwupd.%1.device").arg(DeviceID); +} + +QString FwupdBackend::FwupdGetAppName(QString ID) +{ + //To Do Implement it! + return ID; +} + +QSet FwupdBackend::FwupdGetAllUpdates() +{ + QSet ret; + ret.reserve(m_toUpdate.size()); + foreach(FwupdResource* r, m_toUpdate) + { + AbstractResource* res = (AbstractResource*) r; + if(r->m_id.isEmpty()) + qDebug() << "Resource ID is Empty" << r->m_name; + ret.insert(res); + } + return ret; + +} + +FwupdResource * FwupdBackend::FwupdCreateDevice(FwupdDevice *device) +{ + const QString name = QLatin1String(fwupd_device_get_name(device)); + FwupdResource* res = new FwupdResource(name, true, this); + res->setId(FwupdBuildDeviceID(device)); + res->addCategories(QStringLiteral("Releases")); + res->setIconName(QLatin1String((const gchar *)g_ptr_array_index (fwupd_device_get_icons(device),0)));// Implement a Better way to decide icon + + FwupdSetDeviceDetails(res,device); + return res; +} + +FwupdResource * FwupdBackend::FwupdCreateRelease(FwupdDevice *device) +{ + FwupdRelease *rel = fwupd_device_get_release_default (device); + const QString name = QLatin1String(fwupd_release_get_name(rel)); + FwupdResource* res = new FwupdResource(name, true, this); + + res->setDeviceID(QLatin1String(fwupd_device_get_id (device))); + FwupdSetReleaseDetails(res,rel); + FwupdSetDeviceDetails(res,device); + + if (fwupd_release_get_appstream_id (rel)) + res->setId(QLatin1String(fwupd_release_get_appstream_id (rel))); + + /* the same as we have already */ + if(QLatin1Literal(fwupd_device_get_version (device)) == QLatin1Literal(fwupd_release_get_version (rel))) + { + qWarning() << "same firmware version as installed"; + } + + return res; + +} +void FwupdBackend::FwupdSetReleaseDetails(FwupdResource *res,FwupdRelease *rel) +{ + res->addCategories(QLatin1String("Releases")); + if(fwupd_release_get_summary(rel)) + res->setSummary(QLatin1String(fwupd_release_get_summary(rel))); + if(fwupd_release_get_vendor(rel)) + res->setVendor(QLatin1String(fwupd_release_get_vendor(rel))); + if(fwupd_release_get_version(rel)) + res->setVersion(QLatin1String(fwupd_release_get_version(rel))); + if(fwupd_release_get_description(rel)) + res->setDescription(QLatin1String((fwupd_release_get_description (rel)))); + if(fwupd_release_get_homepage(rel)) + res->setHomePage(QUrl(QLatin1String(fwupd_release_get_homepage(rel)))); + if(fwupd_release_get_license(rel)) + res->setLicense(QLatin1String(fwupd_release_get_license(rel))); + if (fwupd_release_get_uri (rel)) + res->m_updateURI = QLatin1String(fwupd_release_get_uri (rel)); +} +void FwupdBackend::FwupdSetDeviceDetails(FwupdResource *res,FwupdDevice *dev) +{ + res->isLiveUpdatable = fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); + res->isOnlyOffline = fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_OFFLINE); + res->needsReboot = fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + res->isDeviceRemoval = !fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); + + GPtrArray *guids = fwupd_device_get_guids (dev); + if(guids->len > 0) + { + QString guidStr = QLatin1Literal((char *)g_ptr_array_index (guids, 0)); + for (uint i = 1; i < guids->len; i++) + { + guidStr += QLatin1Char(',') + QLatin1Literal((char *)g_ptr_array_index (guids, i)); + } + res->guidString = guidStr; + } + if(fwupd_device_get_name (dev)) + { + QString vendorName; + vendorName.sprintf("%s",fwupd_device_get_name (dev)); + + if(vendorName.indexOf(QLatin1String(fwupd_device_get_vendor (dev))) == 0) + vendorName.sprintf("%s %s",fwupd_device_get_vendor (dev), fwupd_device_get_name (dev)); + res->setName(vendorName); + } + if(fwupd_device_get_summary (dev)) + res->setSummary(QLatin1String(fwupd_device_get_summary(dev))); + if(fwupd_device_get_vendor(dev)) + res->setVendor(QLatin1String(fwupd_device_get_vendor(dev))); + if(fwupd_device_get_version(dev)) + res->setVersion(QLatin1String(fwupd_device_get_version(dev))); + if(fwupd_device_get_description(dev)) + res->setDescription(QLatin1String((fwupd_device_get_description(dev)))); +} + +void FwupdBackend::populate(const QString& n) +{ + /* get devices */ + g_autoptr(GPtrArray) devices = fwupd_client_get_devices (client, NULL, NULL); + + if (devices) + { + for (uint i = 0; i < devices->len; i++) + { + FwupdDevice *device = (FwupdDevice *)g_ptr_array_index (devices, i); + + /* Devices Which are not updatable */ + if (!fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE)) + continue; + + /* add releases */ + FwupdResource * res = FwupdCreateDevice(device); + res->addCategories(n); + + + g_autoptr(GPtrArray) releases = fwupd_client_get_releases (client,res->m_deviceID.toUtf8().constData(),NULL,NULL); + + if (releases) + { + for (int j = 0; j < (int)releases->len; j++) + { + FwupdRelease *rel = (FwupdRelease *)g_ptr_array_index (releases, j); + const QString name = QLatin1String(fwupd_release_get_name(rel)); + FwupdResource* res_ = new FwupdResource(name, true, this); + FwupdSetReleaseDetails (res_, rel); + res->m_releases.append(res_); + } + } + /* add all Valid Resources */ + m_resources.insert(res->name().toLower(), res); + } + } +} + + +void FwupdBackend::FwupdAddUpdates() +{ + g_autoptr(GCancellable) cancellable = g_cancellable_new(); + g_autoptr(GError) error = NULL; + g_autoptr(GError) error2 = NULL; + g_autoptr(GPtrArray) devices = fwupd_client_get_devices (client, cancellable, &error); + g_autoptr(GPtrArray) rels = NULL; + + if(!devices) + { + if (g_error_matches (error,FWUPD_ERROR,FWUPD_ERROR_NOTHING_TO_DO)) + { + #ifdef FWUPD_DEBUG + qDebug() << "No Devices Found"; + #endif + FwupdHandleError(&error); + } + } + else{ + for (uint i = 0; i < devices->len; i++) + { + FwupdDevice *device = (FwupdDevice *)g_ptr_array_index (devices, i); + FwupdResource* res; + + res = FwupdCreateDevice(device); //just to test code should be deleted + if(!m_toUpdate.contains(res)) // Just To Test code Should Be deleted + m_toUpdate.append(res); //just to test code should be deleted + + if (!fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_SUPPORTED)) + continue; + + /*Device is Locked Needs Unlocking*/ + if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_LOCKED)) + { + res = FwupdCreateDevice(device); + res->setIsDeviceLocked(true); + if(!m_toUpdate.contains(res)) + m_toUpdate.append(res); + connect(res, &FwupdResource::stateChanged, this, &FwupdBackend::updatesCountChanged); + continue; + } + + + rels = fwupd_client_get_upgrades (client,fwupd_device_get_id(device),cancellable, &error2); + + if (!rels) + { + if (g_error_matches (error2,FWUPD_ERROR,FWUPD_ERROR_NOTHING_TO_DO)) + { + qWarning() << "No Packages Found for "<< fwupd_device_get_id(device); + FwupdHandleError(&error2); + continue; + } + } + else + { + fwupd_device_add_release(device,(FwupdRelease *)g_ptr_array_index(rels,0)); + if(FwupdAddToSchedule(device)) + { + qWarning() << "Cannot Add To Schdule" << fwupd_device_get_id(device); + continue; + } + } + } + } +} + + +QByteArray FwupdBackend::FwupdGetChecksum(const QUrl filename,QCryptographicHash::Algorithm hashAlgorithm) +{ + QFile f(filename.toString()); + if (f.open(QFile::ReadOnly)) + { + QCryptographicHash hash(hashAlgorithm); + if (hash.addData(&f)) + { + return hash.result().toHex(); + } + } + return QByteArray(); +} + +bool FwupdBackend::FwupdAddToSchedule(FwupdDevice *device) +{ + FwupdRelease *rel = fwupd_device_get_release_default (device); + GPtrArray *checksums; + FwupdResource* app = NULL; + + /* update unsupported */ + app = FwupdCreateRelease(device); + if (!app->isLiveUpdatable) + { + qWarning() << app->m_name << "[" << app->m_id << "]" << "cannot be updated "; + return false; + } + + /* Important Attributes missing */ + if (app->m_id.isNull()) + { + qWarning() << "fwupd: No id for firmware"; + return true; + } + if (app->m_version.isNull()) + { + qWarning() << "fwupd: No version! for " << app->m_id; + return true; + } + if (app->m_updateVersion.isNull()) + { + qWarning() << "fwupd: No update-version! for " << app->m_id; + return true; + } + checksums = fwupd_release_get_checksums (rel); + if (checksums->len == 0) + { + qWarning() << app->m_name << "[" << app->m_id << "]" << "(" << app->m_updateVersion << ")" "has no checksums, ignoring as unsafe"; + return false; + } + const QUrl update_uri(QLatin1String(fwupd_release_get_uri(rel))); + + if (!update_uri.isValid()) + { + qWarning() << "no location available for" << app->m_name << "[" << app->m_id << "]"; + return false; + } + + /* Checking for firmware in the cache? */ + QFileInfo basename = QFileInfo(update_uri.path()); + const QUrl filename_cache = FwupdCacheFile(QStringLiteral("fwupd"),basename); + if (!filename_cache.isValid()) + return false; + + if (filename_cache.isLocalFile()) + { + QByteArray checksum_tmp = QByteArray(fwupd_checksum_get_by_kind (checksums,G_CHECKSUM_SHA1)); + + /* Currently LVFS supports SHA1 only*/ + if (checksum_tmp.isNull()) + { + qWarning() << "No valid checksum for" << filename_cache; + } + QByteArray checksum = FwupdGetChecksum(filename_cache,QCryptographicHash::Sha1); + if (checksum.isNull()) + return false; + if (checksum_tmp != checksum) + { + qWarning() << filename_cache << " does not match checksum, expected" << checksum_tmp << "got" << checksum; + QFile::remove((filename_cache.toString())); + return false; + } + } + + /* link file to application and append to update list */ + QFile file(filename_cache.toString()); + app->m_file = &file; + if(!m_toUpdate.contains(app)) + m_toUpdate.append(app); + /* schedule for download */ + if (!filename_cache.isLocalFile()) + FwupdAddToScheduleForDownload(update_uri); + + return true; +} + +bool FwupdBackend::FwupdDownloadFile(const QUrl &uri,const QString &filename) +{ + QEventLoop loop; + QTimer getTimer; + QString fileName = filename; + QNetworkAccessManager *manager = new QNetworkAccessManager(this); + QTimer::connect(&getTimer,SIGNAL(timeout()),&loop, SLOT(quit())); + connect(manager, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit())); + QNetworkReply *reply = manager->get(QNetworkRequest(uri)); + getTimer.start(600000); // 60 Seconds TimeOout Period + loop.exec(); + if(!reply) + { + return false; + } + else if( QNetworkReply::NoError != reply->error() ) + { + return false; + } + else + { + QByteArray Data = reply->readAll(); + QFile file(fileName); + if (file.open(QIODevice::WriteOnly)) + { + file.write(Data); + } + file.close(); + delete reply; + delete manager; + return true; + } +} + +bool FwupdBackend::FwupdRefreshRemotes(uint cacheAge) +{ + g_autoptr(GCancellable) cancellable = g_cancellable_new(); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) remotes = fwupd_client_get_remotes (client, cancellable, &error); + if (!remotes) + return false; + for (uint i = 0; i < remotes->len; i++) + { + FwupdRemote *remote = (FwupdRemote *)g_ptr_array_index (remotes, i); + /*Remotes disabled by user so ignore*/ + if (!fwupd_remote_get_enabled (remote)) + continue; + /*Local Remotes Ignore*/ + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL) + continue; + /*Refresh the left ones*/ + if (!FwupdRefreshRemote(remote, cacheAge)) + return false; + } + return true; +} + +bool FwupdBackend::FwupdRefreshRemote(FwupdRemote* remote,uint cacheAge) +{ + g_autoptr(GCancellable) cancellable = g_cancellable_new(); + g_autoptr(GError) error = NULL; + + if (fwupd_remote_get_filename_cache_sig (remote) == NULL) + { + qWarning() << "Remote " << fwupd_remote_get_id (remote) << "has no cache signature!"; + return false; + } + + /* check cache age */ + if (cacheAge > 0) + { + quint64 age = fwupd_remote_get_age (remote); + uint tmp = age < std::numeric_limits::max() ? (uint) age : std::numeric_limits::max(); + if (tmp < cacheAge) + { + #ifdef FWUPD_DEBUG + qDebug() << remote << "is only" << tmp << "seconds old, so ignoring refresh! "; + #endif + return true; + } + } + + QString cacheId = QStringLiteral("fwupd/remotes.d/%1").arg(QString::fromUtf8(fwupd_remote_get_id (remote))); + QFileInfo basenameSig = QFileInfo(QString::fromUtf8(g_path_get_basename(fwupd_remote_get_filename_cache_sig (remote)))); + const QUrl filename_sig = FwupdCacheFile(cacheId,basenameSig); + + if (filename_sig.isEmpty()) + return false; + + /* download the signature first*/ + const QUrl url_sig(QLatin1String(fwupd_remote_get_metadata_uri_sig(remote))); + #ifdef FWUPD_DEBUG + qDebug() << "downloading remotes signatures ..."; + #endif + + const QUrl filename_sig_(filename_sig.toString() + QStringLiteral(".tmp")); + + if(!FwupdDownloadFile(url_sig,filename_sig_.toString())) + { + qDebug() << "remote signature download failed ..."; + return false; + } + + QMap map = initHashMap(); + QCryptographicHash::Algorithm hashAlgorithm = map[(fwupd_checksum_guess_kind (fwupd_remote_get_checksum (remote)))]; + QByteArray hash = FwupdGetChecksum(filename_sig_,hashAlgorithm); + + if (fwupd_remote_get_checksum (remote) == hash) + { + #ifdef FWUPD_DEBUG + qDebug() << "signature of" << url_sig.toString() << "is unchanged"; + #endif + return true; + } + + /* save to a file */ + #ifdef FWUPD_DEBUG + qDebug() << "saving new remote signature to:" << filename_sig.toString(); + #endif + + if (!(QFile::copy(filename_sig_.toString(),filename_sig.toString()))) + { + qWarning() << "cannot save remote signature"; + return false; + } + else + { + QFile::remove(filename_sig_.toString()); + } + + QFileInfo basename = QFileInfo(QString::fromUtf8(g_path_get_basename (fwupd_remote_get_filename_cache (remote)))); + const QUrl filename = FwupdCacheFile(cacheId,basename); + + if (filename.isEmpty()) + return false; + + #ifdef FWUPD_DEBUG + qDebug() << "saving new firmware metadata to:" << filename; + #endif + + const QUrl url(QLatin1String(fwupd_remote_get_metadata_uri (remote))); + if (!FwupdDownloadFile (url, filename.toString())) + { + qWarning() << "cannot download file : " << filename ; + return false; + } + /* Sending Metadata to fwupd Daemon*/ + if (!fwupd_client_update_metadata (client,fwupd_remote_get_id (remote),filename.toString().toUtf8().constData(),filename_sig.toString().toUtf8().constData(),cancellable,&error)) + { + FwupdHandleError(&error); + return false; + } + return true; +} + +void FwupdBackend::FwupdHandleError(GError **perror) +{ + GError *error = perror != NULL ? *perror : NULL; + + if(!error) + return; + //To DO Indivitual take action based on case,Show Notification on Discover; + switch (error->code) + { + case FWUPD_ERROR_ALREADY_PENDING: + qWarning() << "FWUPD_ERROR_ALREADY_PENDING"; + break; + case FWUPD_ERROR_INVALID_FILE: + qWarning() << "FWUPD_ERROR_INVALID_FILE"; + break; + case FWUPD_ERROR_NOT_SUPPORTED: + qWarning() << "FWUPD_ERROR_NOT_SUPPORTED"; + break; + case FWUPD_ERROR_AUTH_FAILED: + qWarning() << "FWUPD_ERROR_AUTH_FAILED"; + break; + case FWUPD_ERROR_SIGNATURE_INVALID: + qWarning() << "FWUPD_ERROR_SIGNATURE_INVALID"; + break; + case FWUPD_ERROR_AC_POWER_REQUIRED: + qWarning() << "FWUPD_ERROR_AC_POWER_REQUIRED"; + break; + default: + qWarning() << "Unknown Error ::" << error->code; + break; + } +} + +const QUrl FwupdBackend::FwupdCacheFile(const QString &kind,const QFileInfo &resource) +{ + QString basename = resource.fileName(); + const QDir cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); + const QUrl cacheDirFile = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1Char('/') + kind); + const QUrl fileUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1Char('/') + kind + QLatin1Char('/') + basename); + + if(!QFileInfo::exists(cacheDirFile.toLocalFile()) && !cacheDir.mkpath(kind)) + { + #ifdef FWUPD_DEBUG + qDebug() << "cannot make cache directory!"; + #endif + return QUrl(); + } + return QUrl(fileUrl.toString().remove(QStringLiteral("file://"))); +} +bool FwupdBackend::FwupdDownloadAllScheduled(uint cacheAge) +{ + if (!FwupdRefreshRemotes(cacheAge)) + return false; + + /* download the files to the cachedir */ + foreach(QUrl uri, toDownload) + { + const QUrl filename_cache = FwupdCacheFile(QStringLiteral("fwupd"),QFileInfo(uri.fileName())); + if(!filename_cache.isValid()) + return false; + /* download file */ + if(!FwupdDownloadFile(uri,filename_cache.toString())) + { + qWarning() <<"Failed to download " << uri.path() << "so, ignoring:" ; + if(!toIgnore.contains(uri)) + toIgnore.append(uri); + } + } + + return true; +} + +bool FwupdBackend::FwupdAddToScheduleForDownload(const QUrl uri) +{ + if(toIgnore.contains(uri)) + return false; + if(toDownload.contains(uri)) + return false; + else + { + toDownload.append(uri); + return true; + } +} + + +void FwupdBackend::toggleFetching() +{ + m_fetching = !m_fetching; + #ifdef FWUPD_DEBUG + qDebug() << "Fwupd fetching..." << m_fetching; + #endif + FwupdAddUpdates(); + FwupdDownloadAllScheduled(60*60*24*30); // Nicer Way to put time? currently 30 days in seconds + emit fetchingChanged(); +} + +int FwupdBackend::updatesCount() const +{ + return m_updater->updatesCount(); +} + +ResultsStream* FwupdBackend::search(const AbstractResourcesBackend::Filters& filter) +{ + QVector ret; + if (!filter.resourceUrl.isEmpty() && filter.resourceUrl.scheme() == QLatin1String("fwupd")) + return findResourceByPackageName(filter.resourceUrl); + else foreach(AbstractResource* r, m_resources) { + if(r->name().contains(filter.search, Qt::CaseInsensitive) || r->comment().contains(filter.search, Qt::CaseInsensitive)) + ret += r; + } + return new ResultsStream(QStringLiteral("Firmware Updates Stream"), ret); +} + +ResultsStream * FwupdBackend::findResourceByPackageName(const QUrl& search) +{ + auto res = search.scheme() == QLatin1String("fwupd") ? m_resources.value(search.host().replace(QLatin1Char('.'), QLatin1Char(' '))) : NULL; + if (!res) { + return new ResultsStream(QStringLiteral("Firmware Updates Stream"), {}); + } else + return new ResultsStream(QStringLiteral("Firmware Updates Stream"), { res }); +} + +AbstractBackendUpdater* FwupdBackend::backendUpdater() const +{ + return m_updater; +} + +AbstractReviewsBackend* FwupdBackend::reviewsBackend() const +{ + return NULL; +} + +Transaction* FwupdBackend::installApplication(AbstractResource* app, const AddonList& addons) +{ + return new FwupdTransaction(qobject_cast(app), this, addons, Transaction::InstallRole); +} + +Transaction* FwupdBackend::installApplication(AbstractResource* app) +{ + return new FwupdTransaction(qobject_cast(app), this, Transaction::InstallRole); +} + +Transaction* FwupdBackend::removeApplication(AbstractResource* app) +{ + return new FwupdTransaction(qobject_cast(app), this, Transaction::RemoveRole); +} + +void FwupdBackend::checkForUpdates() +{ + if(m_fetching) + return; + toggleFetching(); + populate(QStringLiteral("Releases")); + QTimer::singleShot(500, this, &FwupdBackend::toggleFetching); + #ifdef FWUPD_DEBUG + qDebug() << "FwupdBackend::checkForUpdates"; + #endif +} + +AbstractResource * FwupdBackend::resourceForFile(const QUrl& path) +{ + g_autoptr(GCancellable) cancellable = g_cancellable_new(); + g_autoptr(GError) error = NULL; + + QMimeDatabase db; + QMimeType type = db.mimeTypeForFile(path.fileName()); + FwupdResource* app = NULL; + + if(type.isValid() && type.inherits(QStringLiteral("application/vnd.ms-cab-compressed"))) + { + g_autofree gchar *filename = path.fileName().toUtf8().data(); + g_autoptr(GPtrArray) devices = fwupd_client_get_details (client,filename,cancellable,&error); + + if (devices) + { + FwupdDevice *dev = (FwupdDevice *)g_ptr_array_index (devices, 0); + app = FwupdCreateRelease(dev); + app->setState(AbstractResource::None); + for (uint i = 1; i < devices->len; i++) + { + FwupdDevice *dev = (FwupdDevice *)g_ptr_array_index (devices, i); + FwupdResource* app_ = FwupdCreateRelease(dev); + app_->setState(AbstractResource::None); + if(!app->m_releases.contains(app_)) + app->m_releases.append(app_); + } + m_resources.insert(app->packageName(), app); + if(!m_toUpdate.contains(app)) + m_toUpdate.append(app); + connect(app, &FwupdResource::stateChanged, this, &FwupdBackend::updatesCountChanged); + } + else + { + FwupdHandleError(&error); + } + } + return app; +} + +QString FwupdBackend::displayName() const +{ + return QStringLiteral("Firmware Updates"); +} + +bool FwupdBackend::hasApplications() const +{ + return m_resources.count() ? true : false; +} + +#include "FwupdBackend.moc" diff --git a/libdiscover/backends/FwupdBackend/FwupdNotifier.h b/libdiscover/backends/FwupdBackend/FwupdNotifier.h new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/FwupdNotifier.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright © 2013 Lukas Appelhans * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License or (at your option) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ +#ifndef FWUPDNOTIFIER_H +#define FWUPDNOTIFIER_H + +#include + +class FwupdNotifier : public BackendNotifierModule +{ +Q_OBJECT +Q_PLUGIN_METADATA(IID "org.kde.discover.BackendNotifierModule") +Q_INTERFACES(BackendNotifierModule) +public: + explicit FwupdNotifier(QObject* parent = nullptr); + ~FwupdNotifier() override; + + void recheckSystemUpdateNeeded() override; + uint securityUpdatesCount() override; + uint updatesCount() override; + +private: + uint m_securityUpdates; + uint m_normalUpdates; +}; + +#endif diff --git a/libdiscover/backends/FwupdBackend/FwupdNotifier.cpp b/libdiscover/backends/FwupdBackend/FwupdNotifier.cpp new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/FwupdNotifier.cpp @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright © 2013 Lukas Appelhans * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License or (at your option) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ +#include "FwupdNotifier.h" + +#include + +FwupdNotifier::FwupdNotifier(QObject* parent) + : BackendNotifierModule(parent) + , m_securityUpdates(0) + , m_normalUpdates(0) +{ +} + +FwupdNotifier::~FwupdNotifier() +{ +} + +void FwupdNotifier::recheckSystemUpdateNeeded() +{ + emit foundUpdates(); +} + +uint FwupdNotifier::securityUpdatesCount() +{ + return 0; +} + +uint FwupdNotifier::updatesCount() +{ + return 0; +} diff --git a/libdiscover/backends/FwupdBackend/FwupdResource.h b/libdiscover/backends/FwupdBackend/FwupdResource.h new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/FwupdResource.h @@ -0,0 +1,117 @@ +/*************************************************************************** + * Copyright © 2013 Aleix Pol Gonzalez * + * Copyright © 2018 Abhijeet Sharma * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License or (at your option) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifndef FWUPDRESOURCE_H +#define FWUPDRESOURCE_H + +#include +#include "FwupdBackend.h" + +class AddonList; +class FwupdResource : public AbstractResource +{ +Q_OBJECT +public: + explicit FwupdResource(QString name, bool isTechnical, AbstractResourcesBackend* parent); + + QList addonsInformation() override; + QString section() override; + QString origin() const override; + QString longDescription() override; + QString availableVersion() const override; + QString installedVersion() const override; + QString license() override; + int size() override; + QUrl homepage() override; + QUrl helpURL() override; + QUrl bugURL() override; + QUrl donationURL() override; + QStringList categories() override; + AbstractResource::State state() override; + QVariant icon() const override; + QString comment() override; + QString name() const override; + QString packageName() const override; + QString vendor() const; + bool isTechnical() const override { return m_isTechnical; } + bool canExecute() const override { return true; } + void invokeApplication() const override; + void fetchChangelog() override; + QUrl url() const override; + + void setState(State state); + void setSize(int size) { m_size = size; } + void setAddons(const AddonList& addons); + void setId(const QString &id){m_id = id;} + void setName(const QString &name){ m_name = name;} + void setSummary(const QString &summary){ m_summary = summary;} + void setDescription(const QString &description){ m_description = description;} + void setVersion(const QString &version){ m_version = version;} + void setVendor(const QString &vendor){ m_vendor = vendor;} + void addCategories(const QString &category); + void setHomePage(const QUrl &homepage){ m_homepage = homepage;} + void setLicense(const QString &license){ m_license = license;} + void setIconName(const QString &iconName){ m_iconName = iconName;} + virtual QStringList allResourceNames() const; + + void setIsDeviceLocked(bool status){ isDeviceLocked = status;} + void setDeviceID(const QString &deviceID){ m_deviceID = deviceID;} + void setUpdateURI(const QString &updateURI){m_updateURI = updateURI;} + // void setFile(const QFile &file){m_file = file;}; + + + void setAddonInstalled(const QString& addon, bool installed); + QString sourceIcon() const override { return QStringLiteral("player-time"); } + QDate releaseDate() const override { return {}; } + +public: + QString m_id; + QString m_name; + QString m_summary; + QString m_description; + QString m_version; + QString m_updateVersion; + QString m_vendor; + QStringList m_categories; + QString m_license; + + AbstractResource::State m_state; + QUrl m_homepage; + QString m_iconName; + QList m_addons; + bool m_isTechnical; + int m_size; + + bool isDeviceLocked = false; // True if device is locked! + QString m_deviceID; + QString m_updateURI; + QFile* m_file; + bool isOnlyOffline = false; // True if only offline updates + bool isLiveUpdatable = false; // True if device is live updatable + bool needsReboot = false; // True if device needs Reboot + bool isDeviceRemoval = false; //True if device is Removal + QString guidString; + + + QList m_releases; // A list of all refrences to releases of a device. +}; + +#endif // FWUPDRESOURCE_H diff --git a/libdiscover/backends/FwupdBackend/FwupdResource.cpp b/libdiscover/backends/FwupdBackend/FwupdResource.cpp new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/FwupdResource.cpp @@ -0,0 +1,194 @@ +/*************************************************************************** + * Copyright © 2013 Aleix Pol Gonzalez * + * Copyright © 2018 Abhijeet Sharma * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License or (at your option) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#include "FwupdResource.h" + + +#include +#include +#include +#include + +FwupdResource::FwupdResource(QString name, bool isTechnical, AbstractResourcesBackend* parent) + : AbstractResource(parent) + , m_name(std::move(name)) + , m_state(State::Broken) + , m_isTechnical(isTechnical) +{ + +} + +QList FwupdResource::addonsInformation() +{ + return m_addons; +} + +QString FwupdResource::availableVersion() const +{ + return m_version; +} + +QStringList FwupdResource::allResourceNames() const +{ + return { m_name }; +} + +QStringList FwupdResource::categories() +{ + return m_categories; +} + +void FwupdResource::addCategories(const QString &category){ + m_categories.append(category); +} + +QString FwupdResource::comment() +{ + return m_summary; +} + +int FwupdResource::size() +{ + return m_size; +} + +QUrl FwupdResource::homepage() +{ + return m_homepage; +} + +QUrl FwupdResource::helpURL() +{ + return m_homepage; +} + +QUrl FwupdResource::bugURL() +{ + return m_homepage; +} + +QUrl FwupdResource::donationURL() +{ + return m_homepage; +} + +QVariant FwupdResource::icon() const +{ + return m_iconName; +} + +QString FwupdResource::installedVersion() const +{ + return m_version; +} + +QString FwupdResource::license() +{ + return m_license; +} + +QString FwupdResource::longDescription() +{ + return m_description; +} + +QString FwupdResource::name() const +{ + return m_name; +} + +QString FwupdResource::vendor() const +{ + return m_vendor; +} + +QString FwupdResource::origin() const +{ + return m_homepage.toString(); +} + +QString FwupdResource::packageName() const +{ + return m_name; +} + +QString FwupdResource::section() +{ + return QStringLiteral("Firmware Updates"); +} + +AbstractResource::State FwupdResource::state() +{ + return m_state; +} + +void FwupdResource::fetchChangelog() +{ + QString log = longDescription(); + log.replace(QLatin1Char('\n'), QLatin1String("
")); + + emit changelogFetched(log); +} + +void FwupdResource::setState(AbstractResource::State state) +{ + if(m_state != state) + { + m_state = state; + emit stateChanged(); + } + +} + +void FwupdResource::setAddons(const AddonList& addons) +{ + Q_FOREACH (const QString& toInstall, addons.addonsToInstall()) + { + setAddonInstalled(toInstall, true); + } + Q_FOREACH (const QString& toRemove, addons.addonsToRemove()) + { + setAddonInstalled(toRemove, false); + } +} + +void FwupdResource::setAddonInstalled(const QString& addon, bool installed) +{ + for(auto & elem : m_addons) + { + if(elem.name() == addon) + { + elem.setInstalled(installed); + } + } +} + + +void FwupdResource::invokeApplication() const +{ + QDesktopServices d; + d.openUrl(QUrl(QStringLiteral("https://projects.kde.org/projects/extragear/sysadmin/muon"))); +} + +QUrl FwupdResource::url() const +{ + return m_homepage; +} diff --git a/libdiscover/backends/FwupdBackend/FwupdSourcesBackend.h b/libdiscover/backends/FwupdBackend/FwupdSourcesBackend.h new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/FwupdSourcesBackend.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright © 2014 Aleix Pol Gonzalez * + * Copyright © 2018 Abhijeet Sharma * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License or (at your option) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifndef FWUPDSOURCESBACKEND_H +#define FWUPDSOURCESBACKEND_H + +#include +#include "FwupdBackend.h" +#include + +#include "FwupdBackend.h" + +class FwupdSourcesModel; + +class FwupdSourcesBackend : public AbstractSourcesBackend +{ + Q_OBJECT +public: + explicit FwupdSourcesBackend(AbstractResourcesBackend * parent); + + FwupdBackend* backend ; + QAbstractItemModel* sources() override; + bool addSource(const QString& id) override; + bool removeSource(const QString& id) override; + QString idDescription() override { return QStringLiteral(""); } + QList actions() const override; + bool supportsAdding() const override { return false; } + void eulaRequired(const QString& remoteName , const QString& licenseAgreement); +Q_SIGNALS: + void proceed() override; + void cancel() override; + +private: + FwupdSourcesModel* m_sources; + QList m_actions; +}; + +#endif // FWUPDSOURCESBACKEND_H diff --git a/libdiscover/backends/FwupdBackend/FwupdSourcesBackend.cpp b/libdiscover/backends/FwupdBackend/FwupdSourcesBackend.cpp new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/FwupdSourcesBackend.cpp @@ -0,0 +1,161 @@ +/*************************************************************************** + * Copyright © 2014 Aleix Pol Gonzalez * + * Copyright © 2018 Abhijeet Sharma * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License or (at your option) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#include "FwupdSourcesBackend.h" + +#include +#include +#include +#include + + +class FwupdSourcesModel : public QStandardItemModel +{ +Q_OBJECT +public: + FwupdSourcesModel(FwupdSourcesBackend* backend) + : QStandardItemModel(backend) + , m_backend(backend) {} + + QHash roleNames() const override + { + auto roles = QStandardItemModel::roleNames(); + roles[Qt::CheckStateRole] = "checked"; + return roles; + } + + bool setData(const QModelIndex & index, const QVariant & value, int role) override { + auto item = itemFromIndex(index); + if (!item) + return false; + + remote = fwupd_client_get_remote_by_id(m_backend->backend->client,item->data(AbstractSourcesBackend::IdRole).toString().toUtf8().constData(),NULL,NULL); + status = fwupd_remote_get_enabled(remote); + switch(role) + { + case Qt::CheckStateRole: + { + if((value.toInt() == Qt::Checked) ) + { + m_backend->eulaRequired(QLatin1String(fwupd_remote_get_title(remote)),QLatin1String(fwupd_remote_get_agreement(remote))); + connect(m_backend,&FwupdSourcesBackend::proceed,this, + [=]() + { + if(fwupd_client_modify_remote(m_backend->backend->client,fwupd_remote_get_id(remote),QString(QLatin1String("Enabled")).toUtf8().constData(),(QString(QLatin1String("true")).toUtf8().constData()),NULL,NULL)) + item->setData(value, role); + } + ); + connect(m_backend,&FwupdSourcesBackend::cancel,this, + [=]() + { + item->setCheckState(Qt::Unchecked); + Q_EMIT dataChanged(index,index,{}); + return false; + } + ); + } + else if(value.toInt() == Qt::Unchecked) + { + if(fwupd_client_modify_remote(m_backend->backend->client,fwupd_remote_get_id(remote),QString(QLatin1String("Enabled")).toUtf8().constData(),(QString(QLatin1String("false")).toUtf8().constData()),NULL,NULL)) + item->setData(value, role); + } + + } + } + Q_EMIT dataChanged(index,index,{}); + return true; + } + +private: + FwupdSourcesBackend* m_backend; + FwupdRemote* remote; + bool status; +}; + +FwupdSourcesBackend::FwupdSourcesBackend(AbstractResourcesBackend * parent) + : AbstractSourcesBackend(parent) + , m_sources(new FwupdSourcesModel(this)) +{ + backend = qobject_cast(parent); + g_autoptr(GCancellable) cancellable = g_cancellable_new(); + g_autoptr(GError) error = NULL; + /* find all remotes */ + g_autoptr(GPtrArray) remotes = fwupd_client_get_remotes (backend->client,cancellable,&error); + if(remotes != NULL) + { + for (uint i = 0; i < remotes->len; i++) + { + FwupdRemote *remote = (FwupdRemote *)g_ptr_array_index (remotes, i); + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL) + continue; + addSource(QLatin1String(fwupd_remote_get_id (remote))); + } + } +} + +QAbstractItemModel* FwupdSourcesBackend::sources() +{ + return m_sources; +} + +void FwupdSourcesBackend::eulaRequired( const QString& remoteName , const QString& licenseAgreement) +{ + Q_EMIT proceedRequest(i18n("Accept EULA"), i18n("The remote %1 require that you accept their license:\n %2", + remoteName, licenseAgreement)); +} + +bool FwupdSourcesBackend::addSource(const QString& id) +{ + g_autoptr(GCancellable) cancellable = g_cancellable_new(); + g_autoptr(GError) error = NULL; + FwupdBackend* backend = qobject_cast(parent()); + FwupdRemote* remote; + bool status ; + + if (id.isEmpty()) + return false; + + remote = fwupd_client_get_remote_by_id(backend->client,id.toUtf8().constData(),cancellable,&error); + status = !fwupd_remote_get_enabled(remote); + + QStandardItem* it = new QStandardItem(id); + it->setData(id, AbstractSourcesBackend::IdRole); + it->setData(QVariant(QLatin1Literal(fwupd_remote_get_title (remote))), Qt::ToolTipRole); + it->setCheckable(true); + it->setCheckState(status ? Qt::Unchecked : Qt::Checked); + m_sources->appendRow(it); + return true; +} + +bool FwupdSourcesBackend::removeSource(const QString& id) +{ + qWarning() << "Removal of Sources Not Allowed" << "Remote-ID" << id; + return false; +} + +QList FwupdSourcesBackend::actions() const +{ + return m_actions ; +} + +#include "FwupdSourcesBackend.moc" + + diff --git a/libdiscover/backends/FwupdBackend/FwupdTransaction.h b/libdiscover/backends/FwupdBackend/FwupdTransaction.h new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/FwupdTransaction.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright © 2013 Aleix Pol Gonzalez * + * Copyright © 2018 Abhijeet Sharma * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License or (at your option) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifndef FWUPDTRANSACTION_H +#define FWUPDTRANSACTION_H + +#include +#include "FwupdBackend.h" +#include "FwupdResource.h" + + +class FwupdResource; +class FwupdTransaction : public Transaction +{ + Q_OBJECT + public: + FwupdTransaction(FwupdResource* app, FwupdBackend* backend, Role role); + FwupdTransaction(FwupdResource* app, FwupdBackend* backend, const AddonList& list, Role role); + ~FwupdTransaction(); + bool FwupdCheck(); + bool FwupdInstall(); + bool FwupdRemove(); + void cancel() override; + void proceed() override; + int speed(); + + private Q_SLOTS: + void iterateTransaction(); + void finishTransaction(); + + private: + bool m_iterate = true; + FwupdResource* m_app; + FwupdBackend* m_backend; +}; + +#endif // FWUPDTRANSACTION_H diff --git a/libdiscover/backends/FwupdBackend/FwupdTransaction.cpp b/libdiscover/backends/FwupdBackend/FwupdTransaction.cpp new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/FwupdTransaction.cpp @@ -0,0 +1,189 @@ +/*************************************************************************** + * Copyright © 2013 Aleix Pol Gonzalez * + * Copyright © 2018 Abhijeet Sharma * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License or (at your option) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#include "FwupdTransaction.h" + +#include +#include +#include + + +#define TEST_PROCEED + +FwupdTransaction::FwupdTransaction(FwupdResource* app, FwupdBackend* backend, Role role) + : FwupdTransaction(app, backend,{}, role) +{ +} + +FwupdTransaction::FwupdTransaction(FwupdResource* app, FwupdBackend* backend, const AddonList& addons, Transaction::Role role) + : Transaction(app->backend(), app, role, addons) + , m_app(app) + , m_backend(backend) +{ + setCancellable(true); + if(role == InstallRole) + { + if(!FwupdCheck()) + qWarning() << "Error In Install!"; + } + else if(role == RemoveRole) + { + if(!FwupdRemove()) + qWarning() << "Error in Remove!"; + } + + iterateTransaction(); +} + +FwupdTransaction::~FwupdTransaction() +{ + +} + +bool FwupdTransaction::FwupdCheck() +{ + g_autoptr(GCancellable) cancellable = g_cancellable_new(); + g_autoptr(GError) error = NULL; + + if(m_app->isDeviceLocked) + { + QString device_id = m_app->m_deviceID; + if(device_id.isNull()) + { + qWarning("No Device ID Set"); + return false; + } + if (!fwupd_client_unlock (m_backend->client, device_id.toUtf8().constData(),cancellable, &error)) + { + m_backend->FwupdHandleError(&error); + return false; + } + return true; + } + if(!FwupdInstall()) + { + // To DO error handling + return false; + } + return true; + +} + +bool FwupdTransaction::FwupdInstall() +{ + FwupdInstallFlags install_flags = FWUPD_INSTALL_FLAG_NONE;//Removed 0 check for ussage + g_autoptr(GCancellable) cancellable = g_cancellable_new(); + g_autoptr(GError) error = NULL; + + QFile *local_file = m_app->m_file; + + if(!local_file) + { + //to Do error handling + qWarning("No Local File Set For this Resource"); + return false; + } + + QString filename = local_file->fileName(); + + if (!(QFileInfo::exists(filename) && QFileInfo(filename).isFile())) + { + const QUrl uri(m_app->m_updateURI); + if(!m_backend->FwupdDownloadFile(uri,filename)) + return false; + } + + /* limit to single device? */ + QString device_id = m_app->m_deviceID; + if (device_id.isNull()) + device_id = QStringLiteral(FWUPD_DEVICE_ID_ANY); + + /* only offline supported */ + if (m_app->isOnlyOffline) + install_flags = FWUPD_INSTALL_FLAG_OFFLINE; // removed the bit wise or operation |= + + if (!fwupd_client_install (m_backend->client, device_id.toUtf8().constData(),filename.toUtf8().constData(), install_flags,cancellable, &error)) { + m_backend->FwupdHandleError(&error); + return false; + } + return true; +} + +bool FwupdTransaction::FwupdRemove() +{ + // To Do Implement It + return true; +} + +int FwupdTransaction::speed() +{ + //To Do Implement It + return 0; +} + +void FwupdTransaction::iterateTransaction() +{ + if (!m_iterate) + return; + + setStatus(CommittingStatus); + if(progress()<100) + { + setProgress(fwupd_client_get_percentage (m_backend->client)); + + QTimer::singleShot(100, this, &FwupdTransaction::iterateTransaction); + } else +#ifdef TEST_PROCEED + Q_EMIT proceedRequest(QStringLiteral("yadda yadda"), QStringLiteral("Biii BOooo
  • A
  • A
  • A
  • A
")); +#else + finishTransaction(); +#endif +} + +void FwupdTransaction::proceed() +{ + finishTransaction(); +} + +void FwupdTransaction::cancel() +{ + m_iterate = false; + + setStatus(CancelledStatus); +} + +void FwupdTransaction::finishTransaction() +{ + AbstractResource::State newState; + switch(role()) { + case InstallRole: + case ChangeAddonsRole: + newState = AbstractResource::Installed; + break; + case RemoveRole: + newState = AbstractResource::None; + break; + } + m_app->setAddons(addons()); + m_app->setState(newState); + setStatus(DoneStatus); + deleteLater(); +} diff --git a/libdiscover/backends/FwupdBackend/FwupdUpdater.h b/libdiscover/backends/FwupdBackend/FwupdUpdater.h new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/FwupdUpdater.h @@ -0,0 +1,75 @@ +/*************************************************************************** +* Copyright © 2018 Abhijeet Sharma * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License as * +* published by the Free Software Foundation; either version 2 of * +* the License or (at your option) version 3 or any later version * +* accepted by the membership of KDE e.V. (or its successor approved * +* by the membership of KDE e.V.), which shall act as a proxy * +* defined in Section 14 of version 3 of the license. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +***************************************************************************/ + +#ifndef FWUPDUPDATER_H +#define FWUPDUPDATER_H + +#include +#include +#include "FwupdBackend.h" +#include "FwupdTransaction.h" + +class FwupdUpdater : public AbstractBackendUpdater +{ +Q_OBJECT +public: + explicit FwupdUpdater(FwupdBackend * parent = nullptr); + ~FwupdUpdater() override; + + void prepare() override; + int updatesCount(); + + quint64 downloadSpeed() const override; + double updateSize() const override; + bool isMarked(AbstractResource* res) const override; + bool isProgressing() const override; + bool isCancelable() const override; + QDateTime lastUpdate() const override; + QList toUpdate() const override; + void addResources(const QList& apps) override; + void removeResources(const QList& apps) override; + qreal progress() const override; + bool hasUpdates() const override; + void setProgressing(bool progressing); + + QSet involvedResources(const QSet& resources) const; + QSet resourcesForResourceId(const QSet& resids) const; + +public Q_SLOTS: + + void start() override; + void cancel() override; + +Q_SIGNALS: + void updatesCountChanged(); + +private: + FwupdTransaction* m_transaction; + FwupdBackend * const m_backend; + bool m_isCancelable; + bool m_isProgressing; + int m_percentage; + QDateTime m_lastUpdate; + + QSet m_toUpgrade; + QSet m_allUpgradeable; +}; + +#endif diff --git a/libdiscover/backends/FwupdBackend/FwupdUpdater.cpp b/libdiscover/backends/FwupdBackend/FwupdUpdater.cpp new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/FwupdUpdater.cpp @@ -0,0 +1,178 @@ +/*************************************************************************** +* Copyright © 2018 Abhijeet Sharma * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License as * +* published by the Free Software Foundation; either version 2 of * +* the License or (at your option) version 3 or any later version * +* accepted by the membership of KDE e.V. (or its successor approved * +* by the membership of KDE e.V.), which shall act as a proxy * +* defined in Section 14 of version 3 of the license. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +***************************************************************************/ + +#include + +#include +#include + +FwupdUpdater::FwupdUpdater(FwupdBackend * parent) + : AbstractBackendUpdater(parent), + m_transaction(nullptr), + m_backend(parent), + m_isCancelable(false), + m_isProgressing(false), + m_percentage(0), + m_lastUpdate() +{ +} + +FwupdUpdater::~FwupdUpdater() +{ + +} + +void FwupdUpdater::prepare() +{ + Q_ASSERT(!m_transaction); + m_toUpgrade = m_backend->FwupdGetAllUpdates(); + m_allUpgradeable = m_toUpgrade; +} + +int FwupdUpdater::updatesCount() +{ + return m_toUpgrade.count(); +} + +void FwupdUpdater::start() +{ + Q_ASSERT(!isProgressing()); +} + +void FwupdUpdater::cancel() +{ + if (m_transaction) + m_transaction->cancel(); + else + setProgressing(false); +} + +void FwupdUpdater::setProgressing(bool progressing) +{ + if (m_isProgressing != progressing) + { + m_isProgressing = progressing; + emit progressingChanged(m_isProgressing); + } +} + +quint64 FwupdUpdater::downloadSpeed() const +{ + return m_transaction ? m_transaction->speed() : 0; +} + +double FwupdUpdater::updateSize() const +{ + double ret = 0.; + QSet donePkgs; + for (AbstractResource * res : m_toUpgrade) + { + FwupdResource * app = qobject_cast(res); + QString pkgid = app->m_id; + if (!donePkgs.contains(pkgid)) + { + donePkgs.insert(pkgid); + ret += app->size(); + } + } + return ret; +} + +bool FwupdUpdater::isMarked(AbstractResource* res) const +{ + return m_toUpgrade.contains(res); +} + +bool FwupdUpdater::isProgressing() const +{ + return m_isProgressing; +} + +bool FwupdUpdater::isCancelable() const +{ + return m_isCancelable; +} + +QDateTime FwupdUpdater::lastUpdate() const +{ + return m_lastUpdate; +} + +QList FwupdUpdater::toUpdate() const +{ + return m_toUpgrade.toList(); +} + +void FwupdUpdater::addResources(const QList& apps) +{ + QSet pkgs = involvedResources(apps.toSet()); + m_toUpgrade.unite(resourcesForResourceId(pkgs)); +} + +void FwupdUpdater::removeResources(const QList& apps) +{ + QSet pkgs = involvedResources(apps.toSet()); + m_toUpgrade.subtract(resourcesForResourceId(pkgs)); +} + +QSet FwupdUpdater::involvedResources(const QSet& resources) const +{ + QSet resIds; + resIds.reserve(resources.size()); + foreach (AbstractResource * res, resources) + { + FwupdResource * app = qobject_cast(res); + QString resid = app->m_id; + resIds.insert(resid); + } + return resIds; +} + +QSet FwupdUpdater::resourcesForResourceId(const QSet& resids) const +{ + QSet resources; + resources.reserve(resids.size()); + foreach(const QString& resid, resids) { + resources += m_backend->FwupdGetAppName(resid); + } + + QSet ret; + foreach (AbstractResource * res, m_allUpgradeable) + { + FwupdResource* pres = qobject_cast(res); + if (resources.contains(pres->allResourceNames().toSet())) + { + ret.insert(res); + } + } + + return ret; +} + +qreal FwupdUpdater::progress() const +{ + return m_percentage; +} + +bool FwupdUpdater::hasUpdates() const +{ + return m_backend->updatesCount() > 0; +} + diff --git a/libdiscover/backends/FwupdBackend/tests/CMakeLists.txt b/libdiscover/backends/FwupdBackend/tests/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/tests/CMakeLists.txt @@ -0,0 +1,4 @@ +add_unit_test(fwupdtest FwupdTest.cpp) +add_unit_test(updatefwupdtest UpdateFwupdTest.cpp) + +target_link_libraries(updatefwupdtest KF5::CoreAddons) diff --git a/libdiscover/backends/FwupdBackend/tests/FwupdTest.h b/libdiscover/backends/FwupdBackend/tests/FwupdTest.h new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/tests/FwupdTest.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright © 2012 Aleix Pol Gonzalez * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License or (at your option) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifndef FWUPDTEST_H +#define FWUPDTEST_H + +#include + +class ResourcesModel; +class AbstractResourcesBackend; + +class FwupdTest : public QObject +{ + Q_OBJECT +public: + explicit FwupdTest(QObject* parent = nullptr); + +private Q_SLOTS: + void initTestCase(); + + void testReadData(); + void testProxy(); + void testProxySorting(); + void testFetch(); + void testSort(); + void testUpdateModel(); + +private: + AbstractResourcesBackend* m_appBackend; + ResourcesModel* m_model; +}; + +#endif // FWUPDTEST_H diff --git a/libdiscover/backends/FwupdBackend/tests/FwupdTest.cpp b/libdiscover/backends/FwupdBackend/tests/FwupdTest.cpp new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/tests/FwupdTest.cpp @@ -0,0 +1,202 @@ +/*************************************************************************** + * Copyright © 2012 Aleix Pol Gonzalez * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License or (at your option) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#include "FwupdTest.h" +#include "DiscoverBackendsFactory.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +QTEST_MAIN(FwupdTest) + +AbstractResourcesBackend* backendByName(ResourcesModel* m, const QString& name) +{ + QVector backends = m->backends(); + foreach(AbstractResourcesBackend* backend, backends) { + if(QString::fromLatin1(backend->metaObject()->className()) == name) { + return backend; + } + } + return nullptr; +} + +FwupdTest::FwupdTest(QObject* parent): QObject(parent) +{ + DiscoverBackendsFactory::setRequestedBackends({ QStringLiteral("fwupd-backend") }); + + m_model = new ResourcesModel(QStringLiteral("fwupd-backend"), this); + m_appBackend = backendByName(m_model, QStringLiteral("FwupdBackend")); + + // CategoryModel::global()->populateCategories(); +} + +void FwupdTest::initTestCase() +{ + QVERIFY(m_appBackend); + while(m_appBackend->isFetching()) { + QSignalSpy spy(m_appBackend, &AbstractResourcesBackend::fetchingChanged); + QVERIFY(spy.wait()); + } +} + +QVector fetchResources(ResultsStream* stream) +{ + QVector ret; + QObject::connect(stream, &ResultsStream::resourcesFound, stream, [&ret](const QVector& res) { ret += res; }); + QSignalSpy spy(stream, &ResultsStream::destroyed); + Q_ASSERT(spy.wait()); + return ret; +} + +void FwupdTest::testReadData() +{ + const auto resources = fetchResources(m_appBackend->search({})); + + QCOMPARE(m_appBackend->property("startElements").toInt()*2, resources.size()); + QBENCHMARK { + for(AbstractResource* res: resources) { + QVERIFY(!res->name().isEmpty()); + } + } +} + +void FwupdTest::testProxy() +{ + ResourcesProxyModel pm; + QSignalSpy spy(&pm, &ResourcesProxyModel::busyChanged); +// QVERIFY(spy.wait()); + QVERIFY(!pm.isBusy()); + + pm.setFiltersFromCategory(CategoryModel::global()->rootCategories().first()); + pm.componentComplete(); + QVERIFY(pm.isBusy()); + QVERIFY(spy.wait()); + QVERIFY(!pm.isBusy()); + + QCOMPARE(m_appBackend->property("startElements").toInt()*2, pm.rowCount()); + pm.setSearch(QStringLiteral("techie")); + QVERIFY(pm.isBusy()); + QVERIFY(spy.wait()); + QVERIFY(!pm.isBusy()); + QCOMPARE(m_appBackend->property("startElements").toInt(), pm.rowCount()); + QCOMPARE(pm.subcategories().count(), 7); + pm.setSearch(QString()); + QVERIFY(pm.isBusy()); + QVERIFY(spy.wait()); + QVERIFY(!pm.isBusy()); + QCOMPARE(m_appBackend->property("startElements").toInt()*2, pm.rowCount()); +} + +void FwupdTest::testProxySorting() +{ + ResourcesProxyModel pm; + QSignalSpy spy(&pm, &ResourcesProxyModel::busyChanged); +// QVERIFY(spy.wait()); + QVERIFY(!pm.isBusy()); + + pm.setFiltersFromCategory(CategoryModel::global()->rootCategories().first()); + pm.setSortOrder(Qt::DescendingOrder); + pm.setSortRole(ResourcesProxyModel::RatingCountRole); + pm.componentComplete(); + QVERIFY(pm.isBusy()); + QVERIFY(spy.wait()); + QVERIFY(!pm.isBusy()); + + QCOMPARE(m_appBackend->property("startElements").toInt()*2, pm.rowCount()); + QVariant lastRatingCount; + for(int i=0, rc=pm.rowCount(); isearch({})); + QCOMPARE(m_appBackend->property("startElements").toInt()*2, resources.count()); + + //fetches updates, adds new things + m_appBackend->checkForUpdates(); + QSignalSpy spy(m_model, SIGNAL(allInitialized())); + QVERIFY(spy.wait(80000)); + auto resources2 = fetchResources(m_appBackend->search({})); + QCOMPARE(m_appBackend->property("startElements").toInt()*4, resources2.count()); +} + +void FwupdTest::testSort() +{ + ResourcesProxyModel pm; + + QCollator c; + QBENCHMARK_ONCE { + pm.setSortRole(ResourcesProxyModel::NameRole); + pm.sort(0); + QCOMPARE(pm.sortOrder(), Qt::AscendingOrder); + QString last; + for(int i = 0, count = pm.rowCount(); ibackends().first(); + + ResourcesUpdatesModel ruModel; + new ModelTest(&ruModel, &ruModel); + UpdateModel model; + new ModelTest(&model, &model); + model.setBackend(&ruModel); + + QCOMPARE(model.rowCount(), 4*backend->property("startElements").toInt()/3); + QCOMPARE(model.hasUpdates(), true); +} + +//TODO test cancel transaction diff --git a/libdiscover/backends/FwupdBackend/tests/UpdateFwupdTest.cpp b/libdiscover/backends/FwupdBackend/tests/UpdateFwupdTest.cpp new file mode 100644 --- /dev/null +++ b/libdiscover/backends/FwupdBackend/tests/UpdateFwupdTest.cpp @@ -0,0 +1,171 @@ +/*************************************************************************** + * Copyright © 2012 Aleix Pol Gonzalez * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License or (at your option) version 3 or any later version * + * accepted by the membership of KDE e.V. (or its successor approved * + * by the membership of KDE e.V.), which shall act as a proxy * + * defined in Section 14 of version 3 of the license. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#include "FwupdTest.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +class UpdateFwupdTest + : public QObject +{ + Q_OBJECT +public: + AbstractResourcesBackend* backendByName(ResourcesModel* m, const QString& name) + { + QVector backends = m->backends(); + foreach(AbstractResourcesBackend* backend, backends) { + if(QLatin1String(backend->metaObject()->className()) == name) { + return backend; + } + } + return nullptr; + } + + UpdateFwupdTest(QObject* parent = nullptr): QObject(parent) + { + m_model = new ResourcesModel(QStringLiteral("fwupd-backend"), this); + m_appBackend = backendByName(m_model, QStringLiteral("FwupdBackend")); + } + +private Q_SLOTS: + void init() + { + QVERIFY(m_appBackend); + while(m_appBackend->isFetching()) { + QSignalSpy spy(m_appBackend, &AbstractResourcesBackend::fetchingChanged); + QVERIFY(spy.wait()); + } + } + + void testInformation() + { + ResourcesUpdatesModel* rum = new ResourcesUpdatesModel(this); + new ModelTest(rum, rum); + + UpdateModel* m = new UpdateModel(this); + new ModelTest(m, m); + m->setBackend(rum); + + rum->prepare(); + QSignalSpy spySetup(m_appBackend->backendUpdater(), &AbstractBackendUpdater::progressingChanged); + QVERIFY(!m_appBackend->backendUpdater()->isProgressing() || spySetup.wait()); + QCOMPARE(m_appBackend->updatesCount(), m_appBackend->property("startElements").toInt()*2/3); + QCOMPARE(m->hasUpdates(), true); + + QCOMPARE(m->index(0,0).data(UpdateModel::ChangelogRole).toString(), {}); + + QSignalSpy spy(m, &QAbstractItemModel::dataChanged); + m->fetchChangelog(0); + QVERIFY(spy.count() || spy.wait()); + QCOMPARE(spy.count(), 1); + delete m; + } + + void testUpdate() + { + ResourcesUpdatesModel* rum = new ResourcesUpdatesModel(this); + new ModelTest(rum, rum); + + UpdateModel* m = new UpdateModel(this); + new ModelTest(m, m); + m->setBackend(rum); + + rum->prepare(); + QSignalSpy spySetup(m_appBackend->backendUpdater(), &AbstractBackendUpdater::progressingChanged); + QVERIFY(!m_appBackend->backendUpdater()->isProgressing() || spySetup.wait()); + QCOMPARE(m_appBackend->updatesCount(), m_appBackend->property("startElements").toInt()*2/3); + QCOMPARE(m->hasUpdates(), true); + + for(int i=0, c=m->rowCount(); iindex(i,0); + QVERIFY(resourceIdx.isValid()); + + AbstractResource* res = qobject_cast(resourceIdx.data(UpdateModel::ResourceRole).value()); + QVERIFY(res); + + QCOMPARE(Qt::CheckState(resourceIdx.data(Qt::CheckStateRole).toInt()), Qt::Checked); + QVERIFY(m->setData(resourceIdx, int(Qt::Unchecked), Qt::CheckStateRole)); + QCOMPARE(Qt::CheckState(resourceIdx.data(Qt::CheckStateRole).toInt()), Qt::Unchecked); + QCOMPARE(resourceIdx.data(Qt::DisplayRole).toString(), res->name()); + + if (i!=0) { + QVERIFY(m->setData(resourceIdx, int(Qt::Checked), Qt::CheckStateRole)); + } + } + + QSignalSpy spy(rum, &ResourcesUpdatesModel::progressingChanged); + QVERIFY(!rum->isProgressing() || spy.wait()); + QCOMPARE(rum->isProgressing(), false); + + QCOMPARE(m_appBackend->updatesCount(), m->rowCount()); + QCOMPARE(m->hasUpdates(), true); + + rum->prepare(); + + spy.clear(); + QCOMPARE(rum->isProgressing(), false); + rum->updateAll(); + QVERIFY(spy.count() || spy.wait()); + QCOMPARE(rum->isProgressing(), true); + + QCOMPARE(TransactionModel::global()->rowCount(), 1); + connect(TransactionModel::global(), &TransactionModel::progressChanged, this, []() { + const int progress = TransactionModel::global()->progress(); + static int lastProgress = -1; + Q_ASSERT(progress >= lastProgress || (TransactionModel::global()->rowCount() == 0 && progress == 0)); + lastProgress = progress; + }); + + QTest::qWait(20); + QScopedPointer rum2(new ResourcesUpdatesModel(this)); + new ModelTest(rum2.data(), rum2.data()); + + QScopedPointer m2(new UpdateModel(this)); + new ModelTest(m2.data(), m2.data()); + m->setBackend(rum2.data()); + + QCOMPARE(rum->isProgressing(), true); + QVERIFY(spy.wait()); + QCOMPARE(rum->isProgressing(), false); + + QCOMPARE(m_appBackend->updatesCount(), 0); + QCOMPARE(m->hasUpdates(), false); + } + +private: + ResourcesModel* m_model; + AbstractResourcesBackend* m_appBackend; +}; + +QTEST_MAIN(UpdateFwupdTest) + +#include "UpdateFwupdTest.moc" diff --git a/libdiscover/resources/AbstractSourcesBackend.h b/libdiscover/resources/AbstractSourcesBackend.h --- a/libdiscover/resources/AbstractSourcesBackend.h +++ b/libdiscover/resources/AbstractSourcesBackend.h @@ -67,10 +67,15 @@ QString firstSourceId() const; QString lastSourceId() const; + public Q_SLOTS: + virtual void cancel() {} + virtual void proceed() {} + Q_SIGNALS: void firstSourceIdChanged(); void lastSourceIdChanged(); void passiveMessage(const QString &message); + void proceedRequest(const QString &title, const QString &description); }; #endif // ABSTRACTRESOURCESBACKEND_H