diff --git a/.gitignore b/.gitignore index 10da3ba027..87ce6bf86a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build +Makefile *.orig *.rej *.swp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f431fc929..418a6fa56b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ OPTION (DISABLE_MEDIABACKEND_TESTS "Disable Tests depending on Nginx and libfcgi OPTION (DISABLE_LIBPROXY "Build without libproxy support even if package is installed?" OFF) OPTION (DISABLE_AUTODOCS "Do not require doxygen being installed (required to build autodocs)?" OFF) -OPTION (EXPORT_NG_API "Export experimental libzypp API" OFF) +OPTION (BUILD_GLIB_API "Build experimental glib libzypp API" OFF) # This option will reroute all tool binaries to the libzypp build dir instead of taking those installed in the default directories. OPTION (ENABLE_DEVEL_BUILD "Developer build, use zypp tools directly from build dir rather than the default locations" OFF) OPTION (INSTALL_NG_BINARIES "Installs the NG binaries, disabled for now since we are not actively using them." OFF) @@ -135,7 +135,10 @@ if ( NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") if( ENABLE_UBSAN_CHECKS ) target_compile_options( zypp_general_compiler_flags INTERFACE "$<$:-fsanitize=undefined>" ) + target_compile_options( zypp_general_compiler_flags INTERFACE "$<$:-fsanitize=address>" ) target_link_options( zypp_general_compiler_flags INTERFACE "$<$:-fsanitize=undefined>" ) + target_link_options( zypp_general_compiler_flags INTERFACE "$<$:-fsanitize=address>" ) + target_link_options( zypp_general_compiler_flags INTERFACE "$<$:-lubsan>" ) endif() endif() @@ -401,7 +404,7 @@ MACRO(ADD_TESTS) TARGET_LINK_LIBRARIES( ${loop_var}_test PUBLIC zypp_exe_compiler_flags ) TARGET_LINK_LIBRARIES( ${loop_var}_test PUBLIC ${TEST_REQ_LIBS} ) - TARGET_LINK_LIBRARIES( ${loop_var}_test PUBLIC zypp-allsym ) + TARGET_LINK_LIBRARIES( ${loop_var}_test PUBLIC zypp-allsym ) ADD_TEST( ${loop_var}_test ${CMAKE_CURRENT_BINARY_DIR}/${loop_var}_test --catch_system_errors=no) ENDFOREACH( loop_var ) ENDMACRO(ADD_TESTS) @@ -427,16 +430,20 @@ ADD_SUBDIRECTORY( tools ) ADD_SUBDIRECTORY( shared ) ADD_SUBDIRECTORY( doc ) +IF( BUILD_GLIB_API ) + ADD_SUBDIRECTORY( zypp-glib ) +ENDIF ( BUILD_GLIB_API ) + IF ( ENABLE_BUILD_TRANS ) ADD_SUBDIRECTORY( po ) ELSE ( ENABLE_BUILD_TRANS ) ADD_SUBDIRECTORY( po EXCLUDE_FROM_ALL ) ENDIF ( ENABLE_BUILD_TRANS ) -IF ( ENABLE_BUILD_TESTS ) - ADD_SUBDIRECTORY( tests ) -ELSE ( ENABLE_BUILD_TESTS ) +#IF ( ENABLE_BUILD_TESTS ) +# ADD_SUBDIRECTORY( tests ) +#ELSE ( ENABLE_BUILD_TESTS ) ADD_SUBDIRECTORY( tests EXCLUDE_FROM_ALL ) -ENDIF ( ENABLE_BUILD_TESTS ) +#ENDIF ( ENABLE_BUILD_TESTS ) INCLUDE(CTest) ENABLE_TESTING() diff --git a/VERSION.cmake b/VERSION.cmake index f1e044ebca..1131365da8 100644 --- a/VERSION.cmake +++ b/VERSION.cmake @@ -61,8 +61,8 @@ SET(LIBZYPP_MAJOR "17") SET(LIBZYPP_COMPATMINOR "35") SET(LIBZYPP_MINOR "35") -SET(LIBZYPP_PATCH "13") +SET(LIBZYPP_PATCH "14") # -# LAST RELEASED: 17.35.13 (35) +# LAST RELEASED: 17.35.14 (35) # (The number in parenthesis is LIBZYPP_COMPATMINOR) #======= diff --git a/cmake/modules/GLibTools.cmake b/cmake/modules/GLibTools.cmake new file mode 100644 index 0000000000..9c39ada390 --- /dev/null +++ b/cmake/modules/GLibTools.cmake @@ -0,0 +1,97 @@ +# Taken from https://github.com/GNOME/evolution +# +# GLibTools.cmake +# +# Provides functions to run glib tools. +# +# Functions: +# +# glib_mkenums(_output_filename_noext _header_templ _src_tmpl _enums_header ...) +# runs glib-mkenums to generate enumtypes .h and .c files from multiple +# _enums_header using _header_templ and _src_tmpl template files. It searches for files in the current source directory and +# exports to the current binary directory. +# +# An example call is: +# glib_mkenums(camel-enumtypes camel-enums.h CAMEL_ENUMTYPES_H) +# which uses camel-enums.h as the source of known enums and generates +# camel-enumtypes.h which will use the CAMEL_ENUMTYPES_H define +# and also generates camel-enumtypes.c with the needed code. +# +# glib_genmarshal(_output_filename_noext _prefix _marshallist_filename) +# runs glib-genmarshal to process ${_marshallist_filename} to ${_output_filename_noext}.c +# and ${_output_filename_noext}.h files in the current binary directory, using +# the ${_prefix} as the function prefix. +# +# glib_compile_resources _sourcedir _outputprefix _cname _inxml ...deps) +# Calls glib-compile-resources as defined in _inxml and using _outputprefix and_cname as other arguments +# beside _sourcedir. The optional arguments are other dependencies. + +find_program(GLIB_MKENUMS glib-mkenums) +if(NOT GLIB_MKENUMS) + message(FATAL_ERROR "Cannot find glib-mkenums, which is required to build ${PROJECT_NAME}") +endif(NOT GLIB_MKENUMS) + +function( glib_mkenums _output_filename_noext _header_templ _src_tmpl _enums_header0 ) + + foreach(_enums_header ${_enums_header0} ${ARGN}) + list(APPEND _enums_headers "${CMAKE_CURRENT_SOURCE_DIR}/${_enums_header}") + endforeach(_enums_header) + + message("Generating file ${CMAKE_CURRENT_BINARY_DIR}/${_output_filename_noext}.h") + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_output_filename_noext}.h + COMMAND ${GLIB_MKENUMS} --template "${CMAKE_CURRENT_SOURCE_DIR}/${_header_templ}" ${_enums_headers} >${CMAKE_CURRENT_BINARY_DIR}/${_output_filename_noext}.h + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${_header_templ}" ${_enums_headers} + ) + + message("Generating file ${CMAKE_CURRENT_BINARY_DIR}/${_output_filename_noext}.c") + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_output_filename_noext}.c + COMMAND ${GLIB_MKENUMS} --template "${CMAKE_CURRENT_SOURCE_DIR}/${_src_tmpl}" ${_enums_headers} >${CMAKE_CURRENT_BINARY_DIR}/${_output_filename_noext}.c + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${_src_tmpl}" ${_enums_headers} + ) +endfunction( glib_mkenums ) + +find_program(GLIB_GENMARSHAL glib-genmarshal) +if(NOT GLIB_GENMARSHAL) + message(FATAL_ERROR "Cannot find glib-genmarshal, which is required to build ${PROJECT_NAME}") +endif(NOT GLIB_GENMARSHAL) + +function(glib_genmarshal _output_filename_noext _prefix _marshallist_filename) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_output_filename_noext}.h + COMMAND ${GLIB_GENMARSHAL} --header --skip-source --prefix=${_prefix} "${CMAKE_CURRENT_SOURCE_DIR}/${_marshallist_filename}" >${CMAKE_CURRENT_BINARY_DIR}/${_output_filename_noext}.h.tmp + COMMAND ${CMAKE_COMMAND} -E rename ${CMAKE_CURRENT_BINARY_DIR}/${_output_filename_noext}.h.tmp ${CMAKE_CURRENT_BINARY_DIR}/${_output_filename_noext}.h + DEPENDS ${_marshallist_filename} + ) + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_output_filename_noext}.c + COMMAND ${CMAKE_COMMAND} -E echo " #include \\\"${_output_filename_noext}.h\\\"" >${CMAKE_CURRENT_BINARY_DIR}/${_output_filename_noext}.c.tmp + COMMAND ${GLIB_GENMARSHAL} --body --skip-source --prefix=${_prefix} "${CMAKE_CURRENT_SOURCE_DIR}/${_marshallist_filename}" >>${CMAKE_CURRENT_BINARY_DIR}/${_output_filename_noext}.c.tmp + COMMAND ${CMAKE_COMMAND} -E rename ${CMAKE_CURRENT_BINARY_DIR}/${_output_filename_noext}.c.tmp ${CMAKE_CURRENT_BINARY_DIR}/${_output_filename_noext}.c + DEPENDS ${_marshallist_filename} + ) +endfunction(glib_genmarshal) + +find_program(GLIB_COMPILE_RESOURCES glib-compile-resources) +if(NOT GLIB_COMPILE_RESOURCES) + message(FATAL_ERROR "Cannot find glib-compile-resources, which is required to build ${PROJECT_NAME}") +endif(NOT GLIB_COMPILE_RESOURCES) + +macro(glib_compile_resources _sourcedir _outputprefix _cname _inxml) + add_custom_command( + OUTPUT ${_outputprefix}.h + COMMAND ${GLIB_COMPILE_RESOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/${_inxml} --target=${_outputprefix}.h --sourcedir=${_sourcedir} --c-name ${_cname} --generate-header + DEPENDS ${_inxml} ${ARGN} + VERBATIM + ) + add_custom_command( + OUTPUT ${_outputprefix}.c + COMMAND ${GLIB_COMPILE_RESOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/${_inxml} --target=${_outputprefix}.c --sourcedir=${_sourcedir} --c-name ${_cname} --generate-source + DEPENDS ${_inxml} ${ARGN} + VERBATIM + ) +endmacro(glib_compile_resources) diff --git a/cmake/modules/GObjectIntrospection.cmake b/cmake/modules/GObjectIntrospection.cmake new file mode 100644 index 0000000000..899069f141 --- /dev/null +++ b/cmake/modules/GObjectIntrospection.cmake @@ -0,0 +1,234 @@ +include(CMakeParseArguments) +include(FindPkgConfig) + +set(_PKG_CONFIG_MODULE "gobject-introspection-1.0") + +pkg_check_modules(GOBJECT_INTROSPECTION REQUIRED ${_PKG_CONFIG_MODULE}) + +############################################################################### +# Helpers +############################################################################### +# this macro will run "pkg-config --variable=VARIABLE ${_PKG_CONFIG_MODULE}" +# and store the result in OUTPUT_VARIABLE +macro(_pkg_config_variable VARIABLE OUTPUT_VARIABLE) + execute_process( + COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=${VARIABLE} ${_PKG_CONFIG_MODULE} + OUTPUT_VARIABLE ${OUTPUT_VARIABLE} + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +endmacro(_pkg_config_variable) + +# this macro will prefix every item in _list with _prefix and return it in +# _newlist. +macro(_gir_list_prefix _newlist _list _prefix) + set(${_newlist}) + foreach(_item IN LISTS ${_list}) + list(APPEND ${_newlist} ${_prefix}${_item}) + endforeach(_item) +endmacro(_gir_list_prefix) + +############################################################################### +# use the pkg-config to grab a bunch of variables from the +# gobject-introspection.pc file +############################################################################### +_pkg_config_variable(g_ir_scanner GIR_SCANNER) +_pkg_config_variable(g_ir_compiler GIR_COMPILER) + +# CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT is only set when the variable is +# actually set, so we need to create another variable to track that. +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} CACHE INTERNAL + "holds the default install path if cmake set it") + mark_as_advanced(_INSTALL_PREFIX) +endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + +# check if cmake_install_prefix was specified, if so build our paths using that +if(_INSTALL_PREFIX) + _pkg_config_variable(girdir GIR_GIRDIR) + _pkg_config_variable(typelibdir GIR_TYPELIBDIR) +else(_INSTALL_PREFIX) + set(GIR_GIRDIR "${CMAKE_INSTALL_FULL_DATAROOTDIR}/gir-1.0") + set(GIR_TYPELIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}/girepository-1.0") +endif(_INSTALL_PREFIX) + +############################################################################### +# The main function +############################################################################### +function(gobject_introspection _FIRST_ARG) + set(options QUIET VERBOSE) + set(oneValueArgs + FILENAME + FORMAT + LIBRARY + NAMESPACE + NSVERSION + PROGRAM + PROGRAM_ARG + ) + set(multiValueArgs + BUILT_SOURCES + CFLAGS + COMPILER_ARGS + HEADERS + IDENTIFIER_PREFIXES + PACKAGES + SCANNER_ARGS + SOURCES + SYMBOL_PREFIXES + ) + + CMAKE_PARSE_ARGUMENTS(GIR "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN}) + + if(ADD_GIR_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown keys given to ADD_GIR_INTROSPECTION(): \"${ADD_GIR_UNPARSED_ARGUMENTS}\"") + endif(ADD_GIR_UNPARSED_ARGUMENTS) + + ########################################################################### + # make sure that the user set some variables... + ########################################################################### + if(NOT GIR_FILENAME) + message(FATAL_ERROR "No gir filename given") + endif(NOT GIR_FILENAME) + + if(NOT GIR_NAMESPACE) + # the caller didn't give us a namespace, try to grab it from the filename + string(REGEX REPLACE "([^-]+)-.*" "\\1" GIR_NAMESPACE "${GIR_FILENAME}") + if(NOT GIR_NAMESPACE) + message(FATAL_ERROR "No namespace given and couldn't find one in FILENAME") + endif(NOT GIR_NAMESPACE) + endif(NOT GIR_NAMESPACE) + + if(NOT GIR_NSVERSION) + # the caller didn't give us a namespace version, try to grab it from the filemenu + string(REGEX REPLACE ".*-([^-]+).gir" "\\1" GIR_NSVERSION "${GIR_FILENAME}") + if(NOT GIR_NSVERSION) + message(FATAL_ERROR "No namespace version given and couldn't find one in FILENAME") + endif(NOT GIR_NSVERSION) + endif(NOT GIR_NSVERSION) + + if(NOT GIR_CFLAGS) + get_directory_property(GIR_CFLAGS INCLUDE_DIRECTORIES) + _gir_list_prefix(GIR_REAL_CFLAGS GIR_CFLAGS "-I") + endif(NOT GIR_CFLAGS) + + ########################################################################### + # Fix up some of our arguments + ########################################################################### + if(GIR_VERBOSE) + set(GIR_VERBOSE "--verbose") + else(GIR_VERBOSE) + set(GIR_VERBOSE "") + endif(GIR_VERBOSE) + + if(GIR_QUIET) + set(GIR_QUIET "--quiet") + else(GIR_QUIET) + set(GIR_QUIET "") + endif(GIR_QUIET) + + if(GIR_FORMAT) + set(GIR_FORMAT "--format=${GIR_FORMAT}") + endif(GIR_FORMAT) + + # if library is set, we need to prepend --library= on to it + if(GIR_LIBRARY) + set(GIR_REAL_LIBRARY "--library=${GIR_LIBRARY}") + endif(GIR_LIBRARY) + + # if program has been set, we prepend --program= on to it + if(GIR_PROGRAM) + set(GIR_PROGRAM "--program=${GIR_PROGRAM}") + endif(GIR_PROGRAM) + + # if program_arg has been set, we prepend --program-arg= on to it + if(GIR_PROGRAM_ARG) + set(GIR_PROGRAM_ARG "--program-arg=${GIR_PROGRAM_ARG}") + endif(GIR_PROGRAM_ARG) + + ########################################################################### + # Clean up any of the multivalue items that all need to be prefixed + ########################################################################### + + # if the user specified IDENTIFIER_PREFIXES we need to prefix each with --identifier-prefix + if(GIR_IDENTIFIER_PREFIXES) + _gir_list_prefix(GIR_REAL_IDENTIFIER_PREFIXES GIR_IDENTIFIER_PREFIXES "--identifier-prefix=") + endif(GIR_IDENTIFIER_PREFIXES) + + # if the user specified SYMBOL_PREFIXES we need to prefix each with --symbol-prefix= + if(GIR_SYMBOL_PREFIXES) + _gir_list_prefix(GIR_REAL_SYMBOL_PREFIXES GIR_SYMBOL_PREFIXES "--symbol-prefix=") + endif(GIR_SYMBOL_PREFIXES) + + # if the user specified PACKAGES we need to prefix each with --pkg + if(GIR_PACKAGES) + _gir_list_prefix(GIR_REAL_PACKAGES GIR_PACKAGES "--pkg=") + endif(GIR_PACKAGES) + + # if the user specified BUILT_SOURCES, we need to get their paths since + # they could be in CMAKE_CURRENT_BUILD_DIR + if(GIR_BUILT_SOURCES) + set(GIR_REAL_BUILT_SOURCES) + + foreach(ITEM ${GIR_BUILT_SOURCES}) + get_source_file_property(LOCATION ${ITEM} LOCATION) + list(APPEND GIR_REAL_BUILT_SOURCES "${LOCATION}") + endforeach(ITEM) + endif(GIR_BUILT_SOURCES) + + ########################################################################### + # Add the custom commands + ########################################################################### + set(ENV{CFLAGS} ${GIR_REAL_CFLAGS}) + add_custom_command( + OUTPUT ${GIR_FILENAME} + COMMAND ${GIR_SCANNER} ${GIR_SCANNER_ARGS} + --strict + --warn-all + --namespace=${GIR_NAMESPACE} + --nsversion=${GIR_NSVERSION} + ${GIR_REAL_CFLAGS} + ${GIR_FORMAT} + ${GIR_REAL_LIBRARY} + ${GIR_PROGRAM} ${GIR_PROGRAM_ARGS} + ${GIR_QUIET} ${GIR_VERBOSE} + ${GIR_REAL_IDENTIFIER_PREFIXES} + ${GIR_REAL_SYMBOL_PREFIXES} + ${GIR_REAL_PACKAGES} + --no-libtool + -L${CMAKE_CURRENT_BINARY_DIR} + --output=${CMAKE_CURRENT_BINARY_DIR}/${GIR_FILENAME} + ${GIR_SOURCES} + ${GIR_REAL_BUILT_SOURCES} + DEPENDS ${GIR_LIBRARY} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + VERBATIM + ) + + add_custom_target("gir_${GIR_FILENAME}" ALL DEPENDS ${GIR_LIBRARY} ${GIR_FILENAME}) + + install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/${GIR_FILENAME} + DESTINATION ${GIR_GIRDIR} + ) + + # create the name of the typelib + string(REPLACE ".gir" ".typelib" GIR_TYPELIB "${GIR_FILENAME}") + + add_custom_command( + COMMAND ${GIR_COMPILER} ${GIR_COMPILER_ARGS} + ${CMAKE_CURRENT_BINARY_DIR}/${GIR_FILENAME} + --output=${CMAKE_CURRENT_BINARY_DIR}/${GIR_TYPELIB} + OUTPUT ${GIR_TYPELIB} + DEPENDS ${GIR_FILENAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + + add_custom_target("typelib_${GIR_TYPELIB}" ALL DEPENDS ${GIR_LIBRARY} ${GIR_FILENAME} ${GIR_TYPELIB}) + install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/${GIR_TYPELIB} + DESTINATION ${GIR_TYPELIBDIR} + ) + + string(TOUPPER ${GIR_LIBRARY} GIR_TARGET) + set(${GIR_TARGET}_GIR_TARGETS "gir_${GIR_FILENAME}" "typelib_${GIR_TYPELIB}" PARENT_SCOPE) +endfunction(gobject_introspection) diff --git a/libzypp.spec.cmake b/libzypp.spec.cmake index 9f44a4d020..4e438b5073 100644 --- a/libzypp.spec.cmake +++ b/libzypp.spec.cmake @@ -114,6 +114,9 @@ BuildRequires: graphviz BuildRequires: libxml2-devel BuildRequires: yaml-cpp-devel +BuildRequires: gobject-introspection-devel +BuildRequires: gtk-doc + # we are loading libproxy dynamically, however we have # a failsafe unit test that links against libproxy to make # sure the API did not change diff --git a/package/libzypp.changes b/package/libzypp.changes index 2f287b89df..9bb551b3b9 100644 --- a/package/libzypp.changes +++ b/package/libzypp.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Fri Nov 15 10:45:20 CET 2024 - ma@suse.de + +- The 20MB download limit must not apply to non-metadata files like + package URLs provided via the CLI (bsc#1233393). +- version 17.35.14 (35) + ------------------------------------------------------------------- Tue Nov 12 14:35:35 CET 2024 - ma@suse.de diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt index bfac1ae3bf..82b818e229 100644 --- a/po/CMakeLists.txt +++ b/po/CMakeLists.txt @@ -12,7 +12,7 @@ SET( XGETTEXT_OPTIONS ${XGETTEXT_OPTIONS} --copyright-holder=\"SuSE Linux GmbH, SET( XGETTEXT_OPTIONS ${XGETTEXT_OPTIONS} --package-name=${POT_NAME} --default-domain=${POT_NAME} ) SET( _abs_POT_FILE_DEPENDS ) -SET( POT_FILE_DEPENDS ${POT_FILE_DEPENDS_ZYPP} ${POT_FILE_DEPENDS_ZYPP_CORE} ${POT_FILE_DEPENDS_ZYPP_MEDIA} ${POT_FILE_DEPENDS_ZYPP_CURL} ${POT_FILE_DEPENDS_ZYPP_TUI} ) +SET( POT_FILE_DEPENDS ${POT_FILE_DEPENDS_ZYPP} ${POT_FILE_DEPENDS_ZYPP_CORE} ${POT_FILE_DEPENDS_ZYPP_MEDIA} ${POT_FILE_DEPENDS_ZYPP_CURL} ${POT_FILE_DEPENDS_ZYPP_TUI} ${POT_FILE_DEPENDS_ZYPP_GLIB} ) FOREACH( _currentDepends ${POT_FILE_DEPENDS} ) SET( _abs_POT_FILE_DEPENDS ${_abs_POT_FILE_DEPENDS} ${LIBZYPP_SOURCE_DIR}/${_currentDepends} ) ENDFOREACH() diff --git a/po/id.po b/po/id.po index dc993d8883..f6b5a2a470 100644 --- a/po/id.po +++ b/po/id.po @@ -9,8 +9,8 @@ msgstr "" "Project-Id-Version: YaST (@memory@)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-11-11 12:40+0100\n" -"PO-Revision-Date: 2023-09-23 11:15+0000\n" -"Last-Translator: Kukuh Syafaat \n" +"PO-Revision-Date: 2024-11-13 15:48+0000\n" +"Last-Translator: Arif Budiman \n" "Language-Team: Indonesian \n" "Language: id\n" @@ -18,7 +18,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.9.1\n" +"X-Generator: Weblate 5.8.3\n" #: zypp/CountryCode.cc:50 msgid "Unknown country: " @@ -4170,7 +4170,7 @@ msgstr "Kontrak Pelanggan Tambahan Diperlukan" #: zypp/VendorSupportOptions.cc:31 msgid "Discontinued and superseded by a different package" -msgstr "" +msgstr "Dihentikan dan digantikan oleh paket yang berbeda" #: zypp/VendorSupportOptions.cc:33 msgid "invalid" @@ -4226,6 +4226,8 @@ msgid "" "The package was discontinued and has been superseded by a new package with a " "different name." msgstr "" +"Paket ini sudah tidak dilanjutkan dan telah digantikan oleh paket baru " +"dengan nama yang berbeda." #: zypp/VendorSupportOptions.cc:60 msgid "Unknown support option. Description not available" @@ -4325,11 +4327,11 @@ msgstr "Tidak dapat membuat %s" #: zypp/ng/repo/workflows/repomanagerwf.cc:491 msgid "Failed to retrieve new repository metadata." -msgstr "" +msgstr "Gagal mengambil metadata repositori baru." #: zypp/ng/repo/workflows/repomanagerwf.cc:578 msgid "Failed to cache repo ( unable to start repo2solv )." -msgstr "" +msgstr "Gagal menyimpan cache repo (tidak dapat memulai repo2solv)." #: zypp/ng/repo/workflows/repomanagerwf.cc:596 #: zypp/ng/repo/workflows/repomanagerwf.cc:625 @@ -4350,7 +4352,7 @@ msgstr "Tidak dapat membuat singgahan di %s - tidak ada izin untuk menulis." #: zypp/ng/repo/workflows/repomanagerwf.cc:808 #, boost-format msgid "Failed to cache repo %1%" -msgstr "" +msgstr "Gagal menyimpan cache repo %1%" #: zypp/ng/repo/workflows/repomanagerwf.cc:825 msgid "Unhandled repository type" @@ -4401,28 +4403,28 @@ msgstr "Tidak dapat membaca berkas repo '%1%': Izin ditolak" #: zypp/ng/repomanager.cc:383 msgid "Cleaning metadata" -msgstr "" +msgstr "Membersihkan metadata" #: zypp/ng/repomanager.cc:401 msgid "Cleaning packages" -msgstr "" +msgstr "Membersihkan paket" #: zypp/ng/repomanager.cc:453 msgid "Cleaning up cache dirs" -msgstr "" +msgstr "Membersihkan dir cache" #: zypp/ng/repomanager.cc:473 #, boost-format msgid "Cleaning up directory: %1%" -msgstr "" +msgstr "Membersihkan direktori: %1%" #: zypp/ng/repomanager.cc:503 msgid "Cleaning cache" -msgstr "" +msgstr "Membersihkan cache" #: zypp/ng/repomanager.cc:524 msgid "Loading from cache" -msgstr "" +msgstr "Memuat dari cache" #: zypp/ng/repomanager.cc:615 #, c-format, boost-format @@ -4441,11 +4443,11 @@ msgstr "Tidak dapat menghapus '%s'" #: zypp/ng/repomanager.cc:705 msgid "Modifying repository" -msgstr "" +msgstr "Memodifikasi repositori" #: zypp/ng/repomanager.cc:892 msgid "Refreshing Repository: " -msgstr "" +msgstr "Menyegarkan Repositori: " #: zypp/ng/repomanager.cc:1073 zypp/ng/repomanager.cc:1145 msgid "Can't figure out where the service is stored." @@ -4472,56 +4474,58 @@ msgstr "Alias layanan tidak dapat dimulai dengan titik." #: zypp/ng/reporthelper.cc:26 #, c-format, boost-format msgid "No digest for file %s." -msgstr "" +msgstr "Tidak ada intisari untuk berkas %s." #: zypp/ng/reporthelper.cc:39 #, c-format, boost-format msgid "Unknown digest %s for file %s." -msgstr "" +msgstr "Intisari %s tidak dikenal untuk berkas %s." #: zypp/ng/reporthelper.cc:52 #, c-format, boost-format msgid "Digest verification failed for file '%s'" -msgstr "" +msgstr "Verifikasi intisari gagal untuk berkas '%s'" #. TranslatorExplanation: speaking of a file #: zypp/ng/reporthelper.cc:69 #, c-format, boost-format msgid "File '%s' is unsigned, continue?" -msgstr "" +msgstr "Berkas '%s' tidak ditandatangani, lanjutkan?" #. TranslatorExplanation: speaking of a file #: zypp/ng/reporthelper.cc:73 #, c-format, boost-format msgid "File '%s' from repository '%s' is unsigned, continue?" -msgstr "" +msgstr "Berkas '%s' dari repositori '%s' tidak ditandatangani, lanjutkan?" #: zypp/ng/reporthelper.cc:90 msgid "Do you want to reject the key, trust temporarily, or trust always?" msgstr "" +"Apakah Anda ingin menolak kunci, percaya untuk sementara, atau selalu " +"percaya?" #: zypp/ng/reporthelper.cc:116 #, boost-format msgid "Key Name: %1%" -msgstr "" +msgstr "Nama kunci: %1%" #: zypp/ng/reporthelper.cc:128 #, boost-format msgid "Received %1% new package signing key from repository \"%2%\":" msgid_plural "Received %1% new package signing keys from repository \"%2%\":" -msgstr[0] "" +msgstr[0] "Menerima %1% kunci penandatanganan paket baru dari repositori \"%2%\":" #. translator: %1% is a file name #: zypp/ng/reporthelper.cc:144 #, boost-format msgid "Signature verification failed for file '%1%'." -msgstr "" +msgstr "Verifikasi tanda tangan gagal untuk berkas '%1%'." #. translator: %1% is a file name, %2% a repositories na me #: zypp/ng/reporthelper.cc:147 #, boost-format msgid "Signature verification failed for file '%1%' from repository '%2%'." -msgstr "" +msgstr "Verifikasi tanda tangan gagal untuk berkas '%1%' dari repositori '%2%'." #. @TODO use a centralized Continue string! #: zypp/ng/reporthelper.cc:150 zypp-tui/output/Out.cc:32 @@ -4533,6 +4537,7 @@ msgstr "Lanjutkan?" #, c-format, boost-format msgid "File '%s' is signed with an unknown key '%s'. Continue?" msgstr "" +"Berkas '%s' ditandatangani dengan kunci '%s' yang tidak dikenal. Lanjutkan?" #. translators: the last %s is gpg key ID #: zypp/ng/reporthelper.cc:172 @@ -4540,6 +4545,8 @@ msgstr "" msgid "" "File '%s' from repository '%s' is signed with an unknown key '%s'. Continue?" msgstr "" +"Berkas '%s' dari repositori '%s' ditandatangani dengan kunci '%s' yang tidak " +"dikenal. Lanjutkan?" #. translator: %1% is a repositories name #: zypp/ng/workflows/repoinfowf.cc:78 @@ -4604,7 +4611,7 @@ msgstr "applydeltarpm gagal." #: zypp/repo/RepoException.cc:73 msgid "No permision to write repository cache." -msgstr "" +msgstr "Tidak ada izin untuk menulis cache repositori." #: zypp/repo/RepoException.cc:130 msgid "Service plugin does not support changing an attribute." diff --git a/po/nb.po b/po/nb.po index 122a430eba..7ce5f79455 100644 --- a/po/nb.po +++ b/po/nb.po @@ -13,8 +13,8 @@ msgstr "" "Project-Id-Version: zypp\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-11-11 12:40+0100\n" -"PO-Revision-Date: 2022-05-29 21:13+0000\n" -"Last-Translator: Karl Ove Hufthammer \n" +"PO-Revision-Date: 2024-11-14 10:48+0000\n" +"Last-Translator: Martin Hansen \n" "Language-Team: Norwegian Bokmål \n" "Language: nb\n" @@ -22,7 +22,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.9.1\n" +"X-Generator: Weblate 5.8.3\n" #: zypp/CountryCode.cc:50 msgid "Unknown country: " @@ -1023,7 +1023,7 @@ msgstr "Qatar" #. :QAT:634: #: zypp/CountryCode.cc:344 msgid "Reunion" -msgstr "Reunion" +msgstr "Réunion" #. :REU:638: #: zypp/CountryCode.cc:345 @@ -1354,7 +1354,7 @@ msgstr "Inneholder" #: zypp/Dep.cc:97 msgid "Prerequires" -msgstr "" +msgstr "Forutsetninger" #: zypp/Dep.cc:98 msgid "Requires" @@ -1365,9 +1365,8 @@ msgid "Conflicts" msgstr "Konflikter" #: zypp/Dep.cc:100 -#, fuzzy msgid "Obsoletes" -msgstr "behold den foreldede pakken %s" +msgstr "Foreldes" #: zypp/Dep.cc:101 msgid "Recommends" @@ -1392,9 +1391,8 @@ msgid "Tried to import not existent key %s into keyring %s" msgstr "Forsøkte å importere ikke-eksisterende nøkkel %s til nøkkelring %s" #: zypp/KeyRing.cc:407 -#, fuzzy msgid "Failed to import key." -msgstr "Kunne ikke importere offentlig nøkkel %1%" +msgstr "Kunne ikke importere nøkkel." #: zypp/KeyRing.cc:414 msgid "Failed to delete key." @@ -3685,7 +3683,7 @@ msgstr "Vietnamesisk" #. language code: vol vo #: zypp/LanguageCode.cc:1103 msgid "Volapuk" -msgstr "Volapuk" +msgstr "Volapük" #. language code: vot #: zypp/LanguageCode.cc:1105 @@ -3805,21 +3803,20 @@ msgstr "Følgende handlinger vil bli utført:" #. translators: an annotation to a gpg keys expiry date #: zypp/PublicKey.cc:65 -#, fuzzy msgid "does not expire" -msgstr "(utløper ikke)" +msgstr "utløper ikke" #. translators: an annotation to a gpg keys expiry date: "expired: 1999-04-12" #: zypp/PublicKey.cc:70 #, boost-format msgid "expired: %1%" -msgstr "" +msgstr "utløpt: %1%" #. translators: an annotation to a gpg keys expiry date: "expires: 2111-04-12" #: zypp/PublicKey.cc:75 #, boost-format msgid "expires: %1%" -msgstr "" +msgstr "utløper: %1%" #. translators: an annotation to a gpg keys expiry date #: zypp/PublicKey.cc:84 @@ -3838,11 +3835,11 @@ msgstr "(utløper innen 24 t)" #. translators: an annotation to a gpg keys expiry date #: zypp/PublicKey.cc:101 -#, fuzzy, c-format, boost-format +#, boost-format, c-format msgid "(expires in %d day)" msgid_plural "(expires in %d days)" -msgstr[0] "(utløper innen 24 t)" -msgstr[1] "(utløper innen 24 t)" +msgstr[0] "(utløper om %d dag)" +msgstr[1] "(utløper om %d dager)" #: zypp/VendorSupportOptions.cc:14 msgid "unknown" @@ -3870,7 +3867,7 @@ msgstr "Kundekontrakt kreves" #: zypp/VendorSupportOptions.cc:31 msgid "Discontinued and superseded by a different package" -msgstr "" +msgstr "Utgått og erstattet av en annen pakke" #: zypp/VendorSupportOptions.cc:33 msgid "invalid" @@ -3925,6 +3922,7 @@ msgid "" "The package was discontinued and has been superseded by a new package with a " "different name." msgstr "" +"Pakken har utgått og har blitt erstattet av en ny pakke med et nytt navn." #: zypp/VendorSupportOptions.cc:60 msgid "Unknown support option. Description not available" @@ -3947,12 +3945,12 @@ msgstr "Ukjent samsvarsmodus '%s'" #: zypp/base/StrMatcher.cc:153 #, c-format, boost-format msgid "Unknown match mode '%s' for pattern '%s'" -msgstr "Ukjent samsvarsmodus '%s' for mønsteret '%s'." +msgstr "Ukjent samsvarsmodus '%s' for mønsteret '%s'" #: zypp/base/StrMatcher.cc:157 #, c-format, boost-format msgid "Invalid regular expression '%s': regcomp returned %d" -msgstr "Ugyldig regulært uttrykk '%s': tilbakemelding 'regcomp' %d" +msgstr "Ugyldig regulært uttrykk '%s': regcomp returnerte %d" #: zypp/base/StrMatcher.cc:158 #, c-format, boost-format @@ -3969,18 +3967,20 @@ msgstr "Autentisering kreves for '%s'" #. just report (NO_ERROR); no interactive request to the user #: zypp/media/MediaCurl.cc:789 msgid "Will try again..." -msgstr "" +msgstr "Vil forsøke igjen..." #: zypp/media/MediaCurl.cc:792 #, boost-format msgid "Giving up after %1% attempts." -msgstr "" +msgstr "Gir opp etter %1% forsøk." #: zypp/media/MediaCurl.cc:907 zypp-curl/ng/network/networkrequesterror.cc:124 msgid "" "Visit the SUSE Customer Center to check whether your registration is valid " "and has not expired." msgstr "" +"Besøk SUSE-kundesenter for å sjekke om registreringen din er gyldig og ikke " +"har utløpt." #: zypp/media/MediaCurl.cc:909 zypp-curl/ng/network/networkrequesterror.cc:126 msgid "" @@ -3995,6 +3995,8 @@ msgid "" "Create attach point: Can't find a writable directory to create an attach " "point" msgstr "" +"Opprett tilknytningspunkt: Kan ikke finne skrivbar mappe å opprette et " +"tilknytningspunkt" #: zypp/misc/CheckAccessDeleted.cc:453 msgid "Please install package 'lsof' first." @@ -4020,11 +4022,11 @@ msgstr "Kan ikke opprette %s" #: zypp/ng/repo/workflows/repomanagerwf.cc:491 msgid "Failed to retrieve new repository metadata." -msgstr "" +msgstr "Kunne ikke hente nye pakkebrønn metadata." #: zypp/ng/repo/workflows/repomanagerwf.cc:578 msgid "Failed to cache repo ( unable to start repo2solv )." -msgstr "" +msgstr "Kunne ikke hurtiglagre pakkebrønn ( kan ikke starte repo2solv )." #: zypp/ng/repo/workflows/repomanagerwf.cc:596 #: zypp/ng/repo/workflows/repomanagerwf.cc:625 @@ -4045,7 +4047,7 @@ msgstr "Kan ikke opprette mellomlager på %s - skrivebeskyttet." #: zypp/ng/repo/workflows/repomanagerwf.cc:808 #, boost-format msgid "Failed to cache repo %1%" -msgstr "" +msgstr "Kunne ikke hurtiglagre pakkebrønn %1%" #: zypp/ng/repo/workflows/repomanagerwf.cc:825 msgid "Unhandled repository type" @@ -4080,44 +4082,44 @@ msgstr "Ukjent feil ved lesing fra '%s'" #: zypp/ng/repomanager.cc:196 #, boost-format msgid "Cannot read repo directory '%1%': Permission denied" -msgstr "" +msgstr "Kan ikke lese pakkebrønn mappe '%1%': Tilgang nektet" #. TranslatorExplanation '%s' is a pathname #: zypp/ng/repomanager.cc:204 zypp/ng/repomanager.cc:468 #: zypp/ng/repomanager.cc:1329 zypp/repo/PluginServices.cc:49 #, c-format, boost-format msgid "Failed to read directory '%s'" -msgstr "Kunnne ikke lese katalogen: '%s'." +msgstr "Kunne ikke lese mappen '%s'" #: zypp/ng/repomanager.cc:214 #, boost-format msgid "Cannot read repo file '%1%': Permission denied" -msgstr "" +msgstr "Kan ikke lese pakkebrønn fil '%1%': Tilgang nektet" #: zypp/ng/repomanager.cc:383 msgid "Cleaning metadata" -msgstr "" +msgstr "Renser metadata" #: zypp/ng/repomanager.cc:401 msgid "Cleaning packages" -msgstr "" +msgstr "Renser pakker" #: zypp/ng/repomanager.cc:453 msgid "Cleaning up cache dirs" -msgstr "" +msgstr "Renser hurtiglager mapper" #: zypp/ng/repomanager.cc:473 #, boost-format msgid "Cleaning up directory: %1%" -msgstr "" +msgstr "Renser mapper: %1%" #: zypp/ng/repomanager.cc:503 msgid "Cleaning cache" -msgstr "" +msgstr "Renser hurtiglager" #: zypp/ng/repomanager.cc:524 msgid "Loading from cache" -msgstr "" +msgstr "Laster fra hurtiglager" #: zypp/ng/repomanager.cc:615 #, c-format, boost-format @@ -4136,11 +4138,11 @@ msgstr "Kan ikke slette '%s'" #: zypp/ng/repomanager.cc:705 msgid "Modifying repository" -msgstr "" +msgstr "Endrer pakkebrønn" #: zypp/ng/repomanager.cc:892 msgid "Refreshing Repository: " -msgstr "" +msgstr "Oppdaterer Pakkebrønn: " #: zypp/ng/repomanager.cc:1073 zypp/ng/repomanager.cc:1145 msgid "Can't figure out where the service is stored." @@ -4152,7 +4154,7 @@ msgstr "Finner ikke ut hvor tjenesten er lagret." #: zypp/ng/repomanager.cc:1433 #, boost-format msgid "Unknown service '%1%': Removing orphaned service repository '%2%'" -msgstr "" +msgstr "Ukjent tjeneste '%1%': Fjerner foreldreløs tjeneste pakkebrønn '%2%'" #: zypp/ng/repomanager.h:65 msgid "Repository alias cannot start with dot." @@ -4165,57 +4167,57 @@ msgstr "Tjenestealiaset kan ikke begynne med punktum." #: zypp/ng/reporthelper.cc:26 #, c-format, boost-format msgid "No digest for file %s." -msgstr "" +msgstr "Ingen sammendrag for filen %s." #: zypp/ng/reporthelper.cc:39 #, c-format, boost-format msgid "Unknown digest %s for file %s." -msgstr "" +msgstr "Ukjent sammendrag %s for filen %s." #: zypp/ng/reporthelper.cc:52 #, c-format, boost-format msgid "Digest verification failed for file '%s'" -msgstr "" +msgstr "Sammendragsbekreftelse mislyktes for filen '%s'" #. TranslatorExplanation: speaking of a file #: zypp/ng/reporthelper.cc:69 #, c-format, boost-format msgid "File '%s' is unsigned, continue?" -msgstr "" +msgstr "Filen '%s' er usignert, fortsett?" #. TranslatorExplanation: speaking of a file #: zypp/ng/reporthelper.cc:73 #, c-format, boost-format msgid "File '%s' from repository '%s' is unsigned, continue?" -msgstr "" +msgstr "Filen '%s' fra pakkebrønn '%s' er usignert, fortsett?" #: zypp/ng/reporthelper.cc:90 msgid "Do you want to reject the key, trust temporarily, or trust always?" -msgstr "" +msgstr "Vil du avvise nøkkelen, stole midlertidig, eller alltid stole på?" #: zypp/ng/reporthelper.cc:116 #, boost-format msgid "Key Name: %1%" -msgstr "" +msgstr "Nøkkel Navn: %1%" #: zypp/ng/reporthelper.cc:128 #, boost-format msgid "Received %1% new package signing key from repository \"%2%\":" msgid_plural "Received %1% new package signing keys from repository \"%2%\":" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Mottok %1% ny pakkesigneringsnøkkel fra pakkebrønn \"%2%\":" +msgstr[1] "Mottok %1% nye pakkesigneringsnøkler fra pakkebrønn \"%2%\":" #. translator: %1% is a file name #: zypp/ng/reporthelper.cc:144 #, boost-format msgid "Signature verification failed for file '%1%'." -msgstr "" +msgstr "Signaturbekreftelse mislyktes for filen '%1%'." #. translator: %1% is a file name, %2% a repositories na me #: zypp/ng/reporthelper.cc:147 #, boost-format msgid "Signature verification failed for file '%1%' from repository '%2%'." -msgstr "" +msgstr "Signaturbekreftelse mislyktes for filen '%1%' fra pakkebrønn '%2%'." #. @TODO use a centralized Continue string! #: zypp/ng/reporthelper.cc:150 zypp-tui/output/Out.cc:32 @@ -4226,7 +4228,7 @@ msgstr "Vil du fortsette?" #: zypp/ng/reporthelper.cc:168 #, c-format, boost-format msgid "File '%s' is signed with an unknown key '%s'. Continue?" -msgstr "" +msgstr "Filen '%s' er signert med en ukjent nøkkel '%s'. Fortsett?" #. translators: the last %s is gpg key ID #: zypp/ng/reporthelper.cc:172 @@ -4234,12 +4236,14 @@ msgstr "" msgid "" "File '%s' from repository '%s' is signed with an unknown key '%s'. Continue?" msgstr "" +"Filen '%s' fra pakkebrønn '%s' er signert med en ukjent nøkkel '%s'. " +"Fortsett?" #. translator: %1% is a repositories name #: zypp/ng/workflows/repoinfowf.cc:78 #, boost-format msgid "Repository %1% does not define additional 'gpgkey=' URLs." -msgstr "" +msgstr "Pakkebrønn %1% definerer ikke ytterligere 'gpgkey=' URLer." #. no key in the cache is what we are looking for, lets download #. all keys specified in gpgkey= entries @@ -4248,14 +4252,14 @@ msgstr "" #: zypp/ng/workflows/repoinfowf.cc:87 #, boost-format msgid "Looking for gpg key ID %1% in repository %2%." -msgstr "" +msgstr "Ser etter gpg-nøkkel med ID %1% i pakkebrønn %2%." #. translator: %1% is a gpg key ID like 3DBDC284 #. %2% is a cache directories path #: zypp/ng/workflows/repoinfowf.cc:134 #, boost-format msgid "Looking for gpg key ID %1% in cache %2%." -msgstr "" +msgstr "Ser etter gpg-nøkkel med ID %1% i hurtiglager %2%." #: zypp/parser/RepoindexFileReader.cc:198 #, c-format, boost-format @@ -4268,9 +4272,8 @@ msgid "One or both of '%s' or '%s' attributes is required." msgstr "Én eller begge attributtene '%s' eller '%s' kreves." #: zypp/repo/PackageProvider.cc:343 -#, fuzzy msgid "Signature verification failed" -msgstr " kjøring mislyktes" +msgstr "Signaturbekreftelse mislyktes" #. TranslatorExplanation %s = package being checked for integrity #: zypp/repo/PackageProvider.cc:474 @@ -4298,12 +4301,11 @@ msgstr "applydeltarpm mislyktes." #: zypp/repo/RepoException.cc:73 msgid "No permision to write repository cache." -msgstr "" +msgstr "Ingen tillatelse til å skrive pakkebrønn hurtiglager." #: zypp/repo/RepoException.cc:130 -#, fuzzy msgid "Service plugin does not support changing an attribute." -msgstr "ressurstypen VAR1 støtter ikke funksjonen 'vis endringer'" +msgstr "Tjeneste-programtillegg støtter ikke endring av egenskap." #: zypp/repo/RepoProvideFile.cc:260 #, c-format, boost-format @@ -4318,7 +4320,7 @@ msgstr "Ingen nettadresse i pakkebrønn." #: zypp/repo/SUSEMediaVerifier.cc:104 zypp-media/ng/mediaverifier.cc:109 #, boost-format msgid "Expected medium %1%/%2% identified by file '%3%' with content:" -msgstr "" +msgstr "Forventet medium %1%/%2% identifisert av filen '%3%' med innhold:" #. [lhs][rhs] 0 = installed; 1 = to be installed #. TranslatorExplanation %1%(filename) %2%(package1) %3%(package2) @@ -4331,6 +4333,11 @@ msgid "" " conflicts with file from package\n" " %3%" msgstr "" +"Filen %1%\n" +" fra pakke\n" +" %2%\n" +" er i konflikt med filen fra pakke\n" +" %3%" #. TranslatorExplanation %1%(filename) %2%(package1) %3%(package2) #: zypp/sat/FileConflicts.cc:40 @@ -4342,6 +4349,11 @@ msgid "" " conflicts with file from install of\n" " %3%" msgstr "" +"Filen %1%\n" +" fra pakke\n" +" %2%\n" +" er i konflikt med filen fra installasjon av\n" +" %3%" #. TranslatorExplanation %1%(filename) %2%(package1) %3%(package2) #: zypp/sat/FileConflicts.cc:47 @@ -4353,6 +4365,11 @@ msgid "" " conflicts with file from package\n" " %3%" msgstr "" +"Filen %1%\n" +" fra installasjon av\n" +" %2%\n" +" er i konflikt med filen fra pakke\n" +" %3%" #. TranslatorExplanation %1%(filename) %2%(package1) %3%(package2) #: zypp/sat/FileConflicts.cc:53 @@ -4364,6 +4381,11 @@ msgid "" " conflicts with file from install of\n" " %3%" msgstr "" +"Filen %1%\n" +" fra installasjon av\n" +" %2%\n" +" er i konflikt med filen fra installasjon av\n" +" %3%" #. [lhs][rhs] 0 = installed; 1 = to be installed #. TranslatorExplanation %1%(filename1) %2%(package1) %%3%(filename2) 4%(package2) @@ -4378,6 +4400,13 @@ msgid "" " from package\n" " %4%" msgstr "" +"File %1%\n" +" fra pakke\n" +" %2%\n" +" er i konflikt med filen\n" +" %3%\n" +" fra pakke\n" +" %4%" #. TranslatorExplanation %1%(filename1) %2%(package1) %3%(filename2) %4%(package2) #: zypp/sat/FileConflicts.cc:76 @@ -4391,6 +4420,13 @@ msgid "" " from install of\n" " %4%" msgstr "" +"File %1%\n" +" fra pakke\n" +" %2%\n" +" er i konflikt med filen\n" +" %3%\n" +" fra installasjon av\n" +" %4%" #. TranslatorExplanation %1%(filename1) %2%(package1) %3%(filename2) %4%(package2) #: zypp/sat/FileConflicts.cc:85 @@ -4404,6 +4440,13 @@ msgid "" " from package\n" " %4%" msgstr "" +"Filen %1%\n" +" fra installasjon av\n" +" %2%\n" +" er i konflikt med filen\n" +" %3%\n" +" fra pakke\n" +" %4%" #. TranslatorExplanation %1%(filename1) %2%(package1) %3%(filename2) %4%(package2) #: zypp/sat/FileConflicts.cc:93 @@ -4417,6 +4460,13 @@ msgid "" " from install of\n" " %4%" msgstr "" +"Filen %1%\n" +" fra installasjon av \n" +" %2%\n" +" er i konflikt med filen\n" +" %3%\n" +" fra installasjon av\n" +" %4%" #: zypp/sat/detail/PoolImpl.cc:201 msgid "Can not create sat-pool." @@ -4429,9 +4479,8 @@ msgid "break %s by ignoring some of its dependencies" msgstr "ignorer noen avhengigheter selv om %s ikke vil fungere" #: zypp/solver/detail/ProblemSolutionIgnore.cc:48 -#, fuzzy msgid "generally ignore of some dependencies" -msgstr "ignorer generelt noen avhengigheter" +msgstr "generelt ignorer noen avhengigheter" #: zypp/solver/detail/SATResolver.cc:1160 #, boost-format @@ -4439,27 +4488,29 @@ msgid "" "the installed %1% does not belong to a distupgrade repository and must be " "replaced" msgstr "" +"den installerte %1% tilhører ikke et oppgraderings-pakkebrønn og må bli " +"erstattet" #. just in case #: zypp/solver/detail/SATResolver.cc:1162 #, boost-format msgid "the to be installed %1% does not belong to a distupgrade repository" -msgstr "" +msgstr "Det som skal installeres %1% tilhører ikke en oppgraderings-pakkebrønn" #: zypp/solver/detail/SATResolver.cc:1166 #, boost-format msgid "the installed %1% has inferior architecture" -msgstr "" +msgstr "det installerte %1% har en dårligere arkitektur" #: zypp/solver/detail/SATResolver.cc:1168 #, boost-format msgid "the to be installed %1% has inferior architecture" -msgstr "" +msgstr "det som skal installeres %1% har en dårligere arkitektur" #: zypp/solver/detail/SATResolver.cc:1171 #, boost-format msgid "problem with the installed %1%" -msgstr "" +msgstr "problem med den installerte %1%" #: zypp/solver/detail/SATResolver.cc:1174 msgid "conflicting requests" @@ -4472,17 +4523,17 @@ msgstr "en konflikt" #: zypp/solver/detail/SATResolver.cc:1180 #, boost-format msgid "nothing provides the requested '%1%'" -msgstr "" +msgstr "ingenting gir den etterspurte '%1%'" #: zypp/solver/detail/SATResolver.cc:1181 #: zypp/solver/detail/SATResolver.cc:1185 msgid "Have you enabled all the required repositories?" -msgstr "" +msgstr "Har du aktivert alle de nødvendige pakkebrønnene?" #: zypp/solver/detail/SATResolver.cc:1184 #, boost-format msgid "the requested package %1% does not exist" -msgstr "" +msgstr "den etterspurte pakken %1% eksisterer ikke" #: zypp/solver/detail/SATResolver.cc:1188 msgid "unsupported request" @@ -4491,44 +4542,47 @@ msgstr "forespørselen støttes ikke" #: zypp/solver/detail/SATResolver.cc:1191 #, boost-format msgid "'%1%' is provided by the system and cannot be erased" -msgstr "" +msgstr "'%1%' er anskaffet av systemet og kan ikke bli slettet" #: zypp/solver/detail/SATResolver.cc:1194 #, boost-format msgid "%1% is not installable" -msgstr "" +msgstr "%1% er ikke installerbar" #: zypp/solver/detail/SATResolver.cc:1199 #, boost-format msgid "nothing provides '%1%' needed by the installed %2%" -msgstr "" +msgstr "ingenting tilbyr '%1%' påkrevd av den installerte %2%" #: zypp/solver/detail/SATResolver.cc:1201 #, boost-format msgid "nothing provides '%1%' needed by the to be installed %2%" -msgstr "" +msgstr "ingenting tilbyr '%1%' som er nødvendig av %2% for å bli installert" #: zypp/solver/detail/SATResolver.cc:1204 #, boost-format msgid "cannot install both %1% and %2%" -msgstr "" +msgstr "kan ikke installere både %1% og %2%" #: zypp/solver/detail/SATResolver.cc:1209 #, boost-format msgid "the installed %1% conflicts with '%2%' provided by the installed %3%" msgstr "" +"den installerte %1% er i konflikt med '%2%' som gis av den installerte %3%" #: zypp/solver/detail/SATResolver.cc:1211 #, boost-format msgid "" "the installed %1% conflicts with '%2%' provided by the to be installed %3%" msgstr "" +"den installerte %1% er i konflikt med '%2%' gitt av %3% som skal installeres" #: zypp/solver/detail/SATResolver.cc:1215 #, boost-format msgid "" "the to be installed %1% conflicts with '%2%' provided by the installed %3%" msgstr "" +"den som skal installeres %1% er i konflikt med '%2%' gitt av installerte %3%" #: zypp/solver/detail/SATResolver.cc:1217 #, boost-format @@ -4536,50 +4590,57 @@ msgid "" "the to be installed %1% conflicts with '%2%' provided by the to be installed " "%3%" msgstr "" +"den som skal installeres %1% er i konflikt med '%2%' gitt av %3% som skal " +"installeres" #: zypp/solver/detail/SATResolver.cc:1224 #, boost-format msgid "the installed %1% obsoletes '%2%' provided by the installed %3%" -msgstr "" +msgstr "den installerte %1% har foreldet '%2%' gitt av den installerte %3%" #: zypp/solver/detail/SATResolver.cc:1226 #, boost-format msgid "the installed %1% obsoletes '%2%' provided by the to be installed %3%" msgstr "" +"den installerte %1% har foreldet '%2%' gitt av den som skal installeres %3%" #: zypp/solver/detail/SATResolver.cc:1230 #, boost-format msgid "the to be installed %1% obsoletes '%2%' provided by the installed %3%" msgstr "" +"den som skal installeres %1% har foreldet '%2%' gitt av den installerte %3%" #: zypp/solver/detail/SATResolver.cc:1232 #, boost-format msgid "" "the to be installed %1% obsoletes '%2%' provided by the to be installed %3%" msgstr "" +"den som skal installeres %1% har foreldet '%2%' gitt av den som skal " +"installeres %3%" #: zypp/solver/detail/SATResolver.cc:1237 #, boost-format msgid "the installed %1% conflicts with '%2%' provided by itself" -msgstr "" +msgstr "den installerte %1% er i konflikt med '%2%' som er gitt av den selv" #: zypp/solver/detail/SATResolver.cc:1239 #, boost-format msgid "the to be installed %1% conflicts with '%2%' provided by itself" msgstr "" +"den som skal installeres %1% er i konflikt med '%2%' som er gitt av seg selv" #: zypp/solver/detail/SATResolver.cc:1271 #, boost-format msgid "" "the installed %1% requires '%2%', but this requirement cannot be provided" -msgstr "" +msgstr "den installerte %1% er påkrevd av '%2%', men dette kravet kan ikke gis" #: zypp/solver/detail/SATResolver.cc:1273 #, boost-format msgid "" "the to be installed %1% requires '%2%', but this requirement cannot be " "provided" -msgstr "" +msgstr "%1% som skal installeres krever '%2%', men dette kravet kan ikke gis" #: zypp/solver/detail/SATResolver.cc:1275 msgid "deleted providers: " @@ -4601,13 +4662,15 @@ msgstr "uinstallerbare nødvendige pakker: " #: zypp/solver/detail/SATResolver.cc:1324 #, boost-format msgid "%1% is not yet fully integrated into %2%." -msgstr "" +msgstr "%1% er enda ikke fullstendig integrert i %2%." #: zypp/solver/detail/SATResolver.cc:1325 msgid "" "Typically you want to keep the PTF and choose to not install the maintenance " "patches." msgstr "" +"Vanligvis vil du beholde PTF-ene og velge å ikke installere vedlikeholds-" +"programfiks." #. translator: %1% is the name of a PTF. #: zypp/solver/detail/SATResolver.cc:1333 @@ -4616,6 +4679,8 @@ msgid "" "Removing the installed %1% in this context will remove (not replace!) the " "included PTF-packages too." msgstr "" +"Fjerning av den installerte %1% i denne sammenhengen vil fjerne (ikke " +"erstatte!) de inkluderte PTF-pakkene også." #: zypp/solver/detail/SATResolver.cc:1334 #, boost-format @@ -4623,42 +4688,44 @@ msgid "" "The PTF should be removed by calling '%1%'. This will update the included " "PTF-packages rather than removing them." msgstr "" +"PTF-ene burde bli fjernet ved å tilkalle '%1%'. Dette vil oppdatere de " +"inkluderte PTF-pakkene i stedet for å fjerne dem." #: zypp/solver/detail/SATResolver.cc:1335 msgid "Typically you want to keep the PTF or choose to cancel the action." -msgstr "" +msgstr "Vanligvis vil du beholde PTF-ene eller velge å avbryte handlingen." #. translator: %1% is the name of a PTF. #: zypp/solver/detail/SATResolver.cc:1340 #, boost-format msgid "The installed %1% blocks the desired action." -msgstr "" +msgstr "Den installerte %1% blokkerer den ønskede handlingen." #: zypp/solver/detail/SATResolver.cc:1341 msgid "Typically you want to keep the PTF and choose to cancel the action." -msgstr "" +msgstr "Vanligvis vil du beholde PTF-ene og velge å avbryte handlingen." #: zypp/solver/detail/SATResolver.cc:1398 #, boost-format msgid "remove lock to allow removal of %1%" -msgstr "" +msgstr "fjern låsen for å tillate fjerning av %1%" #: zypp/solver/detail/SATResolver.cc:1405 #: zypp/solver/detail/SATResolver.cc:1443 #, boost-format msgid "do not install %1%" -msgstr "" +msgstr "ikke installer %1%" #: zypp/solver/detail/SATResolver.cc:1422 #: zypp/solver/detail/SATResolver.cc:1464 #, boost-format msgid "keep %1%" -msgstr "" +msgstr "behold %1%" #: zypp/solver/detail/SATResolver.cc:1427 #, boost-format msgid "remove lock to allow installation of %1%" -msgstr "" +msgstr "fjern låsen for å tillate installasjonen av %1%" #: zypp/solver/detail/SATResolver.cc:1478 #: zypp/solver/detail/SATResolver.cc:1499 @@ -4673,65 +4740,65 @@ msgstr "ignorer advarsel om skadet system" #: zypp/solver/detail/SATResolver.cc:1484 #, boost-format msgid "do not ask to install a solvable providing %1%" -msgstr "" +msgstr "ikke be om å installere en løsning som gir %1%" #: zypp/solver/detail/SATResolver.cc:1506 #, boost-format msgid "do not ask to delete all solvables providing %1%" -msgstr "" +msgstr "ikke be om å slette alle løsningene som gir %1%" #: zypp/solver/detail/SATResolver.cc:1519 #, boost-format msgid "do not install most recent version of %1%" -msgstr "" +msgstr "ikke installer den nyeste versjonen av %1%" #: zypp/solver/detail/SATResolver.cc:1540 #, boost-format msgid "keep %1% despite the inferior architecture" -msgstr "" +msgstr "behold %1% til tross for den dårlige arkitekturen" #: zypp/solver/detail/SATResolver.cc:1545 #, boost-format msgid "install %1% despite the inferior architecture" -msgstr "" +msgstr "installer %1% til tross for den dårlige arkitekturen" #: zypp/solver/detail/SATResolver.cc:1554 #, boost-format msgid "keep obsolete %1%" -msgstr "" +msgstr "beholde foreldet %1%" #: zypp/solver/detail/SATResolver.cc:1559 #, boost-format msgid "install %1% from excluded repository" -msgstr "" +msgstr "installer %1% fra den ekskluderte pakkebrønnen" #. translator: %1% is a package name #: zypp/solver/detail/SATResolver.cc:1573 #, boost-format msgid "install %1% although it has been retracted" -msgstr "" +msgstr "installer %1% selv om den er trukket tilbake" #. translator: %1% is a package name #: zypp/solver/detail/SATResolver.cc:1576 #, boost-format msgid "allow installing the PTF %1%" -msgstr "" +msgstr "tillat installering av PTF-en %1%" #. translator: %1% is a package name #: zypp/solver/detail/SATResolver.cc:1579 #, boost-format msgid "install %1% although it is blacklisted" -msgstr "" +msgstr "installer %1% selv om den er svartlistet" #: zypp/solver/detail/SATResolver.cc:1599 #, boost-format msgid "downgrade of %1% to %2%" -msgstr "" +msgstr "nedgradering av %1% til %2%" #: zypp/solver/detail/SATResolver.cc:1606 #, boost-format msgid "architecture change of %1% to %2%" -msgstr "" +msgstr "arkitektur endring av %1% til %2%" #. FIXME? Actually .ident() must be eq. But the more verbose 'else' isn't bad either. #: zypp/solver/detail/SATResolver.cc:1617 @@ -4740,6 +4807,8 @@ msgid "" "install %1% (with vendor change)\n" " %2% --> %3%" msgstr "" +"installer %1% (med leverandør endring)\n" +" %2% --> %3%" #: zypp/solver/detail/SATResolver.cc:1622 #, boost-format @@ -4747,33 +4816,35 @@ msgid "" "install %1% from vendor %2%\n" " replacing %3% from vendor %4%" msgstr "" +"installer %1% fra leverandør %2%\n" +" erstatter %3% fra leverandør %4%" #: zypp/solver/detail/SATResolver.cc:1631 #, boost-format msgid "replacement of %1% with %2%" -msgstr "" +msgstr "erstatting av %1% med %2%" #: zypp/solver/detail/SATResolver.cc:1642 #, boost-format msgid "deinstallation of %1%" -msgstr "" +msgstr "avinstallering av %1%" #. Translator: progress bar label #: zypp/target/RpmPostTransCollector.cc:200 msgid "Running post-transaction scripts" -msgstr "" +msgstr "Kjører ettertransaksjon skript" #. Translator: progress bar label; %1% is a script identifier like '%posttrans(mypackage-2-0.noarch)' #: zypp/target/RpmPostTransCollector.cc:202 #, boost-format msgid "Running %1% script" -msgstr "" +msgstr "Kjører %1% skript" #. Translator: headline; %1% is a script identifier like '%posttrans(mypackage-2-0.noarch)' #: zypp/target/RpmPostTransCollector.cc:204 #, boost-format msgid "%1% script output:" -msgstr "" +msgstr "%1% skript utdata:" #: zypp/target/TargetException.cc:27 msgid "Installation has been aborted as directed." @@ -4816,10 +4887,12 @@ msgid "" "Received signal :\"%1% (%2%)\", to ensure the consistency of the system it " "is not possible to cancel a running rpm transaction." msgstr "" +"Mottok signal :\"%1% (%2%)\", for å sikre konsistensen til systemet er det " +"ikke mulig å avbryte kjørende rpm-transaksjon." #: zypp/target/TargetImpl.cc:2720 msgid "Executing the transaction failed because of the following problems:" -msgstr "" +msgstr "Utføringen av transaksjonen mislyktes på grunn av følgende problemer:" #. TranslatorExplanation after semicolon is error message #. TranslatorExplanation the colon is followed by an error message @@ -4842,11 +4915,11 @@ msgstr "Kunne ikke fjerne offentlig nøkkel %1%" #: zypp/target/rpm/RpmDb.cc:1250 msgid "Package header is not signed!" -msgstr "" +msgstr "Pakkeoverskrift er ikke signert!" #: zypp/target/rpm/RpmDb.cc:1252 msgid "Package payload is not signed!" -msgstr "" +msgstr "Pakkeinnhold er ikke signert!" #. Translator: %s = name of an rpm package. A list of diffs follows #. this message. @@ -4902,36 +4975,33 @@ msgstr "opprettet sikkerhetskopi %s" #. translators: possible rpm package signature check result [brief] #: zypp/target/rpm/RpmDb.cc:2221 -#, fuzzy msgid "Signature is OK" -msgstr "Signaturfilen %s ikke funnet" +msgstr "Signaturen er OK" #. translators: possible rpm package signature check result [brief] #: zypp/target/rpm/RpmDb.cc:2223 msgid "Unknown type of signature" -msgstr "" +msgstr "Ukjent signatur type" #. translators: possible rpm package signature check result [brief] #: zypp/target/rpm/RpmDb.cc:2225 -#, fuzzy msgid "Signature does not verify" -msgstr "Signaturfilen %s ikke funnet" +msgstr "Signaturen verifiserer ikke" #. translators: possible rpm package signature check result [brief] #: zypp/target/rpm/RpmDb.cc:2227 -#, fuzzy msgid "Signature is OK, but key is not trusted" -msgstr "Signaturfilen %s ikke funnet" +msgstr "Signaturen er OK, men nøkkelen er ikke til å stole på" #. translators: possible rpm package signature check result [brief] #: zypp/target/rpm/RpmDb.cc:2229 msgid "Signatures public key is not available" -msgstr "" +msgstr "Signaturens offentlige nøkkel er ikke tilgjengelig" #. translators: possible rpm package signature check result [brief] #: zypp/target/rpm/RpmDb.cc:2231 msgid "File does not exist or signature can't be checked" -msgstr "" +msgstr "Filen eksisterer ikke eller signaturen kan ikke bli sjekket" #. translators: possible rpm package signature check result [brief] #: zypp/target/rpm/RpmDb.cc:2233 @@ -5078,11 +5148,11 @@ msgstr "Kommandoen ble avsluttet med en ukjent feil." #: zypp-core/zyppng/io/forkspawnengine.cc:243 #: zypp-core/zyppng/io/forkspawnengine.cc:486 msgid "Invalid spawn arguments given." -msgstr "" +msgstr "Ugyldige spawn-argumenter gitt." #: zypp-core/zyppng/io/forkspawnengine.cc:299 msgid "Unable to create control pipe." -msgstr "" +msgstr "Kan ikke opprette kontrollrør." #: zypp-core/zyppng/io/forkspawnengine.cc:366 #, c-format, boost-format @@ -5114,22 +5184,22 @@ msgstr "Kan ikke splitte (%s)." #: zypp-core/zyppng/io/forkspawnengine.cc:432 #, c-format, boost-format msgid "Can't exec '%s', chdir failed (%s)." -msgstr "" +msgstr "Kan ikke utføre '%s', chdir mislykket (%s)." #: zypp-core/zyppng/io/forkspawnengine.cc:435 #, c-format, boost-format msgid "Can't exec '%s', chroot failed (%s)." -msgstr "" +msgstr "Kan ikke utføre '%s', chroot mislykket (%s)." #: zypp-core/zyppng/io/forkspawnengine.cc:438 #, c-format, boost-format msgid "Can't exec '%s', exec failed (%s)." -msgstr "" +msgstr "Kan ikke utføre '%s', utførelsen mislyktes (%s)." #: zypp-core/zyppng/io/forkspawnengine.cc:442 #, c-format, boost-format msgid "Can't exec '%s', unexpected error." -msgstr "" +msgstr "Kan ikke utføre '%s', uventet feil." #: zypp-media/mediaexception.cc:33 #, c-format, boost-format @@ -5266,7 +5336,7 @@ msgstr "Tidsavbrudd under tilgang '%s'." #: zypp-media/mediaexception.cc:197 #, c-format, boost-format msgid "Downloaded data exceeded the expected filesize '%s' of '%s'." -msgstr "" +msgstr "Nedlastede data overskred den forventede filstørrelsen '%s' av '%s'." #: zypp-media/mediaexception.cc:205 #: zypp-curl/ng/network/networkrequesterror.cc:115 @@ -5281,7 +5351,7 @@ msgstr " SSL-sertifikatproblem, bekreft at CA-sertifikat er OK for '%s'." #: zypp-media/mediaexception.cc:220 msgid "No free ressources available to attach medium." -msgstr "" +msgstr "Ingen tilgjengelige ressurser for å legge ved medium." #: zypp-curl/auth/curlauthdata.cc:97 #, c-format, boost-format @@ -5294,6 +5364,8 @@ msgid "" "Download (curl) error for '%s':\n" "Error code: %s\n" msgstr "" +"Last ned (curl) feil for '%s':\n" +"Feil kode: %s\n" #: zypp-curl/ng/network/networkrequesterror.cc:146 #, c-format, boost-format @@ -5301,6 +5373,8 @@ msgid "" "Download (curl) error for '%s':\n" "Unable to retrieve HTTP response\n" msgstr "" +"Last ned (curl) feil for '%s':\n" +"Kunne ikke hente HTTP-svar\n" #: zypp-tui/Table.cc:32 msgid "Yes" @@ -5313,19 +5387,17 @@ msgstr "Nei" #. translator: usually followed by a ' ' and some explanatory text #: zypp-tui/output/Out.cc:26 msgid "Note:" -msgstr "" +msgstr "Notat:" #. translator: usually followed by a ' ' and some explanatory text #: zypp-tui/output/Out.cc:28 -#, fuzzy msgid "Warning:" -msgstr "Advarsel: " +msgstr "Advarsel:" #. translator: usually followed by a ' ' and some explanatory text #: zypp-tui/output/Out.cc:30 -#, fuzzy msgid "Error:" -msgstr "Feil" +msgstr "Feil:" #. translator: Shown as result tag in a progress bar: ............[done] #. Translator: download progress bar result: ".............[done]" @@ -5337,7 +5409,7 @@ msgstr "fullført" #. translator: Shown as result tag in a progress bar: .......[attention] #: zypp-tui/output/Out.cc:143 msgid "attention" -msgstr "" +msgstr "oppmerksomhet" #. translator: Shown as result tag in a progress bar: ...........[error] #. Translator: download progress bar result: "............[error]" @@ -5362,9 +5434,8 @@ msgstr "starter" #. Translator: download progress bar result: "........[not found]" #: zypp-tui/output/OutNormal.cc:335 zypp-tui/output/OutNormal.cc:344 -#, fuzzy msgid "not found" -msgstr "Ikke funnet" +msgstr "ikke funnet" #: zypp-tui/output/OutNormal.cc:421 msgid "No help available for this prompt." @@ -5377,7 +5448,7 @@ msgstr "ingen tilgjengelig hjelp for dette valget" #. translators: Press '?' to see all options embedded in this prompt: "Continue? [y/n/? shows all options] (y):" #: zypp-tui/output/promptoptions.cc:85 msgid "shows all options" -msgstr "" +msgstr "Vis alle alternativer" #: zypp-tui/output/promptoptions.cc:194 msgid "yes" diff --git a/po/pt_BR.po b/po/pt_BR.po index e5034e17df..369e6d5a57 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -14,7 +14,7 @@ msgstr "" "Project-Id-Version: zypp\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-11-11 12:40+0100\n" -"PO-Revision-Date: 2024-09-09 18:47+0000\n" +"PO-Revision-Date: 2024-11-14 15:48+0000\n" "Last-Translator: Rodrigo Macedo \n" "Language-Team: Portuguese (Brazil) \n" @@ -23,7 +23,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 5.7.2\n" +"X-Generator: Weblate 5.8.3\n" "X-Poedit-Language: Portuguese\n" "X-Poedit-Country: BRAZIL\n" "X-Poedit-SourceCharset: utf-8\n" @@ -3899,7 +3899,7 @@ msgstr "Não foi possível criar %s" #: zypp/ng/repo/workflows/repomanagerwf.cc:491 msgid "Failed to retrieve new repository metadata." -msgstr "" +msgstr "Falha ao recuperar novos metadados do repositório." #: zypp/ng/repo/workflows/repomanagerwf.cc:578 msgid "Failed to cache repo ( unable to start repo2solv )." @@ -4189,7 +4189,7 @@ msgstr "Falha no applydeltarpm." #: zypp/repo/RepoException.cc:73 msgid "No permision to write repository cache." -msgstr "" +msgstr "Nenhuma permissão para gravar no cache do repositório." #: zypp/repo/RepoException.cc:130 msgid "Service plugin does not support changing an attribute." diff --git a/tests/media/CredentialManager_test.cc b/tests/media/CredentialManager_test.cc index 094c79d0b3..8d381b7499 100644 --- a/tests/media/CredentialManager_test.cc +++ b/tests/media/CredentialManager_test.cc @@ -4,14 +4,16 @@ #include #include #include -#include +#include #include +#include using std::cout; using std::endl; using namespace zypp; using namespace zypp::media; +using zyppng::media::CredentialManager; inline void testGetCreds( CredentialManager & cm_r, const std::string & url_r, const std::string & user_r = "", @@ -34,19 +36,22 @@ inline void testGetCreds( CredentialManager & cm_r, const std::string & url_r, BOOST_AUTO_TEST_CASE(read_cred_for_url) { - CredManagerOptions opts; + auto ctx = zyppng::SyncContext::create(); + ctx->initialize().unwrap (); + + CredManagerSettings opts(ctx); opts.globalCredFilePath = TESTS_SRC_DIR "/media/data/credentials.cat"; opts.userCredFilePath = Pathname(); - CredentialManager cm( opts ); + auto cm = CredentialManager::create( opts ); - BOOST_CHECK_EQUAL( cm.credsGlobalSize(), 3 ); + BOOST_CHECK_EQUAL( cm->credsGlobalSize(), 3 ); - testGetCreds( cm, "https://drink.it/repo/roots", "ginger", "ale" ); - testGetCreds( cm, "ftp://weprovidesoft.fr/download/opensuse/110", "agda", "ichard" ); - testGetCreds( cm, "ftp://magda@weprovidesoft.fr/download/opensuse/110", "magda", "richard" ); - testGetCreds( cm, "ftp://agda@weprovidesoft.fr/download/opensuse/110", "agda", "ichard" ); - testGetCreds( cm, "ftp://unknown@weprovidesoft.fr/download/opensuse/110" ); // NULL - testGetCreds( cm, "http://url.ok/but/not/creds" ); // NULL + testGetCreds( *cm, "https://drink.it/repo/roots", "ginger", "ale" ); + testGetCreds( *cm, "ftp://weprovidesoft.fr/download/opensuse/110", "agda", "ichard" ); + testGetCreds( *cm, "ftp://magda@weprovidesoft.fr/download/opensuse/110", "magda", "richard" ); + testGetCreds( *cm, "ftp://agda@weprovidesoft.fr/download/opensuse/110", "agda", "ichard" ); + testGetCreds( *cm, "ftp://unknown@weprovidesoft.fr/download/opensuse/110" ); // NULL + testGetCreds( *cm, "http://url.ok/but/not/creds" ); // NULL } struct CredCollector @@ -64,10 +69,15 @@ struct CredCollector BOOST_AUTO_TEST_CASE(save_creds) { + auto ctx = zyppng::SyncContext::create(); + ctx->initialize().unwrap (); + + CredManagerSettings opts(ctx); + filesystem::TmpDir tmp; - CredManagerOptions opts; opts.globalCredFilePath = tmp / "fooha"; - CredentialManager cm1(opts); + + auto cm1 = CredentialManager::create(opts); AuthData cr1("benson","absolute"); cr1.setUrl(Url("http://joooha.com")); @@ -76,20 +86,20 @@ BOOST_AUTO_TEST_CASE(save_creds) cr2.setUrl(Url("ftp://filesuck.org")); // should create a new file - cm1.saveInGlobal(cr1); + cm1->saveInGlobal(cr1); CredCollector collector; CredentialFileReader( opts.globalCredFilePath, bind( &CredCollector::collect, &collector, _1 ) ); BOOST_CHECK_EQUAL( collector.creds.size(), 1 ); collector.creds.clear(); - cm1.saveInGlobal(cr2); + cm1->saveInGlobal(cr2); CredentialFileReader( opts.globalCredFilePath, bind( &CredCollector::collect, &collector, _1 ) ); BOOST_CHECK_EQUAL(collector.creds.size(), 2 ); collector.creds.clear(); // save the same creds again - cm1.saveInGlobal(cr2); + cm1->saveInGlobal(cr2); CredentialFileReader( opts.globalCredFilePath, bind( &CredCollector::collect, &collector, _1 ) ); BOOST_CHECK_EQUAL(collector.creds.size(), 2 ); @@ -98,16 +108,21 @@ BOOST_AUTO_TEST_CASE(save_creds) BOOST_AUTO_TEST_CASE(service_base_url) { + auto ctx = zyppng::SyncContext::create(); + ctx->initialize().unwrap (); + + CredManagerSettings opts(ctx); + filesystem::TmpDir tmp; - CredManagerOptions opts; opts.globalCredFilePath = tmp / "fooha"; - CredentialManager cm( opts ); + + auto cm = CredentialManager::create( opts ); AuthData cred( "benson","absolute" ); cred.setUrl( Url( "http://joooha.com/service/path" ) ); - cm.addGlobalCred( cred ); + cm->addGlobalCred( cred ); - testGetCreds( cm, "http://joooha.com/service/path/repo/repofoo", "benson", "absolute" ); - testGetCreds( cm, "http://benson@joooha.com/service/path/repo/repofoo", "benson", "absolute" ); - testGetCreds( cm, "http://nobody@joooha.com/service/path/repo/repofoo" ); // NULL + testGetCreds( *cm, "http://joooha.com/service/path/repo/repofoo", "benson", "absolute" ); + testGetCreds( *cm, "http://benson@joooha.com/service/path/repo/repofoo", "benson", "absolute" ); + testGetCreds( *cm, "http://nobody@joooha.com/service/path/repo/repofoo" ); // NULL } diff --git a/tests/parser/RepoFileReader_test.cc b/tests/parser/RepoFileReader_test.cc index 6b861d0c8e..bcb33c779e 100644 --- a/tests/parser/RepoFileReader_test.cc +++ b/tests/parser/RepoFileReader_test.cc @@ -1,13 +1,14 @@ #include #include -#include +#include +#include +#include #include #include "TestSetup.h" using std::stringstream; using std::string; -using namespace zypp; static std::string suse_repo = "[factory-oss]\n" "name=factory-oss $releasever - $basearch\n" @@ -29,13 +30,13 @@ static std::string suse_repo = "[factory-oss]\n" struct RepoCollector : private base::NonCopyable { - bool collect( const RepoInfo &repo ) + bool collect( const zyppng::RepoInfo &repo ) { repos.push_back(repo); return true; } - RepoInfoList repos; + zyppng::RepoInfoList repos; }; // Must be the first test! @@ -44,10 +45,12 @@ BOOST_AUTO_TEST_CASE(read_repo_file) { std::stringstream input(suse_repo); RepoCollector collector; - parser::RepoFileReader parser( input, bind( &RepoCollector::collect, &collector, _1 ) ); + zyppng::SyncContextRef ctx = zyppng::SyncContext::create (); + ctx->initialize().unwrap(); + zyppng::parser::RepoFileReader parser( ctx, input, bind( &RepoCollector::collect, &collector, _1 ) ); BOOST_CHECK_EQUAL(1, collector.repos.size()); - const RepoInfo & repo( collector.repos.front() ); + const zyppng::RepoInfo & repo( collector.repos.front() ); BOOST_CHECK_EQUAL( 5, repo.baseUrlsSize() ); BOOST_CHECK_EQUAL( 5, repo.gpgKeyUrlsSize() ); diff --git a/tests/parser/RepoindexFileReader_test.cc b/tests/parser/RepoindexFileReader_test.cc index 25b68ff002..5e61220b9d 100644 --- a/tests/parser/RepoindexFileReader_test.cc +++ b/tests/parser/RepoindexFileReader_test.cc @@ -1,9 +1,12 @@ #include #include #include -#include #include +#include +#include +#include + #include "TestSetup.h" using std::stringstream; @@ -21,13 +24,13 @@ static string service = "" struct RepoCollector : private base::NonCopyable { - bool collect( const RepoInfo &repo ) + bool collect( const zyppng::RepoInfo &repo ) { repos.push_back(repo); return true; } - RepoInfoList repos; + zyppng::RepoInfoList repos; }; // Must be the first test! @@ -36,11 +39,14 @@ BOOST_AUTO_TEST_CASE(read_index_file) { stringstream input(service); RepoCollector collector; - parser::RepoindexFileReader parser( input, bind( &RepoCollector::collect, &collector, _1 ) ); + + auto ctx = zyppng::SyncContext::create(); + ctx->initialize().unwrap(); + + zyppng::parser::RepoIndexFileReader parser( ctx, input, bind( &RepoCollector::collect, &collector, _1 ) ); BOOST_REQUIRE_EQUAL(3, collector.repos.size()); - RepoInfo repo; - repo = collector.repos.front(); + zyppng::RepoInfo repo = collector.repos.front(); BOOST_CHECK_EQUAL("Company's Foo", repo.name()); BOOST_CHECK_EQUAL("company-foo", repo.alias()); diff --git a/tests/repo/MirrorList_test.cc b/tests/repo/MirrorList_test.cc index 89f8494aec..514192ce04 100644 --- a/tests/repo/MirrorList_test.cc +++ b/tests/repo/MirrorList_test.cc @@ -1,10 +1,10 @@ -#include #include #include #include "WebServer.h" #include +#include using namespace zypp; using namespace zypp::repo; @@ -20,8 +20,11 @@ BOOST_AUTO_TEST_CASE(get_mirrorlist) weburl1.setPathName("/metalink.xml"); weburl2.setPathName("/mirrors.txt"); - RepoMirrorList rml1 (weburl1); - RepoMirrorList rml2 (weburl2); + auto ctx = zyppng::SyncContext::create(); + ctx->initialize ().unwrap (); + + RepoMirrorList rml1 ( ctx, weburl1 ); + RepoMirrorList rml2 ( ctx, weburl2 ); BOOST_CHECK(rml1.getUrls().begin()->asString() == "http://ftp-stud.hs-esslingen.de/pub/fedora/linux/updates/13/x86_64/"); BOOST_CHECK(rml2.getUrls().begin()->asString() == "http://ftp-stud.hs-esslingen.de/pub/fedora/linux/updates/13/x86_64/"); diff --git a/tests/repo/PluginServices_test.cc b/tests/repo/PluginServices_test.cc index 8fdd0c4b94..59824a540c 100644 --- a/tests/repo/PluginServices_test.cc +++ b/tests/repo/PluginServices_test.cc @@ -1,8 +1,4 @@ -#include #include -#include -#include -#include #include #include @@ -10,15 +6,17 @@ #include #include #include -#include -#include + +#include +#include +#include using std::cout; using std::endl; using std::string; -using namespace zypp; +using namespace zyppng; using namespace boost::unit_test; -using namespace zypp::repo; +using namespace zyppng::repo; #define DATADIR (Pathname(TESTS_SRC_DIR) + "/repo/yum/data") @@ -46,7 +44,9 @@ BOOST_AUTO_TEST_CASE(plugin_services) { ServiceCollector::ServiceSet services; - PluginServices local("/space/tmp/services", ServiceCollector(services)); + auto ctx = SyncContext::create(); + ctx->initialize().unwrap(); + PluginServices local(ctx, "/space/tmp/services", ServiceCollector(services)); } // vim: set ts=2 sts=2 sw=2 ai et: diff --git a/tests/repo/susetags/Downloader_test.cc b/tests/repo/susetags/Downloader_test.cc index c67ea235ed..4c60b5affb 100644 --- a/tests/repo/susetags/Downloader_test.cc +++ b/tests/repo/susetags/Downloader_test.cc @@ -7,9 +7,9 @@ #include #include +#include #include #include -#include #include #include "tests/zypp/KeyRingTestReceiver.h" @@ -31,17 +31,19 @@ BOOST_AUTO_TEST_CASE(susetags_download) KeyRingTestReceiver keyring_callbacks; keyring_callbacks.answerAcceptKey(KeyRingReport::KEY_TRUST_TEMPORARILY); + + auto ctx = zyppng::SyncContext::create (); + Pathname p = DATADIR + "/stable-x86-subset"; - RepoInfo repoinfo; + zyppng::RepoInfo repoinfo(ctx); repoinfo.setAlias("testrepo"); repoinfo.setPath("/"); filesystem::TmpDir tmp; Pathname localdir(tmp.path()); - - auto ctx = zyppng::SyncContext::create (); - auto res = ctx->provider()->attachMedia( p.asDirUrl() , zyppng::ProvideMediaSpec() ) + auto res = ctx->initialize () + | and_then( [&]() { return ctx->provider()->attachMedia( p.asDirUrl() , zyppng::ProvideMediaSpec(ctx) ); } ) | and_then( [&]( zyppng::SyncMediaHandle h ){ auto dlctx = std::make_shared( ctx, repoinfo, localdir ); return zyppng::SuseTagsWorkflows::download(dlctx, h); @@ -90,6 +92,12 @@ BOOST_AUTO_TEST_CASE(susetags_download) return zyppng::expected::success(); }); + try { + res.unwrap (); + } catch ( const zypp::Exception & e ) { + std::cout << e << std::endl; + } + BOOST_REQUIRE ( res.is_valid () ); } @@ -99,17 +107,18 @@ BOOST_AUTO_TEST_CASE(susetags_gz_download) KeyRingTestReceiver keyring_callbacks; keyring_callbacks.answerAcceptKey(KeyRingReport::KEY_TRUST_TEMPORARILY); + auto ctx = zyppng::SyncContext::create (); + Pathname p = DATADIR + "/stable-x86-subset-gz"; - RepoInfo repoinfo; + zyppng::RepoInfo repoinfo(ctx); repoinfo.setAlias("testrepo"); repoinfo.setPath("/"); filesystem::TmpDir tmp; Pathname localdir(tmp.path()); - - auto ctx = zyppng::SyncContext::create (); - auto res = ctx->provider()->attachMedia( p.asDirUrl() , zyppng::ProvideMediaSpec() ) + auto res = ctx->initialize () + | and_then( [&]() { return ctx->provider()->attachMedia( p.asDirUrl() , zyppng::ProvideMediaSpec(ctx) ); } ) | and_then( [&]( zyppng::SyncMediaHandle h ){ auto dlctx = std::make_shared( ctx, repoinfo, localdir ); return zyppng::SuseTagsWorkflows::download(dlctx, h); @@ -159,6 +168,12 @@ BOOST_AUTO_TEST_CASE(susetags_gz_download) }); + try { + res.unwrap (); + } catch ( const zypp::Exception & e ) { + std::cout << e << std::endl; + } + BOOST_REQUIRE ( res.is_valid () ); } diff --git a/tests/repo/yum/YUMDownloader_test.cc b/tests/repo/yum/YUMDownloader_test.cc index b02f478c91..ac12b79c98 100644 --- a/tests/repo/yum/YUMDownloader_test.cc +++ b/tests/repo/yum/YUMDownloader_test.cc @@ -7,9 +7,9 @@ #include #include +#include #include #include -#include #include #include "tests/zypp/KeyRingTestReceiver.h" @@ -28,17 +28,19 @@ BOOST_AUTO_TEST_CASE(yum_download) KeyRingTestReceiver keyring_callbacks; keyring_callbacks.answerAcceptKey(KeyRingReport::KEY_TRUST_TEMPORARILY); + auto ctx = zyppng::SyncContext::create (); + Pathname p = DATADIR + "/ZCHUNK"; Url url(p.asDirUrl()); - RepoInfo repoinfo; + zyppng::RepoInfo repoinfo(ctx); repoinfo.setAlias("testrepo"); repoinfo.setPath("/"); filesystem::TmpDir tmp; Pathname localdir(tmp.path()); - auto ctx = zyppng::SyncContext::create (); - auto res = ctx->provider()->attachMedia( p.asDirUrl() , zyppng::ProvideMediaSpec() ) + auto res = ctx->initialize () + | and_then( [&]() { return ctx->provider()->attachMedia( p.asDirUrl() , zyppng::ProvideMediaSpec(ctx) ); } ) | and_then( [&]( zyppng::SyncMediaHandle h ){ auto dlctx = std::make_shared( ctx, repoinfo, localdir ); return zyppng::RpmmdWorkflows::download(dlctx, h); diff --git a/tests/zypp/KeyRing_test.cc b/tests/zypp/KeyRing_test.cc index a0e141cd23..d356da1106 100644 --- a/tests/zypp/KeyRing_test.cc +++ b/tests/zypp/KeyRing_test.cc @@ -4,18 +4,19 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include "KeyRingTestReceiver.h" -#include using boost::unit_test::test_suite; using boost::unit_test::test_case; @@ -31,7 +32,7 @@ bool verifyFileSignatureWorkflow( KeyRing_Ptr ring, const Pathname &file, const keyring::VerifyFileContext context( file, signature ); context.shortFile( filedesc ); context.keyContext( keycontext ); - const auto &res = zyppng::KeyRingWorkflow::verifyFileSignature( zyppng::SyncContext::create(), ring, std::move(context) ); + const auto &res = zyppng::KeyRingWorkflow::verifyFileSignature( zypp::zypp_detail::GlobalStateHelper::context(), ring, std::move(context) ); sigValid_r = res.second.fileValidated(); return res.second.fileAccepted(); } @@ -41,7 +42,7 @@ bool verifyFileSignatureWorkflow( KeyRing_Ptr ring, const Pathname &file, const keyring::VerifyFileContext context( file, signature ); context.shortFile( filedesc ); context.keyContext( keycontext ); - const auto &res = zyppng::KeyRingWorkflow::verifyFileSignature( zyppng::SyncContext::create(), ring, std::move(context) ); + const auto &res = zyppng::KeyRingWorkflow::verifyFileSignature( zypp::zypp_detail::GlobalStateHelper::context(), ring, std::move(context) ); return res.second.fileAccepted(); } diff --git a/tests/zypp/RepoManager_test.cc b/tests/zypp/RepoManager_test.cc index 32343b75a7..15101f2bb2 100644 --- a/tests/zypp/RepoManager_test.cc +++ b/tests/zypp/RepoManager_test.cc @@ -1,4 +1,3 @@ - #include #include #include diff --git a/tests/zyppng/CMakeLists.txt b/tests/zyppng/CMakeLists.txt index 8bb0e473e6..0fdbe04dfb 100644 --- a/tests/zyppng/CMakeLists.txt +++ b/tests/zyppng/CMakeLists.txt @@ -1,6 +1,7 @@ ADD_TESTS( EventLoop IOBuffer + ResourceLocks UnixSignalSource Pipelines ) @@ -8,3 +9,7 @@ ADD_TESTS( ADD_SUBDIRECTORY( media ) ADD_SUBDIRECTORY( io ) ADD_SUBDIRECTORY( rpc ) + +#add_executable( apitest NgAPI_test.cc ) +#target_include_directories( apitest PUBLIC ${LIBZYPP_SOURCE_DIR} ${LIBZYPP_BINARY_DIR} ${LIBGLIB_INCLUDE_DIRS} ) +#target_link_libraries( apitest zypp-glib ) diff --git a/tests/zyppng/NgAPI_test.cc b/tests/zyppng/NgAPI_test.cc new file mode 100644 index 0000000000..4ae2da850f --- /dev/null +++ b/tests/zyppng/NgAPI_test.cc @@ -0,0 +1,47 @@ + +#include +#include +#include +#include + +int main ( int argc, char *argv[] ) +{ + zypp::glib::ZyppContextRef context = zypp::glib::zypp_context_create ( nullptr ); + if ( !context ) { + std::cerr << "Could not create context, goodbye" << std::endl; + return 1; + } + + GError *err = nullptr; + if ( !zypp_context_load_system ( context.get(), "/", &err ) ) { + if ( err ) { + std::cerr << "Loading the context failed: " << err->message << std::endl; + return 1; + } else { + std::cerr << "Loading the context failed: unknown error!" << std::endl; + return 1; + } + } + + zypp::glib::ZyppRepoManagerRef rMgr( zypp_repo_manager_new( context.get() ), zypp::glib::adopt_object ); + if ( !zypp_repo_manager_initialize( rMgr.get(), &err ) ) { + if ( err ) { + std::cerr << "Loading the context failed: " << err->message << std::endl; + return 1; + } else { + std::cerr << "Loading the context failed: unknown error!" << std::endl; + return 1; + } + } + + zypp::glib::GListView knownRepos( zypp_repo_manager_get_known_repos(rMgr.get()), zypp::glib::Ownership::Full ); + std::cout << "We know: " << knownRepos.size () << " repositories:" << std::endl; + + for ( int i = 0; i < knownRepos.size (); i++ ) { + auto repo = *knownRepos[i]; + std::cout << "Repo : " << zypp_info_base_name( ZYPP_INFO_BASE( repo ) ) << std::endl; + } + + return 0; + +} diff --git a/tests/zyppng/Pipelines_test.cc b/tests/zyppng/Pipelines_test.cc index 3ff716435f..b68986022e 100644 --- a/tests/zyppng/Pipelines_test.cc +++ b/tests/zyppng/Pipelines_test.cc @@ -153,9 +153,9 @@ BOOST_AUTO_TEST_CASE( asyncToMixedPipelineWithIndirectAsyncCB ) auto op = zyppng::AsyncOpRef(std::make_shared>("5")) | &toSignedInt - | []( auto &&in ){ in.value += 5; return std::make_shared>(std::move(in)); } + | []( auto in ){ in.value += 5; return std::make_shared>(std::move(in)); } | &toString - | [&]( auto && res ){ + | [&]( auto res ){ BOOST_CHECK_EQUAL ( std::string("10") , res ); ev->quit (); return res; @@ -172,13 +172,13 @@ BOOST_AUTO_TEST_CASE( asyncToMixedPipelineWithIndirectAsyncCBInStdFunction ) const auto &makePipeline = [&](){ - const std::function< AsyncOpRef( Int && ) > &addFiveAsync = []( auto &&in ){ in.value += 5; return std::make_shared>(std::move(in)); }; + const std::function< AsyncOpRef( Int && ) > &addFiveAsync = []( auto in ){ in.value += 5; return std::make_shared>(std::move(in)); }; return zyppng::AsyncOpRef(std::make_shared>("5")) | &toSignedInt | addFiveAsync | &toString - | [&]( auto && res ){ + | [&]( auto res ){ BOOST_CHECK_EQUAL ( std::string("10") , res ); ev->quit (); return res; diff --git a/tests/zyppng/ResourceLocks_test.cc b/tests/zyppng/ResourceLocks_test.cc new file mode 100644 index 0000000000..86e78d8064 --- /dev/null +++ b/tests/zyppng/ResourceLocks_test.cc @@ -0,0 +1,133 @@ +#include +#include +#include + +#include +#include +#include + +#include + + +BOOST_AUTO_TEST_CASE(simplelock) +{ + auto ctx = zyppng::SyncContext::create(); + auto lExp = ctx->lockResource ( "test" ); // shared lock + BOOST_REQUIRE( lExp.is_valid () ); + + // store in a optional so we can release the lock + auto l = std::make_optional( std::move(lExp.get()) ); + BOOST_REQUIRE_EQUAL( l->lockIdent(), std::string("test") ); + + { + // now lock again, try exclusive + auto lExcl = ctx->lockResource ( "test", zyppng::ResourceLockRef::Exclusive ); + BOOST_REQUIRE( !lExcl.is_valid () ); + BOOST_REQUIRE_THROW ( lExcl.unwrap(), zyppng::ResourceAlreadyLockedException ); + } + + // clear the lock + l.reset(); + + { + // now lock again, try exclusive + auto lExcl = ctx->lockResource ( "test", zyppng::ResourceLockRef::Exclusive ); + BOOST_REQUIRE_NO_THROW ( lExcl.unwrap() ); + BOOST_REQUIRE_EQUAL( lExcl->lockIdent(), std::string("test") ); + } + +} + +BOOST_AUTO_TEST_CASE(two_simple_locks) +{ + auto ctx = zyppng::SyncContext::create(); + auto lExp = ctx->lockResource ( "test1", zyppng::ResourceLockRef::Exclusive ); + BOOST_REQUIRE( lExp.is_valid () ); + BOOST_REQUIRE_EQUAL( lExp->lockIdent(), std::string("test1") ); + + auto lExp2 = ctx->lockResource ( "test2", zyppng::ResourceLockRef::Exclusive ); + BOOST_REQUIRE( lExp.is_valid () ); + BOOST_REQUIRE_EQUAL( lExp2->lockIdent(), std::string("test2") ); +} + + + +BOOST_AUTO_TEST_CASE(asyncLock) +{ + using namespace zyppng::operators; + + auto el = zyppng::EventLoop::create(); + auto ctx = zyppng::AsyncContext::create(); + + std::optional l; + + { + auto expLock = ctx->lockResource ("test", zyppng::ResourceLockRef::Exclusive ); + BOOST_REQUIRE( expLock.is_valid () ); + l.emplace ( std::move(expLock.get()) ); + } + + std::vector sharedLocks; + + const auto &sharedLockCb = [&]( zyppng::expected l ) { + + BOOST_REQUIRE( l.is_valid () ); + if ( !l ) { + el->quit(); + return zyppng::expected::error( l.error() ); + } + + BOOST_REQUIRE_EQUAL( l->lockIdent (), "test" ); + + sharedLocks.emplace_back( std::move(l.get()) ); + if ( sharedLocks.size() == 2 ) + sharedLocks.clear(); // kill all locks, letting the last o ne move on + + return zyppng::expected::success(); + }; + + auto asyncLock1 = ctx->lockResourceWait ( "test", 10, zyppng::ResourceLockRef::Shared ) | sharedLockCb; + auto asyncLock2 = ctx->lockResourceWait ( "test", 10, zyppng::ResourceLockRef::Shared ) | sharedLockCb; + auto asyncLock3 = ctx->lockResourceWait ( "test", 20, zyppng::ResourceLockRef::Exclusive ); + + bool gotLock4 = false; + auto asyncLock4 = ctx->lockResourceWait ( "test", 30, zyppng::ResourceLockRef::Exclusive ) + | ( [&]( zyppng::expected l ) { + gotLock4 = true; // should not happen + return l; + }); + + BOOST_REQUIRE( !asyncLock1->isReady() ); + BOOST_REQUIRE( !asyncLock2->isReady() ); + BOOST_REQUIRE( !asyncLock3->isReady() ); + BOOST_REQUIRE( !asyncLock4->isReady() ); + + auto t = zyppng::Timer::create(); + t->connectFunc( &zyppng::Timer::sigExpired, [&]( auto &){ el->quit(); } ); + t->start( 40 ); + + // release the existing lock as soon as the ev is running + zyppng::EventDispatcher::invokeOnIdle([&](){ + l.reset(); + return false; + }); + + el->run(); + + BOOST_REQUIRE( asyncLock1->isReady() ); + BOOST_REQUIRE( asyncLock1->get().is_valid() ); + + BOOST_REQUIRE( asyncLock2->isReady() ); + BOOST_REQUIRE( asyncLock2->get().is_valid() ); + + // third lock should have worked out too after the first 2 were released + BOOST_REQUIRE( asyncLock3->isReady() ); + BOOST_REQUIRE( asyncLock3->get().is_valid() ); + + // fourh lock should fail with timeout + BOOST_REQUIRE( asyncLock4->isReady() ); + BOOST_REQUIRE( !asyncLock4->get().is_valid() ); + + BOOST_REQUIRE_THROW ( asyncLock4->get().unwrap(), zyppng::ResourceLockTimeoutException ); + +} diff --git a/tests/zyppng/media/Provider_test.cc b/tests/zyppng/media/Provider_test.cc index 696b760194..579b407c4d 100644 --- a/tests/zyppng/media/Provider_test.cc +++ b/tests/zyppng/media/Provider_test.cc @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include +#include #ifndef TESTS_BUILD_DIR #error "TESTS_BUILD_DIR not defined" @@ -57,6 +59,9 @@ BOOST_AUTO_TEST_CASE( http_prov ) zypp::filesystem::TmpDir provideRoot; + auto ctx = zyppng::AsyncContext::create (); + ctx->initialize().unwrap(); + auto prov = zyppng::Provide::create ( provideRoot ); prov->setWorkerPath ( workerPath ); prov->start(); @@ -66,7 +71,7 @@ BOOST_AUTO_TEST_CASE( http_prov ) auto fileUrl = web.url(); fileUrl.setPathName( "/media.1/media" ); - auto op = prov->provide( fileUrl, zyppng::ProvideFileSpec() ); + auto op = prov->provide( ctx, fileUrl, zyppng::ProvideFileSpec() ); std::exception_ptr err; std::optional resOpt; @@ -100,6 +105,9 @@ BOOST_AUTO_TEST_CASE( http_attach ) auto ev = zyppng::EventLoop::create (); + auto ctx = zyppng::AsyncContext::create (); + ctx->initialize().unwrap(); + const auto &workerPath = zypp::Pathname ( TESTS_BUILD_DIR ).dirname() / "tools" / "workers"; const auto &webRoot = zypp::Pathname (TESTS_SRC_DIR)/"/zyppng/data/downloader"; zypp::filesystem::TmpDir provideRoot; @@ -111,7 +119,7 @@ BOOST_AUTO_TEST_CASE( http_attach ) WebServer web( webRoot.c_str(), 10001, false ); BOOST_REQUIRE( web.start() ); - auto op = prov->attachMedia( web.url(), zyppng::ProvideMediaSpec( "OnlineMedia" ) + auto op = prov->attachMedia( web.url(), zyppng::ProvideMediaSpec( ctx, "OnlineMedia" ) .setMediaFile( webRoot / "media.1" / "media" ) .setMedianr(1) ); @@ -138,6 +146,9 @@ BOOST_AUTO_TEST_CASE( http_attach_prov ) zypp::filesystem::TmpDir provideRoot; + auto ctx = zyppng::AsyncContext::create (); + ctx->initialize().unwrap(); + auto prov = zyppng::Provide::create ( provideRoot ); prov->setWorkerPath ( workerPath ); prov->start(); @@ -147,7 +158,7 @@ BOOST_AUTO_TEST_CASE( http_attach_prov ) zyppng::Provide::MediaHandle media; - auto op = prov->attachMedia( web.url(), zyppng::ProvideMediaSpec( "OnlineMedia" ) + auto op = prov->attachMedia( web.url(), zyppng::ProvideMediaSpec( ctx, "OnlineMedia" ) .setMediaFile( webRoot / "media.1" / "media" ) .setMedianr(1) ) | and_then ( [&]( zyppng::Provide::MediaHandle &&res ){ @@ -187,6 +198,9 @@ BOOST_AUTO_TEST_CASE( http_attach_prov_404 ) zypp::filesystem::TmpDir provideRoot; + auto ctx = zyppng::AsyncContext::create (); + ctx->initialize().unwrap(); + auto prov = zyppng::Provide::create ( provideRoot ); prov->setWorkerPath ( workerPath ); prov->start(); @@ -196,7 +210,7 @@ BOOST_AUTO_TEST_CASE( http_attach_prov_404 ) zyppng::Provide::MediaHandle media; - auto op = prov->attachMedia( web.url(), zyppng::ProvideMediaSpec( "OnlineMedia" ) + auto op = prov->attachMedia( web.url(), zyppng::ProvideMediaSpec( ctx, "OnlineMedia" ) .setMediaFile( webRoot / "media.1" / "media" ) .setMedianr(1) ) | and_then ( [&]( zyppng::Provide::MediaHandle &&res ){ @@ -235,6 +249,9 @@ BOOST_AUTO_TEST_CASE( http_attach_prov_notafile ) zypp::filesystem::TmpDir provideRoot; + auto ctx = zyppng::AsyncContext::create (); + ctx->initialize().unwrap(); + auto prov = zyppng::Provide::create ( provideRoot ); prov->setWorkerPath ( workerPath ); prov->start(); @@ -245,7 +262,7 @@ BOOST_AUTO_TEST_CASE( http_attach_prov_notafile ) zyppng::Provide::MediaHandle media; std::exception_ptr err; - auto op = prov->attachMedia( web.url(), zyppng::ProvideMediaSpec( "OnlineMedia" ) + auto op = prov->attachMedia( web.url(), zyppng::ProvideMediaSpec( ctx, "OnlineMedia" ) .setMediaFile( webRoot / "media.1" / "media" ) .setMedianr(1) ) | and_then ( [&]( zyppng::Provide::MediaHandle &&res ){ @@ -307,6 +324,9 @@ BOOST_AUTO_TEST_CASE( http_prov_auth ) zypp::filesystem::TmpDir provideRoot; + auto ctx = zyppng::AsyncContext::create (); + ctx->initialize().unwrap(); + auto prov = zyppng::Provide::create ( provideRoot ); prov->setWorkerPath ( workerPath ); prov->start(); @@ -314,7 +334,8 @@ BOOST_AUTO_TEST_CASE( http_prov_auth ) //don't write or read creds from real settings dir zypp::filesystem::TmpDir globCredPath; zypp::filesystem::TmpDir userCredPath; - zypp::media::CredManagerOptions opts; + + zypp::media::CredManagerSettings opts; opts.globalCredFilePath = globCredPath.path() / "credentials.cat"; opts.userCredFilePath = userCredPath.path() / "credentials.cat"; prov->setCredManagerOptions( opts ); @@ -336,7 +357,7 @@ BOOST_AUTO_TEST_CASE( http_prov_auth ) auto fileUrl = web.url(); fileUrl.setPathName( "/handler/test.txt" ); - auto op = prov->provide( fileUrl, zyppng::ProvideFileSpec() ); + auto op = prov->provide( ctx, fileUrl, zyppng::ProvideFileSpec() ); std::exception_ptr err; std::optional resOpt; @@ -380,6 +401,9 @@ BOOST_AUTO_TEST_CASE( http_prov_auth_nouserresponse ) zypp::filesystem::TmpDir provideRoot; + auto ctx = zyppng::AsyncContext::create (); + ctx->initialize().unwrap(); + auto prov = zyppng::Provide::create ( provideRoot ); prov->setWorkerPath ( workerPath ); prov->start(); @@ -387,7 +411,7 @@ BOOST_AUTO_TEST_CASE( http_prov_auth_nouserresponse ) //don't write or read creds from real settings dir zypp::filesystem::TmpDir globCredPath; zypp::filesystem::TmpDir userCredPath; - zypp::media::CredManagerOptions opts; + zypp::media::CredManagerSettings opts; opts.globalCredFilePath = globCredPath.path() / "credentials.cat"; opts.userCredFilePath = userCredPath.path() / "credentials.cat"; prov->setCredManagerOptions( opts ); @@ -405,7 +429,7 @@ BOOST_AUTO_TEST_CASE( http_prov_auth_nouserresponse ) auto fileUrl = web.url(); fileUrl.setPathName( "/handler/test.txt" ); - auto op = prov->provide( fileUrl, zyppng::ProvideFileSpec() ); + auto op = prov->provide( ctx, fileUrl, zyppng::ProvideFileSpec() ); std::exception_ptr err; std::optional resOpt; @@ -443,6 +467,9 @@ BOOST_AUTO_TEST_CASE( http_prov_auth_wrongpw ) zypp::filesystem::TmpDir provideRoot; + auto ctx = zyppng::AsyncContext::create (); + ctx->initialize().unwrap(); + auto prov = zyppng::Provide::create ( provideRoot ); prov->setWorkerPath ( workerPath ); prov->start(); @@ -450,7 +477,7 @@ BOOST_AUTO_TEST_CASE( http_prov_auth_wrongpw ) //don't write or read creds from real settings dir zypp::filesystem::TmpDir globCredPath; zypp::filesystem::TmpDir userCredPath; - zypp::media::CredManagerOptions opts; + zypp::media::CredManagerSettings opts; opts.globalCredFilePath = globCredPath.path() / "credentials.cat"; opts.userCredFilePath = userCredPath.path() / "credentials.cat"; prov->setCredManagerOptions( opts ); @@ -478,7 +505,7 @@ BOOST_AUTO_TEST_CASE( http_prov_auth_wrongpw ) auto fileUrl = web.url(); fileUrl.setPathName( "/handler/test.txt" ); - auto op = prov->provide( fileUrl, zyppng::ProvideFileSpec() ); + auto op = prov->provide( ctx, fileUrl, zyppng::ProvideFileSpec() ); std::exception_ptr err; std::optional resOpt; @@ -518,13 +545,16 @@ BOOST_AUTO_TEST_CASE( http_attach_prov_auth ) zypp::filesystem::TmpDir provideRoot; + auto ctx = zyppng::AsyncContext::create (); + ctx->initialize().unwrap(); + auto prov = zyppng::Provide::create ( provideRoot ); prov->setWorkerPath ( workerPath ); //don't write or read creds from real settings dir zypp::filesystem::TmpDir globCredPath; zypp::filesystem::TmpDir userCredPath; - zypp::media::CredManagerOptions opts; + zypp::media::CredManagerSettings opts; opts.globalCredFilePath = globCredPath.path() / "credentials.cat"; opts.userCredFilePath = userCredPath.path() / "credentials.cat"; prov->setCredManagerOptions( opts ); @@ -550,7 +580,7 @@ BOOST_AUTO_TEST_CASE( http_attach_prov_auth ) auto baseUrl = web.url(); baseUrl.setPathName("/handler"); - auto op = prov->attachMedia( baseUrl, zyppng::ProvideMediaSpec( "OnlineMedia" ) + auto op = prov->attachMedia( baseUrl, zyppng::ProvideMediaSpec( ctx, "OnlineMedia" ) .setMediaFile( webRoot / "media.1" / "media" ) .setMedianr(1) ) | and_then ( [&]( zyppng::Provide::MediaHandle &&res ){ @@ -604,17 +634,17 @@ static void writeTVMConfig ( const zypp::Pathname &file, const zypp::test::TVMSe } } -static auto makeDVDProv ( zyppng::ProvideRef &prov, const zypp::filesystem::Pathname &devRoot, int mediaNr, const std::string &fName ) +static auto makeDVDProv ( zyppng::MediaContextRef ctx, zyppng::ProvideRef &prov, const zypp::filesystem::Pathname &devRoot, int mediaNr, const std::string &fName ) { using namespace zyppng::operators; - return prov->attachMedia( zypp::Url("tvm:/"), zyppng::ProvideMediaSpec("CD Test Set") + return prov->attachMedia( zypp::Url("tvm:/"), zyppng::ProvideMediaSpec( ctx, "CD Test Set") .setMediaFile( devRoot / (std::string("cd") + zypp::str::numstring(mediaNr)) / (std::string("media.") + zypp::str::numstring(mediaNr)) / "media" ) .setMedianr(mediaNr)) | [&prov, mediaNr, fName]( zyppng::expected &&res ){ if ( res ) { std::cout << "Attached " << mediaNr << " as: " << res->handle() << std::endl; - return prov->provide ( *res, fName , zyppng::ProvideFileSpec() ) | [ attachId = *res, &prov ]( auto &&res ) { + return prov->provide ( *res, fName , zyppng::ProvideFileSpec() ) | [ attachId = *res ]( auto &&res ) { if ( !res ) { try { std::rethrow_exception(res.error()); @@ -655,6 +685,9 @@ BOOST_AUTO_TEST_CASE( tvm_basic ) auto ev = zyppng::EventLoop::create (); + auto ctx = zyppng::AsyncContext::create (); + ctx->initialize().unwrap(); + const auto &workerPath = zypp::Pathname ( TESTS_BUILD_DIR ).dirname() / "tools" / "workers"; const auto &devRoot = zypp::Pathname ( TESTS_SRC_DIR ) / "zyppng" / "data" / "provide"; @@ -688,9 +721,9 @@ BOOST_AUTO_TEST_CASE( tvm_basic ) std::vector< zyppng::AsyncOpRef>> ops; - ops.push_back( makeDVDProv( prov, devRoot, 1, "/file1") ); - ops.push_back( makeDVDProv( prov, devRoot, 2, "/file2") ); - ops.push_back( makeDVDProv( prov, devRoot, 3, "/file3") ); + ops.push_back( makeDVDProv( ctx, prov, devRoot, 1, "/file1") ); + ops.push_back( makeDVDProv( ctx, prov, devRoot, 2, "/file2") ); + ops.push_back( makeDVDProv( ctx, prov, devRoot, 3, "/file3") ); auto r = std::move(ops) | zyppng::waitFor(); r->sigReady().connect([&](){ @@ -718,6 +751,9 @@ BOOST_AUTO_TEST_CASE( tvm_medchange ) zypp::filesystem::TmpDir provideRoot; + auto ctx = zyppng::AsyncContext::create (); + ctx->initialize().unwrap(); + auto prov = zyppng::Provide::create ( provideRoot ); prov->setWorkerPath ( workerPath ); @@ -760,8 +796,8 @@ BOOST_AUTO_TEST_CASE( tvm_medchange ) std::vector< zyppng::AsyncOpRef>> ops; - ops.push_back( makeDVDProv( prov, devRoot, 1, "/file1") ); - ops.push_back( makeDVDProv( prov, devRoot, 2, "/file2") ); + ops.push_back( makeDVDProv( ctx, prov, devRoot, 1, "/file1") ); + ops.push_back( makeDVDProv( ctx, prov, devRoot, 2, "/file2") ); auto r = std::move(ops) | zyppng::waitFor(); r->sigReady().connect([&](){ @@ -794,8 +830,10 @@ BOOST_DATA_TEST_CASE( tvm_medchange_abort, bdata::make( cancelOps ), cancelOp ) const auto &workerPath = zypp::Pathname ( TESTS_BUILD_DIR ).dirname() / "tools" / "workers"; const auto &devRoot = zypp::Pathname ( TESTS_SRC_DIR ) / "zyppng" / "data" / "provide"; - zypp::filesystem::TmpDir provideRoot; + auto ctx = zyppng::AsyncContext::create (); + ctx->initialize().unwrap(); + zypp::filesystem::TmpDir provideRoot; auto prov = zyppng::Provide::create ( provideRoot ); prov->setWorkerPath ( workerPath ); @@ -834,8 +872,8 @@ BOOST_DATA_TEST_CASE( tvm_medchange_abort, bdata::make( cancelOps ), cancelOp ) return cancelOp; }); - auto op1 = makeDVDProv( prov, devRoot, 1, "/file1"); - auto op2 = makeDVDProv( prov, devRoot, 2, "/file2"); + auto op1 = makeDVDProv( ctx, prov, devRoot, 1, "/file1"); + auto op2 = makeDVDProv( ctx, prov, devRoot, 2, "/file2"); const auto &readyCB = [&](){ if ( op1->isReady() && op2->isReady() ) @@ -875,8 +913,10 @@ BOOST_AUTO_TEST_CASE( tvm_jammed ) const auto &workerPath = zypp::Pathname ( TESTS_BUILD_DIR ).dirname() / "tools" / "workers"; const auto &devRoot = zypp::Pathname ( TESTS_SRC_DIR ) / "zyppng" / "data" / "provide"; - zypp::filesystem::TmpDir provideRoot; + auto ctx = zyppng::AsyncContext::create (); + ctx->initialize().unwrap(); + zypp::filesystem::TmpDir provideRoot; auto prov = zyppng::Provide::create ( provideRoot ); prov->setWorkerPath ( workerPath ); @@ -897,10 +937,10 @@ BOOST_AUTO_TEST_CASE( tvm_jammed ) prov->start(); - auto op1 = prov->attachMedia( zypp::Url("tvm:/"), zyppng::ProvideMediaSpec("CD Test Set") + auto op1 = prov->attachMedia( zypp::Url("tvm:/"), zyppng::ProvideMediaSpec( ctx, "CD Test Set" ) .setMediaFile( devRoot / (std::string("cd") + zypp::str::numstring(1)) / (std::string("media.") + zypp::str::numstring(1)) / "media" ) .setMedianr(1)); - auto op2 = prov->attachMedia( zypp::Url("tvm:/"), zyppng::ProvideMediaSpec("CD Test Set") + auto op2 = prov->attachMedia( zypp::Url("tvm:/"), zyppng::ProvideMediaSpec( ctx, "CD Test Set" ) .setMediaFile( devRoot / (std::string("cd") + zypp::str::numstring(2)) / (std::string("media.") + zypp::str::numstring(2)) / "media" ) .setMedianr(2)); @@ -939,8 +979,10 @@ BOOST_AUTO_TEST_CASE( tvm_jammed_release ) const auto &workerPath = zypp::Pathname ( TESTS_BUILD_DIR ).dirname() / "tools" / "workers"; const auto &devRoot = zypp::Pathname ( TESTS_SRC_DIR ) / "zyppng" / "data" / "provide"; - zypp::filesystem::TmpDir provideRoot; + auto ctx = zyppng::AsyncContext::create (); + ctx->initialize().unwrap(); + zypp::filesystem::TmpDir provideRoot; auto prov = zyppng::Provide::create ( provideRoot ); prov->setWorkerPath ( workerPath ); @@ -969,7 +1011,7 @@ BOOST_AUTO_TEST_CASE( tvm_jammed_release ) prov->start(); - auto op1 = prov->attachMedia( zypp::Url("tvm:/"), zyppng::ProvideMediaSpec("CD Test Set") + auto op1 = prov->attachMedia( zypp::Url("tvm:/"), zyppng::ProvideMediaSpec( ctx, "CD Test Set" ) .setMediaFile( devRoot / (std::string("cd") + zypp::str::numstring(1)) / (std::string("media.") + zypp::str::numstring(1)) / "media" ) .setMedianr(1)); @@ -987,7 +1029,7 @@ BOOST_AUTO_TEST_CASE( tvm_jammed_release ) } attach1Success = true; - op2 = prov->attachMedia( zypp::Url("tvm:/"), zyppng::ProvideMediaSpec("CD Test Set") + op2 = prov->attachMedia( zypp::Url("tvm:/"), zyppng::ProvideMediaSpec( ctx, "CD Test Set" ) .setMediaFile( devRoot / (std::string("cd") + zypp::str::numstring(2)) / (std::string("media.") + zypp::str::numstring(2)) / "media" ) .setMedianr(2)); @@ -998,7 +1040,7 @@ BOOST_AUTO_TEST_CASE( tvm_jammed_release ) op1.reset(); // kill the first media handle mediaChangeAllowed = true; - op3 = prov->attachMedia( zypp::Url("tvm:/"), zyppng::ProvideMediaSpec("CD Test Set") + op3 = prov->attachMedia( zypp::Url("tvm:/"), zyppng::ProvideMediaSpec( ctx, "CD Test Set" ) .setMediaFile( devRoot / (std::string("cd") + zypp::str::numstring(2)) / (std::string("media.") + zypp::str::numstring(2)) / "media" ) .setMedianr(2)); op3->sigReady().connect( [&]() { diff --git a/zypp-core/AutoDispose.h b/zypp-core/AutoDispose.h index 8fa3deadc1..e124d33ee7 100644 --- a/zypp-core/AutoDispose.h +++ b/zypp-core/AutoDispose.h @@ -279,6 +279,8 @@ namespace zypp { template Deferred( F&&cb ); + + Deferred() : AutoDispose() {} }; template diff --git a/zypp-core/CMakeLists.txt b/zypp-core/CMakeLists.txt index 989e244f0f..d823646c63 100644 --- a/zypp-core/CMakeLists.txt +++ b/zypp-core/CMakeLists.txt @@ -320,6 +320,9 @@ SET( zyppng_pipelines_HEADERS zyppng/pipelines/lift.h zyppng/pipelines/MTry zyppng/pipelines/mtry.h + zyppng/pipelines/operators.h + zyppng/pipelines/Optional + zyppng/pipelines/optional.h zyppng/pipelines/Redo zyppng/pipelines/redo.h zyppng/pipelines/Transform diff --git a/zypp-core/Globals.h b/zypp-core/Globals.h index c972f62f70..3f22b6bb21 100644 --- a/zypp-core/Globals.h +++ b/zypp-core/Globals.h @@ -12,6 +12,7 @@ #ifndef ZYPP_GLOBALS_H #define ZYPP_GLOBALS_H +#include #include // LIBZYPP_ version defines for the LEGACY macro #include // some macros used almost everywhere @@ -117,4 +118,88 @@ #endif #endif + +#ifdef ZYPP_DLL //defined if zypp is compiled as DLL +// used to flag API to be deprected inside of libzypp. +#define ZYPP_INTERNAL_DEPRECATE ZYPP_DEPRECATED +// used to mark externally used API as internally deprected +#define ZYPP_LEGACY_API ZYPP_DECL_EXPORT ZYPP_INTERNAL_DEPRECATE +#else +#define ZYPP_INTERNAL_DEPRECATE +#define ZYPP_LEGACY_API +#endif + +/** + * Macro to disable legacy warnings for code that was otherwise marked as + * internal deprecated, for examples in files that are defining legacy API. + */ +#if __GNUC__ - 0 > 3 || (__GNUC__ - 0 == 3 && __GNUC_MINOR__ - 0 >= 2) + #ifndef ZYPP_BEGIN_LEGACY_API + #define ZYPP_BEGIN_LEGACY_API \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated\"") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") + #endif + + #ifndef ZYPP_END_LEGACY_API + #define ZYPP_END_LEGACY_API \ + _Pragma("GCC diagnostic pop") + #endif + +#else + #define ZYPP_BEGIN_LEGACY_API + #define ZYPP_END_LEGACY_API +#endif + +namespace zyppng { + template + using Ref = std::shared_ptr; + + template + using WeakRef = std::weak_ptr; +} + +namespace zypp { + template + using Ref = std::shared_ptr; + + template + using WeakRef = std::weak_ptr; +} + +/*! + * Helper macro to declare Ref types + */ +#define ZYPP_FWD_DECL_REFS(T) \ + using T##Ref = Ref; \ + using T##WeakRef = WeakRef + +/* + * Helper Macro to forward declare types and ref types + */ +#define ZYPP_FWD_DECL_TYPE_WITH_REFS(T) \ + class T; \ + ZYPP_FWD_DECL_REFS(T) + +#define ZYPP_FWD_DECL_TEMPL_TYPE_WITH_REFS_ARG1(T, TArg1) \ + template< typename TArg1> \ + class T; \ + template< typename TArg1> \ + using T##Ref = Ref>; \ + template< typename TArg1> \ + using T##WeakRef = WeakRef> + + +//@TODO enable for c++20 +#if 0 +#define ZYPP_FWD_DECL_TEMPL_TYPE_WITH_REFS(T, TArg1, ...) \ + template< typename TArg1 __VA_OPT__(, typename) __VA_ARGS__ > \ + class T; \ + template< typename TArg1 __VA_OPT__(, typename) __VA_ARGS__ > \ + using T##Ref = std::shared_ptr>; \ + template< typename TArg1 __VA_OPT__(, typename) __VA_ARGS__ > \ + using T##WeakRef = std::weak_ptr> +#endif + + #endif diff --git a/zypp-core/base/Iterator.h b/zypp-core/base/Iterator.h index 791973c61a..dfba3e3489 100644 --- a/zypp-core/base/Iterator.h +++ b/zypp-core/base/Iterator.h @@ -13,6 +13,7 @@ #define ZYPP_BASE_ITERATOR_H #include +#include #include #include @@ -148,6 +149,49 @@ namespace zypp using boost::transform_iterator; using boost::make_transform_iterator; + + template + class GenericIteratorNode { + using NodePtr = std::unique_ptr; + virtual RefT ref() = 0; + virtual NodePtr clone() const = 0; + virtual NodePtr next() const = 0; + virtual NodePtr prev() const = 0; + virtual bool equals( const GenericIteratorNode &other ) const = 0; + }; + + template + class GenericIterator : public boost::iterators::iterator_facade < GenericIterator, T, boost::iterators::bidirectional_traversal_tag, RefT > { + public: + GenericIterator( std::unique_ptr> &&node ) : _node(std::move(node)){} + ~GenericIterator() = default; + + template + GenericIterator(GenericIterator const& other) + : _node(other._node) {} + + GenericIterator(const GenericIterator &other) : _node( other._node->clone() ) {} + GenericIterator(GenericIterator &&other) : _node(std::move(other._node) ) {} + GenericIterator &operator=(const GenericIterator &other) { _node = other._node->clone(); } + GenericIterator &operator=(GenericIterator &&other) { _node = std::move(other._node); } + + private: + friend class boost::iterator_core_access; + + void increment() { _node = _node->next(); } + void decrement() { _node = _node->prev(); } + + bool equal( GenericIterator const& other) const + { + return this->_node->equals( *other._node ); + } + + RefT dereference() const { return _node->ref(); } + + private: + std::unique_ptr> _node; + }; + /** Functor taking a \c std::pair returning \c std::pair.first. * \see MapKVIteratorTraits */ diff --git a/zypp-core/base/defaultintegral.h b/zypp-core/base/defaultintegral.h index 3235f3e1bc..73eb321120 100644 --- a/zypp-core/base/defaultintegral.h +++ b/zypp-core/base/defaultintegral.h @@ -13,6 +13,7 @@ #define ZYPP_CORE_BASE_DEFAULTINTEGRAL_H #include +#include #include #include diff --git a/zypp-core/onmedialocation.cc b/zypp-core/onmedialocation.cc index 06b63e82d1..d9d89569f7 100644 --- a/zypp-core/onmedialocation.cc +++ b/zypp-core/onmedialocation.cc @@ -40,7 +40,7 @@ namespace zypp bool _optional = false; - ByteCount _downloadSize = zypp::ByteCount( 20, zypp::ByteCount::MB ); + ByteCount _downloadSize; CheckSum _checksum; ByteCount _openSize; diff --git a/zypp-core/onmedialocation.h b/zypp-core/onmedialocation.h index 8347225fb6..82a9f80010 100644 --- a/zypp-core/onmedialocation.h +++ b/zypp-core/onmedialocation.h @@ -82,10 +82,7 @@ namespace zypp OnMediaLocation & setOptional( bool val ); public: - /** The size of the resource on the server. - * \note If unset a default of at most 20MB is assumed. - * \ref setDownloadSize to zero for unlimited downloads. - */ + /** The size of the resource on the server. */ const ByteCount & downloadSize() const; /** Set the \ref downloadSize. */ OnMediaLocation & setDownloadSize( ByteCount val_r ); diff --git a/zypp-core/zyppng/async/asyncop.h b/zypp-core/zyppng/async/asyncop.h index af56171be9..b6e9797e11 100644 --- a/zypp-core/zyppng/async/asyncop.h +++ b/zypp-core/zyppng/async/asyncop.h @@ -302,8 +302,26 @@ namespace zyppng { } } -} - + /*! + * Generic Promise type to be returned to calling code waiting for async results. + * Can register a cleanup function to clean up resources when the request is cancelled. + */ + template< typename T > + class AsyncOpPromise : public AsyncOp + { + public: + using CleanupFun = std::function &)>; + AsyncOpPromise( CleanupFun cleanup = nullptr ) + : _cleanup( std::move(cleanup) ) + {} + ~AsyncOpPromise() { + if ( _cleanup ) + _cleanup(*this); + } + private: + CleanupFun _cleanup; + }; +} #endif diff --git a/zypp-core/zyppng/base/abstracteventsource.h b/zypp-core/zyppng/base/abstracteventsource.h index 109dbdcf65..7f37349dce 100644 --- a/zypp-core/zyppng/base/abstracteventsource.h +++ b/zypp-core/zyppng/base/abstracteventsource.h @@ -34,7 +34,7 @@ class AbstractEventSourcePrivate; * In case there is activity on the file descriptor the EventDispatcher wakes up * and forwards it to \a onFdReady. */ -class LIBZYPP_NG_EXPORT AbstractEventSource : public Base +class AbstractEventSource : public Base { ZYPP_DECLARE_PRIVATE(AbstractEventSource) public: diff --git a/zypp-core/zyppng/base/base.cc b/zypp-core/zyppng/base/base.cc index 0497599964..0ff58b77ef 100644 --- a/zypp-core/zyppng/base/base.cc +++ b/zypp-core/zyppng/base/base.cc @@ -73,4 +73,25 @@ namespace zyppng { return d_func()->threadId; } + void Base::setData( uint32_t quark, zypp::AutoDispose data ) + { + Z_D(); + d->_data.insert_or_assign ( quark, data ); + } + + void *Base::data( uint32_t quark ) + { + Z_D(); + if ( !d->_data.count (quark) ) + return nullptr; + return d->_data.at(quark).value (); + } + + void Base::clearData( uint32_t quark ) + { + Z_D(); + d->_data.erase(quark); + } + + } // namespace zyppng diff --git a/zypp-core/zyppng/base/base.h b/zypp-core/zyppng/base/base.h index 6819d76905..034913b716 100644 --- a/zypp-core/zyppng/base/base.h +++ b/zypp-core/zyppng/base/base.h @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -56,7 +57,7 @@ namespace zyppng { * * \sa zypp/zyppng/base/signals.h */ - class LIBZYPP_NG_EXPORT Base : public sigc::trackable, public std::enable_shared_from_this + class Base : public sigc::trackable, public std::enable_shared_from_this { NON_COPYABLE(Base); ZYPP_DECLARE_PRIVATE(Base) @@ -169,6 +170,13 @@ namespace zyppng { return connectFunc( static_cast::ClassType &>(*this), std::forward(sFun), std::forward(rFunc), trackers... ); } + /*! + * \internal Used by the C layer to connect a existing wrapper to the C++ instance + */ + void setData ( uint32_t quark, zypp::AutoDispose data ); + void* data ( uint32_t quark ); + void clearData ( uint32_t quark ); + protected: Base ( BasePrivate &dd ); std::unique_ptr d_ptr; diff --git a/zypp-core/zyppng/base/eventdispatcher.h b/zypp-core/zyppng/base/eventdispatcher.h index 282bfb0f2e..7dfc62e2dd 100644 --- a/zypp-core/zyppng/base/eventdispatcher.h +++ b/zypp-core/zyppng/base/eventdispatcher.h @@ -21,11 +21,12 @@ #include #include +typedef struct _GMainContext GMainContext; + namespace zyppng { class SocketNotifier; class Timer; - ZYPP_FWD_DECL_TYPE_WITH_REFS( EventDispatcher ); ZYPP_FWD_DECL_TYPE_WITH_REFS( UnixSignalSource ); class EventDispatcherPrivate; @@ -38,7 +39,7 @@ class EventDispatcherPrivate; * uses the glib eventloop, just like Qt and GTK, so integrating libzypp here is just a matter of passing the default main context * to the constructor of \ref EventDispatcher. */ -class LIBZYPP_NG_EXPORT EventDispatcher : public Base +class EventDispatcher : public Base { ZYPP_DECLARE_PRIVATE(EventDispatcher) friend class AbstractEventSource; @@ -46,8 +47,8 @@ class LIBZYPP_NG_EXPORT EventDispatcher : public Base public: - using Ptr = std::shared_ptr; - using WeakPtr = std::shared_ptr; + using Ptr = EventDispatcherRef; + using WeakPtr = EventDispatcherWeakRef; using IdleFunction = std::function; @@ -63,12 +64,11 @@ class LIBZYPP_NG_EXPORT EventDispatcher : public Base * \brief Convenience function to schedule a callback to be called later. * \param callback a std::function that is called after all other events have been processed */ - template< typename T = IdleFunction > - static void invokeOnIdle ( T &&callback ) + static void invokeOnIdle ( IdleFunction &&callback ) { auto ev = instance(); if ( ev ) - ev->invokeOnIdleImpl( std::forward(callback) ); + ev->invokeOnIdleImpl( std::move(callback) ); } /*! @@ -143,12 +143,15 @@ class LIBZYPP_NG_EXPORT EventDispatcher : public Base */ bool untrackChildProcess ( int pid ); + /*! * Returns the currently active \ref UnixSignalSource for this EventDispatcher. * It is required to keep the reference alive as long as signals need to be catched. */ UnixSignalSourceRef unixSignalSource (); + GMainContext * glibContext(); + protected: /*! diff --git a/zypp-core/zyppng/base/eventdispatcher_glib.cc b/zypp-core/zyppng/base/eventdispatcher_glib.cc index fa665c2ebf..f9b110c4e2 100644 --- a/zypp-core/zyppng/base/eventdispatcher_glib.cc +++ b/zypp-core/zyppng/base/eventdispatcher_glib.cc @@ -338,9 +338,9 @@ void EventDispatcherPrivate::enableIdleSource() } } -std::shared_ptr EventDispatcherPrivate::create() +std::shared_ptr EventDispatcherPrivate::create( GMainContext *ctx ) { - return std::shared_ptr( new EventDispatcher() ); + return std::shared_ptr( new EventDispatcher( ctx ) ); } void EventDispatcherPrivate::waitPidCallback( GPid pid, gint status, gpointer user_data ) @@ -563,6 +563,11 @@ UnixSignalSourceRef EventDispatcher::unixSignalSource() return r; } +GMainContext * EventDispatcher::glibContext() +{ + return d_func()->_ctx; +} + bool EventDispatcher::run_once() { return g_main_context_iteration( d_func()->_ctx, false ); diff --git a/zypp-core/zyppng/base/eventloop.h b/zypp-core/zyppng/base/eventloop.h index 8aff854645..8d77063b5e 100644 --- a/zypp-core/zyppng/base/eventloop.h +++ b/zypp-core/zyppng/base/eventloop.h @@ -18,7 +18,7 @@ #include #include -// CONTINUE WITH THREAD DATA AND PUT THE DISPATCHER INSTANCE THERE! +typedef struct _GMainContext GMainContext; namespace zyppng { @@ -39,7 +39,7 @@ namespace zyppng { * utilizing more of the CPU compared to starting all the tasks serially. * */ - class LIBZYPP_NG_EXPORT EventLoop : public Base + class EventLoop : public Base { ZYPP_DECLARE_PRIVATE(EventLoop) @@ -47,7 +47,8 @@ namespace zyppng { using Ptr = EventLoopRef; using WeakPtr = EventLoopWeakRef; - static Ptr create (); + static Ptr create ( GMainContext *ctx = nullptr ); + static Ptr create ( EventDispatcherRef dispatcher ); ~EventLoop() override; /*! @@ -67,7 +68,8 @@ namespace zyppng { std::shared_ptr eventDispatcher () const; private: - EventLoop(); + EventLoop( GMainContext *ctx = nullptr ); + EventLoop( EventDispatcherRef dispatcher ); }; diff --git a/zypp-core/zyppng/base/eventloop_glib.cc b/zypp-core/zyppng/base/eventloop_glib.cc index 6f20dcd0a5..06a615aa1d 100644 --- a/zypp-core/zyppng/base/eventloop_glib.cc +++ b/zypp-core/zyppng/base/eventloop_glib.cc @@ -8,31 +8,44 @@ namespace zyppng { ZYPP_IMPL_PRIVATE(EventLoop) - EventLoop::EventLoop() + EventLoop::EventLoop( EventDispatcherRef disp ) : Base ( * new EventLoopPrivate(*this) ) { Z_D(); - d->_dispatcher = ThreadData::current().ensureDispatcher(); - d->_loop = g_main_loop_new( reinterpret_cast(d->_dispatcher->nativeDispatcherHandle()), false ); + d->_dispatcher = std::move(disp); + d->_loop = g_main_loop_new( reinterpret_cast(d->_dispatcher->nativeDispatcherHandle()), false ); } + + EventLoop::EventLoop( GMainContext *ctx ) + : EventLoop( ThreadData::current().ensureDispatcher( ctx ) ) + {} + EventLoop::~EventLoop() { g_main_loop_unref( d_func()->_loop ); } - EventLoop::Ptr EventLoop::create() + EventLoop::Ptr EventLoop::create( GMainContext *ctx ) + { + return Ptr( new EventLoop( ctx ) ); + } + + EventLoop::Ptr EventLoop::create( EventDispatcherRef dispatcher ) { - return Ptr( new EventLoop() ); + return Ptr( new EventLoop( std::move(dispatcher) ) ); } + void EventLoop::run() { Z_D(); g_main_context_push_thread_default( reinterpret_cast(d->_dispatcher->nativeDispatcherHandle()) ); + zypp_defer { + d->_dispatcher->clearUnrefLaterList(); + g_main_context_pop_thread_default( reinterpret_cast(d->_dispatcher->nativeDispatcherHandle()) ); + }; g_main_loop_run( d->_loop ); - d->_dispatcher->clearUnrefLaterList(); - g_main_context_pop_thread_default( reinterpret_cast(d->_dispatcher->nativeDispatcherHandle()) ); } void EventLoop::quit() diff --git a/zypp-core/zyppng/base/private/base_p.h b/zypp-core/zyppng/base/private/base_p.h index e39b3e5014..fbd6029eb3 100644 --- a/zypp-core/zyppng/base/private/base_p.h +++ b/zypp-core/zyppng/base/private/base_p.h @@ -1,6 +1,7 @@ #ifndef ZYPP_NG_BASE_PRIVATE_BASE_P_H_INCLUDED #define ZYPP_NG_BASE_PRIVATE_BASE_P_H_INCLUDED +#include "zypp-core/AutoDispose.h" #include #include #include @@ -9,7 +10,6 @@ namespace zyppng { - class BasePrivate : public sigc::trackable { ZYPP_DECLARE_PUBLIC(Base) @@ -21,6 +21,7 @@ namespace zyppng Base::WeakPtr parent; std::unordered_set< Base::Ptr > children; + std::unordered_map > _data; Base *z_ptr = nullptr; std::thread::id threadId = std::this_thread::get_id(); }; diff --git a/zypp-core/zyppng/base/private/eventdispatcher_glib_p.h b/zypp-core/zyppng/base/private/eventdispatcher_glib_p.h index 4db8beacef..a358a2f1a6 100644 --- a/zypp-core/zyppng/base/private/eventdispatcher_glib_p.h +++ b/zypp-core/zyppng/base/private/eventdispatcher_glib_p.h @@ -82,7 +82,7 @@ class EventDispatcherPrivate : public BasePrivate bool runIdleTasks(); void enableIdleSource (); - static std::shared_ptr create ( ); + static std::shared_ptr create ( GMainContext *ctx = 0 ); static void waitPidCallback ( GPid pid, gint status, gpointer user_data ); std::thread::id _myThreadId; diff --git a/zypp-core/zyppng/base/private/threaddata_p.h b/zypp-core/zyppng/base/private/threaddata_p.h index d753be9ca1..e7824f603c 100644 --- a/zypp-core/zyppng/base/private/threaddata_p.h +++ b/zypp-core/zyppng/base/private/threaddata_p.h @@ -6,6 +6,8 @@ #include #include +typedef struct _GMainContext GMainContext; + namespace zyppng { class EventDispatcher; @@ -23,7 +25,7 @@ namespace zyppng const std::string &name() const; std::shared_ptr dispatcher(); - std::shared_ptr ensureDispatcher(); + std::shared_ptr ensureDispatcher( GMainContext *ctx = 0 ); void setDispatcher( const std::shared_ptr &disp ); diff --git a/zypp-core/zyppng/base/socketnotifier.h b/zypp-core/zyppng/base/socketnotifier.h index f98e312258..e44a56139d 100644 --- a/zypp-core/zyppng/base/socketnotifier.h +++ b/zypp-core/zyppng/base/socketnotifier.h @@ -22,6 +22,8 @@ namespace zyppng { class SocketNotifierPrivate; +ZYPP_FWD_DECL_TYPE_WITH_REFS (SocketNotifier); + /*! * The SocketNotifier class provides a generic way to monitor activity on a file descriptors. * diff --git a/zypp-core/zyppng/base/threaddata.cc b/zypp-core/zyppng/base/threaddata.cc index 8d1a6f5a0a..5fbf986dd2 100644 --- a/zypp-core/zyppng/base/threaddata.cc +++ b/zypp-core/zyppng/base/threaddata.cc @@ -29,12 +29,14 @@ namespace zyppng return _threadName; } - std::shared_ptr ThreadData::ensureDispatcher() + std::shared_ptr ThreadData::ensureDispatcher( GMainContext *ctx ) { auto sp = _dispatcher.lock(); if (!sp) { MIL << "Creating the Event Dispatcher for thread: " << name() << "("<<_threadId<<")" << std::endl; - _dispatcher = sp = EventDispatcherPrivate::create(); + _dispatcher = sp = EventDispatcherPrivate::create( ctx ); + } else { + if ( ctx && ctx != sp->glibContext() ) MIL << "Ignoring passed GMainContext, because a Zypp Event Dispatcher was created before. This might be a bug!" << std::endl; } return sp; } diff --git a/zypp-core/zyppng/base/timer.h b/zypp-core/zyppng/base/timer.h index 0f50efe3a8..daea621c47 100644 --- a/zypp-core/zyppng/base/timer.h +++ b/zypp-core/zyppng/base/timer.h @@ -25,6 +25,8 @@ class TimerPrivate; class EventDispatcher; ZYPP_FWD_DECL_TYPE_WITH_REFS (Timer); +ZYPP_FWD_DECL_TYPE_WITH_REFS( Timer ); + /*! * \brief The Timer class provides repetitive and single-shot timers. * @@ -48,8 +50,8 @@ class Timer : public Base public: - using Ptr = std::shared_ptr; - using WeakPtr = std::shared_ptr; + using Ptr = TimerRef; + using WeakPtr = TimerWeakRef; /*! * \brief Creates a new Timer object, the timer is not started at this point diff --git a/zypp-core/zyppng/base/zyppglobal.h b/zypp-core/zyppng/base/zyppglobal.h index f562d36ea2..ee66252543 100644 --- a/zypp-core/zyppng/base/zyppglobal.h +++ b/zypp-core/zyppng/base/zyppglobal.h @@ -3,13 +3,7 @@ #include #include - -#ifndef EXPORT_EXPERIMENTAL_API -#define LIBZYPP_NG_EXPORT -#define LIBZYPP_NG_NO_EXPORT -#else -#include -#endif +#include /* * Convenience helpers to automatically generate boilerplate code @@ -105,48 +99,6 @@ template inline auto zyppGetPtrHelper(Ptr &ptr) -> decltype(ptr.o #define Z_D() auto const d = d_func() #define Z_Z() auto const z = z_func() -namespace zyppng { - template - using Ref = std::shared_ptr; - - template - using WeakRef = std::weak_ptr; -} - -/*! - * Helper macro to declare Ref types - */ -#define ZYPP_FWD_DECL_REFS(T) \ - using T##Ref = Ref; \ - using T##WeakRef = WeakRef - -/* - * Helper Macro to forward declare types and ref types - */ -#define ZYPP_FWD_DECL_TYPE_WITH_REFS(T) \ - class T; \ - ZYPP_FWD_DECL_REFS(T) - -#define ZYPP_FWD_DECL_TEMPL_TYPE_WITH_REFS_ARG1(T, TArg1) \ - template< typename TArg1> \ - class T; \ - template< typename TArg1> \ - using T##Ref = Ref>; \ - template< typename TArg1> \ - using T##WeakRef = WeakRef> - - -//@TODO enable for c++20 -#if 0 -#define ZYPP_FWD_DECL_TEMPL_TYPE_WITH_REFS(T, TArg1, ...) \ - template< typename TArg1 __VA_OPT__(, typename) __VA_ARGS__ > \ - class T; \ - template< typename TArg1 __VA_OPT__(, typename) __VA_ARGS__ > \ - using T##Ref = std::shared_ptr>; \ - template< typename TArg1 __VA_OPT__(, typename) __VA_ARGS__ > \ - using T##WeakRef = std::weak_ptr> -#endif - /*! * Defines a dummy struct that can be used to make a public constructor unusable * outside the class. \sa ZYPP_ADD_CREATE_FUNC. diff --git a/zypp-core/zyppng/pipelines/Optional b/zypp-core/zyppng/pipelines/Optional new file mode 100644 index 0000000000..16d841e3fc --- /dev/null +++ b/zypp-core/zyppng/pipelines/Optional @@ -0,0 +1 @@ +#include "optional.h" diff --git a/zypp-core/zyppng/pipelines/asyncresult.h b/zypp-core/zyppng/pipelines/asyncresult.h index 7a3cd4a986..4984170372 100644 --- a/zypp-core/zyppng/pipelines/asyncresult.h +++ b/zypp-core/zyppng/pipelines/asyncresult.h @@ -125,6 +125,13 @@ namespace zyppng { template constexpr bool is_nested_async_v = is_nested_async::value; + // helper to figure out the return type for a mbind callback, if the ArgType is void the callback is considered to take no argument. + // Due to how std::conditional works, we cannot pass std::invoke_result_t but instead use the template type std::invoke_result, since + // one of the two options have no "::type" because the substitution fails, this breaks the std::conditional_t since it can only work with two well formed + // types. Instead we pass in the template types and evaluate the ::type in the end, when the correct invoke_result was chosen. + template < typename Function, typename ArgType> + using mbind_cb_result_t = typename std::conditional_t< std::is_same_v, std::invoke_result,std::invoke_result >::type; + // case 1: connect async result to async callback template diff --git a/zypp-core/zyppng/pipelines/await.h b/zypp-core/zyppng/pipelines/await.h index 826671f9d6..68721c3d95 100644 --- a/zypp-core/zyppng/pipelines/await.h +++ b/zypp-core/zyppng/pipelines/await.h @@ -61,8 +61,7 @@ namespace zyppng { //return a async op that waits for a signal to emitted by a object template - auto await ( SignalGetter &&sigGet ) - { + auto await ( SignalGetter &&sigGet ) { return std::make_shared>( std::forward(sigGet) ); } diff --git a/zypp-core/zyppng/pipelines/expected.h b/zypp-core/zyppng/pipelines/expected.h index fe429337a4..50653d506f 100644 --- a/zypp-core/zyppng/pipelines/expected.h +++ b/zypp-core/zyppng/pipelines/expected.h @@ -20,6 +20,7 @@ #include #include #include +#include namespace zyppng { @@ -393,6 +394,29 @@ namespace zyppng { }; + namespace detail { + template + struct is_expected_type { + static constexpr bool value = false; + }; + + template + struct is_expected_type> { + static constexpr bool value = true; + }; + } + + /*! + * \brief is_expected_type_v + * + * Detect at compile time if a given type is a expected type + */ + template + constexpr bool is_expected_type_v = detail::is_expected_type::value; + + #define expected_return_on_error(T, exp) \ + if ( !exp ) return expected::error( exp.error() ) + template static expected,Err> make_expected_success( Type &&t ) { @@ -400,14 +424,6 @@ namespace zyppng { } namespace detail { - - // helper to figure out the return type for a mbind callback, if the ArgType is void the callback is considered to take no argument. - // Due to how std::conditional works, we cannot pass std::invoke_result_t but instead use the template type std::invoke_result, since - // one of the two options have no "::type" because the substitution fails, this breaks the std::conditional_t since it can only work with two well formed - // types. Instead we pass in the template types and evaluate the ::type in the end, when the correct invoke_result was chosen. - template < typename Function, typename ArgType> - using mbind_cb_result_t = typename std::conditional_t< std::is_same_v, std::invoke_result,std::invoke_result >::type; - template bool waitForCanContinueExpected( const expected &value ) { return value.is_valid(); @@ -552,57 +568,6 @@ namespace zyppng { namespace detail { - - template - struct and_then_helper { - Callback function; - - template< typename T, typename E > - auto operator()( const expected& exp ) { - return and_then( exp, function ); - } - - template< typename T, typename E > - auto operator()( expected&& exp ) { - return and_then( std::move(exp), function ); - } - }; - - template - struct or_else_helper { - Callback function; - - template< typename T, typename E > - auto operator()( const expected& exp ) { - return or_else( exp, function ); - } - - template< typename T, typename E > - auto operator()( expected&& exp ) { - return or_else( std::move(exp), function ); - } - }; - - template - struct inspect_helper { - Callback function; - - template< typename T, typename E > - auto operator()( expected&& exp ) { - return inspect( std::move(exp), function ); - } - }; - - template - struct inspect_err_helper { - Callback function; - - template< typename T, typename E > - auto operator()( expected&& exp ) { - return inspect_err( std::move(exp), function ); - } - }; - struct collect_helper { template < typename T > inline auto operator()( T&& in ) { @@ -612,41 +577,6 @@ namespace zyppng { } namespace operators { - template - auto mbind ( Fun && function ) { - return detail::and_then_helper { - std::forward(function) - }; - } - - template - auto and_then ( Fun && function ) { - return detail::and_then_helper { - std::forward(function) - }; - } - - template - auto or_else ( Fun && function ) { - return detail::or_else_helper { - std::forward(function) - }; - } - - template - auto inspect ( Fun && function ) { - return detail::inspect_helper { - std::forward(function) - }; - } - - template - auto inspect_err ( Fun && function ) { - return detail::inspect_err_helper { - std::forward(function) - }; - } - inline detail::collect_helper collect() { return detail::collect_helper(); } @@ -693,7 +623,10 @@ namespace zyppng { namespace detail { template struct transform_collect_helper { + template + transform_collect_helper( F &&cb ) : _callback( std::forward(cb)) {} Fun _callback; + template auto operator() ( T &&in ) { return transform_collect( std::forward(in), _callback ); @@ -704,7 +637,7 @@ namespace zyppng { namespace operators { template auto transform_collect( Transformation &&f ) { - return detail::transform_collect_helper{ std::forward(f)}; + return detail::transform_collect_helper( std::forward(f) ); } } diff --git a/zypp-core/zyppng/pipelines/mtry.h b/zypp-core/zyppng/pipelines/mtry.h index 1712b5c2b2..94de4e609d 100644 --- a/zypp-core/zyppng/pipelines/mtry.h +++ b/zypp-core/zyppng/pipelines/mtry.h @@ -56,7 +56,7 @@ namespace zyppng { namespace operators { template auto mtry ( Fun && function ) { - return detail::mtry_helper { + return zyppng::detail::mtry_helper { std::forward(function) }; } diff --git a/zypp-core/zyppng/pipelines/operators.h b/zypp-core/zyppng/pipelines/operators.h new file mode 100644 index 0000000000..c1708a71f1 --- /dev/null +++ b/zypp-core/zyppng/pipelines/operators.h @@ -0,0 +1,106 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +----------------------------------------------------------------------/ +* +* This file contains private API, this might break at any time between releases. +* You have been warned! +*/ + +#ifndef ZYPP_ZYPPNG_PIPELINES_OPERATORS_H +#define ZYPP_ZYPPNG_PIPELINES_OPERATORS_H + +#include + +namespace zyppng { + + namespace detail { + template + struct and_then_helper { + Callback function; + + template< typename T > + auto operator()( T&& exp ) { + return and_then( std::forward(exp), function ); + } + }; + + template + struct or_else_helper { + Callback function; + + template< typename T > + auto operator()(T&& exp ) { + return or_else( std::forward(exp), function ); + } + }; + + template + struct inspect_helper { + Callback function; + + template< typename T> + auto operator()( T &&exp ) { + return inspect( std::forward(exp), function ); + } + }; + + template + struct inspect_err_helper { + Callback function; + + template< typename T> + auto operator()( T &&exp ) { + return inspect_err( std::forward(exp), function ); + } + }; + } + + + namespace operators { + /*! + * \brief inspect + * Invokes the callback if the value passed to the inspect implementation + * evaluates as valid, e.g for a \ref expected this means that it does not contain an error. + */ + template + auto inspect ( Fun && function ) { + return detail::inspect_helper { + std::forward(function) + }; + } + + /*! + * \brief inspect_err + * Invokes the callback if the value passed to the inspect implementation + * evaluates as invalid, e.g for a \ref expected this means that it does contain an error. + */ + template + auto inspect_err ( Fun && function ) { + return detail::inspect_err_helper { + std::forward(function) + }; + } + + template + auto and_then ( Fun && function ) { + return detail::and_then_helper { + std::forward(function) + }; + } + + template + auto or_else ( Fun && function ) { + return detail::or_else_helper { + std::forward(function) + }; + } + } + +} + +#endif diff --git a/zypp-core/zyppng/pipelines/optional.h b/zypp-core/zyppng/pipelines/optional.h new file mode 100644 index 0000000000..9c8a9a242a --- /dev/null +++ b/zypp-core/zyppng/pipelines/optional.h @@ -0,0 +1,93 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +----------------------------------------------------------------------/ +* +* This file contains private API, this might break at any time between releases. +* You have been warned! +*/ + +#ifndef ZYPP_ZYPPNG_PIPELINES_OPTIONAL_H +#define ZYPP_ZYPPNG_PIPELINES_OPTIONAL_H + +#include + +#ifdef __cpp_lib_optional +#include +#include +#include +#include +#include + +namespace zyppng { + + template < typename T + , typename Function + , typename ResultType = std::invoke_result_t + > + ResultType and_then( const std::optional& opt, Function &&f) + { + if (opt) { + return std::invoke( std::forward(f), opt.value() ); + } else { + if constexpr ( !detail::is_async_op< remove_smart_ptr_t >::value ) + return std::optional(); + else + return makeReadyResult( std::optional::value_type>() ); + } + } + + template < typename T + , typename Function + , typename ResultType = std::invoke_result_t + > + ResultType and_then( std::optional &&opt, Function &&f) + { + if (opt) { + return std::invoke( std::forward(f), std::move(opt.value()) ); + } else { + if constexpr ( !detail::is_async_op< remove_smart_ptr_t >::value ) + return std::optional(); + else + return makeReadyResult( std::optional::value_type>() ); + } + } + + template < typename T + , typename Function + , typename ResultType = std::invoke_result_t + > + ResultType or_else( const std::optional& opt, Function &&f) + { + if (!opt) { + return std::invoke( std::forward(f), opt.error() ); + } else { + if constexpr ( !detail::is_async_op< remove_smart_ptr_t >::value ) + return opt; + else + return makeReadyResult( std::move(opt) ); + } + } + + template < typename T + , typename Function + , typename ResultType = std::invoke_result_t + > + ResultType or_else( std::optional&& opt, Function &&f) + { + if (!opt) { + return std::invoke( std::forward(f), std::move(opt.error()) ); + } else { + if constexpr ( !detail::is_async_op< remove_smart_ptr_t >::value ) + return opt; + else + return makeReadyResult( std::move(opt) ); + } + } +} +#endif +#endif diff --git a/zypp-core/zyppng/thread/asyncqueue.h b/zypp-core/zyppng/thread/asyncqueue.h index 6e34daa565..1297fc842b 100644 --- a/zypp-core/zyppng/thread/asyncqueue.h +++ b/zypp-core/zyppng/thread/asyncqueue.h @@ -144,7 +144,7 @@ namespace zyppng { }; class AsyncQueueWatchPrivate; - class LIBZYPP_NG_EXPORT AsyncQueueWatch : public AbstractEventSource + class AsyncQueueWatch : public AbstractEventSource { ZYPP_DECLARE_PRIVATE(AsyncQueueWatch) public: diff --git a/zypp-core/zyppng/ui/progressobserver.cc b/zypp-core/zyppng/ui/progressobserver.cc index 309b819725..397072ddbc 100644 --- a/zypp-core/zyppng/ui/progressobserver.cc +++ b/zypp-core/zyppng/ui/progressobserver.cc @@ -2,6 +2,7 @@ #include "zypp-core/AutoDispose.h" #include #include +#include namespace zyppng { @@ -77,6 +78,7 @@ namespace zyppng { Signal _sigProgressChanged; Signal _sigFinished; Signal _sigNewSubprogress; + Signal _sigEvent; }; ZYPP_IMPL_PRIVATE(ProgressObserver) @@ -127,6 +129,8 @@ namespace zyppng { return; } + child.d_func()->_parent.reset(); + const auto idx = std::distance ( _children.begin (), i ); _children.erase(i); _childInfo.erase( _childInfo.begin () + idx ); @@ -193,6 +197,11 @@ namespace zyppng { return d_func()->_counterValue; } + ProgressObserverRef ProgressObserver::parent() const + { + return d_func()->_parent.lock(); + } + const std::vector &ProgressObserver::children() { return d_func()->_children; @@ -238,6 +247,11 @@ namespace zyppng { return d_func()->_sigNewSubprogress; } + SignalProxy ProgressObserver::sigEvent() + { + return d_func()->_sigEvent; + } + void ProgressObserver::setBaseSteps(int steps) { Z_D(); @@ -258,6 +272,8 @@ namespace zyppng { void ProgressObserver::setCurrent(double curr) { Z_D(); + if ( !d->_started ) start(); + auto set = std::max(0, std::min( curr, d->_baseSteps ) ); if ( set == d->_baseValue ) return; @@ -280,12 +296,12 @@ namespace zyppng { // others we have to manually remove while ( d->_children.size() ) { auto back = d->_children.back(); - bool remove = !back->started (); back->setFinished( result ); + bool remove = !back->started (); if ( remove ) d->_children.pop_back(); } - if ( result != Error ) + if ( d->_started && result != Error ) setCurrent( d->_baseSteps ); if ( d->_started ) @@ -309,13 +325,14 @@ namespace zyppng { } else { d->_children.push_back( child ); d->_childInfo.push_back( { - { connectFunc ( *child, &ProgressObserver::sigStepsChanged, [this]( auto &sender, auto ){ d_func()->updateCounters(); }, *this ), - connectFunc ( *child, &ProgressObserver::sigValueChanged, [this]( auto &sender, auto ){ d_func()->updateCounters(); }, *this ), + { connectFunc ( *child, &ProgressObserver::sigStepsChanged, [this]( auto &, auto ){ d_func()->updateCounters(); }, *this ), + connectFunc ( *child, &ProgressObserver::sigValueChanged, [this]( auto &, auto ){ d_func()->updateCounters(); }, *this ), connect ( *child, &ProgressObserver::sigStarted, *d, &ProgressObserverPrivate::onChildStarted ), connect ( *child, &ProgressObserver::sigFinished, *d, &ProgressObserverPrivate::onChildFinished ) } , adjustedWeight }); + child->d_func ()->_parent = weak_this(); d->_sigNewSubprogress.emit( *this, child ); // if the child has been started already, we also need to start() @@ -355,4 +372,20 @@ namespace zyppng { }; } + void ProgressObserver::sendUserRequest( const UserRequestRef &event ) + { + Z_D(); + d->_sigEvent.emit( *this, event ); + if ( !event->acknowledged () ) { + // our receivers did not handle the request, we need to bubble up! + auto p = d->_parent.lock(); + if ( p ) { + p->sendUserRequest( event ); + } else { + // no parent, no ack, finished + event->setFinished(); + } + } + } + } // namespace zyppng diff --git a/zypp-core/zyppng/ui/progressobserver.h b/zypp-core/zyppng/ui/progressobserver.h index e13042d01b..3872d95184 100644 --- a/zypp-core/zyppng/ui/progressobserver.h +++ b/zypp-core/zyppng/ui/progressobserver.h @@ -6,8 +6,8 @@ | /_____||_| |_| |_| | | | \---------------------------------------------------------------------*/ -#ifndef ZYPPNG_PROGRESSOBSERVER_H -#define ZYPPNG_PROGRESSOBSERVER_H +#ifndef ZYPP_CORE_ZYPPNG_PROGRESSOBSERVER_H +#define ZYPP_CORE_ZYPPNG_PROGRESSOBSERVER_H #include #include @@ -22,6 +22,7 @@ namespace zyppng { ZYPP_FWD_DECL_TYPE_WITH_REFS( ProgressObserver ); + ZYPP_FWD_DECL_TYPE_WITH_REFS( UserRequest ); class ProgressObserverPrivate; class ProgressObserver : public Base @@ -58,6 +59,7 @@ namespace zyppng { double progress() const; double current() const; + ProgressObserverRef parent() const; inline static ProgressObserverRef makeSubTask( ProgressObserverRef parentProgress, float weight = 1.0, const std::string &label = std::string(), int steps = 100 ) { if ( parentProgress ) return parentProgress->makeSubTask( weight, label, steps ); @@ -106,6 +108,8 @@ namespace zyppng { zypp::ProgressData::ReceiverFnc makeProgressDataReceiver (); + void sendUserRequest( const UserRequestRef& event ); + SignalProxy sigStarted (); SignalProxy sigLabelChanged (); SignalProxy sigStepsChanged(); @@ -113,6 +117,7 @@ namespace zyppng { SignalProxy sigProgressChanged(); SignalProxy sigFinished(); SignalProxy sigNewSubprogress(); + SignalProxy sigEvent(); }; @@ -258,4 +263,4 @@ namespace zyppng { } // namespace zyppng -#endif // ZYPPNG_PROGRESSOBSERVER_H +#endif // ZYPP_CORE_ZYPPNG_PROGRESSOBSERVER_H diff --git a/zypp-core/zyppng/ui/userinterface.cc b/zypp-core/zyppng/ui/userinterface.cc index 8d1b9bc571..485e520e0e 100644 --- a/zypp-core/zyppng/ui/userinterface.cc +++ b/zypp-core/zyppng/ui/userinterface.cc @@ -16,9 +16,17 @@ namespace zyppng { ZYPP_IMPL_PRIVATE_CONSTR( UserInterface ) : Base ( *( new UserInterfacePrivate(*this) ) ) { } + UserInterface::UserInterface() : Base ( *( new UserInterfacePrivate(*this) ) ) { } + UserInterface::UserInterface( UserInterfacePrivate &d ) : Base(d) { } + UserInterfaceRef UserInterface::instance() + { + static UserInterfaceRef r = UserInterface::create(); + return r; + } + void UserInterface::sendUserRequest(const UserRequestRef& event) { Z_D(); @@ -29,4 +37,5 @@ namespace zyppng { { return d_func()->_sigEvent; } + } diff --git a/zypp-core/zyppng/ui/userinterface.h b/zypp-core/zyppng/ui/userinterface.h index 65986d36ce..7bcf7b1c6e 100644 --- a/zypp-core/zyppng/ui/userinterface.h +++ b/zypp-core/zyppng/ui/userinterface.h @@ -36,10 +36,14 @@ namespace zyppng { public: ZYPP_DECL_PRIVATE_CONSTR(UserInterface); + + static UserInterfaceRef instance(); + void sendUserRequest( const UserRequestRef& event ); SignalProxy sigEvent(); protected: + UserInterface(); UserInterface( UserInterfacePrivate &d ); }; diff --git a/zypp-core/zyppng/ui/userrequest.cc b/zypp-core/zyppng/ui/userrequest.cc index 320fe64658..678db6d4bf 100644 --- a/zypp-core/zyppng/ui/userrequest.cc +++ b/zypp-core/zyppng/ui/userrequest.cc @@ -29,11 +29,59 @@ namespace zyppng return _userData; } + void UserRequest::ack() + { + _acknowledged = true; + } + + bool UserRequest::acknowledged() const + { + return _acknowledged; + } + + void UserRequest::accept() + { + _acknowledged = true; + _accepted = true; + setFinished (); + } + + void UserRequest::ignore() + { + _acknowledged = false; + } + + bool UserRequest::accepted() const + { + return _accepted; + } + + SignalProxy UserRequest::sigFinished() + { + return _sigFinished; + } + + void UserRequest::setFinished() + { + _finished = true; + _sigFinished.emit(); + } + + + void UserRequest::reject() + { + ack(); + _accepted = false; + setFinished (); + } + ZYPP_IMPL_PRIVATE_CONSTR_ARGS(ShowMessageRequest, std::string message, MType mType, UserData data ) : UserRequest( std::move(data) ) , _type( mType ) , _message( std::move(message) ) - { } + { + _finished = _accepted = true; // always finished and accepted + } UserRequestType ShowMessageRequest::type() const { @@ -72,7 +120,10 @@ namespace zyppng { if ( sel >= _answers.size() ) ZYPP_THROW( std::logic_error("Selection index is out of range") ); + + accept(); _answer = sel; + setFinished(); // tell the code the event is ready } ListChoiceRequest::index_type ListChoiceRequest::choice() const @@ -108,7 +159,9 @@ namespace zyppng void BooleanChoiceRequest::setChoice(const bool sel) { + accept(); _answer = sel; + setFinished(); // tell the code the event is ready } bool BooleanChoiceRequest::choice() const @@ -116,4 +169,34 @@ namespace zyppng return _answer; } + ZYPP_IMPL_PRIVATE_CONSTR_ARGS ( InputRequest, std::string label, UserData userData ) + : UserRequest( std::move(userData) ) + , _label( std::move(label) ) + { + } + + UserRequestType InputRequest::type() const + { + return UserRequestType::InputRequest; + } + + const std::string &InputRequest::label() const + { + return _label; + } + + void InputRequest::addField(FieldType type, std::string label, std::string initialValue) + { + _fields.push_back ( Field{ type, label, initialValue} ); + } + + const std::vector &InputRequest::fields() const + { + return _fields; + } + + std::vector &InputRequest::fields() + { + return _fields; + } } diff --git a/zypp-core/zyppng/ui/userrequest.h b/zypp-core/zyppng/ui/userrequest.h index 9f0949724d..603973f1b0 100644 --- a/zypp-core/zyppng/ui/userrequest.h +++ b/zypp-core/zyppng/ui/userrequest.h @@ -11,6 +11,7 @@ #include #include +#include #include #include namespace zyppng { @@ -18,24 +19,20 @@ namespace zyppng { using UserData = zypp::callback::UserData; using ContentType = zypp::ContentType; - ZYPP_FWD_DECL_TYPE_WITH_REFS( UserRequest ); ZYPP_FWD_DECL_TYPE_WITH_REFS( ShowMessageRequest ); ZYPP_FWD_DECL_TYPE_WITH_REFS( ListChoiceRequest ); ZYPP_FWD_DECL_TYPE_WITH_REFS( BooleanChoiceRequest ); - - /* - constexpr std::string_view CTYPE_SHOW_MESSAGE_REQUEST ("userreq/show-message"); - constexpr std::string_view CTYPE_LIST_CHOICE_REQUEST ("userreq/list-choice"); - constexpr std::string_view CTYPE_BOOLEAN_COICE_REQUEST("userreq/boolean-choice"); - */ + ZYPP_FWD_DECL_TYPE_WITH_REFS( InputRequest ); + // keep in sync with glib wrapper code enum class UserRequestType : uint { + Invalid, // invalid message, used as a default return value in Glib Code Message, // simple message to the user, no input or predefined like y/n ListChoice, // request to select from a list of options BooleanChoice, // request user to say yes or no - KeyTrust, // request to the user to trust a key + InputRequest, // generic request for user input defining a list of input fields Custom = 512 }; @@ -54,18 +51,70 @@ namespace zyppng { const UserData &userData() const; UserData &userData(); + /*! + * Call this function when a request should be handled asynchronously, to notify + * the sender that the event was acknowledged but can not be handled right away + */ + void ack(); + + bool acknowledged() const; + + /*! + * Sets the internal ack flag to false, event is now considered as "not yet handled" + * and will bubble up to the parent event handler. + */ + void ignore(); + + /*! + * User accepted the event + */ + void accept(); + + /*! + * User rejected the event + */ + void reject(); + + /*! + * Returns true if the event was accepted by the user, otherwise false is retuend + */ + bool accepted() const; + + /*! + * Returns true if the event was marked as finished, e.g. in cases where the + * user needs to be asked to resolve the event or another user request is pending and + * this one needs to wait the answer will arrive asynchronously + */ + bool finished() const; + + /*! + * Sets the event to finished in it's current state + */ + void setFinished(); + + /*! + * Signal emitted when the event is ready + */ + SignalProxy sigFinished(); + + protected: + Signal _sigFinished; + + protected: + bool _accepted = false; //< User accepted or rejected the event + bool _finished = false; //< The usercode explicitely handled the event + private: + bool _acknowledged = false; //< User code has seen and will handle the event UserData _userData; }; - - /*! * The ShowMessageRequest class represents a simple informal message that the code needs to * print on the users screen * * \code - * context->sendUserRequest( ShowMessageRequest::create("Repository downloaded") ); + * progressObserver->sendUserRequest( ShowMessageRequest::create("Repository downloaded") ); * \endcode */ class ShowMessageRequest : public UserRequest @@ -73,6 +122,7 @@ namespace zyppng { ZYPP_ADD_CREATE_FUNC(ShowMessageRequest) public: + // Keep in sync with the GLib wrapper enum! enum class MType { Debug, Info, Warning, Error, Important, Data }; @@ -97,7 +147,7 @@ namespace zyppng { * \code * * auto request = ListChoiceRequest::create( "Please select the choice you want: ", { {"y", "Info about y"}, {"n", "Info about n"}, {"d", "Info about d"} }, 1 ); - * context->sendUserRequest( request ); + * progressObserver->sendUserRequest( request ); * * const auto choice = request->choice(); * switch( choice ) { @@ -155,7 +205,7 @@ namespace zyppng { ZYPP_ADD_CREATE_FUNC(BooleanChoiceRequest) public: - ZYPP_DECL_PRIVATE_CONSTR_ARGS(BooleanChoiceRequest, std::string label, const bool defaultAnswer = false, UserData userData = {} ); + ZYPP_DECL_PRIVATE_CONSTR_ARGS( BooleanChoiceRequest, std::string label, const bool defaultAnswer = false, UserData userData = {} ); UserRequestType type() const override; const std::string &label() const; @@ -169,6 +219,53 @@ namespace zyppng { }; + class InputRequest : public UserRequest + { + ZYPP_ADD_CREATE_FUNC(InputRequest) + + public: + /*! + * \brief The FieldType enum + * \attention Keep in sync with ZyppInputRequest glib wrapper code + */ + enum FieldType { + Text, + Password + }; + + struct Field { + FieldType type; + std::string label; + std::string value; + }; + + ZYPP_DECL_PRIVATE_CONSTR_ARGS( InputRequest, std::string label, UserData userData = {} ); + + UserRequestType type() const override; + + const std::string &label() const; + + void addField( FieldType type, std::string label, std::string initialValue = "" ); + std::vector &fields (); + const std::vector &fields () const; + + private: + std::string _label; + std::vector _fields; + }; + + template< typename T > + AsyncOpRef< Ref > waitForUserRespose( Ref event ) { + + if ( event->isFinished() ) { + return makeReadyResult ( std::move(event) ); + } + + using namespace zyppng::operators; + return std::move( event ) | await( &UserRequest::sigFinished ); + + } + } diff --git a/zypp-curl/ng/network/downloader.cc b/zypp-curl/ng/network/downloader.cc index df8639b4f8..94930fdedd 100644 --- a/zypp-curl/ng/network/downloader.cc +++ b/zypp-curl/ng/network/downloader.cc @@ -63,7 +63,7 @@ namespace zyppng { - zypp::url::ViewOption::WITH_PASSWORD - zypp::url::ViewOption::WITH_QUERY_STR; - auto cachedCred = zypp::media::CredentialManager::findIn( _credCache, req->url(), vopt ); + auto cachedCred = zyppng::media::CredentialManager::findIn( _credCache, req->url(), vopt ); // only consider a cache entry if its newer than what we tried last time if ( cachedCred && cachedCred->lastDatabaseUpdate() > req->_authTimestamp ) { @@ -177,7 +177,7 @@ namespace zyppng { if ( set.authType() == "basic" && set.username().size() && !set.password().size() ) { - zypp::media::CredentialManager cm( _parent ? _parent->credManagerOptions() : zypp::media::CredManagerOptions() ); + zypp::media::CredentialManager cm( _parent ? _parent->credManagerOptions() : zypp::media::CredManagerSettings() ); const auto cred = cm.getCred( url ); if ( cred && cred->valid() ) { if ( !set.username().size() ) diff --git a/zypp-curl/ng/network/downloader.h b/zypp-curl/ng/network/downloader.h index 13dc730269..46c0f1a060 100644 --- a/zypp-curl/ng/network/downloader.h +++ b/zypp-curl/ng/network/downloader.h @@ -35,7 +35,7 @@ namespace zyppng { * implementing Metalink on top. If in doubt which one to use, always * use this one. */ - class LIBZYPP_NG_EXPORT Downloader : public Base + class Downloader : public Base { ZYPP_DECLARE_PRIVATE( Downloader ) public: @@ -123,7 +123,7 @@ namespace zyppng { * \endcode * */ - class LIBZYPP_NG_EXPORT Download : public Base + class Download : public Base { ZYPP_DECLARE_PRIVATE( Download ) diff --git a/zypp-curl/ng/network/networkrequestdispatcher.h b/zypp-curl/ng/network/networkrequestdispatcher.h index eeedd87523..8f7ce7cfa1 100644 --- a/zypp-curl/ng/network/networkrequestdispatcher.h +++ b/zypp-curl/ng/network/networkrequestdispatcher.h @@ -74,7 +74,7 @@ namespace zyppng { * * \sa zyppng::Downloader */ - class LIBZYPP_NG_EXPORT NetworkRequestDispatcher : public Base + class NetworkRequestDispatcher : public Base { ZYPP_DECLARE_PRIVATE(NetworkRequestDispatcher) public: diff --git a/zypp-curl/ng/network/networkrequesterror.h b/zypp-curl/ng/network/networkrequesterror.h index 20cefbccf8..cd020c7b11 100644 --- a/zypp-curl/ng/network/networkrequesterror.h +++ b/zypp-curl/ng/network/networkrequesterror.h @@ -20,7 +20,7 @@ class NetworkRequestErrorPrivate; * * \attention Keep in sync with zypp/zyppng/proto/networkrequest.proto !!! */ - class LIBZYPP_NG_EXPORT NetworkRequestError + class NetworkRequestError { public: enum Type { diff --git a/zypp-curl/ng/network/private/downloaderstates/base_p.h b/zypp-curl/ng/network/private/downloaderstates/base_p.h index 0eac110544..a7bfb96c89 100644 --- a/zypp-curl/ng/network/private/downloaderstates/base_p.h +++ b/zypp-curl/ng/network/private/downloaderstates/base_p.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include namespace zyppng { @@ -93,7 +93,7 @@ namespace zyppng { std::shared_ptr _requestDispatcher; std::shared_ptr _mirrorControl; - zypp::media::CredentialManager::CredentialSet _credCache; //< the credential cache for this download + zyppng::media::CredentialManager::CredentialSet _credCache; //< the credential cache for this download DownloadSpec _spec; // the download settings mutable zypp::TriBool _specHasZckInfo = zypp::indeterminate; diff --git a/zypp-curl/ng/network/request.h b/zypp-curl/ng/network/request.h index f244cbf14b..2492875846 100644 --- a/zypp-curl/ng/network/request.h +++ b/zypp-curl/ng/network/request.h @@ -39,7 +39,7 @@ namespace zyppng { * After creating a NetworkRequest and changing the required settings is enqueued * to the \sa zyppng::NetworkRequestDispatcher. */ - class LIBZYPP_NG_EXPORT NetworkRequest : public Base + class NetworkRequest : public Base { public: diff --git a/zypp-curl/transfersettings.cc b/zypp-curl/transfersettings.cc index ad10640ed9..46d9225c1f 100644 --- a/zypp-curl/transfersettings.cc +++ b/zypp-curl/transfersettings.cc @@ -36,12 +36,12 @@ namespace zypp { public: Impl() : _useproxy( false ), - _timeout( MediaConfig::instance().download_transfer_timeout() ), - _connect_timeout( MediaConfig::instance().download_connect_timeout() ), - _maxConcurrentConnections( MediaConfig::instance().download_max_concurrent_connections() ), - _minDownloadSpeed(MediaConfig::instance().download_min_download_speed()), - _maxDownloadSpeed(MediaConfig::instance().download_max_download_speed()), - _maxSilentTries(MediaConfig::instance().download_max_silent_tries() ), + _timeout( MediaConfig::systemConfig().download_transfer_timeout() ), + _connect_timeout( MediaConfig::systemConfig().download_connect_timeout() ), + _maxConcurrentConnections( MediaConfig::systemConfig().download_max_concurrent_connections() ), + _minDownloadSpeed(MediaConfig::systemConfig().download_min_download_speed()), + _maxDownloadSpeed(MediaConfig::systemConfig().download_max_download_speed()), + _maxSilentTries(MediaConfig::systemConfig().download_max_silent_tries() ), _verify_host(false), _verify_peer(false), _ca_path("/etc/ssl/certs"), diff --git a/zypp-glib/CMakeLists.txt b/zypp-glib/CMakeLists.txt new file mode 100644 index 0000000000..80c5cae001 --- /dev/null +++ b/zypp-glib/CMakeLists.txt @@ -0,0 +1,169 @@ +PROJECT( zypp-glib C CXX ) +set (CMAKE_CXX_STANDARD 17) +SET (CMAKE_CXX_EXTENSIONS OFF) + +pkg_check_modules ( LIBGLIB REQUIRED glib-2.0 ) +INCLUDE_DIRECTORIES( ${LIBGLIB_INCLUDE_DIRS} ) + +pkg_check_modules ( LIBGOBJECT REQUIRED gobject-2.0 ) +INCLUDE_DIRECTORIES( ${LIBGOBJECT_INCLUDE_DIRS} ) + +pkg_check_modules ( LIBGIO REQUIRED gio-2.0 ) +INCLUDE_DIRECTORIES( ${LIBGIO_INCLUDE_DIRS} ) + +include(GObjectIntrospection) +include(GLibTools) + +# Collect all files that may contain translatable texts +FILE( GLOB_RECURSE POT_FILE_DEPENDS RELATIVE ${LIBZYPP_SOURCE_DIR} "*.h" "*.cc" ) +SET( POT_FILE_DEPENDS_ZYPP_GLIB ${POT_FILE_DEPENDS} PARENT_SCOPE ) + +INCLUDE_DIRECTORIES ( ${LIBZYPP_SOURCE_DIR} ${LIBZYPP_BINARY_DIR} ) + +ADD_DEFINITIONS( -DLOCALEDIR="${CMAKE_INSTALL_PREFIX}/share/locale" -DTEXTDOMAIN="zypp" -DZYPP_DLL ) + +SET( zypp_glib_HEADERS + application.h + context.h + error.h + expected.h + infobase.h + managedfile.h + progressobserver.h + repoinfo.h + repomanager.h + repository.h + serviceinfo.h + zypp-glib.h + +) + +SET( zypp_glib_ui_HEADERS + ui/booleanchoicerequest.h + ui/inputrequest.h + ui/listchoicerequest.h + ui/showmessagerequest.h + ui/userrequest.h + +) + +SET( zypp_glib_private_HEADERS + private/cancellable_p.h + private/context_p.h + private/error_p.h + private/expected_p.h + private/globals_p.h + private/infobase_p.h + private/managedfile_p.h + private/progressobserver_p.h + private/repoinfo_p.h + private/repomanager_p.h + private/repository_p.h + private/serviceinfo_p.h + private/callbacks/legacyreportreceiverbase.h + #private/callbacks/keyring.h + #private/callbacks/media.h + #private/callbacks/rpm.h + private/callbacks/repo.h + private/callbacks/job.h + ui/private/booleanchoicerequest_p.h + ui/private/inputrequest_p.h + ui/private/listchoicerequest_p.h + ui/private/showmessagerequest_p.h + ui/private/userrequest_p.h +) + +SET( zypp_glib_SRCS + application.cc + context.cc + error.cc + expected.cc + globals.cc + infobase.cc + managedfile.cc + progressobserver.cc + repoinfo.cc + repomanager.cc + repository.cc + serviceinfo.cc + zypp-glib.cc + private/cancellable_p.cc + ui/booleanchoicerequest.cc + ui/inputrequest.cc + ui/listchoicerequest.cc + ui/showmessagerequest.cc + ui/userrequest.cc +) + +glib_mkenums( zyppenums zyppenums.h.in zyppenums.c.in ${zypp_glib_HEADERS} ) +glib_mkenums( ui/zyppenums-ui ui/zyppenums-ui.h.in ui/zyppenums-ui.c.in ${zypp_glib_ui_HEADERS} ) + +INSTALL( FILES ${zypp_glib_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/zyppenums.h DESTINATION "${INCLUDE_INSTALL_DIR}/zypp-glib" ) +INSTALL( FILES ${zypp_glib_ui_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/ui/zyppenums-ui.h DESTINATION "${INCLUDE_INSTALL_DIR}/zypp-glib/ui" ) + +SET( zypp_glib_public_HEADERS ${zypp_glib_HEADERS} ${zypp_glib_ui_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/zyppenums.h ${CMAKE_CURRENT_BINARY_DIR}/ui/zyppenums-ui.h ) + +SET( zypp_glib_utils_HEADERS + utils/GLibMemory + utils/GList + utils/GObjectMemory + utils/GioMemory + utils/OpaqueTypePtr + utils/ResourcePtr + utils/RetainPtr +) + +SET( zypp_glib_utils_SRCS +) + +INSTALL( FILES ${zypp_glib_utils_HEADERS} DESTINATION "${INCLUDE_INSTALL_DIR}/zypp-glib/utils" ) + +SET( zypp_glib_lib_SRCS + ${zypp_glib_SRCS} + ${zypp_glib_utils_SRCS} + ${CMAKE_CURRENT_BINARY_DIR}/zyppenums.c + ${CMAKE_CURRENT_BINARY_DIR}/ui/zyppenums-ui.c +) + +SET( zypp_glib_lib_HEADERS + ${zypp_glib_private_HEADERS} + ${zypp_glib_HEADERS} + ${zypp_glib_ui_HEADERS} + ${zypp_glib_utils_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/zyppenums.h + ${CMAKE_CURRENT_BINARY_DIR}/ui/zyppenums-ui.h +) + +# Default loggroup for all files +SET_LOGGROUP( "zyppng" ${zypp_glib_lib_SRCS} ) + +ADD_LIBRARY( zypp-glib SHARED ${zypp_glib_lib_SRCS} ${zypp_glib_lib_HEADERS} ) +target_link_libraries( zypp-glib zypp_lib_compiler_flags ) +TARGET_LINK_LIBRARIES( zypp-glib zypp-allsym ) +target_link_libraries( zypp-glib ${LIBGOBJECT_LIBRARIES} ) +target_link_libraries( zypp-glib ${LIBGIO_LIBRARIES} ) + +INSTALL(TARGETS zypp-glib LIBRARY DESTINATION ${LIB_INSTALL_DIR} ) + +INCLUDE(GenerateExportHeader) +message("Exporting experimental libzypp-ng API") +GENERATE_EXPORT_HEADER( + zypp-glib + BASE_NAME zypp-glib + PREFIX_NAME LIB +) + +gobject_introspection( + FILENAME Zypp-1.0.gir + PACKAGES glib-2.0 gobject-2.0 gio-2.0 + NAMESPACE Zypp + LIBRARY zypp-glib + #QUIET + SCANNER_ARGS --add-include-path=${CMAKE_CURRENT_SOURCE_DIR} + --include=GLib-2.0 --include=GObject-2.0 --include=Gio-2.0 + COMPILER_ARGS --includedir=${CMAKE_CURRENT_SOURCE_DIR} + SYMBOL_PREFIXES zypp + SOURCES ${zypp_glib_public_HEADERS} + #BUILT_SOURCES ${zypp_glib_PUBLIC_BUILT_SOURCES} + # ${zypp_glib_PUBLIC_BUILT_HEADERS} +) diff --git a/zypp-glib/application.cc b/zypp-glib/application.cc new file mode 100644 index 0000000000..41f663a8b3 --- /dev/null +++ b/zypp-glib/application.cc @@ -0,0 +1,213 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#include "application.h" +#include "private/globals_p.h" + +#include +#include +#include + + +static void glogHandler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data); +static gpointer installLogHandler ( gpointer ); + +struct ZyppApplicationPrivate +{ + ZyppApplicationPrivate( ZyppApplication *pub ) { + static GOnce my_once = G_ONCE_INIT; + g_once( &my_once, installLogHandler, nullptr ); + } + + void initialize() { + if ( !_dispatcher ) { + _dispatcher = zyppng::ThreadData::current().ensureDispatcher(); + } + } + + void finalize() { /* Nothing to do atm */} + + + ZyppApplication *_gObject = nullptr; + zyppng::EventDispatcherRef _dispatcher; + std::string version = LIBZYPP_VERSION_STRING; +}; + +G_DEFINE_TYPE_WITH_PRIVATE( ZyppApplication, zypp_application, G_TYPE_OBJECT ) + +ZYPP_DECLARE_GOBJECT_BOILERPLATE( ZyppApplication, zypp_application ) +ZYPP_DEFINE_GOBJECT_BOILERPLATE ( ZyppApplication, zypp_application, ZYPP, APPLICATION ) + +#define ZYPP_APPLICATION_D() \ + auto d = zypp_application_get_private( self ) + +typedef enum +{ + PROP_EVENT_DISPATCHER = 1, + PROP_VERSION, + N_PROPERTIES +} ZyppApplicationProperty; + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +void zypp_application_class_init( ZyppApplicationClass *klass ) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + ZYPP_INIT_GOBJECT_BOILERPLATE_KLASS( zypp_application, object_class ); + + obj_properties[PROP_EVENT_DISPATCHER] = + g_param_spec_boxed ( "eventDispatcher", + "EventDispatcher", + "Libzypp Event Dispatcher.", + G_TYPE_MAIN_CONTEXT, + GParamFlags( G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE ) ); + + obj_properties[PROP_VERSION] = + g_param_spec_string ( "version", + "Version", + "Libzypp Library version.", + NULL /* default value */, + GParamFlags( G_PARAM_READABLE) ); + + g_object_class_install_properties (object_class, + N_PROPERTIES, + obj_properties); +} + +static void +zypp_application_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail( ZYPP_IS_APPLICATION(object) ); + ZyppApplication *self = ZYPP_APPLICATION (object); + + ZYPP_APPLICATION_D(); + + switch ((ZyppApplicationProperty)property_id ) + { + case PROP_EVENT_DISPATCHER: { + GMainContext *ctx = reinterpret_cast(g_value_get_boxed( value )); + + // this will take a reference of the context + if ( !d->_dispatcher ) d->_dispatcher = zyppng::ThreadData::current().ensureDispatcher( ctx ); + else MIL << "Ignoring GMainContext, dispatcher already initialized!" << std::endl; + + break; + } + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +zypp_application_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail( ZYPP_IS_APPLICATION(object) ); + ZyppApplication *self = ZYPP_APPLICATION (object); + + ZYPP_APPLICATION_D(); + + switch ((ZyppApplicationProperty)property_id ) + { + case PROP_EVENT_DISPATCHER: + g_value_set_boxed( value, d->_dispatcher->nativeDispatcherHandle() ); + break; + case PROP_VERSION: + g_value_set_string ( value, d->version.c_str() ); + break; + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +ZyppApplication *zypp_application_new( GMainContext *eventDispatcher ) +{ + if ( eventDispatcher ){ + GValue dispValue = G_VALUE_INIT; + g_value_init( &dispValue, G_TYPE_MAIN_CONTEXT ); + g_value_set_boxed ( &dispValue, eventDispatcher ); + return static_cast( g_object_new( ZYPP_TYPE_APPLICATION, "eventDispatcher", &dispValue, nullptr ) ); + } else { + return static_cast( g_object_new( ZYPP_TYPE_APPLICATION, nullptr ) ); + } +} + +GMainContext *zypp_application_get_dispatcher( ZyppApplication *self ) +{ + g_return_val_if_fail ( ZYPP_IS_APPLICATION(self), nullptr ); + ZYPP_APPLICATION_D(); + return d->_dispatcher->glibContext(); +} + +const gchar * zypp_application_get_version ( ZyppApplication *self ) +{ + g_return_val_if_fail( ZYPP_IS_APPLICATION(self), nullptr ); + ZYPP_APPLICATION_D(); + return d->version.c_str(); +} + +void zypp_application_set_user_data (ZyppApplication *self, const gchar *userData ) +{ + if ( !userData ) { + zyppng::UserData::setData( std::string() ); + return; + } + zyppng::UserData::setData ( zypp::str::asString (userData) ); +} + +gboolean zypp_application_has_user_data ( ZyppApplication *self ) +{ + return zyppng::UserData::hasData(); +} + +const gchar *zypp_application_get_user_data ( ZyppApplication *self ) +{ + return zyppng::UserData::data().c_str(); +} + + +static gpointer installLogHandler ( gpointer ) +{ + g_log_set_default_handler( glogHandler, nullptr ); + return nullptr; +} + +void glogHandler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer ) +{ + switch (log_level & G_LOG_LEVEL_MASK) { + case G_LOG_LEVEL_ERROR: + case G_LOG_LEVEL_CRITICAL: + ERR << log_domain << ":" << message << std::endl; + break; + case G_LOG_LEVEL_WARNING: + WAR << log_domain << ":" << message << std::endl; + break; + case G_LOG_LEVEL_MESSAGE: + MIL << log_domain << ":" << message << std::endl; + break; + case G_LOG_LEVEL_INFO: + XXX << log_domain << ":" << message << std::endl; + break; + case G_LOG_LEVEL_DEBUG: + DBG << log_domain << ":" << message << std::endl; + break; + default: + MIL << log_domain << "("<<(log_level & G_LOG_LEVEL_MASK)<<"):" << message << std::endl; + break; + } +} diff --git a/zypp-glib/application.h b/zypp-glib/application.h new file mode 100644 index 0000000000..fc20999c24 --- /dev/null +++ b/zypp-glib/application.h @@ -0,0 +1,111 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_APPLICATION_H +#define ZYPP_GLIB_APPLICATION_H + +/* + * The zyppng API library aims to provide a new set of APIs for the libzypp API which + * makes it possible to use libzypp from different programming languages and offers a + * more high level and stable API than the original library. + * + * In order to support using multiple languages, zyppng will leverage GObject and GIR technologies, + * featuring a pure glib based C API as described here: https://gi.readthedocs.io/en/latest/index.html + * + * The ultimate goal of this project is to function as the only officially supported API for compiling against + * zypp. Tools like zypper will be rewritten to use this API set. + * + * \code {.python} + * #!/usr/bin/env python3 + * + * import gi.repository + * + * # Set the search path to use the newly generated introspection files, only required if they are not in the default directories + * gi.require_version('GIRepository', '2.0') + * from gi.repository import GIRepository + * GIRepository.Repository.prepend_search_path('/home/zbenjamin/build/libzypp/zyppng') + * + * gi.require_version('Zypp', '1.0') + * from gi.repository import Zypp + * + * zyppApplication = Zypp.Application() + * context = Zypp.Context() + * print(context.version()) + * \endcode + */ + +#include +#include + +G_BEGIN_DECLS + +#define ZYPP_TYPE_APPLICATION (zypp_application_get_type ()) + +#pragma GCC visibility push(default) +G_DECLARE_DERIVABLE_TYPE ( ZyppApplication, zypp_application, ZYPP, APPLICATION, GObject ) +#pragma GCC visibility pop + +struct LIBZYPP_GLIB_EXPORT _ZyppApplicationClass { + GObjectClass parent_class; + gpointer padding[12]; +}; + +/** + * zypp_application_new: (constructor): + * @eventDispatcher: (transfer none) (nullable): The event dispatcher to use when running async code. + * + * Creates a new ZyppApplication instance, if there is already a existing instance this one is returned instead. + * If there is no event dispatcher passed to the constructor, one is created automatically. + * + * Returns: (transfer full): Reference to the new Application object + */ +ZyppApplication *zypp_application_new( GMainContext *eventDispatcher ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_application_get_dispatcher: + * + * Returns the internally used event dispatcher, this is at least valid as long as the Application + * instance is valid. + * + * Returns: (nullable) (transfer none): The event dispatcher used by zypp + */ +GMainContext *zypp_application_get_dispatcher( ZyppApplication *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_application_get_version: + * Returns: The libzypp version string + */ +const gchar * zypp_application_get_version ( ZyppApplication *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_application_set_user_data: + * @userData: (transfer none) (nullable): The userdata string + * + * Set's a user defined string to be passed to log, history, plugins. + * Passing a nullptr string clears the userdata + */ +void zypp_application_set_user_data ( ZyppApplication *self, const gchar *userData ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_application_has_user_data: + * + * Returns: True if a userdata string has been set + */ +gboolean zypp_application_has_user_data ( ZyppApplication *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_application_get_user_data: + * + * Returns: (transfer none) (nullable): The currently used userdata string, or NULL if none was set + */ +const gchar *zypp_application_get_user_data ( ZyppApplication *self ) LIBZYPP_GLIB_EXPORT; + +G_END_DECLS + + +#endif diff --git a/zypp-glib/context.cc b/zypp-glib/context.cc new file mode 100644 index 0000000000..0fa9f01a09 --- /dev/null +++ b/zypp-glib/context.cc @@ -0,0 +1,180 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#include "private/error_p.h" +#include "private/context_p.h" +#include "private/progressobserver_p.h" +#include +#include +#include +#include + +#include + +typedef enum +{ + PROP_CPPOBJ = 1, + N_PROPERTIES +} ZyppContextProperty; + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +#if 0 +/* Signals */ +typedef enum { + LAST_SIGNAL +} ZyppContextSignals; + +static guint signals[LAST_SIGNAL] = { 0, }; +#endif + +G_DEFINE_TYPE_WITH_PRIVATE(ZyppContext, zypp_context, G_TYPE_OBJECT) + +ZYPP_DECLARE_GOBJECT_BOILERPLATE( ZyppContext, zypp_context ) +ZYPP_DEFINE_GOBJECT_BOILERPLATE ( ZyppContext, zypp_context, ZYPP, CONTEXT ) + +#define ZYPP_CONTEXT_D() \ + auto d = zypp_context_get_private(self) + +void zypp_context_class_init( ZyppContextClass *klass ) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + ZYPP_INIT_GOBJECT_BOILERPLATE_KLASS( zypp_context, object_class ); + + obj_properties[PROP_CPPOBJ] = ZYPP_GLIB_ADD_CPPOBJ_PROP(); + + g_object_class_install_properties (object_class, + N_PROPERTIES, + obj_properties); +} + +void ZyppContextPrivate::initializeCpp() +{ + if ( _constructProps && _constructProps->_cppObj ) { + _context = std::move( _constructProps->_cppObj ); + } else { + _context = zyppng::AsyncContext::create(); + } + _constructProps.reset(); + + _signalConns.insert ( _signalConns.end(), { + _context->connectFunc( &zyppng::ContextBase::sigProgressObserverChanged, [this]() { + if ( _context->progressObserver () ) + _masterProgress = zypp::glib::zypp_wrap_cpp( _context->progressObserver ()); + else + _masterProgress = nullptr; + }) + }); + + if ( _context->progressObserver () ) + _masterProgress = zypp::glib::zypp_wrap_cpp( _context->progressObserver ()); + +} + +zyppng::AsyncContextRef &ZyppContextPrivate::cppType() +{ + return _context; +} + +static void +zypp_context_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail( ZYPP_IS_CONTEXT(object) ); + ZyppContext *self = ZYPP_CONTEXT (object); + + ZYPP_CONTEXT_D(); + + switch ((ZyppContextProperty)property_id ) + { + case PROP_CPPOBJ: + g_return_if_fail( d->_constructProps ); // only if the constr props are still valid + ZYPP_GLIB_SET_CPPOBJ_PROP( zyppng::AsyncContextRef, value, d->_constructProps->_cppObj ) + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +zypp_context_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail( ZYPP_IS_CONTEXT(object) ); + + switch ((ZyppContextProperty)property_id ) + { + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +zyppng::AsyncContextRef zypp_context_get_cpp( ZyppContext *self ) +{ + g_return_val_if_fail( ZYPP_CONTEXT(self), nullptr ); + ZYPP_CONTEXT_D(); + return d->_context; +} + +gboolean zypp_context_load_system (ZyppContext *self, const gchar *sysRoot , GError **error) +{ + g_return_val_if_fail( ZYPP_CONTEXT(self), false ); + ZYPP_CONTEXT_D(); + + zyppng::ContextSettings set; + if ( sysRoot ) + set.root = zypp::asString(sysRoot); + + try { + d->_context->initialize( std::move(set) ).unwrap(); + return true; + } catch ( ... ) { + zypp_error_from_exception ( error, std::current_exception () ); + } + + return false; +} + +gchar * zypp_context_sysroot ( ZyppContext *self ) +{ + g_return_val_if_fail( ZYPP_CONTEXT(self), nullptr ); + ZYPP_CONTEXT_D(); + return g_strdup ( d->_context->contextRoot().c_str() ); +} + +ZyppProgressObserver *zypp_context_get_progress_observer( ZyppContext *self ) +{ + g_return_val_if_fail( ZYPP_CONTEXT(self), nullptr ); + ZYPP_CONTEXT_D(); + return d->_masterProgress.get(); +} + +void zypp_context_set_progress_observer( ZyppContext *self, ZyppProgressObserver *obs ) +{ + g_return_if_fail( ZYPP_CONTEXT(self) ); + ZYPP_CONTEXT_D(); + if ( obs ) + d->_context->setProgressObserver ( zypp_progress_observer_get_cpp (obs) ); + else + d->_context->resetProgressObserver (); +} + +void zypp_context_reset_progress_observer( ZyppContext *self ) +{ + g_return_if_fail( ZYPP_CONTEXT(self) ); + ZYPP_CONTEXT_D(); + d->_context->resetProgressObserver(); +} diff --git a/zypp-glib/context.h b/zypp-glib/context.h new file mode 100644 index 0000000000..173310e00f --- /dev/null +++ b/zypp-glib/context.h @@ -0,0 +1,99 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_CONTEXT_H +#define ZYPP_GLIB_CONTEXT_H + +#include +#include + +G_BEGIN_DECLS + +typedef struct _ZyppProgressObserver ZyppProgressObserver; + +/** + * ZyppContext: + * + * This class is the basic building block for the zypp glib API. It defines the path of the + * root filesystem we are operating on. This is usually "/" but to support chroot use cases it + * can point to any directory in a filesystem where packages should be installed into. If the rootfs + * is not defined as "/" then zypp will install packages using chroot into the directory. + * + * Settings for zypp are loaded from the rootfs directory and locks are also applied relative to it. + * Meaning that one context can operate on "/" while another one can operate on "/tmp/rootfs". + */ + + +/** + * ZyppContext: glibContext: (transfer full) + * + * The glib main context zypper should use to execute async code, if not given zypp + * will create its own context. + */ + + +/** + * ZyppContext: cppObj: (skip) + */ + +#define ZYPP_TYPE_CONTEXT (zypp_context_get_type ()) + +#pragma GCC visibility push(default) +G_DECLARE_FINAL_TYPE ( ZyppContext, zypp_context, ZYPP, CONTEXT, GObject ) +#pragma GCC visibility pop + +/** + * zypp_context_load_system: + * @sysRoot: (nullable): The system sysroot to load, if a nullptr is given "/" is used + * + * Loads the system at the given sysroot, returns TRUE on success, otherwise FALSE + */ +gboolean zypp_context_load_system ( ZyppContext *self, const gchar *sysRoot, GError **error ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_context_sysroot: + * + * Returns: (transfer full) (nullable): The context root as requested when loading the system + */ +gchar *zypp_context_sysroot( ZyppContext *self ) LIBZYPP_GLIB_EXPORT; + + +/** + * zypp_context_get_progress_observer: + * + * Returns: (transfer full) (nullable): The currently used progress observer, or NULL if there was none registered. + */ +ZyppProgressObserver *zypp_context_get_progress_observer( ZyppContext *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_context_set_progress_observer: + * + * Sets the progress observer, this is where libzypp will generate progress and callback messages. + * The context will hold a strong reference to the observer until it is resettet. + */ +void zypp_context_set_progress_observer( ZyppContext *self, ZyppProgressObserver *obs ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_context_reset_progress_observer: + * + * Clears the reference to the current progress observer, code will not be able to generate task information + * for new tasks anymore, already running code however might still hold a reference to it. + */ +void zypp_context_reset_progress_observer( ZyppContext *self ) LIBZYPP_GLIB_EXPORT; + + + +G_END_DECLS + +#ifdef __cplusplus + +#include +ZYPP_DEFINE_GOBJECT_SIMPLE( ZyppContext, zypp_context, ZYPP, CONTEXT ) +#endif + +#endif // ZYPP_GLIB_CONTEXT_H diff --git a/zypp-glib/error.cc b/zypp-glib/error.cc new file mode 100644 index 0000000000..5d85c94a22 --- /dev/null +++ b/zypp-glib/error.cc @@ -0,0 +1,84 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "error.h" +#include +#include +#include + +#include + +typedef struct +{ + zypp::Exception e; +} ZyppErrorPrivate; + +static void +zypp_error_private_init ( ZyppErrorPrivate *priv ) +{ + new (priv) ZyppErrorPrivate(); +} + +static void +zypp_error_private_copy (const ZyppErrorPrivate *src_priv, ZyppErrorPrivate *dest_priv) +{ + *dest_priv = *src_priv; +} + +static void +zypp_error_private_clear (ZyppErrorPrivate *priv) +{ + priv->~ZyppErrorPrivate(); +} + +// This defines the zypp_error_get_private and zypp_error_quark functions. +G_DEFINE_EXTENDED_ERROR (ZyppError, zypp_error) + +GList *zypp_error_get_history (GError *error) +{ + ZyppErrorPrivate *priv = zypp_error_get_private (error); + g_return_val_if_fail (priv != NULL, NULL); + // g_return_val_if_fail (error->code != MY_ERROR_BAD_REQUEST, NULL); + + zypp::glib::GCharContainer res; + for ( auto i = priv->e.historyBegin (); i != priv->e.historyEnd (); i++ ) { + res.push_back ( g_strdup( (*i).c_str ()) ); + } + return res.take(); +} + +void zypp_error_from_exception ( GError **err, std::exception_ptr exception ) +{ + try { + std::rethrow_exception (exception); + } catch ( const zypp::Exception &e ) { + ZyppErrorPrivate *priv; + g_set_error (err, ZYPP_ERROR, ZYPP_ERROR_GENERIC, "%s", e.msg ().c_str() ); + if (err != nullptr && *err != nullptr) { + priv = zypp_error_get_private (*err); + g_return_if_fail ( priv != nullptr ); + priv->e = e; + } + } catch ( std::exception &e ) { + ZyppErrorPrivate *priv; + g_set_error (err, ZYPP_ERROR, ZYPP_ERROR_GENERIC, "%s", e.what() ); + if (err != nullptr && *err != nullptr) { + priv = zypp_error_get_private (*err); + g_return_if_fail ( priv != nullptr ); + priv->e = zypp::Exception( e.what() ); + } + } catch ( ... ) { + ZyppErrorPrivate *priv; + g_set_error (err, ZYPP_ERROR, ZYPP_ERROR_GENERIC, "Unknown exception." ); + if (err != nullptr && *err != nullptr) { + priv = zypp_error_get_private (*err); + g_return_if_fail ( priv != nullptr ); + priv->e = zypp::Exception( "Unknown exception" ); + } + } +} diff --git a/zypp-glib/error.h b/zypp-glib/error.h new file mode 100644 index 0000000000..3dd09d99fb --- /dev/null +++ b/zypp-glib/error.h @@ -0,0 +1,47 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_ERROR_H +#define ZYPP_GLIB_ERROR_H + +#include +#include + +G_BEGIN_DECLS + +/** + * ZYPP_ERROR: + * + * Error domain for the zypp exception handling. Errors in this domain will + * be from the #ZyppError enumeration. See #GError for information + * on error domains. +*/ +#define ZYPP_ERROR zypp_error_quark () + +/** + * ZyppError: + * @ZYPP_ERROR_GENERIC: Generic Error that happend in the zypp API, check error string for details + */ +typedef enum +{ + ZYPP_ERROR_GENERIC +} ZyppError; + +GQuark zypp_error_quark () LIBZYPP_GLIB_EXPORT; + + +/** + * zypp_error_get_history: + * + * Returns: (element-type gchar) (transfer full) (nullable): the history strings from the exception + */ +GList * zypp_error_get_history (GError *error) LIBZYPP_GLIB_EXPORT; + +G_END_DECLS + +#endif // ZYPP_GLIB_ERROR_H diff --git a/zypp-glib/expected.cc b/zypp-glib/expected.cc new file mode 100644 index 0000000000..9d9cad2687 --- /dev/null +++ b/zypp-glib/expected.cc @@ -0,0 +1,81 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#include "private/expected_p.h" + +G_DEFINE_TYPE(ZyppExpected, zypp_expected, G_TYPE_OBJECT) + +static void +zypp_expected_finalize (GObject *object) +{ + auto self = ZYPP_EXPECTED(object); + if (zypp_expected_has_value(self)) { + g_value_unset ( &self->value ); + } else { + if ( self->error ) + g_error_free( self->error ); + } + G_OBJECT_CLASS (zypp_expected_parent_class)->finalize (object); +} + +static void +zypp_expected_class_init (ZyppExpectedClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = zypp_expected_finalize; +} + +static void zypp_expected_init (ZyppExpected *self) +{ + self->value = G_VALUE_INIT; + self->error = nullptr; +} + +ZyppExpected *zypp_expected_new_value( const GValue *value ) +{ + ZyppExpected *self = ZYPP_EXPECTED(g_object_new (ZYPP_TYPE_EXPECTED, NULL)); + g_value_init(&self->value, G_VALUE_TYPE(value)); + g_value_copy(value, &self->value); + return self; +} + +ZyppExpected *zypp_expected_new_error(GError *error) +{ + ZyppExpected *self = ZYPP_EXPECTED(g_object_new (ZYPP_TYPE_EXPECTED, NULL)); + self->error = error; + return self; +} + +gboolean zypp_expected_has_value(ZyppExpected *self) +{ + return self->error == NULL; +} + +const GError *zypp_expected_get_error(ZyppExpected *self) +{ + if ( !self->error ) + return nullptr; + + return self->error; +} + +const GValue *zypp_expected_get_value( ZyppExpected *self, GError **error ) +{ + if ( !zypp_expected_has_value (self ) ) { + if ( error && self->error ) *error = g_error_copy ( self->error ); + return nullptr; + } + return &self->value; +} + +gboolean zypp_expected_has_error(ZyppExpected *self) +{ + return self->error != NULL; +} diff --git a/zypp-glib/expected.h b/zypp-glib/expected.h new file mode 100644 index 0000000000..da1302699c --- /dev/null +++ b/zypp-glib/expected.h @@ -0,0 +1,65 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_EXPECTED_H +#define ZYPP_GLIB_EXPECTED_H + +#include +#include +#include + +G_BEGIN_DECLS + +typedef struct _ZyppExpected ZyppExpected; + +#define ZYPP_TYPE_EXPECTED (zypp_expected_get_type ()) + +#pragma GCC visibility push(default) +G_DECLARE_FINAL_TYPE ( ZyppExpected, zypp_expected, ZYPP, EXPECTED, GObject ) +#pragma GCC visibility pop + +/** + * zypp_expected_new_value: (constructor) + * + * Creates a new ZyppExcpected containing a value + */ +ZyppExpected *zypp_expected_new_value( const GValue *value ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_expected_new_error: (constructor) + * + * Creates a new ZyppExcpected containing a error + */ +ZyppExpected *zypp_expected_new_error(GError *error) LIBZYPP_GLIB_EXPORT; + +gboolean zypp_expected_has_value(ZyppExpected *self) LIBZYPP_GLIB_EXPORT; +gboolean zypp_expected_has_error(ZyppExpected *self) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_expected_get_error: + * + * Returns: (transfer none) (nullable): The error or NULL if there is no error + */ +const GError *zypp_expected_get_error(ZyppExpected *self) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_expected_get_value: + * + * Returns: (transfer none) (nullable): The value or NULL if there is none or a error + */ +const GValue *zypp_expected_get_value( ZyppExpected *self, GError **error ) LIBZYPP_GLIB_EXPORT; + +G_END_DECLS + +#ifdef __cplusplus + +#include +ZYPP_DEFINE_GOBJECT_SIMPLE( ZyppExpected, zypp_expected, ZYPP, EXPECTED ) +#endif + +#endif diff --git a/zypp-glib/globals.cc b/zypp-glib/globals.cc new file mode 100644 index 0000000000..95ee0720d0 --- /dev/null +++ b/zypp-glib/globals.cc @@ -0,0 +1,27 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#include "private/globals_p.h" +#include + +void zypp::glib::internal::registerWrapper(const zyppng::BaseRef &ref, GObject *wrapper) +{ + if ( ref->data ( ZYPP_WRAPPED_OBJ ) != nullptr ) + g_error( "Overriding a existing wrapper, this is a bug!" ); + ref->setData( ZYPP_WRAPPED_OBJ, zypp::AutoDispose(static_cast(wrapper)) ); +} + +void zypp::glib::internal::unregisterWrapper(const zyppng::BaseRef &ref, GObject *wrapper) +{ + if ( !ref ) return; + if ( ref->data ( ZYPP_WRAPPED_OBJ ) == wrapper ) + ref->clearData ( ZYPP_WRAPPED_OBJ ); +} + +G_DEFINE_QUARK(zypp-wrapped-obj-quark, zypp_wrapped_obj) diff --git a/zypp-glib/infobase.cc b/zypp-glib/infobase.cc new file mode 100644 index 0000000000..8a4a925737 --- /dev/null +++ b/zypp-glib/infobase.cc @@ -0,0 +1,101 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/* zypp-info-base.c */ + +#include "infobase.h" + +G_DEFINE_INTERFACE (ZyppInfoBase, zypp_info_base, G_TYPE_OBJECT) +static void zypp_info_base_default_init ( ZyppInfoBaseInterface *g_class ) +{ + /* add properties and signals to the interface here */ +} + +gchar *zypp_info_base_alias ( ZyppInfoBase *self ) +{ + g_return_val_if_fail (ZYPP_IS_INFO_BASE (self), nullptr); + return ZYPP_INFO_BASE_GET_IFACE (self)->alias( self ); +} + +gchar* zypp_info_base_escaped_alias (ZyppInfoBase *self) +{ + g_return_val_if_fail (ZYPP_IS_INFO_BASE (self), nullptr); + return ZYPP_INFO_BASE_GET_IFACE (self)->escaped_alias( self ); +} + +gchar* zypp_info_base_name (ZyppInfoBase *self) +{ + g_return_val_if_fail (ZYPP_IS_INFO_BASE (self), nullptr); + return ZYPP_INFO_BASE_GET_IFACE (self)->name( self ); +} + +gchar* zypp_info_base_raw_name (ZyppInfoBase *self) +{ + g_return_val_if_fail (ZYPP_IS_INFO_BASE (self), nullptr); + return ZYPP_INFO_BASE_GET_IFACE (self)->raw_name( self ); +} + +gchar* zypp_info_base_label (ZyppInfoBase *self) +{ + g_return_val_if_fail (ZYPP_IS_INFO_BASE (self), nullptr); + return ZYPP_INFO_BASE_GET_IFACE (self)->label( self ); +} + +gchar* zypp_info_base_as_user_string (ZyppInfoBase *self) +{ + g_return_val_if_fail (ZYPP_IS_INFO_BASE (self), nullptr); + return ZYPP_INFO_BASE_GET_IFACE (self)->as_user_string( self ); +} + +gboolean zypp_info_base_enabled (ZyppInfoBase *self) +{ + g_return_val_if_fail (ZYPP_IS_INFO_BASE (self), false); + return ZYPP_INFO_BASE_GET_IFACE (self)->enabled( self ); +} + +gboolean zypp_info_base_autorefresh (ZyppInfoBase *self) +{ + g_return_val_if_fail (ZYPP_IS_INFO_BASE (self), false); + return ZYPP_INFO_BASE_GET_IFACE (self)->autorefresh( self ); +} + +gchar* zypp_info_base_filepath (ZyppInfoBase *self) +{ + g_return_val_if_fail (ZYPP_IS_INFO_BASE (self), nullptr); + return ZYPP_INFO_BASE_GET_IFACE (self)->filepath( self ); +} + +void zypp_info_base_set_alias ( ZyppInfoBase *self, const gchar* alias ) +{ + g_return_if_fail (ZYPP_IS_INFO_BASE (self) ); + ZYPP_INFO_BASE_GET_IFACE (self)->set_alias( self, alias ); +} + +void zypp_info_base_set_name (ZyppInfoBase *self, const gchar *name ) +{ + g_return_if_fail (ZYPP_IS_INFO_BASE (self) ); + ZYPP_INFO_BASE_GET_IFACE (self)->set_name( self, name ); +} + +void zypp_info_base_set_enabled (ZyppInfoBase *self, gboolean enabled ) +{ + g_return_if_fail (ZYPP_IS_INFO_BASE (self) ); + ZYPP_INFO_BASE_GET_IFACE (self)->set_enabled( self, enabled ); +} + +void zypp_info_base_set_autorefresh (ZyppInfoBase *self, gboolean enabled ) +{ + g_return_if_fail (ZYPP_IS_INFO_BASE (self) ); + ZYPP_INFO_BASE_GET_IFACE (self)->set_autorefresh( self, enabled ); +} + +void zypp_info_base_set_filepath (ZyppInfoBase *self, const gchar* filepath ) +{ + g_return_if_fail (ZYPP_IS_INFO_BASE (self) ); + ZYPP_INFO_BASE_GET_IFACE (self)->set_filepath( self, filepath ); +} diff --git a/zypp-glib/infobase.h b/zypp-glib/infobase.h new file mode 100644 index 0000000000..dce8aedef8 --- /dev/null +++ b/zypp-glib/infobase.h @@ -0,0 +1,56 @@ +/* zypp-info-base.h */ + +#ifndef _ZYPP_INFO_BASE_H +#define _ZYPP_INFO_BASE_H + +#include +#include + +G_BEGIN_DECLS + +#define ZYPP_TYPE_INFO_BASE (zypp_info_base_get_type()) + +#pragma GCC visibility push(default) +G_DECLARE_INTERFACE (ZyppInfoBase, zypp_info_base, ZYPP, INFO_BASE, GObject) +#pragma GCC visibility pop + +struct LIBZYPP_GLIB_EXPORT _ZyppInfoBaseInterface +{ + GTypeInterface parent_iface; + + gchar* (*alias) (ZyppInfoBase *self); + gchar* (*escaped_alias) (ZyppInfoBase *self); + gchar* (*name) (ZyppInfoBase *self); + gchar* (*raw_name) (ZyppInfoBase *self); + gchar* (*label) (ZyppInfoBase *self); + gchar* (*as_user_string) (ZyppInfoBase *self); + gboolean (*enabled) (ZyppInfoBase *self); + gboolean (*autorefresh) (ZyppInfoBase *self); + gchar* (*filepath) (ZyppInfoBase *self); + + void (*set_alias) ( ZyppInfoBase *self, const gchar* alias ); + void (*set_name) (ZyppInfoBase *self, const gchar *name ); + void (*set_enabled) (ZyppInfoBase *self, gboolean enabled ); + void (*set_autorefresh) (ZyppInfoBase *self, gboolean enabled ); + void (*set_filepath) (ZyppInfoBase *self, const gchar* filepath ); +}; + +gchar* zypp_info_base_alias (ZyppInfoBase *self) LIBZYPP_GLIB_EXPORT; +gchar* zypp_info_base_escaped_alias (ZyppInfoBase *self) LIBZYPP_GLIB_EXPORT; +gchar* zypp_info_base_name (ZyppInfoBase *self) LIBZYPP_GLIB_EXPORT; +gchar* zypp_info_base_raw_name (ZyppInfoBase *self) LIBZYPP_GLIB_EXPORT; +gchar* zypp_info_base_label (ZyppInfoBase *self) LIBZYPP_GLIB_EXPORT; +gchar* zypp_info_base_as_user_string (ZyppInfoBase *self) LIBZYPP_GLIB_EXPORT; +gboolean zypp_info_base_enabled (ZyppInfoBase *self) LIBZYPP_GLIB_EXPORT; +gboolean zypp_info_base_autorefresh (ZyppInfoBase *self) LIBZYPP_GLIB_EXPORT; +gchar* zypp_info_base_filepath ( ZyppInfoBase *self ) LIBZYPP_GLIB_EXPORT; + +void zypp_info_base_set_alias ( ZyppInfoBase *self, const gchar* alias ) LIBZYPP_GLIB_EXPORT; +void zypp_info_base_set_name (ZyppInfoBase *self, const gchar *name ) LIBZYPP_GLIB_EXPORT; +void zypp_info_base_set_enabled (ZyppInfoBase *self, gboolean enabled ) LIBZYPP_GLIB_EXPORT; +void zypp_info_base_set_autorefresh (ZyppInfoBase *self, gboolean enabled ) LIBZYPP_GLIB_EXPORT; +void zypp_info_base_set_filepath (ZyppInfoBase *self, const gchar* filepath ) LIBZYPP_GLIB_EXPORT; + +G_END_DECLS + +#endif /* _ZYPP_INFO_BASE_H */ diff --git a/zypp-glib/managedfile.cc b/zypp-glib/managedfile.cc new file mode 100644 index 0000000000..e6ae834b18 --- /dev/null +++ b/zypp-glib/managedfile.cc @@ -0,0 +1,56 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#include "private/managedfile_p.h" +#include +#include +#include + +ZyppManagedFile *zypp_managed_file_new( const gchar *path, gboolean dispose ) +{ + std::unique_ptr ptr( new ZyppManagedFile() ); + ptr->_file = zypp::ManagedFile( zypp::Pathname(path) ); + if ( dispose ) + ptr->_file.setDispose( zypp::filesystem::unlink ); + + return ptr.release(); +} + +ZyppManagedFile * zypp_managed_file_copy ( ZyppManagedFile *r ) +{ + return zypp_managed_file_new( r->_file ); +} + +void zypp_managed_file_free ( ZyppManagedFile *r ) +{ + delete r; +} + +G_DEFINE_BOXED_TYPE (ZyppManagedFile, zypp_managed_file, + zypp_managed_file_copy, + zypp_managed_file_free) + + +ZyppManagedFile *zypp_managed_file_new( const zypp::ManagedFile &f ) +{ + return (new _ZyppManagedFile{f}); +} + +void zypp_managed_file_set_dispose_enabled( ZyppManagedFile *self, gboolean enabled ) +{ + if ( enabled ) + self->_file.setDispose( zypp::filesystem::unlink ); + else + self->_file.resetDispose(); +} + +gchar *zypp_managed_file_get_path( ZyppManagedFile *self ) +{ + return g_strdup( self->_file->c_str() ); +} diff --git a/zypp-glib/managedfile.h b/zypp-glib/managedfile.h new file mode 100644 index 0000000000..e33d5a86bf --- /dev/null +++ b/zypp-glib/managedfile.h @@ -0,0 +1,63 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#ifndef ZYPP_GLIB_MANAGEDFILE_H +#define ZYPP_GLIB_MANAGEDFILE_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define ZYPP_TYPE_MANAGED_FILE (zypp_managed_file_get_type()) + +typedef struct _ZyppManagedFile ZyppManagedFile; + +GType zypp_managed_file_get_type (void) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_managed_file_new: (constructor): + * @path: (in): The path of the file we want to manage + * @dispose: If set to true the file is cleaned up when the #ZyppManagedFile gets out of scope + */ +ZyppManagedFile *zypp_managed_file_new( const gchar *path, gboolean dispose ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_managed_file_copy: (skip): + * + * Copy the boxed type + */ +ZyppManagedFile * zypp_managed_file_copy ( ZyppManagedFile *r ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_managed_file_free: (skip): + * + * Free the boxed type + */ +void zypp_managed_file_free ( ZyppManagedFile *r ) LIBZYPP_GLIB_EXPORT; + + +/** + * zypp_managed_file_set_dispose_enabled: + * + * Enables or disables dispose for this object + */ +void zypp_managed_file_set_dispose_enabled( ZyppManagedFile *self, gboolean enabled ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_managed_file_get_path: + * + * Returns: (transfer full): The currently managed path + */ +gchar *zypp_managed_file_get_path( ZyppManagedFile *self ) LIBZYPP_GLIB_EXPORT; + +G_END_DECLS + +#endif // ZYPP_GLIB_MANAGEDFILE_H diff --git a/zypp-glib/private/callbacks/job.h b/zypp-glib/private/callbacks/job.h new file mode 100644 index 0000000000..6ed2121636 --- /dev/null +++ b/zypp-glib/private/callbacks/job.h @@ -0,0 +1,62 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#ifndef ZYPP_GLIB_ZMART_JOB_CALLBACKS_H +#define ZYPP_GLIB_ZMART_JOB_CALLBACKS_H + +#include + +#include +#include +#include + +#include +#include +#include + + +namespace zyppng +{ + /** + * \class JobReportReceiver + * \brief Receive generic notification callbacks + */ + struct JobReportReceiver : public zypp::callback::ReceiveReport + { + JobReportReceiver( SyncContextRef ctx ) : _ctx( std::move(ctx)) { + if ( !ctx ) ZYPP_THROW( zypp::Exception("Context can not be null for JobReportReceiver") ); + } + + bool message( MsgType type_r, const std::string & msg_r, const UserData & userData_r ) const override + { + JobReportHelper helper( _ctx ); + switch ( type_r.asEnum() ) + { + case MsgType::debug: + return helper.debug ( msg_r, userData_r ); + case MsgType::info: + return helper.info ( msg_r, userData_r ); + case MsgType::warning: + return helper.warning ( msg_r, userData_r ); + case MsgType::error: + return helper.error ( msg_r, userData_r ); + case MsgType::important: + return helper.important ( msg_r, userData_r ); + case MsgType::data: + return helper.data ( msg_r, userData_r ); + } + return true; + } + + private: + SyncContextRef _ctx; + }; +} // namespace zyppng + +#endif // ZYPP_GLIB_ZMART_JOB_CALLBACKS_H diff --git a/zypp-glib/private/callbacks/keyring.h b/zypp-glib/private/callbacks/keyring.h new file mode 100644 index 0000000000..e573a36dfc --- /dev/null +++ b/zypp-glib/private/callbacks/keyring.h @@ -0,0 +1,275 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ + +#ifndef ZYPP_GLIB_ZMART_KEYRINGCALLBACKS_H +#define ZYPP_GLIB_ZMART_KEYRINGCALLBACKS_H + +#include +#include +#include +#include +#include + + +namespace zypp +{ + struct KeyRingReceive : public callback::ReceiveReport + { + KeyRingReceive() {} + + //////////////////////////////////////////////////////////////////// + + virtual void infoVerify( const std::string & file_r, const PublicKeyData & keyData_r, const KeyContext & context = KeyContext() ) + { + + } + + //////////////////////////////////////////////////////////////////// + virtual bool askUserToAcceptUnsignedFile( + const std::string & file, const KeyContext & context) + { + + } + + //////////////////////////////////////////////////////////////////// + + virtual bool askUserToAcceptUnknownKey( + const std::string & file, + const std::string & id, + const KeyContext & context) + { + + } + + virtual KeyRingReport::KeyTrust askUserToAcceptKey( + const PublicKey &key, const KeyContext & context) + { + return askUserToAcceptKey( key, context, true ); + } + + KeyRingReport::KeyTrust askUserToAcceptKey( + const PublicKey &key_r, const KeyContext & context_r, bool canTrustTemporarily_r ) + { + return KeyRingReport::KEY_DONT_TRUST; + } + + //////////////////////////////////////////////////////////////////// + + virtual bool askUserToAcceptVerificationFailed( + const std::string & file, + const PublicKey & key, + const KeyContext & context ) + { + } + + //////////////////////////////////////////////////////////////////// + + virtual void report ( const UserData & data ) + { + if ( data.type() == zypp::ContentType( KeyRingReport::ACCEPT_PACKAGE_KEY_REQUEST ) ) + return askUserToAcceptPackageKey( data ); + else if ( data.type() == zypp::ContentType( KeyRingReport::KEYS_NOT_IMPORTED_REPORT ) ) + return reportKeysNotImportedReport( data ); + else if ( data.type() == zypp::ContentType( KeyRingReport::REPORT_AUTO_IMPORT_KEY ) ) + return reportAutoImportKey( data ); + WAR << "Unhandled report() call" << std::endl; + } + + void askUserToAcceptPackageKey( const UserData & data ) + { + if ( !data.hasvalue("PublicKey") || !data.hasvalue(("KeyContext")) ) { + WAR << "Missing arguments in report call for content type: " << data.type() << std::endl; + return; + } + const PublicKey &key = data.get("PublicKey"); + const KeyContext &ctx = data.get("KeyContext"); + KeyRingReport::KeyTrust res = askUserToAcceptKey(key,ctx, false); + data.set("TrustKey", res == KeyRingReport::KEY_TRUST_AND_IMPORT); + return; + } + + void reportKeysNotImportedReport( const UserData & data ) + { + if ( !data.hasvalue("Keys") ) + { + WAR << "Missing arguments in report call for content type: " << data.type() << endl; + return; + } + Zypper & zypper = Zypper::instance(); + + zypper.out().notePar(_("The rpm database seems to contain old V3 version gpg keys which are meanwhile obsolete and considered insecure:") ); + + zypper.out().gap(); + for ( const Edition & ed : data.get( "Keys", std::set() ) ) + zypper.out().info( str::Str() << /*indent8*/" gpg-pubkey-" << ed ); + + Zypper::instance().out().par( 4, + str::Format(_("To see details about a key call '%1%'.") ) + % "rpm -qi GPG-PUBKEY-VERSION" ); + + Zypper::instance().out().par( 4, + str::Format(_("Unless you believe the key in question is still in use, you can remove it from the rpm database calling '%1%'.") ) + % "rpm -e GPG-PUBKEY-VERSION" ); + + zypper.out().gap(); + } + + void reportAutoImportKey( const UserData & data_r ) + { + if ( not ( data_r.hasvalue("KeyDataList") && data_r.hasvalue("KeySigning") && data_r.hasvalue("KeyContext") ) ) { + WAR << "Missing arguments in report call for content type: " << data_r.type() << endl; + return; + } + const std::list & keyDataList { data_r.get>("KeyDataList") }; + const PublicKeyData & keySigning { data_r.get("KeySigning") }; + const KeyContext & context { data_r.get("KeyContext") }; + + zypper.out().par( 2,_("Those additional keys are usually used to sign packages shipped by the repository. In order to validate those packages upon download and installation the new keys will be imported into the rpm database.") ); + + auto newTag { HIGHLIGHTString(_("New:") ) }; + for ( const auto & kd : keyDataList ) { + zypper.out().gap(); + dumpKeyInfo( std::cout << " " << newTag << endl, kd ); + } + + zypper.out().par( 2,HIGHLIGHTString(_("The repository metadata introducing the new keys have been signed and validated by the trusted key:")) ); + zypper.out().gap(); + dumpKeyInfo( std::cout, keySigning, context ); + + zypper.out().gap(); + } + + private: + const Config & _gopts; + }; + + /////////////////////////////////////////////////////////////////// + // DigestReceive + /////////////////////////////////////////////////////////////////// + + struct DigestReceive : public callback::ReceiveReport + { + DigestReceive() : _gopts(Zypper::instance().config()) {} + + //////////////////////////////////////////////////////////////////// + + virtual bool askUserToAcceptNoDigest( const Pathname &file ) + { + std::string question = (str::Format(_("No digest for file %s.")) % file).str() + " " + text::qContinue(); + return read_bool_answer(PROMPT_GPG_NO_DIGEST_ACCEPT, question, _gopts.no_gpg_checks); + } + + //////////////////////////////////////////////////////////////////// + + virtual bool askUserToAccepUnknownDigest( const Pathname &file, const std::string &name ) + { + std::string question = (str::Format(_("Unknown digest %s for file %s.")) %name % file).str() + " " + text::qContinue(); + return read_bool_answer(PROMPT_GPG_UNKNOWN_DIGEST_ACCEPT, question, _gopts.no_gpg_checks); + } + + //////////////////////////////////////////////////////////////////// + + virtual bool askUserToAcceptWrongDigest( const Pathname &file, const std::string &requested, const std::string &found ) + { + Zypper & zypper = Zypper::instance(); + std::string unblock( found.substr( 0, 4 ) ); + + zypper.out().gap(); + // translators: !!! BOOST STYLE PLACEHOLDERS ( %N% - reorder and multiple occurrence is OK ) + // translators: %1% - a file name + // translators: %2% - full path name + // translators: %3%, %4% - checksum strings (>60 chars), please keep them aligned + zypper.out().warning( str::Format(_( + "Digest verification failed for file '%1%'\n" + "[%2%]\n" + "\n" + " expected %3%\n" + " but got %4%\n" ) ) + % file.basename() + % file + % requested + % found + ); + + zypper.out().info( MSG_WARNINGString(_( + "Accepting packages with wrong checksums can lead to a corrupted system " + "and in extreme cases even to a system compromise." ) ).str() + ); + zypper.out().gap(); + + // translators: !!! BOOST STYLE PLACEHOLDERS ( %N% - reorder and multiple occurrence is OK ) + // translators: %1% - abbreviated checksum (4 chars) + zypper.out().info( str::Format(_( + "However if you made certain that the file with checksum '%1%..' is secure, correct\n" + "and should be used within this operation, enter the first 4 characters of the checksum\n" + "to unblock using this file on your own risk. Empty input will discard the file.\n" ) ) + % unblock + ); + + // translators: A prompt option + PromptOptions popts( unblock+"/"+_("discard"), 1 ); + // translators: A prompt option help text + popts.setOptionHelp( 0, _("Unblock using this file on your own risk.") ); + // translators: A prompt option help text + popts.setOptionHelp( 1, _("Discard the file.") ); + popts.setShownCount( 1 ); + + // translators: A prompt text + zypper.out().prompt( PROMPT_GPG_WRONG_DIGEST_ACCEPT, _("Unblock or discard?"), popts ); + int reply = get_prompt_reply( zypper, PROMPT_GPG_WRONG_DIGEST_ACCEPT, popts ); + return( reply == 0 ); + } + + private: + const Config & _gopts; + }; + + /////////////////////////////////////////////////////////////////// +}; // namespace zypp +/////////////////////////////////////////////////////////////////// + +class KeyRingCallbacks { + + private: + KeyRingReceive _keyRingReport; + + public: + KeyRingCallbacks() + { + _keyRingReport.connect(); + } + + ~KeyRingCallbacks() + { + _keyRingReport.disconnect(); + } + +}; + +class DigestCallbacks { + + private: + DigestReceive _digestReport; + + public: + DigestCallbacks() + { + _digestReport.connect(); + } + + ~DigestCallbacks() + { + _digestReport.disconnect(); + } + +}; + + +#endif // ZYPP_GLIB_ZMART_KEYRINGCALLBACKS_H +// Local Variables: +// c-basic-offset: 2 +// End: diff --git a/zypp-glib/private/callbacks/legacyreportreceiverbase.h b/zypp-glib/private/callbacks/legacyreportreceiverbase.h new file mode 100644 index 0000000000..95e58c6d81 --- /dev/null +++ b/zypp-glib/private/callbacks/legacyreportreceiverbase.h @@ -0,0 +1,22 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#include +#include + +namespace zyppng { + + class LegacyReportReceiverBase + { + public: + virtual ContextBaseRef context() = 0; + virtual ProgressObserverRef masterProgress() = 0; + }; + +} diff --git a/zypp-glib/private/callbacks/locks.h b/zypp-glib/private/callbacks/locks.h new file mode 100644 index 0000000000..20b31f1ecd --- /dev/null +++ b/zypp-glib/private/callbacks/locks.h @@ -0,0 +1,77 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ + +#ifndef LOCKS_ZYPPER_CALLBACKS_H +#define LOCKS_ZYPPER_CALLBACKS_H + +#include + +#include +#include +#include + +#include "utils/prompt.h" + +namespace zypp { + + struct LocksSaveReportReceiver : public callback::ReceiveReport + { + virtual Action conflict( const PoolQuery& query, ConflictState state ) + { + if (state == SAME_RESULTS) + Zypper::instance().out().error( + _("The following query locks the same objects as the one you want to remove:")); + else + Zypper::instance().out().error( + _("The following query locks some of the objects you want to unlock:")); + + query.serialize(std::cout); + + return read_bool_answer( + PROMPT_YN_REMOVE_LOCK, _("Do you want to remove this lock?"), true) ? + DELETE : IGNORE; + } + }; + + struct CleanLocksReportReceiver : public callback::ReceiveReport + { + virtual Action execute( const PoolQuery& query ) + { + Zypper::instance().out().error( + _("The following query does not lock anything:")); + + query.serialize(std::cout); + + return read_bool_answer( + PROMPT_YN_REMOVE_LOCK, _("Do you want to remove this lock?"), true) ? + DELETE : IGNORE; + } + }; + +} + + +class LocksCallbacks { + private: + LocksSaveReportReceiver _saveReport; + CleanLocksReportReceiver _cleanReport; + + public: + LocksCallbacks() + { + _saveReport.connect(); + _cleanReport.connect(); + } + + ~LocksCallbacks() + { + _saveReport.disconnect(); + _cleanReport.disconnect(); + } +}; + +#endif diff --git a/zypp-glib/private/callbacks/media.cc b/zypp-glib/private/callbacks/media.cc new file mode 100644 index 0000000000..bd9f4dbdda --- /dev/null +++ b/zypp-glib/private/callbacks/media.cc @@ -0,0 +1,345 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ + +#include +#include +#include // for getpass + +#include "callbacks/media.h" + +#include "utils/messages.h" +#include "utils/prompt.h" + +#include +#include + +using std::cin; +using namespace zypp; + +// ---------[ common ]-------------------------------------------------------- + +static void set_common_option_help( PromptOptions & popts ) +{ + // help text for the "Abort, retry, ignore?" prompt for media errors + popts.setOptionHelp( 0, _("Skip retrieval of the file and abort current operation.") ); + // help text for the "Abort, retry, ignore?" prompt for media errors + popts.setOptionHelp( 1, _("Try to retrieve the file again.") ); + // help text for the "Abort, retry, ignore?" prompt for media errors + popts.setOptionHelp( 2, _("Skip retrieval of the file and try to continue with the operation without the file.") ); + // help text for the "Abort, retry, ignore?" prompt for media errors + popts.setOptionHelp( 3, _("Change current base URI and try retrieving the file again.") ); + // hide advanced options + popts.setShownCount( 3 ); +} + +static MediaChangeReport::Action handle_common_options( unsigned reply, Url & url ) +{ + MediaChangeReport::Action action = MediaChangeReport::ABORT; + switch ( reply ) + { + case 0: /* abort */ + break; + case 3: /* change url */ + { + // translators: this is a prompt label, will appear as "New URI: " + Url newurl( get_text( _("New URI") + std::string(": "), url.asString() ) ); + url = newurl; + } + // fall through + case 1: /* retry */ + action = MediaChangeReport::RETRY; + break; + case 2: /* ignore */ + action = MediaChangeReport::IGNORE; + break; + default: + WAR << "invalid prompt reply: " << reply << endl; + break; + } + return action; +} + + +// ---------[ https ]-------------------------------------------------------- + +static MediaChangeReport::Action request_medium_https_handler( Zypper & zypper, Url & url ) +{ + // https options + // translators: a/r/i/u are replies to the "Abort, retry, ignore?" prompt. + // Translate the a/r/i part exactly as you did the a/r/i string. + // The 'u' reply means 'Change URI'. + // https protocol-specific options: + // 's' stands for Disable SSL certificate authority check + PromptOptions popts( _("a/r/i/u/s"), 0 ); + set_common_option_help( popts ); + popts.setOptionHelp( 4, _("Disable SSL certificate authority check and continue.") ); + + // translators: this is a prompt text + zypper.out().prompt( PROMPT_ARI_MEDIA_PROBLEM, _("Abort, retry, ignore?"), popts ); + int reply = get_prompt_reply( zypper, PROMPT_ARI_MEDIA_PROBLEM, popts ); + + MediaChangeReport::Action action; + switch ( reply ) + { + case 4: /* disable SSL */ + url.setQueryParam( "ssl_verify", "no" ); + zypper.out().info(_("SSL certificate authority check disabled.") ); + action = MediaChangeReport::RETRY; + break; + default: + action = handle_common_options( reply, url ); + } + return action; +} + + +// ---------[ cd/dvd ]--------------------------------------------------------- + +static void eject_drive_dialog( Zypper & zypper, Url & url, const std::vector & devices, unsigned & index ) +{ + bool cancel = false; + if ( devices.empty() ) + { + zypper.out().info(_("No devices detected, cannot eject.") ); + zypper.out().info(_("Try to eject the device manually.") ); + } + if ( devices.size() == 1 ) + { + MIL << "ejecting " << devices.front() << endl; + media::MediaManager mm; + media::MediaAccessId mid = mm.open( url ); + mm.release( mid, devices.front() ); + } + else + { + zypper.out().info( _("Detected devices:") ); + int devn = 1; + std::ostringstream numbers; + for_( it, devices.begin(), devices.end() ) + { + // enhancement: we could try to get nicer device names like + // "DVDRAM GSA-U10N on /dev/sr0" + cout << devn << " " << *it << " " << endl; + numbers << devn << "/"; + ++devn; + } + numbers << "c"; // c for cancel + + int devcount = devices.size(); + PromptOptions popts( numbers.str(), 0 ); + popts.setOptionHelp( devcount, _("Cancel") ); + + zypper.out().prompt( PROMPT_MEDIA_EJECT, _("Select device to eject."), popts ); + int reply = get_prompt_reply( zypper, PROMPT_MEDIA_EJECT, popts ); + if ( reply == devcount ) + cancel = true; + else + { + MIL << "ejecting " << devices[reply] << endl; + media::MediaManager mm; + media::MediaAccessId mid = mm.open( url ); + mm.release( mid, devices[reply] ); + } + } + + if ( !cancel ) + { + zypper.out().info(_("Insert the CD/DVD and press ENTER to continue.") ); + getchar(); + } + zypper.out().info(_("Retrying...") ); +} + + +static MediaChangeReport::Action request_medium_dvd_handler( Zypper & zypper, + Url & url, + const std::vector & devices, + unsigned & index ) +{ + // cd/dvd options + // translators: a/r/i/u are replies to the "Abort, retry, ignore?" prompt. + // Translate the a/r/i part exactly as you did the a/r/i string. + // The 'u' reply means 'Change URI'. + // cd/dvd protocol-specific options: + // 'e' stands for Eject medium + PromptOptions popts(_("a/r/i/u/e"), 0 ); + set_common_option_help( popts ); + popts.setOptionHelp( 4, _("Eject medium.") ); + + // translators: this is a prompt text + zypper.out().prompt( PROMPT_ARI_MEDIA_PROBLEM, _("Abort, retry, ignore?"), popts ); + int reply = get_prompt_reply( zypper, PROMPT_ARI_MEDIA_PROBLEM, popts ); + MediaChangeReport::Action action; + switch ( reply ) + { + case 4: /* eject medium */ + eject_drive_dialog( zypper, url, devices, index ); + action = MediaChangeReport::RETRY; + break; + default: + action = handle_common_options( reply, url ); + } + return action; +} + +// --------------------------------------------------------------------------- +/////////////////////////////////////////////////////////////////// +namespace ZmartRecipients +{ + + MediaChangeReport::Action MediaChangeReportReceiver::requestMedia( Url & url, + unsigned mediumNr, + const std::string & label, + MediaChangeReport::Error error, + const std::string & description, + const std::vector & devices, + unsigned & index) + { + Zypper & zypper = Zypper::instance(); + + DBG << "medium problem, url: " << url.asString() + << ", error " << error + << ", label '" << label << "', #" << mediumNr << endl; + + zypper.out().error( description ); + if ( url.schemeIsVolatile() ) // cd/dvd + { + // TranslatorExplanation translate letters 'y' and 'n' to whathever is appropriate for your language. + // Try to check what answers does zypper accept (it always accepts y/n at least) + // You can also have a look at the regular expressions used to check the answer here: + // /usr/lib/locale//LC_MESSAGES/SYS_LC_MESSAGES + std::string request = str::Format(_("Please insert medium [%s] #%d and type 'y' to continue or 'n' to cancel the operation.")) + % label % mediumNr; + if ( read_bool_answer( PROMPT_YN_MEDIA_CHANGE, request, false ) ) + { + zypper.requestExit( false ); + return MediaChangeReport::RETRY; + } + else + return MediaChangeReport::ABORT; + } + + if ( error == MediaChangeReport::IO_SOFT ) + { + MediaChangeReport::Action default_action = MediaChangeReport::RETRY; + if ( repeat_counter.counter_overrun( url ) ) + default_action = MediaChangeReport::ABORT; + + MediaChangeReport::Action action = (Action)read_action_ari_with_timeout( PROMPT_ARI_MEDIA_PROBLEM, 30, default_action ); + + if ( action == MediaChangeReport::RETRY ) + zypper.requestExit( false ); + + return action; + } + + Action action = MediaChangeReport::ABORT; + if ( url.getScheme() == "https" ) + action = request_medium_https_handler( zypper, url ); + else if ( url.schemeIsVolatile() ) // cd/dvd + action = request_medium_dvd_handler( zypper, url, devices, index ); + else + { + // translators: a/r/i/u are replies to the "Abort, retry, ignore?" prompt + // Translate the a/r/i part exactly as you did the a/r/i string. + // the 'u' reply means 'Change URI'. + PromptOptions popts(_("a/r/i/u"), 0 ); + set_common_option_help( popts ); + + // translators: this is a prompt text + zypper.out().prompt( PROMPT_ARI_MEDIA_PROBLEM, _("Abort, retry, ignore?"), popts ); + int reply = get_prompt_reply( zypper, PROMPT_ARI_MEDIA_PROBLEM, popts ); + + action = handle_common_options( reply, url ); + } + + // if an rpm download failed and user chose to ignore that, advice to + // run zypper verify afterwards + if ( action == MediaChangeReport::IGNORE ) + { + if ( zypper.runtimeData().action_rpm_download + && !zypper.runtimeData().seen_verify_hint ) + { + print_verify_hint( Zypper::instance().out() ); + } + zypper.requestExit( false ); + } + + if ( action == MediaChangeReport::RETRY ) + zypper.requestExit( false ); + + return action; + } + + + // --------------------------------------------------------------------------- + // - AuthenticationReportReceiver + // --------------------------------------------------------------------------- + + bool AuthenticationReportReceiver::prompt( const Url & url, + const std::string & description, + media::AuthData & auth_data ) + { + Zypper & zypper = Zypper::instance(); + + if ( geteuid() != 0 && url.getQueryString().find("credentials=") != std::string::npos ) + { + std::string credfile( "/etc/zypp/credentials.d/" + url.getQueryParam("credentials") ); + zypper.out().warning( str::form(_("Authentication required to access %s. You need to be root to be able to read the credentials from %s."), + url.asString().c_str(), credfile.c_str() ) ); + } + + if ( zypper.config().non_interactive ) + { + MIL << "Non-interactive mode: aborting" << endl; + return false; + } + + // curl authentication + media::CurlAuthData * curl_auth_data = dynamic_cast(&auth_data); + + if ( curl_auth_data ) + curl_auth_data->setAuthType( "basic,digest" ); + + // user name + + std::string username; + // expect the input from machine on stdin + if ( zypper.config().machine_readable ) + { + zypper.out().prompt( PROMPT_AUTH_USERNAME, _("User Name"), PromptOptions(), description ); + cin >> username; + } + // input from human using readline + else + { + zypper.out().info( description, Out::QUIET ); + username = get_text(_("User Name") + std::string(": "), auth_data.username() ); + } + if ( username.empty() ) + return false; + auth_data.setUsername( username ); + + // password + + zypper.out().prompt( PROMPT_AUTH_PASSWORD, _("Password"), PromptOptions() ); + + std::string password; + // expect the input from machine on stdin + if ( zypper.config().machine_readable ) + cin >> password; + else + password = ::getpass( "" ); + if ( password.empty() ) + return false; + auth_data.setPassword( password ); + + return true; + } + +} //namespace ZmartRecipients +/////////////////////////////////////////////////////////////////// diff --git a/zypp-glib/private/callbacks/media.h b/zypp-glib/private/callbacks/media.h new file mode 100644 index 0000000000..0accfbf2d4 --- /dev/null +++ b/zypp-glib/private/callbacks/media.h @@ -0,0 +1,219 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ + +#ifndef ZMART_MEDIA_CALLBACKS_H +#define ZMART_MEDIA_CALLBACKS_H + +#include +#include + +#include +#include +#include +#include + +#include "Zypper.h" +#include "utils/prompt.h" + +// auto-repeat counter limit +#define REPEAT_LIMIT 3 + +using media::MediaChangeReport; +using media::DownloadProgressReport; + +/////////////////////////////////////////////////////////////////// +namespace ZmartRecipients +{ + class repeat_counter_ { + private: + Url url; + unsigned counter; + public: + repeat_counter_():counter(0){} + bool counter_overrun(const Url & u){ + if (u==url) + { + if (++counter>=REPEAT_LIMIT) + { + counter = 0; // reset!: next request might use the same URL again. + return true; + } + } + else + { + url = u; + counter = 0; + } + return false; + } + }; + + /////////////////////////////////////////////////////////////////// + /// \brief Legacy or feature - Base class protecting a callback receiver from exiting on the 1st CTRL-C + /// + /// Media callbacks pass down the exit request to abort the download and + /// handle the user response. This base class handles the Zypper::SigExitGuard + /// to accompoish this. + /// + /// \note Derived classes overriding reportbegin/reportend must explicitly call + /// the method in this instance. + /// + template + struct ExitGuardedReceiveReport : public callback::ReceiveReport + { + void reportbegin() override + { _g = Zypper::sigExitGuard(); } + + void reportend() override + { _g.reset(); } + + private: + Zypper::SigExitGuard _g; + }; + + + struct MediaChangeReportReceiver : public ExitGuardedReceiveReport + { + virtual MediaChangeReport::Action + requestMedia(Url & url, + unsigned mediumNr, + const std::string & label, + MediaChangeReport::Error error, + const std::string & description, + const std::vector & devices, + unsigned & index); + private: + repeat_counter_ repeat_counter; + }; + + // progress for downloading a file + struct DownloadProgressReportReceiver : public ExitGuardedReceiveReport + { + DownloadProgressReportReceiver() + : _be_quiet(false) + {} + + virtual void start( const Url & uri, Pathname localfile ) + { + _last_drate_avg = -1; + + Out & out = Zypper::instance().out(); + + if (out.verbosity() < Out::HIGH && + ( + // don't show download info unless scopedVerboseDownloadProgress is demanded + not Zypper::instance().runtimeData().scopedVerboseDownloadProgress.isDemanded() || + // don't report download of the media file (bnc #330614) + Pathname(uri.getPathName()).basename() == "media" + ) + ) + { + _be_quiet = true; + return; + } + else + _be_quiet = false; + + out.dwnldProgressStart(uri); + } + + virtual bool progress(int value, const Url & uri, double drate_avg, double drate_now) + { + Zypper & zypper( Zypper::instance() ); + + if (zypper.exitRequested()) + { + DBG << "received exit request" << std::endl; + return false; + } + + if (!zypper.runtimeData().raw_refresh_progress_label.empty()) + zypper.out().progress( + "raw-refresh", zypper.runtimeData().raw_refresh_progress_label); + + if (_be_quiet) + return true; + + zypper.out().dwnldProgress(uri, value, (long) drate_now); + _last_drate_avg = drate_avg; + return true; + } + + virtual DownloadProgressReport::Action + problem( const Url & uri, DownloadProgressReport::Error error, const std::string & description ) + { + if ( error == DownloadProgressReport::NO_ERROR ) { + // NO_ERROR: just a report but let the caller proceed as appropriate... + Zypper::instance().out().info() << "- " << ( ColorContext::LOWLIGHT << description ); + return DownloadProgressReport::IGNORE; + } + + if ( not _be_quiet ) + Zypper::instance().out().dwnldProgressEnd(uri, _last_drate_avg, true); + Zypper::instance().out().error(zcb_error2str(error, description)); + + Action action = (Action) read_action_ari( + PROMPT_ARI_MEDIA_PROBLEM, DownloadProgressReport::ABORT); + if (action == DownloadProgressReport::RETRY) + Zypper::instance().requestExit(false); + return action; + } + + // used only to finish, errors will be reported in media change callback (libzypp 3.20.0) + virtual void finish( const Url & uri, Error error, const std::string & konreason ) + { + if (_be_quiet) + return; + + Zypper::instance().out().dwnldProgressEnd( + uri, _last_drate_avg, ( error == NOT_FOUND ? indeterminate : TriBool(error != NO_ERROR) ) ); + } + + private: + bool _be_quiet; + double _last_drate_avg; + }; + + + struct AuthenticationReportReceiver : public ExitGuardedReceiveReport + { + virtual bool prompt(const Url & url, + const std::string & description, + media::AuthData & auth_data); + }; + +} // namespace ZmartRecipients +/////////////////////////////////////////////////////////////////// + +class MediaCallbacks { + + private: + ZmartRecipients::MediaChangeReportReceiver _mediaChangeReport; + ZmartRecipients::DownloadProgressReportReceiver _mediaDownloadReport; + ZmartRecipients::AuthenticationReportReceiver _mediaAuthenticationReport; + public: + MediaCallbacks() + { + MIL << "Set media callbacks.." << std::endl; + _mediaChangeReport.connect(); + _mediaDownloadReport.connect(); + _mediaAuthenticationReport.connect(); + } + + ~MediaCallbacks() + { + _mediaChangeReport.disconnect(); + _mediaDownloadReport.disconnect(); + _mediaAuthenticationReport.disconnect(); + } +}; + +#endif +// Local Variables: +// mode: c++ +// c-basic-offset: 2 +// End: diff --git a/zypp-glib/private/callbacks/repo.h b/zypp-glib/private/callbacks/repo.h new file mode 100644 index 0000000000..5ba1126923 --- /dev/null +++ b/zypp-glib/private/callbacks/repo.h @@ -0,0 +1,356 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#ifndef ZMART_SOURCE_CALLBACKS_H +#define ZMART_SOURCE_CALLBACKS_H + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////// +namespace zyppng +{ +/////////////////////////////////////////////////////////////////// + +// progress for downloading a resolvable +struct DownloadResolvableReportReceiver : public zypp::callback::ReceiveReport +{ +private: + LegacyReportReceiverBase &_parent; + zyppng::ProgressObserverRef _progress; +public: + + DownloadResolvableReportReceiver( LegacyReportReceiverBase &parent ) : _parent( parent ) {} + + zypp::Resolvable::constPtr _resolvable_ptr; + zypp::Url _url; + zypp::Pathname _delta; + zypp::ByteCount _delta_size; + std::string _label_apply_delta; + zypp::Pathname _patch; + zypp::ByteCount _patch_size; + + void reportbegin() override + { + + //legacy code instantiated a SendReport + } + void reportend() override + { + //legacy code deleted a SendReport + } + + // Dowmload delta rpm: + // - path below url reported on start() + // - expected download size (0 if unknown) + // - download is interruptable + // - problems are just informal + void startDeltaDownload( const zypp::Pathname & filename, const zypp::ByteCount & downloadsize ) override + { + if ( _parent.masterProgress() ) { + + if ( _progress ) + ERR << "Exisiting progress in DownloadResolvableReportReceiver, this is a bug" << std::endl; + + _delta = filename; + _delta_size = downloadsize; + std::ostringstream s; + s << _("Retrieving delta") << ": " << _delta; + + _progress = _parent.masterProgress ()->makeSubTask ( 1.0, s.str(), downloadsize ); + _progress->start(); + } + } + + bool progressDeltaDownload( int value ) override { + if ( _progress ) { + _progress->setCurrent ( value ); + } + return true; + } + + void problemDeltaDownload( const std::string & description ) override + { + if ( _progress ) { + _progress->setLabel ( description ); + _progress->setFinished ( ProgressObserver::Error ); + _progress.reset(); + } + } + + + void finishDeltaDownload() override + { + if ( _progress ) { + _progress->setFinished(); + _progress.reset(); + } + } + + // Apply delta rpm: + // - local path of downloaded delta + // - aplpy is not interruptable + // - problems are just informal + void startDeltaApply( const zypp::Pathname & filename ) override + { + if ( _parent.masterProgress() ) { + + if ( _progress ) + ERR << "Exisiting progress in DownloadResolvableReportReceiver, this is a bug" << std::endl; + + std::ostringstream s; + // translators: this text is a progress display label e.g. "Applying delta foo [42%]" + s << _("Applying delta") << ": " << _delta; + _label_apply_delta = s.str(); + _delta = filename; + + _progress = _parent.masterProgress ()->makeSubTask ( 1.0, _label_apply_delta ); + _progress->start(); + } + _delta = filename.basename(); + + } + + void progressDeltaApply( int value ) override + { + if ( _progress ) { + _progress->setCurrent ( value ); + } + } + + void problemDeltaApply( const std::string & description ) override + { + if ( _progress ) { + _progress->setLabel ( description ); + _progress->setFinished ( ProgressObserver::Error ); + _progress.reset(); + } + } + + void finishDeltaApply() override + { + if ( _progress ) { + _progress->setFinished(); + _progress.reset(); + } + } + + void fillsRhs( TermLine & outstr_r, Zypper & zypper_r, Resolvable::constPtr res_r ) + { + outstr_r.rhs << " (" << ++zypper_r.runtimeData().commit_pkg_current + << "/" << zypper_r.runtimeData().commit_pkgs_total << ")"; + if ( res_r ) + { + outstr_r.rhs << ", " << res_r->downloadSize().asString( 5, 3 ) << " "/* indent `/s)]` of download speed line following */; + // TranslatorExplanation %s is package size like "5.6 M" + // outstr_r.rhs << " " << str::Format(_("(%s unpacked)")) % pkg_r->installSize().asString( 5, 3 ); + } + } + + virtual void infoInCache( Resolvable::constPtr res_r, const Pathname & localfile_r ) + { + Zypper & zypper = Zypper::instance(); + + TermLine outstr( TermLine::SF_SPLIT | TermLine::SF_EXPAND ); + outstr.lhs << str::Format(_("In cache %1%")) % localfile_r.basename(); + fillsRhs( outstr, zypper, res_r ); + zypper.out().infoLine( outstr ); + } + + /** this is interesting because we have full resolvable data at hand here + * The media backend has only the file URI + * \todo combine this and the media data progress callbacks in a reasonable manner + */ + virtual void start( Resolvable::constPtr resolvable_ptr, const Url & url ) + { + _resolvable_ptr = resolvable_ptr; + _url = url; + Zypper & zypper = Zypper::instance(); + + TermLine outstr( TermLine::SF_SPLIT | TermLine::SF_EXPAND ); + outstr.lhs << _("Retrieving:") << " " << _resolvable_ptr-> asUserString(); + fillsRhs( outstr, zypper, resolvable_ptr ); + + // temporary fix for bnc #545295 + if ( zypper.runtimeData().commit_pkg_current == zypper.runtimeData().commit_pkgs_total ) + zypper.runtimeData().commit_pkg_current = 0; + + zypper.out().infoLine( outstr ); + zypper.runtimeData().action_rpm_download = true; + } + + // The progress is reported by the media backend + // virtual bool progress(int value, Resolvable::constPtr /*resolvable_ptr*/) { return true; } + + virtual Action problem( Resolvable::constPtr resolvable_ptr, Error /*error*/, const std::string & description ) + { + Zypper::instance().out().error(description); + DBG << "error report" << std::endl; + + Action action = (Action) read_action_ari(PROMPT_ARI_RPM_DOWNLOAD_PROBLEM, ABORT); + if (action == DownloadResolvableReport::RETRY) + --Zypper::instance().runtimeData().commit_pkg_current; + else + Zypper::instance().runtimeData().action_rpm_download = false; + return action; + } + + virtual void pkgGpgCheck( const UserData & userData_r ) + { + Zypper & zypper = Zypper::instance(); + // "ResObject" ResObject::constPtr of the package + // "Localpath" Pathname to downloaded package on disk + // "CheckPackageResult" RpmDb::CheckPackageResult of signature check + // "CheckPackageDetail" RpmDb::CheckPackageDetail logmessages of rpm signature check + // + // Userdata accepted: + // "Action" DownloadResolvableReport::Action user advice how to behave on error (ABORT). + using target::rpm::RpmDb; + RpmDb::CheckPackageResult result ( userData_r.get( "CheckPackageResult" ) ); + const RpmDb::CheckPackageDetail & details ( userData_r.get( "CheckPackageDetail" ) ); + + str::Str msg; + if ( result != RpmDb::CHK_OK ) // only on error... + { + const Pathname & localpath ( userData_r.get( "Localpath" ) ); + const std::string & rpmname ( localpath.basename() ); + msg << rpmname << ":" << "\n"; + } + + // report problems in individual checks... + for ( const auto & el : details ) + { + switch ( el.first ) + { + case RpmDb::CHK_OK: + if ( zypper.out().verbosity() >= Out::HIGH ) // quiet about good sigcheck unless verbose. + msg << el.second << "\n"; + break; + case RpmDb::CHK_NOSIG: + msg << ( (result == RpmDb::CHK_OK ? ColorContext::MSG_WARNING : ColorContext::MSG_ERROR ) << el.second ) << "\n"; + break; + case RpmDb::CHK_NOKEY: // can't check + case RpmDb::CHK_NOTFOUND: + msg << ( ColorContext::MSG_WARNING << el.second ) << "\n"; + break; + case RpmDb::CHK_FAIL: // failed check + case RpmDb::CHK_NOTTRUSTED: + case RpmDb::CHK_ERROR: + msg << ( ColorContext::MSG_ERROR << el.second ) << "\n"; + break; + } + } + + if ( result == RpmDb::CHK_OK ) + { + const std::string & msgstr( msg.str() ); + if ( ! msgstr.empty() ) + zypper.out().info( msg ); + return; + } + + // determine action + if ( zypper.config().no_gpg_checks ) + { + // report and continue + ResObject::constPtr pkg( userData_r.get( "ResObject" ) ); + std::string err( str::Str() << pkg->asUserString() << ": " << _("Signature verification failed") << " " << result ); + switch ( result ) + { + case RpmDb::CHK_OK: + // Can't happen; already handled above + break; + + case RpmDb::CHK_NOKEY: // can't check + case RpmDb::CHK_NOTFOUND: + case RpmDb::CHK_NOSIG: + msg << ( ColorContext::MSG_WARNING << err ) << "\n"; + break; + + case RpmDb::CHK_FAIL: // failed check + case RpmDb::CHK_ERROR: + case RpmDb::CHK_NOTTRUSTED: + default: + msg << ( ColorContext::MSG_ERROR << err ) << "\n"; + break; + } + msg << _("Accepting package despite the error.") << " (--no-gpg-checks)" << "\n"; + userData_r.set( "Action", IGNORE ); + } + else + { + // error -> requests the default problem report + userData_r.reset( "Action" ); + } + zypper.out().info( msg ); + } + + // implementation not needed prehaps - the media backend reports the download progress + virtual void finish( Resolvable::constPtr /*resolvable_ptr**/, Error error, const std::string & reason ) + { + Zypper::instance().runtimeData().action_rpm_download = false; + /* + display_done ("download-resolvable", cout_v); + display_error (error, reason); +*/ + } +}; + +struct ProgressReportReceiver : public zypp::callback::ReceiveReport +{ +private: + LegacyReportReceiverBase &_parent; + zyppng::ProgressObserverRef _progress; +public: + + ProgressReportReceiver( LegacyReportReceiverBase &parent ) : _parent( parent ) {} + virtual void start( const zypp::ProgressData &data ) + { + if ( _parent.masterProgress() ) { + _progress = _parent.masterProgress ()->makeSubTask ( 1.0, data.name(), data.max () - data.min () ); + _progress->start(); + _progress->setCurrent ( data.val () - data.min () ); + } + } + + virtual bool progress( const zypp::ProgressData &data ) + { + if ( _progress ) { + _progress->setBaseSteps ( data.max () - data.min () ); + _progress->setCurrent ( data.val () - data.min () ); + _progress->setLabel ( data.name () ); + } + } + + virtual void finish( const zypp::ProgressData &data ) + { + if ( _progress ) { + // Don't report success if data reports percent and is not at 100% + zypp::ProgressData::value_type last = data.reportValue(); + + _progress->setBaseSteps ( data.max () - data.min () ); + _progress->setCurrent ( data.val () - data.min () ); + _progress->setLabel ( data.name () ); + _progress->setFinished ( (last == 100) ? zyppng::ProgressObserver::Success : zyppng::ProgressObserver::Error ); + _progress.reset(); + } + } +}; + +} +#endif diff --git a/zypp-glib/private/callbacks/rpm.h b/zypp-glib/private/callbacks/rpm.h new file mode 100644 index 0000000000..b9cc1405b3 --- /dev/null +++ b/zypp-glib/private/callbacks/rpm.h @@ -0,0 +1,967 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ + +#ifndef ZMART_RPM_CALLBACKS_H +#define ZMART_RPM_CALLBACKS_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Zypper.h" +#include "output/prompt.h" +#include "global-settings.h" +#include "utils/prompt.h" + +/////////////////////////////////////////////////////////////////// +namespace +{ + using loglevel = zypp::target::rpm::SingleTransReport::loglevel; + + /** Print additional rpm outout line and scan for %script errors. */ + inline void processAdditionalRpmOutputLine( const std::string & line_r, loglevel level_r = loglevel::msg, const char *const prefix_r = nullptr ) + { + Out::Info info( Zypper::instance().out() ); + ColorStream msg( info << "", ColorContext::HIGHLIGHT ); + + std::string_view msgline { zypp::strv::rtrim( line_r, "\n" ) }; + + if ( prefix_r ) { + // Checking for ZYPPER_EXIT_INF_RPM_SCRIPT_FAILED (like in the traditional rpv case below) + // is not needed here. The script callback callback handles this. + switch ( level_r ) { + case loglevel::crt: [[fallthrough]]; + case loglevel::err: + msg << ( ColorContext::MSG_ERROR << prefix_r< + std::string xmlListElement( const Tp_ & val_r ) const + { return xmlListElement( makeResObject( asSolvable( val_r ) ) ); } + + std::string xmlListElement( const ResObject::Ptr & val_r ) const + { + str::Str ret; + ret << "kind() << "\""; + ret << " name=\"" << val_r->name() << "\""; + ret << " edition=\"" << val_r->edition() << "\""; + ret << " arch=\"" << val_r->arch() << "\""; + { + const std::string & text( val_r->summary() ); + if ( ! text.empty() ) + ret << " summary=\"" << xml::escape( text ) << "\""; + } + { + const std::string & text( val_r->description() ); + if ( ! text.empty() ) + ret << ">\n" << "" << xml::escape( text ) << "" << ""; + else + ret << "/>"; + } + return ret; + } + + template + std::string listElement( const Tp & val_r ) const + { return listElement( makeResObject( asSolvable( val_r ) ) ); } + + std::string listElement( const ResObject::Ptr & val_r ) const + { return val_r->ident().asString(); } + + private: + template + static sat::Solvable asSolvable( const Tp_ & val_r ) + { return sat::asSolvable()( val_r ); } + + static sat::Solvable asSolvable( int val_r ) // e.g. satQueues use int as SolvabeId + { return sat::Solvable( val_r ); } + }; + +} // namespace out +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +namespace ZmartRecipients +{ + +// resolvable Message +struct PatchMessageReportReceiver : public callback::ReceiveReport +{ + + /** Display \c patch->message(). + * Return \c true to continue, \c false to abort commit. + */ + virtual bool show( Patch::constPtr & patch ) + { + Out & out = Zypper::instance().out(); + std::ostringstream s; + s << patch; // [patch]important-patch-101 \todo make some meaningful message out of this + out.info(s.str(), Out::HIGH); + out.info(patch->message()); + + return read_bool_answer(PROMPT_PATCH_MESSAGE_CONTINUE, text::qContinue(), true); + } +}; + + +struct PatchScriptReportReceiver : public callback::ReceiveReport +{ + std::string _label; + scoped_ptr _guard; // guard script output if Out::TYPE_XML + + void closeNode() + { if ( _guard ) _guard.reset(); } + + std::ostream & printOut( const std::string & output_r ) + { + if ( _guard ) + std::cout << xml::escape( output_r ); + else + std::cout << output_r; + return std::cout; + } + + + virtual void start( const Package::constPtr & package, + const Pathname & path_r ) // script path + { + Zypper & zypper = Zypper::instance(); + if ( zypper.out().type() == Out::TYPE_XML ) + _guard.reset( new Out::XmlNode( zypper.out(), "message", { "type", "info" } ) ); + + // TranslatorExplanation speaking of a script - "Running: script file name (package name, script dir)" + _label = str::Format(_("Running: %s (%s, %s)")) % path_r.basename() % package->name() % path_r.dirname(); + printOut( _label ) << std::endl; + } + + /** + * Progress provides the script output. If the script is quiet, + * from time to time still-alive pings are sent to the ui. (Notify=PING) + * Returning \c FALSE aborts script execution. + */ + virtual bool progress( Notify kind, const std::string &output ) + { + Zypper & zypper = Zypper::instance(); + static bool was_ping_before = false; + if (kind == PING) + { + std::cout << "." << std::flush; + was_ping_before = true; + } + else + { + if (was_ping_before) + std::cout << std::endl; + printOut( output ); + + was_ping_before = false; + } + + return !zypper.exitRequested(); + } + + /** Report error. */ + virtual Action problem( const std::string & description ) + { + closeNode(); + Zypper & zypper = Zypper::instance(); + + zypper.out().error(description); + + Action action = (Action) read_action_ari (PROMPT_ARI_PATCH_SCRIPT_PROBLEM, ABORT); + if (action == target::PatchScriptReport::ABORT) + zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP); + return action; + } + + /** Report success. */ + virtual void finish() + { + closeNode(); + Zypper::instance().out().progressEnd("run-script", _label); + } + + /** Catch unexpected end. */ + virtual void reportend() + { closeNode(); } +}; + +/////////////////////////////////////////////////////////////////// + // progress for removing a resolvable +struct RemoveResolvableReportReceiver : public callback::ReceiveReport +{ + virtual void start( Resolvable::constPtr resolvable ) + { + ++Zypper::instance().runtimeData().rpm_pkg_current; + showProgress( resolvable ); + } + + virtual bool progress( int value, Resolvable::constPtr resolvable ) + { + if ( _progress ) + (*_progress)->set( value ); + return !Zypper::instance().exitRequested(); + } + + virtual Action problem( Resolvable::constPtr resolvable, Error error, const std::string & description_r ) + { + std::string description; // We just need the 1st line (exception message), the rest is additional rpm output we already reported. + strv::split( description_r, "\n", [&description]( std::string_view line_r, unsigned nr_r ) { + if ( nr_r == 0 ) description = line_r; + return false; + }); + + // finsh progress; indicate error + if ( _progress ) + { + (*_progress).error(); + _progress.reset(); + } + + std::ostringstream s; + s << str::Format(_("Removal of %s failed:")) % resolvable << std::endl; + s << zcb_error2str(error, description); + Zypper::instance().out().error(s.str()); + + Action ret = (Action) read_action_ari (PROMPT_ARI_RPM_REMOVE_PROBLEM, ABORT); + if ( ret == RETRY ) + showProgress( resolvable ); // bsc#1131113: need to re-show progress + + return ret; + } + + virtual void finish( Resolvable::constPtr /*resolvable*/, Error error, const std::string & reason ) + { + // finsh progress; indicate error + if ( _progress ) + { + (*_progress).error( error != NO_ERROR ); + _progress.reset(); + } + + if (error != NO_ERROR) + // set proper exit code, don't write to output, the error should have been reported in problem() + Zypper::instance().setExitCode(ZYPPER_EXIT_ERR_ZYPP); + } + + void report( const UserData & userData_r ) override + { + // Any additional rpm output is printed immediately.... + if ( userData_r.type() == ReportType::contentRpmout && userData_r.haskey("line") ) { + processAdditionalRpmOutput( userData_r.get>("line").get() ); + } + } + + virtual void reportend() + { _progress.reset(); } + +private: + void showProgress( Resolvable::constPtr resolvable_r ) + { + Zypper & zypper = Zypper::instance(); + _progress.reset( new Out::ProgressBar( zypper.out(), + "remove-resolvable", + // translators: This text is a progress display label e.g. "Removing packagename-x.x.x [42%]" + str::Format(_("Removing: %s") ) % resolvable_r->asString(), + zypper.runtimeData().rpm_pkg_current, + zypper.runtimeData().rpm_pkgs_total ) ); + (*_progress)->range( 100 ); // progress reports percent + } + +private: + scoped_ptr _progress; +}; + +/////////////////////////////////////////////////////////////////// +// progress for installing a resolvable +struct InstallResolvableReportReceiver : public callback::ReceiveReport +{ + virtual void start( Resolvable::constPtr resolvable ) + { + ++Zypper::instance().runtimeData().rpm_pkg_current; + showProgress( resolvable ); + } + + virtual bool progress( int value, Resolvable::constPtr resolvable ) + { + if ( _progress ) + (*_progress)->set( value ); + return !Zypper::instance().exitRequested(); + } + + virtual Action problem( Resolvable::constPtr resolvable, Error error, const std::string & description_r, RpmLevel /*unused*/ ) + { + std::string description; // We just need the 1st line (exception message), the rest is additional rpm output we already reported. + strv::split( description_r, "\n", [&description]( std::string_view line_r, unsigned nr_r ) { + if ( nr_r == 0 ) description = line_r; + return false; + }); + + // finsh progress; indicate error + if ( _progress ) + { + (*_progress).error(); + _progress.reset(); + } + + std::ostringstream s; + s << ( str::Format(_("Installation of %s failed:") ) % resolvable->asString() ) << std::endl; + s << zcb_error2str(error, description); + Zypper::instance().out().error(s.str()); + + Action ret = (Action) read_action_ari (PROMPT_ARI_RPM_INSTALL_PROBLEM, ABORT); + if ( ret == RETRY ) + showProgress( resolvable ); // bsc#1131113: need to re-show progress + + return ret; + } + + virtual void finish( Resolvable::constPtr /*resolvable*/, Error error, const std::string & reason, RpmLevel /*unused*/ ) + { + // finsh progress; indicate error + if ( _progress ) + { + (*_progress).error( error != NO_ERROR ); + _progress.reset(); + } + + if ( error != NO_ERROR ) + // don't write to output, the error should have been reported in problem() (bnc #381203) + Zypper::instance().setExitCode(ZYPPER_EXIT_ERR_ZYPP); + } + + void report( const UserData & userData_r ) override + { + // Any additional rpm output is printed immediately.... + if ( userData_r.type() == ReportType::contentRpmout && userData_r.haskey("line") ) { + processAdditionalRpmOutput( userData_r.get>("line").get() ); + } + } + + virtual void reportend() + { _progress.reset(); } + +private: + void showProgress( Resolvable::constPtr resolvable_r ) + { + Zypper & zypper = Zypper::instance(); + _progress.reset( new Out::ProgressBar( zypper.out(), + "install-resolvable", + // TranslatorExplanation This text is a progress display label e.g. "Installing: foo-1.1.2 [42%]" + str::Format(_("Installing: %s") ) % resolvable_r->asString(), + zypper.runtimeData().rpm_pkg_current, + zypper.runtimeData().rpm_pkgs_total ) ); + (*_progress)->range( 100 ); + } + +private: + scoped_ptr _progress; +}; + +/////////////////////////////////////////////////////////////////// +/// \class FindFileConflictstReportReceive +/// \brief +/////////////////////////////////////////////////////////////////// +struct FindFileConflictstReportReceiver : public callback::ReceiveReport +{ + static std::string mkProgressBarLabel( unsigned skipped_r = 0 ) + { + // translators: A progressbar label + std::string ret { _("Checking for file conflicts:") }; + if ( skipped_r ) { + // translators: progressbar label extension; %1% is the number of skipped items + static str::Format fmt { MSG_WARNINGString(" (%1% skipped)" ).str() }; + ret += fmt % skipped_r; + } + return ret; + } + + virtual void reportbegin() + { + Zypper::instance().out().gap(); + _lastskip = 0; + _progress.reset( new Out::ProgressBar( Zypper::instance().out(), + "fileconflict-check", + mkProgressBarLabel() ) ); + } + + virtual bool start( const ProgressData & progress_r ) + { + (*_progress)->set( progress_r ); + return !Zypper::instance().exitRequested(); + } + + virtual bool progress( const ProgressData & progress_r, const sat::Queue & noFilelist_r ) + { + (*_progress)->set( progress_r ); + if ( noFilelist_r.size() != _lastskip ) { + (*_progress).print( mkProgressBarLabel( (_lastskip = noFilelist_r.size()) ) ); + } + return !Zypper::instance().exitRequested(); + } + + virtual bool result( const ProgressData & progress_r, const sat::Queue & noFilelist_r, const sat::FileConflicts & conflicts_r ) + { + // finsh progress; only conflicts count as error; missing filelists due + // to download-as-needed are just a warning. Different behavior breaks KIWI. + (*_progress).error( !conflicts_r.empty() ); + _progress.reset(); + + if ( conflicts_r.empty() && noFilelist_r.empty() ) + return !Zypper::instance().exitRequested(); + + // show error result + Out & out( Zypper::instance().out() ); + { + Out::XmlNode guard( out, "fileconflict-summary" ); + + if ( ! noFilelist_r.empty() ) // warning + { + out.warning( str::Format( // TranslatorExplanation %1%(number of packages); detailed list follows + PL_( "%1% package had to be excluded from file conflicts check because it is not yet download.", + "%1% packages had to be excluded from file conflicts check because they are not yet downloaded.", + noFilelist_r.size() ) ) % noFilelist_r.size() ); + + out.notePar( 4, str::Format( + // TranslatorExplanation %1%(commandline option) + _("Checking for file conflicts requires not installed packages to be downloaded in advance " + "in order to access their file lists. See option '%1%' in the zypper manual page for details.") + ) % "--download-in-advance / --dry-run --download-only" ); + out.gap(); + } + + if ( ! conflicts_r.empty() ) // error + prompt + { + out.list( "fileconflicts", + // TranslatorExplanation %1%(number of conflicts); detailed list follows + PL_("Detected %1% file conflict:", + "Detected %1% file conflicts:", + conflicts_r.size() ), + conflicts_r, out::FileConflictsListFormater() ); + out.gap(); + + if ( FileConflictPolicy::instance()._replaceFiles ) + { + out.info( _("Conflicting files will be replaced."), " [--replacefiles]" ); + } + else + { + bool cont = read_bool_answer( PROMPT_YN_CONTINUE_ON_FILECONFLICT, str::Str() + // TranslatorExplanation Problem description before asking whether to "Continue? [yes/no] (no):" + <<_("File conflicts happen when two packages attempt to install files with the same name but different contents. If you continue, conflicting files will be replaced losing the previous content.") + << "\n" + << text::qContinue(), + false ); + out.gap(); + + if ( ! cont ) + return false; // aborted. + } + } + } + + return !Zypper::instance().exitRequested(); + } + + virtual void reportend() + { _progress.reset(); } + +private: + scoped_ptr _progress; + unsigned _lastskip = 0; +}; + + +/////////////////////////////////////////////////////////////////// +/// \brief Report active throughout the whole rpm transaction. +/////////////////////////////////////////////////////////////////// +struct SingleTransReportReceiver : public callback::ReceiveReport +{ + void report( const UserData & userData_r ) override + { + if ( userData_r.type() == ReportType::contentLogline ) { + const std::string & line { userData_r.get>("line").get() }; + ReportType::loglevel level { userData_r.get("level") }; + processAdditionalRpmOutputLine( line, level, ReportType::loglevelPrefix( level ) ); + } + } +}; + +/////////////////////////////////////////////////////////////////// + // progress for removing a resolvable during a single transaction +struct RemoveResolvableSAReportReceiver : public callback::ReceiveReport +{ + void start( + Resolvable::constPtr resolvable, + const UserData & /*userdata*/ ) override + { + ++Zypper::instance().runtimeData().rpm_pkg_current; + showProgress( resolvable ); + } + + void progress( + int value, + Resolvable::constPtr resolvable, + const UserData & /*userdata*/ ) override + { + if ( _progress ) + (*_progress)->set( value ); + } + + void finish( Resolvable::constPtr /*resolvable*/, Error error, const UserData & /*userdata*/ ) override + { + // finsh progress; indicate error + if ( _progress ) + { + (*_progress).error( error != NO_ERROR ); + _progress.reset(); + } + + if (error != NO_ERROR) + // set proper exit code, don't write to output, the error should have been reported in problem() + Zypper::instance().setExitCode(ZYPPER_EXIT_ERR_ZYPP); + } + + void report( const UserData & userData_r ) override + { + if ( userData_r.type() == ReportType::contentRpmout + && userData_r.haskey("line") ) { + std::string line; + if ( userData_r.get("line", line) ) { + processAdditionalRpmOutput( line ); + } + } + } + + void reportend() override + { _progress.reset(); } + +private: + void showProgress( Resolvable::constPtr resolvable_r ) + { + Zypper & zypper = Zypper::instance(); + _progress.reset( new Out::ProgressBar( zypper.out(), + "remove-resolvable", + // translators: This text is a progress display label e.g. "Removing packagename-x.x.x [42%]" + str::Format(_("Removing: %s") ) % resolvable_r->asString(), + zypper.runtimeData().rpm_pkg_current, + zypper.runtimeData().rpm_pkgs_total ) ); + (*_progress)->range( 100 ); // progress reports percent + } + +private: + scoped_ptr _progress; +}; + +/////////////////////////////////////////////////////////////////// +// progress for installing a resolvable during a single transaction +struct InstallResolvableSAReportReceiver : public callback::ReceiveReport +{ + void start( Resolvable::constPtr resolvable, const UserData & /*userdata*/ ) override + { + ++Zypper::instance().runtimeData().rpm_pkg_current; + showProgress( resolvable ); + } + + void progress( int value, Resolvable::constPtr resolvable, const UserData & /*userdata*/ ) override + { + if ( _progress ) + (*_progress)->set( value ); + } + + void finish( Resolvable::constPtr /*resolvable*/, Error error, const UserData & /*userdata*/ ) override + { + // finsh progress; indicate error + if ( _progress ) + { + (*_progress).error( error != NO_ERROR ); + _progress.reset(); + } + + if ( error != NO_ERROR ) + // don't write to output, the error should have been reported in problem() (bnc #381203) + Zypper::instance().setExitCode(ZYPPER_EXIT_ERR_ZYPP); + } + + void report( const UserData & userData_r ) override + { + if ( userData_r.type() == ReportType::contentRpmout + && userData_r.haskey("line") ) { + std::string line; + if ( userData_r.get("line", line) ) { + processAdditionalRpmOutput( line ); + } + } + } + + void reportend() override + { _progress.reset(); } + +private: + void showProgress( Resolvable::constPtr resolvable_r ) + { + Zypper & zypper = Zypper::instance(); + _progress.reset( new Out::ProgressBar( zypper.out(), + "install-resolvable", + // TranslatorExplanation This text is a progress display label e.g. "Installing: foo-1.1.2 [42%]" + str::Format(_("Installing: %s") ) % resolvable_r->asString(), + zypper.runtimeData().rpm_pkg_current, + zypper.runtimeData().rpm_pkgs_total ) ); + (*_progress)->range( 100 ); + } + +private: + scoped_ptr _progress; +}; + +/////////////////////////////////////////////////////////////////// +// progress for executing a commit script during a transaction +struct CommitScriptReportSAReportReceiver : public callback::ReceiveReport +{ + void start( + const std::string & scriptType, + const std::string & packageName, + Resolvable::constPtr resolvable, + const UserData & /*userdata*/ ) override + { + showProgress( scriptType, packageName, resolvable ); + } + + void progress( int value, Resolvable::constPtr resolvable, const UserData & /*userdata*/ ) override + { + if ( _progress ) + (*_progress)->set( value ); + } + + void finish( Resolvable::constPtr /*resolvable*/, Error error, const UserData & /*userdata*/ ) override + { + // finsh progress; indicate error + if ( _progress ) + { + ProgressEnd donetag { error==NO_ERROR ? ProgressEnd::done : error==CRITICAL ? ProgressEnd::error : ProgressEnd::attention }; + (*_progress).error( donetag ); + _progress.reset(); + } + + if ( error == WARN ) + // don't write to output, the error should have been reported in problem() (bnc #381203) + Zypper::instance().setExitInfoCode( ZYPPER_EXIT_INF_RPM_SCRIPT_FAILED ); + } + + void report( const UserData & userData_r ) override + { + if ( userData_r.type() == ReportType::contentRpmout + && userData_r.haskey("line") ) { + std::string line; + if ( userData_r.get("line", line) ) { + processAdditionalRpmOutput( line ); + } + } + } + + void reportend() override + { _progress.reset(); } + +private: + void showProgress( const std::string &scriptType, const std::string &packageName, Resolvable::constPtr resolvable_r ) + { + Zypper & zypper = Zypper::instance(); + + if ( resolvable_r ) { + _progress.reset( new Out::ProgressBar( zypper.out(), + "execute-resolvable-script", + // TranslatorExplanation This text is a progress display label e.g. "Installing: foo-1.1.2 [42%]" + str::Format(_("Executing %s script for: %s") ) % scriptType % resolvable_r->asString(), + zypper.runtimeData().rpm_pkg_current, + zypper.runtimeData().rpm_pkgs_total ) ); + } else if ( packageName.size() ) { + _progress.reset( new Out::ProgressBar( zypper.out(), + "execute-resolvable-script", + // TranslatorExplanation This text is a progress display label e.g. "Installing: foo-1.1.2 [42%]" + str::Format(_("Executing %s script for: %s") ) % scriptType % packageName, + zypper.runtimeData().rpm_pkg_current, + zypper.runtimeData().rpm_pkgs_total ) ); + } else { + _progress.reset( new Out::ProgressBar( zypper.out(), + "execute-script", + // TranslatorExplanation This text is a progress display label e.g. "Installing: foo-1.1.2 [42%]" + str::Format( _("Executing %s script") ) % scriptType, zypper.runtimeData().rpm_pkg_current, zypper.runtimeData().rpm_pkgs_total ) ); + } + (*_progress)->range( 100 ); + } + +private: + scoped_ptr _progress; +}; + +/////////////////////////////////////////////////////////////////// +// progress for generic tasks during a transaction ( used for verifying and preparing ) +struct TransactionReportSAReceiver : public callback::ReceiveReport +{ + void start( + const std::string &name, + const UserData & /*userdata*/ ) override + { + showProgress( name ); + } + + void progress( int value, const UserData & /*userdata*/ ) override + { + if ( _progress ) + (*_progress)->set( value ); + } + + void finish( Error error, const UserData & /*userdata*/ ) override + { + // finsh progress; indicate error + if ( _progress ) + { + (*_progress).error( error != NO_ERROR ); + _progress.reset(); + } + + if ( error != NO_ERROR ) + // don't write to output, the error should have been reported in problem() (bnc #381203) + Zypper::instance().setExitCode(ZYPPER_EXIT_ERR_ZYPP); + } + + void report( const UserData & userData_r ) override + { + if ( userData_r.type() == ReportType::contentRpmout + && userData_r.haskey("line") ) { + std::string line; + if ( userData_r.get("line", line) ) { + processAdditionalRpmOutput( line ); + } + } + } + + + void reportend() override + { _progress.reset(); } + +private: + void showProgress( const std::string &name ) + { + Zypper & zypper = Zypper::instance(); + _progress.reset( new Out::ProgressBar( zypper.out(), + "transaction-prepare", name ) ); + (*_progress)->range( 100 ); + } + +private: + scoped_ptr _progress; +}; + + +/////////////////////////////////////////////////////////////////// +// progress for generic tasks during a transaction ( used for verifying and preparing ) +struct CleanupPackageReportSAReceiver : public callback::ReceiveReport +{ + void start( + const std::string &nvra, + const UserData & /*userdata*/ ) override + { + showProgress( nvra ); + } + + void progress( int value, const UserData & /*userdata*/ ) override + { + if ( _progress ) + (*_progress)->set( value ); + } + + void finish( Error error, const UserData & /*userdata*/ ) override + { + // finsh progress; indicate error + if ( _progress ) + { + (*_progress).error( error != NO_ERROR ); + _progress.reset(); + } + + if ( error != NO_ERROR ) + // don't write to output, the error should have been reported in problem() (bnc #381203) + Zypper::instance().setExitCode(ZYPPER_EXIT_ERR_ZYPP); + } + + void report( const UserData & userData_r ) override + { + if ( userData_r.type() == ReportType::contentRpmout + && userData_r.haskey("line") ) { + std::string line; + if ( userData_r.get("line", line) ) { + processAdditionalRpmOutput( line ); + } + } + } + + + void reportend() override + { _progress.reset(); } + +private: + void showProgress( const std::string &name ) + { + Zypper & zypper = Zypper::instance(); + _progress.reset( new Out::ProgressBar( zypper.out(), + "cleanup-task", + // TranslatorExplanation This text is a progress display label e.g. "Installing: foo-1.1.2 [42%]" + str::Format(_("Cleaning up: %s") ) % name, + zypper.runtimeData().rpm_pkg_current, + zypper.runtimeData().rpm_pkgs_total ) ); + (*_progress)->range( 100 ); + } + +private: + scoped_ptr _progress; +}; + + + + +/////////////////////////////////////////////////////////////////// +}; // namespace ZyppRecipients +/////////////////////////////////////////////////////////////////// + +class RpmCallbacks { + + private: + ZmartRecipients::PatchMessageReportReceiver _messageReceiver; + ZmartRecipients::PatchScriptReportReceiver _scriptReceiver; + ZmartRecipients::RemoveResolvableReportReceiver _installReceiver; + ZmartRecipients::InstallResolvableReportReceiver _removeReceiver; + ZmartRecipients::FindFileConflictstReportReceiver _fileConflictsReceiver; + + ZmartRecipients::SingleTransReportReceiver _singleTransaReceiver; // active throughout the whole rpm transaction + ZmartRecipients::RemoveResolvableSAReportReceiver _installSaReceiver; + ZmartRecipients::InstallResolvableSAReportReceiver _removeSaReceiver; + ZmartRecipients::CommitScriptReportSAReportReceiver _scriptSaReceiver; + ZmartRecipients::TransactionReportSAReceiver _transReceiver; + ZmartRecipients::CleanupPackageReportSAReceiver _cleanupReceiver; + + public: + RpmCallbacks() + { + _messageReceiver.connect(); + _scriptReceiver.connect(); + _installReceiver.connect(); + _removeReceiver.connect(); + _fileConflictsReceiver.connect(); + + _singleTransaReceiver.connect(); + _installSaReceiver.connect(); + _removeSaReceiver.connect(); + _scriptSaReceiver.connect(); + _transReceiver.connect(); + _cleanupReceiver.connect(); + } + + ~RpmCallbacks() + { + _messageReceiver.disconnect(); + _scriptReceiver.disconnect(); + _installReceiver.disconnect(); + _removeReceiver.disconnect(); + _fileConflictsReceiver.disconnect(); + + _singleTransaReceiver.disconnect(); + _installSaReceiver.disconnect(); + _removeSaReceiver.disconnect(); + _scriptSaReceiver.disconnect(); + _transReceiver.disconnect(); + _cleanupReceiver.disconnect(); + } +}; + +#endif // ZMART_RPM_CALLBACKS_H +// Local Variables: +// mode: c++ +// c-basic-offset: 2 +// End: diff --git a/zypp-glib/private/cancellable_p.cc b/zypp-glib/private/cancellable_p.cc new file mode 100644 index 0000000000..bd7ad43a8f --- /dev/null +++ b/zypp-glib/private/cancellable_p.cc @@ -0,0 +1,22 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#include "cancellable_p.h" + +namespace zypp::glib +{ + + + + + + + + +} diff --git a/zypp-glib/private/cancellable_p.h b/zypp-glib/private/cancellable_p.h new file mode 100644 index 0000000000..4ad03f48aa --- /dev/null +++ b/zypp-glib/private/cancellable_p.h @@ -0,0 +1,59 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include + +namespace zypp::glib { + + template + class CancellableOp : public zyppng::AsyncOp> + { + // AbstractEventSource interface + public: + + CancellableOp( zyppng::AsyncOpRef> op, GCancellableRef cancellable ) + : _op( std::move(op) ) + , _cancellable( std::move(cancellable) ) + { + if ( _cancellable ) { + _cancellableWatcher = zyppng::SocketNotifier::create( g_cancellable_get_fd( _cancellable.get()), zyppng::SocketNotifier::Read ); + _cancellableWatcher->connect( &zyppng::SocketNotifier::sigActivated, this, &CancellableOp::cancel ); + } + _op->onReady( [this]( zyppng::expected result ) { pipelineReady(std::move(result)); }); + } + + + private: + + void cancel () { + _op.reset(); // cancel by calling the destructor + pipelineReady ( ZYPP_EXCPT_PTR( zypp::Exception("Cancelled by User.") ) ); + } + + void pipelineReady( zyppng::expected &&result ) { + if ( _cancellableWatcher ) { + _cancellableWatcher->setEnabled ( false ); + _cancellableWatcher.reset(); + g_cancellable_release_fd ( _cancellable.get() ); + } + setReady( std::move(result) ); + } + + zyppng::AsyncOpRef> _op; + zyppng::SocketNotifierRef _cancellableWatcher; + GCancellableRef _cancellable; + + int _myFd = -1; + }; +} diff --git a/zypp-glib/private/context_p.h b/zypp-glib/private/context_p.h new file mode 100644 index 0000000000..dac44b18d2 --- /dev/null +++ b/zypp-glib/private/context_p.h @@ -0,0 +1,59 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#ifndef CONTEXT_P_H +#define CONTEXT_P_H + +#include +#include +#include +#include +#include + +#include "globals_p.h" +#include "progressobserver_p.h" + +// the good ol zypp API +#include + +struct ZyppContextPrivate + : public zypp::glib::WrapperPrivateBase +{ + ZyppContextPrivate( ZyppContext *pub ) : WrapperPrivateBase(pub) {}; + + void initializeCpp(); + zyppng::AsyncContextRef &cppType(); + + struct ConstructionProps { + zypp::Pathname _sysRoot = "/"; + zyppng::AsyncContextRef _cppObj; + }; + std::optional _constructProps = ConstructionProps(); + + zypp::glib::GObjectPtr _masterProgress; //synced with the progress observer in zyppng::Context + + zyppng::AsyncContextRef _context; +}; + +/* + * This is the GObject derived type, it is simply used to host our c++ data object and is + * passed as a opaque pointer to the user code. + * This is always created with malloc, so no con or destructors are executed here! + */ +struct _ZyppContext +{ + GObjectClass parent_class; +}; + +/** + * zypp_context_get_cpp: (skip) + */ +zyppng::AsyncContextRef zypp_context_get_cpp( ZyppContext *self ); + +#endif // CONTEXT_P_H diff --git a/zypp-glib/private/error_p.h b/zypp-glib/private/error_p.h new file mode 100644 index 0000000000..625cc2a580 --- /dev/null +++ b/zypp-glib/private/error_p.h @@ -0,0 +1,18 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#ifndef ERROR_P_H +#define ERROR_P_H + +#include +#include + +void zypp_error_from_exception (GError **err, std::exception_ptr exception ); + +#endif diff --git a/zypp-glib/private/expected_p.h b/zypp-glib/private/expected_p.h new file mode 100644 index 0000000000..1c316d7fcd --- /dev/null +++ b/zypp-glib/private/expected_p.h @@ -0,0 +1,21 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#ifndef ZYPP_GLIB_PRIVATE_EXPECTED_P_H +#define ZYPP_GLIB_PRIVATE_EXPECTED_P_H + +#include +struct _ZyppExpected { + GObject parent_instance; + + GError *error; + GValue value; +}; + +#endif diff --git a/zypp-glib/private/globals_p.h b/zypp-glib/private/globals_p.h new file mode 100644 index 0000000000..a0f5443c3b --- /dev/null +++ b/zypp-glib/private/globals_p.h @@ -0,0 +1,329 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#ifndef GLOBALS_P_H +#define GLOBALS_P_H + +#include "zypp-core/AutoDispose.h" +#include +#include +#include +#include + +#define ZYPP_WRAPPED_OBJ (zypp_wrapped_obj_quark ()) +GQuark zypp_wrapped_obj_quark (void); + +namespace zyppng { + ZYPP_FWD_DECL_TYPE_WITH_REFS (Base); +} + +namespace zypp::glib +{ + + namespace internal { + + constexpr std::string_view ZYPP_CPP_OBJECT_PROPERTY_NAME("zypp_cppObj"); + + void registerWrapper ( const zyppng::BaseRef &ref, GObject *wrapper ); + void unregisterWrapper ( const zyppng::BaseRef &ref, GObject *wrapper ); + + template + class WrapperRegistry + { + static std::shared_ptr &storage () + { + static thread_local std::shared_ptr globObj; + return globObj; + } + + public: + static bool hasObj () + { + return storage() ? true : false; + } + + static void setCppObj ( const std::shared_ptr &obj ) + { + auto &ref = storage(); + g_assert(!ref); + ref = obj; + } + + static std::shared_ptr takeCppObj () + { + auto objCopy = storage(); + storage().reset(); + return objCopy; + } + }; + } + + /*! + * Helper class for a private GObject implementation for a Cpp wrapper type, + * the subclass needs to have the methods: + * + * - void initializeCpp( ) + * If no construct cppObj property is set creates a new instance of the cpp type and + * connects signals etc, this is the case whenever the GObject type is created and there is no + * Cpp instance that should be wrapped. If a onstruct cppObj property is set a already existing and intialized + * cpp Object is to be used. + * + * - std::shared_ptr &cppType() + * Return the current cpp instance + * + * The GObject type needs to have a private that is derived from WrapperPrivateBase e.g.: + * \code + * struct MyClassPrivate + * : public zypp::glib::WrapperPrivateBase + * { + * MyClassPrivate( MyClass *pub ) : WrapperPrivateBase(pub) { }; + * + * // automatically called by the Wrapper superclass + * void initializeCpp() { + * if ( _constructProps && _constructProps._cppObj ) { + * // we got a ready cpp Object, ignore all other construct properties + * _cppRef = std::move( _constructProps._cppObj ); + * } else { + * // custom code to initialize + * _cppRef = MyClassCpp::create(); + * } + * _contructProps.reset(); // don't need those anymore + * + * // here connect signals etc + * ... + * } + * + * MyClassCppRef &cppType() { + * return _cppRef; + * } + * + * // a place to store construct only properties + * struct ConstructionProps { + * MyClassCppRef _cppObj; + * }; + * + * // those properties are set at construction right away, and will be unset + * // as soon as they have been consumed + * std::optional _constructProps = ConstructionProps(); + * MyClassCppRef _cppRef; + * }; + * \endcode + * + * Have a construction property that can hold the Cpp reference, sadly GObject construction + * is somewhat different to C++ so that contructor arguments/properties are set one by one + * with the set_property() functions.. however C++ requires its constructor properties right away. + * So we have to store the construct only properties somewhere and then query them later + * + * \code + * + * typedef enum + * { + * PROP_CPPOBJ = 1, + * N_PROPERTIES + * } MyClassProperty; + * + * void my_class_class_init( ZyppContextClass *klass ) + * { + * GObjectClass *object_class = G_OBJECT_CLASS(klass); + * object_class->constructed = my_class_constructed; + * object_class->finalize = my_class_finalize; + * + * object_class->set_property = my_class_set_property; + * object_class->get_property = my_class_get_property; + * obj_properties[PROP_CPPOBJ] = ZYPP_GLIB_ADD_CPPOBJ_PROP(); + * + * // Add other properties ...... + * + * g_object_class_install_properties (object_class, + * N_PROPERTIES, + * obj_properties); + * } + * + * static void + * my_class_class_set_property (GObject *object, + * guint property_id, + * const GValue *value, + * GParamSpec *pspec) + * { + * MyClass *self = MY_CLASS (object); + * ZYPP_GLIB_WRAPPER_D( MyClass, my_class ); + * + * switch ((MyClassProperty)property_id ) + * { + * case PROP_CPPOBJ: ZYPP_GLIB_SET_CPPOBJ_PROP( MyClassCpp, value, d->_constructProps->_cppObj) + * default: + * // We don't have any other property... + * G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + * break; + * } + * } + * + * + * \endcode + * + * Finally initialize the private in its own type_name_init() and type_name_constructed() function: + * \code + * static void my_class_init( MyClass *self ) + * { + * // call C++ constructors for the Private + * ZYPP_GLIB_CONSTRUCT_WRAPPER_PRIVATE(MyClass, my_class); + * } + * + * static void my_class_constructed ( MyClass *self ) + * { + * // call initialize() to signal that we have everything to create + * // or pick up our cpp object + * ZYPP_GLIB_INIT_WRAPPER_PRIVATE(MyClass, my_class); + * } + * + * static void my_class_finalize (GObject *gobject) + * { + * auto *self = MY_CLASS (gobject); + * + * ZYPP_GLIB_FINALIZE_WRAPPER_PRIVATE( MyClass, my_class ) + * + * // always call parent class finalizer + * G_OBJECT_CLASS (my_class_parent_class)->finalize (gobject); + * } + * \endcode + * + */ + template + class WrapperPrivateBase + { + + public: + WrapperPrivateBase(PublicGObject *gObjPtr) : _gObject(gObjPtr) {} + WrapperPrivateBase(const WrapperPrivateBase &) = delete; + WrapperPrivateBase(WrapperPrivateBase &&) = delete; + WrapperPrivateBase &operator=(const WrapperPrivateBase &) = delete; + WrapperPrivateBase &operator=(WrapperPrivateBase &&) = delete; + virtual ~WrapperPrivateBase() = default; + + void initialize () { + static_cast(this)->initializeCpp(); + const auto &ptr = static_cast(this)->cppType(); + if ( !ptr ) + g_error("cppType() must return a instance at this point. This is a bug!"); + + internal::registerWrapper ( static_cast(this)->cppType(), G_OBJECT(_gObject) ); + } + + void finalize() { + std::for_each ( _signalConns.begin (), _signalConns.end(), []( zyppng::connection &conn ) { conn.disconnect(); }); + internal::unregisterWrapper ( static_cast(this)->cppType(), G_OBJECT(_gObject) ); + } + + public: + PublicGObject *_gObject = nullptr; + std::vector _signalConns; + }; + + + template + auto zypp_wrap_cpp( const std::shared_ptr &ref ) { + void *ptr = ref->data( ZYPP_WRAPPED_OBJ ); + auto existingWrapper = zypp::glib::GLibTypeTraits::GObjectTrait::gobjectCast( G_OBJECT(ptr) ); + if ( existingWrapper ) { + return zypp::glib::GObjectPtr ( existingWrapper, retain_object ); + } + + g_assert( !ptr ); + return zypp::glib::g_object_create( internal::ZYPP_CPP_OBJECT_PROPERTY_NAME.data(), (void *)&ref ); + } + +} + +/** + * Equivalent of Z_D() in the glib world, creates a pointer to the private data called \a d + */ +#define ZYPP_GLIB_WRAPPER_D( TypeName, type_name ) \ + auto d = static_cast(type_name##_get_instance_private( self )) + +#define ZYPP_GLIB_CONSTRUCT_WRAPPER_PRIVATE( TypeName, type_name ){ \ + ZYPP_GLIB_WRAPPER_D( TypeName, type_name ); \ + new( d ) TypeName##Private( self ); /*call all constructors*/ \ + } + +#define ZYPP_GLIB_INIT_WRAPPER_PRIVATE( TypeName, type_name ){ \ + ZYPP_GLIB_WRAPPER_D( TypeName, type_name ); \ + d->initialize(); \ + } + +#define ZYPP_GLIB_FINALIZE_WRAPPER_PRIVATE( TypeName, type_name ){ \ + ZYPP_GLIB_WRAPPER_D( TypeName, type_name ); \ + d->finalize(); \ + d->~TypeName##Private(); \ + } + +#define ZYPP_GLIB_ADD_CPPOBJ_PROP() \ + g_param_spec_pointer ( ::zypp::glib::internal::ZYPP_CPP_OBJECT_PROPERTY_NAME.data(), \ + nullptr, \ + nullptr, \ + GParamFlags( G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE) ) + +#define ZYPP_GLIB_SET_CPPOBJ_PROP( CppType, value, target ) { \ + gpointer obj = g_value_get_pointer( value ); \ + if ( obj ) \ + target = *( reinterpret_cast(obj) ); \ + break; \ + } + + +/** + * Helper macros to reduce the boilerplate code we'd need to repeat over and + * over again. This is to be used with the \ref zypp::glib:WrapperPrivateBase and + * a GObject with a instance private. \ref G_DEFINE_TYPE_WITH_PRIVATE. + * See \ref ZyppContext as a example. + */ +#define ZYPP_DECLARE_GOBJECT_BOILERPLATE( TypeName, type_name ) \ + static void type_name##_init( TypeName *self ); \ + static void type_name##_constructed ( GObject *gobject ); \ + static void type_name##_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec ); \ + static void type_name##_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec ); \ + static void type_name##_finalize (GObject *gobject); \ + static TypeName##Private * type_name##_get_private( TypeName *self ); + +#define ZYPP_DEFINE_GOBJECT_BOILERPLATE( ModuleObjName, module_obj_name, MODULE, OBJ_NAME ) \ + static void module_obj_name##_init( ModuleObjName *self )\ + {\ + ZYPP_GLIB_CONSTRUCT_WRAPPER_PRIVATE(ModuleObjName, module_obj_name);\ + }\ + \ + static void module_obj_name##_constructed ( GObject *gobject ) { \ + g_return_if_fail( (gobject != nullptr) && MODULE##_IS_##OBJ_NAME(gobject) ); \ + \ + /* Call the parent class's constructed method */ \ + G_OBJECT_CLASS(module_obj_name##_parent_class)->constructed(gobject); \ + \ + ModuleObjName *self = MODULE##_##OBJ_NAME(gobject); \ + ZYPP_GLIB_INIT_WRAPPER_PRIVATE(ModuleObjName, module_obj_name); \ + }\ + \ + static void module_obj_name##_finalize (GObject *gobject) \ + { \ + ModuleObjName *self = MODULE##_##OBJ_NAME(gobject); \ + \ + ZYPP_GLIB_FINALIZE_WRAPPER_PRIVATE( ModuleObjName, module_obj_name ) \ + \ + /* always call parent class finalizer*/ \ + G_OBJECT_CLASS (module_obj_name##_parent_class)->finalize (gobject); \ + } \ + \ + static ModuleObjName##Private * module_obj_name##_get_private( ModuleObjName *self ) { \ + return static_cast( module_obj_name##_get_instance_private( self ) ) ; \ + } + +#define ZYPP_INIT_GOBJECT_BOILERPLATE_KLASS( module_obj_name, object_class ) \ + object_class->constructed = module_obj_name##_constructed; \ + object_class->finalize = module_obj_name##_finalize; \ + object_class->set_property = module_obj_name##_set_property; \ + object_class->get_property = module_obj_name##_get_property + +#endif diff --git a/zypp-glib/private/infobase_p.h b/zypp-glib/private/infobase_p.h new file mode 100644 index 0000000000..7512a3b9e4 --- /dev/null +++ b/zypp-glib/private/infobase_p.h @@ -0,0 +1,133 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#ifndef ZYPP_GLIB_PRIVATE_INFOBASE_P_H +#define ZYPP_GLIB_PRIVATE_INFOBASE_P_H + +#include + +template +struct ZyppInfoBaseImpl +{ + static gboolean T_IS_EXPECTED_GLIBTYPE (gpointer ptr) { + return ZYPP_IS_INFO_BASE(ptr) && G_TYPE_CHECK_INSTANCE_TYPE ( ptr, GlibTypeFun() ); + } + + // make sure to call T_IS_EXPECTED_GLIBTYPE before calling this + static auto T_GET_PRIVATE( ZyppInfoBase *self ) { + return GetPrivateFun( G_TYPE_CHECK_INSTANCE_CAST (self, GlibTypeFun(), T) ); + } + + static gchar* zypp_info_base_alias ( ZyppInfoBase *self ) + { + g_return_val_if_fail ( T_IS_EXPECTED_GLIBTYPE (self), nullptr ); + return g_strdup( T_GET_PRIVATE( self )->_info.alias().c_str() ); + } + + static gchar* zypp_info_base_escaped_alias (ZyppInfoBase *self) + { + g_return_val_if_fail ( T_IS_EXPECTED_GLIBTYPE (self), nullptr ); + return g_strdup( T_GET_PRIVATE( self )->_info.escaped_alias().c_str() ); + } + + static gchar* zypp_info_base_name (ZyppInfoBase *self) + { + g_return_val_if_fail ( T_IS_EXPECTED_GLIBTYPE (self), nullptr ); + return g_strdup( T_GET_PRIVATE( self )->_info.name().c_str() ); + } + + static gchar* zypp_info_base_raw_name (ZyppInfoBase *self) + { + g_return_val_if_fail ( T_IS_EXPECTED_GLIBTYPE (self), nullptr ); + return g_strdup( T_GET_PRIVATE( self )->_info.rawName().c_str() ); + } + + static gchar* zypp_info_base_label (ZyppInfoBase *self) + { + g_return_val_if_fail ( T_IS_EXPECTED_GLIBTYPE (self), nullptr ); + return g_strdup( T_GET_PRIVATE( self )->_info.label().c_str() ); + } + + static gchar* zypp_info_base_as_user_string (ZyppInfoBase *self) + { + g_return_val_if_fail ( T_IS_EXPECTED_GLIBTYPE (self), nullptr ); + return g_strdup( T_GET_PRIVATE( self )->_info.asUserString().c_str() ); + } + + static gboolean zypp_info_base_enabled (ZyppInfoBase *self) + { + g_return_val_if_fail ( T_IS_EXPECTED_GLIBTYPE (self), false ); + return T_GET_PRIVATE( self )->_info.enabled(); + } + + static gboolean zypp_info_base_autorefresh (ZyppInfoBase *self) + { + g_return_val_if_fail ( T_IS_EXPECTED_GLIBTYPE (self), false ); + return T_GET_PRIVATE( self )->_info.autorefresh(); + } + + static gchar* zypp_info_base_filepath ( ZyppInfoBase *self ) + { + g_return_val_if_fail ( T_IS_EXPECTED_GLIBTYPE (self), nullptr ); + return g_strdup( T_GET_PRIVATE( self )->_info.filepath().c_str() ); + } + + static void zypp_info_base_set_alias ( ZyppInfoBase *self, const gchar* alias ) + { + g_return_if_fail ( T_IS_EXPECTED_GLIBTYPE (self) ); + T_GET_PRIVATE( self )->_info.setAlias( alias ); + } + + static void zypp_info_base_set_name ( ZyppInfoBase *self, const gchar *name ) + { + g_return_if_fail ( T_IS_EXPECTED_GLIBTYPE (self) ); + T_GET_PRIVATE( self )->_info.setName( name ); + } + + static void zypp_info_base_set_enabled ( ZyppInfoBase *self, gboolean enabled ) + { + g_return_if_fail ( T_IS_EXPECTED_GLIBTYPE (self) ); + T_GET_PRIVATE( self )->_info.setEnabled( enabled ); + } + + static void zypp_info_base_set_autorefresh ( ZyppInfoBase *self, gboolean enabled ) + { + g_return_if_fail ( T_IS_EXPECTED_GLIBTYPE (self) ); + T_GET_PRIVATE( self )->_info.setAutorefresh( enabled ); + } + + static void zypp_info_base_set_filepath ( ZyppInfoBase *self, const gchar* filepath ) + { + g_return_if_fail ( T_IS_EXPECTED_GLIBTYPE (self) ); + T_GET_PRIVATE( self )->_info.setFilepath( filepath ); + } + + static void init_interface( ZyppInfoBaseInterface *iface ) + { + iface->alias = zypp_info_base_alias; + iface->escaped_alias = zypp_info_base_escaped_alias; + iface->name = zypp_info_base_name; + iface->raw_name = zypp_info_base_raw_name; + iface->label = zypp_info_base_label; + iface->as_user_string = zypp_info_base_as_user_string; + iface->enabled = zypp_info_base_enabled; + iface->autorefresh = zypp_info_base_autorefresh; + iface->filepath = zypp_info_base_filepath; + + iface->set_alias = zypp_info_base_set_alias; + iface->set_name = zypp_info_base_set_name; + iface->set_enabled = zypp_info_base_set_enabled; + iface->set_autorefresh = zypp_info_base_set_autorefresh; + iface->set_filepath = zypp_info_base_set_filepath; + } + +}; + + +#endif // INFOBASE_P_H diff --git a/zypp-glib/private/managedfile_p.h b/zypp-glib/private/managedfile_p.h new file mode 100644 index 0000000000..3ccd8b5b7c --- /dev/null +++ b/zypp-glib/private/managedfile_p.h @@ -0,0 +1,21 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_PRIVATE_MANAGEDFILE_P_H +#define ZYPP_GLIB_PRIVATE_MANAGEDFILE_P_H + +#include +#include + +struct _ZyppManagedFile { + zypp::ManagedFile _file; +}; + +ZyppManagedFile *zypp_managed_file_new( const zypp::ManagedFile &f ); + +#endif diff --git a/zypp-glib/private/progressobserver_p.h b/zypp-glib/private/progressobserver_p.h new file mode 100644 index 0000000000..6bbf711efd --- /dev/null +++ b/zypp-glib/private/progressobserver_p.h @@ -0,0 +1,52 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_PRIVATE_TASKSTATUS_P_H +#define ZYPP_GLIB_PRIVATE_TASKSTATUS_P_H + +#include +#include +#include +#include + +#include +#include "globals_p.h" + +struct ZyppProgressObserverPrivate + : public zypp::glib::WrapperPrivateBase +{ + + ZyppProgressObserverPrivate( ZyppProgressObserver *pub ) : WrapperPrivateBase(pub) {}; + + zyppng::ProgressObserverRef &cppType() { + return _cppObj; + } + + void initializeCpp();; + + struct ConstrProps { + zyppng::ProgressObserverRef _cppObj; + }; + std::optional _constrProps = ConstrProps(); + + + zyppng::ProgressObserverRef _cppObj; + zypp::glib::GListContainer _children; +}; + +struct _ZyppProgressObserver +{ + GObjectClass parent_class; +}; + +/** + * zypp_progress_observer_get_cpp: (skip) + */ +zyppng::ProgressObserverRef zypp_progress_observer_get_cpp( ZyppProgressObserver *self ); + +#endif diff --git a/zypp-glib/private/repoinfo_p.h b/zypp-glib/private/repoinfo_p.h new file mode 100644 index 0000000000..c97f133ea8 --- /dev/null +++ b/zypp-glib/private/repoinfo_p.h @@ -0,0 +1,50 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#ifndef ZYPP_GLIB_PRIVATE_REPOINFO_P_H +#define ZYPP_GLIB_PRIVATE_REPOINFO_P_H + +#include +#include +#include +#include +#include + +struct ZyppRepoInfoPrivate +{ + struct ConstructionProps { + std::optional _cppObj; + zypp::glib::ZyppContextRef _context = nullptr; + }; + + std::optional _constrProps = ConstructionProps(); + zyppng::RepoInfo _info{ zyppng::ContextBaseRef(nullptr) }; + + ZyppRepoInfoPrivate( ZyppRepoInfo *pub ) : _gObject(pub) {} + void initialize(); + void finalize(){} + +private: + ZyppRepoInfo *_gObject = nullptr; +}; + + +struct _ZyppRepoInfo +{ + GObjectClass parent_class; +}; + +ZyppRepoInfo *zypp_wrap_cpp ( zyppng::RepoInfo info ); + +/** + * zypp_repo_info_get_cpp: (skip) + */ +zyppng::RepoInfo &zypp_repo_info_get_cpp( ZyppRepoInfo *self ); + +#endif // ZYPP_GLIB_PRIVATE_REPOINFO_P_H diff --git a/zypp-glib/private/repomanager_p.h b/zypp-glib/private/repomanager_p.h new file mode 100644 index 0000000000..a5fe70d45d --- /dev/null +++ b/zypp-glib/private/repomanager_p.h @@ -0,0 +1,45 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#ifndef ZYPP_GLIB_PRIVATE_REPOMANAGER_P_H +#define ZYPP_GLIB_PRIVATE_REPOMANAGER_P_H + +#include +#include +#include +#include + +#include "globals_p.h" + +struct ZyppRepoManagerPrivate + : public zypp::glib::WrapperPrivateBase +{ + ZyppRepoManagerPrivate( ZyppRepoManager *pub ) : WrapperPrivateBase(pub) {}; + + void initializeCpp(); + zyppng::AsyncRepoManagerRef &cppType() { + return _cppObj; + } + + struct ConstructData { + zyppng::AsyncRepoManagerRef _cppObj; + zypp::glib::ZyppContextRef _ctx; + }; + std::optional _constrProps = ConstructData(); + + zyppng::AsyncRepoManagerRef _cppObj; + + std::vector _asyncOpsRunning; +}; + +struct _ZyppRepoManager +{ + GObjectClass parent_class; +}; +#endif // ZYPP_GLIB_PRIVATE_REPOMANAGER_P_H diff --git a/zypp-glib/private/repository_p.h b/zypp-glib/private/repository_p.h new file mode 100644 index 0000000000..49c1ce7c01 --- /dev/null +++ b/zypp-glib/private/repository_p.h @@ -0,0 +1,17 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_PRIVATE_REPOSITORY_P_H +#define ZYPP_GLIB_PRIVATE_REPOSITORY_P_H + +#include +#include + +ZyppRepository *zypp_repository_new( const zypp::Repository &cppVersion, ZyppRepoManager *mgr ); + +#endif // ZYPP_GLIB_PRIVATE_REPOSITORY_P_H diff --git a/zypp-glib/private/serviceinfo_p.h b/zypp-glib/private/serviceinfo_p.h new file mode 100644 index 0000000000..c863c02611 --- /dev/null +++ b/zypp-glib/private/serviceinfo_p.h @@ -0,0 +1,45 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#ifndef ZYPP_GLIB_PRIVATE_SERVICEINFO_P_H +#define ZYPP_GLIB_PRIVATE_SERVICEINFO_P_H + +#include +#include +#include +#include +#include + +struct ZyppServiceInfoPrivate +{ + struct ConstructionProps { + std::optional _cppObj; + zypp::glib::ZyppContextRef _context = nullptr; + }; + std::optional _constrProps = ConstructionProps(); + + zyppng::ServiceInfo _info{ zyppng::ContextBaseRef(nullptr) }; + + ZyppServiceInfoPrivate( ZyppServiceInfo *pub ) : _gObject(pub) {} + void initialize(); + void finalize(){} + +private: + ZyppServiceInfo *_gObject = nullptr; +}; + +struct _ZyppServiceInfo { + GObject parent_instance; +}; + + +ZyppServiceInfo *zypp_wrap_cpp(zyppng::ServiceInfo info); + + +#endif // SERVICEINFO_P_H diff --git a/zypp-glib/progressobserver.cc b/zypp-glib/progressobserver.cc new file mode 100644 index 0000000000..9b4b59b4d4 --- /dev/null +++ b/zypp-glib/progressobserver.cc @@ -0,0 +1,459 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "private/progressobserver_p.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +G_DEFINE_FINAL_TYPE_WITH_PRIVATE( ZyppProgressObserver, zypp_progress_observer, G_TYPE_OBJECT ) + +/* Signals */ +typedef enum { + SIG_FINISHED = 1, + SIG_STARTED, + SIG_NEW_CHILD, + SIG_EVENT, + LAST_SIGNAL +} ZyppProgressObserverSignals; + +static guint signals[LAST_SIGNAL] = { 0, }; + +typedef enum +{ + PROP_CPPOBJ = 1, + PROP_LABEL, + PROP_BASE_STEPS, + PROP_STEPS, + PROP_VALUE, + PROP_PROGRESS, + N_PROPERTIES +} ZyppProgressObserverProperty; + +#define ZYPP_PROGRESS_OBSERVER_D() \ + ZYPP_GLIB_WRAPPER_D( ZyppProgressObserver, zypp_progress_observer ) + + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +static void zypp_progress_observer_constructed (GObject *gobject); +static void zypp_progress_observer_finalize (GObject *gobject); +static void zypp_progress_observer_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); +static void zypp_progress_observer_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); + +static void zypp_progress_observer_class_init (ZyppProgressObserverClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + object_class->constructed = zypp_progress_observer_constructed; + object_class->finalize = zypp_progress_observer_finalize; + object_class->get_property = zypp_progress_observer_get_property; + object_class->set_property = zypp_progress_observer_set_property; + + { + std::vector signal_parms = {}; + signals[SIG_STARTED] = + g_signal_newv ("start", + G_TYPE_FROM_CLASS (klass), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS), + NULL /* closure */, + NULL /* accumulator */, + NULL /* accumulator data */, + NULL /* C marshaller */, + G_TYPE_NONE /* return_type */, + signal_parms.size() /* n_params */, + signal_parms.data() ); + } + + { + std::vector signal_parms = {}; + signals[SIG_FINISHED] = + g_signal_newv ("finished", + G_TYPE_FROM_CLASS (klass), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS), + NULL /* closure */, + NULL /* accumulator */, + NULL /* accumulator data */, + NULL /* C marshaller */, + G_TYPE_NONE /* return_type */, + signal_parms.size() /* n_params */, + signal_parms.data() ); + } + + { + std::vector signal_parms = { ZYPP_TYPE_PROGRESS_OBSERVER }; + signals[SIG_NEW_CHILD] = + g_signal_newv ("new-subtask", + G_TYPE_FROM_CLASS (klass), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS), + NULL /* closure */, + NULL /* accumulator */, + NULL /* accumulator data */, + NULL /* C marshaller */, + G_TYPE_NONE /* return_type */, + signal_parms.size() /* n_params */, + signal_parms.data() ); + } + + { + std::vector signal_parms = { ZYPP_TYPE_USER_REQUEST }; + signals[SIG_EVENT] = + g_signal_newv ("event", + G_TYPE_FROM_CLASS (klass), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS), + NULL /* closure */, + NULL /* accumulator */, + NULL /* accumulator data */, + NULL /* C marshaller */, + G_TYPE_NONE /* return_type */, + signal_parms.size() /* n_params */, + signal_parms.data() ); + } + + obj_properties[PROP_CPPOBJ] = ZYPP_GLIB_ADD_CPPOBJ_PROP(); + + obj_properties[PROP_LABEL] = g_param_spec_string ( + "label", + nullptr, + "The label of the corresponding Task.", + nullptr /* default value */, + GParamFlags( G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY )); + + obj_properties[PROP_BASE_STEPS] = g_param_spec_int ( + "base-steps", + nullptr, + "The number of steps for this task.", + 0.0, /* minimum */ + G_MAXINT, /* max */ + 0, /* default */ + GParamFlags( G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY )); + + obj_properties[PROP_STEPS] = g_param_spec_double ( + "steps", + nullptr, + "The number of steps for this task and weighted subtasks.", + 0.0, /* minimum */ + G_MAXDOUBLE, /* max */ + 0, /* default */ + GParamFlags( G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY )); + + obj_properties[PROP_VALUE] = g_param_spec_double ( + "value", + nullptr, + "The progress tasks's current step counter value.", + 0.0, /* minimum */ + G_MAXDOUBLE, /* max */ + 0, /* default */ + GParamFlags( G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY )); + + obj_properties[PROP_PROGRESS] = g_param_spec_double ( + "progress", + nullptr, + "The progress tasks's current step percentage value.", + 0.0, /* minimum */ + 100.0, /* max */ + 0, /* default */ + GParamFlags( G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY )); + + g_object_class_install_properties ( object_class, N_PROPERTIES, obj_properties ); +} + +static void zypp_progress_observer_init ( ZyppProgressObserver *self ) +{ + ZYPP_GLIB_CONSTRUCT_WRAPPER_PRIVATE(ZyppProgressObserver, zypp_progress_observer); +} + +static void zypp_progress_observer_constructed ( GObject *object ) +{ + g_return_if_fail( ZYPP_IS_PROGRESS_OBSERVER(object) ); + ZyppProgressObserver *self = ZYPP_PROGRESS_OBSERVER (object); + ZYPP_GLIB_INIT_WRAPPER_PRIVATE(ZyppProgressObserver, zypp_progress_observer); +} + +static void +zypp_progress_observer_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail( ZYPP_IS_PROGRESS_OBSERVER(object) ); + ZyppProgressObserver *self = ZYPP_PROGRESS_OBSERVER (object); + ZYPP_PROGRESS_OBSERVER_D(); + + switch ((ZyppProgressObserverProperty)property_id ) { + case PROP_CPPOBJ: + g_return_if_fail( d->_constrProps ); // only if the constr props are still valid + ZYPP_GLIB_SET_CPPOBJ_PROP( zyppng::ProgressObserverRef, value, d->_constrProps->_cppObj ) + case PROP_LABEL: { + zypp_progress_observer_set_label( self, g_value_get_string ( value ) ); + break; + } + case PROP_BASE_STEPS: { + zypp_progress_observer_set_base_steps( self, g_value_get_int ( value ) ); + break; + } + case PROP_VALUE: { + zypp_progress_observer_set_current ( self, g_value_get_double ( value ) ); + break; + } + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +zypp_progress_observer_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail( ZYPP_IS_PROGRESS_OBSERVER(object) ); + ZyppProgressObserver *self = ZYPP_PROGRESS_OBSERVER (object); + ZYPP_PROGRESS_OBSERVER_D(); + + switch ((ZyppProgressObserverProperty)property_id ) + { + case PROP_LABEL: { + g_value_set_string ( value, d->_cppObj->label().c_str() ); + break; + } + case PROP_BASE_STEPS: { + g_value_set_int ( value, zypp_progress_observer_get_steps(self) ); + break; + } + case PROP_STEPS: { + g_value_set_double ( value, zypp_progress_observer_get_steps(self) ); + break; + } + case PROP_VALUE: { + g_value_set_double ( value, zypp_progress_observer_get_current(self) ); + break; + } + case PROP_PROGRESS: { + g_value_set_double ( value, zypp_progress_observer_get_progress(self) ); + break; + } + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void zypp_progress_observer_finalize (GObject *gobject) +{ + ZyppProgressObserver *self = ZYPP_PROGRESS_OBSERVER(gobject); + ZYPP_PROGRESS_OBSERVER_D(); + + // make sure our children don't try to send data to us anymore. + for ( ZyppProgressObserver *child : d->_children ) + g_signal_handlers_disconnect_by_data( child, self ); + + d->~ZyppProgressObserverPrivate(); + + // always call parent class finalizer + G_OBJECT_CLASS (zypp_progress_observer_parent_class)->finalize (gobject); +} + + +static void child_finished ( ZyppProgressObserver *sender, ZyppProgressObserver *self ) +{ + ZYPP_PROGRESS_OBSERVER_D(); + //forget about it + g_signal_handlers_disconnect_by_data( sender, self ); + + auto i = d->_children.find( sender ); + if ( i != d->_children.end() ) + d->_children.remove(i); +} + +// here in the C world we only need to track the childs lifetime, progress calculation +// and tracking is done in the C++ world anyway +static void zypp_progress_observer_reg_child ( ZyppProgressObserver *self, zypp::glib::ZyppProgressObserverRef &&child ) +{ + if ( !child ) + return; + + ZYPP_PROGRESS_OBSERVER_D(); + + if ( d->_children.find( child.get() )!= d->_children.end() ) + return; + + // first things first: make sure the ref is in our list so its cleaned up + d->_children.push_back ( child.get() ); + + // the ref is now tracked by the list + auto rawChild = child.detach(); + + // once the child is finished, forget about it + g_signal_connect ( rawChild, "finished", G_CALLBACK( child_finished ), self ); +} + +void zypp_progress_observer_add_subtask( ZyppProgressObserver *self, ZyppProgressObserver *newChild, gfloat weight ) +{ + ZYPP_PROGRESS_OBSERVER_D(); + auto dChild = static_cast(zypp_progress_observer_get_instance_private( newChild )); + d->_cppObj->registerSubTask ( dChild->_cppObj, weight ); +} + +const gchar *zypp_progress_observer_get_label ( ZyppProgressObserver *self ) +{ + ZYPP_PROGRESS_OBSERVER_D(); + return d->_cppObj->label().c_str(); +} + +gdouble zypp_progress_observer_get_steps(ZyppProgressObserver *self) +{ + ZYPP_PROGRESS_OBSERVER_D(); + return d->_cppObj->steps(); +} + +gint zypp_progress_observer_get_base_steps(ZyppProgressObserver *self) +{ + ZYPP_PROGRESS_OBSERVER_D(); + return d->_cppObj->baseSteps(); +} + +gdouble zypp_progress_observer_get_current ( ZyppProgressObserver *self ) +{ + ZYPP_PROGRESS_OBSERVER_D(); + return d->_cppObj->current(); +} + +gdouble zypp_progress_observer_get_progress ( ZyppProgressObserver *self ) +{ + ZYPP_PROGRESS_OBSERVER_D(); + return d->_cppObj->progress (); +} + +void zypp_progress_observer_set_label(ZyppProgressObserver *self, const gchar *label) +{ + ZYPP_PROGRESS_OBSERVER_D(); + d->_cppObj->setLabel( zypp::str::asString(label) ); +} + +void zypp_progress_observer_set_base_steps (ZyppProgressObserver *self, gint max ) +{ + ZYPP_PROGRESS_OBSERVER_D(); + d->_cppObj->setBaseSteps(max); +} + +void zypp_progress_observer_set_current (ZyppProgressObserver *self, gdouble value ) +{ + ZYPP_PROGRESS_OBSERVER_D(); + d->_cppObj->setCurrent(value); +} + +void zypp_progress_observer_inc(ZyppProgressObserver *self, gint increase) +{ + ZYPP_PROGRESS_OBSERVER_D(); + d->_cppObj->inc(increase, {}); +} + +void zypp_progress_observer_set_finished(ZyppProgressObserver *self) +{ + ZYPP_PROGRESS_OBSERVER_D(); + d->_cppObj->setFinished(); +} + +const GList *zypp_progress_observer_get_children(ZyppProgressObserver *self) +{ + ZYPP_PROGRESS_OBSERVER_D(); + return d->_children.get(); +} + +void ZyppProgressObserverPrivate::initializeCpp() { + + if ( _constrProps && _constrProps->_cppObj ) { + _cppObj = std::move( _constrProps->_cppObj ); + } else { + _cppObj = zyppng::ProgressObserver::create(); + } + _constrProps.reset(); + + _signalConns.insert ( _signalConns.end(), { + _cppObj->connectFunc( &zyppng::ProgressObserver::sigLabelChanged, [this]( auto &, const std::string & ){ + g_object_notify_by_pspec ( G_OBJECT(_gObject), obj_properties[PROP_LABEL] ); + }), + _cppObj->connectFunc( &zyppng::ProgressObserver::sigStepsChanged, [this]( auto &, double ){ + g_object_notify_by_pspec ( G_OBJECT(_gObject), obj_properties[PROP_STEPS] ); + }), + _cppObj->connectFunc( &zyppng::ProgressObserver::sigValueChanged, [this]( auto &, double ){ + g_object_notify_by_pspec ( G_OBJECT(_gObject), obj_properties[PROP_VALUE] ); + }), + _cppObj->connectFunc( &zyppng::ProgressObserver::sigProgressChanged, [this]( auto &, double ){ + g_object_notify_by_pspec ( G_OBJECT(_gObject), obj_properties[PROP_PROGRESS] ); + }), + _cppObj->connectFunc( &zyppng::ProgressObserver::sigStarted, [this]( zyppng::ProgressObserver &sender ){ + g_signal_emit (_gObject, signals[SIG_STARTED], 0); + }), + _cppObj->connectFunc( &zyppng::ProgressObserver::sigFinished, [this]( zyppng::ProgressObserver &sender, zyppng::ProgressObserver::FinishResult ){ + g_signal_emit (_gObject, signals[SIG_FINISHED], 0); + }), + _cppObj->connectFunc( &zyppng::ProgressObserver::sigNewSubprogress, [this]( auto &, zyppng::ProgressObserverRef newRef ){ + auto wrapped = zypp::glib::zypp_wrap_cpp( newRef ); + zypp_progress_observer_reg_child ( _gObject, zypp::glib::ZyppProgressObserverRef(wrapped) ); + g_signal_emit( _gObject, signals[SIG_NEW_CHILD], 0, wrapped.get() ); + }), + _cppObj->connectFunc( &zyppng::ProgressObserver::sigEvent, [this]( zyppng::ProgressObserver &s, zyppng::UserRequestRef req ) { + switch( req->type() ) { + case zyppng::UserRequestType::Invalid: { + ERR << "Ignoring user request with type Invalid, this is a bug!" << std::endl; + return; //ignore + } + case zyppng::UserRequestType::Message: { + auto actualReq = std::dynamic_pointer_cast(req); + auto gObjMsg = zypp::glib::zypp_wrap_cpp(actualReq); + g_signal_emit (_gObject, signals[SIG_EVENT], 0, gObjMsg.get(), nullptr ); + return; + } + case zyppng::UserRequestType::ListChoice: { + auto actualReq = std::dynamic_pointer_cast(req); + auto gObjMsg = zypp::glib::zypp_wrap_cpp(actualReq); + g_signal_emit (_gObject, signals[SIG_EVENT], 0, gObjMsg.get(), nullptr ); + return; + } + case zyppng::UserRequestType::BooleanChoice: { + auto actualReq = std::dynamic_pointer_cast(req); + auto gObjMsg = zypp::glib::zypp_wrap_cpp(actualReq); + g_signal_emit (_gObject, signals[SIG_EVENT], 0, gObjMsg.get(), nullptr ); + return; + } + case zyppng::UserRequestType::InputRequest: { + auto actualReq = std::dynamic_pointer_cast(req); + auto gObjMsg = zypp::glib::zypp_wrap_cpp(actualReq); + g_signal_emit (_gObject, signals[SIG_EVENT], 0, gObjMsg.get(), nullptr ); + return; + } + case zyppng::UserRequestType::Custom: { + ERR << "Custom user requests can not be wrapped with glib!" << std::endl; + return; //ignore + } + } + }) + }); + + for ( const auto &chld : _cppObj->children () ) { + zypp_progress_observer_reg_child( _gObject, zypp::glib::zypp_wrap_cpp(chld) ); + } +} + +zyppng::ProgressObserverRef zypp_progress_observer_get_cpp( ZyppProgressObserver *self ) +{ + g_return_val_if_fail( ZYPP_PROGRESS_OBSERVER(self), nullptr ); + ZYPP_PROGRESS_OBSERVER_D(); + return d->_cppObj; +} diff --git a/zypp-glib/progressobserver.h b/zypp-glib/progressobserver.h new file mode 100644 index 0000000000..dcfab59179 --- /dev/null +++ b/zypp-glib/progressobserver.h @@ -0,0 +1,138 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_PROGRESSOBSERVER_H +#define ZYPP_GLIB_PROGRESSOBSERVER_H + +#include +#include + +G_BEGIN_DECLS + +#define ZYPP_TYPE_PROGRESS_OBSERVER zypp_progress_observer_get_type() + +#pragma GCC visibility push(default) +G_DECLARE_FINAL_TYPE (ZyppProgressObserver, zypp_progress_observer, ZYPP, PROGRESS_OBSERVER, GObject) +#pragma GCC visibility pop + +/** + * zypp_progress_observer_add_subtask: + * @self: a `ZyppProgressObserver` + * @newChild: (transfer none): A reference to the new subtask, the parent takes a reference to it + * @weight: The weight how the subtasks steps should be calculated into the parents percentage + * + * Registers a subtask as a child to the current one + */ +void zypp_progress_observer_add_subtask(ZyppProgressObserver *self, ZyppProgressObserver *newChild, gfloat weight ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_progress_observer_get_children: + * @self: a `ZyppProgressObserver` + * + * Returns: (element-type ZyppProgressObserver) (transfer none): The direct children of this Task + */ +const GList *zypp_progress_observer_get_children ( ZyppProgressObserver *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_progress_observer_get_label: + * @self: a `ZyppProgressObserver` + * + * Returns: (transfer none) (nullable): The task label or NULL if none was set + */ +const gchar *zypp_progress_observer_get_label ( ZyppProgressObserver *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_progress_observer_get_steps: + * @self: a `ZyppProgressObserver` + * + * Returns: The effective number of steps for this `ZyppProgressObserver` including possible substasks + */ +gdouble zypp_progress_observer_get_steps ( ZyppProgressObserver *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_progress_observer_get_base_steps: + * @self: a `ZyppProgressObserver` + * + * Returns: The number of steps for this `ZyppProgressObserver` excluding possible substasks + */ +gint zypp_progress_observer_get_base_steps ( ZyppProgressObserver *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_progress_observer_get_current: + * @self: a `ZyppProgressObserver` + * + * Returns: The current effective value of the task progress including subtasks, by default this is 0 + */ +gdouble zypp_progress_observer_get_current ( ZyppProgressObserver *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_progress_observer_get_progress: + * @self: a `ZyppProgressObserver` + * + * Returns: The current percentage value of the task progress including subtasks, by default this is 0 + */ +gdouble zypp_progress_observer_get_progress ( ZyppProgressObserver *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_progress_observer_set_label: + * @self: a `ZyppProgressObserver` + * @label: (transfer none): The new label + * + * Changes the currently used label + * + */ +void zypp_progress_observer_set_label ( ZyppProgressObserver *self, const gchar *label ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_progress_observer_set_base_steps: + * @self: a `ZyppProgressObserver` + * @stepCount: New number of steps + * + * Changes the currently used nr of expected steps for this `ZyppProgressObserver`, if the given value is less than + * 0 nothing is changed. + * + */ +void zypp_progress_observer_set_base_steps (ZyppProgressObserver *self, gint stepCount ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_progress_observer_set_value: + * @self: a `ZyppProgressObserver` + * @value: New current value + * + * Changes the current completed stepcount for this `ZyppProgressObserver` the subtasks will be added on top. + */ +void zypp_progress_observer_set_current ( ZyppProgressObserver *self, gdouble value ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_progress_observer_set_finished: + * @self: a `ZyppProgressObserver` + * + * Fills the progress and all its children up to 100% and emits the finished signal + */ +void zypp_progress_observer_set_finished ( ZyppProgressObserver *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_progress_observer_inc: + * @self: a `ZyppProgressObserver` + * @increase: Number of steps to increase the value + * + * Increases the current progress value by the number of given steps + */ +void zypp_progress_observer_inc ( ZyppProgressObserver *self, gint increase ) LIBZYPP_GLIB_EXPORT; + +// void zypp_progress_observer_begin ( ZyppProgressObserver *self ); +// void zypp_progress_observer_end ( ZyppProgressObserver *self ); + +G_END_DECLS + +#ifdef __cplusplus +#include +ZYPP_DEFINE_GOBJECT_SIMPLE( ZyppProgressObserver, zypp_progress_observer, ZYPP, PROGRESS_OBSERVER ) +#endif + +#endif diff --git a/zypp-glib/repoinfo.cc b/zypp-glib/repoinfo.cc new file mode 100644 index 0000000000..08572b7ac9 --- /dev/null +++ b/zypp-glib/repoinfo.cc @@ -0,0 +1,190 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "private/repoinfo_p.h" +#include "private/context_p.h" +#include "private/infobase_p.h" + + +static void zypp_info_base_interface_init( ZyppInfoBaseInterface *iface ); +ZYPP_DECLARE_GOBJECT_BOILERPLATE ( ZyppRepoInfo, zypp_repo_info ) + +G_DEFINE_TYPE_WITH_CODE(ZyppRepoInfo, zypp_repo_info, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE ( ZYPP_TYPE_INFO_BASE, zypp_info_base_interface_init) + G_ADD_PRIVATE ( ZyppRepoInfo ) +) + + +ZYPP_DEFINE_GOBJECT_BOILERPLATE ( ZyppRepoInfo, zypp_repo_info, ZYPP, REPOINFO ) +static void zypp_info_base_interface_init( ZyppInfoBaseInterface *iface ) +{ + ZyppInfoBaseImpl::init_interface( iface ); +} + +#define ZYPP_REPO_INFO_D() \ + ZYPP_GLIB_WRAPPER_D( ZyppRepoInfo, zypp_repo_info ) + +// define the GObject stuff +enum { + PROP_0, + PROP_CPPOBJ, + PROP_CONTEXT, + PROP_NAME, + PROP_ALIAS, + PROP_ENABLED, + N_PROPERTIES +}; + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +static void +zypp_repo_info_class_init (ZyppRepoInfoClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + ZYPP_INIT_GOBJECT_BOILERPLATE_KLASS ( zypp_repo_info, object_class); + + obj_properties[PROP_CPPOBJ] = ZYPP_GLIB_ADD_CPPOBJ_PROP(); + + obj_properties[PROP_CONTEXT] = + g_param_spec_object( "zyppcontext", + "ZyppContext", + "The zypp context this repo manager belongs to", + zypp_context_get_type(), + GParamFlags( G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE) ); + + obj_properties[PROP_NAME] = + g_param_spec_string ("name", + "Name", + "The name of the repository", + "", + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) ); + + obj_properties[PROP_ALIAS] = + g_param_spec_string ("alias", + "Alias", + "The alias of the repository", + "", + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) ); + + obj_properties[PROP_ENABLED] = + g_param_spec_boolean ("enabled", + "Enabled", + "Whether the repository is enabled or not", + FALSE, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) ); + + g_object_class_install_properties (object_class, + N_PROPERTIES, + obj_properties); +} + +static void +zypp_repo_info_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + ZyppRepoInfo *self = ZYPP_REPOINFO (object); + + ZYPP_REPO_INFO_D(); + + switch (property_id) + { + case PROP_NAME: + g_value_set_string (value, d->_info.name().c_str()); + break; + + case PROP_ALIAS: + g_value_set_string (value, d->_info.alias().c_str()); + break; + + case PROP_ENABLED: + g_value_set_boolean (value, d->_info.enabled()); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +zypp_repo_info_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + ZyppRepoInfo *self = ZYPP_REPOINFO (object); + ZYPP_REPO_INFO_D(); + + switch (property_id) + { + case PROP_CPPOBJ: + g_return_if_fail( d->_constrProps ); // only if the constr props are still valid + ZYPP_GLIB_SET_CPPOBJ_PROP( zyppng::RepoInfo, value, d->_constrProps->_cppObj ) + case PROP_CONTEXT: { + g_return_if_fail( d->_constrProps ); // only if the constr props are still valid + ZyppContext *obj = ZYPP_CONTEXT(g_value_get_object( value )); + g_return_if_fail( ZYPP_IS_CONTEXT(obj) ); + if ( d->_constrProps ) { + d->_constrProps->_context = zypp::glib::ZyppContextRef( obj, zypp::glib::retain_object ); + } + break; + } + case PROP_NAME: + d->_info.setName(g_value_get_string (value)); + break; + + case PROP_ALIAS: + d->_info.setAlias(g_value_get_string (value)); + break; + + case PROP_ENABLED: + d->_info.setEnabled(g_value_get_boolean (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void ZyppRepoInfoPrivate::initialize() +{ + g_return_if_fail ( _constrProps.has_value() ); + if ( _constrProps->_cppObj ) { + _info = std::move( _constrProps->_cppObj.value() ); + } else { + if ( !_constrProps->_context ) g_error("Context argument can not be NULL"); + _info = zyppng::RepoInfo( zypp_context_get_cpp( _constrProps->_context.get() ) ); + } + _constrProps.reset(); +} + +ZyppRepoInfo *zypp_repo_info_new(ZyppContext *context) +{ + g_return_val_if_fail( context != nullptr, nullptr ); + return static_cast(g_object_new (ZYPP_TYPE_REPOINFO, "zyppcontext", context, NULL)); +} + +ZyppRepoInfo *zypp_wrap_cpp(zyppng::RepoInfo info ) +{ + return static_cast(g_object_new (ZYPP_TYPE_REPOINFO, zypp::glib::internal::ZYPP_CPP_OBJECT_PROPERTY_NAME.data(), &info, NULL)); +} + +zyppng::RepoInfo &zypp_repo_info_get_cpp( ZyppRepoInfo *self ) +{ + ZYPP_REPO_INFO_D(); + return d->_info; +} + +ZyppRepoInfoType zypp_repo_info_get_repo_type( ZyppRepoInfo *self ) +{ + ZYPP_REPO_INFO_D(); + return static_cast(d->_info.type ().toEnum ()); +} diff --git a/zypp-glib/repoinfo.h b/zypp-glib/repoinfo.h new file mode 100644 index 0000000000..3c7bcd06c9 --- /dev/null +++ b/zypp-glib/repoinfo.h @@ -0,0 +1,52 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_REPOINFO_H +#define ZYPP_GLIB_REPOINFO_H + +#include +#include +#include + +G_BEGIN_DECLS + +typedef struct _ZyppContext ZyppContext; +typedef struct _ZyppRepoInfo ZyppRepoInfo; + +typedef enum +{ + ZYPP_REPO_NONE, + ZYPP_REPO_RPMMD, + ZYPP_REPO_YAST2, + ZYPP_REPO_RPMPLAINDIR +} ZyppRepoInfoType; + +#define ZYPP_TYPE_REPOINFO (zypp_repo_info_get_type ()) +#pragma GCC visibility push(default) +G_DECLARE_FINAL_TYPE ( ZyppRepoInfo, zypp_repo_info, ZYPP, REPOINFO, GObject ) +#pragma GCC visibility pop + +ZyppRepoInfo *zypp_repo_info_new ( ZyppContext *context ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_repo_info_get_repo_type: + * + * Returns: The type of repository + */ +ZyppRepoInfoType zypp_repo_info_get_repo_type( ZyppRepoInfo *self ) LIBZYPP_GLIB_EXPORT; + + +G_END_DECLS + +#ifdef __cplusplus +#include +ZYPP_DEFINE_GOBJECT_SIMPLE( ZyppRepoInfo, zypp_repo_info, ZYPP, REPOINFO ) +#endif + + +#endif // ZYPP_GLIB_REPOINFO_H diff --git a/zypp-glib/repomanager.cc b/zypp-glib/repomanager.cc new file mode 100644 index 0000000000..c81fca7db7 --- /dev/null +++ b/zypp-glib/repomanager.cc @@ -0,0 +1,303 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "private/repomanager_p.h" +#include "private/serviceinfo_p.h" +#include "private/repoinfo_p.h" +#include "private/error_p.h" +#include "expected.h" +#include +#include + +#include "utils/GList" +#include "private/cancellable_p.h" +#include "progressobserver.h" +#include + +// define the GObject stuff +G_DEFINE_TYPE_WITH_PRIVATE(ZyppRepoManager, zypp_repo_manager, G_TYPE_OBJECT) +G_DEFINE_QUARK (zypp-repo-manager-error-quark, zypp_repo_manager_error) + +typedef enum +{ + PROP_CPPOBJ = 1, + CONTEXT_PROPERTY, + N_PROPERTIES +} ZyppRepoManagerProperty; +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL }; + +/* Signals */ +typedef enum { + //FIRST_SIG = 1, + LAST_SIGNAL +} ZyppRepoManagerSignals; +//static guint signals[LAST_SIGNAL] = { 0, }; + +#define ZYPP_REPO_MANAGER_D() \ + ZYPP_GLIB_WRAPPER_D( ZyppRepoManager, zypp_repo_manager ) + +ZYPP_DECLARE_GOBJECT_BOILERPLATE ( ZyppRepoManager, zypp_repo_manager ) +ZYPP_DEFINE_GOBJECT_BOILERPLATE ( ZyppRepoManager, zypp_repo_manager, ZYPP, REPOMANAGER ) + +void zypp_repo_manager_class_init( ZyppRepoManagerClass *klass ) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + ZYPP_INIT_GOBJECT_BOILERPLATE_KLASS ( zypp_repo_manager, object_class ); + + obj_properties[PROP_CPPOBJ] = ZYPP_GLIB_ADD_CPPOBJ_PROP(); + + obj_properties[CONTEXT_PROPERTY] = + g_param_spec_object( "zyppcontext", + "ZyppContext", + "The zypp context this repo manager belongs to", + zypp_context_get_type(), + GParamFlags( G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE) ); + + /* + for now we do not support passing RepoManagerOptions, the context defines those + obj_properties[OPTIONS_PROPERTY] = + g_param_spec_boxed( "options", + "ZyppRepoManagerOptions", + "The repo manager options to be used", + zypp_repo_manager_options_get_type (), + GParamFlags( G_PARAM_CONSTRUCT | G_PARAM_READWRITE ) ); + */ + + g_object_class_install_properties (object_class, + N_PROPERTIES, + obj_properties); +} + +void ZyppRepoManagerPrivate::initializeCpp( ) +{ + g_return_if_fail ( _constrProps.has_value() ); + + if ( _constrProps->_cppObj ) { + _cppObj = std::move( _constrProps->_cppObj ); + } else { + if ( !_constrProps->_ctx ) g_error("Context argument can not be NULL"); + auto ctx = zypp_context_get_cpp( _constrProps->_ctx.get() ); + _cppObj = zyppng::AsyncRepoManager::create ( ctx, zyppng::RepoManagerOptions(ctx) ); + } + _constrProps.reset(); +} + +static void +zypp_repo_manager_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail( ZYPP_IS_REPOMANAGER(object) ); + ZyppRepoManager *self = ZYPP_REPOMANAGER (object); + + ZYPP_REPO_MANAGER_D(); + + switch ((ZyppRepoManagerProperty)property_id ) + { + case PROP_CPPOBJ: + g_return_if_fail( d->_constrProps ); // only if the constr props are still valid + ZYPP_GLIB_SET_CPPOBJ_PROP( zyppng::AsyncRepoManagerRef, value, d->_constrProps->_cppObj ) + + case CONTEXT_PROPERTY: { + ZyppContext *obj = ZYPP_CONTEXT(g_value_get_object( value )); + g_return_if_fail( ZYPP_IS_CONTEXT(obj) ); + if ( d->_constrProps ) { + d->_constrProps->_ctx = zypp::glib::ZyppContextRef( obj, zypp::glib::retain_object ); + } + break; + } + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +zypp_repo_manager_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail( ZYPP_IS_REPOMANAGER(object) ); +// ZyppRepoManager *self = ZYPP_REPOMANAGER (object); +// ZYPP_REPO_MANAGER_D(); + + switch ((ZyppRepoManagerProperty)property_id ) { + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +/* + * Method definitions. + */ + +ZyppRepoManager *zypp_repo_manager_new( ZyppContext *ctx ) +{ + g_return_val_if_fail( ctx != nullptr, nullptr ); + return static_cast( g_object_new( zypp_repo_manager_get_type(), "zyppcontext", ctx, nullptr ) ); +} + +ZyppRepoManager *zypp_repo_manager_new_initialized( ZyppContext *ctx, GError **error ) +{ + auto rM = zypp::glib::ZyppRepoManagerRef( zypp_repo_manager_new(ctx), zypp::glib::retain_object ); + if ( !zypp_repo_manager_initialize( rM.get(), error ) ) + return nullptr; + + return rM.detach (); +} + + +gboolean zypp_repo_manager_initialize( ZyppRepoManager *self, GError **error ) +{ + ZYPP_REPO_MANAGER_D(); + + using namespace zyppng::operators; + try { + d->cppType ()->initialize().unwrap(); + return true; + } catch ( ... ) { + zypp_error_from_exception ( error, std::current_exception() ); + } + return false; +} + +#if 0 +GList *zypp_repo_manager_get_repos ( ZyppRepoManager *self ) +{ + ZYPP_REPO_MANAGER_D(); + GList *ret = nullptr; + + auto ctx = d->_cppObj->zyppContext(); + + g_return_val_if_fail( ctx.operator bool() , nullptr ); + + for ( const auto &repo : ctx->pool().knownRepositories() ) { + ret = g_list_append( ret, zypp_repository_new( repo, self ) ); + } + + return ret; +} +#endif + +GList *zypp_repo_manager_get_known_repos(ZyppRepoManager *self) +{ + ZYPP_REPO_MANAGER_D(); + + GList *ret = nullptr; + + g_return_val_if_fail( d->_cppObj.operator bool() , nullptr ); + + for ( auto i = d->_cppObj->repoBegin (); i != d->_cppObj->repoEnd(); i++ ) { + ret = g_list_append( ret, zypp_wrap_cpp ( i->second ) ); + } + + return ret; +} + +GList *zypp_repo_manager_get_known_services(ZyppRepoManager *self) +{ + ZYPP_REPO_MANAGER_D(); + + GList *ret = nullptr; + + g_return_val_if_fail( d->_cppObj.operator bool() , nullptr ); + + for ( auto i = d->_cppObj->serviceBegin (); i != d->_cppObj->serviceEnd(); i++ ) { + ret = g_list_append( ret, zypp_wrap_cpp ( i->second ) ); + } + + return ret; +} + + +struct TaskData { + zyppng::AsyncOpBaseRef _op; + zyppng::ProgressObserverRef _prog; +}; + +void zypp_repo_manager_refresh_repo ( ZyppRepoManager *self, ZyppRepoInfo *repo, gboolean forceDownload, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer user_data ) +{ + ZYPP_REPO_MANAGER_D(); + + auto ctx = d->_cppObj->zyppContext(); + zyppng::ProgressObserverRef progress = zyppng::ProgressObserver::makeSubTask( ctx->progressObserver(), 1.0, "Refreshing Repo und so" ); + + g_return_if_fail( zyppng::EventDispatcher::instance()->glibContext() != nullptr ); + + if ( !repo ) { + GError *err = nullptr; + zypp_error_from_exception (&err, ZYPP_EXCPT_PTR ( zypp::Exception("Invalid arguments to zypp_repo_manager_refresh_repo_async") )); + g_task_report_error( self, cb, user_data, (gpointer)zypp_repo_manager_refresh_repo, err ); + return; + } + + g_main_context_push_thread_default( zyppng::EventDispatcher::instance()->glibContext() ); + zypp::glib::GTaskRef task = zypp::glib::adopt_gobject( g_task_new( self, cancellable, cb, user_data ) ); + g_main_context_pop_thread_default ( zyppng::EventDispatcher::instance()->glibContext() ); + + + auto op = d->_cppObj->refreshMetadata( zypp_repo_info_get_cpp(repo), forceDownload ? zypp::RepoManagerFlags::RefreshForced : zypp::RepoManagerFlags::RefreshIfNeeded, progress ); + + auto taskData = std::make_unique(); + taskData->_prog = std::move(progress); + taskData->_op = op; + + // task keeps the reference to our async op + g_task_set_task_data( task.get(), new zyppng::AsyncOpBaseRef(op), zypp::glib::g_destroy_notify_delete ); + + auto taskPtr = task.get(); + + // we keep the reference to our task + d->_asyncOpsRunning.push_back( std::move(task) ); + + // this will get triggered immediately if the task is already done + op->onReady( + [ task = taskPtr /*do not take a reference*/ ]( zyppng::expected res ){ + MIL << "Async Operation finished" << std::endl; + if ( !res ) { + GError *err = nullptr; + zypp_error_from_exception (&err, res.error() ); + g_task_return_error( task, err ); + return; + } + + // return the RepoInfo to the caller via callback + g_task_return_pointer( task, zypp_wrap_cpp( res.get() ), g_object_unref ); + } + ); +} + +ZyppRepoInfo *zypp_repo_manager_refresh_repo_finish ( ZyppRepoManager *self, + GAsyncResult *result, + GError **error ) +{ + MIL << "Inside finish func" << std::endl; + g_return_val_if_fail (g_task_is_valid (result, self), NULL); + + MIL << "Inside finish func 2" << std::endl; + // if the result is tagged with the zypp_repo_manager_refresh_repo func it was created before the task + // was even started and registered. No need to clean it + if ( !g_async_result_is_tagged ( result, (gpointer)zypp_repo_manager_refresh_repo ) ) { + ZYPP_REPO_MANAGER_D(); + auto i = std::find_if( d->_asyncOpsRunning.begin(), d->_asyncOpsRunning.end(),[&]( const auto &e ) { return e.get() == G_TASK(result); } ); + if ( i != d->_asyncOpsRunning.end() ) { + d->_asyncOpsRunning.erase(i); + } else { + WAR << "Task was not in the list of currently running tasks, thats a bug" << std::endl; + } + } + + MIL << "Inside finish func 3" << std::endl; + return reinterpret_cast(g_task_propagate_pointer (G_TASK (result), error)); +} + diff --git a/zypp-glib/repomanager.h b/zypp-glib/repomanager.h new file mode 100644 index 0000000000..cb6455e219 --- /dev/null +++ b/zypp-glib/repomanager.h @@ -0,0 +1,114 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_REPOMANAGER_H +#define ZYPP_GLIB_REPOMANAGER_H + + +#include +#include +#include + +G_BEGIN_DECLS + +typedef struct _ZyppContext ZyppContext; +typedef struct _ZyppRepoInfo ZyppRepoInfo; +typedef struct _ZyppExpected ZyppExpected; + +typedef enum { + ZYPP_REPO_MANAGER_UP_TO_DATE, + ZYPP_REPO_MANAGER_REFRESHED +} ZyppRepoRefreshResult; + +#define ZYPP_TYPE_REPOMANAGER (zypp_repo_manager_get_type ()) + +#pragma GCC visibility push(default) +G_DECLARE_FINAL_TYPE ( ZyppRepoManager, zypp_repo_manager, ZYPP, REPOMANAGER, GObject ) +#pragma GCC visibility pop + +#define ZYPP_REPO_MANAGER_ERROR zypp_repo_manager_error_quark () +GQuark zypp_repo_manager_error_quark (void) LIBZYPP_GLIB_EXPORT; +typedef enum { + ZYPP_REPO_MANAGER_ERROR_REF_FAILED, + ZYPP_REPO_MANAGER_ERROR_REF_SKIPPED, + ZYPP_REPO_MANAGER_ERROR_REF_ABORTED +} ZyppRepoManagerError; + +/** + * zypp_repo_manager_new: (constructor) + * @ctx: The #ZyppContext the RepoManager should operate on + * + * Returns: (transfer full): newly created #ZyppRepoManager + */ +ZyppRepoManager *zypp_repo_manager_new( ZyppContext *ctx ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_repo_manager_new_initialized: (constructor) + * @ctx: The #ZyppContext the RepoManager should operate on + * + * Returns: (transfer full): newly created #ZyppRepoManager + */ +ZyppRepoManager *zypp_repo_manager_new_initialized( ZyppContext *ctx, GError **error ) LIBZYPP_GLIB_EXPORT; + + +/** + * zypp_repo_manager_initialize: + * + * Loads the known repositories and services. + * + * Returns: True if init was successful, otherwise returns false and sets the error + */ +gboolean zypp_repo_manager_initialize( ZyppRepoManager *self, GError **error ) LIBZYPP_GLIB_EXPORT; + + +/** + * zypp_repo_manager_get_known_repos: + * + * Returns: (element-type ZyppRepoInfo) (transfer full): list of repositories, + * free the list with g_list_free and the elements with gobject_unref when done. + */ +GList *zypp_repo_manager_get_known_repos ( ZyppRepoManager *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_repo_manager_get_known_services: + * + * Returns: (element-type ZyppServiceInfo) (transfer full): list of existing services, + * free the list with g_list_free and the elements with gobject_unref when done. + */ +GList *zypp_repo_manager_get_known_services ( ZyppRepoManager *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_repo_manager_refresh_repo: + * @self: a #ZyppRepoManager + * @repo: (transfer none): the repository to refresh + * @forceDownload: Force downloading the repository even if its up 2 date + * @cancellable: (nullable) + * @cb: (scope async) (closure user_data): a #GAsyncReadyCallback to call when the request is satisfied + * @user_data: the data to pass to callback function + */ +void zypp_repo_manager_refresh_repo ( ZyppRepoManager *self, ZyppRepoInfo *repo, gboolean forceDownload, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer user_data ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_repo_manager_refresh_repo_finish: + * @self: (in): a #ZyppRepoManager + * @result: (in): where to place the result + * @error: return location for a GError, or NULL + * + * Returns: (transfer full): The refreshed #ZyppRepoInfo object + */ +ZyppRepoInfo *zypp_repo_manager_refresh_repo_finish ( ZyppRepoManager *self, GAsyncResult *result, GError **error ) LIBZYPP_GLIB_EXPORT; + + +G_END_DECLS + +#ifdef __cplusplus +#include +ZYPP_DEFINE_GOBJECT_SIMPLE( ZyppRepoManager, zypp_repo_manager, ZYPP, REPOMANAGER ) +#endif + +#endif // ZYPP_GLIB_REPOMANAGER_H diff --git a/zypp-glib/repository.cc b/zypp-glib/repository.cc new file mode 100644 index 0000000000..9e8cadd754 --- /dev/null +++ b/zypp-glib/repository.cc @@ -0,0 +1,77 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "private/repository_p.h" +#include "private/repoinfo_p.h" +#include + +struct _ZyppRepository +{ + GObjectClass parent_class; + struct Cpp { + zypp::Repository _repo; + ZyppRepoManager *_repoManager; + } _data; +}; +G_DEFINE_TYPE(ZyppRepository, zypp_repository, G_TYPE_OBJECT) + +static void zypp_repository_dispose (GObject *gobject) +{ + /* In dispose(), you are supposed to free all types referenced from this + * object which might themselves hold a reference to self. Generally, + * the most simple solution is to unref all members on which you own a + * reference. + */ + + // always call parent class dispose + G_OBJECT_CLASS (zypp_repository_parent_class)->dispose (gobject); +} + +static void zypp_repository_finalize (GObject *gobject) +{ + ZyppRepository *ptr = ZYPP_REPOSITORY(gobject); + g_clear_weak_pointer( &ptr->_data._repoManager ); + ptr->_data.~Cpp(); + + // always call parent class finalizer + G_OBJECT_CLASS (zypp_repository_parent_class)->finalize (gobject); +} + +void zypp_repository_class_init( ZyppRepositoryClass *klass ) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + object_class->dispose = zypp_repository_dispose; + object_class->finalize = zypp_repository_finalize; +} + +void zypp_repository_init( ZyppRepository *ctx ) +{ + new ( &ctx->_data ) ZyppRepository::Cpp(); +} + +ZyppRepository *zypp_repository_new( const zypp::Repository &cppVersion, ZyppRepoManager *mgr ) +{ + ZyppRepository *obj = (ZyppRepository *)g_object_new( zypp_repository_get_type(), NULL ); + obj->_data._repo = cppVersion; + g_set_weak_pointer( &obj->_data._repoManager, mgr ); + return obj; +} + +gchar *zypp_repository_get_name( ZyppRepository *self ) +{ + if ( !self || !self->_data._repoManager ) + return nullptr; + return g_strdup( self->_data._repo.name().c_str() ); +} + +ZyppRepoInfo *zypp_repository_get_repoinfo(ZyppRepository *self) +{ + if ( !self || !self->_data._repoManager || !self->_data._repo.ngInfo() ) + return nullptr; + return zypp_wrap_cpp ( *self->_data._repo.ngInfo() ); +} diff --git a/zypp-glib/repository.h b/zypp-glib/repository.h new file mode 100644 index 0000000000..d66a0b9dbc --- /dev/null +++ b/zypp-glib/repository.h @@ -0,0 +1,49 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_REPOSITORY_H +#define ZYPP_GLIB_REPOSITORY_H + +#include +#include +#include + +G_BEGIN_DECLS + +typedef struct _ZyppContext ZyppContext; +typedef struct _ZyppRepoManager ZyppRepoManager; + +#define ZYPP_TYPE_REPOSITORY (zypp_repository_get_type ()) +#pragma GCC visibility push(default) +G_DECLARE_FINAL_TYPE ( ZyppRepository, zypp_repository, ZYPP, REPOSITORY, GObject ) +#pragma GCC visibility pop + +/** + * zypp_repository_get_name: + * + * Returns: (transfer full): Name of the repository + */ +gchar *zypp_repository_get_name( ZyppRepository *self ) LIBZYPP_GLIB_EXPORT; + + +/** + * zypp_repository_get_repoinfo: + * + * Returns: (transfer full): The corresponding ZyppRepoInfo + */ +ZyppRepoInfo *zypp_repository_get_repoinfo( ZyppRepository *self ) LIBZYPP_GLIB_EXPORT; + + +G_END_DECLS + +#ifdef __cplusplus +#include +ZYPP_DEFINE_GOBJECT_SIMPLE( ZyppRepository, zypp_repository, ZYPP, REPOSITORY ) +#endif + +#endif // ZYPP_GLIB_REPOSITORY_H diff --git a/zypp-glib/serviceinfo.cc b/zypp-glib/serviceinfo.cc new file mode 100644 index 0000000000..029607845a --- /dev/null +++ b/zypp-glib/serviceinfo.cc @@ -0,0 +1,115 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "private/serviceinfo_p.h" +#include "private/infobase_p.h" +#include "zypp-glib/private/context_p.h" + + +ZYPP_DECLARE_GOBJECT_BOILERPLATE ( ZyppServiceInfo, zypp_service_info ) +static void zypp_info_base_interface_init( ZyppInfoBaseInterface *iface ); + +G_DEFINE_TYPE_WITH_CODE(ZyppServiceInfo, zypp_service_info, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE ( ZYPP_TYPE_INFO_BASE, zypp_info_base_interface_init) + G_ADD_PRIVATE ( ZyppServiceInfo ) +) + +#define ZYPP_SERVICE_INFO_D() \ + ZYPP_GLIB_WRAPPER_D( ZyppServiceInfo, zypp_service_info ) + + +enum { + PROP_0, + PROP_CPPOBJ, + PROP_CONTEXT, + N_PROPERTIES +}; + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +ZYPP_DEFINE_GOBJECT_BOILERPLATE ( ZyppServiceInfo, zypp_service_info, ZYPP, SERVICE_INFO ) + +static void zypp_info_base_interface_init( ZyppInfoBaseInterface *iface ) +{ + ZyppInfoBaseImpl::init_interface( iface ); +} + +static void +zypp_service_info_class_init (ZyppServiceInfoClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + ZYPP_INIT_GOBJECT_BOILERPLATE_KLASS ( zypp_service_info, gobject_class ); + + obj_properties[PROP_CPPOBJ] = ZYPP_GLIB_ADD_CPPOBJ_PROP(); +} + +static void +zypp_service_info_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +zypp_service_info_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + ZyppServiceInfo *self = ZYPP_SERVICE_INFO (object); + ZYPP_SERVICE_INFO_D(); + + switch (property_id) + { + case PROP_CPPOBJ: + g_return_if_fail( d->_constrProps ); // only if the constr props are still valid + ZYPP_GLIB_SET_CPPOBJ_PROP( zyppng::ServiceInfo, value, d->_constrProps->_cppObj ) + case PROP_CONTEXT: { + g_return_if_fail( d->_constrProps ); // only if the constr props are still valid + ZyppContext *obj = ZYPP_CONTEXT(g_value_get_object( value )); + g_return_if_fail( ZYPP_IS_CONTEXT(obj) ); + if ( d->_constrProps ) { + d->_constrProps->_context = zypp::glib::ZyppContextRef( obj, zypp::glib::retain_object ); + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void ZyppServiceInfoPrivate::initialize() +{ + g_return_if_fail ( _constrProps.has_value() ); + if ( _constrProps->_cppObj ) { + _info = std::move( _constrProps->_cppObj.value() ); + } else { + if ( !_constrProps->_context ) g_error("Context argument can not be NULL"); + _info = zyppng::ServiceInfo( zypp_context_get_cpp( _constrProps->_context.get() ) ); + } + _constrProps.reset(); +} + +ZyppServiceInfo *zypp_service_info_new ( ZyppContext *context ) +{ + g_return_val_if_fail( context != nullptr, nullptr ); + return static_cast( g_object_new (ZYPP_TYPE_SERVICE_INFO, "zyppcontext", context, NULL) ); +} + +ZyppServiceInfo *zypp_wrap_cpp( zyppng::ServiceInfo info ) +{ + return ZYPP_SERVICE_INFO(g_object_new (ZYPP_TYPE_SERVICE_INFO, zypp::glib::internal::ZYPP_CPP_OBJECT_PROPERTY_NAME.data(), &info, NULL)); +} diff --git a/zypp-glib/serviceinfo.h b/zypp-glib/serviceinfo.h new file mode 100644 index 0000000000..a39704cb9a --- /dev/null +++ b/zypp-glib/serviceinfo.h @@ -0,0 +1,26 @@ +#ifndef __ZYPP_SERVICE_INFO_H__ +#define __ZYPP_SERVICE_INFO_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _ZyppServiceInfo ZyppServiceInfo; +typedef struct _ZyppContext ZyppContext; + +#define ZYPP_TYPE_SERVICE_INFO (zypp_service_info_get_type ()) +#pragma GCC visibility push(default) +G_DECLARE_FINAL_TYPE ( ZyppServiceInfo, zypp_service_info, ZYPP, SERVICE_INFO, GObject ) +#pragma GCC visibility pop + +ZyppServiceInfo *zypp_service_info_new ( ZyppContext *context ) LIBZYPP_GLIB_EXPORT; + +G_END_DECLS + +#ifdef __cplusplus +#include +ZYPP_DEFINE_GOBJECT_SIMPLE( ZyppServiceInfo, zypp_service_info, ZYPP, SERVICE_INFO ) +#endif + +#endif /* __ZYPP_SERVICE_INFO_H__ */ diff --git a/zypp-glib/test.py b/zypp-glib/test.py new file mode 100755 index 0000000000..17a25d0ee8 --- /dev/null +++ b/zypp-glib/test.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python3 + +import sys +import re +import urwid +import inquirer +import gi.repository + +# Set the search path to use the newly generated introspection files +gi.require_version('GIRepository', '2.0') +gi.require_version('GLib', '2.0') +gi.require_version('Gio', '2.0') + +from tqdm import tqdm + +from gi.repository import GIRepository +from gi.repository import GLib +from gi.repository import Gio +GIRepository.Repository.prepend_search_path('/home/zbenjamin/build/zypp-stack/Desktop-Debug/libzypp/zypp-glib') + +gi.require_version('Zypp', '1.0') +from gi.repository import Zypp + + +loop = urwid.GLibEventLoop() + +application = Zypp.Application( eventDispatcher=loop._loop.get_context() ) +context = Zypp.Context() + + +class ZyppMainView: + def __init(): + return + +class Tracker: + def __init__(self, tracker = None, nesting = 0, label = None ): + if tracker is None: + self.zyppTracker = Zypp.ProgressObserver() + else: + self.zyppTracker = tracker + + if label is not None: + self.zyppTracker.set_label(label) + + self.childBars = [] #where we store our children + self.nesting = nesting + self.progressBar = tqdm( total=100, position=self.nesting, desc=self.zyppTracker.get_label() ) + + self.zyppTracker.connect("notify::label", self.on_label_change ) + self.zyppTracker.connect("notify::progress", self.on_progress ) + self.zyppTracker.connect("start", self.on_start ) + self.zyppTracker.connect("finished", self.on_finished ) + self.zyppTracker.connect("new-subtask", self.on_new_subtask ) + self.zyppTracker.connect("event", self.on_user_request ) + + def on_start( self, sender ): + self.progressBar.update() + self.lastProgress = 0 + + def on_finished( self, sender ): + self.progressBar.close() + self.progressBar.update() + + def on_progress( self, sender, param ): + newProgress = sender.get_property(param.name) + self.progressBar.update( n=(newProgress - self.lastProgress) ) + self.lastProgress = newProgress + + def on_label_change( self, sender, param ): + self.progressBar.set_description( desc=sender.get_property(param.name), refresh=True ) + + def on_child_finished( self, child ): + try: + for child in self.childBars: + if child.zyppTracker == child: + self.childBars.remove(child) + return + except ValueError: + pass + + def on_new_subtask( self, sender, subtask_param ): + self.childBars.append( Tracker(subtask_param, self.nesting+1) ) + subtask_param.connect("finished", self.on_child_finished ) + + def on_user_request( self, sender, event ): + match event: + case Zypp.BooleanChoiceRequest() as boolReq: + + # we are going to handle the event + boolReq.set_accepted() + + questions = [ + inquirer.List('choice', + message=boolReq.get_label(), + choices=[('yes', True), ('no', False)], + default=['no'] + ), + ] + answer = inquirer.prompt(questions)["choice"] + print("User selected: %s" % str(answer)) + boolReq.set_choice(answer) + + case Zypp.ListChoiceRequest() as listReq: + + # we are going to handle the event + listReq.set_accepted() + + # build a list of tuples for our choices, + # where each tuple is the label for the option, and the value returned if the corresponding option is chosen. + # Here it's simply the index of the option in the options list + choices = [] + for idx, opt in enumerate(listReq.get_options()): + choices.append( ("%s(%s)" % (opt.get_label(), opt.get_detail()), idx) ); + + print ("Default for upcoming question is: %s" % choices[listReq.get_default()][0]) + + questions = [ + inquirer.List('choice', + message=listReq.get_label(), + choices=choices, + default=choices[listReq.get_default()][0] + ), + ] + answer = inquirer.prompt(questions)["choice"] + print("User selected: %s" % str(answer)) + listReq.set_choice(answer) + + case Zypp.ShowMsgRequest() as msgReq: + + # we are going to handle the event + msgReq.set_accepted() + + print(msgReq.get_message()) + + +class Data: + def __init__( self ): + self.count = 0 + + def inc( self ): + self.count = self.count+1 + + def dec( self ): + self.count = self.count-1 + + def isDone( self ): + return (self.count <= 0) + + +progBar = Tracker( label="Refreshing repositories" ) +context.set_progress_observer(progBar.zyppTracker) + + +print ("Load system") + +if not context.load_system("/tmp/fake"): + print ("Failed to load system") + exit(1) + +print ("Loaded system") + +repomgr = None +try: + repomgr = Zypp.RepoManager.new_initialized( context ) +except GLib.GError as e: + print("Error: " + e.message) + print("History: " + str(Zypp.Error.get_history(e))) + exit(1) + +known_repos = repomgr.get_known_repos() +if len(known_repos) == 0: + print("Nothing to do") + exit(0) + +print ("Knows repos: " + str(len(known_repos) )) + +def finRefresh( source_object, result, user_data ): + print("Ref_count is: " + str(user_data.count) ) + try: + mep = source_object.refresh_repo_finish(result) + print("Yay refresh done for: " + mep.alias() ) + except GLib.GError as e: + print("Error: " + e.message) + print("History: " + str(Zypp.Error.get_history(e))) + finally: + user_data.dec() + if user_data.isDone(): + loop._loop.quit() + +counter = Data() +for i in known_repos: + print ( "Repo: "+i.name() ) + print ("Refreshing") + counter.inc() + repomgr.refresh_repo( i, True, None, finRefresh, counter ) + +loop.run() diff --git a/zypp-glib/ui/booleanchoicerequest.cc b/zypp-glib/ui/booleanchoicerequest.cc new file mode 100644 index 0000000000..2b8f9addab --- /dev/null +++ b/zypp-glib/ui/booleanchoicerequest.cc @@ -0,0 +1,115 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "private/booleanchoicerequest_p.h" +#include "private/userrequest_p.h" + +#include +#include + +static void user_request_if_init( ZyppUserRequestInterface *iface ); + +ZYPP_DECLARE_GOBJECT_BOILERPLATE ( ZyppBooleanChoiceRequest, zypp_boolean_choice_request ) + +G_DEFINE_TYPE_WITH_CODE(ZyppBooleanChoiceRequest, zypp_boolean_choice_request, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE ( ZYPP_TYPE_USER_REQUEST, user_request_if_init ) + G_ADD_PRIVATE ( ZyppBooleanChoiceRequest ) +) + +ZYPP_DEFINE_GOBJECT_BOILERPLATE ( ZyppBooleanChoiceRequest, zypp_boolean_choice_request, ZYPP, BOOLEAN_CHOICE_REQUEST ) + +#define ZYPP_D() \ + ZYPP_GLIB_WRAPPER_D( ZyppBooleanChoiceRequest, zypp_boolean_choice_request ) + +// define the GObject stuff +enum { + PROP_CPPOBJ = 1, + N_PROPERTIES +}; + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +static void user_request_if_init( ZyppUserRequestInterface *iface ) +{ + ZyppUserRequestImpl::init_interface( iface ); +} + +static void zypp_boolean_choice_request_class_init (ZyppBooleanChoiceRequestClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + ZYPP_INIT_GOBJECT_BOILERPLATE_KLASS ( zypp_boolean_choice_request, gobject_class ); + obj_properties[PROP_CPPOBJ] = ZYPP_GLIB_ADD_CPPOBJ_PROP(); + + g_object_class_install_properties (gobject_class, + N_PROPERTIES, + obj_properties); +} + +static void +zypp_boolean_choice_request_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail( ZYPP_IS_BOOLEAN_CHOICE_REQUEST (object) ); + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +zypp_boolean_choice_request_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail( ZYPP_IS_BOOLEAN_CHOICE_REQUEST (object) ); + ZyppBooleanChoiceRequest *self = ZYPP_BOOLEAN_CHOICE_REQUEST (object); + + ZYPP_D(); + + switch (property_id) + { + case PROP_CPPOBJ: { + g_return_if_fail( d->_constrProps ); // only if the constr props are still valid + ZYPP_GLIB_SET_CPPOBJ_PROP( zyppng::BooleanChoiceRequestRef, value, d->_constrProps->_cppObj ); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +zyppng::BooleanChoiceRequestRef &zypp_boolean_choice_request_get_cpp( ZyppBooleanChoiceRequest *self ) +{ + ZYPP_D(); + return d->_cppObj; +} + +const char * zypp_boolean_choice_request_get_label( ZyppBooleanChoiceRequest *self ) +{ + ZYPP_D(); + return d->_cppObj->label().c_str(); +} + +void zypp_boolean_choice_request_set_choice ( ZyppBooleanChoiceRequest *self, gboolean choice ) +{ + ZYPP_D(); + d->_cppObj->setChoice( static_cast(choice) ); +} + +gboolean zypp_boolean_choice_request_get_choice ( ZyppBooleanChoiceRequest *self ) +{ + ZYPP_D(); + return static_cast(d->_cppObj->choice()); +} + diff --git a/zypp-glib/ui/booleanchoicerequest.h b/zypp-glib/ui/booleanchoicerequest.h new file mode 100644 index 0000000000..0b520cd7de --- /dev/null +++ b/zypp-glib/ui/booleanchoicerequest.h @@ -0,0 +1,57 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_BOOLEAN_CHOICE_MESSAGE_REQUEST_H +#define ZYPP_GLIB_BOOLEAN_CHOICE_MESSAGE_REQUEST_H + +#include +#include +#include + +G_BEGIN_DECLS + + +/** + * ZyppBooleanChoiceRequest: + * + * The `ZyppBooleanChoiceRequest` event represents a choice request to the user, + * the possible answers are true or false. + * + */ + +#pragma GCC visibility push(default) +G_DECLARE_FINAL_TYPE ( ZyppBooleanChoiceRequest, zypp_boolean_choice_request, ZYPP, BOOLEAN_CHOICE_REQUEST, GObject ) +#pragma GCC visibility pop + +#define ZYPP_TYPE_BOOLEAN_CHOICE_REQUEST (zypp_boolean_choice_request_get_type ()) + +const char * zypp_boolean_choice_request_get_label( ZyppBooleanChoiceRequest *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_boolean_choice_request_set_choice: + * + * Remember the users choice, this will be returned to the code that triggered the event. + */ +void zypp_boolean_choice_request_set_choice ( ZyppBooleanChoiceRequest *self, gboolean choice ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_boolean_choice_request_get_choice: + * + * Get the current choice + */ +gboolean zypp_boolean_choice_request_get_choice( ZyppBooleanChoiceRequest *self ) LIBZYPP_GLIB_EXPORT; + + +G_END_DECLS + +#ifdef __cplusplus +#include +ZYPP_DEFINE_GOBJECT_SIMPLE( ZyppBooleanChoiceRequest, zypp_boolean_choice_request, ZYPP, BOOLEAN_CHOICE_REQUEST ) +#endif + +#endif // ZYPP_GLIB_BOOLEAN_CHOICE_MESSAGE_REQUEST_H diff --git a/zypp-glib/ui/inputrequest.cc b/zypp-glib/ui/inputrequest.cc new file mode 100644 index 0000000000..2dd1c9ab2b --- /dev/null +++ b/zypp-glib/ui/inputrequest.cc @@ -0,0 +1,157 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "private/inputrequest_p.h" +#include "private/userrequest_p.h" + +#include +#include + +ZyppInputRequestField * zypp_wrap_cpp( zyppng::InputRequest::Field obj ) +{ + std::unique_ptr ptr( new ZyppInputRequestField() ); + ptr->_cppObj = std::move(obj); + return ptr.release(); +} + +ZyppInputRequestField *zypp_input_request_field_copy(ZyppInputRequestField *r) +{ + return zypp_wrap_cpp(r->_cppObj); +} + +void zypp_input_request_field_free(ZyppInputRequestField *r) +{ + delete r; +} + +ZyppInputRequestFieldType zypp_input_request_field_get_type(ZyppInputRequestField *field) +{ + return (ZyppInputRequestFieldType)field->_cppObj.type; +} + +const char *zypp_input_request_field_get_label(ZyppInputRequestField *field) +{ + return field->_cppObj.label.c_str (); +} + +const char *zypp_input_request_field_get_value(ZyppInputRequestField *field) +{ + return field->_cppObj.value.c_str (); +} + + +G_DEFINE_BOXED_TYPE (ZyppInputRequestField, zypp_input_request_field, + zypp_input_request_field_copy, + zypp_input_request_field_free) + + +static void user_request_if_init( ZyppUserRequestInterface *iface ); + +ZYPP_DECLARE_GOBJECT_BOILERPLATE ( ZyppInputRequest, zypp_input_request ) + +G_DEFINE_TYPE_WITH_CODE( ZyppInputRequest, zypp_input_request, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE ( ZYPP_TYPE_USER_REQUEST, user_request_if_init ) + G_ADD_PRIVATE ( ZyppInputRequest ) +) + +ZYPP_DEFINE_GOBJECT_BOILERPLATE ( ZyppInputRequest, zypp_input_request, ZYPP, INPUT_REQUEST ) + +#define ZYPP_D() \ + ZYPP_GLIB_WRAPPER_D( ZyppInputRequest, zypp_input_request ) + +// define the GObject stuff +enum { + PROP_CPPOBJ = 1, + N_PROPERTIES +}; + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +static void user_request_if_init( ZyppUserRequestInterface *iface ) +{ + ZyppUserRequestImpl::init_interface( iface ); +} + +static void zypp_input_request_class_init (ZyppInputRequestClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + ZYPP_INIT_GOBJECT_BOILERPLATE_KLASS ( zypp_input_request, gobject_class ); + obj_properties[PROP_CPPOBJ] = ZYPP_GLIB_ADD_CPPOBJ_PROP(); + + g_object_class_install_properties (gobject_class, + N_PROPERTIES, + obj_properties); +} + +static void +zypp_input_request_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail( ZYPP_IS_INPUT_REQUEST (object) ); + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +zypp_input_request_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail( ZYPP_IS_INPUT_REQUEST (object) ); + ZyppInputRequest *self = ZYPP_INPUT_REQUEST (object); + + ZYPP_D(); + + switch (property_id) + { + case PROP_CPPOBJ: { + g_return_if_fail( d->_constrProps ); // only if the constr props are still valid + ZYPP_GLIB_SET_CPPOBJ_PROP( zyppng::InputRequestRef, value, d->_constrProps->_cppObj ); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +zyppng::InputRequestRef &zypp_input_request_get_cpp( ZyppInputRequest *self ) +{ + ZYPP_D(); + return d->_cppObj; +} + +const char * zypp_input_request_get_label( ZyppInputRequest *self ) +{ + ZYPP_D(); + return d->_cppObj->label().c_str(); +} + +GList *zypp_input_request_get_fields( ZyppInputRequest *self ) +{ + ZYPP_D(); + zypp::glib::GListContainer opts; + for ( const auto &f : d->_cppObj->fields()) { + opts.push_back ( zypp_wrap_cpp(f) ); + } + return opts.take(); +} + +void zypp_input_request_set_field_value( ZyppInputRequest *self, guint fieldIndex, const char *value ) +{ + ZYPP_D(); + g_return_if_fail( ( fieldIndex >= 0 && fieldIndex < d->_cppObj->fields ().size()) ); + d->_cppObj->fields ()[fieldIndex].value = zypp::str::asString(value); +} diff --git a/zypp-glib/ui/inputrequest.h b/zypp-glib/ui/inputrequest.h new file mode 100644 index 0000000000..9d3e06d03c --- /dev/null +++ b/zypp-glib/ui/inputrequest.h @@ -0,0 +1,119 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_INPUT_REQUEST_H +#define ZYPP_GLIB_INPUT_REQUEST_H + +#include +#include +#include + +G_BEGIN_DECLS + + +/** + * ZyppInputRequest: + * + * The `ZyppInputRequest` event represents a generic input request to the user, + * it can define a list of input fields that should be presented to the user and + * can be accepted or rejected. + * + */ + +#pragma GCC visibility push(default) +G_DECLARE_FINAL_TYPE ( ZyppInputRequest, zypp_input_request, ZYPP, INPUT_REQUEST, GObject ) +#pragma GCC visibility pop + +#define ZYPP_TYPE_INPUT_REQUEST (zypp_input_request_get_type ()) + +/** + * Type of a field in a ZyppInputRequest + */ +enum ZyppInputRequestFieldType { + Text, + Password +}; + +/** + * ZyppInputRequestField: + * + * One possible option input field in a InputRequest. The type defines + * which field should be rendered. + * + * For example: + * {"y", "Info about y"}, {"n", "Info about n"}, {"d", "Info about d"} + * + */ +typedef struct _ZyppInputRequestField ZyppInputRequestField; + +/** + * zypp_input_request_field_copy: (skip): + * + * Copy the boxed type + */ +ZyppInputRequestField * zypp_input_request_field_copy ( ZyppInputRequestField *r ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_input_request_field_free: (skip): + * + * Free the boxed type + */ +void zypp_input_request_field_free ( ZyppInputRequestField *r ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_input_request_field_get_type: + * + * Get the input type for this field + */ +ZyppInputRequestFieldType zypp_input_request_field_get_type( ZyppInputRequestField* field ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_input_request_field_get_label: + * + * Get the label string for this field + */ +const char * zypp_input_request_field_get_label ( ZyppInputRequestField* field ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_input_request_field_get_value: + * + * Get the current value for the field + */ +const char * zypp_input_request_field_get_value ( ZyppInputRequestField* field ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_input_request_get_label: + * + * Get the label string for this request + */ +const char * zypp_input_request_get_label ( ZyppInputRequest* field ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_input_request_get_fields: + * + * Returns: (element-type ZyppInputRequestField) (transfer full): list of the available fields + */ +GList *zypp_input_request_get_fields ( ZyppInputRequest *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_input_request_set_field_value: + * + * Sets the value of the field defined by fieldIndex. + */ +void zypp_input_request_set_field_value ( ZyppInputRequest *self, guint fieldIndex, const char* value ); + + +G_END_DECLS + +#ifdef __cplusplus +#include +ZYPP_DEFINE_GOBJECT_SIMPLE( ZyppInputRequest, zypp_input_request, ZYPP, INPUT_REQUEST ) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE( ZyppInputRequestField, zypp_input_request_field_free, ZYPP_GLIB_ADD_GLIB_COPYTRAIT(zypp_input_request_field_copy) ) +#endif + +#endif // ZYPP_GLIB_INPUT_REQUEST_H diff --git a/zypp-glib/ui/listchoicerequest.cc b/zypp-glib/ui/listchoicerequest.cc new file mode 100644 index 0000000000..e9aa2ee203 --- /dev/null +++ b/zypp-glib/ui/listchoicerequest.cc @@ -0,0 +1,164 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "private/listchoicerequest_p.h" +#include "private/userrequest_p.h" + +#include +#include + +ZyppListChoiceOption * zypp_wrap_cpp( zyppng::ListChoiceRequest::Choice obj ) +{ + std::unique_ptr ptr( new ZyppListChoiceOption() ); + ptr->_cppObj = std::move(obj); + return ptr.release(); +} + +ZyppListChoiceOption * zypp_list_choice_option_copy ( ZyppListChoiceOption *r ) +{ + return zypp_wrap_cpp(r->_cppObj); +} + +void zypp_list_choice_option_free ( ZyppListChoiceOption *r ) +{ + delete r; +} + + +G_DEFINE_BOXED_TYPE (ZyppListChoiceOption, zypp_list_choice_option, + zypp_list_choice_option_copy, + zypp_list_choice_option_free) + + +const char * zypp_list_choice_option_get_label( ZyppListChoiceOption *self ) +{ + return self->_cppObj.opt.c_str (); +} + +const char * zypp_list_choice_option_get_detail( ZyppListChoiceOption *self ) +{ + return self->_cppObj.detail.c_str (); +} + +static void user_request_if_init( ZyppUserRequestInterface *iface ); + +ZYPP_DECLARE_GOBJECT_BOILERPLATE ( ZyppListChoiceRequest, zypp_list_choice_request ) + +G_DEFINE_TYPE_WITH_CODE(ZyppListChoiceRequest, zypp_list_choice_request, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE ( ZYPP_TYPE_USER_REQUEST, user_request_if_init ) + G_ADD_PRIVATE ( ZyppListChoiceRequest ) +) + +ZYPP_DEFINE_GOBJECT_BOILERPLATE ( ZyppListChoiceRequest, zypp_list_choice_request, ZYPP, LIST_CHOICE_REQUEST ) + +#define ZYPP_D() \ + ZYPP_GLIB_WRAPPER_D( ZyppListChoiceRequest, zypp_list_choice_request ) + +// define the GObject stuff +enum { + PROP_CPPOBJ = 1, + N_PROPERTIES +}; + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +static void user_request_if_init( ZyppUserRequestInterface *iface ) +{ + ZyppUserRequestImpl::init_interface( iface ); +} + +static void zypp_list_choice_request_class_init (ZyppListChoiceRequestClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + ZYPP_INIT_GOBJECT_BOILERPLATE_KLASS ( zypp_list_choice_request, gobject_class ); + obj_properties[PROP_CPPOBJ] = ZYPP_GLIB_ADD_CPPOBJ_PROP(); + + g_object_class_install_properties (gobject_class, + N_PROPERTIES, + obj_properties); +} + +static void +zypp_list_choice_request_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail( ZYPP_IS_LIST_CHOICE_REQUEST (object) ); + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +zypp_list_choice_request_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail( ZYPP_IS_LIST_CHOICE_REQUEST (object) ); + ZyppListChoiceRequest *self = ZYPP_LIST_CHOICE_REQUEST (object); + + ZYPP_D(); + + switch (property_id) + { + case PROP_CPPOBJ: { + g_return_if_fail( d->_constrProps ); // only if the constr props are still valid + ZYPP_GLIB_SET_CPPOBJ_PROP( zyppng::ListChoiceRequestRef, value, d->_constrProps->_cppObj ); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +zyppng::ListChoiceRequestRef &zypp_list_choice_request_get_cpp( ZyppListChoiceRequest *self ) +{ + ZYPP_D(); + return d->_cppObj; +} + +const char * zypp_list_choice_request_get_label( ZyppListChoiceRequest *self ) +{ + ZYPP_D(); + return d->_cppObj->label().c_str(); +} + +GList *zypp_list_choice_request_get_options ( ZyppListChoiceRequest *self ) +{ + ZYPP_D(); + zypp::glib::GListContainer opts; + for ( const auto &answer : d->_cppObj->answers() ) { + opts.push_back ( zypp_wrap_cpp(answer) ); + } + return opts.take(); +} + +void zypp_list_choice_request_set_choice ( ZyppListChoiceRequest *self, guint choice ) +{ + ZYPP_D(); + d->_cppObj->setChoice(choice); +} + +guint zypp_list_choice_request_get_choice ( ZyppListChoiceRequest *self ) +{ + ZYPP_D(); + return d->_cppObj->choice(); +} + +guint zypp_list_choice_request_get_default( ZyppListChoiceRequest *self ) +{ + ZYPP_D(); + return d->_cppObj->defaultAnswer(); +} + diff --git a/zypp-glib/ui/listchoicerequest.h b/zypp-glib/ui/listchoicerequest.h new file mode 100644 index 0000000000..a0b72ff1de --- /dev/null +++ b/zypp-glib/ui/listchoicerequest.h @@ -0,0 +1,127 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_LIST_CHOICE_MESSAGE_REQUEST_H +#define ZYPP_GLIB_LIST_CHOICE_MESSAGE_REQUEST_H + +#include +#include +#include + +G_BEGIN_DECLS + + +#define ZYPP_TYPE_LIST_CHOICE_OPTION (zypp_list_choice_option_get_type()) + +/** + * ZyppListChoiceOption: + * + * One possible option for the user to select from, a option + * always consists of a label and a detail. The label is the short + * string that can be shown on a button or in a drop box , the detail is the description. + * + * For example: + * {"y", "Info about y"}, {"n", "Info about n"}, {"d", "Info about d"} + * + */ +typedef struct _ZyppListChoiceOption ZyppListChoiceOption; + +/** + * zypp_list_choice_option_copy: (skip): + * + * Copy the boxed type + */ +ZyppListChoiceOption * zypp_list_choice_option_copy ( ZyppListChoiceOption *r ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_list_choice_option_free: (skip): + * + * Free the boxed type + */ +void zypp_list_choice_option_free ( ZyppListChoiceOption *r ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_list_choice_option_get_label: + * + * Get the short label string for this option + */ +const char * zypp_list_choice_option_get_label( ZyppListChoiceOption *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_list_choice_option_get_detail: + * + * Get the detail string for this option + */ +const char * zypp_list_choice_option_get_detail( ZyppListChoiceOption *self ) LIBZYPP_GLIB_EXPORT; + + +/** + * ZyppListChoiceRequest: + * + * The `ZyppListChoiceRequest` event represents a choice request to the user, + * the possible answers are given via a GList of possible choices. + * + * |[ + * GList *choices = zypp_list_choice_request_get_options(msg); + * for (GList *l = choices; l != NULL; l = l->next) + * { + * ZyppListChoiceOption *option = l->data; + * printf("Option: %s with detail: %s") + * , zypp_list_choice_option_get_label(option) + * , zypp_list_choice_option_get_detail(option)); + * } + * g_list_free_full( choices, zypp_list_choice_option_free ); + * ]| + * + */ + +#pragma GCC visibility push(default) +G_DECLARE_FINAL_TYPE ( ZyppListChoiceRequest, zypp_list_choice_request, ZYPP, LIST_CHOICE_REQUEST, GObject ) +#pragma GCC visibility pop + +#define ZYPP_TYPE_LIST_CHOICE_REQUEST (zypp_list_choice_request_get_type ()) + +const char * zypp_list_choice_request_get_label( ZyppListChoiceRequest *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_list_choice_request_get_options: + * + * Returns: (element-type ZyppListChoiceOption) (transfer full): list of the available answer options + */ +GList *zypp_list_choice_request_get_options ( ZyppListChoiceRequest *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_list_choice_request_set_choice: + * + * Remember the users choice, this will be returned to the code that triggered the event. + */ +void zypp_list_choice_request_set_choice ( ZyppListChoiceRequest *self, guint choice ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_list_choice_request_get_choice: + * + * Get the current selected choice + */ +guint zypp_list_choice_request_get_choice( ZyppListChoiceRequest *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_list_choice_request_get_default: + * + * Get the default choice, this will be selected if is not overriden by the receiving code + */ +guint zypp_list_choice_request_get_default ( ZyppListChoiceRequest *self ) LIBZYPP_GLIB_EXPORT; + +G_END_DECLS + +#ifdef __cplusplus +#include +ZYPP_DEFINE_GOBJECT_SIMPLE( ZyppListChoiceRequest, zypp_list_choice_request, ZYPP, LIST_CHOICE_REQUEST ) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE( ZyppListChoiceOption, zypp_list_choice_option_free, ZYPP_GLIB_ADD_GLIB_COPYTRAIT(zypp_list_choice_option_copy) ) +#endif + +#endif // ZYPP_GLIB_LIST_CHOICE_MESSAGE_REQUEST_H diff --git a/zypp-glib/ui/private/booleanchoicerequest_p.h b/zypp-glib/ui/private/booleanchoicerequest_p.h new file mode 100644 index 0000000000..36d931776f --- /dev/null +++ b/zypp-glib/ui/private/booleanchoicerequest_p.h @@ -0,0 +1,59 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_BOOLEAN_CHOICE_REQUEST_P_H +#define ZYPP_GLIB_BOOLEAN_CHOICE_REQUEST_P_H + +#include +#include +#include + +#include + + +struct ZyppBooleanChoiceRequestPrivate + : public zypp::glib::WrapperPrivateBase +{ + struct ConstructionProps { + zyppng::BooleanChoiceRequestRef _cppObj; + }; + + std::optional _constrProps = ConstructionProps(); + zyppng::BooleanChoiceRequestRef _cppObj; + + ZyppBooleanChoiceRequestPrivate( ZyppBooleanChoiceRequest *pub ) : WrapperPrivateBase(pub) {} + + void initializeCpp(){ + g_return_if_fail ( _constrProps.has_value() ); + + if ( _constrProps->_cppObj ) { + _cppObj = std::move( _constrProps->_cppObj ); + } else { + g_error("It's not supported to create a ZyppBooleanChoiceRequest from C Code."); + } + _constrProps.reset(); + } + zyppng::BooleanChoiceRequestRef &cppType() { + return _cppObj; + } +}; + + +struct _ZyppBooleanChoiceRequest +{ + GObjectClass parent_class; +}; + +/** + * zypp_boolean_choice_request_get_cpp: (skip) + */ +zyppng::BooleanChoiceRequestRef &zypp_boolean_choice_request_get_cpp( ZyppBooleanChoiceRequest *self ); + + + +#endif diff --git a/zypp-glib/ui/private/inputrequest_p.h b/zypp-glib/ui/private/inputrequest_p.h new file mode 100644 index 0000000000..ccb4c4296e --- /dev/null +++ b/zypp-glib/ui/private/inputrequest_p.h @@ -0,0 +1,66 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_INPUT_REQUEST_P_H +#define ZYPP_GLIB_INPUT_REQUEST_P_H + +#include +#include +#include + +#include + +struct _ZyppInputRequestField +{ + zyppng::InputRequest::Field _cppObj; +}; + +ZyppInputRequestField * zypp_wrap_cpp( zyppng::InputRequest::Field obj ); + + +struct ZyppInputRequestPrivate + : public zypp::glib::WrapperPrivateBase +{ + struct ConstructionProps { + zyppng::InputRequestRef _cppObj; + }; + + std::optional _constrProps = ConstructionProps(); + zyppng::InputRequestRef _cppObj; + + ZyppInputRequestPrivate( ZyppInputRequest *pub ) : WrapperPrivateBase(pub) {} + + void initializeCpp(){ + g_return_if_fail ( _constrProps.has_value() ); + + if ( _constrProps->_cppObj ) { + _cppObj = std::move( _constrProps->_cppObj ); + } else { + g_error("It's not supported to create a ZyppInputRequest from C Code."); + } + _constrProps.reset(); + } + zyppng::InputRequestRef &cppType() { + return _cppObj; + } +}; + + +struct _ZyppInputRequest +{ + GObjectClass parent_class; +}; + +/** + * zypp_input_request_get_cpp: (skip) + */ +zyppng::InputRequestRef &zypp_input_request_get_cpp( ZyppInputRequest *self ); + + + +#endif // ZYPP_GLIB_INPUT_REQUEST_P_H diff --git a/zypp-glib/ui/private/listchoicerequest_p.h b/zypp-glib/ui/private/listchoicerequest_p.h new file mode 100644 index 0000000000..56be6a6470 --- /dev/null +++ b/zypp-glib/ui/private/listchoicerequest_p.h @@ -0,0 +1,65 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_LIST_CHOICE_REQUEST_P_H +#define ZYPP_GLIB_LIST_CHOICE_REQUEST_P_H + +#include +#include +#include + +#include + +struct _ZyppListChoiceOption +{ + zyppng::ListChoiceRequest::Choice _cppObj; +}; + +ZyppListChoiceOption * zypp_wrap_cpp( zyppng::ListChoiceRequest::Choice obj ); + +struct ZyppListChoiceRequestPrivate + : public zypp::glib::WrapperPrivateBase +{ + struct ConstructionProps { + zyppng::ListChoiceRequestRef _cppObj; + }; + + std::optional _constrProps = ConstructionProps(); + zyppng::ListChoiceRequestRef _cppObj; + + ZyppListChoiceRequestPrivate( ZyppListChoiceRequest *pub ) : WrapperPrivateBase(pub) {} + + void initializeCpp(){ + g_return_if_fail ( _constrProps.has_value() ); + + if ( _constrProps->_cppObj ) { + _cppObj = std::move( _constrProps->_cppObj ); + } else { + g_error("It's not supported to create a ZyppListChoiceRequest from C Code."); + } + _constrProps.reset(); + } + zyppng::ListChoiceRequestRef &cppType() { + return _cppObj; + } +}; + + +struct _ZyppListChoiceRequest +{ + GObjectClass parent_class; +}; + +/** + * zypp_list_choice_request_get_cpp: (skip) + */ +zyppng::ListChoiceRequestRef &zypp_list_choice_request_get_cpp( ZyppListChoiceRequest *self ); + + + +#endif diff --git a/zypp-glib/ui/private/showmessagerequest_p.h b/zypp-glib/ui/private/showmessagerequest_p.h new file mode 100644 index 0000000000..13da7b77db --- /dev/null +++ b/zypp-glib/ui/private/showmessagerequest_p.h @@ -0,0 +1,102 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_SHOW_MESSAGE_REQUEST_P_H +#define ZYPP_GLIB_SHOW_MESSAGE_REQUEST_P_H + +#include +#include + +#include +#include + +struct ZyppShowMsgRequestPrivate + : public zypp::glib::WrapperPrivateBase +{ + struct ConstructionProps { + zyppng::ShowMessageRequestRef _cppObj; + std::optional _label; + std::optional _type; + }; + + std::optional _constrProps = ConstructionProps(); + zyppng::ShowMessageRequestRef _cppObj; + + ZyppShowMsgRequestPrivate( ZyppShowMsgRequest *pub ) : WrapperPrivateBase(pub) {} + + void initializeCpp(){ + g_return_if_fail ( _constrProps.has_value() ); + + if ( _constrProps->_cppObj ) { + _cppObj = std::move( _constrProps->_cppObj ); + } else { + _cppObj = zyppng::ShowMessageRequest::create( _constrProps->_label.value_or(""), convertEnum( _constrProps->_type.value_or( ZYPP_SHOW_MSG_TYPE_INFO ) )); + } + _constrProps.reset(); + } + zyppng::ShowMessageRequestRef &cppType() { + return _cppObj; + } + + static zyppng::ShowMessageRequest::MType convertEnum( ZyppShowMsgRequestType t ) { + switch(t){ + case ZYPP_SHOW_MSG_TYPE_DEBUG: + return zyppng::ShowMessageRequest::MType::Debug; + case ZYPP_SHOW_MSG_TYPE_INFO: + return zyppng::ShowMessageRequest::MType::Info; + case ZYPP_SHOW_MSG_TYPE_WARNING: + return zyppng::ShowMessageRequest::MType::Warning; + case ZYPP_SHOW_MSG_TYPE_ERROR: + return zyppng::ShowMessageRequest::MType::Error; + case ZYPP_SHOW_MSG_TYPE_IMPORTANT: + return zyppng::ShowMessageRequest::MType::Important; + case ZYPP_SHOW_MSG_TYPE_DATA: + return zyppng::ShowMessageRequest::MType::Data; + break; + } + + ERR << "Unknown message type " << (int)t << std::endl; + return zyppng::ShowMessageRequest::MType::Info; + } + + static ZyppShowMsgRequestType convertEnum( zyppng::ShowMessageRequest::MType t ) { + switch(t){ + case zyppng::ShowMessageRequest::MType::Debug: + return ZYPP_SHOW_MSG_TYPE_DEBUG; + case zyppng::ShowMessageRequest::MType::Info: + return ZYPP_SHOW_MSG_TYPE_INFO; + case zyppng::ShowMessageRequest::MType::Warning: + return ZYPP_SHOW_MSG_TYPE_WARNING; + case zyppng::ShowMessageRequest::MType::Error: + return ZYPP_SHOW_MSG_TYPE_ERROR; + case zyppng::ShowMessageRequest::MType::Important: + return ZYPP_SHOW_MSG_TYPE_IMPORTANT; + case zyppng::ShowMessageRequest::MType::Data: + return ZYPP_SHOW_MSG_TYPE_DATA; + break; + } + + ERR << "Unknown message type " << (int)t << std::endl; + return ZYPP_SHOW_MSG_TYPE_INFO; + } + +}; + + +struct _ZyppShowMsgRequest +{ + GObjectClass parent_class; +}; + +/** + * zypp_show_message_request_get_cpp: (skip) + */ +zyppng::ShowMessageRequestRef &zypp_show_message_request_get_cpp( ZyppShowMsgRequest *self ); + + +#endif // ZYPP_GLIB_SHOW_MESSAGE_REQUEST_P_H diff --git a/zypp-glib/ui/private/userrequest_p.h b/zypp-glib/ui/private/userrequest_p.h new file mode 100644 index 0000000000..990c865bc6 --- /dev/null +++ b/zypp-glib/ui/private/userrequest_p.h @@ -0,0 +1,121 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_USERREQUEST_P_H +#define ZYPP_GLIB_USERREQUEST_P_H + +#include +#include + +#include +#include + +template +struct ZyppUserRequestImpl +{ + static gboolean T_IS_EXPECTED_GLIBTYPE (gpointer ptr) { + return ZYPP_IS_USER_REQUEST(ptr) && G_TYPE_CHECK_INSTANCE_TYPE ( ptr, GlibTypeFun() ); + } + + // make sure to call T_IS_EXPECTED_GLIBTYPE before calling this + static auto T_GET_PRIVATE( ZyppUserRequest *self ) { + return GetPrivateFun( G_TYPE_CHECK_INSTANCE_CAST (self, GlibTypeFun(), T) ); + } + + static ZyppUserRequestType get_request_type( ZyppUserRequest *self ) { + g_return_val_if_fail ( T_IS_EXPECTED_GLIBTYPE (self) && T_GET_PRIVATE(self)->_cppObj, ZYPP_USER_REQUEST_INVALID ); + return static_cast( T_GET_PRIVATE(self)->_cppObj->type() ); + } + + static GValue * get_data( ZyppUserRequest *self, const char *key ) { + g_return_val_if_fail ( T_IS_EXPECTED_GLIBTYPE (self) && T_GET_PRIVATE(self)->_cppObj, nullptr ); + const zypp::callback::UserData &data = T_GET_PRIVATE(self)->_cppObj->userData(); + g_return_val_if_fail ( data.haskey(key), nullptr ); + + const boost::any &val = data.getvalue(key); + if ( val.type() == boost::typeindex::type_id() ) { + GValue *value = g_new0 (GValue, 1); + g_value_init(value, G_TYPE_STRING ); + g_value_set_string(value, g_strdup( boost::any_cast( val ).c_str() ) ); + return value; + } else if( val.type() == boost::typeindex::type_id() ) { + GValue *value = g_new0 (GValue, 1); + g_value_init(value, G_TYPE_INT ); + g_value_set_int( value, boost::any_cast( val ) ); + return value; + } else if( val.type() == boost::typeindex::type_id() ) { + GValue *value = g_new0 (GValue, 1); + g_value_init(value, G_TYPE_INT ); + g_value_set_int( value, boost::any_cast( val ) ); + return value; + } else if( val.type() == boost::typeindex::type_id() ) { + GValue *value = g_new0 (GValue, 1); + g_value_init(value, G_TYPE_STRING ); + g_value_set_string(value, g_strdup( boost::any_cast( val ).c_str() ) ); + return value; + } + + g_warning( ( zypp::str::Str()<<"Unknown value type for key: "<_cppObj, nullptr ); + + zypp::glib::GCharContainer list; + const zypp::callback::UserData &data = T_GET_PRIVATE(self)->_cppObj->userData(); + for ( const auto &entry : data.data() ) { + list.push_back( g_strdup( entry.first.c_str () ) ); + } + return list.take (); + } + + static gchar *get_content_type( ZyppUserRequest *self ) { + g_return_val_if_fail ( T_IS_EXPECTED_GLIBTYPE (self) && T_GET_PRIVATE(self)->_cppObj, nullptr ); + const zypp::callback::UserData &data = T_GET_PRIVATE(self)->_cppObj->userData(); + return g_strdup(data.type().asString().c_str()); + } + + static void set_accepted( ZyppUserRequest *self ) + { + g_return_if_fail ( T_IS_EXPECTED_GLIBTYPE (self) && T_GET_PRIVATE(self)->_cppObj ); + T_GET_PRIVATE(self)->_cppObj->accept(); + } + + static void set_rejected( ZyppUserRequest *self ) + { + g_return_if_fail ( T_IS_EXPECTED_GLIBTYPE (self) && T_GET_PRIVATE(self)->_cppObj ); + T_GET_PRIVATE(self)->_cppObj->reject(); + } + + static void set_ignored ( ZyppUserRequest *self ) + { + g_return_if_fail ( T_IS_EXPECTED_GLIBTYPE (self) && T_GET_PRIVATE(self)->_cppObj ); + T_GET_PRIVATE(self)->_cppObj->ignore(); + } + + static gboolean get_accepted( ZyppUserRequest *self ) + { + g_return_val_if_fail ( T_IS_EXPECTED_GLIBTYPE (self) && T_GET_PRIVATE(self)->_cppObj, false ); + return T_GET_PRIVATE(self)->_cppObj->accepted(); + } + + static void init_interface( ZyppUserRequestInterface *iface ) + { + iface->get_request_type = get_request_type; + iface->get_data = get_data; + iface->get_keys = get_keys; + iface->get_content_type = get_content_type; + iface->set_accepted = set_accepted; + iface->set_rejected = set_rejected; + iface->set_ignored = set_ignored; + iface->get_accepted = get_accepted; + } +}; + +#endif diff --git a/zypp-glib/ui/showmessagerequest.cc b/zypp-glib/ui/showmessagerequest.cc new file mode 100644 index 0000000000..451a9ba692 --- /dev/null +++ b/zypp-glib/ui/showmessagerequest.cc @@ -0,0 +1,173 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "private/showmessagerequest_p.h" +#include "private/userrequest_p.h" + +#include +#include + + +static void user_request_if_init( ZyppUserRequestInterface *iface ); + +ZYPP_DECLARE_GOBJECT_BOILERPLATE ( ZyppShowMsgRequest, zypp_show_msg_request ) + +G_DEFINE_TYPE_WITH_CODE(ZyppShowMsgRequest, zypp_show_msg_request, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE ( ZYPP_TYPE_USER_REQUEST, user_request_if_init ) + G_ADD_PRIVATE ( ZyppShowMsgRequest ) +) + +ZYPP_DEFINE_GOBJECT_BOILERPLATE ( ZyppShowMsgRequest, zypp_show_msg_request, ZYPP, SHOW_MSG_REQUEST ) + +#define ZYPP_D() \ + ZYPP_GLIB_WRAPPER_D( ZyppShowMsgRequest, zypp_show_msg_request ) + + +// define the GObject stuff +enum { + PROP_CPPOBJ = 1, + PROP_LABEL, + PROP_TYPE, + N_PROPERTIES +}; + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +static void user_request_if_init( ZyppUserRequestInterface *iface ) +{ + ZyppUserRequestImpl::init_interface( iface ); +} + +static void zypp_show_msg_request_class_init (ZyppShowMsgRequestClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + ZYPP_INIT_GOBJECT_BOILERPLATE_KLASS ( zypp_show_msg_request, gobject_class ); + + obj_properties[PROP_CPPOBJ] = ZYPP_GLIB_ADD_CPPOBJ_PROP(); + obj_properties[PROP_LABEL] = g_param_spec_string ( + "label", + "Label", + "String for the message Label.", + NULL /* default value */, + GParamFlags( G_PARAM_CONSTRUCT | G_PARAM_READWRITE ) ); + + obj_properties[PROP_TYPE] = g_param_spec_enum ( + "type", + "Type", + "Message type specifier.", + zypp_show_msg_request_type_get_type(), + ZYPP_SHOW_MSG_TYPE_INFO, + GParamFlags( G_PARAM_CONSTRUCT | G_PARAM_READWRITE ) ); + + g_object_class_install_properties (gobject_class, + N_PROPERTIES, + obj_properties); +} + +static void +zypp_show_msg_request_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail( ZYPP_IS_SHOW_MSG_REQUEST (object) ); + ZyppShowMsgRequest *self = ZYPP_SHOW_MSG_REQUEST (object); + + ZYPP_D(); + + switch (property_id) + { + case PROP_LABEL: { + if ( d->_constrProps ) { + if ( d->_constrProps->_label ) + g_value_set_string( value, d->_constrProps->_label->c_str() ); + } else { + g_return_if_fail( d->_cppObj ); + g_value_set_string( value, d->_cppObj->message().c_str() ); + return; + } + break; + } + case PROP_TYPE: { + if ( d->_constrProps ) { + if ( d->_constrProps->_type ) + g_value_set_enum( value, static_cast(*d->_constrProps->_type) ); + } else { + g_return_if_fail( d->_cppObj ); + g_value_set_enum( value, static_cast( d->convertEnum( d->_cppObj->messageType() ))); + return; + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +zypp_show_msg_request_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail( ZYPP_IS_SHOW_MSG_REQUEST (object) ); + ZyppShowMsgRequest *self = ZYPP_SHOW_MSG_REQUEST (object); + + ZYPP_D(); + + switch (property_id) + { + case PROP_CPPOBJ: { + g_return_if_fail( d->_constrProps ); // only if the constr props are still valid + ZYPP_GLIB_SET_CPPOBJ_PROP( zyppng::ShowMessageRequestRef, value, d->_constrProps->_cppObj ); + break; + } + case PROP_LABEL: { + if ( d->_constrProps ) { + d->_constrProps->_label = zypp::str::asString( g_value_get_string(value) ); + } else { + g_warning ("The label property is only writable at construction."); + return; + } + break; + } + case PROP_TYPE: { + if ( d->_constrProps ) { + d->_constrProps->_type = static_cast(g_value_get_enum ( value )); + } else { + g_warning ("The type property is only writable at construction."); + return; + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +ZyppShowMsgRequestType zypp_show_msg_request_get_message_type ( ZyppShowMsgRequest *self ) +{ + ZYPP_D(); + g_return_val_if_fail ( d->_cppObj, ZYPP_SHOW_MSG_TYPE_INFO ); + return d->convertEnum(d->_cppObj->messageType()); +} + +const char * zypp_show_msg_request_get_message( ZyppShowMsgRequest *self ) +{ + ZYPP_D(); + g_return_val_if_fail ( d->_cppObj, nullptr ); + return d->_cppObj->message().data(); +} + +zyppng::ShowMessageRequestRef &zypp_show_message_request_get_cpp( ZyppShowMsgRequest *self ) +{ + ZYPP_D(); + return d->_cppObj; +} diff --git a/zypp-glib/ui/showmessagerequest.h b/zypp-glib/ui/showmessagerequest.h new file mode 100644 index 0000000000..2f6bb59eea --- /dev/null +++ b/zypp-glib/ui/showmessagerequest.h @@ -0,0 +1,61 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_SHOW_MESSAGE_REQUEST_H +#define ZYPP_GLIB_SHOW_MESSAGE_REQUEST_H + +#include +#include +#include + +G_BEGIN_DECLS + +#pragma GCC visibility push(default) +G_DECLARE_FINAL_TYPE ( ZyppShowMsgRequest, zypp_show_msg_request, ZYPP, SHOW_MSG_REQUEST, GObject ) +#pragma GCC visibility pop + +#define ZYPP_TYPE_SHOW_MSG_REQUEST (zypp_show_msg_request_get_type ()) + +/** + * ZyppShowMsgRequestType: + * @ZYPP_SHOW_MSG_TYPE_DEBUG: Show a debug level message + * @ZYPP_SHOW_MSG_TYPE_INFO: Show a info level message + * @ZYPP_SHOW_MSG_TYPE_WARNING: Show a warning level message + * @ZYPP_SHOW_MSG_TYPE_ERROR: Show a error level message + * @ZYPP_SHOW_MSG_TYPE_IMPORTANT: Show a important level message + * @ZYPP_SHOW_MSG_TYPE_DATA: Show a data level message + * + * Specifies the type of message to be shown + */ +typedef enum { + ZYPP_SHOW_MSG_TYPE_DEBUG, + ZYPP_SHOW_MSG_TYPE_INFO, + ZYPP_SHOW_MSG_TYPE_WARNING, + ZYPP_SHOW_MSG_TYPE_ERROR, + ZYPP_SHOW_MSG_TYPE_IMPORTANT, + ZYPP_SHOW_MSG_TYPE_DATA +} ZyppShowMsgRequestType; + +/** + * ZyppShowMsgRequest: + * + * Signals the application to show a message to the user, which does not require + * a answer. This could be implemented as a popup, or simply printed to a output window. + */ + +ZyppShowMsgRequestType zypp_show_msg_request_get_message_type ( ZyppShowMsgRequest *self ) LIBZYPP_GLIB_EXPORT; +const char * zypp_show_msg_request_get_message( ZyppShowMsgRequest *self ) LIBZYPP_GLIB_EXPORT; + +G_END_DECLS + +#ifdef __cplusplus +#include +ZYPP_DEFINE_GOBJECT_SIMPLE( ZyppShowMsgRequest, zypp_show_msg_request, ZYPP, SHOW_MSG_REQUEST ) +#endif + +#endif // ZYPP_GLIB_SHOW_MESSAGE_REQUEST_H diff --git a/zypp-glib/ui/userrequest.cc b/zypp-glib/ui/userrequest.cc new file mode 100644 index 0000000000..e8f95bb4f8 --- /dev/null +++ b/zypp-glib/ui/userrequest.cc @@ -0,0 +1,58 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "private/userrequest_p.h" +#include + +G_DEFINE_INTERFACE (ZyppUserRequest, zypp_user_request, G_TYPE_OBJECT) +static void zypp_user_request_default_init ( ZyppUserRequestInterface *g_class ) +{ + /* add properties and signals to the interface here */ +} + +ZyppUserRequestType zypp_user_request_get_request_type( ZyppUserRequest *self ) +{ + g_return_val_if_fail (ZYPP_IS_USER_REQUEST (self), ZYPP_USER_REQUEST_INVALID); + return ZYPP_USER_REQUEST_GET_IFACE (self)->get_request_type( self ); +} + +GValue *zypp_user_request_get_data ( ZyppUserRequest *self, const char *key ) +{ + g_return_val_if_fail (ZYPP_IS_USER_REQUEST (self), nullptr); + return ZYPP_USER_REQUEST_GET_IFACE (self)->get_data( self, key ); +} + +GList *zypp_user_request_get_keys ( ZyppUserRequest *self ) +{ + g_return_val_if_fail (ZYPP_IS_USER_REQUEST (self), nullptr); + return ZYPP_USER_REQUEST_GET_IFACE (self)->get_keys( self ); +} + +gchar *zypp_user_request_get_content_type( ZyppUserRequest *self ) +{ + g_return_val_if_fail (ZYPP_IS_USER_REQUEST (self), nullptr); + return ZYPP_USER_REQUEST_GET_IFACE (self)->get_content_type( self ); +} + +void zypp_user_request_set_accepted( ZyppUserRequest *self ) +{ + g_return_if_fail (ZYPP_IS_USER_REQUEST (self) ); + ZYPP_USER_REQUEST_GET_IFACE (self)->set_accepted( self ); +} + +void zypp_user_request_set_ignored ( ZyppUserRequest *self ) +{ + g_return_if_fail (ZYPP_IS_USER_REQUEST (self) ); + ZYPP_USER_REQUEST_GET_IFACE (self)->set_ignored( self ); +} + +gboolean zypp_user_request_get_accepted( ZyppUserRequest *self ) +{ + g_return_val_if_fail (ZYPP_IS_USER_REQUEST (self), false ); + return ZYPP_USER_REQUEST_GET_IFACE (self)->get_accepted( self ); +} diff --git a/zypp-glib/ui/userrequest.h b/zypp-glib/ui/userrequest.h new file mode 100644 index 0000000000..bdcdcd9503 --- /dev/null +++ b/zypp-glib/ui/userrequest.h @@ -0,0 +1,123 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_USERREQUEST_H +#define ZYPP_GLIB_USERREQUEST_H + +#include +#include + +G_BEGIN_DECLS + + +#define ZYPP_TYPE_USER_REQUEST (zypp_user_request_get_type ()) + +#pragma GCC visibility push(default) +G_DECLARE_INTERFACE (ZyppUserRequest, zypp_user_request, ZYPP, USER_REQUEST, GObject) +#pragma GCC visibility pop + +/** + * ZyppUserRequestType: + * @ZYPP_USER_REQUEST_POPUP: As user request that has a label and predefined possible answers + * @ZYPP_USER_REQUEST_MEDIACHANGE: Ask the user to change a medium + * + * Specifies the type of the event. + */ +typedef enum { + ZYPP_USER_REQUEST_INVALID, + ZYPP_USER_REQUEST_MESSAGE, + ZYPP_USER_REQUEST_LIST_CHOICE, + ZYPP_USER_REQUEST_BOOLEAN_CHOICE, + ZYPP_USER_REQUEST_LAST /* helper variable for decls */ +} ZyppUserRequestType; + + +struct LIBZYPP_GLIB_EXPORT _ZyppUserRequestInterface +{ + GTypeInterface parent_iface; + + ZyppUserRequestType (*get_request_type)( ZyppUserRequest *self ); + GValue *(*get_data) ( ZyppUserRequest *self, const char *key ); + GList *(*get_keys) ( ZyppUserRequest *self ); + gchar *(*get_content_type)( ZyppUserRequest *self ); + void (*set_accepted)( ZyppUserRequest *self ); + void (*set_rejected)( ZyppUserRequest *self ); + void (*set_ignored) ( ZyppUserRequest *self ); + gboolean(*get_accepted)( ZyppUserRequest *self ); +}; + + +/** + * ZyppUserRequest: + * + * `ZyppUserRequest`s are data structures, created by libzypp to represent direct requests to + * the user. They are delivered via a signal in the currently active zypp context object. + * + * If a request requires a answer from the user, they always have a default response in case the progress is running in non interactive mode. + */ + +ZyppUserRequestType zypp_user_request_get_request_type( ZyppUserRequest *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_user_request_get_data: + * + * Get's the corresponding request data value for key, if there is no such key NULL is returned. + * See the user request documentation for a data field listing of libzypp's user requests. + * + * Returns: (nullable) (transfer full): The data type corresponding to the key. + */ +GValue *zypp_user_request_get_data ( ZyppUserRequest *self, const char *key ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_user_request_get_keys: + * + * Returns: (element-type gchar) (transfer full): list of keys of userdata + */ +GList *zypp_user_request_get_keys ( ZyppUserRequest *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_user_request_get_content_type: + * + * Returns: (nullable) (transfer full): Returns the content type string of the user request. + */ +gchar *zypp_user_request_get_content_type( ZyppUserRequest *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_user_request_set_accepted: + * + * Marks the user request as handled. Before handling a event code should always check if it + * was already handled. If a request is not marked as handled, it will bubble up to the parent + * task observer until being returned as unhandled to the calling code. + */ +void zypp_user_request_set_accepted( ZyppUserRequest *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_user_request_set_ignored: + * + * Marks the user request as NOT handled, basically clearing the internal flag. As long as a request + * is not marked as handled it will bubble up the task observer tree until either the root observer + * also chose to ignore it, or it is marked as handled by user code. + */ +void zypp_user_request_set_ignored ( ZyppUserRequest *self ) LIBZYPP_GLIB_EXPORT; + +/** + * zypp_user_request_get_accepted: + * + * Returns true if the request was already handled. + */ +gboolean zypp_user_request_get_accepted( ZyppUserRequest *self ) LIBZYPP_GLIB_EXPORT; + + +G_END_DECLS + +#ifdef __cplusplus +#include +ZYPP_DEFINE_GOBJECT_SIMPLE( ZyppUserRequest, zypp_user_request, ZYPP, USER_REQUEST ) +#endif + +#endif diff --git a/zypp-glib/ui/zyppenums-ui.c.in b/zypp-glib/ui/zyppenums-ui.c.in new file mode 100644 index 0000000000..7e640196a0 --- /dev/null +++ b/zypp-glib/ui/zyppenums-ui.c.in @@ -0,0 +1,29 @@ +/*** BEGIN file-header ***/ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +/* enumerations from \"zyppng/@basename@\" */ +#include +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +G_DEFINE_ENUM_TYPE (@EnumName@, @enum_name@ +/*** END value-header ***/ + +/*** BEGIN value-production ***/ + ,G_DEFINE_ENUM_VALUE ( @VALUENAME@, "@valuenick@") +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ +) +/*** END value-tail ***/ diff --git a/zypp-glib/ui/zyppenums-ui.h.in b/zypp-glib/ui/zyppenums-ui.h.in new file mode 100644 index 0000000000..d515e98d7b --- /dev/null +++ b/zypp-glib/ui/zyppenums-ui.h.in @@ -0,0 +1,31 @@ +/*** BEGIN file-header ***/ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#pragma once +#include +#include +G_BEGIN_DECLS +#pragma GCC visibility push(default) +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + +/* enumerations from "@basename@" */ +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType @enum_name@_get_type (void) G_GNUC_CONST LIBZYPP_GLIB_EXPORT; +#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) +/*** END value-header ***/ + + +/*** BEGIN file-tail ***/ +#pragma GCC visibility pop +G_END_DECLS +/*** END file-tail ***/ diff --git a/zypp-glib/utils/GHashTable b/zypp-glib/utils/GHashTable new file mode 100644 index 0000000000..4fcd6ea700 --- /dev/null +++ b/zypp-glib/utils/GHashTable @@ -0,0 +1,212 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_UTIL_GHASHTABLE_H +#define ZYPP_GLIB_UTIL_GHASHTABLE_H + +#include +#include +#include +#include + +namespace zypp { + + namespace internal { + + template + struct GHashKeyTraits : public GContainerTraits { + static guint hash ( gconstpointer v ) { + if constexpr ( std::is_same_v< guint8, T> || std::is_same_v< guint16, T> || std::is_same_v< guint32, T> ) { + return ::g_direct_hash( GPOINTER_TO_UINT( v ) ); + } else if constexpr ( std::is_same_v< gint8, T> || std::is_same_v< gint16, T> || std::is_same_v< gint32, T> ) { + return ::g_direct_hash( GPOINTER_TO_INT( v ) ); + } else if constexpr ( std::is_same_v< guint64, T> || std::is_same_v< gulong, T> || std::is_same_v< gsize, T> ) { + return ::g_direct_hash( GPOINTER_TO_SIZE( v ) ); + } else if constexpr ( std::is_same_v< gint64, T> || std::is_same_v< glong, T> ) { + return ::g_direct_hash( GPOINTER_TO_SIZE( v ) ); + } else if constexpr ( std::is_same_v< GString*, T> ) { + return ::g_string_hash( v ); + } else { + const T &val = *((T*)v); + const auto &hash = std::hash(val); + if ( hash > UINT32_MAX ) { + + } + return (guint32)hash; + } + } + }; + + template + class ghashtable_ref + { + public: + using value_type = typename Traits::value_type; + + ghashtable_ref( ::GHashTable *_table, gconstpointer key, gpointer value = nullptr ) : _table(_table), _key(key), _valueCache(value) { } + + operator value_type () const { + return getValue(); + } + + ghashtable_ref &operator= ( const value_type& val ) { + ::g_hash_table_replace( _table, _key, Traits::valueToPointer(val) ); + _valueCache = nullptr; + return *this; + } + + ghashtable_ref &operator= ( const ghashtable_ref& val ) { + (*this) = val.getValue(); + _valueCache = nullptr;s + return *this; + } + + bool operator== ( const ghashtable_ref& other ) const { + return getValue() == other.getValue(); + } + + + bool operator== ( const value_type& val ) const { + return getValue() == val; + } + + private: + value_type getValue () const { + if ( !_valueCache ) { + if ( !g_hash_table_lookup_extended( _table, _key, nullptr, &_valueCache ) ) { + throw std::logic_error("Dereferencing a invalid element"); + } + } + return Traits::pointerToValue(_valueCache); + } + + private: + ::GHashTable *_table; + gconstpointer _key; + gpointer _valueCache = nullptr; //set after the first lookup + }; + + template + class ghashtable_iter + : public boost::iterator_facade< + glistcontainer_iter + , T + , boost::forward_traversal_tag + , std::conditional_t< std::is_const_v + , std::pair + , std::pair + > + > + { + public: + ghashtable_iter() {} + + explicit ghashtable_iter(GHashTable* p) { + _iter = ::GHashTableIter(); + ::g_hash_table_iter_init( &(_iter.value()), p ); + increment(); + } + + private: + friend class boost::iterator_core_access; + + void increment() { + if ( _iter ) { + if ( !::g_hash_table_iter_next( &(_iter.value()), &currKey, &currValue ) ) + _iter.reset(); + } + } + + bool equal(ghashtable_iter const& other) const { + if ( _iter == other._iter ) { + if ( !iter ) + return true; // end iterator + + if ( ::g_hash_table_iter_get_hash_table( _iter.get() ) == ::g_hash_table_iter_get_hash_table( other._iter.get() ) ) { + return Traits::hash(this->currKey) == Traits::hash(other.currKey); + } + } + return false; + } + + decltype(auto) dereference() const { + if constexpr ( std::is_const_v ) { + return Traits::dereferenceConstData( _node ); + } else { + return Traits::dereferenceData( _node ); + } + } + + std::optional<::GHashTableIter> _iter; + gpointer currKey = nullptr; + gpointer currValue = nullptr; + }; + + } + + template + class GHashTableView + { + public: + using key_value_type = typename KeyTraits::value_type; + using value_type = typename ValueTraits::value_type; + + GHashTableView ( const ::GHashTable *table ) + : _table( const_cast<::GHashTable*>(table) ) // removing the const for internal use of the pointer, all glib func want a non const version + { } + + ~GHashTableView() { + ::g_hash_table_unref( _table ); + } + + value_type lookup ( const key_value_type &val ) const { + auto res = ::g_hash_table_lookup( _table, KeyTraits::valueToPointer(val) ); + if ( !res ) + throw std::out_of_range("No such key"); + return ValueTraits::pointerToValue( res ); + } + + bool contains ( const key_value_type &val ) const { + return ::g_hash_table_lookup( _table, KeyTraits::valueToPointer(val) ) != nullptr; + } + + size_t size () const { + return ::g_hash_table_size( _table ); + } + + GListView keys () const { + return GListView ( + g_hash_table_get_keys ( _table ) + , Ownership::Container + ); + } + + GListView values () const { + return GListView ( + g_hash_table_get_values ( _table ) + , Ownership::Container + ); + } + + private: + ::GHashTable *_table; + + }; + + + template + class GHashTableContainer : public GHashTableView + { + + }; + + +} + + +#endif diff --git a/zypp-glib/utils/GLibMemory b/zypp-glib/utils/GLibMemory new file mode 100644 index 0000000000..58b3be99c1 --- /dev/null +++ b/zypp-glib/utils/GLibMemory @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2017 Canonical Ltd. + * Copyright (C) 2022 SUSE Software Solutions Germany GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 as + * published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: Pete Woods + * Michi Henning + * James Henstridge + * Benjamin Zeller + */ + +#ifndef ZYPP_GLIB_UTIL_GLIBMEMORY_H +#define ZYPP_GLIB_UTIL_GLIBMEMORY_H + +#include +#include + + +#include +#include +#include +namespace zypp::glib { + + template< typename T> struct GLibTypeTraits; + + template > + struct StdDeleterForGlibType { + void operator() ( T* ptr ) const { + Trait::delete_fn(ptr); + } + }; + + namespace internal + { + /** + * \brief Adapter class to assign to smart pointers from functions that take a reference. + * + * Adapter class that allows passing a shared_ptr or unique_ptr where glib + * expects a parameter of type ElementType** (such as GError**), by providing + * a default conversion operator to ElementType**. This allows the glib method + * to assign to the ptr_ member. From the destructor, we assign to the + * provided smart pointer. + */ + template + class GlibAssigner + { + public: + typedef typename SP::element_type ElementType; + using TraitsType = typename SP::traits_type; + + GlibAssigner(SP& smart_ptr) noexcept : + smart_ptr_(smart_ptr) + { + } + + GlibAssigner(const GlibAssigner& other) = delete; + + GlibAssigner(GlibAssigner&& other) noexcept: + ptr_(other.ptr_), smart_ptr_(other.smart_ptr_) + { + other.ptr_ = nullptr; + } + + ~GlibAssigner() noexcept + { + smart_ptr_ = SP(ptr_); + } + + GlibAssigner& operator=(const GlibAssigner& other) = delete; + + operator ElementType**() noexcept + { + return &ptr_; + } + + private: + ElementType* ptr_ = nullptr; + + SP& smart_ptr_; + }; + + struct GSourceUnsubscriber + { + void operator()(guint tag) noexcept + { + if (tag != 0) + { + g_source_remove(tag); + } + } + }; + + template + using has_glib_type_trait = typename GLibTypeTraits::type_name; // type name is required to be in all the glib traits + + template + using has_retain_traits = typename T::RetainTraits; + + template + using has_delete_trait = decltype(T::delete_fn(std::declval< typename T::type_name *>())); + + template + using is_simple_copy_trait_fn = decltype( std::declval()(std::declval()) ); + + template + using is_extended_copy_trait_fn = decltype(std::declval()(std::declval(), std::declval< gpointer >()) ); + + template + using has_simple_copy_trait = is_simple_copy_trait_fn< typename T::type_name, decltype(T::copy_fn) >; + + template + using has_extended_copy_trait = is_extended_copy_trait_fn< typename T::type_name, decltype(T::copy_fn) >; + } + +/** + \brief Helper method to take ownership of glib types assigned from a reference. + + Example: + \code{.cpp} + GErrorUPtr error; + if (!g_key_file_get_boolean(gkf.get(), "group", "key", assign_glib(error))) + { + std::cerr << error->message << std::endl; + throw some_exception(); + } + \endcode + + Another example: + \code{.cpp} + gcharUPtr name; + g_object_get(obj, "name", assign_glib(name), nullptr); + \endcode + */ +template +inline internal::GlibAssigner assign_glib(SP& smart_ptr) noexcept +{ + return internal::GlibAssigner(smart_ptr); +} + +using GSourceManager = ResourcePtr; + +/** + \brief Simple wrapper to manage the lifecycle of sources. + + When 'timer' goes out of scope or is dealloc'ed, the source will be removed: + \code{.cpp} + auto timer = g_source_manager(g_timeout_add(5000, on_timeout, nullptr)); + \endcode + */ +inline GSourceManager g_source_manager(guint id) +{ + return GSourceManager(id, internal::GSourceUnsubscriber()); +} + +} // namespace zypp::glib + +/** + * @brief Generates the minimum \ref zypp::internal::GLibTypeTraits for the given \a TypeName. + * These Type traits are used in C++ code to detect features of the glib types at compile time. + */ +#define ZYPP_GLIB_DEFINE_GLIB_TRAITS_WITH_CODE(TypeName, ...) \ +namespace zypp::glib \ +{ \ + template<> struct GLibTypeTraits<::TypeName> \ + { \ + using type_name = ::TypeName; \ + __VA_ARGS__\ + }; \ +} + +/** + * @brief Generates the minimum \ref zypp::internal::GLibTypeTraits for the given ambigous \a TypeName. + * Some types that are exported from glib are just simply typedefs for void. In those cases overloading + * the \ref GLibTypeTraits template does not work. And they are not detected automatically. + * Instead we create a Traits type having the TypeName as a postfix: GLibTypeTraitsTypeName for example. + * This trait can then be passed explicitely to templates requiring a GLibTypeTraits + */ +#define ZYPP_GLIB_DEFINE_AMBIGOUS_TYPE_GLIB_TRAITS_WITH_CODE(TypeName, ...) \ +namespace zypp::glib \ +{ \ + struct GLibTypeTraits##TypeName \ + { \ + using type_name = TypeName; \ + __VA_ARGS__\ + }; \ +} + +/** + * @brief Adds a retain trait to the enclosing \ref GLibTypeTraits. + * Use this as a argument to a \ref GLibTypeTraits definition in case the type supports reference counting. + * \code {.cpp} + * + * ZYPP_GLIB_DEFINE_GLIB_TRAITS_WITH_CODE(TypeName, + * ZYPP_GLIB_ADD_GLIB_RETAINTRAITS_FULL( TypeName_ref, TypeName_unref ) + * ) + * + * \endcode + */ +#define ZYPP_GLIB_ADD_GLIB_RETAINTRAITS_FULL( ref, unref ) \ +static constexpr auto ref_counting = true; \ +struct RetainTrait { \ + static void increment( type_name *ptr ){ \ + ::ref(ptr); \ + } \ + static void decrement( type_name *ptr ) { \ + ::unref(ptr); \ + } \ +}; + +/** + * @brief Convenience macro to add a retain trait to a type + * This macro can be used whenever the type has reference counting and + * uses functions with _ref and _unref postfixes. E.g. g_object_ref and g_object_unref + * + * \code {.cpp} + * // will add retain traits using g_object_ref and g_object_unref functions + * ZYPP_GLIB_DEFINE_GLIB_TRAITS_WITH_CODE(GObject, + * ZYPP_GLIB_ADD_GLIB_RETAINTRAITS( g_object ) + * ) + * \endcode + */ +#define ZYPP_GLIB_ADD_GLIB_RETAINTRAITS( ref_prefix ) ZYPP_GLIB_ADD_GLIB_RETAINTRAITS_FULL( ref_prefix##_ref, ref_prefix##_unref ) + +/** + * @brief Adds a copy helper trait to a \ref GLibTypeTraits type + * The given \a copyfn must either return a new instance or increase the refcount and return a pointer to the refcounted object, + * this is the case for all GObject types, because GObject's can not be copied + */ +#define ZYPP_GLIB_ADD_GLIB_COPYTRAIT(copyfn) \ + static type_name *copy_fn ( type_name *ptr ){ \ + return ::copyfn(ptr); \ + } + +/** + * @brief Adds a delete helper trait to a \ref GLibTypeTraits type + * The given function must either delete the given object or decrease the refcount in case of reference counted types. + */ +#define ZYPP_GLIB_ADD_GLIB_DELETETRAIT(delfn) \ + static void delete_fn ( type_name *ptr ){ \ + ::delfn(ptr); \ + } + +/** + * @brief Convencience macro to define the standard traits and smart pointer types for ref counted types + */ +#define ZYPP_GLIB_DEFINE_GLIB_REF_TYPE_FULL(TypeName, ref, unref, ...) \ +ZYPP_GLIB_DEFINE_GLIB_TRAITS_WITH_CODE(TypeName, \ + ZYPP_GLIB_ADD_GLIB_RETAINTRAITS_FULL( ref, unref ) \ + ZYPP_GLIB_ADD_GLIB_COPYTRAIT ( ref ) \ + ZYPP_GLIB_ADD_GLIB_DELETETRAIT ( unref ) \ + __VA_ARGS__ \ +) \ +namespace zypp::glib { \ + using TypeName##Ref = RetainPtr::RetainTrait>; \ + using TypeName##UniqueRef = std::unique_ptr >; \ +} + +/** + * @brief Convencience macro to define the standard traits and smart pointer types for ref counted types using ref and unref functions + * with the same prefix, e.g. g_object_ref and g_object_unref + */ +#define ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(TypeName, ref_prefix ) \ + ZYPP_GLIB_DEFINE_GLIB_REF_TYPE_FULL( TypeName, ref_prefix##_ref, ref_prefix##_unref ) + +/** + * @brief Convencience macro to define the standard traits and smart pointer types for a simply glib type, that is a type only + * having a delete helper trait. + */ +#define ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(TypeName, func, ...) \ +ZYPP_GLIB_DEFINE_GLIB_TRAITS_WITH_CODE(TypeName, \ + ZYPP_GLIB_ADD_GLIB_DELETETRAIT ( func ) \ + __VA_ARGS__ \ +) \ +namespace zypp::glib { \ + static_assert( !std::is_same_v, "Void derived types can not be used with ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE" );\ + using TypeName##Ref = OpaqueTypePtr >; \ + using TypeName##UniqueRef = std::unique_ptr >; \ +} + +/** + * @brief Convencience macro to define the standard traits and smart pointer types for a simple ambiguous glib type, that is a type only + * having a delete helper trait. + */ +#define ZYPP_GLIB_DEFINE_GLIB_AMBIGUOUS_TYPE(TypeName, func, ... ) \ +ZYPP_GLIB_DEFINE_AMBIGOUS_TYPE_GLIB_TRAITS_WITH_CODE(TypeName, \ + ZYPP_GLIB_ADD_GLIB_DELETETRAIT ( func ) \ + __VA_ARGS__ \ +) \ +namespace zypp::glib { \ + using TypeName##Ref = OpaqueTypePtr >; \ + using TypeName##UniqueRef = std::unique_ptr >; \ +} + + +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GAsyncQueue, g_async_queue) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GBookmarkFile, g_bookmark_file_free) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GBytes, g_bytes) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GChecksum, g_checksum_free) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GDateTime, g_date_time) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GDate, g_date_free) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GDir, g_dir_close) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GError, g_error_free) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GHashTable, g_hash_table) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GHmac, g_hmac) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GIOChannel, g_io_channel) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GKeyFile, g_key_file) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GList, g_list_free) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GArray, g_array) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GPtrArray, g_ptr_array) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GByteArray, g_byte_array) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GMainContext, g_main_context) +ZYPP_GLIB_DEFINE_GLIB_AMBIGUOUS_TYPE(GMainContextPusher, g_main_context_pusher_free) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GMainLoop, g_main_loop) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GSource, g_source) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GMappedFile, g_mapped_file) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GMarkupParseContext, g_markup_parse_context) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GNode, g_node_destroy) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GOptionContext, g_option_context_free) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GOptionGroup, g_option_group) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GPatternSpec, g_pattern_spec_free) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GQueue, g_queue_free) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GRand, g_rand_free) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GRegex, g_regex) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GMatchInfo, g_match_info) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GScanner, g_scanner_destroy) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GSequence, g_sequence_free) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GSList, g_slist_free) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GString, g_autoptr_cleanup_gstring_free) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GStringChunk, g_string_chunk_free) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GStrvBuilder, g_strv_builder) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GThread, g_thread) +ZYPP_GLIB_DEFINE_GLIB_AMBIGUOUS_TYPE(GMutexLocker, g_mutex_locker_free) +ZYPP_GLIB_DEFINE_GLIB_AMBIGUOUS_TYPE(GRecMutexLocker, g_rec_mutex_locker_free) +ZYPP_GLIB_DEFINE_GLIB_AMBIGUOUS_TYPE(GRWLockWriterLocker, g_rw_lock_writer_locker_free) +ZYPP_GLIB_DEFINE_GLIB_AMBIGUOUS_TYPE(GRWLockReaderLocker, g_rw_lock_reader_locker_free) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GTimer, g_timer_destroy) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GTimeZone, g_time_zone) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GTree, g_tree) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GVariant, g_variant) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GVariantBuilder, g_variant_builder) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GVariantIter, g_variant_iter_free) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE( GVariantDict, g_variant_dict ) +ZYPP_GLIB_DEFINE_GLIB_SIMPLE_TYPE(GVariantType, g_variant_type_free) +ZYPP_GLIB_DEFINE_GLIB_AMBIGUOUS_TYPE(GRefString, g_ref_string_release) +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE(GUri, g_uri) + +/** + * Manually add extra definitions for gchar* and gchar** + */ +ZYPP_GLIB_DEFINE_GLIB_AMBIGUOUS_TYPE(gchar, g_free) + +typedef gchar* gcharv; +ZYPP_GLIB_DEFINE_GLIB_AMBIGUOUS_TYPE(gcharv, g_strfreev) + + + + +#endif diff --git a/zypp-glib/utils/GList b/zypp-glib/utils/GList new file mode 100644 index 0000000000..5ddb56eca6 --- /dev/null +++ b/zypp-glib/utils/GList @@ -0,0 +1,460 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_UTIL_GLIST_H +#define ZYPP_GLIB_UTIL_GLIST_H + +#include +#include +#include + + +namespace zypp::glib { + + enum Ownership { + Full, //<< The container owns the Glist and the elements + Container, //<< Just owns the GList, but not the elements + None //<< Just wraps the container, but does not maintain its lifetime or the elements lifetime + }; + + namespace internal { + template < typename GLibContainer, typename T, typename Traits = GLibTypeTraits, typename Enable = void > + struct GContainerTraits; + + template + class glistcontainer_iter; + } + + template > + class GListView; + + template > + class GListContainer; + + namespace internal { + + template + constexpr bool always_false = false; + + template + constexpr bool list_can_copy_v = std::is_detected_v< internal::has_simple_copy_trait, Trait> || std::is_detected_v< internal::has_extended_copy_trait, Trait>; + + template + constexpr bool list_can_del_v = std::is_detected_v< internal::has_delete_trait, Trait >; + + + /*! + * Detects if the given type is compatible to a common glib Container optimization that directly stores int types in + * the pointer part of a container node. + */ + template + constexpr bool g_containter_int_mode = std::is_same_v< guint8, T> || std::is_same_v< guint16, T> || std::is_same_v< guint32, T> || + std::is_same_v< gint8, T> || std::is_same_v< gint16, T> || std::is_same_v< gint32, T> || + std::is_same_v< guint64, T> || std::is_same_v< gulong, T> || std::is_same_v< gsize, T> || + std::is_same_v< gint64, T> || std::is_same_v< glong, T>; + + template + constexpr auto delFnFromTrait () { + if constexpr ( list_can_del_v ) + return Trait::del_fn; + else { + return nullptr; + } + } + + template + constexpr auto copyFnFromTrait () { + if constexpr ( list_can_copy_v ) + return Trait::copy_fn; + else { + return nullptr; + } + } + + template + T gcontainer_gpointer_to_value( gconstpointer data ) { + if constexpr ( std::is_same_v< guint8, T> || std::is_same_v< guint16, T> || std::is_same_v< guint32, T> ) { + return GPOINTER_TO_UINT( data ); + } else if constexpr ( std::is_same_v< gint8, T> || std::is_same_v< gint16, T> || std::is_same_v< gint32, T> ) { + return GPOINTER_TO_INT( data ); + } else if constexpr ( std::is_same_v< guint64, T> || std::is_same_v< gulong, T> || std::is_same_v< gsize, T> ) { + return GPOINTER_TO_SIZE( data ); + } else if constexpr ( std::is_same_v< gint64, T> || std::is_same_v< glong, T> ) { + return GPOINTER_TO_SIZE( data ); + } else if constexpr ( std::is_pointer_v ) { + return (T)(data); + } else { + static_assert( always_false, "gcontainer_gpointer_to_value can not be used with this type" ); + } + } + + template + gpointer gcontainer_value_to_gpointer( T val ) { + if constexpr ( std::is_same_v< guint8, T> || std::is_same_v< guint16, T> || std::is_same_v< guint32, T> ) { + return GUINT_TO_POINTER( val ); + } else if constexpr ( std::is_same_v< gint8, T> || std::is_same_v< gint16, T> || std::is_same_v< gint32, T> ) { + return GINT_TO_POINTER( val ); + } else if constexpr ( std::is_same_v< guint64, T> || std::is_same_v< gulong, T> || std::is_same_v< gsize, T> ) { + return GSIZE_TO_POINTER( val ); + } else if constexpr ( std::is_same_v< gint64, T> || std::is_same_v< glong, T> ) { + return GSIZE_TO_POINTER( val ); + } else if constexpr ( std::is_pointer_v ) { + return ( gpointer )(val); + } else { + static_assert( always_false, "gcontainer_value_to_gpointer can not be used with this type" ); + } + } + + + template class gcontainer_value_ref; + + + template + class gcontainer_value_ref<::GList, T> + { + public: + static_assert( g_containter_int_mode, "gcontainer_value_ref is only usable with int based values" ); + gcontainer_value_ref( ::GList *node ) : _node(node) { } + + operator T () const { + return getValue(); + } + + gcontainer_value_ref &operator= ( const T& val ) { + _node->data = gcontainer_value_to_gpointer(val); + return *this; + } + + gcontainer_value_ref &operator= ( const gcontainer_value_ref& val ) { + (*this) = val.getValue(); + return *this; + } + + bool operator== ( const gcontainer_value_ref& other ) const { + return getValue() == other.getValue(); + } + + + bool operator== ( const T& val ) const { + return getValue() == val; + } + + private: + T getValue() const { return gcontainer_gpointer_to_value( _node->data ); } + ::GList *_node = nullptr; + }; + + /** + * Simple helper template to provide a correct GCopyFunc signature + * for the glist copy functions, since we are allowing copy functions + * with just one argument as well + * + * @tparam T The type we want to copy + * @tparam simpleCopyFn The Function we want to call + */ + template < typename T, auto simpleCopyFn > + gpointer simpleCopyFnHelper( gconstpointer copy, gpointer ) { + return reinterpret_cast( simpleCopyFn( (T*)(copy) ) ); + } + + template + void glist_release( ::GList *list, Ownership os, const Fn &delFn ) { + switch ( os ) { + case Ownership::Full: { + g_list_free_full( list, (GDestroyNotify)(delFn) ); + break; + } + case Ownership::Container: { + g_list_free( list ); + break; + } + case Ownership::None: { + break; + } + } + } + + template < typename GLibContainer, typename T, typename Traits, typename Enable > + struct GContainerTraits { + using type = T; + using value_type = T*; + using reference = value_type; + using const_reference = const value_type; + + static reference dereferenceData ( ::GList *node ) { + return (value_type)(node->data); + } + + static const_reference dereferenceConstData ( const ::GList *node ) { + return (value_type)(node->data); + } + + static value_type pointerToValue ( gpointer data ) { + return (value_type)(data); + } + + static gpointer valueToPointer ( value_type value ) { + return (gpointer)value; + } + + //static gconstpointer valueToPointer ( const value_type value ) { + // return (gconstpointer)value; + //} + + static void releaseData ( gpointer data ) { + static_assert( list_can_del_v, "A delete trait is required to use GListContainer" ); + Traits::delete_fn( static_cast(data)); + } + }; + + template < typename GLibContainer, typename T, typename Traits > + struct GContainerTraits > >{ + using type = T; + using value_type = T; + using reference = internal::gcontainer_value_ref; + using const_reference = T; + + static reference dereferenceData ( ::GList *node ) { + return reference(node); + } + + static const_reference dereferenceConstData ( const ::GList *node ) { + return gcontainer_gpointer_to_value(node->data); + } + + static value_type pointerToValue ( gpointer data ) { + return gcontainer_gpointer_to_value( data ); + } + + static gpointer valueToPointer ( reference value ) { + return gcontainer_value_to_gpointer( value ); + } + + static gpointer valueToPointer ( const_reference value ) { + return gcontainer_value_to_gpointer( value ); + } + + static void releaseData ( gpointer data ) { + // the gpointers just contain plain data , nothing to free + return; + } + }; + + + template + class glistcontainer_iter + : public boost::iterator_facade< + glistcontainer_iter + , typename Traits::value_type + , boost::bidirectional_traversal_tag + , std::conditional_t< std::is_const_v, typename Traits::const_reference, typename Traits::reference > + > + { + public: + glistcontainer_iter() + : _node(0) {} + + explicit glistcontainer_iter(GList* p) + : _node(p) {} + + private: + friend class boost::iterator_core_access; + friend class GListContainer; + + void increment() { if ( _node) _node = _node->next; } + void decrement() { if ( _node) _node = _node->prev; } + + bool equal(glistcontainer_iter const& other) const { + return this->_node == other._node; + } + + decltype(auto) dereference() const { + if constexpr ( std::is_const_v ) { + return Traits::dereferenceConstData( _node ); + } else { + return Traits::dereferenceData( _node ); + } + } + + GList* _node = nullptr; + }; + } + + template + class GListView { + public: + using value_type = typename Traits::value_type; + using const_iterator = internal::glistcontainer_iter; + using const_ref = typename Traits::const_reference; + using Ownership = ::zypp::glib::Ownership; + + GListView ( const ::GList *list, Ownership os = None ) + : _list( const_cast<::GList*>(list) ) // removing the const for internal use of the pointer, all glib func want a non const version + , _os( os ) + { } + + GListView ( ::GList *list, Ownership os ) + : _list( list ) + , _os( os ) + { } + + // no implicit copies for now + GListView ( const GListView &other ) = delete; + GListView &operator= ( const GListView &other ) = delete; + + GListView ( GListView &&other ) { + _list = other._list; + _os = other._os; + other._list = nullptr; + } + + GListView &operator= ( GListView &&other ) { + _list = other._list; + _os = other._os; + other._list = nullptr; + } + + virtual ~GListView() { + internal::glist_release( this->_list, this->_os, Traits::releaseData ); + } + + size_t size () const { + return g_list_length( _list ); + } + + const_iterator begin () const { + return const_iterator( _list ); + } + + const_iterator last () const { + return const_iterator( g_list_last( _list) ); + } + + const_iterator end () const { + return const_iterator(); + } + + const ::GList *get() { + return _list; + } + + const_iterator operator[] ( const size_t index ) const { + auto node = g_list_nth( _list, index ); + return const_iterator(node); + } + + /** + * Creates a shallow copy of the list, that is copying the container and filling it only with references to the + * same elements as the initial list. + * + * \note the returned container will have \ref Ownership::Container regardless of the ownership strategy of the original + * container. + */ + GListContainer copy () const { + return GListContainer( g_list_copy( _list ), GListContainer::Ownership::Container ); + } + + protected: + ::GList *_list = nullptr; + Ownership _os = Ownership::Full; + }; + + template + class GListContainer : public GListView + { + public: + using this_type = GListContainer; + using value_type = typename Traits::value_type; + using reference = typename Traits::reference; + using const_reference = typename Traits::const_reference; + using iterator = internal::glistcontainer_iter; + using const_iterator = internal::glistcontainer_iter; + using Ownership = ::zypp::glib::Ownership; + + friend iterator; + friend const_iterator; + + GListContainer () : GListView ( (::GList *)nullptr, Ownership::Full ) { } + GListContainer ( ::GList *list, Ownership os ) : GListView ( list, os ) { } + + ::GList *get() { + return this->_list; + } + + ::GList *take() { + this->_os = Ownership::None; + return this->_list; + } + + void reverse () { + this->_list = g_list_reverse( this->_list ); + } + + iterator begin () { + return iterator( this->_list ); + } + + iterator last () { + return iterator( g_list_last( this->_list) ); + } + + iterator end () { + return iterator(); + } + + iterator operator[] ( const size_t index ) { + auto node = g_list_nth( this->_list, index ); + return iterator(node); + } + + void push_back ( const_reference data ) { + this->_list = g_list_append( this->_list, Traits::valueToPointer(data) ); + } + + void push_front ( const_reference data ) { + this->_list = g_list_prepend( this->_list, Traits::valueToPointer(data) ); + } + + iterator remove ( iterator i ) { + if ( i._node ) { + auto *next = i._node->next; + if ( this->_os == Ownership::Full ) + Traits::releaseData( i._node->data ); + this->_list = g_list_delete_link( this->_list, i._node ); + return iterator(next); + } + return iterator(); + } + + void clear () { + internal::glist_release( this->_list, this->_os, Traits::releaseData ); + } + + iterator find ( GCompareFunc compare ) { + auto *node = g_list_find_custom( this->_list, nullptr, compare ); + return iterator(node); + } + + iterator find ( const_reference data ) { + return iterator( g_list_find( this->_list, Traits::valueToPointer(data) ) ); + } + + this_type deepCopy ( GCopyFunc copyFn, gpointer userdata = nullptr ) const { + GList *copy = g_list_copy_deep( this->_list, copyFn, userdata ); + return this_type( copy, Ownership::Full ); + } + }; + + + // some convenience types + using GCharContainer = GListContainer>; + using GCharView = GListView>; + +} + +#endif diff --git a/zypp-glib/utils/GObjectMemory b/zypp-glib/utils/GObjectMemory new file mode 100644 index 0000000000..4d9c1fc3c3 --- /dev/null +++ b/zypp-glib/utils/GObjectMemory @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2013-2017 Canonical Ltd. + * Copyright (C) 2022 SUSE Software Solutions Germany GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 as + * published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: Jussi Pakkanen + * Pete Woods + * Benjamin Zeller + */ + +#ifndef ZYPP_GLIB_UTIL_GOBJECTMEMORY_H +#define ZYPP_GLIB_UTIL_GOBJECTMEMORY_H + +#include +#include +#include + +#include +#include +#include + +namespace zypp::glib { + +template +using GObjectPtr = RetainPtr::RetainTrait>; + +namespace { + inline static void check_floating_gobject(gpointer t) { + if (G_IS_OBJECT(t) && g_object_is_floating(G_OBJECT(t))) { + throw std::invalid_argument("cannot manage floating GObject reference - call g_object_ref_sink(o) first"); + } + } +} + +namespace internal { + + template + Type *zypp_gobject_ref_helper( Type *obj ) { + return g_object_ref(obj); + } + + template + class GObjectAssigner + { + public: + using ElementType = typename SP::element_type ; + + GObjectAssigner(SP& smart_ptr) noexcept: + smart_ptr_(smart_ptr) + { + } + + GObjectAssigner(const GObjectAssigner& other) = delete; + + GObjectAssigner(GObjectAssigner&& other) noexcept: + ptr_(other.ptr_), smart_ptr_(other.smart_ptr_) + { + other.ptr_ = nullptr; + } + + ~GObjectAssigner() noexcept + { + smart_ptr_ = SP(ptr_, GLibTypeTraits()); + } + + GObjectAssigner& operator=(const GObjectAssigner& other) = delete; + + operator ElementType**() noexcept + { + return &ptr_; + } + + private: + ElementType* ptr_ = nullptr; + + SP& smart_ptr_; + }; + + template + struct GObjectSignalUnsubscriber + { + void operator()(gulong handle) noexcept + { + if (handle != 0 && G_IS_OBJECT(obj_.get())) { + g_signal_handler_disconnect(obj_.get(), handle); + } + } + + GObjectPtr obj_; + }; +} + +/*! + * Simple wrapper around a GObject weak pointer. + * Currently this is not thread safe but we could consider to switch to GWeakRef if required + */ +template +class GObjectWeakPtr +{ + public: + GObjectWeakPtr( ) : _weakRef( nullptr ) { } + + GObjectWeakPtr( T *ptr ) : _weakRef( nullptr ) { + g_set_weak_pointer( &_weakRef, ptr ); + } + + GObjectWeakPtr ( const GObjectWeakPtr & other ) { + if ( other ) { + g_set_weak_pointer( &_weakRef, other._weakRef ); + } + } + + ~GObjectWeakPtr() { + reset(); + } + + void operator= ( const GObjectWeakPtr &other ) { + reset( other._weakRef ); + } + + void reset ( T* ptr = nullptr ) { + g_clear_weak_pointer( &_weakRef ); + if ( ptr ) { + g_set_weak_pointer( &_weakRef, ptr ); + } + } + + operator bool () const { + return (_weakRef != nullptr); + } + + GObjectPtr lock () const { + if ( _weakRef ) + return { _weakRef, retain_object }; + return {}; + } + + T* weakGet() const{ + return _weakRef; + } + + private: + T* _weakRef; +}; + +} // namespace zypp::glib + + +#define ZYPP_DEFINE_GOBJECTSMARTPTR( ModuleObjName, module_obj_name, MODULE, OBJ_NAME ) \ + namespace zypp::glib { \ + using ModuleObjName##WeakRef = GObjectWeakPtr; \ + \ + template \ + std::enable_if_t< std::is_same_v, \ + ModuleObjName##Ref > gobject_pointer_cast( const GObjectPtr<_Up> &o ) { \ + if ( !MODULE##_IS_##OBJ_NAME(o.get()) ) \ + return {}; \ + \ + return ModuleObjName##Ref( MODULE##_##OBJ_NAME( o.get() ), retain_object ); \ + } \ + } + +// return unique_gobject(G_TYPE_CHECK_INSTANCE_CAST(ptr, object_type, T)); + +#define ZYPP_DEFINE_GOBJECTSMARTPTR_CREATE( ModuleObjName, module_obj_name, MODULE, OBJ_NAME ) \ + namespace zypp::glib { \ + template \ + ModuleObjName##Ref module_obj_name##_create ( gchar *first_property_name, Args&&... args ) { \ + gpointer ptr = g_object_new( module_obj_name##_get_type(), first_property_name, std::forward(args)..., nullptr ); \ + if (G_IS_OBJECT(ptr) && g_object_is_floating(ptr)) { \ + g_object_ref_sink(ptr); \ + } \ + \ + return ModuleObjName##Ref( MODULE##_##OBJ_NAME( ptr ), adopt_object ); \ + } \ + } + + +#define ZYPP_GLIB_ADD_GLIB_GOBJECTTRAIT( ModuleObjName, module_obj_name ) \ + struct GObjectTrait { \ + static auto gobjectType() { \ + return module_obj_name##_get_type();\ + } \ + static auto gobjectCast( GObject *object ) { \ + return (G_TYPE_CHECK_INSTANCE_CAST ((object), gobjectType(), ModuleObjName)); \ + } \ + }; \ + static constexpr auto is_g_object_type = true; + + +/** + * @brief Convencience macro to define the standard traits and smart pointer types for GObject types + */ +#define ZYPP_DEFINE_GOBJECT_SIMPLE( ModuleObjName, module_obj_name, MODULE, OBJ_NAME, ...) \ +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE_FULL( ModuleObjName, zypp::glib::internal::zypp_gobject_ref_helper, g_object_unref, \ + ZYPP_GLIB_ADD_GLIB_GOBJECTTRAIT( ModuleObjName, module_obj_name ) \ + __VA_ARGS__ \ +)\ +ZYPP_DEFINE_GOBJECTSMARTPTR( ModuleObjName, module_obj_name, MODULE, OBJ_NAME ) \ +ZYPP_DEFINE_GOBJECTSMARTPTR_CREATE( ModuleObjName, module_obj_name, MODULE, OBJ_NAME ) + +// define the GObject smart pointers and traits +ZYPP_GLIB_DEFINE_GLIB_REF_TYPE_FULL( GObject, zypp::glib::internal::zypp_gobject_ref_helper, g_object_unref, ZYPP_GLIB_ADD_GLIB_GOBJECTTRAIT( GObject, g_object ) ) +ZYPP_DEFINE_GOBJECTSMARTPTR( GObject, g_object, G, OBJECT ) + +namespace zypp::glib { + +/** + \brief Helper method to wrap a shared_ptr around an existing GObject. + + Useful if the GObject class you are constructing already has a + dedicated factory from the C library it comes from, and you + intend to share it. + + Example: + \code{.cpp} + auto obj = adopt_gobject(foo_bar_new("name")); + \endcode + */ +template +inline GObjectPtr adopt_gobject(T* ptr) +{ + check_floating_gobject(ptr); + return GObjectPtr( ptr, adopt_object ); +} + +/** + \brief Helper method to construct a gobj_ptr-wrapped GObject class. + + Uses the same signature as the g_object_new() method. + Requires the zyppng GObject Type Traits. + + Example: + \code{.cpp} + auto obj = g_object_create("name", "banana", nullptr); + \endcode + */ +template +inline GObjectPtr g_object_create( const gchar *first_property_name = nullptr, Args&&... args ) noexcept +{ + gpointer ptr = g_object_new( GLibTypeTraits::GObjectTrait::gobjectType(), first_property_name, std::forward(args)..., nullptr ); + if (G_IS_OBJECT(ptr) && g_object_is_floating(ptr)) + { + g_object_ref_sink(ptr); + } + return GObjectPtr( GLibTypeTraits::GObjectTrait::gobjectCast( G_OBJECT(ptr)), adopt_object ); +} + +/** + \brief Helper method to take ownership of GObjects assigned from a reference. + + Example: + \code{.cpp} + GObjectRefPtr o; + method_that_assigns_a_foobar(assign_gobject(o)); + \endcode + */ +template +inline internal::GObjectAssigner assign_gobject(SP& smart_ptr) noexcept +{ + return internal::GObjectAssigner(smart_ptr); +} + +template +using GObjectSignalConnection = ResourcePtr>; + +/** + \brief Simple wrapper to manage the lifecycle of GObject signal connections. + + When 'nameConnection_' goes out of scope or is dealloc'ed, the source will be removed: + \code{.cpp} + GObjectSignalConnection nameConnection_; + nameConnection_ = gobject_signal_connection(g_signal_connect(o.get(), "notify::name", G_CALLBACK(on_notify_name), this), o); + \endcode + */ +template +inline GObjectSignalConnection gobject_signal_connection( gulong id, const stdx::retain_ptr::RetainTrait> &obj ) +{ + return GObjectSignalConnection(id, internal::GObjectSignalUnsubscriber{obj}); +} + +} // namespace zypp::glib + +#endif diff --git a/zypp-glib/utils/GioMemory b/zypp-glib/utils/GioMemory new file mode 100644 index 0000000000..a90609d701 --- /dev/null +++ b/zypp-glib/utils/GioMemory @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2013-2017 Canonical Ltd. + * Copyright (C) 2022 SUSE Software Solutions Germany GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 as + * published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: Pete Woods + * Benjamin Zeller + */ + +#ifndef ZYPP_GLIB_UTIL_GIOMEMORY_H +#define ZYPP_GLIB_UTIL_GIOMEMORY_H + +#include + +#include +#include +#include + +ZYPP_DEFINE_GOBJECT_SIMPLE( GTask, g_task, G, TASK ); +ZYPP_DEFINE_GOBJECT_SIMPLE( GCancellable, g_cancellable, G, CANCELLABLE ) +ZYPP_DEFINE_GOBJECT_SIMPLE( GDBusConnection, g_dbus_connection, G, DBUS_CONNECTION ); + +namespace zypp::glib +{ +namespace internal +{ +struct GDBusSignalUnsubscriber +{ +public: + void operator()(guint handle) noexcept + { + if (handle != 0 && G_IS_OBJECT(bus_.get())) + { + g_dbus_connection_signal_unsubscribe(bus_.get(), handle); + } + } + + RetainPtr::RetainTrait> bus_; +}; + +} + +typedef ResourcePtr GDBusSignalConnection; + +/** + \brief Simple wrapper to manage the lifecycle of manual GDBus signal connections. + + When 'signalConnection_' goes out of scope or is dealloc'ed, the connection will be removed: + \code{.cpp} + GDBusSignalConnection signalConnection_; + + signalConnection_ = gdbus_signal_connection( + g_dbus_connection_signal_subscribe(bus.get(), nullptr, "org.does.not.exist", nullptr, "/does/not/exist", nullptr, G_DBUS_SIGNAL_FLAGS_NONE, on_dbus_signal, this, nullptr), bus); + \endcode + */ +inline GDBusSignalConnection gdbus_signal_connection(guint id, RetainPtr::RetainTrait> bus) noexcept +{ + return GDBusSignalConnection(id, internal::GDBusSignalUnsubscriber{bus}); +} + + +/** + * \brief Helper template as a GDestroyNotify argument that simply calls delete on the passed object + */ +template +void g_destroy_notify_delete ( gpointer data ) { + delete (reinterpret_cast(data)); +} + +} // namespace zypp::glib + +#endif diff --git a/zypp-glib/utils/OpaqueTypePtr b/zypp-glib/utils/OpaqueTypePtr new file mode 100644 index 0000000000..b9db937a36 --- /dev/null +++ b/zypp-glib/utils/OpaqueTypePtr @@ -0,0 +1,168 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_GLIB_UTIL_TRAITSTYPEPTR_H +#define ZYPP_GLIB_UTIL_TRAITSTYPEPTR_H + +#include +#include + +namespace zypp::glib +{ + template struct OpaqueCppTypePtrTraits { + struct Deleter { + void operator()( T *ptr ) { + if ( ptr ) + delete ptr; + }; + }; + }; + + + /** + * \brief Simple shared pointer wrapper to make the use of void* C types more safe + * + * When dealing with C libraries its very common to have types like: + * \code {.cpp} + * typedef MyType void; + * void my_type_free( MyType *t ); + * + * typedef OtherType void; + * void other_type_free( OtherType *t); + * \endcode + * + * This kind of code makes the use of std::shared_ptr a bit unsafe because the deleter + * is not part of the shared_ptr type, instead all types would resove to std::shared_ptr. + * The OpaqueTypePtr uses a Type trait as part of the type id so those can not be mixed: + * \code {.cpp} + * struct MyTypeTraits { + * struct Deleter { + * void operator( MyType *p ) { + * if (p) ::my_type_free(p); + * } + * } + * } + * + * using MyTypeRef = OpaqueTypePtr; + * @endcode + * + * + * \endcode + * + */ + template + class OpaqueTypePtr + { + public: + using PtrType = std::shared_ptr; + using element_type = T; + using traits_type = Traits; + + OpaqueTypePtr() + {} + + OpaqueTypePtr( std::nullptr_t ) + {} + + OpaqueTypePtr( const OpaqueTypePtr &other ) + : _dptr(other._dptr) + {} + + explicit + OpaqueTypePtr( typename PtrType::element_type * dptr ) + : _dptr( dptr, Traits::Deleter() ) + {} + + OpaqueTypePtr & operator=( const OpaqueTypePtr &other ) + { _dptr = other._dptr; } + + OpaqueTypePtr & operator=( std::nullptr_t ) + { reset(); return *this; } + + void reset() + { PtrType().swap( _dptr ); } + + void reset( typename PtrType::element_type * dptr ) + { _dptr.reset(dptr, Traits::Deleter()); } + + void swap( OpaqueTypePtr & rhs ) + { _dptr.swap( rhs._dptr ); } + + void swap( PtrType & rhs ) + { _dptr.swap( rhs ); } + + explicit operator bool() const + { return _dptr.get() != nullptr; } + + const T & operator*() const + { return *_dptr; }; + + const T * operator->() const + { return _dptr.operator->(); } + + const T * get() const + { return _dptr.get(); } + + T & operator*() + { return *_dptr; } + + T * operator->() + { return _dptr.operator->(); } + + T * get() + { return _dptr.get(); } + + private: + PtrType _dptr; + }; + /////////////////////////////////////////////////////////////////// + + /** \relates OpaqueTypePtr Stream output. + * + * Print the \c D object the OpaqueTypePtr refers, or \c "NULL" + * if the pointer is \c NULL. + */ + template + inline std::ostream & operator<<( std::ostream & str, const OpaqueTypePtr & obj ) + { + if ( obj.get() ) + return str << *obj.get(); + return str << std::string("NULL"); + } + + /** \relates OpaqueTypePtr */ + template + inline bool operator==( const OpaqueTypePtr & lhs, const OpaqueTypePtr & rhs ) + { return( lhs.get() == rhs.get() ); } + /** \relates OpaqueTypePtr */ + template + inline bool operator==( const OpaqueTypePtr & lhs, std::nullptr_t ) + { return( lhs.get() == nullptr ); } + /** \relates OpaqueTypePtr */ + template + inline bool operator==( std::nullptr_t, const OpaqueTypePtr & rhs ) + { return( nullptr == rhs.get() ); } + + + /** \relates OpaqueTypePtr */ + template + inline bool operator!=( const OpaqueTypePtr & lhs, const OpaqueTypePtr & rhs ) + { return ! ( lhs == rhs ); } + /** \relates OpaqueTypePtr */ + template + inline bool operator!=( const OpaqueTypePtr & lhs, std::nullptr_t ) + { return( lhs.get() != nullptr ); } + /** \relates OpaqueTypePtr */ + template + inline bool operator!=( std::nullptr_t, const OpaqueTypePtr & rhs ) + { return( nullptr != rhs.get() ); } + +} + + +#endif diff --git a/zypp-glib/utils/ResourcePtr b/zypp-glib/utils/ResourcePtr new file mode 100644 index 0000000000..ffa8fad5d4 --- /dev/null +++ b/zypp-glib/utils/ResourcePtr @@ -0,0 +1,752 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * Copyright (C) 2022 SUSE Software Solutions Germany GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 as + * published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: Michi Henning + * Benjamin Zeller + */ + +#ifndef ZYPP_GLIB_UTIL_RESOURCEPTR_H +#define ZYPP_GLIB_UTIL_RESOURCEPTR_H + +#include +#include +#include + +namespace zypp::glib +{ + +namespace +{ + +// Simple helper class so we can adopt a lock without inconvenient syntax. + +template +class LockAdopter +{ +public: + LockAdopter(T& mutex) noexcept + : m_(mutex, std::adopt_lock) + { + assert(!mutex.try_lock()); // Mutex must be locked to be adoptable. + } + +private: + std::unique_lock m_; +}; + +} // namespace + +/** +\brief Class to guarantee deallocation of arbitrary resources. + +ResourcePtr is a generalized resource pointer that guarantees deallocation. +It is intended for arbitrary pairs of allocate/deallocate functions, such +as XCreateDisplay/XDestroyDisplay. + +The resource managed by this class must be default-constructible, copy-constructible, and assignable. + +ResourcePtr essentially does what std::unique_ptr does, but it works with opaque types +and resource allocation functions that do not return a pointer type, such as open(). + +ResourcePtr is thread-safe. + +\note Do not use reset() to set the resource to the "no resource allocated" state. + Instead, call dealloc() to do this. ResourcePtr has no idea + what a "not allocated" resource value looks like and therefore cannot test + for it. If you use reset() to install a "no resource allocated" value for + for the resource, the deleter will eventually be called with this value + as its argument. Whether this is benign or not depends on the deleter. For + example, XFree() must not be called with a nullptr argument. + +\note Do not call get() or release() if no resource is currently allocated. + Doing so throws std::logic_error. + +Here is an example that shows how to use this for a glXCreateContext/GLXDestroyContext pair. +The returned GLXContext is a pointer to an opaque type; std::unique_ptr cannot be used +for this, even with a custom deleter, because the signatures of the allocator and deallocator +do not match unique_ptr's expectations. + +~~~ +ResourcePtr> context = + std::bind(&glXDestroyContext, display_, std::placeholders::_1); +~~~ + +display_ is declared as + +~~~ + Display* display_; +~~~ + +in this case. + +The deleter for the resource can return any type (including int, such as returned by XDestroyWindow()), +and it must accept a single argument of the resource type (GLXContext in this example). + +glXDestroyContext() expects the display pointer as the first argument so, for this example, +std::bind converts the binary glXDestroyContext() function into a +unary function suitable as the deleter. + +Rather than mucking around with std::bind, it is often easier to use a lambda. For example: + +~~~ +ResourcePtr> context = + [this](GLXContext c) { this->dealloc_GLXContext(c); }; +~~~ + +This calls a member function dealloc_GLXContext() that, in turn calls glXDestroyContext() +and supplies the display parameter. + +\note Even though you can use ResourcePtr to deallocate dynamic memory, doing so is discouraged. +Use std::unique_ptr instead, which is better suited to the task. +*/ + +// TODO: Discuss throwing deleters and requirements (copy constructible, etc.) on deleter. + +template +class ResourcePtr final +{ +public: + /** Deleted */ + ResourcePtr(ResourcePtr const &) = delete; + /** Deleted */ + ResourcePtr& operator=(ResourcePtr const&) = delete; + /** + \typedef element_type + The type of resource managed by this ResourcePtr. + */ + typedef R element_type; + + /** + \typedef deleter_type + A function object or lvalue reference to a function or function object. The ResourcePtr + calls this to deallocate the resource. + */ + typedef D deleter_type; + + ResourcePtr(); + explicit ResourcePtr(D d); + ResourcePtr(R r, D d); + ResourcePtr(ResourcePtr&& r); + ResourcePtr& operator=(ResourcePtr&& r); + ~ResourcePtr() noexcept; + + void swap(ResourcePtr& other); + + void reset(R r); + R release(); + void dealloc(); + + R get() const; + bool has_resource() const noexcept; + explicit operator bool() const noexcept; + D& get_deleter() noexcept; + D const& get_deleter() const noexcept; + + bool operator==(ResourcePtr const& rhs) const; + + bool operator!=(ResourcePtr const& rhs) const; + + bool operator<(ResourcePtr const& rhs) const; + + bool operator<=(ResourcePtr const& rhs) const; + + bool operator>(ResourcePtr const& rhs) const; + + bool operator>=(ResourcePtr const& rhs) const; + +private: + R resource_; // The managed resource. + D delete_; // The deleter to call. + bool initialized_; // True while we have a resource assigned. + mutable std::mutex m_; // Protects this instance. + + typedef std::lock_guard AutoLock; + typedef LockAdopter AdoptLock; +}; + +template +ResourcePtr::ResourcePtr() + : initialized_(false) +{ + static_assert(!std::is_pointer::value, + "constructed with null function pointer deleter"); +} + +/** +Constructs a ResourcePtr with the specified deleter. No resource is held, so a call to has_resource() +after constructing a ResourcePtr this way returns false. +*/ + +template +ResourcePtr::ResourcePtr(D d) + : delete_(d), initialized_(false) +{ +} + +/** +Constructs a ResourcePtr with the specified resource and deleter. has_resource() returns true after +calling this constructor. + +\note It is legal to pass a resource that represents the "not allocated" state. For example, the + following code passes the value -1 to close() if the call to open() fails: + +~~~ +ResourcePtr fd(::open("/somefile", O_RDONLY), ::close); +~~~ + When the ResourcePtr goes out of scope, this results in a call to close(-1). In this case, + the call with an invalid file descriptor is harmless (but causes noise from diagnostic tools, such as + valgrind). However, depending on the specific deleter, passing an invalid value to the deleter may + have more serious consequences. + + To avoid the problem, you can delay initialization of the ResourcePtr until you know that the + resource was successfully allocated, for example: +~~~ + int tmp_fd = ::open(filename.c_str(), O_RDONLY); + if (tmp_fd == -1) + { + throw FileException(filename.c_str()); + } + glib::ResourcePtr fd(tmp_fd, ::close(fd)); +~~~ + Alternatively, you can use a deleter function that tests the resource value + for validity and avoids calling the deleter with an invalid value: +~~~ + glib::ResourcePtr> fd( + ::open(filename.c_str(), O_RDONLY), + [](int fd) { if (fd != -1) ::close(fd); } + ); +~~~ + Note that, with the second approach, a call to get() will succeed and return -1 rather than throwing an + exception, so the first approach is the recommended one. +*/ + +template +ResourcePtr::ResourcePtr(R r, D d) + : resource_(r), delete_(d), initialized_(true) +{ +} + +/** +Constructs a ResourcePtr by transferring ownership from r to this. + +If the resource's move or copy constructor throws, the exception is propagated to the caller. +The strong exception guarantee is preserved if it is provided by the resource. +*/ +// TODO: Mark as nothrow if the resource has a nothrow move constructor or nothrow copy constructor + +template +ResourcePtr::ResourcePtr(ResourcePtr&& r) + : resource_(std::move(r.resource_)), delete_(r.delete_), initialized_(r.initialized_) +{ + r.initialized_ = false; // Stop r from deleting its resource, if it held any. No need to lock: r is a temporary. +} + +/** +Assigns the resource held by r, transferring ownership. After the transfer, +r.has_resource() returns false, and this.has_resource() returns +the value of r.has_resource() prior to the assignment. +*/ +// TODO: document exception safety behavior + +template +ResourcePtr& ResourcePtr::operator=(ResourcePtr&& r) +{ + AutoLock lock(m_); + + if (initialized_) // If we hold a resource, deallocate it first. + { + initialized_ = false; // If the deleter throws, we will not try it again for the same resource. + delete_(resource_); // Delete our own resource. + } + + // r is a temporary, so we don't need to lock it. + + resource_ = std::move(r.resource_); + initialized_ = r.initialized_; + r.initialized_ = false; // Stop r from deleting its resource, if it held any. + delete_ = r.delete_; + + return *this; +} + +/** +Destroys the ResourcePtr. If a resource is held, it calls the deleter for the current resource (if any). +*/ + +template +ResourcePtr::~ResourcePtr() noexcept +{ + try + { + dealloc(); + } + catch (...) + { + } +} + +/** +Swaps the resource and deleter of this with the resource and deleter of other +using argument dependent lookup (ADL). + +If the underlying swap throws an exception, that exception is propagated to the caller, and the resource +held by the ResourcePtr is unchanged. +*/ +// TODO Split this into throw and no-throw versions depending on the underlying swap? + +template +void ResourcePtr::swap(ResourcePtr& other) +{ + if (this == &other) // This is necessary to avoid deadlock for self-swap + { + return; + } + + std::lock(m_, other.m_); + AdoptLock left(m_); + AdoptLock right(other.m_); + + using std::swap; // Enable ADL + swap(resource_, other.resource_); + swap(delete_, other.delete_); + swap(initialized_, other.initialized_); +} + +// The non-member swap() must be in the same namespace as ResourcePtr, so it will work with ADL. And, once it is +// defined here, there is no point in adding a specialization to namespace std any longer, because ADL +// will find it here anyway. + +/** +Swaps the resource and deleter of lhs with the resource and deleter of rhs +by calling lhs.swap(rhs). + +If the underlying swap throws an exception, that exception is propagated to the caller, and the resource +held by the ResourcePtr is unchanged. +*/ +// TODO Split this into throw and no-throw versions depending on the underlying swap? + +template +void swap(zypp::glib::ResourcePtr& lhs, zypp::glib::ResourcePtr& rhs) +{ + lhs.swap(rhs); +} + +/** +Assigns a new resource to this, first deallocating the current resource (if any). + +If the deleter for the current resource throws an exception, the exception is propagated to the caller. In this +case, the transfer of r to this is still carried out so, after the call to reset(), +this manages r, whether the deleter throws or not. (If the deleter does throw, +no attempt is made to call the deleter again for the same resource.) +*/ + +template +void ResourcePtr::reset(R r) +{ + AutoLock lock(m_); + + bool has_old = initialized_; + R old_resource; + + if (has_old) + { + old_resource = resource_; + } + resource_ = r; + initialized_ = true; // If the deleter throws, we still satisfy the postcondition: resource_ == r. + if (has_old) + { + delete_(old_resource); + } +} + +/** +Releases ownership of the current resource without calling the deleter. +\return The current resource. +\throw std::logic_error if has_resource() is false. +*/ + +template +inline +R ResourcePtr::release() +{ + AutoLock lock(m_); + + if (!initialized_) + { + throw std::logic_error("release() called on ResourcePtr without resource"); + } + initialized_ = false; + return resource_; +} + +/** +Calls the deleter for the current resource. + +If the deleter throws, the resource is considered in the "not allocated" state, +that is, no attempt is made to call the deleter again for this resource. +*/ + +template +void ResourcePtr::dealloc() +{ + AutoLock lock(m_); + + if (!initialized_) + { + return; + } + initialized_ = false; // If the deleter throws, we will not try it again for the same resource. + delete_(resource_); +} + +/** +Returns the current resource. If no resource is currently held, get() throws std::logic_error. +\return The current resource (if any). + +If the resource's copy constructor throws an exception, that exception is propagated to the caller. + +\throw std::logic_error if has_resource() is false. +*/ + +template +inline +R ResourcePtr::get() const +{ + AutoLock lock(m_); + + if (!initialized_) + { + throw std::logic_error("get() called on ResourcePtr without resource"); + } + return resource_; +} + +/** +\return true if this currently manages a resource; false, otherwise. +*/ + +template +inline +bool ResourcePtr::has_resource() const noexcept +{ + AutoLock lock(m_); + return initialized_; +} + +/** +Synonym for has_resource(). +*/ + +template +inline +ResourcePtr::operator bool() const noexcept +{ + return has_resource(); +} + +/** +\return The deleter for the resource. +*/ + +template +inline +D& ResourcePtr::get_deleter() noexcept +{ + AutoLock lock(m_); + return delete_; +} + +/** +\return The deleter for the resource. +*/ + +template +inline +D const& ResourcePtr::get_deleter() const noexcept +{ + AutoLock lock(m_); + return delete_; +} + +/** +\brief Compares two instances for equality. + +Two instances that do not hold a resource are equal. An instance that does not hold a resource is not equal +to any instance that holds a resource. + +If the underlying operator== throws an exception, that exception is propagated to the caller. + +\note This operator is available only if the underlying resource provides operator==. +*/ + +template +bool ResourcePtr::operator==(ResourcePtr const& rhs) const +{ + if (this == &rhs) // This is necessary to avoid deadlock for self-comparison + { + return true; + } + + std::lock(m_, rhs.m_); + AdoptLock left(m_); + AdoptLock right(rhs.m_); + + if (!initialized_) + { + return !rhs.initialized_; // Equal if both are not initialized + } + else if (!rhs.initialized_) + { + return false; // Not equal if lhs initialized, but rhs not initialized + } + else + { + return resource_ == rhs.resource_; + } +} + +/** +\brief Compares two instances for inequality. + +If the underlying operator== throws an exception, that exception is propagated to the caller. + +\note This operator is available only if the underlying resource provides operator==. +*/ + +template +inline +bool ResourcePtr::operator!=(ResourcePtr const& rhs) const +{ + return !(*this == rhs); +} + +/** +\brief Returns true if this is less than rhs. + +An instance that does not hold a resource is less than any instance that holds a resource. + +If the underlying operator\< throws an exception, that exception is propagated to the caller. + +\note This operator is available only if the underlying resource provides operator\<. +*/ + +template +bool ResourcePtr::operator<(ResourcePtr const& rhs) const +{ + if (this == &rhs) // This is necessary to avoid deadlock for self-comparison + { + return false; + } + + std::lock(m_, rhs.m_); + AdoptLock left(m_); + AdoptLock right(rhs.m_); + + if (!initialized_) + { + return rhs.initialized_; // Not initialized is less than initialized + } + else if (!rhs.initialized_) // Initialized is not less than not initialized + { + return false; + } + else + { + return resource_ < rhs.resource_; + } +} + +/** +\brief Returns true if this is less than or equal to rhs. + +An instance that does not hold a resource is less than any instance that holds a resource. +Two instances that do not hold a resource are equal. + +If the underlying operator\< or operator== throws an exception, +that exception is propagated to the caller. + +\note This operator is available only if the underlying resource provides operator\< +and operator==. +*/ + +template +bool ResourcePtr::operator<=(ResourcePtr const& rhs) const +{ + if (this == &rhs) // This is necessary to avoid deadlock for self-comparison + { + return true; + } + + // We can't just write: + // + // return *this < rhs || *this == rhs; + // + // because that creates a race condition: the locks would be released and + // re-aquired in between the two comparisons. + + std::lock(m_, rhs.m_); + AdoptLock left(m_); + AdoptLock right(rhs.m_); + + return resource_ < rhs.resource_ || resource_ == rhs.resource_; +} + +/** +\brief Returns true if this is greater than rhs. + +An instance that holds a resource is greater than any instance that does not hold a resource. + +If the underlying operator\< or operator== throws an exception, +that exception is propagated to the caller. + +\note This operator is available only if the underlying resource provides operator\< +and operator==. +*/ + +template +inline +bool ResourcePtr::operator>(ResourcePtr const& rhs) const +{ + return !(*this <= rhs); +} + +/** +\brief Returns true if this is greater than or equal to rhs. + +An instance that holds a resource is greater than any instance that does not hold a resource. +Two instances that do not hold a resource are equal. + +If the underlying operator\< throws an exception, that exception is propagated to the caller. + +\note This operator is available only if the underlying resource provides operator\<. +*/ + +template +inline +bool ResourcePtr::operator>=(ResourcePtr const& rhs) const +{ + return !(*this < rhs); +} + +} // namespace zypp::glib + +// Specializations in namespace std, so we play nicely with STL and metaprogramming. + +namespace std +{ + +/** +\brief Function object for equality comparison. +*/ + +template +struct equal_to> +{ + /** + Invokes operator== on lhs. + */ + bool operator()(zypp::glib::ResourcePtr const& lhs, zypp::glib::ResourcePtr const& rhs) const + { + return lhs == rhs; + } +}; + +/** +\brief Function object for inequality comparison. +*/ + +template +struct not_equal_to> +{ + /** + Invokes operator!= on lhs. + */ + bool operator()(zypp::glib::ResourcePtr const& lhs, zypp::glib::ResourcePtr const& rhs) const + { + return lhs != rhs; + } +}; + +/** +\brief Function object for less than comparison. +*/ + +template +struct less> +{ + /** + Invokes operator\< on lhs. + */ + bool operator()(zypp::glib::ResourcePtr const& lhs, zypp::glib::ResourcePtr const& rhs) const + { + return lhs < rhs; + } +}; + +/** +\brief Function object for less than or equal comparison. +*/ + +template +struct less_equal> +{ + /** + Invokes operator\<= on lhs. + */ + bool operator()(zypp::glib::ResourcePtr const& lhs, zypp::glib::ResourcePtr const& rhs) const + { + return lhs <= rhs; + } +}; + +/** +\brief Function object for greater than comparison. +*/ + +template +struct greater> +{ + /** + Invokes operator\> on lhs. + */ + bool operator()(zypp::glib::ResourcePtr const& lhs, zypp::glib::ResourcePtr const& rhs) const + { + return lhs > rhs; + } +}; + +/** +\brief Function object for less than or equal comparison. +*/ + +template +struct greater_equal> +{ + /** + Invokes operator\>= on lhs. + */ + bool operator()(zypp::glib::ResourcePtr const& lhs, zypp::glib::ResourcePtr const& rhs) const + { + return lhs >= rhs; + } +}; + +// TODO: provide hash if std::hash exists. + +} // namespace std + +#endif diff --git a/zypp-glib/utils/RetainPtr b/zypp-glib/utils/RetainPtr new file mode 100644 index 0000000000..957d0ed617 --- /dev/null +++ b/zypp-glib/utils/RetainPtr @@ -0,0 +1,368 @@ +/** + * An Intrusive Smart Pointer based on the proposal P0468R1 + * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0468r1.html + * + * Copyright (C) 2016, Isabella Muerte + * Copyright (C) 2022, SUSE Software Solutions Germany GmbH + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + */ + + +#ifndef ZYPP_GLIB_UTIL_RETAINPTR_H +#define ZYPP_GLIB_UTIL_RETAINPTR_H + +#include +#include +#include +#include + +namespace stdx { + +using std::is_convertible; +using std::is_same; + +using std::conditional_t; +using std::add_pointer_t; +using std::nullptr_t; +using std::is_detected; +using std::detected_t; +using std::detected_or_t; + +using std::declval; + +} /* namespace stdx */ + +namespace stdx::detail { + +template class U, class... Args> +using is_detected_exact = std::is_same>; + +template +using has_pointer = typename T::pointer; + +template +using has_default_action = typename T::default_action; + +template +using has_use_count = decltype(T::use_count(std::declval

())); + +} /* namespace stdx::detail */ + +namespace stdx { + +template struct retain_traits; + +template +struct atomic_reference_count { + template friend struct retain_traits; +protected: + atomic_reference_count () = default; +private: + std::atomic count { 1 }; +}; + +template +struct reference_count { + template friend struct retain_traits; +protected: + reference_count () = default; +private: + long count { 1 }; +}; + +struct retain_object_t { retain_object_t () noexcept = default; }; +struct adopt_object_t { adopt_object_t () noexcept = default; }; + +constexpr retain_object_t retain_object { }; +constexpr adopt_object_t adopt_object { }; + +template +struct retain_traits final { + template + using enable_if_base = std::enable_if_t>; + + template > + static void increment (atomic_reference_count* ptr) noexcept { + ptr->count.fetch_add(1, std::memory_order_relaxed); + } + + template > + static void decrement (atomic_reference_count* ptr) noexcept { + ptr->count.fetch_sub(1, std::memory_order_acq_rel); + if (not use_count(ptr)) { delete static_cast(ptr); } + } + + template > + static long use_count (atomic_reference_count* ptr) noexcept { + return ptr->count.load(std::memory_order_relaxed); + } + + template > + static void increment (reference_count* ptr) noexcept { + ++ptr->count; + } + template > + static void decrement (reference_count* ptr) noexcept { + --ptr->count; + if (not use_count(ptr)) { delete static_cast(ptr); } + } + template > + static long use_count (reference_count* ptr) noexcept { + return ptr->count; + } +}; + +template > +struct retain_ptr { + using element_type = T; + using traits_type = R; + + using pointer = detected_or_t< + add_pointer_t, + detail::has_pointer, + traits_type + >; + + using default_action = detected_or_t< + adopt_object_t, + detail::has_default_action, + traits_type + >; + + static constexpr bool CheckAction = std::disjunction_v< + std::is_same, + std::is_same + >; + + static_assert( + CheckAction, + "traits_type::default_action must be adopt_object_t or retain_object_t"); + + static constexpr auto has_use_count = is_detected< + detail::has_use_count, + traits_type, + pointer + > { }; + + retain_ptr (pointer ptr, retain_object_t) : + retain_ptr { ptr, adopt_object } + { if (*this) { traits_type::increment(this->get()); } } + + retain_ptr (pointer ptr, adopt_object_t) : ptr { ptr } { } + + explicit retain_ptr (pointer ptr) : + retain_ptr { ptr, default_action() } + { } + + retain_ptr (nullptr_t) : retain_ptr { } { } + + retain_ptr (retain_ptr const& that) : + ptr { that.ptr } + { if (*this) { traits_type::increment(this->get()); } } + + retain_ptr (retain_ptr&& that) noexcept : + ptr { that.detach() } + { } + + retain_ptr () noexcept = default; + ~retain_ptr () { + if (*this) { traits_type::decrement(this->get()); } + } + + retain_ptr& operator = (retain_ptr const& that) { + retain_ptr(that).swap(*this); + return *this; + } + + retain_ptr& operator = (retain_ptr&& that) { + retain_ptr(std::move(that)).swap(*this); + return *this; + } + + retain_ptr& operator = (nullptr_t) noexcept { this->reset( nullptr ); return *this; } + + void swap (retain_ptr& that) noexcept { + using std::swap; + swap(this->ptr, that.ptr); + } + + explicit operator bool () const noexcept { return this->get(); } + decltype(auto) operator * () const noexcept { return *this->get(); } + pointer operator -> () const noexcept { return this->get(); } + + pointer get () const noexcept { return this->ptr; } + + long use_count () const { + if constexpr (has_use_count) { + return this->get() ? traits_type::use_count(this->get()) : 0; + } else { return -1; } + } + + pointer detach () noexcept { + auto ptr = this->get(); + this->ptr = pointer { }; + return ptr; + } + + void reset (pointer ptr, retain_object_t) { + *this = retain_ptr(ptr, retain_object); + } + + void reset (pointer ptr, adopt_object_t) noexcept { + *this = retain_ptr(ptr, adopt_object); + } + + void reset (pointer ptr) { *this = retain_ptr(ptr, default_action()); } + +private: + pointer ptr { }; +}; + +template +void swap (retain_ptr& lhs, retain_ptr& rhs) noexcept { + lhs.swap(rhs); +} + +template +bool operator == ( + retain_ptr const& lhs, + retain_ptr const& rhs +) noexcept { return lhs.get() == rhs.get(); } + +template +bool operator != ( + retain_ptr const& lhs, + retain_ptr const& rhs +) noexcept { return lhs.get() != rhs.get(); } + +template +bool operator >= ( + retain_ptr const& lhs, + retain_ptr const& rhs +) noexcept { return lhs.get() >= rhs.get(); } + +template +bool operator <= ( + retain_ptr const& lhs, + retain_ptr const& rhs +) noexcept { return lhs.get() <= rhs.get(); } + +template +bool operator > ( + retain_ptr const& lhs, + retain_ptr const& rhs +) noexcept { return lhs.get() > rhs.get(); } + +template +bool operator < ( + retain_ptr const& lhs, + retain_ptr const& rhs +) noexcept { return lhs.get() < rhs.get(); } + +template +bool operator == (retain_ptr const& lhs, nullptr_t) noexcept { + return bool(lhs); +} + +template +bool operator != (retain_ptr const& lhs, nullptr_t) noexcept { + return not lhs; +} + +template +bool operator >= (retain_ptr const& lhs, nullptr_t) noexcept { + return not (lhs < nullptr); +} + +template +bool operator <= (retain_ptr const& lhs, nullptr_t) noexcept { + return nullptr < lhs; +} + +template +bool operator > (retain_ptr const& lhs, nullptr_t) noexcept { + return not (nullptr < lhs); +} + +template +bool operator < (retain_ptr const& lhs, nullptr_t) noexcept { + return std::less<>()(lhs.get(), nullptr); +} + +template +bool operator == (nullptr_t, retain_ptr const& rhs) noexcept { + return not rhs; +} + +template +bool operator != (nullptr_t, retain_ptr const& rhs) noexcept { + return bool(rhs); +} + +template +bool operator >= (nullptr_t, retain_ptr const& rhs) noexcept { + return not (nullptr < rhs); +} + +template +bool operator <= (nullptr_t, retain_ptr const& rhs) noexcept; + +template +bool operator > (nullptr_t, retain_ptr const& rhs) noexcept { + return not (rhs < nullptr); +} + +template +bool operator < (nullptr_t, retain_ptr const& rhs) noexcept { + return std::less<>()(rhs.get(), nullptr); +} + +template +inline retain_ptr<_Tp, _Traits> +reinterpret_pointer_cast(const retain_ptr<_Up, _Traits>& __r) noexcept +{ + using _Sp = retain_ptr<_Tp, _Traits>; + return _Sp( reinterpret_cast(__r.get()), retain_object ); +} + +template +inline retain_ptr<_Tp, _Traits> +static_pointer_cast(const retain_ptr<_Up, _Traits>& __r) noexcept +{ + using _Sp = retain_ptr<_Tp, _Traits>; + return _Sp( static_cast(__r.get()), retain_object ); +} + +} /* namespace stdx */ + +namespace zypp::glib { + template > + using RetainPtr = stdx::retain_ptr; + + constexpr stdx::retain_object_t retain_object { }; + constexpr stdx::adopt_object_t adopt_object { }; +} + + +#endif /* ZYPP_GLIB_UTIL_RETAINPTR_H */ diff --git a/zypp-glib/zypp-glib.cc b/zypp-glib/zypp-glib.cc new file mode 100644 index 0000000000..7757042d9d --- /dev/null +++ b/zypp-glib/zypp-glib.cc @@ -0,0 +1,9 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "zypp-glib.h" diff --git a/zypp-glib/zypp-glib.h b/zypp-glib/zypp-glib.h new file mode 100644 index 0000000000..a53758fb12 --- /dev/null +++ b/zypp-glib/zypp-glib.h @@ -0,0 +1,16 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include diff --git a/zypp-glib/zyppenums.c.in b/zypp-glib/zyppenums.c.in new file mode 100644 index 0000000000..9f64484a04 --- /dev/null +++ b/zypp-glib/zyppenums.c.in @@ -0,0 +1,29 @@ +/*** BEGIN file-header ***/ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "zyppenums.h" + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +/* enumerations from \"zyppng/@basename@\" */ +#include +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +G_DEFINE_ENUM_TYPE (@EnumName@, @enum_name@ +/*** END value-header ***/ + +/*** BEGIN value-production ***/ + ,G_DEFINE_ENUM_VALUE ( @VALUENAME@, "@valuenick@") +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ +) +/*** END value-tail ***/ diff --git a/zypp-glib/zyppenums.h.in b/zypp-glib/zyppenums.h.in new file mode 100644 index 0000000000..498a3d008b --- /dev/null +++ b/zypp-glib/zyppenums.h.in @@ -0,0 +1,30 @@ +/*** BEGIN file-header ***/ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#pragma once +#include +#include +G_BEGIN_DECLS +#pragma GCC visibility push(default) +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + +/* enumerations from "@basename@" */ +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType @enum_name@_get_type (void) G_GNUC_CONST LIBZYPP_GLIB_EXPORT; +#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) +/*** END value-header ***/ + +/*** BEGIN file-tail ***/ +#pragma GCC visibility pop +G_END_DECLS +/*** END file-tail ***/ diff --git a/zypp-media/CMakeLists.txt b/zypp-media/CMakeLists.txt index 0b256333b2..e608ad9382 100644 --- a/zypp-media/CMakeLists.txt +++ b/zypp-media/CMakeLists.txt @@ -67,8 +67,11 @@ SET( zypp_media_ng_HEADERS ng/provideres.h ng/provideitem.h ng/ProvideRes + ng/mediacontext.h + ng/MediaContext ng/mediaverifier.h ng/MediaVerifier + ng/auth/credentialmanager.h ng/worker/devicedriver.h ng/worker/DeviceDriver ng/worker/provideworker.h @@ -93,11 +96,13 @@ SET( zypp_media_ng_SRCS ng/headervaluemap.cc ng/provide.cc ng/provideres.cc + ng/mediacontext.cc ng/providespec.cc ng/provideitem.cc ng/providemessage.cc ng/providequeue.cc ng/mediaverifier.cc + ng/auth/credentialmanager.cc ng/worker/devicedriver.cc ng/worker/provideworker.cc ng/worker/mountingworker.cc diff --git a/zypp-media/auth/authdata.cc b/zypp-media/auth/authdata.cc index 8ae4fab9d5..8a95b86094 100644 --- a/zypp-media/auth/authdata.cc +++ b/zypp-media/auth/authdata.cc @@ -92,5 +92,24 @@ std::ostream & operator << (std::ostream & str, const AuthData & auth_data) return str; } +////////////////////////////////////////////////////////////////////// +// +// CLASS NAME : AuthDataComparator +// +////////////////////////////////////////////////////////////////////// + +bool AuthDataComparator::operator()( const AuthData_Ptr & lhs, const AuthData_Ptr & rhs ) const +{ + static const url::ViewOption vopt = url::ViewOption::DEFAULTS + - url::ViewOption::WITH_USERNAME + - url::ViewOption::WITH_PASSWORD + - url::ViewOption::WITH_QUERY_STR; + // std::less semantic! + int cmp = lhs->url().asString(vopt).compare( rhs->url().asString(vopt) ); + if ( ! cmp ) + cmp = lhs->username().compare( rhs->username() ); + return( cmp < 0 ); +} + } // namespace media } // namespace zypp diff --git a/zypp-media/auth/authdata.h b/zypp-media/auth/authdata.h index 746c0aed65..4819e9a05c 100644 --- a/zypp-media/auth/authdata.h +++ b/zypp-media/auth/authdata.h @@ -81,6 +81,12 @@ class ZYPP_API AuthData using AuthData_Ptr = shared_ptr; std::ostream & operator << (std::ostream & str, const AuthData & auth_data); +// comparator for CredentialSet +struct ZYPP_API AuthDataComparator +{ + bool operator()(const AuthData_Ptr & lhs, const AuthData_Ptr & rhs) const; +}; + /////////////////////////////////////////////////////////////////// } // namespace media diff --git a/zypp-media/auth/credentialmanager.cc b/zypp-media/auth/credentialmanager.cc index 75f35278d4..8361de04fb 100644 --- a/zypp-media/auth/credentialmanager.cc +++ b/zypp-media/auth/credentialmanager.cc @@ -12,497 +12,44 @@ #include "credentialmanager.h" -#include -#include - -#include #include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -namespace bpci = boost::interprocess; +#include using std::endl; -#define USER_CREDENTIALS_FILE ".zypp/credentials.cat" +constexpr std::string_view USER_CREDENTIALS_FILE(".zypp/credentials.cat"); -////////////////////////////////////////////////////////////////////// namespace zypp -{ //////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////// +{ namespace media - { //////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////// - // - // CLASS NAME : AuthDataComparator - // - ////////////////////////////////////////////////////////////////////// - - bool AuthDataComparator::operator()( const AuthData_Ptr & lhs, const AuthData_Ptr & rhs ) const - { - static const url::ViewOption vopt = url::ViewOption::DEFAULTS - - url::ViewOption::WITH_USERNAME - - url::ViewOption::WITH_PASSWORD - - url::ViewOption::WITH_QUERY_STR; - // std::less semantic! - int cmp = lhs->url().asString(vopt).compare( rhs->url().asString(vopt) ); - if ( ! cmp ) - cmp = lhs->username().compare( rhs->username() ); - return( cmp < 0 ); - } - - ////////////////////////////////////////////////////////////////////// - // - // CLASS NAME : CredManagerOptions - // - ////////////////////////////////////////////////////////////////////// - - CredManagerOptions::CredManagerOptions(const Pathname & rootdir) - : globalCredFilePath(rootdir / MediaConfig::instance().credentialsGlobalFile()) - , customCredFileDir(rootdir / MediaConfig::instance().credentialsGlobalDir()) - { - char * homedir = getenv("HOME"); - if (homedir) - userCredFilePath = rootdir / homedir / USER_CREDENTIALS_FILE; - } - - - ////////////////////////////////////////////////////////////////////// - // - // CLASS NAME : CredentialManager::Impl - // - struct CredentialManager::Impl - { - Impl(CredManagerOptions &&options); - - Impl(const Impl &) = delete; - Impl(Impl &&) = delete; - Impl &operator=(const Impl &) = delete; - Impl &operator=(Impl &&) = delete; - - ~Impl() - {} - - void init_globalCredentials(); - void init_userCredentials(); - - bool processCredentials(AuthData_Ptr & cred); - - AuthData_Ptr getCred(const Url & url) const; - AuthData_Ptr getCredFromFile(const Pathname & file); - void saveGlobalCredentials(); - void saveUserCredentials(); - - - CredManagerOptions _options; - - CredentialSet _credsGlobal; - CredentialSet _credsUser; - CredentialSet _credsTmp; - - bool _globalDirty; - bool _userDirty; - }; - ////////////////////////////////////////////////////////////////////// - - - ////////////////////////////////////////////////////////////////////// - // - // CLASS NAME : CredentialManager::Impl - // - ////////////////////////////////////////////////////////////////////// - - CredentialManager::Impl::Impl(CredManagerOptions &&options) - : _options(std::move(options)) - , _globalDirty(false) - , _userDirty(false) - { - init_globalCredentials(); - init_userCredentials(); - } - - - void CredentialManager::Impl::init_globalCredentials() { - if (_options.globalCredFilePath.empty()) - DBG << "global cred file not known"; - else if (PathInfo(_options.globalCredFilePath).isExist()) - { - /* list entries; - if (filesystem::readdir(entries, _options.globalCredFilePath, false) != 0) - ZYPP_THROW(Exception("failed to read directory")); - - for_(it, entries.begin(), entries.end())*/ - - CredentialFileReader(_options.globalCredFilePath, - bind(&Impl::processCredentials, this, _1)); - } - else - DBG << "global cred file does not exist"; - - _credsGlobal = _credsTmp; _credsTmp.clear(); - DBG << "Got " << _credsGlobal.size() << " global records." << endl; - } - - - void CredentialManager::Impl::init_userCredentials() - { - if (_options.userCredFilePath.empty()) - DBG << "user cred file not known"; - else if (PathInfo(_options.userCredFilePath).isExist()) - { - /* list entries; - if (filesystem::readdir(entries, _options.userCredFilePath, false ) != 0) - ZYPP_THROW(Exception("failed to read directory")); - - for_(it, entries.begin(), entries.end())*/ - CredentialFileReader(_options.userCredFilePath, - bind(&Impl::processCredentials, this, _1)); - } - else - DBG << "user cred file does not exist" << endl; - - _credsUser = _credsTmp; _credsTmp.clear(); - DBG << "Got " << _credsUser.size() << " user records." << endl; - } - - - bool CredentialManager::Impl::processCredentials(AuthData_Ptr & cred) - { - _credsTmp.insert(cred); - return true; - } - - - AuthData_Ptr CredentialManager::findIn(const CredentialManager::CredentialSet & set, - const Url & url, - url::ViewOption vopt) - { - const std::string & username = url.getUsername(); - for( CredentialManager::CredentialIterator it = set.begin(); it != set.end(); ++it ) - { - if ( !(*it)->url().isValid() ) - continue; - - // this ignores url params - not sure if it is good or bad... - if ( url.asString(vopt).find((*it)->url().asString(vopt)) == 0 ) - { - if ( username.empty() || username == (*it)->username() ) - return *it; + namespace { + void setUserCredFilePath( const zypp::Pathname &root, zypp::Pathname &userCredFilePath ) { + char * homedir = getenv("HOME"); + if (homedir) + userCredFilePath = root / homedir / USER_CREDENTIALS_FILE.data (); } } - return AuthData_Ptr(); - } - - AuthData_Ptr CredentialManager::Impl::getCred(const Url & url) const - { - AuthData_Ptr result; - - // compare the urls via asString(), but ignore password - // default url::ViewOption will take care of that. - // operator==(Url,Url) compares the whole Url - - url::ViewOption vopt; - vopt = vopt - - url::ViewOption::WITH_USERNAME - - url::ViewOption::WITH_PASSWORD - - url::ViewOption::WITH_QUERY_STR; - - // search in global credentials - result = findIn(_credsGlobal, url, vopt); - - // search in home credentials - if (!result) - result = findIn(_credsUser, url, vopt); - - if (result) - DBG << "Found credentials for '" << url << "':" << endl << *result; - else - DBG << "No credentials for '" << url << "'" << endl; - - return result; - } - - - AuthData_Ptr CredentialManager::Impl::getCredFromFile(const Pathname & file) - { - AuthData_Ptr result; - - Pathname credfile; - if (file.absolute()) - // get from that file - credfile = file; - else - // get from /etc/zypp/credentials.d, delete the leading path - credfile = _options.customCredFileDir / file.basename(); - - PathInfo pi { credfile }; - if ( pi.userMayR() ) try { - // make sure only our thread accesses the file - bpci::file_lock lockFile ( credfile.c_str() ); - bpci::scoped_lock lock( lockFile ); - - CredentialFileReader(credfile, bind(&Impl::processCredentials, this, _1)); - } - catch ( ... ) { - WAR << pi << " failed to lock file for reading." << endl; - } - - if (_credsTmp.empty()) - WAR << pi << " does not contain valid credentials or is not readable." << endl; - else + CredManagerSettings::CredManagerSettings( zyppng::MediaContextRef ctx ) + : globalCredFilePath( ctx->contextRoot() / ctx->mediaConfig().credentialsGlobalFile() ) + , customCredFileDir ( ctx->contextRoot() / ctx->mediaConfig().credentialsGlobalDir() ) { - result = *_credsTmp.begin(); - _credsTmp.clear(); + setUserCredFilePath( ctx->contextRoot(), userCredFilePath ); } - return result; - } - - static int save_creds_in_file( - CredentialManager::CredentialSet &creds, - const Pathname & file, - const mode_t mode) - { - int ret = 0; - filesystem::assert_file_mode( file, mode ); - - const auto now = time( nullptr ); - - PathInfo pi { file }; - if ( pi.userMayRW() ) try { - // make sure only our thread accesses the file - bpci::file_lock lockFile ( file.c_str() ); - bpci::scoped_lock lock( lockFile ); - - std::ofstream fs(file.c_str()); - for_(it, creds.begin(), creds.end()) - { - (*it)->dumpAsIniOn(fs); - (*it)->setLastDatabaseUpdate( now ); - fs << endl; - } - if ( !fs ) { - WAR << pi << " failed to write credentials to file." << endl; - ret = 1; - } - fs.close(); - } - catch ( ... ) { - WAR << pi << " failed to lock file for writing." << endl; - ret = 1; - } - - return ret; - } - - void CredentialManager::Impl::saveGlobalCredentials() - { - save_creds_in_file(_credsGlobal, _options.globalCredFilePath, 0640); - } - - void CredentialManager::Impl::saveUserCredentials() - { - save_creds_in_file(_credsUser, _options.userCredFilePath, 0600); - } - - - ////////////////////////////////////////////////////////////////////// - // - // CLASS NAME : CredentialManager - // - ////////////////////////////////////////////////////////////////////// - - CredentialManager::CredentialManager(CredManagerOptions opts) - : _pimpl(new Impl(std::move(opts))) - {} - - - AuthData_Ptr CredentialManager::getCred(const Url & url) - { - std::string credfile = url.getQueryParam("credentials"); - if (credfile.empty()) - return _pimpl->getCred(url); - return _pimpl->getCredFromFile(credfile); - } - - - AuthData_Ptr CredentialManager::getCredFromFile(const Pathname & file) - { return _pimpl->getCredFromFile(file); } - - - void CredentialManager::addCred(const AuthData & cred) - { - if ( !cred.url().isValid() ) - ZYPP_THROW( MediaInvalidCredentialsException( "URL must be valid in order to save AuthData." ) ); - - Pathname credfile = cred.url().getQueryParam("credentials"); - if (credfile.empty()) - //! \todo ask user where to store these creds. saving to user creds for now - addUserCred(cred); - else - saveInFile(cred, credfile); - } - - time_t CredentialManager::timestampForCredDatabase ( const zypp::Url &url ) - { - Pathname credfile; - if ( url.isValid() ) { - credfile = url.getQueryParam("credentials"); - } - - if (credfile.empty()) - credfile = _pimpl->_options.userCredFilePath; - - zypp::PathInfo pi(credfile); - if ( pi.isExist() && pi.isFile() ) - return pi.mtime(); - - return 0; - } - - void CredentialManager::addGlobalCred(const AuthData & cred) - { - if ( !cred.url().isValid() ) - ZYPP_THROW( MediaInvalidCredentialsException( "URL must be valid in order to save AuthData." ) ); - - AuthData_Ptr c_ptr; - c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed - std::pair ret = _pimpl->_credsGlobal.insert(c_ptr); - if (ret.second) - _pimpl->_globalDirty = true; - else if ((*ret.first)->password() != cred.password()) + CredManagerSettings::CredManagerSettings() + : globalCredFilePath( MediaConfig::defaults().credentialsGlobalFile() ) + , customCredFileDir ( MediaConfig::defaults().credentialsGlobalDir() ) { - _pimpl->_credsGlobal.erase(ret.first); - _pimpl->_credsGlobal.insert(c_ptr); - _pimpl->_globalDirty = true; + setUserCredFilePath( "", userCredFilePath ); } - } - - void CredentialManager::addUserCred(const AuthData & cred) - { - if ( !cred.url().isValid() ) - ZYPP_THROW( MediaInvalidCredentialsException( "URL must be valid in order to save AuthData." ) ); - - AuthData_Ptr c_ptr; - c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed - std::pair ret = _pimpl->_credsUser.insert(c_ptr); - if (ret.second) - _pimpl->_userDirty = true; - else if ((*ret.first)->password() != cred.password()) - { - _pimpl->_credsUser.erase(ret.first); - _pimpl->_credsUser.insert(c_ptr); - _pimpl->_userDirty = true; - } - } - - - void CredentialManager::save() - { - if (_pimpl->_globalDirty) - _pimpl->saveGlobalCredentials(); - if (_pimpl->_userDirty) - _pimpl->saveUserCredentials(); - _pimpl->_globalDirty = false; - _pimpl->_userDirty = false; - } - - - void CredentialManager::saveInGlobal(const AuthData & cred) - { - addGlobalCred(cred); - save(); - } - - - void CredentialManager::saveInUser(const AuthData & cred) - { - addUserCred(cred); - save(); - } - - - void CredentialManager::saveInFile(const AuthData & cred, const Pathname & credFile) - { - AuthData_Ptr c_ptr; - c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed - c_ptr->setUrl(Url()); // don't save url in custom creds file - CredentialManager::CredentialSet creds; - creds.insert(c_ptr); - - int ret = 0; - if (credFile.absolute()) - ret = save_creds_in_file(creds, credFile, 0640); - else - ret = save_creds_in_file( - creds, _pimpl->_options.customCredFileDir / credFile, 0600); - - if (!ret) + const char *CredManagerSettings::userCredFile() { - //! \todo figure out the reason(?), call back to user - ERR << "error saving the credentials" << endl; + return USER_CREDENTIALS_FILE.data(); } - } - - - void CredentialManager::clearAll(bool global) - { - if (global) - { - if (!filesystem::unlink(_pimpl->_options.globalCredFilePath)) - ERR << "could not delete user credentials file " - << _pimpl->_options.globalCredFilePath << endl; - _pimpl->_credsUser.clear(); - } - else - { - if (!filesystem::unlink(_pimpl->_options.userCredFilePath)) - ERR << "could not delete global credentials file" - << _pimpl->_options.userCredFilePath << endl; - _pimpl->_credsGlobal.clear(); - } - } - - - CredentialManager::CredentialIterator CredentialManager::credsGlobalBegin() const - { return _pimpl->_credsGlobal.begin(); } - - CredentialManager::CredentialIterator CredentialManager::credsGlobalEnd() const - { return _pimpl->_credsGlobal.end(); } - - CredentialManager::CredentialSize CredentialManager::credsGlobalSize() const - { return _pimpl->_credsGlobal.size(); } - - bool CredentialManager::credsGlobalEmpty() const - { return _pimpl->_credsGlobal.empty(); } - - - CredentialManager::CredentialIterator CredentialManager::credsUserBegin() const - { return _pimpl->_credsUser.begin(); } - - CredentialManager::CredentialIterator CredentialManager::credsUserEnd() const - { return _pimpl->_credsUser.end(); } - - CredentialManager::CredentialSize CredentialManager::credsUserSize() const - { return _pimpl->_credsUser.size(); } - - bool CredentialManager::credsUserEmpty() const - { return _pimpl->_credsUser.empty(); } - //////////////////////////////////////////////////////////////////// } // media diff --git a/zypp-media/auth/credentialmanager.h b/zypp-media/auth/credentialmanager.h index 0c31b281f3..3185f8c754 100644 --- a/zypp-media/auth/credentialmanager.h +++ b/zypp-media/auth/credentialmanager.h @@ -12,23 +12,19 @@ #ifndef ZYPP_MEDIA_AUTH_CREDENTIALMANAGER_H #define ZYPP_MEDIA_AUTH_CREDENTIALMANAGER_H -#include - #include #include #include -////////////////////////////////////////////////////////////////////// -namespace zypp -{ //////////////////////////////////////////////////////////////////// +namespace zyppng { + ZYPP_FWD_DECL_TYPE_WITH_REFS (MediaContext); +} +namespace zypp +{ class Url; - - ////////////////////////////////////////////////////////////////////// namespace media - { //////////////////////////////////////////////////////////////////// - - + { ////////////////////////////////////////////////////////////////////// // // CLASS NAME : CredManagerOptions @@ -36,161 +32,18 @@ namespace zypp /** * \todo configurable cred file locations */ - struct ZYPP_API CredManagerOptions + struct ZYPP_API CredManagerSettings { - CredManagerOptions(const Pathname & rootdir = ""); - + CredManagerSettings( zyppng::MediaContextRef ctx ); + CredManagerSettings() ZYPP_LOCAL; // to support legacy API and tests Pathname globalCredFilePath; Pathname userCredFilePath; Pathname customCredFileDir; - }; - ////////////////////////////////////////////////////////////////////// - // comparator for CredentialSet - struct ZYPP_API AuthDataComparator - { - bool operator()(const AuthData_Ptr & lhs, const AuthData_Ptr & rhs) const; + static const char *userCredFile(); }; - ////////////////////////////////////////////////////////////////////// - // - // CLASS NAME : CredentialManager - // - /** - * \todo better method names - * \todo delete(AuthData) method - */ - class ZYPP_API CredentialManager - { - public: - using CredentialSet = std::set; - using CredentialSize = CredentialSet::size_type; - using CredentialIterator = CredentialSet::const_iterator; - - - CredentialManager(CredManagerOptions opts = CredManagerOptions()); - - ~CredentialManager() - {} - - public: - /** - * Get credentials for the specified \a url. - * - * If the URL contains also username, it will be used to find the match - * for this user (in case mutliple are available). - * - * \param url URL to find credentials for. - * \return Pointer to retrieved authentication data on success or an empty - * AuthData_Ptr otherwise. - * \todo return a copy instead? - */ - AuthData_Ptr getCred(const Url & url); - - /** - * Read credentials from a file. - */ - AuthData_Ptr getCredFromFile(const Pathname & file); - - /** - * Add new global credentials. - */ - void addGlobalCred(const AuthData & cred); - - /** - * Add new user credentials. - */ - void addUserCred(const AuthData & cred); - - /** - * Add new credentials with user callbacks. - * - * If the cred->url() contains 'credentials' query parameter, the - * credentials will be automatically saved to the specified file using the - * \ref saveInFile() method. - * - * Otherwise a callback will be called asking whether to save to custom - * file, or to global or user's credentials catalog. - * - * \todo Currently no callback is called, credentials are automatically - * saved to user's credentials.cat if no 'credentials' parameter - * has been specified - */ - void addCred(const AuthData & cred); - - /** - * Saves any unsaved credentials added via \ref addUserCred() or - * \a addGlobalCred() methods. - */ - void save(); - - /** - * Saves given \a cred to global credentials file. - * - * \note Use this method to add just one piece of credentials. To add - * multiple items at once, use addGlobalCred() followed - * by save() - */ - void saveInGlobal(const AuthData & cred); - - /** - * Saves given \a cred to user's credentials file. - * - * \note Use this method to add just one piece of credentials. To add - * multiple items at once, use addUserCred() followed - * by save() - */ - void saveInUser(const AuthData & cred); - - /** - * Saves given \a cred to user specified credentials file. - * - * If the credFile path is absolute, it will be saved at that precise - * location. If \a credFile is just a filename, it will be saved - * in \ref CredManagerOptions::customCredFileDir. Otherwise the current - * working directory will be prepended to the file path. - */ - void saveInFile(const AuthData &, const Pathname & credFile); - - /** - * Remove all global or user credentials from memory and disk. - * - * \param global Whether to remove global or user credentials. - */ - void clearAll(bool global = false); - - /*! - * Helper function to find a matching AuthData instance in a CredentialSet - */ - static AuthData_Ptr findIn( const CredentialManager::CredentialSet & set, const Url & url, url::ViewOption vopt ); - - /*! - * Returns the timestamp of the database the given URL creds would be stored - */ - time_t timestampForCredDatabase ( const zypp::Url &url ); - - CredentialIterator credsGlobalBegin() const; - CredentialIterator credsGlobalEnd() const; - CredentialSize credsGlobalSize() const; - bool credsGlobalEmpty() const; - - CredentialIterator credsUserBegin() const; - CredentialIterator credsUserEnd() const; - CredentialSize credsUserSize() const; - bool credsUserEmpty() const; - - struct Impl; - private: - RW_pointer _pimpl; - }; - ////////////////////////////////////////////////////////////////////// - - - //////////////////////////////////////////////////////////////////// } // media - ////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////// } // zypp -////////////////////////////////////////////////////////////////////// #endif /* ZYPP_MEDIA_AUTH_CREDENTIALMANAGER_H */ diff --git a/zypp-media/mediaconfig.cc b/zypp-media/mediaconfig.cc index 589c73f190..143cc2190f 100644 --- a/zypp-media/mediaconfig.cc +++ b/zypp-media/mediaconfig.cc @@ -11,11 +11,24 @@ */ #include "mediaconfig.h" +#include +#include #include #include +#include + namespace zypp { + namespace { + // LEGACY: detect zypp conf + zypp::Pathname autodetectZyppConfPath() { + const char *env_confpath = getenv("ZYPP_CONF"); + return env_confpath ? env_confpath + : zyppng::MediaContext::defaultConfigPath(); + } + } + class MediaConfigPrivate { public: @@ -40,13 +53,42 @@ namespace zypp { }; - MediaConfig::MediaConfig() : d_ptr( new MediaConfigPrivate() ) + MediaConfig::MediaConfig( Pathname confFile ) : d_ptr( new MediaConfigPrivate() ) + { + if ( zypp::filesystem::PathInfo(confFile).isExist() ) + { + zypp::parser::IniDict dict( confFile ); + for ( auto sit = dict.sectionsBegin(); + sit != dict.sectionsEnd(); + ++sit ) + { + const std::string& section(*sit); + //MIL << section << endl; + for ( auto it = dict.entriesBegin(*sit); + it != dict.entriesEnd(*sit); + ++it ) + { + std::string entry(it->first); + std::string value(it->second); + setConfigValue( section, entry, value ); + } + } + } + } + + MediaConfig::~MediaConfig() { } - MediaConfig &MediaConfig::instance() + MediaConfig &MediaConfig::systemConfig() + { + static MediaConfig _sysConf( autodetectZyppConfPath() ); + return _sysConf; + } + + const MediaConfig &MediaConfig::defaults() { - static MediaConfig instance; - return instance; + static MediaConfig _defConf( "" ); + return _defConf; } bool MediaConfig::setConfigValue( const std::string §ion, const std::string &entry, const std::string &value ) diff --git a/zypp-media/mediaconfig.h b/zypp-media/mediaconfig.h index 8e0de5e91b..a4079c4f03 100644 --- a/zypp-media/mediaconfig.h +++ b/zypp-media/mediaconfig.h @@ -43,9 +43,11 @@ namespace zypp { { ZYPP_DECLARE_PRIVATE(MediaConfig) public: + MediaConfig( zypp::Pathname confFile ); + ~MediaConfig(); - /*! Singleton ctor */ - static MediaConfig & instance(); + static MediaConfig & systemConfig(); + static const MediaConfig & defaults(); bool setConfigValue ( const std::string §ion, const std::string &entry, const std::string &value ); @@ -91,7 +93,6 @@ namespace zypp { long download_connect_timeout() const; private: - MediaConfig(); std::unique_ptr d_ptr; }; diff --git a/zypp-media/ng/MediaContext b/zypp-media/ng/MediaContext new file mode 100644 index 0000000000..67abe91264 --- /dev/null +++ b/zypp-media/ng/MediaContext @@ -0,0 +1 @@ +#include "mediacontext.h" diff --git a/zypp-media/ng/auth/credentialmanager.cc b/zypp-media/ng/auth/credentialmanager.cc new file mode 100644 index 0000000000..72e77ff8d8 --- /dev/null +++ b/zypp-media/ng/auth/credentialmanager.cc @@ -0,0 +1,393 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#include +#include + +#include "credentialmanager.h" +#include +#include + +#include +#include + +#include +#include +#include + +namespace bpci = boost::interprocess; + + +namespace zyppng::media { + + CredentialManager::CredentialManager( ZYPP_PRIVATE_CONSTR_ARG, zypp::media::CredManagerSettings options ) + : _options(std::move(options)) + , _globalDirty(false) + , _userDirty(false) + { + init_globalCredentials(); + init_userCredentials(); + } + + CredentialManager::~CredentialManager() + { } + + + void CredentialManager::init_globalCredentials() + { + if (_options.globalCredFilePath.empty()) + DBG << "global cred file not known"; + else if ( zypp::PathInfo(_options.globalCredFilePath).isExist()) + { + /* list entries; + if (filesystem::readdir(entries, _options.globalCredFilePath, false) != 0) + ZYPP_THROW(Exception("failed to read directory")); + + for_(it, entries.begin(), entries.end())*/ + + zypp::media::CredentialFileReader(_options.globalCredFilePath, + bind(&CredentialManager::processCredentials, this, std::placeholders::_1)); + } + else + DBG << "global cred file does not exist"; + + _credsGlobal = _credsTmp; _credsTmp.clear(); + DBG << "Got " << _credsGlobal.size() << " global records." << std::endl; + } + + + void CredentialManager::init_userCredentials() + { + if (_options.userCredFilePath.empty()) + DBG << "user cred file not known"; + else if ( zypp::PathInfo(_options.userCredFilePath).isExist() ) + { + /* list entries; + if (filesystem::readdir(entries, _options.userCredFilePath, false ) != 0) + ZYPP_THROW(Exception("failed to read directory")); + + for_(it, entries.begin(), entries.end())*/ + zypp::media::CredentialFileReader(_options.userCredFilePath, + bind(&CredentialManager::processCredentials, this, std::placeholders::_1)); + } + else + DBG << "user cred file does not exist" << std::endl; + + _credsUser = _credsTmp; _credsTmp.clear(); + DBG << "Got " << _credsUser.size() << " user records." << std::endl; + } + + + bool CredentialManager::processCredentials( zypp::media::AuthData_Ptr & cred ) + { + _credsTmp.insert(cred); + return true; + } + + + zypp::media::AuthData_Ptr CredentialManager::findIn(const CredentialManager::CredentialSet & set, + const zypp::Url & url, + zypp::url::ViewOption vopt) + { + const std::string & username = url.getUsername(); + for( CredentialManager::CredentialIterator it = set.begin(); it != set.end(); ++it ) + { + if ( !(*it)->url().isValid() ) + continue; + + // this ignores url params - not sure if it is good or bad... + if ( url.asString(vopt).find((*it)->url().asString(vopt)) == 0 ) + { + if ( username.empty() || username == (*it)->username() ) + return *it; + } + } + + return zypp::media::AuthData_Ptr(); + } + + zypp::media::AuthData_Ptr CredentialManager::getCredFromUrl( const zypp::Url & url ) const + { + zypp::media::AuthData_Ptr result; + + // compare the urls via asString(), but ignore password + // default url::ViewOption will take care of that. + // operator==(Url,Url) compares the whole Url + + zypp::url::ViewOption vopt; + vopt = vopt + - zypp::url::ViewOption::WITH_USERNAME + - zypp::url::ViewOption::WITH_PASSWORD + - zypp::url::ViewOption::WITH_QUERY_STR; + + // search in global credentials + result = findIn(_credsGlobal, url, vopt); + + // search in home credentials + if (!result) + result = findIn(_credsUser, url, vopt); + + if (result) + DBG << "Found credentials for '" << url << "':" << std::endl << *result; + else + DBG << "No credentials for '" << url << "'" << std::endl; + + return result; + } + + + zypp::media::AuthData_Ptr CredentialManager::getCredFromFile(const zypp::Pathname & file) + { + zypp::media::AuthData_Ptr result; + + zypp::Pathname credfile; + if (file.absolute()) + // get from that file + credfile = file; + else + // get from /etc/zypp/credentials.d, delete the leading path + credfile = _options.customCredFileDir / file.basename(); + + zypp::PathInfo pi { credfile }; + if ( pi.userMayR() ) try { + // make sure only our thread accesses the file + bpci::file_lock lockFile ( credfile.c_str() ); + bpci::scoped_lock lock( lockFile ); + + zypp::media::CredentialFileReader(credfile, bind(&CredentialManager::processCredentials, this, std::placeholders::_1)); + } + catch ( ... ) { + WAR << pi << " failed to lock file for reading." << std::endl; + } + + if (_credsTmp.empty()) + WAR << pi << " does not contain valid credentials or is not readable." << std::endl; + else + { + result = *_credsTmp.begin(); + _credsTmp.clear(); + } + + return result; + } + + static int save_creds_in_file( + CredentialManager::CredentialSet &creds, + const zypp::Pathname & file, + const mode_t mode) + { + int ret = 0; + zypp::filesystem::assert_file_mode( file, mode ); + + const auto now = time( nullptr ); + + zypp::PathInfo pi { file }; + if ( pi.userMayRW() ) try { + // make sure only our thread accesses the file + bpci::file_lock lockFile ( file.c_str() ); + bpci::scoped_lock lock( lockFile ); + + std::ofstream fs(file.c_str()); + for_(it, creds.begin(), creds.end()) + { + (*it)->dumpAsIniOn(fs); + (*it)->setLastDatabaseUpdate( now ); + fs << std::endl; + } + if ( !fs ) { + WAR << pi << " failed to write credentials to file." << std::endl; + ret = 1; + } + fs.close(); + } + catch ( ... ) { + WAR << pi << " failed to lock file for writing." << std::endl; + ret = 1; + } + + return ret; + } + + void CredentialManager::saveGlobalCredentials() + { + save_creds_in_file(_credsGlobal, _options.globalCredFilePath, 0640); + } + + void CredentialManager::saveUserCredentials() + { + save_creds_in_file( _credsUser, _options.userCredFilePath, 0600); + } + + zypp::media::AuthData_Ptr CredentialManager::getCred(const zypp::Url & url) + { + std::string credfile = url.getQueryParam("credentials"); + if (credfile.empty()) + return getCredFromUrl(url); + return getCredFromFile(credfile); + } + + void CredentialManager::addCred(const zypp::media::AuthData & cred) + { + if ( !cred.url().isValid() ) + ZYPP_THROW( zypp::media::MediaInvalidCredentialsException( "URL must be valid in order to save AuthData." ) ); + + zypp::Pathname credfile = cred.url().getQueryParam("credentials"); + if (credfile.empty()) + //! \todo ask user where to store these creds. saving to user creds for now + addUserCred(cred); + else + saveInFile(cred, credfile); + } + + time_t CredentialManager::timestampForCredDatabase ( const zypp::Url &url ) + { + zypp::Pathname credfile; + if ( url.isValid() ) { + credfile = url.getQueryParam("credentials"); + } + + if (credfile.empty()) + credfile = _options.userCredFilePath; + + zypp::PathInfo pi(credfile); + if ( pi.isExist() && pi.isFile() ) + return pi.mtime(); + + return 0; + } + + void CredentialManager::addGlobalCred(const zypp::media::AuthData & cred) + { + if ( !cred.url().isValid() ) + ZYPP_THROW( zypp::media::MediaInvalidCredentialsException( "URL must be valid in order to save AuthData." ) ); + + zypp::media::AuthData_Ptr c_ptr; + c_ptr.reset(new zypp::media::AuthData(cred)); // FIX for child classes if needed + std::pair ret = _credsGlobal.insert(c_ptr); + if (ret.second) + _globalDirty = true; + else if ((*ret.first)->password() != cred.password()) + { + _credsGlobal.erase(ret.first); + _credsGlobal.insert(c_ptr); + _globalDirty = true; + } + } + + + void CredentialManager::addUserCred(const zypp::media::AuthData & cred) + { + if ( !cred.url().isValid() ) + ZYPP_THROW( zypp::media::MediaInvalidCredentialsException( "URL must be valid in order to save AuthData." ) ); + + zypp::media::AuthData_Ptr c_ptr; + c_ptr.reset(new zypp::media::AuthData(cred)); // FIX for child classes if needed + std::pair ret = _credsUser.insert(c_ptr); + if (ret.second) + _userDirty = true; + else if ((*ret.first)->password() != cred.password()) + { + _credsUser.erase(ret.first); + _credsUser.insert(c_ptr); + _userDirty = true; + } + } + + + void CredentialManager::save() + { + if (_globalDirty) + saveGlobalCredentials(); + if (_userDirty) + saveUserCredentials(); + _globalDirty = false; + _userDirty = false; + } + + + void CredentialManager::saveInGlobal(const zypp::media::AuthData & cred) + { + addGlobalCred(cred); + save(); + } + + + void CredentialManager::saveInUser(const zypp::media::AuthData & cred) + { + addUserCred(cred); + save(); + } + + + void CredentialManager::saveInFile(const zypp::media::AuthData & cred, const zypp::Pathname & credFile) + { + zypp::media::AuthData_Ptr c_ptr; + c_ptr.reset(new zypp::media::AuthData(cred)); // FIX for child classes if needed + c_ptr->setUrl( zypp::Url() ); // don't save url in custom creds file + CredentialManager::CredentialSet creds; + creds.insert(c_ptr); + + int ret = 0; + if (credFile.absolute()) + ret = save_creds_in_file(creds, credFile, 0640); + else + ret = save_creds_in_file( + creds, _options.customCredFileDir / credFile, 0600); + + if (!ret) + { + //! \todo figure out the reason(?), call back to user + ERR << "error saving the credentials" << std::endl; + } + } + + + void CredentialManager::clearAll(bool global) + { + if (global) + { + if (!zypp::filesystem::unlink(_options.globalCredFilePath)) + ERR << "could not delete user credentials file " + << _options.globalCredFilePath << std::endl; + _credsUser.clear(); + } + else + { + if (!zypp::filesystem::unlink(_options.userCredFilePath)) + ERR << "could not delete global credentials file" + << _options.userCredFilePath << std::endl; + _credsGlobal.clear(); + } + } + + CredentialManager::CredentialIterator CredentialManager::credsGlobalBegin() const + { return _credsGlobal.begin(); } + + CredentialManager::CredentialIterator CredentialManager::credsGlobalEnd() const + { return _credsGlobal.end(); } + + CredentialManager::CredentialSize CredentialManager::credsGlobalSize() const + { return _credsGlobal.size(); } + + bool CredentialManager::credsGlobalEmpty() const + { return _credsGlobal.empty(); } + + CredentialManager::CredentialIterator CredentialManager::credsUserBegin() const + { return _credsUser.begin(); } + + CredentialManager::CredentialIterator CredentialManager::credsUserEnd() const + { return _credsUser.end(); } + + CredentialManager::CredentialSize CredentialManager::credsUserSize() const + { return _credsUser.size(); } + + bool CredentialManager::credsUserEmpty() const + { return _credsUser.empty(); } + +} diff --git a/zypp-media/ng/auth/credentialmanager.h b/zypp-media/ng/auth/credentialmanager.h new file mode 100644 index 0000000000..54eea5e2dc --- /dev/null +++ b/zypp-media/ng/auth/credentialmanager.h @@ -0,0 +1,172 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp-media/ng/auth/CredentialManager + * + */ +#ifndef ZYPP_MEDIA_NG_AUTH_CREDENTIALMANAGER_H +#define ZYPP_MEDIA_NG_AUTH_CREDENTIALMANAGER_H + +#include +#include +#include +#include + +namespace zyppng { + + namespace media { + + ZYPP_FWD_DECL_TYPE_WITH_REFS (CredentialManager); + + class CredentialManager : public Base + { + ZYPP_ADD_CREATE_FUNC (CredentialManager) + public: + using CredentialSet = std::set; + using CredentialSize = CredentialSet::size_type; + using CredentialIterator = CredentialSet::const_iterator; + + CredentialManager( const CredentialManager &) = delete; + CredentialManager( CredentialManager &&) = delete; + CredentialManager &operator=(const CredentialManager &) = delete; + CredentialManager &operator=(CredentialManager &&) = delete; + CredentialManager( ZYPP_PRIVATE_CONSTR_ARG, zypp::media::CredManagerSettings opts); + + ~CredentialManager() override; + + public: + /** + * Get credentials for the specified \a url. + * + * If the URL contains also username, it will be used to find the match + * for this user (in case mutliple are available). + * + * \param url URL to find credentials for. + * \return Pointer to retrieved authentication data on success or an empty + * AuthData_Ptr otherwise. + * \todo return a copy instead? + */ + zypp::media::AuthData_Ptr getCred(const zypp::Url & url); + + /** + * Read credentials from a file. + */ + zypp::media::AuthData_Ptr getCredFromFile(const zypp::Pathname & file); + + /** + * Add new global credentials. + */ + void addGlobalCred(const zypp::media::AuthData & cred); + + /** + * Add new user credentials. + */ + void addUserCred(const zypp::media::AuthData & cred); + + /** + * Add new credentials with user callbacks. + * + * If the cred->url() contains 'credentials' query parameter, the + * credentials will be automatically saved to the specified file using the + * \ref saveInFile() method. + * + * Otherwise a callback will be called asking whether to save to custom + * file, or to global or user's credentials catalog. + * + * \todo Currently no callback is called, credentials are automatically + * saved to user's credentials.cat if no 'credentials' parameter + * has been specified + */ + void addCred(const zypp::media::AuthData & cred); + + /** + * Saves any unsaved credentials added via \ref addUserCred() or + * \a addGlobalCred() methods. + */ + void save(); + + /** + * Saves given \a cred to global credentials file. + * + * \note Use this method to add just one piece of credentials. To add + * multiple items at once, use addGlobalCred() followed + * by save() + */ + void saveInGlobal(const zypp::media::AuthData & cred); + + /** + * Saves given \a cred to user's credentials file. + * + * \note Use this method to add just one piece of credentials. To add + * multiple items at once, use addUserCred() followed + * by save() + */ + void saveInUser(const zypp::media::AuthData & cred); + + /** + * Saves given \a cred to user specified credentials file. + * + * If the credFile path is absolute, it will be saved at that precise + * location. If \a credFile is just a filename, it will be saved + * in \ref CredManagerOptions::customCredFileDir. Otherwise the current + * working directory will be prepended to the file path. + */ + void saveInFile(const zypp::media::AuthData &, const zypp::Pathname & credFile); + + /** + * Remove all global or user credentials from memory and disk. + * + * \param global Whether to remove global or user credentials. + */ + void clearAll(bool global = false); + + /*! + * Helper function to find a matching AuthData instance in a CredentialSet + */ + static zypp::media::AuthData_Ptr findIn(const CredentialManager::CredentialSet & set, const zypp::Url & url, zypp::url::ViewOption vopt ); + + /*! + * Returns the timestamp of the database the given URL creds would be stored + */ + time_t timestampForCredDatabase ( const zypp::Url &url ); + + CredentialIterator credsGlobalBegin() const; + CredentialIterator credsGlobalEnd() const; + CredentialSize credsGlobalSize() const; + bool credsGlobalEmpty() const; + + CredentialIterator credsUserBegin() const; + CredentialIterator credsUserEnd() const; + CredentialSize credsUserSize() const; + bool credsUserEmpty() const; + + struct Impl; + private: + void init_globalCredentials(); + void init_userCredentials(); + + bool processCredentials(zypp::media::AuthData_Ptr & cred); + + zypp::media::AuthData_Ptr getCredFromUrl(const zypp::Url & url) const; + void saveGlobalCredentials(); + void saveUserCredentials(); + + zypp::media::CredManagerSettings _options; + + CredentialSet _credsGlobal; + CredentialSet _credsUser; + CredentialSet _credsTmp; + + bool _globalDirty; + bool _userDirty; + }; + } +} + + +#endif diff --git a/zypp-media/ng/lazymediahandle.h b/zypp-media/ng/lazymediahandle.h index 45897e018f..ab9777568f 100644 --- a/zypp-media/ng/lazymediahandle.h +++ b/zypp-media/ng/lazymediahandle.h @@ -15,6 +15,8 @@ namespace zyppng { + ZYPP_FWD_DECL_TYPE_WITH_REFS (MediaContext); + template < class ProvideType > class LazyMediaHandle { public: diff --git a/zypp-media/ng/mediacontext.cc b/zypp-media/ng/mediacontext.cc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/zypp/ng/private/context_p.h b/zypp-media/ng/mediacontext.h similarity index 50% rename from zypp/ng/private/context_p.h rename to zypp-media/ng/mediacontext.h index 811ababe1c..06c6d10ccc 100644 --- a/zypp/ng/private/context_p.h +++ b/zypp-media/ng/mediacontext.h @@ -6,27 +6,27 @@ | /_____||_| |_| |_| | | | \---------------------------------------------------------------------*/ -#ifndef ZYPP_NG_PRIVATE_CONTEXT_P_H -#define ZYPP_NG_PRIVATE_CONTEXT_P_H +#ifndef ZYPP_MEDIA_NG_MEDIACONTEXT_H_INCLUDED +#define ZYPP_MEDIA_NG_MEDIACONTEXT_H_INCLUDED -#include -#include -#include -#include -#include +#include -namespace zyppng -{ - ZYPP_FWD_DECL_TYPE_WITH_REFS ( EventDispatcher ); +namespace zypp { + class MediaConfig; +} + +namespace zyppng { - class ContextPrivate : public UserInterfacePrivate - { + ZYPP_FWD_DECL_TYPE_WITH_REFS( MediaContext ); + + class MediaContext : public UserInterface { public: - ContextPrivate ( Context &b ) : UserInterfacePrivate(b){} - EventDispatcherRef _eventDispatcher; - zypp::filesystem::TmpDir _providerDir; - ProvideRef _provider; - zypp::ZYpp::Ptr _zyppPtr; + virtual zypp::Pathname contextRoot() const = 0; + virtual zypp::MediaConfig &mediaConfig() = 0; + + static zypp::Pathname defaultConfigPath(){ + return "/etc/zypp/zypp.conf"; + } }; } diff --git a/zypp-media/ng/private/provide_p.h b/zypp-media/ng/private/provide_p.h index a97166c924..aa353cf25e 100644 --- a/zypp-media/ng/private/provide_p.h +++ b/zypp-media/ng/private/provide_p.h @@ -18,7 +18,7 @@ #include "providequeue_p.h" #include "attachedmediainfo_p.h" -#include +#include #include #include #include @@ -28,6 +28,8 @@ namespace zyppng { + ZYPP_FWD_DECL_TYPE_WITH_REFS ( InputRequest ); + namespace constants { constexpr std::string_view DEFAULT_PROVIDE_WORKER_PATH = ZYPP_WORKER_PATH; constexpr std::string_view ATTACHED_MEDIA_SUFFIX = "-media"; @@ -61,6 +63,11 @@ namespace zyppng { void queueItem ( ProvideItemRef item ); void dequeueItem ( ProvideItem *item ); + + using AuthRequestCb = std::function )>; + void authenticationRequired ( ProgressObserverRef pO, ProvideRequestRef item, zypp::Url effectiveUrl, std::string username, std::map extra, AuthRequestCb asyncReadyCb ); + void requestDestructing( ProvideRequest &req ); + std::string nextMediaId () const; AttachedMediaInfo_Ptr addMedium ( AttachedMediaInfo_Ptr &&medium ); @@ -83,7 +90,7 @@ namespace zyppng { std::list &items(); - zypp::media::CredManagerOptions &credManagerOptions (); + zypp::media::CredManagerSettings &credManagerOptions (); std::vector sanitizeUrls ( const std::vector &urls ); @@ -93,9 +100,6 @@ namespace zyppng { uint32_t nextRequestId(); - Signal< Provide::MediaChangeAction ( const std::string &, const std::string &, const int32_t, const std::vector &, const std::optional &) > _sigMediaChange; - Signal< std::optional ( const zypp::Url &reqUrl, const std::string &triedUsername, const std::map &extraValues ) > _sigAuthRequired; - protected: void doSchedule (Timer &); @@ -127,6 +131,19 @@ namespace zyppng { }; std::deque _queues; //< List of request queues for the workers, grouped by scheme. We use a deque and not a map because of possible changes to the list of queues during scheduling + struct AuthRequest { + zypp::Url _url; + std::string _username; + InputRequestRef _userRequest; + + struct Waiter { + ProvideRequest *_reqRef; // ProvideRequest will unregister all of its Auth events on destructions + AuthRequestCb _asyncReadyCb; + }; + std::vector _authWaiters; + }; + std::vector _authRequests; //< List of all Authentication requests, grouped by URL and username.. we try to coalesce the requests if possible + std::vector< AttachedMediaInfo_Ptr > _attachedMediaInfos; //< List of currently attached medias @@ -140,7 +157,7 @@ namespace zyppng { std::unordered_map< std::string, FileCacheItem > _fileCache; zypp::Pathname _workerPath; - zypp::media::CredManagerOptions _credManagerOptions; + zypp::media::CredManagerSettings _credManagerOptions; ProvideStatusRef _log; Signal _sigIdle; diff --git a/zypp-media/ng/private/provideitem_p.h b/zypp-media/ng/private/provideitem_p.h index ea1aec4adc..347328ac4c 100644 --- a/zypp-media/ng/private/provideitem_p.h +++ b/zypp-media/ng/private/provideitem_p.h @@ -38,7 +38,9 @@ namespace zyppng { friend class ProvideItem; - static expected create( ProvideItem &owner, const std::vector &urls, const std::string &id, ProvideMediaSpec &spec ); + virtual ~ProvideRequest(); + + static expected create ( ProvideItem &owner, const std::vector &urls, const std::string &id, ProvideMediaSpec &spec ); static expected create ( ProvideItem &owner, const std::vector &urls, ProvideFileSpec &spec ); static expected createDetach( const zypp::Url &url ); @@ -90,8 +92,9 @@ namespace zyppng { class ProvideItemPrivate : public BasePrivate { public: - ProvideItemPrivate( ProvidePrivate & parent, ProvideItem &pub ) : BasePrivate(pub), _parent(parent) {} + ProvideItemPrivate( ProvidePrivate & parent, ProvideItem &pub, ProgressObserverRef taskTracker ) : BasePrivate(pub), _parent(parent), _taskTracker( std::move(taskTracker) ) {} ProvidePrivate &_parent; + ProgressObserverRef _taskTracker; ProvideItem::State _itemState = ProvideItem::Uninitialized; std::chrono::steady_clock::time_point _itemStarted; std::chrono::steady_clock::time_point _itemFinished; @@ -131,7 +134,7 @@ namespace zyppng { { public: - static ProvideFileItemRef create ( const std::vector &urls,const ProvideFileSpec &request, ProvidePrivate &parent ); + static ProvideFileItemRef create ( const std::vector &urls,const ProvideFileSpec &request, ProvidePrivate &parent, zyppng::ProgressObserverRef &&taskTracker ); // ProvideItem interface void initialize () override; @@ -144,14 +147,14 @@ namespace zyppng { zypp::ByteCount bytesExpected () const override; protected: - ProvideFileItem ( const std::vector &urls,const ProvideFileSpec &request, ProvidePrivate &parent ); + ProvideFileItem ( const std::vector &urls,const ProvideFileSpec &request, ProvidePrivate &parent, zyppng::ProgressObserverRef &&taskTracker ); void informalMessage ( ProvideQueue &, ProvideRequestRef req, const ProvideMessage &msg ) override; using ProvideItem::finishReq; void finishReq ( ProvideQueue &queue, ProvideRequestRef finishedReq, const ProvideMessage &msg ) override; void cancelWithError ( std::exception_ptr error ) override; - expected authenticationRequired ( ProvideQueue &queue, ProvideRequestRef req, const zypp::Url &effectiveUrl, int64_t lastTimestamp, const std::map &extraFields ) override; + void authenticationRequired( ProvideQueue &queue, ProvideRequestRef req, const zypp::Url &effectiveUrl, int64_t lastTimestamp, const std::map &extraFields, AuthReadyCb readyCb ) override; private: Provide::MediaHandle _handleRef; //< If we are using a attached media, this will keep the reference around @@ -172,13 +175,13 @@ namespace zyppng { { public: ~AttachMediaItem(); - static AttachMediaItemRef create ( const std::vector &urls, const ProvideMediaSpec &request, ProvidePrivate &parent ); + static AttachMediaItemRef create ( const std::vector &urls, const ProvideMediaSpec &request, ProvidePrivate &parent, zyppng::ProgressObserverRef &&taskTracker ); SignalProxy< void( const zyppng::expected & ) > sigReady (); ProvidePromiseRef promise(); protected: - AttachMediaItem ( const std::vector &urls, const ProvideMediaSpec &request, ProvidePrivate &parent ); + AttachMediaItem ( const std::vector &urls, const ProvideMediaSpec &request, ProvidePrivate &parent, zyppng::ProgressObserverRef &&taskTracker ); // ProvideItem interface void initialize () override; @@ -187,8 +190,8 @@ namespace zyppng { void finishReq ( ProvideQueue &queue, ProvideRequestRef finishedReq, const ProvideMessage &msg ) override; void cancelWithError( std::exception_ptr error ) override; void finishWithSuccess (AttachedMediaInfo_Ptr medium ); - expected authenticationRequired ( ProvideQueue &queue, ProvideRequestRef req, const zypp::Url &effectiveUrl, int64_t lastTimestamp, const std::map &extraFields ) override; - + void authenticationRequired ( ProvideQueue &queue, ProvideRequestRef req, const zypp::Url &effectiveUrl, int64_t lastTimestamp, const std::map &extraFields, AuthReadyCb readyCb ) override; + void mediaChangeRequired ( const std::string &queueName, ProvideRequestRef req, const std::string &label, const int32_t mediaNr, const std::vector &freeDevs, const std::optional &desc, MediaChangeCb readyCb ) override; void onMasterItemReady ( const zyppng::expected& result ); private: @@ -200,6 +203,7 @@ namespace zyppng { ProvideQueue::Config::WorkerType _workerType = ProvideQueue::Config::Invalid; ProvidePromiseWeakRef _promise; MediaDataVerifierRef _verifier; + InputRequestRef _pendingMediaChangeRequest; }; } diff --git a/zypp-media/ng/private/providequeue_p.h b/zypp-media/ng/private/providequeue_p.h index 25fa1d043c..2a623f630c 100644 --- a/zypp-media/ng/private/providequeue_p.h +++ b/zypp-media/ng/private/providequeue_p.h @@ -101,6 +101,8 @@ namespace zyppng { SignalProxy sigIdle(); + void finishAuthRequest ( const uint32_t reqId, expected authData ); + private: bool doStartup (); void processMessage ( ); @@ -117,6 +119,7 @@ namespace zyppng { std::list< ProvideQueue::Item >::iterator dequeueActive ( std::list::iterator it ); void fatalWorkerError ( const std::exception_ptr &reason = nullptr ); void immediateShutdown ( const std::exception_ptr &reason ); + bool sendErrorToWorker(const uint32_t reqId, const MessageCodes code, const std::string &reason, bool transient = false); /*! * Cancels the item the iterator \a i is pointing to, advancing the iterator to the next element in the list diff --git a/zypp-media/ng/provide.cc b/zypp-media/ng/provide.cc index 72b9acd573..4d1793813b 100644 --- a/zypp-media/ng/provide.cc +++ b/zypp-media/ng/provide.cc @@ -9,6 +9,8 @@ #include #include #include +#include +#include // required to generate uuids #include @@ -18,6 +20,26 @@ L_ENV_CONSTR_DEFINE_FUNC(ZYPP_MEDIA_PROVIDER_DEBUG) namespace zyppng { + UserData ProvideAuthRequest::makeData(const zypp::Url &url, const std::string &username) + { + auto data = UserData( CTYPE.data() ); + data.set ( "url", url ); + data.set ( "username", username ); + return data; + } + + UserData ProvideMediaChangeRequest::makeData(const std::string &label, const int32_t mediaNr, const std::vector &freeDevs, const std::optional &desc) + { + auto data = UserData( CTYPE.data() ); + data.set( "label", label ); + data.set( "mediaNr", mediaNr ); + data.set( "freeDevs", freeDevs ); + if ( desc ) + data.set( "desc", *desc ); + return data; + } + + ProvidePrivate::ProvidePrivate(zypp::filesystem::Pathname &&workDir, Provide &pub) : BasePrivate(pub) , _workDir( std::move(workDir) ) @@ -701,7 +723,7 @@ namespace zyppng { return _items; } - zypp::media::CredManagerOptions &ProvidePrivate::credManagerOptions () + zypp::media::CredManagerSettings &ProvidePrivate::credManagerOptions() { return _credManagerOptions; } @@ -800,6 +822,87 @@ namespace zyppng { } } + void ProvidePrivate::authenticationRequired(ProgressObserverRef pO, ProvideRequestRef item, zypp::Url effectiveUrl, std::string username, std::map extra, AuthRequestCb asyncReadyCb) + { + auto elem = std::find_if( _authRequests.begin(), _authRequests.end(), [&]( const auto &i){ return (i->_url == effectiveUrl && i->_username == username ); } ); + if ( elem != _authRequests.end() ) { + MIL_PRV << "Found existing auth request for " << effectiveUrl << ":" << username << ", appending" << std::endl; + elem->_authWaiters.push_back( AuthRequest::Waiter{ ._reqRef = item.get(), ._asyncReadyCb = std::move(asyncReadyCb) } ); + } else { + MIL_PRV << "No existing auth request for " << effectiveUrl << ":" << username << ", creating a new one" << std::endl; + + auto &elem = _authRequests.emplace_back ( + AuthRequest{ + ._url = std::move(effectiveUrl), + ._username = std::move(username), + ._userRequest = InputRequest::create( "Please provide the password.", ProvideAuthRequest::makeData ( effectiveUrl, username ) ), + ._authWaiters = { AuthRequest::Waiter{ ._reqRef = item.get(), ._asyncReadyCb = std::move(asyncReadyCb) } } + } + ); + + // add the fields that we need + elem._userRequest->addField ( InputRequest::Text, "Username", elem._username ); + elem._userRequest->addField ( InputRequest::Password, "Password" ); + + elem._userRequest->connectFunc ( &InputRequest::sigFinished, [this, weakReq = InputRequestWeakRef(elem._userRequest), effectiveUrl ]( ){ + + auto i = std::find_if( _authRequests.begin(), _authRequests.end(), [&]( const auto &i){ return ( i->_userRequest == weakReq ); } ); + if ( i == _authRequests.end() ) { + MIL_PRV << "Invalid user auth request finished, this might be a bug!" << std::endl; + return; // request is deprecated or unknown + } + + // remove before we notify the queues, so there are not accidentially new + // requests appended while we handle them + auto elem = std::move(*i); + _authRequests.erase (i); + + if ( elem._userRequest->accepted () ) { + zypp::media::AuthData authData; + authData.setUrl ( effectiveUrl ); + authData.setUsername ( elem._userRequest->fields ()[0].value ); + authData.setPassword ( elem._userRequest->fields ()[1].value ); + + auto res = make_expected_success ( std::move(authData) ); + for ( auto &waiter : elem._authWaiters ) { + waiter._asyncReadyCb( res ); + } + + } else { + auto err = expected::error( ZYPP_EXCPT_PTR( zypp::media::MediaException("No auth given by user." ) ) ); + for ( auto &waiter : elem._authWaiters ) { + waiter._asyncReadyCb( err ); + } + } + }); + + // send the request to the user code to handle, async CB will be called as soon as its ready + pO->sendUserRequest ( elem._userRequest ); + } + } + + void ProvidePrivate::requestDestructing(ProvideRequest &req) + { + // make sure request is not in pending auth requests + for( auto authIter = _authRequests.begin (); authIter != _authRequests.end(); ) { + + for( auto i = authIter->_authWaiters.begin (); i != authIter->_authWaiters.end(); ) { + if ( i->_reqRef == &req ) { + i = authIter->_authWaiters.erase(i); + } else { + i++; + } + } + + if ( authIter->_authWaiters.empty () ) { + authIter = _authRequests.erase (authIter); + } else { + authIter++; + } + } + + } + std::string ProvidePrivate::nextMediaId() const { zypp::AutoDispose rawStr( g_uuid_string_random (), g_free ); @@ -987,6 +1090,13 @@ namespace zyppng { return _mediaRef->_localMountPoint; } + std::optional ProvideMediaHandle::spec() const + { + if ( !_mediaRef ) + return {}; + return _mediaRef->_spec; + } + AttachedMediaInfo_constPtr ProvideMediaHandle::mediaInfo() const { return _mediaRef; @@ -1001,7 +1111,11 @@ namespace zyppng { ProvideRef Provide::create( const zypp::filesystem::Pathname &workDir ) { - return ProvideRef( new Provide(workDir) ); + static ProvideWeakRef prov; + auto inst = prov.lock(); + if ( !inst ) + prov = inst = ProvideRef( new Provide(workDir) ); + return inst; } expected Provide::prepareMedia(const std::vector &urls, const ProvideMediaSpec &request) @@ -1020,7 +1134,7 @@ namespace zyppng { return prepareMedia( std::vector{url}, request ); } - AsyncOpRef > Provide::attachMediaIfNeeded( LazyMediaHandle lazyHandle) + AsyncOpRef > Provide::attachMediaIfNeeded( LazyMediaHandle lazyHandle, ProgressObserverRef tracker) { using namespace zyppng::operators; if ( lazyHandle.attached() ) @@ -1035,12 +1149,12 @@ namespace zyppng { }); } - AsyncOpRef> Provide::attachMedia( const zypp::Url &url, const ProvideMediaSpec &request ) + AsyncOpRef> Provide::attachMedia( const zypp::Url &url, const ProvideMediaSpec &request, ProgressObserverRef tracker ) { - return attachMedia ( std::vector{url}, request ); + return attachMedia ( std::vector{url}, request, std::move(tracker) ); } - AsyncOpRef> Provide::attachMedia( const std::vector &urls, const ProvideMediaSpec &request ) + AsyncOpRef> Provide::attachMedia( const std::vector &urls, const ProvideMediaSpec &request, ProgressObserverRef tracker ) { Z_D(); @@ -1058,25 +1172,26 @@ namespace zyppng { } } - auto op = AttachMediaItem::create( usableMirrs, request, *d_func() ); + auto op = AttachMediaItem::create( usableMirrs, request, *d_func(), std::move(tracker) ); d->queueItem (op); return op->promise(); } - AsyncOpRef< expected > Provide::provide( const std::vector &urls, const ProvideFileSpec &request ) + AsyncOpRef< expected > Provide::provide(zyppng::MediaContextRef ctx, const std::vector &urls, const ProvideFileSpec &request, ProgressObserverRef tracker ) { +#warning Implement context handling Z_D(); - auto op = ProvideFileItem::create( urls, request, *d ); + auto op = ProvideFileItem::create( urls, request, *d, std::move(tracker) ); d->queueItem (op); return op->promise(); } - AsyncOpRef< expected > Provide::provide( const zypp::Url &url, const ProvideFileSpec &request ) + AsyncOpRef< expected > Provide::provide(zyppng::MediaContextRef ctx, const zypp::Url &url, const ProvideFileSpec &request, ProgressObserverRef tracker ) { - return provide( std::vector{ url }, request ); + return provide( std::move(ctx), std::vector{ url }, request ); } - AsyncOpRef< expected > Provide::provide( const MediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request ) + AsyncOpRef< expected > Provide::provide( const MediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request, ProgressObserverRef tracker ) { Z_D(); const auto i = std::find( d->_attachedMediaInfos.begin(), d->_attachedMediaInfos.end(), attachHandle.mediaInfo() ); @@ -1098,14 +1213,14 @@ namespace zyppng { } url.appendPathName( fileName ); - auto op = ProvideFileItem::create( {url}, request, *d ); + auto op = ProvideFileItem::create( {url}, request, *d, std::move(tracker) ); op->setMediaRef( MediaHandle( *this, (*i) )); d->queueItem (op); return op->promise(); } - AsyncOpRef > Provide::provide( const LazyMediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request ) + AsyncOpRef > Provide::provide( const LazyMediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request, ProgressObserverRef tracker ) { using namespace zyppng::operators; return attachMediaIfNeeded ( attachHandle ) @@ -1117,13 +1232,13 @@ namespace zyppng { }); } - zyppng::AsyncOpRef > Provide::checksumForFile( const zypp::Pathname &p, const std::string &algorithm ) + zyppng::AsyncOpRef > Provide::checksumForFile( MediaContextRef ctx, const zypp::Pathname &p, const std::string &algorithm, ProgressObserverRef tracker ) { using namespace zyppng::operators; zypp::Url url("chksum:///"); url.setPathName( p ); - auto fut = provide( url, zyppng::ProvideFileSpec().setCustomHeaderValue( "chksumType", algorithm ) ) + auto fut = provide( std::move(ctx), url, zyppng::ProvideFileSpec().setCustomHeaderValue( "chksumType", algorithm ) ) | and_then( [algorithm]( zyppng::ProvideRes &&chksumRes ) { if ( chksumRes.headers().contains(algorithm) ) { try { @@ -1137,25 +1252,25 @@ namespace zyppng { return fut; } - AsyncOpRef> Provide::copyFile ( const zypp::Pathname &source, const zypp::Pathname &target ) + AsyncOpRef> Provide::copyFile ( MediaContextRef ctx, const zypp::Pathname &source, const zypp::Pathname &target, ProgressObserverRef tracker ) { using namespace zyppng::operators; zypp::Url url("copy:///"); url.setPathName( source ); - auto fut = provide( url, ProvideFileSpec().setDestFilenameHint( target )) + auto fut = provide( std::move(ctx), url, ProvideFileSpec().setDestFilenameHint( target )) | and_then( [&]( ProvideRes &©Res ) { return expected::success( copyRes.asManagedFile() ); } ); return fut; } - AsyncOpRef > Provide::copyFile( ProvideRes &&source, const zypp::filesystem::Pathname &target ) + AsyncOpRef > Provide::copyFile( zyppng::MediaContextRef ctx, ProvideRes &&source, const zypp::filesystem::Pathname &target, ProgressObserverRef tracker ) { using namespace zyppng::operators; auto fName = source.file(); - return copyFile( fName, target ) + return copyFile( std::move(ctx), fName, target ) | [ resSave = std::move(source) ] ( auto &&result ) { // callback lambda to keep the ProvideRes reference around until the op is finished, // if the op fails the callback will be cleaned up and so the reference @@ -1195,13 +1310,13 @@ namespace zyppng { return d_func()->_workDir; } - const zypp::media::CredManagerOptions &Provide::credManangerOptions () const + const zypp::media::CredManagerSettings &Provide::credManangerOptions () const { Z_D(); return d->_credManagerOptions; } - void Provide::setCredManagerOptions( const zypp::media::CredManagerOptions & opt ) + void Provide::setCredManagerOptions( const zypp::media::CredManagerSettings & opt ) { d_func()->_credManagerOptions = opt; } @@ -1211,16 +1326,6 @@ namespace zyppng { return d_func()->_sigIdle; } - SignalProxy &, const std::optional &)> Provide::sigMediaChangeRequested() - { - return d_func()->_sigMediaChange; - } - - SignalProxy< std::optional ( const zypp::Url &reqUrl, const std::string &triedUsername, const std::map &extraValues ) > Provide::sigAuthRequired() - { - return d_func()->_sigAuthRequired; - } - ZYPP_IMPL_PRIVATE(Provide); ProvideStatus::ProvideStatus( ProvideRef parent ) @@ -1318,4 +1423,5 @@ namespace zyppng { _stats._perSecond = zypp::ByteCount( diff / sinceStart.count() ); } } + } diff --git a/zypp-media/ng/provide.h b/zypp-media/ng/provide.h index d932bcaaab..18dae8f6fa 100644 --- a/zypp-media/ng/provide.h +++ b/zypp-media/ng/provide.h @@ -9,6 +9,7 @@ #ifndef ZYPP_MEDIA_PROVIDE_H_INCLUDED #define ZYPP_MEDIA_PROVIDE_H_INCLUDED +#include #include #include #include @@ -25,7 +26,7 @@ namespace zypp { class Url; namespace media { - struct CredManagerOptions; + struct CredManagerSettings; } } @@ -41,10 +42,44 @@ namespace zypp { */ namespace zyppng { + + /*! + * A media user request asking the user to provide authentication + * for a URL. + * + * RequestType: InputRequest + * Userdata fields: + * - "url" Url in question + * - "username" last Username given to zypp + */ + namespace ProvideAuthRequest { + constexpr std::string_view CTYPE ("media/auth-request"); + UserData makeData ( const zypp::Url &url, const std::string &username ); + } + + /*! + * A media user request asking the user to provide a different medium + * than the currently available ones. + * + * RequestType: InputRequest + * Userdata fields: + * - "label" Label of the required medium + * - "mediaNr" Media Nr of the required medium + * - "freeDevs" list of free devices the user can utilize to provide the medium + * - "desc" Media description (optional) + */ + namespace ProvideMediaChangeRequest { + constexpr std::string_view CTYPE ("media/media-change-request"); + UserData makeData( const std::string &label, const int32_t mediaNr, const std::vector &freeDevs, const std::optional &desc ); + } + + class ProvidePrivate; using AnyMap = std::unordered_map; DEFINE_PTR_TYPE(AttachedMediaInfo); + ZYPP_FWD_DECL_TYPE_WITH_REFS (ProgressObserver); + /*! * RAII helper for media handles */ @@ -61,6 +96,7 @@ namespace zyppng { std::string handle() const; const zypp::Url &baseUrl() const; const std::optional &localPath() const; + std::optional spec() const; zyppng::AttachedMediaInfo_constPtr mediaInfo() const; private: ProvideWeakRef _parent; @@ -130,26 +166,26 @@ namespace zyppng { expected prepareMedia ( const std::vector &urls, const ProvideMediaSpec &request ); expected prepareMedia ( const zypp::Url &url, const ProvideMediaSpec &request ); - AsyncOpRef> attachMediaIfNeeded( LazyMediaHandle lazyHandle ); - AsyncOpRef> attachMedia( const std::vector &urls, const ProvideMediaSpec &request ); - AsyncOpRef> attachMedia( const zypp::Url &url, const ProvideMediaSpec &request ); + AsyncOpRef> attachMediaIfNeeded( LazyMediaHandle lazyHandle, ProgressObserverRef tracker = nullptr ); + AsyncOpRef> attachMedia( const std::vector &urls, const ProvideMediaSpec &request, ProgressObserverRef tracker = nullptr ); + AsyncOpRef> attachMedia( const zypp::Url &url, const ProvideMediaSpec &request, ProgressObserverRef tracker = nullptr ); - AsyncOpRef> provide( const std::vector &urls, const ProvideFileSpec &request ); - AsyncOpRef> provide( const zypp::Url &url, const ProvideFileSpec &request ); - AsyncOpRef> provide( const MediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request ); - AsyncOpRef> provide( const LazyMediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request ); + AsyncOpRef> provide( MediaContextRef ctx, const std::vector &urls, const ProvideFileSpec &request, ProgressObserverRef tracker = nullptr ); + AsyncOpRef> provide( MediaContextRef ctx, const zypp::Url &url, const ProvideFileSpec &request, ProgressObserverRef tracker = nullptr ); + AsyncOpRef> provide( const MediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request, ProgressObserverRef tracker = nullptr ); + AsyncOpRef> provide( const LazyMediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request, ProgressObserverRef tracker = nullptr ); /*! * Schedules a job to calculate the checksum for the given file */ - AsyncOpRef> checksumForFile ( const zypp::Pathname &p, const std::string &algorithm ); + AsyncOpRef> checksumForFile ( MediaContextRef ctx, const zypp::Pathname &p, const std::string &algorithm, ProgressObserverRef tracker = nullptr ); /*! * Schedules a copy job to copy a file from \a source to \a target */ - AsyncOpRef> copyFile ( const zypp::Pathname &source, const zypp::Pathname &target ); - AsyncOpRef> copyFile ( ProvideRes &&source, const zypp::Pathname &target ); + AsyncOpRef> copyFile ( MediaContextRef ctx, const zypp::Pathname &source, const zypp::Pathname &target, ProgressObserverRef tracker = nullptr ); + AsyncOpRef> copyFile ( MediaContextRef ctx, ProvideRes &&source, const zypp::Pathname &target, ProgressObserverRef tracker = nullptr ); void start(); void setWorkerPath( const zypp::Pathname &path ); @@ -160,41 +196,18 @@ namespace zyppng { const zypp::Pathname &providerWorkdir () const; - const zypp::media::CredManagerOptions &credManangerOptions () const; - void setCredManagerOptions( const zypp::media::CredManagerOptions & opt ); + const zypp::media::CredManagerSettings &credManangerOptions () const; + void setCredManagerOptions(const zypp::media::CredManagerSettings &opt ); SignalProxy sigIdle(); - enum Action { - ABORT, // abort and return error - RETRY, // retry - SKIP // abort and set skip request - }; - using MediaChangeAction = std::optional; - - /*! - * Connect to this signal to handle media change requests - * - * \note It is NOT supported to shutdown the provider or cancel items when in this callback - * Returning Abort here will effectively cancel the current item anyway. - */ - SignalProxy &devices, const std::optional &desc )> sigMediaChangeRequested( ); - - /*! - * This signal is emitted in case a request signaled a need to get Auth Info and nothing was found - * in the \ref zypp::media::CredentialManager. - */ - SignalProxy< std::optional ( const zypp::Url &reqUrl, const std::string &triedUsername, const std::map &extraValues ) > sigAuthRequired(); - - - static auto copyResultToDest ( ProvideRef provider, const zypp::Pathname &targetPath ) { - return [ providerRef=std::move(provider), targetPath = targetPath ]( ProvideRes &&file ){ + static auto copyResultToDest ( ProvideRef provider, MediaContextRef ctx, zypp::Pathname targetPath, ProgressObserverRef tracker = nullptr ) { + return [ providerRef=std::move(provider), opContext = std::move(ctx), targetPath = std::move(targetPath), tracker = std::move(tracker) ]( ProvideRes &&file ) mutable { zypp::filesystem::assert_dir( targetPath.dirname () ); - return providerRef->copyFile( std::move(file), targetPath ); + return providerRef->copyFile( std::move(opContext), std::move(file), std::move(targetPath), std::move(tracker) ); }; } - private: Provide( const zypp::Pathname &workDir ); }; diff --git a/zypp-media/ng/provideitem.cc b/zypp-media/ng/provideitem.cc index 87afebc257..cab63cafe1 100644 --- a/zypp-media/ng/provideitem.cc +++ b/zypp-media/ng/provideitem.cc @@ -16,6 +16,8 @@ #include #include #include "mediaverifier.h" +#include "zypp-core/zyppng/ui/progressobserver.h" +#include #include using namespace std::literals; @@ -24,6 +26,13 @@ namespace zyppng { static constexpr std::string_view DEFAULT_MEDIA_VERIFIER("SuseMediaV1"); + ProvideRequest::~ProvideRequest() + { + if ( _owner ) { + _owner->provider().requestDestructing(*this); + } + } + expected ProvideRequest::create(ProvideItem &owner, const std::vector &urls, const std::string &id, ProvideMediaSpec &spec ) { if ( urls.empty() ) @@ -80,8 +89,8 @@ namespace zyppng { ZYPP_IMPL_PRIVATE(ProvideItem); - ProvideItem::ProvideItem( ProvidePrivate &parent ) - : Base( *new ProvideItemPrivate( parent, *this ) ) + ProvideItem::ProvideItem(ProvidePrivate &parent , ProgressObserverRef &&taskTracker) + : Base( *new ProvideItemPrivate( parent, *this, std::move(taskTracker) ) ) { } ProvideItem::~ProvideItem() @@ -156,6 +165,11 @@ namespace zyppng { return 0; } + ProgressObserverRef ProvideItem::taskTracker() const + { + return d_func()->_taskTracker; + } + ProvideItem::ItemStats ProvideItem::makeStats () { return ItemStats { @@ -396,23 +410,27 @@ namespace zyppng { cancelWithError(excpt); } - expected ProvideItem::authenticationRequired ( ProvideQueue &queue, ProvideRequestRef req, const zypp::Url &effectiveUrl, int64_t lastTimestamp, const std::map &extraFields ) + void ProvideItem::authenticationRequired(ProvideQueue &queue, ProvideRequestRef req, const zypp::Url &effectiveUrl, int64_t lastTimestamp, const std::map &extraFields , zyppng::ProvideItem::AuthReadyCb readyCb ) { + Z_D(); if ( req != _runningReq ) { WAR << "Received authenticationRequired for unknown request, rejecting" << std::endl; - return expected::error( ZYPP_EXCPT_PTR( zypp::media::MediaException("Unknown request in authenticationRequired, this is a bug.") ) ); + readyCb ( expected::error( ZYPP_EXCPT_PTR( zypp::media::MediaException("Unknown request in authenticationRequired, this is a bug.") ) ) ); + return; } try { - zypp::media::CredentialManager mgr ( provider().credManagerOptions() ); +#warning Use Context here + auto mgr = zyppng::media::CredentialManager::create( provider().credManagerOptions() ); MIL << "Looking for existing auth data for " << effectiveUrl << "more recent then " << lastTimestamp << std::endl; - auto credPtr = mgr.getCred( effectiveUrl ); + auto credPtr = mgr->getCred( effectiveUrl ); if ( credPtr && credPtr->lastDatabaseUpdate() > lastTimestamp ) { MIL << "Found existing auth data for " << effectiveUrl << "ts: " << credPtr->lastDatabaseUpdate() << std::endl; - return expected::success( *credPtr ); + readyCb ( expected::success( *credPtr ) ); + return; } if ( credPtr ) MIL << "Found existing auth data for " << effectiveUrl << "but too old ts: " << credPtr->lastDatabaseUpdate() << std::endl; @@ -422,29 +440,42 @@ namespace zyppng { username = i->second; } + if ( !d->_taskTracker ) { + MIL << "No ProgressObserver registered for request, no auth available" << std::endl; + readyCb ( expected::error( ZYPP_EXCPT_PTR( zypp::media::MediaException("No auth found.") ) ) ); + return; + } + MIL << "NO Auth data found, asking user. Last tried username was: " << username << std::endl; + provider().authenticationRequired ( d->_taskTracker, req, effectiveUrl, username, extraFields, [ mgr = std::move(mgr), effUrl = effectiveUrl, readyCb = std::move(readyCb) ]( expected userAuth){ - auto userAuth = provider()._sigAuthRequired.emit( effectiveUrl, username, extraFields ); - if ( !userAuth || !userAuth->valid() ) { - MIL << "User rejected to give auth" << std::endl; - return expected::error( ZYPP_EXCPT_PTR( zypp::media::MediaException("No auth given by user." ) ) ); - } + if ( !userAuth || !userAuth->valid() ) { + MIL << "User rejected to give auth" << std::endl; + readyCb( expected::error( ZYPP_EXCPT_PTR( zypp::media::MediaException("No auth given by user." ) ) ) ); + } + + mgr->addCred( *userAuth ); + mgr->save(); - mgr.addCred( *userAuth ); - mgr.save(); + // rather ugly, but update the timestamp to the last mtime of the cred database our URL belongs to + // otherwise we'd need to reload the cred database + userAuth->setLastDatabaseUpdate( mgr->timestampForCredDatabase( effUrl ) ); + readyCb( expected::success(*userAuth) ); - // rather ugly, but update the timestamp to the last mtime of the cred database our URL belongs to - // otherwise we'd need to reload the cred database - userAuth->setLastDatabaseUpdate( mgr.timestampForCredDatabase( effectiveUrl ) ); + }); - return expected::success(*userAuth); } catch ( const zypp::Exception &e ) { ZYPP_CAUGHT(e); - return expected::error( ZYPP_FWD_CURRENT_EXCPT() ); + readyCb ( expected::error( ZYPP_FWD_CURRENT_EXCPT() ) ); } } + void ProvideItem::mediaChangeRequired(const std::string &, zyppng::ProvideRequestRef, const std::string &, const int32_t, const std::vector &, const std::optional &, MediaChangeCb readyCb) + { + readyCb( {} ); + } + bool ProvideItem::enqueueRequest( ProvideRequestRef request ) { // base item just supports one running request at a time @@ -556,15 +587,15 @@ namespace zyppng { } } - ProvideFileItem::ProvideFileItem(const std::vector &urls, const ProvideFileSpec &request, ProvidePrivate &parent) - : ProvideItem( parent ) + ProvideFileItem::ProvideFileItem(const std::vector &urls, const ProvideFileSpec &request, ProvidePrivate &parent, ProgressObserverRef &&taskTracker) + : ProvideItem( parent, std::move(taskTracker) ) , _mirrorList ( urls ) , _initialSpec ( request ) { } - ProvideFileItemRef ProvideFileItem::create(const std::vector &urls, const ProvideFileSpec &request, ProvidePrivate &parent ) + ProvideFileItemRef ProvideFileItem::create(const std::vector &urls, const ProvideFileSpec &request, ProvidePrivate &parent , ProgressObserverRef &&taskTracker) { - return ProvideFileItemRef( new ProvideFileItem( urls, request, parent ) ); + return ProvideFileItemRef( new ProvideFileItem( urls, request, parent, std::move(taskTracker) ) ); } void ProvideFileItem::initialize() @@ -777,18 +808,20 @@ namespace zyppng { updateState( Finished ); } - expected ProvideFileItem::authenticationRequired ( ProvideQueue &queue, ProvideRequestRef req, const zypp::Url &effectiveUrl, int64_t lastTimestamp, const std::map &extraFields ) + void ProvideFileItem::authenticationRequired (ProvideQueue &queue, ProvideRequestRef req, const zypp::Url &effectiveUrl, int64_t lastTimestamp, const std::map &extraFields , AuthReadyCb readyCb) { zypp::Url urlToUse = effectiveUrl; if ( _handleRef.isValid() ) { // if we have a attached medium this overrules the URL we are going to ask the user about... this is how the old media backend did handle this // i guess there were never password protected repositories that have different credentials on the redirection targets auto &attachedMedia = provider().attachedMediaInfos(); - if ( std::find( attachedMedia.begin(), attachedMedia.end(), _handleRef.mediaInfo() ) == attachedMedia.end() ) - return expected::error( ZYPP_EXCPT_PTR( zypp::media::MediaException("Attachment handle vanished during request.") ) ); + if ( std::find( attachedMedia.begin(), attachedMedia.end(), _handleRef.mediaInfo() ) == attachedMedia.end() ) { + readyCb( expected::error( ZYPP_EXCPT_PTR( zypp::media::MediaException("Attachment handle vanished during request.") ) ) ); + return; + } urlToUse = _handleRef.mediaInfo()->_attachedUrl; } - return ProvideItem::authenticationRequired( queue, req, urlToUse, lastTimestamp, extraFields ); + ProvideItem::authenticationRequired( queue, req, urlToUse, lastTimestamp, extraFields, std::move(readyCb) ); } ProvideFileItem::ItemStats ProvideFileItem::makeStats () @@ -821,8 +854,8 @@ namespace zyppng { return (_initialSpec.checkExistsOnly() ? zypp::ByteCount(0) : _expectedBytes); } - AttachMediaItem::AttachMediaItem( const std::vector &urls, const ProvideMediaSpec &request, ProvidePrivate &parent ) - : ProvideItem ( parent ) + AttachMediaItem::AttachMediaItem(const std::vector &urls, const ProvideMediaSpec &request, ProvidePrivate &parent , ProgressObserverRef &&taskTracker) + : ProvideItem ( parent, std::move(taskTracker) ) , _mirrorList ( urls ) , _initialSpec ( request ) { } @@ -1102,9 +1135,9 @@ namespace zyppng { } } - AttachMediaItemRef AttachMediaItem::create( const std::vector &urls, const ProvideMediaSpec &request, ProvidePrivate &parent ) + AttachMediaItemRef AttachMediaItem::create(const std::vector &urls, const ProvideMediaSpec &request, ProvidePrivate &parent , ProgressObserverRef &&taskTracker) { - return AttachMediaItemRef( new AttachMediaItem(urls, request, parent) ); + return AttachMediaItemRef( new AttachMediaItem( urls, request, parent, std::move(taskTracker) ) ); } SignalProxy &)> AttachMediaItem::sigReady() @@ -1195,14 +1228,58 @@ namespace zyppng { return ProvideItem::finishReq ( queue, finishedReq, msg ); } - expected AttachMediaItem::authenticationRequired ( ProvideQueue &queue, ProvideRequestRef req, const zypp::Url &effectiveUrl, int64_t lastTimestamp, const std::map &extraFields ) + void AttachMediaItem::authenticationRequired(ProvideQueue &queue, ProvideRequestRef req, const zypp::Url &effectiveUrl, int64_t lastTimestamp, const std::map &extraFields , AuthReadyCb readyCb) { zypp::Url baseUrl = effectiveUrl; if( _workerType == ProvideQueue::Config::Downloading ) { // remove /media.n/media baseUrl.setPathName( zypp::Pathname(baseUrl.getPathName()).dirname().dirname() ); } - return ProvideItem::authenticationRequired( queue, req, baseUrl, lastTimestamp, extraFields ); + ProvideItem::authenticationRequired( queue, req, baseUrl, lastTimestamp, extraFields, std::move(readyCb) ); + } + + void AttachMediaItem::mediaChangeRequired(const std::string &queueName, ProvideRequestRef req, const std::string &label, const int32_t mediaNr, const std::vector &freeDevs, const std::optional &desc, MediaChangeCb readyCb) + { + if ( req != _runningReq ) { + WAR << "Received authenticationRequired for unknown request, rejecting" << std::endl; + readyCb ( Action::ABORT ); + return; + } + + if ( _pendingMediaChangeRequest ) { + WAR << "Pending request to the user does already exist, only one request per item is supported" << std::endl; + return; + } + + auto tracker = taskTracker(); + if ( !tracker ) { + readyCb( {} ); + return; + } + + _pendingMediaChangeRequest = InputRequest::create( + zypp::str::Format(_("Please insert medium [%s] #%d.")) % label % mediaNr, + ProvideMediaChangeRequest::makeData( label, mediaNr, freeDevs, desc ) + ); + + _pendingMediaChangeRequest->sigFinished ().connect( + [wtis = weak_this(), readyCb = std::move(readyCb)]() { + + bool accepted = false; + auto tis = wtis.lock(); + if ( tis ) { + accepted = tis->_pendingMediaChangeRequest->accepted (); + tis->_pendingMediaChangeRequest.reset(); + } + + if ( accepted ) { + readyCb( Action::RETRY ); + } else { + readyCb( Action::ABORT ); + } + } + ); + tracker->sendUserRequest ( _pendingMediaChangeRequest ); } } diff --git a/zypp-media/ng/provideitem.h b/zypp-media/ng/provideitem.h index c562206cdd..9d2cc11800 100644 --- a/zypp-media/ng/provideitem.h +++ b/zypp-media/ng/provideitem.h @@ -9,16 +9,23 @@ #ifndef ZYPP_MEDIA_PROVIDEITEM_H_INCLUDED #define ZYPP_MEDIA_PROVIDEITEM_H_INCLUDED +#include +#include #include #include #include #include +#include namespace zyppng { + class ProvideQueue; + class ProvideMessage; class ProvidePrivate; class ProvideItemPrivate; + ZYPP_FWD_DECL_TYPE_WITH_REFS ( ProgressObserver ); + /*! * Represents a operation added to the provide queue by the user code. A "user" operation can have multiple * steps of downloading and processing one or multiple files. Even though this class is in public API space it's @@ -49,7 +56,7 @@ namespace zyppng zypp::ByteCount _bytesExpected; }; - ProvideItem( ProvidePrivate &parent ); + ProvideItem(ProvidePrivate &parent, zyppng::ProgressObserverRef &&taskTracker ); ~ProvideItem (); /*! @@ -112,6 +119,8 @@ namespace zyppng */ virtual zypp::ByteCount bytesExpected () const; + ProgressObserverRef taskTracker() const; + protected: virtual ItemStats makeStats (); @@ -142,11 +151,31 @@ namespace zyppng */ virtual void finishReq ( ProvideQueue *queue, ProvideRequestRef finishedReq, const std::exception_ptr excpt ); + using AuthReadyCb = std::function )>; + /*! * Request needs authentication data, the function is supposed to return the AuthData to use for the response, or an error * The default implementation simply uses the given URL to look for a Auth match in the \ref zypp::media::CredentialManager. */ - virtual expected authenticationRequired ( ProvideQueue &queue, ProvideRequestRef req, const zypp::Url &effectiveUrl, int64_t lastTimestamp, const std::map &extraFields ); + virtual void authenticationRequired ( ProvideQueue &queue, ProvideRequestRef req, const zypp::Url &effectiveUrl, int64_t lastTimestamp, const std::map &extraFields, AuthReadyCb readyCb ); + + enum Action { + ABORT, // abort and return error + RETRY, // retry + SKIP // abort and set skip request + }; + using MediaChangeAction = std::optional; + + /*! + * Callback type for the async mediaChangeRequired func + */ + using MediaChangeCb = std::function; + + /*! + * Request needs a media change, the function is supposed to report back the action chosen by the user. + * Can be handled async, as long as the request is marked as ack() + */ + virtual void mediaChangeRequired ( const std::string &queueName, ProvideRequestRef req, const std::string &label, const int32_t mediaNr, const std::vector &freeDevs, const std::optional &desc, MediaChangeCb readyCb ); /*! * Remembers previous redirects and returns false if the URL was encountered before, use this @@ -183,8 +212,6 @@ namespace zyppng */ void updateState( const State newState ); - void setFinished (); - protected: ProvideRequestRef _runningReq; }; diff --git a/zypp-media/ng/providequeue.cc b/zypp-media/ng/providequeue.cc index 6b0ffd01eb..f41ce597e3 100644 --- a/zypp-media/ng/providequeue.cc +++ b/zypp-media/ng/providequeue.cc @@ -384,6 +384,17 @@ namespace zyppng { return true; } + bool ProvideQueue::sendErrorToWorker ( const uint32_t reqId, const MessageCodes code, const std::string &reason, bool transient ) { + auto r = ProvideMessage::createErrorResponse ( reqId, code, reason, transient ); + if ( !_messageStream->sendMessage( r ) ) { + ERR << "Failed to send Error message to worker process." << std::endl; + fatalWorkerError( ZYPP_EXCPT_PTR( zypp::media::MediaException("Failed to communicate with worker process.") ) ); + return false; + } + return true; + }; + + void ProvideQueue::processMessage() { const auto &getRequest = [&]( const auto &exp ) -> decltype(_activeItems)::iterator { @@ -406,16 +417,6 @@ namespace zyppng { return i; }; - const auto &sendErrorToWorker = [&]( const uint32_t reqId, const MessageCodes code, const std::string &reason, bool transient = false ) { - auto r = ProvideMessage::createErrorResponse ( reqId, code, reason, transient ); - if ( !_messageStream->sendMessage( r ) ) { - ERR << "Failed to send Error message to worker process." << std::endl; - fatalWorkerError( ZYPP_EXCPT_PTR( zypp::media::MediaException("Failed to communicate with worker process.") ) ); - return false; - } - return true; - }; - const bool doesDownload = this->_capabilities.worker_type() == Config::Downloading; const bool fileNeedsCleanup = doesDownload || ( _capabilities.worker_type() == Config::CPUBound && _capabilities.cfg_flags() & Config::FileArtifacts ); @@ -607,19 +608,9 @@ namespace zyppng { extraVals[hdr.first] = hdr.second.asString(); } - const auto &authOpt = reqRef->owner()->authenticationRequired( *this, reqRef, u, provMsg->value( AuthDataRequestMsgFields::LastAuthTimestamp ).asInt64(), extraVals ); - if ( !authOpt ) { - if ( !sendErrorToWorker( reqRef->provideMessage().requestId(), ProvideMessage::Code::NoAuthData, "No auth given by user." ) ) - return; - continue; - } + reqRef->owner()->authenticationRequired( *this, reqRef, u, provMsg->value( AuthDataRequestMsgFields::LastAuthTimestamp ).asInt64(), extraVals + ,[this, id = reqRef->provideMessage().requestId() ]( expected authData ){ finishAuthRequest( id, std::move(authData)); } ); - auto r = ProvideMessage::createAuthInfo ( reqRef->provideMessage().requestId(), authOpt->username(), authOpt->password(), authOpt->lastDatabaseUpdate(), authOpt->extraValues() ); - if ( !_messageStream->sendMessage( r ) ) { - ERR << "Failed to send AuthorizationInfo to worker process." << std::endl; - fatalWorkerError( ZYPP_EXCPT_PTR( zypp::media::MediaException("Failed to communicate with worker process.") ) ); - return; - } continue; } catch ( const zypp::Exception &e ) { @@ -657,39 +648,47 @@ namespace zyppng { if ( descVal.valid () && descVal.isString() ) desc = descVal.asString(); - auto res = _parent._sigMediaChange.emit( + req._request->owner()->mediaChangeRequired( _parent.queueName(*this), provMsg->value( MediaChangeRequestMsgFields::Label ).asString(), provMsg->value( MediaChangeRequestMsgFields::MediaNr ).asInt(), freeDevs, - desc - ); + desc, + [this, reqRef = ProvideRequestWeakRef(reqIter->_request)]( Provide::MediaChangeAction res ) { - auto action = res ? *res : Provide::Action::ABORT; - switch ( action ) { - case Provide::Action::RETRY: { - MIL << "Sending back a MediaChanged message, retrying to find medium " << std::endl; - auto r = ProvideMessage::createMediaChanged ( reqIter->_request->provideMessage().requestId() ); - if ( !_messageStream->sendMessage( r ) ){ - ERR << "Failed to send MediaChanged to worker process." << std::endl; - fatalWorkerError( ZYPP_EXCPT_PTR( zypp::media::MediaException("Failed to communicate with worker process.") ) ); + auto request = reqRef.lock(); + if ( !request ) { + MIL_PRV << "Ignoring response to media change, request is long gone!" << std::endl; return; } - continue; - } - case Provide::Action::ABORT: { - MIL << "Sending back a MediaChangeFailure message, request will fail " << std::endl; - if ( !sendErrorToWorker( reqRef->provideMessage().requestId(), ProvideMessage::Code::MediaChangeAbort, "Cancelled by User" ) ) - return; - continue; - } - case Provide::Action::SKIP: { - MIL << "Sending back a MediaChangeFailure message, request will fail " << std::endl; - if ( !sendErrorToWorker( reqRef->provideMessage().requestId(), ProvideMessage::Code::MediaChangeSkip, "Skipped by User" ) ) - return; - continue; + + auto action = res ? *res : Provide::Action::ABORT; + switch ( action ) { + case Provide::Action::RETRY: { + MIL << "Sending back a MediaChanged message, retrying to find medium " << std::endl; + auto r = ProvideMessage::createMediaChanged ( request->provideMessage().requestId() ); + if ( !_messageStream->sendMessage( r ) ){ + ERR << "Failed to send MediaChanged to worker process." << std::endl; + fatalWorkerError( ZYPP_EXCPT_PTR( zypp::media::MediaException("Failed to communicate with worker process.") ) ); + return; + } + return; + } + case Provide::Action::ABORT: { + MIL << "Sending back a MediaChangeFailure message, request will fail " << std::endl; + if ( !sendErrorToWorker( request->provideMessage().requestId(), ProvideMessage::Code::MediaChangeAbort, "Cancelled by User" ) ) + return; + return; + } + case Provide::Action::SKIP: { + MIL << "Sending back a MediaChangeFailure message, request will fail " << std::endl; + if ( !sendErrorToWorker( request->provideMessage().requestId(), ProvideMessage::Code::MediaChangeSkip, "Skipped by User" ) ) + return; + return; + } + } } - } + ); } else { // if there is a unsupported worker request we need to stop immediately because the worker will be blocked until it gets a answer ERR << "Unsupported worker request: "< authData ) + { + // only active items can have pending auth requests + auto i = std::find_if( _activeItems.begin(), _activeItems.end(), [&]( const auto &elem ) { + if ( ! elem._request ) + return false; + return reqId == elem._request->provideMessage().requestId(); + }); + + if ( i == _activeItems.end() ) { + ERR << "Ignoring unknown request ID: " << reqId << " maybe it was cancelled?" << std::endl; + return; + } + + if ( !authData ) { + if ( !sendErrorToWorker( reqId, ProvideMessage::Code::NoAuthData, "No auth given by user." ) ) + return; + } + + auto r = ProvideMessage::createAuthInfo ( reqId, authData->username(), authData->password(), authData->lastDatabaseUpdate(), authData->extraValues() ); + if ( !_messageStream->sendMessage( r ) ) { + ERR << "Failed to send AuthorizationInfo to worker process." << std::endl; + fatalWorkerError( ZYPP_EXCPT_PTR( zypp::media::MediaException("Failed to communicate with worker process.") ) ); + return; + } + } + /*! * Reads all of the log lines from stderr, call only when shutting down the queue * because this will also read partial lines and forwards them diff --git a/zypp-media/ng/providespec.cc b/zypp-media/ng/providespec.cc index 5e2805c322..8177e21571 100644 --- a/zypp-media/ng/providespec.cc +++ b/zypp-media/ng/providespec.cc @@ -13,6 +13,7 @@ #include #include #include "providespec.h" +#include using std::endl; @@ -37,12 +38,14 @@ namespace zyppng Impl() {} - Impl( std::string &&label, zypp::Pathname &&vPath, unsigned medianr ) - : _label(std::move( label )) + Impl( MediaContextRef &&ctx, std::string &&label, zypp::Pathname &&vPath, unsigned medianr ) + : _context(std::move(ctx)) + , _label(std::move( label )) , _medianr( medianr ) , _verifyDataPath(std::move(vPath)) {} + MediaContextRef _context; std::string _label; unsigned _medianr = 0U; zypp::Pathname _verifyDataPath; @@ -68,7 +71,7 @@ namespace zyppng bool _checkExistsOnly = false; bool _optional = false; - zypp::ByteCount _downloadSize = zypp::ByteCount( 20, zypp::ByteCount::MB ); + zypp::ByteCount _downloadSize; zypp::CheckSum _checksum; zypp::ByteCount _openSize; @@ -91,12 +94,24 @@ namespace zyppng }; - ProvideMediaSpec::ProvideMediaSpec( std::string label, zypp::filesystem::Pathname verifyData, unsigned medianr ) - : _pimpl( new Impl( std::move(label), std::move(verifyData), medianr ) ) + ProvideMediaSpec::ProvideMediaSpec( MediaContextRef ctx, std::string label, zypp::filesystem::Pathname verifyData, unsigned medianr ) + : _pimpl( new Impl( std::move(ctx), std::move(label), std::move(verifyData), medianr ) ) { } + MediaContextRef ProvideMediaSpec::mediaContext() const + { + return _pimpl->_context; + } + + void ProvideMediaSpec::setMediaContext(MediaContextRef ctx) + { + if ( !ctx ) + return; + _pimpl->_context = ctx; + } + const std::string &ProvideMediaSpec::label() const { return _pimpl->_label; } diff --git a/zypp-media/ng/providespec.h b/zypp-media/ng/providespec.h index 9bb12f22ed..daca34452c 100644 --- a/zypp-media/ng/providespec.h +++ b/zypp-media/ng/providespec.h @@ -25,11 +25,17 @@ namespace zyppng { + ZYPP_FWD_DECL_TYPE_WITH_REFS (MediaContext); + class ProvideMediaSpec { public: - ProvideMediaSpec(std::string label="", zypp::Pathname verifyData = zypp::Pathname(), unsigned medianr = 1 ); + ProvideMediaSpec( MediaContextRef ctx, std::string label="", zypp::Pathname verifyData = zypp::Pathname(), unsigned medianr = 1 ); + + + MediaContextRef mediaContext() const; + void setMediaContext( MediaContextRef ctx ); /*! * The label of the medium, this will be shown in case a media change is required @@ -132,10 +138,7 @@ namespace zyppng /** Set whether the resource is \ref optional. */ ProvideFileSpec & setOptional( bool val ); - /** The size of the resource on the server. - * \note If unset a default of at most 20MB is assumed. - * \ref setDownloadSize to zero for unlimited downloads. - */ + /** The size of the resource on the server. */ const zypp::ByteCount &downloadSize() const; /** Set the \ref downloadSize. */ ProvideFileSpec &setDownloadSize( const zypp::ByteCount &val_r ); diff --git a/zypp-media/ng/worker/provideworker.cc b/zypp-media/ng/worker/provideworker.cc index d5ccb90f4e..42b9933744 100644 --- a/zypp-media/ng/worker/provideworker.cc +++ b/zypp-media/ng/worker/provideworker.cc @@ -304,7 +304,7 @@ namespace zyppng::worker { _workerConf = std::move(conf); - auto &mediaConf = zypp::MediaConfig::instance(); + auto &mediaConf = zypp::MediaConfig::systemConfig(); for( const auto &[key,value] : _workerConf ) { zypp::Url keyUrl( key ); if ( keyUrl.getScheme() == "zconfig" && keyUrl.getAuthority() == "main" ) { diff --git a/zypp/CMakeLists.txt b/zypp/CMakeLists.txt index 9a5a1f71c8..5c5bdd9428 100644 --- a/zypp/CMakeLists.txt +++ b/zypp/CMakeLists.txt @@ -46,6 +46,7 @@ SET( zypp_SRCS IdString.cc InstanceId.cc KeyManager.cc + KeyContext.cc KeyRing.cc KeyRingContexts.cc Locks.cc @@ -70,6 +71,7 @@ SET( zypp_SRCS RepoManagerOptions.cc Repository.cc RepoStatus.cc + ResFilters.cc ResKind.cc ResObject.cc Resolvable.cc @@ -290,13 +292,25 @@ INSTALL( FILES ) SET( zypp_ng_SRCS - ng/context.cc + ng/contextbase.cc + ng/fusionpool.cc ng/progressobserveradaptor.cc + ng/repoinfo.cc ng/reporthelper.cc ng/repomanager.cc + ng/resource.cc + ng/serviceinfo.cc + ng/userdata.cc ng/userrequest.cc + ng/parser/RepoFileReader.cc + ng/parser/repoindexfilereader.cc + ng/parser/servicefilereader.cc ng/repo/downloader.cc - ng/repo/refresh.cc + ng/repo/pluginservices.cc + ng/repo/repoinfobase.cc + ng/repo/repoinfobaseshareddata.cc + ng/repo/repovariables.cc + ng/repo/repovariablescache.cc ng/repo/workflows/plaindir.cc ng/repo/workflows/repodownloaderwf.cc ng/repo/workflows/repomanagerwf.cc @@ -304,7 +318,6 @@ SET( zypp_ng_SRCS ng/repo/workflows/serviceswf.cc ng/repo/workflows/susetags.cc ng/workflows/checksumwf.cc - ng/workflows/contextfacade.cc ng/workflows/downloadwf.cc ng/workflows/keyringwf.cc ng/workflows/mediafacade.cc @@ -314,17 +327,36 @@ SET( zypp_ng_SRCS SET( zypp_ng_HEADERS ng/context.h + ng/context_fwd.h + ng/contextbase.h + ng/ContextBase + ng/fusionpool.h + ng/FusionPool ng/Context ng/progressobserveradaptor.h + ng/repoinfo.h + ng/repoinfoshareddata.h ng/reporthelper.h ng/repomanager.h + ng/resource.h + ng/serviceinfo.h + ng/serviceinfoshareddata.h ng/RepoManager + ng/userdata.h ng/userrequest.h ng/UserRequest + ng/parser/RepoFileReader.h + ng/parser/repoindexfilereader.h + ng/parser/servicefilereader.h ng/repo/downloader.h ng/repo/Downloader + ng/repo/pluginservices.h ng/repo/refresh.h ng/repo/Refresh + ng/repo/repoinfobase.h + ng/repo/repoinfobaseshareddata.h + ng/repo/repovariables.h + ng/repo/repovariablescache.h ng/repo/workflows/plaindir.h ng/repo/workflows/repodownloaderwf.h ng/repo/workflows/repomanagerwf.h @@ -332,7 +364,6 @@ SET( zypp_ng_HEADERS ng/repo/workflows/serviceswf.h ng/repo/workflows/susetags.h ng/workflows/checksumwf.h - ng/workflows/contextfacade.h ng/workflows/downloadwf.h ng/workflows/keyringwf.h ng/workflows/mediafacade.h @@ -342,8 +373,6 @@ SET( zypp_ng_HEADERS ) SET( zypp_ng_private_HEADERS - ng/private/context_p.h - ng/private/repomanager_p.h ) #INSTALL( FILES @@ -354,17 +383,11 @@ SET( zypp_ng_private_HEADERS SET( zypp_parser_SRCS parser/HistoryLogReader.cc - parser/RepoFileReader.cc - parser/RepoindexFileReader.cc - parser/ServiceFileReader.cc parser/ProductFileReader.cc ) SET( zypp_parser_HEADERS parser/HistoryLogReader.h - parser/RepoFileReader.h - parser/RepoindexFileReader.h - parser/ServiceFileReader.h parser/ProductFileReader.h ) @@ -650,12 +673,14 @@ INSTALL( FILES SET( zypp_zypp_detail_SRCS zypp_detail/ZYppImpl.cc + zypp_detail/ZyppLock.cc ) SET( zypp_zypp_detail_HEADERS zypp_detail/keyring_p.h zypp_detail/urlcredentialextractor_p.h zypp_detail/ZYppImpl.h + zypp_detail/ZyppLock.h zypp_detail/ZYppReadOnlyHack.h ) @@ -665,9 +690,11 @@ INSTALL( FILES ) SET( zypp_repo_SRCS + repo/GpgCheck.cc repo/RepoException.cc repo/RepoMirrorList.cc repo/RepoType.cc + repo/ServiceRepoState.cc repo/ServiceType.cc repo/PackageProvider.cc repo/SrcPackageProvider.cc @@ -680,26 +707,29 @@ SET( zypp_repo_SRCS repo/RepoVariables.cc repo/RepoInfoBase.cc repo/PluginRepoverification.cc - repo/PluginServices.cc ) SET( zypp_repo_HEADERS + repo/GpgCheck.h repo/RepoException.h - repo/RepoMirrorList.h repo/RepoType.h + repo/ServiceRepoState.h repo/ServiceType.h repo/PackageProvider.h repo/SrcPackageProvider.h repo/RepoProvideFile.h repo/DeltaCandidates.h + repo/RepoVariables.h + repo/RepoInfoBase.h + repo/PluginRepoverification.h +) + +SET( zypp_repo_detail_HEADERS + repo/RepoMirrorList.h repo/Applydeltarpm.h repo/PackageDelta.h repo/SUSEMediaVerifier.h repo/MediaInfoDownloader.h - repo/RepoVariables.h - repo/RepoInfoBase.h - repo/PluginRepoverification.h - repo/PluginServices.h ) INSTALL( FILES @@ -726,14 +756,12 @@ SET( zypp_repo_susetags_HEADERS SET( zypp_misc_HEADERS Misc.h - misc/DefaultLoadSystem.h misc/CheckAccessDeleted.h misc/TestcaseSetup.h misc/LoadTestcase.h ) SET( zypp_misc_SRCS - misc/DefaultLoadSystem.cc misc/CheckAccessDeleted.cc misc/TestcaseSetup.cc misc/LoadTestcase.cc @@ -837,6 +865,10 @@ SET ( zypp_media_compat_HEADERS media/CurlConfig.h ) +SET( zypp_media_compat_SOURCES + media/CredentialManager.cc +) + INSTALL( FILES ${zypp_media_compat_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/media @@ -886,6 +918,7 @@ ${zypp_parser_susetags_SRCS} ${zypp_parser_xml_SRCS} ${zypp_parser_yum_SRCS} ${zypp_parser_SRCS} +${zypp_media_compat_SOURCES} ${zypp_media_proxyinfo_SRCS} ${zypp_media_SRCS} ${zypp_ng_SRCS} @@ -929,6 +962,7 @@ ${zypp_url_HEADERS} ${zypp_HEADERS} ${zypp_zypp_detail_HEADERS} ${zypp_repo_HEADERS} +${zypp_repo_detail_HEADERS} ${zypp_source_susetags_HEADERS} ${zypp_target_modalias_HEADERS} ${zypp_target_HEADERS} @@ -1043,20 +1077,6 @@ INSTALL(TARGETS zypp LIBRARY DESTINATION ${LIB_INSTALL_DIR} ) # library with more symbols for tests etc add_zypp_lib( zypp-allsym STATIC ) -#this part does nothing yet, only when switching away from using a map file to -#a approach where symbols are exported explicitly it would make a difference -#ZYPPNG symbols need to be added to the map file to be exported -IF( EXPORT_NG_API ) -ADD_DEFINITIONS(-DEXPORT_EXPERIMENTAL_API) -INCLUDE(GenerateExportHeader) -message("Exporting experimental libzypp-ng API") -GENERATE_EXPORT_HEADER( - zypp - BASE_NAME zypp-ng - PREFIX_NAME LIB -) -ENDIF ( EXPORT_NG_API ) - # install XML schemas FILE( GLOB YUM_SCHEMA_FILES ${LIBZYPP_SOURCE_DIR}/zypp/parser/yum/schema/*.rng ) INSTALL(FILES ${YUM_SCHEMA_FILES} DESTINATION "${CMAKE_INSTALL_PREFIX}/share/zypp/schema/yum" ) diff --git a/zypp/FileChecker.cc b/zypp/FileChecker.cc index c73351bf66..9e2dbed214 100644 --- a/zypp/FileChecker.cc +++ b/zypp/FileChecker.cc @@ -11,11 +11,13 @@ */ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -35,7 +37,7 @@ namespace zypp void ChecksumFileChecker::operator()( const Pathname &file ) const { - const auto &res = zyppng::CheckSumWorkflow::verifyChecksum ( zyppng::SyncContext::create(), _checksum, file ); + const auto &res = zyppng::CheckSumWorkflow::verifyChecksum ( zypp_detail::GlobalStateHelper::context(), zypp_detail::GlobalStateHelper::context()->progressObserver(), _checksum, file ); if ( !res ) { std::rethrow_exception( res.error ( ) ); } @@ -86,7 +88,7 @@ namespace zypp SignatureFileChecker & self { const_cast(*this) }; self._verifyContext.file( file_r ); - auto res = zyppng::SignatureFileCheckWorkflow::verifySignature ( zyppng::SyncContext::create(), keyring::VerifyFileContext(_verifyContext) ); + auto res = zyppng::SignatureFileCheckWorkflow::verifySignature ( zypp_detail::GlobalStateHelper::context(), zypp_detail::GlobalStateHelper::context()->progressObserver(), keyring::VerifyFileContext(_verifyContext) ); if ( !res ) { std::rethrow_exception( res.error ( ) ); } diff --git a/zypp/HistoryLog.cc b/zypp/HistoryLog.cc index a1a5444a40..a35360cba8 100644 --- a/zypp/HistoryLog.cc +++ b/zypp/HistoryLog.cc @@ -21,12 +21,13 @@ #include #include -#include +#include #include #include #include #include +#include using std::endl; using std::string; @@ -111,7 +112,7 @@ namespace zypp inline void openLog() { if ( _fname.empty() ) - _fname = ZConfig::instance().historyLogFile(); + _fname = ZConfig::systemConfig().historyLogFile(); _log.clear(); _log.open( _fname.asString().c_str(), std::ios::out|std::ios::app ); @@ -168,7 +169,7 @@ namespace zypp if ( _refcnt ) closeLog(); - _fname = ZConfig::instance().historyLogFile(); + _fname = ZConfig::systemConfig().historyLogFile(); if ( _fname != "/dev/null" ) // no need to redirect /dev/null into the target _fname = rootdir / _fname; filesystem::assert_dir( _fname.dirname() ); @@ -181,7 +182,7 @@ namespace zypp const Pathname & HistoryLog::fname() { if ( _fname.empty() ) - _fname = ZConfig::instance().historyLogFile(); + _fname = ZConfig::systemConfig().historyLogFile(); return _fname; } @@ -226,7 +227,7 @@ namespace zypp << _sep << HistoryActionID::STAMP_COMMAND.asString(true) // 2 action << _sep << userAtHostname() // 3 requested by << _sep << cmdline() // 4 command - << _sep << str::escape(ZConfig::instance().userData(), _sep) // 6 userdata + << _sep << str::escape(zyppng::UserData::data(), _sep) // 6 userdata << endl; } @@ -252,9 +253,9 @@ namespace zypp _log << _sep; _log - << _sep << p->repoInfo().alias() // 7 repo alias + << _sep << (p->ngRepoInfo().has_value () ? p->ngRepoInfo()->alias() : std::string()) // 7 repo alias << _sep << p->checksum().checksum() // 8 checksum - << _sep << str::escape(ZConfig::instance().userData(), _sep) // 9 userdata + << _sep << str::escape(zyppng::UserData::data(), _sep) // 9 userdata << endl; } @@ -280,37 +281,37 @@ namespace zypp _log << _sep; _log - << _sep << str::escape(ZConfig::instance().userData(), _sep) // 7 userdata + << _sep << str::escape(zyppng::UserData::data(), _sep) // 7 userdata << endl; } ///////////////////////////////////////////////////////////////////////// - void HistoryLog::addRepository(const RepoInfo & repo) + void HistoryLog::addRepository(const zyppng::RepoInfo & repo) { _log << timestamp() // 1 timestamp << _sep << HistoryActionID::REPO_ADD.asString(true) // 2 action << _sep << str::escape(repo.alias(), _sep) // 3 alias << _sep << str::escape(repo.url().asString(), _sep) // 4 primary URL - << _sep << str::escape(ZConfig::instance().userData(), _sep) // 5 userdata + << _sep << str::escape(zyppng::UserData::data(), _sep) // 5 userdata << endl; } - void HistoryLog::removeRepository(const RepoInfo & repo) + void HistoryLog::removeRepository(const zyppng::RepoInfo & repo) { _log << timestamp() // 1 timestamp << _sep << HistoryActionID::REPO_REMOVE.asString(true) // 2 action << _sep << str::escape(repo.alias(), _sep) // 3 alias - << _sep << str::escape(ZConfig::instance().userData(), _sep) // 4 userdata + << _sep << str::escape(zyppng::UserData::data(), _sep) // 4 userdata << endl; } void HistoryLog::modifyRepository( - const RepoInfo & oldrepo, const RepoInfo & newrepo) + const zyppng::RepoInfo & oldrepo, const zyppng::RepoInfo & newrepo) { if (oldrepo.alias() != newrepo.alias()) { @@ -319,7 +320,7 @@ namespace zypp << _sep << HistoryActionID::REPO_CHANGE_ALIAS.asString(true) // 2 action << _sep << str::escape(oldrepo.alias(), _sep) // 3 old alias << _sep << str::escape(newrepo.alias(), _sep) // 4 new alias - << _sep << str::escape(ZConfig::instance().userData(), _sep) // 5 userdata + << _sep << str::escape(zyppng::UserData::data(), _sep) // 5 userdata << endl; } if ( oldrepo.url() != newrepo.url() ) @@ -329,7 +330,7 @@ namespace zypp << _sep << HistoryActionID::REPO_CHANGE_URL.asString(true) // 2 action << _sep << str::escape(oldrepo.url().asString(), _sep) // 3 old url << _sep << str::escape(newrepo.url().asString(), _sep) // 4 new url - << _sep << str::escape(ZConfig::instance().userData(), _sep) // 5 userdata + << _sep << str::escape(zyppng::UserData::data(), _sep) // 5 userdata << endl; } } @@ -345,12 +346,12 @@ namespace zypp << _sep << p->name() // 3 name << _sep << p->edition() // 4 evr << _sep << p->arch() // 5 arch - << _sep << p->repoInfo().alias() // 6 repo alias + << _sep << (p->ngRepoInfo().has_value () ? p->ngRepoInfo()->alias() : std::string()) // 6 repo alias << _sep << p->severity() // 7 severity << _sep << p->category() // 8 category << _sep << ResStatus::validateValueAsString( oldstate ) // 9 old state << _sep << pi.status().validateValueAsString() // 10 new state - << _sep << str::escape(ZConfig::instance().userData(), _sep) // 11 userdata + << _sep << str::escape(zyppng::UserData::data(), _sep) // 11 userdata << endl; } diff --git a/zypp/HistoryLog.h b/zypp/HistoryLog.h index 96c9a7f354..c57ed164fd 100644 --- a/zypp/HistoryLog.h +++ b/zypp/HistoryLog.h @@ -17,10 +17,13 @@ #include #include +namespace zyppng { + class RepoInfo; +} + namespace zypp { class PoolItem; - class RepoInfo; /////////////////////////////////////////////////////////////////// /// \class HistoryLog @@ -107,14 +110,14 @@ namespace zypp * * \param repo info about the added repository */ - void addRepository( const RepoInfo & repo ); + void addRepository( const zyppng::RepoInfo & repo ); /** * Log recently removed repository. * * \param repo info about the removed repository */ - void removeRepository( const RepoInfo & repo ); + void removeRepository( const zyppng::RepoInfo & repo ); /** * Log certain modifications to a repository. @@ -122,7 +125,7 @@ namespace zypp * \param oldrepo info about the old repository * \param newrepo info about the new repository */ - void modifyRepository( const RepoInfo & oldrepo, const RepoInfo & newrepo ); + void modifyRepository( const zyppng::RepoInfo & oldrepo, const zyppng::RepoInfo & newrepo ); /** * Log state changes in patches diff --git a/zypp/KeyContext.cc b/zypp/KeyContext.cc new file mode 100644 index 0000000000..6dec3e37a2 --- /dev/null +++ b/zypp/KeyContext.cc @@ -0,0 +1,62 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "KeyContext.h" + +#include +#include + +namespace zypp { + + class KeyContext::Impl { + + public: + Impl(){} + Impl( zyppng::RepoInfo ri ) : _repoInfo( std::move(ri) ) {} + + std::optional _repoInfo; + + private: + friend KeyContext::Impl * zypp::rwcowClone( const KeyContext::Impl * rhs ); + Impl * clone() const { return new Impl( *this ); } + }; + + ZYPP_BEGIN_LEGACY_API + KeyContext::KeyContext(const RepoInfo &repoinfo) : KeyContext( repoinfo.ngRepoInfo() ) + { } + + const RepoInfo KeyContext::repoInfo() const + { + if ( _pimpl->_repoInfo ) { + return RepoInfo( *_pimpl->_repoInfo ); + } + return RepoInfo(); + } + ZYPP_END_LEGACY_API + + void KeyContext::setRepoInfo(const RepoInfo &repoinfo) + { + _pimpl->_repoInfo = repoinfo.ngRepoInfo(); + } + + KeyContext::KeyContext() : _pimpl(new Impl()) {} + KeyContext::KeyContext(const zyppng::RepoInfo &repoinfo) + : _pimpl( new Impl(repoinfo) ) + { } + + bool KeyContext::empty() const { + return (!_pimpl->_repoInfo.has_value()) || _pimpl->_repoInfo->alias().empty(); + } + void KeyContext::setRepoInfo( const zyppng::RepoInfo &repoinfo ) + { + _pimpl->_repoInfo = repoinfo; + } + const std::optional &KeyContext::ngRepoInfo() const { + return _pimpl->_repoInfo; + } +} // namespace zypp diff --git a/zypp/KeyContext.h b/zypp/KeyContext.h index 2768a7dc0b..4360e1501b 100644 --- a/zypp/KeyContext.h +++ b/zypp/KeyContext.h @@ -1,25 +1,57 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/KeyManager.h + * +*/ #ifndef KEYCONTEXT_H_ #define KEYCONTEXT_H_ -#include +#include +#include +#include + +namespace zyppng { + class RepoInfo; +} namespace zypp { - struct KeyContext + class RepoInfo; + + struct ZYPP_API KeyContext { + class Impl; public: - KeyContext(){} - KeyContext( const RepoInfo & repoinfo ) : _repoInfo( repoinfo ) {} + KeyContext(); + KeyContext(const zyppng::RepoInfo &repoinfo); + KeyContext(const KeyContext &) = default; + KeyContext(KeyContext &&) = default; + KeyContext &operator=(const KeyContext &) = default; + KeyContext &operator=(KeyContext &&) = default; + ~KeyContext() = default; /** Is the context unknown? */ - bool empty() const { return _repoInfo.alias().empty(); } + bool empty() const; public: - const RepoInfo repoInfo() const { return _repoInfo; } - void setRepoInfo(const RepoInfo & repoinfo) { _repoInfo = repoinfo; } - +#ifdef __cpp_lib_optional // YAST/PK explicitly use c++11 until 15-SP3 + const std::optional &ngRepoInfo() const; +#endif + void setRepoInfo(const zyppng::RepoInfo &repoinfo); + + ZYPP_BEGIN_LEGACY_API + KeyContext(const RepoInfo &repoinfo) ZYPP_INTERNAL_DEPRECATE; + const RepoInfo repoInfo() const ZYPP_INTERNAL_DEPRECATE; + void setRepoInfo(const RepoInfo &repoinfo) ZYPP_INTERNAL_DEPRECATE; + ZYPP_END_LEGACY_API private: - RepoInfo _repoInfo; + zypp::RWCOW_pointer _pimpl; }; } diff --git a/zypp/KeyRing.cc b/zypp/KeyRing.cc index 6080746715..2c0a5cd0e2 100644 --- a/zypp/KeyRing.cc +++ b/zypp/KeyRing.cc @@ -128,7 +128,7 @@ namespace zypp // frankly: don't remember why an explicit setDirty was introduced and // why WatchFile was not enough. Maybe some corner case when the keyrings // are created? - _cache.setDirty( _keyring ); + _cache.get().setDirty( _keyring ); return _context.value(); } diff --git a/zypp/MediaSetAccess.cc b/zypp/MediaSetAccess.cc index b4295e9e64..b157365fa2 100644 --- a/zypp/MediaSetAccess.cc +++ b/zypp/MediaSetAccess.cc @@ -19,6 +19,7 @@ #include #include #include +#include //#include #undef ZYPP_BASE_LOGGER_LOGGROUP @@ -34,16 +35,30 @@ IMPL_PTR_TYPE(MediaSetAccess); /////////////////////////////////////////////////////////////////// - MediaSetAccess::MediaSetAccess(Url url, - Pathname prefered_attach_point) - : _url(std::move(url)) - , _prefAttachPoint(std::move(prefered_attach_point)) + MediaSetAccess::MediaSetAccess(Url url, Pathname prefered_attach_point) + : MediaSetAccess( zypp_detail::GlobalStateHelper::context(), std::move(url), std::move(prefered_attach_point) ) {} MediaSetAccess::MediaSetAccess(std::string label_r, Url url, Pathname prefered_attach_point) - : _url(std::move(url)) + : MediaSetAccess( zypp_detail::GlobalStateHelper::context(), std::move(label_r), std::move(url), std::move(prefered_attach_point) ) + {} + + MediaSetAccess::MediaSetAccess(zyppng::ContextBaseRef ctx, + Url url, + Pathname prefered_attach_point) + : _zyppContext( std::move(ctx) ) + , _url(std::move(url)) + , _prefAttachPoint(std::move(prefered_attach_point)) + {} + + MediaSetAccess::MediaSetAccess( zyppng::ContextBaseRef ctx, + std::string label_r, + Url url, + Pathname prefered_attach_point) + : _zyppContext( std::move(ctx) ) + , _url(std::move(url)) , _prefAttachPoint(std::move(prefered_attach_point)) , _label(std::move( label_r )) {} @@ -192,13 +207,13 @@ IMPL_PTR_TYPE(MediaSetAccess); return Pathname(); } - ManagedFile MediaSetAccess::provideFileFromUrl(const Url &file_url, ProvideFileOptions options) + ManagedFile MediaSetAccess::provideFileFromUrl( zyppng::ContextBaseRef ctx, const Url &file_url, ProvideFileOptions options ) { Url url(file_url); Pathname path(url.getPathName()); url.setPathName ("/"); - MediaSetAccess access(url); + MediaSetAccess access(ctx, url); ManagedFile tmpFile = filesystem::TmpFile::asManagedFile(); @@ -212,11 +227,16 @@ IMPL_PTR_TYPE(MediaSetAccess); return tmpFile; } - ManagedFile MediaSetAccess::provideOptionalFileFromUrl( const Url & file_url ) + ManagedFile MediaSetAccess::provideFileFromUrl(const Url &file_url, ProvideFileOptions options) + { + return provideFileFromUrl( zypp_detail::GlobalStateHelper::context(), file_url, options ); + } + + ManagedFile MediaSetAccess::provideOptionalFileFromUrl( zyppng::ContextBaseRef ctx, const Url & file_url ) { try { - return provideFileFromUrl( file_url, PROVIDE_NON_INTERACTIVE ); + return provideFileFromUrl( ctx, file_url, PROVIDE_NON_INTERACTIVE ); } catch ( const media::MediaFileNotFoundException & excpt_r ) { ZYPP_CAUGHT( excpt_r ); } @@ -225,6 +245,11 @@ IMPL_PTR_TYPE(MediaSetAccess); return ManagedFile(); } + ManagedFile MediaSetAccess::provideOptionalFileFromUrl( const Url & file_url ) + { + return provideOptionalFileFromUrl( zypp_detail::GlobalStateHelper::context(), file_url ); + } + bool MediaSetAccess::doesFileExist(const Pathname & file, unsigned media_nr ) { ProvideFileExistenceOperation op; @@ -413,7 +438,7 @@ IMPL_PTR_TYPE(MediaSetAccess); Url url( medianr > 1 ? rewriteUrl( _url, medianr ) : _url ); media::MediaManager media_mgr; - media::MediaAccessId id = media_mgr.open( url, _prefAttachPoint ); + media::MediaAccessId id = media_mgr.open( _zyppContext, url, _prefAttachPoint ); _medias[medianr] = id; try diff --git a/zypp/MediaSetAccess.h b/zypp/MediaSetAccess.h index 3146296c2c..d1001413e2 100644 --- a/zypp/MediaSetAccess.h +++ b/zypp/MediaSetAccess.h @@ -25,6 +25,10 @@ #include #include +namespace zyppng { + ZYPP_FWD_DECL_TYPE_WITH_REFS(ContextBase); +} + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -89,9 +93,23 @@ namespace zypp * \param prefered_attach_point Prefered attach (mount) point. Use, if * you want to mount the media to a specific directory. */ - MediaSetAccess( Url url, Pathname prefered_attach_point = "" ); + MediaSetAccess( Url url, Pathname prefered_attach_point = "" ) ZYPP_INTERNAL_DEPRECATE; /** \overload Also taking a \ref label. */ - MediaSetAccess( std::string label_r, Url url, Pathname prefered_attach_point = "" ); + MediaSetAccess( std::string label_r, Url url, Pathname prefered_attach_point = "" ) ZYPP_INTERNAL_DEPRECATE; + + + /** + * Creates a callback enabled media access for specified \a url. + * + * \param url + * \param prefered_attach_point Prefered attach (mount) point. Use, if + * you want to mount the media to a specific directory. + */ + MediaSetAccess( zyppng::ContextBaseRef ctx, Url url, Pathname prefered_attach_point = "" ); + /** \overload Also taking a \ref label. */ + MediaSetAccess( zyppng::ContextBaseRef ctx, std::string label_r, Url url, Pathname prefered_attach_point = "" ); + + ~MediaSetAccess() override; /** @@ -215,7 +233,8 @@ namespace zypp * with the next one, if possible. * \see zypp::media::MediaManager::provideFile() */ - static ManagedFile provideFileFromUrl( const Url & file_url, ProvideFileOptions options = PROVIDE_DEFAULT ); + static ManagedFile provideFileFromUrl( const Url & file_url, ProvideFileOptions options = PROVIDE_DEFAULT ) ZYPP_INTERNAL_DEPRECATE; + static ManagedFile provideFileFromUrl( zyppng::ContextBaseRef ctx, const Url & file_url, ProvideFileOptions options = PROVIDE_DEFAULT ); /** * Provides an optional \a file from \a url. @@ -224,7 +243,8 @@ namespace zypp * rather than throwing a \ref MediaException if the file is not present on * the media. */ - static ManagedFile provideOptionalFileFromUrl( const Url & file_url ); + static ManagedFile provideOptionalFileFromUrl( const Url & file_url ) ZYPP_INTERNAL_DEPRECATE; + static ManagedFile provideOptionalFileFromUrl( zyppng::ContextBaseRef ctx, const Url & file_url ); /** * Release file from media. @@ -364,6 +384,7 @@ namespace zypp std::ostream & dumpOn( std::ostream & str ) const override; private: + zyppng::ContextBaseRef _zyppContext; /** Media or media set URL */ Url _url; diff --git a/zypp/Misc.h b/zypp/Misc.h index bf09a4a3a1..f90e196092 100644 --- a/zypp/Misc.h +++ b/zypp/Misc.h @@ -12,7 +12,6 @@ #ifndef ZYPP_MISC_H #define ZYPP_MISC_H -#include #include #endif // ZYPP_MISC_H diff --git a/zypp/Package.cc b/zypp/Package.cc index c711610da4..ab3c1150a0 100644 --- a/zypp/Package.cc +++ b/zypp/Package.cc @@ -22,6 +22,8 @@ #include #include +#include + /////////////////////////////////////////////////////////////////// namespace zyppintern { @@ -96,7 +98,7 @@ namespace zyppintern } // here and from SrcPackage.cc - Pathname cachedLocation( const OnMediaLocation & loc_r, const RepoInfo & repo_r ) + Pathname cachedLocation( const OnMediaLocation & loc_r, const zyppng::RepoInfo & repo_r ) { PathInfo pi( repo_r.packagesPath() / repo_r.path() / loc_r.filename() ); @@ -277,7 +279,12 @@ namespace zypp { return lookupLocation(); } Pathname Package::cachedLocation() const - { return zyppintern::cachedLocation( location(), repoInfo() ); } + { + const auto &optRepoInfo = ngRepoInfo (); + if ( !optRepoInfo ) + return Pathname(); + return zyppintern::cachedLocation( location(), *optRepoInfo ); + } std::string Package::sourcePkgName() const { diff --git a/zypp/PluginExecutor.cc b/zypp/PluginExecutor.cc index 826a915cf5..792c691f11 100644 --- a/zypp/PluginExecutor.cc +++ b/zypp/PluginExecutor.cc @@ -16,6 +16,8 @@ #include #include +#include + using std::endl; #undef ZYPP_BASE_LOGGER_LOGGROUP @@ -111,8 +113,8 @@ namespace zypp plugin.open(); PluginFrame frame( "PLUGINBEGIN" ); - if ( ZConfig::instance().hasUserData() ) - frame.setHeader( "userdata", ZConfig::instance().userData() ); + if ( zyppng::UserData::hasData() ) + frame.setHeader( "userdata", zyppng::UserData::data() ); doSend( plugin, frame ); // closes on error if ( plugin.isOpen() ) diff --git a/zypp/PurgeKernels.cc b/zypp/PurgeKernels.cc index bb7d16a848..6d85900a3d 100644 --- a/zypp/PurgeKernels.cc +++ b/zypp/PurgeKernels.cc @@ -22,12 +22,10 @@ #include #include -#include #include #include #include #include -#include #include #undef ZYPP_BASE_LOGGER_LOGGROUP @@ -132,7 +130,7 @@ namespace zypp { std::set _runningKernelEditionVariants; Flavour _runningKernelFlavour; Arch _kernelArch; - std::string _keepSpec = ZConfig::instance().multiversionKernels(); + std::string _keepSpec = ZConfig::systemConfig().multiversionKernels(); bool _keepRunning = true; bool _detectedRunning = false; }; @@ -639,7 +637,6 @@ namespace zypp { MIL << "Package not explicitly handled" << std::endl; } } - } MIL << "Grouped packages: " << std::endl; diff --git a/zypp/RepoInfo.cc b/zypp/RepoInfo.cc index 3d892cc237..6fbc509bea 100644 --- a/zypp/RepoInfo.cc +++ b/zypp/RepoInfo.cc @@ -9,655 +9,252 @@ /** \file zypp/RepoInfo.cc * */ -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - -#include -#include -#include -#include -#include - -#include - -using std::endl; -using zypp::xml::escape; - -/////////////////////////////////////////////////////////////////// -namespace zypp -{ ///////////////////////////////////////////////////////////////// - - namespace - { - repo::RepoType probeCache( const Pathname & path_r ) - { - repo::RepoType ret = repo::RepoType::NONE; - if ( PathInfo(path_r).isDir() ) - { - if ( PathInfo(path_r/"/repodata/repomd.xml").isFile() ) - { ret = repo::RepoType::RPMMD; } - else if ( PathInfo(path_r/"/content").isFile() ) - { ret = repo::RepoType::YAST2; } - else if ( PathInfo(path_r/"/cookie").isFile() ) - { ret = repo::RepoType::RPMPLAINDIR; } - } - DBG << "Probed cached type " << ret << " at " << path_r << endl; - return ret; - } - } // namespace - - /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : RepoInfo::Impl - // - /** RepoInfo implementation. */ - struct RepoInfo::Impl - { - Impl() - : _rawGpgCheck( indeterminate ) - , _rawRepoGpgCheck( indeterminate ) - , _rawPkgGpgCheck( indeterminate ) - , _validRepoSignature( indeterminate ) - , _type(repo::RepoType::NONE_e) - , keeppackages(indeterminate) - , _mirrorListForceMetalink(false) - , emptybaseurls(false) - {} - - Impl(const Impl &) = default; - Impl(Impl &&) = delete; - Impl &operator=(const Impl &) = delete; - Impl &operator=(Impl &&) = delete; - - ~Impl() {} - - public: - static const unsigned defaultPriority = 99; - static const unsigned noPriority = unsigned(-1); - - void setType( const repo::RepoType & t ) - { _type = t; } - - void setProbedType( const repo::RepoType & t ) const - { - if ( _type == repo::RepoType::NONE && t != repo::RepoType::NONE ) - { const_cast(this)->_type = t; } - } - - repo::RepoType type() const - { - if ( _type == repo::RepoType::NONE && not metadataPath().empty() ) - setProbedType( probeCache( metadataPath() / path ) ); - return _type; - } - - public: - /** Path to a license tarball in case it exists in the repo. */ - Pathname licenseTgz( const std::string & name_r ) const - { - Pathname ret; - if ( !metadataPath().empty() ) - { - std::string licenseStem( "license" ); - if ( !name_r.empty() ) - { - licenseStem += "-"; - licenseStem += name_r; - } - - filesystem::Glob g; - // TODO: REPOMD: this assumes we know the name of the tarball. In fact - // we'd need to get the file from repomd.xml () - g.add( metadataPath() / path / ("repodata/*"+licenseStem+".tar.gz") ); - if ( g.empty() ) - g.add( metadataPath() / path / (licenseStem+".tar.gz") ); - - if ( !g.empty() ) - ret = *g.begin(); - } - return ret; - } - - const RepoVariablesReplacedUrlList & baseUrls() const - { - const Url & mlurl( _mirrorListUrl.transformed() ); // Variables replaced! - if ( _baseUrls.empty() && ! mlurl.asString().empty() ) - { - emptybaseurls = true; - DBG << "MetadataPath: " << metadataPath() << endl; - repo::RepoMirrorList rmurls( mlurl, metadataPath(), _mirrorListForceMetalink ); - _baseUrls.raw().insert( _baseUrls.raw().end(), rmurls.getUrls().begin(), rmurls.getUrls().end() ); - } - return _baseUrls; - } - - RepoVariablesReplacedUrlList & baseUrls() - { return _baseUrls; } - - bool baseurl2dump() const - { return !emptybaseurls && !_baseUrls.empty(); } - - - const RepoVariablesReplacedUrlList & gpgKeyUrls() const - { return _gpgKeyUrls; } - - RepoVariablesReplacedUrlList & gpgKeyUrls() - { return _gpgKeyUrls; } - - - const std::set & contentKeywords() const - { hasContent()/*init if not yet done*/; return _keywords.second; } - - void addContent( const std::string & keyword_r ) - { _keywords.second.insert( keyword_r ); if ( ! hasContent() ) _keywords.first = true; } - - bool hasContent() const - { - if ( !_keywords.first && ! metadataPath().empty() ) - { - // HACK directly check master index file until RepoManager offers - // some content probing and zypper uses it. - ///////////////////////////////////////////////////////////////// - MIL << "Empty keywords...." << metadataPath() << endl; - Pathname master; - if ( PathInfo( (master=metadataPath()/"/repodata/repomd.xml") ).isFile() ) - { - //MIL << "GO repomd.." << endl; - xml::Reader reader( master ); - while ( reader.seekToNode( 2, "content" ) ) - { - _keywords.second.insert( reader.nodeText().asString() ); - reader.seekToEndNode( 2, "content" ); - } - _keywords.first = true; // valid content in _keywords even if empty - } - else if ( PathInfo( (master=metadataPath()/"/content") ).isFile() ) - { - //MIL << "GO content.." << endl; - iostr::forEachLine( InputStream( master ), - [this]( int num_r, const std::string& line_r )->bool - { - if ( str::startsWith( line_r, "REPOKEYWORDS" ) ) - { - std::vector words; - if ( str::split( line_r, std::back_inserter(words) ) > 1 - && words[0].length() == 12 /*"REPOKEYWORDS"*/ ) - { - this->_keywords.second.insert( ++words.begin(), words.end() ); - } - return true; // mult. occurrances are ok. - } - return( ! str::startsWith( line_r, "META " ) ); // no need to parse into META section. - } ); - _keywords.first = true; // valid content in _keywords even if empty - } - ///////////////////////////////////////////////////////////////// - } - return _keywords.first; - } - - bool hasContent( const std::string & keyword_r ) const - { return( hasContent() && _keywords.second.find( keyword_r ) != _keywords.second.end() ); } - - /** Signature check result needs to be stored/retrieved from _metadataPath. - * Don't call them from outside validRepoSignature/setValidRepoSignature - */ - //@{ - TriBool internalValidRepoSignature() const - { - if ( ! indeterminate(_validRepoSignature) ) - return _validRepoSignature; - // check metadata: - if ( ! metadataPath().empty() ) - { - // A missing ".repo_gpgcheck" might be plaindir(no Downloader) or not yet refreshed signed repo! - TriBool linkval = triBoolFromPath( metadataPath() / ".repo_gpgcheck" ); - return linkval; - } - return indeterminate; - } - - void internalSetValidRepoSignature( TriBool value_r ) - { - if ( PathInfo(metadataPath()).isDir() ) - { - Pathname gpgcheckFile( metadataPath() / ".repo_gpgcheck" ); - if ( PathInfo(gpgcheckFile).isExist() ) - { - TriBool linkval( indeterminate ); - if ( triBoolFromPath( gpgcheckFile, linkval ) && linkval == value_r ) - return; // existing symlink fits value_r - else - filesystem::unlink( gpgcheckFile ); // will write a new one - } - filesystem::symlink( asString(value_r), gpgcheckFile ); - } - _validRepoSignature = value_r; - } - - /** We definitely have a symlink pointing to "indeterminate" (for repoGpgCheckIsMandatory)? - * I.e. user accepted the unsigned repo in Downloader. A test whether `internalValidRepoSignature` - * is indeterminate would include not yet checked repos, which is unwanted here. - */ - bool internalUnsignedConfirmed() const - { - TriBool linkval( true ); // want to see it being switched to indeterminate - return triBoolFromPath( metadataPath() / ".repo_gpgcheck", linkval ) && indeterminate(linkval); - } - - bool triBoolFromPath( const Pathname & path_r, TriBool & ret_r ) const - { - static const Pathname truePath( "true" ); - static const Pathname falsePath( "false" ); - static const Pathname indeterminatePath( "indeterminate" ); - - // Quiet readlink; - static const ssize_t bufsiz = 63; - static char buf[bufsiz+1]; - ssize_t ret = ::readlink( path_r.c_str(), buf, bufsiz ); - buf[ret == -1 ? 0 : ret] = '\0'; - - Pathname linkval( buf ); - - bool known = true; - if ( linkval == truePath ) - ret_r = true; - else if ( linkval == falsePath ) - ret_r = false; - else if ( linkval == indeterminatePath ) - ret_r = indeterminate; - else - known = false; - return known; - } - - TriBool triBoolFromPath( const Pathname & path_r ) const - { TriBool ret(indeterminate); triBoolFromPath( path_r, ret ); return ret; } - - //@} - - private: - TriBool _rawGpgCheck; ///< default gpgcheck behavior: Y/N/ZConf - TriBool _rawRepoGpgCheck; ///< need to check repo sign.: Y/N/(ZConf(Y/N/gpgCheck)) - TriBool _rawPkgGpgCheck; ///< need to check pkg sign.: Y/N/(ZConf(Y/N/gpgCheck)) - - public: - TriBool rawGpgCheck() const { return _rawGpgCheck; } - TriBool rawRepoGpgCheck() const { return _rawRepoGpgCheck; } - TriBool rawPkgGpgCheck() const { return _rawPkgGpgCheck; } - - void rawGpgCheck( TriBool val_r ) { _rawGpgCheck = val_r; } - void rawRepoGpgCheck( TriBool val_r ) { _rawRepoGpgCheck = val_r; } - void rawPkgGpgCheck( TriBool val_r ) { _rawPkgGpgCheck = val_r; } - - bool cfgGpgCheck() const - { return indeterminate(_rawGpgCheck) ? ZConfig::instance().gpgCheck() : (bool)_rawGpgCheck; } - TriBool cfgRepoGpgCheck() const - { return indeterminate(_rawGpgCheck) && indeterminate(_rawRepoGpgCheck) ? ZConfig::instance().repoGpgCheck() : _rawRepoGpgCheck; } - TriBool cfgPkgGpgCheck() const - { return indeterminate(_rawGpgCheck) && indeterminate(_rawPkgGpgCheck) ? ZConfig::instance().pkgGpgCheck() : _rawPkgGpgCheck; } - - private: - TriBool _validRepoSignature; ///< have signed and valid repo metadata - repo::RepoType _type; - public: - TriBool keeppackages; - RepoVariablesReplacedUrl _mirrorListUrl; - bool _mirrorListForceMetalink; - Pathname path; - std::string service; - std::string targetDistro; - - void metadataPath( Pathname new_r ) - { _metadataPath = std::move( new_r ); } - - void packagesPath( Pathname new_r ) - { _packagesPath = std::move( new_r ); } - - bool usesAutoMetadataPaths() const - { return str::hasSuffix( _metadataPath.asString(), "/%AUTO%" ); } - - Pathname metadataPath() const - { - if ( usesAutoMetadataPaths() ) - return _metadataPath.dirname() / "%RAW%"; - return _metadataPath; - } - - Pathname packagesPath() const - { - if ( _packagesPath.empty() && usesAutoMetadataPaths() ) - return _metadataPath.dirname() / "%PKG%"; - return _packagesPath; - } - - DefaultIntegral priority; - mutable bool emptybaseurls; - - private: - Pathname _metadataPath; - Pathname _packagesPath; - - mutable RepoVariablesReplacedUrlList _baseUrls; - mutable std::pair > _keywords; - - RepoVariablesReplacedUrlList _gpgKeyUrls; - - friend Impl * rwcowClone( const Impl * rhs ); - /** clone for RWCOW_pointer */ - Impl * clone() const - { return new Impl( *this ); } - }; - /////////////////////////////////////////////////////////////////// - - /** \relates RepoInfo::Impl Stream output */ - inline std::ostream & operator<<( std::ostream & str, const RepoInfo::Impl & obj ) - { - return str << "RepoInfo::Impl"; - } - /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : RepoInfo - // - /////////////////////////////////////////////////////////////////// +#include "RepoInfo.h" + +#include +#include +#include + +namespace zypp { - const RepoInfo RepoInfo::noRepo; + ZYPP_BEGIN_LEGACY_API - RepoInfo::RepoInfo() - : _pimpl( new Impl() ) + const RepoInfo RepoInfo::noRepo( zyppng::RepoInfo(nullptr) ); + + RepoInfo::RepoInfo( ) + : _pimpl( std::make_unique( zypp_detail::GlobalStateHelper::context() ) ) + {} + + RepoInfo::RepoInfo(zyppng::RepoInfo *pimpl) + : _pimpl(pimpl) + , _ownsImpl(false) {} RepoInfo::~RepoInfo() + { + if ( !_ownsImpl ) + _pimpl.release(); + } + + RepoInfo::RepoInfo( const zyppng::RepoInfo &pimpl ) + : _pimpl( std::make_unique(pimpl) ) + , _ownsImpl( true ) + { } + + RepoInfo::RepoInfo(const RepoInfo &other) + : _pimpl( std::make_unique(*other._pimpl) ) + , _ownsImpl( true ) + {} + + RepoInfo::RepoInfo(RepoInfo &&other) + : _pimpl( std::move(other._pimpl) ) + , _ownsImpl( other._ownsImpl ) {} + zyppng::repo::RepoInfoBase &RepoInfo::pimpl() + { + return *_pimpl; + } + + const zyppng::repo::RepoInfoBase &RepoInfo::pimpl() const + { + return *_pimpl; + } + + RepoInfo &RepoInfo::operator=(const RepoInfo &other) + { + _pimpl = std::make_unique(*other._pimpl); + _ownsImpl = true; + return *this; + } + + RepoInfo &RepoInfo::operator=( RepoInfo &&other ) + { + _pimpl = std::move(other._pimpl); + _ownsImpl = other._ownsImpl; + return *this; + } + unsigned RepoInfo::priority() const - { return _pimpl->priority; } + { return _pimpl->priority(); } unsigned RepoInfo::defaultPriority() - { return Impl::defaultPriority; } + { return zyppng::RepoInfoSharedData::defaultPriority; } unsigned RepoInfo::noPriority() - { return Impl::noPriority; } + { return zyppng::RepoInfoSharedData::noPriority; } void RepoInfo::setPriority( unsigned newval_r ) - { _pimpl->priority = newval_r ? newval_r : Impl::defaultPriority; } - + { _pimpl->setPriority(newval_r); } bool RepoInfo::gpgCheck() const - { return _pimpl->cfgGpgCheck(); } - - void RepoInfo::setGpgCheck( TriBool value_r ) - { _pimpl->rawGpgCheck( value_r ); } + { return _pimpl->gpgCheck(); } - void RepoInfo::setGpgCheck( bool value_r ) // deprecated legacy and for squid - { setGpgCheck( TriBool(value_r) ); } + void RepoInfo::setGpgCheck( zypp::TriBool value_r ) + { _pimpl->setGpgCheck(value_r); } + void RepoInfo::setGpgCheck(bool value_r) + { _pimpl->setGpgCheck(zypp::TriBool(value_r)); } bool RepoInfo::repoGpgCheck() const - { return gpgCheck() || bool(_pimpl->cfgRepoGpgCheck()); } + { return _pimpl->repoGpgCheck(); } bool RepoInfo::repoGpgCheckIsMandatory() const - { - bool ret = ( gpgCheck() && indeterminate(_pimpl->cfgRepoGpgCheck()) ) || bool(_pimpl->cfgRepoGpgCheck()); - if ( ret && _pimpl->internalUnsignedConfirmed() ) // relax if unsigned repo was confirmed in the past - ret = false; - return ret; - } - - void RepoInfo::setRepoGpgCheck( TriBool value_r ) - { _pimpl->rawRepoGpgCheck( value_r ); } + { return _pimpl->repoGpgCheckIsMandatory (); } + void RepoInfo::setRepoGpgCheck( zypp::TriBool value_r ) + { _pimpl->setRepoGpgCheck(value_r); } bool RepoInfo::pkgGpgCheck() const - { return bool(_pimpl->cfgPkgGpgCheck()) || ( gpgCheck() && !bool(validRepoSignature())/*enforced*/ ) ; } + { return _pimpl->pkgGpgCheck(); } bool RepoInfo::pkgGpgCheckIsMandatory() const - { return bool(_pimpl->cfgPkgGpgCheck()) || ( gpgCheck() && indeterminate(_pimpl->cfgPkgGpgCheck()) && !bool(validRepoSignature())/*enforced*/ ); } - - void RepoInfo::setPkgGpgCheck( TriBool value_r ) - { _pimpl->rawPkgGpgCheck( value_r ); } - + { return _pimpl->pkgGpgCheckIsMandatory(); } - void RepoInfo::getRawGpgChecks( TriBool & g_r, TriBool & r_r, TriBool & p_r ) const - { - g_r = _pimpl->rawGpgCheck(); - r_r = _pimpl->rawRepoGpgCheck(); - p_r = _pimpl->rawPkgGpgCheck(); - } + void RepoInfo::setPkgGpgCheck( zypp::TriBool value_r ) + { _pimpl->setPkgGpgCheck(value_r); } + void RepoInfo::getRawGpgChecks( zypp::TriBool & g_r, zypp::TriBool & r_r, zypp::TriBool & p_r ) const + { _pimpl->getRawGpgChecks( g_r, r_r, p_r ); } - TriBool RepoInfo::validRepoSignature() const - { - TriBool ret( _pimpl->internalValidRepoSignature() ); - if ( ret && !repoGpgCheck() ) ret = false; // invalidate any old signature if repoGpgCheck is off - return ret; - } + zypp::TriBool RepoInfo::validRepoSignature() const + { return _pimpl->validRepoSignature(); } - void RepoInfo::setValidRepoSignature( TriBool value_r ) - { _pimpl->internalSetValidRepoSignature( value_r ); } + void RepoInfo::setValidRepoSignature( zypp::TriBool value_r ) + { _pimpl->setValidRepoSignature (value_r ); } - /////////////////////////////////////////////////////////////////// - namespace - { - inline bool changeGpgCheckTo( TriBool & lhs, TriBool rhs ) - { if ( ! sameTriboolState( lhs, rhs ) ) { lhs = rhs; return true; } return false; } - - inline bool changeGpgCheckTo( TriBool ogpg[3], TriBool g, TriBool r, TriBool p ) - { - bool changed = false; - if ( changeGpgCheckTo( ogpg[0], g ) ) changed = true; - if ( changeGpgCheckTo( ogpg[1], r ) ) changed = true; - if ( changeGpgCheckTo( ogpg[2], p ) ) changed = true; - return changed; - } - } // namespace - /////////////////////////////////////////////////////////////////// bool RepoInfo::setGpgCheck( GpgCheck mode_r ) - { - TriBool ogpg[3]; // Gpg RepoGpg PkgGpg - getRawGpgChecks( ogpg[0], ogpg[1], ogpg[2] ); - - bool changed = false; - switch ( mode_r ) - { - case GpgCheck::On: - changed = changeGpgCheckTo( ogpg, true, indeterminate, indeterminate ); - break; - case GpgCheck::Strict: - changed = changeGpgCheckTo( ogpg, true, true, true ); - break; - case GpgCheck::AllowUnsigned: - changed = changeGpgCheckTo( ogpg, true, false, false ); - break; - case GpgCheck::AllowUnsignedRepo: - changed = changeGpgCheckTo( ogpg, true, false, indeterminate ); - break; - case GpgCheck::AllowUnsignedPackage: - changed = changeGpgCheckTo( ogpg, true, indeterminate, false ); - break; - case GpgCheck::Default: - changed = changeGpgCheckTo( ogpg, indeterminate, indeterminate, indeterminate ); - break; - case GpgCheck::Off: - changed = changeGpgCheckTo( ogpg, false, indeterminate, indeterminate ); - break; - case GpgCheck::indeterminate: // no change - break; - } - - if ( changed ) - { - setGpgCheck ( ogpg[0] ); - setRepoGpgCheck( ogpg[1] ); - setPkgGpgCheck ( ogpg[2] ); - } - return changed; - } + { return _pimpl->setGpgCheck(mode_r); } - void RepoInfo::setMirrorListUrl( const Url & url_r ) // Raw - { _pimpl->_mirrorListUrl.raw() = url_r; _pimpl->_mirrorListForceMetalink = false; } + void RepoInfo::setMirrorListUrl( const zypp::Url & url_r ) // Raw + { _pimpl->setMirrorListUrl(url_r); } void RepoInfo::setMirrorListUrls( url_set urls ) // Raw - { setMirrorListUrl( urls.empty() ? Url() : urls.front() ); } + { _pimpl->setMirrorListUrls(std::move(urls)); } - void RepoInfo::setMetalinkUrl( const Url & url_r ) // Raw - { _pimpl->_mirrorListUrl.raw() = url_r; _pimpl->_mirrorListForceMetalink = true; } + void RepoInfo::setMetalinkUrl( const zypp::Url & url_r ) // Raw + { _pimpl->setMetalinkUrl(url_r); } void RepoInfo::setMetalinkUrls( url_set urls ) // Raw - { setMetalinkUrl( urls.empty() ? Url() : urls.front() ); } + { _pimpl->setMetalinkUrls(std::move(urls)); } void RepoInfo::setGpgKeyUrls( url_set urls ) - { _pimpl->gpgKeyUrls().raw().swap( urls ); } - - void RepoInfo::setGpgKeyUrl( const Url & url_r ) - { - _pimpl->gpgKeyUrls().raw().clear(); - _pimpl->gpgKeyUrls().raw().push_back( url_r ); - } - + { _pimpl->setGpgKeyUrls(std::move(urls)); } - Pathname RepoInfo::provideKey(const std::string &keyID_r, const Pathname &targetDirectory_r) const { - return zyppng::RepoInfoWorkflow::provideKey( zyppng::SyncContext::defaultContext(), *this, keyID_r, targetDirectory_r ); - } + void RepoInfo::setGpgKeyUrl( const zypp::Url & url_r ) + { _pimpl->setGpgKeyUrl(url_r); } - void RepoInfo::addBaseUrl( Url url_r ) - { - for ( const auto & url : _pimpl->baseUrls().raw() ) // Raw unique! - if ( url == url_r ) - return; - _pimpl->baseUrls().raw().push_back( std::move(url_r) ); - } + void RepoInfo::addBaseUrl( zypp::Url url_r ) + { _pimpl->addBaseUrl( std::move(url_r) ); } - void RepoInfo::setBaseUrl( Url url_r ) - { - _pimpl->baseUrls().raw().clear(); - _pimpl->baseUrls().raw().push_back( std::move(url_r) ); - } + void RepoInfo::setBaseUrl( zypp::Url url_r ) + { _pimpl->setBaseUrl( std::move(url_r) ); } void RepoInfo::setBaseUrls( url_set urls ) - { _pimpl->baseUrls().raw().swap( urls ); } + { _pimpl->setBaseUrls(std::move(urls)); } - void RepoInfo::setPath( const Pathname &path ) - { _pimpl->path = path; } + void RepoInfo::setPath( const zypp::Pathname &path ) + { _pimpl->setPath(path); } - void RepoInfo::setType( const repo::RepoType &t ) - { _pimpl->setType( t ); } + void RepoInfo::setType( const zypp::repo::RepoType &t ) + { _pimpl->setType(t); } - void RepoInfo::setProbedType( const repo::RepoType &t ) const - { _pimpl->setProbedType( t ); } + void RepoInfo::setProbedType( const zypp::repo::RepoType &t ) const + { _pimpl->setProbedType(t); } + void RepoInfo::setMetadataPath( const zypp::Pathname &path ) + { _pimpl->setMetadataPath(path); } - void RepoInfo::setMetadataPath( const Pathname &path ) - { _pimpl->metadataPath( path ); } + void RepoInfo::setPackagesPath( const zypp::Pathname &path ) + { _pimpl->setPackagesPath(path); } - void RepoInfo::setPackagesPath( const Pathname &path ) - { _pimpl->packagesPath( path ); } + void RepoInfo::setSolvCachePath(const zypp::Pathname &path) + { _pimpl->setSolvCachePath(path); } void RepoInfo::setKeepPackages( bool keep ) - { _pimpl->keeppackages = keep; } + { _pimpl->setKeepPackages( keep ); } void RepoInfo::setService( const std::string& name ) - { _pimpl->service = name; } + { _pimpl->setService(name); } void RepoInfo::setTargetDistribution( const std::string & targetDistribution ) - { _pimpl->targetDistro = targetDistribution; } + { _pimpl->setTargetDistribution( targetDistribution ); } bool RepoInfo::keepPackages() const - { return indeterminate(_pimpl->keeppackages) ? false : (bool)_pimpl->keeppackages; } + { return _pimpl->keepPackages(); } - Pathname RepoInfo::metadataPath() const + zypp::Pathname RepoInfo::metadataPath() const { return _pimpl->metadataPath(); } - Pathname RepoInfo::packagesPath() const + zypp::Pathname RepoInfo::packagesPath() const { return _pimpl->packagesPath(); } + zypp::Pathname RepoInfo::solvCachePath() const + { return _pimpl->solvCachePath(); } + bool RepoInfo::usesAutoMetadataPaths() const { return _pimpl->usesAutoMetadataPaths(); } - repo::RepoType RepoInfo::type() const + zypp::repo::RepoType RepoInfo::type() const { return _pimpl->type(); } - Url RepoInfo::mirrorListUrl() const // Variables replaced! - { return _pimpl->_mirrorListUrl.transformed(); } + zypp::Url RepoInfo::mirrorListUrl() const + { return _pimpl->mirrorListUrl(); } - Url RepoInfo::rawMirrorListUrl() const // Raw - { return _pimpl->_mirrorListUrl.raw(); } + zypp::Url RepoInfo::rawMirrorListUrl() const // Raw + { return _pimpl->rawMirrorListUrl(); } bool RepoInfo::gpgKeyUrlsEmpty() const - { return _pimpl->gpgKeyUrls().empty(); } + { return _pimpl->gpgKeyUrlsEmpty(); } RepoInfo::urls_size_type RepoInfo::gpgKeyUrlsSize() const - { return _pimpl->gpgKeyUrls().size(); } + { return _pimpl->gpgKeyUrlsSize(); } RepoInfo::url_set RepoInfo::gpgKeyUrls() const // Variables replaced! - { return _pimpl->gpgKeyUrls().transformed(); } + { return _pimpl->gpgKeyUrls(); } RepoInfo::url_set RepoInfo::rawGpgKeyUrls() const // Raw - { return _pimpl->gpgKeyUrls().raw(); } + { return _pimpl->rawGpgKeyUrls(); } - Url RepoInfo::gpgKeyUrl() const // Variables replaced! - { return( _pimpl->gpgKeyUrls().empty() ? Url() : *_pimpl->gpgKeyUrls().transformedBegin() ); } + zypp::Url RepoInfo::gpgKeyUrl() const // Variables replaced! + { return _pimpl->gpgKeyUrl(); } - Url RepoInfo::rawGpgKeyUrl() const // Raw - { return( _pimpl->gpgKeyUrls().empty() ? Url() : *_pimpl->gpgKeyUrls().rawBegin() ) ; } + zypp::Url RepoInfo::rawGpgKeyUrl() const // Raw + { return _pimpl->rawGpgKeyUrl(); } RepoInfo::url_set RepoInfo::baseUrls() const // Variables replaced! - { return _pimpl->baseUrls().transformed(); } + { return _pimpl->baseUrls(); } RepoInfo::url_set RepoInfo::rawBaseUrls() const // Raw - { return _pimpl->baseUrls().raw(); } + { return _pimpl->rawBaseUrls(); } - Pathname RepoInfo::path() const - { return _pimpl->path; } + zypp::Pathname RepoInfo::path() const + { return _pimpl->path(); } std::string RepoInfo::service() const - { return _pimpl->service; } + { return _pimpl->service(); } std::string RepoInfo::targetDistribution() const - { return _pimpl->targetDistro; } + { return _pimpl->targetDistribution(); } - Url RepoInfo::rawUrl() const - { return( _pimpl->baseUrls().empty() ? Url() : *_pimpl->baseUrls().rawBegin() ); } + zypp::Url RepoInfo::rawUrl() const + { return _pimpl->rawUrl(); } RepoInfo::urls_const_iterator RepoInfo::baseUrlsBegin() const - { return _pimpl->baseUrls().transformedBegin(); } + { return _pimpl->baseUrlsBegin(); } RepoInfo::urls_const_iterator RepoInfo::baseUrlsEnd() const - { return _pimpl->baseUrls().transformedEnd(); } + { return _pimpl->baseUrlsEnd(); } RepoInfo::urls_size_type RepoInfo::baseUrlsSize() const - { return _pimpl->baseUrls().size(); } + { return _pimpl->baseUrlsSize(); } bool RepoInfo::baseUrlsEmpty() const - { return _pimpl->baseUrls().empty(); } + { return _pimpl->baseUrlsEmpty(); } bool RepoInfo::baseUrlSet() const - { return _pimpl->baseurl2dump(); } + { return _pimpl->baseUrlSet(); } const std::set & RepoInfo::contentKeywords() const { return _pimpl->contentKeywords(); } @@ -671,318 +268,53 @@ namespace zypp bool RepoInfo::hasContent( const std::string & keyword_r ) const { return _pimpl->hasContent( keyword_r ); } - /////////////////////////////////////////////////////////////////// - bool RepoInfo::hasLicense() const - { return hasLicense( std::string() ); } + { return _pimpl->hasLicense( ); } bool RepoInfo::hasLicense( const std::string & name_r ) const - { return !_pimpl->licenseTgz( name_r ).empty(); } - + { return _pimpl->hasLicense(name_r); } bool RepoInfo::needToAcceptLicense() const - { return needToAcceptLicense( std::string() ); } + { return _pimpl->needToAcceptLicense(); } bool RepoInfo::needToAcceptLicense( const std::string & name_r ) const - { - const Pathname & licenseTgz( _pimpl->licenseTgz( name_r ) ); - if ( licenseTgz.empty() ) - return false; // no licenses at all - - ExternalProgram::Arguments cmd; - cmd.push_back( "tar" ); - cmd.push_back( "-t" ); - cmd.push_back( "-z" ); - cmd.push_back( "-f" ); - cmd.push_back( licenseTgz.asString() ); - ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout ); - - bool accept = true; - static const std::string noAcceptanceFile = "no-acceptance-needed\n"; - for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) - { - if ( output == noAcceptanceFile ) - { - accept = false; - } - } - prog.close(); - MIL << "License(" << name_r << ") in " << name() << " has to be accepted: " << (accept?"true":"false" ) << endl; - return accept; - } + { return _pimpl->needToAcceptLicense( name_r ); } + std::string RepoInfo::getLicense( const zypp::Locale & lang_r ) + { return _pimpl->getLicense(lang_r); } - std::string RepoInfo::getLicense( const Locale & lang_r ) - { return const_cast(this)->getLicense( std::string(), lang_r ); } + std::string RepoInfo::getLicense( const zypp::Locale & lang_r ) const + { return _pimpl->getLicense (lang_r); } - std::string RepoInfo::getLicense( const Locale & lang_r ) const - { return getLicense( std::string(), lang_r ); } + std::string RepoInfo::getLicense( const std::string & name_r, const zypp::Locale & lang_r ) const + { return _pimpl->getLicense ( name_r, lang_r ); } - std::string RepoInfo::getLicense( const std::string & name_r, const Locale & lang_r ) const - { - LocaleSet avlocales( getLicenseLocales( name_r ) ); - if ( avlocales.empty() ) - return std::string(); - - Locale getLang( Locale::bestMatch( avlocales, lang_r ) ); - if ( !getLang && avlocales.find( Locale::noCode ) == avlocales.end() ) - { - WAR << "License(" << name_r << ") in " << name() << " contains no fallback text!" << endl; - // Using the fist locale instead of returning no text at all. - // So the user might recognize that there is a license, even if they - // can't read it. - getLang = *avlocales.begin(); - } - - // now extract the license file. - static const std::string licenseFileFallback( "license.txt" ); - std::string licenseFile( !getLang ? licenseFileFallback - : str::form( "license.%s.txt", getLang.c_str() ) ); - - ExternalProgram::Arguments cmd; - cmd.push_back( "tar" ); - cmd.push_back( "-x" ); - cmd.push_back( "-z" ); - cmd.push_back( "-O" ); - cmd.push_back( "-f" ); - cmd.push_back( _pimpl->licenseTgz( name_r ).asString() ); // if it not exists, avlocales was empty. - cmd.push_back( licenseFile ); - - std::string ret; - ExternalProgram prog( cmd, ExternalProgram::Discard_Stderr ); - for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) - { - ret += output; - } - prog.close(); - return ret; - } + zypp::LocaleSet RepoInfo::getLicenseLocales() const + { return _pimpl->getLicenseLocales(); } - - LocaleSet RepoInfo::getLicenseLocales() const - { return getLicenseLocales( std::string() ); } - - LocaleSet RepoInfo::getLicenseLocales( const std::string & name_r ) const - { - const Pathname & licenseTgz( _pimpl->licenseTgz( name_r ) ); - if ( licenseTgz.empty() ) - return LocaleSet(); - - ExternalProgram::Arguments cmd; - cmd.push_back( "tar" ); - cmd.push_back( "-t" ); - cmd.push_back( "-z" ); - cmd.push_back( "-f" ); - cmd.push_back( licenseTgz.asString() ); - - LocaleSet ret; - ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout ); - for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) - { - static const C_Str license( "license." ); - static const C_Str dotTxt( ".txt\n" ); - if ( str::hasPrefix( output, license ) && str::hasSuffix( output, dotTxt ) ) - { - if ( output.size() <= license.size() + dotTxt.size() ) // license.txt - ret.insert( Locale() ); - else - ret.insert( Locale( std::string( output.c_str()+license.size(), output.size()- license.size() - dotTxt.size() ) ) ); - } - } - prog.close(); - return ret; - } - - /////////////////////////////////////////////////////////////////// + zypp::LocaleSet RepoInfo::getLicenseLocales( const std::string & name_r ) const + { return _pimpl->getLicenseLocales( name_r ); } std::ostream & RepoInfo::dumpOn( std::ostream & str ) const - { - RepoInfoBase::dumpOn(str); - if ( _pimpl->baseurl2dump() ) - { - for ( const auto & url : _pimpl->baseUrls().raw() ) - { - str << "- url : " << url << std::endl; - } - } - - // print if non empty value - auto strif( [&] ( const std::string & tag_r, const std::string & value_r ) { - if ( ! value_r.empty() ) - str << tag_r << value_r << std::endl; - }); - - strif( (_pimpl->_mirrorListForceMetalink ? "- metalink : " : "- mirrorlist : "), rawMirrorListUrl().asString() ); - strif( "- path : ", path().asString() ); - str << "- type : " << type() << std::endl; - str << "- priority : " << priority() << std::endl; - - // Yes No Default(Y) Default(N) -#define OUTS(T,B) ( indeterminate(T) ? (std::string("D(")+(B?"Y":"N")+")") : ((bool)T?"Y":"N") ) - str << "- gpgcheck : " << OUTS(_pimpl->rawGpgCheck(),gpgCheck()) - << " repo" << OUTS(_pimpl->rawRepoGpgCheck(),repoGpgCheck()) << (repoGpgCheckIsMandatory() ? "* ": " " ) - << "sig" << asString( validRepoSignature(), "?", "Y", "N" ) - << " pkg" << OUTS(_pimpl->rawPkgGpgCheck(),pkgGpgCheck()) << (pkgGpgCheckIsMandatory() ? "* ": " " ) - << std::endl; -#undef OUTS - - for ( const auto & url : _pimpl->gpgKeyUrls().raw() ) - { - str << "- gpgkey : " << url << std::endl; - } - - if ( ! indeterminate(_pimpl->keeppackages) ) - str << "- keeppackages: " << keepPackages() << std::endl; - - strif( "- service : ", service() ); - strif( "- targetdistro: ", targetDistribution() ); - strif( "- filePath: ", filepath().asString() ); - strif( "- metadataPath: ", metadataPath().asString() ); - strif( "- packagesPath: ", packagesPath().asString() ); - - return str; - } + { return _pimpl->dumpOn( str ); } std::ostream & RepoInfo::dumpAsIniOn( std::ostream & str ) const - { - RepoInfoBase::dumpAsIniOn(str); - - if ( _pimpl->baseurl2dump() ) - { - str << "baseurl="; - std::string indent; - for ( const auto & url : _pimpl->baseUrls().raw() ) - { - str << indent << hotfix1050625::asString( url ) << endl; - if ( indent.empty() ) indent = " "; // "baseurl=" - } - } - - if ( ! _pimpl->path.empty() ) - str << "path="<< path() << endl; - - if ( ! (rawMirrorListUrl().asString().empty()) ) - str << (_pimpl->_mirrorListForceMetalink ? "metalink=" : "mirrorlist=") << hotfix1050625::asString( rawMirrorListUrl() ) << endl; - - if ( type() != repo::RepoType::NONE ) - str << "type=" << type().asString() << endl; - - if ( priority() != defaultPriority() ) - str << "priority=" << priority() << endl; - - if ( ! indeterminate(_pimpl->rawGpgCheck()) ) - str << "gpgcheck=" << (_pimpl->rawGpgCheck() ? "1" : "0") << endl; - - if ( ! indeterminate(_pimpl->rawRepoGpgCheck()) ) - str << "repo_gpgcheck=" << (_pimpl->rawRepoGpgCheck() ? "1" : "0") << endl; - - if ( ! indeterminate(_pimpl->rawPkgGpgCheck()) ) - str << "pkg_gpgcheck=" << (_pimpl->rawPkgGpgCheck() ? "1" : "0") << endl; - - { - std::string indent( "gpgkey="); - for ( const auto & url : _pimpl->gpgKeyUrls().raw() ) - { - str << indent << url << endl; - if ( indent[0] != ' ' ) - indent = " "; - } - } - - if (!indeterminate(_pimpl->keeppackages)) - str << "keeppackages=" << keepPackages() << endl; - - if( ! service().empty() ) - str << "service=" << service() << endl; - - return str; - } + { return _pimpl->dumpAsIniOn( str ); } std::ostream & RepoInfo::dumpAsXmlOn( std::ostream & str, const std::string & content ) const - { - std::string tmpstr; - str - << "rawGpgCheck()) ) - str << " raw_gpgcheck=\"" << (_pimpl->rawGpgCheck() ? "1" : "0") << "\""; - if ( ! indeterminate(_pimpl->rawRepoGpgCheck()) ) - str << " raw_repo_gpgcheck=\"" << (_pimpl->rawRepoGpgCheck() ? "1" : "0") << "\""; - if ( ! indeterminate(_pimpl->rawPkgGpgCheck()) ) - str << " raw_pkg_gpgcheck=\"" << (_pimpl->rawPkgGpgCheck() ? "1" : "0") << "\""; - if (!(tmpstr = gpgKeyUrl().asString()).empty()) - if (!(tmpstr = gpgKeyUrl().asString()).empty()) - str << " gpgkey=\"" << escape(tmpstr) << "\""; - if (!(tmpstr = mirrorListUrl().asString()).empty()) - str << (_pimpl->_mirrorListForceMetalink ? " metalink=\"" : " mirrorlist=\"") << escape(tmpstr) << "\""; - str << ">" << endl; - - if ( _pimpl->baseurl2dump() ) - { - for_( it, baseUrlsBegin(), baseUrlsEnd() ) // !transform iterator replaces variables - str << "" << escape((*it).asString()) << "" << endl; - } - - str << "" << endl; - return str; - } - + { return _pimpl->dumpAsXmlOn ( str, content );} std::ostream & operator<<( std::ostream & str, const RepoInfo & obj ) - { - return obj.dumpOn(str); - } - - std::ostream & operator<<( std::ostream & str, const RepoInfo::GpgCheck & obj ) - { - switch ( obj ) - { -#define OUTS( V ) case RepoInfo::V: return str << #V; break - OUTS( GpgCheck::On ); - OUTS( GpgCheck::Strict ); - OUTS( GpgCheck::AllowUnsigned ); - OUTS( GpgCheck::AllowUnsignedRepo ); - OUTS( GpgCheck::AllowUnsignedPackage ); - OUTS( GpgCheck::Default ); - OUTS( GpgCheck::Off ); - OUTS( GpgCheck::indeterminate ); -#undef OUTS - } - return str << "GpgCheck::UNKNOWN"; - } + { return obj.dumpOn(str); } bool RepoInfo::requireStatusWithMediaFile () const - { - // We skip the check for downloading media unless a local copy of the - // media file exists and states that there is more than one medium. - bool canSkipMediaCheck = std::all_of( baseUrlsBegin(), baseUrlsEnd(), []( const zypp::Url &url ) { return url.schemeIsDownloading(); }); - if ( canSkipMediaCheck ) { - const auto &mDataPath = metadataPath(); - if ( not mDataPath.empty() ) { - PathInfo mediafile { mDataPath/"media.1/media" }; - if ( mediafile.isExist() ) { - repo::SUSEMediaVerifier lverifier { mediafile.path() }; - if ( lverifier && lverifier.totalMedia() > 1 ) { - canSkipMediaCheck = false; - } - } - } - } - if ( canSkipMediaCheck ) - DBG << "Can SKIP media.1/media check for status calc of repo " << alias() << endl; - return not canSkipMediaCheck; - } + { return _pimpl->requireStatusWithMediaFile(); } + + zyppng::RepoInfo &RepoInfo::ngRepoInfo() + { return *_pimpl; } + + const zyppng::RepoInfo &RepoInfo::ngRepoInfo() const + { return *_pimpl; } - ///////////////////////////////////////////////////////////////// -} // namespace zypp -/////////////////////////////////////////////////////////////////// + ZYPP_END_LEGACY_API +} diff --git a/zypp/RepoInfo.h b/zypp/RepoInfo.h index 648539721e..cb9ce885aa 100644 --- a/zypp/RepoInfo.h +++ b/zypp/RepoInfo.h @@ -23,13 +23,20 @@ #include #include #include - #include +#include + +namespace zyppng { + class RepoInfo; +} + +ZYPP_BEGIN_LEGACY_API /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// // // CLASS NAME : RepoInfo @@ -68,7 +75,7 @@ namespace zypp * \note Name, baseUrls and mirrorUrl are subject to repo variable replacement * (\see \ref RepoVariablesStringReplacer). */ - class ZYPP_API RepoInfo : public repo::RepoInfoBase + class ZYPP_API ZYPP_INTERNAL_DEPRECATE RepoInfo : public repo::RepoInfoBase { friend std::ostream & operator<<( std::ostream & str, const RepoInfo & obj ); @@ -76,13 +83,16 @@ namespace zypp RepoInfo(); ~RepoInfo() override; - RepoInfo(const RepoInfo &) = default; - RepoInfo(RepoInfo &&) = default; - RepoInfo &operator=(const RepoInfo &) = default; - RepoInfo &operator=(RepoInfo &&) = default; + // copy of the ng repoinfo, cow semantics apply + explicit RepoInfo( const zyppng::RepoInfo &pimpl ); + + RepoInfo(const RepoInfo &); + RepoInfo(RepoInfo &&); + RepoInfo &operator=(const RepoInfo &) ; + RepoInfo &operator=(RepoInfo &&); /** Represents no Repository (one with an empty alias). */ - static const RepoInfo noRepo; + static const ZYPP_INTERNAL_DEPRECATE RepoInfo noRepo; public: /** @@ -107,7 +117,7 @@ namespace zypp using url_set = std::list; using urls_size_type = url_set::size_type; - using urls_const_iterator = transform_iterator; + using urls_const_iterator = transform_iterator; /** * whether repository urls are available */ @@ -284,6 +294,17 @@ namespace zypp */ void setPackagesPath( const Pathname &path ); + /** + * \short Path where this repo's solv cache is located + */ + Pathname solvCachePath() const; + /** + * \short set the path this repo's solv cache is located + * + * \param path directory path + */ + void setSolvCachePath( const Pathname &path ); + /** \name Repository gpgchecks * How signature checking should be performed for this repo. @@ -369,17 +390,7 @@ namespace zypp /** Set the value for \ref validRepoSignature (or \c indeterminate if unsigned). */ void setValidRepoSignature( TriBool value_r ); - /** Some predefined settings */ - enum class GpgCheck { - indeterminate, //< not specified - On, //< 1** --gpgcheck - Strict, //< 111 --gpgcheck-strict - AllowUnsigned, //< 100 --gpgcheck-allow-unsigned - AllowUnsignedRepo, //< 10* --gpgcheck-allow-unsigned-repo - AllowUnsignedPackage, //< 1*0 --gpgcheck-allow-unsigned-package - Default, //< *** --default-gpgcheck - Off, //< 0** --no-gpgcheck - }; + using GpgCheck = zypp::repo::GpgCheck; /** Adjust *GpgCheck settings according to \a mode_r. * \c GpgCheck::indeterminate will leave the settings as they are. @@ -409,7 +420,7 @@ namespace zypp void setGpgKeyUrl( const Url &gpgkey ); /** downloads all configured gpg keys into the defined directory */ - Pathname provideKey(const std::string &keyID_r, const Pathname &targetDirectory_r ) const; + Pathname provideKey(const std::string &keyID_r, const Pathname &targetDirectory_r ) const ZYPP_INTERNAL_DEPRECATE ; /** * \short Whether packages downloaded from this repository will be kept in local cache @@ -560,15 +571,29 @@ namespace zypp */ void getRawGpgChecks( TriBool & g_r, TriBool & r_r, TriBool & p_r ) const; - struct Impl; + zyppng::RepoInfo &ngRepoInfo(); + const zyppng::RepoInfo &ngRepoInfo() const; + private: friend class RepoManager; - /** Pointer to implementation */ - RWCOW_pointer _pimpl; + /*! + * Creates a RepoInfo instance that basically works like + * a reference to the ng object. Moving it will keep the same reference semantics, + * however a copy also will copy the ng RepoInfo + * \internal + */ + RepoInfo( zyppng::RepoInfo *pimpl ); + + zyppng::repo::RepoInfoBase &pimpl() override; + const zyppng::repo::RepoInfoBase &pimpl() const override; + + // only reason this is a pointer , is that we do not want to export the ng symbols + std::unique_ptr _pimpl; + bool _ownsImpl = true; }; /////////////////////////////////////////////////////////////////// - + /// /** \relates RepoInfo */ using RepoInfo_Ptr = shared_ptr; /** \relates RepoInfo */ @@ -576,13 +601,25 @@ namespace zypp /** \relates RepoInfo */ using RepoInfoList = std::list; + /** \relates RepoInfoBase */ + inline bool operator==( const RepoInfo & lhs, const RepoInfo & rhs ) + { return lhs.alias() == rhs.alias(); } + + /** \relates RepoInfoBase */ + inline bool operator!=( const RepoInfo & lhs, const RepoInfo & rhs ) + { return lhs.alias() != rhs.alias(); } + + inline bool operator<( const RepoInfo & lhs, const RepoInfo & rhs ) + { return lhs.alias() < rhs.alias(); } + + /** \relates RepoInfo Stream output */ std::ostream & operator<<( std::ostream & str, const RepoInfo & obj ) ZYPP_API; - /** \relates RepoInfo::GpgCheck Stream output */ - std::ostream & operator<<( std::ostream & str, const RepoInfo::GpgCheck & obj ) ZYPP_API; - ///////////////////////////////////////////////////////////////// } // namespace zypp + +ZYPP_END_LEGACY_API + /////////////////////////////////////////////////////////////////// #endif // ZYPP2_REPOSITORYINFO_H diff --git a/zypp/RepoManager.cc b/zypp/RepoManager.cc index f55d0e5487..7c4d4f3f6f 100644 --- a/zypp/RepoManager.cc +++ b/zypp/RepoManager.cc @@ -10,13 +10,17 @@ * */ +#include "RepoManager.h" #include #include #include + +#include +#include #include -#include #include #include +#include #undef ZYPP_BASE_LOGGER_LOGGROUP #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::repomanager" @@ -30,6 +34,9 @@ using namespace zypp::repo; /////////////////////////////////////////////////////////////////// namespace zypp { + + ZYPP_BEGIN_LEGACY_API + /////////////////////////////////////////////////////////////////// /// \class RepoManager::Impl /// \brief RepoManager implementation. @@ -39,7 +46,9 @@ namespace zypp { public: Impl( zyppng::SyncContextRef &&ctx, RepoManagerOptions &&opt) { - _ngMgr = zyppng::SyncRepoManager::create( std::move(ctx), std::move(opt) ).unwrap(); + _ngMgr = zyppng::SyncRepoManager::create( std::move(ctx), std::move(opt) ); + _ngMgr->initialize().unwrap(); + sync(); } Impl(const Impl &) = delete; @@ -56,6 +65,47 @@ namespace zypp return *_ngMgr; } + zyppng::SyncRepoManagerRef ngMgrRef() { + return _ngMgr; + } + + void syncRepos() { + auto &ngRepos = _ngMgr->reposManip(); + _repos.clear(); + + // add repos we do not know yet + for ( const auto &r : ngRepos ) { + // COW semantics apply + zypp::RepoInfo tmp(r.second); + if ( _repos.count(tmp) == 0 ) + _repos.insert( std::move(tmp) ); + } + } + + void syncServices() { + auto &ngServices = _ngMgr->servicesManip(); + _services.clear(); + + // add repos we do not know yet + for ( const auto &s : ngServices ) { + // COW semantics apply + zypp::ServiceInfo tmp = s.second; + if ( _services.count(tmp) == 0 ) + _services.insert( std::move(tmp) ); + } + } + + void sync() { + // we need to keep source level compatibility, and because we return direct iterators + // into our service and repo sets we need to provide real sets of the legacy RepoInfo and ServiceInfo + // using sync'ed sets is the only way I could think of for now + syncRepos(); + syncServices(); + } + + ServiceSet _services; + RepoSet _repos; + private: zyppng::SyncRepoManagerRef _ngMgr; @@ -78,7 +128,7 @@ namespace zypp /////////////////////////////////////////////////////////////////// RepoManager::RepoManager( RepoManagerOptions opt ) - : _pimpl( new Impl( zyppng::SyncContext::defaultContext(), std::move(opt)) ) + : _pimpl( new Impl( zypp_detail::GlobalStateHelper::context(), std::move(opt)) ) {} RepoManager::~RepoManager() @@ -91,13 +141,18 @@ namespace zypp { return _pimpl->ngMgr().repoSize(); } RepoManager::RepoConstIterator RepoManager::repoBegin() const - { return _pimpl->ngMgr().repoBegin(); } + { return _pimpl->_repos.begin(); } RepoManager::RepoConstIterator RepoManager::repoEnd() const - { return _pimpl->ngMgr().repoEnd(); } + { return _pimpl->_repos.end(); } RepoInfo RepoManager::getRepo( const std::string & alias ) const - { return _pimpl->ngMgr().getRepo( alias ); } + { + const auto &optRepo = _pimpl->ngMgr().getRepo( alias ); + if ( !optRepo ) + return RepoInfo(); + return RepoInfo(*optRepo); + } bool RepoManager::hasRepo( const std::string & alias ) const { return _pimpl->ngMgr().hasRepo( alias ); } @@ -123,48 +178,55 @@ namespace zypp } RepoStatus RepoManager::metadataStatus( const RepoInfo & info ) const - { return _pimpl->ngMgr().metadataStatus( info ).unwrap(); } + { return _pimpl->ngMgr().metadataStatus( info.ngRepoInfo() ).unwrap(); } RepoManager::RefreshCheckStatus RepoManager::checkIfToRefreshMetadata( const RepoInfo &info, const Url &url, RawMetadataRefreshPolicy policy ) - { return _pimpl->ngMgr().checkIfToRefreshMetadata( info, url, policy ).unwrap(); } + { + auto res = _pimpl->ngMgr().checkIfToRefreshMetadata( const_cast(info).ngRepoInfo() , url, policy ).unwrap(); + const_cast(info).ngRepoInfo() = res.first; + _pimpl->syncRepos(); + return res.second; + } Pathname RepoManager::metadataPath( const RepoInfo &info ) const - { return _pimpl->ngMgr().metadataPath( info ).unwrap(); } + { return _pimpl->ngMgr().metadataPath( info.ngRepoInfo() ).unwrap(); } Pathname RepoManager::packagesPath( const RepoInfo &info ) const - { return _pimpl->ngMgr().packagesPath( info ).unwrap(); } + { return _pimpl->ngMgr().packagesPath( info.ngRepoInfo() ).unwrap(); } void RepoManager::refreshMetadata( const RepoInfo &info, RawMetadataRefreshPolicy policy, const ProgressData::ReceiverFnc & progressrcv ) { // Suppress (interactive) media::MediaChangeReport if we in have multiple basurls (>1) zypp::media::ScopedDisableMediaChangeReport guard( info.baseUrlsSize() > 1 ); - return _pimpl->ngMgr().refreshMetadata( info, policy, nullptr ).unwrap(); + const_cast(info).ngRepoInfo() = _pimpl->ngMgr().refreshMetadata( info.ngRepoInfo(), policy, nullptr ).unwrap(); + _pimpl->syncRepos(); } void RepoManager::cleanMetadata( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv ) - { return _pimpl->ngMgr().cleanMetadata( info, nullptr ).unwrap(); } + { return _pimpl->ngMgr().cleanMetadata( info.ngRepoInfo(), nullptr ).unwrap(); } void RepoManager::cleanPackages( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv ) - { return _pimpl->ngMgr().cleanPackages( info, nullptr ).unwrap(); } + { return _pimpl->ngMgr().cleanPackages( info.ngRepoInfo(), nullptr ).unwrap(); } RepoStatus RepoManager::cacheStatus( const RepoInfo &info ) const - { return _pimpl->ngMgr().cacheStatus( info ).unwrap(); } + { return _pimpl->ngMgr().cacheStatus( info.ngRepoInfo() ).unwrap(); } void RepoManager::buildCache( const RepoInfo &info, CacheBuildPolicy policy, const ProgressData::ReceiverFnc & progressrcv ) { callback::SendReport report; auto adapt = zyppng::ProgressObserverAdaptor( progressrcv, report ); - return _pimpl->ngMgr().buildCache( info, policy, adapt.observer() ).unwrap(); + const_cast(info).ngRepoInfo() = _pimpl->ngMgr().buildCache( const_cast(info).ngRepoInfo(), policy, adapt.observer() ).unwrap(); + _pimpl->syncRepos(); } void RepoManager::cleanCache( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv ) - { return _pimpl->ngMgr().cleanCache( info, nullptr ).unwrap(); } + { return _pimpl->ngMgr().cleanCache( info.ngRepoInfo(), nullptr ).unwrap(); } bool RepoManager::isCached( const RepoInfo &info ) const - { return _pimpl->ngMgr().isCached( info ).unwrap(); } + { return _pimpl->ngMgr().isCached( info.ngRepoInfo() ).unwrap(); } void RepoManager::loadFromCache( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv ) - { return _pimpl->ngMgr().loadFromCache( info, nullptr ).unwrap(); } + { return zypp_detail::GlobalStateHelper::pool ()->loadFromCache ( info.ngRepoInfo() , nullptr ).unwrap(); } void RepoManager::cleanCacheDirGarbage( const ProgressData::ReceiverFnc & progressrcv ) { return _pimpl->ngMgr().cleanCacheDirGarbage( nullptr ).unwrap(); } @@ -179,42 +241,39 @@ namespace zypp { callback::SendReport report; auto adapt = zyppng::ProgressObserverAdaptor( progressrcv, report ); - RepoInfo updatedRepo = _pimpl->ngMgr().addRepository( info, adapt.observer() ).unwrap(); - - // We should fix the API as we must inject those paths - // into the repoinfo in order to keep it usable. - RepoInfo & oinfo( const_cast(info) ); - oinfo.setFilepath( updatedRepo.filepath() ); - oinfo.setMetadataPath( zyppng::rawcache_path_for_repoinfo( _pimpl->ngMgr().options(), updatedRepo ).unwrap() ); - oinfo.setPackagesPath( zyppng::packagescache_path_for_repoinfo( _pimpl->ngMgr().options(), updatedRepo ).unwrap() ); + const_cast(info).ngRepoInfo() = _pimpl->ngMgr().addRepository( info.ngRepoInfo (), adapt.observer() ).unwrap(); + _pimpl->syncRepos(); } void RepoManager::addRepositories( const Url &url, const ProgressData::ReceiverFnc & progressrcv ) - { return _pimpl->ngMgr().addRepositories( url, nullptr ).unwrap(); } + { + _pimpl->ngMgr().addRepositories( url, nullptr ).unwrap(); + _pimpl->syncRepos(); + } void RepoManager::removeRepository( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv ) { callback::SendReport report; auto adapt = zyppng::ProgressObserverAdaptor( progressrcv, report ); - return _pimpl->ngMgr().removeRepository( info, adapt.observer() ).unwrap(); + _pimpl->ngMgr().removeRepository( const_cast(info).ngRepoInfo(), adapt.observer() ).unwrap(); + _pimpl->syncRepos(); } void RepoManager::modifyRepository( const std::string &alias, const RepoInfo & newinfo, const ProgressData::ReceiverFnc & progressrcv ) { - RepoInfo updated = _pimpl->ngMgr().modifyRepository( alias, newinfo, nullptr ).unwrap(); // We should fix the API as we must inject those paths // into the repoinfo in order to keep it usable. - RepoInfo & oinfo( const_cast(newinfo) ); - oinfo.setFilepath( updated.filepath()); - oinfo.setMetadataPath( zyppng::rawcache_path_for_repoinfo( _pimpl->ngMgr().options(), updated ).unwrap() ); - oinfo.setPackagesPath( zyppng::packagescache_path_for_repoinfo( _pimpl->ngMgr().options(), updated ).unwrap() ); + const_cast(newinfo).ngRepoInfo() = _pimpl->ngMgr().modifyRepository( alias, newinfo.ngRepoInfo(), nullptr ).unwrap(); + _pimpl->syncRepos(); } RepoInfo RepoManager::getRepositoryInfo( const std::string &alias, const ProgressData::ReceiverFnc & progressrcv ) - { return _pimpl->ngMgr().getRepositoryInfo( alias ).unwrap(); } + { + return RepoInfo(_pimpl->ngMgr().getRepositoryInfo( alias ).unwrap()); + } RepoInfo RepoManager::getRepositoryInfo( const Url & url, const url::ViewOption & urlview, const ProgressData::ReceiverFnc & progressrcv ) - { return _pimpl->ngMgr().getRepositoryInfo( url, urlview ).unwrap(); } + { return RepoInfo(_pimpl->ngMgr().getRepositoryInfo( url, urlview ).unwrap()); } bool RepoManager::serviceEmpty() const { return _pimpl->ngMgr().serviceEmpty(); } @@ -223,13 +282,17 @@ namespace zypp { return _pimpl->ngMgr().serviceSize(); } RepoManager::ServiceConstIterator RepoManager::serviceBegin() const - { return _pimpl->ngMgr().serviceBegin(); } + { return _pimpl->_services.begin(); } RepoManager::ServiceConstIterator RepoManager::serviceEnd() const - { return _pimpl->ngMgr().serviceEnd(); } + { return _pimpl->_services.end(); } ServiceInfo RepoManager::getService( const std::string & alias ) const - { return _pimpl->ngMgr().getService( alias ); } + { + const auto &optService = _pimpl->ngMgr().getService( alias ); + if ( !optService ) return ServiceInfo(); + return ServiceInfo(*optService); + } bool RepoManager::hasService( const std::string & alias ) const { return _pimpl->ngMgr().hasService( alias ); } @@ -238,31 +301,57 @@ namespace zypp { return _pimpl->ngMgr().probeService( url ).unwrap(); } void RepoManager::addService( const std::string & alias, const Url& url ) - { return _pimpl->ngMgr().addService( alias, url ).unwrap(); } + { + _pimpl->ngMgr().addService( alias, url ).unwrap(); + _pimpl->syncServices(); + } void RepoManager::addService( const ServiceInfo & service ) - { return _pimpl->ngMgr().addService( service ).unwrap(); } + { + _pimpl->ngMgr().addService( service.ngServiceInfo() ).unwrap(); + _pimpl->syncServices(); + } void RepoManager::removeService( const std::string & alias ) - { return _pimpl->ngMgr().removeService( alias ).unwrap(); } + { + _pimpl->ngMgr().removeService( alias ).unwrap(); + _pimpl->syncServices(); + } void RepoManager::removeService( const ServiceInfo & service ) - { return _pimpl->ngMgr().removeService( service ).unwrap(); } + { + _pimpl->ngMgr().removeService( service.ngServiceInfo() ).unwrap(); + _pimpl->syncServices(); + } void RepoManager::refreshServices( const RefreshServiceOptions & options_r ) - { return _pimpl->ngMgr().refreshServices( options_r ).unwrap(); } + { + _pimpl->ngMgr().refreshServices( options_r ).unwrap(); + _pimpl->sync(); + } void RepoManager::refreshService( const std::string & alias, const RefreshServiceOptions & options_r ) - { return _pimpl->ngMgr().refreshService( alias, options_r ).unwrap(); } + { + _pimpl->ngMgr().refreshService( alias, options_r ).unwrap(); + _pimpl->sync(); + } void RepoManager::refreshService( const ServiceInfo & service, const RefreshServiceOptions & options_r ) - { return _pimpl->ngMgr().refreshService( service, options_r ).unwrap(); } + { + _pimpl->ngMgr().refreshService( service.ngServiceInfo(), options_r ).unwrap(); + _pimpl->sync(); + } void RepoManager::modifyService( const std::string & oldAlias, const ServiceInfo & service ) - { return _pimpl->ngMgr().modifyService( oldAlias, service ).unwrap(); } + { + _pimpl->ngMgr().modifyService( oldAlias, service.ngServiceInfo() ).unwrap(); + _pimpl->syncServices(); + } void RepoManager::refreshGeoIp (const RepoInfo::url_set &urls) - { (void) _pimpl->ngMgr().refreshGeoIp( urls ); } + { + (void) zyppng::RepoManagerWorkflow::refreshGeoIPData( _pimpl->ngMgr().zyppContext(), urls); + } //////////////////////////////////////////////////////////////////////////// @@ -271,9 +360,17 @@ namespace zypp std::list readRepoFile(const Url &repo_file) { - return zyppng::RepoManagerWorkflow::readRepoFile( zyppng::SyncContext::defaultContext (), repo_file ).unwrap(); + std::list rIs; + + auto ngList = zyppng::RepoManagerWorkflow::readRepoFile( zypp_detail::GlobalStateHelper::context(), repo_file ).unwrap(); + for ( const auto &ngRi : ngList ) + rIs.push_back( zypp::RepoInfo(ngRi) ); + + return rIs; } + ZYPP_END_LEGACY_API + ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// diff --git a/zypp/RepoManager.h b/zypp/RepoManager.h index b274a87b4c..1a00716776 100644 --- a/zypp/RepoManager.h +++ b/zypp/RepoManager.h @@ -36,6 +36,8 @@ namespace zypp { ///////////////////////////////////////////////////////////////// + ZYPP_BEGIN_LEGACY_API + /** * Parses \a repo_file and returns a list of \ref RepoInfo objects * corresponding to repositories found within the file. @@ -49,7 +51,7 @@ namespace zypp * \throws ParseException If the file parsing fails * \throws Exception On other errors. */ - std::list readRepoFile(const Url & repo_file) ZYPP_API; + std::list readRepoFile( const Url & repo_file ) ZYPP_INTERNAL_DEPRECATE ZYPP_API; /** * \short creates and provides information about known sources. @@ -661,6 +663,8 @@ namespace zypp inline Iterable RepoManager::services() const { return makeIterable( serviceBegin(), serviceEnd() ); } + ZYPP_END_LEGACY_API + ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// diff --git a/zypp/RepoManagerOptions.cc b/zypp/RepoManagerOptions.cc index 402e01aee5..987c9bc61e 100644 --- a/zypp/RepoManagerOptions.cc +++ b/zypp/RepoManagerOptions.cc @@ -12,6 +12,8 @@ #include "RepoManagerOptions.h" #include +#include +#include namespace zypp { @@ -21,7 +23,8 @@ namespace zypp // //////////////////////////////////////////////////////////////////// - RepoManagerOptions::RepoManagerOptions( const Pathname & root_r ) + ZYPP_BEGIN_LEGACY_API + RepoManagerOptions::RepoManagerOptions( const Pathname & root_r ) : probe(ZConfig::instance().repo_add_probe()) { repoCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoCachePath() ); repoRawCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoMetadataPath() ); @@ -30,13 +33,30 @@ namespace zypp knownReposPath = Pathname::assertprefix( root_r, ZConfig::instance().knownReposPath() ); knownServicesPath = Pathname::assertprefix( root_r, ZConfig::instance().knownServicesPath() ); pluginsPath = Pathname::assertprefix( root_r, ZConfig::instance().pluginsPath() ); - probe = ZConfig::instance().repo_add_probe(); + rootDir = root_r; + context = zypp_detail::GlobalStateHelper::context(); + } + ZYPP_END_LEGACY_API + + RepoManagerOptions::RepoManagerOptions( zyppng::ContextBaseRef ctx ) + : probe(ctx->config().repo_add_probe()) + , context(ctx) + { + rootDir = ctx->contextRoot(); + repoCachePath = Pathname::assertprefix( rootDir, ctx->config().repoCachePath() ); + repoRawCachePath = Pathname::assertprefix( rootDir, ctx->config().repoMetadataPath() ); + repoSolvCachePath = Pathname::assertprefix( rootDir, ctx->config().repoSolvfilesPath() ); + repoPackagesCachePath = Pathname::assertprefix( rootDir, ctx->config().repoPackagesPath() ); + knownReposPath = Pathname::assertprefix( rootDir, ctx->config().knownReposPath() ); + knownServicesPath = Pathname::assertprefix( rootDir, ctx->config().knownServicesPath() ); + pluginsPath = Pathname::assertprefix( rootDir, ctx->config().pluginsPath() ); } RepoManagerOptions RepoManagerOptions::makeTestSetup( const Pathname & root_r ) { + ZYPP_BEGIN_LEGACY_API RepoManagerOptions ret; ret.repoCachePath = root_r; ret.repoRawCachePath = root_r/"raw"; @@ -46,6 +66,7 @@ namespace zypp ret.knownServicesPath = root_r/"services.d"; ret.pluginsPath = root_r/"plugins"; ret.rootDir = root_r; + ZYPP_END_LEGACY_API return ret; } diff --git a/zypp/RepoManagerOptions.h b/zypp/RepoManagerOptions.h index fa37c646f6..069f635882 100644 --- a/zypp/RepoManagerOptions.h +++ b/zypp/RepoManagerOptions.h @@ -16,6 +16,10 @@ #include #include +namespace zyppng { + ZYPP_FWD_DECL_TYPE_WITH_REFS (ContextBase); +} + namespace zypp { /** @@ -35,7 +39,21 @@ namespace zypp * \knownReposPath * \endcode */ - RepoManagerOptions( const Pathname & root_r = Pathname() ); + RepoManagerOptions( const Pathname & root_r = Pathname() ) ZYPP_INTERNAL_DEPRECATE; + + + /** Default ctor following \ref ZConfig global settings. + * If an optional \c root_r directory is given, all paths will + * be prefixed accordingly. + * \code + * ctx->contextRoot() \repoCachePath + * \repoRawCachePath + * \repoSolvCachePath + * \repoPackagesCachePath + * \knownReposPath + * \endcode + */ + RepoManagerOptions( zyppng::ContextBaseRef ctx ); /** Test setup adjusting all paths to be located below one \c root_r directory. * \code @@ -66,6 +84,9 @@ namespace zypp /** remembers root_r value for later use */ Pathname rootDir; + + /** remember the context we want to use */ + zyppng::ContextBaseWeakRef context; }; std::ostream & operator<<( std::ostream & str, const RepoManagerOptions & obj ); diff --git a/zypp/RepoStatus.cc b/zypp/RepoStatus.cc index f0756b4dd4..bbac78e511 100644 --- a/zypp/RepoStatus.cc +++ b/zypp/RepoStatus.cc @@ -19,6 +19,7 @@ #include #include #include +#include using std::endl; @@ -192,12 +193,18 @@ namespace zypp } } - RepoStatus::RepoStatus( const RepoInfo & info_r ) + ZYPP_BEGIN_LEGACY_API + RepoStatus::RepoStatus( const RepoInfo & info_r ) : RepoStatus( info_r.ngRepoInfo() ) + { } + ZYPP_END_LEGACY_API + + RepoStatus::RepoStatus( const zyppng::RepoInfo & info_r ) : _pimpl( new Impl() ) { _pimpl->assignFromCtor( CheckSum::sha1FromString( info_r.url().asString() ).checksum(), Date() ); } + RepoStatus::RepoStatus( std::string checksum_r, Date timestamp_r ) : _pimpl( new Impl() ) { diff --git a/zypp/RepoStatus.h b/zypp/RepoStatus.h index 7aaf2c72fc..f4acdd00ca 100644 --- a/zypp/RepoStatus.h +++ b/zypp/RepoStatus.h @@ -17,6 +17,10 @@ #include #include +namespace zyppng { + class RepoInfo; +} + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -56,8 +60,13 @@ namespace zypp */ explicit RepoStatus( const Pathname & path_r ); +ZYPP_BEGIN_LEGACY_API /** Compute status of a \a RepoInfo to track changes requiring a refresh. */ explicit RepoStatus( const RepoInfo & info_r ); +ZYPP_END_LEGACY_API + + /** Compute status of a \a RepoInfo to track changes requiring a refresh. */ + explicit RepoStatus( const zyppng::RepoInfo & info_r ); /** Explicitly specify checksum string and timestamp to use. */ RepoStatus( std::string checksum_r, Date timestamp_r ); diff --git a/zypp/Repository.cc b/zypp/Repository.cc index f28e2f3403..b44747f7d2 100644 --- a/zypp/Repository.cc +++ b/zypp/Repository.cc @@ -27,6 +27,8 @@ #include #include +#include + using std::endl; /////////////////////////////////////////////////////////////////// @@ -66,10 +68,20 @@ namespace zypp } std::string Repository::name() const - { return info().name(); } + { + const auto &info = ngInfo(); + if ( info ) + return info->name(); + return std::string(); + } std::string Repository::label() const - { return info().label(); } + { + const auto &info = ngInfo(); + if ( info ) + return info->label(); + return std::string(); + } int Repository::satInternalPriority() const { @@ -271,13 +283,24 @@ namespace zypp return ProductInfoIterator(); } + const std::optional &Repository::ngInfo() const + { + NO_REPOSITORY_RETURN( zyppng::RepoInfo::nullRepo() ); + return myPool().repoInfo( _repo ); + } + + ZYPP_BEGIN_LEGACY_API RepoInfo Repository::info() const { NO_REPOSITORY_RETURN( RepoInfo() ); - return myPool().repoInfo( _repo ); + const auto &i = myPool().repoInfo( _repo ); + if ( i ) + return RepoInfo(*i); + return RepoInfo(); } + ZYPP_END_LEGACY_API - void Repository::setInfo( const RepoInfo & info_r ) + void Repository::setInfo( const zyppng::RepoInfo & info_r ) { NO_REPOSITORY_THROW( Exception( "Can't set RepoInfo for norepo." ) ); if ( info_r.alias() != alias() ) @@ -289,10 +312,17 @@ namespace zypp MIL << *this << endl; } + ZYPP_BEGIN_LEGACY_API + void Repository::setInfo( const RepoInfo & info_r ) + { + setInfo( info_r.ngRepoInfo() ); + } + ZYPP_END_LEGACY_API + void Repository::clearInfo() { NO_REPOSITORY_RETURN(); - myPool().setRepoInfo( _repo, RepoInfo() ); + myPool().eraseRepoInfo( _repo ); } void Repository::eraseFromPool() diff --git a/zypp/Repository.h b/zypp/Repository.h index 67147a9d8c..5804cc8368 100644 --- a/zypp/Repository.h +++ b/zypp/Repository.h @@ -22,6 +22,12 @@ #include #include +#include + +namespace zyppng { + class RepoInfo; +} + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -251,15 +257,22 @@ namespace zypp Iterable updatesProduct() const; public: - /** Return any associated \ref RepoInfo. */ - RepoInfo info() const; +#ifdef __cpp_lib_optional + const std::optional &ngInfo() const; +#endif /** Set \ref RepoInfo for this repository. * \throws Exception if this is \ref noRepository * \throws Exception if the \ref RepoInfo::alias * does not match the \ref Repository::name. */ - void setInfo( const RepoInfo & info_r ); + void setInfo( const zyppng::RepoInfo &info_r ); + + ZYPP_BEGIN_LEGACY_API + void ZYPP_INTERNAL_DEPRECATE setInfo( const RepoInfo & info_r ); + /** Return any associated \ref RepoInfo. */ + RepoInfo ZYPP_INTERNAL_DEPRECATE info() const; + ZYPP_END_LEGACY_API /** Remove any \ref RepoInfo set for this repository. */ void clearInfo(); diff --git a/zypp/ResFilters.cc b/zypp/ResFilters.cc new file mode 100644 index 0000000000..bde9d139cc --- /dev/null +++ b/zypp/ResFilters.cc @@ -0,0 +1,20 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "ResFilters.h" +#include + +namespace zypp { + resfilter::ByRepository::ByRepository(Repository repository_r) + : _alias(repository_r.ngInfo() ? repository_r.ngInfo()->alias() : "" ) {} + resfilter::ByRepository::ByRepository(std::string alias_r) + : _alias(std::move(alias_r)) {} + bool resfilter::ByRepository::operator()(const ResObject::constPtr &p) const { + return (p->ngRepoInfo() ? p->ngRepoInfo()->alias() : "" ) == _alias; + } +} // namespace zypp diff --git a/zypp/ResFilters.h b/zypp/ResFilters.h index f52e05f490..dfa02d6ff0 100644 --- a/zypp/ResFilters.h +++ b/zypp/ResFilters.h @@ -166,20 +166,13 @@ namespace zypp }; /** Select ResObject by repository or repository alias. */ - struct ByRepository + struct ZYPP_API ByRepository { - ByRepository( Repository repository_r ) - : _alias( repository_r.info().alias() ) - {} + ByRepository(Repository repository_r); - ByRepository( std::string alias_r ) - : _alias(std::move( alias_r )) - {} + ByRepository(std::string alias_r); - bool operator()( const ResObject::constPtr& p ) const - { - return p->repoInfo().alias() == _alias; - } + bool operator()(const ResObject::constPtr &p) const; std::string _alias; }; diff --git a/zypp/ServiceInfo.cc b/zypp/ServiceInfo.cc index 0ad9b08a0a..f5c1e4e59c 100644 --- a/zypp/ServiceInfo.cc +++ b/zypp/ServiceInfo.cc @@ -6,237 +6,178 @@ | /_____||_| |_| |_| | | | \---------------------------------------------------------------------*/ -/** \file zypp/ServiceInfo.cc - * - */ -#include -#include - -#include -#include -#include - -#include -#include - -using std::endl; -using zypp::xml::escape; - -/////////////////////////////////////////////////////////////////////////////// -namespace zypp -{////////////////////////////////////////////////////////////////////////////// - - /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : ServiceInfo::Impl - // - struct ServiceInfo::Impl + +#include "ServiceInfo.h" +#include +#include + +ZYPP_BEGIN_LEGACY_API + +namespace zypp { + + const ServiceInfo ServiceInfo::noService( zyppng::ServiceInfo(nullptr) ); + + ServiceInfo::ServiceInfo( ) + : _pimpl( new zyppng::ServiceInfo( zypp_detail::GlobalStateHelper::context() ) ) + { } + + ServiceInfo::ServiceInfo( const zyppng::ServiceInfo &i ) + : _pimpl( std::make_unique(i) ) + { } + + ServiceInfo::ServiceInfo( const ServiceInfo &other ) + : _pimpl( std::make_unique(*other._pimpl) ) + { } + + ServiceInfo::ServiceInfo(ServiceInfo &&other) + : _pimpl( std::move(other._pimpl) ) + , _ownsPimpl( other._ownsPimpl ) + { } + + ServiceInfo &ServiceInfo::operator=(const ServiceInfo &other) + { + _pimpl = std::make_unique(*other._pimpl); + _ownsPimpl = true; + return *this; + } + + ServiceInfo &ServiceInfo::operator=(ServiceInfo &&other) { - using ReposToEnable = ServiceInfo::ReposToEnable; - using ReposToDisable = ServiceInfo::ReposToDisable; - - public: - RepoVariablesReplacedUrl _url; - repo::ServiceType _type; - ReposToEnable _reposToEnable; - ReposToDisable _reposToDisable; - RepoStates _repoStates; - DefaultIntegral _ttl; - Date _lrf; - - public: - Impl() - {} - - Impl(const Url &url_r) : _url(url_r) {} - - Impl(const Impl &) = default; - Impl(Impl &&) = delete; - Impl &operator=(const Impl &) = delete; - Impl &operator=(Impl &&) = delete; - - ~Impl() - {} - - void setProbedType( const repo::ServiceType & type_r ) const - { - if ( _type == repo::ServiceType::NONE - && type_r != repo::ServiceType::NONE ) - { - // lazy init! - const_cast(this)->_type = type_r; - } - } - - private: - friend Impl * rwcowClone( const Impl * rhs ); - - /** clone for RWCOW_pointer */ - Impl * clone() const - { return new Impl( *this ); } - }; - /////////////////////////////////////////////////////////////////// - - - /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : ServiceInfo::Impl - // - /////////////////////////////////////////////////////////////////// - - const ServiceInfo ServiceInfo::noService; - - ServiceInfo::ServiceInfo() : _pimpl( new Impl() ) {} - - ServiceInfo::ServiceInfo(const std::string & alias) - : repo::RepoInfoBase(alias), _pimpl( new Impl() ) - {} - - ServiceInfo::ServiceInfo(const std::string & alias, const Url & url) - : repo::RepoInfoBase(alias), _pimpl( new Impl(url) ) - {} + _pimpl = std::move(other._pimpl); + _ownsPimpl = other._ownsPimpl; + return *this; + } + + ServiceInfo::ServiceInfo( const std::string & alias ) : _pimpl( new zyppng::ServiceInfo( zypp_detail::GlobalStateHelper::context(), alias ) ) {} + + ServiceInfo::ServiceInfo( const std::string & alias, const zypp::Url & url ) : _pimpl( new zyppng::ServiceInfo( zypp_detail::GlobalStateHelper::context(), alias, url ) ) {} ServiceInfo::~ServiceInfo() - {} + { + if ( !_ownsPimpl ) _pimpl.release(); + } + + zypp::Url ServiceInfo::url() const + { return _pimpl->url(); } + + zypp::Url ServiceInfo::rawUrl() const + { return _pimpl->rawUrl(); } + + void ServiceInfo::setUrl( const zypp::Url& url ) + { _pimpl->setUrl(url); } + + zypp::repo::ServiceType ServiceInfo::type() const + { return _pimpl->type(); } + + void ServiceInfo::setType( const zypp::repo::ServiceType & type ) + { _pimpl->setType(type); } - Url ServiceInfo::url() const // Variables replaced - { return _pimpl->_url.transformed(); } + void ServiceInfo::setProbedType( const zypp::repo::ServiceType &t ) const + { _pimpl->setProbedType( t ); } - Url ServiceInfo::rawUrl() const // Raw - { return _pimpl->_url.raw(); } + zypp::Date::Duration ServiceInfo::ttl() const + { return _pimpl->ttl(); } - void ServiceInfo::setUrl( const Url& url ) // Raw - { _pimpl->_url.raw() = url; } + void ServiceInfo::setTtl( zypp::Date::Duration ttl_r ) + { return _pimpl->setTtl(ttl_r); } - repo::ServiceType ServiceInfo::type() const { return _pimpl->_type; } - void ServiceInfo::setType( const repo::ServiceType & type ) { _pimpl->_type = type; } - void ServiceInfo::setProbedType( const repo::ServiceType &t ) const { _pimpl->setProbedType( t ); } + void ServiceInfo::setProbedTtl( zypp::Date::Duration ttl_r ) const + { _pimpl->setProbedTtl(ttl_r); } - Date::Duration ServiceInfo::ttl() const { return _pimpl->_ttl; } - void ServiceInfo::setTtl( Date::Duration ttl_r ) { _pimpl->_ttl = ttl_r; } - void ServiceInfo::setProbedTtl( Date::Duration ttl_r ) const { const_cast(this)->setTtl( ttl_r ); } + zypp::Date ServiceInfo::lrf() const + { return _pimpl->lrf(); } - Date ServiceInfo::lrf() const { return _pimpl->_lrf; } - void ServiceInfo::setLrf( Date lrf_r ) { _pimpl->_lrf = lrf_r; } + void ServiceInfo::setLrf( zypp::Date lrf_r ) + { _pimpl->setLrf(lrf_r); } - bool ServiceInfo::reposToEnableEmpty() const { return _pimpl->_reposToEnable.empty(); } - ServiceInfo::ReposToEnable::size_type ServiceInfo::reposToEnableSize() const { return _pimpl->_reposToEnable.size(); } - ServiceInfo::ReposToEnable::const_iterator ServiceInfo::reposToEnableBegin() const { return _pimpl->_reposToEnable.begin(); } - ServiceInfo::ReposToEnable::const_iterator ServiceInfo::reposToEnableEnd() const { return _pimpl->_reposToEnable.end(); } + bool ServiceInfo::reposToEnableEmpty() const + { return _pimpl->reposToEnableEmpty(); } + + ServiceInfo::ReposToEnable::size_type ServiceInfo::reposToEnableSize() const + { return _pimpl->reposToEnableSize(); } + + ServiceInfo::ReposToEnable::const_iterator ServiceInfo::reposToEnableBegin() const + { return _pimpl->reposToEnableBegin(); } + + ServiceInfo::ReposToEnable::const_iterator ServiceInfo::reposToEnableEnd() const + { return _pimpl->reposToEnableEnd(); } bool ServiceInfo::repoToEnableFind( const std::string & alias_r ) const - { return( _pimpl->_reposToEnable.find( alias_r ) != _pimpl->_reposToEnable.end() ); } + { return _pimpl->repoToEnableFind(alias_r); } void ServiceInfo::addRepoToEnable( const std::string & alias_r ) - { - _pimpl->_reposToEnable.insert( alias_r ); - _pimpl->_reposToDisable.erase( alias_r ); - } + { _pimpl->addRepoToEnable(alias_r); } void ServiceInfo::delRepoToEnable( const std::string & alias_r ) - { _pimpl->_reposToEnable.erase( alias_r ); } + { _pimpl->delRepoToEnable(alias_r); } void ServiceInfo::clearReposToEnable() - { _pimpl->_reposToEnable.clear(); } + { _pimpl->clearReposToEnable(); } + + bool ServiceInfo::reposToDisableEmpty() const + { return _pimpl->reposToDisableEmpty(); } + ServiceInfo::ReposToDisable::size_type ServiceInfo::reposToDisableSize() const + { return _pimpl->reposToDisableSize(); } - bool ServiceInfo::reposToDisableEmpty() const { return _pimpl->_reposToDisable.empty(); } - ServiceInfo::ReposToDisable::size_type ServiceInfo::reposToDisableSize() const { return _pimpl->_reposToDisable.size(); } - ServiceInfo::ReposToDisable::const_iterator ServiceInfo::reposToDisableBegin() const { return _pimpl->_reposToDisable.begin(); } - ServiceInfo::ReposToDisable::const_iterator ServiceInfo::reposToDisableEnd() const { return _pimpl->_reposToDisable.end(); } + ServiceInfo::ReposToDisable::const_iterator ServiceInfo::reposToDisableBegin() const + { return _pimpl->reposToDisableBegin(); } + + ServiceInfo::ReposToDisable::const_iterator ServiceInfo::reposToDisableEnd() const + { return _pimpl->reposToDisableEnd(); } bool ServiceInfo::repoToDisableFind( const std::string & alias_r ) const - { return( _pimpl->_reposToDisable.find( alias_r ) != _pimpl->_reposToDisable.end() ); } + { return _pimpl->repoToDisableFind( alias_r ); } void ServiceInfo::addRepoToDisable( const std::string & alias_r ) - { - _pimpl->_reposToDisable.insert( alias_r ); - _pimpl->_reposToEnable.erase( alias_r ); - } + { return _pimpl->addRepoToDisable(alias_r); } void ServiceInfo::delRepoToDisable( const std::string & alias_r ) - { _pimpl->_reposToDisable.erase( alias_r ); } + { return _pimpl->delRepoToDisable(alias_r); } void ServiceInfo::clearReposToDisable() - { _pimpl->_reposToDisable.clear(); } + { _pimpl->clearReposToDisable(); } + const ServiceInfo::RepoStates & ServiceInfo::repoStates() const + { return _pimpl->repoStates(); } - const ServiceInfo::RepoStates & ServiceInfo::repoStates() const { return _pimpl->_repoStates; } - void ServiceInfo::setRepoStates( RepoStates newStates_r ) { swap( _pimpl->_repoStates, newStates_r ); } + void ServiceInfo::setRepoStates( RepoStates newStates_r ) + { _pimpl->setRepoStates( std::move(newStates_r) ); } + std::ostream & ServiceInfo::dumpAsIniOn( std::ostream & str ) const + { + return _pimpl->dumpAsIniOn(str); + } - std::ostream & operator<<( std::ostream & str, const ServiceInfo::RepoState & obj ) + std::ostream & ServiceInfo::dumpAsXmlOn( std::ostream & str, const std::string & content ) const { - return str - << "enabled=" << obj.enabled << " " - << "autorefresh=" << obj.autorefresh << " " - << "priority=" << obj.priority; + return _pimpl->dumpAsXmlOn(str, content); } - std::ostream & ServiceInfo::dumpAsIniOn( std::ostream & str ) const + zyppng::ServiceInfo &ServiceInfo::ngServiceInfo() { - RepoInfoBase::dumpAsIniOn(str) - << "url = " << hotfix1050625::asString( rawUrl() ) << endl - << "type = " << type() << endl; - - if ( ttl() ) - str << "ttl_sec = " << ttl() << endl; - - if ( lrf() ) - str << "lrf_dat = " << lrf().asSeconds() << endl; - - if ( ! repoStates().empty() ) - { - unsigned cnt = 0U; - for ( const auto & el : repoStates() ) - { - std::string tag( "repo_" ); - tag += str::numstring( ++cnt ); - const RepoState & state( el.second ); - - str << tag << "=" << el.first << endl - << tag << "_enabled=" << state.enabled << endl - << tag << "_autorefresh=" << state.autorefresh << endl; - if ( state.priority != RepoInfo::defaultPriority() ) - str - << tag << "_priority=" << state.priority << endl; - } - } - - if ( ! reposToEnableEmpty() ) - str << "repostoenable = " << str::joinEscaped( reposToEnableBegin(), reposToEnableEnd() ) << endl; - if ( ! reposToDisableEmpty() ) - str << "repostodisable = " << str::joinEscaped( reposToDisableBegin(), reposToDisableEnd() ) << endl; - return str; + return *_pimpl; } - std::ostream & ServiceInfo::dumpAsXmlOn( std::ostream & str, const std::string & content ) const + const zyppng::ServiceInfo &ServiceInfo::ngServiceInfo() const + { + return *_pimpl; + } + + zyppng::repo::RepoInfoBase &ServiceInfo::pimpl() { - str - << "" << endl; - else - str << ">" << endl << content << "" << endl; - - return str; + return *_pimpl; } + const zyppng::repo::RepoInfoBase &ServiceInfo::pimpl() const + { + return *_pimpl; + } std::ostream & operator<<( std::ostream& str, const ServiceInfo &obj ) { return obj.dumpAsIniOn(str); } +} - -/////////////////////////////////////////////////////////////////////////////// -} //namespace zypp -/////////////////////////////////////////////////////////////////////////////// +ZYPP_END_LEGACY_API diff --git a/zypp/ServiceInfo.h b/zypp/ServiceInfo.h index 5e046999a8..d58eecaf83 100644 --- a/zypp/ServiceInfo.h +++ b/zypp/ServiceInfo.h @@ -19,9 +19,16 @@ #include #include +#include #include #include +namespace zyppng { + class ServiceInfo; +} + +ZYPP_BEGIN_LEGACY_API + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -33,12 +40,19 @@ namespace zypp /// \note Name and Url are subject to repo variable replacement /// (\see \ref RepoVariablesStringReplacer). /// - class ZYPP_API ServiceInfo : public repo::RepoInfoBase + class ZYPP_API ZYPP_INTERNAL_DEPRECATE ServiceInfo : public repo::RepoInfoBase { public: /** Default ctor creates \ref noService.*/ ServiceInfo(); + ServiceInfo( const zyppng::ServiceInfo &i ); + + ServiceInfo(const ServiceInfo &other); + ServiceInfo(ServiceInfo &&other); + ServiceInfo &operator=(const ServiceInfo &other); + ServiceInfo &operator=(ServiceInfo &&other); + /** * Creates ServiceInfo with specified alias. * @@ -157,31 +171,7 @@ namespace zypp void clearReposToDisable(); //@} - /** \name The original repo state as defined by the repoindex.xml upon last refresh. - * - * This state is remembered to detect any user modifications applied to the repos. - * It may not be available for all repos or in plugin services. In this case all - * changes requested by a service refresh are applied unconditionally. - */ - //@{ - struct RepoState - { - bool enabled; - bool autorefresh; - unsigned priority; - - RepoState() - : enabled( false ), autorefresh( true ), priority( RepoInfo::defaultPriority() ) - {} - RepoState( const RepoInfo & repo_r ) - : enabled( repo_r.enabled() ), autorefresh( repo_r.autorefresh() ), priority( repo_r.priority() ) - {} - bool operator==( const RepoState & rhs ) const - { return( enabled==rhs.enabled && autorefresh==rhs.autorefresh && priority==rhs.priority ); } - bool operator!=( const RepoState & rhs ) const - { return ! operator==( rhs ); } - friend std::ostream & operator<<( std::ostream & str, const RepoState & obj ); - }; + using RepoState = ServiceRepoState; using RepoStates = std::map; /** Access the remembered repository states. */ @@ -208,10 +198,17 @@ namespace zypp */ std::ostream & dumpAsXmlOn( std::ostream & str, const std::string & content = "" ) const override; - struct Impl; + + zyppng::ServiceInfo &ngServiceInfo(); + const zyppng::ServiceInfo &ngServiceInfo() const; + private: - RWCOW_pointer _pimpl; + zyppng::repo::RepoInfoBase &pimpl() override; + const zyppng::repo::RepoInfoBase &pimpl() const override; + + std::unique_ptr _pimpl; + bool _ownsPimpl = true; }; /////////////////////////////////////////////////////////////////// @@ -222,11 +219,24 @@ namespace zypp /** \relates ServiceInfo */ using ServiceInfoList = std::list; + /** \relates RepoInfoBase */ + inline bool operator==( const ServiceInfo & lhs, const ServiceInfo & rhs ) + { return lhs.alias() == rhs.alias(); } + + /** \relates RepoInfoBase */ + inline bool operator!=( const ServiceInfo & lhs, const ServiceInfo & rhs ) + { return lhs.alias() != rhs.alias(); } + + inline bool operator<( const ServiceInfo & lhs, const ServiceInfo & rhs ) + { return lhs.alias() < rhs.alias(); } + /** \relates ServiceInfo Stream output */ std::ostream & operator<<( std::ostream & str, const ServiceInfo & obj ) ZYPP_API; ///////////////////////////////////////////////////////////////// } // namespace zypp -/////////////////////////////////////////////////////////////////// -#endif // ZYPP_SAT_REPOSITORY_H + +ZYPP_END_LEGACY_API + +#endif // ZYPP_SERVICE_H diff --git a/zypp/SrcPackage.cc b/zypp/SrcPackage.cc index 07439ec486..8635760d12 100644 --- a/zypp/SrcPackage.cc +++ b/zypp/SrcPackage.cc @@ -10,12 +10,13 @@ * */ #include +#include /////////////////////////////////////////////////////////////////// namespace zyppintern { using namespace zypp; // in Package.cc - Pathname cachedLocation( const OnMediaLocation & loc_r, const RepoInfo & repo_r ); + Pathname cachedLocation( const OnMediaLocation & loc_r, const zyppng::RepoInfo & repo_r ); } // namespace zyppintern /////////////////////////////////////////////////////////////////// @@ -55,7 +56,12 @@ namespace zypp { return lookupLocation(); } Pathname SrcPackage::cachedLocation() const - { return zyppintern::cachedLocation( location(), repoInfo() ); } + { + const auto &optRepoInfo = ngRepoInfo (); + if ( !optRepoInfo ) + return Pathname(); + return zyppintern::cachedLocation( location(), *optRepoInfo ); + } ///////////////////////////////////////////////////////////////// } // namespace zypp diff --git a/zypp/Target.h b/zypp/Target.h index b0e6fa2936..91830be3cf 100644 --- a/zypp/Target.h +++ b/zypp/Target.h @@ -23,6 +23,11 @@ #include #include +namespace zyppng { + template + class FusionPool; +} + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -237,6 +242,7 @@ namespace zypp private: /** Direct access to Impl. */ friend class zypp_detail::ZYppImpl; + template friend class zyppng::FusionPool; /** Pointer to implementation */ RW_pointer > _pimpl; diff --git a/zypp/ZConfig.cc b/zypp/ZConfig.cc index c3558542c5..cd5001d26d 100644 --- a/zypp/ZConfig.cc +++ b/zypp/ZConfig.cc @@ -37,6 +37,8 @@ extern "C" #include #include +#include +#include using std::endl; using namespace zypp::filesystem; @@ -45,6 +47,8 @@ using namespace zypp::parser; #undef ZYPP_BASE_LOGGER_LOGGROUP #define ZYPP_BASE_LOGGER_LOGGROUP "zconfig" +#warning "Still need to sync MediaConfig::systemConfig and the one in ZConfig::systemConfig" + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -318,12 +322,6 @@ namespace zypp return target ? target->root() : Pathname(); } - inline Pathname _autodetectZyppConfPath() - { - const char *env_confpath = getenv( "ZYPP_CONF" ); - return env_confpath ? env_confpath : "/etc/zypp/zypp.conf"; - } - ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// @@ -483,8 +481,8 @@ namespace zypp }; public: - Impl() - : _parsedZyppConf ( _autodetectZyppConfPath() ) + Impl( Pathname &&confPath ) + : _parsedZyppConf ( std::move(confPath) ) , cfg_arch ( defaultSystemArchitecture() ) , cfg_textLocale ( defaultTextLocale() ) , cfg_cache_path { "/var/cache/zypp" } @@ -505,8 +503,9 @@ namespace zypp , pkgGpgCheck ( indeterminate ) , apply_locks_file ( true ) , pluginsPath ( "/usr/lib/zypp/plugins" ) - , geoipEnabled ( true ) - , geoipHosts { "download.opensuse.org" } + , geoipEnabled ( true ) + , geoipHosts { "download.opensuse.org" } + , _mediaConf ( _parsedZyppConf ) { MIL << "libzypp: " LIBZYPP_VERSION_STRING << endl; if ( PathInfo(_parsedZyppConf).isExist() ) @@ -525,9 +524,6 @@ namespace zypp std::string entry(it->first); std::string value(it->second); - if ( _mediaConf.setConfigValue( section, entry, value ) ) - continue; - //DBG << (*it).first << "=" << (*it).second << endl; if ( section == "main" ) { @@ -563,6 +559,7 @@ namespace zypp { cfg_config_path = Pathname(value); } + else if ( entry == "reposdir" ) { cfg_known_repos_path = Pathname(value); @@ -729,9 +726,8 @@ namespace zypp Impl &operator=(Impl &&) = delete; ~Impl() {} - void notifyTargetChanged() + void notifyTargetChanged( const zypp::Pathname &newRoot, const zypp::Pathname &newConf ) { - Pathname newRoot { _autodetectSystemRoot() }; MIL << "notifyTargetChanged (" << newRoot << ")" << endl; if ( newRoot.emptyOrRoot() ) { @@ -740,7 +736,6 @@ namespace zypp else { _currentTargetDefaults = TargetDefaults(); - Pathname newConf { newRoot/_autodetectZyppConfPath() }; if ( PathInfo(newConf).isExist() ) { parser::IniDict dict( newConf ); for ( const auto & [entry,value] : dict.entries( "main" ) ) { @@ -815,7 +810,7 @@ namespace zypp std::vector geoipHosts; /* Other config singleton instances */ - MediaConfig &_mediaConf = MediaConfig::instance(); + MediaConfig _mediaConf; public: @@ -870,7 +865,7 @@ namespace zypp { static const str::regex rx( "^multiversion *= *(.*)" ); str::smatch what; - return iostr::simpleParseFile( InputStream( Pathname::assertprefix( root_r, _autodetectZyppConfPath() ) ), + return iostr::simpleParseFile( InputStream( Pathname::assertprefix( root_r, zypp_detail::autodetectZyppConfPath() ) ), [&]( int num_r, std::string line_r )->bool { if ( line_r[0] == 'm' && str::regex_match( line_r, what, rx ) ) @@ -915,17 +910,23 @@ namespace zypp mutable MultiversionMap _multiversionMap; }; - /////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////// - // - // METHOD NAME : ZConfig::instance - // METHOD TYPE : ZConfig & - // + + const ZConfig &ZConfig::defaults() + { + static ZConfig _conf("/dev/null"); + return _conf; + } + + ZConfig &ZConfig::systemConfig() + { + static ZConfig _sysConf( zypp_detail::autodetectZyppConfPath() ); + return _sysConf; + } + ZConfig & ZConfig::instance() { - static ZConfig _instance; // The singleton - return _instance; + return zypp_detail::GlobalStateHelper::config(); } /////////////////////////////////////////////////////////////////// @@ -933,8 +934,8 @@ namespace zypp // METHOD NAME : ZConfig::ZConfig // METHOD TYPE : Ctor // - ZConfig::ZConfig() - : _pimpl( new Impl ) + ZConfig::ZConfig(Pathname p) + : _pimpl( new Impl( std::move(p) ) ) { about( MIL ); } @@ -947,8 +948,8 @@ namespace zypp ZConfig::~ZConfig( ) {} - void ZConfig::notifyTargetChanged() - { return _pimpl->notifyTargetChanged(); } + void ZConfig::notifyTargetChanged( const zypp::Pathname &newRoot, const zypp::Pathname &newConfig ) + { return _pimpl->notifyTargetChanged( newRoot, newConfig ); } Pathname ZConfig::systemRoot() const { return _autodetectSystemRoot(); } @@ -1017,24 +1018,14 @@ namespace zypp /////////////////////////////////////////////////////////////////// bool ZConfig::hasUserData() const - { return !_pimpl->userData.empty(); } + { return zyppng::UserData::hasData(); } std::string ZConfig::userData() const - { return _pimpl->userData; } + { return zyppng::UserData::data(); } bool ZConfig::setUserData( const std::string & str_r ) { - for_( ch, str_r.begin(), str_r.end() ) - { - if ( *ch < ' ' && *ch != '\t' ) - { - ERR << "New user data string rejectded: char " << (int)*ch << " at position " << (ch - str_r.begin()) << endl; - return false; - } - } - MIL << "Set user data string to '" << str_r << "'" << endl; - _pimpl->userData = str_r; - return true; + return zyppng::UserData::setData(str_r); } /////////////////////////////////////////////////////////////////// @@ -1266,25 +1257,16 @@ namespace zypp { return _pimpl->apply_locks_file; } Pathname ZConfig::update_dataPath() -#if LEGACY(1735) - const -#endif { return Pathname("/var/adm"); } Pathname ZConfig::update_messagesPath() -#if LEGACY(1735) - const -#endif { return Pathname(update_dataPath()/"update-messages"); } Pathname ZConfig::update_scriptsPath() -#if LEGACY(1735) - const -#endif { return Pathname(update_dataPath()/"update-scripts"); } @@ -1335,6 +1317,16 @@ namespace zypp return _pimpl->cfg_kernel_keep_spec; } + const MediaConfig &ZConfig::mediaConfig() const + { + return _pimpl->_mediaConf; + } + + MediaConfig &ZConfig::mediaConfig() + { + return _pimpl->_mediaConf; + } + /////////////////////////////////////////////////////////////////// std::ostream & ZConfig::about( std::ostream & str ) const diff --git a/zypp/ZConfig.h b/zypp/ZConfig.h index 352ffe232c..6617a80331 100644 --- a/zypp/ZConfig.h +++ b/zypp/ZConfig.h @@ -30,8 +30,13 @@ #include namespace zyppng { - // just for the friend declaration + // just for the friend declarations template class RepoManager; + class ContextBase; +} + +namespace zypp::zypp_detail{ + class GlobalStateHelper; } /////////////////////////////////////////////////////////////////// @@ -39,6 +44,7 @@ namespace zypp { ///////////////////////////////////////////////////////////////// class RepoManager; + class MediaConfig; /////////////////////////////////////////////////////////////////// // @@ -69,8 +75,17 @@ namespace zypp { public: + /** A ZConfig instance that has only the default settings, usable as fallback if + * there is no context that can be asked and the system config is not applicable */ + static const ZConfig &defaults(); + + /** + * The system config, parsed from /etc/zypp/zypp.conf. + */ + static ZConfig &systemConfig(); + /** Singleton ctor */ - static ZConfig & instance(); + static ZYPP_INTERNAL_DEPRECATE ZConfig & instance(); /** Print some detail about the current libzypp version.*/ std::ostream & about( std::ostream & str ) const; @@ -386,7 +401,7 @@ namespace zypp void resetPkgGpgCheck(); ///< Reset to the zconfig default //@} // - /** + /**ZConfig * Directory for equivalent vendor definitions (configPath()/vendors.d) * \ingroup g_ZC_CONFIGFILES */ @@ -493,22 +508,6 @@ namespace zypp */ bool apply_locks_file() const; -#if LEGACY(1735) - /** - * Path where the update items are kept (/var/adm) - */ - Pathname update_dataPath() const; - - /** - * Path where the update scripts are stored ( /var/adm/update-scripts ) - */ - Pathname update_scriptsPath() const; - - /** - * Path where the update messages are stored ( /var/adm/update-messages ) - */ - Pathname update_messagesPath() const; -#else /** * Path where the update items are kept (/var/adm) */ @@ -523,7 +522,6 @@ namespace zypp * Path where the update messages are stored ( /var/adm/update-messages ) */ static Pathname update_messagesPath(); -#endif /** \name Command to be invoked to send update messages. */ //@{ @@ -586,6 +584,10 @@ namespace zypp */ std::string multiversionKernels() const; + + const MediaConfig &mediaConfig() const; + MediaConfig &mediaConfig(); + //@} public: @@ -598,10 +600,13 @@ namespace zypp /** Dtor */ ~ZConfig(); - void notifyTargetChanged(); ///< internal + void notifyTargetChanged( const zypp::Pathname &newRoot, const zypp::Pathname &newConfig ); ///< internal private: friend class RepoManager; + friend class zyppng::ContextBase; + friend class zypp_detail::GlobalStateHelper; + template friend class zyppng::RepoManager; /** The builtin config file value. */ Pathname builtinRepoCachePath() const; @@ -615,7 +620,7 @@ namespace zypp private: friend class Impl; /** Default ctor. */ - ZConfig(); + ZConfig( zypp::Pathname p ); /** Pointer to implementation */ RW_pointer > _pimpl; }; diff --git a/zypp/ZYpp.h b/zypp/ZYpp.h index af376a789d..dbcc96d6b6 100644 --- a/zypp/ZYpp.h +++ b/zypp/ZYpp.h @@ -27,10 +27,7 @@ #include #include #include - -namespace zyppng { - class Context; -} +#include /////////////////////////////////////////////////////////////////// namespace zypp diff --git a/zypp/ZYppCallbacks.h b/zypp/ZYppCallbacks.h index 68f4f98ff1..9bdfa04ff3 100644 --- a/zypp/ZYppCallbacks.h +++ b/zypp/ZYppCallbacks.h @@ -25,6 +25,9 @@ #include #include // bsc#1194597: CurlAuthData must be exposed for zypper + +ZYPP_BEGIN_LEGACY_API + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -1065,4 +1068,6 @@ namespace zypp } // namespace zypp /////////////////////////////////////////////////////////////////// +ZYPP_END_LEGACY_API + #endif // ZYPP_ZYPPCALLBACKS_H diff --git a/zypp/ZYppFactory.cc b/zypp/ZYppFactory.cc index 71e1df1eb3..26e43e4ee4 100644 --- a/zypp/ZYppFactory.cc +++ b/zypp/ZYppFactory.cc @@ -14,12 +14,10 @@ extern "C" #include } #include -#include #include #include #include -#include #include #include #include @@ -28,22 +26,15 @@ extern "C" #include #include +#include + -#include -#include -#include #include #include -using boost::interprocess::file_lock; -using boost::interprocess::scoped_lock; -using boost::interprocess::sharable_lock; - using std::endl; -namespace zyppintern { void repoVariablesReset(); } // upon re-acquiring the lock... - /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -69,254 +60,20 @@ namespace zypp template class SigBacktraceHandler; } - namespace env - { - /** Hack to circumvent the currently poor --root support. */ - inline Pathname ZYPP_LOCKFILE_ROOT() - { return getenv("ZYPP_LOCKFILE_ROOT") ? getenv("ZYPP_LOCKFILE_ROOT") : "/"; } - } - - /////////////////////////////////////////////////////////////////// - namespace zypp_readonly_hack - { ///////////////////////////////////////////////////////////////// - - static bool active = getenv("ZYPP_READONLY_HACK"); - - ZYPP_API void IWantIt() // see zypp/zypp_detail/ZYppReadOnlyHack.h - { - active = true; - MIL << "ZYPP_READONLY promised." << endl; - } - - bool IGotIt() - { - return active; - } - - ///////////////////////////////////////////////////////////////// - } // namespace zypp_readonly_hack - /////////////////////////////////////////////////////////////////// - - /////////////////////////////////////////////////////////////////// - /// \class ZYppGlobalLock - /// \brief Our broken global lock - /// - /////////////////////////////////////////////////////////////////// - class ZYppGlobalLock - { - public: - ZYppGlobalLock(Pathname &&lFilePath) - : _zyppLockFilePath(std::move(lFilePath)), _zyppLockFile(NULL), - _lockerPid(0), _cleanLock(false) { - filesystem::assert_dir(_zyppLockFilePath.dirname() ); - } - - ZYppGlobalLock(const ZYppGlobalLock &) = delete; - ZYppGlobalLock(ZYppGlobalLock &&) = delete; - ZYppGlobalLock &operator=(const ZYppGlobalLock &) = delete; - ZYppGlobalLock &operator=(ZYppGlobalLock &&) = delete; - - ~ZYppGlobalLock() - { - if ( _cleanLock ) - try { - // Exception safe access to the lockfile. - ScopedGuard closeOnReturn( accessLockFile() ); - { - scoped_lock flock( _zyppLockFileLock ); // aquire write lock - // Truncate the file rather than deleting it. Other processes may - // still use it to synchronsize. - ftruncate( fileno(_zyppLockFile), 0 ); - } - MIL << "Cleaned lock file. (" << getpid() << ")" << std::endl; - } - catch(...) {} // let no exception escape. - } - - pid_t lockerPid() const - { return _lockerPid; } - - const std::string & lockerName() const - { return _lockerName; } - - const Pathname & zyppLockFilePath() const - { return _zyppLockFilePath; } - - - private: - Pathname _zyppLockFilePath; - file_lock _zyppLockFileLock; - FILE * _zyppLockFile; - - pid_t _lockerPid; - std::string _lockerName; - bool _cleanLock; - - private: - using ScopedGuard = shared_ptr; - - /** Exception safe access to the lockfile. - * \code - * // Exception safe access to the lockfile. - * ScopedGuard closeOnReturn( accessLockFile() ); - * \endcode - */ - ScopedGuard accessLockFile() - { - _openLockFile(); - return ScopedGuard( static_cast(0), - std::bind( std::mem_fn( &ZYppGlobalLock::_closeLockFile ), this ) ); - } - - /** Use \ref accessLockFile. */ - void _openLockFile() - { - if ( _zyppLockFile != NULL ) - return; // is open - - // open pid file rw so we are sure it exist when creating the flock - _zyppLockFile = fopen( _zyppLockFilePath.c_str(), "a+" ); - if ( _zyppLockFile == NULL ) - ZYPP_THROW( Exception( "Cant open " + _zyppLockFilePath.asString() ) ); - _zyppLockFileLock = _zyppLockFilePath.c_str(); - MIL << "Open lockfile " << _zyppLockFilePath << endl; - } - - /** Use \ref accessLockFile. */ - void _closeLockFile() - { - if ( _zyppLockFile == NULL ) - return; // is closed - - clearerr( _zyppLockFile ); - fflush( _zyppLockFile ); - // http://www.boost.org/doc/libs/1_50_0/doc/html/interprocess/synchronization_mechanisms.html - // If you are using a std::fstream/native file handle to write to the file - // while using file locks on that file, don't close the file before releasing - // all the locks of the file. - _zyppLockFileLock = file_lock(); - fclose( _zyppLockFile ); - _zyppLockFile = NULL; - MIL << "Close lockfile " << _zyppLockFilePath << endl; - } - - - bool isProcessRunning( pid_t pid_r ) - { - // it is another program, not me, see if it is still running - Pathname procdir( Pathname("/proc")/str::numstring(pid_r) ); - PathInfo status( procdir ); - MIL << "Checking " << status << endl; - - if ( ! status.isDir() ) - { - DBG << "No such process." << endl; - return false; - } - - static char buffer[513]; - buffer[0] = buffer[512] = 0; - // man proc(5): /proc/[pid]/cmdline is empty if zombie. - if ( std::ifstream( (procdir/"cmdline").c_str() ).read( buffer, 512 ).gcount() > 0 ) - { - _lockerName = buffer; - DBG << "Is running: " << _lockerName << endl; - return true; - } - - DBG << "In zombie state." << endl; - return false; - } - - pid_t readLockFile() - { - clearerr( _zyppLockFile ); - fseek( _zyppLockFile, 0, SEEK_SET ); - long readpid = 0; - fscanf( _zyppLockFile, "%ld", &readpid ); - MIL << "read: Lockfile " << _zyppLockFilePath << " has pid " << readpid << " (our pid: " << getpid() << ") "<< std::endl; - return (pid_t)readpid; - } - - void writeLockFile() - { - clearerr( _zyppLockFile ); - fseek( _zyppLockFile, 0, SEEK_SET ); - ftruncate( fileno(_zyppLockFile), 0 ); - fprintf(_zyppLockFile, "%ld\n", (long)getpid() ); - fflush( _zyppLockFile ); - _cleanLock = true; // cleanup on exit - MIL << "write: Lockfile " << _zyppLockFilePath << " got pid " << getpid() << std::endl; - } - - /*! - * Expects the calling function to lock the access lock - */ - bool safeCheckIsLocked() - { - _lockerPid = readLockFile(); - if ( _lockerPid == 0 ) { - // no or empty lock file - return false; - } else if ( _lockerPid == getpid() ) { - // keep my own lock - return false; - } else { - // a foreign pid in lock - if ( isProcessRunning( _lockerPid ) ) { - WAR << _lockerPid << " is running and has a ZYpp lock. Sorry." << std::endl; - return true; - } else { - MIL << _lockerPid << " is dead. Ignoring the existing lock file." << std::endl; - return false; - } - } - } - - public: - - bool isZyppLocked() - { - if ( geteuid() != 0 ) - return false; // no lock as non-root - - // Exception safe access to the lockfile. - ScopedGuard closeOnReturn( accessLockFile() ); - scoped_lock flock( _zyppLockFileLock ); // aquire write lock - return safeCheckIsLocked (); - } - - /** Try to aquire a lock. - * \return \c true if zypp is already locked by another process. - */ - bool zyppLocked() - { - if ( geteuid() != 0 ) - return false; // no lock as non-root - - // Exception safe access to the lockfile. - ScopedGuard closeOnReturn( accessLockFile() ); - scoped_lock flock( _zyppLockFileLock ); // aquire write lock - if ( !safeCheckIsLocked() ) { - writeLockFile(); - return false; - } - return true; - } - - }; - /////////////////////////////////////////////////////////////////// namespace { static weak_ptr _theZYppInstance; - static scoped_ptr _theGlobalLock; // on/off in sync with _theZYppInstance - ZYppGlobalLock & globalLock() - { - if ( !_theGlobalLock ) - _theGlobalLock.reset( new ZYppGlobalLock( ZYppFactory::lockfileDir() / "zypp.pid" ) ); - return *_theGlobalLock; + boost::shared_ptr makeZyppImpl() { + boost::shared_ptr inst( new zypp_detail::ZYppImpl()); + return inst; + } + + boost::shared_ptr assertZyppImpl() { + // using boost shared_ptr to not break ABI + static boost::shared_ptr theInstance( makeZyppImpl() ); + return theInstance; } } //namespace /////////////////////////////////////////////////////////////////// @@ -330,13 +87,14 @@ namespace zypp ZYpp::ZYpp( const Impl_Ptr & impl_r ) : _pimpl( impl_r ) { - ::zyppintern::repoVariablesReset(); // upon re-acquiring the lock... + zypp_detail::GlobalStateHelper::context ()->clearRepoVariables(); // upon re-acquiring the lock... MIL << "ZYpp is on..." << endl; } ZYpp::~ZYpp() { - _theGlobalLock.reset(); + // here unload everything from the pool belonging to context, repos and target + zypp_detail::GlobalStateHelper::unlock (); MIL << "ZYpp is off..." << endl; } @@ -349,7 +107,7 @@ namespace zypp ZYppFactoryException::ZYppFactoryException( std::string msg_r, pid_t lockerPid_r, std::string lockerName_r ) : Exception( std::move(msg_r) ) , _lockerPid( lockerPid_r ) - , _lockerName(std::move( lockerName_r )) + , _lockerName( std::move( lockerName_r ) ) {} ZYppFactoryException::~ZYppFactoryException() throw () @@ -374,88 +132,24 @@ namespace zypp // ZYpp::Ptr ZYppFactory::getZYpp() const { - - const auto &makeLockedError = []( pid_t pid, const std::string &lockerName ){ - const std::string &t = str::form(_("System management is locked by the application with pid %d (%s).\n" - "Close this application before trying again."), pid, lockerName.c_str() ); - return ZYppFactoryException(t, pid, lockerName ); - }; - - ZYpp::Ptr _instance = _theZYppInstance.lock(); - if ( ! _instance ) + ZYpp::Ptr instance = _theZYppInstance.lock(); + if ( ! instance ) { - if ( geteuid() != 0 ) - { - MIL << "Running as user. Skip creating " << globalLock().zyppLockFilePath() << std::endl; - } - else if ( zypp_readonly_hack::active ) - { - MIL << "ZYPP_READONLY active." << endl; - } - else if ( globalLock().zyppLocked() ) - { - bool failed = true; - // bsc#1184399,1213231: A negative ZYPP_LOCK_TIMEOUT will wait forever. - const long LOCK_TIMEOUT = str::strtonum( getenv( "ZYPP_LOCK_TIMEOUT" ) ); - if ( LOCK_TIMEOUT != 0 ) - { - Date logwait = Date::now(); - Date giveup; /* 0 = forever */ - if ( LOCK_TIMEOUT > 0 ) { - giveup = logwait+LOCK_TIMEOUT; - MIL << "$ZYPP_LOCK_TIMEOUT=" << LOCK_TIMEOUT << " sec. Waiting for the zypp lock until " << giveup << endl; - } - else - MIL << "$ZYPP_LOCK_TIMEOUT=" << LOCK_TIMEOUT << " sec. Waiting for the zypp lock..." << endl; - - unsigned delay = 0; - do { - if ( delay < 60 ) - delay += 1; - else { - Date now { Date::now() }; - if ( now - logwait > Date::day ) { - WAR << "$ZYPP_LOCK_TIMEOUT=" << LOCK_TIMEOUT << " sec. Another day has passed waiting for the zypp lock..." << endl; - logwait = now; - } - } - sleep( delay ); - { - zypp::base::LogControl::TmpLineWriter shutUp; // be quiet - failed = globalLock().zyppLocked(); - } - } while ( failed && ( not giveup || Date::now() <= giveup ) ); - - if ( failed ) { - MIL << "$ZYPP_LOCK_TIMEOUT=" << LOCK_TIMEOUT << " sec. Gave up waiting for the zypp lock." << endl; - } - else { - MIL << "$ZYPP_LOCK_TIMEOUT=" << LOCK_TIMEOUT << " sec. Finally got the zypp lock." << endl; - } - } - if ( failed ) - ZYPP_THROW( makeLockedError( globalLock().lockerPid(), globalLock().lockerName() )); - - // we got the global lock, now make sure zypp-rpm is not still running - { - ZYppGlobalLock zyppRpmLock( ZYppFactory::lockfileDir() / "zypp-rpm.pid" ); - if ( zyppRpmLock.isZyppLocked () ) { - // release global lock, we will exit now - _theGlobalLock.reset(); - ZYPP_THROW( makeLockedError( zyppRpmLock.lockerPid(), zyppRpmLock.lockerName() )); - } - } + // first aquire the lock, will throw if zypp is locked already + // The Zypp destructor will release the lock again + zypp_detail::GlobalStateHelper::lock(); + + try { + // Here we go... + instance.reset( new ZYpp( assertZyppImpl() ) ); + _theZYppInstance = instance; + } catch (...) { + // should not happen but just to be safe, if no instance is returned release the lock + if ( !instance ) zypp_detail::GlobalStateHelper::unlock(); + throw; } - - // Here we go... - static ZYpp::Impl_Ptr _theImplInstance; // for now created once - if ( !_theImplInstance ) - _theImplInstance.reset( new ZYpp::Impl ); - _instance.reset( new ZYpp( _theImplInstance ) ); - _theZYppInstance = _instance; } - - return _instance; + return instance; } /////////////////////////////////////////////////////////////////// @@ -465,7 +159,7 @@ namespace zypp zypp::Pathname ZYppFactory::lockfileDir() { - return env::ZYPP_LOCKFILE_ROOT() / "run"; + return zypp_detail::GlobalStateHelper::lockfileDir(); } /****************************************************************** diff --git a/zypp/base/ValueTransform.h b/zypp/base/ValueTransform.h index f2b856fd1a..33ec1dddd7 100644 --- a/zypp/base/ValueTransform.h +++ b/zypp/base/ValueTransform.h @@ -76,6 +76,9 @@ namespace zypp const Transformator & transformator() const { return _transform; } + void setTransformator ( Transformator &&t ) + { _transform = std::move(t); } + private: RawType _raw; Transformator _transform; @@ -87,7 +90,7 @@ namespace zypp /// /// This helper enforces to explicitly state wheter you are using /// the raw or the variable replaced value. Usually you set \c raw - /// and get \c transformed (uness writing \c raw to some config file). + /// and get \c transformed (unless writing \c raw to some config file). /// /// Offers iterating over transformed strings in the list. /////////////////////////////////////////////////////////////////// @@ -163,6 +166,9 @@ namespace zypp const Transformator & transformator() const { return _transform; } + void setTransformator ( Transformator &&t ) + { _transform = std::move(t); } + private: Container _raw; Transformator _transform; diff --git a/zypp/media/CredentialManager.cc b/zypp/media/CredentialManager.cc new file mode 100644 index 0000000000..e046e0b6dc --- /dev/null +++ b/zypp/media/CredentialManager.cc @@ -0,0 +1,98 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "CredentialManager.h" +#include +#include +#include + +namespace zypp::media { + + CredManagerOptions::CredManagerOptions(const Pathname & rootdir) + { + this->globalCredFilePath = rootdir / zypp_detail::GlobalStateHelper::config().mediaConfig().credentialsGlobalFile(); + this->customCredFileDir = rootdir / zypp_detail::GlobalStateHelper::config().mediaConfig().credentialsGlobalDir(); + char * homedir = getenv("HOME"); + if (homedir) + userCredFilePath = rootdir / homedir / CredManagerSettings::userCredFile(); + } + + AuthData_Ptr CredentialManager::findIn(const CredentialManager::CredentialSet & set, + const Url & url, + url::ViewOption vopt) + { return zyppng::media::CredentialManager::findIn( set, url, vopt ); } + + ////////////////////////////////////////////////////////////////////// + // + // CLASS NAME : CredentialManager + // + ////////////////////////////////////////////////////////////////////// + + CredentialManager::CredentialManager( zyppng::media::CredentialManagerRef pimpl ) + : _pimpl( std::move(pimpl) ) + {} + + CredentialManager::CredentialManager( CredManagerOptions opts ) + : _pimpl( zyppng::media::CredentialManager::create(opts) ) + {} + + AuthData_Ptr CredentialManager::getCred(const Url & url) + { return _pimpl->getCred(url); } + + AuthData_Ptr CredentialManager::getCredFromFile(const Pathname & file) + { return _pimpl->getCredFromFile(file); } + + void CredentialManager::addCred(const AuthData & cred) + { return _pimpl->addCred (cred); } + + time_t CredentialManager::timestampForCredDatabase ( const zypp::Url &url ) + { return _pimpl->timestampForCredDatabase(url); } + + void CredentialManager::addGlobalCred(const AuthData & cred) + { return _pimpl->addGlobalCred(cred); } + + void CredentialManager::addUserCred(const AuthData & cred) + { return _pimpl->addUserCred ( cred ); } + + void CredentialManager::saveInGlobal(const AuthData & cred) + { return _pimpl->saveInGlobal (cred); } + + void CredentialManager::saveInUser(const AuthData & cred) + { return _pimpl->saveInUser(cred); } + + void CredentialManager::saveInFile(const AuthData & cred, const Pathname & credFile) + { return _pimpl->saveInFile(cred, credFile); } + + void CredentialManager::clearAll(bool global) + { return _pimpl->clearAll(global); } + + CredentialManager::CredentialIterator CredentialManager::credsGlobalBegin() const + { return _pimpl->credsGlobalBegin(); } + + CredentialManager::CredentialIterator CredentialManager::credsGlobalEnd() const + { return _pimpl->credsGlobalEnd(); } + + CredentialManager::CredentialSize CredentialManager::credsGlobalSize() const + { return _pimpl->credsGlobalSize(); } + + bool CredentialManager::credsGlobalEmpty() const + { return _pimpl->credsGlobalEmpty(); } + + CredentialManager::CredentialIterator CredentialManager::credsUserBegin() const + { return _pimpl->credsUserBegin(); } + + CredentialManager::CredentialIterator CredentialManager::credsUserEnd() const + { return _pimpl->credsUserEnd(); } + + CredentialManager::CredentialSize CredentialManager::credsUserSize() const + { return _pimpl->credsUserSize(); } + + bool CredentialManager::credsUserEmpty() const + { return _pimpl->credsUserEmpty(); } + +} diff --git a/zypp/media/CredentialManager.h b/zypp/media/CredentialManager.h index 61dd4a230f..7e9d21e189 100644 --- a/zypp/media/CredentialManager.h +++ b/zypp/media/CredentialManager.h @@ -1 +1,164 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp-media/auth/CredentialManager + * + */ +#ifndef ZYPP_CREDENTIALMANAGER_H +#define ZYPP_CREDENTIALMANAGER_H + +#include #include +#include +#include + +namespace zyppng::media { + ZYPP_FWD_DECL_TYPE_WITH_REFS(CredentialManager); +} + +namespace zypp::media { + + struct ZYPP_API ZYPP_DEPRECATED CredManagerOptions : public CredManagerSettings + { + CredManagerOptions( const Pathname & rootdir = "" ); + }; + + ////////////////////////////////////////////////////////////////////// + // + // CLASS NAME : CredentialManager + // + /** + * \todo better method names + * \todo delete(AuthData) method + */ + class ZYPP_API ZYPP_DEPRECATED CredentialManager + { + public: + using CredentialSet = std::set; + using CredentialSize = CredentialSet::size_type; + using CredentialIterator = CredentialSet::const_iterator; + + CredentialManager( zyppng::media::CredentialManagerRef pimpl ) ZYPP_LOCAL; + CredentialManager( CredManagerOptions opts = CredManagerOptions() ); + ~CredentialManager() + {} + + public: + /** + * Get credentials for the specified \a url. + * + * If the URL contains also username, it will be used to find the match + * for this user (in case mutliple are available). + * + * \param url URL to find credentials for. + * \return Pointer to retrieved authentication data on success or an empty + * AuthData_Ptr otherwise. + * \todo return a copy instead? + */ + AuthData_Ptr getCred(const Url & url); + + /** + * Read credentials from a file. + */ + AuthData_Ptr getCredFromFile(const Pathname & file); + + /** + * Add new global credentials. + */ + void addGlobalCred(const AuthData & cred); + + /** + * Add new user credentials. + */ + void addUserCred(const AuthData & cred); + + /** + * Add new credentials with user callbacks. + * + * If the cred->url() contains 'credentials' query parameter, the + * credentials will be automatically saved to the specified file using the + * \ref saveInFile() method. + * + * Otherwise a callback will be called asking whether to save to custom + * file, or to global or user's credentials catalog. + * + * \todo Currently no callback is called, credentials are automatically + * saved to user's credentials.cat if no 'credentials' parameter + * has been specified + */ + void addCred(const AuthData & cred); + + /** + * Saves any unsaved credentials added via \ref addUserCred() or + * \a addGlobalCred() methods. + */ + void save(); + + /** + * Saves given \a cred to global credentials file. + * + * \note Use this method to add just one piece of credentials. To add + * multiple items at once, use addGlobalCred() followed + * by save() + */ + void saveInGlobal(const AuthData & cred); + + /** + * Saves given \a cred to user's credentials file. + * + * \note Use this method to add just one piece of credentials. To add + * multiple items at once, use addUserCred() followed + * by save() + */ + void saveInUser(const AuthData & cred); + + /** + * Saves given \a cred to user specified credentials file. + * + * If the credFile path is absolute, it will be saved at that precise + * location. If \a credFile is just a filename, it will be saved + * in \ref CredManagerOptions::customCredFileDir. Otherwise the current + * working directory will be prepended to the file path. + */ + void saveInFile(const AuthData &, const Pathname & credFile); + + /** + * Remove all global or user credentials from memory and disk. + * + * \param global Whether to remove global or user credentials. + */ + void clearAll(bool global = false); + + /*! + * Helper function to find a matching AuthData instance in a CredentialSet + */ + static AuthData_Ptr findIn( const CredentialManager::CredentialSet & set, const Url & url, url::ViewOption vopt ); + + /*! + * Returns the timestamp of the database the given URL creds would be stored + */ + time_t timestampForCredDatabase ( const zypp::Url &url ); + + CredentialIterator credsGlobalBegin() const; + CredentialIterator credsGlobalEnd() const; + CredentialSize credsGlobalSize() const; + bool credsGlobalEmpty() const; + + CredentialIterator credsUserBegin() const; + CredentialIterator credsUserEnd() const; + CredentialSize credsUserSize() const; + bool credsUserEmpty() const; + + struct Impl; + private: + zyppng::media::CredentialManagerRef _pimpl; + }; + +} + +#endif diff --git a/zypp/media/MediaCD.cc b/zypp/media/MediaCD.cc index 0b73935b02..2067e9d2ac 100644 --- a/zypp/media/MediaCD.cc +++ b/zypp/media/MediaCD.cc @@ -127,8 +127,8 @@ namespace zypp ////////////////////////////////////////////////////////////////// - MediaCD::MediaCD( const Url & url_r, const Pathname & attach_point_hint_r ) - : MediaHandler( url_r, attach_point_hint_r, url_r.getPathName(), false ) + MediaCD::MediaCD( zyppng::ContextBaseRef ctx, const Url & url_r, const Pathname & attach_point_hint_r ) + : MediaHandler( std::move(ctx), url_r, attach_point_hint_r, url_r.getPathName(), false ) , _lastdev( -1 ) , _lastdev_tried( -1 ) { diff --git a/zypp/media/MediaCD.h b/zypp/media/MediaCD.h index 3d0b17ac77..5e26f3555a 100644 --- a/zypp/media/MediaCD.h +++ b/zypp/media/MediaCD.h @@ -63,7 +63,8 @@ namespace zypp { public: - MediaCD( const Url & url_r, + MediaCD( zyppng::ContextBaseRef ctx, + const Url & url_r, const Pathname & attach_point_hint_r ); ~MediaCD() override { try { release(); } catch(...) {} } diff --git a/zypp/media/MediaCIFS.cc b/zypp/media/MediaCIFS.cc index 43b4ef4813..0a890fe446 100644 --- a/zypp/media/MediaCIFS.cc +++ b/zypp/media/MediaCIFS.cc @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include @@ -27,9 +27,10 @@ #include #include -#include #include +#include + using std::endl; namespace zypp { @@ -98,9 +99,9 @@ namespace zypp { // // DESCRIPTION : // - MediaCIFS::MediaCIFS( const Url & url_r, - const Pathname & attach_point_hint_r ) - : MediaHandler( url_r, attach_point_hint_r, + MediaCIFS::MediaCIFS(zyppng::ContextBaseRef ctx, const Url & url_r, + const Pathname & attach_point_hint_r ) + : MediaHandler( std::move(ctx), url_r, attach_point_hint_r, stripShare( url_r.getPathName() ), // urlpath WITHOUT share name at attachpoint false ) // does_download { @@ -162,7 +163,7 @@ namespace zypp { std::string mountpoint( attachPoint().asString() ); Mount mount; - CredentialManager cm(CredManagerOptions(ZConfig::instance().repoManagerRoot())); + auto cm = zyppng::media::CredentialManager::create( CredManagerSettings(_zyppContext) ); Mount::Options options( _url.getQueryParam("mountoptions") ); std::string username = _url.getUsername(); @@ -214,7 +215,7 @@ namespace zypp { if ( username.empty() || password.empty() ) { - AuthData_Ptr c = cm.getCred(_url); + AuthData_Ptr c = cm->getCred(_url); if (c) { username = c->username(); @@ -403,10 +404,10 @@ namespace zypp { bool MediaCIFS::authenticate(AuthData & authdata, bool firstTry) const { //! \todo need a way to pass different CredManagerOptions here - CredentialManager cm(CredManagerOptions(ZConfig::instance().repoManagerRoot())); + auto cm = zyppng::media::CredentialManager::create( CredManagerSettings(_zyppContext) ); // get stored credentials - AuthData_Ptr cmcred = cm.getCred(_url); + AuthData_Ptr cmcred = cm->getCred(_url); AuthData_Ptr smbcred; smbcred.reset(new AuthData()); @@ -457,8 +458,8 @@ namespace zypp { // save the credentials cmcred->setUrl(_url); - cm.addCred(*cmcred); - cm.save(); + cm->addCred(*cmcred); + cm->save(); return true; } diff --git a/zypp/media/MediaCIFS.h b/zypp/media/MediaCIFS.h index 22ffcc41f7..430bc77b90 100644 --- a/zypp/media/MediaCIFS.h +++ b/zypp/media/MediaCIFS.h @@ -44,8 +44,9 @@ namespace zypp { bool getDoesFileExist( const Pathname & filename ) const override; public: - MediaCIFS( const Url& url_r, - const Pathname & attach_point_hint_r ); + MediaCIFS( zyppng::ContextBaseRef ctx, + const Url& url_r, + const Pathname & attach_point_hint_r ); ~MediaCIFS() override { try { release(); } catch(...) {} } diff --git a/zypp/media/MediaCurl.cc b/zypp/media/MediaCurl.cc index 79e13ae440..79d44c42ee 100644 --- a/zypp/media/MediaCurl.cc +++ b/zypp/media/MediaCurl.cc @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -43,6 +43,8 @@ #include #include +#include + using std::endl; namespace internal { @@ -344,9 +346,9 @@ Pathname MediaCurl::_cookieFile = "/var/lib/YaST2/cookies"; #define SET_OPTION_LONG(opt,val) SET_OPTION(opt,(long)val) #define SET_OPTION_VOID(opt,val) SET_OPTION(opt,(void*)val) -MediaCurl::MediaCurl( const Url & url_r, - const Pathname & attach_point_hint_r ) - : MediaNetworkCommonHandler( url_r, attach_point_hint_r, +MediaCurl::MediaCurl( zyppng::ContextBaseRef ctx, const Url & url_r, + const Pathname & attach_point_hint_r ) + : MediaNetworkCommonHandler( std::move(ctx), url_r, attach_point_hint_r, "/", // urlpath at attachpoint true ), // does_download _curl( NULL ), @@ -541,8 +543,8 @@ void MediaCurl::setupEasy() && _settings.username().size() && !_settings.password().size() ) { - CredentialManager cm(CredManagerOptions(ZConfig::instance().repoManagerRoot())); - const auto cred = cm.getCred( _url ); + auto cm = zyppng::media::CredentialManager::create( CredManagerSettings(_zyppContext) ); + const auto cred = cm->getCred( _url ); if ( cred && cred->valid() ) { if ( !_settings.username().size() ) _settings.setUsername(cred->username()); @@ -1482,11 +1484,11 @@ CURLcode MediaCurl::executeCurl() const bool MediaCurl::authenticate(const std::string & availAuthTypes, bool firstTry) const { //! \todo need a way to pass different CredManagerOptions here - CredentialManager cm(CredManagerOptions(ZConfig::instance().repoManagerRoot())); + auto cm = zyppng::media::CredentialManager::create( CredManagerSettings(_zyppContext) ); CurlAuthData_Ptr credentials; // get stored credentials - AuthData_Ptr cmcred = cm.getCred(_url); + AuthData_Ptr cmcred = cm->getCred(_url); if (cmcred && firstTry) { @@ -1570,8 +1572,8 @@ bool MediaCurl::authenticate(const std::string & availAuthTypes, bool firstTry) if (!cmcred) { credentials->setUrl(_url); - cm.addCred(*credentials); - cm.save(); + cm->addCred(*credentials); + cm->save(); } return true; diff --git a/zypp/media/MediaCurl.h b/zypp/media/MediaCurl.h index 3ded2e688c..42b6ccf257 100644 --- a/zypp/media/MediaCurl.h +++ b/zypp/media/MediaCurl.h @@ -95,7 +95,8 @@ class MediaCurl : public MediaNetworkCommonHandler public: - MediaCurl( const Url & url_r, + MediaCurl( zyppng::ContextBaseRef ctx, + const Url & url_r, const Pathname & attach_point_hint_r ); ~MediaCurl() override { try { release(); } catch(...) {} } diff --git a/zypp/media/MediaDIR.cc b/zypp/media/MediaDIR.cc index 4f416b5c13..304d01ff3d 100644 --- a/zypp/media/MediaDIR.cc +++ b/zypp/media/MediaDIR.cc @@ -39,9 +39,9 @@ namespace zypp { // as files are not copied. // Thus attach_point_hint_r is ignored. // - MediaDIR::MediaDIR( const Url & url_r, - const Pathname & /*attach_point_hint_r*/ ) - : MediaHandler( url_r, url_r.getPathName(), + MediaDIR::MediaDIR(zyppng::ContextBaseRef ctx, const Url & url_r, + const Pathname & /*attach_point_hint_r*/ ) + : MediaHandler( std::move(ctx), url_r, url_r.getPathName(), "/", // urlpath below attachpoint false ) // does_download { diff --git a/zypp/media/MediaDIR.h b/zypp/media/MediaDIR.h index a3bd8efe29..f1be25b50d 100644 --- a/zypp/media/MediaDIR.h +++ b/zypp/media/MediaDIR.h @@ -41,7 +41,8 @@ namespace zypp { public: - MediaDIR( const Url & url_r, + MediaDIR( zyppng::ContextBaseRef ctx, + const Url & url_r, const Pathname & attach_point_hint_r ); ~MediaDIR() override { try { release(); } catch(...) {} } diff --git a/zypp/media/MediaDISK.cc b/zypp/media/MediaDISK.cc index ac3e79e728..f425c84e6c 100644 --- a/zypp/media/MediaDISK.cc +++ b/zypp/media/MediaDISK.cc @@ -50,9 +50,9 @@ namespace zypp { // // DESCRIPTION : // - MediaDISK::MediaDISK( const Url & url_r, - const Pathname & attach_point_hint_r ) - : MediaHandler( url_r, attach_point_hint_r, + MediaDISK::MediaDISK(zyppng::ContextBaseRef ctx, const Url & url_r, + const Pathname & attach_point_hint_r ) + : MediaHandler( std::move(ctx), url_r, attach_point_hint_r, url_r.getPathName(), // urlpath below attachpoint false ) // does_download { diff --git a/zypp/media/MediaDISK.h b/zypp/media/MediaDISK.h index 9a75554e7e..61e00c224f 100644 --- a/zypp/media/MediaDISK.h +++ b/zypp/media/MediaDISK.h @@ -44,7 +44,8 @@ namespace zypp { public: - MediaDISK( const Url & url_r, + MediaDISK( zyppng::ContextBaseRef ctx, + const Url & url_r, const Pathname & attach_point_hint_r ); ~MediaDISK() override { try { release(); } catch(...) {} } diff --git a/zypp/media/MediaHandler.cc b/zypp/media/MediaHandler.cc index 1e78533ef0..c94660df55 100644 --- a/zypp/media/MediaHandler.cc +++ b/zypp/media/MediaHandler.cc @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -24,9 +23,9 @@ #include #include #include -#include #include -#include + +#include using std::endl; @@ -52,10 +51,11 @@ namespace zypp { // // DESCRIPTION : // -MediaHandler::MediaHandler ( Url url_r, - const Pathname & attach_point_r, - Pathname urlpath_below_attachpoint_r, - const bool does_download_r ) + MediaHandler::MediaHandler (zyppng::ContextBaseRef ctx, + Url url_r, + const Pathname & attach_point_r, + Pathname urlpath_below_attachpoint_r, + const bool does_download_r ) : _mediaSource() , _attachPoint( new AttachPoint()) , _attachPointHint() @@ -64,6 +64,7 @@ MediaHandler::MediaHandler ( Url url_r, , _attach_mtime(0) , _url(std::move( url_r )) , _parentId(0) + , _zyppContext( std::move(ctx) ) { Pathname real_attach_point( getRealPath(attach_point_r.asString())); @@ -321,7 +322,7 @@ MediaHandler::createAttachPoint() const if ( apoint.empty() ) // fallback to config value { - aroot = ZConfig::instance().download_mediaMountdir(); + aroot = ZConfig::systemConfig().download_mediaMountdir(); if ( ! aroot.empty() ) apoint = createAttachPoint( aroot ); } diff --git a/zypp/media/MediaHandler.h b/zypp/media/MediaHandler.h index 1b293ca210..84ff258daf 100644 --- a/zypp/media/MediaHandler.h +++ b/zypp/media/MediaHandler.h @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -31,6 +32,10 @@ #undef ZYPP_BASE_LOGGER_LOGGROUP #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::media" +namespace zyppng { + ZYPP_FWD_DECL_TYPE_WITH_REFS(ContextBase); +} + namespace zypp { namespace media { @@ -117,6 +122,9 @@ class MediaHandler { */ MediaAccessId _parentId; + /** media handle context */ + zyppng::ContextBaseRef _zyppContext; + public: /** @@ -466,7 +474,8 @@ class MediaHandler { * On any error, the attach_point is set to an empty Pathname, * which should lead to E_bad_attachpoint. **/ - MediaHandler ( Url url_r, + MediaHandler ( zyppng::ContextBaseRef ctx, + Url url_r, const Pathname & attach_point_r, Pathname urlpath_below_attachpoint_r, const bool does_download_r ); diff --git a/zypp/media/MediaHandlerFactory.cc b/zypp/media/MediaHandlerFactory.cc index cb1a5c8508..c9d2f1756e 100644 --- a/zypp/media/MediaHandlerFactory.cc +++ b/zypp/media/MediaHandlerFactory.cc @@ -47,8 +47,12 @@ namespace zypp::media { return {}; } - std::unique_ptr MediaHandlerFactory::createHandler( const Url &o_url, const Pathname &preferred_attach_point ) + std::unique_ptr MediaHandlerFactory::createHandler( zyppng::ContextBaseRef ctx, const Url &o_url, const Pathname &preferred_attach_point ) { + if ( !ctx ) { + MIL << "A MediaHandler always needs a context" << std::endl; + ZYPP_THROW(MediaException("MediaHandler always needs a valid Context.")); + } if(!o_url.isValid()) { MIL << "Url is not valid" << std::endl; ZYPP_THROW(MediaBadUrlException(o_url)); @@ -66,27 +70,27 @@ namespace zypp::media { std::unique_ptr _handler; switch(*hdlType) { case MediaCDType: { - _handler = std::make_unique (url,preferred_attach_point); + _handler = std::make_unique (std::move(ctx), url,preferred_attach_point); break; } case MediaNFSType: { - _handler = std::make_unique (url,preferred_attach_point); + _handler = std::make_unique (std::move(ctx), url,preferred_attach_point); break; } case MediaISOType: { - _handler = std::make_unique (url,preferred_attach_point); + _handler = std::make_unique (std::move(ctx), url,preferred_attach_point); break; } case MediaFileType: { - _handler = std::make_unique (url,preferred_attach_point); + _handler = std::make_unique (std::move(ctx), url,preferred_attach_point); break; } case MediaDISKType: { - _handler = std::make_unique (url,preferred_attach_point); + _handler = std::make_unique (std::move(ctx), url,preferred_attach_point); break; } case MediaCIFSType: { - _handler = std::make_unique (url,preferred_attach_point); + _handler = std::make_unique (std::move(ctx), url,preferred_attach_point); break; } case MediaCURLType: { @@ -126,15 +130,15 @@ namespace zypp::media { switch ( which ) { default: case multicurl: - handler = std::make_unique( url, preferred_attach_point ); + handler = std::make_unique( std::move(ctx), url, preferred_attach_point ); break; case network: - handler = std::make_unique( url, preferred_attach_point ); + handler = std::make_unique( std::move(ctx), url, preferred_attach_point ); break; case curl: - handler = std::make_unique( url, preferred_attach_point ); + handler = std::make_unique( std::move(ctx), url, preferred_attach_point ); break; } // Set up the handler diff --git a/zypp/media/MediaHandlerFactory.h b/zypp/media/MediaHandlerFactory.h index 12f90e177b..37155f6885 100644 --- a/zypp/media/MediaHandlerFactory.h +++ b/zypp/media/MediaHandlerFactory.h @@ -1,11 +1,15 @@ #ifndef MEDIAHANDLERFACTORY_H #define MEDIAHANDLERFACTORY_H +#include #include #include #include #include +namespace zyppng { + ZYPP_FWD_DECL_TYPE_WITH_REFS(ContextBase); +} namespace zypp::media { @@ -27,7 +31,7 @@ namespace zypp::media { }; MediaHandlerFactory(); - static std::unique_ptr createHandler (const Url& o_url, const Pathname & preferred_attach_point); + static std::unique_ptr createHandler ( zyppng::ContextBaseRef ctx, const Url& o_url, const Pathname & preferred_attach_point); static std::optional handlerType( const Url &url ); }; diff --git a/zypp/media/MediaISO.cc b/zypp/media/MediaISO.cc index 4cadffece3..caeb5a5bb3 100644 --- a/zypp/media/MediaISO.cc +++ b/zypp/media/MediaISO.cc @@ -41,9 +41,10 @@ namespace zypp // filesystem: Optional, defaults to "auto". // /////////////////////////////////////////////////////////////////// - MediaISO::MediaISO(const Url &url_r, + MediaISO::MediaISO(zyppng::ContextBaseRef ctx, const Url &url_r, const Pathname &attach_point_hint_r) - : MediaHandler(url_r, attach_point_hint_r, + : MediaHandler(std::move(ctx), + url_r, attach_point_hint_r, url_r.getPathName(), // urlpath below attachpoint false) // does_download { @@ -108,7 +109,7 @@ namespace zypp MediaManager manager; - _parentId = manager.open(src, _url.getQueryParam("mnt")); + _parentId = manager.open( _zyppContext, src, _url.getQueryParam("mnt")); } // --------------------------------------------------------------- diff --git a/zypp/media/MediaISO.h b/zypp/media/MediaISO.h index c83e814e8d..1782958523 100644 --- a/zypp/media/MediaISO.h +++ b/zypp/media/MediaISO.h @@ -52,10 +52,11 @@ namespace zypp public: - MediaISO(const Url &url_r, + MediaISO(zyppng::ContextBaseRef ctx, + const Url &url_r, const Pathname &attach_point_hint_r); - + ~MediaISO() override; bool diff --git a/zypp/media/MediaManager.cc b/zypp/media/MediaManager.cc index e728d9443a..08ed9787b6 100644 --- a/zypp/media/MediaManager.cc +++ b/zypp/media/MediaManager.cc @@ -25,6 +25,7 @@ #include #include #include +#include ////////////////////////////////////////////////////////////////////// namespace zypp @@ -61,9 +62,9 @@ namespace zypp : desired(m.desired), verifier(std::move(m.verifier)), _handler(std::move(m._handler)) {} - static ManagedMedia makeManagedMedia ( const Url &o_url, const Pathname &preferred_attach_point, const MediaVerifierRef &v ) + static ManagedMedia makeManagedMedia ( zyppng::ContextBaseRef &&ctx, const Url &o_url, const Pathname &preferred_attach_point, const MediaVerifierRef &v ) { - auto handler = MediaHandlerFactory::createHandler( o_url, preferred_attach_point ); + auto handler = MediaHandlerFactory::createHandler( std::move(ctx), o_url, preferred_attach_point ); if ( !handler ) { ERR << "Failed to create media handler" << std::endl; ZYPP_THROW( MediaSystemException(o_url, "Failed to create media handler")); @@ -314,10 +315,15 @@ namespace zypp // --------------------------------------------------------------- MediaAccessId MediaManager::open(const Url &url, const Pathname &preferred_attach_point) + { + return open( zypp_detail::GlobalStateHelper::context(), url, preferred_attach_point ); + } + + MediaAccessId MediaManager::open( zyppng::ContextBaseRef ctx, const Url &url, const Pathname &preferred_attach_point ) { // create new access handler for it MediaVerifierRef verifier( new NoVerifier()); - ManagedMedia tmp = ManagedMedia::makeManagedMedia( url, preferred_attach_point, verifier ); + ManagedMedia tmp = ManagedMedia::makeManagedMedia( std::move(ctx), url, preferred_attach_point, verifier ); MediaAccessId nextId = m_impl->nextAccessId(); diff --git a/zypp/media/MediaManager.h b/zypp/media/MediaManager.h index f1fa81a349..d2155f484b 100644 --- a/zypp/media/MediaManager.h +++ b/zypp/media/MediaManager.h @@ -24,6 +24,9 @@ #include +namespace zyppng { + ZYPP_FWD_DECL_TYPE_WITH_REFS(ContextBase); +} namespace zypp::media { @@ -493,7 +496,32 @@ namespace zypp::media * \throws MediaException */ MediaAccessId - open(const Url &url, const Pathname & preferred_attach_point = ""); + open( const Url &url, const Pathname & preferred_attach_point = "" ) ZYPP_INTERNAL_DEPRECATE; + + + /** + * Opens the media access for specified with the url. + * + * If the \p preferred_attach_point parameter does not + * point to a usable attach point directory, the media + * manager automatically creates a temporary attach + * point in a default directory. This default directory + * can be changed using setAttachPrefix() function. + * + * Remember to close() each id you've opened and not + * need any more. It is like a new and delete! + * + * \param ctx, the zyppng context used for settings for the created MediaHandler + * \param url The \ref MediaAccessUrl. + * \param preferred_attach_point The preferred, already + * existing directory, where the media should be + * attached. + * \return a new media access id. + * \throws std::bad_alloc + * \throws MediaException + */ + MediaAccessId + open( zyppng::ContextBaseRef ctx, const Url &url, const Pathname & preferred_attach_point = ""); /** * Close the media access with specified id. diff --git a/zypp/media/MediaMultiCurl.cc b/zypp/media/MediaMultiCurl.cc index 8cddbb3c04..5ac5fac144 100644 --- a/zypp/media/MediaMultiCurl.cc +++ b/zypp/media/MediaMultiCurl.cc @@ -143,7 +143,7 @@ class multifetchworker : private MediaCurl, public zyppng::CurlMultiPartDataRece friend class multifetchrequest; public: - multifetchworker(int no, multifetchrequest &request, const Url &url); + multifetchworker(zyppng::ContextBaseRef ctx, int no, multifetchrequest &request, const Url &url); multifetchworker(const multifetchworker &) = delete; multifetchworker(multifetchworker &&) = delete; multifetchworker &operator=(const multifetchworker &) = delete; @@ -439,8 +439,8 @@ multifetchworker::headerfunction( char *p, size_t bytes ) return bytes; } -multifetchworker::multifetchworker(int no, multifetchrequest &request, const Url &url) -: MediaCurl(url, Pathname()) +multifetchworker::multifetchworker( zyppng::ContextBaseRef ctx, int no, multifetchrequest &request, const Url &url) +: MediaCurl(std::move(ctx), url, Pathname()) , _workerno( no ) , _maxspeed( request._maxspeed ) , _request ( &request ) @@ -1048,7 +1048,7 @@ multifetchrequest::run(std::vector &urllist) if ((int)_activeworkers < _maxworkers && urliter != urllist.end() && _workers.size() < MAXURLS) { // spawn another worker! - _workers.push_back(std::make_unique(workerno++, *this, *urliter)); + _workers.push_back(std::make_unique( _context->_zyppContext, workerno++, *this, *urliter)); auto &worker = _workers.back(); if (worker->_state != WORKER_BROKEN) { @@ -1369,8 +1369,8 @@ inline zypp::ByteCount multifetchrequest::makeBlksize ( uint maxConns, size_t fi ////////////////////////////////////////////////////////////////////// -MediaMultiCurl::MediaMultiCurl(const Url &url_r, const Pathname & attach_point_hint_r) - : MediaCurl(url_r, attach_point_hint_r) +MediaMultiCurl::MediaMultiCurl(zyppng::ContextBaseRef ctx, const Url &url_r, const Pathname & attach_point_hint_r) + : MediaCurl( std::move(ctx), url_r, attach_point_hint_r) { MIL << "MediaMultiCurl::MediaMultiCurl(" << url_r << ", " << attach_point_hint_r << ")" << endl; _multi = 0; @@ -1582,7 +1582,7 @@ void MediaMultiCurl::doGetFileCopy( const OnMediaLocation &srcFile , const Pathn if ( ismetalink != MetaDataType::None ) { bool userabort = false; - Pathname failedFile = ZConfig::instance().repoCachePath() / "MultiCurl.failed"; + Pathname failedFile = ZConfig::systemConfig().repoCachePath() / "MultiCurl.failed"; file = nullptr; // explicitly close destNew before the parser reads it. try { diff --git a/zypp/media/MediaMultiCurl.h b/zypp/media/MediaMultiCurl.h index 42f335376b..8aae5e74a8 100644 --- a/zypp/media/MediaMultiCurl.h +++ b/zypp/media/MediaMultiCurl.h @@ -42,7 +42,7 @@ class MediaMultiCurl : public MediaCurl { friend class multifetchrequest; friend class multifetchworker; - MediaMultiCurl(const Url &url_r, const Pathname & attach_point_hint_r); + MediaMultiCurl( zyppng::ContextBaseRef ctx, const Url &url_r, const Pathname & attach_point_hint_r); ~MediaMultiCurl() override; void doGetFileCopy( const OnMediaLocation & srcFile, const Pathname & targetFilename, callback::SendReport & _report, RequestOptions options = OPTION_NONE ) const override; diff --git a/zypp/media/MediaNFS.cc b/zypp/media/MediaNFS.cc index b59e6a7cde..a6e1cb3861 100644 --- a/zypp/media/MediaNFS.cc +++ b/zypp/media/MediaNFS.cc @@ -39,9 +39,10 @@ namespace zypp { // // DESCRIPTION : // - MediaNFS::MediaNFS( const Url & url_r, - const Pathname & attach_point_hint_r ) - : MediaHandler( url_r, attach_point_hint_r, + MediaNFS::MediaNFS( zyppng::ContextBaseRef ctx, + const Url & url_r, + const Pathname & attach_point_hint_r ) + : MediaHandler( std::move(ctx), url_r, attach_point_hint_r, "/", // urlpath at attachpoint false ) // does_download { diff --git a/zypp/media/MediaNFS.h b/zypp/media/MediaNFS.h index 208b0e5719..d79bd282d6 100644 --- a/zypp/media/MediaNFS.h +++ b/zypp/media/MediaNFS.h @@ -50,7 +50,8 @@ namespace zypp { public: - MediaNFS( const Url& url_r, + MediaNFS( zyppng::ContextBaseRef ctx, + const Url& url_r, const Pathname & attach_point_hint_r ); ~MediaNFS() override { try { release(); } catch(...) {} } diff --git a/zypp/media/MediaNetwork.cc b/zypp/media/MediaNetwork.cc index f50bd1e89b..43c7dff670 100644 --- a/zypp/media/MediaNetwork.cc +++ b/zypp/media/MediaNetwork.cc @@ -30,10 +30,11 @@ #include #include -#include +#include #include #include +#include using std::endl; @@ -151,7 +152,7 @@ namespace internal { MIL << "Initializing internal::SharedData for MediaNetwork" << std::endl; _dispatcher = zyppng::ThreadData::current().ensureDispatcher(); _downloader = std::make_shared(); - _downloader->requestDispatcher()->setMaximumConcurrentConnections( zypp::MediaConfig::instance().download_max_concurrent_connections() ); + _downloader->requestDispatcher()->setMaximumConcurrentConnections( zypp::ZConfig::systemConfig().download_max_concurrent_connections() ); } }; @@ -164,9 +165,9 @@ namespace zypp { namespace media { - MediaNetwork::MediaNetwork( const Url & url_r, - const Pathname & attach_point_hint_r ) - : MediaNetworkCommonHandler( url_r, attach_point_hint_r, + MediaNetwork::MediaNetwork(zyppng::ContextBaseRef ctx, const Url & url_r, + const Pathname & attach_point_hint_r ) + : MediaNetworkCommonHandler( std::move(ctx), url_r, attach_point_hint_r, "/", // urlpath at attachpoint true ) // does_download { @@ -286,11 +287,11 @@ namespace zypp { const auto &authRequiredSlot = [&]( zyppng::Download &req, zyppng::NetworkAuthData &auth, const std::string &availAuth ){ //! \todo need a way to pass different CredManagerOptions here - CredentialManager cm(CredManagerOptions(ZConfig::instance().repoManagerRoot())); + auto cm = zyppng::media::CredentialManager::create( CredManagerSettings(_zyppContext) ); CurlAuthData_Ptr credentials; // get stored credentials - AuthData_Ptr cmcred = cm.getCred(_url); + AuthData_Ptr cmcred = cm->getCred(_url); if ( cmcred && auth.lastDatabaseUpdate() < cmcred->lastDatabaseUpdate() ) { credentials.reset(new CurlAuthData(*cmcred)); DBG << "got stored credentials:" << endl << *credentials << endl; @@ -351,8 +352,8 @@ namespace zypp { auth = *credentials; if (!cmcred) { credentials->setUrl(_url); - cm.addCred(*credentials); - cm.save(); + cm->addCred(*credentials); + cm->save(); } }; diff --git a/zypp/media/MediaNetwork.h b/zypp/media/MediaNetwork.h index 6a37c46ca6..2b3e440c4c 100644 --- a/zypp/media/MediaNetwork.h +++ b/zypp/media/MediaNetwork.h @@ -64,8 +64,9 @@ namespace zypp { public: - MediaNetwork( const Url & url_r, - const Pathname & attach_point_hint_r ); + MediaNetwork( zyppng::ContextBaseRef ctx, + const Url & url_r, + const Pathname & attach_point_hint_r ); ~MediaNetwork() override { try { release(); } catch(...) {} } diff --git a/zypp/media/MediaNetworkCommonHandler.cc b/zypp/media/MediaNetworkCommonHandler.cc index 25a32405d7..402d7359be 100644 --- a/zypp/media/MediaNetworkCommonHandler.cc +++ b/zypp/media/MediaNetworkCommonHandler.cc @@ -24,7 +24,7 @@ namespace zypp::media zypp::Url MediaNetworkCommonHandler::findGeoIPRedirect ( const zypp::Url &url ) { try { - const auto &conf = ZConfig::instance(); + const auto &conf = ZConfig::systemConfig(); if ( !conf.geoipEnabled() ) { MIL << "GeoIp rewrites disabled via ZConfig." << std::endl; return Url(); diff --git a/zypp/media/MediaNetworkCommonHandler.h b/zypp/media/MediaNetworkCommonHandler.h index 514e59cf54..f6487bcec1 100644 --- a/zypp/media/MediaNetworkCommonHandler.h +++ b/zypp/media/MediaNetworkCommonHandler.h @@ -30,11 +30,12 @@ namespace zypp class MediaNetworkCommonHandler : public MediaHandler { public: - MediaNetworkCommonHandler( const Url & url_r, + MediaNetworkCommonHandler( zyppng::ContextBaseRef ctx, + const Url & url_r, const Pathname & attach_point_r, const Pathname & urlpath_below_attachpoint_r, const bool does_download_r ) - : MediaHandler( url_r, attach_point_r, urlpath_below_attachpoint_r, does_download_r ) + : MediaHandler( std::move(ctx), url_r, attach_point_r, urlpath_below_attachpoint_r, does_download_r ) , _redirTarget( findGeoIPRedirect(url_r) ) {} diff --git a/zypp/media/MediaPlugin.cc b/zypp/media/MediaPlugin.cc index 48ba094fff..076f3a6bf0 100644 --- a/zypp/media/MediaPlugin.cc +++ b/zypp/media/MediaPlugin.cc @@ -28,8 +28,8 @@ namespace zypp namespace media { ////////////////////////////////////////////////////////////////// - MediaPlugin::MediaPlugin( const Url & url_r, const Pathname & attach_point_hint_r ) - : MediaHandler( url_r, attach_point_hint_r, /*path below attachpoint*/"/", /*does_download*/false ) + MediaPlugin::MediaPlugin(zyppng::ContextBaseRef ctx, const Url & url_r, const Pathname & attach_point_hint_r ) + : MediaHandler( std::move(ctx), url_r, attach_point_hint_r, /*path below attachpoint*/"/", /*does_download*/false ) { MIL << "MediaPlugin::MediaPlugin(" << url_r << ", " << attach_point_hint_r << ")" << endl; } diff --git a/zypp/media/MediaPlugin.h b/zypp/media/MediaPlugin.h index 998e1ef9ff..d9d6869373 100644 --- a/zypp/media/MediaPlugin.h +++ b/zypp/media/MediaPlugin.h @@ -29,7 +29,7 @@ namespace zypp class MediaPlugin : public MediaHandler { public: - MediaPlugin( const Url & url_r, const Pathname & attach_point_hint_r ); + MediaPlugin( zyppng::ContextBaseRef ctx, const Url & url_r, const Pathname & attach_point_hint_r ); ~MediaPlugin() override { try { release(); } catch(...) {} } diff --git a/zypp/media/MediaPriority.cc b/zypp/media/MediaPriority.cc index 52f842556c..0ad2b79c88 100644 --- a/zypp/media/MediaPriority.cc +++ b/zypp/media/MediaPriority.cc @@ -44,27 +44,27 @@ namespace zypp #define RETURN_IF(scheme,value) \ if ( ::strcmp( scheme+1, scheme_r.c_str()+1 ) == 0 ) return value; case 'c': - RETURN_IF( "cd", ZConfig::instance().download_media_prefer_download() ? 1 : 2 ); + RETURN_IF( "cd", ZConfig::systemConfig().download_media_prefer_download() ? 1 : 2 ); RETURN_IF( "cifs", 3 ); break; case 'd': - RETURN_IF( "dvd", ZConfig::instance().download_media_prefer_download() ? 1 : 2 ); + RETURN_IF( "dvd", ZConfig::systemConfig().download_media_prefer_download() ? 1 : 2 ); RETURN_IF( "dir", 4 ); break; case 'f': RETURN_IF( "file", 4 ); - RETURN_IF( "ftp", ZConfig::instance().download_media_prefer_download() ? 2 : 1); + RETURN_IF( "ftp", ZConfig::systemConfig().download_media_prefer_download() ? 2 : 1); break; case 't': - RETURN_IF( "tftp", ZConfig::instance().download_media_prefer_download() ? 2 : 1); + RETURN_IF( "tftp", ZConfig::systemConfig().download_media_prefer_download() ? 2 : 1); break; case 'h': - RETURN_IF( "http", ZConfig::instance().download_media_prefer_download() ? 2 : 1 ); - RETURN_IF( "https", ZConfig::instance().download_media_prefer_download() ? 2 : 1 ); + RETURN_IF( "http", ZConfig::systemConfig().download_media_prefer_download() ? 2 : 1 ); + RETURN_IF( "https", ZConfig::systemConfig().download_media_prefer_download() ? 2 : 1 ); RETURN_IF( "hd", 4 ); break; @@ -74,7 +74,7 @@ namespace zypp break; case 's': - RETURN_IF( "sftp", ZConfig::instance().download_media_prefer_download() ? 2 : 1 ); + RETURN_IF( "sftp", ZConfig::systemConfig().download_media_prefer_download() ? 2 : 1 ); RETURN_IF( "smb", 3 ); break; #undef RETURN_IF diff --git a/zypp/media/UrlResolverPlugin.cc b/zypp/media/UrlResolverPlugin.cc index 6bf7605a00..09a86929ce 100644 --- a/zypp/media/UrlResolverPlugin.cc +++ b/zypp/media/UrlResolverPlugin.cc @@ -40,7 +40,7 @@ namespace zypp Url url(o_url); std::string name = url.getPathName(); - Pathname plugin_path = (ZConfig::instance().pluginsPath()/"urlresolver")/name; + Pathname plugin_path = (ZConfig::systemConfig().pluginsPath()/"urlresolver")/name; if (PathInfo(plugin_path).isExist()) { PluginScript scr; scr.open(plugin_path); diff --git a/zypp/misc/DefaultLoadSystem.cc b/zypp/misc/DefaultLoadSystem.cc deleted file mode 100644 index 751a9dfd08..0000000000 --- a/zypp/misc/DefaultLoadSystem.cc +++ /dev/null @@ -1,114 +0,0 @@ -/*---------------------------------------------------------------------\ -| ____ _ __ __ ___ | -| |__ / \ / / . \ . \ | -| / / \ V /| _/ _/ | -| / /__ | | | | | | | -| /_____||_| |_| |_| | -| | -\---------------------------------------------------------------------*/ -/** \file zypp/misc/DefaultLoadSystem.cc - * -*/ -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include - -using std::endl; - -#undef ZYPP_BASE_LOGGER_LOGGROUP -#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::misc" - -/////////////////////////////////////////////////////////////////// -namespace zypp -{ ///////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////// - namespace misc - { ///////////////////////////////////////////////////////////////// - - void defaultLoadSystem( const Pathname & sysRoot_r, LoadSystemFlags flags_r ) - { - if ( not flags_r && geteuid() != 0 ) { - flags_r |= LS_NOREFRESH; - } - MIL << str::form( "*** Load system at '%s' (%lx)", sysRoot_r.c_str(), (unsigned long)flags_r ) << endl; - - if ( ! PathInfo( sysRoot_r ).isDir() ) - ZYPP_THROW( Exception(str::form("sysRoot_r argument needs to be a directory. (%s)", sysRoot_r.c_str())) ); - - if ( ZYppFactory::instance().haveZYpp() ) - ZYPP_THROW( Exception("ZYpp instance is already created. (Call this method earlier.)") ); - - if ( flags_r.testFlag( LS_READONLY ) ) - zypp_readonly_hack::IWantIt (); - - sat::Pool satpool( sat::Pool::instance() ); - - if ( 1 ) - { - MIL << "*** load target '" << Repository::systemRepoAlias() << "'\t" << endl; - getZYpp()->initializeTarget( sysRoot_r ); - getZYpp()->target()->load(); - MIL << satpool.systemRepo() << endl; - } - - if ( not flags_r.testFlag( LS_NOREPOS ) ) - { - RepoManager repoManager( sysRoot_r ); - RepoInfoList repos = repoManager.knownRepositories(); - for_( it, repos.begin(), repos.end() ) - { - RepoInfo & nrepo( *it ); - - if ( ! nrepo.enabled() ) - continue; - - if ( ! flags_r.testFlag( LS_NOREFRESH ) ) - { - if ( repoManager.isCached( nrepo ) - && ( nrepo.type() == repo::RepoType::RPMPLAINDIR // refreshes always - || repoManager.checkIfToRefreshMetadata( nrepo, nrepo.url() ) == RepoManager::REFRESH_NEEDED ) ) - { - MIL << str::form( "*** clean cache for repo '%s'\t", nrepo.name().c_str() ) << endl; - repoManager.cleanCache( nrepo ); - MIL << str::form( "*** refresh repo '%s'\t", nrepo.name().c_str() ) << endl; - repoManager.refreshMetadata( nrepo ); - } - } - - if ( ! repoManager.isCached( nrepo ) ) - { - MIL << str::form( "*** build cache for repo '%s'\t", nrepo.name().c_str() ) << endl; - repoManager.buildCache( nrepo ); - } - - MIL << str::form( "*** load repo '%s'\t", nrepo.name().c_str() ) << std::flush; - try - { - repoManager.loadFromCache( nrepo ); - MIL << satpool.reposFind( nrepo.alias() ) << endl; - } - catch ( const Exception & exp ) - { - ERR << "*** load repo failed: " << exp.asString() + "\n" + exp.historyAsString() << endl; - ZYPP_RETHROW ( exp ); - } - } - } - MIL << str::form( "*** Read system at '%s'", sysRoot_r.c_str() ) << endl; - } - - ///////////////////////////////////////////////////////////////// - } // namespace misc - /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////// -} // namespace zypp -/////////////////////////////////////////////////////////////////// diff --git a/zypp/misc/DefaultLoadSystem.h b/zypp/misc/DefaultLoadSystem.h deleted file mode 100644 index faa3b0fe1c..0000000000 --- a/zypp/misc/DefaultLoadSystem.h +++ /dev/null @@ -1,64 +0,0 @@ -/*---------------------------------------------------------------------\ -| ____ _ __ __ ___ | -| |__ / \ / / . \ . \ | -| / / \ V /| _/ _/ | -| / /__ | | | | | | | -| /_____||_| |_| |_| | -| | -\---------------------------------------------------------------------*/ -/** \file zypp/misc/DefaultLoadSystem.h - * -*/ -#ifndef ZYPP_MISC_DEFAULTLOADSYSTEM_H -#define ZYPP_MISC_DEFAULTLOADSYSTEM_H - -#include - -#include -#include - -/////////////////////////////////////////////////////////////////// -namespace zypp -{ ///////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////// - namespace misc - { ///////////////////////////////////////////////////////////////// - - /** - * Bits for tuning \ref defaultLoadSystem. - * - * Use \ref LoadSystemFlags as a type-safe way of - * storing OR-combinations. - */ - enum LoadSystemFlag - { - LS_READONLY = (1 << 0), //!< // Create readonly ZYpp instance. - LS_NOREFRESH = (1 << 1), //!< // Don't refresh existing repos. - LS_NOREPOS = (1 << 2), //!< // Don't loag existing repos (just Target). - }; - - /** \relates LoadSystemFlag Type-safe way of storing OR-combinations. */ - ZYPP_DECLARE_FLAGS_AND_OPERATORS( LoadSystemFlags, LoadSystemFlag ); - - /** - * Create the ZYpp instance and load target and enabled repositories. - * - * \see LoadSystemFlag for options. - * - * \throws Exception on error - * - * \todo properly handle service refreshs - */ - void defaultLoadSystem( const Pathname & sysRoot_r = "/", LoadSystemFlags flags_r = LoadSystemFlags() ); - - /** \overload */ - inline void defaultLoadSystem( LoadSystemFlags flags_r ) - { defaultLoadSystem( "/", flags_r ); } - - ///////////////////////////////////////////////////////////////// - } // namespace misc - /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////// -} // namespace zypp -/////////////////////////////////////////////////////////////////// -#endif // ZYPP_MISC_DEFAULTLOADSYSTEM_H diff --git a/zypp/misc/TestcaseSetup.cc b/zypp/misc/TestcaseSetup.cc index 0766b9fa03..8dcd2b3f36 100644 --- a/zypp/misc/TestcaseSetup.cc +++ b/zypp/misc/TestcaseSetup.cc @@ -2,6 +2,7 @@ namespace zypp::misc::testcase { + ZYPP_BEGIN_LEGACY_API RepoData::RepoData() : _pimpl( new RepoDataImpl ) {} @@ -257,4 +258,5 @@ namespace zypp::misc::testcase return *_pimpl; } + ZYPP_END_LEGACY_API } diff --git a/zypp/misc/TestcaseSetup.h b/zypp/misc/TestcaseSetup.h index 0230f39d39..3c3519ee22 100644 --- a/zypp/misc/TestcaseSetup.h +++ b/zypp/misc/TestcaseSetup.h @@ -27,6 +27,8 @@ #include #include +ZYPP_BEGIN_LEGACY_API + namespace zypp { class RepoManager; } @@ -132,5 +134,5 @@ namespace zypp::misc::testcase } - +ZYPP_END_LEGACY_API #endif // ZYPP_MISC_TESTCASESETUPIMPL_H diff --git a/zypp/ng/ContextBase b/zypp/ng/ContextBase new file mode 100644 index 0000000000..308e2f3c94 --- /dev/null +++ b/zypp/ng/ContextBase @@ -0,0 +1 @@ +#include "contextbase.h" diff --git a/zypp/ng/FusionPool b/zypp/ng/FusionPool new file mode 100644 index 0000000000..5e1f36a1ab --- /dev/null +++ b/zypp/ng/FusionPool @@ -0,0 +1 @@ +#include "fusionpool.h" diff --git a/zypp/ng/context.cc b/zypp/ng/context.cc deleted file mode 100644 index f5bb6f8624..0000000000 --- a/zypp/ng/context.cc +++ /dev/null @@ -1,72 +0,0 @@ -/*---------------------------------------------------------------------\ -| ____ _ __ __ ___ | -| |__ / \ / / . \ . \ | -| / / \ V /| _/ _/ | -| / /__ | | | | | | | -| /_____||_| |_| |_| | -| | -\---------------------------------------------------------------------*/ -#include "private/context_p.h" -#include -#include -#include -#include - -namespace zyppng { - - ZYPP_IMPL_PRIVATE( Context ) - - ZYPP_IMPL_PRIVATE_CONSTR( Context ) - : UserInterface( *new ContextPrivate( *this ) ) - { - Z_D(); - d->_zyppPtr = zypp::getZYpp(); - d->_eventDispatcher = ThreadData::current().ensureDispatcher(); - - d->_provider = Provide::create( d->_providerDir ); - - // @TODO should start be implicit as soon as something is enqueued? - d->_provider->start(); - } - - ProvideRef Context::provider() const - { - Z_D(); - return d->_provider; - } - - KeyRingRef Context::keyRing() const - { - return d_func()->_zyppPtr->keyRing(); - } - - zypp::ZConfig &Context::config() - { - return zypp::ZConfig::instance(); - } - - zypp::ResPool Context::pool() - { - return zypp::ResPool::instance(); - } - - zypp::ResPoolProxy Context::poolProxy() - { - return zypp::ResPool::instance().proxy(); - } - - zypp::sat::Pool Context::satPool() - { - return zypp::sat::Pool::instance(); - } - - void Context::executeImpl(const AsyncOpBaseRef& op) - { - auto loop = EventLoop::create(); - op->sigReady().connect([&](){ - loop->quit(); - }); - loop->run(); - return; - } -} diff --git a/zypp/ng/context.h b/zypp/ng/context.h index 39ae471ffb..8712f36ca2 100644 --- a/zypp/ng/context.h +++ b/zypp/ng/context.h @@ -6,79 +6,212 @@ | /_____||_| |_| |_| | | | \---------------------------------------------------------------------*/ -#ifndef ZYPP_NG_CONTEXT_INCLUDED -#define ZYPP_NG_CONTEXT_INCLUDED - -#include -#include -#include -#include - -namespace zypp { - DEFINE_PTR_TYPE(KeyRing); - class ZConfig; -} +#ifndef ZYPP_NG_SYNCCONTEXT_INCLUDED +#define ZYPP_NG_SYNCCONTEXT_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace zyppng { - ZYPP_FWD_DECL_TYPE_WITH_REFS( Context ); - ZYPP_FWD_DECL_TYPE_WITH_REFS( ProgressObserver ); - ZYPP_FWD_DECL_TYPE_WITH_REFS( Provide ); - - using KeyRing = zypp::KeyRing; - using KeyRingRef = zypp::KeyRing_Ptr; - - class ContextPrivate; + struct SyncTag{}; + struct AsyncTag{}; + + namespace detail { + + template + struct ContextData; + + template <> + struct ContextData + { + ContextData() + : _provider( MediaSyncFacade::create()) {} + + MediaSyncFacadeRef _provider; + }; + + template <> + struct ContextData + { + ContextData() + : _eventDispatcher(ThreadData::current().ensureDispatcher()) + , _provider( Provide::create() ){ + // @TODO should start be implicit as soon as something is enqueued? + _provider->start(); + } + zyppng::EventDispatcherRef _eventDispatcher; + ProvideRef _provider; + }; + } + template + class Context : public ContextBase, public MaybeAsyncMixin< std::is_same_v >, private detail::ContextData { - /*! - * The Context class is the central object of libzypp, carrying all state that is - * required to manage the system. - */ - class Context : public UserInterface - { - ZYPP_DECLARE_PRIVATE(Context) ZYPP_ADD_CREATE_FUNC(Context) public: + ZYPP_DECL_PRIVATE_CONSTR(Context) + { } - using ProvideType = Provide; + ZYPP_ENABLE_MAYBE_ASYNC_MIXIN( (std::is_same_v) ); + using ProvideType = std::conditional_t< std::is_same_v, Provide, MediaSyncFacade >; + using SyncOrAsyncTag = Tag; - ZYPP_DECL_PRIVATE_CONSTR(Context); + auto provider() { + return this->_provider; + } - template - void execute ( AsyncOpRef op ) { + /** + * Tries to lock a resource \a ident with specified \a mode , if the resource is locked already, + * a delayed lock request is enqueued in a list of waiters for said lock. A \a timeout is required. + */ + MaybeAsyncRef> lockResourceWait( std::string ident, uint timeout, ResourceLockRef::Mode mode = ResourceLockRef::Shared ) + { + if constexpr ( std::is_same_v ) { + auto res = this->lockResource ( ident, mode ); + if ( res ) { + return makeReadyResult ( std::move(res) ); + } else { + // any other exception than "already locked" is directly forwarded + if ( !containsException(res.error()) ) { + return makeReadyResult ( std::move(res) ); + } + + const auto &lockEntry = this->_resourceLocks.find(ident); + if ( lockEntry == this->_resourceLocks.end() ) { + ERR << "Could not find resource entry, this is a bug, trying to lock directly again!" << std::endl; + return makeReadyResult(this->lockResource ( ident, mode )); + } + + AsyncResourceLockReqRef promise = std::make_shared( ident, mode, timeout ); + lockEntry->second->_lockQueue.push_back(promise); + promise->connect( &AsyncResourceLockReq::sigTimeout, *this, &Context::onResourceLockTimeout ); + return promise; + } + } else { + // no waiting in sync context + return this->lockResource ( ident, mode ); + } + } + + template + std::enable_if_t< std::is_same_v> execute ( AsyncOpRef op ) { if ( op->isReady () ) return; - return executeImpl( op ); + + auto loop = EventLoop::create( this->_eventDispatcher ); + op->sigReady().connect([&](){ + loop->quit(); + }); + loop->run(); + return; } - ProvideRef provider() const; - KeyRingRef keyRing () const; - zypp::ZConfig &config(); + using ContextBase::legacyInit; + using ContextBase::changeToTarget; - /** - * Access to the resolvable pool. - */ - zypp::ResPool pool(); - /** Pool of ui::Selectable. - * Based on the ResPool, ui::Selectable groups ResObjetcs of - * same kind and name. - */ - zypp::ResPoolProxy poolProxy(); + private: + void onResourceLockTimeout( AsyncResourceLockReq &req ) { + // just deque the lock, finishing the pipeline is done directly by the request itself + const auto &lockEntry = this->_resourceLocks.find( req.ident () ); + if ( lockEntry == this->_resourceLocks.end() ) { + ERR << "Could not find lock ident after receiving a timeout signal from it, this is a BUG." << std::endl; + return; + } + + detail::ResourceLockData &lockData = *lockEntry->second.get(); + auto i = std::find_if( lockData._lockQueue.begin (), lockData._lockQueue.end(), [&req]( auto &weakLockOp ){ + auto lockOp = weakLockOp.lock(); + return ( lockOp && (lockOp.get() == &req) ); + }); - /** - * Access to the sat pool. - */ - zypp::sat::Pool satPool(); + if ( i == lockData._lockQueue.end() ) { + ERR << "Could not find lock request after receiving a timeout signal from it, this is a BUG." << std::endl; + return; + } - private: - void executeImpl ( const AsyncOpBaseRef& op ); + lockData._lockQueue.erase(i); + } + + void dequeueWaitingLocks( detail::ResourceLockData &resLckData ) override { + if constexpr ( std::is_same_v ) { + + // callable to be executed when event loop is idle + const auto &makeResultCallable = []( std::weak_ptr asyncOp, expected &&result ) { + // the STL does copy the lambda around inside the std::function implementation instead of moving it. So we need to make it copy'able + // which means storing the ResourceLock in a shared_ptr. + return [ asyncOp, res = std::make_shared>(std::move(result)) ] () mutable { + auto promise = asyncOp.lock(); + if ( promise ) + promise->setFinished ( std::move(*res.get()) ); + return false; // stop calling after the first time + }; + }; + + // currently we got no lock, we now will give locks to the next waiters + bool canCont = true; + bool isFirst = true; + while ( canCont && !resLckData._lockQueue.empty() ) { + auto front = resLckData._lockQueue.front().lock(); + if ( !front ) { + resLckData._lockQueue.pop_front (); + continue; + } + if ( isFirst ) { + isFirst = false; + // first iteration, we can simply give the lock no matter if shared or not + resLckData._mode = front->mode(); + // we can continue if the mode is shared, the next iteration will make sure the next one in the queue + // has shared mode too + canCont = ( resLckData._mode == ResourceLockRef::Shared ); + EventDispatcher::invokeOnIdle( makeResultCallable( front, make_expected_success( ResourceLockRef( detail::ResourceLockData_Ptr(&resLckData) ) ) ) ); + resLckData._lockQueue.pop_front(); + } else if ( front->mode() == ResourceLockRef::Shared ) { + // no need to further check the lock's mode, if we end up here the first iteration already + // checked that it is a shared lock and set canCont accordingly + resLckData._lockQueue.pop_front(); + EventDispatcher::invokeOnIdle( makeResultCallable( front, make_expected_success( ResourceLockRef( detail::ResourceLockData_Ptr(&resLckData) ) ) ) ); + } else { + // front does not have a shared lock, we need to stop here + break; + } + } + } else { + // in non async mode lock waiting is not supported + // while this code should never be executed i'll add it for completeness + while ( !resLckData._lockQueue.empty() ) { + auto front = resLckData._lockQueue.front().lock(); + if ( !front ) { + resLckData._lockQueue.pop_front (); + continue; + } + front->setFinished( expected::error( ZYPP_EXCPT_PTR( zypp::Exception("Lock waits not supported in sync mode")) ) ); + resLckData._lockQueue.pop_front (); + } + } + } }; + template + using MaybeAsyncContextRef = std::conditional_t, AsyncContextRef, SyncContextRef>; + template - auto joinPipeline( ContextRef ctx, AsyncOpRef res ) { + auto joinPipeline( SyncContextRef ctx, T &&val ) { + return std::forward(val); + } + + template + auto joinPipeline( AsyncContextRef ctx, AsyncOpRef res ) { if constexpr ( detail::is_async_op_v ) { ctx->execute(res); return res->get(); @@ -86,8 +219,6 @@ namespace zyppng { return res; } } - } - #endif diff --git a/zypp/ng/context_fwd.h b/zypp/ng/context_fwd.h new file mode 100644 index 0000000000..91799cfe61 --- /dev/null +++ b/zypp/ng/context_fwd.h @@ -0,0 +1,29 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_NG_CONTEXT_FWD_INCLUDED +#define ZYPP_NG_CONTEXT_FWD_INCLUDED + +#include + +namespace zyppng { + + struct SyncTag; + struct AsyncTag; + + ZYPP_FWD_DECL_TYPE_WITH_REFS ( ContextBase ); + ZYPP_FWD_DECL_TEMPL_TYPE_WITH_REFS_ARG1( Context, Tag ); + + using AsyncContext = Context; + ZYPP_FWD_DECL_REFS(AsyncContext); + + using SyncContext = Context; + ZYPP_FWD_DECL_REFS(SyncContext); + +} +#endif diff --git a/zypp/ng/contextbase.cc b/zypp/ng/contextbase.cc new file mode 100644 index 0000000000..fb92d05eda --- /dev/null +++ b/zypp/ng/contextbase.cc @@ -0,0 +1,284 @@ +#include "contextbase.h" +#include "zypp-core/base/dtorreset.h" +#include "zypp-core/zyppng/pipelines/mtry.h" +#include "zypp/KeyRing.h" +#include +#include "zypp/ZConfig.h" +#include "zypp/zypp_detail/ZyppLock.h" + +namespace zyppng { + + ContextBase::ContextBase() + : _tmpDir( zypp::filesystem::TmpPath::defaultLocation(), "zypp." ) + , _repoVarCache( *this ) + { } + + void ContextBase::setProgressObserver(ProgressObserverRef observer) + { + if ( _masterProgress != observer ) { + _masterProgress = observer; + _sigProgressObserverChanged.emit(); + } + } + + ProgressObserverRef ContextBase::progressObserver() const + { + return _masterProgress; + } + + void ContextBase::resetProgressObserver() + { + if ( _masterProgress ) { + _masterProgress.reset(); + _sigProgressObserverChanged.emit(); + } + } + + ContextBase::~ContextBase() + { } + + zypp::Pathname ContextBase::contextRoot() const + { + // this is a programming error, the C API will hide the 2 step create and init process. + if ( !_settings ) + ZYPP_THROW (zypp::Exception("Uninitialized Context")); + + // target always wins, normally this should be same same as the settings root + // but legacy mode can change the target + if ( _target ) + return _target->root (); + + return _settings->root; + } + + /*! + * Legacy support, we change the target inside our context + */ + void ContextBase::changeToTarget( const zypp::Pathname & root, bool doRebuild_r ) + { + if ( _target && _target->root() == root ) { + MIL << "Repeated call to changeToTarget()" << std::endl; + return; + } + + assertInitialized(); + finishTarget().unwrap (); + _target = new zypp::Target( root, doRebuild_r ); + _sigTargetChanged.emit(); + + _config->notifyTargetChanged( _target->root(), *_settings->configPath ); + } + + expected ContextBase::aquireLock() + { + auto myLock = zypp::ZyppContextLock::globalLock( _myRoot ); + try { + myLock->acquireLock (); + } catch (...) { + return expected::error ( ZYPP_FWD_CURRENT_EXCPT() ); + } + return expected::success ( std::move(myLock) ); + } + + expected ContextBase::loadConfig( zypp::Pathname confPath ) + { + try { + _config.reset( new zypp::ZConfig(confPath) ); + } catch (...) { + _config.reset(); + return expected::error( ZYPP_FWD_CURRENT_EXCPT() ); + } + return expected::success(); + } + + void ContextBase::assertInitialized() + { + // this is a programming error, the C API will hide the 2 step create and init process. + if ( !_settings ) + ZYPP_THROW (zypp::Exception("Uninitialized Context")); + + if ( !_config && !_settings->configPath ) { + _settings->configPath = _settings->root / defaultConfigPath(); + } + + if ( !_keyRing ) { + MIL << "Initializing keyring..." << std::endl; + _keyRing = new KeyRing(tmpPath()); + _keyRing->allowPreload( true ); + } + } + + expected ContextBase::initialize( ContextSettings &&settings ) + { + if ( _settings ) { + return expected::error( ZYPP_EXCPT_PTR (zypp::Exception("Context can not be initialized twice")) ); + } + + _settings = std::move(settings); + + try { + assertInitialized (); + } catch ( const zypp::Exception & ) { + return expected::error( ZYPP_FWD_CURRENT_EXCPT() ); + } + + using namespace zyppng::operators; + + return loadConfig( *_settings->configPath ) + // aquire the lock + | and_then ( [this](){ return aquireLock(); } ) + // last step , remember the lock, init the target + | and_then ( [this]( zypp::ZyppContextLockRef myLock ) { + // init the target + try { + // everything worked , keep the lock + _myLock = myLock; + + return expected::success(); + } catch(...) { + return expected::error( ZYPP_FWD_CURRENT_EXCPT () ); + } + }); + } + + expected ContextBase::initTarget() + { + try { + + if ( _target ) { + MIL << "Repeated call to initTarget, ignoring." << std::endl; + return expected::success(); + } + + MIL << "context(" << this << ") initTarget( " << _myRoot << (_settings->rebuildDb ?", rebuilddb":"") << ")" << std::endl; + _target = new zypp::Target( _myRoot, _settings->rebuildDb ); + return expected::success(); + + } catch ( ... ) { + return expected::error( ZYPP_FWD_CURRENT_EXCPT() ); + } + } + + expected ContextBase::finishTarget() + { + try { + _sigClose.emit(); // trigger target unload from the pools it might be loaded into + return expected::success(); + } catch ( ... ) { + return expected::error( ZYPP_FWD_CURRENT_EXCPT() ); + } + } + + void ContextBase::legacyInit( ContextSettings &&settings, zypp::ZConfigRef sharedConf ) + { + if ( _settings ) { + ZYPP_THROW (zypp::Exception("Context can not be initialized twice")); + } + _settings = std::move(settings); + _config = std::move(sharedConf); + _legacyMode = true; + } + + KeyRingRef ContextBase::keyRing() + { + assertInitialized(); + return _keyRing; + } + + zypp::ZConfig &ContextBase::config() + { + assertInitialized(); + // config loaded on demand if queried before initializing the target + if ( !_config ) loadConfig ( *_settings->configPath ).unwrap(); + return *_config; + } + + zypp::MediaConfig &ContextBase::mediaConfig() + { + assertInitialized(); + // config loaded on demand if queried before initializing the target + if ( !_config ) loadConfig ( *_settings->configPath ).unwrap(); + return _config->mediaConfig(); + } + + zypp::Pathname ContextBase::tmpPath() const + { + return _tmpDir.path(); + } + + TargetRef ContextBase::target() const + { + return _target; + } + + expected ContextBase::lockResource(std::string ident , ResourceLockRef::Mode mode) + { + auto i = _resourceLocks.find ( ident ); + if ( i == _resourceLocks.end() ) { + // simple case, lock does not exist + auto lockData = detail::ResourceLockData_Ptr( new detail::ResourceLockData()); + lockData->_resourceIdent = std::move(ident); + lockData->_mode = mode; + lockData->_zyppContext = shared_this(); + _resourceLocks.insert( std::make_pair( lockData->_resourceIdent, lockData ) ); + return expected::success( std::move(lockData) ); + } else { + if ( mode == ResourceLockRef::Shared && i->second->_mode == ResourceLockRef::Shared ) + return expected::success( i->second ); + return expected::error( ZYPP_EXCPT_PTR(ResourceAlreadyLockedException(ident))); + } + } + + void ContextBase::lockUnref( const std::string &ident ) + { + if ( _inUnrefLock ) + return; + + zypp::DtorReset resetUnrefLock( _inUnrefLock, false ); + _inUnrefLock = true; + + auto i = _resourceLocks.find ( ident ); + if ( i == _resourceLocks.end() ) { + MIL << "Unknown lock: " << ident << " can not be unref'ed" << std::endl; + return; + } + + auto &lockData = *i->second.get(); + if ( lockData.refCount() > 1 ) + return; + + // some house keeping, remove expired waiters + { + auto i = std::remove_if( lockData._lockQueue.begin (), lockData._lockQueue.end(), []( const auto &elem ){ return elem.expired(); }); + lockData._lockQueue.erase( i, lockData._lockQueue.end() ); + } + + if ( lockData._lockQueue.empty() ) { + _resourceLocks.erase( lockData._resourceIdent ); + return; + } else { + dequeueWaitingLocks ( lockData ); + } + } + + const std::string *ContextBase::resolveRepoVar(const std::string &var) + { + return _repoVarCache.lookup(var); + } + + repo::RepoVarsMap &ContextBase::repoVarCache() + { + return _repoVarCache; + } + + const repo::RepoVarsMap &ContextBase::repoVarCache() const + { + return _repoVarCache; + } + + void ContextBase::clearRepoVariables() + { + _repoVarCache.clear(); + } + +} diff --git a/zypp/ng/contextbase.h b/zypp/ng/contextbase.h new file mode 100644 index 0000000000..7d51b13b50 --- /dev/null +++ b/zypp/ng/contextbase.h @@ -0,0 +1,211 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_NG_CONTEXTBASE_INCLUDED +#define ZYPP_NG_CONTEXTBASE_INCLUDED + +#include +#include +#include +#include +#include + +namespace zypp { + DEFINE_PTR_TYPE(KeyRing); + DEFINE_PTR_TYPE(Target); + ZYPP_FWD_DECL_TYPE_WITH_REFS( ZyppContextLock ); + ZYPP_FWD_DECL_TYPE_WITH_REFS( ZConfig ); + class ZConfig; +} + + +namespace zyppng { + + ZYPP_FWD_DECL_TYPE_WITH_REFS (ContextBase); + ZYPP_FWD_DECL_TYPE_WITH_REFS (ProgressObserver); + + using KeyRing = zypp::KeyRing; + using KeyRingRef = zypp::KeyRing_Ptr; + + using Target = zypp::Target; + using TargetRef = zypp::Target_Ptr; + + struct ContextSettings { + zypp::Pathname root = "/"; + bool rebuildDb = false; + std::optional configPath; + }; + + class ContextBase : public MediaContext + { + public: + ~ContextBase() override; + ContextBase(const ContextBase &) = delete; + ContextBase(ContextBase &&) = delete; + ContextBase &operator=(const ContextBase &) = delete; + ContextBase &operator=(ContextBase &&) = delete; + + + /*! + * Sets the master progress observer for this context, this is the place where all + * events and progress are received from, can be shared with another context. + */ + void setProgressObserver( ProgressObserverRef observer ); + + + /*! + * Returns the current \ref ProgressObserver, or a empty reference if + * no observer was registered + */ + ProgressObserverRef progressObserver( ) const; + + /*! + * Resets the currently used \ref ProgressObserver. + * Currently running pipelines might still have a reference to the + * observer though. + */ + void resetProgressObserver(); + + + /*! + * Returns the root path of the context + */ + zypp::Pathname contextRoot() const override; + + /*! + * Gets the zypp lock, loads the config and sets up keyring + */ + expected initialize( ContextSettings &&settings = {} ); + + + /*! + * Initialize the target, this will trigger file creation + * in the context root, for example the rpm database. + */ + expected initTarget (); + + /*! + * Request the target to be released from all pools it is currently + * part of. + */ + expected finishTarget(); + + KeyRingRef keyRing (); + zypp::ZConfig &config(); + zypp::MediaConfig &mediaConfig() override; + zypp::Pathname tmpPath() const; + TargetRef target() const; + + /*! + * Attempts to lock the resource identified by \a ident. + * The returned lock is automatically released when the last + * Shared or the last Exclusive lock instance is released. + */ + expected lockResource (std::string ident, ResourceLockRef::Mode mode = ResourceLockRef::Shared ); + + + void lockUnref( const std::string &ident ); + + + /*! + * Tries to resolve the variable \a var from the repoCache, + * returns a pointer to the found value or nullptr if the variable + * is not known. + */ + const std::string * resolveRepoVar( const std::string & var ); + + repo::RepoVarsMap &repoVarCache(); + const repo::RepoVarsMap &repoVarCache() const; + + /*! + * Resets all cached repo variables + */ + void clearRepoVariables(); + + /*! + * Signal emitted during context close, e.g. unloading the target. + * All classes depending on the context can connect to it to clean up. + * E.g. FusionPool uses it to know when a target that is loaded into the pool + * is shutting down, so it can be automatically unloaded + */ + SignalProxy sigClose() { + return _sigClose; + } + + /*! + * This signal is always emitted when the progress observer is changed, + * primarily used to signal the C wrapper to update its reference + */ + SignalProxy sigProgressObserverChanged() { + return _sigProgressObserverChanged; + } + + protected: + ContextBase(); + + // legacy support functions, we need those for supporting the + // Zypp pointer and other legacy things. Do not use in logic code + + /*! + * Partially initializes the context, sets up keyring and assigns the global config + * reference, but does not yet boot the target. In legacy mode changeToTarget + * needs to be called as well by the Zypp instance + */ + void legacyInit( ContextSettings &&settings, zypp::ZConfigRef sharedConf ); + + /*! + * Legacy support, might throw. This changes the internaly used zypp::Target. + */ + void changeToTarget( const zypp::Pathname &root , bool doRebuild_r ); + + SignalProxy sigTargetChanged() { + return _sigTargetChanged; + } + + private: + + virtual void dequeueWaitingLocks( detail::ResourceLockData & ) = 0; + + /** + * \todo move CredentialManager here + */ + + std::optional _settings; + bool _legacyMode = false; // set by legacyInit. Will disable locking inside the context, Zypp and ZyppFactory take care of that + bool _inUnrefLock = false; + + Signal _sigClose; + Signal _sigTargetChanged; // legacy support signal in case the context changes its target + Signal _sigProgressObserverChanged; + + expected aquireLock(); + expected loadConfig( zypp::Pathname confPath ); + void assertInitialized(); + + + zypp::Pathname _myRoot; + zypp::ZConfigRef _config; + + zypp::filesystem::TmpDir _tmpDir; + KeyRingRef _keyRing; + TargetRef _target; + + zypp::ZyppContextLockRef _myLock; + repo::RepoVarsMap _repoVarCache; + + ProgressObserverRef _masterProgress; + + protected: + std::map _resourceLocks; + }; + + +} + + +#endif diff --git a/zypp/ng/fusionpool.cc b/zypp/ng/fusionpool.cc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/zypp/ng/fusionpool.h b/zypp/ng/fusionpool.h new file mode 100644 index 0000000000..337eb46be6 --- /dev/null +++ b/zypp/ng/fusionpool.h @@ -0,0 +1,277 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_NG_FUSIONPOOL_INCLUDED +#define ZYPP_NG_FUSIONPOOL_INCLUDED + +#include +#include +#include +#include +#include +#include +#include + +#include + + +#include +#include +#include +#include +#include +#include + +namespace zyppng { + + ZYPP_FWD_DECL_TEMPL_TYPE_WITH_REFS_ARG1 (FusionPool, ContextType ); + + /*! + * This class is the C++ representation of the GLib-C Pool class, + * it defines the combination of Repositories, Target and solv Pool that + * can be used to query and manipulate a system. + * + * The zypp context of a repository can be different than the one from + * the target. Idea here is that we can use the repo config from "/" to install + * into a target in a different location, with different settings .. e.g. "/mnt/newtarget". + * The FusionPool will then use the "/" context to download files but install them into "/mnt/newtarget". + * + * \note Currently there is just one FusionPool instance, until we figured out if we can refactor the code to support multiple. + * + * \sa ZyppPool + */ + template + class FusionPool : public Base + { + ZYPP_ADD_PRIVATE_CONSTR_HELPER (); + + friend class RepoManager>; + + public: + + FusionPool( ZYPP_PRIVATE_CONSTR_ARG ) + : _pool( zypp::ResPool::instance() ) + , _satPool( zypp::sat::Pool::instance() ) + , _proxy( _pool.proxy() ) + , _resolver( new zypp::Resolver( zypp::ResPool::instance()) ) + { } + + /*! + * Loads the \ref zypp::Target into the pool, will unload any other currently loaded target before. + * If \a context is a nullptr just unloads the current target + */ + expected setTargetContext( Ref context ) { + try { + // do nothing if we have the target loaded already + if ( _targetContext == context ) { + MIL << "Repeated call to setTargetContext()" << std::endl; + return expected::success(); + } + + unloadTargetContext (); + + if ( context ) { + zypp::Target_Ptr newTarget = context->target(); + if ( !newTarget ) { + ZYPP_THROW(zypp::Exception("Target not initialized.")); + } + + newTarget->buildCache(); + newTarget->load(); + + _targetContext = std::move(context); + _targetCloseConn = _targetContext->sigClose().connect( sigc::mem_fun( *this, &FusionPool::onContextClose ) ); + } + + return expected::success(); + + } catch (...) { + return expected::error( ZYPP_FWD_CURRENT_EXCPT () ); + } + } + + void unloadTargetContext () { + _targetCloseConn.disconnect(); + if (!_targetContext ) + return; + + MIL << "Unloading closing context"; + _targetContext->target()->unload(); + _targetContext.reset(); + _resolver->setDefaultSolverFlags( /*all_r*/false ); // just changed defaults + } + + Ref targetContext() const { return _targetContext; } + + expected commit ( const zypp::ZYppCommitPolicy & policy_r ) { + try { + + if ( getenv("ZYPP_TESTSUITE_FAKE_ARCH") ) { + ZYPP_THROW( zypp::Exception("ZYPP_TESTSUITE_FAKE_ARCH set. Commit not allowed and disabled.") ); + } + + MIL << "Attempt to commit (" << policy_r << ")" << std::endl; + if (! _targetContext ) + ZYPP_THROW( zypp::Exception("No target context associated with the pool, commit not possible.") ); + + zypp::Target_Ptr _target = _targetContext->target(); + if (! _target) + ZYPP_THROW( zypp::Exception("Target not initialized.") ); + + zypp::env::ScopedSet ea { "ZYPP_IS_RUNNING", zypp::str::numstring(getpid()).c_str() }; + zypp::env::ScopedSet eb; + if ( _target->chrooted() ) + eb = zypp::env::ScopedSet( "SYSTEMD_OFFLINE", "1" ); // bsc#1118758 - indicate no systemd if chrooted install + + zypp::ZYppCommitResult res = _target->_pimpl->commit( resPool(), policy_r ); + + if (! policy_r.dryRun() ) + { + if ( policy_r.syncPoolAfterCommit() ) + { + // reload new status from target + DBG << "reloading " << _satPool.systemRepoAlias() << " repo to pool" << std::endl; + _target->load(); + } + else + { + DBG << "unloading " << _satPool.systemRepoAlias() << " repo from pool" << std::endl; + unloadTargetContext(); + } + } + + MIL << "Commit (" << policy_r << ") returned: " + << res << std::endl; + return expected::success(res); + } catch (...) { + return expected::error( ZYPP_FWD_CURRENT_EXCPT() ); + } + } + + expected loadFromCache ( const RepoInfo & info, ProgressObserverRef myProgress ) { + using namespace zyppng::operators; + return zyppng::mtry( [this, info, myProgress](){ + ProgressObserver::setup( myProgress, _("Loading from cache"), 3 ); + ProgressObserver::start( myProgress ); + + if ( info.solvCachePath ().empty () ) { + ZYPP_THROW( zypp::Exception("RepoInfo must have a solv cache path initialized") ); + } + + assert_alias(info).unwrap(); + zypp::Pathname solvfile = info.solvCachePath() / "solv"; + + if ( ! zypp::PathInfo(solvfile).isExist() ) + ZYPP_THROW(zypp::repo::RepoNotCachedException(info)); + + satPool().reposErase( info.alias() ); + + ProgressObserver::increase ( myProgress ); + + zypp::Repository repo = satPool().addRepoSolv( solvfile, info ); + + ProgressObserver::increase ( myProgress ); + + // test toolversion in order to rebuild solv file in case + // it was written by a different libsolv-tool parser. + const std::string & toolversion( zypp::sat::LookupRepoAttr( zypp::sat::SolvAttr::repositoryToolVersion, repo ).begin().asString() ); + if ( toolversion != LIBSOLV_TOOLVERSION ) { + repo.eraseFromPool(); + ZYPP_THROW(zypp::Exception(zypp::str::Str() << "Solv-file was created by '"<cleanCache( info, ProgressObserver::makeSubTask( myProgress ) ) + | and_then([this, repoMgr, info, myProgress]{ + return repoMgr->buildCache ( info, zypp::RepoManagerFlags::BuildIfNeeded, ProgressObserver::makeSubTask( myProgress ) ); + }) + | and_then( mtry([this, repoMgr, info = info]{ + satPool().addRepoSolv( solv_path_for_repoinfo( repoMgr->options(), info).unwrap() / "solv", info ); + })); + }) + */ + | and_then([myProgress]{ + ProgressObserver::finish ( myProgress ); + return expected::success(); + }) + | or_else([myProgress]( auto ex ){ + ProgressObserver::finish ( myProgress, ProgressObserver::Error ); + return expected::error(ex); + }) + ; + } + + expected addRepo ( const RepoInfo &info ) { + return expected::success (); + } + + + /*! + * Returns the default Pool, currently this is the only supported Pool, + * in the future we might allow having multiple pools at the same time. + */ + static FusionPoolRef defaultPool() { + static FusionPoolRef me = std::make_shared>( ZYPP_PRIVATE_CONSTR_ARG_VAL ); + return me; + } + + /*! + * \internal Access to legacy ResPool, not exported as C API + */ + zypp::ResPool &resPool() { + return _pool; + } + + /*! + * \internal Access to legacy sat::Pool, not exported as C API + */ + zypp::sat::Pool &satPool() { + return _satPool; + } + + /*! + * \internal Access to legacy ResPoolProxy, not exported as C API + */ + zypp::ResPoolProxy &poolProxy() { + return _proxy; + } + + zypp::Resolver_Ptr resolver() { + return _resolver; + } + + private: + + void onContextClose() { + unloadTargetContext (); + } + + /*! + * Loads the given RepoInfo associated with a solvFile into the Pool. + */ + expected addRepository ( RepoInfo info, zypp::Pathname solvFilePath ) + { + return expected::error( ZYPP_EXCPT_PTR( zypp::Exception("Not implemented")) ); + } + + + private: + Ref _targetContext; + zypp::ResPool _pool; + zypp::sat::Pool _satPool; + zypp::ResPoolProxy _proxy; + zypp::Resolver_Ptr _resolver; + connection _targetCloseConn; + }; + +} + +#endif diff --git a/zypp/parser/RepoFileReader.cc b/zypp/ng/parser/RepoFileReader.cc similarity index 71% rename from zypp/parser/RepoFileReader.cc rename to zypp/ng/parser/RepoFileReader.cc index e3d9090d0e..9daf8e911a 100644 --- a/zypp/parser/RepoFileReader.cc +++ b/zypp/ng/parser/RepoFileReader.cc @@ -6,24 +6,25 @@ | /_____||_| |_| |_| | | | \---------------------------------------------------------------------*/ -/** \file zypp/repo/RepoFileReader.cc +/** \file zypp/ng/repo/RepoFileReader.cc * */ + +#include "RepoFileReader.h" #include #include #include #include +#include #include #include #include - #include -#include using std::endl; /////////////////////////////////////////////////////////////////// -namespace zypp +namespace zyppng { /////////////////////////////////////////////////////////////////// namespace parser @@ -35,10 +36,10 @@ namespace zypp /// \class RepoFileParser /// \brief Modified \ref IniDict to allow parsing multiple 'baseurl=' entries /////////////////////////////////////////////////////////////////// - class RepoFileParser : public IniDict + class RepoFileParser : public zypp::parser::IniDict { public: - RepoFileParser( const InputStream & is_r ) + RepoFileParser( const zypp::InputStream & is_r ) { read( is_r ); } using IniDict::consume; // don't hide overloads we don't redefine here @@ -93,40 +94,40 @@ namespace zypp break; case MultiLine::none: - IniDict::garbageLine( section_r, line_r ); // throw + zypp::parser::IniDict::garbageLine( section_r, line_r ); // throw break; } } - std::list & baseurls( const std::string & section_r ) + std::list & baseurls( const std::string & section_r ) { return _baseurls[section_r]; } - std::list & gpgkeys( const std::string & section_r ) + std::list & gpgkeys( const std::string & section_r ) { return _gpgkeys[section_r]; } - std::list & mirrorlist( const std::string & section_r ) + std::list & mirrorlist( const std::string & section_r ) { return _mirrorlist[section_r]; } - std::list & metalink( const std::string & section_r ) + std::list & metalink( const std::string & section_r ) { return _metalink[section_r]; } private: - void storeUrl( std::list & store_r, const std::string & line_r ) + void storeUrl( std::list & store_r, const std::string & line_r ) { // #285: Fedora/dnf allows WS separated urls (and an optional comma) - strv::splitRx( line_r, "[,[:blank:]]*[[:blank:]][,[:blank:]]*", [&store_r]( std::string_view w ) { + zypp::strv::splitRx( line_r, "[,[:blank:]]*[[:blank:]][,[:blank:]]*", [&store_r]( std::string_view w ) { if ( ! w.empty() ) - store_r.push_back( Url(std::string(w)) ); + store_r.push_back( zypp::Url(std::string(w)) ); }); } enum class MultiLine { none, baseurl, gpgkey, mirrorlist, metalink }; MultiLine _inMultiline = MultiLine::none; - std::map> _baseurls; - std::map> _gpgkeys; - std::map> _mirrorlist; - std::map> _metalink; + std::map> _baseurls; + std::map> _gpgkeys; + std::map> _mirrorlist; + std::map> _metalink; }; } //namespace @@ -136,14 +137,15 @@ namespace zypp * \short List of RepoInfo's from a file. * \param file pathname of the file to read. */ - static void repositories_in_stream( const InputStream &is, + static void repositories_in_stream( ContextBaseRef ctx, + const zypp::InputStream &is, const RepoFileReader::ProcessRepo &callback, - const ProgressData::ReceiverFnc &progress ) + const zypp::ProgressData::ReceiverFnc &progress ) try { RepoFileParser dict(is); for_( its, dict.sectionsBegin(), dict.sectionsEnd() ) { - RepoInfo info; + RepoInfo info(ctx); info.setAlias(*its); std::string proxy; std::string proxyport; @@ -154,23 +156,23 @@ namespace zypp if (it->first == "name" ) info.setName(it-> second); else if ( it->first == "enabled" ) - info.setEnabled( str::strToTrue( it->second ) ); + info.setEnabled( zypp::str::strToTrue( it->second ) ); else if ( it->first == "priority" ) - info.setPriority( str::strtonum( it->second ) ); + info.setPriority( zypp::str::strtonum( it->second ) ); else if ( it->first == "path" ) - info.setPath( Pathname(it->second) ); + info.setPath( zypp::Pathname(it->second) ); else if ( it->first == "type" ) ; // bsc#1177427 et.al.: type in a .repo file is legacy - ignore it and let RepoManager probe else if ( it->first == "autorefresh" ) - info.setAutorefresh( str::strToTrue( it->second ) ); + info.setAutorefresh( zypp::str::strToTrue( it->second ) ); else if ( it->first == "gpgcheck" ) - info.setGpgCheck( str::strToTriBool( it->second ) ); + info.setGpgCheck( zypp::str::strToTriBool( it->second ) ); else if ( it->first == "repo_gpgcheck" ) - info.setRepoGpgCheck( str::strToTrue( it->second ) ); + info.setRepoGpgCheck( zypp::str::strToTrue( it->second ) ); else if ( it->first == "pkg_gpgcheck" ) - info.setPkgGpgCheck( str::strToTrue( it->second ) ); + info.setPkgGpgCheck( zypp::str::strToTrue( it->second ) ); else if ( it->first == "keeppackages" ) - info.setKeepPackages( str::strToTrue( it->second ) ); + info.setKeepPackages( zypp::str::strToTrue( it->second ) ); else if ( it->first == "service" ) info.setService( it->second ); else if ( it->first == "proxy" ) @@ -178,9 +180,9 @@ namespace zypp // Translate it into baseurl queryparams // NOTE: The hack here does not add proxy to mirrorlist urls but the // original code worked without complains, so keep it for now. - static const str::regex ex( ":[0-9]+$" ); // portspec - str::smatch what; - if ( str::regex_match( it->second, what, ex ) ) + static const zypp::str::regex ex( ":[0-9]+$" ); // portspec + zypp::str::smatch what; + if ( zypp::str::regex_match( it->second, what, ex ) ) { proxy = it->second.substr( 0, it->second.size() - what[0].size() ); proxyport = what[0].substr( 1 ); @@ -222,7 +224,7 @@ namespace zypp // ZYPP_THROW(AbortRequestException()); } } - catch ( Exception & ex ) { + catch ( zypp::Exception & ex ) { ex.addHistory( "Parsing .repo file "+is.name() ); ZYPP_RETHROW( ex ); } @@ -233,20 +235,24 @@ namespace zypp // /////////////////////////////////////////////////////////////////// - RepoFileReader::RepoFileReader( const Pathname & repo_file, + RepoFileReader::RepoFileReader( ContextBaseRef context, + const zypp::Pathname & repo_file, ProcessRepo callback, - const ProgressData::ReceiverFnc &progress ) - : _callback(std::move(callback)) + const zypp::ProgressData::ReceiverFnc &progress ) + : _context( std::move(context) ) + , _callback(std::move(callback)) { - repositories_in_stream(InputStream(repo_file), _callback, progress); + repositories_in_stream(_context, zypp::InputStream(repo_file), _callback, progress); } - RepoFileReader::RepoFileReader( const InputStream &is, + RepoFileReader::RepoFileReader( ContextBaseRef context, + const zypp::InputStream &is, ProcessRepo callback, - const ProgressData::ReceiverFnc &progress ) - : _callback(std::move(callback)) + const zypp::ProgressData::ReceiverFnc &progress ) + : _context( std::move(context) ) + , _callback(std::move(callback)) { - repositories_in_stream(is, _callback, progress); + repositories_in_stream(_context, is, _callback, progress); } RepoFileReader::~RepoFileReader() diff --git a/zypp/parser/RepoFileReader.h b/zypp/ng/parser/RepoFileReader.h similarity index 85% rename from zypp/parser/RepoFileReader.h rename to zypp/ng/parser/RepoFileReader.h index e97c86790b..663ead3564 100644 --- a/zypp/parser/RepoFileReader.h +++ b/zypp/ng/parser/RepoFileReader.h @@ -6,7 +6,7 @@ | /_____||_| |_| |_| | | | \---------------------------------------------------------------------*/ -/** \file zypp/repo/RepoFileReader.h +/** \file zypp/ng/parser/RepoFileReader.h * */ #ifndef ZYPP_REPO_REPOFILEREADER_H @@ -18,9 +18,10 @@ #include #include #include +#include /////////////////////////////////////////////////////////////////// -namespace zypp +namespace zyppng { ///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// namespace parser @@ -61,7 +62,7 @@ namespace zypp * Return false from the callback to get a \ref AbortRequestException * to be thrown and the processing to be cancelled. */ - using ProcessRepo = function; + using ProcessRepo = std::function; /** Implementation */ class Impl; @@ -70,6 +71,7 @@ namespace zypp /** * \short Constructor. Creates the reader and start reading. * + * \param context The zypp context this RepoFileReader should evaluate in * \param repo_file A valid .repo file * \param callback Callback that will be called for each repository. * \param progress Optional progress function. \see ProgressData @@ -78,9 +80,10 @@ namespace zypp * \throws Exception If a error occurs at reading / parsing * */ - RepoFileReader( const Pathname & repo_file, + RepoFileReader( ContextBaseRef context, + const zypp::Pathname & repo_file, ProcessRepo callback, - const ProgressData::ReceiverFnc &progress = ProgressData::ReceiverFnc() ); + const zypp::ProgressData::ReceiverFnc &progress = zypp::ProgressData::ReceiverFnc() ); /** * \short Constructor. Creates the reader and start reading. @@ -93,15 +96,17 @@ namespace zypp * \throws Exception If a error occurs at reading / parsing * */ - RepoFileReader( const InputStream &is, + RepoFileReader( ContextBaseRef context, + const zypp::InputStream &is, ProcessRepo callback, - const ProgressData::ReceiverFnc &progress = ProgressData::ReceiverFnc() ); + const zypp::ProgressData::ReceiverFnc &progress = zypp::ProgressData::ReceiverFnc() ); /** * Dtor */ ~RepoFileReader(); private: + ContextBaseRef _context; ProcessRepo _callback; }; /////////////////////////////////////////////////////////////////// diff --git a/zypp/ng/parser/repoindexfilereader.cc b/zypp/ng/parser/repoindexfilereader.cc new file mode 100644 index 0000000000..9601cd078a --- /dev/null +++ b/zypp/ng/parser/repoindexfilereader.cc @@ -0,0 +1,255 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/ng/parser/repoindexfilereader.cc + * Implementation of repoindex.xml file reader. + */ + +#include "repoindexfilereader.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + + +#undef ZYPP_BASE_LOGGER_LOGGROUP +#define ZYPP_BASE_LOGGER_LOGGROUP "parser" + +using std::endl; + +namespace zyppng +{ + namespace parser + { + class RepoIndexVarReplacer + { + public: + RepoIndexVarReplacer() = default; + ~RepoIndexVarReplacer() = default; + RepoIndexVarReplacer(const RepoIndexVarReplacer &) = delete; + RepoIndexVarReplacer(RepoIndexVarReplacer &&) = delete; + RepoIndexVarReplacer &operator=(const RepoIndexVarReplacer &) = delete; + RepoIndexVarReplacer &operator=(RepoIndexVarReplacer &&) = delete; + /** */ + void setVar( const std::string & key_r, const std::string & val_r ) + { + //MIL << "*** Inject " << key_r << " = " << val_r; + _vars[key_r] = replace( val_r ); + //MIL << " (" << _vars[key_r] << ")" << endl; + } + + std::string replace( const std::string & val_r ) const + { + std::string::size_type vbeg = val_r.find( "%{", 0 ); + if ( vbeg == std::string::npos ) + return val_r; + + zypp::str::Str ret; + std::string::size_type cbeg = 0; + for( ; vbeg != std::string::npos; vbeg = val_r.find( "%{", vbeg ) ) + { + std::string::size_type nbeg = vbeg+2; + std::string::size_type nend = val_r.find( '}', nbeg ); + if ( nend == std::string::npos ) + { + WAR << "Incomplete variable in '" << val_r << "'" << endl; + break; + } + const auto & iter = _vars.find( val_r.substr( nbeg, nend-nbeg ) ); + if ( iter != _vars.end() ) + { + if ( cbeg < vbeg ) + ret << val_r.substr( cbeg, vbeg-cbeg ); + ret << iter->second; + cbeg = nend+1; + } + else + WAR << "Undefined variable %{" << val_r.substr( nbeg, nend-nbeg ) << "} in '" << val_r << "'" << endl; + vbeg = nend+1; + } + if ( cbeg < val_r.size() ) + ret << val_r.substr( cbeg ); + + return ret; + } + private: + std::unordered_map _vars; + }; + + bool RepoIndexFileReader::getAttrValue( const std::string & key_r, zypp::xml::Reader & reader_r, std::string & value_r ) + { + const zypp::xml::XmlString & s( reader_r->getAttribute( key_r ) ); + if ( s.get() ) + { + value_r = _replacer->replace( s.asString() ); + return !value_r.empty(); + } + value_r.clear(); + return false; + } + + + // -------------------------------------------------------------------------- + + /* + * xpath and multiplicity of processed nodes are included in the code + * for convenience: + * + * // xpath: (?|*|+) + * + * if multiplicity is ommited, then the node has multiplicity 'one'. + */ + + // -------------------------------------------------------------------------- + + bool RepoIndexFileReader::consumeNode( zypp::xml::Reader & reader_r ) + { + if ( reader_r->nodeType() == XML_READER_TYPE_ELEMENT ) + { + // xpath: /repoindex + if ( reader_r->name() == "repoindex" ) + { + while ( reader_r.nextNodeAttribute() ) + { + const std::string & name( reader_r->localName().asString() ); + const std::string & value( reader_r->value().asString() ); + _replacer->setVar( name, value ); + // xpath: /repoindex@ttl + if ( name == "ttl" ) + _ttl = zypp::str::strtonum(value); + } + return true; + } + + // xpath: /repoindex/data (+) + if ( reader_r->name() == "repo" ) + { + RepoInfo info(_zyppCtx); + // Set some defaults that are not contained in the repo information + info.setAutorefresh( true ); + info.setEnabled(false); + + std::string attrValue; + + // required alias + // mandatory, so we can allow it in var replacement without reset + if ( getAttrValue( "alias", reader_r, attrValue ) ) + { + info.setAlias( attrValue ); + _replacer->setVar( "alias", attrValue ); + } + else + throw zypp::parser::ParseException(zypp::str::form(_("Required attribute '%s' is missing."), "alias")); + + // required url + // SLES HACK: or path, but beware of the hardcoded '/repo' prefix! + { + std::string urlstr; + std::string pathstr; + getAttrValue( "url", reader_r, urlstr ); + getAttrValue( "path", reader_r, pathstr ); + if ( urlstr.empty() ) + { + if ( pathstr.empty() ) + throw zypp::parser::ParseException(zypp::str::form(_("One or both of '%s' or '%s' attributes is required."), "url", "path")); + else + info.setPath( zypp::Pathname("/repo") / pathstr ); + } + else + { + if ( pathstr.empty() ) + info.setBaseUrl( zypp::Url(urlstr) ); + else + { + zypp::Url url( urlstr ); + url.setPathName( zypp::Pathname(url.getPathName()) / "repo" / pathstr ); + info.setBaseUrl( url ); + } + } + } + + // optional name + if ( getAttrValue( "name", reader_r, attrValue ) ) + info.setName( attrValue ); + + // optional targetDistro + if ( getAttrValue( "distro_target", reader_r, attrValue ) ) + info.setTargetDistribution( attrValue ); + + // optional priority + if ( getAttrValue( "priority", reader_r, attrValue ) ) + info.setPriority( zypp::str::strtonum( attrValue ) ); + + + // optional enabled + if ( getAttrValue( "enabled", reader_r, attrValue ) ) + info.setEnabled( zypp::str::strToBool( attrValue, info.enabled() ) ); + + // optional autorefresh + if ( getAttrValue( "autorefresh", reader_r, attrValue ) ) + info.setAutorefresh( zypp::str::strToBool( attrValue, info.autorefresh() ) ); + + DBG << info << endl; + + // ignore the rest + _callback(info); + return true; + } + } + + return true; + } + + + /////////////////////////////////////////////////////////////////// + // + // CLASS NAME : RepoindexFileReader + // + /////////////////////////////////////////////////////////////////// + + RepoIndexFileReader::RepoIndexFileReader( ContextBaseRef ctx, zypp::Pathname repoindex_file, ProcessResource callback ) + : _zyppCtx( std::move(ctx) ) + , _callback( std::move(callback) ) + , _replacer( std::make_unique() ) + { run( zypp::InputStream(std::move(repoindex_file)) ); } + + RepoIndexFileReader::RepoIndexFileReader( ContextBaseRef ctx, const zypp::InputStream &is, ProcessResource callback ) + : _zyppCtx( std::move(ctx) ) + , _callback( std::move(callback) ) + , _replacer( std::make_unique() ) + { run( is ); } + + RepoIndexFileReader::~RepoIndexFileReader() + {} + + zypp::Date::Duration RepoIndexFileReader::ttl() const { return _ttl; } + + void RepoIndexFileReader::run( const zypp::InputStream &is ) + { + zypp::xml::Reader reader( is ); + MIL << "Reading " << is.path() << endl; + reader.foreachNode( [this]( auto &reader ) { return consumeNode (reader); } ); + } + + } // ns parser +} // ns zypp + +// vim: set ts=2 sts=2 sw=2 et ai: diff --git a/zypp/parser/RepoindexFileReader.h b/zypp/ng/parser/repoindexfilereader.h similarity index 53% rename from zypp/parser/RepoindexFileReader.h rename to zypp/ng/parser/repoindexfilereader.h index 9171d2d530..19a979bb98 100644 --- a/zypp/parser/RepoindexFileReader.h +++ b/zypp/ng/parser/repoindexfilereader.h @@ -9,22 +9,28 @@ /** \file zypp/parser/RepoindexFileReader.h * Interface of repoindex.xml file reader. */ -#ifndef zypp_source_yum_RepoindexFileReader_H -#define zypp_source_yum_RepoindexFileReader_H +#ifndef ZYPP_NG_PARSER_REPOINDEXFILEREADER_H_INCLUDED +#define ZYPP_NG_PARSER_REPOINDEXFILEREADER_H_INCLUDED #include -#include #include #include #include #include -namespace zypp +#include + +namespace zypp::xml { + class Reader; +} + +namespace zyppng { class RepoInfo; namespace parser { + class RepoIndexVarReplacer; /** * Reads through a repoindex.xml file and collects repositories. @@ -41,7 +47,7 @@ namespace zypp * bind( &SomeClass::callbackfunc, &SomeClassInstance, _1) ); * \endcode */ - class ZYPP_API RepoindexFileReader : private base::NonCopyable + class RepoIndexFileReader { public: /** @@ -49,17 +55,17 @@ namespace zypp * First parameter is a \ref RepoInfo object with the resource * FIXME return value is ignored */ - using ProcessResource = function; - - /** - * CTOR. Creates also \ref xml::Reader and starts reading. - * - * \param repoindexFile is the repoindex.xml file you want to read - * \param callback is a function. - * - * \see RepoindexFileReader::ProcessResource - */ - RepoindexFileReader(Pathname repoindexFile, + using ProcessResource = std::function; + /** + * CTOR. Creates also \ref xml::Reader and starts reading. + * + * \param repoindexFile is the repoindex.xml file you want to read + * \param callback is a function. + * + * \see RepoIndexFileReader::ProcessResource + */ + RepoIndexFileReader( ContextBaseRef ctx, + zypp::Pathname repoindexFile, ProcessResource callback); /** @@ -68,28 +74,41 @@ namespace zypp * \param is a valid input stream * \param callback Callback that will be called for each repository. * - * \see RepoindexFileReader::ProcessResource + * \see RepoIndexFileReader::ProcessResource */ - RepoindexFileReader( const InputStream &is, + RepoIndexFileReader( ContextBaseRef ctx, + const zypp::InputStream &is, ProcessResource callback ); /** * DTOR */ - ~RepoindexFileReader(); + ~RepoIndexFileReader(); + + RepoIndexFileReader(const RepoIndexFileReader &) = delete; + RepoIndexFileReader(RepoIndexFileReader &&) = delete; + RepoIndexFileReader &operator=(const RepoIndexFileReader &) = delete; + RepoIndexFileReader &operator=(RepoIndexFileReader &&) = delete; + /** Metadata TTL (repoindex.xml:xpath:/repoindex@ttl or 0). */ - Date::Duration ttl() const; + zypp::Date::Duration ttl() const; private: - class Impl; - RW_pointer > _pimpl; + void run( const zypp::InputStream &is ); + bool consumeNode( zypp::xml::Reader & reader_r ); + bool getAttrValue( const std::string & key_r, zypp::xml::Reader & reader_r, std::string & value_r ); + + private: + ContextBaseRef _zyppCtx; + /** Function for processing collected data. Passed-in through constructor. */ + ProcessResource _callback; + std::unique_ptr _replacer; + zypp::DefaultIntegral _ttl; }; } // ns parser } // ns zypp -#endif /*zypp_source_yum_RepoindexFileReader_H*/ - -// vim: set ts=2 sts=2 sw=2 et ai: +#endif /*ZYPP_NG_PARSER_REPOINDEXFILEREADER_H_INCLUDED*/ diff --git a/zypp/parser/ServiceFileReader.cc b/zypp/ng/parser/servicefilereader.cc similarity index 72% rename from zypp/parser/ServiceFileReader.cc rename to zypp/ng/parser/servicefilereader.cc index b71740cffd..c49f36df19 100644 --- a/zypp/parser/ServiceFileReader.cc +++ b/zypp/ng/parser/servicefilereader.cc @@ -9,6 +9,8 @@ /** \file zypp/parser/RepoFileReader.cc * */ + +#include "servicefilereader.h" #include #include #include @@ -17,14 +19,13 @@ #include #include -#include -#include +#include using std::endl; using zypp::parser::IniDict; /////////////////////////////////////////////////////////////////// -namespace zypp +namespace zyppng { ///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// namespace parser @@ -33,28 +34,28 @@ namespace zypp class ServiceFileReader::Impl { public: - static void parseServices( const Pathname & file, + static void parseServices( zyppng::ContextBaseRef ctx, const zypp::Pathname & file, const ServiceFileReader::ProcessService & callback ); }; - void ServiceFileReader::Impl::parseServices( const Pathname & file, + void ServiceFileReader::Impl::parseServices( zyppng::ContextBaseRef ctx, const zypp::Pathname & file, const ServiceFileReader::ProcessService & callback/*, const ProgressData::ReceiverFnc &progress*/ ) try { - InputStream is(file); + zypp::InputStream is(file); if( is.stream().fail() ) { - ZYPP_THROW(Exception("Failed to open service file")); + ZYPP_THROW(zypp::Exception("Failed to open service file")); } - parser::IniDict dict(is); - for ( parser::IniDict::section_const_iterator its = dict.sectionsBegin(); + zypp::parser::IniDict dict(is); + for ( zypp::parser::IniDict::section_const_iterator its = dict.sectionsBegin(); its != dict.sectionsEnd(); ++its ) { MIL << (*its) << endl; - ServiceInfo service(*its); + zyppng::ServiceInfo service(ctx, *its); std::map> repoStates; // > for ( IniDict::entry_const_iterator it = dict.entriesBegin(*its); @@ -65,21 +66,21 @@ namespace zypp if ( it->first == "name" ) service.setName( it->second ); else if ( it->first == "url" && ! it->second.empty() ) - service.setUrl( Url (it->second) ); + service.setUrl( zypp::Url (it->second) ); else if ( it->first == "enabled" ) - service.setEnabled( str::strToTrue( it->second ) ); + service.setEnabled( zypp::str::strToTrue( it->second ) ); else if ( it->first == "autorefresh" ) - service.setAutorefresh( str::strToTrue( it->second ) ); + service.setAutorefresh( zypp::str::strToTrue( it->second ) ); else if ( it->first == "type" ) - service.setType( repo::ServiceType(it->second) ); + service.setType( zypp::repo::ServiceType(it->second) ); else if ( it->first == "ttl_sec" ) - service.setTtl( str::strtonum(it->second) ); + service.setTtl( zypp::str::strtonum(it->second) ); else if ( it->first == "lrf_dat" ) - service.setLrf( Date( it->second ) ); + service.setLrf( zypp::Date( it->second ) ); else if ( it->first == "repostoenable" ) { std::vector aliases; - str::splitEscaped( it->second, std::back_inserter(aliases) ); + zypp::str::splitEscaped( it->second, std::back_inserter(aliases) ); for_( ait, aliases.begin(), aliases.end() ) { service.addRepoToEnable( *ait ); @@ -88,28 +89,28 @@ namespace zypp else if ( it->first == "repostodisable" ) { std::vector aliases; - str::splitEscaped( it->second, std::back_inserter(aliases) ); + zypp::str::splitEscaped( it->second, std::back_inserter(aliases) ); for_( ait, aliases.begin(), aliases.end() ) { service.addRepoToDisable( *ait ); } } - else if ( str::startsWith( it->first, "repo_" ) ) + else if ( zypp::str::startsWith( it->first, "repo_" ) ) { - static str::regex rxexpr( "([0-9]+)(_(.*))?" ); - str::smatch what; - if ( str::regex_match( it->first.c_str()+5/*repo_*/, what, rxexpr ) ) + static zypp::str::regex rxexpr( "([0-9]+)(_(.*))?" ); + zypp::str::smatch what; + if ( zypp::str::regex_match( it->first.c_str()+5/*repo_*/, what, rxexpr ) ) { std::string tag( what[1] ); if ( what.size() > 3 ) { // attribute if ( what[3] == "enabled" ) - repoStates[tag].second.enabled = str::strToBool( it->second, repoStates[tag].second.enabled ); + repoStates[tag].second.enabled = zypp::str::strToBool( it->second, repoStates[tag].second.enabled ); else if ( what[3] == "autorefresh" ) - repoStates[tag].second.autorefresh = str::strToBool( it->second, repoStates[tag].second.autorefresh ); + repoStates[tag].second.autorefresh = zypp::str::strToBool( it->second, repoStates[tag].second.autorefresh ); else if ( what[3] == "priority" ) - str::strtonum( it->second, repoStates[tag].second.priority ); + zypp::str::strtonum( it->second, repoStates[tag].second.priority ); else ERR << "Unknown attribute " << it->first << " ignored" << endl; } @@ -145,10 +146,10 @@ namespace zypp // add it to the list. if ( !callback(service) ) - ZYPP_THROW(AbortRequestException()); + ZYPP_THROW(zypp::AbortRequestException()); } } - catch ( Exception & ex ) { + catch ( zypp::Exception & ex ) { ex.addHistory( "Parsing .service file "+file.asString() ); ZYPP_RETHROW( ex ); } @@ -159,11 +160,13 @@ namespace zypp // /////////////////////////////////////////////////////////////////// - ServiceFileReader::ServiceFileReader( const Pathname & repo_file, + ServiceFileReader::ServiceFileReader( + zyppng::ContextBaseRef ctx, + const zypp::Pathname & repo_file, const ProcessService & callback/*, const ProgressData::ReceiverFnc &progress */) { - Impl::parseServices(repo_file, callback/*, progress*/); + Impl::parseServices(ctx, repo_file, callback/*, progress*/); //MIL << "Done" << endl; } diff --git a/zypp/parser/ServiceFileReader.h b/zypp/ng/parser/servicefilereader.h similarity index 90% rename from zypp/parser/ServiceFileReader.h rename to zypp/ng/parser/servicefilereader.h index 16d467a9d4..d76bce4647 100644 --- a/zypp/parser/ServiceFileReader.h +++ b/zypp/ng/parser/servicefilereader.h @@ -18,8 +18,10 @@ #include #include +#include + /////////////////////////////////////////////////////////////////// -namespace zypp +namespace zyppng { ///////////////////////////////////////////////////////////////// class ServiceInfo; @@ -52,7 +54,7 @@ namespace zypp * Return false from the callback to get a \ref AbortRequestException * to be thrown and the processing to be cancelled. */ - using ProcessService = function; + using ProcessService = std::function; /** Implementation */ class Impl; @@ -68,8 +70,9 @@ namespace zypp * \throws Exception If a error occurs at reading / parsing * */ - ServiceFileReader( const Pathname & serviceFile, - const ProcessService & callback); + ServiceFileReader( zyppng::ContextBaseRef ctx, + const zypp::Pathname & serviceFile, + const ProcessService & callback); /** * Dtor diff --git a/zypp/ng/private/repomanager_p.h b/zypp/ng/private/repomanager_p.h deleted file mode 100644 index 9abba79c24..0000000000 --- a/zypp/ng/private/repomanager_p.h +++ /dev/null @@ -1,37 +0,0 @@ -/*---------------------------------------------------------------------\ -| ____ _ __ __ ___ | -| |__ / \ / / . \ . \ | -| / / \ V /| _/ _/ | -| / /__ | | | | | | | -| /_____||_| |_| |_| | -| | -\---------------------------------------------------------------------*/ -#ifndef ZYPP_NG_PRIVATE_REPOMANAGER_P_H -#define ZYPP_NG_PRIVATE_REPOMANAGER_P_H - -#include -#include -#include - -namespace zyppng { - - class ZYPP_LOCAL RepoManagerPrivate : public BasePrivate, public zypp::RepoManagerBaseImpl - { - ZYPP_DECLARE_PUBLIC(RepoManager) - public: - - RepoManagerPrivate( ContextRef ctx, RepoManagerOptions repoOpts, RepoManager &p ); - - AsyncOpRef> probe( const zypp::Url & url, const zypp::Pathname & path = zypp::Pathname() ) const; - - ContextWeakRef _context; //< weak ref to our context to prevent a ref loop, this should always be valid - - // RepoManagerBaseImpl interface - public: - void removeRepository(const zypp::RepoInfo &info, const zypp::ProgressData::ReceiverFnc &) override; - }; - -} - - -#endif diff --git a/zypp/ng/repo/downloader.cc b/zypp/ng/repo/downloader.cc index 35b8e0ab2e..41ce3478a3 100644 --- a/zypp/ng/repo/downloader.cc +++ b/zypp/ng/repo/downloader.cc @@ -8,7 +8,8 @@ \---------------------------------------------------------------------*/ #include "downloader.h" -#include +#include + #include #include #include @@ -16,7 +17,6 @@ #include #include -#include #include #include @@ -28,19 +28,19 @@ namespace zyppng::repo { using namespace zyppng::operators; template - DownloadContext::DownloadContext(ContextRefType zyppContext, const zypp::RepoInfo &info, const zypp::Pathname &destDir ) + DownloadContext::DownloadContext(ContextRefType zyppContext, const RepoInfo &info, const zypp::Pathname &destDir ) : CacheProviderContext( typename CacheProviderContext::private_constr_t{}, std::move(zyppContext), destDir ) , _repoinfo(info) {} template - const zypp::RepoInfo &DownloadContext::repoInfo() const { return _repoinfo; } + const RepoInfo &DownloadContext::repoInfo() const { return _repoinfo; } template const zypp::filesystem::Pathname &DownloadContext::deltaDir() const { return _deltaDir; } template - zypp::RepoInfo &DownloadContext::repoInfo() { return _repoinfo; } + RepoInfo &DownloadContext::repoInfo() { return _repoinfo; } template std::vector &DownloadContext::files() { return _files; } @@ -55,5 +55,5 @@ namespace zyppng::repo { // explicitely intantiate the template types we want to work with template class DownloadContext; - template class DownloadContext; + template class DownloadContext; } diff --git a/zypp/ng/repo/downloader.h b/zypp/ng/repo/downloader.h index 95d45909ae..5c5f9c0987 100644 --- a/zypp/ng/repo/downloader.h +++ b/zypp/ng/repo/downloader.h @@ -19,17 +19,13 @@ #include #include #include -#include +#include #include +#include #include -namespace zyppng { - ZYPP_FWD_DECL_TYPE_WITH_REFS( Context ); - ZYPP_FWD_DECL_TYPE_WITH_REFS( SyncContext ); -} - namespace zyppng::repo { template class DownloadContext : public CacheProviderContext @@ -41,12 +37,12 @@ namespace zyppng::repo { using ProvideType = typename ContextType::ProvideType; using MediaHandle = typename ProvideType::MediaHandle; - DownloadContext( ContextRefType zyppContext, const zypp::RepoInfo &info, const zypp::Pathname &destDir ); + DownloadContext( ContextRefType zyppContext, const RepoInfo &info, const zypp::Pathname &destDir ); - const zypp::RepoInfo &repoInfo () const; + const RepoInfo &repoInfo () const; const zypp::Pathname &deltaDir () const; - zypp::RepoInfo &repoInfo(); + RepoInfo &repoInfo(); std::vector &files(); const std::optional &pluginRepoverification() const; @@ -60,14 +56,14 @@ namespace zyppng::repo { void setDeltaDir(const zypp::Pathname &newDeltaDir); private: - zypp::RepoInfo _repoinfo; + RepoInfo _repoinfo; zypp::Pathname _deltaDir; std::vector _files; ///< Files downloaded std::optional _pluginRepoverification; ///< \see \ref plugin-repoverification }; using SyncDownloadContext = DownloadContext; - using AsyncDownloadContext = DownloadContext; + using AsyncDownloadContext = DownloadContext; ZYPP_FWD_DECL_REFS(SyncDownloadContext); ZYPP_FWD_DECL_REFS(AsyncDownloadContext); } diff --git a/zypp/repo/PluginServices.cc b/zypp/ng/repo/pluginservices.cc similarity index 68% rename from zypp/repo/PluginServices.cc rename to zypp/ng/repo/pluginservices.cc index 696c98d4fd..565b83b678 100644 --- a/zypp/repo/PluginServices.cc +++ b/zypp/ng/repo/pluginservices.cc @@ -6,6 +6,9 @@ | /_____||_| |_| |_| | | | \---------------------------------------------------------------------*/ + +#include "pluginservices.h" + #include #include #include @@ -14,16 +17,15 @@ #include #include -#include -#include -#include +#include +#include #include using std::endl; using std::stringstream; /////////////////////////////////////////////////////////////////// -namespace zypp +namespace zyppng { ///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// namespace repo @@ -32,33 +34,34 @@ namespace zypp class PluginServices::Impl { public: - static void loadServices( const Pathname &path, - const PluginServices::ProcessService &callback ); + static void loadServices(ContextBaseRef ctx, const zypp::Pathname &path, + const PluginServices::ProcessService &callback ); }; - void PluginServices::Impl::loadServices( const Pathname &path, + void PluginServices::Impl::loadServices( ContextBaseRef ctx, + const zypp::Pathname &path, const PluginServices::ProcessService & callback/*, const ProgressData::ReceiverFnc &progress*/ ) { - std::list entries; - if (PathInfo(path).isExist()) + std::list entries; + if (zypp::PathInfo(path).isExist()) { - if ( filesystem::readdir( entries, path, false ) != 0 ) + if ( zypp::filesystem::readdir( entries, path, false ) != 0 ) { // TranslatorExplanation '%s' is a pathname - ZYPP_THROW(Exception(str::form(_("Failed to read directory '%s'"), path.c_str()))); + ZYPP_THROW(zypp::Exception(zypp::str::form(_("Failed to read directory '%s'"), path.c_str()))); } //str::regex allowedServiceExt("^\\.service(_[0-9]+)?$"); for_(it, entries.begin(), entries.end() ) { - ServiceInfo service_info; + ServiceInfo service_info(ctx); service_info.setAlias((*it).basename()); - Url url; + zypp::Url url; url.setPathName((*it).asString()); url.setScheme("file"); service_info.setUrl(url); - service_info.setType(ServiceType::PLUGIN); + service_info.setType(zypp::repo::ServiceType::PLUGIN); service_info.setAutorefresh( true ); DBG << "Plugin Service: " << service_info << endl; callback(service_info); @@ -67,11 +70,11 @@ namespace zypp } } - PluginServices::PluginServices( const Pathname &path, - const ProcessService & callback/*, - const ProgressData::ReceiverFnc &progress */) + PluginServices::PluginServices(ContextBaseRef ctx, const zypp::Pathname &path, + const ProcessService & callback/*, + const ProgressData::ReceiverFnc &progress */) { - Impl::loadServices(path, callback/*, progress*/); + Impl::loadServices(ctx, path, callback/*, progress*/); } PluginServices::~PluginServices() diff --git a/zypp/repo/PluginServices.h b/zypp/ng/repo/pluginservices.h similarity index 91% rename from zypp/repo/PluginServices.h rename to zypp/ng/repo/pluginservices.h index 910ce897a6..8635300053 100644 --- a/zypp/repo/PluginServices.h +++ b/zypp/ng/repo/pluginservices.h @@ -13,11 +13,11 @@ #include #include -#include #include +#include /////////////////////////////////////////////////////////////////// -namespace zypp +namespace zyppng { ///////////////////////////////////////////////////////////////// class ServiceInfo; @@ -37,13 +37,14 @@ namespace zypp * Return false from the callback to get a \ref AbortRequestException * to be thrown and the processing to be cancelled. */ - using ProcessService = function; + using ProcessService = std::function; /** Implementation */ class Impl; public: - PluginServices(const Pathname &path, + PluginServices( ContextBaseRef ctx, + const zypp::Pathname &path, const ProcessService & callback); /** diff --git a/zypp/ng/repo/refresh.cc b/zypp/ng/repo/refresh.cc deleted file mode 100644 index 2555bc7729..0000000000 --- a/zypp/ng/repo/refresh.cc +++ /dev/null @@ -1,154 +0,0 @@ -/*---------------------------------------------------------------------\ -| ____ _ __ __ ___ | -| |__ / \ / / . \ . \ | -| / / \ V /| _/ _/ | -| / /__ | | | | | | | -| /_____||_| |_| |_| | -| | -\---------------------------------------------------------------------*/ -#include "refresh.h" -#include -#include -#include -#include -#include - -namespace zyppng::repo { - - template - RefreshContext::RefreshContext( private_constr_t, ZyppContextRefType &&zyppContext, zypp::RepoInfo &&info, zypp::Pathname &&rawCachePath, zypp::filesystem::TmpDir &&tempDir, RepoManagerRef &&repoManager ) - : _zyppContext( std::move(zyppContext) ) - , _repoManager( std::move(repoManager) ) - , _repoInfo( std::move(info) ) - , _rawCachePath( std::move(rawCachePath) ) - , _tmpDir( std::move(tempDir) ) - {} - - template - expected> RefreshContext::create( ZyppContextRefType zyppContext, zypp::RepoInfo info, RepoManagerRef repoManager ) - { - using namespace operators; - using CtxType = RefreshContext; - using CtxRefType = RefreshContextRef; - - return rawcache_path_for_repoinfo ( repoManager->options(), info ) - | and_then( [&]( zypp::Pathname rawCachePath ) { - - zypp::filesystem::TmpDir tmpdir( zypp::filesystem::TmpDir::makeSibling( rawCachePath, 0755 ) ); - if( tmpdir.path().empty() && geteuid() != 0 ) { - tmpdir = zypp::filesystem::TmpDir(); // non-root user may not be able to write the cache - } - if( tmpdir.path().empty() ) { - return expected::error( ZYPP_EXCPT_PTR(zypp::Exception(_("Can't create metadata cache directory."))) ); - } - - MIL << "Creating RefreshContext " << std::endl; - - return expected::success( std::make_shared( private_constr_t{} - , std::move(zyppContext) - , std::move(info) - , std::move(rawCachePath) - , std::move(tmpdir) - , std::move(repoManager))); - } ); - } - - template - RefreshContext::~RefreshContext() - { - MIL << "Deleting RefreshContext" << std::endl; - } - - template - void RefreshContext::saveToRawCache() - { - zypp::filesystem::exchange( _tmpDir.path(), _rawCachePath ); - } - - template - const zypp::Pathname &RefreshContext::rawCachePath() const - { - return _rawCachePath; - } - - template - zypp::Pathname RefreshContext::targetDir() const - { - return _tmpDir.path(); - } - - template - const ZyppContextRefType &RefreshContext::zyppContext() const - { - return _zyppContext; - } - - template - const zypp::RepoInfo &RefreshContext::repoInfo() const - { - return _repoInfo; - } - - template - zypp::RepoInfo &RefreshContext::repoInfo() - { - return _repoInfo; - } - - template - const RepoManagerRef &RefreshContext::repoManager() const - { - return _repoManager; - } - - template - const zypp::RepoManagerOptions &RefreshContext::repoManagerOptions() const - { - return _repoManager->options(); - } - - template - repo::RawMetadataRefreshPolicy RefreshContext::policy() const - { - return _policy; - } - - template - void RefreshContext::setPolicy(RawMetadataRefreshPolicy newPolicy) - { - _policy = newPolicy; - } - - template - const std::optional::PluginRepoverification> &RefreshContext::pluginRepoverification() const - { - return _pluginRepoverification; - } - - template - void RefreshContext::setProbedType(zypp::repo::RepoType rType) - { - if ( _probedType && *_probedType == rType ) - return; - - _probedType = rType; - _sigProbedTypeChanged.emit(rType); - } - - template - const std::optional &RefreshContext::probedType() const - { - return _probedType; - } - - template - SignalProxy RefreshContext::sigProbedTypeChanged() - { - return _sigProbedTypeChanged; - } - - // explicitely intantiate the template types we want to work with - template class RefreshContext; - template class RefreshContext; - -} diff --git a/zypp/ng/repo/refresh.h b/zypp/ng/repo/refresh.h index 650dd3c457..cd7319128e 100644 --- a/zypp/ng/repo/refresh.h +++ b/zypp/ng/repo/refresh.h @@ -9,26 +9,28 @@ #ifndef ZYPP_NG_REPO_REFRESH_INCLUDED #define ZYPP_NG_REPO_REFRESH_INCLUDED +#include #include #include #include #include -#include #include #include -#include #include + #include +#include +#include +#include namespace zyppng { - ZYPP_FWD_DECL_TYPE_WITH_REFS( Context ); - ZYPP_FWD_DECL_TYPE_WITH_REFS( SyncContext ); + ZYPP_FWD_DECL_TEMPL_TYPE_WITH_REFS_ARG1 (RepoManager, ZyppContextType); } namespace zyppng::repo { - ZYPP_FWD_DECL_TEMPL_TYPE_WITH_REFS_ARG1 (RefreshContext, ZyppContextRefType); + ZYPP_FWD_DECL_TEMPL_TYPE_WITH_REFS_ARG1 (RefreshContext, ZyppContextType); using RawMetadataRefreshPolicy = zypp::RepoManagerFlags::RawMetadataRefreshPolicy; using RefreshCheckStatus = zypp::RepoManagerFlags::RefreshCheckStatus; @@ -39,71 +41,168 @@ namespace zyppng::repo { * on a local cache and a remote repository, as defined by the \ref zypp::RepoInfo * */ - template - class RefreshContext : public Base, public MaybeAsyncMixin< std::is_same_v > { + template + class RefreshContext : public Base, public MaybeAsyncMixin< std::is_same_v > { ZYPP_ADD_PRIVATE_CONSTR_HELPER(); - ZYPP_ENABLE_MAYBE_ASYNC_MIXIN( (std::is_same_v) ); + ZYPP_ENABLE_MAYBE_ASYNC_MIXIN( (std::is_same_v) ); public: - using ContextRefType = ZyppContextRefType; - using ContextType = typename ZyppContextRefType::element_type; + using ContextRefType = Ref; + using ContextType = ZyppContextType; using ProvideType = typename ContextType::ProvideType; using MediaHandle = typename ProvideType::MediaHandle; using PluginRepoverification = zypp_private::repo::PluginRepoverification; + using RepoLockRef = zypp::Deferred; + + static expected> create( RepoManagerRef repoManager, RepoInfo info ) + { + using namespace operators; + using CtxType = RefreshContext; + using CtxRefType = RefreshContextRef; + + return rawcache_path_for_repoinfo ( repoManager->options(), info ) + | and_then( [&]( zypp::Pathname rawCachePath ) { + + zypp::filesystem::TmpDir tmpdir( zypp::filesystem::TmpDir::makeSibling( rawCachePath, 0755 ) ); + if( tmpdir.path().empty() && geteuid() != 0 ) { + tmpdir = zypp::filesystem::TmpDir(); // non-root user may not be able to write the cache + } + if( tmpdir.path().empty() ) { + return expected::error( ZYPP_EXCPT_PTR(zypp::Exception(_("Can't create metadata cache directory."))) ); + } + + MIL << "Creating RefreshContext " << std::endl; + + return expected::success( std::make_shared( private_constr_t{} + , std::move(repoManager) + , std::move(info) + , std::move(rawCachePath) + , std::move(tmpdir))); + } ); + } + + ZYPP_DECL_PRIVATE_CONSTR_ARGS(RefreshContext, RepoManagerRef &&repoManager, RepoInfo &&info, zypp::Pathname &&rawCachePath, zypp::filesystem::TmpDir &&tempDir ) + : _repoManager( std::move(repoManager) ) + , _repoInfo( std::move(info) ) + , _rawCachePath( std::move(rawCachePath) ) + , _tmpDir( std::move(tempDir) ) + {} + + ~RefreshContext() override + { + MIL << "Deleting RefreshContext" << std::endl; + } + + /** + * Engages the lock for the resource of the Repo to be refreshed. + * Can be called multiple times. Returns a RAII object that + * resets the lock once its destroyed. + */ + MaybeAsyncRef> engageLock() { + using namespace zyppng::operators; + const auto lockSuccess = [this]() -> expected{ + _resLockRef++; + return expected::success( [this](){ releaseLock(); } ); + }; + + if ( _resLock ) { + return makeReadyResult( lockSuccess() ); + } + + return this->_repoManager->zyppContext()->lockResourceWait( resources::repo::REPO_RESOURCE( _repoInfo) , 1000, ResourceLockRef::Exclusive ) + | and_then( [this]( ResourceLockRef lock ) { + _resLock = std::move(lock); + return expected::success(); + }) + | and_then( lockSuccess ); - static expected> create( ZyppContextRefType zyppContext, zypp::RepoInfo info, RepoManagerRef repoManager ); - ZYPP_DECL_PRIVATE_CONSTR_ARGS(RefreshContext, ZyppContextRefType &&zyppContext, zypp::RepoInfo &&info, zypp::Pathname &&rawCachePath, zypp::filesystem::TmpDir &&tempDir, RepoManagerRef &&repoManager ); + } - ~RefreshContext() override; /*! * Commits the internal temporary cache into the raw cache * of the \ref zypp::RepoInfo this context is currently operating * on. */ - void saveToRawCache(); + void saveToRawCache() + { + zypp::filesystem::exchange( _tmpDir.path(), _rawCachePath ); + } /*! * The raw cache path belonging to this context's \ref zypp::RepoInfo */ - const zypp::Pathname &rawCachePath() const; + const zypp::Pathname &rawCachePath() const + { + return _rawCachePath; + } /*! * The current temporary target dir where the refresh workflow is * storing the metadata during operation. Once we have a finished * set of metadata and cache we exchange it with the rawCache */ - zypp::Pathname targetDir() const; + zypp::Pathname targetDir() const + { + return _tmpDir.path(); + } /*! * Current zypp context we are working on, either \ref zyppng::Context * or \ref zyppng::SyncContext. */ - const ZyppContextRefType &zyppContext () const; + Ref zyppContext() const + { + return _repoManager->zyppContext(); + } /*! * Current \ref zypp::RepoInfo this refresh context is operating with, * the workflow is free to change data in this \ref zypp::RepoInfo , so calling * code should take care to use it once the workflow has finished. */ - const zypp::RepoInfo &repoInfo () const; - zypp::RepoInfo &repoInfo (); + const RepoInfo &repoInfo () const + { + return _repoInfo; + } + + RepoInfo &repoInfo () + { + return _repoInfo; + } /*! * Reference to the \ref zyppng::RepoManager that initiated the refresh */ - const RepoManagerRef &repoManager() const; - const zypp::RepoManagerOptions &repoManagerOptions() const; + const RepoManagerRef &repoManager() const + { + return _repoManager; + } + + const zypp::RepoManagerOptions &repoManagerOptions() const + { + return _repoManager->options(); + } /*! * The refresh policy, defines wether a refresh is forced, or only done if needed. */ - RawMetadataRefreshPolicy policy() const; - void setPolicy(RawMetadataRefreshPolicy newPolicy); + RawMetadataRefreshPolicy policy() const + { + return _policy; + } + + void setPolicy(RawMetadataRefreshPolicy newPolicy) + { + _policy = newPolicy; + } /*! * Optional repo verification via a plugin */ - const std::optional &pluginRepoverification() const; + const std::optional &pluginRepoverification() const + { + return _pluginRepoverification; + } void setPluginRepoverification( std::optional pluginRepoverification_r ) { _pluginRepoverification = std::move(pluginRepoverification_r); } @@ -118,26 +217,57 @@ namespace zyppng::repo { * Updated the probed repo type in \ref zypp::RepoInfo, calling code should * take care to fetch the updated one at the end of the refresh workflow. */ - void setProbedType( zypp::repo::RepoType rType ); - const std::optional &probedType() const; - SignalProxy sigProbedTypeChanged(); + void setProbedType( zypp::repo::RepoType rType ) + { + if ( _probedType && *_probedType == rType ) + return; + + _probedType = rType; + _sigProbedTypeChanged.emit(rType); + } + + const std::optional &probedType() const + { + return _probedType; + } + + SignalProxy sigProbedTypeChanged() + { + return _sigProbedTypeChanged; + } private: - ZyppContextRefType _zyppContext; - RepoManagerRef _repoManager; - zypp::RepoInfo _repoInfo; + + /** + * release the lock. Destroying the refresh context also + * immediately releases the lock. + */ + void releaseLock() { + if ( _resLockRef ) { + _resLockRef--; + if ( _resLockRef == 0 ) + _resLock.reset(); + } + } + + + RepoManagerRef _repoManager; + RepoInfo _repoInfo; zypp::Pathname _rawCachePath; zypp::filesystem::TmpDir _tmpDir; repo::RawMetadataRefreshPolicy _policy = RawMetadataRefreshPolicy::RefreshIfNeeded; std::optional _pluginRepoverification; ///< \see \ref plugin-repoverification + std::optional _resLock; + uint _resLockRef = 0; + std::optional _probedType; Signal _sigProbedTypeChanged; }; - using SyncRefreshContext = RefreshContext; - using AsyncRefreshContext = RefreshContext; + using SyncRefreshContext = RefreshContext; + using AsyncRefreshContext = RefreshContext; ZYPP_FWD_DECL_REFS(SyncRefreshContext); ZYPP_FWD_DECL_REFS(AsyncRefreshContext); diff --git a/zypp/ng/repo/repoinfobase.cc b/zypp/ng/repo/repoinfobase.cc new file mode 100644 index 0000000000..8753ccc83c --- /dev/null +++ b/zypp/ng/repo/repoinfobase.cc @@ -0,0 +1,180 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/repo/RepoInfoBase.cc + * + */ +#include +#include + +#include "repoinfobase.h" + +#include +#include + +#include +#include +#include + +#include + +using std::endl; + +namespace zyppng::repo { + + RepoInfoBaseSharedData::RepoInfoBaseSharedData( zyppng::ContextBaseRef &&context ) + : _ctx( std::move(context) ) + , _enabled( zypp::indeterminate ) + , _autorefresh( zypp::indeterminate ) + { + RepoInfoBaseSharedData::bindVariables(); + } + + RepoInfoBaseSharedData::RepoInfoBaseSharedData( zyppng::ContextBaseRef &&context, const std::string & alias_r ) + : _ctx( std::move(context) ) + , _enabled( zypp::indeterminate ) + , _autorefresh( zypp::indeterminate ) + { + RepoInfoBaseSharedData::bindVariables(); + setAlias( alias_r ); + } + + void RepoInfoBaseSharedData::bindVariables() + { + if ( _ctx ) { + _name.setTransformator( RepoVariablesStringReplacer( zypp::repo::RepoVarRetriever( *_ctx.get() ) ) ); + } else { + _name.setTransformator( RepoVariablesStringReplacer( nullptr ) ); + } + } + + + void RepoInfoBaseSharedData::setAlias( const std::string & alias_r ) + { + _alias = _escaped_alias = alias_r; + // replace slashes with underscores + zypp::str::replaceAll( _escaped_alias, "/", "_" ); + } + + void RepoInfoBaseSharedData::switchContext(ContextBaseRef ctx) + { + if ( ctx != _ctx ) { + _ctx = std::move(ctx); + bindVariables(); + } + } + + RepoInfoBaseSharedData * RepoInfoBaseSharedData::clone() const + { + auto *n = new RepoInfoBaseSharedData( *this ); + n->bindVariables (); + return n; + } + + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + // + // CLASS NAME : RepoInfoBase + // + /////////////////////////////////////////////////////////////////// + + RepoInfoBase::RepoInfoBase( RepoInfoBaseSharedData &pimpl ) : _pimpl( &pimpl ) + {} + + zyppng::ContextBaseRef RepoInfoBase::context() const + { return _pimpl->_ctx; } + + RepoInfoBase::~RepoInfoBase() + {} + + void RepoInfoBase::setEnabled( bool enabled ) + { _pimpl->_enabled = enabled; } + + void RepoInfoBase::setAutorefresh( bool autorefresh ) + { _pimpl->_autorefresh = autorefresh; } + + void RepoInfoBase::setAlias( const std::string &alias ) + { _pimpl->setAlias(alias); } + + void RepoInfoBase::setName( const std::string &name ) + { _pimpl->_name.raw() = name; } + + void RepoInfoBase::setFilepath( const zypp::Pathname &filepath ) + { _pimpl->_filepath = filepath; } + + // true by default (if not set by setEnabled()) + bool RepoInfoBase::enabled() const + { return indeterminate(_pimpl->_enabled) ? true : (bool) _pimpl->_enabled; } + + // false by default (if not set by setAutorefresh()) + bool RepoInfoBase::autorefresh() const + { return indeterminate(_pimpl->_autorefresh) ? false : (bool) _pimpl->_autorefresh; } + + const std::string &RepoInfoBase::alias() const + { return _pimpl->_alias; } + + const std::string &RepoInfoBase::escaped_alias() const + { return _pimpl->_escaped_alias; } + + std::string RepoInfoBase::name() const + { + if ( rawName().empty() ) + return alias(); + return repo::RepoVariablesStringReplacer()( rawName() ); + } + + const std::string &RepoInfoBase::rawName() const + { return _pimpl->_name.raw(); } + + std::string RepoInfoBase::label() const + { + if ( _pimpl->_ctx && _pimpl->_ctx->config().repoLabelIsAlias() ) + return alias(); + return name(); + } + + const zypp::Pathname &RepoInfoBase::filepath() const + { return _pimpl->_filepath; } + + + std::ostream & RepoInfoBase::dumpOn( std::ostream & str ) const + { + str << "--------------------------------------" << std::endl; + str << "- alias : " << alias() << std::endl; + if ( ! rawName().empty() ) + str << "- name : " << rawName() << std::endl; + str << "- enabled : " << enabled() << std::endl; + str << "- autorefresh : " << autorefresh() << std::endl; + + return str; + } + + std::ostream & RepoInfoBase::dumpAsIniOn( std::ostream & str ) const + { + // we save the original data without variable replacement + str << "[" << alias() << "]" << endl; + if ( ! rawName().empty() ) + str << "name=" << rawName() << endl; + str << "enabled=" << (enabled() ? "1" : "0") << endl; + str << "autorefresh=" << (autorefresh() ? "1" : "0") << endl; + + return str; + } + + std::ostream & RepoInfoBase::dumpAsXmlOn( std::ostream & str, const std::string & content ) const + { + return str << "" << endl; + } + + std::ostream & operator<<( std::ostream & str, const RepoInfoBase & obj ) + { + return obj.dumpOn(str); + } + +} //namespace zyppng::repo diff --git a/zypp/ng/repo/repoinfobase.h b/zypp/ng/repo/repoinfobase.h new file mode 100644 index 0000000000..7a09e953e6 --- /dev/null +++ b/zypp/ng/repo/repoinfobase.h @@ -0,0 +1,192 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_NG_REPO_REPOINFOBASE_H_INCLUDED +#define ZYPP_NG_REPO_REPOINFOBASE_H_INCLUDED + +#include + +#include +#include +#include +#include +#include + + +namespace zyppng::repo +{ + + /** + * \short Base class implementing common features of \ref RepoInfo and + * \ref ServiceInfo. + * + * \note Name is subject to repo variable replacement + * (\see \ref RepoVariablesStringReplacer). + */ + class RepoInfoBase + { + friend std::ostream & operator<<( std::ostream & str, const RepoInfoBase & obj ); + + public: + + virtual ~RepoInfoBase(); + + protected: + RepoInfoBase(const RepoInfoBase &) = default; + RepoInfoBase(RepoInfoBase &&) noexcept = default; + RepoInfoBase &operator=(const RepoInfoBase &) = default; + RepoInfoBase &operator=(RepoInfoBase &&) noexcept = default; + + public: + + /** + * Returns the associated context of the RepoInfo + */ + zyppng::ContextBaseRef context() const; + + /** + * unique identifier for this source. If not specified + * It should be generated from the base url. + * + * Normally, in a .repo file the section name is used + * ( [somerepo] ) + */ + const std::string &alias() const; + + /** + * Same as alias(), just escaped in a way to be a valid file name. + */ + const std::string &escaped_alias() const; + + /** + * \short Repository name + * + * Short label or description of the repository. Defaults to \ref alias. + * Subject to repo variable replacement (\see \ref RepoVariablesStringReplacer). + * ie: "SUSE Linux 10.2 updates" + */ + std::string name() const; + + /** The raw metadata name (no default, no variables replaced). */ + const std::string &rawName() const; + + /** + * \short Label for use in messages for the user interface. + * + * Returns an alias or name, according to ZConfig::repoLabelIsAlias(). + */ + std::string label() const; + + /** User string: \ref label (alias or name) */ + std::string asUserString() const + { return label(); } + + /** + * If enabled is false, then this repository must be ignored as if does + * not exists, except when checking for duplicate alias. + */ + bool enabled() const; + + /** + * If true, the repostory must be refreshed before creating resolvables + * from it + */ + bool autorefresh() const; + + /** + * \short File where this repo was read from + * + * \note could be an empty pathname for repo + * infos created in memory. + */ + const zypp::Pathname &filepath() const; + + + public: + + /** + * set the repository alias \see alias + * \param alias + */ + void setAlias( const std::string &alias ); + + /** + * set the repository name \see name + * \param name + */ + void setName( const std::string &name ); + + /** + * enable or disable the repository \see enabled + * \param enabled + */ + void setEnabled( bool enabled ); + + /** + * enable or disable autorefresh \see autorefresh + * \param enabled + */ + void setAutorefresh( bool autorefresh ); + + /** + * \short set the path to the .repo file + * + * The path to the .repo file where this repository + * was defined, or empty if nowhere. + * + * \param path File path + */ + void setFilepath( const zypp::Pathname &filename ); + + /** + * Write a human-readable representation of this RepoInfoBase object + * into the \a str stream. Useful for logging. + */ + virtual std::ostream & dumpOn( std::ostream & str ) const; + + /** + * Write this RepoInfoBase object into \a str in a .repo (ini) file format. + * Raw values, no variable replacement. + */ + virtual std::ostream & dumpAsIniOn( std::ostream & str ) const; + + /** + * Write an XML representation of this object with content (if available). + * Repo variables replaced. + */ + virtual std::ostream & dumpAsXmlOn( std::ostream & str, const std::string & content = "" ) const; + + protected: + RepoInfoBase( RepoInfoBaseSharedData &pimpl ); + + // support rw_cow copying for derived types + RepoInfoBase( const zypp::RWCOW_pointer &other ); + + /** Pointer to implementation */ + zypp::RWCOW_pointer _pimpl; + }; + /////////////////////////////////////////////////////////////////// + + /** \relates RepoInfoBase */ + inline bool operator==( const RepoInfoBase & lhs, const RepoInfoBase & rhs ) + { return ( lhs.context() == rhs.context() && lhs.alias() == rhs.alias()); } + + /** \relates RepoInfoBase */ + inline bool operator!=( const RepoInfoBase & lhs, const RepoInfoBase & rhs ) + { return (lhs.context() != rhs.context() || lhs.alias() != rhs.alias()); } + + inline bool operator<( const RepoInfoBase & lhs, const RepoInfoBase & rhs ) + { return lhs.alias() < rhs.alias(); } + + /** \relates RepoInfoBase Stream output */ + std::ostream & operator<<( std::ostream & str, const RepoInfoBase & obj ); + + + } // namespace zyppng::repo + +#endif /*ZYPP_NG_REPO_REPOINFOBASE_H_INCLUDED*/ diff --git a/zypp/ng/repo/repoinfobaseshareddata.cc b/zypp/ng/repo/repoinfobaseshareddata.cc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/zypp/ng/repo/repoinfobaseshareddata.h b/zypp/ng/repo/repoinfobaseshareddata.h new file mode 100644 index 0000000000..d19e86bd79 --- /dev/null +++ b/zypp/ng/repo/repoinfobaseshareddata.h @@ -0,0 +1,63 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/repo/detail/RepoInfoBaseImpl.h + * +*/ + +#ifndef ZYPP_NG_REPOINFOBASESHAREDDATA_INCLUDED +#define ZYPP_NG_REPOINFOBASESHAREDDATA_INCLUDED + +#include +#include +#include +#include + +namespace zyppng::repo +{ + + /*! + * \brief Contains shared data for Service and RepoInfo types + */ + struct RepoInfoBaseSharedData + { + RepoInfoBaseSharedData(const RepoInfoBaseSharedData &) = default; + RepoInfoBaseSharedData(RepoInfoBaseSharedData &&) = delete; + RepoInfoBaseSharedData &operator=(const RepoInfoBaseSharedData &) = default; + RepoInfoBaseSharedData &operator=(RepoInfoBaseSharedData &&) = delete; + + RepoInfoBaseSharedData( zyppng::ContextBaseRef &&context ); + RepoInfoBaseSharedData( zyppng::ContextBaseRef &&context, const std::string & alias_r ); + + virtual ~RepoInfoBaseSharedData() = default; + + public: + zyppng::ContextBaseRef _ctx; + zypp::TriBool _enabled; + zypp::TriBool _autorefresh; + std::string _alias; + std::string _escaped_alias; + RepoVariablesReplacedString _name; + zypp::Pathname _filepath; + + public: + void setAlias( const std::string & alias_r ); + void switchContext( ContextBaseRef ctx ); + + protected: + virtual void bindVariables(); + + private: + friend RepoInfoBaseSharedData * zypp::rwcowClone( const RepoInfoBaseSharedData * rhs ); + + /** clone for RWCOW_pointer */ + virtual RepoInfoBaseSharedData *clone() const; + }; +} + +#endif //ZYPP_NG_REPOINFOBASESHAREDDATA_INCLUDED diff --git a/zypp/ng/repo/repovariables.cc b/zypp/ng/repo/repovariables.cc new file mode 100644 index 0000000000..3ee8e16df3 --- /dev/null +++ b/zypp/ng/repo/repovariables.cc @@ -0,0 +1,16 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "repovariables.h" + +#include + +namespace zyppng { + namespace repo { + } +} diff --git a/zypp/ng/repo/repovariables.h b/zypp/ng/repo/repovariables.h new file mode 100644 index 0000000000..6ef74f1d35 --- /dev/null +++ b/zypp/ng/repo/repovariables.h @@ -0,0 +1,53 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_NG_REPO_REPOVARIABLES_H_INCLUDED +#define ZYPP_NG_REPO_REPOVARIABLES_H_INCLUDED + +#include +#include +#include +#include + +namespace zyppng { + + namespace repo { + + /* + * Since we need the RepoVar replacer as part of the public zypp API + * ( because of RepoInfo returning it as part of a iterator type ) they are + * defined in zypp::repo and only pulled into the zyppng namespace via using declarations. + * Once we can drop legacy APIs, or find a better way, this can be changed. + */ + using RepoVarRetrieverFunctor = zypp::repo::RepoVarRetrieverFunctor; + + template + using RepoVarRetriever = zypp::repo::RepoVarRetriever; + + using RepoVariablesStringReplacer = zypp::repo::RepoVariablesStringReplacerNg; + using RepoVariablesUrlReplacer = zypp::repo::RepoVariablesUrlReplacerNg; + +} // namespace repo + +/** \relates RepoVariablesStringReplacer Helper managing repo variables replaced strings */ +using RepoVariablesReplacedString = zypp::base::ValueTransform; + +/** \relates RepoVariablesStringReplacer Helper managing repo variables replaced string lists */ +using RepoVariablesReplacedStringList = zypp::base::ContainerTransform, repo::RepoVariablesStringReplacer>; + +/** \relates RepoVariablesUrlReplacer Helper managing repo variables replaced urls */ +using RepoVariablesReplacedUrl = zypp::base::ValueTransform; + +/** \relates RepoVariablesUrlReplacer Helper managing repo variables replaced url lists */ +using RepoVariablesReplacedUrlList = zypp::base::ContainerTransform, repo::RepoVariablesUrlReplacer>; + + + +} + +#endif //ZYPP_NG_REPO_REPOVARIABLES_H_INCLUDED diff --git a/zypp/ng/repo/repovariablescache.cc b/zypp/ng/repo/repovariablescache.cc new file mode 100644 index 0000000000..707d8aa5d1 --- /dev/null +++ b/zypp/ng/repo/repovariablescache.cc @@ -0,0 +1,157 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#include "repovariablescache.h" + +#include + +#include +#include + +namespace zyppng::repo { + + namespace env + { + /** Use faked releasever (e.g. for 'zupper dup' to next distro version */ + inline std::string ZYPP_REPO_RELEASEVER() + { + const char * env = getenv("ZYPP_REPO_RELEASEVER"); + return( env ? env : "" ); + } + } + + RepoVarsMap::RepoVarsMap(ContextBase &myContext) : _myCtx(myContext) + { } + + const std::string *RepoVarsMap::lookup(const std::string &name_r) { + if (empty()) // at init / after reset + { + // load user definitions from vars.d + + // @TODO-NG check if _myCtx.contextRoot() is correct, before this used the config() repomanager root + zypp::filesystem::dirForEach( _myCtx.contextRoot() / + _myCtx.config().varsPath(), + zypp::filesystem::matchNoDots(), + std::bind(&RepoVarsMap::parse, this, std::placeholders::_1, std::placeholders::_2)); + // releasever_major/_minor are per default derived from releasever. + // If releasever is userdefined, inject missing _major/_minor too. + deriveFromReleasever("releasever", + /*dont't overwrite user defined values*/ false); + + dumpOn(DBG); + // add builtin vars except for releasever{,_major,_minor} (see + // checkOverride) + { + const zypp::Arch &arch( _myCtx.config().systemArchitecture() ); + { + std::string &var(operator[]("arch")); + if (var.empty()) + var = arch.asString(); + } + { + std::string &var(operator[]("basearch")); + if (var.empty()) + var = arch.baseArch().asString(); + } + } + } + + const std::string *ret = checkOverride(name_r); + if (!ret) { + // get value from map + iterator it = find(name_r); + if (it != end()) + ret = &(it->second); + } + + return ret; + } + std::ostream &RepoVarsMap::dumpOn(std::ostream &str) const { + for (auto &&kv : *this) { + str << '{' << kv.first << '=' << kv.second << '}' << std::endl; + } + return str; + } + bool RepoVarsMap::parse(const zypp::Pathname &dir_r, const std::string &str_r) { + std::ifstream file((dir_r / str_r).c_str()); + operator[](str_r) = zypp::str::getline(file, /*trim*/ false); + return true; + } + void RepoVarsMap::deriveFromReleasever(const std::string &stem_r, + bool overwrite_r) { + if (count(stem_r)) // releasever is defined.. + { + const std::string &stem_major(stem_r + "_major"); + const std::string &stem_minor(stem_r + "_minor"); + if (overwrite_r) + splitReleaseverTo(operator[](stem_r), &operator[](stem_major), + &operator[](stem_minor)); + else + splitReleaseverTo(operator[](stem_r), + count(stem_major) ? nullptr : &operator[](stem_major), + count(stem_minor) ? nullptr + : &operator[](stem_minor)); + } + } + void RepoVarsMap::splitReleaseverTo(const std::string &releasever_r, + std::string *major_r, + std::string *minor_r) const { + if (major_r || minor_r) { + std::string::size_type pos = releasever_r.find('.'); + if (pos == std::string::npos) { + if (major_r) + *major_r = releasever_r; + if (minor_r) + minor_r->clear(); + } else { + if (major_r) + *major_r = releasever_r.substr(0, pos); + if (minor_r) + *minor_r = releasever_r.substr(pos + 1); + } + } + } + const std::string *RepoVarsMap::checkOverride(const std::string &name_r) { + /////////////////////////////////////////////////////////////////// + // Always check for changing releasever{,_major,_minor} (bnc#943563) + if (zypp::str::startsWith(name_r, "releasever") && + (name_r.size() == 10 || strcmp(name_r.c_str() + 10, "_minor") == 0 || + strcmp(name_r.c_str() + 10, "_major") == 0)) { + std::string val(env::ZYPP_REPO_RELEASEVER()); + if (!val.empty()) { + // $ZYPP_REPO_RELEASEVER always overwrites any defined value + if (val != operator[]("$releasever")) { + operator[]("$releasever") = std::move(val); + deriveFromReleasever("$releasever", + /*overwrite previous values*/ true); + } + return &operator[]("$" + name_r); + } else if (!count(name_r)) { + // No user defined value, so we follow the target + zypp::Target_Ptr trg(_myCtx.target()); + if (trg) + val = trg->distributionVersion(); + else + val = zypp::Target::distributionVersion( _myCtx.contextRoot() ); + + if (val != operator[]("$_releasever")) { + operator[]("$_releasever") = std::move(val); + deriveFromReleasever("$_releasever", + /*overwrite previous values*/ true); + } + return &operator[]("$_" + name_r); + } + // else: + return nullptr; // get user value from map + } + /////////////////////////////////////////////////////////////////// + + return nullptr; // get user value from map + } +} // namespace zyppng::repo diff --git a/zypp/ng/repo/repovariablescache.h b/zypp/ng/repo/repovariablescache.h new file mode 100644 index 0000000000..fd4b6e41fa --- /dev/null +++ b/zypp/ng/repo/repovariablescache.h @@ -0,0 +1,63 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_NG_REPO_REPOVARIABLES_CACHE_H_INCLUDED +#define ZYPP_NG_REPO_REPOVARIABLES_CACHE_H_INCLUDED + +#include +#include +#include +#include + +namespace zyppng { + class ContextBase; +} + +namespace zyppng::repo { + + class RepoVarsMap : public std::map + { + public: + + ~RepoVarsMap() = default; + RepoVarsMap(const RepoVarsMap &) = delete; + RepoVarsMap(RepoVarsMap &&) = delete; + RepoVarsMap &operator=(const RepoVarsMap &) = delete; + RepoVarsMap &operator=(RepoVarsMap &&) = delete; + + const std::string *lookup(const std::string &name_r); + + std::ostream &dumpOn(std::ostream &str) const; + + private: + friend class zyppng::ContextBase; // only context may create a cache + + RepoVarsMap(ContextBase &myContext); + /** Get first line from file */ + bool parse( const zypp::Pathname &dir_r, const std::string &str_r ); + + /** Derive \c releasever_major/_minor from \c releasever, keeping or overwrititing existing values. */ + void deriveFromReleasever(const std::string &stem_r, bool overwrite_r); + + /** Split \c releasever at \c '.' and store major/minor parts as requested. */ + void splitReleaseverTo(const std::string &releasever_r, + std::string *major_r, std::string *minor_r) const; + + /** Check for conditions overwriting the (user) defined values. */ + const std::string *checkOverride(const std::string &name_r); + + ContextBase &_myCtx; // the context this Cache is owned by + }; + + +} + + + +#endif // ZYPP_NG_REPO_REPOVARIABLES_CACHE_H_INCLUDED + diff --git a/zypp/ng/repo/workflows/plaindir.cc b/zypp/ng/repo/workflows/plaindir.cc index 5482833b65..2829d4f395 100644 --- a/zypp/ng/repo/workflows/plaindir.cc +++ b/zypp/ng/repo/workflows/plaindir.cc @@ -13,7 +13,7 @@ #include #include -#include + #include #include @@ -24,7 +24,7 @@ namespace zyppng::PlaindirWorkflows { namespace { template - auto statusLogic( DlContextRefType &&ctx, MediaHandle mediaHandle ) { + auto statusLogic( DlContextRefType &&ctx, ProgressObserverRef taskObserver, MediaHandle mediaHandle ) { constexpr bool isAsync = std::is_same_v; // this can only happen if this function is called with a non mounting medium, but those do not support plaindir anyway @@ -39,14 +39,14 @@ namespace zyppng::PlaindirWorkflows { } } - AsyncOpRef > repoStatus(repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle) + AsyncOpRef > repoStatus(repo::AsyncDownloadContextRef dl, ProgressObserverRef taskObserver, ProvideMediaHandle mediaHandle) { - return statusLogic( std::move(dl), std::move(mediaHandle) ); + return statusLogic( std::move(dl), std::move(taskObserver), std::move(mediaHandle) ); } - expected repoStatus(repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle) + expected repoStatus(repo::SyncDownloadContextRef dl, ProgressObserverRef taskObserver, SyncMediaHandle mediaHandle) { - return statusLogic( std::move(dl), std::move(mediaHandle) ); + return statusLogic( std::move(dl), std::move(taskObserver), std::move(mediaHandle) ); } @@ -85,12 +85,12 @@ namespace zyppng::PlaindirWorkflows { } } - AsyncOpRef > download(repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver) + AsyncOpRef > download(repo::AsyncDownloadContextRef dl, ProgressObserverRef progressObserver, ProvideMediaHandle mediaHandle ) { return dlLogic( std::move(dl), std::move(mediaHandle), std::move(progressObserver) ); } - expected download(repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle, ProgressObserverRef progressObserver) + expected download(repo::SyncDownloadContextRef dl, ProgressObserverRef progressObserver, SyncMediaHandle mediaHandle) { return dlLogic( std::move(dl), std::move(mediaHandle), std::move(progressObserver) ); } diff --git a/zypp/ng/repo/workflows/plaindir.h b/zypp/ng/repo/workflows/plaindir.h index 2ea7f78f36..5e227cb2f0 100644 --- a/zypp/ng/repo/workflows/plaindir.h +++ b/zypp/ng/repo/workflows/plaindir.h @@ -24,11 +24,11 @@ namespace zyppng { ZYPP_FWD_DECL_TYPE_WITH_REFS( ProgressObserver ); namespace PlaindirWorkflows { - AsyncOpRef> repoStatus( repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle ); - expected repoStatus( repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle ); + AsyncOpRef> repoStatus(repo::AsyncDownloadContextRef dl, ProgressObserverRef taskObserver, ProvideMediaHandle mediaHandle ); + expected repoStatus( repo::SyncDownloadContextRef dl, ProgressObserverRef taskObserver, SyncMediaHandle mediaHandle ); - AsyncOpRef> download ( repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver = nullptr ); - expected download ( repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle, ProgressObserverRef progressObserver = nullptr ); + AsyncOpRef> download (repo::AsyncDownloadContextRef dl, ProgressObserverRef progressObserver, ProvideMediaHandle mediaHandle ); + expected download ( repo::SyncDownloadContextRef dl, ProgressObserverRef progressObserver, SyncMediaHandle mediaHandle ); } } diff --git a/zypp/ng/repo/workflows/repodownloaderwf.cc b/zypp/ng/repo/workflows/repodownloaderwf.cc index 9ce54a73d2..6e291b91ea 100644 --- a/zypp/ng/repo/workflows/repodownloaderwf.cc +++ b/zypp/ng/repo/workflows/repodownloaderwf.cc @@ -8,7 +8,8 @@ \---------------------------------------------------------------------*/ #include "repodownloaderwf.h" #include -#include "zypp/parser/yum/RepomdFileReader.h" +#include +#include #include #include @@ -24,7 +25,7 @@ #include // sync workflow helpers -#include + #include #undef ZYPP_BASE_LOGGER_LOGGROUP @@ -47,10 +48,11 @@ namespace zyppng { using MediaHandle = typename ProvideType::MediaHandle; using ProvideRes = typename ProvideType::Res; - DownloadMasterIndexLogic( DlContextRefType &&ctxRef, MediaHandle &&mediaHandle, zypp::filesystem::Pathname &&masterIndex_r ) + DownloadMasterIndexLogic( DlContextRefType &&ctxRef, MediaHandle &&mediaHandle, zypp::filesystem::Pathname &&masterIndex_r, ProgressObserverRef progressObserver ) : _dlContext( std::move(ctxRef) ) , _media(std::move( mediaHandle )) , _masterIndex(std::move( masterIndex_r )) + , _progressObserver(std::move(progressObserver)) { } public: @@ -63,10 +65,10 @@ namespace zyppng { auto providerRef = _dlContext->zyppContext()->provider(); return std::vector { // fetch signature and keys - providerRef->provide( _media, _sigpath, ProvideFileSpec().setOptional( true ) ) - | and_then( ProvideType::copyResultToDest ( providerRef, _destdir / _sigpath ) ), - providerRef->provide( _media, _keypath, ProvideFileSpec().setOptional( true ) ) - | and_then( ProvideType::copyResultToDest ( providerRef, _destdir / _keypath ) ), + providerRef->provide( _media, _sigpath, ProvideFileSpec().setOptional( true ).setDownloadSize( zypp::ByteCount( 20, zypp::ByteCount::MB ) ) ) + | and_then( ProvideType::copyResultToDest ( providerRef, _dlContext->zyppContext(), _destdir / _sigpath ) ), + providerRef->provide( _media, _keypath, ProvideFileSpec().setOptional( true ).setDownloadSize( zypp::ByteCount( 20, zypp::ByteCount::MB ) ) ) + | and_then( ProvideType::copyResultToDest ( providerRef, _dlContext->zyppContext(), _destdir / _keypath ) ), } | join() | [this]( std::vector> &&res ) { @@ -80,7 +82,7 @@ namespace zyppng { }); // get the master index file - return provider()->provide( _media, _masterIndex, ProvideFileSpec() ); + return provider()->provide( _media, _masterIndex, ProvideFileSpec().setDownloadSize( zypp::ByteCount( 20, zypp::ByteCount::MB ) ) ); } // execute plugin verification if there is one | and_then( std::bind( &DownloadMasterIndexLogic::pluginVerification, this, std::placeholders::_1 ) ) @@ -89,7 +91,7 @@ namespace zyppng { | and_then( std::bind( &DownloadMasterIndexLogic::signatureCheck, this, std::placeholders::_1 ) ) // copy everything into a directory - | and_then( ProvideType::copyResultToDest ( providerRef, _destdir / _masterIndex ) ) + | and_then( ProvideType::copyResultToDest ( providerRef, _dlContext->zyppContext(), _destdir / _masterIndex ) ) // final tasks | and_then([this]( zypp::ManagedFile &&masterIndex ) { @@ -150,7 +152,7 @@ namespace zyppng { vCtx.addBuddyKey( keyData.id() ); } - return SignatureFileCheckWorkflow::verifySignature( _dlContext->zyppContext(), std::move(vCtx)) + return SignatureFileCheckWorkflow::verifySignature( _dlContext->zyppContext(), _progressObserver, std::move(vCtx)) | and_then([ this, res = std::move(res) ]( zypp::keyring::VerifyFileContext verRes ){ // remember the validation status _repoSigValidated = verRes.fileValidated(); @@ -228,7 +230,7 @@ namespace zyppng { | or_else ([ this, file = file, keyid = keyid, cacheFile ] ( auto ) mutable -> MaybeAsyncRef> { auto providerRef = _dlContext->zyppContext()->provider(); return providerRef->provide( _media, file, ProvideFileSpec().setOptional(true) ) - | and_then( ProvideType::copyResultToDest( providerRef, _destdir / file ) ) + | and_then( ProvideType::copyResultToDest( providerRef, _dlContext->zyppContext(), _destdir / file ) ) | and_then( [this, providerRef, file, keyid , cacheFile = std::move(cacheFile)]( zypp::ManagedFile &&res ) { // remember we downloaded the file @@ -236,14 +238,14 @@ namespace zyppng { auto key = zypp::PublicKey::noThrow( _dlContext->files().back() ); if ( not key.fileProvidesKey( keyid ) ) { - const auto &str = zypp::str::Str() << "Keyhint " << file << " does not contain a key with id " << keyid << ". Skipping it."; + const std::string str = zypp::str::Str() << "Keyhint " << file << " does not contain a key with id " << keyid << ". Skipping it."; WAR << str << std::endl; return makeReadyResult(expected::error( std::make_exception_ptr( zypp::Exception(str)) )); } // Try to cache it... zypp::filesystem::assert_dir( cacheFile.dirname() ); - return providerRef->copyFile( key.path(), cacheFile ) + return providerRef->copyFile( _dlContext->zyppContext(), key.path(), cacheFile ) | [ key ]( expected res ) mutable { if ( res ) { // do not delete from cache @@ -277,6 +279,7 @@ namespace zyppng { DlContextRefType _dlContext; MediaHandle _media; zypp::Pathname _masterIndex; + ProgressObserverRef _progressObserver; zypp::Pathname _destdir; zypp::Pathname _sigpath; @@ -288,38 +291,38 @@ namespace zyppng { } - AsyncOpRef > RepoDownloaderWorkflow::downloadMasterIndex(repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle, zypp::Pathname masterIndex_r) + AsyncOpRef > RepoDownloaderWorkflow::downloadMasterIndex(repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle, zypp::Pathname masterIndex_r, ProgressObserverRef progressObserver ) { - return SimpleExecutor>>::run( std::move(dl), std::move(mediaHandle), std::move(masterIndex_r) ); + return SimpleExecutor>>::run( std::move(dl), std::move(mediaHandle), std::move(masterIndex_r), std::move(progressObserver) ); } - expected RepoDownloaderWorkflow::downloadMasterIndex(repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle, zypp::Pathname masterIndex_r) + expected RepoDownloaderWorkflow::downloadMasterIndex(repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle, zypp::Pathname masterIndex_r, ProgressObserverRef progressObserver ) { - return SimpleExecutor>>::run( std::move(dl), std::move(mediaHandle), std::move(masterIndex_r) ); + return SimpleExecutor>>::run( std::move(dl), std::move(mediaHandle), std::move(masterIndex_r), std::move(progressObserver) ); } - AsyncOpRef> RepoDownloaderWorkflow::downloadMasterIndex ( repo::AsyncDownloadContextRef dl, AsyncLazyMediaHandle mediaHandle, zypp::filesystem::Pathname masterIndex_r ) + AsyncOpRef> RepoDownloaderWorkflow::downloadMasterIndex ( repo::AsyncDownloadContextRef dl, AsyncLazyMediaHandle mediaHandle, zypp::filesystem::Pathname masterIndex_r, ProgressObserverRef progressObserver ) { using namespace zyppng::operators; return dl->zyppContext()->provider()->attachMediaIfNeeded( mediaHandle ) - | and_then([ dl, mi = std::move(masterIndex_r) ]( ProvideMediaHandle handle ) mutable { - return downloadMasterIndex( std::move(dl), std::move(handle), std::move(mi) ); + | and_then([ dl, mi = std::move(masterIndex_r), po = std::move(progressObserver) ]( ProvideMediaHandle handle ) mutable { + return downloadMasterIndex( std::move(dl), std::move(handle), std::move(mi), std::move(po) ); }); } - expected RepoDownloaderWorkflow::downloadMasterIndex ( repo::SyncDownloadContextRef dl, SyncLazyMediaHandle mediaHandle, zypp::filesystem::Pathname masterIndex_r ) + expected RepoDownloaderWorkflow::downloadMasterIndex ( repo::SyncDownloadContextRef dl, SyncLazyMediaHandle mediaHandle, zypp::filesystem::Pathname masterIndex_r, ProgressObserverRef progressObserver ) { using namespace zyppng::operators; return dl->zyppContext()->provider()->attachMediaIfNeeded( mediaHandle ) - | and_then([ dl, mi = std::move(masterIndex_r) ]( SyncMediaHandle handle ) mutable { - return downloadMasterIndex( std::move(dl), std::move(handle), std::move(mi) ); + | and_then([ dl, mi = std::move(masterIndex_r), po = std::move(progressObserver) ]( SyncMediaHandle handle ) mutable { + return downloadMasterIndex( std::move(dl), std::move(handle), std::move(mi), std::move(po) ); }); } namespace { template - auto statusImpl ( DlContextRefType dlCtx, MediaHandleType &&mediaHandle ) { + auto statusImpl ( DlContextRefType dlCtx, MediaHandleType &&mediaHandle, ProgressObserverRef progressObserver ) { constexpr bool isAsync = std::is_same_v; @@ -329,11 +332,11 @@ namespace zyppng { switch( dlCtx->repoInfo().type().toEnum()) { case zypp::repo::RepoType::RPMMD_e: - return RpmmdWorkflows::repoStatus( dlCtx, std::forward(mediaHandle) ) | and_then( std::move(finalizeStatus) ); + return RpmmdWorkflows::repoStatus( dlCtx, std::move(progressObserver), std::forward(mediaHandle) ) | and_then( std::move(finalizeStatus) ); case zypp::repo::RepoType::YAST2_e: - return SuseTagsWorkflows::repoStatus( dlCtx, std::forward(mediaHandle) ) | and_then( std::move(finalizeStatus) ); + return SuseTagsWorkflows::repoStatus( dlCtx, std::move(progressObserver), std::forward(mediaHandle) ) | and_then( std::move(finalizeStatus) ); case zypp::repo::RepoType::RPMPLAINDIR_e: - return PlaindirWorkflows::repoStatus ( dlCtx, std::forward(mediaHandle) ) | and_then( std::move(finalizeStatus) ); + return PlaindirWorkflows::repoStatus ( dlCtx, std::move(progressObserver), std::forward(mediaHandle) ) | and_then( std::move(finalizeStatus) ); case zypp::repo::RepoType::NONE_e: break; } @@ -342,27 +345,27 @@ namespace zyppng { } } - AsyncOpRef > RepoDownloaderWorkflow::repoStatus(repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle) { - return statusImpl( dl, std::move(mediaHandle) ); + AsyncOpRef > RepoDownloaderWorkflow::repoStatus(repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver ) { + return statusImpl( dl, std::move(mediaHandle), std::move(progressObserver) ); } - expected RepoDownloaderWorkflow::repoStatus(repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle) { - return statusImpl( dl, std::move(mediaHandle) ); + expected RepoDownloaderWorkflow::repoStatus(repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle, ProgressObserverRef progressObserver ) { + return statusImpl( dl, std::move(mediaHandle), std::move(progressObserver) ); } - AsyncOpRef > RepoDownloaderWorkflow::repoStatus( repo::AsyncDownloadContextRef dl, AsyncLazyMediaHandle mediaHandle ) { + AsyncOpRef > RepoDownloaderWorkflow::repoStatus( repo::AsyncDownloadContextRef dl, AsyncLazyMediaHandle mediaHandle, ProgressObserverRef progressObserver ) { using namespace zyppng::operators; return dl->zyppContext()->provider()->attachMediaIfNeeded( mediaHandle ) - | and_then([ dl ]( ProvideMediaHandle handle ) { - return repoStatus( dl, std::move(handle) ); + | and_then([ dl, obs = std::move(progressObserver) ]( ProvideMediaHandle handle ) mutable { + return repoStatus( dl, std::move(handle), std::move(obs) ); }); } - expected RepoDownloaderWorkflow::repoStatus( repo::SyncDownloadContextRef dl, SyncLazyMediaHandle mediaHandle ) { + expected RepoDownloaderWorkflow::repoStatus( repo::SyncDownloadContextRef dl, SyncLazyMediaHandle mediaHandle, ProgressObserverRef progressObserver ) { using namespace zyppng::operators; return dl->zyppContext()->provider()->attachMediaIfNeeded( mediaHandle ) - | and_then([ dl ]( SyncMediaHandle handle ) { - return repoStatus( dl, std::move(handle) ); + | and_then([ dl, obs = std::move(progressObserver) ]( SyncMediaHandle handle ) { + return repoStatus( dl, std::move(handle), std::move(obs) ); }); } @@ -375,11 +378,11 @@ namespace zyppng { switch( dlCtx->repoInfo().type().toEnum()) { case zypp::repo::RepoType::RPMMD_e: - return RpmmdWorkflows::download( std::move(dlCtx), std::forward(mediaHandle), std::move(progressObserver) ); + return RpmmdWorkflows::download( std::move(dlCtx), std::move(progressObserver), std::forward(mediaHandle) ); case zypp::repo::RepoType::YAST2_e: - return SuseTagsWorkflows::download( std::move(dlCtx), std::forward(mediaHandle), std::move(progressObserver) ); + return SuseTagsWorkflows::download( std::move(dlCtx), std::move(progressObserver), std::forward(mediaHandle) ); case zypp::repo::RepoType::RPMPLAINDIR_e: - return PlaindirWorkflows::download ( std::move(dlCtx), std::forward(mediaHandle) ); + return PlaindirWorkflows::download ( std::move(dlCtx), std::move(progressObserver), std::forward(mediaHandle) ); case zypp::repo::RepoType::NONE_e: break; } diff --git a/zypp/ng/repo/workflows/repodownloaderwf.h b/zypp/ng/repo/workflows/repodownloaderwf.h index 4d75c10490..ed0f64910f 100644 --- a/zypp/ng/repo/workflows/repodownloaderwf.h +++ b/zypp/ng/repo/workflows/repodownloaderwf.h @@ -34,20 +34,20 @@ namespace zyppng { using SyncLazyMediaHandle = LazyMediaHandle; namespace RepoDownloaderWorkflow { - AsyncOpRef> downloadMasterIndex ( repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle, zypp::filesystem::Pathname masterIndex_r ); - AsyncOpRef> downloadMasterIndex ( repo::AsyncDownloadContextRef dl, AsyncLazyMediaHandle mediaHandle, zypp::filesystem::Pathname masterIndex_r ); - expected downloadMasterIndex ( repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle, zypp::filesystem::Pathname masterIndex_r ); - expected downloadMasterIndex ( repo::SyncDownloadContextRef dl, SyncLazyMediaHandle mediaHandle, zypp::filesystem::Pathname masterIndex_r ); + AsyncOpRef> downloadMasterIndex ( repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle, zypp::filesystem::Pathname masterIndex_r, ProgressObserverRef progressObserver = nullptr ); + AsyncOpRef> downloadMasterIndex ( repo::AsyncDownloadContextRef dl, AsyncLazyMediaHandle mediaHandle, zypp::filesystem::Pathname masterIndex_r, ProgressObserverRef progressObserver = nullptr ); + expected downloadMasterIndex ( repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle, zypp::filesystem::Pathname masterIndex_r, ProgressObserverRef progressObserver = nullptr ); + expected downloadMasterIndex ( repo::SyncDownloadContextRef dl, SyncLazyMediaHandle mediaHandle, zypp::filesystem::Pathname masterIndex_r, ProgressObserverRef progressObserver = nullptr ); - AsyncOpRef> repoStatus( repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle ); - AsyncOpRef > repoStatus( repo::AsyncDownloadContextRef dl, AsyncLazyMediaHandle mediaHandle ); - expected repoStatus( repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle ); - expected repoStatus( repo::SyncDownloadContextRef dl, SyncLazyMediaHandle mediaHandle ); + AsyncOpRef> repoStatus( repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver = nullptr ); + AsyncOpRef > repoStatus( repo::AsyncDownloadContextRef dl, AsyncLazyMediaHandle mediaHandle, ProgressObserverRef progressObserver = nullptr ); + expected repoStatus( repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle, ProgressObserverRef progressObserver = nullptr ); + expected repoStatus( repo::SyncDownloadContextRef dl, SyncLazyMediaHandle mediaHandle, ProgressObserverRef progressObserver = nullptr ); AsyncOpRef> download ( repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver = nullptr ); AsyncOpRef > download(repo::AsyncDownloadContextRef dl, AsyncLazyMediaHandle mediaHandle, ProgressObserverRef progressObserver); expected download ( repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle, ProgressObserverRef progressObserver = nullptr ); - expected download(repo::SyncDownloadContextRef dl, SyncLazyMediaHandle mediaHandle, ProgressObserverRef progressObserver); + expected download( repo::SyncDownloadContextRef dl, SyncLazyMediaHandle mediaHandle, ProgressObserverRef progressObserver); template auto downloadMediaInfo ( MediaHandle &&mediaHandle, const zypp::filesystem::Pathname &destdir ) { @@ -57,12 +57,15 @@ namespace zyppng { // check if we have a async media handle constexpr bool isAsync = std::is_same_v; auto provider = mediaHandle.parent(); - if ( !provider ) + if ( !mediaHandle.isValid() || !provider ) return makeReadyResult, isAsync>( expected::error(ZYPP_EXCPT_PTR(zypp::media::MediaException("Invalid handle"))) ); - return provider->provide( std::forward(mediaHandle), "/media.1/media", ProvideFileSpec().setOptional(true) ) - | and_then( ProvideType::copyResultToDest( provider, destdir / "/media.1/media" ) ); + auto spec = mediaHandle.spec(); + if ( !spec || !spec->mediaContext() ) + return makeReadyResult, isAsync>( expected::error(ZYPP_EXCPT_PTR(zypp::media::MediaException("Invalid mediaspec in handle"))) ); + return provider->provide( std::forward(mediaHandle), "/media.1/media", ProvideFileSpec().setOptional(true).setDownloadSize( zypp::ByteCount(20, zypp::ByteCount::MB ) ) ) + | and_then( ProvideType::copyResultToDest( provider, spec->mediaContext(), destdir / "/media.1/media" ) ); } } } diff --git a/zypp/ng/repo/workflows/repomanagerwf.cc b/zypp/ng/repo/workflows/repomanagerwf.cc index 52d3c2b75d..fd1c67f6f6 100644 --- a/zypp/ng/repo/workflows/repomanagerwf.cc +++ b/zypp/ng/repo/workflows/repomanagerwf.cc @@ -8,7 +8,8 @@ \---------------------------------------------------------------------*/ #include "repomanagerwf.h" -#include "zypp/parser/xml/Reader.h" +#include +#include #include #include @@ -23,7 +24,7 @@ #include #include #include -#include + #include #include @@ -46,7 +47,7 @@ namespace zyppng::RepoManagerWorkflow { ZYPP_ENABLE_LOGIC_BASE(Executor, OpType); public: - using ZyppContextRefType = std::conditional_t, ContextRef, SyncContextRef >; + using ZyppContextRefType = std::conditional_t, AsyncContextRef, SyncContextRef >; using ProvideType = typename remove_smart_ptr_t::ProvideType; using MediaHandle = typename ProvideType::MediaHandle; using LazyMediaHandle = typename ProvideType::LazyMediaHandle; @@ -159,7 +160,7 @@ namespace zyppng::RepoManagerWorkflow { if ( _targetPath ) { MIL << "Target path is set, copying " << file.file() << " to " << *_targetPath/subPath << std::endl; return std::move(file) - | ProvideType::copyResultToDest( _zyppContext->provider(), *_targetPath/subPath) + | ProvideType::copyResultToDest( _zyppContext->provider(), _zyppContext, *_targetPath/subPath) | and_then([]( zypp::ManagedFile file ){ file.resetDispose(); return expected::success(); } ); } return makeReadyResult( expected::success() ); @@ -180,14 +181,14 @@ namespace zyppng::RepoManagerWorkflow { auto probeRepoLogic( RefreshContextRef ctx, RepoInfo repo, std::optional targetPath) { using namespace zyppng::operators; - return ctx->provider()->prepareMedia( repo.url(), zyppng::ProvideMediaSpec() ) + return ctx->provider()->prepareMedia( repo.url(), zyppng::ProvideMediaSpec( repo.context() ) ) | and_then( [ctx, path = repo.path() ]( auto &&mediaHandle ) { return probeRepoType( ctx, std::forward(mediaHandle), path ); }); } } - AsyncOpRef > probeRepoType(ContextRef ctx, AsyncLazyMediaHandle medium, zypp::Pathname path, std::optional targetPath) + AsyncOpRef > probeRepoType(AsyncContextRef ctx, AsyncLazyMediaHandle medium, zypp::Pathname path, std::optional targetPath) { return SimpleExecutor< ProbeRepoLogic, AsyncOp> >::run( std::move(ctx), std::move(medium), std::move(path), std::move(targetPath) ); } @@ -197,7 +198,7 @@ namespace zyppng::RepoManagerWorkflow { return SimpleExecutor< ProbeRepoLogic, SyncOp> >::run( std::move(ctx), std::move(medium), std::move(path), std::move(targetPath) ); } - AsyncOpRef > probeRepoType( ContextRef ctx, RepoInfo repo, std::optional targetPath ) + AsyncOpRef > probeRepoType( AsyncContextRef ctx, RepoInfo repo, std::optional targetPath ) { return probeRepoLogic( std::move(ctx), std::move(repo), std::move(targetPath) ); } @@ -213,15 +214,15 @@ namespace zyppng::RepoManagerWorkflow { auto readRepoFileLogic( ZyppContextRef ctx, zypp::Url repoFileUrl ) { using namespace zyppng::operators; - return ctx->provider()->provide( repoFileUrl, ProvideFileSpec() ) - | and_then([repoFileUrl]( auto local ){ + return ctx->provider()->provide( ctx, repoFileUrl, ProvideFileSpec() ) + | and_then([ctx, repoFileUrl]( auto local ){ DBG << "reading repo file " << repoFileUrl << ", local path: " << local.file() << std::endl; - return repositories_in_file( local.file() ); + return repositories_in_file( ctx, local.file() ); }); } } - AsyncOpRef > > readRepoFile(ContextRef ctx, zypp::Url repoFileUrl) + AsyncOpRef > > readRepoFile(AsyncContextRef ctx, zypp::Url repoFileUrl) { return readRepoFileLogic( std::move(ctx), std::move(repoFileUrl) ); } @@ -264,7 +265,7 @@ namespace zyppng::RepoManagerWorkflow { MIL << "Check if to refresh repo " << _refreshContext->repoInfo().alias() << " at " << _medium.baseUrl() << " (" << info.type() << ")" << std::endl; // first check old (cached) metadata - return zyppng::RepoManager::metadataStatus( info, _refreshContext->repoManagerOptions() ); + return zyppng::RepoManager::metadataStatus( info, _refreshContext->repoManagerOptions() ); }) | and_then( [this](zypp::RepoStatus oldstatus) { @@ -295,7 +296,7 @@ namespace zyppng::RepoManagerWorkflow { // bsc#1174016: Prerequisite to skipping the refresh is that metadata // and solv cache status match. They will not, if the repos URL was // changed e.g. due to changed repovars. - expected cachestatus = zyppng::RepoManager::cacheStatus( info, _refreshContext->repoManagerOptions() ); + expected cachestatus = zyppng::RepoManager::cacheStatus( info, _refreshContext->repoManagerOptions() ); if ( !cachestatus ) return makeReadyResult( expected::error(cachestatus.error()) ); if ( oldstatus == *cachestatus ) { @@ -336,7 +337,7 @@ namespace zyppng::RepoManagerWorkflow { // check status if ( oldstatus == newstatus ) { MIL << "repo has not changed" << std::endl; - return zyppng::RepoManager::touchIndexFile( _refreshContext->repoInfo(), _refreshContext->repoManagerOptions() ) + return zyppng::RepoManager::touchIndexFile( _refreshContext->repoInfo(), _refreshContext->repoManagerOptions() ) | and_then([](){ return expected::success(zypp::RepoManagerFlags::REPO_UP_TO_DATE); }); } else { // includes newstatus.empty() if e.g. repo format changed @@ -440,10 +441,14 @@ namespace zyppng::RepoManagerWorkflow { return makeReadyResult( expected::error( std::move(exception) )); } - auto dlContext = std::make_shared( _refreshContext->zyppContext(), _refreshContext->repoInfo(), _refreshContext->targetDir() ); - dlContext->setPluginRepoverification( _refreshContext->pluginRepoverification() ); - - return RepoDownloaderWorkflow::download ( dlContext, _medium, _progress ); + return _refreshContext->engageLock() + | and_then( [this]( zypp::Deferred lockRef ) { + _lock = std::move(lockRef); + auto dlContext = std::make_shared( _refreshContext->zyppContext(), _refreshContext->repoInfo(), _refreshContext->targetDir() ); + dlContext->setPluginRepoverification( _refreshContext->pluginRepoverification() ); + return RepoDownloaderWorkflow::download ( dlContext, _medium, _progress ); + } + ); }) | and_then([this]( DlContextRefType && ) { @@ -456,10 +461,15 @@ namespace zyppng::RepoManagerWorkflow { // we are done. return expected::success( std::move(_refreshContext) ); - }); + }) + | [this]( auto res ) { + _lock.reset(); // clear the lock + return res; + }; }); } + zypp::Deferred _lock; RefreshContextRefType _refreshContext; ProgressObserverRef _progress; LazyMediaHandle _medium; @@ -505,12 +515,12 @@ namespace zyppng::RepoManagerWorkflow { // the actual logic pipeline, attaches the medium and tries to refresh from it auto refreshPipeline = [ refCtx, progressObserver ]( zypp::Url url ){ - return refCtx->zyppContext()->provider()->prepareMedia( url, zyppng::ProvideMediaSpec() ) + return refCtx->zyppContext()->provider()->prepareMedia( url, zyppng::ProvideMediaSpec( refCtx->zyppContext() ) ) | and_then( [ refCtx , progressObserver]( auto mediaHandle ) mutable { return refreshMetadata ( std::move(refCtx), std::move(mediaHandle), progressObserver ); } ); }; // predicate that accepts only valid results, and in addition collects all errors in rexception - auto predicate = [ info = refCtx->repoInfo(), helper ]( const expected &res ) -> bool{ + auto predicate = [ /* info = refCtx->repoInfo(), */ helper ]( const expected &res ) -> bool{ if ( !res ) { try { ZYPP_RETHROW( res.error() ); @@ -557,17 +567,17 @@ namespace zyppng::RepoManagerWorkflow { template struct Repo2SolvOp; template <> - struct Repo2SolvOp : public AsyncOp> + struct Repo2SolvOp : public AsyncOp> { Repo2SolvOp() { } - static AsyncOpRef> run( zypp::RepoInfo repo, zypp::ExternalProgram::Arguments args ) { + static AsyncOpRef> run( RepoInfo repo, zypp::ExternalProgram::Arguments args ) { MIL << "Starting repo2solv for repo " << repo.alias () << std::endl; - auto me = std::make_shared>(); + auto me = std::make_shared>(); me->_repo = std::move(repo); me->_proc = Process::create(); - me->_proc->connect( &Process::sigFinished, *me, &Repo2SolvOp::procFinished ); - me->_proc->connect( &Process::sigReadyRead, *me, &Repo2SolvOp::readyRead ); + me->_proc->connect( &Process::sigFinished, *me, &Repo2SolvOp::procFinished ); + me->_proc->connect( &Process::sigReadyRead, *me, &Repo2SolvOp::readyRead ); std::vector argsIn; argsIn.reserve ( args.size() ); @@ -603,14 +613,14 @@ namespace zyppng::RepoManagerWorkflow { private: ProcessRef _proc; - zypp::RepoInfo _repo; + RepoInfo _repo {nullptr}; std::string _errdetail; }; template <> struct Repo2SolvOp { - static expected run( zypp::RepoInfo repo, zypp::ExternalProgram::Arguments args ) { + static expected run( RepoInfo repo, zypp::ExternalProgram::Arguments args ) { zypp::ExternalProgram prog( args, zypp::ExternalProgram::Stderr_To_Stdout ); std::string errdetail; @@ -651,13 +661,18 @@ namespace zyppng::RepoManagerWorkflow { MaybeAsyncRef> execute() { ProgressObserver::setup ( _progressObserver, zypp::str::form(_("Building repository '%s' cache"), _refCtx->repoInfo().label().c_str()), 100 ); + ProgressObserver::start ( _progressObserver ); return assert_alias(_refCtx->repoInfo() ) | and_then( mtry( [this] { _mediarootpath = rawcache_path_for_repoinfo( _refCtx->repoManagerOptions(), _refCtx->repoInfo() ).unwrap(); _productdatapath = rawproductdata_path_for_repoinfo( _refCtx->repoManagerOptions(), _refCtx->repoInfo() ).unwrap(); })) - | and_then( [this] { + | and_then( [this]() { return _refCtx->engageLock(); } ) + | and_then( [this]( zypp::Deferred repoLock ) { + + _repoLock = std::move(repoLock); + const auto &options = _refCtx->repoManagerOptions(); @@ -666,7 +681,7 @@ namespace zyppng::RepoManagerWorkflow { return expected::error( std::move(ex) ); } - return RepoManager::metadataStatus( _refCtx->repoInfo(), options ); + return RepoManager::metadataStatus( _refCtx->repoInfo(), options ); }) | and_then( [this](RepoStatus raw_metadata_status ) { @@ -682,7 +697,7 @@ namespace zyppng::RepoManagerWorkflow { && zypp::PathInfo(mediarootParent).userMayWX() ) { return refreshMetadata( _refCtx, ProgressObserver::makeSubTask( _progressObserver ) ) - | and_then([this]( auto /*refCtx*/) { return RepoManager::metadataStatus( _refCtx->repoInfo(), _refCtx->repoManagerOptions() ); } ); + | and_then([this]( auto /*refCtx*/) { return RepoManager::metadataStatus( _refCtx->repoInfo(), _refCtx->repoManagerOptions() ); } ); } else { // Non-root user is not allowed to write the raw cache. @@ -700,7 +715,7 @@ namespace zyppng::RepoManagerWorkflow { if ( _refCtx->repoManager()->isCached( info ) ) { MIL << info.alias() << " is already cached." << std::endl; - expected cache_status = RepoManager::cacheStatus( info, _refCtx->repoManagerOptions() ); + expected cache_status = RepoManager::cacheStatus( info, _refCtx->repoManagerOptions() ); if ( !cache_status ) return makeReadyResult( expected::error(cache_status.error()) ); @@ -727,8 +742,6 @@ namespace zyppng::RepoManagerWorkflow { needs_cleaning = true; } - ProgressObserver::start( _progressObserver ); - if (needs_cleaning) { auto r = _refCtx->repoManager()->cleanCache(info); @@ -764,7 +777,7 @@ namespace zyppng::RepoManagerWorkflow { { case zypp::repo::RepoType::NONE_e: // unknown, probe the local metadata - repokind = RepoManager::probeCache( _productdatapath ); + repokind = RepoManager::probeCache( _productdatapath ); break; default: break; @@ -833,28 +846,31 @@ namespace zyppng::RepoManagerWorkflow { }) | and_then( [this](){ MIL << "Commit cache.." << std::endl; + _repoLock.reset (); ProgressObserver::finish( _progressObserver, ProgressObserver::Success ); return make_expected_success ( _refCtx ); }) | or_else ( [this]( std::exception_ptr e ) { + _repoLock.reset (); ProgressObserver::finish( _progressObserver, ProgressObserver::Success ); return expected::error(e); }); } private: - MaybeAsyncRef>> mountIfRequired ( zypp::repo::RepoType repokind, zypp::RepoInfo info ) { + MaybeAsyncRef>> mountIfRequired ( zypp::repo::RepoType repokind, RepoInfo info ) { if ( repokind != zypp::repo::RepoType::RPMPLAINDIR ) return makeReadyResult( make_expected_success( std::optional() )); - return _refCtx->zyppContext()->provider()->attachMedia( info.url(), ProvideMediaSpec() ) + return _refCtx->zyppContext()->provider()->attachMedia( info.url(), ProvideMediaSpec( _refCtx->zyppContext() ) ) | and_then( [this]( MediaHandle handle ) { return makeReadyResult( make_expected_success( std::optional( std::move(handle)) )); }); } private: + zypp::Deferred _repoLock; RefreshContextRefType _refCtx; zypp::RepoManagerFlags::CacheBuildPolicy _policy; ProgressObserverRef _progressObserver; @@ -901,7 +917,7 @@ namespace zyppng::RepoManagerWorkflow { ProgressObserver::setup( _myProgress, zypp::str::form(_("Adding repository '%s'"), _info.label().c_str()) ); ProgressObserver::start( _myProgress ); - if ( _repoMgrRef->repos().find(_info) != _repoMgrRef->repos().end() ) + if ( _repoMgrRef->repos().find(_info.alias()) != _repoMgrRef->repos().end() ) return makeReadyResult( expected::error( ZYPP_EXCPT_PTR(zypp::repo::RepoAlreadyExistsException(_info)) ) ); // check the first url for now @@ -943,7 +959,7 @@ namespace zyppng::RepoManagerWorkflow { }; }; - AsyncOpRef > addRepository( AsyncRepoManagerRef mgr, RepoInfo info, ProgressObserverRef myProgress ) + AsyncOpRef< expected > addRepository( AsyncRepoManagerRef mgr, RepoInfo info, ProgressObserverRef myProgress ) { return SimpleExecutor>>::run( std::move(mgr), std::move(info), std::move(myProgress) ); } @@ -970,7 +986,7 @@ namespace zyppng::RepoManagerWorkflow { MaybeAsyncRef> execute() { using namespace zyppng::operators; - return mtry( zypp::repo::RepoVariablesUrlReplacer(), _url ) + return mtry( zypp::repo::RepoVariablesUrlReplacerNg( zypp::repo::RepoVarRetriever( *_repoMgrRef->zyppContext() ) ), _url ) | and_then([this]( zypp::Url repoFileUrl ) { return readRepoFile( _repoMgrRef->zyppContext(), std::move(repoFileUrl) ); } ) | and_then([this]( std::list repos ) { @@ -981,9 +997,9 @@ namespace zyppng::RepoManagerWorkflow { // look if the alias is in the known repos. for_ ( kit, _repoMgrRef->repoBegin(), _repoMgrRef->repoEnd() ) { - if ( (*it).alias() == (*kit).alias() ) + if ( (*it).alias() == kit->first ) { - ERR << "To be added repo " << (*it).alias() << " conflicts with existing repo " << (*kit).alias() << std::endl; + ERR << "To be added repo " << (*it).alias() << " conflicts with existing repo " << kit->first << std::endl; return expected::error(ZYPP_EXCPT_PTR(zypp::repo::RepoAlreadyExistsException(*it))); } } @@ -1028,7 +1044,7 @@ namespace zyppng::RepoManagerWorkflow { it->setFilepath(repofile); it->setMetadataPath( *rawCachePath ); it->setPackagesPath( *pckCachePath ); - _repoMgrRef->reposManip().insert(*it); + _repoMgrRef->reposManip().insert( std::make_pair(it->alias(), *it)); zypp::HistoryLog( _repoMgrRef->options().rootDir).addRepository(*it); } @@ -1065,7 +1081,7 @@ namespace zyppng::RepoManagerWorkflow { ZYPP_ENABLE_LOGIC_BASE(Executor, OpType); public: - using ZyppContextRefType = std::conditional_t, ContextRef, SyncContextRef >; + using ZyppContextRefType = std::conditional_t, AsyncContextRef, SyncContextRef >; using ZyppContextType = typename ZyppContextRefType::element_type; using ProvideType = typename ZyppContextType::ProvideType; using MediaHandle = typename ProvideType::MediaHandle; @@ -1149,7 +1165,7 @@ namespace zyppng::RepoManagerWorkflow { } // always https ,but attaching makes things easier - return _zyppCtx->provider()->attachMedia( url, ProvideMediaSpec() ) + return _zyppCtx->provider()->attachMedia( url, ProvideMediaSpec( _zyppCtx ) ) | and_then( [this]( MediaHandle provideHdl ) { return _zyppCtx->provider()->provide( provideHdl, "/geoip", ProvideFileSpec() ); }) | inspect_err( [hostname]( const std::exception_ptr& ){ MIL << "Failed to query GeoIP from hostname: " << hostname << std::endl; } ) | and_then( [hostname, this]( ProvideRes provideRes ) { @@ -1219,7 +1235,7 @@ namespace zyppng::RepoManagerWorkflow { }; } - AsyncOpRef > refreshGeoIPData( ContextRef ctx, RepoInfo::url_set urls ) + AsyncOpRef > refreshGeoIPData( AsyncContextRef ctx, RepoInfo::url_set urls ) { return SimpleExecutor>>::run( std::move(ctx), std::move(urls) ); } diff --git a/zypp/ng/repo/workflows/repomanagerwf.h b/zypp/ng/repo/workflows/repomanagerwf.h index 247f903c30..616ced711b 100644 --- a/zypp/ng/repo/workflows/repomanagerwf.h +++ b/zypp/ng/repo/workflows/repomanagerwf.h @@ -19,12 +19,10 @@ //@ TODO move required types into their own files... e.g. CheckStatus #include +#include namespace zyppng { - - ZYPP_FWD_DECL_TYPE_WITH_REFS (Context); - ZYPP_FWD_DECL_TYPE_WITH_REFS (SyncContext); ZYPP_FWD_DECL_TYPE_WITH_REFS (ProgressObserver); class Provide; @@ -35,13 +33,13 @@ namespace zyppng { namespace RepoManagerWorkflow { - AsyncOpRef > probeRepoType( ContextRef ctx, AsyncLazyMediaHandle medium, zypp::Pathname path, std::optional targetPath = {} ); + AsyncOpRef > probeRepoType( AsyncContextRef ctx, AsyncLazyMediaHandle medium, zypp::Pathname path, std::optional targetPath = {} ); expected probeRepoType ( SyncContextRef ctx, SyncLazyMediaHandle medium, zypp::Pathname path, std::optional targetPath = {} ); - AsyncOpRef > probeRepoType( ContextRef ctx, RepoInfo repo, std::optional targetPath = {} ); + AsyncOpRef > probeRepoType( AsyncContextRef ctx, RepoInfo repo, std::optional targetPath = {} ); expected probeRepoType ( SyncContextRef ctx, RepoInfo repo, std::optional targetPath = {} ); - AsyncOpRef>> readRepoFile( ContextRef ctx, zypp::Url repoFileUrl ); + AsyncOpRef>> readRepoFile( AsyncContextRef ctx, zypp::Url repoFileUrl ); expected> readRepoFile( SyncContextRef ctx, zypp::Url repoFileUrl ); AsyncOpRef > checkIfToRefreshMetadata( repo::AsyncRefreshContextRef refCtx, AsyncLazyMediaHandle medium, ProgressObserverRef progressObserver = nullptr ); @@ -62,7 +60,7 @@ namespace zyppng { AsyncOpRef> addRepositories( AsyncRepoManagerRef mgr, zypp::Url url, ProgressObserverRef myProgress = nullptr ); expected addRepositories( SyncRepoManagerRef mgr, zypp::Url url, ProgressObserverRef myProgress = nullptr ); - AsyncOpRef> refreshGeoIPData( ContextRef ctx, RepoInfo::url_set urls ); + AsyncOpRef> refreshGeoIPData( AsyncContextRef ctx, RepoInfo::url_set urls ); expected refreshGeoIPData( SyncContextRef ctx, RepoInfo::url_set urls ); } diff --git a/zypp/ng/repo/workflows/rpmmd.cc b/zypp/ng/repo/workflows/rpmmd.cc index c759296e56..130a0949be 100644 --- a/zypp/ng/repo/workflows/rpmmd.cc +++ b/zypp/ng/repo/workflows/rpmmd.cc @@ -7,12 +7,13 @@ | | \---------------------------------------------------------------------*/ #include "rpmmd.h" +#include #include #include #include #include -#include + #include #include #include @@ -39,9 +40,10 @@ namespace zyppng::RpmmdWorkflows { using MediaHandle = typename ProvideType::MediaHandle; using ProvideRes = typename ProvideType::Res; - StatusLogic( DlContextRefType ctx, MediaHandle &&media ) + StatusLogic( DlContextRefType ctx, MediaHandle &&media, ProgressObserverRef &&progressObserver ) : _ctx(std::move(ctx)) , _handle(std::move(media)) + , _progressObserver( std::move(progressObserver) ) {} MaybeAsyncRef> execute() { @@ -68,17 +70,18 @@ namespace zyppng::RpmmdWorkflows { DlContextRefType _ctx; MediaHandle _handle; + ProgressObserverRef _progressObserver; }; } - AsyncOpRef > repoStatus(repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle) + AsyncOpRef > repoStatus(repo::AsyncDownloadContextRef dl, ProgressObserverRef progressObserver, ProvideMediaHandle mediaHandle ) { - return SimpleExecutor< StatusLogic, AsyncOp> >::run( std::move(dl), std::move(mediaHandle) ); + return SimpleExecutor< StatusLogic, AsyncOp> >::run( std::move(dl), std::move(mediaHandle), std::move(progressObserver) ); } - expected repoStatus(repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle) + expected repoStatus(repo::SyncDownloadContextRef dl, ProgressObserverRef progressObserver, SyncMediaHandle mediaHandle) { - return SimpleExecutor< StatusLogic, SyncOp> >::run( std::move(dl), std::move(mediaHandle) ); + return SimpleExecutor< StatusLogic, SyncOp> >::run( std::move(dl), std::move(mediaHandle), std::move(progressObserver) ); } @@ -99,7 +102,7 @@ namespace zyppng::RpmmdWorkflows { using ProvideRes = typename ProvideType::Res; DlLogic( DlContextRefType ctx, MediaHandle &&mediaHandle, ProgressObserverRef &&progressObserver ) - : zypp::repo::yum::RepomdFileCollector( ctx->destDir() ) + : zypp::repo::yum::RepomdFileCollector( ctx->zyppContext(), ctx->destDir() ) , _ctx( std::move(ctx)) , _mediaHandle(std::move(mediaHandle)) , _progressObserver(std::move(progressObserver)) @@ -115,8 +118,7 @@ namespace zyppng::RpmmdWorkflows { if ( _progressObserver ) _progressObserver->inc(); - return RepoDownloaderWorkflow::downloadMasterIndex( _ctx, _mediaHandle, _ctx->repoInfo().path() / "/repodata/repomd.xml" ) - | inspect( incProgress( _progressObserver ) ) + return RepoDownloaderWorkflow::downloadMasterIndex( _ctx, _mediaHandle, _ctx->repoInfo().path() / "/repodata/repomd.xml", _progressObserver ) | inspect( incProgress( _progressObserver ) ) | and_then( [this] ( DlContextRefType && ) { zypp::Pathname repomdPath = _ctx->files().front(); @@ -139,7 +141,7 @@ namespace zyppng::RpmmdWorkflows { return transform_collect ( std::move(requiredFiles), [this]( zypp::OnMediaLocation file ) { - return DownloadWorkflow::provideToCacheDir( _ctx, _mediaHandle, file.filename(), ProvideFileSpec(file) ) + return DownloadWorkflow::provideToCacheDir( _ctx, _progressObserver, _mediaHandle, file.filename(), ProvideFileSpec(file) ) | inspect ( incProgress( _progressObserver ) ); }) | and_then ( [this]( std::vector &&dlFiles ) { @@ -154,7 +156,7 @@ namespace zyppng::RpmmdWorkflows { private: - const zypp::RepoInfo &repoInfo() const override { + const zyppng::RepoInfo &repoInfo() const override { return _ctx->repoInfo(); } @@ -168,12 +170,12 @@ namespace zyppng::RpmmdWorkflows { }; } - AsyncOpRef > download(repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver) + AsyncOpRef > download(repo::AsyncDownloadContextRef dl, ProgressObserverRef progressObserver, ProvideMediaHandle mediaHandle) { return SimpleExecutor< DlLogic, AsyncOp> >::run( std::move(dl), std::move(mediaHandle), std::move(progressObserver) ); } - expected download(repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle, ProgressObserverRef progressObserver) + expected download(repo::SyncDownloadContextRef dl, ProgressObserverRef progressObserver, SyncMediaHandle mediaHandle) { return SimpleExecutor< DlLogic, SyncOp> >::run( std::move(dl), std::move(mediaHandle), std::move(progressObserver) ); } diff --git a/zypp/ng/repo/workflows/rpmmd.h b/zypp/ng/repo/workflows/rpmmd.h index 1dc6829ba8..f3cd0c434f 100644 --- a/zypp/ng/repo/workflows/rpmmd.h +++ b/zypp/ng/repo/workflows/rpmmd.h @@ -30,11 +30,11 @@ namespace zyppng { * to be downloaded to the local disk. */ namespace RpmmdWorkflows { - AsyncOpRef> repoStatus( repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle ); - expected repoStatus(repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle ); + AsyncOpRef> repoStatus(repo::AsyncDownloadContextRef dl, ProgressObserverRef progressObserver , ProvideMediaHandle mediaHandle); + expected repoStatus(repo::SyncDownloadContextRef dl, ProgressObserverRef progressObserver, SyncMediaHandle mediaHandle ); - AsyncOpRef> download ( repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver = nullptr ); - expected download ( repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle, ProgressObserverRef progressObserver = nullptr ); + AsyncOpRef> download ( repo::AsyncDownloadContextRef dl, ProgressObserverRef progressObserver, ProvideMediaHandle mediaHandle ); + expected download ( repo::SyncDownloadContextRef dl, ProgressObserverRef progressObserver, SyncMediaHandle mediaHandle ); } } diff --git a/zypp/ng/repo/workflows/serviceswf.cc b/zypp/ng/repo/workflows/serviceswf.cc index 552fae8b0b..d22f26a258 100644 --- a/zypp/ng/repo/workflows/serviceswf.cc +++ b/zypp/ng/repo/workflows/serviceswf.cc @@ -16,14 +16,15 @@ #include #include #include -#include -#include +#include +#include #include #include #include #include -#include + +#include #include #include @@ -53,8 +54,9 @@ namespace zyppng::RepoServicesWorkflow { ZYPP_ENABLE_LOGIC_BASE(Executor, OpType); public: - using ZyppContextRefType = std::conditional_t, ContextRef, SyncContextRef >; - using RepoMgrRefType = RepoManagerRef; + using ZyppContextType = std::conditional_t, AsyncContext, SyncContext >; + using ZyppContextRefType = Ref; + using RepoMgrRefType = RepoManagerRef; FetchRIMServiceLogic( ZyppContextRefType &&ctx, zypp::Pathname &&root_r, ServiceInfo &&service, ProgressObserverRef &&myProgress ) : _ctx( std::move(ctx) ) @@ -64,7 +66,7 @@ namespace zyppng::RepoServicesWorkflow { {} - MaybeAsyncRef >> execute() { + MaybeAsyncRef >> execute() { using namespace zyppng::operators; @@ -74,15 +76,15 @@ namespace zyppng::RepoServicesWorkflow { serviceUrl.setQueryParam( "cookies", "0" ); return adaptServiceUrlToChroot( serviceUrl, _root_r ); }) - | and_then( [this]( zypp::Url serviceUrl ){ return _ctx->provider()->attachMedia( serviceUrl, ProvideMediaSpec() ); }) + | and_then( [this]( zypp::Url serviceUrl ){ return _ctx->provider()->attachMedia( serviceUrl, ProvideMediaSpec( _ctx ) ); }) | and_then( [this]( auto mediaHandle ) { return _ctx->provider()->provide( mediaHandle, "repo/repoindex.xml", ProvideFileSpec() ); } ) | and_then( [this]( auto provideResult ) { try { - zypp::RepoInfoList repos; - auto callback = [&]( const zypp::RepoInfo &r) { repos.push_back(r); return true; }; + RepoInfoList repos; + auto callback = [&]( const RepoInfo &r) { repos.push_back(r); return true; }; - zypp::parser::RepoindexFileReader reader( provideResult.file(), callback); + parser::RepoIndexFileReader reader( _ctx, provideResult.file(), callback); _service.setProbedTtl( reader.ttl() ); // hack! Modifying the const Service to set parsed TTL return make_expected_success( std::make_pair( _service, std::move(repos) ) ); @@ -93,7 +95,7 @@ namespace zyppng::RepoServicesWorkflow { ZYPP_CAUGHT ( e ); zypp::repo::ServicePluginInformalException ex ( e.msg() ); ex.remember( e ); - return expected>::error( ZYPP_EXCPT_PTR( ex ) ); + return expected>::error( ZYPP_EXCPT_PTR( ex ) ); } }); } @@ -113,9 +115,10 @@ namespace zyppng::RepoServicesWorkflow { ZYPP_ENABLE_LOGIC_BASE(Executor, OpType); public: - using ZyppContextRefType = std::conditional_t, ContextRef, SyncContextRef >; - using RepoMgrRefType = RepoManagerRef; - using Ret = expected>; + using ZyppContextType = std::conditional_t, AsyncContext, SyncContext >; + using ZyppContextRefType = Ref; + using RepoMgrRefType = RepoManagerRef; + using Ret = expected>; FetchPluginServiceLogic( ZyppContextRefType &&ctx, zypp::Pathname &&root_r, ServiceInfo &&service, ProgressObserverRef &&myProgress ) : _ctx( std::move(ctx) ) @@ -144,11 +147,11 @@ namespace zyppng::RepoServicesWorkflow { } try { - zypp::RepoInfoList repos; - auto callback = [&]( const zypp::RepoInfo &r) { repos.push_back(r); return true; }; + RepoInfoList repos; + auto callback = [&]( const RepoInfo &r) { repos.push_back(r); return true; }; std::stringstream buffer( _stdoutBuf ); - zypp::parser::RepoFileReader parser( buffer, callback ); + parser::RepoFileReader parser( _ctx, buffer, callback ); return make_expected_success( std::make_pair( _service, std::move(repos) ) ); } catch (...) { @@ -167,7 +170,7 @@ namespace zyppng::RepoServicesWorkflow { }; - struct SyncFetchPluginService : FetchPluginServiceLogic >>> + struct SyncFetchPluginService : FetchPluginServiceLogic >>> { using FetchPluginServiceLogic::FetchPluginServiceLogic; expected runPlugin( std::string command ) { @@ -197,7 +200,7 @@ namespace zyppng::RepoServicesWorkflow { } }; - struct ASyncFetchPluginService : FetchPluginServiceLogic >>> + struct ASyncFetchPluginService : FetchPluginServiceLogic >>> { using FetchPluginServiceLogic::FetchPluginServiceLogic; AsyncOpRef> runPlugin( std::string command ) { @@ -241,20 +244,20 @@ namespace zyppng::RepoServicesWorkflow { } - AsyncOpRef>> fetchRepoListfromService( ContextRef ctx, zypp::Pathname root_r, ServiceInfo service, ProgressObserverRef myProgress ) + AsyncOpRef>> fetchRepoListfromService( AsyncContextRef ctx, zypp::Pathname root_r, ServiceInfo service, ProgressObserverRef myProgress ) { if ( service.type() == zypp::repo::ServiceType::PLUGIN ) return ASyncFetchPluginService::run( std::move(ctx), std::move(root_r), std::move(service), std::move(myProgress) ); else - return SimpleExecutor >>>::run( std::move(ctx), std::move(root_r), std::move(service), std::move(myProgress) ); + return SimpleExecutor >>>::run( std::move(ctx), std::move(root_r), std::move(service), std::move(myProgress) ); } - expected> fetchRepoListfromService( SyncContextRef ctx, zypp::Pathname root_r, ServiceInfo service, ProgressObserverRef myProgress ) + expected> fetchRepoListfromService( SyncContextRef ctx, zypp::Pathname root_r, ServiceInfo service, ProgressObserverRef myProgress ) { if ( service.type() == zypp::repo::ServiceType::PLUGIN ) return SyncFetchPluginService::run( std::move(ctx), std::move(root_r), std::move(service), std::move(myProgress) ); else - return SimpleExecutor >>>::run( std::move(ctx), std::move(root_r), std::move(service), std::move(myProgress) ); + return SimpleExecutor >>>::run( std::move(ctx), std::move(root_r), std::move(service), std::move(myProgress) ); } @@ -263,11 +266,11 @@ namespace zyppng::RepoServicesWorkflow { template auto probeServiceLogic( ContextRefType ctx, const zypp::Url &url ) { - constexpr bool isAsync = std::is_same_v; + constexpr bool isAsync = std::is_same_v; using MediaHandle = std::conditional_t; using ProvideRes = std::conditional_t; - return ctx->provider()->attachMedia( url, ProvideMediaSpec() ) + return ctx->provider()->attachMedia( url, ProvideMediaSpec( ctx ) ) | and_then( [ctx]( MediaHandle medium ) { return ctx->provider()->provide( medium, "/repo/repoindex.xml", ProvideFileSpec().setCheckExistsOnly()); } ) | [url]( expected result ) { if ( result ) @@ -303,7 +306,7 @@ namespace zyppng::RepoServicesWorkflow { } } - AsyncOpRef > probeServiceType(ContextRef ctx, const zypp::Url &url) + AsyncOpRef > probeServiceType(AsyncContextRef ctx, const zypp::Url &url) { return probeServiceLogic( std::move(ctx), url ); } @@ -321,14 +324,16 @@ namespace zyppng::RepoServicesWorkflow { ZYPP_ENABLE_LOGIC_BASE(Executor, OpType); public: - using ZyppContextRefType = std::conditional_t, ContextRef, SyncContextRef >; - using RepoMgrRefType = RepoManagerRef; + using ZyppContextType = std::conditional_t, AsyncContext, SyncContext >; + using ZyppContextRefType = Ref; + using RepoMgrRefType = RepoManagerRef; using Ret = expected; - RefreshServiceLogic( RepoMgrRefType &&repoMgr, zypp::ServiceInfo &&info, zypp::RepoManager::RefreshServiceOptions options ) + RefreshServiceLogic( RepoMgrRefType &&repoMgr, ServiceInfo &&info, zypp::RepoManagerFlags::RefreshServiceOptions options ) : _repoMgr( std::move(repoMgr) ) , _service( std::move(info) ) , _options(options) + , _urlCredentialExtractor( _repoMgr->zyppContext() ) { } MaybeAsyncRef> probeServiceIfNeeded() { @@ -357,7 +362,7 @@ namespace zyppng::RepoServicesWorkflow { MIL << "Going to refresh service '" << _service.alias() << "', url: " << _service.url() << ", opts: " << _options << std::endl; - if ( _service.ttl() && !( _options.testFlag( zypp::RepoManager::RefreshService_forceRefresh) || _options.testFlag( zypp::RepoManager::RefreshService_restoreStatus ) ) ) + if ( _service.ttl() && !( _options.testFlag( zypp::RepoManagerFlags::RefreshService_forceRefresh) || _options.testFlag( zypp::RepoManagerFlags::RefreshService_restoreStatus ) ) ) { // Service defines a TTL; maybe we can re-use existing data without refresh. zypp::Date lrf = _service.lrf(); @@ -389,7 +394,7 @@ namespace zyppng::RepoServicesWorkflow { // to ServiceRepos. return fetchRepoListfromService( _repoMgr->zyppContext(), _repoMgr->options().rootDir, _service, nullptr ); } ) - | [this]( expected> serviceReposExp ) { + | [this]( expected> serviceReposExp ) { if ( !serviceReposExp ) { try { @@ -400,11 +405,11 @@ namespace zyppng::RepoServicesWorkflow { _informalError = e; } catch ( ... ) { // all other errors cancel the operation - return Ret::error( ZYPP_FWD_CURRENT_EXCPT() ); + return makeReadyResult(Ret::error( ZYPP_FWD_CURRENT_EXCPT() )); } } - std::pair serviceRepos = serviceReposExp.is_valid() ? std::move( serviceReposExp.get() ) : std::make_pair( _service, RepoInfoList{} ); + std::pair serviceRepos = serviceReposExp.is_valid() ? std::move( serviceReposExp.get() ) : std::make_pair( _service, RepoInfoList{} ); // get target distro identifier std::string servicesTargetDistro = _repoMgr->options().servicesTargetDistro; @@ -478,12 +483,11 @@ namespace zyppng::RepoServicesWorkflow { //////////////////////////////////////////////////////////////////////////// // Now compare collected repos with the ones in the system... // - RepoInfoList oldRepos; - _repoMgr->getRepositoriesInService( _service.alias(), std::back_inserter( oldRepos ) ); + _repoMgr->getRepositoriesInService( _service.alias(), std::back_inserter( _oldRepos ) ); //////////////////////////////////////////////////////////////////////////// // find old repositories to remove... - for_( oldRepo, oldRepos.begin(), oldRepos.end() ) + for_( oldRepo, _oldRepos.begin(), _oldRepos.end() ) { if ( ! foundAliasIn( oldRepo->alias(), collector.repos ) ) { @@ -504,224 +508,232 @@ namespace zyppng::RepoServicesWorkflow { DBG << "Service removes disabled repo " << oldRepo->alias() << std::endl; auto remRes = _repoMgr->removeRepository( *oldRepo ); - if ( !remRes ) return Ret::error( remRes.error() ); + if ( !remRes ) return makeReadyResult(Ret::error( remRes.error() )); } } - //////////////////////////////////////////////////////////////////////////// // create missing repositories and modify existing ones if needed... - zypp::UrlCredentialExtractor urlCredentialExtractor( _repoMgr->options().rootDir ); // To collect any credentials stored in repo URLs - for_( it, collector.repos.begin(), collector.repos.end() ) - { - // User explicitly requested the repo being enabled? - // User explicitly requested the repo being disabled? - // And hopefully not both ;) If so, enable wins. - - zypp::TriBool toBeEnabled( zypp::indeterminate ); // indeterminate - follow the service request - DBG << "Service request to " << (it->enabled()?"enable":"disable") << " service repo " << it->alias() << std::endl; - - if ( _options.testFlag( zypp::RepoManagerFlags::RefreshService_restoreStatus ) ) - { - DBG << "Opt RefreshService_restoreStatus " << it->alias() << std::endl; - // this overrides any pending request! - // Remove from enable request list. - // NOTE: repoToDisable is handled differently. - // It gets cleared on each refresh. - _service.delRepoToEnable( it->alias() ); - // toBeEnabled stays indeterminate! - } - else - { - if ( _service.repoToEnableFind( it->alias() ) ) + return std::move( collector.repos ) + | operators::transform_collect( [this]( RepoInfo info ){ return updateOrAddRepo(info); } ) + | and_then([this, newRepoStates = std::move(newRepoStates)]( auto ) mutable -> expected { + // Unlike reposToEnable, reposToDisable is always cleared after refresh. + if ( ! _service.reposToDisableEmpty() ) { - DBG << "User request to enable service repo " << it->alias() << std::endl; - toBeEnabled = true; - // Remove from enable request list. - // NOTE: repoToDisable is handled differently. - // It gets cleared on each refresh. - _service.delRepoToEnable( it->alias() ); + _service.clearReposToDisable(); _serviceModified = true; } - else if ( _service.repoToDisableFind( it->alias() ) ) + + // Remember original service request for next refresh + if ( _service.repoStates() != newRepoStates ) { - DBG << "User request to disable service repo " << it->alias() << std::endl; - toBeEnabled = false; + _service.setRepoStates( std::move(newRepoStates) ); + _serviceModified = true; } - } - - RepoInfoList::iterator oldRepo( findAlias( it->alias(), oldRepos ) ); - if ( oldRepo == oldRepos.end() ) - { - // Not found in oldRepos ==> a new repo to add - - // Make sure the service repo is created with the appropriate enablement - if ( ! indeterminate(toBeEnabled) ) - it->setEnabled( ( bool ) toBeEnabled ); - DBG << "Service adds repo " << it->alias() << " " << (it->enabled()?"enabled":"disabled") << std::endl; - const auto &addRes = _repoMgr->addRepository( *it ); - if (!addRes) return Ret::error( addRes.error() ); - } - else - { - // ==> an exising repo to check - bool oldRepoModified = false; - - if ( indeterminate(toBeEnabled) ) + //////////////////////////////////////////////////////////////////////////// + // save service if modified: (unless a plugin service) + if ( _service.type() != zypp::repo::ServiceType::PLUGIN ) { - // No user request: check for an old user modificaton otherwise follow service request. - // NOTE: Assert toBeEnabled is boolean afterwards! - if ( oldRepo->enabled() == it->enabled() ) - toBeEnabled = it->enabled(); // service requests no change to the system - else if ( _options.testFlag( zypp::RepoManagerFlags::RefreshService_restoreStatus ) ) + if ( _service.ttl() ) { - toBeEnabled = it->enabled(); // RefreshService_restoreStatus forced - DBG << "Opt RefreshService_restoreStatus " << it->alias() << " forces " << (toBeEnabled?"enabled":"disabled") << std::endl; + _service.setLrf( zypp::Date::now() ); // remember last refresh + _serviceModified = true; // or use a cookie file } - else + + if ( _serviceModified ) { - const auto & last = _service.repoStates().find( oldRepo->alias() ); - if ( last == _service.repoStates().end() || last->second.enabled != it->enabled() ) - toBeEnabled = it->enabled(); // service request has changed since last refresh -> follow - else - { - toBeEnabled = oldRepo->enabled(); // service request unchaned since last refresh -> keep user modification - DBG << "User modified service repo " << it->alias() << " may stay " << (toBeEnabled?"enabled":"disabled") << std::endl; - } + // write out modified service file. + auto modRes = _repoMgr->modifyService( _service.alias(), _service ); + if ( !modRes ) return Ret::error( modRes.error() ); } } - // changed enable? - if ( toBeEnabled == oldRepo->enabled() ) - { - DBG << "Service repo " << it->alias() << " stays " << (oldRepo->enabled()?"enabled":"disabled") << std::endl; - } - else if ( toBeEnabled ) - { - DBG << "Service repo " << it->alias() << " gets enabled" << std::endl; - oldRepo->setEnabled( true ); - oldRepoModified = true; - } - else - { - DBG << "Service repo " << it->alias() << " gets disabled" << std::endl; - oldRepo->setEnabled( false ); - oldRepoModified = true; + if ( _informalError ) { + return Ret::error( std::make_exception_ptr (_informalError.value()) ); } - // all other attributes follow the service request: + return Ret::success( ); + }); + }; + } - // changed name (raw!) - if ( oldRepo->rawName() != it->rawName() ) - { - DBG << "Service repo " << it->alias() << " gets new NAME " << it->rawName() << std::endl; - oldRepo->setName( it->rawName() ); - oldRepoModified = true; - } + MaybeAsyncRef> updateOrAddRepo( RepoInfo info ) + { + // User explicitly requested the repo being enabled? + // User explicitly requested the repo being disabled? + // And hopefully not both ;) If so, enable wins. + zypp::TriBool toBeEnabled( zypp::indeterminate ); // indeterminate - follow the service request + DBG << "Service request to " << (info.enabled()?"enable":"disable") << " service repo " << info.alias() << std::endl; - // changed autorefresh - if ( oldRepo->autorefresh() != it->autorefresh() ) - { - DBG << "Service repo " << it->alias() << " gets new AUTOREFRESH " << it->autorefresh() << std::endl; - oldRepo->setAutorefresh( it->autorefresh() ); - oldRepoModified = true; - } + if ( _options.testFlag( zypp::RepoManagerFlags::RefreshService_restoreStatus ) ) + { + DBG << "Opt RefreshService_restoreStatus " << info.alias() << std::endl; + // this overrides any pending request! + // Remove from enable request list. + // NOTE: repoToDisable is handled differently. + // It gets cleared on each refresh. + _service.delRepoToEnable( info.alias() ); + // toBeEnabled stays indeterminate! + } + else + { + if ( _service.repoToEnableFind( info.alias() ) ) + { + DBG << "User request to enable service repo " << info.alias() << std::endl; + toBeEnabled = true; + // Remove from enable request list. + // NOTE: repoToDisable is handled differently. + // It gets cleared on each refresh. + _service.delRepoToEnable( info.alias() ); + _serviceModified = true; + } + else if ( _service.repoToDisableFind( info.alias() ) ) + { + DBG << "User request to disable service repo " << info.alias() << std::endl; + toBeEnabled = false; + } + } - // changed priority? - if ( oldRepo->priority() != it->priority() ) - { - DBG << "Service repo " << it->alias() << " gets new PRIORITY " << it->priority() << std::endl; - oldRepo->setPriority( it->priority() ); - oldRepoModified = true; - } + RepoInfoList::iterator oldRepo( findAlias( info.alias(), _oldRepos ) ); + if ( oldRepo == _oldRepos.end() ) + { + // Not found in oldRepos ==> a new repo to add - // changed url? - { - RepoInfo::url_set newUrls( it->rawBaseUrls() ); - urlCredentialExtractor.extract( newUrls ); // Extract! to prevent passwds from disturbing the comparison below - if ( oldRepo->rawBaseUrls() != newUrls ) - { - DBG << "Service repo " << it->alias() << " gets new URLs " << newUrls << std::endl; - oldRepo->setBaseUrls( std::move(newUrls) ); - oldRepoModified = true; - } - } + // Make sure the service repo is created with the appropriate enablement + if ( ! indeterminate(toBeEnabled) ) + info.setEnabled( ( bool ) toBeEnabled ); - // changed gpg check settings? - // ATM only plugin services can set GPG values. - if ( _service.type() == zypp::repo::ServiceType::PLUGIN ) - { - zypp::TriBool ogpg[3]; // Gpg RepoGpg PkgGpg - zypp::TriBool ngpg[3]; - oldRepo->getRawGpgChecks( ogpg[0], ogpg[1], ogpg[2] ); - it-> getRawGpgChecks( ngpg[0], ngpg[1], ngpg[2] ); - #define Z_CHKGPG(I,N) \ - if ( ! sameTriboolState( ogpg[I], ngpg[I] ) ) \ - { \ - DBG << "Service repo " << it->alias() << " gets new "#N"Check " << ngpg[I] << std::endl; \ - oldRepo->set##N##Check( ngpg[I] ); \ - oldRepoModified = true; \ - } - Z_CHKGPG( 0, Gpg ); - Z_CHKGPG( 1, RepoGpg ); - Z_CHKGPG( 2, PkgGpg ); - #undef Z_CHKGPG - } + DBG << "Service adds repo " << info.alias() << " " << (info.enabled()?"enabled":"disabled") << std::endl; + return _repoMgr->addRepository( info ); + } + else + { + // ==> an exising repo to check + bool oldRepoModified = false; - // save if modified: - if ( oldRepoModified ) + if ( indeterminate(toBeEnabled) ) + { + // No user request: check for an old user modificaton otherwise follow service request. + // NOTE: Assert toBeEnabled is boolean afterwards! + if ( oldRepo->enabled() == info.enabled() ) + toBeEnabled = info.enabled(); // service requests no change to the system + else if ( _options.testFlag( zypp::RepoManagerFlags::RefreshService_restoreStatus ) ) + { + toBeEnabled = info.enabled(); // RefreshService_restoreStatus forced + DBG << "Opt RefreshService_restoreStatus " << info.alias() << " forces " << (toBeEnabled?"enabled":"disabled") << std::endl; + } + else + { + const auto & last = _service.repoStates().find( oldRepo->alias() ); + if ( last == _service.repoStates().end() || last->second.enabled != info.enabled() ) + toBeEnabled = info.enabled(); // service request has changed since last refresh -> follow + else { - auto modRes = _repoMgr->modifyRepository( oldRepo->alias(), *oldRepo ); - if ( !modRes ) return Ret::error( modRes.error() ); + toBeEnabled = oldRepo->enabled(); // service request unchaned since last refresh -> keep user modification + DBG << "User modified service repo " << info.alias() << " may stay " << (toBeEnabled?"enabled":"disabled") << std::endl; } } } - // Unlike reposToEnable, reposToDisable is always cleared after refresh. - if ( ! _service.reposToDisableEmpty() ) + // changed enable? + if ( toBeEnabled == oldRepo->enabled() ) { - _service.clearReposToDisable(); - _serviceModified = true; + DBG << "Service repo " << info.alias() << " stays " << (oldRepo->enabled()?"enabled":"disabled") << std::endl; + } + else if ( toBeEnabled ) + { + DBG << "Service repo " << info.alias() << " gets enabled" << std::endl; + oldRepo->setEnabled( true ); + oldRepoModified = true; + } + else + { + DBG << "Service repo " << info.alias() << " gets disabled" << std::endl; + oldRepo->setEnabled( false ); + oldRepoModified = true; } - // Remember original service request for next refresh - if ( _service.repoStates() != newRepoStates ) + // all other attributes follow the service request: + + // changed name (raw!) + if ( oldRepo->rawName() != info.rawName() ) { - _service.setRepoStates( std::move(newRepoStates) ); - _serviceModified = true; + DBG << "Service repo " << info.alias() << " gets new NAME " << info.rawName() << std::endl; + oldRepo->setName( info.rawName() ); + oldRepoModified = true; } - //////////////////////////////////////////////////////////////////////////// - // save service if modified: (unless a plugin service) - if ( _service.type() != zypp::repo::ServiceType::PLUGIN ) + // changed autorefresh + if ( oldRepo->autorefresh() != info.autorefresh() ) { - if ( _service.ttl() ) - { - _service.setLrf( zypp::Date::now() ); // remember last refresh - _serviceModified = true; // or use a cookie file - } + DBG << "Service repo " << info.alias() << " gets new AUTOREFRESH " << info.autorefresh() << std::endl; + oldRepo->setAutorefresh( info.autorefresh() ); + oldRepoModified = true; + } - if ( _serviceModified ) + // changed priority? + if ( oldRepo->priority() != info.priority() ) + { + DBG << "Service repo " << info.alias() << " gets new PRIORITY " << info.priority() << std::endl; + oldRepo->setPriority( info.priority() ); + oldRepoModified = true; + } + + // changed url? + { + RepoInfo::url_set newUrls( info.rawBaseUrls() ); + _urlCredentialExtractor.extract( newUrls ); // Extract! to prevent passwds from disturbing the comparison below + if ( oldRepo->rawBaseUrls() != newUrls ) { - // write out modified service file. - auto modRes = _repoMgr->modifyService( _service.alias(), _service ); - if ( !modRes ) return Ret::error( modRes.error() ); + DBG << "Service repo " << info.alias() << " gets new URLs " << newUrls << std::endl; + oldRepo->setBaseUrls( std::move(newUrls) ); + oldRepoModified = true; } } - if ( _informalError ) { - return Ret::error( std::make_exception_ptr (_informalError.value()) ); + // changed gpg check settings? + // ATM only plugin services can set GPG values. + if ( _service.type() == zypp::repo::ServiceType::PLUGIN ) + { + zypp::TriBool ogpg[3]; // Gpg RepoGpg PkgGpg + zypp::TriBool ngpg[3]; + oldRepo->getRawGpgChecks( ogpg[0], ogpg[1], ogpg[2] ); + info. getRawGpgChecks( ngpg[0], ngpg[1], ngpg[2] ); + +#define Z_CHKGPG(I,N) \ + if ( ! sameTriboolState( ogpg[I], ngpg[I] ) ) \ + { \ + DBG << "Service repo " << info.alias() << " gets new "#N"Check " << ngpg[I] << std::endl; \ + oldRepo->set##N##Check( ngpg[I] ); \ + oldRepoModified = true; \ + } + + Z_CHKGPG( 0, Gpg ); + Z_CHKGPG( 1, RepoGpg ); + Z_CHKGPG( 2, PkgGpg ); +#undef Z_CHKGPG } - return Ret::success( ); - }; + // save if modified: + if ( oldRepoModified ) { + return makeReadyResult( _repoMgr->modifyRepository( oldRepo->alias(), *oldRepo ) ); + } else { + // nothing to do + return makeReadyResult( make_expected_success(*oldRepo) ); + } + } } + RepoMgrRefType _repoMgr; - zypp::ServiceInfo _service; - zypp::RepoManager::RefreshServiceOptions _options; + ServiceInfo _service; + zypp::RepoManagerFlags::RefreshServiceOptions _options; + zypp::UrlCredentialExtractor _urlCredentialExtractor; // To collect any credentials stored in repo URLs + + // working variable so we do not have to store the oldRepos multiple times + RepoInfoList _oldRepos; // NOTE: It might be necessary to modify and rewrite the service info. // Either when probing the type, or when adjusting the repositories diff --git a/zypp/ng/repo/workflows/serviceswf.h b/zypp/ng/repo/workflows/serviceswf.h index 15111ee7d0..5bb7dfe39f 100644 --- a/zypp/ng/repo/workflows/serviceswf.h +++ b/zypp/ng/repo/workflows/serviceswf.h @@ -19,23 +19,21 @@ #include #include - +#include namespace zyppng { - ZYPP_FWD_DECL_TYPE_WITH_REFS (Context); - ZYPP_FWD_DECL_TYPE_WITH_REFS (SyncContext); ZYPP_FWD_DECL_TYPE_WITH_REFS (ProgressObserver); namespace RepoServicesWorkflow { - AsyncOpRef>> fetchRepoListfromService( ContextRef ctx, zypp::Pathname root_r, ServiceInfo service, ProgressObserverRef myProgress = nullptr ); - expected> fetchRepoListfromService( SyncContextRef ctx, zypp::Pathname root_r, ServiceInfo service, ProgressObserverRef myProgress = nullptr ); + AsyncOpRef>> fetchRepoListfromService( AsyncContextRef ctx, zypp::Pathname root_r, ServiceInfo service, ProgressObserverRef myProgress = nullptr ); + expected> fetchRepoListfromService( SyncContextRef ctx, zypp::Pathname root_r, ServiceInfo service, ProgressObserverRef myProgress = nullptr ); - AsyncOpRef > probeServiceType( ContextRef ctx, const zypp::Url &url ); + AsyncOpRef > probeServiceType( AsyncContextRef ctx, const zypp::Url &url ); expected probeServiceType ( SyncContextRef ctx, const zypp::Url &url ); - AsyncOpRef> refreshService ( AsyncRepoManagerRef repoMgr, zypp::ServiceInfo info, zypp::RepoManagerFlags::RefreshServiceOptions options ); - expected refreshService ( SyncRepoManagerRef repoMgr, zypp::ServiceInfo info, zypp::RepoManagerFlags::RefreshServiceOptions options ); + AsyncOpRef> refreshService ( AsyncRepoManagerRef repoMgr, ServiceInfo info, zypp::RepoManagerFlags::RefreshServiceOptions options ); + expected refreshService ( SyncRepoManagerRef repoMgr, ServiceInfo info, zypp::RepoManagerFlags::RefreshServiceOptions options ); } } // namespace zyppng; diff --git a/zypp/ng/repo/workflows/susetags.cc b/zypp/ng/repo/workflows/susetags.cc index 1122d1ee69..f46cf86ea1 100644 --- a/zypp/ng/repo/workflows/susetags.cc +++ b/zypp/ng/repo/workflows/susetags.cc @@ -18,7 +18,7 @@ #include #include -#include + #include #include @@ -48,8 +48,9 @@ namespace zyppng::SuseTagsWorkflows { using MediaHandle = typename ProvideType::MediaHandle; using ProvideRes = typename ProvideType::Res; - StatusLogic( DlContextRefType ctx, MediaHandle &&media ) + StatusLogic( DlContextRefType ctx, ProgressObserverRef &&taskObserver, MediaHandle &&media ) : _ctx(std::move(ctx)) + , _taskObserver( std::move(taskObserver) ) , _handle(std::move(media)) {} @@ -77,18 +78,19 @@ namespace zyppng::SuseTagsWorkflows { } DlContextRefType _ctx; + ProgressObserverRef _taskObserver; MediaHandle _handle; }; } - AsyncOpRef > repoStatus(repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle) + AsyncOpRef > repoStatus(repo::AsyncDownloadContextRef dl, ProgressObserverRef taskObserver, ProvideMediaHandle mediaHandle) { - return SimpleExecutor< StatusLogic, AsyncOp> >::run( std::move(dl), std::move(mediaHandle) ); + return SimpleExecutor< StatusLogic, AsyncOp> >::run( std::move(dl), std::move(taskObserver), std::move(mediaHandle) ); } - expected repoStatus(repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle) + expected repoStatus(repo::SyncDownloadContextRef dl, ProgressObserverRef taskObserver, SyncMediaHandle mediaHandle) { - return SimpleExecutor< StatusLogic, SyncOp> >::run( std::move(dl), std::move(mediaHandle) ); + return SimpleExecutor< StatusLogic, SyncOp> >::run( std::move(dl), std::move(taskObserver), std::move(mediaHandle) ); } @@ -293,7 +295,7 @@ namespace zyppng::SuseTagsWorkflows { return transform_collect ( std::move(requiredFiles), [this]( zypp::OnMediaLocation file ) { - return DownloadWorkflow::provideToCacheDir( _ctx, _mediaHandle, file.filename(), ProvideFileSpec(file) ) + return DownloadWorkflow::provideToCacheDir( _ctx, _progressObserver, _mediaHandle, file.filename(), ProvideFileSpec(file) ) | inspect ( incProgress( _progressObserver ) ); }) | and_then ( [this]( std::vector &&dlFiles ) { @@ -308,7 +310,7 @@ namespace zyppng::SuseTagsWorkflows { private: - const zypp::RepoInfo &repoInfo() const { + const RepoInfo &repoInfo() const { return _ctx->repoInfo(); } @@ -327,12 +329,12 @@ namespace zyppng::SuseTagsWorkflows { }; } - AsyncOpRef > download(repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver) + AsyncOpRef > download(repo::AsyncDownloadContextRef dl, ProgressObserverRef progressObserver, ProvideMediaHandle mediaHandle) { return SimpleExecutor< DlLogic, AsyncOp> >::run( std::move(dl), std::move(mediaHandle), std::move(progressObserver) ); } - expected download(repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle, ProgressObserverRef progressObserver) + expected download(repo::SyncDownloadContextRef dl, ProgressObserverRef progressObserver, SyncMediaHandle mediaHandle) { return SimpleExecutor< DlLogic, SyncOp> >::run( std::move(dl), std::move(mediaHandle), std::move(progressObserver) ); } diff --git a/zypp/ng/repo/workflows/susetags.h b/zypp/ng/repo/workflows/susetags.h index eb400a6c0e..b7e7cbf743 100644 --- a/zypp/ng/repo/workflows/susetags.h +++ b/zypp/ng/repo/workflows/susetags.h @@ -33,14 +33,14 @@ namespace zyppng { /*! * Calculate status of the remote SUSETags repository */ - AsyncOpRef> repoStatus( repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle ); - expected repoStatus( repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle ); + AsyncOpRef> repoStatus(repo::AsyncDownloadContextRef dl, ProgressObserverRef taskObserver, ProvideMediaHandle mediaHandle ); + expected repoStatus(repo::SyncDownloadContextRef dl, ProgressObserverRef taskObserver, SyncMediaHandle mediaHandle ); /*! * Download metadata to a local directory */ - AsyncOpRef> download ( repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver = nullptr ); - expected download ( repo::SyncDownloadContextRef dl, SyncMediaHandle mediaHandle, ProgressObserverRef progressObserver = nullptr ); + AsyncOpRef> download ( repo::AsyncDownloadContextRef dl, ProgressObserverRef progressObserver, ProvideMediaHandle mediaHandle ); + expected download ( repo::SyncDownloadContextRef dl, ProgressObserverRef progressObserver, SyncMediaHandle mediaHandle ); } } diff --git a/zypp/ng/repoinfo.cc b/zypp/ng/repoinfo.cc new file mode 100644 index 0000000000..31b89bab20 --- /dev/null +++ b/zypp/ng/repoinfo.cc @@ -0,0 +1,989 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/ng/repoinfo.cc + * +*/ + +#include "repoinfo.h" + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "repoinfoshareddata.h" +#include "zypp/repo/SUSEMediaVerifier.h" + +using std::endl; +using zypp::xml::escape; + +namespace zyppng { + + namespace + { + zypp::repo::RepoType probeCache( const zypp::Pathname & path_r ) + { + zypp::repo::RepoType ret = zypp::repo::RepoType::NONE; + if ( zypp::PathInfo(path_r).isDir() ) + { + if ( zypp::PathInfo(path_r/"/repodata/repomd.xml").isFile() ) + { ret = zypp::repo::RepoType::RPMMD; } + else if ( zypp::PathInfo(path_r/"/content").isFile() ) + { ret = zypp::repo::RepoType::YAST2; } + else if ( zypp::PathInfo(path_r/"/cookie").isFile() ) + { ret = zypp::repo::RepoType::RPMPLAINDIR; } + } + DBG << "Probed cached type " << ret << " at " << path_r << endl; + return ret; + } + } // + + RepoInfoSharedData::RepoInfoSharedData( zyppng::ContextBaseRef &&context ) + : RepoInfoBaseSharedData( std::move(context) ) + , _rawGpgCheck( zypp::indeterminate ) + , _rawRepoGpgCheck( zypp::indeterminate ) + , _rawPkgGpgCheck( zypp::indeterminate ) + , _validRepoSignature( zypp::indeterminate ) + , _type(zypp::repo::RepoType::NONE_e) + , keeppackages(zypp::indeterminate) + , _mirrorListForceMetalink(false) + , emptybaseurls(false) + { RepoInfoSharedData::bindVariables(); } + + void RepoInfoSharedData::bindVariables() + { + repo::RepoInfoBaseSharedData::bindVariables(); + if ( _ctx ) { + _mirrorListUrl.setTransformator( repo::RepoVariablesUrlReplacer( zypp::repo::RepoVarRetriever( *_ctx.get() ) ) ); + _baseUrls.setTransformator( repo::RepoVariablesUrlReplacer( zypp::repo::RepoVarRetriever( *_ctx.get() ) ) ); + _gpgKeyUrls.setTransformator( repo::RepoVariablesUrlReplacer( zypp::repo::RepoVarRetriever( *_ctx.get() ) ) ); + } else { + _mirrorListUrl.setTransformator( repo::RepoVariablesUrlReplacer( nullptr ) ); + _baseUrls.setTransformator( repo::RepoVariablesUrlReplacer( nullptr ) ); + _gpgKeyUrls.setTransformator( repo::RepoVariablesUrlReplacer( nullptr ) ); + } + } + + void RepoInfoSharedData::setType(const zypp::repo::RepoType &t) + { _type = t; } + + void RepoInfoSharedData::setProbedType(const zypp::repo::RepoType &t) const + { + if (_type == zypp::repo::RepoType::NONE && + t != zypp::repo::RepoType::NONE) { + const_cast(this)->_type = t; + } + } + + zypp::repo::RepoType RepoInfoSharedData::type() const + { + if ( _type == zypp::repo::RepoType::NONE && !metadataPath().empty() ) + setProbedType( probeCache( metadataPath() / path ) ); + return _type; + } + + /** Path to a license tarball in case it exists in the repo. */ + zypp::Pathname RepoInfoSharedData::licenseTgz(const std::string &name_r) const + { + zypp::Pathname ret; + if (!metadataPath().empty()) { + std::string licenseStem("license"); + if (!name_r.empty()) { + licenseStem += "-"; + licenseStem += name_r; + } + + zypp::filesystem::Glob g; + // TODO: REPOMD: this assumes we know the name of the tarball. In fact + // we'd need to get the file from repomd.xml () + g.add(metadataPath() / path / ("repodata/*" + licenseStem + ".tar.gz")); + if (g.empty()) + g.add(metadataPath() / path / (licenseStem + ".tar.gz")); + + if (!g.empty()) + ret = *g.begin(); + } + return ret; + } + + const RepoVariablesReplacedUrlList & RepoInfoSharedData::baseUrls() const + { + const zypp::Url &mlurl(_mirrorListUrl.transformed()); // Variables replaced! + if (_baseUrls.empty() && !mlurl.asString().empty()) { + emptybaseurls = true; + DBG << "MetadataPath: " << metadataPath() << endl; + zypp::repo::RepoMirrorList rmurls(_ctx, mlurl, metadataPath(), + _mirrorListForceMetalink); + _baseUrls.raw().insert(_baseUrls.raw().end(), rmurls.getUrls().begin(), + rmurls.getUrls().end()); + } + return _baseUrls; + } + + RepoVariablesReplacedUrlList &RepoInfoSharedData::baseUrls() + { + return _baseUrls; + } + + bool RepoInfoSharedData::baseurl2dump() const + { + return !emptybaseurls && !_baseUrls.empty(); + } + + const RepoVariablesReplacedUrlList &RepoInfoSharedData::gpgKeyUrls() const + { + return _gpgKeyUrls; + } + + RepoVariablesReplacedUrlList &RepoInfoSharedData::gpgKeyUrls() + { + return _gpgKeyUrls; + } + + const std::set &RepoInfoSharedData::contentKeywords() const + { + hasContent() /*init if not yet done*/; + return _keywords.second; + } + + void RepoInfoSharedData::addContent(const std::string &keyword_r) + { + _keywords.second.insert(keyword_r); + if (!hasContent()) + _keywords.first = true; + } + + bool RepoInfoSharedData::hasContent() const + { + if (!_keywords.first && !metadataPath().empty()) { + // HACK directly check master index file until RepoManager offers + // some content probing and zypper uses it. + ///////////////////////////////////////////////////////////////// + MIL << "Empty keywords...." << metadataPath() << endl; + zypp::Pathname master; + if (zypp::PathInfo((master = metadataPath() / "/repodata/repomd.xml")) + .isFile()) { + // MIL << "GO repomd.." << endl; + zypp::xml::Reader reader(master); + while (reader.seekToNode(2, "content")) { + _keywords.second.insert(reader.nodeText().asString()); + reader.seekToEndNode(2, "content"); + } + _keywords.first = true; // valid content in _keywords even if empty + } else if (zypp::PathInfo((master = metadataPath() / "/content")).isFile()) { + // MIL << "GO content.." << endl; + zypp::iostr::forEachLine( + zypp::InputStream(master), + [this](int num_r, const std::string &line_r) -> bool { + if (zypp::str::startsWith(line_r, "REPOKEYWORDS")) { + std::vector words; + if (zypp::str::split(line_r, std::back_inserter(words)) > 1 && + words[0].length() == 12 /*"REPOKEYWORDS"*/) { + this->_keywords.second.insert(++words.begin(), words.end()); + } + return true; // mult. occurrances are ok. + } + return (!zypp::str::startsWith( + line_r, "META ")); // no need to parse into META section. + }); + _keywords.first = true; // valid content in _keywords even if empty + } + ///////////////////////////////////////////////////////////////// + } + return _keywords.first; + } + + bool RepoInfoSharedData::hasContent(const std::string &keyword_r) const + { + return (hasContent() && + _keywords.second.find(keyword_r) != _keywords.second.end()); + } + + zypp::TriBool RepoInfoSharedData::internalValidRepoSignature() const + { + if (!zypp::indeterminate(_validRepoSignature)) + return _validRepoSignature; + // check metadata: + if (!metadataPath().empty()) { + // A missing ".repo_gpgcheck" might be plaindir(no Downloader) or not yet + // refreshed signed repo! + zypp::TriBool linkval = triBoolFromPath(metadataPath() / ".repo_gpgcheck"); + return linkval; + } + return zypp::indeterminate; + } + + void RepoInfoSharedData::internalSetValidRepoSignature( zypp::TriBool value_r) + { + if (zypp::PathInfo(metadataPath()).isDir()) { + zypp::Pathname gpgcheckFile(metadataPath() / ".repo_gpgcheck"); + if (zypp::PathInfo(gpgcheckFile).isExist()) { + zypp::TriBool linkval(zypp::indeterminate); + if (triBoolFromPath(gpgcheckFile, linkval) && linkval == value_r) + return; // existing symlink fits value_r + else + zypp::filesystem::unlink(gpgcheckFile); // will write a new one + } + zypp::filesystem::symlink(zypp::asString(value_r), gpgcheckFile); + } + _validRepoSignature = value_r; + } + + bool RepoInfoSharedData::internalUnsignedConfirmed() const + { + zypp::TriBool linkval( + true); // want to see it being switched to zypp::indeterminate + return triBoolFromPath(metadataPath() / ".repo_gpgcheck", linkval) && + zypp::indeterminate(linkval); + } + + bool RepoInfoSharedData::triBoolFromPath(const zypp::Pathname &path_r, zypp::TriBool &ret_r) const + { + static const zypp::Pathname truePath("true"); + static const zypp::Pathname falsePath("false"); + static const zypp::Pathname indeterminatePath("zypp::indeterminate"); + + // Quiet readlink; + static const ssize_t bufsiz = 63; + static char buf[bufsiz + 1]; + ssize_t ret = ::readlink(path_r.c_str(), buf, bufsiz); + buf[ret == -1 ? 0 : ret] = '\0'; + + zypp::Pathname linkval(buf); + + bool known = true; + if (linkval == truePath) + ret_r = true; + else if (linkval == falsePath) + ret_r = false; + else if (linkval == indeterminatePath) + ret_r = zypp::indeterminate; + else + known = false; + return known; + } + + zypp::TriBool RepoInfoSharedData::triBoolFromPath(const zypp::Pathname &path_r) const + { + zypp::TriBool ret(zypp::indeterminate); + triBoolFromPath(path_r, ret); + return ret; + } + + bool RepoInfoSharedData::cfgGpgCheck() const + { + const zypp::ZConfig *zConf = nullptr; + if (!this->_ctx) { + MIL << "RepoInfo has no context, returning default setting for " + "cfgRepoGpgCheck!" + << std::endl; + zConf = &zypp::ZConfig::defaults(); + } else { + zConf = &this->_ctx->config(); + } + return zypp::indeterminate(_rawGpgCheck) ? zConf->gpgCheck() + : (bool)_rawGpgCheck; + } + + zypp::TriBool RepoInfoSharedData::cfgRepoGpgCheck() const + { + const zypp::ZConfig *zConf = nullptr; + if (!this->_ctx) { + MIL << "RepoInfo has no context, returning default setting for " + "cfgRepoGpgCheck!" + << std::endl; + zConf = &zypp::ZConfig::defaults(); + } else { + zConf = &this->_ctx->config(); + } + return zypp::indeterminate(_rawGpgCheck) && + zypp::indeterminate(_rawRepoGpgCheck) + ? zConf->repoGpgCheck() + : _rawRepoGpgCheck; + } + + zypp::TriBool RepoInfoSharedData::cfgPkgGpgCheck() const + { + const zypp::ZConfig *zConf = nullptr; + if (!this->_ctx) { + MIL << "RepoInfo has no context, returning default setting for " + "cfgRepoGpgCheck!" + << std::endl; + zConf = &zypp::ZConfig::defaults(); + } else { + zConf = &this->_ctx->config(); + } + return zypp::indeterminate(_rawGpgCheck) && + zypp::indeterminate(_rawPkgGpgCheck) + ? zConf->pkgGpgCheck() + : _rawPkgGpgCheck; + } + + void RepoInfoSharedData::solvPath(zypp::Pathname new_r) { + _slvPath = std::move(new_r); + } + + void RepoInfoSharedData::metadataPath(zypp::Pathname new_r) { + _metadataPath = std::move(new_r); + } + + void RepoInfoSharedData::packagesPath(zypp::Pathname new_r) { + _packagesPath = std::move(new_r); + } + + bool RepoInfoSharedData::usesAutoMetadataPaths() const + { + return zypp::str::hasSuffix(_metadataPath.asString(), "/%AUTO%"); + } + + zypp::Pathname RepoInfoSharedData::solvPath() const + { + if (usesAutoMetadataPaths()) + return _metadataPath.dirname() / "%SLV%"; + return _slvPath; + } + + zypp::Pathname RepoInfoSharedData::metadataPath() const + { + if (usesAutoMetadataPaths()) + return _metadataPath.dirname() / "%RAW%"; + return _metadataPath; + } + + zypp::Pathname RepoInfoSharedData::packagesPath() const + { + if (_packagesPath.empty() && usesAutoMetadataPaths()) + return _metadataPath.dirname() / "%PKG%"; + return _packagesPath; + } + + RepoInfoSharedData *RepoInfoSharedData::clone() const + { + auto *n = new RepoInfoSharedData(*this); + n->bindVariables (); + return n; + } + + /////////////////////////////////////////////////////////////////// + + /** \relates RepoInfo::Impl Stream output */ + inline std::ostream & operator<<( std::ostream & str, const RepoInfo::Impl & obj ) + { + return str << "RepoInfo::Impl"; + } + + RepoInfo::RepoInfo( zyppng::ContextBaseRef context ) + : RepoInfoBase( *( new RepoInfoSharedData( std::move(context) ) ) ) + {} + + RepoInfo::~RepoInfo() + {} + + unsigned RepoInfo::priority() const + { return pimpl()->priority; } + + const std::optional &RepoInfo::nullRepo() + { + static std::optional _nullRepo; + return _nullRepo; + } + + unsigned RepoInfo::defaultPriority() + { return RepoInfoSharedData::defaultPriority; } + + unsigned RepoInfo::noPriority() + { return RepoInfoSharedData::noPriority; } + + void RepoInfo::setPriority( unsigned newval_r ) + { pimpl()->priority = newval_r ? newval_r : RepoInfoSharedData::defaultPriority; } + + bool RepoInfo::gpgCheck() const + { return pimpl()->cfgGpgCheck(); } + + void RepoInfo::setGpgCheck( zypp::TriBool value_r ) + { pimpl()->rawGpgCheck( value_r ); } + + bool RepoInfo::repoGpgCheck() const + { return gpgCheck() || bool(pimpl()->cfgRepoGpgCheck()); } + + bool RepoInfo::repoGpgCheckIsMandatory() const + { + bool ret = ( gpgCheck() && indeterminate(pimpl()->cfgRepoGpgCheck()) ) || bool(pimpl()->cfgRepoGpgCheck()); + if ( ret && pimpl()->internalUnsignedConfirmed() ) // relax if unsigned repo was confirmed in the past + ret = false; + return ret; + } + + void RepoInfo::setRepoGpgCheck( zypp::TriBool value_r ) + { pimpl()->rawRepoGpgCheck( value_r ); } + + + bool RepoInfo::pkgGpgCheck() const + { return bool(pimpl()->cfgPkgGpgCheck()) || ( gpgCheck() && !bool(validRepoSignature())/*enforced*/ ) ; } + + bool RepoInfo::pkgGpgCheckIsMandatory() const + { return bool(pimpl()->cfgPkgGpgCheck()) || ( gpgCheck() && indeterminate(pimpl()->cfgPkgGpgCheck()) && !bool(validRepoSignature())/*enforced*/ ); } + + void RepoInfo::setPkgGpgCheck( zypp::TriBool value_r ) + { pimpl()->rawPkgGpgCheck( value_r ); } + + + void RepoInfo::getRawGpgChecks( zypp::TriBool & g_r, zypp::TriBool & r_r, zypp::TriBool & p_r ) const + { + g_r = pimpl()->rawGpgCheck(); + r_r = pimpl()->rawRepoGpgCheck(); + p_r = pimpl()->rawPkgGpgCheck(); + } + + void RepoInfo::setContext( zyppng::ContextBaseRef context ) + { + pimpl()->switchContext(context); + } + + RepoInfoSharedData *RepoInfo::pimpl() + { + return static_cast(_pimpl.get()); + } + + const RepoInfoSharedData *RepoInfo::pimpl() const + { + return static_cast( _pimpl.get() ); + } + + zypp::TriBool RepoInfo::validRepoSignature() const + { + zypp::TriBool ret( pimpl()->internalValidRepoSignature() ); + if ( ret && !repoGpgCheck() ) ret = false; // invalidate any old signature if repoGpgCheck is off + return ret; + } + + void RepoInfo::setValidRepoSignature( zypp::TriBool value_r ) + { pimpl()->internalSetValidRepoSignature( value_r ); } + + /////////////////////////////////////////////////////////////////// + namespace + { + inline bool changeGpgCheckTo( zypp::TriBool & lhs, zypp::TriBool rhs ) + { if ( ! sameTriboolState( lhs, rhs ) ) { lhs = rhs; return true; } return false; } + + inline bool changeGpgCheckTo( zypp::TriBool ogpg[3], zypp::TriBool g, zypp::TriBool r, zypp::TriBool p ) + { + bool changed = false; + if ( changeGpgCheckTo( ogpg[0], g ) ) changed = true; + if ( changeGpgCheckTo( ogpg[1], r ) ) changed = true; + if ( changeGpgCheckTo( ogpg[2], p ) ) changed = true; + return changed; + } + } // namespace + /////////////////////////////////////////////////////////////////// + bool RepoInfo::setGpgCheck( GpgCheck mode_r ) + { + zypp::TriBool ogpg[3]; // Gpg RepoGpg PkgGpg + getRawGpgChecks( ogpg[0], ogpg[1], ogpg[2] ); + + bool changed = false; + switch ( mode_r ) + { + case GpgCheck::On: + changed = changeGpgCheckTo( ogpg, true, zypp::indeterminate, zypp::indeterminate ); + break; + case GpgCheck::Strict: + changed = changeGpgCheckTo( ogpg, true, true, true ); + break; + case GpgCheck::AllowUnsigned: + changed = changeGpgCheckTo( ogpg, true, false, false ); + break; + case GpgCheck::AllowUnsignedRepo: + changed = changeGpgCheckTo( ogpg, true, false, zypp::indeterminate ); + break; + case GpgCheck::AllowUnsignedPackage: + changed = changeGpgCheckTo( ogpg, true, zypp::indeterminate, false ); + break; + case GpgCheck::Default: + changed = changeGpgCheckTo( ogpg, zypp::indeterminate, zypp::indeterminate, zypp::indeterminate ); + break; + case GpgCheck::Off: + changed = changeGpgCheckTo( ogpg, false, zypp::indeterminate, zypp::indeterminate ); + break; + case GpgCheck::indeterminate: // no change + break; + } + + if ( changed ) + { + setGpgCheck ( ogpg[0] ); + setRepoGpgCheck( ogpg[1] ); + setPkgGpgCheck ( ogpg[2] ); + } + return changed; + } + + void RepoInfo::setMirrorListUrl( const zypp::Url & url_r ) // Raw + { pimpl()->_mirrorListUrl.raw() = url_r; pimpl()->_mirrorListForceMetalink = false; } + + void RepoInfo::setMirrorListUrls( url_set urls ) // Raw + { setMirrorListUrl( urls.empty() ? zypp::Url() : urls.front() ); } + + void RepoInfo::setMetalinkUrl( const zypp::Url & url_r ) // Raw + { pimpl()->_mirrorListUrl.raw() = url_r; pimpl()->_mirrorListForceMetalink = true; } + + void RepoInfo::setMetalinkUrls( url_set urls ) // Raw + { setMetalinkUrl( urls.empty() ? zypp::Url() : urls.front() ); } + + void RepoInfo::setGpgKeyUrls( url_set urls ) + { pimpl()->gpgKeyUrls().raw().swap( urls ); } + + void RepoInfo::setGpgKeyUrl( const zypp::Url & url_r ) + { + pimpl()->gpgKeyUrls().raw().clear(); + pimpl()->gpgKeyUrls().raw().push_back( url_r ); + } + + void RepoInfo::addBaseUrl( zypp::Url url_r ) + { + for ( const auto & url : pimpl()->baseUrls().raw() ) // Raw unique! + if ( url == url_r ) + return; + pimpl()->baseUrls().raw().push_back( std::move(url_r) ); + } + + void RepoInfo::setBaseUrl( zypp::Url url_r ) + { + pimpl()->baseUrls().raw().clear(); + pimpl()->baseUrls().raw().push_back( std::move(url_r) ); + } + + void RepoInfo::setBaseUrls( url_set urls ) + { pimpl()->baseUrls().raw().swap( urls ); } + + void RepoInfo::setPath( const zypp::Pathname &path ) + { pimpl()->path = path; } + + void RepoInfo::setType( const zypp::repo::RepoType &t ) + { pimpl()->setType( t ); } + + void RepoInfo::setProbedType( const zypp::repo::RepoType &t ) const + { pimpl()->setProbedType( t ); } + + void RepoInfo::setMetadataPath( const zypp::Pathname &path ) + { pimpl()->metadataPath( path ); } + + void RepoInfo::setPackagesPath( const zypp::Pathname &path ) + { pimpl()->packagesPath( path ); } + + void RepoInfo::setSolvCachePath(const zypp::Pathname &path) + { pimpl()->solvPath (path); } + + void RepoInfo::setKeepPackages( bool keep ) + { pimpl()->keeppackages = keep; } + + void RepoInfo::setService( const std::string& name ) + { pimpl()->service = name; } + + void RepoInfo::setTargetDistribution( const std::string & targetDistribution ) + { pimpl()->targetDistro = targetDistribution; } + + bool RepoInfo::keepPackages() const + { return indeterminate(pimpl()->keeppackages) ? false : (bool)pimpl()->keeppackages; } + + zypp::Pathname RepoInfo::metadataPath() const + { return pimpl()->metadataPath(); } + + zypp::Pathname RepoInfo::packagesPath() const + { return pimpl()->packagesPath(); } + + zypp::Pathname RepoInfo::solvCachePath() const + { return pimpl()->solvPath(); } + + bool RepoInfo::usesAutoMetadataPaths() const + { return pimpl()->usesAutoMetadataPaths(); } + + zypp::repo::RepoType RepoInfo::type() const + { return pimpl()->type(); } + + zypp::Url RepoInfo::mirrorListUrl() const // Variables replaced! + { return pimpl()->_mirrorListUrl.transformed(); } + + zypp::Url RepoInfo::rawMirrorListUrl() const // Raw + { return pimpl()->_mirrorListUrl.raw(); } + + bool RepoInfo::gpgKeyUrlsEmpty() const + { return pimpl()->gpgKeyUrls().empty(); } + + RepoInfo::urls_size_type RepoInfo::gpgKeyUrlsSize() const + { return pimpl()->gpgKeyUrls().size(); } + + RepoInfo::url_set RepoInfo::gpgKeyUrls() const // Variables replaced! + { return pimpl()->gpgKeyUrls().transformed(); } + + RepoInfo::url_set RepoInfo::rawGpgKeyUrls() const // Raw + { return pimpl()->gpgKeyUrls().raw(); } + + zypp::Url RepoInfo::gpgKeyUrl() const // Variables replaced! + { return( pimpl()->gpgKeyUrls().empty() ? zypp::Url() : *pimpl()->gpgKeyUrls().transformedBegin() ); } + + zypp::Url RepoInfo::rawGpgKeyUrl() const // Raw + { return( pimpl()->gpgKeyUrls().empty() ? zypp::Url() : *pimpl()->gpgKeyUrls().rawBegin() ) ; } + + RepoInfo::url_set RepoInfo::baseUrls() const // Variables replaced! + { return pimpl()->baseUrls().transformed(); } + + RepoInfo::url_set RepoInfo::rawBaseUrls() const // Raw + { return pimpl()->baseUrls().raw(); } + + zypp::Pathname RepoInfo::path() const + { return pimpl()->path; } + + std::string RepoInfo::service() const + { return pimpl()->service; } + + std::string RepoInfo::targetDistribution() const + { return pimpl()->targetDistro; } + + zypp::Url RepoInfo::rawUrl() const + { return( pimpl()->baseUrls().empty() ? zypp::Url() : *pimpl()->baseUrls().rawBegin() ); } + + RepoInfo::urls_const_iterator RepoInfo::baseUrlsBegin() const + { return pimpl()->baseUrls().transformedBegin(); } + + RepoInfo::urls_const_iterator RepoInfo::baseUrlsEnd() const + { return pimpl()->baseUrls().transformedEnd(); } + + RepoInfo::urls_size_type RepoInfo::baseUrlsSize() const + { return pimpl()->baseUrls().size(); } + + bool RepoInfo::baseUrlsEmpty() const + { return pimpl()->baseUrls().empty(); } + + bool RepoInfo::baseUrlSet() const + { return pimpl()->baseurl2dump(); } + + const std::set & RepoInfo::contentKeywords() const + { return pimpl()->contentKeywords(); } + + void RepoInfo::addContent( const std::string & keyword_r ) + { pimpl()->addContent( keyword_r ); } + + bool RepoInfo::hasContent() const + { return pimpl()->hasContent(); } + + bool RepoInfo::hasContent( const std::string & keyword_r ) const + { return pimpl()->hasContent( keyword_r ); } + + /////////////////////////////////////////////////////////////////// + + bool RepoInfo::hasLicense() const + { return hasLicense( std::string() ); } + + bool RepoInfo::hasLicense( const std::string & name_r ) const + { return !pimpl()->licenseTgz( name_r ).empty(); } + + + bool RepoInfo::needToAcceptLicense() const + { return needToAcceptLicense( std::string() ); } + + bool RepoInfo::needToAcceptLicense( const std::string & name_r ) const + { + const zypp::Pathname & licenseTgz( pimpl()->licenseTgz( name_r ) ); + if ( licenseTgz.empty() ) + return false; // no licenses at all + + zypp::ExternalProgram::Arguments cmd; + cmd.push_back( "tar" ); + cmd.push_back( "-t" ); + cmd.push_back( "-z" ); + cmd.push_back( "-f" ); + cmd.push_back( licenseTgz.asString() ); + zypp::ExternalProgram prog( cmd, zypp::ExternalProgram::Stderr_To_Stdout ); + + bool accept = true; + static const std::string noAcceptanceFile = "no-acceptance-needed\n"; + for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) + { + if ( output == noAcceptanceFile ) + { + accept = false; + } + } + prog.close(); + MIL << "License(" << name_r << ") in " << name() << " has to be accepted: " << (accept?"true":"false" ) << endl; + return accept; + } + + std::string RepoInfo::getLicense( const zypp::Locale & lang_r ) const + { return getLicense( std::string(), lang_r ); } + + std::string RepoInfo::getLicense( const std::string & name_r, const zypp::Locale & lang_r ) const + { + zypp::LocaleSet avlocales( getLicenseLocales( name_r ) ); + if ( avlocales.empty() ) + return std::string(); + + zypp::Locale getLang( zypp::Locale::bestMatch( avlocales, lang_r ) ); + if ( !getLang && avlocales.find( zypp::Locale::noCode ) == avlocales.end() ) + { + WAR << "License(" << name_r << ") in " << name() << " contains no fallback text!" << endl; + // Using the fist locale instead of returning no text at all. + // So the user might recognize that there is a license, even if they + // can't read it. + getLang = *avlocales.begin(); + } + + // now extract the license file. + static const std::string licenseFileFallback( "license.txt" ); + std::string licenseFile( !getLang ? licenseFileFallback + : zypp::str::form( "license.%s.txt", getLang.c_str() ) ); + + zypp::ExternalProgram::Arguments cmd; + cmd.push_back( "tar" ); + cmd.push_back( "-x" ); + cmd.push_back( "-z" ); + cmd.push_back( "-O" ); + cmd.push_back( "-f" ); + cmd.push_back( pimpl()->licenseTgz( name_r ).asString() ); // if it not exists, avlocales was empty. + cmd.push_back( licenseFile ); + + std::string ret; + zypp::ExternalProgram prog( cmd, zypp::ExternalProgram::Discard_Stderr ); + for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) + { + ret += output; + } + prog.close(); + return ret; + } + + zypp::LocaleSet RepoInfo::getLicenseLocales() const + { return getLicenseLocales( std::string() ); } + + zypp::LocaleSet RepoInfo::getLicenseLocales( const std::string & name_r ) const + { + const zypp::Pathname & licenseTgz( pimpl()->licenseTgz( name_r ) ); + if ( licenseTgz.empty() ) + return zypp::LocaleSet(); + + zypp::ExternalProgram::Arguments cmd; + cmd.push_back( "tar" ); + cmd.push_back( "-t" ); + cmd.push_back( "-z" ); + cmd.push_back( "-f" ); + cmd.push_back( licenseTgz.asString() ); + + zypp::LocaleSet ret; + zypp::ExternalProgram prog( cmd, zypp::ExternalProgram::Stderr_To_Stdout ); + for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) + { + static const zypp::C_Str license( "license." ); + static const zypp::C_Str dotTxt( ".txt\n" ); + if ( zypp::str::hasPrefix( output, license ) && zypp::str::hasSuffix( output, dotTxt ) ) + { + if ( output.size() <= license.size() + dotTxt.size() ) // license.txt + ret.insert( zypp::Locale() ); + else + ret.insert( zypp::Locale( std::string( output.c_str()+license.size(), output.size()- license.size() - dotTxt.size() ) ) ); + } + } + prog.close(); + return ret; + } + + /////////////////////////////////////////////////////////////////// + + std::ostream & RepoInfo::dumpOn( std::ostream & str ) const + { + RepoInfoBase::dumpOn(str); + if ( pimpl()->baseurl2dump() ) + { + for ( const auto & url : pimpl()->baseUrls().raw() ) + { + str << "- url : " << url << std::endl; + } + } + + // print if non empty value + auto strif( [&] ( const std::string & tag_r, const std::string & value_r ) { + if ( ! value_r.empty() ) + str << tag_r << value_r << std::endl; + }); + + strif( (pimpl()->_mirrorListForceMetalink ? "- metalink : " : "- mirrorlist : "), rawMirrorListUrl().asString() ); + strif( "- path : ", path().asString() ); + str << "- type : " << type() << std::endl; + str << "- priority : " << priority() << std::endl; + + // Yes No Default(Y) Default(N) +#define OUTS(T,B) ( indeterminate(T) ? (std::string("D(")+(B?"Y":"N")+")") : ((bool)T?"Y":"N") ) + str << "- gpgcheck : " << OUTS(pimpl()->rawGpgCheck(),gpgCheck()) + << " repo" << OUTS(pimpl()->rawRepoGpgCheck(),repoGpgCheck()) << (repoGpgCheckIsMandatory() ? "* ": " " ) + << "sig" << zypp::asString( validRepoSignature(), "?", "Y", "N" ) + << " pkg" << OUTS(pimpl()->rawPkgGpgCheck(),pkgGpgCheck()) << (pkgGpgCheckIsMandatory() ? "* ": " " ) + << std::endl; +#undef OUTS + + for ( const auto & url : pimpl()->gpgKeyUrls().raw() ) + { + str << "- gpgkey : " << url << std::endl; + } + + if ( ! indeterminate(pimpl()->keeppackages) ) + str << "- keeppackages: " << keepPackages() << std::endl; + + strif( "- service : ", service() ); + strif( "- targetdistro: ", targetDistribution() ); + strif( "- filePath: ", filepath().asString() ); + strif( "- metadataPath: ", metadataPath().asString() ); + strif( "- packagesPath: ", packagesPath().asString() ); + + return str; + } + + std::ostream & RepoInfo::dumpAsIniOn( std::ostream & str ) const + { + RepoInfoBase::dumpAsIniOn(str); + + if ( pimpl()->baseurl2dump() ) + { + str << "baseurl="; + std::string indent; + for ( const auto & url : pimpl()->baseUrls().raw() ) + { + str << indent << zypp::hotfix1050625::asString( url ) << endl; + if ( indent.empty() ) indent = " "; // "baseurl=" + } + } + + if ( ! pimpl()->path.empty() ) + str << "path="<< path() << endl; + + if ( ! (rawMirrorListUrl().asString().empty()) ) + str << (pimpl()->_mirrorListForceMetalink ? "metalink=" : "mirrorlist=") << zypp::hotfix1050625::asString( rawMirrorListUrl() ) << endl; + + if ( type() != zypp::repo::RepoType::NONE ) + str << "type=" << type().asString() << endl; + + if ( priority() != defaultPriority() ) + str << "priority=" << priority() << endl; + + if ( ! indeterminate(pimpl()->rawGpgCheck()) ) + str << "gpgcheck=" << (pimpl()->rawGpgCheck() ? "1" : "0") << endl; + + if ( ! indeterminate(pimpl()->rawRepoGpgCheck()) ) + str << "repo_gpgcheck=" << (pimpl()->rawRepoGpgCheck() ? "1" : "0") << endl; + + if ( ! indeterminate(pimpl()->rawPkgGpgCheck()) ) + str << "pkg_gpgcheck=" << (pimpl()->rawPkgGpgCheck() ? "1" : "0") << endl; + + { + std::string indent( "gpgkey="); + for ( const auto & url : pimpl()->gpgKeyUrls().raw() ) + { + str << indent << url << endl; + if ( indent[0] != ' ' ) + indent = " "; + } + } + + if (!indeterminate(pimpl()->keeppackages)) + str << "keeppackages=" << keepPackages() << endl; + + if( ! service().empty() ) + str << "service=" << service() << endl; + + return str; + } + + std::ostream & RepoInfo::dumpAsXmlOn( std::ostream & str, const std::string & content ) const + { + std::string tmpstr; + str + << "rawGpgCheck()) ) + str << " raw_gpgcheck=\"" << (pimpl()->rawGpgCheck() ? "1" : "0") << "\""; + if ( ! indeterminate(pimpl()->rawRepoGpgCheck()) ) + str << " raw_repo_gpgcheck=\"" << (pimpl()->rawRepoGpgCheck() ? "1" : "0") << "\""; + if ( ! indeterminate(pimpl()->rawPkgGpgCheck()) ) + str << " raw_pkg_gpgcheck=\"" << (pimpl()->rawPkgGpgCheck() ? "1" : "0") << "\""; + if (!(tmpstr = gpgKeyUrl().asString()).empty()) + if (!(tmpstr = gpgKeyUrl().asString()).empty()) + str << " gpgkey=\"" << escape(tmpstr) << "\""; + if (!(tmpstr = mirrorListUrl().asString()).empty()) + str << (pimpl()->_mirrorListForceMetalink ? " metalink=\"" : " mirrorlist=\"") << escape(tmpstr) << "\""; + str << ">" << endl; + + if ( pimpl()->baseurl2dump() ) + { + for_( it, baseUrlsBegin(), baseUrlsEnd() ) // !transform iterator replaces variables + str << "" << escape((*it).asString()) << "" << endl; + } + + str << "" << endl; + return str; + } + + + std::ostream & operator<<( std::ostream & str, const RepoInfo & obj ) + { + return obj.dumpOn(str); + } + + bool RepoInfo::requireStatusWithMediaFile () const + { + // We skip the check for downloading media unless a local copy of the + // media file exists and states that there is more than one medium. + bool canSkipMediaCheck = std::all_of( baseUrlsBegin(), baseUrlsEnd(), []( const zypp::Url &url ) { return url.schemeIsDownloading(); }); + if ( canSkipMediaCheck ) { + const auto &mDataPath = metadataPath(); + if ( not mDataPath.empty() ) { + zypp::PathInfo mediafile { mDataPath/"media.1/media" }; + if ( mediafile.isExist() ) { + zypp::repo::SUSEMediaVerifier lverifier { mediafile.path() }; + if ( lverifier && lverifier.totalMedia() > 1 ) { + canSkipMediaCheck = false; + } + } + } + } + if ( canSkipMediaCheck ) + DBG << "Can SKIP media.1/media check for status calc of repo " << alias() << endl; + return not canSkipMediaCheck; + } +} // namespace zyppng diff --git a/zypp/ng/repoinfo.h b/zypp/ng/repoinfo.h new file mode 100644 index 0000000000..454e41c542 --- /dev/null +++ b/zypp/ng/repoinfo.h @@ -0,0 +1,598 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/ng/repoinfo.h + * +*/ +#ifndef ZYPP_NG_REPOINFO_INCLUDED +#define ZYPP_NG_REPOINFO_INCLUDED + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +/////////////////////////////////////////////////////////////////// +namespace zyppng +{ ///////////////////////////////////////////////////////////////// + + class RepoInfoSharedData; + + /////////////////////////////////////////////////////////////////// + // + // CLASS NAME : RepoInfo + // + /** + * \short What is known about a repository + * + * The class RepoInfo represents everything that + * is known about a software repository. + * + * It can be used to store information about known + * sources. + * + * This class tries to be compatible with the + * concept of a .repo file used by YUM and + * also available in the openSUSE build service. + * See man yum.conf. + * + * Example file + * + * \code + * [ruby] + * name=Ruby repository (openSUSE_10.2) + * type=rpm-md + * baseurl=http://software.opensuse.org/download/ruby/openSUSE_10.2/ + * http://some.opensuse.mirror/ruby/openSUSE_10.2/ + * gpgcheck=1 + * gpgkey=http://software.opensuse.org/openSUSE-Build-Service.asc + * enabled=1 + * priority=10 + * \endcode + * + * \note A RepoInfo is a hint about how + * to create a Repository. + * + * \note Name, baseUrls and mirrorUrl are subject to repo variable replacement + * (\see \ref RepoVariablesStringReplacer). + */ + class RepoInfo : public repo::RepoInfoBase + { + friend std::ostream & operator<<( std::ostream & str, const RepoInfo & obj ); + + public: + + // nullable -> ContextFactory::defaultContext() ? + RepoInfo ( zyppng::ContextBaseRef context ) ZYPP_LOCAL; + ~RepoInfo() override; + + RepoInfo(const RepoInfo &) = default; + RepoInfo(RepoInfo &&) = default; + RepoInfo &operator=(const RepoInfo &) = default; + RepoInfo &operator=(RepoInfo &&) = default; + + public: + + static const std::optional &nullRepo(); + + /** + * The default priority (\c 99). + */ + static unsigned defaultPriority(); + /** + * The least priority (unsigned(-1)). + */ + static unsigned noPriority(); + /** + * Repository priority for solver. + * Some number between \c 1 (highest priority) and \c 99 (\ref defaultPriority). + */ + unsigned priority() const; + /** + * Set repository priority for solver. + * A \c newval_r of \c 0 sets the default priority. + * \see \ref priority. + */ + void setPriority( unsigned newval_r ); + + using url_set = std::list; + using urls_size_type = url_set::size_type; + using urls_const_iterator = zypp::transform_iterator; + /** + * whether repository urls are available + */ + bool baseUrlsEmpty() const; + /** + * Whether there are manualy configured repository urls. + * If \c false, a mirrorlist might be used. + */ + bool baseUrlSet() const; + /** + * number of repository urls + */ + urls_size_type baseUrlsSize() const; + /** + * iterator that points at begin of repository urls + */ + urls_const_iterator baseUrlsBegin() const; + /** + * iterator that points at end of repository urls + */ + urls_const_iterator baseUrlsEnd() const; + + /** + * Pars pro toto: The first repository url + */ + zypp::Url url() const + { return( baseUrlsEmpty() ? zypp::Url() : *baseUrlsBegin()); } + /** + * Pars pro toto: The first repository raw url (no variables replaced) + */ + zypp::Url rawUrl() const; + + /** + * The complete set of repository urls + * + * These are either the configured baseurls, or if empty, the downloaded + * mirror list (\see \ref mirrorListUrl) + */ + url_set baseUrls() const; + /** + * The complete set of raw repository urls (no variables replaced) + */ + url_set rawBaseUrls() const; + + /** + * Add a base url. \see baseUrls + * \param url The base url for the repository. + * + * To recreate the base URLs list, use \ref setBaseUrl(const Url &) followed + * by addBaseUrl(). + */ + void addBaseUrl( zypp::Url url ); + /** + * Clears current base URL list and adds \a url. + */ + void setBaseUrl( zypp::Url url ); + /** + * Clears current base URL list and adds an \ref url_set. + */ + void setBaseUrls( url_set urls ); + + /** + * \short Repository path + * + * Pathname relative to the base Url where the product/repository + * is located + * + * For media containing more than one product, or repositories not + * located at the root of the media it is important to know the path + * to the product directory relative to the media root. So a media + * verifier can be set for that media. You may also read it as + * baseUrl = url to mount and path = path on the + * mounted media. + * + * It is not mandatory, and the default is \c /. + * + * \note As a repository can have multiple Urls, the path is unique and + * the same for all Urls, so it is assumed all the Urls have the + * same media layout. + * + */ + zypp::Pathname path() const; + /** + * set the product path. \see path() + * \param path the path to the product + */ + void setPath( const zypp::Pathname &path ); + + /** + * Url of a file which contains a list of repository urls + */ + zypp::Url mirrorListUrl() const; + /** + * The raw mirrorListUrl (no variables replaced). + */ + zypp::Url rawMirrorListUrl() const; + /** + * Set mirror list url. \see mirrorListUrl + * \param url The base url for the list + */ + void setMirrorListUrl( const zypp::Url &url ); + /** Like \ref setMirrorListUrl but take an \a url_set */ + void setMirrorListUrls( url_set urls ); + + /** Like \ref setMirrorListUrl but expect metalink format. */ + void setMetalinkUrl( const zypp::Url &url ); + /** Like \ref setMirrorListUrls but expect metalink format. */ + void setMetalinkUrls( url_set urls ); + + /** + * Type of repository, + * + */ + zypp::repo::RepoType type() const; + /** + * This allows to adjust the \ref RepoType lazy, from \c NONE to + * some probed value, even for const objects. + * + * This is a NOOP if the current type is not \c NONE. + */ + void setProbedType( const zypp::repo::RepoType &t ) const; + /** + * set the repository type \see type + * \param t + */ + void setType( const zypp::repo::RepoType &t ); + + /** + * \short Path where this repo metadata was read from + * + * \note could be an empty pathname for repo + * infos created in memory. + */ + zypp::Pathname metadataPath() const; + /** + * \short Set the path where the local metadata is stored + * + * The path to the repositories metadata is usually provided by + * the RepoManager. If you want to use a temporary repository + * (not under RepoManagers control), and you set a metadataPath + * with basename \c %AUTO%, all data directories (raw metadata, + * solv file and package cache) will be created by replacing \c %AUTO% + * with \c %RAW%, \c %SLV% or \c %PKG% . This will change the value + * of \ref packagesPath accordingly, unless you assigned a custom + * value using \ref setPackagesPath. + * + * \code + * RepoInfo repo; + * repo.setAlias( "Temp" ); + * repo.setBaseUrl( Url("http://someserver/somepath/") ); + * repo.setMetadataPath( "/tmp/temprepodata/%AUTO%" ); + * + * // will use + * // /tmp/temprepodata/%RAW% - raw metadata + * // /%SLV% - solv file + * // /%PKG% - packages + *\endcode + * + * \param path directory path + */ + void setMetadataPath( const zypp::Pathname &path ); + + /** Whether \ref metadataPath uses \c %AUTO% setup. */ + bool usesAutoMetadataPaths() const; + + /** + * \short Path where this repo packages are cached + */ + zypp::Pathname packagesPath() const; + /** + * \short set the path where the local packages are stored + * + * \param path directory path + */ + void setPackagesPath( const zypp::Pathname &path ); + + /** + * \short Path where this repo's solv cache is located + */ + zypp::Pathname solvCachePath() const; + /** + * \short set the path this repo's solv cache is located + * + * \param path directory path + */ + void setSolvCachePath( const zypp::Pathname &path ); + + + /** \name Repository gpgchecks + * How signature checking should be performed for this repo. + * + * The values are computed based in the settings of \c gpgcheck, \c repo_gpgcheck + * end \c pkg_gpgcheck in \c zypp.conf. Explicitly setting these values in the + * repositories \a .repo file will overwrite the defaults from \c zypp.conf for this + * repo. + * + * If \c gpgcheck is \c on (the default) we will check the signature of repo metadata + * (packages are secured via checksum inside the metadata). Using unsigned repos + * needs to be confirmed. + * Packages from signed repos are accepted if their checksum matches the checksum + * stated in the repo metadata. + * Packages from unsigned repos need a valid gpg signature, using unsigned packages + * needs to be confirmed. + * + * The above default behavior can be tuned by explicitly setting \c repo_gpgcheck + * and/or \c pkg_gpgcheck: + * + * \c repo_gpgcheck = \c on same as the default. + * + * \c repo_gpgcheck = \c off will silently accept unsigned repos. It will NOT turn of + * signature checking on the whole. Nevertheless, it's not a secure setting. + * + * \c pkg_gpgcheck = \c on will enforce the package signature checking and the need + * to confirm unsigned packages for all repos (signed and unsigned). + * + * \c pkg_gpgcheck = \c off will silently accept unsigned packages. It will NOT turn of + * signature checking on the whole. Nevertheless, it's not a secure setting. + * + * If \c gpgCheck is \c off (not recommneded), no checks are performed. You can still + * enable them individually by setting \c repo_gpgcheck and/or \c pkg_gpgcheck to \c on. + * + * \code + * R: check repo signature is mandatory, confirm unsigned repos + * r: check repo signature, unsigned repos are ok but enforce p + * : do not check repo signatures + * + * P: check package signature always, confirm unsigned packages + * p: like P for unsigned repos, accepted by checksum for signed repos + * b: like p but accept unsigned packages + * : do not check package signatures + * pkg_ + * gpgcheck 1| * 0 1 + * ------------------------------------ + * repo_ *1| R/p R/b R/P + * 0| r/p r/b r/P + * + * pkg_ + * gpgcheck 0| * 0 1 + * ------------------------------------ + * repo_ *0| P + * 1| R R R/P + * \endcode + */ + //@{ + /** Whether default signature checking should be performed. */ + bool gpgCheck() const; + /** Set the value for \ref gpgCheck (or \c indeterminate to use the default). */ + void setGpgCheck( zypp::TriBool value_r ); + + /** Whether the signature of repo metadata should be checked for this repo. */ + bool repoGpgCheck() const; + /** Mandatory check (\ref repoGpgCheck is \c on) must ask to confirm using unsigned repos. */ + bool repoGpgCheckIsMandatory() const; + /** Set the value for \ref repoGpgCheck (or \c indeterminate to use the default). */ + void setRepoGpgCheck( zypp::TriBool value_r ); + + /** Whether the signature of rpm packages should be checked for this repo. */ + bool pkgGpgCheck() const; + /** Mandatory check (\ref pkgGpgCheck is not \c off) must ask to confirm using unsigned packages. */ + bool pkgGpgCheckIsMandatory() const; + /** Set the value for \ref pkgGpgCheck (or \c indeterminate to use the default). */ + void setPkgGpgCheck( zypp::TriBool value_r ); + + /** Whether the repo metadata are signed and successfully validated or \c indeterminate if unsigned. + * The value is usually set by \ref repo::Downloader when retrieving the metadata. + */ + zypp::TriBool validRepoSignature() const; + /** Set the value for \ref validRepoSignature (or \c indeterminate if unsigned). */ + void setValidRepoSignature( zypp::TriBool value_r ); + + using GpgCheck = zypp::repo::GpgCheck; + + /** Adjust *GpgCheck settings according to \a mode_r. + * \c GpgCheck::indeterminate will leave the settings as they are. + * \return whether setting were changed + */ + bool setGpgCheck( GpgCheck mode_r ); + //@} + + + /** Whether gpgkey URLs are defined */ + bool gpgKeyUrlsEmpty() const; + /** Number of gpgkey URLs defined */ + urls_size_type gpgKeyUrlsSize() const; + + /** The list of gpgkey URLs defined for this repo */ + url_set gpgKeyUrls() const; + /** The list of raw gpgkey URLs defined for this repo (no variables replaced) */ + url_set rawGpgKeyUrls() const; + /** Set a list of gpgkey URLs defined for this repo */ + void setGpgKeyUrls( url_set urls ); + + /** (leagcy API) The 1st gpgkey URL defined for this repo */ + zypp::Url gpgKeyUrl() const; + /** (leagcy API) The 1st raw gpgkey URL defined for this repo (no variables replaced) */ + zypp::Url rawGpgKeyUrl() const; + /** (leagcy API) Set the gpgkey URL defined for this repo */ + void setGpgKeyUrl( const zypp::Url &gpgkey ); + + /** + * \short Whether packages downloaded from this repository will be kept in local cache + */ + bool keepPackages() const; + /** + * \short Set if packaqes downloaded from this repository will be kept in local cache + * + * If the setting is true, all downloaded packages from this repository will be + * copied to the local raw cache. + * + * \param keep true (keep the downloaded packages) or false (delete them after installation) + * + */ + void setKeepPackages( bool keep ); + + /** + * Gets name of the service to which this repository belongs or empty string + * if it has been added manually. + */ + std::string service() const; + /** + * sets service which added this repository + */ + void setService( const std::string& name ); + + /** + * Distribution for which is this repository meant. + */ + std::string targetDistribution() const; + /** + * Sets the distribution for which is this repository meant. This is + * an in-memory value only, does norepoInfot get written to the .repo file upon + * saving. + */ + void setTargetDistribution(const std::string & targetDistribution); + + + /** Content keywords defined. */ + const std::set & contentKeywords() const; + + /** Add content keywords */ + void addContent( const std::string & keyword_r ); + /** \overload add keywords from container */ + template + void addContentFrom( TIterator begin_r, TIterator end_r ) + { for_( it, begin_r, end_r ) addContent( *it ); } + /** \overload */ + template + void addContentFrom( const TContainer & container_r ) + { addContentFrom( container_r.begin(), container_r.end() ); } + + /** Check for content keywords. + * They may be missing due to missing metadata in disabled repos. + */ + bool hasContent() const; + /** \overload check for a keywords being present */ + bool hasContent( const std::string & keyword_r ) const; + /** \overload check for \b all keywords being present */ + template + bool hasContentAll( TIterator begin_r, TIterator end_r ) const + { for_( it, begin_r, end_r ) if ( ! hasContent( *it ) ) return false; return true; } + /** \overload */ + template + bool hasContentAll( const TContainer & container_r ) const + { return hasContentAll( container_r.begin(), container_r.end() ); } + /** \overload check for \b any keyword being present */ + template + bool hasContentAny( TIterator begin_r, TIterator end_r ) const + { for_( it, begin_r, end_r ) if ( hasContent( *it ) ) return true; return false; } + /** \overload */ + template + bool hasContentAny( const TContainer & container_r ) const + { return hasContentAny( container_r.begin(), container_r.end() ); } + + public: + /** \name Repository/Product license + * In case a repository provides multiple license tarballs in repomd.xml + * \code + * ... + * ... + * ... + * \endcode + * you can address the individual licenses by passing their name + * (e.g. \c "sles" to access the \c type="license-sles"). + * No on an empty name will refer to \c type="license". + */ + //@{ + /** Whether there is a license associated with the repo. */ + bool hasLicense() const; + /** \overload taking a (product)name */ + bool hasLicense( const std::string & name_r ) const; + + /** Whether the repo license has to be accepted, e.g. there is no + * no acceptance needed for openSUSE. + */ + bool needToAcceptLicense() const; + /** \overload taking a (product)name */ + bool needToAcceptLicense( const std::string & name_r ) const; + + /** Return the best license for the current (or a specified) locale. */ + std::string getLicense( const zypp::Locale & lang_r = zypp::Locale() ) const; + /** \overload taking a (product)name */ + std::string getLicense( const std::string & name_r, const zypp::Locale & lang_r = zypp::Locale() ) const; + + /** Return the locales the license is available for. + * \ref Locale::noCode is included in case of \c license.txt which does + * not specify a specific locale. + */ + zypp::LocaleSet getLicenseLocales() const; + + /** \overload taking a (product)name */ + zypp::LocaleSet getLicenseLocales( const std::string & name_r ) const; + //@} + + /** + * Returns true if this repository requires the media.1/media file to be included + * in the metadata status and repo status calculations. + */ + bool requireStatusWithMediaFile () const; + + public: + /** + * Write a human-readable representation of this RepoInfo object + * into the \a str stream. Useful for logging. + */ + std::ostream & dumpOn( std::ostream & str ) const override; + + /** + * Write this RepoInfo object into \a str in a .repo file format. + * Raw values, no variable replacement. + */ + std::ostream & dumpAsIniOn( std::ostream & str ) const override; + + /** + * Write an XML representation of this RepoInfo object. + * Repo variables replaced. + * + * \param str + * \param content this argument is ignored (used in other classed derived + * from RepoInfoBase. + */ + std::ostream & dumpAsXmlOn( std::ostream & str, const std::string & content = "" ) const override; + + /** Raw values for RepoManager + * \internal + */ + void getRawGpgChecks( zypp::TriBool & g_r, zypp::TriBool & r_r, zypp::TriBool & p_r ) const; + + struct Impl; + private: + template friend class zyppng::RepoManager; + + // for RepoManager to be able to set the context + void setContext( zyppng::ContextBaseRef context ); + + RepoInfoSharedData *pimpl(); + const RepoInfoSharedData *pimpl() const; + }; + + /** \relates RepoInfo */ + using RepoInfoList = std::list; + + /** \relates RepoInfoBase */ + inline bool operator==( const RepoInfo & lhs, const RepoInfo & rhs ) + { return lhs.alias() == rhs.alias(); } + + /** \relates RepoInfoBase */ + inline bool operator!=( const RepoInfo & lhs, const RepoInfo & rhs ) + { return lhs.alias() != rhs.alias(); } + + inline bool operator<( const RepoInfo & lhs, const RepoInfo & rhs ) + { return lhs.alias() < rhs.alias(); } + + /** \relates RepoInfo Stream output */ + std::ostream & operator<<( std::ostream & str, const RepoInfo & obj ) ZYPP_API; + + ///////////////////////////////////////////////////////////////// +} // namespace zypp +/////////////////////////////////////////////////////////////////// +#endif // ZYPP_NG_REPOINFO_INCLUDED diff --git a/zypp/ng/repoinfoshareddata.h b/zypp/ng/repoinfoshareddata.h new file mode 100644 index 0000000000..d728e871b7 --- /dev/null +++ b/zypp/ng/repoinfoshareddata.h @@ -0,0 +1,147 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#ifndef ZYPP_NG_REPOINFOSHAREDDATA_INCLUDED +#define ZYPP_NG_REPOINFOSHAREDDATA_INCLUDED + +#include +#include +#include +#include +#include + + +namespace zyppng { + + /** RepoInfo implementation. */ + struct RepoInfoSharedData : public repo::RepoInfoBaseSharedData + { + RepoInfoSharedData( zyppng::ContextBaseRef &&context ); + RepoInfoSharedData(RepoInfoSharedData &&) = delete; + RepoInfoSharedData &operator=(const RepoInfoSharedData &) = delete; + RepoInfoSharedData &operator=(RepoInfoSharedData &&) = delete; + ~RepoInfoSharedData() override {} + + public: + static const unsigned defaultPriority = 99; + static const unsigned noPriority = unsigned(-1); + + void setType(const zypp::repo::RepoType &t); + + void setProbedType(const zypp::repo::RepoType &t) const; + + zypp::repo::RepoType type() const; + + public: + zypp::Pathname licenseTgz(const std::string &name_r) const; + + const RepoVariablesReplacedUrlList &baseUrls() const; + + RepoVariablesReplacedUrlList &baseUrls(); + + bool baseurl2dump() const; + + const RepoVariablesReplacedUrlList &gpgKeyUrls() const; + + RepoVariablesReplacedUrlList &gpgKeyUrls(); + + const std::set &contentKeywords() const; + + void addContent(const std::string &keyword_r); + + bool hasContent() const; + + bool hasContent(const std::string &keyword_r) const; + + /** Signature check result needs to be stored/retrieved from _metadataPath. + * Don't call them from outside validRepoSignature/setValidRepoSignature + */ + zypp::TriBool internalValidRepoSignature() const; + + void internalSetValidRepoSignature( zypp::TriBool value_r); + + /** We definitely have a symlink pointing to "zypp::indeterminate" (for repoGpgCheckIsMandatory)? + * I.e. user accepted the unsigned repo in Downloader. A test whether `internalValidRepoSignature` + * is zypp::indeterminate would include not yet checked repos, which is unwanted here. + */ + bool internalUnsignedConfirmed() const; + + bool triBoolFromPath(const zypp::Pathname &path_r, zypp::TriBool &ret_r) const; + + zypp::TriBool triBoolFromPath(const zypp::Pathname &path_r) const; + + zypp::TriBool rawGpgCheck() const { return _rawGpgCheck; } + zypp::TriBool rawRepoGpgCheck() const { return _rawRepoGpgCheck; } + zypp::TriBool rawPkgGpgCheck() const { return _rawPkgGpgCheck; } + + void rawGpgCheck( zypp::TriBool val_r ) { _rawGpgCheck = val_r; } + void rawRepoGpgCheck( zypp::TriBool val_r ) { _rawRepoGpgCheck = val_r; } + void rawPkgGpgCheck( zypp::TriBool val_r ) { _rawPkgGpgCheck = val_r; } + + bool cfgGpgCheck() const; + + zypp::TriBool cfgRepoGpgCheck() const; + + zypp::TriBool cfgPkgGpgCheck() const; + + void solvPath(zypp::Pathname new_r); + + void metadataPath(zypp::Pathname new_r); + + void packagesPath(zypp::Pathname new_r); + + bool usesAutoMetadataPaths() const; + + zypp::Pathname solvPath() const; + + zypp::Pathname metadataPath() const; + + zypp::Pathname packagesPath() const; + + zypp::DefaultIntegral priority; + + protected: + void bindVariables() override; + + private: + zypp::TriBool _rawGpgCheck; ///< default gpgcheck behavior: Y/N/ZConf + zypp::TriBool _rawRepoGpgCheck; ///< need to check repo sign.: Y/N/(ZConf(Y/N/gpgCheck)) + zypp::TriBool _rawPkgGpgCheck; ///< need to check pkg sign.: Y/N/(ZConf(Y/N/gpgCheck)) + zypp::TriBool _validRepoSignature; ///< have signed and valid repo metadata + zypp::repo::RepoType _type; + + public: + zypp::TriBool keeppackages; + RepoVariablesReplacedUrl _mirrorListUrl; + bool _mirrorListForceMetalink; + zypp::Pathname path; + std::string service; + std::string targetDistro; + mutable bool emptybaseurls; + + private: + zypp::Pathname _slvPath; + zypp::Pathname _metadataPath; + zypp::Pathname _packagesPath; + + mutable RepoVariablesReplacedUrlList _baseUrls; + mutable std::pair > _keywords; + + RepoVariablesReplacedUrlList _gpgKeyUrls; + + // support copying only for clone + RepoInfoSharedData(const RepoInfoSharedData &) = default; + + friend RepoInfoSharedData * zypp::rwcowClone( const RepoInfoSharedData * rhs ); + /** clone for RWCOW_pointer */ + RepoInfoSharedData *clone() const override; + }; +} + +#endif diff --git a/zypp/ng/repomanager.cc b/zypp/ng/repomanager.cc index 981a5914d8..e558c594b3 100644 --- a/zypp/ng/repomanager.cc +++ b/zypp/ng/repomanager.cc @@ -23,18 +23,20 @@ #include #include #include -#include -#include +#include +#include #include #include #include -#include +#include +#include +#include #include #include #include #include -#include + #include #include @@ -164,12 +166,12 @@ namespace zyppng return true; } - expected> repositories_in_file(const zypp::Pathname &file) + expected> repositories_in_file( ContextBaseRef ctx, const zypp::Pathname &file) { try { MIL << "repo file: " << file << std::endl; RepoCollector collector; - zypp::parser::RepoFileReader parser( file, std::bind( &RepoCollector::collect, &collector, std::placeholders::_1 ) ); + zyppng::parser::RepoFileReader parser( ctx, file, std::bind( &RepoCollector::collect, &collector, std::placeholders::_1 ) ); return expected>::success( std::move(collector.repos) ); } catch ( ... ) { return expected>::error( ZYPP_FWD_CURRENT_EXCPT() ); @@ -186,14 +188,14 @@ namespace zyppng * \param dir pathname of the directory to read. */ template - std::list repositories_in_dir( ZContextRef zyppContext, const zypp::Pathname &dir ) + std::list repositories_in_dir( ZContextRef zyppContext, ProgressObserverRef taskObserver, const zypp::Pathname &dir ) { MIL << "directory " << dir << std::endl; std::list repos; bool nonroot( geteuid() != 0 ); if ( nonroot && ! zypp::PathInfo(dir).userMayRX() ) { - JobReportHelper(zyppContext).warning( zypp::str::Format(_("Cannot read repo directory '%1%': Permission denied")) % dir ); + JobReportHelper(zyppContext, taskObserver).warning( zypp::str::Format(_("Cannot read repo directory '%1%': Permission denied")) % dir ); } else { @@ -211,11 +213,11 @@ namespace zyppng { if ( nonroot && ! zypp::PathInfo(*it).userMayR() ) { - JobReportHelper(zyppContext).warning( zypp::str::Format(_("Cannot read repo file '%1%': Permission denied")) % *it ); + JobReportHelper(zyppContext, taskObserver).warning( zypp::str::Format(_("Cannot read repo file '%1%': Permission denied")) % *it ); } else { - const std::list tmp( repositories_in_file( *it ).unwrap() ); + const std::list tmp( repositories_in_file( zyppContext, *it ).unwrap() ); repos.insert( repos.end(), tmp.begin(), tmp.end() ); } } @@ -235,8 +237,8 @@ namespace zyppng { return not zypp::PathInfo(path_r/".no_auto_prune").isExist(); } - template - RepoManager::RepoManager( ZYPP_PRIVATE_CONSTR_ARG, ZyppContextRefType zyppCtx, RepoManagerOptions opt ) + template + RepoManager::RepoManager( ZYPP_PRIVATE_CONSTR_ARG, Ref zyppCtx, RepoManagerOptions opt ) : _zyppContext( std::move(zyppCtx) ) , _options( std::move(opt) ) , _pluginRepoverification( _options.pluginsPath / "repoverification", @@ -245,8 +247,8 @@ namespace zyppng } - template - RepoManager::~RepoManager() + template + RepoManager::~RepoManager() { // trigger appdata refresh if some repos change if ( ( _reposDirty || env::ZYPP_PLUGIN_APPDATA_FORCE_COLLECT() ) @@ -263,14 +265,14 @@ namespace zyppng cmd.push_back( "PROGRAM" ); // [2] - fix index below if changing! for ( const auto & rinfo : repos() ) { - if ( ! rinfo.enabled() ) + if ( ! rinfo.second.enabled() ) continue; cmd.push_back( "-R" ); - cmd.push_back( rinfo.alias() ); + cmd.push_back( rinfo.second.alias() ); cmd.push_back( "-t" ); - cmd.push_back( rinfo.type().asString() ); + cmd.push_back( rinfo.second.type().asString() ); cmd.push_back( "-p" ); - cmd.push_back( (rinfo.metadataPath()/rinfo.path()).asString() ); // bsc#1197684: path to the repodata/ directory inside the cache + cmd.push_back( (rinfo.second.metadataPath()/rinfo.second.path()).asString() ); // bsc#1197684: path to the repodata/ directory inside the cache } for_( it, entries.begin(), entries.end() ) @@ -290,8 +292,8 @@ namespace zyppng } } - template - expected RepoManager::initialize() + template + expected RepoManager::initialize() { using namespace zyppng::operators; return @@ -299,14 +301,14 @@ namespace zyppng | and_then( [this](){ return init_knownRepositories(); } ); } - template - const RepoManagerOptions &RepoManager::options() const + template + const RepoManagerOptions &RepoManager::options() const { return _options; } - template - expected RepoManager::metadataStatus(const RepoInfo & info , const RepoManagerOptions &options) + template + expected RepoManager::metadataStatus(const RepoInfo & info , const RepoManagerOptions &options) { try { using namespace zyppng::operators; @@ -369,14 +371,14 @@ namespace zyppng } } - template - expected RepoManager::metadataStatus(const RepoInfo &info) const + template + expected RepoManager::metadataStatus(const RepoInfo &info) const { return metadataStatus( info, _options ); } - template - expected RepoManager::cleanMetadata(const RepoInfo &info, ProgressObserverRef myProgress ) + template + expected RepoManager::cleanMetadata(const RepoInfo &info, ProgressObserverRef myProgress ) { try { @@ -394,8 +396,8 @@ namespace zyppng return expected::success(); } - template - expected RepoManager::cleanPackages(const RepoInfo &info, ProgressObserverRef myProgress, bool isAutoClean ) + template + expected RepoManager::cleanPackages(const RepoInfo &info, ProgressObserverRef myProgress, bool isAutoClean ) { try { ProgressObserver::setup( myProgress, _("Cleaning packages"), 100 ); @@ -421,8 +423,8 @@ namespace zyppng * \note Metadata in local cache directories must not be probed using \ref probe as * a cache path must not be rewritten (bnc#946129) */ - template - zypp::repo::RepoType RepoManager::probeCache( const zypp::Pathname & path_r ) + template + zypp::repo::RepoType RepoManager::probeCache( const zypp::Pathname & path_r ) { MIL << "going to probe the cached repo at " << path_r << std::endl; @@ -439,8 +441,8 @@ namespace zyppng return ret; } - template - expected RepoManager::cleanCacheDirGarbage( ProgressObserverRef myProgress ) + template + expected RepoManager::cleanCacheDirGarbage( ProgressObserverRef myProgress ) { try { MIL << "Going to clean up garbage in cache dirs" << std::endl; @@ -476,7 +478,7 @@ namespace zyppng // if it does not belong known repo, make it disappear bool found = false; for_( r, repoBegin(), repoEnd() ) - if ( subdir.basename() == r->escaped_alias() ) + if ( subdir.basename() == r->second.escaped_alias() ) { found = true; break; } if ( ! found && ( zypp::Date::now()-zypp::PathInfo(subdir).mtime() > zypp::Date::day ) ) @@ -496,8 +498,8 @@ namespace zyppng return expected::success(); } - template - expected RepoManager::cleanCache(const RepoInfo &info, ProgressObserverRef myProgress ) + template + expected RepoManager::cleanCache(const RepoInfo &info, ProgressObserverRef myProgress ) { try { ProgressObserver::setup( myProgress, _("Cleaning cache"), 100 ); @@ -516,11 +518,16 @@ namespace zyppng } } - template - expected RepoManager::loadFromCache( const RepoInfo & info, ProgressObserverRef myProgress ) + template + typename RepoManager::template MaybeAsyncRef> RepoManager::loadFromCache( FusionPoolRef fPool, RepoInfo info, ProgressObserverRef myProgress ) { using namespace zyppng::operators; - return zyppng::mtry( [this, info, myProgress](){ + + if ( !info.context() || info.context() != zyppContext() ) { + return makeReadyResult(expected::error( ZYPP_EXCPT_PTR( zypp::Exception("None or different context in RepoInfo is not supported.")) )); + } + + return zyppng::mtry( [this, fPool, info, myProgress](){ ProgressObserver::setup( myProgress, _("Loading from cache"), 3 ); ProgressObserver::start( myProgress ); @@ -530,11 +537,11 @@ namespace zyppng if ( ! zypp::PathInfo(solvfile).isExist() ) ZYPP_THROW(zypp::repo::RepoNotCachedException(info)); - _zyppContext->satPool().reposErase( info.alias() ); + fPool->satPool().reposErase( info.alias() ); ProgressObserver::increase ( myProgress ); - zypp::Repository repo = _zyppContext->satPool().addRepoSolv( solvfile, info ); + zypp::Repository repo = fPool->satPool().addRepoSolv( solvfile, info ); ProgressObserver::increase ( myProgress ); @@ -546,15 +553,15 @@ namespace zyppng ZYPP_THROW(zypp::Exception(zypp::str::Str() << "Solv-file was created by '"<satPool().addRepoSolv( solv_path_for_repoinfo(_options, info).unwrap() / "solv", info ); + | and_then( mtry([this, fPool]( RepoInfo info ){ + fPool->satPool().addRepoSolv( solv_path_for_repoinfo(_options, info).unwrap() / "solv", info ); })); }) | and_then([myProgress]{ @@ -568,12 +575,15 @@ namespace zyppng ; } - template - expected RepoManager::addProbedRepository( RepoInfo info, zypp::repo::RepoType probedType ) + template + expected RepoManager::addProbedRepository( RepoInfo info, zypp::repo::RepoType probedType ) { try { auto tosave = info; + if ( repos().find(tosave.alias()) != repos().end() ) + return expected::error( ZYPP_EXCPT_PTR(zypp::repo::RepoAlreadyExistsException(tosave)) ); + // assert the directory exists zypp::filesystem::assert_dir(_options.knownReposPath); @@ -593,10 +603,10 @@ namespace zyppng tosave.setFilepath(repofile); tosave.setMetadataPath( rawcache_path_for_repoinfo( _options, tosave ).unwrap() ); tosave.setPackagesPath( packagescache_path_for_repoinfo( _options, tosave ).unwrap() ); - reposManip().insert(tosave); + reposManip().insert( std::make_pair( tosave.alias(), tosave) ); // check for credentials in Urls - zypp::UrlCredentialExtractor( _options.rootDir ).collect( tosave.baseUrls() ); + zypp::UrlCredentialExtractor( _zyppContext ).collect( tosave.baseUrls() ); zypp::HistoryLog(_options.rootDir).addRepository(tosave); @@ -608,13 +618,15 @@ namespace zyppng } } - template - expected RepoManager::removeRepository( const RepoInfo & info, ProgressObserverRef myProgress ) + template + expected RepoManager::removeRepository( RepoInfo & info, ProgressObserverRef myProgress ) { try { ProgressObserver::setup( myProgress, zypp::str::form(_("Removing repository '%s'"), info.label().c_str()), 1 ); ProgressObserver::start( myProgress ); + prepareRepoInfo(info).unwrap(); + MIL << "Going to delete repo " << info.alias() << std::endl; for( const auto &repo : repos() ) @@ -622,14 +634,14 @@ namespace zyppng // they can be the same only if the provided is empty, that means // the provided repo has no alias // then skip - if ( (!info.alias().empty()) && ( info.alias() != repo.alias() ) ) + if ( (!info.alias().empty()) && ( info.alias() != repo.first ) ) continue; // TODO match by url // we have a matching repository, now we need to know // where it does come from. - RepoInfo todelete = repo; + RepoInfo todelete = repo.second; if (todelete.filepath().empty()) { ZYPP_THROW(zypp::repo::RepoException( todelete, _("Can't figure out where the repo is stored.") )); @@ -637,7 +649,9 @@ namespace zyppng else { // figure how many repos are there in the file: - std::list filerepos = repositories_in_file(todelete.filepath()).unwrap(); + std::list filerepos = repositories_in_file( _zyppContext, todelete.filepath()).unwrap(); + std::for_each( filerepos.begin (), filerepos.end(), [this]( RepoInfo &info ){ prepareRepoInfo(info).unwrap(); }); + if ( filerepos.size() == 0 // bsc#984494: file may have already been deleted ||(filerepos.size() == 1 && filerepos.front().alias() == todelete.alias() ) ) { @@ -681,7 +695,7 @@ namespace zyppng // now delete metadata (#301037) cleanMetadata( todelete, ProgressObserver::makeSubTask( myProgress, 0.4 )).unwrap(); cleanPackages( todelete, ProgressObserver::makeSubTask( myProgress, 0.4 ), true/*isAutoClean*/ ).unwrap(); - reposManip().erase(todelete); + reposManip().erase(todelete.alias()); MIL << todelete.alias() << " successfully deleted." << std::endl; zypp::HistoryLog(_options.rootDir).removeRepository(todelete); @@ -697,8 +711,8 @@ namespace zyppng } } - template - expected RepoManager::modifyRepository( const std::string & alias, const RepoInfo & newinfo_r, ProgressObserverRef myProgress ) + template + expected RepoManager::modifyRepository(const std::string & alias, RepoInfo newinfo_r, ProgressObserverRef myProgress ) { try { @@ -706,7 +720,9 @@ namespace zyppng ProgressObserver::start( myProgress ); RepoInfo toedit = getRepositoryInfo(alias).unwrap(); + RepoInfo newinfo( newinfo_r ); // need writable copy to upadte housekeeping data + prepareRepoInfo (newinfo).unwrap (); // check if the new alias already exists when renaming the repo if ( alias != newinfo.alias() && hasRepo( newinfo.alias() ) ) @@ -722,7 +738,8 @@ namespace zyppng { ProgressObserver::increase( myProgress ); // figure how many repos are there in the file: - std::list filerepos = repositories_in_file(toedit.filepath()).unwrap(); + std::list filerepos = repositories_in_file( _zyppContext, toedit.filepath()).unwrap(); + std::for_each( filerepos.begin (), filerepos.end(), [this]( RepoInfo &info ){ prepareRepoInfo(info).unwrap(); }); // there are more repos in the same file // write them back except the deleted one. @@ -766,18 +783,19 @@ namespace zyppng ProgressObserver::increase( myProgress ); - reposManip().erase(toedit); - reposManip().insert(newinfo); + reposManip().erase(toedit.alias()); + reposManip().insert(std::make_pair(newinfo.alias(), newinfo)); ProgressObserver::increase( myProgress ); // check for credentials in Urls - zypp::UrlCredentialExtractor( _options.rootDir ).collect( newinfo.baseUrls() ); + zypp::UrlCredentialExtractor( _zyppContext ).collect( newinfo.baseUrls() ); zypp::HistoryLog(_options.rootDir).modifyRepository(toedit, newinfo); MIL << "repo " << alias << " modified" << std::endl; ProgressObserver::finish ( myProgress ); - return expected::success( newinfo ); + + return expected::success(newinfo); } } catch ( ... ) { @@ -786,14 +804,14 @@ namespace zyppng } } - template - expected RepoManager::getRepositoryInfo( const std::string & alias ) + template + expected RepoManager::getRepositoryInfo( const std::string & alias ) { try { RepoConstIterator it( findAlias( alias, repos() ) ); if ( it != repos().end() ) - return make_expected_success(*it); - RepoInfo info; + return make_expected_success(it->second); + RepoInfo info( _zyppContext ); info.setAlias( alias ); ZYPP_THROW( zypp::repo::RepoNotFoundException(info) ); } catch ( ... ) { @@ -802,20 +820,20 @@ namespace zyppng } - template - expected RepoManager::getRepositoryInfo( const zypp::Url & url, const zypp::url::ViewOption & urlview ) + template + expected RepoManager::getRepositoryInfo( const zypp::Url & url, const zypp::url::ViewOption & urlview ) { try { for_( it, repoBegin(), repoEnd() ) { - for_( urlit, (*it).baseUrlsBegin(), (*it).baseUrlsEnd() ) + for_( urlit, it->second.baseUrlsBegin(), it->second.baseUrlsEnd() ) { if ( (*urlit).asString(urlview) == url.asString(urlview) ) - return make_expected_success(*it); + return make_expected_success(it->second); } } - RepoInfo info; + RepoInfo info( _zyppContext ); info.setBaseUrl( url ); ZYPP_THROW( zypp::repo::RepoNotFoundException(info) ); @@ -824,81 +842,83 @@ namespace zyppng } } - template - expected::RefreshCheckStatus> RepoManager::checkIfToRefreshMetadata(const RepoInfo &info, const zypp::Url &url, RawMetadataRefreshPolicy policy) + template + typename RepoManager::template MaybeAsyncRef::RefreshCheckStatus>>> RepoManager::checkIfToRefreshMetadata( RepoInfo info, const zypp::Url &url, RawMetadataRefreshPolicy policy) { using namespace zyppng::operators; - return joinPipeline( _zyppContext, - RepoManagerWorkflow::refreshGeoIPData( _zyppContext, {url} ) - | [this, info](auto) { return zyppng::repo::RefreshContext::create( _zyppContext, info, shared_this>() ); } - | and_then( [this, url, policy]( zyppng::repo::RefreshContextRef &&refCtx ) { + return RepoManagerWorkflow::refreshGeoIPData( _zyppContext, {url} ) + | [this, info](auto) { return prepareRefreshContext(info); } + | and_then( [this, url, policy]( zyppng::repo::RefreshContextRef &&refCtx ) { refCtx->setPolicy ( static_cast( policy ) ); - return _zyppContext->provider()->prepareMedia( url, zyppng::ProvideMediaSpec() ) - | and_then( [ r = std::move(refCtx) ]( auto mediaHandle ) mutable { return zyppng::RepoManagerWorkflow::checkIfToRefreshMetadata ( std::move(r), std::move(mediaHandle), nullptr ); } ); - }) - ); + return refCtx->engageLock( ) + | and_then( [this, url, refCtx ]( zypp::Deferred lockRef ) { + return _zyppContext->provider()->prepareMedia( url, zyppng::ProvideMediaSpec(_zyppContext) ) + | and_then( [ refCtx ]( auto mediaHandle ) mutable { return zyppng::RepoManagerWorkflow::checkIfToRefreshMetadata ( std::move(refCtx), std::move(mediaHandle), nullptr ); } ) + | and_then( [ refCtx, lockRef ]( auto checkStatus ){ return make_expected_success (std::make_pair( refCtx->repoInfo(), checkStatus ) ); }); + }); + }); } - template - expected RepoManager::refreshMetadata( const RepoInfo &info, RawMetadataRefreshPolicy policy, ProgressObserverRef myProgress ) + template + typename RepoManager::template MaybeAsyncRef> RepoManager::refreshMetadata( RepoInfo info, RawMetadataRefreshPolicy policy, ProgressObserverRef myProgress ) { using namespace zyppng::operators; // helper callback in case the repo type changes on the remote // do NOT capture by reference here, since this is possibly executed async const auto &updateProbedType = [this, info = info]( zypp::repo::RepoType repokind ) { // update probed type only for repos in system - for( const auto &repo : repos() ) { - if ( info.alias() == repo.alias() ) + for( const auto &repoIter : repos() ) { + if ( info.alias() == repoIter.first ) { - RepoInfo modifiedrepo = repo; + RepoInfo modifiedrepo = repoIter.second; modifiedrepo.setType( repokind ); // don't modify .repo in refresh. - // modifyRepository( info.alias(), modifiedrepo ); + // modifyRepository( info.alias(), modifiedrepo ); m break; } } }; - return joinPipeline( _zyppContext, // make sure geoIP data is up 2 date, but ignore errors - RepoManagerWorkflow::refreshGeoIPData( _zyppContext, info.baseUrls() ) - | [this, info = info](auto) { return zyppng::repo::RefreshContext::create( _zyppContext, info, shared_this>()); } - | and_then( [policy, myProgress, cb = updateProbedType]( repo::RefreshContextRef refCtx ) { + return RepoManagerWorkflow::refreshGeoIPData( _zyppContext, info.baseUrls() ) + | [this, info = info](auto) { return prepareRefreshContext(info); } + | and_then( [policy, myProgress, cb = updateProbedType]( repo::RefreshContextRef refCtx ) { refCtx->setPolicy( static_cast( policy ) ); // in case probe detects a different repokind, update our internal repos - refCtx->connectFunc( &repo::RefreshContext::sigProbedTypeChanged, cb ); + refCtx->connectFunc( &repo::RefreshContext::sigProbedTypeChanged, cb ); return zyppng::RepoManagerWorkflow::refreshMetadata ( std::move(refCtx), myProgress ); }) - | and_then([rMgr = shared_this>()]( repo::RefreshContextRef ctx ) { + | and_then([rMgr = shared_this>()]( repo::RefreshContextRef ctx ) { if ( ! isTmpRepo( ctx->repoInfo() ) ) rMgr->reposManip(); // remember to trigger appdata refresh - return expected::success (); - })); + return expected::success ( ctx->repoInfo() ); + }); } - template - std::vector>> RepoManager::refreshMetadata( std::vector infos, RawMetadataRefreshPolicy policy, ProgressObserverRef myProgress ) + template + typename RepoManager::template MaybeAsyncRef > > > RepoManager::refreshMetadata( std::vector infos, RawMetadataRefreshPolicy policy, ProgressObserverRef myProgress ) { using namespace zyppng::operators; ProgressObserver::setup( myProgress, "Refreshing repositories" , 1 ); - auto r = std::move(infos) + return std::move(infos) | transform( [this, policy, myProgress]( const RepoInfo &info ) { auto subProgress = ProgressObserver::makeSubTask( myProgress, 1.0, zypp::str::Str() << _("Refreshing Repository: ") << info.alias(), 3 ); + ProgressObserver::start( subProgress ); // helper callback in case the repo type changes on the remote // do NOT capture by reference here, since this is possibly executed async const auto &updateProbedType = [this, info = info]( zypp::repo::RepoType repokind ) { // update probed type only for repos in system - for( const auto &repo : repos() ) { - if ( info.alias() == repo.alias() ) + for( const auto &repoIter : repos() ) { + if ( info.alias() == repoIter.first ) { - RepoInfo modifiedrepo = repo; + RepoInfo modifiedrepo = repoIter.second; modifiedrepo.setType( repokind ); // don't modify .repo in refresh. // modifyRepository( info.alias(), modifiedrepo ); @@ -907,22 +927,22 @@ namespace zyppng } }; - auto sharedThis = shared_this>(); + auto sharedThis = shared_this>(); return // make sure geoIP data is up 2 date, but ignore errors RepoManagerWorkflow::refreshGeoIPData( _zyppContext, info.baseUrls() ) - | [sharedThis, info = info](auto) { return zyppng::repo::RefreshContext::create( sharedThis->_zyppContext, info, sharedThis); } + | [sharedThis, info = info](auto) { return sharedThis->prepareRefreshContext(info); } | inspect( incProgress( subProgress ) ) - | and_then( [policy, subProgress, cb = updateProbedType]( repo::RefreshContextRef refCtx ) { + | and_then( [policy, subProgress, cb = updateProbedType]( repo::RefreshContextRef refCtx ) { refCtx->setPolicy( static_cast( policy ) ); // in case probe detects a different repokind, update our internal repos - refCtx->connectFunc( &repo::RefreshContext::sigProbedTypeChanged, cb ); + refCtx->connectFunc( &repo::RefreshContext::sigProbedTypeChanged, cb ); return zyppng::RepoManagerWorkflow::refreshMetadata ( std::move(refCtx), ProgressObserver::makeSubTask( subProgress ) ); }) | inspect( incProgress( subProgress ) ) - | and_then([subProgress]( repo::RefreshContextRef ctx ) { + | and_then([subProgress]( repo::RefreshContextRef ctx ) { if ( ! isTmpRepo( ctx->repoInfo() ) ) ctx->repoManager()->reposManip(); // remember to trigger appdata refresh @@ -930,9 +950,11 @@ namespace zyppng return zyppng::RepoManagerWorkflow::buildCache ( std::move(ctx), CacheBuildPolicy::BuildIfNeeded, ProgressObserver::makeSubTask( subProgress ) ); }) | inspect( incProgress( subProgress ) ) - | [ info = info, subProgress ]( expected> result ) { + | [ info = info, subProgress ]( expected> result ) { if ( result ) { ProgressObserver::finish( subProgress, ProgressObserver::Success ); + RepoInfo info = result.get()->repoInfo(); + info.setName( info.name() + " refreshed" ); return std::make_pair(info, expected::success() ); } else { ProgressObserver::finish( subProgress, ProgressObserver::Error ); @@ -945,8 +967,6 @@ namespace zyppng return res; } ); - - return joinPipeline( _zyppContext, r ); } /** Probe the metadata type of a repository located at \c url. @@ -955,52 +975,56 @@ namespace zyppng * \note Metadata in local cache directories must be probed using \ref probeCache as * a cache path must not be rewritten (bnc#946129) */ - template - expected RepoManager::probe(const zypp::Url &url, const zypp::Pathname &path) const + template + typename RepoManager::template MaybeAsyncRef> RepoManager::probe(const zypp::Url &url, const zypp::Pathname &path) const { using namespace zyppng::operators; - return joinPipeline( _zyppContext, - RepoManagerWorkflow::refreshGeoIPData( _zyppContext, {url} ) - | [this, url=url](auto) { return _zyppContext->provider()->prepareMedia( url, zyppng::ProvideMediaSpec() ); } + return RepoManagerWorkflow::refreshGeoIPData( _zyppContext, {url} ) + | [this, url=url](auto) { return _zyppContext->provider()->prepareMedia( url, zyppng::ProvideMediaSpec(_zyppContext) ); } | and_then( [this, path = path]( auto mediaHandle ) { return RepoManagerWorkflow::probeRepoType( _zyppContext, std::forward(mediaHandle), path ); - })); + }); } - template - expected RepoManager::buildCache( const RepoInfo &info, CacheBuildPolicy policy, ProgressObserverRef myProgress ) + template + typename RepoManager::template MaybeAsyncRef> RepoManager::buildCache( RepoInfo info, CacheBuildPolicy policy, ProgressObserverRef myProgress ) { using namespace zyppng::operators; - return joinPipeline( _zyppContext, - zyppng::repo::RefreshContext::create( _zyppContext, info, shared_this>() ) - | and_then( [policy, myProgress]( repo::RefreshContextRef refCtx ) { + + return cloneAndPrepare ( info ) + | and_then( [this ]( auto info ) { return zyppng::repo::RefreshContext::create( shared_this>(), info ); } ) + | and_then( [policy, myProgress]( repo::RefreshContextRef refCtx ) { return zyppng::RepoManagerWorkflow::buildCache ( std::move(refCtx), policy, myProgress ); }) - | and_then([]( auto ){ return expected::success(); }) - ); + | and_then([]( zyppng::repo::RefreshContextRef ctx ){ return make_expected_success(ctx->repoInfo());}) + ; } - template - expected RepoManager::addRepository(const RepoInfo &info, ProgressObserverRef myProgress) + template + typename RepoManager::template MaybeAsyncRef> RepoManager::addRepository( RepoInfo info, ProgressObserverRef myProgress ) { - return joinPipeline( _zyppContext, RepoManagerWorkflow::addRepository( shared_this>(), info, std::move(myProgress) ) ); + using namespace zyppng::operators; + return cloneAndPrepare (info) + | and_then( [this, myProgress]( RepoInfo info ){ + return RepoManagerWorkflow::addRepository( shared_this>(), info, std::move(myProgress) ); + }); } - template - expected RepoManager::addRepositories(const zypp::Url &url, ProgressObserverRef myProgress) + template + typename RepoManager::template MaybeAsyncRef> RepoManager::addRepositories( const zypp::Url &url, ProgressObserverRef myProgress ) { using namespace zyppng::operators; - return joinPipeline( _zyppContext, RepoManagerWorkflow::addRepositories( shared_this>(), url, std::move(myProgress))); + return RepoManagerWorkflow::addRepositories( shared_this>(), url, std::move(myProgress)); } - template - expected RepoManager::probeService( const zypp::Url & url ) const + template + typename RepoManager::template MaybeAsyncRef> RepoManager::probeService( const zypp::Url & url ) const { - return joinPipeline( _zyppContext, RepoServicesWorkflow::probeServiceType ( _zyppContext, url ) ); + return RepoServicesWorkflow::probeServiceType ( _zyppContext, url ); } - template - expected RepoManager::addService( const ServiceInfo & service ) + template + expected RepoManager::addService( const ServiceInfo & service ) { try { @@ -1014,10 +1038,10 @@ namespace zyppng // of the .service file. Finaly insert into the service list. ServiceInfo toSave( service ); saveService( toSave ).unwrap(); - _services.insert( toSave ); + _services.insert( std::make_pair( toSave.alias(), toSave ) ); // check for credentials in Url - zypp::UrlCredentialExtractor( _options.rootDir ).collect( toSave.url() ); + zypp::UrlCredentialExtractor( _zyppContext ).collect( toSave.url() ); MIL << "added service " << toSave.alias() << std::endl; @@ -1028,44 +1052,52 @@ namespace zyppng return expected::success(); } - template - expected RepoManager::refreshService( const std::string &alias, const RefreshServiceOptions &options_r ) + template + typename RepoManager::template MaybeAsyncRef> RepoManager::refreshService( const std::string &alias, const RefreshServiceOptions &options_r ) { - return joinPipeline ( _zyppContext, RepoServicesWorkflow::refreshService( shared_this>(), getService( alias ), options_r ) ); + const auto &serviceOpt = getService(alias); + if( !serviceOpt ) + { + ZYPP_THROW(zypp::repo::ServiceException( _("Can't find service alias.") )); + } + return RepoServicesWorkflow::refreshService( shared_this>(), *serviceOpt, options_r ); } /*! * \todo ignore ServicePluginInformalException in calling code */ - template - expected RepoManager::refreshServices(const RefreshServiceOptions &options_r) + template + typename RepoManager::template MaybeAsyncRef> RepoManager::refreshServices(const RefreshServiceOptions &options_r) { using namespace zyppng::operators; + // copy the set of services since refreshService // can eventually invalidate the iterator - ServiceSet servicesCopy( serviceBegin(), serviceEnd() ); - - // convert the set into a vector, transform needs a container with push_back support + // save it into a vector, transform needs a container with push_back support std::vector servicesVec; - std::copy( std::make_move_iterator(servicesCopy.begin()), std::make_move_iterator(servicesCopy.end()), std::back_inserter(servicesVec)); + std::transform( serviceBegin(), serviceEnd(), std::back_inserter(servicesVec), []( const auto &pair ){ return pair.second;} ); - return joinPipeline( _zyppContext, - std::move(servicesVec) - | transform( [options_r, this]( ServiceInfo i ){ return RepoServicesWorkflow::refreshService( shared_this>(), i, options_r ); } ) + return std::move(servicesVec) + | transform( [options_r, this]( ServiceInfo i ){ return RepoServicesWorkflow::refreshService( shared_this>(), i, options_r ); } ) | join() - | collect() - ); + | collect(); } //////////////////////////////////////////////////////////////////////////// - template - expected RepoManager::removeService( const std::string & alias ) + template + expected RepoManager::removeService( const std::string & alias ) { try { MIL << "Going to delete service " << alias << std::endl; - const ServiceInfo & service = getService( alias ); + const auto &serviceOpt = getService(alias); + if( !serviceOpt ) + { + ZYPP_THROW(zypp::repo::ServiceException( _("Can't find service alias.") )); + } + + const ServiceInfo & service = *serviceOpt; zypp::Pathname location = service.filepath(); if( location.empty() ) @@ -1073,11 +1105,11 @@ namespace zyppng ZYPP_THROW(zypp::repo::ServiceException( service, _("Can't figure out where the service is stored.") )); } - ServiceSet tmpSet; - zypp::parser::ServiceFileReader( location, ServiceCollector(tmpSet) ); + ServiceMap tmpMap; + parser::ServiceFileReader( _zyppContext, location, ServiceCollector(tmpMap) ); // only one service definition in the file - if ( tmpSet.size() == 1 ) + if ( tmpMap.size() == 1 ) { if ( zypp::filesystem::unlink(location) != 0 ) { @@ -1097,10 +1129,10 @@ namespace zyppng ZYPP_THROW( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), location.c_str() ))); } - for_(it, tmpSet.begin(), tmpSet.end()) + for_(it, tmpMap.begin(), tmpMap.end()) { - if( it->alias() != alias ) - it->dumpAsIniOn(file); + if( it->first != alias ) + it->second.dumpAsIniOn(file); } MIL << alias << " successfully deleted from file " << location << std::endl; @@ -1121,23 +1153,24 @@ namespace zyppng } } - template - expected RepoManager::modifyService( const std::string & oldAlias, const ServiceInfo & newService ) + template + expected RepoManager::modifyService( const std::string & oldAlias, ServiceInfo newService ) { try { MIL << "Going to modify service " << oldAlias << std::endl; + if ( newService.type() == zypp::repo::ServiceType::PLUGIN ) + { + ZYPP_THROW(zypp::repo::ServicePluginImmutableException( newService )); + } - // we need a writable copy to link it to the file where - // it is saved if we modify it - ServiceInfo service(newService); - - if ( service.type() == zypp::repo::ServiceType::PLUGIN ) + const auto &oldServiceOpt = getService(oldAlias); + if( !oldServiceOpt ) { - ZYPP_THROW(zypp::repo::ServicePluginImmutableException( service )); + ZYPP_THROW(zypp::repo::ServiceException( _("Can't find service alias.") )); } - const ServiceInfo & oldService = getService(oldAlias); + const ServiceInfo &oldService = *oldServiceOpt; zypp::Pathname location = oldService.filepath(); if( location.empty() ) @@ -1146,49 +1179,49 @@ namespace zyppng } // remember: there may multiple services being defined in one file: - ServiceSet tmpSet; - zypp::parser::ServiceFileReader( location, ServiceCollector(tmpSet) ); + ServiceMap tmpMap; + parser::ServiceFileReader( _zyppContext, location, ServiceCollector(tmpMap) ); zypp::filesystem::assert_dir(location.dirname()); std::ofstream file(location.c_str()); - for_(it, tmpSet.begin(), tmpSet.end()) + for_(it, tmpMap.begin(), tmpMap.end()) { - if( *it != oldAlias ) - it->dumpAsIniOn(file); + if( it->first != oldAlias ) + it->second.dumpAsIniOn(file); } - service.dumpAsIniOn(file); + newService.dumpAsIniOn(file); file.close(); - service.setFilepath(location); + newService.setFilepath(location); - _services.erase(oldAlias); - _services.insert(service); + _services.erase ( oldAlias ); + _services.insert ( std::make_pair( newService.alias(), newService) ); // check for credentials in Urls - zypp::UrlCredentialExtractor( _options.rootDir ).collect( service.url() ); + zypp::UrlCredentialExtractor( _zyppContext ).collect( newService.url() ); // changed properties affecting also repositories - if ( oldAlias != service.alias() // changed alias - || oldService.enabled() != service.enabled() ) // changed enabled status + if ( oldAlias != newService.alias() // changed alias + || oldService.enabled() != newService.enabled() ) // changed enabled status { std::vector toModify; getRepositoriesInService(oldAlias, std::back_inserter(toModify)); for_( it, toModify.begin(), toModify.end() ) { - if ( oldService.enabled() != service.enabled() ) + if ( oldService.enabled() != newService.enabled() ) { - if ( service.enabled() ) + if ( newService.enabled() ) { // reset to last refreshs state - const auto & last = service.repoStates().find( it->alias() ); - if ( last != service.repoStates().end() ) + const auto & last = newService.repoStates().find( it->alias() ); + if ( last != newService.repoStates().end() ) it->setEnabled( last->second.enabled ); } else it->setEnabled( false ); } - if ( oldAlias != service.alias() ) - it->setService(service.alias()); + if ( oldAlias != newService.alias() ) + it->setService(newService.alias()); modifyRepository(it->alias(), *it).unwrap(); } @@ -1204,8 +1237,8 @@ namespace zyppng } - template - expected RepoManager::saveService( ServiceInfo & service ) const + template + expected RepoManager::saveService( ServiceInfo & service ) const { try { @@ -1247,8 +1280,8 @@ namespace zyppng * \param dir Directory where the file needs to be unique * \param basefilename string to base the filename on. */ - template - zypp::Pathname RepoManager::generateNonExistingName( const zypp::Pathname & dir, + template + zypp::Pathname RepoManager::generateNonExistingName( const zypp::Pathname & dir, const std::string & basefilename ) const { std::string final_filename = basefilename; @@ -1261,8 +1294,8 @@ namespace zyppng return dir + zypp::Pathname(final_filename); } - template - expected RepoManager::touchIndexFile(const RepoInfo &info, const RepoManagerOptions &options) + template + expected RepoManager::touchIndexFile(const RepoInfo &info, const RepoManagerOptions &options) { try { zypp::Pathname productdatapath = rawproductdata_path_for_repoinfo( options, info ).unwrap(); @@ -1303,20 +1336,14 @@ namespace zyppng return expected::success(); } - template - expected RepoManager::refreshGeoIp( const RepoInfo::url_set &urls ) - { - return joinPipeline( _zyppContext, RepoManagerWorkflow::refreshGeoIPData( _zyppContext, urls) ); - } - - template - expected RepoManager::touchIndexFile( const RepoInfo & info ) + template + expected RepoManager::touchIndexFile( const RepoInfo & info ) { return touchIndexFile( info, _options ); } - template - expected RepoManager::init_knownServices() + template + expected RepoManager::init_knownServices() { try { zypp::Pathname dir = _options.knownServicesPath; @@ -1332,11 +1359,11 @@ namespace zyppng //str::regex allowedServiceExt("^\\.service(_[0-9]+)?$"); for_(it, entries.begin(), entries.end() ) { - zypp::parser::ServiceFileReader(*it, ServiceCollector(_services)); + parser::ServiceFileReader( _zyppContext, *it, ServiceCollector(_services)); } } - zypp::repo::PluginServices(_options.pluginsPath/"services", ServiceCollector(_services)); + repo::PluginServices( _zyppContext, _options.pluginsPath/"services", ServiceCollector(_services) ); return expected::success(); @@ -1389,8 +1416,8 @@ namespace zyppng } } // namespace - template - expected RepoManager::init_knownRepositories() + template + expected RepoManager::init_knownRepositories() { try { @@ -1400,14 +1427,14 @@ namespace zyppng { std::list repoEscAliases; std::list orphanedRepos; - for ( RepoInfo & repoInfo : repositories_in_dir( _zyppContext, _options.knownReposPath ) ) + for ( const RepoInfo & rI : repositories_in_dir( _zyppContext, _zyppContext->progressObserver(), _options.knownReposPath ) ) { - // set the metadata path for the repo - repoInfo.setMetadataPath( rawcache_path_for_repoinfo(_options, repoInfo).unwrap() ); - // set the downloaded packages path for the repo - repoInfo.setPackagesPath( packagescache_path_for_repoinfo(_options, repoInfo).unwrap() ); + RepoInfo repoInfo = rI; + + // initialize the paths' + prepareRepoInfo(repoInfo).unwrap(); // remember it - _reposX.insert( repoInfo ); // direct access via _reposX in ctor! no reposManip. + _reposX.insert( std::make_pair( repoInfo.alias(), repoInfo ) ); // direct access via _reposX in ctor! no reposManip. // detect orphaned repos belonging to a deleted service const std::string & serviceAlias( repoInfo.service() ); @@ -1430,15 +1457,16 @@ namespace zyppng // translators: Cleanup a repository previously owned by a meanwhile unknown (deleted) service. // %1% = service name // %2% = repository name - JobReportHelper(_zyppContext).warning( zypp::str::Format(_("Unknown service '%1%': Removing orphaned service repository '%2%'")) + JobReportHelper(_zyppContext, _zyppContext->progressObserver()).warning( zypp::str::Format(_("Unknown service '%1%': Removing orphaned service repository '%2%'")) % repoInfo.service() % repoInfo.alias() ); try { - removeRepository( repoInfo ).unwrap(); + RepoInfo ri = repoInfo; + removeRepository( ri ).unwrap(); } catch ( const zypp::Exception & caugth ) { - JobReportHelper(_zyppContext).error( caugth.asUserHistory() ); + JobReportHelper(_zyppContext, _zyppContext->progressObserver()).error( caugth.asUserHistory() ); } } } @@ -1474,6 +1502,6 @@ namespace zyppng } // explicitely intantiate the template types we want to work with - template class RepoManager; - template class RepoManager; + template class RepoManager; + template class RepoManager; } // namespace zyppng diff --git a/zypp/ng/repomanager.h b/zypp/ng/repomanager.h index 8b198da114..3a0a33ff2f 100644 --- a/zypp/ng/repomanager.h +++ b/zypp/ng/repomanager.h @@ -12,6 +12,7 @@ #ifndef ZYPP_NG_REPOMANAGER_INCLUDED #define ZYPP_NG_REPOMANAGER_INCLUDED + #include #include @@ -21,6 +22,10 @@ #include #include #include +#include +#include +#include + #include #include @@ -30,25 +35,20 @@ #include #include #include +#include namespace zyppng { - - using RepoInfo = zypp::RepoInfo; using RepoStatus = zypp::RepoStatus; - using RepoInfoList = zypp::RepoInfoList; - using ServiceInfo = zypp::ServiceInfo; using RepoManagerOptions = zypp::RepoManagerOptions; - ZYPP_FWD_DECL_TYPE_WITH_REFS( Context ); - ZYPP_FWD_DECL_TYPE_WITH_REFS( SyncContext ); ZYPP_FWD_DECL_TYPE_WITH_REFS( ProgressObserver ); - ZYPP_FWD_DECL_TEMPL_TYPE_WITH_REFS_ARG1 ( RepoManager, ZyppContextRefType ); - - using SyncRepoManager = RepoManager; - using SyncRepoManagerRef = RepoManagerRef; + ZYPP_FWD_DECL_TEMPL_TYPE_WITH_REFS_ARG1 ( RepoManager, ZyppContextType ); + ZYPP_FWD_DECL_TEMPL_TYPE_WITH_REFS_ARG1 ( FusionPool, ContextType ); - using AsyncRepoManager = RepoManager; - using AsyncRepoManagerRef = RepoManagerRef; + using SyncRepoManager = RepoManager; + using AsyncRepoManager = RepoManager; + ZYPP_FWD_DECL_REFS( SyncRepoManager ); + ZYPP_FWD_DECL_REFS( AsyncRepoManager ); /** Whether repo is not under RM control and provides its own methadata paths. */ inline bool isTmpRepo( const RepoInfo & info_r ) @@ -79,15 +79,41 @@ namespace zyppng { return expected::success(); } + namespace detail { + template + struct AliasCompare { + AliasCompare( const std::string &alias, const Info &iterValue ) : _res( alias == iterValue.alias() ) {} + operator bool() { + return _res; + } + private: + bool _res; + }; + + template + struct AliasCompare> { + AliasCompare( const std::string &alias, const std::pair &iterValue ) : _res(alias == iterValue.first) { + } + operator bool() { + return _res; + } + private: + bool _res; + }; + } + /** Check if alias_r is present in repo/service container. */ template inline bool foundAliasIn( const std::string & alias_r, Iterator begin_r, Iterator end_r ) { - for_( it, begin_r, end_r ) - if ( it->alias() == alias_r ) - return true; + for_( it, begin_r, end_r ) { + if ( detail::AliasCompare( alias_r, *it ) ) { + return true; + } + } return false; } + /** \overload */ template inline bool foundAliasIn( const std::string & alias_r, const Container & cont_r ) @@ -97,9 +123,11 @@ namespace zyppng { template inline Iterator findAlias( const std::string & alias_r, Iterator begin_r, Iterator end_r ) { - for_( it, begin_r, end_r ) - if ( it->alias() == alias_r ) - return it; + for_( it, begin_r, end_r ) { + if ( detail::AliasCompare( alias_r, *it ) ) { + return it; + } + } return end_r; } /** \overload */ @@ -146,12 +174,16 @@ namespace zyppng { }; //////////////////////////////////////////////////////////////////////////// + + + + /** * Reads RepoInfo's from a repo file. * * \param file pathname of the file to read. */ - expected> repositories_in_file( const zypp::Pathname & file ); + expected> repositories_in_file( ContextBaseRef ctx, const zypp::Pathname & file ); //////////////////////////////////////////////////////////////////////////// @@ -171,7 +203,8 @@ namespace zyppng { inline expected rawcache_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info ) { using namespace zyppng::operators; - return assert_alias(info) | and_then( [&](){ return make_expected_success( isTmpRepo( info ) ? info.metadataPath() : opt.repoRawCachePath / info.escaped_alias()); }); + return assert_alias(info) | and_then( [&](){ + return make_expected_success( isTmpRepo( info ) ? info.metadataPath() : opt.repoRawCachePath / info.escaped_alias()); }); } /** @@ -195,7 +228,7 @@ namespace zyppng { { using namespace zyppng::operators; return assert_alias(info) | - and_then([&](){ return make_expected_success(isTmpRepo( info ) ? info.packagesPath() : opt.repoPackagesCachePath / info.escaped_alias()); }); + and_then([&](){ return make_expected_success( isTmpRepo( info ) ? info.packagesPath() : opt.repoPackagesCachePath / info.escaped_alias()); }); } /** @@ -205,7 +238,7 @@ namespace zyppng { { using namespace zyppng::operators; return assert_alias(info) | - and_then([&](){ return make_expected_success(isTmpRepo( info ) ? info.metadataPath().dirname() / "%SLV%" : opt.repoSolvCachePath / info.escaped_alias()); }); + and_then([&](){ return make_expected_success( isTmpRepo( info ) ? info.metadataPath().dirname() / "%SLV%" : opt.repoSolvCachePath / info.escaped_alias()); }); } //////////////////////////////////////////////////////////////////////////// @@ -214,20 +247,20 @@ namespace zyppng { class ServiceCollector { public: - using ServiceSet = std::set; + using ServiceMap = std::map; - ServiceCollector( ServiceSet & services_r ) + ServiceCollector( ServiceMap & services_r ) : _services( services_r ) {} bool operator()( const ServiceInfo & service_r ) const { - _services.insert( service_r ); + _services.insert( std::make_pair(service_r.alias(), service_r) ); return true; } private: - ServiceSet & _services; + ServiceMap & _services; }; //////////////////////////////////////////////////////////////////////////// @@ -238,20 +271,20 @@ namespace zyppng { * \brief The RepoManager class * Provides knowledge and methods to maintain repo settings and metadata for a given context. * - * Depending on the \a ZyppContextRefType the convenienve functions execute the workflows in + * Depending on the \a ZyppContextType the convenienve functions execute the workflows in * a sync or async way. In sync mode libzypp's legacy reports are executed. Otherwise progress report * is only provided via the \ref ProgressObserver classes. */ - template - class RepoManager : public Base, private MaybeAsyncMixin> + template + class RepoManager : public Base, private MaybeAsyncMixin> { ZYPP_ADD_PRIVATE_CONSTR_HELPER (); - ZYPP_ENABLE_MAYBE_ASYNC_MIXIN( (std::is_same_v) ); + ZYPP_ENABLE_MAYBE_ASYNC_MIXIN( (std::is_same_v) ); public: - using ContextRefType = ZyppContextRefType; - using ContextType = typename ZyppContextRefType::element_type; + using ContextRefType = Ref; + using ContextType = ZyppContextType; using RawMetadataRefreshPolicy = zypp::RepoManagerFlags::RawMetadataRefreshPolicy; using CacheBuildPolicy = zypp::RepoManagerFlags::CacheBuildPolicy; @@ -264,47 +297,88 @@ namespace zyppng { using RefreshServiceOptions = zypp::RepoManagerFlags::RefreshServiceOptions; - ZYPP_DECL_PRIVATE_CONSTR_ARGS (RepoManager, ZyppContextRefType zyppCtx, RepoManagerOptions opt ); + ZYPP_DECL_PRIVATE_CONSTR_ARGS (RepoManager, Ref zyppCtx, RepoManagerOptions opt ); template < typename ...Args > - inline static expected>> create ( Args && ...args ) { + inline static std::shared_ptr> create ( Args && ...args ) { using namespace zyppng::operators; - auto mgr = std::make_shared< RepoManager >( private_constr_t{}, std::forward(args)... ); - return mgr->initialize() | and_then( [mgr](){ return make_expected_success(mgr); } ); + return std::make_shared< RepoManager >( private_constr_t{}, std::forward(args)... ); } public: - - /** - * Functor thats filter RepoInfo by service which it belongs to. - */ - struct MatchServiceAlias - { - public: - MatchServiceAlias( std::string alias_ ) : alias(std::move(alias_)) {} - bool operator()( const RepoInfo & info ) const - { return info.service() == alias; } - private: - std::string alias; - }; - /** ServiceInfo typedefs */ - using ServiceSet = std::set; - using ServiceConstIterator = ServiceSet::const_iterator; - using ServiceSizeType = ServiceSet::size_type; + using ServiceMap = std::map; + using ServiceConstIterator = ServiceMap::const_iterator; + using ServiceSizeType = ServiceMap::size_type; /** RepoInfo typedefs */ - using RepoSet = std::set; - using RepoConstIterator = RepoSet::const_iterator; - using RepoSizeType = RepoSet::size_type; + using RepoMap = std::map; + using RepoConstIterator = RepoMap::const_iterator; + using RepoSizeType = RepoMap::size_type; - virtual ~RepoManager(); + ~RepoManager() override; public: expected initialize (); + /*! + * \brief Fills the repoInfo with the settings for this RepoManager, if not initialized yet. + * + */ + expected prepareRepoInfo ( RepoInfo &info ) + { + try { + + assert_alias (info).unwrap(); + + if ( !info.context() ) { + info.setContext ( _zyppContext ); + } else if ( info.context () != _zyppContext ) { + return expected::error( ZYPP_EXCPT_PTR(zypp::Exception( "RepoInfo must be part of the same context!" )) ); + } + + if ( info.solvCachePath().empty() ) { + info.setSolvCachePath( solv_path_for_repoinfo( _options, info ).unwrap() ); + } + + if ( info.metadataPath().empty() ) { + info.setMetadataPath( rawcache_path_for_repoinfo( _options, info ).unwrap() ); + } + + if ( info.packagesPath().empty() ) { + info.setPackagesPath( packagescache_path_for_repoinfo( _options, info ).unwrap() ); + } + + } catch(...) { + return expected::error( ZYPP_FWD_CURRENT_EXCPT() ); + } + return expected::success(); + } + + /*! + * \brief Copies the repoInfo and fills it with the settings for this RepoManager, if not initialized yet. + */ + expected cloneAndPrepare( RepoInfo info ) { + using namespace zyppng::operators; + return prepareRepoInfo (info) | and_then( [&info](){ return expected::success(info); } ); + } + + /*! + * Prepare a refresh context that can be used to have more control over running a refresh operation + * manually. + */ + expected> prepareRefreshContext( RepoInfo info ) { + using namespace zyppng::operators; + return cloneAndPrepare (info ) | + and_then( [this]( RepoInfo info ) { + return repo::RefreshContext::create( shared_this>(), info ); + } + ); + } + + ContextRefType zyppContext() const { return _zyppContext; } @@ -319,10 +393,10 @@ namespace zyppng { bool hasRepo( const std::string & alias ) const { return foundAliasIn( alias, repos() ); } - RepoInfo getRepo( const std::string & alias ) const + std::optional getRepo( const std::string & alias ) const { RepoConstIterator it( findAlias( alias, repos() ) ); - return it == repos().end() ? RepoInfo::noRepo : *it; + return it == repos().end() ? std::optional() : it->second; } public: @@ -364,18 +438,20 @@ namespace zyppng { }); } - expected loadFromCache( const RepoInfo & info, ProgressObserverRef myProgress = nullptr ); + MaybeAsyncRef> loadFromCache( FusionPoolRef fPool, RepoInfo info, ProgressObserverRef myProgress = nullptr ); expected addProbedRepository( RepoInfo info, zypp::repo::RepoType probedType ); - expected removeRepository( const RepoInfo & info, ProgressObserverRef myProgress = nullptr ); + expected removeRepository(RepoInfo &info, ProgressObserverRef myProgress = nullptr ); - expected modifyRepository( const std::string & alias, const RepoInfo & newinfo_r, ProgressObserverRef myProgress = nullptr ); + expected modifyRepository(const std::string & alias, RepoInfo newinfo_r, ProgressObserverRef myProgress = nullptr ); expected getRepositoryInfo( const std::string & alias ); expected getRepositoryInfo( const zypp::Url & url, const zypp::url::ViewOption &urlview ); - expected checkIfToRefreshMetadata( const RepoInfo & info, const zypp::Url & url, RawMetadataRefreshPolicy policy ); + MaybeAsyncRef>> checkIfToRefreshMetadata( RepoInfo info, const zypp::Url & url, RawMetadataRefreshPolicy policy ); + + /** * \short Refresh local raw cache @@ -394,20 +470,20 @@ namespace zyppng { * \todo Currently no progress is generated, especially for the async code * We might need to change this */ - expected refreshMetadata( const RepoInfo & info, RawMetadataRefreshPolicy policy, ProgressObserverRef myProgress = nullptr ); + MaybeAsyncRef> refreshMetadata( RepoInfo info, RawMetadataRefreshPolicy policy, ProgressObserverRef myProgress = nullptr ); - std::vector > > refreshMetadata(std::vector infos, RawMetadataRefreshPolicy policy, ProgressObserverRef myProgress = nullptr ); + MaybeAsyncRef>>> refreshMetadata( std::vector infos, RawMetadataRefreshPolicy policy, ProgressObserverRef myProgress = nullptr ); - expected probe( const zypp::Url & url, const zypp::Pathname & path = zypp::Pathname() ) const; + MaybeAsyncRef> probe( const zypp::Url & url, const zypp::Pathname & path = zypp::Pathname() ) const; - expected buildCache( const RepoInfo & info, CacheBuildPolicy policy, ProgressObserverRef myProgress = nullptr ); + MaybeAsyncRef> buildCache( RepoInfo info, CacheBuildPolicy policy, ProgressObserverRef myProgress = nullptr ); /*! * Adds the repository in \a info and returns the updated \ref RepoInfo object. */ - expected addRepository( const RepoInfo & info, ProgressObserverRef myProgress = nullptr ); + MaybeAsyncRef> addRepository( RepoInfo info, ProgressObserverRef myProgress = nullptr ); - expected addRepositories( const zypp::Url & url, ProgressObserverRef myProgress = nullptr ); + MaybeAsyncRef> addRepositories( const zypp::Url & url, ProgressObserverRef myProgress = nullptr ); public: bool serviceEmpty() const { return _services.empty(); } @@ -418,31 +494,31 @@ namespace zyppng { bool hasService( const std::string & alias ) const { return foundAliasIn( alias, _services ); } - ServiceInfo getService( const std::string & alias ) const + std::optional getService( const std::string & alias ) const { ServiceConstIterator it( findAlias( alias, _services ) ); - return it == _services.end() ? ServiceInfo::noService : *it; + return it == _services.end() ? std::optional() : it->second; } public: - expected probeService( const zypp::Url & url ) const; + MaybeAsyncRef> probeService( const zypp::Url & url ) const; expected addService( const ServiceInfo & service ); expected addService( const std::string & alias, const zypp::Url & url ) - { return addService( ServiceInfo( alias, url ) ); } + { return addService( ServiceInfo( _zyppContext, alias, url ) ); } expected removeService( const std::string & alias ); expected removeService( const ServiceInfo & service ) { return removeService( service.alias() ); } - expected refreshService( const std::string & alias, const RefreshServiceOptions & options_r ); - expected refreshService( const ServiceInfo & service, const RefreshServiceOptions & options_r ) + MaybeAsyncRef> refreshService( const std::string & alias, const RefreshServiceOptions & options_r ); + MaybeAsyncRef> refreshService( const ServiceInfo & service, const RefreshServiceOptions & options_r ) { return refreshService( service.alias(), options_r ); } - expected refreshServices( const RefreshServiceOptions & options_r ); + MaybeAsyncRef> refreshServices( const RefreshServiceOptions & options_r ); - expected modifyService( const std::string & oldAlias, const ServiceInfo & newService ); + expected modifyService( const std::string & oldAlias, ServiceInfo newService ); static expected touchIndexFile( const RepoInfo & info, const RepoManagerOptions &options ); @@ -461,19 +537,17 @@ namespace zyppng { }); } - /*! - * Checks for any of the given \a urls if there is no geoip data available, caches the results - * in the metadata cache for 24hrs. The given urls need to be configured as valid geoIP targets ( usually download.opensuse.org ) - */ - expected refreshGeoIp ( const RepoInfo::url_set &urls ); - template void getRepositoriesInService( const std::string & alias, OutputIterator out ) const { - MatchServiceAlias filter( alias ); - std::copy( boost::make_filter_iterator( filter, repos().begin(), repos().end() ), - boost::make_filter_iterator( filter, repos().end(), repos().end() ), - out); + const auto &filter = [&]( const std::pair &elem ){ + return elem.second.service() == alias; + }; + + std::transform( boost::make_filter_iterator( filter, repos().begin(), repos().end() ) + , boost::make_filter_iterator( filter, repos().end(), repos().end() ) + , out + , []( const std::pair &elem ){ return elem.second; } ); } zypp::Pathname generateNonExistingName( const zypp::Pathname & dir, const std::string & basefilename ) const; @@ -494,14 +568,17 @@ namespace zyppng { expected init_knownRepositories(); public: - const RepoSet & repos() const { return _reposX; } - RepoSet & reposManip() { if ( ! _reposDirty ) _reposDirty = true; return _reposX; } + const RepoMap & repos() const { return _reposX; } + RepoMap & reposManip() { if ( ! _reposDirty ) _reposDirty = true; return _reposX; } + + const ServiceMap & services() const { return _services; } + ServiceMap & servicesManip() { return _services; } protected: ContextRefType _zyppContext; RepoManagerOptions _options; - RepoSet _reposX; - ServiceSet _services; + RepoMap _reposX; + ServiceMap _services; zypp_private::repo::PluginRepoverification _pluginRepoverification; zypp::DefaultIntegral _reposDirty; }; diff --git a/zypp/ng/reporthelper.cc b/zypp/ng/reporthelper.cc index fe36524822..079fda5995 100644 --- a/zypp/ng/reporthelper.cc +++ b/zypp/ng/reporthelper.cc @@ -9,252 +9,6 @@ #include "reporthelper.h" -#include -#include - namespace zyppng { - template - BasicReportHelper::BasicReportHelper(ZyppContextRef &&ctx) - : _ctx( std::move(ctx) ) - { } - - template - bool DigestReportHelper::askUserToAcceptNoDigest(const zypp::Pathname &file) - { - if constexpr ( async() ) { - std::string label = (zypp::str::Format(_("No digest for file %s.")) % file ).str(); - auto req = BooleanChoiceRequest::create( label, false, AcceptNoDigestRequest::makeData(file) ); - this->_ctx->sendUserRequest( req ); - return req->choice (); - } else { - return _report->askUserToAcceptNoDigest(file); - } - } - - template - bool DigestReportHelper::askUserToAccepUnknownDigest(const zypp::Pathname &file, const std::string &name) - { - if constexpr ( async() ) { - std::string label = (zypp::str::Format(_("Unknown digest %s for file %s.")) %name % file).str(); - auto req = BooleanChoiceRequest::create( label, false, AcceptUnknownDigestRequest::makeData(file, name) ); - this->_ctx->sendUserRequest( req ); - return req->choice (); - } else { - return _report->askUserToAccepUnknownDigest( file, name ); - } - } - - template - bool DigestReportHelper::askUserToAcceptWrongDigest(const zypp::Pathname &file, const std::string &requested, const std::string &found) - { - if constexpr ( async() ) { - std::string label = (zypp::str::Format(_("Digest verification failed for file '%s'")) % file).str(); - auto req = BooleanChoiceRequest::create( label, false, AcceptWrongDigestRequest::makeData(file, requested, found) ); - this->_ctx->sendUserRequest( req ); - return req->choice (); - } else { - return _report->askUserToAcceptWrongDigest( file, requested, found ); - } - } - - template - bool KeyRingReportHelper::askUserToAcceptUnsignedFile(const std::string &file, const zypp::KeyContext &keycontext) - { - if constexpr ( async() ) { - std::string label; - if (keycontext.empty()) - label = zypp::str::Format( - // TranslatorExplanation: speaking of a file - _("File '%s' is unsigned, continue?")) % file; - else - label = zypp::str::Format( - // TranslatorExplanation: speaking of a file - _("File '%s' from repository '%s' is unsigned, continue?")) - % file % keycontext.repoInfo().asUserString(); - - - auto req = BooleanChoiceRequest::create ( label, false, AcceptUnsignedFileRequest::makeData ( file, keycontext ) ); - this->_ctx->sendUserRequest ( req ); - return req->choice (); - } else { - return _report->askUserToAcceptUnsignedFile( file, keycontext ); - } - } - - template - zypp::KeyRingReport::KeyTrust KeyRingReportHelper::askUserToAcceptKey(const zypp::PublicKey &key, const zypp::KeyContext &keycontext) - { - if constexpr ( async() ) { - auto req = TrustKeyRequest::create( - _("Do you want to reject the key, trust temporarily, or trust always?"), - TrustKeyRequest::KEY_DONT_TRUST, - AcceptKeyRequest::makeData ( key, keycontext ) - ); - this->_ctx->sendUserRequest ( req ); - return static_cast(req->choice()); - } else { - return _report->askUserToAcceptKey( key, keycontext ); - } - } - - template - bool KeyRingReportHelper::askUserToAcceptPackageKey(const zypp::PublicKey &key_r, const zypp::KeyContext &keycontext_r) - { - if constexpr ( async() ) { - ERR << "Not implemented yet" << std::endl; - return false; - } else { - return _report->askUserToAcceptPackageKey ( key_r, keycontext_r ); - } - } - - template - void KeyRingReportHelper::infoVerify(const std::string &file_r, const zypp::PublicKeyData &keyData_r, const zypp::KeyContext &keycontext) - { - if constexpr ( async() ) { - std::string label = zypp::str::Format( _("Key Name: %1%")) % keyData_r.name(); - auto req = ShowMessageRequest::create( label, ShowMessageRequest::MType::Info, VerifyInfoEvent::makeData ( file_r, keyData_r, keycontext) ); - this->_ctx->sendUserRequest ( req ); - } else { - return _report->infoVerify( file_r, keyData_r, keycontext ); - } - } - - template - void KeyRingReportHelper::reportAutoImportKey(const std::list &keyDataList_r, const zypp::PublicKeyData &keySigning_r, const zypp::KeyContext &keyContext_r) - { - if constexpr ( async() ) { - const std::string &lbl = zypp::str::Format( PL_( "Received %1% new package signing key from repository \"%2%\":", - "Received %1% new package signing keys from repository \"%2%\":", - keyDataList_r.size() )) % keyDataList_r.size() % keyContext_r.repoInfo().asUserString(); - this->_ctx->sendUserRequest( ShowMessageRequest::create( lbl, ShowMessageRequest::MType::Info, KeyAutoImportInfoEvent::makeData( keyDataList_r, keySigning_r, keyContext_r) ) ); - } else { - return _report->reportAutoImportKey( keyDataList_r, keySigning_r, keyContext_r ); - } - } - - template - bool KeyRingReportHelper::askUserToAcceptVerificationFailed(const std::string &file, const zypp::PublicKey &key, const zypp::KeyContext &keycontext) - { - if constexpr ( async() ) { - std::string label; - if ( keycontext.empty() ) - // translator: %1% is a file name - label = zypp::str::Format(_("Signature verification failed for file '%1%'.") ) % file; - else - // translator: %1% is a file name, %2% a repositories na me - label = zypp::str::Format(_("Signature verification failed for file '%1%' from repository '%2%'.") ) % file % keycontext.repoInfo().asUserString(); - - // @TODO use a centralized Continue string! - label += std::string(" ") + _("Continue?"); - auto req = BooleanChoiceRequest::create ( label, false, AcceptFailedVerificationRequest::makeData ( file, key, keycontext ) ); - this->_ctx->sendUserRequest ( req ); - return req->choice (); - } else { - return _report->askUserToAcceptVerificationFailed( file, key, keycontext ); - } - } - - template - bool KeyRingReportHelper::askUserToAcceptUnknownKey( const std::string &file, const std::string &id, const zypp::KeyContext &keycontext ) - { - if constexpr ( async() ) { - std::string label; - - if (keycontext.empty()) - label = zypp::str::Format( - // translators: the last %s is gpg key ID - _("File '%s' is signed with an unknown key '%s'. Continue?")) % file % id; - else - label = zypp::str::Format( - // translators: the last %s is gpg key ID - _("File '%s' from repository '%s' is signed with an unknown key '%s'. Continue?")) - % file % keycontext.repoInfo().asUserString() % id; - - auto req = BooleanChoiceRequest::create ( label, false, AcceptUnknownKeyRequest::makeData ( file, id, keycontext ) ); - this->_ctx->sendUserRequest ( req ); - return req->choice (); - } else { - return _report->askUserToAcceptUnknownKey( file, id, keycontext ); - } - } - - template - bool JobReportHelper::debug(std::string msg_r, UserData userData_r) - { - if constexpr ( async() ) { - this->_ctx->sendUserRequest( ShowMessageRequest::create( std::move(msg_r), ShowMessageRequest::MType::Debug, std::move(userData_r) ) ); - return true; - } else { - return zypp::JobReport::debug ( msg_r, userData_r ); - } - } - - template - bool JobReportHelper::info( std::string msg_r, UserData userData_r) - { - if constexpr ( async() ) { - this->_ctx->sendUserRequest( ShowMessageRequest::create( std::move(msg_r), ShowMessageRequest::MType::Info, std::move(userData_r) ) ); - return true; - } else { - return zypp::JobReport::info ( msg_r, userData_r ); - } - } - - template - bool JobReportHelper::warning( std::string msg_r, UserData userData_r) - { - if constexpr ( async() ) { - this->_ctx->sendUserRequest( ShowMessageRequest::create( std::move(msg_r), ShowMessageRequest::MType::Warning, std::move(userData_r) ) ); - return true; - } else { - return zypp::JobReport::warning ( msg_r, userData_r ); - } - } - - template - bool JobReportHelper::error( std::string msg_r, UserData userData_r) - { - if constexpr ( async() ) { - this->_ctx->sendUserRequest( ShowMessageRequest::create( std::move(msg_r), ShowMessageRequest::MType::Error, std::move(userData_r) ) ); - return true; - } else { - return zypp::JobReport::error ( msg_r, userData_r ); - } - } - - template - bool JobReportHelper::important( std::string msg_r, UserData userData_r) - { - if constexpr ( async() ) { - this->_ctx->sendUserRequest( ShowMessageRequest::create( std::move(msg_r), ShowMessageRequest::MType::Important, std::move(userData_r) ) ); - return true; - } else { - return zypp::JobReport::important ( msg_r, userData_r ); - } - } - - template - bool JobReportHelper::data( std::string msg_r, UserData userData_r) - { - if constexpr ( async() ) { - this->_ctx->sendUserRequest( ShowMessageRequest::create( std::move(msg_r), ShowMessageRequest::MType::Data, std::move(userData_r) ) ); - return true; - } else { - return zypp::JobReport::data ( msg_r, userData_r ); - } - } - - // explicitely intantiate the template types we want to work with - template class BasicReportHelper; - template class BasicReportHelper; - template class DigestReportHelper; - template class DigestReportHelper; - template class KeyRingReportHelper; - template class KeyRingReportHelper; - template class JobReportHelper; - template class JobReportHelper; - - } diff --git a/zypp/ng/reporthelper.h b/zypp/ng/reporthelper.h index ea5142a7dc..801e254db0 100644 --- a/zypp/ng/reporthelper.h +++ b/zypp/ng/reporthelper.h @@ -18,22 +18,44 @@ #include #include #include -#include -#include -#include +#include + + +#include +#include +#include +#include #include namespace zyppng { - ZYPP_FWD_DECL_REFS (Context); + struct NewStyleReportTag {}; + struct LegacyStyleReportTag{}; namespace detail { + + template + struct DefaultReportTag; + + template<> + struct DefaultReportTag { + using Type = NewStyleReportTag; + }; + + template<> + struct DefaultReportTag { + using Type = LegacyStyleReportTag; + }; + + template + using default_report_tag_t = NewStyleReportTag; // typename DefaultReportTag::Type; + template class ReportHolder; template - class ReportHolder + class ReportHolder {}; template @@ -41,6 +63,7 @@ namespace zyppng { { public: ReportHolder() : _d( std::make_shared>() ){} + virtual ~ReportHolder(){}; ReportHolder(const ReportHolder &) = default; ReportHolder(ReportHolder &&) = default; @@ -55,9 +78,10 @@ namespace zyppng { }; } - template - class BasicReportHelper { + template + class BasicReportHelper : public MaybeAsyncMixin< std::is_same_v< typename remove_smart_ptr_t::SyncOrAsyncTag, AsyncTag> > { public: + virtual ~BasicReportHelper() = default; BasicReportHelper(const BasicReportHelper &) = default; BasicReportHelper(BasicReportHelper &&) = default; BasicReportHelper &operator=(const BasicReportHelper &) = default; @@ -67,43 +91,80 @@ namespace zyppng { return _ctx; } - static constexpr bool async () { - return std::is_same(); + static constexpr bool useNewStyleReports () { + return std::is_same_v; } protected: - BasicReportHelper( ZyppContextRef &&ctx ); + BasicReportHelper( ZyppContextRef &&ctx, ProgressObserverRef &&taskObserver ) + : _ctx(std::move(ctx)) + , _taskObserver( std::move(taskObserver) ) + { } ZyppContextRef _ctx; + ProgressObserverRef _taskObserver; }; - template - class DigestReportHelper : public BasicReportHelper { + template> + class DigestReportHelper : public BasicReportHelper { public: - using BasicReportHelper::async; + using BasicReportHelper::useNewStyleReports; + + DigestReportHelper(ZyppContextRef r, ProgressObserverRef taskObserver) + : BasicReportHelper(std::move(r), std::move(taskObserver)) {} - DigestReportHelper(ZyppContextRef r) - : BasicReportHelper(std::move(r)) {} + virtual ~DigestReportHelper() = default; DigestReportHelper(const DigestReportHelper &) = default; DigestReportHelper(DigestReportHelper &&) = default; DigestReportHelper &operator=(const DigestReportHelper &) = default; DigestReportHelper &operator=(DigestReportHelper &&) = default; - bool askUserToAcceptNoDigest ( const zypp::Pathname &file ); - bool askUserToAccepUnknownDigest ( const zypp::Pathname &file, const std::string &name ); - bool askUserToAcceptWrongDigest ( const zypp::Pathname &file, const std::string &requested, const std::string &found ); + bool askUserToAcceptNoDigest ( const zypp::Pathname &file ) + { + if constexpr ( useNewStyleReports() ) { + std::string label = (zypp::str::Format(_("No digest for file %s.")) % file ).str(); + auto req = BooleanChoiceRequest::create( label, false, AcceptNoDigestRequest::makeData(file) ); + if ( this->_taskObserver ) this->_taskObserver->sendUserRequest( req ); + return req->choice (); + } else { + return _report->askUserToAcceptNoDigest(file); + } + } + bool askUserToAccepUnknownDigest ( const zypp::Pathname &file, const std::string &name ) + { + if constexpr ( useNewStyleReports() ) { + std::string label = (zypp::str::Format(_("Unknown digest %s for file %s.")) %name % file).str(); + auto req = BooleanChoiceRequest::create( label, false, AcceptUnknownDigestRequest::makeData(file, name) ); + if ( this->_taskObserver ) this->_taskObserver->sendUserRequest( req ); + return req->choice (); + } else { + return _report->askUserToAccepUnknownDigest( file, name ); + } + } + bool askUserToAcceptWrongDigest ( const zypp::Pathname &file, const std::string &requested, const std::string &found ) + { + if constexpr ( useNewStyleReports() ) { + std::string label = (zypp::str::Format(_("Digest verification failed for file '%s'")) % file).str(); + auto req = BooleanChoiceRequest::create( label, false, AcceptWrongDigestRequest::makeData(file, requested, found) ); + if ( this->_taskObserver ) this->_taskObserver->sendUserRequest( req ); + return req->choice (); + } else { + return _report->askUserToAcceptWrongDigest( file, requested, found ); + } + } private: detail::ReportHolder _report; }; - template - class KeyRingReportHelper : public BasicReportHelper { + template> + class KeyRingReportHelper : public BasicReportHelper { public: - using BasicReportHelper::async; + using BasicReportHelper::useNewStyleReports; - KeyRingReportHelper(ZyppContextRef r) - : BasicReportHelper(std::move(r)) {} + KeyRingReportHelper(ZyppContextRef r, ProgressObserverRef taskObserver) + : BasicReportHelper(std::move(r), std::move(taskObserver)) {} + virtual ~KeyRingReportHelper() = default; KeyRingReportHelper(const KeyRingReportHelper &) = default; KeyRingReportHelper(KeyRingReportHelper &&) = default; @@ -112,32 +173,153 @@ namespace zyppng { // -- Key Ring reports -- // - bool askUserToAcceptUnsignedFile( const std::string &file, const zypp::KeyContext &keycontext = {} ); + bool askUserToAcceptUnsignedFile( const std::string &file, const zypp::KeyContext &keycontext = {} ) + { + if constexpr ( useNewStyleReports() ) { + std::string label; + if (keycontext.empty()) + label = zypp::str::Format( + // TranslatorExplanation: speaking of a file + _("File '%s' is unsigned, continue?")) % file; + else + label = zypp::str::Format( + // TranslatorExplanation: speaking of a file + _("File '%s' from repository '%s' is unsigned, continue?")) + % file % keycontext.ngRepoInfo()->asUserString(); + + + auto req = BooleanChoiceRequest::create ( label, false, AcceptUnsignedFileRequest::makeData ( file, keycontext ) ); + if ( this->_taskObserver ) this->_taskObserver->sendUserRequest ( req ); + return req->choice (); + } else { + return _report->askUserToAcceptUnsignedFile( file, keycontext ); + } + } + + zypp::KeyRingReport::KeyTrust askUserToAcceptKey( const zypp::PublicKey &key, const zypp::KeyContext &keycontext = {} ) + { + if constexpr ( useNewStyleReports() ) { + + + auto req = ListChoiceRequest::create( + _("Do you want to reject the key, trust temporarily, or trust always?"), + std::vector{ + { _("r"), _("Reject.") }, + { _("t"), _("Trust temporarily.") }, + { _("a"), _("Trust always.") } + }, + 0, // default is option 0, do not trust + AcceptKeyRequest::makeData ( key, keycontext ) + ); + if ( this->_taskObserver ) this->_taskObserver->sendUserRequest ( req ); + switch (req->choice()) { + default: + case 0: + return zypp::KeyRingReport::KeyTrust::KEY_DONT_TRUST; + case 1: + return zypp::KeyRingReport::KeyTrust::KEY_TRUST_TEMPORARILY; + case 2: + return zypp::KeyRingReport::KEY_TRUST_AND_IMPORT; + + }; + } else { + return _report->askUserToAcceptKey( key, keycontext ); + } + } + + bool askUserToAcceptPackageKey( const zypp::PublicKey &key_r, const zypp::KeyContext &keycontext_r = {} ) + { + if constexpr ( useNewStyleReports() ) { + ERR << "Not implemented yet" << std::endl; + return false; + } else { + return _report->askUserToAcceptPackageKey ( key_r, keycontext_r ); + } + } - zypp::KeyRingReport::KeyTrust askUserToAcceptKey( const zypp::PublicKey &key, const zypp::KeyContext &keycontext = {} ); + void infoVerify( const std::string & file_r, const zypp::PublicKeyData & keyData_r, const zypp::KeyContext &keycontext = {} ) + { + if constexpr ( useNewStyleReports() ) { + std::string label = zypp::str::Format( _("Key Name: %1%")) % keyData_r.name(); + auto req = ShowMessageRequest::create( label, ShowMessageRequest::MType::Info, VerifyInfoEvent::makeData ( file_r, keyData_r, keycontext) ); + if ( this->_taskObserver ) this->_taskObserver->sendUserRequest ( req ); + } else { + return _report->infoVerify( file_r, keyData_r, keycontext ); + } + } - bool askUserToAcceptPackageKey( const zypp::PublicKey &key_r, const zypp::KeyContext &keycontext_r = {} ); + void reportAutoImportKey( const std::list & keyDataList_r, const zypp::PublicKeyData & keySigning_r, const zypp::KeyContext &keyContext_r ) + { + if constexpr ( useNewStyleReports() ) { - void infoVerify( const std::string & file_r, const zypp::PublicKeyData & keyData_r, const zypp::KeyContext &keycontext = {} ); + const auto &repoInfoOpt = keyContext_r.ngRepoInfo(); - void reportAutoImportKey( const std::list & keyDataList_r, const zypp::PublicKeyData & keySigning_r, const zypp::KeyContext &keyContext_r ); + const std::string &lbl = zypp::str::Format( PL_( "Received %1% new package signing key from repository \"%2%\":", + "Received %1% new package signing keys from repository \"%2%\":", + keyDataList_r.size() )) % keyDataList_r.size() % ( repoInfoOpt ? repoInfoOpt->asUserString() : std::string("norepo") ); + if ( this->_taskObserver ) this->_taskObserver->sendUserRequest( ShowMessageRequest::create( lbl, ShowMessageRequest::MType::Info, KeyAutoImportInfoEvent::makeData( keyDataList_r, keySigning_r, keyContext_r) ) ); + } else { + return _report->reportAutoImportKey( keyDataList_r, keySigning_r, keyContext_r ); + } + } - bool askUserToAcceptVerificationFailed( const std::string &file, const zypp::PublicKey &key, const zypp::KeyContext &keycontext = {} ); + bool askUserToAcceptVerificationFailed( const std::string &file, const zypp::PublicKey &key, const zypp::KeyContext &keycontext = {} ) + { + if constexpr ( useNewStyleReports() ) { + std::string label; + if ( keycontext.empty() ) + // translator: %1% is a file name + label = zypp::str::Format(_("Signature verification failed for file '%1%'.") ) % file; + else + // translator: %1% is a file name, %2% a repositories na me + label = zypp::str::Format(_("Signature verification failed for file '%1%' from repository '%2%'.") ) % file % keycontext.ngRepoInfo()->asUserString(); + + // @TODO use a centralized Continue string! + label += std::string(" ") + _("Continue?"); + auto req = BooleanChoiceRequest::create ( label, false, AcceptFailedVerificationRequest::makeData ( file, key, keycontext ) ); + if ( this->_taskObserver ) this->_taskObserver->sendUserRequest ( req ); + return req->choice (); + } else { + return _report->askUserToAcceptVerificationFailed( file, key, keycontext ); + } + } - bool askUserToAcceptUnknownKey( const std::string &file, const std::string &id, const zypp::KeyContext &keycontext = {} ); + bool askUserToAcceptUnknownKey( const std::string &file, const std::string &id, const zypp::KeyContext &keycontext = {} ) + { + if constexpr ( useNewStyleReports() ) { + std::string label; + + if (keycontext.empty()) + label = zypp::str::Format( + // translators: the last %s is gpg key ID + _("File '%s' is signed with an unknown key '%s'. Continue?")) % file % id; + else + label = zypp::str::Format( + // translators: the last %s is gpg key ID + _("File '%s' from repository '%s' is signed with an unknown key '%s'. Continue?")) + % file % keycontext.ngRepoInfo()->asUserString() % id; + + auto req = BooleanChoiceRequest::create ( label, false, AcceptUnknownKeyRequest::makeData ( file, id, keycontext ) ); + if ( this->_taskObserver ) this->_taskObserver->sendUserRequest ( req ); + return req->choice (); + } else { + return _report->askUserToAcceptUnknownKey( file, id, keycontext ); + } + } private: detail::ReportHolder _report; }; - template - class JobReportHelper : public BasicReportHelper { + template> + class JobReportHelper : public BasicReportHelper { public: - using BasicReportHelper::async; + using BasicReportHelper::useNewStyleReports; - JobReportHelper(ZyppContextRef r) - : BasicReportHelper(std::move(r)) {} + JobReportHelper(ZyppContextRef r, ProgressObserverRef taskObserver) + : BasicReportHelper(std::move(r), std::move(taskObserver)) {} + virtual ~JobReportHelper() = default; JobReportHelper(const JobReportHelper &) = default; JobReportHelper(JobReportHelper &&) = default; @@ -145,22 +327,70 @@ namespace zyppng { JobReportHelper &operator=(JobReportHelper &&) = default; /** send debug message text */ - bool debug( std::string msg_r, UserData userData_r = UserData() ); + bool debug( std::string msg_r, UserData userData_r = UserData() ) + { + if constexpr ( useNewStyleReports() ) { + if ( this->_taskObserver ) this->_taskObserver->sendUserRequest( ShowMessageRequest::create( std::move(msg_r), ShowMessageRequest::MType::Debug, std::move(userData_r) ) ); + return true; + } else { + return zypp::JobReport::debug ( msg_r, userData_r ); + } + } /** send message text */ - bool info( std::string msg_r, UserData userData_r = UserData() ); + bool info( std::string msg_r, UserData userData_r = UserData() ) + { + if constexpr ( useNewStyleReports() ) { + if ( this->_taskObserver ) this->_taskObserver->sendUserRequest( ShowMessageRequest::create( std::move(msg_r), ShowMessageRequest::MType::Info, std::move(userData_r) ) ); + return true; + } else { + return zypp::JobReport::info ( msg_r, userData_r ); + } + } /** send warning text */ - bool warning( std::string msg_r, UserData userData_r = UserData() ); + bool warning( std::string msg_r, UserData userData_r = UserData() ) + { + if constexpr ( useNewStyleReports() ) { + if ( this->_taskObserver ) this->_taskObserver->sendUserRequest( ShowMessageRequest::create( std::move(msg_r), ShowMessageRequest::MType::Warning, std::move(userData_r) ) ); + return true; + } else { + return zypp::JobReport::warning ( msg_r, userData_r ); + } + } /** send error text */ - bool error( std::string msg_r, UserData userData_r = UserData() ); + bool error( std::string msg_r, UserData userData_r = UserData() ) + { + if constexpr ( useNewStyleReports() ) { + if ( this->_taskObserver ) this->_taskObserver->sendUserRequest( ShowMessageRequest::create( std::move(msg_r), ShowMessageRequest::MType::Error, std::move(userData_r) ) ); + return true; + } else { + return zypp::JobReport::error ( msg_r, userData_r ); + } + } /** send important message text */ - bool important( std::string msg_r, UserData userData_r = UserData() ); + bool important( std::string msg_r, UserData userData_r = UserData() ) + { + if constexpr ( useNewStyleReports() ) { + if ( this->_taskObserver ) this->_taskObserver->sendUserRequest( ShowMessageRequest::create( std::move(msg_r), ShowMessageRequest::MType::Important, std::move(userData_r) ) ); + return true; + } else { + return zypp::JobReport::important ( msg_r, userData_r ); + } + } /** send data message */ - bool data( std::string msg_r, UserData userData_r = UserData() ); + bool data( std::string msg_r, UserData userData_r = UserData() ) + { + if constexpr ( useNewStyleReports() ) { + if ( this->_taskObserver ) this->_taskObserver->sendUserRequest( ShowMessageRequest::create( std::move(msg_r), ShowMessageRequest::MType::Data, std::move(userData_r) ) ); + return true; + } else { + return zypp::JobReport::data ( msg_r, userData_r ); + } + } }; } diff --git a/zypp/ng/resource.cc b/zypp/ng/resource.cc new file mode 100644 index 0000000000..9e043b89a5 --- /dev/null +++ b/zypp/ng/resource.cc @@ -0,0 +1,129 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "resource.h" +#include +#include +#include +namespace zyppng { + + namespace detail { + IMPL_PTR_TYPE( ResourceLockData ); + + void ResourceLockData::unref_to( unsigned int n ) const + { + if ( n > 1 ) + return; + + auto ctx = _zyppContext.lock (); + if ( !ctx ) + return; + ctx->lockUnref ( _resourceIdent ); + } + } + + namespace resources { + namespace repo { + std::string REPO_RESOURCE( const RepoInfo &info ) + { + return zypp::str::Format( REPO_RESOURCE_STR.data() ) % info.alias(); + } + + } + } + + ResourceAlreadyLockedException::ResourceAlreadyLockedException( std::string ident ) + : Exception( "Resource Already Locked Exception" ) + , _ident( std::move(ident) ) + { } + + const std::string &ResourceAlreadyLockedException::ident() const + { + return _ident; + } + + std::ostream &ResourceAlreadyLockedException::dumpOn(std::ostream &str) const + { + str << "[" << _ident << "] "; + return Exception::dumpOn( str ); + } + + ResourceLockTimeoutException::ResourceLockTimeoutException(std::string ident) + : Exception( "Resource Lock Timeout Exception" ) + , _ident( std::move(ident) ) + { } + + const std::string &ResourceLockTimeoutException::ident() const + { + return _ident; + } + + std::ostream &ResourceLockTimeoutException::dumpOn(std::ostream &str) const + { + str << "[" << _ident << "] "; + return Exception::dumpOn( str ); + } + + AsyncResourceLockReq::AsyncResourceLockReq( std::string ident, ResourceLockRef::Mode m, uint timeout ) + : _ident( std::move(ident) ) + , _mode( m ) + , _timeout( Timer::create() ) + { + _timeout->setSingleShot (true); + _timeout->connect( &Timer::sigExpired, *this, &AsyncResourceLockReq::onTimeoutExceeded ); + _timeout->start( timeout ); + } + + void AsyncResourceLockReq::setFinished(expected &&lock) + { + _timeout->stop(); + setReady ( std::move(lock) ); + } + + const std::string &AsyncResourceLockReq::ident() const + { + return _ident; + } + + ResourceLockRef::Mode AsyncResourceLockReq::mode() const + { + return _mode; + } + + SignalProxy AsyncResourceLockReq::sigTimeout() + { + return _sigTimeout; + } + + void AsyncResourceLockReq::onTimeoutExceeded( Timer & ) + { + _sigTimeout.emit(*this); + setFinished( expected::error( ZYPP_EXCPT_PTR( ResourceLockTimeoutException(_ident) ) ) ); + } + + ResourceLockRef::ResourceLockRef(detail::ResourceLockData_Ptr data) + : _lockData( std::move(data) ) + { + } + + ContextBaseWeakRef ResourceLockRef::lockContext() const + { + return _lockData->_zyppContext; + } + + const std::string &ResourceLockRef::lockIdent() const + { + return _lockData->_resourceIdent; + } + + ResourceLockRef::Mode ResourceLockRef::mode() const + { + return _lockData->_mode; + } + +} diff --git a/zypp/ng/resource.h b/zypp/ng/resource.h new file mode 100644 index 0000000000..3455c0c599 --- /dev/null +++ b/zypp/ng/resource.h @@ -0,0 +1,162 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/ng/resource.h + * +*/ +#ifndef ZYPP_NG_RESOURCE_INCLUDED +#define ZYPP_NG_RESOURCE_INCLUDED + +#include +#include + +#include +#include + +#include +#include +#include + +namespace zyppng { + + ZYPP_FWD_DECL_TYPE_WITH_REFS (ContextBase); + ZYPP_FWD_DECL_TYPE_WITH_REFS (Timer); + class RepoInfo; + + namespace detail { + DEFINE_PTR_TYPE(ResourceLockData); + } + + + namespace resources { + namespace repo { + constexpr std::string_view REPO_RESOURCE_STR("/RepoManager/%1%"); + + std::string REPO_RESOURCE( const RepoInfo &info ); + } + } + + class ResourceAlreadyLockedException : public zypp::Exception + { + public: + ResourceAlreadyLockedException( std::string ident ); + const std::string &ident() const; + + protected: + std::ostream & dumpOn( std::ostream & str ) const override; + private: + std::string _ident; + }; + + class ResourceLockTimeoutException : public zypp::Exception + { + public: + ResourceLockTimeoutException( std::string ident ); + const std::string &ident() const; + + protected: + std::ostream & dumpOn( std::ostream & str ) const override; + private: + std::string _ident; + }; + + /** + * Represents a reference to a shared or exclusive lock of a resource identified by + * a unique string. Since libzypp supports async workflows we need to make + * sure that we do not modify a resource multiple times. + * + * Copying the ResourceLockRef will increase the internal ref count on the lock + * registered in the context. That way even a Exclusive Lock ownership can be + * shared by subparts of a pipeline. + */ + class ResourceLockRef { + + public: + enum Mode{ + Shared, + Exclusive + }; + + ResourceLockRef(detail::ResourceLockData_Ptr data); + ~ResourceLockRef() = default; + + ResourceLockRef(const ResourceLockRef &) = default; + ResourceLockRef &operator=(const ResourceLockRef &) = default; + + ResourceLockRef(ResourceLockRef && other) = default; + ResourceLockRef &operator=(ResourceLockRef && other) = default; + + /** + * Returns the context it belongs to + */ + ContextBaseWeakRef lockContext() const; + + /** + * Returns the lock identifier + */ + const std::string &lockIdent() const; + + /** + * Returns the lock mode + */ + Mode mode() const; + + private: + detail::ResourceLockData_Ptr _lockData; + + }; + + ZYPP_FWD_DECL_TYPE_WITH_REFS(AsyncResourceLockReq); + + class AsyncResourceLockReq : public AsyncOp> + { + public: + AsyncResourceLockReq(std::string ident, ResourceLockRef::Mode m, uint timeout); + + AsyncResourceLockReq(const AsyncResourceLockReq &) = delete; + AsyncResourceLockReq(AsyncResourceLockReq &&) = delete; + AsyncResourceLockReq &operator=(const AsyncResourceLockReq &) = delete; + AsyncResourceLockReq &operator=(AsyncResourceLockReq &&) = delete; + + ~AsyncResourceLockReq() override = default; + + void setFinished( expected &&lock ); + const std::string &ident() const; + ResourceLockRef::Mode mode() const; + + SignalProxy sigTimeout(); + + private: + void onTimeoutExceeded( Timer & ); + Signal _sigTimeout; + std::string _ident; + ResourceLockRef::Mode _mode; + TimerRef _timeout; + }; + + + namespace detail { + class ResourceLockData : public zypp::base::ReferenceCounted, private zypp::base::NonCopyable + { + public: + ContextBaseWeakRef _zyppContext; + std::string _resourceIdent; + ResourceLockRef::Mode _mode = ResourceLockRef::Shared; + + // other requests waiting to lock the resource + // only weak locks, calling code still needs to be able to cancel the pipeline by releasing it + std::deque> _lockQueue; + + // ReferenceCounted interface + protected: + void unref_to(unsigned int) const override; + }; + } +} + +#endif // ZYPP_NG_RESOURCE_INCLUDED diff --git a/zypp/ng/serviceinfo.cc b/zypp/ng/serviceinfo.cc new file mode 100644 index 0000000000..9fdecbbe81 --- /dev/null +++ b/zypp/ng/serviceinfo.cc @@ -0,0 +1,221 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/ServiceInfo.cc + * + */ +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +using std::endl; +using zypp::xml::escape; + +namespace zyppng +{ + + ServiceInfoSharedData::ServiceInfoSharedData( ContextBaseRef &&context ) : repo::RepoInfoBaseSharedData( std::move(context) ) + { ServiceInfoSharedData::bindVariables(); } + + ServiceInfoSharedData::ServiceInfoSharedData( ContextBaseRef &&context, const std::string &alias ) + : repo::RepoInfoBaseSharedData( std::move(context), alias ) + { ServiceInfoSharedData::bindVariables(); } + + ServiceInfoSharedData::ServiceInfoSharedData( ContextBaseRef &&context, const std::string &alias, const zypp::Url &url_r ) + : repo::RepoInfoBaseSharedData( std::move(context), alias ) + , _url(url_r) + { ServiceInfoSharedData::bindVariables(); } + + void ServiceInfoSharedData::bindVariables() + { + repo::RepoInfoBaseSharedData::bindVariables(); + if ( _ctx ) { + _url.setTransformator( repo::RepoVariablesUrlReplacer( zypp::repo::RepoVarRetriever( *_ctx.get() ) ) ); + } else { + _url.setTransformator( repo::RepoVariablesUrlReplacer( nullptr ) ); + } + } + + ServiceInfoSharedData *ServiceInfoSharedData::clone() const + { + auto *n = new ServiceInfoSharedData(*this); + n->bindVariables (); + return n; + } + /////////////////////////////////////////////////////////////////// + // + // CLASS NAME : ServiceInfo::Impl + // + ////////////////////////////////////////////////////////////////// + + ServiceInfo::ServiceInfo( zyppng::ContextBaseRef ctx ) : repo::RepoInfoBase( ( *new ServiceInfoSharedData( std::move(ctx) )) ) {} + + ServiceInfo::ServiceInfo( zyppng::ContextBaseRef ctx, const std::string & alias ) + : repo::RepoInfoBase( ( *new ServiceInfoSharedData( std::move(ctx), alias )) ) + {} + + ServiceInfo::ServiceInfo( zyppng::ContextBaseRef ctx, const std::string & alias, const zypp::Url & url ) + : repo::RepoInfoBase( ( *new ServiceInfoSharedData( std::move(ctx), alias, url )) ) + {} + + ServiceInfo::~ServiceInfo() + {} + + zypp::Url ServiceInfo::url() const // Variables replaced + { return pimpl()->_url.transformed(); } + + zypp::Url ServiceInfo::rawUrl() const // Raw + { return pimpl()->_url.raw(); } + + void ServiceInfo::setUrl( const zypp::Url& url ) // Raw + { pimpl()->_url.raw() = url; } + + zypp::repo::ServiceType ServiceInfo::type() const { return pimpl()->_type; } + void ServiceInfo::setType( const zypp::repo::ServiceType & type ) { pimpl()->_type = type; } + void ServiceInfo::setProbedType( const zypp::repo::ServiceType &t ) const { pimpl()->setProbedType( t ); } + + zypp::Date::Duration ServiceInfo::ttl() const { return pimpl()->_ttl; } + void ServiceInfo::setTtl( zypp::Date::Duration ttl_r ) { pimpl()->_ttl = ttl_r; } + void ServiceInfo::setProbedTtl( zypp::Date::Duration ttl_r ) const { const_cast(this)->setTtl( ttl_r ); } + + zypp::Date ServiceInfo::lrf() const { return pimpl()->_lrf; } + void ServiceInfo::setLrf( zypp::Date lrf_r ) { pimpl()->_lrf = lrf_r; } + + bool ServiceInfo::reposToEnableEmpty() const { return pimpl()->_reposToEnable.empty(); } + ServiceInfo::ReposToEnable::size_type ServiceInfo::reposToEnableSize() const { return pimpl()->_reposToEnable.size(); } + ServiceInfo::ReposToEnable::const_iterator ServiceInfo::reposToEnableBegin() const { return pimpl()->_reposToEnable.begin(); } + ServiceInfo::ReposToEnable::const_iterator ServiceInfo::reposToEnableEnd() const { return pimpl()->_reposToEnable.end(); } + + bool ServiceInfo::repoToEnableFind( const std::string & alias_r ) const + { return( pimpl()->_reposToEnable.find( alias_r ) != pimpl()->_reposToEnable.end() ); } + + void ServiceInfo::addRepoToEnable( const std::string & alias_r ) + { + pimpl()->_reposToEnable.insert( alias_r ); + pimpl()->_reposToDisable.erase( alias_r ); + } + + void ServiceInfo::delRepoToEnable( const std::string & alias_r ) + { pimpl()->_reposToEnable.erase( alias_r ); } + + void ServiceInfo::clearReposToEnable() + { pimpl()->_reposToEnable.clear(); } + + + bool ServiceInfo::reposToDisableEmpty() const { return pimpl()->_reposToDisable.empty(); } + ServiceInfo::ReposToDisable::size_type ServiceInfo::reposToDisableSize() const { return pimpl()->_reposToDisable.size(); } + ServiceInfo::ReposToDisable::const_iterator ServiceInfo::reposToDisableBegin() const { return pimpl()->_reposToDisable.begin(); } + ServiceInfo::ReposToDisable::const_iterator ServiceInfo::reposToDisableEnd() const { return pimpl()->_reposToDisable.end(); } + + bool ServiceInfo::repoToDisableFind( const std::string & alias_r ) const + { return( pimpl()->_reposToDisable.find( alias_r ) != pimpl()->_reposToDisable.end() ); } + + void ServiceInfo::addRepoToDisable( const std::string & alias_r ) + { + pimpl()->_reposToDisable.insert( alias_r ); + pimpl()->_reposToEnable.erase( alias_r ); + } + + void ServiceInfo::delRepoToDisable( const std::string & alias_r ) + { pimpl()->_reposToDisable.erase( alias_r ); } + + void ServiceInfo::clearReposToDisable() + { pimpl()->_reposToDisable.clear(); } + + + const ServiceInfo::RepoStates & ServiceInfo::repoStates() const { return pimpl()->_repoStates; } + void ServiceInfo::setRepoStates( RepoStates newStates_r ) { swap( pimpl()->_repoStates, newStates_r ); } + + std::ostream & ServiceInfo::dumpAsIniOn( std::ostream & str ) const + { + RepoInfoBase::dumpAsIniOn(str) + << "url = " << zypp::hotfix1050625::asString( rawUrl() ) << endl + << "type = " << type() << endl; + + if ( ttl() ) + str << "ttl_sec = " << ttl() << endl; + + if ( lrf() ) + str << "lrf_dat = " << lrf().asSeconds() << endl; + + if ( ! repoStates().empty() ) + { + unsigned cnt = 0U; + for ( const auto & el : repoStates() ) + { + std::string tag( "repo_" ); + tag += zypp::str::numstring( ++cnt ); + const RepoState & state( el.second ); + + str << tag << "=" << el.first << endl + << tag << "_enabled=" << state.enabled << endl + << tag << "_autorefresh=" << state.autorefresh << endl; + if ( state.priority != RepoInfo::defaultPriority() ) + str + << tag << "_priority=" << state.priority << endl; + } + } + + if ( ! reposToEnableEmpty() ) + str << "repostoenable = " << zypp::str::joinEscaped( reposToEnableBegin(), reposToEnableEnd() ) << endl; + if ( ! reposToDisableEmpty() ) + str << "repostodisable = " << zypp::str::joinEscaped( reposToDisableBegin(), reposToDisableEnd() ) << endl; + return str; + } + + std::ostream & ServiceInfo::dumpAsXmlOn( std::ostream & str, const std::string & content ) const + { + str + << "" << endl; + else + str << ">" << endl << content << "" << endl; + + return str; + } + + ServiceInfoSharedData *ServiceInfo::pimpl() + { + return static_cast(_pimpl.get()); + } + + const ServiceInfoSharedData *ServiceInfo::pimpl() const + { + return static_cast(_pimpl.get()); + } + + + std::ostream & operator<<( std::ostream& str, const ServiceInfo &obj ) + { + return obj.dumpAsIniOn(str); + } + + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace zyppng +/////////////////////////////////////////////////////////////////////////////// diff --git a/zypp/ng/serviceinfo.h b/zypp/ng/serviceinfo.h new file mode 100644 index 0000000000..cf739dbb74 --- /dev/null +++ b/zypp/ng/serviceinfo.h @@ -0,0 +1,230 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/ng/ServiceInfo.h + * + */ +#ifndef ZYPP_NG_SERVICE_INFO_H_INCLUDED +#define ZYPP_NG_SERVICE_INFO_H_INCLUDED + +#include +#include + +#include + +#include +#include +#include + + +#include +#include + +/////////////////////////////////////////////////////////////////// +namespace zyppng +{ ///////////////////////////////////////////////////////////////// + + struct ServiceInfoSharedData; + + /////////////////////////////////////////////////////////////////// + /// \class ServiceInfo + /// \brief Service data + /// + /// \note Name and Url are subject to repo variable replacement + /// (\see \ref RepoVariablesStringReplacer). + /// + class ServiceInfo : public repo::RepoInfoBase + { + public: + /** + * Default ctor creates \ref noService. + * \internal + */ + ServiceInfo( zyppng::ContextBaseRef contextRef ); + + /** + * Creates ServiceInfo with specified alias. + * + * \param alias unique short name of service + * \internal + */ + ServiceInfo( zyppng::ContextBaseRef contextRef, const std::string & alias ); + + /** + * ServiceInfo with alias and its URL + * + * \param alias unique shortname of service + * \param url url to service + * \internal + */ + ServiceInfo( zyppng::ContextBaseRef contextRef, const std::string & alias, const zypp::Url& url ); + + ServiceInfo(const ServiceInfo &) = default; + ServiceInfo(ServiceInfo &&) = default; + ServiceInfo &operator=(const ServiceInfo &) = default; + ServiceInfo &operator=(ServiceInfo &&) = default; + + ~ServiceInfo() override; + + /** The service url */ + zypp::Url url() const; + + /** The service raw url (no variables replaced) */ + zypp::Url rawUrl() const; + + /** Set the service url (raw value) */ + void setUrl( const zypp::Url& url ); + + + /** Service type */ + zypp::repo::ServiceType type() const; + + /** Set service type */ + void setType( const zypp::repo::ServiceType & type ); + + /** Lazy init service type */ + void setProbedType( const zypp::repo::ServiceType & t ) const; + + /** \name Housekeeping data + * You don't want to use the setters unless you are a \ref RepoManager. + */ + //@{ + /** Sugested TTL between two metadata auto-refreshs. + * The value (in seconds) may be provided in repoindex.xml:xpath:/repoindex@ttl. + * Default is \a 0 - perform each auto-refresh request. + */ + zypp::Date::Duration ttl() const; + + /** Set sugested TTL. */ + void setTtl( zypp::Date::Duration ttl_r ); + + /** Lazy init sugested TTL. */ + void setProbedTtl( zypp::Date::Duration ttl_r ) const; + + /** Date of last refresh (if known). */ + zypp::Date lrf() const; + + /** Set date of last refresh. */ + void setLrf( zypp::Date lrf_r ); + //@} + // + /** \name Set of repos (repository aliases) to enable on next refresh. + * + * Per default new repositories are created in disabled state. But repositories + * mentioned here will be created in enabled state on the next refresh. + * Afterwards they get removed from the list. + */ + //@{ + /** Container of repos. */ + using ReposToEnable = std::set; + bool reposToEnableEmpty() const; + ReposToEnable::size_type reposToEnableSize() const; + ReposToEnable::const_iterator reposToEnableBegin() const; + ReposToEnable::const_iterator reposToEnableEnd() const; + zypp::Iterable reposToEnable() const + { return zypp::makeIterable( reposToEnableBegin(), reposToEnableEnd() ); } + + /** Whether \c alias_r is mentioned in ReposToEnable. */ + bool repoToEnableFind( const std::string & alias_r ) const; + + /** Add \c alias_r to the set of ReposToEnable. */ + void addRepoToEnable( const std::string & alias_r ); + /** Remove \c alias_r from the set of ReposToEnable. */ + void delRepoToEnable( const std::string & alias_r ); + /** Clear the set of ReposToEnable. */ + void clearReposToEnable(); + //@} + + /** \name Set of repos (repository aliases) to disable on next refresh. + * + * Repositories mentioned here will be disabled on the next refresh, in case they + * still exist. Afterwards they get removed from the list. + */ + //@{ + /** Container of repos. */ + using ReposToDisable = std::set; + bool reposToDisableEmpty() const; + ReposToDisable::size_type reposToDisableSize() const; + ReposToDisable::const_iterator reposToDisableBegin() const; + ReposToDisable::const_iterator reposToDisableEnd() const; + zypp::Iterable reposToDisable() const + { return zypp::makeIterable( reposToDisableBegin(), reposToDisableEnd() ); } + + /** Whether \c alias_r is mentioned in ReposToDisable. */ + bool repoToDisableFind( const std::string & alias_r ) const; + + /** Add \c alias_r to the set of ReposToDisable. */ + void addRepoToDisable( const std::string & alias_r ); + /** Remove \c alias_r from the set of ReposToDisable. */ + void delRepoToDisable( const std::string & alias_r ); + /** Clear the set of ReposToDisable. */ + void clearReposToDisable(); + //@} + + /** \name The original repo state as defined by the repoindex.xml upon last refresh. + * + * This state is remembered to detect any user modifications applied to the repos. + * It may not be available for all repos or in plugin services. In this case all + * changes requested by a service refresh are applied unconditionally. + */ + //@{ + using RepoState = zypp::ServiceRepoState; + using RepoStates = std::map; + + /** Access the remembered repository states. */ + const RepoStates & repoStates() const; + + /** Remember a new set of repository states. */ + void setRepoStates( RepoStates newStates_r ); + //@} + + public: + /** + * Writes ServiceInfo to stream in ".service" format + * + * \param str stream where serialized version service is written + */ + std::ostream & dumpAsIniOn( std::ostream & str ) const override; + + /** + * Write an XML representation of this ServiceInfo object. + * + * \param str + * \param content if not empty, produces content + * otherwise + */ + std::ostream & dumpAsXmlOn( std::ostream & str, const std::string & content = "" ) const override; + + private: + ServiceInfoSharedData *pimpl(); + const ServiceInfoSharedData *pimpl() const; + }; + /////////////////////////////////////////////////////////////////// + /// + /** \relates ServiceInfo */ + using ServiceInfoList = std::list; + + /** \relates RepoInfoBase */ + inline bool operator==( const ServiceInfo & lhs, const ServiceInfo & rhs ) + { return lhs.alias() == rhs.alias(); } + + /** \relates RepoInfoBase */ + inline bool operator!=( const ServiceInfo & lhs, const ServiceInfo & rhs ) + { return lhs.alias() != rhs.alias(); } + + inline bool operator<( const ServiceInfo & lhs, const ServiceInfo & rhs ) + { return lhs.alias() < rhs.alias(); } + + /** \relates ServiceInfo Stream output */ + std::ostream & operator<<( std::ostream & str, const ServiceInfo & obj ); + + + ///////////////////////////////////////////////////////////////// +} // namespace zypp +/////////////////////////////////////////////////////////////////// +#endif // ZYPP_NG_SERVICE_INFO_H_INCLUDED diff --git a/zypp/ng/serviceinfoshareddata.h b/zypp/ng/serviceinfoshareddata.h new file mode 100644 index 0000000000..105e048a38 --- /dev/null +++ b/zypp/ng/serviceinfoshareddata.h @@ -0,0 +1,72 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/ng/ServiceInfo.h + * + */ +#ifndef ZYPP_NG_SERVICE_INFO_SHARED_DATA_H_INCLUDED +#define ZYPP_NG_SERVICE_INFO_SHARED_DATA_H_INCLUDED + +#include +#include +#include + +namespace zyppng +{ + + struct ServiceInfoSharedData : public repo::RepoInfoBaseSharedData + { + using ReposToEnable = ServiceInfo::ReposToEnable; + using ReposToDisable = ServiceInfo::ReposToDisable; + + public: + RepoVariablesReplacedUrl _url; + zypp::repo::ServiceType _type; + ReposToEnable _reposToEnable; + ReposToDisable _reposToDisable; + ServiceInfo::RepoStates _repoStates; + zypp::DefaultIntegral _ttl; + zypp::Date _lrf; + + public: + ServiceInfoSharedData( ContextBaseRef &&context ); + ServiceInfoSharedData( ContextBaseRef &&context, const std::string &alias ); + ServiceInfoSharedData( ContextBaseRef &&context, const std::string &alias, const zypp::Url &url_r ); + + ServiceInfoSharedData( ServiceInfoSharedData && ) = delete; + ServiceInfoSharedData &operator=( const ServiceInfoSharedData & ) = delete; + ServiceInfoSharedData &operator=( ServiceInfoSharedData && ) = delete; + + ~ServiceInfoSharedData() override + {} + + void setProbedType( const zypp::repo::ServiceType & type_r ) const + { + if ( _type == zypp::repo::ServiceType::NONE + && type_r != zypp::repo::ServiceType::NONE ) + { + // lazy init! + const_cast(this)->_type = type_r; + } + } + + protected: + void bindVariables () override; + + private: + friend ServiceInfoSharedData * zypp::rwcowClone( const ServiceInfoSharedData * rhs ); + + /** clone for RWCOW_pointer */ + ServiceInfoSharedData( const ServiceInfoSharedData &) = default; + ServiceInfoSharedData *clone() const override; + }; + +} + + +#endif // ZYPP_NG_SERVICE_INFO_SHARED_DATA_H_INCLUDED diff --git a/zypp/ng/userdata.cc b/zypp/ng/userdata.cc new file mode 100644 index 0000000000..2a2b6c68eb --- /dev/null +++ b/zypp/ng/userdata.cc @@ -0,0 +1,48 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "userdata.h" + +#include + + +#undef ZYPP_BASE_LOGGER_LOGGROUP +#define ZYPP_BASE_LOGGER_LOGGROUP "zyppng::UserData" + +namespace zyppng { + bool UserData::hasData() + { + return !instance()._value.empty(); + } + + const std::string &UserData::data() + { + return instance()._value; + } + + bool UserData::setData( const std::string &str ) + { + for( auto ch = str.begin(); ch != str.end(); ch++ ) + { + if ( *ch < ' ' && *ch != '\t' ) + { + ERR << "New user data string rejectded: char " << (int)*ch << " at position " << (ch - str.begin()) << std::endl; + return false; + } + } + MIL << "Set user data string to '" << str << "'" << std::endl; + instance()._value = str; + return true; + } + + UserData &UserData::instance() + { + static UserData _inst; + return _inst; + } +} diff --git a/zypp/ng/userdata.h b/zypp/ng/userdata.h new file mode 100644 index 0000000000..6d64a925a5 --- /dev/null +++ b/zypp/ng/userdata.h @@ -0,0 +1,37 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#ifndef ZYPP_NG_USERDATA_H_INCLUDED +#define ZYPP_NG_USERDATA_H_INCLUDED + +#include + +namespace zyppng { + + + /** + * Interface for usercode to define a string value to be passed to log, history, plugins... + */ + class UserData { + + public: + ~UserData() = default; + static bool hasData(); + static const std::string &data(); + static bool setData( const std::string &str ); + + private: + UserData() = default; + static UserData &instance(); + + std::string _value; + }; + +} + +#endif diff --git a/zypp/ng/userrequest.cc b/zypp/ng/userrequest.cc index e8e901bd90..8d328d2e09 100644 --- a/zypp/ng/userrequest.cc +++ b/zypp/ng/userrequest.cc @@ -31,24 +31,6 @@ namespace zyppng { return d; } - ZYPP_IMPL_PRIVATE_CONSTR_ARGS(TrustKeyRequest, std::string label, KeyTrust trust, UserData userData ) - : UserRequest( std::move(userData) ) - , _label( std::move(label) ) - , _answer(trust) - { } - - void TrustKeyRequest::setChoice(const KeyTrust sel) - { _answer = sel; } - - TrustKeyRequest::KeyTrust TrustKeyRequest::choice() const - { return _answer; } - - const std::string TrustKeyRequest::label() const - { return _label; } - - UserRequestType TrustKeyRequest::type() const - { return UserRequestType::KeyTrust; } - UserData AcceptKeyRequest::makeData(const zypp::PublicKey &key, const zypp::KeyContext &keycontext) { UserData d( CTYPE.data() ); diff --git a/zypp/ng/userrequest.h b/zypp/ng/userrequest.h index d0fa090566..b763041e6e 100644 --- a/zypp/ng/userrequest.h +++ b/zypp/ng/userrequest.h @@ -65,52 +65,6 @@ namespace zyppng { UserData makeData ( const zypp::Pathname &p, const std::string &requested, const std::string &found ); } - - ZYPP_FWD_DECL_TYPE_WITH_REFS(TrustKeyRequest); - class TrustKeyRequest : public UserRequest - { - ZYPP_ADD_CREATE_FUNC(TrustKeyRequest) - public: - /*! - * Keep in sync with zypp::KeyRingReport::KeyTrust, we do not want - * to include old APIs here if possible. - */ - enum KeyTrust - { - /** - * User has chosen not to trust the key. - */ - KEY_DONT_TRUST = 0, - /** - * This basically means, we knew the key, but it was not trusted. User - * has chosen to continue, but not import the key. - */ - KEY_TRUST_TEMPORARILY, - /** - * Import the key. - * This means saving the key in the trusted database so next run it will appear as trusted. - * Nothing to do with KEY_TRUST_TEMPORARILY, as you CAN trust a key without importing it, - * basically you will be asked every time again. - * There are programs who prefer to manage the trust keyring on their own and use trustKey - * without importing it into rpm. - */ - KEY_TRUST_AND_IMPORT - }; - - ZYPP_DECL_PRIVATE_CONSTR_ARGS(TrustKeyRequest, std::string label, KeyTrust trust = KEY_DONT_TRUST, UserData userData = {} ); - - void setChoice ( const KeyTrust sel ); - KeyTrust choice() const; - - const std::string label() const; - - UserRequestType type() const override; - - private: - std::string _label; - KeyTrust _answer = KEY_DONT_TRUST; - }; - /*! * Ask user to trust and/or import the key to trusted keyring. * \see zypp::KeyTrust diff --git a/zypp/ng/workflows/checksumwf.cc b/zypp/ng/workflows/checksumwf.cc index caaa999513..fde5aa3198 100644 --- a/zypp/ng/workflows/checksumwf.cc +++ b/zypp/ng/workflows/checksumwf.cc @@ -41,9 +41,10 @@ namespace zyppng::CheckSumWorkflow { using MediaHandle = typename ProvideType::MediaHandle; using ProvideRes = typename ProvideType::Res; - CheckSumWorkflowLogic( ZyppContextRefType zyppContext, zypp::CheckSum &&checksum, zypp::Pathname file ) + CheckSumWorkflowLogic( ZyppContextRefType zyppContext, ProgressObserverRef &&taskObserver, zypp::CheckSum &&checksum, zypp::Pathname file ) : _context( std::move(zyppContext) ) - , _report( _context ) + , _taskObserver( std::move(taskObserver) ) + , _report( _context, _taskObserver ) , _checksum(std::move( checksum )) , _file(std::move( file )) {} @@ -63,7 +64,7 @@ namespace zyppng::CheckSumWorkflow { } else { - return _context->provider()->checksumForFile ( _file, _checksum.type() ) + return _context->provider()->checksumForFile ( _context, _file, _checksum.type() ) | [] ( expected sum ) { if ( !sum ) return zypp::CheckSum( ); @@ -106,27 +107,28 @@ namespace zyppng::CheckSumWorkflow { protected: ZyppContextRefType _context; + ProgressObserverRef _taskObserver; DigestReportHelper _report; zypp::CheckSum _checksum; zypp::Pathname _file; }; - expected verifyChecksum( SyncContextRef zyppCtx, zypp::CheckSum checksum, zypp::Pathname file ) + expected verifyChecksum( SyncContextRef zyppCtx, ProgressObserverRef taskObserver, zypp::CheckSum checksum, zypp::Pathname file ) { - return SimpleExecutor>>::run( std::move(zyppCtx), std::move(checksum), std::move(file) ); + return SimpleExecutor>>::run( std::move(zyppCtx), std::move(taskObserver), std::move(checksum), std::move(file) ); } - AsyncOpRef > verifyChecksum( ContextRef zyppCtx, zypp::CheckSum checksum, zypp::filesystem::Pathname file ) + AsyncOpRef > verifyChecksum(AsyncContextRef zyppCtx, ProgressObserverRef taskObserver, zypp::CheckSum checksum, zypp::filesystem::Pathname file ) { - return SimpleExecutor>>::run( std::move(zyppCtx), std::move(checksum), std::move(file) ); + return SimpleExecutor>>::run( std::move(zyppCtx), std::move(taskObserver), std::move(checksum), std::move(file) ); } - std::function > (ProvideRes &&)> checksumFileChecker( ContextRef zyppCtx, zypp::CheckSum checksum ) + std::function > (ProvideRes &&)> checksumFileChecker( AsyncContextRef zyppCtx, ProgressObserverRef taskObserver, zypp::CheckSum checksum ) { using zyppng::operators::operator|; - return [ zyppCtx, checksum=std::move(checksum) ]( ProvideRes res ) mutable -> AsyncOpRef> { - return verifyChecksum( zyppCtx, std::move(checksum), res.file() ) + return [ zyppCtx = std::move(zyppCtx), tO = std::move(taskObserver), checksum=std::move(checksum) ]( ProvideRes res ) mutable -> AsyncOpRef> { + return verifyChecksum( zyppCtx, std::move(tO), std::move(checksum), res.file() ) | [ res ] ( expected result ) mutable { if ( result ) return expected::success( std::move(res) ); @@ -136,11 +138,11 @@ namespace zyppng::CheckSumWorkflow { }; } - std::function (SyncProvideRes &&)> checksumFileChecker(SyncContextRef zyppCtx, zypp::CheckSum checksum) + std::function (SyncProvideRes &&)> checksumFileChecker(SyncContextRef zyppCtx, ProgressObserverRef taskObserver, zypp::CheckSum checksum) { using zyppng::operators::operator|; - return [ zyppCtx = std::move(zyppCtx), checksum=std::move(checksum) ]( SyncProvideRes res ) mutable -> expected { - return verifyChecksum( zyppCtx, std::move(checksum), res.file() ) + return [ zyppCtx = std::move(zyppCtx), tO = std::move(taskObserver), checksum=std::move(checksum) ]( SyncProvideRes res ) mutable -> expected { + return verifyChecksum( zyppCtx, std::move(tO), std::move(checksum), res.file() ) | [ res ] ( expected result ) mutable { if ( result ) return expected::success( std::move(res) ); diff --git a/zypp/ng/workflows/checksumwf.h b/zypp/ng/workflows/checksumwf.h index f4f5eda72a..7ba9aaf430 100644 --- a/zypp/ng/workflows/checksumwf.h +++ b/zypp/ng/workflows/checksumwf.h @@ -9,11 +9,12 @@ #ifndef ZYPP_NG_CHECKSUMWORKFLOW_INCLUDED #define ZYPP_NG_CHECKSUMWORKFLOW_INCLUDED +#include #include #include #include -#include + #include namespace zypp { @@ -27,18 +28,19 @@ namespace zypp { namespace zyppng { class ProvideRes; - ZYPP_FWD_DECL_TYPE_WITH_REFS(Context); + + ZYPP_FWD_DECL_TYPE_WITH_REFS (ProgressObserver); namespace CheckSumWorkflow { - expected verifyChecksum ( SyncContextRef zyppCtx, zypp::CheckSum checksum, zypp::Pathname file ); - AsyncOpRef> verifyChecksum ( ContextRef zyppCtx, zypp::CheckSum checksum, zypp::Pathname file ); + expected verifyChecksum (SyncContextRef zyppCtx, zyppng::ProgressObserverRef taskObserver, zypp::CheckSum checksum, zypp::Pathname file ); + AsyncOpRef> verifyChecksum ( AsyncContextRef zyppCtx, ProgressObserverRef taskObserver, zypp::CheckSum checksum, zypp::Pathname file ); /*! * Returns a callable that executes the verify checksum as part of a pipeline, * forwarding the \ref ProvideRes if the workflow was successful. */ - std::function< AsyncOpRef>( ProvideRes && ) > checksumFileChecker( ContextRef zyppCtx, zypp::CheckSum checksum ); - std::function< expected( SyncProvideRes && ) > checksumFileChecker( SyncContextRef zyppCtx, zypp::CheckSum checksum ); + std::function< AsyncOpRef>( ProvideRes && ) > checksumFileChecker(AsyncContextRef zyppCtx, zyppng::ProgressObserverRef taskObserver, zypp::CheckSum checksum ); + std::function< expected( SyncProvideRes && ) > checksumFileChecker( SyncContextRef zyppCtx, ProgressObserverRef taskObserver, zypp::CheckSum checksum ); } } diff --git a/zypp/ng/workflows/contextfacade.cc b/zypp/ng/workflows/contextfacade.cc deleted file mode 100644 index 485ddce678..0000000000 --- a/zypp/ng/workflows/contextfacade.cc +++ /dev/null @@ -1,61 +0,0 @@ -/*---------------------------------------------------------------------\ -| ____ _ __ __ ___ | -| |__ / \ / / . \ . \ | -| / / \ V /| _/ _/ | -| / /__ | | | | | | | -| /_____||_| |_| |_| | -| | -\---------------------------------------------------------------------*/ -#include "contextfacade.h" -#include - -namespace zyppng -{ - ZYPP_IMPL_PRIVATE_CONSTR(SyncContext) : _media( MediaSyncFacade::create() ) - { - - } - - - /*! - * Returns the default sync zypp context. - * This is only a workaround to support the Legacy APIs. - * For new style APIs the Context should always explicitely be passed down. So use it - * only in top level external classes where we can not touch the API. - */ - SyncContextRef SyncContext::defaultContext() - { - static SyncContextRef def = SyncContext::create(); - return def; - } - - MediaSyncFacadeRef SyncContext::provider() const - { - return _media; - } - - KeyRingRef SyncContext::keyRing() const - { - return zypp::getZYpp()->keyRing(); - } - - zypp::ZConfig &SyncContext::config() - { - return zypp::ZConfig::instance(); - } - - zypp::ResPool SyncContext::pool() - { - return zypp::ResPool::instance(); - } - - zypp::ResPoolProxy SyncContext::poolProxy() - { - return zypp::ResPool::instance().proxy(); - } - - zypp::sat::Pool SyncContext::satPool() - { - return zypp::sat::Pool::instance(); - } -} diff --git a/zypp/ng/workflows/contextfacade.h b/zypp/ng/workflows/contextfacade.h deleted file mode 100644 index a359e22653..0000000000 --- a/zypp/ng/workflows/contextfacade.h +++ /dev/null @@ -1,59 +0,0 @@ -/*---------------------------------------------------------------------\ -| ____ _ __ __ ___ | -| |__ / \ / / . \ . \ | -| / / \ V /| _/ _/ | -| / /__ | | | | | | | -| /_____||_| |_| |_| | -| | -\---------------------------------------------------------------------*/ -#ifndef ZYPP_NG_CONTEXTFACADE_INCLUDED -#define ZYPP_NG_CONTEXTFACADE_INCLUDED - -#include "zypp/ng/context.h" -#include - -namespace zypp { - DEFINE_PTR_TYPE(KeyRing); - class ZConfig; -} - -namespace zyppng { - - ZYPP_FWD_DECL_TYPE_WITH_REFS( SyncContext ); - - using KeyRing = zypp::KeyRing; - using KeyRingRef = zypp::KeyRing_Ptr; - - class ZYPP_API SyncContext { - - ZYPP_ADD_CREATE_FUNC(SyncContext) - - public: - ZYPP_DECL_PRIVATE_CONSTR(SyncContext); - - using ProvideType = MediaSyncFacade; - - static SyncContextRef defaultContext(); - - MediaSyncFacadeRef provider() const; - KeyRingRef keyRing () const; - zypp::ZConfig &config(); - zypp::ResPool pool(); - zypp::ResPoolProxy poolProxy(); - zypp::sat::Pool satPool(); - - - private: - MediaSyncFacadeRef _media; - }; - - template - using MaybeAsyncContextRef = std::conditional_t, ContextRef, SyncContextRef>; - - template - auto joinPipeline( SyncContextRef ctx, T &&val ) { - return std::forward(val); - } -} - -#endif diff --git a/zypp/ng/workflows/downloadwf.cc b/zypp/ng/workflows/downloadwf.cc index d63bcc4010..8ca17b19cd 100644 --- a/zypp/ng/workflows/downloadwf.cc +++ b/zypp/ng/workflows/downloadwf.cc @@ -12,7 +12,7 @@ #include #include -#include + #include @@ -57,7 +57,7 @@ namespace zyppng { } - template class CacheProviderContext; + template class CacheProviderContext; template class CacheProviderContext; @@ -88,8 +88,9 @@ namespace zyppng { using ProvideRes = typename ProvideType::Res; public: - ProvideFromCacheOrMediumLogic( CacheProviderContextRefType cacheContext, MediaHandle &&medium, zypp::Pathname &&file, ProvideFileSpec &&filespec ) + ProvideFromCacheOrMediumLogic( CacheProviderContextRefType cacheContext, ProgressObserverRef &&taskObserver, MediaHandle &&medium, zypp::Pathname &&file, ProvideFileSpec &&filespec ) : _ctx( std::move(cacheContext) ) + , _taskObserver( std::move(taskObserver) ) , _medium( std::move(medium) ) , _file(std::move( file )) , _filespec( std::move(filespec) ) {} @@ -110,7 +111,7 @@ namespace zyppng { return expected::success( std::move(res) ); }); }) - | and_then( ProvideType::copyResultToDest( _ctx->zyppContext()->provider(), _ctx->destDir() / _file ) ) + | and_then( ProvideType::copyResultToDest( _ctx->zyppContext()->provider(), _ctx->zyppContext(), _ctx->destDir() / _file ) ) | and_then( []( zypp::ManagedFile &&file ){ file.resetDispose (); return make_expected_success (std::move(file)); @@ -128,7 +129,7 @@ namespace zyppng { const auto &targetPath = _ctx->destDir() / _file; zypp::filesystem::assert_dir( targetPath.dirname () ); - return _ctx->zyppContext()->provider()->copyFile( cachedFile, _ctx->destDir() / _file ) + return _ctx->zyppContext()->provider()->copyFile( _ctx->zyppContext(), cachedFile, _ctx->destDir() / _file ) | and_then( [cachedFile]( zypp::ManagedFile &&f) { f.resetDispose(); return make_expected_success (std::move(f)); }); }); } @@ -162,7 +163,7 @@ namespace zyppng { // calc checksum, but do not use the workflow. Here we don't want to ask the user if a wrong checksum should // be accepted - return provider->checksumForFile( cacheFilePath, _filespec.checksum().type() ) + return provider->checksumForFile( _ctx->zyppContext(), cacheFilePath, _filespec.checksum().type() ) | and_then([this, cacheFilePath, targetFile]( zypp::CheckSum sum ) { auto mgdFile = zypp::ManagedFile( cacheFilePath ); @@ -190,7 +191,7 @@ namespace zyppng { return zypp::Pathname( dlFilePath ) | [this]( zypp::Pathname &&dlFilePath ) { if ( !_filespec.checksum().empty () ) { - return CheckSumWorkflow::verifyChecksum( _ctx->zyppContext(), _filespec.checksum (), std::move(dlFilePath) ); + return CheckSumWorkflow::verifyChecksum( _ctx->zyppContext(), _taskObserver, _filespec.checksum (), std::move(dlFilePath) ); } return makeReadyResult(expected::success()); }; @@ -198,6 +199,7 @@ namespace zyppng { } CacheProviderContextRefType _ctx; + ProgressObserverRef _taskObserver; MediaHandle _medium; zypp::Pathname _file; ProvideFileSpec _filespec; @@ -206,14 +208,14 @@ namespace zyppng { namespace DownloadWorkflow { - AsyncOpRef > provideToCacheDir( AsyncCacheProviderContextRef cacheContext, ProvideMediaHandle medium, zypp::Pathname file, ProvideFileSpec filespec ) + AsyncOpRef > provideToCacheDir( AsyncCacheProviderContextRef cacheContext,ProgressObserverRef taskObserver, ProvideMediaHandle medium, zypp::Pathname file, ProvideFileSpec filespec ) { - return SimpleExecutor>>::run( std::move(cacheContext), std::move(medium), std::move(file), std::move(filespec) ); + return SimpleExecutor>>::run( std::move(cacheContext), std::move(taskObserver), std::move(medium), std::move(file), std::move(filespec) ); } - expected provideToCacheDir(SyncCacheProviderContextRef cacheContext, SyncMediaHandle medium, zypp::Pathname file, ProvideFileSpec filespec ) + expected provideToCacheDir(SyncCacheProviderContextRef cacheContext, ProgressObserverRef taskObserver, SyncMediaHandle medium, zypp::Pathname file, ProvideFileSpec filespec ) { - return SimpleExecutor>>::run( std::move(cacheContext), std::move(medium), std::move(file), std::move(filespec) ); + return SimpleExecutor>>::run( std::move(cacheContext), std::move(taskObserver), std::move(medium), std::move(file), std::move(filespec) ); } } diff --git a/zypp/ng/workflows/downloadwf.h b/zypp/ng/workflows/downloadwf.h index 91e60d7e3e..4e21ac0c27 100644 --- a/zypp/ng/workflows/downloadwf.h +++ b/zypp/ng/workflows/downloadwf.h @@ -12,11 +12,9 @@ #include #include #include +#include namespace zyppng { - - ZYPP_FWD_DECL_TYPE_WITH_REFS (Context); - ZYPP_FWD_DECL_TYPE_WITH_REFS (SyncContext); ZYPP_FWD_DECL_TYPE_WITH_REFS (ProgressObserver); class ProvideMediaHandle; @@ -49,14 +47,14 @@ namespace zyppng { std::vector _cacheDirs; }; - using AsyncCacheProviderContext = CacheProviderContext; + using AsyncCacheProviderContext = CacheProviderContext; using SyncCacheProviderContext = CacheProviderContext; ZYPP_FWD_DECL_REFS(AsyncCacheProviderContext); ZYPP_FWD_DECL_REFS(SyncCacheProviderContext); namespace DownloadWorkflow { - AsyncOpRef> provideToCacheDir( AsyncCacheProviderContextRef cacheContext, ProvideMediaHandle medium, zypp::Pathname file, ProvideFileSpec filespec ); - expected provideToCacheDir( SyncCacheProviderContextRef cacheContext, SyncMediaHandle medium, zypp::Pathname file, ProvideFileSpec filespec ); + AsyncOpRef> provideToCacheDir(AsyncCacheProviderContextRef cacheContext, ProgressObserverRef taskObserver, ProvideMediaHandle medium, zypp::Pathname file, ProvideFileSpec filespec ); + expected provideToCacheDir( SyncCacheProviderContextRef cacheContext, ProgressObserverRef taskObserver, SyncMediaHandle medium, zypp::Pathname file, ProvideFileSpec filespec ); } } diff --git a/zypp/ng/workflows/keyringwf.cc b/zypp/ng/workflows/keyringwf.cc index 278a6b38ec..6c481c6053 100644 --- a/zypp/ng/workflows/keyringwf.cc +++ b/zypp/ng/workflows/keyringwf.cc @@ -9,7 +9,7 @@ #include "keyringwf.h" #include "logichelpers.h" -#include + #include #include #include @@ -19,10 +19,12 @@ #include #include #include + #include #include #include #include +#include namespace zyppng::KeyRingWorkflow { @@ -38,8 +40,8 @@ namespace zyppng::KeyRingWorkflow { ZYPP_ENABLE_LOGIC_BASE(Executor, OpType); public: - ImportKeyFromRepoLogic( ZyppContextRefType context, std::string &&keyId, zypp::RepoInfo &&info ) - : _context( std::move(context) ), _keyId(std::move(keyId)), _repo( std::move(info) ) + ImportKeyFromRepoLogic( ZyppContextRefType context, ProgressObserverRef &&taskObserver, std::string &&keyId, RepoInfo &&info ) + : _context( std::move(context) ), _taskObserver(std::move(taskObserver)), _keyId(std::move(keyId)), _repo( std::move(info) ) { } MaybeAsyncRef execute () { @@ -54,7 +56,7 @@ namespace zyppng::KeyRingWorkflow { const zypp::ZConfig &conf = _context->config(); zypp::Pathname cacheDir = conf.repoManagerRoot() / conf.pubkeyCachePath(); - return RepoInfoWorkflow::provideKey( _context, _repo, _keyId, cacheDir ) + return RepoInfoWorkflow::provideKey( _context, _taskObserver, _repo, _keyId, cacheDir ) | [this, cacheDir]( zypp::Pathname myKey ) { if ( myKey.empty() ) // if we did not find any keys, there is no point in checking again, break @@ -77,7 +79,7 @@ namespace zyppng::KeyRingWorkflow { zypp::KeyContext context; context.setRepoInfo( _repo ); - if ( !KeyRingReportHelper(_context).askUserToAcceptPackageKey( key, context ) ) { + if ( !KeyRingReportHelper(_context, _taskObserver).askUserToAcceptPackageKey( key, context ) ) { return false; } @@ -94,18 +96,19 @@ namespace zyppng::KeyRingWorkflow { } ZyppContextRefType _context; + ProgressObserverRef _taskObserver; std::string _keyId; - zypp::RepoInfo _repo; + RepoInfo _repo; }; - bool provideAndImportKeyFromRepository( SyncContextRef ctx, std::string id_r, zypp::RepoInfo info_r ) + bool provideAndImportKeyFromRepository( SyncContextRef ctx, ProgressObserverRef taskObserver, std::string id_r, RepoInfo info_r ) { - return SimpleExecutor>::run( ctx, std::move(id_r), std::move(info_r) ); + return SimpleExecutor>::run( ctx, std::move(taskObserver), std::move(id_r), std::move(info_r) ); } - AsyncOpRef provideAndImportKeyFromRepository( ContextRef ctx, std::string id_r, zypp::RepoInfo info_r) + AsyncOpRef provideAndImportKeyFromRepository(AsyncContextRef ctx, ProgressObserverRef taskObserver, std::string id_r, RepoInfo info_r) { - return SimpleExecutor>::run( ctx, std::move(id_r), std::move(info_r) ); + return SimpleExecutor>::run( ctx, std::move(taskObserver), std::move(id_r), std::move(info_r) ); } namespace { @@ -122,9 +125,10 @@ namespace zyppng::KeyRingWorkflow { using ZyppContextRefType = MaybeAsyncContextRef; using KeyTrust = zypp::KeyRingReport::KeyTrust; - VerifyFileSignatureLogic( ZyppContextRefType zyppContext, KeyRingRef &&keyRing, zypp::keyring::VerifyFileContext &&ctx ) + VerifyFileSignatureLogic( ZyppContextRefType zyppContext, ProgressObserverRef &&taskObserver, KeyRingRef &&keyRing, zypp::keyring::VerifyFileContext &&ctx ) : _zyppContext( std::move(zyppContext) ) - , _keyringReport( _zyppContext ) + , _taskObserver( std::move(taskObserver) ) + , _keyringReport( _zyppContext, _taskObserver ) , _keyRing( std::move(keyRing) ) , _verifyContext( std::move(ctx) ) { } @@ -209,12 +213,12 @@ namespace zyppng::KeyRingWorkflow { else if ( ! _verifyContext.keyContext().empty() ) { // try to find the key in the repository info - return provideAndImportKeyFromRepository ( _zyppContext, id, _verifyContext.keyContext().repoInfo() ) + return provideAndImportKeyFromRepository ( _zyppContext, _taskObserver, id, *_verifyContext.keyContext().ngRepoInfo() ) | [this, id]( bool success ) { if ( !success ) { return FoundKeyData{ zypp::PublicKeyData(), zypp::Pathname() }; } - return FoundKeyData{ _keyRing->pimpl().publicKeyExists( id, _keyRing->pimpl().trustedKeyRing() ), _keyRing->pimpl().trustedKeyRing(), true }; + return FoundKeyData{ _keyRing->pimpl().publicKeyExists( id, _keyRing->pimpl().trustedKeyRing() ), _keyRing->pimpl().trustedKeyRing(), true }; }; } } @@ -317,6 +321,7 @@ namespace zyppng::KeyRingWorkflow { protected: ZyppContextRefType _zyppContext; + ProgressObserverRef _taskObserver; KeyRingReportHelper _keyringReport; KeyRingRef _keyRing; zypp::keyring::VerifyFileContext _verifyContext; @@ -329,26 +334,26 @@ namespace zyppng::KeyRingWorkflow { }; } - std::pair verifyFileSignature( SyncContextRef zyppContext, zypp::keyring::VerifyFileContext &&context_r ) + std::pair verifyFileSignature(SyncContextRef zyppContext, ProgressObserverRef taskObserver, zypp::keyring::VerifyFileContext &&context_r ) { auto kr = zyppContext->keyRing(); - return SimpleExecutor >>::run( std::move(zyppContext), std::move(kr), std::move(context_r) ); + return SimpleExecutor >>::run( std::move(zyppContext), std::move(taskObserver), std::move(kr), std::move(context_r) ); } - AsyncOpRef> verifyFileSignature( ContextRef zyppContext, zypp::keyring::VerifyFileContext &&context_r ) + AsyncOpRef> verifyFileSignature( AsyncContextRef zyppContext, ProgressObserverRef taskObserver, zypp::keyring::VerifyFileContext &&context_r ) { auto kr = zyppContext->keyRing(); - return SimpleExecutor >>::run( std::move(zyppContext), std::move(kr), std::move(context_r) ); + return SimpleExecutor >>::run( std::move(zyppContext), std::move(taskObserver), std::move(kr), std::move(context_r) ); } - std::pair verifyFileSignature( SyncContextRef zyppContext, zypp::KeyRing_Ptr keyRing, zypp::keyring::VerifyFileContext &&context_r ) + std::pair verifyFileSignature(SyncContextRef zyppContext, ProgressObserverRef taskObserver, zypp::KeyRing_Ptr keyRing, zypp::keyring::VerifyFileContext &&context_r ) { - return SimpleExecutor >>::run( std::move(zyppContext), std::move(keyRing), std::move(context_r) ); + return SimpleExecutor >>::run( std::move(zyppContext), std::move(taskObserver), std::move(keyRing), std::move(context_r) ); } - AsyncOpRef> verifyFileSignature(ContextRef zyppContext, zypp::KeyRing_Ptr keyRing, zypp::keyring::VerifyFileContext &&context_r ) + AsyncOpRef> verifyFileSignature(AsyncContextRef zyppContext, ProgressObserverRef taskObserver, zypp::KeyRing_Ptr keyRing, zypp::keyring::VerifyFileContext &&context_r ) { - return SimpleExecutor >>::run( std::move(zyppContext), std::move(keyRing), std::move(context_r) ); + return SimpleExecutor >>::run( std::move(zyppContext), std::move(taskObserver), std::move(keyRing), std::move(context_r) ); } } diff --git a/zypp/ng/workflows/keyringwf.h b/zypp/ng/workflows/keyringwf.h index cd25b08583..71667652de 100644 --- a/zypp/ng/workflows/keyringwf.h +++ b/zypp/ng/workflows/keyringwf.h @@ -11,9 +11,9 @@ #include #include +#include namespace zypp { - class RepoInfo; DEFINE_PTR_TYPE(KeyRing); namespace keyring { @@ -24,8 +24,8 @@ namespace zypp { namespace zyppng { - ZYPP_FWD_DECL_TYPE_WITH_REFS (Context); - ZYPP_FWD_DECL_TYPE_WITH_REFS (SyncContext); + class RepoInfo; + ZYPP_FWD_DECL_TYPE_WITH_REFS (ProgressObserver); /*! * \namespace KeyRingWorkflow @@ -39,8 +39,8 @@ namespace zyppng { * Try to find the \a id in key cache or repository specified in \a info. Ask the user to trust * the key if it was found */ - bool provideAndImportKeyFromRepository(SyncContextRef ctx, std::string id_r, zypp::RepoInfo info_r ); - AsyncOpRef provideAndImportKeyFromRepository(ContextRef ctx, std::string id_r, zypp::RepoInfo info_r ); + bool provideAndImportKeyFromRepository(SyncContextRef ctx, zyppng::ProgressObserverRef taskObserver, std::string id_r, RepoInfo info_r ); + AsyncOpRef provideAndImportKeyFromRepository(AsyncContextRef ctx, ProgressObserverRef taskObserver, std::string id_r, RepoInfo info_r ); /** * Follows a signature verification interacting with the user. @@ -73,11 +73,11 @@ namespace zyppng { * * \see \ref zypp::KeyRingReport */ - std::pair verifyFileSignature( SyncContextRef zyppContext, zypp::keyring::VerifyFileContext && context_r ); - AsyncOpRef> verifyFileSignature( ContextRef zyppContext, zypp::keyring::VerifyFileContext && context_r ); + std::pair verifyFileSignature( SyncContextRef zyppContext, ProgressObserverRef taskObserver, zypp::keyring::VerifyFileContext && context_r ); + AsyncOpRef> verifyFileSignature(AsyncContextRef zyppContext, zyppng::ProgressObserverRef taskObserver, zypp::keyring::VerifyFileContext && context_r ); - std::pair verifyFileSignature( SyncContextRef zyppContext, zypp::KeyRing_Ptr keyRing, zypp::keyring::VerifyFileContext &&context_r ); - AsyncOpRef> verifyFileSignature( ContextRef zyppContext, zypp::KeyRing_Ptr keyRing, zypp::keyring::VerifyFileContext &&context_r ); + std::pair verifyFileSignature( SyncContextRef zyppContext, ProgressObserverRef taskObserver, zypp::KeyRing_Ptr keyRing, zypp::keyring::VerifyFileContext &&context_r ); + AsyncOpRef> verifyFileSignature(AsyncContextRef zyppContext, zyppng::ProgressObserverRef taskObserver, zypp::KeyRing_Ptr keyRing, zypp::keyring::VerifyFileContext &&context_r ); } } diff --git a/zypp/ng/workflows/logichelpers.h b/zypp/ng/workflows/logichelpers.h index 97fdad38f2..2dbebddafc 100644 --- a/zypp/ng/workflows/logichelpers.h +++ b/zypp/ng/workflows/logichelpers.h @@ -78,7 +78,7 @@ namespace zyppng * // the public interface for the workflows are just functions, usually with some * // context object just save passing a gazillion of arguments to the func and * // to carry some state. - * AsyncOpRef> computeInt( ContextRef context ); + * AsyncOpRef> computeInt( AsyncContextRef context ); * expected computeInt( SyncContextRef context ); * * // ------------------ computeint.cc --------------------------- @@ -143,9 +143,9 @@ namespace zyppng * * } //namespace * - * // by overloading this function on the (Sync)ContextRef type other workflow implementations + * // by overloading this function on the (Sync)AsyncContextRef type other workflow implementations * // can call the async/sync version just by passing the right parameters - * AsyncOpRef> computeInt( ContextRef context ) { + * AsyncOpRef> computeInt( AsyncContextRef context ) { * // the run() static method is provided by the LogicBase subclass * return ComputeIntAsyncExecutor::run( std::move(context) ); * } diff --git a/zypp/ng/workflows/mediafacade.cc b/zypp/ng/workflows/mediafacade.cc index 8f38e4f697..934539a134 100644 --- a/zypp/ng/workflows/mediafacade.cc +++ b/zypp/ng/workflows/mediafacade.cc @@ -15,6 +15,7 @@ #include #include #include +#include namespace zyppng { @@ -141,6 +142,13 @@ namespace zyppng { return *_data; } + std::optional SyncMediaHandle::spec() const + { + if ( !_data ) + return {}; + return _data->spec(); + } + MediaSyncFacade::Res::Res(MediaHandle hdl, zypp::ManagedFile file) : _res( std::move(file) ) , _provideHandle( std::move (hdl) ) @@ -182,7 +190,7 @@ namespace zyppng { return usableMirrs; } - expected MediaSyncFacade::attachMedia( const zypp::Url &url, const ProvideMediaSpec &request ) + expected MediaSyncFacade::attachMedia( const zypp::Url &url, const ProvideMediaSpec &request, zyppng::ProgressObserverRef tracker ) { bool isVolatile = url.schemeIsVolatile(); @@ -201,7 +209,7 @@ namespace zyppng { if ( request.medianr() > 1 ) effectiveUrl = zypp::MediaSetAccess::rewriteUrl( effectiveUrl, request.medianr() ); - attachId = mgr.open( effectiveUrl ); + attachId = mgr.open( std::dynamic_pointer_cast( request.mediaContext() ), effectiveUrl ); if ( !request.mediaFile().empty() ) { mgr.addVerifier( *attachId, zypp::media::MediaVerifierRef( new zypp::repo::SUSEMediaVerifier( request.mediaFile(), request.medianr() ) ) ); } @@ -355,7 +363,7 @@ namespace zyppng { } while ( true ); } - expected MediaSyncFacade::attachMedia( const std::vector &urls, const ProvideMediaSpec &request ) + expected MediaSyncFacade::attachMedia( const std::vector &urls, const ProvideMediaSpec &request, zyppng::ProgressObserverRef tracker ) { // rewrite and sanitize the urls if required std::vector useableUrls = sanitizeUrls(urls); @@ -431,7 +439,7 @@ namespace zyppng { return prepareMedia( std::vector{url}, request ); } - expected MediaSyncFacade::attachMediaIfNeeded( LazyMediaHandle lazyHandle) + expected MediaSyncFacade::attachMediaIfNeeded( LazyMediaHandle lazyHandle, zyppng::ProgressObserverRef tracker) { using namespace zyppng::operators; if ( lazyHandle.attached() ) @@ -446,7 +454,7 @@ namespace zyppng { }); } - expected MediaSyncFacade::provide(const std::vector &urls, const ProvideFileSpec &request) + expected MediaSyncFacade::provide( MediaContextRef ctx, const std::vector &urls, const ProvideFileSpec &request, zyppng::ProgressObserverRef tracker ) { using namespace zyppng::operators; @@ -460,7 +468,7 @@ namespace zyppng { zypp::Pathname fileName(url.getPathName()); url.setPathName ("/"); - expected res = attachMedia( url, ProvideMediaSpec( "" ) ) + expected res = attachMedia( url, ProvideMediaSpec( std::move(ctx), "" ) ) | and_then( [&, this]( const MediaSyncFacade::MediaHandle& handle ) { return provide( handle, fileName, request.asOnMediaLocation(fileName, 1)); }); @@ -483,12 +491,12 @@ namespace zyppng { } - expected MediaSyncFacade::provide(const zypp::Url &url, const ProvideFileSpec &request) + expected MediaSyncFacade::provide( MediaContextRef ctx, const zypp::Url &url, const ProvideFileSpec &request, zyppng::ProgressObserverRef tracker ) { - return provide( std::vector{url}, request ); + return provide( std::move(ctx), std::vector{url}, request ); } - expected MediaSyncFacade::provide(const MediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request) + expected MediaSyncFacade::provide(const MediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request, zyppng::ProgressObserverRef tracker ) { zypp::media::MediaManager mgr; const auto &handleInfo = attachHandle.info(); @@ -524,7 +532,7 @@ namespace zyppng { } } - expected MediaSyncFacade::provide( const LazyMediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request ) + expected MediaSyncFacade::provide( const LazyMediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request, zyppng::ProgressObserverRef tracker ) { using namespace zyppng::operators; return attachMediaIfNeeded ( attachHandle ) @@ -536,7 +544,7 @@ namespace zyppng { }); } - zyppng::expected MediaSyncFacade::checksumForFile(const zypp::Pathname &p, const std::string &algorithm) + zyppng::expected MediaSyncFacade::checksumForFile( MediaContextRef , const zypp::Pathname &p, const std::string &algorithm, zyppng::ProgressObserverRef tracker ) { try { return expected::success( zypp::CheckSum( algorithm, zypp::filesystem::checksum ( p, algorithm ) ) ); @@ -545,7 +553,7 @@ namespace zyppng { } } - expected MediaSyncFacade::copyFile(const zypp::Pathname &source, const zypp::Pathname &target) + expected MediaSyncFacade::copyFile( MediaContextRef, const zypp::Pathname &source, const zypp::Pathname &target, zyppng::ProgressObserverRef tracker ) { try { // do what Provide would do and make a URL @@ -570,10 +578,10 @@ namespace zyppng { } } - expected MediaSyncFacade::copyFile(zyppng::MediaSyncFacade::Res source, const zypp::Pathname &target) + expected MediaSyncFacade::copyFile(zyppng::MediaContextRef ctx, zyppng::MediaSyncFacade::Res source, const zypp::Pathname &target, zyppng::ProgressObserverRef tracker) { // not much to do here, since this will block until the file has been copied we do not need to remember the ProvideRes - return copyFile( source.file(), target ); + return copyFile( std::move(ctx), source.file(), target ); } void zyppng::MediaSyncFacade::releaseMedium(const AttachedSyncMediaInfo *ptr) diff --git a/zypp/ng/workflows/mediafacade.h b/zypp/ng/workflows/mediafacade.h index c79cfb910b..1d5e6de7cd 100644 --- a/zypp/ng/workflows/mediafacade.h +++ b/zypp/ng/workflows/mediafacade.h @@ -35,6 +35,7 @@ namespace zyppng { const zypp::Url &baseUrl() const; const std::optional &localPath() const; const AttachedSyncMediaInfo &info ()const; + std::optional spec() const; private: AttachedSyncMediaInfo_Ptr _data; @@ -85,31 +86,31 @@ namespace zyppng { expected prepareMedia ( const std::vector &urls, const ProvideMediaSpec &request ); expected prepareMedia ( const zypp::Url &url, const ProvideMediaSpec &request ); - expected attachMediaIfNeeded( LazyMediaHandle lazyHandle ); - expected attachMedia( const std::vector &urls, const ProvideMediaSpec &request ); - expected attachMedia( const zypp::Url &url, const ProvideMediaSpec &request ); + expected attachMediaIfNeeded( LazyMediaHandle lazyHandle, ProgressObserverRef tracker = nullptr ); + expected attachMedia( const std::vector &urls, const ProvideMediaSpec &request, ProgressObserverRef tracker = nullptr ); + expected attachMedia( const zypp::Url &url, const ProvideMediaSpec &request, ProgressObserverRef tracker = nullptr ); - expected provide( const std::vector &urls, const ProvideFileSpec &request ); - expected provide( const zypp::Url &url, const ProvideFileSpec &request ); - expected provide( const MediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request ); - expected provide( const LazyMediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request ); + expected provide( MediaContextRef ctx, const std::vector &urls, const ProvideFileSpec &request, ProgressObserverRef tracker = nullptr ); + expected provide( MediaContextRef ctx, const zypp::Url &url, const ProvideFileSpec &request, ProgressObserverRef tracker = nullptr ); + expected provide( const MediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request, ProgressObserverRef tracker = nullptr ); + expected provide( const LazyMediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request, ProgressObserverRef tracker = nullptr ); /*! * Schedules a job to calculate the checksum for the given file */ - expected checksumForFile ( const zypp::Pathname &p, const std::string &algorithm ); + expected checksumForFile ( MediaContextRef ctx, const zypp::Pathname &p, const std::string &algorithm, ProgressObserverRef tracker = nullptr ); /*! * Schedules a copy job to copy a file from \a source to \a target */ - expected copyFile ( const zypp::Pathname &source, const zypp::Pathname &target ); - expected copyFile ( Res source, const zypp::Pathname &target ); + expected copyFile ( MediaContextRef ctx, const zypp::Pathname &source, const zypp::Pathname &target, ProgressObserverRef tracker = nullptr ); + expected copyFile ( MediaContextRef ctx, Res source, const zypp::Pathname &target, ProgressObserverRef tracker = nullptr ); - static auto copyResultToDest ( MediaSyncFacadeRef provider, const zypp::Pathname &targetPath ) { - return [ providerRef=std::move(provider), targetPath = targetPath ]( Res &&file ){ + static auto copyResultToDest ( MediaSyncFacadeRef provider, MediaContextRef ctx, const zypp::Pathname &targetPath, ProgressObserverRef tracker = nullptr ) { + return [ providerRef=std::move(provider), opContext = std::move(ctx), targetPath = targetPath, tracker = std::move(tracker) ]( Res &&file ){ zypp::filesystem::assert_dir( targetPath.dirname () ); - return providerRef->copyFile( std::move(file), targetPath ); + return providerRef->copyFile( opContext, std::move(file), targetPath, tracker ); }; } diff --git a/zypp/ng/workflows/repoinfowf.cc b/zypp/ng/workflows/repoinfowf.cc index cf739e9935..5ce516a0c8 100644 --- a/zypp/ng/workflows/repoinfowf.cc +++ b/zypp/ng/workflows/repoinfowf.cc @@ -8,7 +8,7 @@ \---------------------------------------------------------------------*/ #include "repoinfowf.h" #include "zypp/ng/reporthelper.h" -#include + #include #include #include @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -47,8 +48,9 @@ namespace zyppng { using MediaHandle = typename ProvideType::MediaHandle; using ProvideRes = typename ProvideType::Res; - RepoInfoProvideKeyLogic( ZyppContextRefType &&zyppContext, zypp::RepoInfo &&info, std::string &&keyID_r, zypp::Pathname &&targetDirectory_r ) - : _reports( std::move(zyppContext )) + RepoInfoProvideKeyLogic( ZyppContextRefType &&zyppContext, ProgressObserverRef &&taskObserver, RepoInfo &&info, std::string &&keyID_r, zypp::Pathname &&targetDirectory_r ) + : _taskObserver( std::move(taskObserver) ) + , _reports( std::move(zyppContext), _taskObserver ) , _info( std::move(info) ) , _keyID_r(std::move( keyID_r )) , _targetDirectory_r(std::move( targetDirectory_r )) @@ -122,8 +124,8 @@ namespace zyppng { protected: MaybeAsyncRef> fetchKey ( const zypp::Url &url ) { - return _reports.zyppContext()->provider ()->provide( url, zyppng::ProvideFileSpec() ) - | and_then( ProvideType::copyResultToDest( _reports.zyppContext()->provider(), _targetDirectory_r / zypp::Pathname( url.getPathName() ).basename() ) ); + return _reports.zyppContext()->provider ()->provide( _reports.zyppContext(), url, zyppng::ProvideFileSpec() ) + | and_then( ProvideType::copyResultToDest( _reports.zyppContext()->provider(), _reports.zyppContext(), _targetDirectory_r / zypp::Pathname( url.getPathName() ).basename() ) ); } void importKeysInTargetDir () { @@ -187,8 +189,9 @@ namespace zyppng { return _targetDirectory_r/(zypp::str::Format("%1%.key") % keyData.rpmName()).asString(); } + ProgressObserverRef _taskObserver; JobReportHelper _reports; - const zypp::RepoInfo _info; + const RepoInfo _info{nullptr}; const std::string _keyID_r; const zypp::Pathname _targetDirectory_r; const std::string _keyIDStr; @@ -197,7 +200,7 @@ namespace zyppng { zypp::KeyRing _tempKeyRing; }; - +#if 0 struct AsyncRepoInfoProvideKey : public RepoInfoProvideKeyLogic> { using RepoInfoProvideKeyLogic::RepoInfoProvideKeyLogic; @@ -207,16 +210,17 @@ namespace zyppng { { using RepoInfoProvideKeyLogic::RepoInfoProvideKeyLogic; }; +#endif } - zypp::filesystem::Pathname RepoInfoWorkflow::provideKey( SyncContextRef ctx, zypp::RepoInfo info, std::string keyID_r, zypp::filesystem::Pathname targetDirectory_r ) + zypp::filesystem::Pathname RepoInfoWorkflow::provideKey( SyncContextRef ctx, ProgressObserverRef taskObserver, RepoInfo info, std::string keyID_r, zypp::filesystem::Pathname targetDirectory_r ) { - return SimpleExecutor>::run( std::move(ctx), std::move(info), std::move(keyID_r), std::move(targetDirectory_r) ); + return SimpleExecutor>::run( std::move(ctx), std::move(taskObserver), std::move(info), std::move(keyID_r), std::move(targetDirectory_r) ); } - AsyncOpRef RepoInfoWorkflow::provideKey(ContextRef ctx, zypp::RepoInfo info, std::string keyID_r, zypp::filesystem::Pathname targetDirectory_r ) + AsyncOpRef RepoInfoWorkflow::provideKey(AsyncContextRef ctx, ProgressObserverRef taskObserver, RepoInfo info, std::string keyID_r, zypp::filesystem::Pathname targetDirectory_r ) { - return SimpleExecutor>::run( std::move(ctx), std::move(info), std::move(keyID_r), std::move(targetDirectory_r) ); + return SimpleExecutor>::run( std::move(ctx), std::move(taskObserver), std::move(info), std::move(keyID_r), std::move(targetDirectory_r) ); } } diff --git a/zypp/ng/workflows/repoinfowf.h b/zypp/ng/workflows/repoinfowf.h index ff28c60f23..58379cf9d9 100644 --- a/zypp/ng/workflows/repoinfowf.h +++ b/zypp/ng/workflows/repoinfowf.h @@ -12,15 +12,15 @@ #include #include #include +#include namespace zyppng { - ZYPP_FWD_DECL_TYPE_WITH_REFS (Context); - ZYPP_FWD_DECL_TYPE_WITH_REFS (SyncContext); + ZYPP_FWD_DECL_TYPE_WITH_REFS (ProgressObserver); namespace RepoInfoWorkflow { - zypp::Pathname provideKey ( SyncContextRef ctx, zypp::RepoInfo info, std::string keyID_r, zypp::Pathname targetDirectory_r ); - AsyncOpRef provideKey ( ContextRef ctx, zypp::RepoInfo info, std::string keyID_r, zypp::Pathname targetDirectory_r ); + zypp::Pathname provideKey ( SyncContextRef ctx, ProgressObserverRef taskObserver, RepoInfo info, std::string keyID_r, zypp::Pathname targetDirectory_r ); + AsyncOpRef provideKey ( AsyncContextRef ctx, ProgressObserverRef taskObserver, RepoInfo info, std::string keyID_r, zypp::Pathname targetDirectory_r ); } } diff --git a/zypp/ng/workflows/signaturecheckwf.cc b/zypp/ng/workflows/signaturecheckwf.cc index 57d9fc03b3..cfdb8dbe65 100644 --- a/zypp/ng/workflows/signaturecheckwf.cc +++ b/zypp/ng/workflows/signaturecheckwf.cc @@ -11,6 +11,7 @@ #include "keyringwf.h" #include "logichelpers.h" +#include #include #include #include @@ -27,8 +28,9 @@ namespace zyppng { ZYPP_ENABLE_LOGIC_BASE(Executor,OpType); using ZyppContextRefType = MaybeAsyncContextRef; - VerifySignatureLogic( ZyppContextRefType &&zyppCtx, zypp::keyring::VerifyFileContext &&ctx ) + VerifySignatureLogic( ZyppContextRefType &&zyppCtx, ProgressObserverRef &&taskObserver, zypp::keyring::VerifyFileContext &&ctx ) : _zyppCtx( std::move(zyppCtx) ) + , _taskObserver( std::move(taskObserver) ) , _verifyCtx( std::move(ctx) ) { } MaybeAsyncRef> execute () { @@ -40,7 +42,7 @@ namespace zyppng { MIL << "Checking " << _verifyCtx.file ()<< " file validity using digital signature.." << std::endl; - return KeyRingWorkflow::verifyFileSignature( _zyppCtx, zypp::keyring::VerifyFileContext( _verifyCtx ) ) + return KeyRingWorkflow::verifyFileSignature( _zyppCtx, _taskObserver, zypp::keyring::VerifyFileContext( _verifyCtx ) ) | []( auto &&res ) { if ( not res.first ) return expected::error( ZYPP_EXCPT_PTR( zypp::SignatureCheckException( "Signature verification failed for " + res.second.file().basename() ) ) ); @@ -49,20 +51,21 @@ namespace zyppng { } protected: - ZyppContextRefType _zyppCtx; + ZyppContextRefType _zyppCtx; + ProgressObserverRef _taskObserver; zypp::keyring::VerifyFileContext _verifyCtx; }; } namespace SignatureFileCheckWorkflow { - expected verifySignature(SyncContextRef ctx, zypp::keyring::VerifyFileContext context ) + expected verifySignature(SyncContextRef ctx, ProgressObserverRef taskObserver, zypp::keyring::VerifyFileContext context ) { - return SimpleExecutor>>::run( std::move(ctx), std::move(context) ); + return SimpleExecutor>>::run( std::move(ctx), std::move(taskObserver), std::move(context) ); } - AsyncOpRef > verifySignature(ContextRef ctx, zypp::keyring::VerifyFileContext context ) + AsyncOpRef > verifySignature(AsyncContextRef ctx, ProgressObserverRef taskObserver, zypp::keyring::VerifyFileContext context ) { - return SimpleExecutor>>::run( std::move(ctx), std::move(context) ); + return SimpleExecutor>>::run( std::move(ctx), std::move(taskObserver), std::move(context) ); } } } diff --git a/zypp/ng/workflows/signaturecheckwf.h b/zypp/ng/workflows/signaturecheckwf.h index 9a24146a19..66a27d1dcb 100644 --- a/zypp/ng/workflows/signaturecheckwf.h +++ b/zypp/ng/workflows/signaturecheckwf.h @@ -9,6 +9,7 @@ #ifndef ZYPP_NG_SIGNATURECHECK_WORKFLOW_INCLUDED #define ZYPP_NG_SIGNATURECHECK_WORKFLOW_INCLUDED +#include #include #include @@ -17,15 +18,15 @@ #include // async helper -#include + namespace zyppng { - ZYPP_FWD_DECL_TYPE_WITH_REFS (Context); + ZYPP_FWD_DECL_TYPE_WITH_REFS (ProgressObserver); namespace SignatureFileCheckWorkflow { - expected verifySignature( SyncContextRef ctx, zypp::keyring::VerifyFileContext context ); - AsyncOpRef> verifySignature( ContextRef ctx, zypp::keyring::VerifyFileContext context ); + expected verifySignature(SyncContextRef ctx, zyppng::ProgressObserverRef taskObserver, zypp::keyring::VerifyFileContext context ); + AsyncOpRef> verifySignature( AsyncContextRef ctx, ProgressObserverRef taskObserver, zypp::keyring::VerifyFileContext context ); } } diff --git a/zypp/parser/RepoindexFileReader.cc b/zypp/parser/RepoindexFileReader.cc deleted file mode 100644 index c8a339aea6..0000000000 --- a/zypp/parser/RepoindexFileReader.cc +++ /dev/null @@ -1,282 +0,0 @@ -/*---------------------------------------------------------------------\ -| ____ _ __ __ ___ | -| |__ / \ / / . \ . \ | -| / / \ V /| _/ _/ | -| / /__ | | | | | | | -| /_____||_| |_| |_| | -| | -\---------------------------------------------------------------------*/ -/** \file zypp/parser/RepoindexFileReader.cc - * Implementation of repoindex.xml file reader. - */ -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include - -#include - - -#undef ZYPP_BASE_LOGGER_LOGGROUP -#define ZYPP_BASE_LOGGER_LOGGROUP "parser" - -using std::endl; - -namespace zypp -{ - namespace parser - { - using xml::Reader; - using xml::XmlString; - - /////////////////////////////////////////////////////////////////// - namespace - { - class VarReplacer : private base::NonCopyable - { - public: - /** */ - void setVar( const std::string & key_r, const std::string & val_r ) - { - //MIL << "*** Inject " << key_r << " = " << val_r; - _vars[key_r] = replace( val_r ); - //MIL << " (" << _vars[key_r] << ")" << endl; - } - - std::string replace( const std::string & val_r ) const - { - std::string::size_type vbeg = val_r.find( "%{", 0 ); - if ( vbeg == std::string::npos ) - return val_r; - - str::Str ret; - std::string::size_type cbeg = 0; - for( ; vbeg != std::string::npos; vbeg = val_r.find( "%{", vbeg ) ) - { - std::string::size_type nbeg = vbeg+2; - std::string::size_type nend = val_r.find( '}', nbeg ); - if ( nend == std::string::npos ) - { - WAR << "Incomplete variable in '" << val_r << "'" << endl; - break; - } - const auto & iter = _vars.find( val_r.substr( nbeg, nend-nbeg ) ); - if ( iter != _vars.end() ) - { - if ( cbeg < vbeg ) - ret << val_r.substr( cbeg, vbeg-cbeg ); - ret << iter->second; - cbeg = nend+1; - } - else - WAR << "Undefined variable %{" << val_r.substr( nbeg, nend-nbeg ) << "} in '" << val_r << "'" << endl; - vbeg = nend+1; - } - if ( cbeg < val_r.size() ) - ret << val_r.substr( cbeg ); - - return ret; - } - private: - std::unordered_map _vars; - }; - } // namespace - /////////////////////////////////////////////////////////////////// - - /////////////////////////////////////////////////////////////////////// - // - // CLASS NAME : RepoindexFileReader::Impl - // - class RepoindexFileReader::Impl : private base::NonCopyable - { - public: - /** - * CTOR - * - * \see RepoindexFileReader::RepoindexFileReader(Pathname,ProcessResource) - */ - Impl(const InputStream &is, ProcessResource &&callback); - - /** - * Callback provided to the XML parser. - */ - bool consumeNode( Reader & reader_r ); - - DefaultIntegral _ttl; - - private: - bool getAttrValue( const std::string & key_r, Reader & reader_r, std::string & value_r ) - { - const XmlString & s( reader_r->getAttribute( key_r ) ); - if ( s.get() ) - { - value_r = _replacer.replace( s.asString() ); - return !value_r.empty(); - } - value_r.clear(); - return false; - } - - private: - /** Function for processing collected data. Passed-in through constructor. */ - ProcessResource _callback; - VarReplacer _replacer; - }; - /////////////////////////////////////////////////////////////////////// - - RepoindexFileReader::Impl::Impl(const InputStream &is, - ProcessResource &&callback) - : _callback(std::move(callback)) - { - Reader reader( is ); - MIL << "Reading " << is.path() << endl; - reader.foreachNode( bind( &RepoindexFileReader::Impl::consumeNode, this, _1 ) ); - } - - // -------------------------------------------------------------------------- - - /* - * xpath and multiplicity of processed nodes are included in the code - * for convenience: - * - * // xpath: (?|*|+) - * - * if multiplicity is ommited, then the node has multiplicity 'one'. - */ - - // -------------------------------------------------------------------------- - - bool RepoindexFileReader::Impl::consumeNode( Reader & reader_r ) - { - if ( reader_r->nodeType() == XML_READER_TYPE_ELEMENT ) - { - // xpath: /repoindex - if ( reader_r->name() == "repoindex" ) - { - while ( reader_r.nextNodeAttribute() ) - { - const std::string & name( reader_r->localName().asString() ); - const std::string & value( reader_r->value().asString() ); - _replacer.setVar( name, value ); - // xpath: /repoindex@ttl - if ( name == "ttl" ) - _ttl = str::strtonum(value); - } - return true; - } - - // xpath: /repoindex/data (+) - if ( reader_r->name() == "repo" ) - { - RepoInfo info; - // Set some defaults that are not contained in the repo information - info.setAutorefresh( true ); - info.setEnabled(false); - - std::string attrValue; - - // required alias - // mandatory, so we can allow it in var replacement without reset - if ( getAttrValue( "alias", reader_r, attrValue ) ) - { - info.setAlias( attrValue ); - _replacer.setVar( "alias", attrValue ); - } - else - throw ParseException(str::form(_("Required attribute '%s' is missing."), "alias")); - - // required url - // SLES HACK: or path, but beware of the hardcoded '/repo' prefix! - { - std::string urlstr; - std::string pathstr; - getAttrValue( "url", reader_r, urlstr ); - getAttrValue( "path", reader_r, pathstr ); - if ( urlstr.empty() ) - { - if ( pathstr.empty() ) - throw ParseException(str::form(_("One or both of '%s' or '%s' attributes is required."), "url", "path")); - else - info.setPath( Pathname("/repo") / pathstr ); - } - else - { - if ( pathstr.empty() ) - info.setBaseUrl( Url(urlstr) ); - else - { - Url url( urlstr ); - url.setPathName( Pathname(url.getPathName()) / "repo" / pathstr ); - info.setBaseUrl( url ); - } - } - } - - // optional name - if ( getAttrValue( "name", reader_r, attrValue ) ) - info.setName( attrValue ); - - // optional targetDistro - if ( getAttrValue( "distro_target", reader_r, attrValue ) ) - info.setTargetDistribution( attrValue ); - - // optional priority - if ( getAttrValue( "priority", reader_r, attrValue ) ) - info.setPriority( str::strtonum( attrValue ) ); - - - // optional enabled - if ( getAttrValue( "enabled", reader_r, attrValue ) ) - info.setEnabled( str::strToBool( attrValue, info.enabled() ) ); - - // optional autorefresh - if ( getAttrValue( "autorefresh", reader_r, attrValue ) ) - info.setAutorefresh( str::strToBool( attrValue, info.autorefresh() ) ); - - DBG << info << endl; - - // ignore the rest - _callback(info); - return true; - } - } - - return true; - } - - - /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : RepoindexFileReader - // - /////////////////////////////////////////////////////////////////// - - RepoindexFileReader::RepoindexFileReader( Pathname repoindex_file, ProcessResource callback ) - : _pimpl(new Impl( InputStream(std::move(repoindex_file)), std::move(callback) )) - {} - - RepoindexFileReader::RepoindexFileReader(const InputStream &is, ProcessResource callback ) - : _pimpl(new Impl( is, std::move(callback) )) - {} - - RepoindexFileReader::~RepoindexFileReader() - {} - - Date::Duration RepoindexFileReader::ttl() const { return _pimpl->_ttl; } - - } // ns parser -} // ns zypp - -// vim: set ts=2 sts=2 sw=2 et ai: diff --git a/zypp/repo/GpgCheck.cc b/zypp/repo/GpgCheck.cc new file mode 100644 index 0000000000..06888422d2 --- /dev/null +++ b/zypp/repo/GpgCheck.cc @@ -0,0 +1,31 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#include "GpgCheck.h" + +namespace zypp { + std::ostream & operator<<( std::ostream & str, const repo::GpgCheck & obj ) + { + switch ( obj ) + { +#define OUTS( V ) case repo::V: return str << #V; break + OUTS( GpgCheck::On ); + OUTS( GpgCheck::Strict ); + OUTS( GpgCheck::AllowUnsigned ); + OUTS( GpgCheck::AllowUnsignedRepo ); + OUTS( GpgCheck::AllowUnsignedPackage ); + OUTS( GpgCheck::Default ); + OUTS( GpgCheck::Off ); + OUTS( GpgCheck::indeterminate ); +#undef OUTS + } + return str << "GpgCheck::UNKNOWN"; + } + +} diff --git a/zypp/repo/GpgCheck.h b/zypp/repo/GpgCheck.h new file mode 100644 index 0000000000..dedb11a5d6 --- /dev/null +++ b/zypp/repo/GpgCheck.h @@ -0,0 +1,40 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/source/GpgCheck.h + * +*/ +#ifndef ZYPP_REPO_GPGCHECK_H_INCLUDED +#define ZYPP_REPO_GPGCHECK_H_INCLUDED + +#include +#include + +namespace zypp { + namespace repo { + /** Some predefined settings */ + enum class ZYPP_API GpgCheck { + indeterminate, //< not specified + On, //< 1** --gpgcheck + Strict, //< 111 --gpgcheck-strict + AllowUnsigned, //< 100 --gpgcheck-allow-unsigned + AllowUnsignedRepo, //< 10* --gpgcheck-allow-unsigned-repo + AllowUnsignedPackage, //< 1*0 --gpgcheck-allow-unsigned-package + Default, //< *** --default-gpgcheck + Off, //< 0** --no-gpgcheck + }; + } + + /** \relates RepoInfo::GpgCheck Stream output */ + std::ostream & operator<<( std::ostream & str, const repo::GpgCheck & obj ) ZYPP_API; +} + + + + +#endif //ZYPP_REPO_GPGCHECK_H_INCLUDED diff --git a/zypp/repo/MediaInfoDownloader.cc b/zypp/repo/MediaInfoDownloader.cc index 189374466a..e7014fcf73 100644 --- a/zypp/repo/MediaInfoDownloader.cc +++ b/zypp/repo/MediaInfoDownloader.cc @@ -29,7 +29,7 @@ void downloadMediaInfo( const Pathname &dest_dir, //hardcode the max filesize to 20MB, to prevent unlimited data downloads but this limit will //never be reached in a sane setup - fetcher.enqueue( OnMediaLocation("/media.1/media").setOptional(true) ); + fetcher.enqueue( OnMediaLocation("/media.1/media").setOptional(true).setDownloadSize( ByteCount(20, ByteCount::MB ) ) ); fetcher.start( dest_dir, media, progressrcv ); // ready, go! fetcher.reset(); diff --git a/zypp/repo/PackageProvider.cc b/zypp/repo/PackageProvider.cc index ab7c315e86..6f9e93fea7 100644 --- a/zypp/repo/PackageProvider.cc +++ b/zypp/repo/PackageProvider.cc @@ -9,10 +9,9 @@ /** \file zypp/repo/PackageProvider.cc * */ -#include "zypp/ng/workflows/contextfacade.h" + #include #include -#include #include #include #include @@ -34,7 +33,13 @@ #include #include #include + +#include +#include #include +#include + +#include using std::endl; @@ -140,8 +145,11 @@ namespace zypp /** Provide the package if it is cached. */ ManagedFile providePackageFromCache() const override { + const auto &ri = _package->ngRepoInfo(); + if ( !ri ) + return ManagedFile(); ManagedFile ret( doProvidePackageFromCache() ); - if ( ! ( ret->empty() || _package->repoInfo().keepPackages() ) ) + if ( ! ( ret->empty() || ri->keepPackages() ) ) ret.setDispose( filesystem::unlink ); return ret; } @@ -183,10 +191,14 @@ namespace zypp ManagedFile ret; OnMediaLocation loc = _package->location(); + const auto &ri = _package->ngRepoInfo(); + if ( !ri ) + ZYPP_THROW(Exception("No RepoInfo in repository, can not provide a package.")); + ProvideFilePolicy policy; policy.progressCB( bind( &Base::progressPackageDownload, this, _1 ) ); policy.fileChecker( bind( &Base::rpmSigFileChecker, this, _1 ) ); - return _access.provideFile( _package->repoInfo(), loc, policy ); + return _access.provideFile( *ri, loc, policy ); } protected: @@ -215,8 +227,8 @@ namespace zypp //@{ void rpmSigFileChecker( const Pathname & file_r ) const { - RepoInfo info = _package->repoInfo(); - if ( info.pkgGpgCheck() ) + const auto &info = _package->ngRepoInfo(); + if ( info.value_or( zyppng::RepoInfo(nullptr) ).pkgGpgCheck() ) { UserData userData( "pkgGpgCheck" ); ResObject::constPtr roptr( _package ); // gcc6 needs it more explcit. Has problem deducing @@ -226,7 +238,7 @@ namespace zypp RpmDb::CheckPackageResult res = RpmDb::CHK_NOKEY; while ( res == RpmDb::CHK_NOKEY ) { - res = packageSigCheck( file_r, info.pkgGpgCheckIsMandatory(), userData ); + res = packageSigCheck( file_r, info->pkgGpgCheckIsMandatory(), userData ); // publish the checkresult, even if it is OK. Apps may want to report something... report()->pkgGpgCheck( userData ); @@ -246,7 +258,7 @@ namespace zypp std::string keyID = hr->signatureKeyID(); if ( keyID.length() > 0 ) { - if ( !zyppng::KeyRingWorkflow::provideAndImportKeyFromRepository ( zyppng::SyncContext::defaultContext(), keyID, info ) ) + if ( !zyppng::KeyRingWorkflow::provideAndImportKeyFromRepository ( zypp::zypp_detail::GlobalStateHelper::context(), zypp_detail::GlobalStateHelper::context()->progressObserver(), keyID, *info ) ) break; } else { @@ -387,25 +399,27 @@ namespace zypp } // HERE: cache misss, check toplevel cache or do download: - RepoInfo info = _package->repoInfo(); + const auto &info = _package->ngRepoInfo(); + if ( !info ) + ZYPP_THROW(Exception("No RepoInfo in repository, can not provide a package.")); // Check toplevel cache { - RepoManagerOptions topCache; - if ( info.packagesPath().dirname() != topCache.repoPackagesCachePath ) // not using toplevel cache + RepoManagerOptions topCache( info->context() ); + if ( info->packagesPath().dirname() != topCache.repoPackagesCachePath ) // not using toplevel cache { const OnMediaLocation & loc( _package->location() ); if ( ! loc.checksum().empty() ) // no cache hit without checksum { - PathInfo pi( topCache.repoPackagesCachePath / info.packagesPath().basename() / info.path() / loc.filename() ); + PathInfo pi( topCache.repoPackagesCachePath / info->packagesPath().basename() / info->path() / loc.filename() ); if ( pi.isExist() && loc.checksum() == CheckSum( loc.checksum().type(), std::ifstream( pi.c_str() ) ) ) { report()->start( _package, pi.path().asFileUrl() ); - const Pathname & dest( info.packagesPath() / info.path() / loc.filename() ); + const Pathname & dest( info->packagesPath() / info->path() / loc.filename() ); if ( filesystem::assert_dir( dest.dirname() ) == 0 && filesystem::hardlinkCopy( pi.path(), dest ) == 0 ) { ret = ManagedFile( dest ); - if ( ! info.keepPackages() ) + if ( ! info->keepPackages() ) ret.setDispose( filesystem::unlink ); MIL << "provided Package from toplevel cache " << _package << " at " << ret << endl; @@ -418,11 +432,11 @@ namespace zypp } // FIXME we only support the first url for now. - if ( info.baseUrlsEmpty() ) + if ( info->baseUrlsEmpty() ) ZYPP_THROW(Exception("No url in repository.")); MIL << "provide Package " << _package << endl; - Url url = * info.baseUrlsBegin(); + Url url = * info->baseUrlsBegin(); try { do { _retry = false; @@ -566,10 +580,14 @@ namespace zypp ManagedFile RpmPackageProvider::doProvidePackage() const { + const auto &ri = _package->ngRepoInfo(); + // check whether to process patch/delta rpms // FIXME we only check the first url for now. - if ( ZConfig::instance().download_use_deltarpm() - && ( _package->repoInfo().url().schemeIsDownloading() || ZConfig::instance().download_use_deltarpm_always() ) ) + if ( ri + && ri->context() + && ri->context()->config().download_use_deltarpm() + && ( _package->ngRepoInfo()->url().schemeIsDownloading() || ri->context()->config().download_use_deltarpm_always() ) ) { std::list deltaRpms; _deltas.deltaRpms( _package ).swap( deltaRpms ); @@ -606,7 +624,11 @@ namespace zypp { ProvideFilePolicy policy; policy.progressCB( bind( &RpmPackageProvider::progressDeltaDownload, this, _1 ) ); - delta = _access.provideFile( delta_r.repository().info(), delta_r.location(), policy ); + const auto &optRepo = delta_r.repository().ngInfo(); + if ( !optRepo ) { + return ManagedFile(); + } + delta = _access.provideFile( *optRepo, delta_r.location(), policy ); } catch ( const Exception & excpt ) { @@ -623,7 +645,7 @@ namespace zypp } // Build the package - Pathname cachedest( _package->repoInfo().packagesPath() / _package->repoInfo().path() / _package->location().filename() ); + Pathname cachedest( _package->ngRepoInfo()->packagesPath() / _package->ngRepoInfo()->path() / _package->location().filename() ); Pathname builddest( cachedest.extend( ".drpm" ) ); if ( ! applydeltarpm::provide( delta, builddest, diff --git a/zypp/repo/PluginRepoverification.cc b/zypp/repo/PluginRepoverification.cc index c6249e9ac7..967bf8e630 100644 --- a/zypp/repo/PluginRepoverification.cc +++ b/zypp/repo/PluginRepoverification.cc @@ -20,6 +20,9 @@ #include #include #include + +#include + using std::endl; /////////////////////////////////////////////////////////////////// @@ -108,7 +111,7 @@ namespace zypp_private { public: Impl( RW_pointer parent_r, - Pathname &&sigpathLocal_r, Pathname &&keypathLocal_r, RepoInfo &&repo_r ) + Pathname &&sigpathLocal_r, Pathname &&keypathLocal_r, zyppng::RepoInfo &&repo_r ) : _parent { std::move( parent_r ) } , _sigpathLocal { std::move(sigpathLocal_r) } , _keypathLocal { std::move(keypathLocal_r) } @@ -118,7 +121,7 @@ namespace zypp_private RW_pointer _parent; Pathname _sigpathLocal; Pathname _keypathLocal; - RepoInfo _repoinfo; + zyppng::RepoInfo _repoinfo; }; /////////////////////////////////////////////////////////////////// @@ -281,7 +284,7 @@ namespace zypp_private bool PluginRepoverification::checkIfNeeded() { return _pimpl->checkIfNeeded(); } - PluginRepoverification::Checker PluginRepoverification::getChecker( Pathname sigpathLocal_r, Pathname keypathLocal_r, RepoInfo repo_r ) const + PluginRepoverification::Checker PluginRepoverification::getChecker( Pathname sigpathLocal_r, Pathname keypathLocal_r, zyppng::RepoInfo repo_r ) const { return Checker( new Checker::Impl( _pimpl, std::move(sigpathLocal_r), std::move(keypathLocal_r), std::move(repo_r) ) ); } diff --git a/zypp/repo/PluginRepoverification.h b/zypp/repo/PluginRepoverification.h index c6e7620719..d40adbaa1e 100644 --- a/zypp/repo/PluginRepoverification.h +++ b/zypp/repo/PluginRepoverification.h @@ -14,10 +14,13 @@ #include #include -#include #include #include +namespace zyppng { + class RepoInfo; +} + /////////////////////////////////////////////////////////////////// namespace zypp_private { @@ -100,7 +103,7 @@ namespace zypp_private /////////////////////////////////////////////////////////////////// /** \ref FileChecker factory remembering the location of the master index files GPG signature and key. */ - Checker getChecker( Pathname sigpathLocal_r, Pathname keypathLocal_r, RepoInfo repo_r ) const; + Checker getChecker( Pathname sigpathLocal_r, Pathname keypathLocal_r, zyppng::RepoInfo repo_r ) const; public: class Impl; ///< Implementation class. diff --git a/zypp/repo/RepoException.cc b/zypp/repo/RepoException.cc index 09e04fb829..4023bbcf17 100644 --- a/zypp/repo/RepoException.cc +++ b/zypp/repo/RepoException.cc @@ -16,6 +16,8 @@ using std::endl; +ZYPP_BEGIN_LEGACY_API + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -45,6 +47,14 @@ namespace zypp : Exception( msg_r ), _info( info ) {} + RepoException::RepoException( const zyppng::RepoInfo & info ) + : RepoException( RepoInfo(info) ) + {} + + RepoException::RepoException( const zyppng::RepoInfo & info, const std::string& msg_r ) + : RepoException( RepoInfo(info), msg_r ) + {} + RepoException::~RepoException() throw() {} @@ -60,7 +70,9 @@ namespace zypp CLASS::CLASS() : RepoException( MSG ) {} \ CLASS::CLASS( const std::string & msg_r ) : RepoException( msg_r ) {} \ CLASS::CLASS( const RepoInfo & service_r ) : RepoException( service_r, MSG ) {} \ - CLASS::CLASS( const RepoInfo & service_r, const std::string & msg_r ) : RepoException( service_r, msg_r ) {} + CLASS::CLASS( const RepoInfo & service_r, const std::string & msg_r ) : RepoException( service_r, msg_r ) {}\ + CLASS::CLASS( const zyppng::RepoInfo & service_r ) : RepoException( service_r, MSG ) {} \ + CLASS::CLASS( const zyppng::RepoInfo & service_r, const std::string & msg_r ) : RepoException( service_r, msg_r ) {} DEF_CTORS( RepoNotCachedException, "Repository is not cached" ); DEF_CTORS( RepoNoUrlException, "Repository has no or invalid url defined." ); @@ -96,6 +108,14 @@ namespace zypp : Exception( msg_r ), _service( service_r ) {} + ServiceException::ServiceException( const zyppng::ServiceInfo & service_r ) + : ServiceException( ServiceInfo(service_r) ) + {} + + ServiceException::ServiceException( const zyppng::ServiceInfo & service_r, const std::string & msg_r ) + : ServiceException( ServiceInfo(service_r), msg_r ) + {} + ServiceException::~ServiceException() throw() {} @@ -111,7 +131,9 @@ namespace zypp CLASS::CLASS() : DEF_BASECLASS( MSG ) {} \ CLASS::CLASS( const std::string & msg_r ) : DEF_BASECLASS( msg_r ) {} \ CLASS::CLASS( const ServiceInfo & service_r ) : DEF_BASECLASS( service_r, MSG ) {} \ - CLASS::CLASS( const ServiceInfo & service_r, const std::string & msg_r ) : DEF_BASECLASS( service_r, msg_r ) {} + CLASS::CLASS( const ServiceInfo & service_r, const std::string & msg_r ) : DEF_BASECLASS( service_r, msg_r ) {} \ + CLASS::CLASS( const zyppng::ServiceInfo & service_r ) : DEF_BASECLASS( service_r, MSG ) {} \ + CLASS::CLASS( const zyppng::ServiceInfo & service_r, const std::string & msg_r ) : DEF_BASECLASS( service_r, msg_r ) {} #define DEF_BASECLASS ServiceException DEF_CTORS( ServiceNoAliasException, "Service has no alias defined." ); @@ -136,3 +158,5 @@ namespace zypp ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// + +ZYPP_END_LEGACY_API diff --git a/zypp/repo/RepoException.h b/zypp/repo/RepoException.h index 99d37282bb..b46af22fe4 100644 --- a/zypp/repo/RepoException.h +++ b/zypp/repo/RepoException.h @@ -20,6 +20,13 @@ #include #include +namespace zyppng { + class RepoInfo; + class ServiceInfo; +} + +ZYPP_BEGIN_LEGACY_API + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -41,6 +48,9 @@ namespace zypp RepoException( const std::string & msg_r ); RepoException( const RepoInfo & info ); RepoException( const RepoInfo & info, const std::string & msg_r ); + RepoException( const zyppng::RepoInfo & info ); + RepoException( const zyppng::RepoInfo & info, const std::string & msg_r ); + ~RepoException() throw() override; RepoInfo info() @@ -69,6 +79,8 @@ namespace zypp RepoNotCachedException( const std::string & msg_r ); RepoNotCachedException( const RepoInfo & info ); RepoNotCachedException( const RepoInfo & info, const std::string & msg_r ); + RepoNotCachedException( const zyppng::RepoInfo & info ); + RepoNotCachedException( const zyppng::RepoInfo & info, const std::string & msg_r ); }; /** @@ -82,6 +94,8 @@ namespace zypp RepoNoUrlException( const std::string & msg_r ); RepoNoUrlException( const RepoInfo & info ); RepoNoUrlException( const RepoInfo & info, const std::string & msg_r ); + RepoNoUrlException( const zyppng::RepoInfo & info ); + RepoNoUrlException( const zyppng::RepoInfo & info, const std::string & msg_r ); }; /** @@ -95,6 +109,8 @@ namespace zypp RepoNoAliasException( const std::string & msg_r ); RepoNoAliasException( const RepoInfo & info ); RepoNoAliasException( const RepoInfo & info, const std::string & msg_r ); + RepoNoAliasException( const zyppng::RepoInfo & info ); + RepoNoAliasException( const zyppng::RepoInfo & info, const std::string & msg_r ); }; /** @@ -107,6 +123,8 @@ namespace zypp RepoInvalidAliasException( const std::string & msg_r ); RepoInvalidAliasException( const RepoInfo & info ); RepoInvalidAliasException( const RepoInfo & info, const std::string & msg_r ); + RepoInvalidAliasException( const zyppng::RepoInfo & info ); + RepoInvalidAliasException( const zyppng::RepoInfo & info, const std::string & msg_r ); }; /** @@ -120,6 +138,8 @@ namespace zypp RepoNotFoundException( const std::string & msg_r ); RepoNotFoundException( const RepoInfo & info ); RepoNotFoundException( const RepoInfo & info, const std::string & msg_r ); + RepoNotFoundException( const zyppng::RepoInfo & info ); + RepoNotFoundException( const zyppng::RepoInfo & info, const std::string & msg_r ); }; /** @@ -133,6 +153,8 @@ namespace zypp RepoAlreadyExistsException( const std::string & msg_r ); RepoAlreadyExistsException( const RepoInfo & info ); RepoAlreadyExistsException( const RepoInfo & info, const std::string & msg_r ); + RepoAlreadyExistsException( const zyppng::RepoInfo & info ); + RepoAlreadyExistsException( const zyppng::RepoInfo & info, const std::string & msg_r ); }; /** @@ -146,6 +168,8 @@ namespace zypp RepoUnknownTypeException( const std::string & msg_r ); RepoUnknownTypeException( const RepoInfo & info ); RepoUnknownTypeException( const RepoInfo & info, const std::string & msg_r ); + RepoUnknownTypeException( const zyppng::RepoInfo & info ); + RepoUnknownTypeException( const zyppng::RepoInfo & info, const std::string & msg_r ); }; /** @@ -159,6 +183,8 @@ namespace zypp RepoMetadataException( const std::string & msg_r ); RepoMetadataException( const RepoInfo & info ); RepoMetadataException( const RepoInfo & info, const std::string & msg_r ); + RepoMetadataException( const zyppng::RepoInfo & info ); + RepoMetadataException( const zyppng::RepoInfo & info, const std::string & msg_r ); }; /** @@ -171,6 +197,8 @@ namespace zypp RepoNoPermissionException( const std::string & msg_r ); RepoNoPermissionException( const RepoInfo & info ); RepoNoPermissionException( const RepoInfo & info, const std::string & msg_r ); + RepoNoPermissionException( const zyppng::RepoInfo & info ); + RepoNoPermissionException( const zyppng::RepoInfo & info, const std::string & msg_r ); }; @@ -192,6 +220,8 @@ namespace zypp ServiceException( const std::string & msg_r ); ServiceException( const ServiceInfo & service_r ); ServiceException( const ServiceInfo & service_r, const std::string & msg_r ); + ServiceException( const zyppng::ServiceInfo & service_r ); + ServiceException( const zyppng::ServiceInfo & service_r, const std::string & msg_r ); ~ServiceException() throw() override; ServiceInfo service() @@ -217,6 +247,8 @@ namespace zypp ServiceNoAliasException( const std::string & msg_r ); ServiceNoAliasException( const ServiceInfo & service_r ); ServiceNoAliasException( const ServiceInfo & service_r, const std::string & msg_r ); + ServiceNoAliasException( const zyppng::ServiceInfo & service_r ); + ServiceNoAliasException( const zyppng::ServiceInfo & service_r, const std::string & msg_r ); }; /** @@ -229,6 +261,8 @@ namespace zypp ServiceInvalidAliasException( const std::string & msg_r ); ServiceInvalidAliasException( const ServiceInfo & info ); ServiceInvalidAliasException( const ServiceInfo & info, const std::string & msg_r ); + ServiceInvalidAliasException( const zyppng::ServiceInfo & service_r ); + ServiceInvalidAliasException( const zyppng::ServiceInfo & service_r, const std::string & msg_r ); }; /** Service already exists and some unique attribute can't be duplicated. @@ -240,6 +274,8 @@ namespace zypp ServiceAlreadyExistsException( const std::string & msg_r ); ServiceAlreadyExistsException( const ServiceInfo & service_r ); ServiceAlreadyExistsException( const ServiceInfo & service_r, const std::string & msg_r ); + ServiceAlreadyExistsException( const zyppng::ServiceInfo & service_r ); + ServiceAlreadyExistsException( const zyppng::ServiceInfo & service_r, const std::string & msg_r ); }; /** Service has no or invalid url defined. @@ -251,6 +287,8 @@ namespace zypp ServiceNoUrlException( const std::string & msg_r ); ServiceNoUrlException( const ServiceInfo & service_r ); ServiceNoUrlException( const ServiceInfo & service_r, const std::string & msg_r ); + ServiceNoUrlException( const zyppng::ServiceInfo & service_r ); + ServiceNoUrlException( const zyppng::ServiceInfo & service_r, const std::string & msg_r ); }; //@} @@ -268,6 +306,8 @@ namespace zypp ServicePluginException( const std::string & msg_r ); ServicePluginException( const ServiceInfo & service_r ); ServicePluginException( const ServiceInfo & service_r, const std::string & msg_r ); + ServicePluginException( const zyppng::ServiceInfo & service_r ); + ServicePluginException( const zyppng::ServiceInfo & service_r, const std::string & msg_r ); }; /** Service plugin has trouble providing the metadata but this should not be treated as error. @@ -279,6 +319,8 @@ namespace zypp ServicePluginInformalException( const std::string & msg_r ); ServicePluginInformalException( const ServiceInfo & service_r ); ServicePluginInformalException( const ServiceInfo & service_r, const std::string & msg_r ); + ServicePluginInformalException( const zyppng::ServiceInfo & service_r ); + ServicePluginInformalException( const zyppng::ServiceInfo & service_r, const std::string & msg_r ); }; /** Service plugin is immutable. @@ -290,6 +332,8 @@ namespace zypp ServicePluginImmutableException( const std::string & msg_r ); ServicePluginImmutableException( const ServiceInfo & service_r ); ServicePluginImmutableException( const ServiceInfo & service_r, const std::string & msg_r ); + ServicePluginImmutableException( const zyppng::ServiceInfo & service_r ); + ServicePluginImmutableException( const zyppng::ServiceInfo & service_r, const std::string & msg_r ); }; //@} @@ -299,4 +343,6 @@ namespace zypp ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// + +ZYPP_END_LEGACY_API #endif // ZYPP_PARSER_TAGFILE_PARSEEXCEPTION_H diff --git a/zypp/repo/RepoInfoBase.cc b/zypp/repo/RepoInfoBase.cc index f36bbe303d..e25b921388 100644 --- a/zypp/repo/RepoInfoBase.cc +++ b/zypp/repo/RepoInfoBase.cc @@ -6,170 +6,74 @@ | /_____||_| |_| |_| | | | \---------------------------------------------------------------------*/ -/** \file zypp/repo/RepoInfoBase.cc +/** \file zypp/repo/RepoInfoBase.cc * - */ -#include +*/ +#include "RepoInfoBase.h" +#include -#include -#include +ZYPP_BEGIN_LEGACY_API -#include -#include -#include +namespace zypp::repo { -using std::endl; - -/////////////////////////////////////////////////////////////////// -namespace zypp -{ - /////////////////////////////////////////////////////////////////// - namespace repo - { - - /////////////////////////////////////////////////////////////////// - /// \class RepoInfoBase::Impl - /// \brief RepoInfoBase data - /////////////////////////////////////////////////////////////////// - struct RepoInfoBase::Impl - { - Impl() - : _enabled( indeterminate ) - , _autorefresh( indeterminate ) - {} - - Impl( const std::string & alias_r ) - : _enabled( indeterminate ) - , _autorefresh( indeterminate ) - { setAlias( alias_r ); } - - public: - TriBool _enabled; - TriBool _autorefresh; - std::string _alias; - std::string _escaped_alias; - RepoVariablesReplacedString _name; - Pathname _filepath; - - public: - - void setAlias( const std::string & alias_r ) - { - _alias = _escaped_alias = alias_r; - // replace slashes with underscores - str::replaceAll( _escaped_alias, "/", "_" ); - } - - private: - friend Impl * rwcowClone( const Impl * rhs ); - /** clone for RWCOW_pointer */ - Impl * clone() const - { return new Impl( *this ); } - }; - /////////////////////////////////////////////////////////////////// - - /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : RepoInfoBase - // - /////////////////////////////////////////////////////////////////// - - RepoInfoBase::RepoInfoBase() - : _pimpl( new Impl() ) - {} - - RepoInfoBase::RepoInfoBase(const std::string & alias) - : _pimpl( new Impl(alias) ) + RepoInfoBase::RepoInfoBase( ) {} RepoInfoBase::~RepoInfoBase() {} void RepoInfoBase::setEnabled( bool enabled ) - { _pimpl->_enabled = enabled; } + { pimpl().setEnabled(enabled); } void RepoInfoBase::setAutorefresh( bool autorefresh ) - { _pimpl->_autorefresh = autorefresh; } + { pimpl().setAutorefresh(autorefresh); } void RepoInfoBase::setAlias( const std::string &alias ) - { _pimpl->setAlias(alias); } + { pimpl().setAlias(alias); } void RepoInfoBase::setName( const std::string &name ) - { _pimpl->_name.raw() = name; } + { pimpl().setName(name); } - void RepoInfoBase::setFilepath( const Pathname &filepath ) - { _pimpl->_filepath = filepath; } + void RepoInfoBase::setFilepath( const zypp::Pathname &filepath ) + { pimpl().setFilepath(filepath); } - // true by default (if not set by setEnabled()) bool RepoInfoBase::enabled() const - { return indeterminate(_pimpl->_enabled) ? true : (bool) _pimpl->_enabled; } + { return pimpl().enabled(); } - // false by default (if not set by setAutorefresh()) bool RepoInfoBase::autorefresh() const - { return indeterminate(_pimpl->_autorefresh) ? false : (bool) _pimpl->_autorefresh; } + { return pimpl().autorefresh(); } std::string RepoInfoBase::alias() const - { return _pimpl->_alias; } + { return pimpl().alias(); } std::string RepoInfoBase::escaped_alias() const - { return _pimpl->_escaped_alias; } + { return pimpl().escaped_alias(); } std::string RepoInfoBase::name() const - { - if ( rawName().empty() ) - return alias(); - return repo::RepoVariablesStringReplacer()( rawName() ); - } + { return pimpl().name(); } std::string RepoInfoBase::rawName() const - { return _pimpl->_name.raw(); } + { return pimpl().rawName(); } std::string RepoInfoBase::label() const - { - if ( ZConfig::instance().repoLabelIsAlias() ) - return alias(); - return name(); - } - - Pathname RepoInfoBase::filepath() const - { return _pimpl->_filepath; } + { return pimpl().label(); } + zypp::Pathname RepoInfoBase::filepath() const + { return pimpl().filepath(); } std::ostream & RepoInfoBase::dumpOn( std::ostream & str ) const - { - str << "--------------------------------------" << std::endl; - str << "- alias : " << alias() << std::endl; - if ( ! rawName().empty() ) - str << "- name : " << rawName() << std::endl; - str << "- enabled : " << enabled() << std::endl; - str << "- autorefresh : " << autorefresh() << std::endl; - - return str; - } + { return pimpl().dumpOn(str); } std::ostream & RepoInfoBase::dumpAsIniOn( std::ostream & str ) const - { - // we save the original data without variable replacement - str << "[" << alias() << "]" << endl; - if ( ! rawName().empty() ) - str << "name=" << rawName() << endl; - str << "enabled=" << (enabled() ? "1" : "0") << endl; - str << "autorefresh=" << (autorefresh() ? "1" : "0") << endl; - - return str; - } + { return pimpl().dumpAsIniOn(str); } std::ostream & RepoInfoBase::dumpAsXmlOn( std::ostream & str, const std::string & content ) const - { - return str << "" << endl; - } + { return pimpl().dumpAsXmlOn (str, content); } std::ostream & operator<<( std::ostream & str, const RepoInfoBase & obj ) { return obj.dumpOn(str); } +} - } // namespace repo - /////////////////////////////////////////////////////////////////// -} // namespace zypp -/////////////////////////////////////////////////////////////////// +ZYPP_END_LEGACY_API diff --git a/zypp/repo/RepoInfoBase.h b/zypp/repo/RepoInfoBase.h index 28669cc8ac..b366e5129b 100644 --- a/zypp/repo/RepoInfoBase.h +++ b/zypp/repo/RepoInfoBase.h @@ -18,6 +18,12 @@ #include #include +ZYPP_BEGIN_LEGACY_API + +namespace zyppng::repo { + class RepoInfoBase; +} + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -36,20 +42,21 @@ namespace zypp * \note Name is subject to repo variable replacement * (\see \ref RepoVariablesStringReplacer). */ - class ZYPP_API RepoInfoBase + class ZYPP_API ZYPP_INTERNAL_DEPRECATE RepoInfoBase { friend std::ostream & operator<<( std::ostream & str, const RepoInfoBase & obj ); public: - RepoInfoBase(); - RepoInfoBase(const std::string &alias); virtual ~RepoInfoBase(); + protected: + RepoInfoBase(); RepoInfoBase(const RepoInfoBase &) = default; RepoInfoBase(RepoInfoBase &&) noexcept = default; RepoInfoBase &operator=(const RepoInfoBase &) = default; RepoInfoBase &operator=(RepoInfoBase &&) noexcept = default; + public: /** * unique identifier for this source. If not specified * It should be generated from the base url. @@ -162,10 +169,9 @@ namespace zypp */ virtual std::ostream & dumpAsXmlOn( std::ostream & str, const std::string & content = "" ) const; - struct Impl; - private: - /** Pointer to implementation */ - RWCOW_pointer _pimpl; + protected: + virtual zyppng::repo::RepoInfoBase &pimpl() = 0; + virtual const zyppng::repo::RepoInfoBase &pimpl() const = 0; }; /////////////////////////////////////////////////////////////////// @@ -196,4 +202,6 @@ namespace zypp } // namespace zypp /////////////////////////////////////////////////////////////////// +ZYPP_END_LEGACY_API + #endif /*REPOINFOBASE_H_*/ diff --git a/zypp/repo/RepoMirrorList.cc b/zypp/repo/RepoMirrorList.cc index 0d6649fc9a..84b5fbcede 100644 --- a/zypp/repo/RepoMirrorList.cc +++ b/zypp/repo/RepoMirrorList.cc @@ -46,12 +46,12 @@ namespace zypp RepoMirrorListTempProvider( Pathname localfile_r ) : _localfile(std::move( localfile_r )) {} - RepoMirrorListTempProvider( const Url & url_r ) + RepoMirrorListTempProvider( zyppng::ContextBaseRef ctx, const Url & url_r ) { Url abs_url( url_r ); abs_url.setPathName( "/" ); abs_url.setQueryParam( "mediahandler", "curl" ); - _access.reset( new MediaSetAccess( abs_url ) ); + _access.reset( new MediaSetAccess( ctx, abs_url ) ); _localfile = _access->provideFile( url_r.getPathName() ); } @@ -124,7 +124,7 @@ namespace zypp } // namespace /////////////////////////////////////////////////////////////////// - RepoMirrorList::RepoMirrorList( const Url & url_r, const Pathname & metadatapath_r, bool mirrorListForceMetalink_r ) + RepoMirrorList::RepoMirrorList( zyppng::ContextBaseRef ctx, const Url & url_r, const Pathname & metadatapath_r, bool mirrorListForceMetalink_r ) { if ( url_r.getScheme() == "file" ) { @@ -134,7 +134,7 @@ namespace zypp else if ( ! PathInfo( metadatapath_r).isDir() ) { // no cachedir - RepoMirrorListTempProvider provider( url_r ); // RAII: lifetime of any downloaded files + RepoMirrorListTempProvider provider( ctx, url_r ); // RAII: lifetime of any downloaded files _urls = RepoMirrorListParse( url_r, provider.localfile(), mirrorListForceMetalink_r ); } else @@ -147,10 +147,10 @@ namespace zypp cachefile /= "mirrorlist.txt"; zypp::filesystem::PathInfo cacheinfo( cachefile ); - if ( !cacheinfo.isFile() || cacheinfo.mtime() < time(NULL) - (long) ZConfig::instance().repo_refresh_delay() * 60 ) + if ( !cacheinfo.isFile() || cacheinfo.mtime() < time(NULL) - (long) ctx->config().repo_refresh_delay() * 60 ) { DBG << "Getting MirrorList from URL: " << url_r << endl; - RepoMirrorListTempProvider provider( url_r ); // RAII: lifetime of downloaded file + RepoMirrorListTempProvider provider( ctx, url_r ); // RAII: lifetime of downloaded file // Create directory, if not existing DBG << "Copy MirrorList file to " << cachefile << endl; diff --git a/zypp/repo/RepoMirrorList.h b/zypp/repo/RepoMirrorList.h index 89a556f73a..b5a04a48ed 100644 --- a/zypp/repo/RepoMirrorList.h +++ b/zypp/repo/RepoMirrorList.h @@ -13,6 +13,7 @@ #include #include #include +#include namespace zypp { @@ -21,10 +22,10 @@ namespace zypp class RepoMirrorList { public: - RepoMirrorList( const Url & url_r, const Pathname & metadatapath_r, bool mirrorListForceMetalink_r ); + RepoMirrorList( zyppng::ContextBaseRef ctx, const Url & url_r, const Pathname & metadatapath_r, bool mirrorListForceMetalink_r ); - RepoMirrorList( const Url & url_r ) - : RepoMirrorList( url_r, Pathname(), false ) + RepoMirrorList( zyppng::ContextBaseRef ctx, const Url & url_r ) + : RepoMirrorList( ctx, url_r, Pathname(), false ) {} const std::vector & getUrls() const diff --git a/zypp/repo/RepoProvideFile.cc b/zypp/repo/RepoProvideFile.cc index 830b0a3ee2..de16fc984c 100644 --- a/zypp/repo/RepoProvideFile.cc +++ b/zypp/repo/RepoProvideFile.cc @@ -32,6 +32,8 @@ #include #include +#include + using std::endl; using std::set; @@ -117,14 +119,15 @@ namespace zypp } // namespace /////////////////////////////////////////////////////////////////// - ManagedFile provideFile( RepoInfo repo_r, + ManagedFile provideFile( zyppng::RepoInfo repo_r, const OnMediaLocation & loc_r, const ProvideFilePolicy & policy_r ) { RepoMediaAccess access; - return access.provideFile(std::move(repo_r), loc_r, policy_r ); + return access.provideFile(repo_r, loc_r, policy_r ); } + /////////////////////////////////////////////////////////////////// class RepoMediaAccess::Impl { @@ -139,13 +142,11 @@ namespace zypp ~Impl() { - std::map >::iterator it; - for ( it = _medias.begin(); - it != _medias.end(); - ++it ) - { - it->second->release(); - } + std::for_each( _medias.begin (), _medias.end(), []( auto &val ){ + std::for_each ( val.second.begin(), val.second.begin(), [](auto &entry) { + entry.second->release(); + }); + }); } /** Provide a MediaSetAccess for \c url with label and verifier adjusted. @@ -155,26 +156,33 @@ namespace zypp * * \todo This mixture of media and repos specific data is fragile. */ - shared_ptr mediaAccessForUrl( const Url &url, RepoInfo repo ) + shared_ptr mediaAccessForUrl( const Url &url, zyppng::RepoInfo repo ) { - std::map >::const_iterator it; - it = _medias.find(url); + if ( !repo.context() ) { + ZYPP_THROW( zypp::Exception( str::Str()<<"Repo: " << repo << ", can not provide files without a context." ) ); + } + // quick hack using the context ptr address as key for the nested map + const uintptr_t key = reinterpret_cast( repo.context().get() ); + auto it = _medias.find(url); shared_ptr media; if ( it != _medias.end() ) { - media = it->second; + auto it2 = it->second.find( key ); + if ( it2 != it->second.end() ) + media = it2->second; } - else + + if ( !media ) { - media.reset( new MediaSetAccess(url) ); - _medias[url] = media; + media.reset( new MediaSetAccess( repo.context(), url) ); + _medias[url][key] = media; } - setVerifierForRepo( std::move(repo), media ); + setVerifierForRepo( repo, media ); return media; } private: - void setVerifierForRepo( const RepoInfo& repo, const shared_ptr& media ) + void setVerifierForRepo( const zyppng::RepoInfo& repo, const shared_ptr& media ) { // Always set the MediaSetAccess label. media->setLabel( repo.name() ); @@ -186,7 +194,7 @@ namespace zypp { if ( PathInfo(mediafile).isExist() ) { - std::map, RepoInfo>::const_iterator it; + std::map, zyppng::RepoInfo>::const_iterator it; it = _verifier.find(media); if ( it != _verifier.end() ) { @@ -204,7 +212,7 @@ namespace zypp media::MediaVerifierRef verifier( new repo::SUSEMediaVerifier( lverifier, i ) ); media->setVerifier( i, verifier); } - _verifier[media] = repo; + _verifier.insert_or_assign( media, repo ); } else { WAR << "Invalid verifier for repo '" << repo.alias() << "' in '" << repo.metadataPath() << "': " << lverifier << endl; @@ -222,8 +230,8 @@ namespace zypp } private: - std::map, RepoInfo> _verifier; - std::map > _medias; + std::map, zyppng::RepoInfo> _verifier; + std::map> > _medias; public: ProvideFilePolicy _defaultPolicy; @@ -244,7 +252,7 @@ namespace zypp const ProvideFilePolicy & RepoMediaAccess::defaultPolicy() const { return _impl->_defaultPolicy; } - ManagedFile RepoMediaAccess::provideFile( const RepoInfo& repo_r, + ManagedFile RepoMediaAccess::provideFile( const zyppng::RepoInfo& repo_r, const OnMediaLocation & loc_rx, const ProvideFilePolicy & policy_r ) { @@ -295,7 +303,7 @@ namespace zypp // Suppress (interactive) media::MediaChangeReport if we in have multiple basurls (>1) media::ScopedDisableMediaChangeReport guard( repo_r.baseUrlsSize() > 1 ); - for ( RepoInfo::urls_const_iterator it = repo_r.baseUrlsBegin(); + for ( auto it = repo_r.baseUrlsBegin(); it != repo_r.baseUrlsEnd(); /* incremented in the loop */ ) { @@ -343,6 +351,34 @@ namespace zypp } ///////////////////////////////////////////////////////////////// + + ManagedFile RepoMediaAccess::provideFile( const zyppng::RepoInfo &repo_r, + const OnMediaLocation &loc_r) { + return provideFile( repo_r, loc_r, defaultPolicy()); + } + + ZYPP_BEGIN_LEGACY_API + ManagedFile provideFile( RepoInfo repo_r, + const OnMediaLocation & loc_r, + const ProvideFilePolicy & policy_r ) + { + return provideFile( repo_r.ngRepoInfo (), loc_r, policy_r ); + } + + ManagedFile RepoMediaAccess::provideFile(RepoInfo repo_r, + const OnMediaLocation &loc_r) { + return provideFile( repo_r.ngRepoInfo (), loc_r ); + } + + ManagedFile RepoMediaAccess::provideFile( const RepoInfo& repo_r, + const OnMediaLocation & loc_rx, + const ProvideFilePolicy & policy_r ) + { + return provideFile( repo_r.ngRepoInfo (), loc_rx, policy_r ); + } + ZYPP_END_LEGACY_API + + } // namespace repo /////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// diff --git a/zypp/repo/RepoProvideFile.h b/zypp/repo/RepoProvideFile.h index 9555479772..dbf44db0a3 100644 --- a/zypp/repo/RepoProvideFile.h +++ b/zypp/repo/RepoProvideFile.h @@ -14,6 +14,7 @@ #include +#include #include #include #include @@ -23,6 +24,10 @@ #include #include +namespace zyppng { + class RepoInfo; +} + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -45,6 +50,10 @@ namespace zypp * \throws Exception */ ManagedFile provideFile( RepoInfo repo_r, + const OnMediaLocation & loc_r, + const ProvideFilePolicy & policy_r = ProvideFilePolicy() ) ZYPP_INTERNAL_DEPRECATE; + + ManagedFile provideFile( zyppng::RepoInfo repo_r, const OnMediaLocation & loc_r, const ProvideFilePolicy & policy_r = ProvideFilePolicy() ); @@ -74,13 +83,18 @@ namespace zypp * \throws Exception * \todo Investigate why this needs a non-const Repository as arg. */ - ManagedFile provideFile( const RepoInfo& repo_r, - const OnMediaLocation & loc_r, - const ProvideFilePolicy & policy_r ); + ManagedFile provideFile ( const RepoInfo& repo_r, + const OnMediaLocation & loc_r, + const ProvideFilePolicy & policy_r ) ZYPP_INTERNAL_DEPRECATE; + + ManagedFile provideFile ( const zyppng::RepoInfo& repo_r, + const OnMediaLocation & loc_r, + const ProvideFilePolicy & policy_r ); /** \overload Using the current default \ref ProvideFilePolicy. */ - ManagedFile provideFile( RepoInfo repo_r, const OnMediaLocation & loc_r ) - { return provideFile( std::move(repo_r), loc_r, defaultPolicy() ); } + ManagedFile provideFile( RepoInfo repo_r, const OnMediaLocation &loc_r ) ZYPP_INTERNAL_DEPRECATE; + + ManagedFile provideFile( const zyppng::RepoInfo &repo_r, const OnMediaLocation &loc_r ); public: /** Set a new default \ref ProvideFilePolicy. */ diff --git a/zypp/repo/RepoVariables.cc b/zypp/repo/RepoVariables.cc index 2cb65d2e4d..cadf1a810e 100644 --- a/zypp/repo/RepoVariables.cc +++ b/zypp/repo/RepoVariables.cc @@ -20,30 +20,23 @@ #include #include +#include +#include +#include +#include + #define ZYPP_DBG_VAREXPAND 0 #if ( ZYPP_DBG_VAREXPAND ) #warning ZYPP_DBG_VAREXPAND is on using std::cout; #endif // ZYPP_DBG_VAREXPAND -/////////////////////////////////////////////////////////////////// namespace zypp { - namespace env - { - /** Use faked releasever (e.g. for 'zupper dup' to next distro version */ - inline std::string ZYPP_REPO_RELEASEVER() - { - const char * env = getenv("ZYPP_REPO_RELEASEVER"); - return( env ? env : "" ); - } - } - - /////////////////////////////////////////////////////////////////// namespace repo { /////////////////////////////////////////////////////////////////// - // RepoVarExpand + // RepoVariables*Replace /////////////////////////////////////////////////////////////////// namespace { @@ -278,13 +271,13 @@ namespace zypp */ inline bool _expand( std::string & result_r, const std::string & value_r, unsigned level_r, RepoVarExpand::VarRetriever & varRetriever_r ) { -#if ( ZYPP_DBG_VAREXPAND ) + #if ( ZYPP_DBG_VAREXPAND ) cout << std::string( 2*level_r, ' ' ) << "\033[7m>>" << value_r << "<<\033[27m" << endl; std::ostringstream dbg; const char * dbgsbeg = value_r.c_str(); // track vars we already added to dbg unsigned dbgi = 0; // color 1-5 var / 6 moved value_r dbg << std::string( 2*level_r, ' ' ) << ">>"; -#endif // ZYPP_DBG_VAREXPAND + #endif // ZYPP_DBG_VAREXPAND bool expanded = false; @@ -297,12 +290,12 @@ namespace zypp const std::string *const knownVar = ( varRetriever_r ? varRetriever_r( scan.varName() ) : nullptr ); const std::string & varValue( knownVar ? *knownVar : _emptyValue ); -#if ( ZYPP_DBG_VAREXPAND ) + #if ( ZYPP_DBG_VAREXPAND ) dbg << std::string(dbgsbeg,scan._vbeg) << "\033[3" << ((dbgi%5)+1) << "m" << scan.var() << "\033[0m"; cout << dbg.str() << "|<< " << scan.varName() << " " << (knownVar?"("+varValue+")":"-") << " {" << scan.varEmbedded() << "}" << endl; dbgsbeg = scan._vend; dbgi++; -#endif // ZYPP_DBG_VAREXPAND + #endif // ZYPP_DBG_VAREXPAND bool mustSubstitute = false; // keep original text per default std::string substitutionValue; @@ -352,9 +345,9 @@ namespace zypp } } -#if ( ZYPP_DBG_VAREXPAND ) + #if ( ZYPP_DBG_VAREXPAND ) dbg << std::string( dbgsbeg ) << (scan._sbeg == value_r.c_str() ? "<<\033[36m(moved)\033[0m" : ""); -#endif // ZYPP_DBG_VAREXPAND + #endif // ZYPP_DBG_VAREXPAND // handle unwritten data: if ( scan._sbeg != value_r.c_str() ) @@ -367,11 +360,11 @@ namespace zypp ; // no replacements at all } -#if ( ZYPP_DBG_VAREXPAND ) + #if ( ZYPP_DBG_VAREXPAND ) dbg << "<<"; cout << dbg.str() << endl; cout << std::string( 2*level_r, ' ' ) << "\033[36m->" << result_r << "<-\033[0m" << endl; -#endif // ZYPP_DBG_VAREXPAND + #endif // ZYPP_DBG_VAREXPAND return expanded; } } // namespace @@ -383,205 +376,67 @@ namespace zypp std::string RepoVarExpand::operator()( std::string && value_r, VarRetriever varRetriever_r ) const { return expand( std::move(value_r), 0, varRetriever_r ); } - /////////////////////////////////////////////////////////////////// - // RepoVariables*Replace - /////////////////////////////////////////////////////////////////// - namespace - { - class RepoVarsMap : public std::map - { - public: - static RepoVarsMap & instance() - { static RepoVarsMap _instance; return _instance; } - - static const std::string * lookup( const std::string & name_r ) - { return instance()._lookup( name_r ); } - private: - const std::string * _lookup( const std::string & name_r ) - { - // Safe guard in case the caller does not own a zypp instance. In this case - // getZYpp()->getTarget() in checkOverride would create a zypp instance which - // would clear the variables parsed so far. - auto guard { getZYpp() }; - - if ( empty() ) // at init / after reset - { - // load user definitions from vars.d - filesystem::dirForEach( ZConfig::instance().repoManagerRoot() / ZConfig::instance().varsPath(), - filesystem::matchNoDots(), bind( &RepoVarsMap::parse, this, _1, _2 ) ); - // releasever_major/_minor are per default derived from releasever. - // If releasever is userdefined, inject missing _major/_minor too. - deriveFromReleasever( "releasever", /*dont't overwrite user defined values*/false ); - - dumpOn( DBG ); - // add builtin vars except for releasever{,_major,_minor} (see checkOverride) - { - const Arch & arch( ZConfig::instance().systemArchitecture() ); - { - std::string & var( operator[]( "arch" ) ); - if ( var.empty() ) var = arch.asString(); - } - { - std::string & var( operator[]( "basearch" ) ); - if ( var.empty() ) var = arch.baseArch().asString(); - } - } - } - - const std::string * ret = checkOverride( name_r ); - if ( !ret ) - { - // get value from map - iterator it = find( name_r ); - if ( it != end() ) - ret = &(it->second); - } - - return ret; - } - - std::ostream & dumpOn( std::ostream & str ) const - { - for ( auto && kv : *this ) - { - str << '{' << kv.first << '=' << kv.second << '}' << endl; - } - return str; - } - - private: - /** Get first line from file */ - bool parse( const Pathname & dir_r, const std::string & str_r ) - { - std::ifstream file( (dir_r/str_r).c_str() ); - operator[]( str_r ) = str::getline( file, /*trim*/false ); - return true; - } - - /** Derive \c releasever_major/_minor from \c releasever, keeping or overwrititing existing values. */ - void deriveFromReleasever( const std::string & stem_r, bool overwrite_r ) - { - if ( count( stem_r ) ) // releasever is defined.. - { - const std::string & stem_major( stem_r+"_major" ); - const std::string & stem_minor( stem_r+"_minor" ); - if ( overwrite_r ) - splitReleaseverTo( operator[]( stem_r ), &operator[]( stem_major ), &operator[]( stem_minor ) ); - else - splitReleaseverTo( operator[]( stem_r ), - count( stem_major ) ? nullptr : &operator[]( stem_major ), - count( stem_minor ) ? nullptr : &operator[]( stem_minor ) ); - } - } - - /** Split \c releasever at \c '.' and store major/minor parts as requested. */ - void splitReleaseverTo( const std::string & releasever_r, std::string * major_r, std::string * minor_r ) const - { - if ( major_r || minor_r ) - { - std::string::size_type pos = releasever_r.find( '.' ); - if ( pos == std::string::npos ) - { - if ( major_r ) *major_r = releasever_r; - if ( minor_r ) minor_r->clear(); - } - else - { - if ( major_r ) *major_r = releasever_r.substr( 0, pos ); - if ( minor_r ) *minor_r = releasever_r.substr( pos+1 ) ; - } - } - } + std::string RepoVariablesStringReplacer::operator()(const std::string &value_r) const + { + return RepoVariablesStringReplacerNg( RepoVarRetriever( *zypp_detail::GlobalStateHelper::context () ) )( value_r ); + } - /** Check for conditions overwriting the (user) defined values. */ - const std::string * checkOverride( const std::string & name_r ) - { - /////////////////////////////////////////////////////////////////// - // Always check for changing releasever{,_major,_minor} (bnc#943563) - if ( str::startsWith( name_r, "releasever" ) - && ( name_r.size() == 10 - || strcmp( name_r.c_str()+10, "_minor" ) == 0 - || strcmp( name_r.c_str()+10, "_major" ) == 0 ) ) - { - std::string val( env::ZYPP_REPO_RELEASEVER() ); - if ( !val.empty() ) - { - // $ZYPP_REPO_RELEASEVER always overwrites any defined value - if ( val != operator[]( "$releasever" ) ) - { - operator[]( "$releasever" ) = std::move(val); - deriveFromReleasever( "$releasever", /*overwrite previous values*/true ); - } - return &operator[]( "$"+name_r ); - } - else if ( !count( name_r ) ) - { - // No user defined value, so we follow the target - Target_Ptr trg( getZYpp()->getTarget() ); - if ( trg ) - val = trg->distributionVersion(); - else - val = Target::distributionVersion( Pathname()/*guess*/ ); + std::string RepoVariablesStringReplacer::operator()( std::string &&value_r ) const + { + return RepoVariablesStringReplacerNg( RepoVarRetriever( *zypp_detail::GlobalStateHelper::context () ) )( std::move(value_r) ); + } - if ( val != operator[]( "$_releasever" ) ) - { - operator[]( "$_releasever" ) = std::move(val); - deriveFromReleasever( "$_releasever", /*overwrite previous values*/true ); - } - return &operator[]( "$_"+name_r ); - } - // else: - return nullptr; // get user value from map - } - /////////////////////////////////////////////////////////////////// + zypp::Url RepoVariablesUrlReplacer::operator()(const zypp::Url &value) const + { + return RepoVariablesUrlReplacerNg( RepoVarRetriever( *zypp_detail::GlobalStateHelper::context () ) )( value ); + } - return nullptr; // get user value from map - } - }; - } // namespace - /////////////////////////////////////////////////////////////////// + RepoVariablesStringReplacerNg::RepoVariablesStringReplacerNg(RepoVarRetrieverFunctor varRetriever) + : _varRetriever( std::move(varRetriever) ) + {} - std::string RepoVariablesStringReplacer::operator()( const std::string & value ) const + std::string RepoVariablesStringReplacerNg::operator()(const std::string &value_r) const { - return RepoVarExpand()( value, RepoVarsMap::lookup ); + if ( _varRetriever ) + return repo::RepoVarExpand()( value_r, _varRetriever ); + return value_r; } - std::string RepoVariablesStringReplacer::operator()( std::string && value ) const + + std::string RepoVariablesStringReplacerNg::operator()( std::string &&value_r ) const { - return RepoVarExpand()( std::move(value), RepoVarsMap::lookup ); + if ( _varRetriever ) + return repo::RepoVarExpand()( std::move(value_r), _varRetriever ); + return value_r; } - Url RepoVariablesUrlReplacer::operator()( const Url & value ) const + RepoVariablesUrlReplacerNg::RepoVariablesUrlReplacerNg(RepoVarRetrieverFunctor varRetriever) + : _varRetriever( std::move(varRetriever) ) + { } + + zypp::Url RepoVariablesUrlReplacerNg::operator()(const zypp::Url &value) const { - Url::ViewOptions toReplace = value.getViewOptions() - url::ViewOption::WITH_USERNAME - url::ViewOption::WITH_PASSWORD; - // Legacy: Not 100% correct because it substitutes inside the 'proxypass=' value, - // but this was done before as well. The final fix will have to keep the proxypasswd - // out side the url in a cedential file. - Url tmpurl { value }; - tmpurl.setViewOptions( toReplace ); - const std::string & replaced( RepoVarExpand()( hotfix1050625::asString( tmpurl ), RepoVarsMap::lookup ) ); - - Url newurl; - if ( !replaced.empty() ) - { - newurl = replaced; - newurl.setUsername( value.getUsername( url::E_ENCODED ), url::E_ENCODED ); - newurl.setPassword( value.getPassword( url::E_ENCODED ), url::E_ENCODED ); - newurl.setViewOptions( value.getViewOptions() ); + if ( _varRetriever ) { + zypp::Url::ViewOptions toReplace = value.getViewOptions() - zypp::url::ViewOption::WITH_USERNAME - zypp::url::ViewOption::WITH_PASSWORD; + // Legacy: Not 100% correct because it substitutes inside the 'proxypass=' value, + // but this was done before as well. The final fix will have to keep the proxypasswd + // out side the url in a cedential file. + zypp::Url tmpurl { value }; + tmpurl.setViewOptions( toReplace ); + const std::string & replaced( zypp::repo::RepoVarExpand()( zypp::hotfix1050625::asString( tmpurl ), _varRetriever ) ); + + zypp::Url newurl; + if ( !replaced.empty() ) + { + newurl = replaced; + newurl.setUsername( value.getUsername( zypp::url::E_ENCODED ), zypp::url::E_ENCODED ); + newurl.setPassword( value.getPassword( zypp::url::E_ENCODED ), zypp::url::E_ENCODED ); + newurl.setViewOptions( value.getViewOptions() ); + } + return newurl; } - return newurl; + return value; } } // namespace repo /////////////////////////////////////////////////////////////////// } // namespace zypp -/////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////// -namespace zyppintern -{ - using namespace zypp; - // internal helper called when re-acquiring the lock - void repoVariablesReset() - { repo::RepoVarsMap::instance().clear(); } - -} // namespace zyppintern -/////////////////////////////////////////////////////////////////// diff --git a/zypp/repo/RepoVariables.h b/zypp/repo/RepoVariables.h index 6c22c99ed4..3613148818 100644 --- a/zypp/repo/RepoVariables.h +++ b/zypp/repo/RepoVariables.h @@ -22,6 +22,38 @@ namespace zypp /////////////////////////////////////////////////////////////////// namespace repo { + + /** Function taking a variable name and returning a pointer to the variable value or \c nullptr if unset. */ + using RepoVarRetrieverFunctor = std::function; + + /*! + * Helper functor class, requires a reference to a object + * implementing a function called \a resolveRepoVar with the RepoVarRetrieverFunctor signature. + * + * \code + * const std::string * SomeType::resolveRepoVar (const std::string &); + * \endcode + */ + template + struct RepoVarRetriever + { + RepoVarRetriever(T &varContainer) : _varContainer(varContainer) {} + + ~RepoVarRetriever() = default; + RepoVarRetriever(const RepoVarRetriever &) = default; + RepoVarRetriever(RepoVarRetriever &&) = default; + RepoVarRetriever &operator=(const RepoVarRetriever &) = default; + RepoVarRetriever &operator=(RepoVarRetriever &&) = default; + + const std::string * operator() (const std::string &val) { + return std::invoke ( memFn, _varContainer.get(), val ); + } + + private: + std::reference_wrapper _varContainer; + }; + + /////////////////////////////////////////////////////////////////// /// \class RepoVarExpand /// \brief Functor expanding repo variables in a string @@ -57,7 +89,7 @@ namespace zypp struct ZYPP_API RepoVarExpand { /** Function taking a variable name and returning a pointer to the variable value or \c nullptr if unset. */ - using VarRetriever = function; + using VarRetriever = RepoVarRetrieverFunctor; /** Return a copy of \a value_r with embedded variables expanded. */ std::string operator()( const std::string & value_r, VarRetriever varRetriever_r ) const; @@ -102,7 +134,7 @@ namespace zypp * * \see \ref RepoVarExpand for supported variable syntax. */ - struct ZYPP_API RepoVariablesStringReplacer + struct ZYPP_API ZYPP_INTERNAL_DEPRECATE RepoVariablesStringReplacer { std::string operator()( const std::string & value_r ) const; @@ -116,24 +148,60 @@ namespace zypp * Replaces repository variables in the URL (except for user/pass inside authority) * \see RepoVariablesStringReplacer */ - struct ZYPP_API RepoVariablesUrlReplacer + struct ZYPP_API ZYPP_INTERNAL_DEPRECATE RepoVariablesUrlReplacer { Url operator()( const Url & url_r ) const; }; + + /*! + * Like \ref RepoVariablesStringReplacer, but uses a explicit \ref RepoVarRetrieverFunctor + * instead of a global static to retrieve variables + */ + struct ZYPP_API RepoVariablesStringReplacerNg + { + RepoVariablesStringReplacerNg( RepoVarRetrieverFunctor varRetriever = nullptr ); + + std::string operator()( const std::string & value_r ) const; + + /** \overload moving */ + std::string operator()( std::string && value_r ) const; + + private: + RepoVarRetrieverFunctor _varRetriever; + }; + + /*! + * Like \ref RepoVariablesUrlReplacer, but uses a explicit \ref RepoVarRetrieverFunctor + * instead of a global static to retrieve variables + */ + struct ZYPP_API RepoVariablesUrlReplacerNg + { + RepoVariablesUrlReplacerNg( RepoVarRetrieverFunctor varRetriever = nullptr ); + + zypp::Url operator()( const zypp::Url & value ) const; + + private: + RepoVarRetrieverFunctor _varRetriever; + }; + } // namespace repo /////////////////////////////////////////////////////////////////// + ZYPP_BEGIN_LEGACY_API + /** \relates RepoVariablesStringReplacer Helper managing repo variables replaced strings */ - using RepoVariablesReplacedString = base::ValueTransform; + using RepoVariablesReplacedString ZYPP_INTERNAL_DEPRECATE = base::ValueTransform; /** \relates RepoVariablesStringReplacer Helper managing repo variables replaced string lists */ - using RepoVariablesReplacedStringList = base::ContainerTransform, repo::RepoVariablesStringReplacer>; + using RepoVariablesReplacedStringList ZYPP_INTERNAL_DEPRECATE = base::ContainerTransform, repo::RepoVariablesStringReplacer>; /** \relates RepoVariablesUrlReplacer Helper managing repo variables replaced urls */ - using RepoVariablesReplacedUrl = base::ValueTransform; + using RepoVariablesReplacedUrl ZYPP_INTERNAL_DEPRECATE = base::ValueTransform; /** \relates RepoVariablesUrlReplacer Helper managing repo variables replaced url lists */ - using RepoVariablesReplacedUrlList = base::ContainerTransform, repo::RepoVariablesUrlReplacer>; + using RepoVariablesReplacedUrlList ZYPP_INTERNAL_DEPRECATE = base::ContainerTransform, repo::RepoVariablesUrlReplacer>; + + ZYPP_END_LEGACY_API } // namespace zypp /////////////////////////////////////////////////////////////////// diff --git a/zypp/repo/ServiceRepoState.cc b/zypp/repo/ServiceRepoState.cc new file mode 100644 index 0000000000..5b35c98864 --- /dev/null +++ b/zypp/repo/ServiceRepoState.cc @@ -0,0 +1,27 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +#include "ServiceRepoState.h" + +#include + +namespace zypp { + + ServiceRepoState::ServiceRepoState( const zyppng::RepoInfo &repo_r ) + : enabled( repo_r.enabled() ), autorefresh( repo_r.autorefresh() ), priority( repo_r.priority() ) + {} + +ZYPP_BEGIN_LEGACY_API + ServiceRepoState::ServiceRepoState(const RepoInfo &repo_r) + : ServiceRepoState(repo_r.ngRepoInfo()) {} +ZYPP_END_LEGACY_API + + ServiceRepoState::ServiceRepoState() + : enabled(false), autorefresh(true), + priority(zyppng::RepoInfo::defaultPriority()) {} +} // namespace zypp diff --git a/zypp/repo/ServiceRepoState.h b/zypp/repo/ServiceRepoState.h new file mode 100644 index 0000000000..5cbbcd46f2 --- /dev/null +++ b/zypp/repo/ServiceRepoState.h @@ -0,0 +1,52 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/repo/ServiceInfo.h + * + */ +#ifndef ZYPP_REPO_SERVICE_REPO_STATE_H +#define ZYPP_REPO_SERVICE_REPO_STATE_H + +#include + +namespace zyppng { + class RepoInfo; +} + +namespace zypp +{ + + /** \name The original repo state as defined by the repoindex.xml upon last refresh. + * + * This state is remembered to detect any user modifications applied to the repos. + * It may not be available for all repos or in plugin services. In this case all + * changes requested by a service refresh are applied unconditionally. + */ + //@{ + struct ZYPP_API ServiceRepoState + { + bool enabled; + bool autorefresh; + unsigned priority; + + ServiceRepoState(); + + ServiceRepoState( const RepoInfo &repo_r ) ZYPP_INTERNAL_DEPRECATE; + + ServiceRepoState( const zyppng::RepoInfo &repo_r ); + + bool operator==( const ServiceRepoState & rhs ) const + { return( enabled==rhs.enabled && autorefresh==rhs.autorefresh && priority==rhs.priority ); } + bool operator!=( const ServiceRepoState & rhs ) const + { return ! operator==( rhs ); } + friend std::ostream & operator<<( std::ostream & str, const ServiceRepoState & obj ); + }; + +} + +#endif diff --git a/zypp/repo/SrcPackageProvider.cc b/zypp/repo/SrcPackageProvider.cc index a6a95a7195..51016ae006 100644 --- a/zypp/repo/SrcPackageProvider.cc +++ b/zypp/repo/SrcPackageProvider.cc @@ -12,10 +12,13 @@ #include #include +#include #include #include #include #include +#include +#include using std::endl; @@ -25,7 +28,6 @@ namespace zypp /////////////////////////////////////////////////////////////////// namespace repo { - SrcPackageProvider::SrcPackageProvider( repo::RepoMediaAccess & access_r ) : _access( access_r ) {} @@ -34,7 +36,16 @@ namespace zypp {} ManagedFile SrcPackageProvider::provideSrcPackage( const SrcPackage_constPtr & srcPackage_r ) const - { return _access.provideFile( srcPackage_r->repoInfo(), srcPackage_r->location() ); } + { + const auto &ri = srcPackage_r->ngRepoInfo(); + if ( !ri ) { + RepoException repo_excpt(str::form(_("Can't provide file '%s' without a RepoInfo"), + srcPackage_r->location().filename().c_str() ) ); + + ZYPP_THROW(repo_excpt); + } + return _access.provideFile( *ri, srcPackage_r->location() ); + } } // namespace repo /////////////////////////////////////////////////////////////////// diff --git a/zypp/repo/yum/RepomdFileCollector.cc b/zypp/repo/yum/RepomdFileCollector.cc index 8eb7692207..1d77625e99 100644 --- a/zypp/repo/yum/RepomdFileCollector.cc +++ b/zypp/repo/yum/RepomdFileCollector.cc @@ -10,7 +10,8 @@ #include "RepomdFileCollector.h" #include #include -#include +#include +#include #include namespace zypp::env @@ -89,11 +90,11 @@ namespace zypp::repo::yum * Localized type: * susedata.LOCALE */ - RepomdFileCollector::RepomdFileCollector( const Pathname &destDir_r ) + RepomdFileCollector::RepomdFileCollector( zyppng::ContextBaseRef ctx, const Pathname &destDir_r ) : _destDir { destDir_r } { - addWantedLocale( ZConfig::instance().textLocale() ); - for ( const Locale & it : ZConfig::instance().repoRefreshLocales() ) + addWantedLocale( ctx->config().textLocale() ); + for ( const Locale & it : ctx->config().repoRefreshLocales() ) addWantedLocale( it ); } diff --git a/zypp/repo/yum/RepomdFileCollector.h b/zypp/repo/yum/RepomdFileCollector.h index a5875c5588..101db720ca 100644 --- a/zypp/repo/yum/RepomdFileCollector.h +++ b/zypp/repo/yum/RepomdFileCollector.h @@ -10,6 +10,7 @@ #ifndef ZYPP_SOURCE_YUM_REPOMDFILECOLLECTOR #define ZYPP_SOURCE_YUM_REPOMDFILECOLLECTOR +#include #include #include #include @@ -18,6 +19,10 @@ #include #include +namespace zyppng { + class RepoInfo; +} + namespace zypp::repo::yum { @@ -28,7 +33,7 @@ namespace zypp::repo::yum using FinalizeCb = std::function; - RepomdFileCollector( const Pathname & destDir_r ); + RepomdFileCollector( zyppng::ContextBaseRef ctx, const Pathname & destDir_r ); virtual ~RepomdFileCollector(); bool collect( const OnMediaLocation & loc_r, const std::string & typestr_r ); @@ -36,7 +41,7 @@ namespace zypp::repo::yum void finalize( const FinalizeCb &cb ); protected: - virtual const RepoInfo &repoInfo() const = 0; + virtual const zyppng::RepoInfo &repoInfo() const = 0; virtual const Pathname &deltaDir() const = 0; private: diff --git a/zypp/sat/Pool.cc b/zypp/sat/Pool.cc index 3eeddbe4f9..ef6ba12c5d 100644 --- a/zypp/sat/Pool.cc +++ b/zypp/sat/Pool.cc @@ -34,6 +34,8 @@ extern "C" #include #include +#include + using std::endl; /////////////////////////////////////////////////////////////////// @@ -150,7 +152,7 @@ namespace zypp if ( ret.isSystemRepo() ) { // autoprovide (dummy) RepoInfo - RepoInfo info; + zyppng::RepoInfo info(nullptr); info.setAlias( alias_r ); info.setName( alias_r ); info.setAutorefresh( true ); @@ -197,7 +199,14 @@ namespace zypp Repository Pool::addRepoSolv( const Pathname & file_r ) { return addRepoSolv( file_r, file_r.basename() ); } + ZYPP_BEGIN_LEGACY_API Repository Pool::addRepoSolv( const Pathname & file_r, const RepoInfo & info_r ) + { + return addRepoSolv( file_r, info_r.ngRepoInfo() ); + } + ZYPP_END_LEGACY_API + + Repository Pool::addRepoSolv( const Pathname & file_r, const zyppng::RepoInfo & info_r ) { Repository ret( addRepoSolv( file_r, info_r.alias() ) ); ret.setInfo( info_r ); @@ -221,13 +230,20 @@ namespace zypp Repository Pool::addRepoHelix( const Pathname & file_r ) { return addRepoHelix( file_r, file_r.basename() ); } - Repository Pool::addRepoHelix( const Pathname & file_r, const RepoInfo & info_r ) + Repository Pool::addRepoHelix( const Pathname & file_r, const zyppng::RepoInfo & info_r ) { Repository ret( addRepoHelix( file_r, info_r.alias() ) ); ret.setInfo( info_r ); return ret; } + ZYPP_BEGIN_LEGACY_API + Repository Pool::addRepoHelix( const Pathname & file_r, const RepoInfo & info_r ) + { + return addRepoHelix( file_r, info_r.ngRepoInfo() ); + } + ZYPP_END_LEGACY_API + ///////////////////////////////////////////////////////////////// void Pool::setTextLocale( const Locale & locale_r ) diff --git a/zypp/sat/Pool.h b/zypp/sat/Pool.h index e57126c6bb..80a619412d 100644 --- a/zypp/sat/Pool.h +++ b/zypp/sat/Pool.h @@ -22,6 +22,10 @@ #include #include +namespace zyppng { + class RepoInfo; +} + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -141,7 +145,11 @@ namespace zypp /** \overload Using the \ref RepoInfo::alias \ref Repo name. * Additionally stores the \ref RepoInfo. \See \ref Prool::setInfo. */ - Repository addRepoSolv( const Pathname & file_r, const RepoInfo & info_r ); + ZYPP_BEGIN_LEGACY_API + Repository ZYPP_INTERNAL_DEPRECATE addRepoSolv( const Pathname & file_r, const RepoInfo & info_r ); + ZYPP_END_LEGACY_API + + Repository addRepoSolv( const Pathname & file_r, const zyppng::RepoInfo & info_r ); public: /** Load \ref Solvables from a helix-file into a \ref Repository named \c name_r. @@ -156,7 +164,11 @@ namespace zypp /** \overload Using the \ref RepoInfo::alias \ref Repo name. * Additionally stores the \ref RepoInfo. \See \ref Prool::setInfo. */ - Repository addRepoHelix( const Pathname & file_r, const RepoInfo & info_r ); + ZYPP_BEGIN_LEGACY_API + Repository ZYPP_INTERNAL_DEPRECATE addRepoHelix( const Pathname & file_r, const RepoInfo & info_r ); + ZYPP_END_LEGACY_API + + Repository addRepoHelix( const Pathname & file_r, const zyppng::RepoInfo & info_r ); public: /** Whether \ref Pool contains solvables. */ diff --git a/zypp/sat/Solvable.cc b/zypp/sat/Solvable.cc index d7c9518872..c5a2857c5e 100644 --- a/zypp/sat/Solvable.cc +++ b/zypp/sat/Solvable.cc @@ -29,6 +29,7 @@ #include #include +#include using std::endl; @@ -234,28 +235,32 @@ namespace zypp medianr = 1; OnMediaLocation ret; - Pathname path; - switch ( repository().info().type().toEnum() ) - { - case repo::RepoType::NONE_e: - { - path = lookupDatadirIn( repository() ); - if ( ! path.empty() ) - repository().info().setProbedType( repo::RepoType::YAST2_e ); - } - break; - case repo::RepoType::YAST2_e: + const auto &ri = repository().ngInfo(); + if ( ri ) { + switch ( ri->type().toEnum() ) { - path = lookupDatadirIn( repository() ); - if ( path.empty() ) - path = "suse"; - } - break; + case repo::RepoType::NONE_e: + { + path = lookupDatadirIn( repository() ); + if ( ! path.empty() ) { + ri->setProbedType( repo::RepoType::YAST2_e ); + } + } + break; - default: + case repo::RepoType::YAST2_e: + { + path = lookupDatadirIn( repository() ); + if ( path.empty() ) + path = "suse"; + } break; + + default: + break; + } } ret.setLocation ( path/file, medianr ); ret.setDownloadSize( ByteCount( lookupNumAttribute( SolvAttr::downloadsize ) ) ); @@ -367,9 +372,13 @@ namespace zypp return Repository( _solvable->repo ); } + ZYPP_BEGIN_LEGACY_API RepoInfo Solvable::repoInfo() const { return repository().info(); } + ZYPP_END_LEGACY_API + const std::optional &Solvable::ngRepoInfo() const + { return repository().ngInfo(); } bool Solvable::isSystem() const { @@ -747,28 +756,34 @@ namespace zypp std::string ret = lookupStrAttribute( SolvAttr::eula, lang_r ); if ( ret.empty() && isKind() ) { - const RepoInfo & ri( repoInfo() ); + const auto &ri( ngRepoInfo () ); + if ( !ri ) + return ret; + std::string riname( name() ); // "license-"+name with fallback "license" - if ( ! ri.hasLicense( riname ) ) + if ( ! ri->hasLicense( riname ) ) riname.clear(); - if ( ri.needToAcceptLicense( riname ) || ! ui::Selectable::get( *this )->hasInstalledObj() ) - ret = ri.getLicense( riname, lang_r ); // bnc#908976: suppress informal license upon update + if ( ri->needToAcceptLicense( riname ) || ! ui::Selectable::get( *this )->hasInstalledObj() ) + ret = ri->getLicense( riname, lang_r ); // bnc#908976: suppress informal license upon update } return ret; } bool Solvable::needToAcceptLicense() const { - NO_SOLVABLE_RETURN( false ); + NO_SOLVABLE_RETURN( true ); if ( isKind() ) { - const RepoInfo & ri( repoInfo() ); + const auto &ri( ngRepoInfo() ); + if ( !ri ) + return true; + std::string riname( name() ); // "license-"+name with fallback "license" - if ( ! ri.hasLicense( riname ) ) + if ( !ri->hasLicense( riname ) ) riname.clear(); - return ri.needToAcceptLicense( riname ); + return ri->needToAcceptLicense( riname ); } return true; } diff --git a/zypp/sat/Solvable.h b/zypp/sat/Solvable.h index f48be2c929..ae11eead4e 100644 --- a/zypp/sat/Solvable.h +++ b/zypp/sat/Solvable.h @@ -24,6 +24,11 @@ #include #include #include +#include + +namespace zyppng { + class RepoInfo; +} /////////////////////////////////////////////////////////////////// namespace zypp @@ -121,8 +126,15 @@ namespace zypp /** The \ref Repository this \ref Solvable belongs to. */ Repository repository() const; + + ZYPP_BEGIN_LEGACY_API /** The repositories \ref RepoInfo. */ - RepoInfo repoInfo() const; + RepoInfo repoInfo() const ZYPP_INTERNAL_DEPRECATE; + ZYPP_END_LEGACY_API + +#ifdef __cpp_lib_optional + const std::optional &ngRepoInfo() const; +#endif /** Return whether this \ref Solvable belongs to the system repo. * \note This includes the otherwise hidden systemSolvable. diff --git a/zypp/sat/SolvableType.h b/zypp/sat/SolvableType.h index 9dcc013d20..3ba7caece7 100644 --- a/zypp/sat/SolvableType.h +++ b/zypp/sat/SolvableType.h @@ -13,6 +13,7 @@ #include +#include #include #include #include @@ -21,6 +22,10 @@ #include #include +namespace zyppng { + class RepoInfo; +} + /////////////////////////////////////////////////////////////////// namespace zypp { @@ -73,7 +78,14 @@ namespace zypp IdString vendor() const { return satSolvable().vendor(); } Repository repository() const { return satSolvable().repository(); } - RepoInfo repoInfo() const { return satSolvable().repoInfo(); } + + ZYPP_BEGIN_LEGACY_API + RepoInfo repoInfo() const ZYPP_INTERNAL_DEPRECATE { return satSolvable().repoInfo(); } + ZYPP_END_LEGACY_API + +#ifdef __cpp_lib_optional + const std::optional &ngRepoInfo() const { return satSolvable().ngRepoInfo(); } +#endif bool isSystem() const { return satSolvable().isSystem(); } bool onSystemByUser() const { return satSolvable().onSystemByUser(); } diff --git a/zypp/sat/detail/PoolImpl.cc b/zypp/sat/detail/PoolImpl.cc index 6466cec3b8..807c2d482d 100644 --- a/zypp/sat/detail/PoolImpl.cc +++ b/zypp/sat/detail/PoolImpl.cc @@ -34,6 +34,8 @@ #include #include +#include + extern "C" { // Workaround libsolv project not providing a common include @@ -427,24 +429,29 @@ namespace zypp return ::repo_add_solvable_block( repo_r, count_r ); } - void PoolImpl::setRepoInfo( RepoIdType id_r, const RepoInfo & info_r ) + void PoolImpl::setRepoInfo(RepoIdType id_r, const std::optional &info_r ) { CRepo * repo( getRepo( id_r ) ); if ( repo ) { + if ( !info_r ) { + eraseRepoInfo ( id_r ); + return; + } + bool dirty = false; // libsolv priority is based on '<', while yum's repoinfo // uses 1(highest)->99(lowest). Thus we use -info_r.priority. - if ( repo->priority != int(-info_r.priority()) ) + if ( repo->priority != int(-info_r->priority()) ) { - repo->priority = -info_r.priority(); + repo->priority = -info_r->priority(); dirty = true; } // subpriority is used to e.g. prefer http over dvd iff // both have same priority. - int mediaPriority( media::MediaPriority( info_r.url() ) ); + int mediaPriority( media::MediaPriority( info_r->url() ) ); if ( repo->subpriority != mediaPriority ) { repo->subpriority = mediaPriority; @@ -452,11 +459,19 @@ namespace zypp } if ( dirty ) - setDirty(__FUNCTION__, info_r.alias().c_str() ); + setDirty(__FUNCTION__, info_r->alias().c_str() ); } - _repoinfos[id_r] = info_r; + _repoinfos.insert_or_assign( id_r, *info_r ); } + const std::optional &PoolImpl::repoInfo(RepoIdType id_r) + { + return _repoinfos[id_r]; + } + + void PoolImpl::eraseRepoInfo(RepoIdType id_r) + { _repoinfos.erase(id_r); } + /////////////////////////////////////////////////////////////////// void PoolImpl::setTextLocale( const Locale & locale_r ) diff --git a/zypp/sat/detail/PoolImpl.h b/zypp/sat/detail/PoolImpl.h index 0e697c5033..9b7edb23d0 100644 --- a/zypp/sat/detail/PoolImpl.h +++ b/zypp/sat/detail/PoolImpl.h @@ -21,6 +21,7 @@ extern "C" #include } #include +#include #include #include @@ -34,6 +35,10 @@ extern "C" #include #include +namespace zyppng { + class RepoInfo; +} + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -215,13 +220,13 @@ namespace zypp public: /** */ - const RepoInfo & repoInfo( RepoIdType id_r ) - { return _repoinfos[id_r]; } + const std::optional &repoInfo( RepoIdType id_r ); + /** Also adjust repo priority and subpriority accordingly. */ - void setRepoInfo( RepoIdType id_r, const RepoInfo & info_r ); + void setRepoInfo( RepoIdType id_r, const std::optional & info_r ); + /** */ - void eraseRepoInfo( RepoIdType id_r ) - { _repoinfos.erase( id_r ); } + void eraseRepoInfo(RepoIdType id_r); public: /** Returns the id stored at \c offset_r in the internal @@ -361,7 +366,7 @@ namespace zypp /** Watch serial number. */ SerialNumberWatcher _watcher; /** Additional \ref RepoInfo. */ - std::map _repoinfos; + std::map> _repoinfos; /** */ base::SetTracker _requestedLocalesTracker; diff --git a/zypp/solver/detail/Testcase.cc b/zypp/solver/detail/Testcase.cc index e4eab3676f..3202ec8a12 100644 --- a/zypp/solver/detail/Testcase.cc +++ b/zypp/solver/detail/Testcase.cc @@ -38,6 +38,7 @@ #include #include #include +#include #include @@ -163,21 +164,21 @@ namespace zypp } const auto &myRepo = pi.repository(); - const auto &myRepoInfo = myRepo.info(); - if ( repos.find( myRepo.id()) == repos.end() ) { + const auto &myRepoInfo = myRepo.ngInfo(); + if ( myRepoInfo && repos.find( myRepo.id()) == repos.end() ) { repos.insert( myRepo.id() ); yOut << YAML::Value << YAML::BeginMap; yOut << YAML::Key << "alias" << YAML::Value << myRepo.alias(); yOut << YAML::Key << "url" << YAML::BeginSeq; - for ( auto itUrl = myRepoInfo.baseUrlsBegin(); itUrl != myRepoInfo.baseUrlsEnd(); ++itUrl ) { + for ( auto itUrl = myRepoInfo->baseUrlsBegin(); itUrl != myRepoInfo->baseUrlsEnd(); ++itUrl ) { yOut << YAML::Value << itUrl->asString(); } yOut << YAML::EndSeq; - yOut << YAML::Key << "path" << YAML::Value << myRepoInfo.path().asString(); - yOut << YAML::Key << "type" << YAML::Value << myRepoInfo.type().asString(); + yOut << YAML::Key << "path" << YAML::Value << myRepoInfo->path().asString(); + yOut << YAML::Key << "type" << YAML::Value << myRepoInfo->type().asString(); yOut << YAML::Key << "generated" << YAML::Value << myRepo.generatedTimestamp().form( "%Y-%m-%d %H:%M:%S" ); yOut << YAML::Key << "outdated" << YAML::Value << myRepo.suggestedExpirationTimestamp().form( "%Y-%m-%d %H:%M:%S" ); - yOut << YAML::Key << "priority" << YAML::Value << myRepoInfo.priority(); + yOut << YAML::Key << "priority" << YAML::Value << myRepoInfo->priority(); yOut << YAML::Key << "file" << YAML::Value << str::Format("%1%.repo.gz") % repoFileNames[myRepo.id()->repoid]; yOut << YAML::EndMap; @@ -330,7 +331,7 @@ namespace zypp << YAML::Key << "name" << YAML::Value << pi.name() << YAML::Key << "status" << YAML::Value << status.str(); if ( !shortInfo ) { - yOut << YAML::Key << "channel" << YAML::Value << pi.repoInfo().alias() + yOut << YAML::Key << "channel" << YAML::Value << (pi.ngRepoInfo() ? pi.ngRepoInfo()->alias() : "") << YAML::Key << "arch" << YAML::Value << pi.arch().asString() << YAML::Key << "version" << YAML::Value << pi.edition().version() << YAML::Key << "release" << YAML::Value << pi.edition().release(); diff --git a/zypp/target/CommitPackageCacheReadAhead.cc b/zypp/target/CommitPackageCacheReadAhead.cc index 8c6433b9e3..30bc0c9e13 100644 --- a/zypp/target/CommitPackageCacheReadAhead.cc +++ b/zypp/target/CommitPackageCacheReadAhead.cc @@ -18,6 +18,8 @@ #include #include +#include + using std::endl; /////////////////////////////////////////////////////////////////// @@ -36,7 +38,7 @@ namespace zypp std::ostream & operator<<( std::ostream & str, const IMediaKey & obj ) { return str << "[S" << obj._repo.id() << ":" << obj._mediaNr << "]" - << " " << obj._repo.info().alias(); + << " " << (obj._repo.ngInfo() ? obj._repo.ngInfo()->alias() : "norepo" ); } /////////////////////////////////////////////////////////////////// @@ -63,9 +65,9 @@ namespace zypp { if ( pi->mediaNr() == 0 ) // no media access at all return false; - if ( pi->repoInfo().baseUrlsEmpty() ) - return false; // no Url - should actually not happen - std::string scheme( pi->repoInfo().baseUrlsBegin()->getScheme() ); + if ( ! pi->ngRepoInfo() || pi->ngRepoInfo()->baseUrlsEmpty() ) + return false; // no RepoInfo or no Url - should actually not happen + std::string scheme( pi->ngRepoInfo()->baseUrlsBegin()->getScheme() ); return ( scheme == "dvd" || scheme == "cd" ); } diff --git a/zypp/target/RpmPostTransCollector.cc b/zypp/target/RpmPostTransCollector.cc index b6b6b37b59..13279ca224 100644 --- a/zypp/target/RpmPostTransCollector.cc +++ b/zypp/target/RpmPostTransCollector.cc @@ -235,7 +235,7 @@ namespace zypp // Scripts first... if ( _scripts ) { - Pathname noRootScriptDir( ZConfig::instance().update_scriptsPath() / tmpDir().basename() ); + Pathname noRootScriptDir( ZConfig::update_scriptsPath() / tmpDir().basename() ); // like rpm would report it (intentionally not translated and NL-terminated): str::Format fmtScriptFailedMsg { "warning: %%posttrans(%1%) scriptlet failed, exit status %2%\n" }; str::Format fmtPosttrans { "%%posttrans(%1%)" }; @@ -336,7 +336,7 @@ namespace zypp /** Lazy create tmpdir on demand. */ Pathname tmpDir() { - if ( !_ptrTmpdir ) _ptrTmpdir.reset( new filesystem::TmpDir( _root / ZConfig::instance().update_scriptsPath(), "posttrans" ) ); + if ( !_ptrTmpdir ) _ptrTmpdir.reset( new filesystem::TmpDir( _root / ZConfig::update_scriptsPath(), "posttrans" ) ); DBG << _ptrTmpdir->path() << endl; return _ptrTmpdir->path(); } diff --git a/zypp/target/TargetImpl.cc b/zypp/target/TargetImpl.cc index 1960c8a3a8..e6ba8588b1 100644 --- a/zypp/target/TargetImpl.cc +++ b/zypp/target/TargetImpl.cc @@ -988,6 +988,7 @@ namespace zypp TargetImpl::~TargetImpl() { _rpm.closeDatabase(); + //@BUG !!! This causes use after free in the exit handlers, use a sigc::signal sigMultiversionSpecChanged(); // HACK: see sigMultiversionSpecChanged MIL << "Closed target on " << _root << endl; } diff --git a/zypp/target/rpm/RpmDb.cc b/zypp/target/rpm/RpmDb.cc index df045ab37c..f548cf8688 100644 --- a/zypp/target/rpm/RpmDb.cc +++ b/zypp/target/rpm/RpmDb.cc @@ -233,6 +233,8 @@ RpmDb::~RpmDb() closeDatabase(); delete process; MIL << "~RpmDb() end" << endl; + + //@BUG !!! This causes use after free in the exit handlers, use a sigc::signal sKeyRingReceiver.reset(); } @@ -1705,7 +1707,7 @@ void RpmDb::doInstallPackage( const Pathname & filename, RpmInstFlags flags, Rpm opts.push_back("--noglob"); // ZConfig defines cross-arch installation - if ( ! ZConfig::instance().systemArchitecture().compatibleWith( ZConfig::instance().defaultSystemArchitecture() ) ) + if ( ! ZConfig::instance().systemArchitecture().compatibleWith( ZConfig::defaults().defaultSystemArchitecture() ) ) opts.push_back("--ignorearch"); if (flags & RPMINST_NODIGEST) diff --git a/zypp/zypp_detail/ZYppImpl.cc b/zypp/zypp_detail/ZYppImpl.cc index 39881adb5d..729c794fc7 100644 --- a/zypp/zypp_detail/ZYppImpl.cc +++ b/zypp/zypp_detail/ZYppImpl.cc @@ -25,6 +25,7 @@ #include #include // JobReport::instance +#include using std::endl; @@ -81,6 +82,17 @@ namespace { namespace zypp { ///////////////////////////////////////////////////////////////// + + namespace env + { + /** Hack to circumvent the currently poor --root support. + * To be replaced by the sysRoot of the context the lock belongs to. + */ + inline Pathname ZYPP_LOCKFILE_ROOT() + { return getenv("ZYPP_LOCKFILE_ROOT") ? getenv("ZYPP_LOCKFILE_ROOT") : "/"; } + } + + /////////////////////////////////////////////////////////////////// namespace media { @@ -108,23 +120,106 @@ namespace zypp namespace zypp_detail { ///////////////////////////////////////////////////////////////// + + static bool zyppLegacyShutdownStarted = false; // set to true if the GlobalStateHelper was destructed + + // if this logic is changed, also update the one in MediaConfig + zypp::Pathname autodetectZyppConfPath() { + const char *env_confpath = getenv("ZYPP_CONF"); + return env_confpath ? env_confpath + : zyppng::ContextBase::defaultConfigPath(); + } + + zyppng::SyncContextRef &GlobalStateHelper::assertContext() { + + if ( zyppLegacyShutdownStarted ) + ZYPP_THROW("Global State requested after it was freed"); + + // set up the global context for the legacy API + // zypp is booting + if (!_defaultContext) { + auto set = zyppng::ContextSettings { + .root = "/", + .configPath = autodetectZyppConfPath () + }; + _defaultContext = zyppng::SyncContext::create(); + + if ( !_config ) + config(); // assert config + + _defaultContext->legacyInit ( std::move(set), _config ); + } + return _defaultContext; + } + + zyppng::FusionPoolRef &GlobalStateHelper::assertPool() + { + if ( !_defaultPool ) + _defaultPool = zyppng::FusionPool::defaultPool(); + return _defaultPool; + } + + zypp::ZConfig &GlobalStateHelper::config() { + + if ( zyppLegacyShutdownStarted ) + ZYPP_THROW("Global State requested after it was freed"); + + auto &inst = instance(); + if (!inst._config) { + inst._config.reset( new ZConfig( autodetectZyppConfPath () ) ); + } + + return *inst._config; + } + + void GlobalStateHelper::lock() + { + if ( zyppLegacyShutdownStarted ) + return; + + auto &me = instance (); + if ( me._lock ) + return; + + const long LOCK_TIMEOUT = str::strtonum( getenv( "ZYPP_LOCK_TIMEOUT" ) ); + auto l = ZyppContextLock::globalLock( env::ZYPP_LOCKFILE_ROOT () ); + l->acquireLock( LOCK_TIMEOUT ); + + // did not throw, we got the lock + me._lock = std::move(l); + } + + void GlobalStateHelper::unlock() + { + if ( zyppLegacyShutdownStarted ) + return; + + auto &me = instance (); + me._lock.reset(); + } + + Pathname GlobalStateHelper::lockfileDir() + { + return ZyppContextLock::globalLockfileDir( env::ZYPP_LOCKFILE_ROOT() ) ; + } + + GlobalStateHelper::~GlobalStateHelper() + { + zyppLegacyShutdownStarted = true; + } + /////////////////////////////////////////////////////////////////// // // METHOD NAME : ZYppImpl::ZYppImpl // METHOD TYPE : Constructor // ZYppImpl::ZYppImpl() - : _target( nullptr ) - , _resolver( new Resolver( ResPool::instance()) ) { // trigger creation of the shutdown pipe if ( !ensureShutdownPipe() ) WAR << "Failed to create shutdown pipe" << std::endl; - ZConfig::instance().about( MIL ); - MIL << "Initializing keyring..." << std::endl; - _keyring = new KeyRing(tmpPath()); - _keyring->allowPreload( true ); + GlobalStateHelper::config().about( MIL ); } /////////////////////////////////////////////////////////////////// @@ -166,41 +261,21 @@ namespace zypp Target_Ptr ZYppImpl::target() const { - if (! _target) + auto ref = getTarget(); + if ( !ref ) ZYPP_THROW(Exception("Target not initialized.")); - return _target; + return ref; } - void ZYppImpl::changeTargetTo( const Target_Ptr& newtarget_r ) - { - if ( _target && newtarget_r ) // bsc#1203760: Make sure the old target is deleted before a new one is created! - INT << "2 active targets at the same time must not happen!" << endl; - _target = newtarget_r; - ZConfig::instance().notifyTargetChanged(); - resolver()->setDefaultSolverFlags( /*all_r*/false ); // just changed defaults - } void ZYppImpl::initializeTarget( const Pathname & root, bool doRebuild_r ) { - MIL << "initTarget( " << root << (doRebuild_r?", rebuilddb":"") << ")" << endl; - if (_target) { - if (_target->root() == root) { - MIL << "Repeated call to initializeTarget()" << endl; - return; - } - _target->unload(); - _target = nullptr; // bsc#1203760: Make sure the old target is deleted before a new one is created! - } - changeTargetTo( new Target( root, doRebuild_r ) ); - _target->buildCache(); + context()->changeToTarget( root, doRebuild_r ); } void ZYppImpl::finishTarget() { - if (_target) - _target->unload(); - - changeTargetTo( nullptr ); + context()->finishTarget().unwrap(); } //------------------------------------------------------------------------ @@ -210,55 +285,21 @@ namespace zypp * and target used for transact. */ ZYppCommitResult ZYppImpl::commit( const ZYppCommitPolicy & policy_r ) { - if ( getenv("ZYPP_TESTSUITE_FAKE_ARCH") ) - { - ZYPP_THROW( Exception("ZYPP_TESTSUITE_FAKE_ARCH set. Commit not allowed and disabled.") ); - } - - MIL << "Attempt to commit (" << policy_r << ")" << endl; - if (! _target) - ZYPP_THROW( Exception("Target not initialized.") ); - - - env::ScopedSet ea { "ZYPP_IS_RUNNING", str::numstring(getpid()).c_str() }; - env::ScopedSet eb; - if ( _target->chrooted() ) - eb = env::ScopedSet( "SYSTEMD_OFFLINE", "1" ); // bsc#1118758 - indicate no systemd if chrooted install - - ZYppCommitResult res = _target->_pimpl->commit( pool(), policy_r ); - - if (! policy_r.dryRun() ) - { - if ( policy_r.syncPoolAfterCommit() ) - { - // reload new status from target - DBG << "reloading " << sat::Pool::instance().systemRepoAlias() << " repo to pool" << endl; - _target->load(); - } - else - { - DBG << "unloading " << sat::Pool::instance().systemRepoAlias() << " repo from pool" << endl; - _target->unload(); - } - } - - MIL << "Commit (" << policy_r << ") returned: " - << res << endl; - return res; + return GlobalStateHelper::pool()->commit( policy_r ).unwrap(); } void ZYppImpl::installSrcPackage( const SrcPackage_constPtr & srcPackage_r ) { - if (! _target) + if (! context()->target() ) ZYPP_THROW( Exception("Target not initialized.") ); - _target->_pimpl->installSrcPackage( srcPackage_r ); + context()->target()->_pimpl->installSrcPackage( srcPackage_r ); } ManagedFile ZYppImpl::provideSrcPackage( const SrcPackage_constPtr & srcPackage_r ) { - if (! _target) + if (! context()->target() ) ZYPP_THROW( Exception("Target not initialized.") ); - return _target->_pimpl->provideSrcPackage( srcPackage_r ); + return context()->target()->_pimpl->provideSrcPackage( srcPackage_r ); } //------------------------------------------------------------------------ @@ -335,15 +376,14 @@ namespace zypp } return r; } - - ///////////////////////////////////////////////////////////////// } // namespace zypp_detail /////////////////////////////////////////////////////////////////// - Pathname myTmpDir() // from TmpPath.h + Pathname myTmpDir() // from TmpPath.h { - static filesystem::TmpDir _tmpdir( filesystem::TmpPath::defaultLocation(), "zypp." ); - return _tmpdir.path(); + static filesystem::TmpDir _tmpdir(filesystem::TmpPath::defaultLocation(), + "zypp."); + return _tmpdir.path(); } ///////////////////////////////////////////////////////////////// diff --git a/zypp/zypp_detail/ZYppImpl.h b/zypp/zypp_detail/ZYppImpl.h index 03b33129a6..0622960f09 100644 --- a/zypp/zypp_detail/ZYppImpl.h +++ b/zypp/zypp_detail/ZYppImpl.h @@ -23,6 +23,9 @@ #include #include +#include +#include + using GPollFD = struct _GPollFD; /////////////////////////////////////////////////////////////////// @@ -32,6 +35,54 @@ namespace zypp namespace zypp_detail { ///////////////////////////////////////////////////////////////// + // Legacy detect zypp conf path + zypp::Pathname autodetectZyppConfPath(); + + // represents the legacy zypp global state, will initialize the internal + // context so that the required parts are initialized as needed + class GlobalStateHelper { + + public: + static zypp::ZConfig &config(); + + static zyppng::SyncContextRef context() { + return instance().assertContext(); + } + + static zypp::Target_Ptr target() { + return instance().assertContext()->target(); + } + + static zyppng::FusionPoolRef pool() { + return instance().assertPool(); + } + + static void lock(); + static void unlock(); + + static zypp::Pathname lockfileDir(); + + private: + GlobalStateHelper() {} + ~GlobalStateHelper(); + + static GlobalStateHelper &instance() { + static GlobalStateHelper me; + return me; + } + + ZyppContextLockRef _lock; + + zyppng::SyncContextRef &assertContext(); + zyppng::FusionPoolRef &assertPool(); + + zyppng::SyncContextRef _defaultContext; + zyppng::FusionPoolRef _defaultPool; + + ZConfigRef _config; // legacy has one config that never goes away + }; + + /////////////////////////////////////////////////////////////////// // // CLASS NAME : ZYppImpl @@ -48,20 +99,25 @@ namespace zypp ~ZYppImpl(); public: + + zyppng::SyncContextRef context() { + return GlobalStateHelper::context(); + } + /** */ ResPool pool() const - { return ResPool::instance(); } + { return GlobalStateHelper::pool()->resPool(); } ResPoolProxy poolProxy() const - { return ResPool::instance().proxy(); } + { return GlobalStateHelper::pool()->poolProxy(); } /** */ KeyRing_Ptr keyRing() const - { return _keyring; } + { return GlobalStateHelper::context()->keyRing(); } Resolver_Ptr resolver() const - { return _resolver; } + { return GlobalStateHelper::pool()->resolver(); } public: /** \todo Signal locale change. */ @@ -74,7 +130,7 @@ namespace zypp * initialized, instead of throwing. */ Target_Ptr getTarget() const - { return _target; } + { return GlobalStateHelper::target(); } /** * \throws Exception @@ -126,12 +182,6 @@ namespace zypp static void clearShutdownSignal(); private: - /** */ - Target_Ptr _target; - /** */ - Resolver_Ptr _resolver; - - KeyRing_Ptr _keyring; /** */ Pathname _home_path; /** defined mount points, used for disk usage counting */ @@ -154,8 +204,6 @@ namespace zypp * \throws zypp::UserAbortException in case the shutdown signal was received */ int zypp_poll( std::vector &fds, int timeout = -1 ); - - ///////////////////////////////////////////////////////////////// } // namespace zypp_detail /////////////////////////////////////////////////////////////////// diff --git a/zypp/zypp_detail/ZyppLock.cc b/zypp/zypp_detail/ZyppLock.cc new file mode 100644 index 0000000000..3b92f438aa --- /dev/null +++ b/zypp/zypp_detail/ZyppLock.cc @@ -0,0 +1,295 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ + +#include "ZyppLock.h" +#include +#include +#include +#include + +#include + +#include + +namespace zypp { + + namespace zypp_readonly_hack { + + static bool active = getenv("ZYPP_READONLY_HACK"); + + ZYPP_API void IWantIt() // see zypp/zypp_detail/ZYppReadOnlyHack.h + { + active = true; + MIL << "ZYPP_READONLY promised." << std::endl; + } + + bool IGotIt() + { + return active; + } + } // namespace zypp_readonly_hack + + ZyppContextLock::ZyppContextLock( Pathname root, const Pathname &fFileName ) + : _zyppLockRoot( std::move(root) ) + , _zyppLockFilePath( ZyppContextLock::globalLockfileDir( root ) / fFileName ) + , _zyppLockFile(NULL) + , _lockerPid(0) + , _cleanLock(false) { + filesystem::assert_dir(_zyppLockFilePath.dirname()); + } + + ZyppContextLock::~ZyppContextLock() { + if (_cleanLock) + try { + // Exception safe access to the lockfile. + ScopedGuard closeOnReturn(accessLockFile()); + { + scoped_lock flock(_zyppLockFileLock); // aquire write lock + // Truncate the file rather than deleting it. Other processes may + // still use it to synchronize. + ftruncate(fileno(_zyppLockFile), 0); + } + MIL << "Cleaned lock file. (" << getpid() << ")" << std::endl; + } catch (...) { + } // let no exception escape. + } + + pid_t ZyppContextLock::lockerPid() const { return _lockerPid; } + const std::string &ZyppContextLock::lockerName() const { return _lockerName; } + const Pathname &ZyppContextLock::zyppLockFilePath() const { + return _zyppLockFilePath; + } + + zypp::Pathname ZyppContextLock::globalLockfileDir( const zypp::Pathname &root ) + { + return root / "run"; + } + + std::shared_ptr ZyppContextLock::globalLock( const Pathname &root ) + { + static std::unordered_map> globalLocks; + + std::string key; + if ( root.empty()) { + key = "/"; + } else { + key = root.asString(); + } + + auto &rootLock = globalLocks[key]; + + auto ptr = rootLock.lock(); + if ( ptr ) { + return ptr; + } + + rootLock = ptr = std::make_shared( root, "zypp.pid" ); + return ptr; + } + + ZyppContextLock::ScopedGuard ZyppContextLock::accessLockFile() { + _openLockFile(); + return ScopedGuard( + static_cast(0), + std::bind(std::mem_fn(&ZyppContextLock::_closeLockFile), this)); + } + void ZyppContextLock::_openLockFile() { + if (_zyppLockFile != NULL) + return; // is open + + // open pid file rw so we are sure it exist when creating the flock + _zyppLockFile = fopen(_zyppLockFilePath.c_str(), "a+"); + if (_zyppLockFile == NULL) + ZYPP_THROW(Exception("Cant open " + _zyppLockFilePath.asString())); + _zyppLockFileLock = _zyppLockFilePath.c_str(); + MIL << "Open lockfile " << _zyppLockFilePath << std::endl; + } + + void ZyppContextLock::_closeLockFile() { + if (_zyppLockFile == NULL) + return; // is closed + + clearerr(_zyppLockFile); + fflush(_zyppLockFile); + // http://www.boost.org/doc/libs/1_50_0/doc/html/interprocess/synchronization_mechanisms.html + // If you are using a std::fstream/native file handle to write to the file + // while using file locks on that file, don't close the file before + // releasing all the locks of the file. + _zyppLockFileLock = file_lock(); + fclose(_zyppLockFile); + _zyppLockFile = NULL; + MIL << "Close lockfile " << _zyppLockFilePath << std::endl; + } + + bool ZyppContextLock::isProcessRunning(pid_t pid_r) { + // it is another program, not me, see if it is still running + Pathname procdir(Pathname("/proc") / str::numstring(pid_r)); + PathInfo status(procdir); + MIL << "Checking " << status << std::endl; + + if (!status.isDir()) { + DBG << "No such process." << std::endl; + return false; + } + + static char buffer[513]; + buffer[0] = buffer[512] = 0; + // man proc(5): /proc/[pid]/cmdline is empty if zombie. + if (std::ifstream((procdir / "cmdline").c_str()) + .read(buffer, 512) + .gcount() > 0) { + _lockerName = buffer; + DBG << "Is running: " << _lockerName << std::endl; + return true; + } + + DBG << "In zombie state." << std::endl; + return false; + } + + pid_t ZyppContextLock::readLockFile() { + clearerr(_zyppLockFile); + fseek(_zyppLockFile, 0, SEEK_SET); + long readpid = 0; + fscanf(_zyppLockFile, "%ld", &readpid); + MIL << "read: Lockfile " << _zyppLockFilePath << " has pid " << readpid + << " (our pid: " << getpid() << ") " << std::endl; + return (pid_t)readpid; + } + + void ZyppContextLock::writeLockFile() { + clearerr(_zyppLockFile); + fseek(_zyppLockFile, 0, SEEK_SET); + ftruncate(fileno(_zyppLockFile), 0); + fprintf(_zyppLockFile, "%ld\n", (long)getpid()); + fflush(_zyppLockFile); + _cleanLock = true; // cleanup on exit + MIL << "write: Lockfile " << _zyppLockFilePath << " got pid " << getpid() + << std::endl; + } + + bool ZyppContextLock::safeCheckIsLocked() { + _lockerPid = readLockFile(); + if (_lockerPid == 0) { + // no or empty lock file + return false; + } else if (_lockerPid == getpid()) { + // keep my own lock + return false; + } else { + // a foreign pid in lock + if (isProcessRunning(_lockerPid)) { + WAR << _lockerPid << " is running and has a ZYpp lock. Sorry." + << std::endl; + return true; + } else { + MIL << _lockerPid << " is dead. Ignoring the existing lock file." + << std::endl; + return false; + } + } + } + + bool ZyppContextLock::isZyppLocked() { + if (geteuid() != 0) + return false; // no lock as non-root + + // Exception safe access to the lockfile. + ScopedGuard closeOnReturn(accessLockFile()); + scoped_lock flock(_zyppLockFileLock); // aquire write lock + return safeCheckIsLocked(); + } + + bool ZyppContextLock::zyppLocked() { + if (geteuid() != 0) + return false; // no lock as non-root + + // Exception safe access to the lockfile. + ScopedGuard closeOnReturn(accessLockFile()); + scoped_lock flock(_zyppLockFileLock); // aquire write lock + if (!safeCheckIsLocked()) { + writeLockFile(); + return false; + } + return true; + } + + void ZyppContextLock::acquireLock( const long lockTimeout ) + { + + const auto &makeLockedError = [](pid_t pid, const std::string &lockerName) { + const std::string &t = str::form( + _("System management is locked by the application with pid %d (%s).\n" + "Close this application before trying again."), + pid, lockerName.c_str()); + + return ZYppFactoryException(t, pid, lockerName); + }; + + if ( geteuid() != 0 ) + { + MIL << "Running as user. Skip creating " << zyppLockFilePath() << std::endl; + } + else if ( zypp_readonly_hack::active ) + { + MIL << "ZYPP_READONLY active." << std::endl; + } + else if ( zyppLocked() ) + { + bool failed = true; + // bsc#1184399,1213231: A negative ZYPP_LOCK_TIMEOUT will wait forever. + if ( lockTimeout != 0 ) + { + Date logwait = Date::now(); + Date giveup; /* 0 = forever */ + if ( lockTimeout > 0 ) { + giveup = logwait+lockTimeout; + MIL << "$ZYPP_LOCK_TIMEOUT=" << lockTimeout << " sec. Waiting for the zypp lock until " << giveup << std::endl; + } + else + MIL << "$ZYPP_LOCK_TIMEOUT=" << lockTimeout << " sec. Waiting for the zypp lock..." << std::endl; + + unsigned delay = 0; + do { + if ( delay < 60 ) + delay += 1; + else { + Date now { Date::now() }; + if ( now - logwait > Date::day ) { + WAR << "$ZYPP_LOCK_TIMEOUT=" << lockTimeout << " sec. Another day has passed waiting for the zypp lock..." << std::endl; + logwait = now; + } + } + sleep( delay ); + { + zypp::base::LogControl::TmpLineWriter shutUp; // be quiet + failed = zyppLocked(); + } + } while ( failed && ( not giveup || Date::now() <= giveup ) ); + + if ( failed ) { + MIL << "$ZYPP_LOCK_TIMEOUT=" << lockTimeout << " sec. Gave up waiting for the zypp lock." << std::endl; + } + else { + MIL << "$ZYPP_LOCK_TIMEOUT=" << lockTimeout << " sec. Finally got the zypp lock." << std::endl; + } + } + if ( failed ) + ZYPP_THROW( makeLockedError( lockerPid(), lockerName() )); + + // we got the base lock, now make sure zypp-rpm is not still running + { + ZyppContextLock zyppRpmLock( _zyppLockRoot, "zypp-rpm.pid" ); + if ( zyppRpmLock.isZyppLocked () ) { + ZYPP_THROW( makeLockedError( zyppRpmLock.lockerPid(), zyppRpmLock.lockerName() )); + } + } + } + } +} // namespace zypp diff --git a/zypp/zypp_detail/ZyppLock.h b/zypp/zypp_detail/ZyppLock.h new file mode 100644 index 0000000000..02359ac47f --- /dev/null +++ b/zypp/zypp_detail/ZyppLock.h @@ -0,0 +1,112 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/zypp_detail/ZYppLock.h + * +*/ +#ifndef ZYPP_ZYPP_DETAIL_ZYPPLOCK_H +#define ZYPP_ZYPP_DETAIL_ZYPPLOCK_H + +#include +#include +#include + +#include +#include +#include + + +namespace zypp { + +using boost::interprocess::file_lock; +using boost::interprocess::scoped_lock; +using boost::interprocess::sharable_lock; + +ZYPP_FWD_DECL_TYPE_WITH_REFS (ZyppContextLock); + +/////////////////////////////////////////////////////////////////// +/// \class ZyppContextLock +/// \brief This lock is aquired by a context, currently its a shared "lock everything" type of lock +/// but it will be replaced by a read/write lock, then maybe made even more granular. +/// +/////////////////////////////////////////////////////////////////// +class ZyppContextLock +{ +public: + ZyppContextLock(Pathname root, const Pathname &fFileName ); + ZyppContextLock( const ZyppContextLock & ) = delete; + ZyppContextLock(ZyppContextLock &&) = delete; + ZyppContextLock &operator=(const ZyppContextLock &) = delete; + ZyppContextLock &operator=(ZyppContextLock &&) = delete; + + ~ZyppContextLock(); + + pid_t lockerPid() const; + const std::string &lockerName() const; + const Pathname &zyppLockFilePath() const; + + static std::shared_ptr globalLock( const zypp::Pathname &root ); + static zypp::Pathname globalLockfileDir( const zypp::Pathname &root ); +private: + + Pathname _zyppLockRoot; //< root of the context aquiring the lock + Pathname _zyppLockFilePath; //< absolute lockfile path + file_lock _zyppLockFileLock; + FILE * _zyppLockFile; + + pid_t _lockerPid; + std::string _lockerName; + bool _cleanLock; + +private: + using ScopedGuard = shared_ptr; + + /** Exception safe access to the lockfile. + * \code + * // Exception safe access to the lockfile. + * ScopedGuard closeOnReturn( accessLockFile() ); + * \endcode + */ + ScopedGuard accessLockFile(); + + /** Use \ref accessLockFile. */ + void _openLockFile(); + + /** Use \ref accessLockFile. */ + void _closeLockFile(); + + bool isProcessRunning(pid_t pid_r); + + pid_t readLockFile(); + + void writeLockFile(); + + /*! + * Expects the calling function to lock the access lock + */ + bool safeCheckIsLocked(); + +public: + bool isZyppLocked(); + + /** Try to aquire a lock. + * \return \c true if zypp is already locked by another process. + */ + bool zyppLocked(); + + + /** + * Aquires the lock, throws if the log could not be acquired. + * If a lockTimeout is given, zypp will try to keep acquiring the lock + * untit it either succeeds or that timeout has been reached + */ + void acquireLock( const long lockTimeout = 0 ); +}; + +} +#endif diff --git a/zypp/zypp_detail/keyring_p.h b/zypp/zypp_detail/keyring_p.h index b60e6bddf8..4a5e32c136 100644 --- a/zypp/zypp_detail/keyring_p.h +++ b/zypp/zypp_detail/keyring_p.h @@ -47,7 +47,7 @@ namespace zypp { KeyManagerCtx & keyManagerCtx(); private: - CachedPublicKeyData & _cache; + std::reference_wrapper _cache; Pathname _keyring; std::optional _context; }; diff --git a/zypp/zypp_detail/urlcredentialextractor_p.h b/zypp/zypp_detail/urlcredentialextractor_p.h index f7cf100bf2..bf98544df1 100644 --- a/zypp/zypp_detail/urlcredentialextractor_p.h +++ b/zypp/zypp_detail/urlcredentialextractor_p.h @@ -14,7 +14,9 @@ #define ZYPP_ZYPP_DETAIL_URLCREDENTIALEXTRACTOR_P_H #include -#include + +#include +#include namespace zypp { @@ -42,12 +44,8 @@ namespace zypp class UrlCredentialExtractor { public: - UrlCredentialExtractor( const Pathname & root_r ) - : _root( root_r ) - {} - - UrlCredentialExtractor( Pathname & root_r ) - : _root( root_r ) + UrlCredentialExtractor( zyppng::ContextBaseRef ctx ) + : _ctx( std::move(ctx) ) {} ~UrlCredentialExtractor() @@ -59,7 +57,7 @@ namespace zypp bool ret = url_r.hasCredentialsInAuthority(); if ( ret ) { - if ( !_cmPtr ) _cmPtr.reset( new media::CredentialManager( _root ) ); + if ( !_cmPtr ) _cmPtr = zyppng::media::CredentialManager::create( media::CredManagerSettings(_ctx) ); _cmPtr->addUserCred( url_r ); } return ret; @@ -83,8 +81,8 @@ namespace zypp { bool ret = false; for ( Url & url : urls_r ) { if ( extract( url ) && !ret ) ret = true; } return ret; } private: - const Pathname & _root; - scoped_ptr _cmPtr; + zyppng::ContextBaseRef _ctx; + zyppng::media::CredentialManagerRef _cmPtr; }; }