diff --git a/libzypp/CMakeLists.txt b/libzypp/CMakeLists.txt index 587f154..47786d4 100644 --- a/libzypp/CMakeLists.txt +++ b/libzypp/CMakeLists.txt @@ -4,10 +4,33 @@ SET( PACKAGE "libzypp" ) SET( CMAKE_MODULE_PATH ${LIBZYPP_SOURCE_DIR}/cmake/modules ) cmake_minimum_required(VERSION 2.6) +OPTION (ENABLE_BUILD_DOCS "Build documentation by default?" OFF) +OPTION (ENABLE_BUILD_TRANS "Build translation files by default?" OFF) +OPTION (ENABLE_BUILD_TESTS "Build and run test suite by default?" OFF) 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) +#-------------------------------------------------------------------------------- +SET (have_system x) + +IF (DEBIAN) + MESSAGE (STATUS "Building for Debian") + SET (ENABLE_BUILD_DOCS ON) + SET (ENABLE_BUILD_TRANS ON) + SET (ENABLE_BUILD_TESTS ON) + SET (have_system ${have_system}x) +ENDIF (DEBIAN) + +IF (${have_system} STREQUAL x) + MESSAGE (STATUS "Building for SUSE") +ENDIF (${have_system} STREQUAL x) + +IF (${have_system} STRGREATER xx) + MESSAGE (FATAL_ERROR "Can only build for one system type.") +ENDIF (${have_system} STRGREATER xx) +#-------------------------------------------------------------------------------- + # allow name libraries by name mixed with full # paths if(COMMAND cmake_policy) @@ -29,8 +52,8 @@ include(CheckCXXCompilerFlag) CHECK_C_COMPILER_FLAG("-Werror=format-security" CC_FORMAT_SECURITY) CHECK_CXX_COMPILER_FLAG("-Werror=format-security" CXX_FORMAT_SECURITY) -SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden -fno-strict-aliasing -fPIC -g -Wall -Woverloaded-virtual -Wnon-virtual-dtor -Wl,-as-needed -std=c++0x" ) -SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing -fPIC -g -Wall -Wl,-as-needed" ) +SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden -fno-strict-aliasing -fPIC -g -rdynamic -Wall -Woverloaded-virtual -Wnon-virtual-dtor -Wl,-as-needed -std=c++11" ) +SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing -fPIC -g -rdynamic -Wall -Wl,-as-needed" ) set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O3" ) set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O3" ) @@ -62,7 +85,7 @@ MACRO(ADD_TESTS) FOREACH( loop_var ${ARGV} ) SET_SOURCE_FILES_PROPERTIES( ${loop_var}_test.cc COMPILE_FLAGS "-DBOOST_TEST_DYN_LINK -DBOOST_TEST_MAIN -DBOOST_AUTO_TEST_MAIN=\"\" " ) ADD_EXECUTABLE( ${loop_var}_test ${loop_var}_test.cc ) - TARGET_LINK_LIBRARIES( ${loop_var}_test zypp boost_unit_test_framework zypp_test_utils) + TARGET_LINK_LIBRARIES( ${loop_var}_test zypp ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} zypp_test_utils) ADD_TEST( ${loop_var}_test ${CMAKE_CURRENT_BINARY_DIR}/${loop_var}_test --catch_system_errors=no) ENDFOREACH( loop_var ) ENDMACRO(ADD_TESTS) @@ -90,7 +113,7 @@ ELSE ( NOT RPM_FOUND) endif ( RPM_SUSPECT_VERSION STREQUAL "5.x" ) ENDIF( NOT RPM_FOUND) -FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options unit_test_framework) +FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options thread unit_test_framework) IF (Boost_FOUND) MESSAGE( STATUS "boost found: includes in ${Boost_INCLUDE_DIRS}, library in ${Boost_LIBRARY_DIRS}") INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) @@ -105,19 +128,19 @@ ELSE (GETTEXT_FOUND) MESSAGE( FATAL_ERROR "Gettext not found" ) ENDIF (GETTEXT_FOUND) -FIND_PACKAGE(Curl REQUIRED) +FIND_PACKAGE(CURL REQUIRED) IF ( NOT CURL_FOUND) MESSAGE( FATAL_ERROR " curl not found" ) ELSE ( NOT CURL_FOUND) - INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIR}) + INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIRS}) ENDIF( NOT CURL_FOUND) -FIND_PACKAGE(Libxml REQUIRED) -IF ( NOT LIBXML_FOUND) +FIND_PACKAGE(LibXml2 REQUIRED) +IF ( NOT LIBXML2_FOUND) MESSAGE( FATAL_ERROR " libxml not found" ) -ELSE ( NOT LIBXML_FOUND) - INCLUDE_DIRECTORIES(${LIBXML_INCLUDE_DIR}) -ENDIF( NOT LIBXML_FOUND) +ELSE ( NOT LIBXML2_FOUND) + INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR}) +ENDIF( NOT LIBXML2_FOUND) FIND_PACKAGE(ZLIB REQUIRED) IF ( NOT ZLIB_FOUND) @@ -213,15 +236,23 @@ INSTALL( FILES ${LIBZYPP_SOURCE_DIR}/zypp-history.lr DESTINATION ${SYSCONFDIR}/l #################################################################### ADD_SUBDIRECTORY( zypp ) -#ADD_SUBDIRECTORY( zypp2 ) # do not build devel by default ADD_SUBDIRECTORY( devel EXCLUDE_FROM_ALL ) ADD_SUBDIRECTORY( tools ) ADD_SUBDIRECTORY( examples ) -ADD_SUBDIRECTORY( po EXCLUDE_FROM_ALL ) ADD_SUBDIRECTORY( doc ) ADD_SUBDIRECTORY( vendor ) -ADD_SUBDIRECTORY( tests EXCLUDE_FROM_ALL ) +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 ) + ADD_SUBDIRECTORY( tests EXCLUDE_FROM_ALL ) +ENDIF ( ENABLE_BUILD_TESTS ) INCLUDE(CTest) ENABLE_TESTING() diff --git a/libzypp/VERSION.cmake b/libzypp/VERSION.cmake index d5d4a68..3820e38 100644 --- a/libzypp/VERSION.cmake +++ b/libzypp/VERSION.cmake @@ -58,11 +58,11 @@ # - Consider calling ./mkChangelog to assist you. # See './mkChangelog -h' for help. # -SET(LIBZYPP_MAJOR "12") -SET(LIBZYPP_COMPATMINOR "0") -SET(LIBZYPP_MINOR "2") +SET(LIBZYPP_MAJOR "14") +SET(LIBZYPP_COMPATMINOR "30") +SET(LIBZYPP_MINOR "35") SET(LIBZYPP_PATCH "0") # -# LAST RELEASED: 12.2.0 (0) +# LAST RELEASED: 14.35.0 (30) # (The number in parenthesis is LIBZYPP_COMPATMINOR) #======= diff --git a/libzypp/cmake/modules/FindCurl.cmake b/libzypp/cmake/modules/FindCurl.cmake deleted file mode 100644 index 8576ddb..0000000 --- a/libzypp/cmake/modules/FindCurl.cmake +++ /dev/null @@ -1,28 +0,0 @@ - -if(CURL_INCLUDE_DIR AND CURL_LIBRARY) - # Already in cache, be silent - set(CURL_FIND_QUIETLY TRUE) -endif(CURL_INCLUDE_DIR AND CURL_LIBRARY) - -set(CURL_LIBRARY) -set(CURL_INCLUDE_DIR) - -FIND_PATH(CURL_INCLUDE_DIR curl/curl.h - /usr/include - /usr/local/include -) - -FIND_LIBRARY(CURL_LIBRARY NAMES curl - PATHS - /usr/lib - /usr/local/lib -) - -if(CURL_INCLUDE_DIR AND CURL_LIBRARY) - MESSAGE( STATUS "curl found: includes in ${CURL_INCLUDE_DIR}, library in ${CURL_LIBRARY}") - set(CURL_FOUND TRUE) -else(CURL_INCLUDE_DIR AND CURL_LIBRARY) - MESSAGE( STATUS "curl not found") -endif(CURL_INCLUDE_DIR AND CURL_LIBRARY) - -MARK_AS_ADVANCED(CURL_INCLUDE_DIR CURL_LIBRARY) \ No newline at end of file diff --git a/libzypp/cmake/modules/FindGettext.cmake b/libzypp/cmake/modules/FindGettext.cmake index a539dd2..a6bf9d1 100644 --- a/libzypp/cmake/modules/FindGettext.cmake +++ b/libzypp/cmake/modules/FindGettext.cmake @@ -49,6 +49,8 @@ MACRO( GETTEXT_CREATE_TARBALL_TRANSLATIONS _translation_set_basename ) ADD_CUSTOM_COMMAND( OUTPUT ${TRANSLATION_SET_CONTENT} COMMAND tar xfj ${CMAKE_CURRENT_SOURCE_DIR}/${TRANSLATION_SET} + COMMAND sed -i '/^msgid/s/do not forbid installation of %s/remove lock to allow installation of %s/' *.po + COMMAND sed -i '/^msgid/s/do not keep %s installed/remove lock to allow removal of %s/' *.po DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${TRANSLATION_SET} ) diff --git a/libzypp/cmake/modules/FindLibxml.cmake b/libzypp/cmake/modules/FindLibxml.cmake deleted file mode 100644 index cb2ae2a..0000000 --- a/libzypp/cmake/modules/FindLibxml.cmake +++ /dev/null @@ -1,29 +0,0 @@ - -if(LIBXML_INCLUDE_DIR AND LIBXML_LIBRARY) - # Already in cache, be silent - set(LIBXML_FIND_QUIETLY TRUE) -endif(LIBXML_INCLUDE_DIR AND LIBXML_LIBRARY) - -set(LIBXML_LIBRARY) -set(LIBXML_INCLUDE_DIR) - -FIND_PATH(LIBXML_INCLUDE_DIR libxml/parser.h - /usr/include - /usr/include/libxml2 - /usr/local/include -) - -FIND_LIBRARY(LIBXML_LIBRARY NAMES xml2 - PATHS - /usr/lib - /usr/local/lib -) - -if(LIBXML_INCLUDE_DIR AND LIBXML_LIBRARY) - MESSAGE( STATUS "libxml found: includes in ${LIBXML_INCLUDE_DIR}, library in ${LIBXML_LIBRARY}") - set(LIBXML_FOUND TRUE) -else(LIBXML_INCLUDE_DIR AND LIBXML_LIBRARY) - MESSAGE( STATUS "libxml not found") -endif(LIBXML_INCLUDE_DIR AND LIBXML_LIBRARY) - -MARK_AS_ADVANCED(LIBXML_INCLUDE_DIR LIBXML_LIBRARY) \ No newline at end of file diff --git a/libzypp/cmake/modules/ZyppCommon.cmake b/libzypp/cmake/modules/ZyppCommon.cmake index 4c33e07..8b3ec77 100644 --- a/libzypp/cmake/modules/ZyppCommon.cmake +++ b/libzypp/cmake/modules/ZyppCommon.cmake @@ -8,6 +8,13 @@ ELSE ( DEFINED LIB ) SET ( LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" ) ENDIF ( DEFINED LIB ) MESSAGE(STATUS "Libraries will be installed in ${LIB_INSTALL_DIR}" ) +# Headers +IF (DEFINED INCLUDE) + SET (INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${INCLUDE}") +else (DEFINED INCLUDE) + SET (INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include") +ENDIF (DEFINED INCLUDE) +MESSAGE (STATUS "Header files will be installed in ${INCLUDE_INSTALL_DIR}") # system configuration dir (etc) IF( NOT DEFINED SYSCONFDIR ) @@ -117,7 +124,7 @@ MACRO(GENERATE_PACKAGING PACKAGE VERSION) SPECFILE() ADD_CUSTOM_TARGET( svncheck - COMMAND cd $(CMAKE_SOURCE_DIR) && LC_ALL=C git status | grep -q "nothing to commit .working directory clean." + COMMAND cd ${CMAKE_SOURCE_DIR} && LC_ALL=C git status | grep -q "nothing to commit .working directory clean." ) SET( AUTOBUILD_COMMAND diff --git a/libzypp/devel/CMakeLists.txt b/libzypp/devel/CMakeLists.txt index aecaaa8..3f9d5db 100644 --- a/libzypp/devel/CMakeLists.txt +++ b/libzypp/devel/CMakeLists.txt @@ -4,4 +4,3 @@ CONFIGURE_FILE(${LIBZYPP_SOURCE_DIR}/devel/genclass.in ${LIBZYPP_BINARY_DIR}/dev ADD_SUBDIRECTORY(devel.dmacvicar) ADD_SUBDIRECTORY(devel.ma) -ADD_SUBDIRECTORY(devel.jkupec) diff --git a/libzypp/devel/devel.jkupec/CMakeLists.txt b/libzypp/devel/devel.jkupec/CMakeLists.txt deleted file mode 100644 index b326079..0000000 --- a/libzypp/devel/devel.jkupec/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -ADD_DEFINITIONS( - -DSRC_DIR="${CMAKE_CURRENT_SOURCE_DIR}" - -DTESTS_SRC_DIR="${LIBZYPP_SOURCE_DIR}/tests" -) - -SET( bridge_SRCS - bridge/bridge.cc - bridge/BaseImpl.cc - bridge/Derived.cc -) - -SET( bridge_HEADERS - bridge/Base.h - bridge/BaseImpl.h - bridge/Derived.h -) - -#ADD_EXECUTABLE( bridge ${bridge_SRCS} ) -#TARGET_LINK_LIBRARIES( bridge zypp ) - -#ADD_EXECUTABLE( deltarpm deltarpm.cc ) -#TARGET_LINK_LIBRARIES( deltarpm zypp ) - -#ADD_EXECUTABLE( pathinfo pathinfo.cc ) -#TARGET_LINK_LIBRARIES( pathinfo zypp ) - -ADD_EXECUTABLE( poolquery poolquery.cc ) -TARGET_LINK_LIBRARIES( poolquery zypp ) - -ADD_EXECUTABLE( repos repos.cc ) -TARGET_LINK_LIBRARIES( repos zypp ) - -#ADD_EXECUTABLE( yumparsertest YUMParser_test.cc ) -#TARGET_LINK_LIBRARIES( yumparsertest zypp ) - -ADD_EXECUTABLE( play play.cc ) -TARGET_LINK_LIBRARIES( play zypp boost_signals ) diff --git a/libzypp/devel/devel.jkupec/YUMParser_test.cc b/libzypp/devel/devel.jkupec/YUMParser_test.cc deleted file mode 100644 index 73df2dc..0000000 --- a/libzypp/devel/devel.jkupec/YUMParser_test.cc +++ /dev/null @@ -1,64 +0,0 @@ -#include "zypp/ZYpp.h" -#include "zypp/ZYppFactory.h" -#include "zypp/base/Logger.h" -#include "zypp/base/LogControl.h" -#include "zypp/base/Measure.h" -#include "zypp/cache/CacheStore.h" -#include "zypp/parser/yum/RepoParser.h" - -#undef ZYPP_BASE_LOGGER_LOGGROUP -#define ZYPP_BASE_LOGGER_LOGGROUP "yumparsertest" - -using namespace std; -using namespace zypp; -using namespace zypp::parser::yum; -using zypp::debug::Measure; - -bool progress_function(ProgressData::value_type p) -{ - cout << "Parsing YUM source [" << p << "%]" << endl; -// cout << "\rParsing YUM source [" << p << "%]" << flush; - return true; -} - -int main(int argc, char **argv) -{ - base::LogControl::instance().logfile("yumparsertest.log"); - - if (argc < 2) - { - cout << "usage: yumparsertest path/to/yumsourcedir" << endl << endl; - return 1; - } - - try - { - ZYpp::Ptr z = getZYpp(); - - Measure open_repository_timer("CacheStore: lookupOrAppendRepository"); - - cache::CacheStore store(getenv("PWD")); - data::RecordId repository_id = store.lookupOrAppendRepository("somealias"); - - open_repository_timer.stop(); - - MIL << "creating PrimaryFileParser" << endl; - Measure parse_primary_timer("primary.xml.gz parsing"); - - parser::yum::RepoParser parser( repository_id, store, &progress_function); - parser.parse(argv[1]); - - store.commit(); - parse_primary_timer.stop(); - - cout << endl; - } - catch ( const Exception &e ) - { - cout << "Oops! " << e.msg() << std::endl; - } - - return 0; -} - -// vim: set ts=2 sts=2 sw=2 et ai: diff --git a/libzypp/devel/devel.jkupec/bridge/Base.h b/libzypp/devel/devel.jkupec/bridge/Base.h deleted file mode 100644 index 8f04e5f..0000000 --- a/libzypp/devel/devel.jkupec/bridge/Base.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef JK_BASE_H_ -#define JK_BASE_H_ - -#include "zypp/base/NonCopyable.h" - -namespace jk -{ - - - class Base : private zypp::base::NonCopyable - { - protected: - class BaseImpl; - }; - - -} // ns jk - - -#endif /*JK_BASE_H_*/ - -// vim: set ts=2 sts=2 sw=2 et ai: - diff --git a/libzypp/devel/devel.jkupec/bridge/BaseImpl.cc b/libzypp/devel/devel.jkupec/bridge/BaseImpl.cc deleted file mode 100644 index 2bbf7a9..0000000 --- a/libzypp/devel/devel.jkupec/bridge/BaseImpl.cc +++ /dev/null @@ -1,16 +0,0 @@ -#include "BaseImpl.h" - -using namespace std; - -namespace jk -{ - - - Base::BaseImpl::BaseImpl() - {} - - -} // ns zypp - -// vim: set ts=2 sts=2 sw=2 et ai: - diff --git a/libzypp/devel/devel.jkupec/bridge/BaseImpl.h b/libzypp/devel/devel.jkupec/bridge/BaseImpl.h deleted file mode 100644 index 4f6252b..0000000 --- a/libzypp/devel/devel.jkupec/bridge/BaseImpl.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef JK_BASEIMPL_H_ -#define JK_BASEIMPL_H_ - -#include "zypp/base/NonCopyable.h" -#include "Base.h" - -namespace jk -{ - - - class Base::BaseImpl : private zypp::base::NonCopyable - { - public: - BaseImpl(); - }; - - -} // ns jk - -#endif /*JK_BASEIMPL_H_*/ - -// vim: set ts=2 sts=2 sw=2 et ai: - diff --git a/libzypp/devel/devel.jkupec/bridge/Derived.cc b/libzypp/devel/devel.jkupec/bridge/Derived.cc deleted file mode 100644 index cc35d30..0000000 --- a/libzypp/devel/devel.jkupec/bridge/Derived.cc +++ /dev/null @@ -1,28 +0,0 @@ -#include "BaseImpl.h" -#include "Derived.h" - -namespace jk -{ - - - class Derived::Impl : public BaseImpl - { - public: - Impl(); - }; - - Derived::Impl::Impl() - {} - - - Derived::Derived() : _pimpl(new Impl()) - {} - - Derived::~Derived() - {} - - -} // ns jk - -// vim: set ts=2 sts=2 sw=2 et ai: - diff --git a/libzypp/devel/devel.jkupec/bridge/Derived.h b/libzypp/devel/devel.jkupec/bridge/Derived.h deleted file mode 100644 index 5efd9a4..0000000 --- a/libzypp/devel/devel.jkupec/bridge/Derived.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef JK_DERIVED_H_ -#define JK_DERIVED_H_ - -#include "zypp/base/PtrTypes.h" -#include "Base.h" - -namespace jk -{ - - - class Derived : public Base - { - public: - Derived(); - ~Derived(); - - private: - class Impl; - zypp::RW_pointer > _pimpl; - }; - - - -} // ns jk - -#endif /*JK_DERIVED_H_*/ diff --git a/libzypp/devel/devel.jkupec/bridge/bridge.cc b/libzypp/devel/devel.jkupec/bridge/bridge.cc deleted file mode 100644 index 6ed712e..0000000 --- a/libzypp/devel/devel.jkupec/bridge/bridge.cc +++ /dev/null @@ -1,26 +0,0 @@ -#include - -#include "zypp/base/Exception.h" - -#include "Derived.h" - - -using namespace std; -using namespace jk; -using namespace zypp; - -int main(int argc, char **argv) -{ - try - { - Derived d; - } - catch ( const Exception &e ) - { - cout << "Oops! " << e.msg() << std::endl; - } - - return 0; -} - -// vim: set ts=2 sts=2 sw=2 et ai: diff --git a/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/deltainfo.xml b/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/deltainfo.xml deleted file mode 100644 index 2909d1b..0000000 --- a/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/deltainfo.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - DRPMS/libzypp-4.21.3-1_4.21.3-2.i386.drpm - libzypp-4.21.3-1-d3571f98b048b1a870e40241bb46c67ab4 - 22452 - 8f05394695dee9399c204614e21e5f6848990ab7 - - - DRPMS/libzypp-4.21.2-3_4.21.3-2.i386.drpm - libzypp-4.21.2-3-e82691677eee1e83b4812572c5c9ce8eb - 110362 - 326658fee45c0baec1e70231046dbaf560f941ce - - - - diff --git a/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/primary.xml.gz b/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/primary.xml.gz deleted file mode 100644 index b41606a..0000000 Binary files a/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/primary.xml.gz and /dev/null differ diff --git a/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/repomd.xml b/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/repomd.xml deleted file mode 100644 index 48a0a5c..0000000 --- a/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/repomd.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - d41033826a12ce44a1b33eff2e7905785e0999da - 1211014822 - 319b2951aad2417c8961442ba692d4700962043b - - - - 4f8f83525b232db93a761ed1be79515956b574cf - 1211014822 - 70eb95f379e0db1c9815f0a1cb2269d93e408015 - - - - 28a6aae0cd873e1df286d4a07fc7e54263fec79d - 1211014821 - 5ad445e403218ef4a6585dbfc37ccf31d5a10096 - - - - 553f609c610b0cf51b54efc4c5c618537707ac8d - 1211014821 - 8c840e0b03ad8c2ed0d4ddf57f9a6b5cea3ac412 - - - - cb4c1c8b35d3c486dde918de72a4e630434e5b40 - 1210522397 - cb4c1c8b35d3c486dde918de72a4e630434e5b40 - - diff --git a/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/repomd.xml.asc b/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/repomd.xml.asc deleted file mode 100644 index 209ad5c..0000000 --- a/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/repomd.xml.asc +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN PGP SIGNATURE----- -Version: GnuPG v1.0.7 (GNU/Linux) - -iD8DBQBILp6nqE7a6JyACsoRApMoAKCSmiVFYUOGXhWikMAKRrh0Lp0jaQCf -YN82OkmNZJRvtpBFUs/R5iCx7CU= -=BuV4 ------END PGP SIGNATURE----- diff --git a/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/updateinfo.xml.gz b/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/updateinfo.xml.gz deleted file mode 100644 index 28061e0..0000000 Binary files a/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/updateinfo.xml.gz and /dev/null differ diff --git a/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/deltainfo.xml b/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/deltainfo.xml deleted file mode 100644 index 2909d1b..0000000 --- a/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/deltainfo.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - DRPMS/libzypp-4.21.3-1_4.21.3-2.i386.drpm - libzypp-4.21.3-1-d3571f98b048b1a870e40241bb46c67ab4 - 22452 - 8f05394695dee9399c204614e21e5f6848990ab7 - - - DRPMS/libzypp-4.21.2-3_4.21.3-2.i386.drpm - libzypp-4.21.2-3-e82691677eee1e83b4812572c5c9ce8eb - 110362 - 326658fee45c0baec1e70231046dbaf560f941ce - - - - diff --git a/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/primary.xml.gz b/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/primary.xml.gz deleted file mode 100644 index b41606a..0000000 Binary files a/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/primary.xml.gz and /dev/null differ diff --git a/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/repomd.xml b/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/repomd.xml deleted file mode 100644 index 48a0a5c..0000000 --- a/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/repomd.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - d41033826a12ce44a1b33eff2e7905785e0999da - 1211014822 - 319b2951aad2417c8961442ba692d4700962043b - - - - 4f8f83525b232db93a761ed1be79515956b574cf - 1211014822 - 70eb95f379e0db1c9815f0a1cb2269d93e408015 - - - - 28a6aae0cd873e1df286d4a07fc7e54263fec79d - 1211014821 - 5ad445e403218ef4a6585dbfc37ccf31d5a10096 - - - - 553f609c610b0cf51b54efc4c5c618537707ac8d - 1211014821 - 8c840e0b03ad8c2ed0d4ddf57f9a6b5cea3ac412 - - - - cb4c1c8b35d3c486dde918de72a4e630434e5b40 - 1210522397 - cb4c1c8b35d3c486dde918de72a4e630434e5b40 - - diff --git a/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/repomd.xml.asc b/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/repomd.xml.asc deleted file mode 100644 index 209ad5c..0000000 --- a/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/repomd.xml.asc +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN PGP SIGNATURE----- -Version: GnuPG v1.0.7 (GNU/Linux) - -iD8DBQBILp6nqE7a6JyACsoRApMoAKCSmiVFYUOGXhWikMAKRrh0Lp0jaQCf -YN82OkmNZJRvtpBFUs/R5iCx7CU= -=BuV4 ------END PGP SIGNATURE----- diff --git a/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/repomd.xml.key b/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/repomd.xml.key deleted file mode 100644 index 91c316f..0000000 --- a/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/repomd.xml.key +++ /dev/null @@ -1,37 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1.4.0 (GNU/Linux) - -mQGiBDnu9IERBACT8Y35+2vv4MGVKiLEMOl9GdST6MCkYS3yEKeueNWc+z/0Kvff -4JctBsgs47tjmiI9sl0eHjm3gTR8rItXMN6sJEUHWzDP+Y0PFPboMvKx0FXl/A0d -M+HFrruCgBlWt6FA+okRySQiliuI5phwqkXefl9AhkwR8xocQSVCFxcwvwCglVcO -QliHu8jwRQHxlRE0tkwQQI0D+wfQwKdvhDplxHJ5nf7U8c/yE/vdvpN6lF0tmFrK -XBUX+K7u4ifrZlQvj/81M4INjtXreqDiJtr99Rs6xa0ScZqITuZC4CWxJa9GynBE -D3+D2t1V/f8l0smsuYoFOF7Ib49IkTdbtwAThlZp8bEhELBeGaPdNCcmfZ66rKUd -G5sRA/9ovnc1krSQF2+sqB9/o7w5/q2qiyzwOSTnkjtBUVKn4zLUOf6aeBAoV6NM -CC3Kj9aZHfA+ND0ehPaVGJgjaVNFhPi4x0e7BULdvgOoAqajLfvkURHAeSsxXIoE -myW/xC1sBbDkDUIBSx5oej73XCZgnj/inphRqGpsb+1nKFvF+rQoU3VTRSBQYWNr -YWdlIFNpZ25pbmcgS2V5IDxidWlsZEBzdXNlLmRlPohiBBMRAgAiBQJA2AY+AhsD -BQkObd+9BAsHAwIDFQIDAxYCAQIeAQIXgAAKCRCoTtronIAKypCfAJ9RuZ6ZSV7Q -W4pTgTIxQ+ABPp0sIwCffG9bCNnrETPlgOn+dGEkAWegKL+IRgQQEQIABgUCOnBe -UgAKCRCeQOMQAAqrpNzOAKCL512FZvv4VZx94TpbA9lxyoAejACeOO1HIbActAev -k5MUBhNeLZa/qM2JARUDBRA6cGBvd7LmAD0l09kBATWnB/9An5vfiUUE1VQnt+T/ -EYklES3tXXaJJp9pHMa4fzFa8jPVtv5UBHGee3XoUNDVwM2OgSEISZxbzdXGnqIl -cT08TzBUD9i579uifklLsnr35SJDZ6ram51/CWOnnaVhUzneOA9gTPSr+/fT3WeV -nwJiQCQ30kNLWVXWATMnsnT486eAOlT6UNBPYQLpUprF5Yryk23pQUPAgJENDEqe -U6iIO9Ot1ZPtB0lniw+/xCi13D360o1tZDYOp0hHHJN3D3EN8C1yPqZd5CvvznYv -B6bWBIpWcRgdn2DUVMmpU661jwqGlRz1F84JG/xe4jGuzgpJt9IXSzyohEJB6XG5 -+D0BuQINBDnu9JIQCACEkdBN6Mxf5WvqDWkcMRy6wnrd9DYJ8UUTmIT2iQf07tRU -KJJ9v0JXfx2Z4d08IQSMNRaq4VgSe+PdYgIy0fbj23Via5/gO7fJEpD2hd2f+pMn -OWvH2rOOIbeYfuhzAc6BQjAKtmgR0ERUTafTM9Wb6F13CNZZNZfDqnFDP6L12w3z -3F7FFXkz07Rs3AIto1ZfYZd4sCSpMr/0S5nLrHbIvGLp271hhQBeRmmoGEKO2JRe -lGgUJ2CUzOdtwDIKT0LbCpvaP8PVnYF5IFoYJIWRHqlEt5ucTXstZy7vYjL6vTP4 -l5xs+LIOkNmPhqmfsgLzVo0UaLt80hOwc4NvDCOLAAMGB/9g+9V3ORzw4LvO1pwR -YJqfDKUq/EJ0rNMMD4N8RLpZRhKHKJUm9nNHLbksnlZwrbSTM5LpC/U6sheLP+l0 -bLVoq0lmsCcUSyh+mY6PxWirLIWCn/IAZAGnXb6Zd6TtIJlGG6pqUN8QxGJYQnon -l0uTJKHJENbI9sWHQdcTtBMc34gorHFCo1Bcvpnc1LFLrWn7mfoGx6INQjf3HGQp -MXAWuSBQhzkazY6vaWFpa8bBJ+gKbBuySWzNm3rFtT5HRKMWpO+M9bHp4d+puY0L -1YwN1OMatcMMpcWnZpiWiR83oi32+xtWUY2U7Ae38mMag8zFbpeqPQUsDv9V7CAJ -1dbriEwEGBECAAwFAkDYBnoFCQ5t3+gACgkQqE7a6JyACspnpgCfRbYwxT3iq+9l -/PgNTUNTZOlof2oAn25y0eGi0371jap9kOV6uq71sUuO -=pJli ------END PGP PUBLIC KEY BLOCK----- diff --git a/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/updateinfo.xml.gz b/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/updateinfo.xml.gz deleted file mode 100644 index 28061e0..0000000 Binary files a/libzypp/devel/devel.jkupec/data/deltarpm/updates2/repodata/updateinfo.xml.gz and /dev/null differ diff --git a/libzypp/devel/devel.jkupec/data/pathinfo/afile b/libzypp/devel/devel.jkupec/data/pathinfo/afile deleted file mode 100644 index aeef426..0000000 --- a/libzypp/devel/devel.jkupec/data/pathinfo/afile +++ /dev/null @@ -1 +0,0 @@ -a file \ No newline at end of file diff --git a/libzypp/devel/devel.jkupec/data/pathinfo/alink b/libzypp/devel/devel.jkupec/data/pathinfo/alink deleted file mode 120000 index 6a93f4f..0000000 --- a/libzypp/devel/devel.jkupec/data/pathinfo/alink +++ /dev/null @@ -1 +0,0 @@ -afile \ No newline at end of file diff --git a/libzypp/devel/devel.jkupec/data/pathinfo/subdir/anotherfile b/libzypp/devel/devel.jkupec/data/pathinfo/subdir/anotherfile deleted file mode 100644 index cdcb284..0000000 --- a/libzypp/devel/devel.jkupec/data/pathinfo/subdir/anotherfile +++ /dev/null @@ -1 +0,0 @@ -another file \ No newline at end of file diff --git a/libzypp/devel/devel.jkupec/data/pathinfo/subdirlink b/libzypp/devel/devel.jkupec/data/pathinfo/subdirlink deleted file mode 120000 index f57a792..0000000 --- a/libzypp/devel/devel.jkupec/data/pathinfo/subdirlink +++ /dev/null @@ -1 +0,0 @@ -subdir/anotherfile \ No newline at end of file diff --git a/libzypp/devel/devel.jkupec/dbqueries.sql b/libzypp/devel/devel.jkupec/dbqueries.sql deleted file mode 100644 index 9c84132..0000000 --- a/libzypp/devel/devel.jkupec/dbqueries.sql +++ /dev/null @@ -1,54 +0,0 @@ --- what kinds of resolvables have been read? -select * from types where class = 'kind'; - --- what languages have been encountered? -select * from types where class = 'lang'; - --- what architectures have been read? -select * from types where class = 'arch'; - --- what types of dependencies have been encountered? -select * from types where class = 'deptype'; - --- ---------------------------------------------------------------------------- - --- how many packages have been read? -select count(*) from resolvables r, types t where t.class = 'kind' and t.name = 'package' and t.id = r.kind; - --- print resolvable kind -> count table -select t.name, count(*) from resolvables r, types t where t.class = 'kind' and t.id = r.kind group by t.name; - --- what patches have been read? print id, name, and version -select r.id, r.name, r.version from resolvables r, types t where t.class = 'kind' and t.name = 'patch' and t.id = r.kind; - --- ---------------------------------------------------------------------------- - --- print all text and numeric attributes of resolvable with id = 2 -select a.weak_resolvable_id "res-id", t.class "attr-class", t.name "attr-name", a.text "value" - from text_attributes a, types t - where t.id = a.attr_id and a.weak_resolvable_id = 2 -union -select a.weak_resolvable_id "res-id", t.class "attr-class", t.name "attr-name", a.value "value" - from numeric_attributes a, types t - where t.id = a.attr_id and a.weak_resolvable_id = 2 -order by t.class - --- print all named dependencies of resolvable with id = 2 -select dt.name "dtype", kt.name "kind", n.name "name", rt.name "rel", c.version "version" - from named_capabilities c, types dt, types kt, types rt, names n - where c.dependency_type = dt.id - and c.refers_kind= kt.id - and c.relation = rt.id - and c.name_id = n.id - and c.resolvable_id = 2; - --- print all file dependencies of resolvable with id = 2 -select dt.name "dtype", kt.name "kind", (dname.name || '/' || fname.name) "file" - from file_capabilities c, types dt, types kt, files f - left outer join file_names fname on fname.id = f.file_name_id - left outer join dir_names dname on dname.id = f.dir_name_id - where c.dependency_type = dt.id - and c.refers_kind= kt.id - and c.file_id = f.id - and c.resolvable_id = 2; - diff --git a/libzypp/devel/devel.jkupec/deltarpm.cc b/libzypp/devel/devel.jkupec/deltarpm.cc deleted file mode 100644 index 33a317f..0000000 --- a/libzypp/devel/devel.jkupec/deltarpm.cc +++ /dev/null @@ -1,179 +0,0 @@ -#include -#include -#include -#include - -extern "C" -{ -#include -} - -#include "zypp/ZYppFactory.h" -#include "zypp/Pathname.h" - -#include "zypp/RepoManager.h" -#include "zypp/repo/DeltaCandidates.h" -#include "zypp/PoolQuery.h" - -using std::cout; -using std::endl; -using std::string; -using namespace zypp; - - -struct PrintAndCount -{ - PrintAndCount() : _count(0) {} - - bool operator()( const sat::Solvable & solvable ) - { - zypp::PoolItem pi( zypp::ResPool::instance().find( solvable ) ); - cout << pi.resolvable() << endl; - // name: yast2-sound 2.16.2-9 i586 - ++_count; - return true; - } - - unsigned _count; -}; - - - -int main (int argc, const char ** argv) -{ - Pathname rootdir(SRC_DIR "/data/deltarpm"); - RepoManagerOptions opts(rootdir); - opts.repoRawCachePath = rootdir; - opts.repoSolvCachePath = rootdir; - RepoManager rm(opts); - - RepoInfo updates; - updates.setAlias("updates"); - updates.addBaseUrl(Url(string("dir:") + rootdir.absolutename().asString() + "/updates")); - - RepoInfo updates2; - updates2.setAlias("updates2"); - updates2.addBaseUrl(Url(string("dir:") + rootdir.absolutename().asString() + "/updates2")); - - try - { - rm.buildCache(updates); - rm.buildCache(updates2); - rm.loadFromCache(updates); - rm.loadFromCache(updates2); - } - catch (const Exception & e) - { - cout << "Problem getting the data: " << e.msg() << endl; - } - - sat::Pool pool(sat::Pool::instance()); - for_(repoit, pool.reposBegin(), pool.reposEnd()) - { - Repository repo(*repoit); - for (int i = 0; i < repo.get()->nextra; ++i) - { - cout << endl << "extra " << i << ":" << endl; - ::Dataiterator di; - ::dataiterator_init(&di, repo.get(), -1 - i, 0, 0, SEARCH_EXTRA | SEARCH_NO_STORAGE_SOLVABLE); - while (::dataiterator_step(&di)) - { - const char * keyname; - keyname = ::id2str(repo.get()->pool, di.key->name); - - cout << keyname << ": "; - - switch (di.key->name) - { - case DELTA_PACKAGE_NAME: - { - cout << IdString(di.kv.id); - break; - } - case DELTA_PACKAGE_EVR: - { - cout << IdString(di.kv.id); - break; - } - case DELTA_PACKAGE_ARCH: - { - cout << IdString(di.kv.id); - break; - } - case DELTA_LOCATION_DIR: - { - cout << IdString(di.kv.id); - break; - } - case DELTA_LOCATION_NAME: - { - cout << IdString(di.kv.id); - break; - } - case DELTA_LOCATION_EVR: - { - cout << IdString(di.kv.id); - break; - } - case DELTA_LOCATION_SUFFIX: - { - cout << IdString(di.kv.id); - break; - } - case DELTA_DOWNLOADSIZE: - { - cout << di.kv.num; - break; - } - case DELTA_CHECKSUM: - { - cout << di.kv.str; - break; - } - case DELTA_BASE_EVR: - { - cout << IdString(di.kv.id); - break; - } - case DELTA_SEQ_NAME: - { - cout << IdString(di.kv.id); - break; - } - case DELTA_SEQ_EVR: - { - cout << IdString(di.kv.id); - break; - } - case DELTA_SEQ_NUM: - { - cout << di.kv.str; - break; - } - default: - cout << "ingoring " << IdString(di.key->name) << endl; - } - cout << endl; - } - } - } - - PoolQuery q; - q.addKind(ResKind::package); - q.addAttribute(sat::SolvAttr::name, "libzypp"); - q.setMatchExact(); - - std::for_each(q.begin(), q.end(), PrintAndCount()); - - PoolItem pi(*q.poolItemBegin()); - if (pi) - { - Package::constPtr p = asKind(pi.resolvable()); - - std::list repos( pool.reposBegin(), pool.reposEnd() ); - repo::DeltaCandidates deltas(repos, p->name()); - deltas.deltaRpms(p); - } - else - cout << "no such package" << endl; -} diff --git a/libzypp/devel/devel.jkupec/pathinfo.cc b/libzypp/devel/devel.jkupec/pathinfo.cc deleted file mode 100644 index 40b97b5..0000000 --- a/libzypp/devel/devel.jkupec/pathinfo.cc +++ /dev/null @@ -1,29 +0,0 @@ -#include - -#include "zypp/Pathname.h" -#include "zypp/PathInfo.h" - -using std::cout; -using std::endl; -using std::string; -using namespace zypp; - -int main (int argc, const char ** argv) -{ - Pathname datadir(SRC_DIR "/data/pathinfo"); - Pathname alink = datadir / "alink"; - PathInfo alinkinfo(alink); - - cout << "alink exists: " << alinkinfo.isExist() << endl; - Pathname alinkExp = filesystem::expandlink(alink); - cout << "alink expands to: " << alinkExp << endl; - cout << "alinkExp exists: " << PathInfo(alinkExp).isExist() << endl; - - Pathname subdirlink = datadir / "subdirlink"; - PathInfo subdirlinkinfo(subdirlink); - - cout << "subdirlink exists: " << subdirlinkinfo.isExist() << endl; - Pathname subdirlinkExp = filesystem::expandlink(subdirlink); - cout << "subdirlink expands to: " << subdirlinkExp << endl; - cout << "subdirlinkExp exists: " << PathInfo(subdirlinkExp).isExist() << endl; -} diff --git a/libzypp/devel/devel.jkupec/play.cc b/libzypp/devel/devel.jkupec/play.cc deleted file mode 100644 index 5133d74..0000000 --- a/libzypp/devel/devel.jkupec/play.cc +++ /dev/null @@ -1,56 +0,0 @@ -#include - -#include "zypp/base/LogTools.h" -#include "zypp/ZYppCallbacks.h" - -#include "zypp/parser/HistoryLogReader.h" -#include "zypp/parser/ParseException.h" - -using std::endl; -using std::cout; -using namespace zypp; - -bool progress_function(const ProgressData & p) -{ - cout << "."; - return true; -} - -struct HistoryItemCollector -{ - std::vector items; - - bool operator()( const HistoryItem::Ptr & item_ptr ) - { - items.push_back(item_ptr); - //cout << *item_ptr << endl; - return true; - } -}; - -// --------------------------------------------------------------------------- - -int main( int argc, const char * argv[] ) -{ - --argc; ++argv; // skip arg 0 - - HistoryItemCollector ic; - parser::HistoryLogReader reader(*argv, boost::ref(ic)); - reader.setIgnoreInvalidItems(true); - ProgressReportReceiver progress; - progress.connect(); - try - { - //reader.readAll(&progress_function); - reader.readFromTo(Date("2009-01-01", "%Y-%m-%d"), Date("2009-01-02", "%Y-%m-%d")); - } - catch (const parser::ParseException & e) - { - cout << "error in " << *argv << ":" << endl; - cout << e.asUserHistory() << endl; - } - progress.disconnect(); - - cout << "got " << ic.items.size() << endl; - return 0; -} diff --git a/libzypp/devel/devel.jkupec/poolquery.cc b/libzypp/devel/devel.jkupec/poolquery.cc deleted file mode 100644 index e471807..0000000 --- a/libzypp/devel/devel.jkupec/poolquery.cc +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include -#include -#include - -#include "zypp/ZYppFactory.h" -#include "zypp/PoolQuery.h" -#include "zypp/PoolQueryUtil.tcc" -#include "zypp/RepoInfo.h" -#include "zypp/Arch.h" -#include "zypp/Pathname.h" -#include "zypp/base/Regex.h" - -using std::cout; -using std::endl; -using std::string; -using namespace zypp; - - -bool result_cb( const sat::Solvable & solvable ) -{ - zypp::PoolItem pi( zypp::ResPool::instance().find( solvable ) ); - cout << pi.resolvable() << endl; - // name: yast2-sound 2.16.2-9 i586 - return true; -} - - -static void init_pool() -{ - Pathname dir(TESTS_SRC_DIR); - dir += "/zypp/data/PoolQuery"; - - ZYpp::Ptr z = getZYpp(); - ZConfig::instance().setSystemArchitecture(Arch("i586")); - - RepoInfo i1; i1.setAlias("factory"); - sat::Pool::instance().addRepoSolv(dir / "factory.solv", i1); - RepoInfo i2; i2.setAlias("factory-nonoss"); - sat::Pool::instance().addRepoSolv(dir / "factory-nonoss.solv", i2); - RepoInfo i3; i3.setAlias("zypp_svn"); - sat::Pool::instance().addRepoSolv(dir / "zypp_svn.solv", i3); - RepoInfo i5; i5.setAlias("pyton"); - sat::Pool::instance().addRepoSolv(dir / "python.solv", i5); - RepoInfo i4; i4.setAlias("@System"); - sat::Pool::instance().addRepoSolv(dir / "@System.solv", i4); -} - - -int main (int argc, const char ** argv) -{ - // ./poolquery regex string - if (argc == 3) - { - str::regex regex(argv[1], REG_EXTENDED | REG_NOSUB | REG_NEWLINE | REG_ICASE); - cout << (str::regex_match(argv[2], regex) ? "" : "no") << "match" << endl; - } - - init_pool(); - - PoolQuery q; - q.addAttribute(sat::SolvAttr::name, "cjson"); - - /* - PoolQuery q; - q.addString("weather"); - q.addAttribute(sat::SolvAttr::name, "thunder"); - q.addAttribute(sat::SolvAttr::description, "storm"); - q.addKind(ResKind::package); - q.addRepo("factory"); -*/ - std::for_each(q.begin(), q.end(), &result_cb); -// cout << q.size() << endl; -// cout << q << endl; - cout << "=====" << endl; - for_(it, q.selectableBegin(), q.selectableEnd()) - cout << *it << endl; -} diff --git a/libzypp/devel/devel.jkupec/repos.cc b/libzypp/devel/devel.jkupec/repos.cc deleted file mode 100755 index 125f8cd..0000000 --- a/libzypp/devel/devel.jkupec/repos.cc +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include -#include -#include - -#include "zypp/ZYppFactory.h" -#include "zypp/RepoInfo.h" -#include "zypp/Arch.h" -#include "zypp/Pathname.h" -#include "zypp/RepoManager.h" - -using std::cout; -using std::endl; -using std::string; -using namespace zypp; - - -bool result_cb( const sat::Solvable & solvable ) -{ - zypp::PoolItem pi( zypp::ResPool::instance().find( solvable ) ); - cout << pi.resolvable() << endl; - // name: yast2-sound 2.16.2-9 i586 - return true; -} - - -static void init_pool() -{ - Pathname dir(TESTS_SRC_DIR); - dir += "/zypp/data/PoolQuery"; - - ZYpp::Ptr z = getZYpp(); - ZConfig::instance().setSystemArchitecture(Arch("i586")); - - RepoInfo i1; i1.setAlias("factory"); - sat::Pool::instance().addRepoSolv(dir / "factory.solv", i1); - RepoInfo i2; i2.setAlias("factory-nonoss"); - sat::Pool::instance().addRepoSolv(dir / "factory-nonoss.solv", i2); - RepoInfo i3; i3.setAlias("zypp_svn"); - sat::Pool::instance().addRepoSolv(dir / "zypp_svn.solv", i3); - RepoInfo i4; i4.setAlias("@System"); - sat::Pool::instance().addRepoSolv(dir / "@System.solv", i4); -} - - -int main (int argc, const char ** argv) -{ - string _target_root = "/local/jkupec/rr"; - - RepoManagerOptions repo_options(_target_root); - // repo_options.knownReposPath = Pathname(_target_root) + repo_options.knownReposPath; - - RepoManager rm(repo_options); - - for ( RepoManager::RepoConstIterator it = rm.repoBegin(); - it != rm.repoEnd(); ++it ) - { - cout << it->packagesPath() << endl; - } -} diff --git a/libzypp/devel/devel.jkupec/yum/patterns-example.xml b/libzypp/devel/devel.jkupec/yum/patterns-example.xml deleted file mode 100644 index b2364e3..0000000 --- a/libzypp/devel/devel.jkupec/yum/patterns-example.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - example pattern - Just an example pattern - Toto je len príklad patternu - Description of the example pattern - Detailnejší popis patternu - - - Services - Služby - repodata/example-pattern.png - - - - - - funky apps - Just an example of funky pattern - Príklad funky patternu - The best apps - Najsamlepjšie programčoke - - - Desktop Apps - Klientské aplikácie - repodata/funky-apps-pattern.png - - - - - diff --git a/libzypp/devel/devel.jkupec/yum/products-example.xml b/libzypp/devel/devel.jkupec/yum/products-example.xml deleted file mode 100644 index e139050..0000000 --- a/libzypp/devel/devel.jkupec/yum/products-example.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - Novell, Inc. - SLES10-SP1 - - SUSE Linux Enterprise Server 10 SP1 - SLES 10 SP1 - The best server OS so far - Doposiaľ najlepší OS pre servery - - - - - - - - - diff --git a/libzypp/devel/devel.ma/Basic.cc b/libzypp/devel/devel.ma/Basic.cc index d27969d..4002b7e 100644 --- a/libzypp/devel/devel.ma/Basic.cc +++ b/libzypp/devel/devel.ma/Basic.cc @@ -153,32 +153,6 @@ using namespace zypp::ui; USR << __PRETTY_FUNCTION__ << endl; } - // Dowmload patch rpm: - // - path below url reported on start() - // - expected download size (0 if unknown) - // - download is interruptable - virtual void startPatchDownload( const Pathname & /*filename*/, const ByteCount & /*downloadsize*/ ) - { - USR << __PRETTY_FUNCTION__ << endl; - } - - virtual bool progressPatchDownload( int /*value*/ ) - { - USR << __PRETTY_FUNCTION__ << endl; - return true; - } - - virtual void problemPatchDownload( const std::string &/*description*/ ) - { - USR << __PRETTY_FUNCTION__ << endl; - } - - virtual void finishPatchDownload() - { - USR << __PRETTY_FUNCTION__ << endl; - } - - // return false if the download should be aborted right now virtual bool progress(int value, Resolvable::constPtr resolvable_ptr) { diff --git a/libzypp/devel/devel.ma/CleandepsOnRemove.cc b/libzypp/devel/devel.ma/CleandepsOnRemove.cc index 003de04..7a378e6 100644 --- a/libzypp/devel/devel.ma/CleandepsOnRemove.cc +++ b/libzypp/devel/devel.ma/CleandepsOnRemove.cc @@ -3,7 +3,7 @@ #include #include #include -#include "zypp/pool/GetResolvablesToInsDel.h" + #include "zypp/sat/WhatObsoletes.h" #include "zypp/ExternalProgram.h" diff --git a/libzypp/devel/devel.ma/DumpSolv.cc b/libzypp/devel/devel.ma/DumpSolv.cc index 86c3329..ad93024 100644 --- a/libzypp/devel/devel.ma/DumpSolv.cc +++ b/libzypp/devel/devel.ma/DumpSolv.cc @@ -2,7 +2,7 @@ #include #include -#include "zypp/pool/GetResolvablesToInsDel.h" + static std::string appname( __FILE__ ); static TestSetup test; diff --git a/libzypp/devel/devel.ma/Ex.cc b/libzypp/devel/devel.ma/Ex.cc index 97a49b7..915644c 100644 --- a/libzypp/devel/devel.ma/Ex.cc +++ b/libzypp/devel/devel.ma/Ex.cc @@ -18,7 +18,7 @@ #include "zypp/Language.h" #include "zypp/Digest.h" #include "zypp/PackageKeyword.h" -#include "zypp/pool/GetResolvablesToInsDel.h" + #include "zypp/parser/TagParser.h" #include "zypp/parser/susetags/PackagesFileReader.h" diff --git a/libzypp/devel/devel.ma/Iorder.cc b/libzypp/devel/devel.ma/Iorder.cc deleted file mode 100644 index f3eb14f..0000000 --- a/libzypp/devel/devel.ma/Iorder.cc +++ /dev/null @@ -1,475 +0,0 @@ -#include "Tools.h" -#include -#include -#include - -#include "zypp/pool/GetResolvablesToInsDel.h" - -void Dbg( ui::Selectable::Ptr s ) -{ - SEC << dump(s) << endl; - if ( s->installedObj() ) - { - PoolItem pi( s->installedObj() ); - DBG << pi.satSolvable().obsoletes() << endl; - sat::WhatObsoletes obs( pi ); - INT << "WhatObsoletes " << pi << " " << obs << endl; - } - if ( s->candidateObj() ) - { - PoolItem pi( s->candidateObj() ); - DBG << pi.satSolvable().obsoletes() << endl; - sat::WhatObsoletes obs( pi ); - INT << "WhatObsoletes " << pi << " " << obs << endl; - } - -} - -/////////////////////////////////////////////////////////////////// - -static std::string appname( "ToolIorder" ); - -void message( const std::string & msg_r ) -{ - cerr << "*** " << msg_r << endl; -} - -int usage( const std::string & msg_r = std::string(), int exit_r = 100 ) -{ - if ( ! msg_r.empty() ) - { - cerr << endl; - message( msg_r ); - cerr << endl; - } - cerr << "Usage: " << appname << "[OPTIONS] TESTCASE" << endl; - cerr << " Load testcase and analyze install order." << endl; - return exit_r; -} - -/////////////////////////////////////////////////////////////////// - - -bool progressReceiver( const ProgressData & v ) -{ - DBG << "...->" << v << endl; - return true; -} - -/////////////////////////////////////////////////////////////////// - -#define LCStack "IOrder::Stack" -#define LCCache "IOrder::Cache" -#define LCVerbose "IOrder::Verbose" - -struct RunnableCache -{ - typedef std::tr1::unordered_map CacheType; - typedef std::vector AnalyzeStack; - - RunnableCache() - : _ltag( "[0000]" ) - {} - - /** - * Test whether there is a runnable provider for each requirement. - */ - bool isRunnable( const PoolItem & pi ) const - { return isRunnable( pi.satSolvable() ); } - - bool isRunnable( sat::Solvable solv_r ) const - { - SEC << "Runnable? " << solv_r << endl; - if ( _isRunnable( solv_r ) ) - { - MIL << "Runnable: " << solv_r << endl; - return true; - } - ERR << "NotRunnable: " << solv_r << endl; - return false; - } - - /** - * Test whether there is a runnable provider for each pre-requirement. - */ - bool isInstallable( const PoolItem & pi ) const - { return isInstallable( pi.satSolvable() ); } - - bool isInstallable( sat::Solvable solv_r ) const - { - SEC << "Installable? " << solv_r << endl; - tribool & cent( get( solv_r ) ); // if (cached) runnable then also installable. - if ( cent || checkCaps( solv_r.prerequires() ) ) - { - MIL << "Installable: " << solv_r << endl; - return true; - } - ERR << "NotInstallable: " << solv_r << endl; - return false; - } - - /** Clear the cache. */ - void clear() const - { - _cache.clear(); - _stack.clear(); - _ltag = "[0000]"; - _INT(LCCache) << "Cache cleared!" << endl; - } - - private: - /** Internal version without loging for recursive calls. */ - bool _isRunnable( const PoolItem & pi ) const - { return _isRunnable( pi.satSolvable() ); } - - bool _isRunnable( sat::Solvable solv_r ) const - { - tribool & cent( get( solv_r ) ); - if ( indeterminate( cent ) ) - cent = analyze( solv_r ); - return cent; - } - - /** - * Determine whether this solvable is runnable. - */ - bool analyze( sat::Solvable solv_r ) const - { - if ( ! push( solv_r ) ) - { - if ( _stack.back() != solv_r ) - _SEC(LCStack) << _ltag << "** CYCLE: " << solv_r << " " << _stack << endl; - // else it's a self requirement - return true; // assume runnable? - } - _INT(LCStack) << _ltag << "->" << solv_r << " " << _stack << endl; - bool ret = checkCaps( solv_r.requires() ); - _INT(LCStack) << _ltag << "<-" << solv_r << " " << _stack << endl; - if ( ! pop( solv_r ) ) - { - _SEC(LCStack) << "** Stack corrupted! Expect " << solv_r << " " << _stack << endl; - } - return ret; - } - - /** - * For each capability find a runnable provider. - */ - bool checkCaps( Capabilities caps_r ) const - { - for_( it, caps_r.begin(), caps_r.end() ) - { - if ( ! findRunnableProvider( *it ) ) - return false; - } - return true; - } - - /** - * Find a runnable provider of a capability on system. - * - * A runnable package is already installed and all of - * its requirements are met by runnable packages. - */ - bool findRunnableProvider( Capability cap_r ) const - { - _MIL(LCVerbose) << _ltag << " " << cap_r << endl; - sat::WhatProvides prv( cap_r ); - for_( pit, prv.begin(), prv.end() ) - { - if ( ! *pit ) - { - _DBG(LCVerbose) << _ltag << " by system" << endl; - return true; // noSolvable provides: i.e. system provides - } - - PoolItem pi( *pit ); - if ( pi.status().onSystem() ) - { - if ( _isRunnable( pi ) ) - { - _DBG(LCVerbose) << _ltag << " " << pi << endl; - return true; - } - else - { - _WAR(LCVerbose) << _ltag << " " << pi << endl; - } - } - } - ERR << _ltag << " NO runnable provider for " << cap_r << endl; - return false; - } - - private: - /** Push a new solvable to the AnalyzeStack, or return false is already on stack. */ - bool push( sat::Solvable solv_r ) const - { - if ( find( _stack.begin(), _stack.end(), solv_r ) == _stack.end() ) - { - _stack.push_back( solv_r ); - _ltag = str::form( "[%04lu]", _stack.size() ); - return true; - } - // cycle? - return false; - } - - /** Pop solvable from AnalyzeStack (expecting it to be \c solv_r). */ - bool pop( sat::Solvable solv_r ) const - { - if ( _stack.back() == solv_r ) - { - _stack.pop_back(); - _ltag = str::form( "[%04lu]", _stack.size() ); - return true; - } - // stack corrupted? - return false; - } - - /** Return cache entry, initializing new entries with \ref indeterminate.*/ - tribool & get( sat::Solvable solv_r ) const - { - CacheType::iterator it( _cache.find( solv_r ) ); - if ( it == _cache.end() ) - return (_cache[solv_r] = indeterminate); - return _cache[solv_r]; - } - - mutable CacheType _cache; - mutable AnalyzeStack _stack; - mutable std::string _ltag; -}; - -RunnableCache rcache; - -//================================================== - -bool upgrade() -{ - bool rres = false; - { - zypp::base::LogControl::TmpLineWriter shutUp; - rres = getZYpp()->resolver()->doUpgrade(); - } - if ( ! rres ) - { - ERR << "upgrade " << rres << endl; - getZYpp()->resolver()->problems(); - return false; - } - MIL << "upgrade " << rres << endl; - return true; -} - -bool solve() -{ - static unsigned run = 0; - USR << "Solve " << run++ << endl; - bool rres = false; - { - zypp::base::LogControl::TmpLineWriter shutUp; - rres = getZYpp()->resolver()->resolvePool(); - } - if ( ! rres ) - { - ERR << "resolve " << rres << endl; - getZYpp()->resolver()->problems(); - return false; - } - - return true; -} - -void display( const pool::GetResolvablesToInsDel & collect, std::set interested ) -{ - if ( ! interested.empty() ) - { - USR << "======================================================================" << endl; - USR << "=== INTERESTED" << endl; - USR << "======================================================================" << endl; - for_( it, interested.begin(), interested.end() ) - { - MIL << dump(ui::Selectable::get( *it )) << endl; - } - } - - USR << "======================================================================" << endl; - USR << "=== DELETE" << endl; - USR << "======================================================================" << endl; - if ( 1 ) - { - ProgressData tics( collect._toDelete.size() ); - tics.name( "DELETE" ); - tics.sendTo( &progressReceiver ); - tics.toMin(); - - for_( it, collect._toDelete.begin(), collect._toDelete.end() ) - { - tics.incr(); - - it->status().setTransact( true, ResStatus::USER ); -// vdumpPoolStats( SEC << "Transacting:"<< endl, -// make_filter_begin(pool), -// make_filter_end(pool) ) << endl; - - if ( !interested.empty() && interested.find( it->satSolvable().ident() ) == interested.end() ) - { - MIL << "..." << *it << endl; - continue; - } - - rcache.clear(); - if ( ! rcache.isInstallable( *it ) ) - { - USR << "FAILED DEL " << *it << endl; - } - } - } - - USR << "======================================================================" << endl; - USR << "=== INSTALL" << endl; - USR << "======================================================================" << endl; - if ( 1 ) - { - ProgressData tics( collect._toInstall.size() ); - tics.name( "INSTALL" ); - tics.sendTo( progressReceiver ); - tics.toMin(); - - - for_( it, collect._toInstall.begin(), collect._toInstall.end() ) - { - tics.incr(); - - ui::Selectable::Ptr p( ui::Selectable::get( *it ) ); - p->setCandidate( *it ); - p->setToInstall(); // also deletes the installed one -// vdumpPoolStats( SEC << "Transacting:"<< endl, -// make_filter_begin(pool), -// make_filter_end(pool) ) << endl; - - - if ( !interested.empty() && interested.find( p->ident() ) == interested.end() ) - { - MIL << "..." << *it << endl; - continue; - } - - rcache.clear(); - - for_( it, p->installedBegin(), p->installedEnd() ) - { - if ( ! rcache.isInstallable( *it ) ) - { - USR << "FAILED OLD " << *it << endl; - } - } - sat::WhatObsoletes obs( *it ); - for_( it, obs.begin(), obs.end() ) - { - if ( ! rcache.isInstallable( *it ) ) - { - USR << "FAILED OBS " << *it << endl; - } - } - - - if ( ! rcache.isInstallable( *it ) ) - { - USR << "FAILED INS " << *it << endl; - } - } - } -} - -void display( const pool::GetResolvablesToInsDel & collect, IdString ident_r ) -{ - std::set interested; - interested.insert( ident_r ); - display( collect, interested ); -} - - -void display( const pool::GetResolvablesToInsDel & collect ) -{ - std::set interested; - display( collect, interested ); -} - - -/****************************************************************** -** -** FUNCTION NAME : main -** FUNCTION TYPE : int -*/ -int main( int argc, char * argv[] ) -{ - INT << "===[START]==========================================" << endl; - appname = Pathname::basename( argv[0] ); - --argc; - ++argv; - - if ( ! argc ) - { - return usage(); - } - - /////////////////////////////////////////////////////////////////// - - Pathname mtest( "/suse/ma/BUGS/439802/bug439802/YaST2/solverTestcase" ); - Arch march( Arch_ppc64 ); - - while ( argc ) - { - --argc; - ++argv; - } - - if ( mtest.empty() ) - { - return usage( "Missing Testcase", 102 ); - } - - /////////////////////////////////////////////////////////////////// - - TestSetup test( march ); - ResPool pool( test.pool() ); - sat::Pool satpool( test.satpool() ); - - { - zypp::base::LogControl::TmpLineWriter shutUp; - test.loadTarget(); - test.loadTestcaseRepos( mtest ); // <<< repos - } - test.poolProxy().saveState(); - - { // <<< transaction - zypp::base::LogControl::TmpLineWriter shutUp; - getPi( "SUSE_SLES", Edition("11-0"), Arch_ppc64 ).status().setTransact( true, ResStatus::USER ); - vdumpPoolStats( USR << "Transacting:"<< endl, - make_filter_begin(pool), - make_filter_end(pool) ) << endl; - upgrade(); - } - vdumpPoolStats( USR << "Transacting:"<< endl, - make_filter_begin(pool), - make_filter_end(pool) ) << endl; - - pool::GetResolvablesToInsDel collect( pool, pool::GetResolvablesToInsDel::ORDER_BY_MEDIANR ); - - - - test.poolProxy().restoreState(); - { - base::LogControl::TmpLineWriter shutUp( new log::FileLineWriter( "iorder.log" ) ); - std::set interested; - //interested.insert( IdString("fillup") ); - display( collect, interested ); - } - - INT << "===[END]============================================" << endl << endl; - zypp::base::LogControl::TmpLineWriter shutUp; - return 0; -} diff --git a/libzypp/devel/devel.ma/MaTest.cc b/libzypp/devel/devel.ma/MaTest.cc index 6791aac..24bd198 100644 --- a/libzypp/devel/devel.ma/MaTest.cc +++ b/libzypp/devel/devel.ma/MaTest.cc @@ -24,7 +24,7 @@ #include "zypp/PackageKeyword.h" #include "zypp/TmpPath.h" #include "zypp/ManagedFile.h" -#include "zypp/pool/GetResolvablesToInsDel.h" + #include "zypp/RepoManager.h" #include "zypp/Repository.h" diff --git a/libzypp/devel/devel.ma/Main.cc b/libzypp/devel/devel.ma/Main.cc index 513cb09..8644aa7 100644 --- a/libzypp/devel/devel.ma/Main.cc +++ b/libzypp/devel/devel.ma/Main.cc @@ -3,7 +3,7 @@ #include #include #include -#include "zypp/pool/GetResolvablesToInsDel.h" + #include "zypp/sat/WhatObsoletes.h" #include "zypp/ExternalProgram.h" diff --git a/libzypp/devel/devel.ma/NewPool.cc b/libzypp/devel/devel.ma/NewPool.cc index d96c453..a8cf123 100644 --- a/libzypp/devel/devel.ma/NewPool.cc +++ b/libzypp/devel/devel.ma/NewPool.cc @@ -25,7 +25,7 @@ #include "zypp/TmpPath.h" #include "zypp/ManagedFile.h" #include "zypp/MediaSetAccess.h" -#include "zypp/pool/GetResolvablesToInsDel.h" + #include "zypp/RepoManager.h" #include "zypp/Repository.h" diff --git a/libzypp/devel/devel.ma/Parse.cc b/libzypp/devel/devel.ma/Parse.cc index 2847296..c9e1a49 100644 --- a/libzypp/devel/devel.ma/Parse.cc +++ b/libzypp/devel/devel.ma/Parse.cc @@ -19,7 +19,7 @@ #include "zypp/Digest.h" #include "zypp/PackageKeyword.h" #include "zypp/ManagedFile.h" -#include "zypp/pool/GetResolvablesToInsDel.h" + #include "zypp/parser/TagParser.h" #include "zypp/parser/susetags/PackagesFileReader.h" diff --git a/libzypp/devel/devel.ma/TransList.cc b/libzypp/devel/devel.ma/TransList.cc index 94a66d7..e644a34 100644 --- a/libzypp/devel/devel.ma/TransList.cc +++ b/libzypp/devel/devel.ma/TransList.cc @@ -3,7 +3,7 @@ #include #include #include -#include "zypp/pool/GetResolvablesToInsDel.h" + #include "zypp/sat/WhatObsoletes.h" #include "zypp/ExternalProgram.h" #include @@ -163,42 +163,6 @@ bool install() /////////////////////////////////////////////////////////////////// -namespace zypp -{ - void tradOrder() - { - scoped_ptr shutUp( new base::LogControl::TmpLineWriter ); - ResPool pool( ResPool::instance() ); - pool::GetResolvablesToInsDel collect( pool, pool::GetResolvablesToInsDel::ORDER_BY_SOURCE ); - shutUp.reset(); - - MIL << "GetResolvablesToInsDel -" << collect._toDelete.size() - << " +" << (collect._toInstall.size() + collect._toSrcinstall.size()) << " {" << endl; - for_( it, collect._toDelete.begin(), collect._toDelete.end() ) - { - MIL << " - " << *it << endl; - } - for_( it, collect._toInstall.begin(), collect._toInstall.end() ) - { - MIL << " + " << *it << endl; - } - for_( it, collect._toSrcinstall.begin(), collect._toSrcinstall.end() ) - { - MIL << " + " << *it << endl; - } - MIL << "}" << endl; - } - -} -/////////////////////////////////////////////////////////////////// - -void checkTrans() -{ - ResPool pool( ResPool::instance() ); - pool::GetResolvablesToInsDel collect( pool, pool::GetResolvablesToInsDel::ORDER_BY_SOURCE ); - collect.debugDiffTransaction(); -} - template unsigned count( _Iter begin, _Iter end ) { diff --git a/libzypp/devel/genclass.in b/libzypp/devel/genclass.in index 600d61a..38c8fdf 100644 --- a/libzypp/devel/genclass.in +++ b/libzypp/devel/genclass.in @@ -100,14 +100,13 @@ $(intro $CLASS_H) #include #include "zypp/base/PtrTypes.h" -#include "zypp/base/SafeBool.h" $(nsopen) ${INDENT}/////////////////////////////////////////////////////////////////// ${INDENT}/// \class ${CLASS} ${INDENT}/// \brief ${INDENT}/////////////////////////////////////////////////////////////////// -${INDENT}class ${CLASS} : protected base::SafeBool<${CLASS}> +${INDENT}class ${CLASS} ${INDENT}{ ${INDENT} friend std::ostream & operator<<( std::ostream & str, const ${CLASS} & obj ); ${INDENT} friend std::ostream & dumpOn( std::ostream & str, const ${CLASS} & obj ); @@ -122,12 +121,7 @@ ${INDENT} ~${CLASS}(); ${INDENT} public: ${INDENT} /** Validate object in a boolean context. */ -${INDENT} using base::SafeBool<${CLASS}>::operator bool_type; - -${INDENT} private: -${INDENT} friend base::SafeBool<${CLASS}>::operator bool_type() const; -${INDENT} /** Validate object in a boolean context. */ -${INDENT} bool boolTest() const +${INDENT} explicit operator bool() const ${INDENT} { ${INDENT} /* !!! Perform Boolean logic here AND check implememtation of operator==!!! ${INDENT} * NOTE: SafeBool requires operator== otherwise equality is reduced to diff --git a/libzypp/doc/CMakeLists.txt b/libzypp/doc/CMakeLists.txt index fe5f576..ed3c0d4 100644 --- a/libzypp/doc/CMakeLists.txt +++ b/libzypp/doc/CMakeLists.txt @@ -1,7 +1,50 @@ -ADD_SUBDIRECTORY( autodoc EXCLUDE_FROM_ALL) +IF ( ENABLE_BUILD_DOCS ) + ADD_SUBDIRECTORY( autodoc ) +ELSE ( ENABLE_BUILD_DOCS ) + ADD_SUBDIRECTORY( autodoc EXCLUDE_FROM_ALL ) +ENDIF ( ENABLE_BUILD_DOCS ) -INSTALL( - FILES locks.5 - DESTINATION ${MANDIR}/man5 + +SET (libzypp_MAN1 + zypp-CheckAccessDeleted.1 zypp-NameReqPrv.1) + +SET (libzypp_MAN5 + locks.5) + +SET (libzypp_MAN + ${libzypp_MAN1} ${libzypp_MAN5}) + +ADD_CUSTOM_TARGET( man ALL + DEPENDS ${libzypp_MAN} ) +FOREACH (libzypp_MANIDX 1 2 3 4 5 6 7 8) + INSTALL (FILES + ${libzypp_MAN${libzypp_MANIDX}} + DESTINATION ${MANDIR}/man${libzypp_MANIDX} + ) +ENDFOREACH (libzypp_MANIDX) + +# +# If a2x is installed, auto update manpage from asciidoc manpage.txt: +# +FIND_PROGRAM(A2X a2x) +FOREACH (libzypp_MANTARGET ${libzypp_MAN}) + IF (A2X) + ADD_CUSTOM_COMMAND ( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${libzypp_MANTARGET} + COMMAND ${A2X} -f manpage ${libzypp_MANTARGET}.txt + DEPENDS ${libzypp_MANTARGET}.txt + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + ELSE (A2X) + ADD_CUSTOM_COMMAND ( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${libzypp_MANTARGET} + DEPENDS ${libzypp_MANTARGET}.txt + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Forgott to fix manpage after changing ascidoc? Install a2x for automated creation or 'touch ${libzypp_MANTARGET}'" + ) + ENDIF (A2X) +ENDFOREACH (libzypp_MANTARGET) + + diff --git a/libzypp/doc/autodoc/CMakeLists.txt b/libzypp/doc/autodoc/CMakeLists.txt index 3ada491..a28f59b 100644 --- a/libzypp/doc/autodoc/CMakeLists.txt +++ b/libzypp/doc/autodoc/CMakeLists.txt @@ -56,17 +56,10 @@ INSTALL( FILES DESTINATION ${DOC_INSTALL_DIR}/libzypp/libzypp.doxytag ) -# We could use the thing below but it wont work with cmake older than 2.4.4 -FILE(GLOB docfiles ${CMAKE_CURRENT_BINARY_DIR}/html/*) -INSTALL( FILES - ${docfiles} - DESTINATION ${DOC_INSTALL_DIR}/libzypp/html +INSTALL( DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR}/html + DESTINATION ${DOC_INSTALL_DIR}/libzypp ) - -#INSTALL( DIRECTORY -# ${CMAKE_CURRENT_BINARY_DIR}/html -# DESTINATION ${DOC_INSTALL_DIR} -#) ### ################################################## ENDIF ( DOXYGEN ) ### ################################################## diff --git a/libzypp/doc/autoinclude/EnvironmentVariables.doc b/libzypp/doc/autoinclude/EnvironmentVariables.doc index 23b69c8..bb040aa 100644 --- a/libzypp/doc/autoinclude/EnvironmentVariables.doc +++ b/libzypp/doc/autoinclude/EnvironmentVariables.doc @@ -6,13 +6,17 @@ \section zypp-envars-intro Environment Variables -Note that for Boolean variables we usually test whether the variable exists and not for the assigned value. +Note that for Boolean variables we usually test whether the variable exists and not for the assigned value. \subsection zypp-envars-config zypp config options \li \c ZYPP_CONF= Location of the zypp.conf file. \li \c ZYPP_LOCK_TIMEOUT= If zypp is locked by another process wait this number of seconds for the lock becoming available. +\subsection zypp-envars-repos Variables related to repositories + +\li \c ZYPP_REPO_RELEASEVER= Overwrite the \c $releasever variable in repository URLs and names (\see zypp::repo::RepoVariablesStringReplacer). + \subsection zypp-envars-commit Variables related to commit \li \c ZYPP_IS_RUNNING=1 Set during commit so packages pre/post/trigger scripts can detect whether rpm was called from within libzypp. @@ -23,13 +27,13 @@ Note that for Boolean variables we usually test whether the variable exists and \li \c ZYPP_FULLLOG=1 Even more verbose logging (usually not needed). \li \c ZYPP_LIBSOLV_FULLLOG=1 Verbose logging when resolving dependencies. \li (\c ZYPP_LIBSAT_FULLLOG=1) deprecated since \c libzypp-10.x, prefer \c ZYPP_LIBSOLV_FULLLOG +\li \c LIBSOLV_DEBUGMASK= Pass value to libsolv::pool_setdebugmask -\li \c ZYPP_MEDIA_CURL_DEBUG=<0|1> Log http headers, if \c 1 also log server responses. +\li \c ZYPP_MEDIA_CURL_DEBUG=<1|2> Log http headers, if \c 2 also log server responses. \subsection zypp-envars-mediabackend Selecting the mediabackend to use. \li \c ZYPP_MULTICURL=0 Turn off multicurl (metalink and zsync) and fall back to plain libcurl. -\li \c ZYPP_ARIA2C=1 Enable aria2c backend (deprecated). \subsection zypp-envars-plugin Variables related to plugins @@ -47,4 +51,4 @@ Note that for Boolean variables we usually test whether the variable exists and \li \c ZYPP_LOCKFILE_ROOT= Hack to circumvent the currently poor --root support. \li \c ZYPP_PROFILING=1 -*/ \ No newline at end of file +*/ diff --git a/libzypp/doc/autoinclude/PatternPackages.doc b/libzypp/doc/autoinclude/PatternPackages.doc new file mode 100644 index 0000000..9fc2e0d --- /dev/null +++ b/libzypp/doc/autoinclude/PatternPackages.doc @@ -0,0 +1,66 @@ +/** + +\page zypp-pattern-packages Code 12 Pattern Packages + +\author Michael Andres + +
+ +\section zypp-pattern-packages_intro Intro + +Since Code12 (SLES-12) we utilizes a new method of defining patterns, as opposed to the older XML-based patterns files. A pattern and it's dependencies are now represented by an rpm package and the few pattern specific properties are provided by the package. No extra XML-file is needed. + +By convention a patterns package for a \c pattern:FOO is named \c patterns-*-FOO and is must provide \c pattern() \c = \c apparmor. The pattens content is expressed by dependencies to other packages and patterns-packages. + +The list of provides used for the new pattern pseudo-package autogeneration: + +\code + Provides: pattern-category() = STRING + Provides: pattern-category(de) = STRING + (... other languages ...) + Provides: pattern-includes() = STRING + Provides: pattern-extends() = STRING + Provides: pattern-icon() = STRING + Provides: pattern-order() = STRING + Provides: pattern-visible() + + STRING must be url-hexencoded so that it does not contain any characters + that rpm provides can't have. E.g.: + ' ' => %20 + ',' => %2C + '-' => %2D +\endcode + +\code +patterns-sles-Minimal-12-37.1.x86_64.rpm + PROVIDES { + pattern() == Minimal + pattern-icon() == pattern-basis + pattern-order() == 1099 + pattern-visible() + pattern-category() == Base%20Technologies + pattern-category(ar) == %D8%A7%D9%84%D8%AA%D9%83%D9%86%D9%88%D9%84%D9%88%D8%AC%D9%8A%D8%A7%D8%AA%20%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9 + pattern-category(ca) == Tecnologies%20de%20base + pattern-category(cs) == Z%C3%A1kladn%C3%AD%20technologie + pattern-category(da) == Basisteknologier + pattern-category(de) == Basistechnologien + ... +} + REQUIRES { + systemd + coreutils + insserv + aaa_base + ... +} + RECOMMENDS (22){ + grub2 + rpcbind + nfs-client + rsyslog + ... +} +\endcode + + +*/ diff --git a/libzypp/doc/autoinclude/Plugin-Commit.doc b/libzypp/doc/autoinclude/Plugin-Commit.doc index 4083633..e03173e 100644 --- a/libzypp/doc/autoinclude/Plugin-Commit.doc +++ b/libzypp/doc/autoinclude/Plugin-Commit.doc @@ -7,7 +7,7 @@
\section intro Introduction -This is a statefull plugin executed during \ref zypp::ZYpp::commit. At the beginning of a commit all plugins found in \c /usr/lib/zypp/plugins/commit are launched. The plugins will receive messages as commit proceeds. Unless otherwise specified messages received need to be confirmed by sending an \c ACC message. Sending back an \c ERROR message execution of the plugin will be canceled. +This is a statefull plugin executed during \ref zypp::ZYpp::commit. At the beginning of a commit all plugins found in \c /usr/lib/zypp/plugins/commit are launched. The plugins will receive messages as commit proceeds. Unless otherwise specified messages received need to be confirmed by sending an \c ACC message. Sending back an unexpected or \c ERROR message execution of the plugin will be canceled. If you have e.g. \c zypp-plugin-python installed a basic commit plugin could look like this: @@ -24,6 +24,8 @@ class MyPlugin(Plugin): def PLUGINBEGIN(self, headers, body): # commit is going to start. + if headers.has_key('userdata'): + print "Commit starts with TID '%s'" % headers['userdata'] self.ack() def PLUGINEND(self, headers, body): @@ -40,11 +42,66 @@ plugin.main() \section pluginbegin PLUGINBEGIN \verbatim PLUGINBEGIN +userdata:TIDfoo42 ^@ \endverbatim Sent as 1st message after the plugin was launched. Prepare your plugin and send an \c ACC message when you are done. Commit will start after all plugins are initialized. +\li \c userdata:stringval Optional header sent if the application has provided a user data string. \see \ref zypp-userdata + + +
+\section commitbegin COMMITBEGIN (added in v1) +\verbatim +COMMITBEGIN + +{ +"TransactionStepList": [ ,... ] +} +^@ +\endverbatim +Sent before installation actually starts. The body contains a JSON encoded object providing the \c TransactionStepList, basically the list of install/remove actions the the commit is going to perform. Each \c TransactionStep is encoded as JSON object: +\verbatim + = { + "type": # [optional] + "stage": # [optional] + "solvable": +} + + = # ignore; implicit or non-package actions + | "-" # remove + | "+" # install + | "M" # multi version install; install keeping the old version; e.g. kernel + + = # todo + | "ok" # done + | "err" # failed + + = { + "n": # name + "e": # epoch if not 0 [optional] + "v": # version + "r": # release + "a": # architecture +} +\endverbatim + +\see \ref zypp::sat::Transaction::Step + +
+\section commitend COMMITEND (added in v1) +\verbatim +COMMITEND + +{ +"TransactionStepList": [ ,... ] +} +^@ +\endverbatim +Sent at the end of commit. The body contains a JSON encoded object providing the final \c TransactionStepList. The \c StepStage indicates whether the action succeeded, failed or was skipped (still 'todo'). + +\see \ref commitbegin
\section pluginend PLUGINEND diff --git a/libzypp/doc/autoinclude/Plugins.doc b/libzypp/doc/autoinclude/Plugins.doc index dcde6ae..040b8b1 100644 --- a/libzypp/doc/autoinclude/Plugins.doc +++ b/libzypp/doc/autoinclude/Plugins.doc @@ -22,14 +22,14 @@ This type of plugin receive input reading the standard input, and answer ZYpp wr \subsection plugin-protocol-stateful Stateful -This type of plugin is called by ZYpp and a conversation using a simple protocol. The protocol is based on STOMP http://stomp.codehaus.org/Protocol (Streaming Text Orientated Messaging Protocol). Messages (called "frames") look like the following: +This type of plugin is called by ZYpp and a conversation using a simple protocol. The protocol is based on STOMP http://stomp.github.com (Streaming Text Orientated Messaging Protocol). Messages (called "frames") look like the following: \verbatim COMMAND param1:val1 param2:val2 ... -Thus a COMMAND hollowed by key:value header lines +Thus a COMMAND followed by key:value header lines and a multiline body separated from header by an empty line and terminated by NUL. ^@ @@ -82,6 +82,19 @@ Plugin closes \c stdin and exits when receiving a \c _DISCONNECT message. Upon a self.ack( {'exit':'99'}, 'Famous last words.' ) \endverbatim +
+\section plugins-impl Developers: Implementation + +Plugins are implemented in the following classes: + +- \ref zypp::PluginScript (Plugin as an external program) +- \ref zypp::PluginScriptException +- \ref zypp::PluginFrame (Message for the stateful protocol) +- \ref zypp::PluginFrameException +- \ref zypp::repo::PluginServices (Finds Service plugins) + +The plugins default location is obtained from \ref zypp::ZConfig::pluginsPath() +
\section plugin-toc Supported plugins @@ -91,6 +104,7 @@ Plugin closes \c stdin and exits when receiving a \c _DISCONNECT message. Upon a \ref plugin-url-resolver +\ref plugin-appdata
\section plugin-services Service plugins @@ -141,7 +155,7 @@ ZYpp sees a repository whose url has the format: plugin:foo?param1=val1¶m2=val2 \endverbatim -ZYpp tries to executa a plugin named foo (in /usr/lib/zypp/plugins/urlresolver) and calla it with the following protocol: +ZYpp tries to executa a plugin named foo (in /usr/lib/zypp/plugins/urlresolver) and call it with the following protocol: \verbatim RESOLVEURL @@ -187,16 +201,17 @@ This type of plugin can be combined with service plugins, because a local servic In this example, the service plugin could have inmediately resolved the urls and returned http://realurl, but the url resolver allows also to add HTTP headers to the request.
-\section plugins-impl Developers: Implementation +\section plugin-appdata Appdata refresh plugins (repo change) -Plugins are implemented in the following classes: +Stateless plugins found in /usr/lib/zypp/plugins/appdata are called whenever any of the system repos has changed (added/removed/renamed/modified) or has been refreshed. Detailed information \b what exactly has changed is not available. (scripts are executed IFF euid is '0' and --root is not used). For every enabled system repo we pass alias type and metadata path on the commandline like this: -- \ref zypp::PluginScript (Plugin as an external program) -- \ref zypp::PluginScriptException -- \ref zypp::PluginFrame (Message for the stateful protocol) -- \ref zypp::PluginFrameException -- \ref zypp::repo::PluginServices (Finds Service plugins) +\verbatim + -R REPO_ALIAS -t REPO_TYPE -p REPO_METADATA_PATH -R NEXT_REPO.... +\endverbatim -The plugins default location is obtained from \ref zypp::ZConfig::pluginsPath() +\note REPO_TYPE can be e.g. "rpm-md", "yast2", "plaindir" or "NONE" indicating the repo was not yet probed. + +\note REPO_METADATA_PATH can be empty or a not existing directory, indicating valid metadata for the repo are not yet available. +Scripts are executed 'fire and forget' whenever a RepoManager instance that performed changes goes out of scope. So it's up to the script to protect against concurrency. */ \ No newline at end of file diff --git a/libzypp/doc/autoinclude/Testcases.doc b/libzypp/doc/autoinclude/Testcases.doc index 372fcc0..022af6e 100644 --- a/libzypp/doc/autoinclude/Testcases.doc +++ b/libzypp/doc/autoinclude/Testcases.doc @@ -1,6 +1,6 @@ /** \page Testcases Writing and tunning testcases -\section Introduction +\section Introduction Introduction ZYpp has a suite of tests located in under test/ directory of the source tree. @@ -18,7 +18,7 @@ Tests are written using boost test library. - The Unit Test Framework - The UTF testing tools reference -\section Anatomy of a ZYpp testcase +\section Anatomy Anatomy of a ZYpp testcase The file should be in one of the described groups, and by general rule it is named ClassName_test.cc where ClassName is the name of the class or module the test covers. @@ -38,7 +38,7 @@ BOOST_AUTO_TEST_CASE(date_test) } \endcode -\section Building and running the testsuite +\section Building Building and running the testsuite - Build the testsuite diff --git a/libzypp/doc/autoinclude/UserData.doc b/libzypp/doc/autoinclude/UserData.doc new file mode 100644 index 0000000..cd7d544 --- /dev/null +++ b/libzypp/doc/autoinclude/UserData.doc @@ -0,0 +1,17 @@ +/** +\page zypp-userdata User data as transaction id + +\author Michael Andres + +
+\section userdata-introduction Introduction + +It is possible to store a user defined data string via \ref zypp::ZConfig::setUserData inside libzypp for use as a transaction id. \c Zypper e.g. supports this via its global '--userdata ' option. + +\li Setting a new user data string, a line will be written to the log file. So you can \c grep for it, or for '(setUserData)' to find all locations where user data strings were set. + +\li The user data string will also be passed to commit plugins, so they can make use of it. The btrfs e.g would be able to tag created snapshots with this string. \see \ref plugin-commit + +\li The user data string will appear on each histoy line logging package or repository related events (install, delete, add, modify). \see \ref zypp::HistoryLog and zypp::parser::HistoryLogReader + +*/ diff --git a/libzypp/doc/autoinclude/g_ZyppHistory.doc b/libzypp/doc/autoinclude/g_ZyppHistory.doc new file mode 100644 index 0000000..c701713 --- /dev/null +++ b/libzypp/doc/autoinclude/g_ZyppHistory.doc @@ -0,0 +1,89 @@ +/** \defgroup g_ZyppHistory Libzypp History File + +Log important events like installation/deletion of packages and repositories. + + +\section g_ZyppHistory_Location Location + +The default location is \c /var/log/zypp/history. This can be changed via \c history.logfile key in \c /etc/zypp/zypp.conf. + + +\section g_ZyppHistory_Format Format + +\li CSV file with pipe character (|) as the value separator +\li one event per line +\li different actions have different set of values (columns), see the tables below +\li lines starting with # are treated as comments + +\see \ref zypp-userdata + +\subsection g_ZyppHistory_Format_Colummn Action Columns + +\subsubsection g_ZyppHistory_Format_Colummn_Install Install +A package has been installed. +\li \b 1 timestamp +\li \b 2 action ID (\c "install") +\li \b 3 package name +\li \b 4 package epoch:version-release +\li \b 5 package architecture +\li \b 6 requested by (user@hostname, pid:appname, or empty (solver)) +\li \b 7 repository alias +\li \b 8 package checksum +\li \b 9 userdata/transactionId + +\subsubsection g_ZyppHistory_Format_Colummn_Remove Remove +A package has been removed. +\li \b 1 timestamp +\li \b 2 action ID (\c "remove") +\li \b 3 package name +\li \b 4 package epoch:version-release +\li \b 5 package architecture +\li \b 6 requested by (user@hostname, pid:appname, or empty (solver)) +\li \b 7 userdata/transactionId + +\subsubsection g_ZyppHistory_Format_Colummn_Radd Radd +A repository has been added. +\li \b 1 timestamp +\li \b 2 action ID (\c "radd") +\li \b 3 repository alias +\li \b 4 primary URL +\li \b 5 userdata/transactionId + +\subsubsection g_ZyppHistory_Format_Colummn_Rremove Rremove +A repository has been removed. +\li \b 1 timestamp +\li \b 2 action ID (\c "rremove") +\li \b 3 repository alias +\li \b 4 userdata/transactionId + +\subsubsection g_ZyppHistory_Format_Colummn_Ralias Ralias +A repository alias has changed. +\li \b 1 timestamp +\li \b 2 action ID (\c "ralias") +\li \b 3 old alias +\li \b 4 new alias +\li \b 5 userdata/transactionId + +\subsubsection g_ZyppHistory_Format_Colummn_Rurl Rurl +The primary URL of a repository has changed. +\li \b 1 timestamp +\li \b 2 action ID (\c "rurl") +\li \b 3 repository alias +\li \b 4 new URL +\li \b 5 userdata/transactionId + + +\section g_ZyppHistory_Example Example + +\code +2008-09-24 11:48:58|rremove|packman +2008-09-24 11:50:02|radd |packman|http://packman.iu-bremen.de/suse/11.0 +2008-09-24 11:53:10|install|amarok-yauap|1.4.10-25|x86_64||factory|4421dfa718ab73c805c1c695c97b1b67f39bf2f3 +2008-09-24 11:53:25|install|amarok-lang|1.4.10-25|x86_64||factory|691030edafcc4fbc22aa225350f9de32974e4bc2 +# Additional rpm output: +# warning: /var/cache/zypp/packages/packman/x86_64/amarok-1.4.10-100.pm.1.x86_64.rpm: Header V3 DSA signature: NOKEY, key ID 9a795806 +# +2008-09-24 11:53:45|install|amarok|1.4.10-100.pm.1|x86_64|root@kompost|packman|ee0fffa1e4eeaaeb8799bd05c6882ef74100d681 +\endcode + +*/ diff --git a/libzypp/doc/autoinclude/groups.doc b/libzypp/doc/autoinclude/groups.doc index 84c0a69..4369f48 100644 --- a/libzypp/doc/autoinclude/groups.doc +++ b/libzypp/doc/autoinclude/groups.doc @@ -23,3 +23,6 @@ /*! \defgroup g_Algorithm Algorithms */ //////////////////////////////////////////////////////////////////////////////// +/*! \defgroup g_Parser Parser +*/ +//////////////////////////////////////////////////////////////////////////////// diff --git a/libzypp/doc/downloaders-mediaset.txt b/libzypp/doc/downloaders-mediaset.txt deleted file mode 100644 index 715e183..0000000 --- a/libzypp/doc/downloaders-mediaset.txt +++ /dev/null @@ -1,4 +0,0 @@ - -Downloaders and MediaSet -======================== -dmacvicar@suse.de diff --git a/libzypp/doc/libzypp.zargo b/libzypp/doc/libzypp.zargo deleted file mode 100644 index 38595b7..0000000 Binary files a/libzypp/doc/libzypp.zargo and /dev/null differ diff --git a/libzypp/doc/locks.5 b/libzypp/doc/locks.5 index ab89790..d446c7a 100644 --- a/libzypp/doc/locks.5 +++ b/libzypp/doc/locks.5 @@ -1,199 +1,290 @@ -.TH "locks" "5" "4.25.0" "libzypp" "System Tools" +'\" t +.\" Title: locks +.\" Author: [see the "AUTHORS" section] +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 10/02/2014 +.\" Manual: LIBZYPP +.\" Source: libzypp +.\" Language: English +.\" +.TH "LOCKS" "5" "10/02/2014" "libzypp" "LIBZYPP" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- .SH "NAME" -.LP -locks - libzypp locking file - +locks \- libzypp locking file .SH "DESCRIPTION" -.LP -The file \fI/etc/zypp/locks\fR is read by libzypp at startup if -\fIzypp.conf\fR allows it. The entries are used for initial locking of -packages. Locking a package means not allowing to install or uninstall -it. Valid entries are -.TP -\fI attribute\fR\fB:\fR \fIvalue\fR -Where attributes and their values are described below. -.br -Locks are separated by empty lines. - +.sp +The file \fI/etc/zypp/locks\fR is read by libzypp at start\-up if \fIzypp\&.conf\fR allows it\&. The entries are used for initial locking of packages\&. Locking a package means not allowing to install or uninstall it\&. +.sp +Valid entries are of the form: +.PP +\fIattribute\fR\fB:\fR \fIvalue\fR +.RS 4 +Where attributes and their values are described below\&. +.RE +.sp +Locks are separated by an empty lines\&. .SH "ATTRIBUTES" -.LP -All attributes are lower-case. - -.TP -.B repo -specifies repository restriction. Only alias is accepted. -.br -By default all repositories match. +.sp +All attributes are lower\-case\&. +.PP +\fBrepo\fR +.RS 4 +specifies repository restriction\&. Only alias is accepted\&. -.TP -.B type -resolvable type restriction -.br -The values can be \fBpackage\fR, \fBpatch\fR, \fBpattern\fR, \fBproduct\fR and \fBsrcpackage\fR. -.br -By default all types match. +By default all repositories match\&. +.RE +.PP +\fBtype\fR +.RS 4 +resolvable type restriction\&. The values can be +\fBpackage\fR, +\fBpatch\fR, +\fBpattern\fR, +\fBproduct\fR +and +\fBsrcpackage\fR\&. -.TP -.B case_sensitive -if strings are matched case sensitive. -The values are \fBtrue\fR, \fBfalse\fR, \fBon\fR, \fBoff\fR. -.br -The default is case insensitive. +By default all types match\&. +.RE +.PP +\fBcase_sensitive\fR +.RS 4 +if strings are matched case sensitive\&. The values are +\fBtrue\fR, +\fBfalse\fR, +\fBon\fR, +\fBoff\fR\&. -.TP -.B install_status -status of object. Possible states are \fBinstalled\fR, -\fBnot-installed\fR and \fBall\fR. If more install statuses are -specified then the last one is used. -.br -The values are \fBinstalled\fR for all packages which are installed, \fBnon-installed\fR for packages which can be installed or reinstalled and \fBall\fR for both. -.br -The default is \fBall\fR. +The default is case insensitive\&. +.RE +.PP +\fBinstall_status\fR +.RS 4 +status of object\&. Possible states are +\fBinstalled\fR, +\fBnot\-installed\fR +and +\fBall\fR\&. If more install statuses are specified then the last one is used\&. The values are +\fBinstalled\fR +for all packages which are installed, +\fBnon\-installed\fR +for packages which can be installed or reinstalled and +\fBall\fR +for both\&. -.TP -.B match_type -type of string matching in values. Does not affect \fBtype\fR and \fBrepo\fR which must be specified exactly. -.br -The values are \fBexact\fR, \fBsubstring\fR, \fBregex\fR for regular -expressions, \fBglob\fR for matching as on the command line, and \fBword\fR. -.br -The default is \fBsubstring\fR. +The default is +\fBall\fR\&. +.RE +.PP +\fBmatch_type\fR +.RS 4 +type of string matching in values\&. Does not affect +\fBtype\fR +and +\fBrepo\fR +which must be specified exactly\&. The values are +\fBexact\fR, +\fBsubstring\fR, +\fBregex\fR +for regular expressions, +\fBglob\fR +for matching as on the command line, and +\fBword\fR\&. -.TP -.B query_string -String to be matched in multiple attributes. Should be restricted by -another attribute with empty value ( it is recommended, because without restriction expect some performance problems ). +The default is +\fBsubstring\fR\&. +.RE +.PP +\fBquery_string\fR +.RS 4 +String to be matched in multiple attributes\&. Should be restricted by another attribute with empty value (it is recommended, because without restriction expect some performance problems)\&. +.RE +.PP +\fBversion\fR +.RS 4 +Restrict the lock only to some versions\&. It contains two parts: an optional operator and the version\&. -.TP -.B version -Restrict the lock only to some versions. It contains two parts: an -optional operator and the version. -.br -The operator is \fB==\fR,\fB!=\fR,\fB<\fR,\fB>\fR,\fB<=\fR,\fB>=\fR. If operator is not specified then \fB==\fR is used. -.br -The version has the format -.RB [ epoch: ] version [ -release ]. -.br -Example: version: < 0:0.11.4-2 +The operator is +\fB==\fR, +\fB!=\fR, +\fB<\fR, +\fB>\fR, +\fB⇐\fR, +\fB>=\fR\&. If operator is not specified then +\fB==\fR +is used\&. -.TP -.B solvable_name -name of object (e.g. zypper) +The version has the format [\fIepoch\fR\fB:\fR]\fIversion\fR[\fB\-\fR\fIrelease\fR]\&. -.TP -.B solvable_summary +Example: +\fBversion: < 0:0\&.11\&.4\-2\fR +.RE +.PP +\fBsolvable_name\fR +.RS 4 +name of object (e\&.g\&. zypper) +.RE +.PP +\fBsolvable_summary\fR +.RS 4 summary of object - -.TP -.B solvable_arch -architecture of object (e.g. x86_64, i586) - -.TP -.B solvable_description -description of object - -.TP -.B solvable_eula +.RE +.PP +\fBsolvable_arch\fR +.RS 4 +architecture of object (e\&.g\&. x86_64, i586) +.RE +.PP +\fBsolvable_description\fR +.RS 4 +description of object +.RE +.PP +\fBsolvable_eula\fR +.RS 4 license text of objects which request accepting license by user - -.TP -.B solvable_license -license of package (only for package) (e.g. GPL2) - -.TP -.B solvable_keywords +.RE +.PP +\fBsolvable_license\fR +.RS 4 +license of package (only for package) (e\&.g\&. GPL2) +.RE +.PP +\fBsolvable_keywords\fR +.RS 4 keywords which specify package (only for package) - -.TP -.B solvable_authors +.RE +.PP +\fBsolvable_authors\fR +.RS 4 authors of package (only for package) - -.TP -.B solvable_group -package group (only for package) (e.g. Development/Tools/Version Control ) - -.TP -.B update_reference_type -reference for update (e.g. bugzilla,cve) (only for patches) - +.RE +.PP +\fBsolvable_group\fR +.RS 4 +package group (only for package) (e\&.g\&. Development/Tools/Version Control ) +.RE +.PP +\fBupdate_reference_type\fR +.RS 4 +reference for update (e\&.g\&. bugzilla,cve) (only for patches) +.RE .SH "EXAMPLES" -.LP - -.TP -.B Exact Package -This is the way YaST UI does it. Lock k3b (e.g. you don't want to update it). -.br ------locks----- -.br +.PP +\fBExact Package\fR +.RS 4 +This is the way YaST UI does it\&. Lock k3b (e\&.g\&. you don\(cqt want to update it)\&. +.RE +.sp +.if n \{\ +.RS 4 +.\} +.nf +\-\-\-\-\-locks\-\-\-\-\- type: package -.br solvable_name: k3b -.br match_type: exact -.br case_sensitive: on - -.TP -.B Package Wildcard -This is the way "zypper addlock cross-*-gcc-icecream-backend" does it. -.br ------locks----- -.br +.fi +.if n \{\ +.RE +.\} +.PP +\fBPackage Wildcard\fR +.RS 4 +This is the way "zypper addlock cross\-*\-gcc\-icecream\-backend" does it\&. +.RE +.sp +.if n \{\ +.RS 4 +.\} +.nf +\-\-\-\-\-locks\-\-\-\-\- type: package -.br -solvable_name: cross-*-gcc-icecream-backend -.br +solvable_name: cross\-*\-gcc\-icecream\-backend match_type: glob -.br case_sensitive: on - -.TP -.B Versioned Lock -Do not install new GCC. This format is used when converting from the -openSUSE-10.3 lock format. -.br ------locks----- -.br +.fi +.if n \{\ +.RE +.\} +.PP +\fBVersioned Lock\fR +.RS 4 +Do not install new GCC\&. This format is used when converting from the openSUSE\-10\&.3 lock format\&. +.RE +.sp +.if n \{\ +.RS 4 +.\} +.nf +\-\-\-\-\-locks\-\-\-\-\- solvable_name: gcc -.br match_type: glob -.br -version: > 4.2 - -.TP -.B Anything named KDE -Locks everything which contains kde in the name. -.br ------locks----- -.br +version: > 4\&.2 +.fi +.if n \{\ +.RE +.\} +.PP +\fBAnything named KDE\fR +.RS 4 +Locks everything which contains kde in the name\&. +.RE +.sp +.if n \{\ +.RS 4 +.\} +.nf +\-\-\-\-\-locks\-\-\-\-\- solvable_name: kde - -.TP -.B Anything mentioning KDE -Locks everything which contains kde in the name, summary, or description. -.br ------locks----- -.br +.fi +.if n \{\ +.RE +.\} +.PP +\fBAnything mentioning KDE\fR +.RS 4 +Locks everything which contains kde in the name, summary, or description\&. +.RE +.sp +.if n \{\ +.RS 4 +.\} +.nf +\-\-\-\-\-locks\-\-\-\-\- query_string: kde -.br solvable_name: -.br solvable_summary: -.br solvable_description: - +.fi +.if n \{\ +.RE +.\} .SH "HOMEPAGE" - -This manual page only covers the most important attributes. The -complete list is available at -http://en.opensuse.org/Libzypp/Locksfile - +.sp +This manual page only covers the most important attributes\&. The complete list is available at http://en\&.opensuse\&.org/Libzypp/Locksfile .SH "AUTHORS" -.LP -Josef Reidinger -.br -Manual page contributions by Martin Vidner . - +.sp +Josef Reidinger Manual page contributions by Martin Vidner \&. .SH "SEE ALSO" -.LP +.sp zypper(8) diff --git a/libzypp/doc/locks.5.txt b/libzypp/doc/locks.5.txt new file mode 100644 index 0000000..4428ccf --- /dev/null +++ b/libzypp/doc/locks.5.txt @@ -0,0 +1,153 @@ +locks(5) +======== +:man manual: LIBZYPP +:man source: libzypp + + +NAME +---- +locks - libzypp locking file + + +DESCRIPTION +----------- +The file '/etc/zypp/locks' is read by libzypp at start-up if 'zypp.conf' allows it. The entries are used for initial locking of packages. Locking a package means not allowing to install or uninstall it. + +Valid entries are of the form: + +'attribute'*:* 'value':: + Where attributes and their values are described below. + +Locks are separated by an empty lines. + + +ATTRIBUTES +---------- +All attributes are lower-case. + +*repo*:: + specifies repository restriction. Only alias is accepted. + + By default all repositories match. + +*type*:: + resolvable type restriction. The values can be *package*, *patch*, *pattern*, *product* and *srcpackage*. + + By default all types match. + + +*case_sensitive*:: + if strings are matched case sensitive. The values are *true*, *false*, *on*, *off*. + + The default is case insensitive. + + +*install_status*:: + status of object. Possible states are *installed*, *not-installed* and *all*. If more install statuses are specified then the last one is used. The values are *installed* for all packages which are installed, *non-installed* for packages which can be installed or reinstalled and *all* for both. + + The default is *all*. + + +*match_type*:: + type of string matching in values. Does not affect *type* and *repo* which must be specified exactly. The values are *exact*, *substring*, *regex* for regular expressions, *glob* for matching as on the command line, and *word*. + + The default is *substring*. + +*query_string*:: + String to be matched in multiple attributes. Should be restricted by another attribute with empty value (it is recommended, because without restriction expect some performance problems). + +*version*:: + Restrict the lock only to some versions. It contains two parts: an optional operator and the version. + + The operator is *==*, *!=*, *<*, *>*, *<=*, *>=*. If operator is not specified then *==* is used. + + The version has the format ['epoch'*:*+]+'version'[*-*'release']. + + Example: *version: < 0:0.11.4-2* + +*solvable_name*:: + name of object (e.g. zypper) + +*solvable_summary*:: + summary of object + +*solvable_arch*:: + architecture of object (e.g. x86_64, i586) + +*solvable_description*:: + description of object + +*solvable_eula*:: + license text of objects which request accepting license by user + +*solvable_license*:: + license of package (only for package) (e.g. GPL2) + +*solvable_keywords*:: + keywords which specify package (only for package) + +*solvable_authors*:: + authors of package (only for package) + +*solvable_group*:: + package group (only for package) (e.g. Development/Tools/Version Control ) + +*update_reference_type*:: + reference for update (e.g. bugzilla,cve) (only for patches) + + +EXAMPLES +-------- +*Exact Package*:: + This is the way YaST UI does it. Lock k3b (e.g. you don't want to update it). +-------------------- +-----locks----- +type: package +solvable_name: k3b +match_type: exact +case_sensitive: on +-------------------- + +*Package Wildcard*:: + This is the way "zypper addlock cross-*-gcc-icecream-backend" does it. +-------------------- +-----locks----- +type: package +solvable_name: cross-*-gcc-icecream-backend +match_type: glob +case_sensitive: on +-------------------- + +*Versioned Lock*:: + Do not install new GCC. This format is used when converting from the openSUSE-10.3 lock format. +-------------------- +-----locks----- +solvable_name: gcc +match_type: glob +version: > 4.2 +-------------------- + +*Anything named KDE*:: + Locks everything which contains kde in the name. +-------------------- +-----locks----- +solvable_name: kde +-------------------- + +*Anything mentioning KDE*:: + Locks everything which contains kde in the name, summary, or description. +-------------------- +-----locks----- +query_string: kde +solvable_name: +solvable_summary: +solvable_description: +-------------------- + + +HOMEPAGE +-------- +This manual page only covers the most important attributes. The complete list is available at http://en.opensuse.org/Libzypp/Locksfile + + +AUTHORS +------- +Josef Reidinger +Manual page contributions by Martin Vidner . + + +SEE ALSO +-------- +zypper(8) diff --git a/libzypp/doc/solverstates.dot b/libzypp/doc/solverstates.dot deleted file mode 100644 index 8bdc0ae..0000000 --- a/libzypp/doc/solverstates.dot +++ /dev/null @@ -1,37 +0,0 @@ -digraph solver_states { - - size="8,5"; - - graph [fontsize=14]; - edge [fontsize=12]; - node [fontsize=12]; - node [shape=doublecircle]; Installed Uninstalled; - node [shape=circle]; Satisfied Incomplete; - node [shape=box]; -// ranksep = 1.5; -// rankdir = LR; -// nodesep = 0.5; - edge [style="setlinewidth(1)"]; - - Installed [label="Installed"]; - Uninstalled [label="Uninstalled"]; - Satisfied [label="Satisfied"]; - Incomplete [label="Incomplete"]; - - Uninstalled -> To_be_installed [ label ="install,explicit"]; - Uninstalled -> To_be_installed [ label ="install,implicit"]; - Installed -> To_be_removed [ label ="remove,explicit"]; - Installed -> To_be_removed [ label ="remove,implicit"]; - To_be_installed -> Installed [ label ="commit"]; - To_be_removed -> Uninstalled [ label ="commit"]; - - Uninstalled -> Satisfied [ label="establish,good" ]; - Uninstalled -> Incomplete [ label="establish,bad" ]; - - Installed -> Incomplete [ label="establish,bad" ]; - - Incomplete -> To_be_installed [ label="resolve" ]; - Incomplete -> To_be_removed [ label="remove" ]; - - Satisfied -> Installed [ label="install" ]; -} diff --git a/libzypp/doc/zypp-CheckAccessDeleted.1 b/libzypp/doc/zypp-CheckAccessDeleted.1 new file mode 100644 index 0000000..ddb4d43 --- /dev/null +++ b/libzypp/doc/zypp-CheckAccessDeleted.1 @@ -0,0 +1,49 @@ +'\" t +.\" Title: zypp-CheckAccessDeleted +.\" Author: [see the "AUTHORS" section] +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 10/02/2014 +.\" Manual: LIBZYPP +.\" Source: libzypp +.\" Language: English +.\" +.TH "ZYPP\-CHECKACCESSDEL" "1" "10/02/2014" "libzypp" "LIBZYPP" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +zypp-CheckAccessDeleted \- List processes which access deleted files +.SH "SYNOPSIS" +.sp +\fBzypp\-CheckAccessDeleted\fR [\fIOPTION\fR]\&... +.SH "DESCRIPTION" +.sp +List running processes which access deleted files\&. This may help to identify services and processes which need to be restarted after an update, e\&.g\&. if they still refer to meanwhile deleted libraries\&. The output is similar to \(oq\fBzypper ps\fR\(cq but does not sort out processes accessing normal files only\&. +.SH "OPTIONS" +.PP +\fB\-\-help\fR +.RS 4 +display help and exit +.RE +.SH "AUTHORS" +.sp +Michael Andres +.SH "SEE ALSO" +.sp +zypper(8) diff --git a/libzypp/doc/zypp-CheckAccessDeleted.1.txt b/libzypp/doc/zypp-CheckAccessDeleted.1.txt new file mode 100644 index 0000000..c418f62 --- /dev/null +++ b/libzypp/doc/zypp-CheckAccessDeleted.1.txt @@ -0,0 +1,35 @@ +zypp-CheckAccessDeleted(1) +========================== +:man manual: LIBZYPP +:man source: libzypp + + +NAME +---- +zypp-CheckAccessDeleted - List processes which access deleted files + + +SYNOPSIS +-------- +*zypp-CheckAccessDeleted* [_OPTION_]... + + +DESCRIPTION +----------- +List running processes which access deleted files. This may help to identify services and processes which need to be restarted after an update, e.g. if they still refer to meanwhile deleted libraries. The output is similar to `*zypper ps*' but does not sort out processes accessing normal files only. + + +OPTIONS +------- +*--help*:: + display help and exit + + +AUTHORS +------- +Michael Andres + + +SEE ALSO +-------- +zypper(8) diff --git a/libzypp/doc/zypp-NameReqPrv.1 b/libzypp/doc/zypp-NameReqPrv.1 new file mode 100644 index 0000000..8a7907d --- /dev/null +++ b/libzypp/doc/zypp-NameReqPrv.1 @@ -0,0 +1,135 @@ +'\" t +.\" Title: zypp-NameReqPrv +.\" Author: [see the "AUTHORS" section] +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 10/02/2014 +.\" Manual: LIBZYPP +.\" Source: libzypp +.\" Language: English +.\" +.TH "ZYPP\-NAMEREQPRV" "1" "10/02/2014" "libzypp" "LIBZYPP" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +zypp-NameReqPrv \- Investigate packages and dependencies in solver test\-cases +.SH "SYNOPSIS" +.sp +\fBzypp\-NameReqPrv\fR [\fB\-\-root\fR \fIDIR\fR] [[\fIOPTIONS\fR] \fINAME\fR\&...]\&... +.SH "DESCRIPTION" +.sp +Load all enabled repositories (without refresh) and search for occurrences of regular expression \fINAME\fR in package names or dependencies\&. In case \fIDIR\fR denotes a directory containing a solver test\-case, repositories and settings provided by the test\-case are loaded instead\&. +.sp +A solver test\-case is an abstract of repositories, packages, hardware and dependency resolution related settings which can be created by using zyppers \fB\-\-debug\-solver\fR option\&. Attached to a bug report the test\-case helps investigating the reported behavior\&. Options and output of this command are tailored to this use\-case and may change as needed\&. +.sp +Reported matches show the packages \fIinternal id\fR, \fIname\fR, \fIversion\fR and \fIarchitecture\fR, \fIpriority\fR and name of the providing \fIrepository\fR, \fIvendor\fR, \fIbuildtime\fR and the locations matching \fINAME\fR\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +2431 zypper\-1\&.9\&.16\-22\&.2\&.x86_64 (99)@System openSUSE 1400499579 + nam: zypper +40947 zypper\-1\&.9\&.3\-1\&.1\&.x86_64 (99)repo\-oss (13\&.1) openSUSE 1383049437 + nam: zypper +56140 zypper\-1\&.9\&.16\-22\&.2\&.x86_64 (99)repo\-oss\-update (13\&.1) openSUSE 1400499579 + nam: zypper +.fi +.if n \{\ +.RE +.\} +.SH "OPTIONS" +.PP +\fB\-\-root\fR \fIDIR\fR +.RS 4 +Load repos from the system located below +\fIDIR\fR\&. If +\fIDIR\fR +denotes a solver test\-case, the test\-case is loaded\&. +.RE +.PP +\fB\-\-installed\fR +.RS 4 +Process installed packages only\&. +.RE +.PP +\fB\-i\fR/\fB\-I\fR +.RS 4 +Turn on/off case insensitive search (default on) +.RE +.PP +\fB\-n\fR/\fB\-N\fR +.RS 4 +Turn on/off looking for names (default on) +.RE +.PP +\fB\-p\fR/\fB\-P\fR +.RS 4 +Turn on/off looking for provides (default off) +.RE +.PP +\fB\-r\fR/\fB\-R\fR +.RS 4 +Turn on/off looking for requires (default off) +.RE +.PP +\fB\-c\fR/\fB\-C\fR +.RS 4 +Turn on/off looking for conflicts (default off) +.RE +.PP +\fB\-o\fR/\fB\-O\fR +.RS 4 +Turn on/off looking for obsoletes (default off) +.RE +.PP +\fB\-m\fR/\fB\-M\fR +.RS 4 +Turn on/off looking for recommends (default off) +.RE +.PP +\fB\-s\fR/\fB\-S\fR +.RS 4 +Turn on/off looking for supplements (default off) +.RE +.PP +\fB\-a\fR +.RS 4 +Short for +\fB\-n \-p \-r\fR +.RE +.PP +\fB\-A\fR +.RS 4 +Short for +\fB\-n \-P \-R\fR +.RE +.PP +\fB\-D\fR \fIPKG\fR +.RS 4 +Dump dependencies of package +\fIPKG\fR +(exact name)\&. +.RE +.SH "AUTHORS" +.sp +Michael Andres +.SH "SEE ALSO" +.sp +zypper(8) diff --git a/libzypp/doc/zypp-NameReqPrv.1.txt b/libzypp/doc/zypp-NameReqPrv.1.txt new file mode 100644 index 0000000..9135a44 --- /dev/null +++ b/libzypp/doc/zypp-NameReqPrv.1.txt @@ -0,0 +1,72 @@ +zypp-NameReqPrv(1) +================== +:man manual: LIBZYPP +:man source: libzypp + + +NAME +---- +zypp-NameReqPrv - Investigate packages and dependencies in solver test-cases + + +SYNOPSIS +-------- +*zypp-NameReqPrv* [*--root* 'DIR'] [['OPTIONS'] 'NAME'...]... + + +DESCRIPTION +----------- +Load all enabled repositories (without refresh) and search for occurrences of regular expression 'NAME' in package names or dependencies. In case 'DIR' denotes a directory containing a solver test-case, repositories and settings provided by the test-case are loaded instead. + +A solver test-case is an abstract of repositories, packages, hardware and dependency resolution related settings which can be created by using zyppers *--debug-solver* option. Attached to a bug report the test-case helps investigating the reported behavior. Options and output of this command are tailored to this use-case and may change as needed. + +Reported matches show the packages 'internal id', 'name', 'version' and 'architecture', 'priority' and name of the providing 'repository', 'vendor', 'buildtime' and the locations matching 'NAME'. + +-------------------- +2431 zypper-1.9.16-22.2.x86_64 (99)@System openSUSE 1400499579 + nam: zypper +40947 zypper-1.9.3-1.1.x86_64 (99)repo-oss (13.1) openSUSE 1383049437 + nam: zypper +56140 zypper-1.9.16-22.2.x86_64 (99)repo-oss-update (13.1) openSUSE 1400499579 + nam: zypper +-------------------- + + +OPTIONS +------- +*--root* 'DIR':: + Load repos from the system located below 'DIR'. If 'DIR' denotes a solver test-case, the test-case is loaded. +*--installed*:: + Process installed packages only. +*-i*/*-I*:: + Turn on/off case insensitive search (default on) +*-n*/*-N*:: + Turn on/off looking for names (default on) +*-p*/*-P*:: + Turn on/off looking for provides (default off) +*-r*/*-R*:: + Turn on/off looking for requires (default off) +*-c*/*-C*:: + Turn on/off looking for conflicts (default off) +*-o*/*-O*:: + Turn on/off looking for obsoletes (default off) +*-m*/*-M*:: + Turn on/off looking for recommends (default off) +*-s*/*-S*:: + Turn on/off looking for supplements (default off) +*-a*:: + Short for *-n -p -r* +*-A*:: + Short for *-n -P -R* +*-D* 'PKG':: + Dump dependencies of package 'PKG' (exact name). + + +AUTHORS +------- +Michael Andres + + +SEE ALSO +-------- +zypper(8) diff --git a/libzypp/libzypp.pc.cmake b/libzypp/libzypp.pc.cmake index 7d64861..1582d9f 100644 --- a/libzypp/libzypp.pc.cmake +++ b/libzypp/libzypp.pc.cmake @@ -1,7 +1,7 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@LIB_INSTALL_DIR@/zypp libdir=@LIB_INSTALL_DIR@ -includedir=@CMAKE_INSTALL_PREFIX@/include +includedir=@INCLUDE_INSTALL_DIR@ Name: @PACKAGE@ Version: @VERSION@ diff --git a/libzypp/libzypp.spec.cmake b/libzypp/libzypp.spec.cmake index f9313d5..b40ef03 100644 --- a/libzypp/libzypp.spec.cmake +++ b/libzypp/libzypp.spec.cmake @@ -1,7 +1,7 @@ # # spec file for package libzypp # -# Copyright (c) 2005-2011 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2005-2013 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -15,17 +15,17 @@ # Please submit bugfixes or comments via http://bugs.opensuse.org/ # -# norootforbuild -%define force_gcc_46 0 +%define force_gcc_46 0 Name: @PACKAGE@ +Version: @VERSION@ +Release: 0 License: GPL-2.0+ +Url: git://gitorious.org/opensuse/libzypp.git +Summary: Package, Patch, Pattern, and Product Management Group: System/Packages BuildRoot: %{_tmppath}/%{name}-%{version}-build -Summary: Package, Patch, Pattern, and Product Management -Version: @VERSION@ -Release: 1 Source: %{name}-%{version}.tar.bz2 Source1: %{name}-rpmlintrc Provides: yast2-packagemanager @@ -33,7 +33,8 @@ Obsoletes: yast2-packagemanager # Features we provide (update doc/autoinclude/FeatureTest.doc): Provides: libzypp(plugin) = 0 -Provides: libzypp(plugin:commit) = 0 +Provides: libzypp(plugin:appdata) = 0 +Provides: libzypp(plugin:commit) = 1 Provides: libzypp(plugin:services) = 0 Provides: libzypp(plugin:system) = 0 Provides: libzypp(plugin:urlresolver) = 0 @@ -61,6 +62,7 @@ BuildRequires: gcc-c++ >= 4.6 %endif BuildRequires: gettext-devel BuildRequires: graphviz +BuildRequires: graphviz-gnome BuildRequires: libxml2-devel %if 0%{?suse_version} != 1110 # No libproxy on SLES @@ -73,8 +75,9 @@ BuildRequires: pkgconfig BuildRequires: pkg-config %endif -BuildRequires: libsolv-devel +BuildRequires: libsolv-devel >= 0.6.7 %if 0%{?suse_version} >= 1100 +BuildRequires: libsolv-tools %requires_eq libsolv-tools %else Requires: libsolv-tools @@ -131,29 +134,21 @@ Requires: libcurl >= %{min_curl_version} %description Package, Patch, Pattern, and Product Management -Authors: --------- - Michael Andres - Jiri Srain - Stefan Schubert - Duncan Mac-Vicar - Klaus Kaempf - Marius Tomaschewski - Stanislav Visnovsky - Ladislav Slezak - %package devel -License: GPL-2.0+ -Requires: libzypp = %{version} +Summary: Package, Patch, Pattern, and Product Management - developers files +Group: Development/Libraries/C and C++ +Provides: yast2-packagemanager-devel +Obsoletes: yast2-packagemanager-devel +Requires: boost-devel +Requires: bzip2 +Requires: glibc-devel +Requires: libstdc++-devel Requires: libxml2-devel +Requires: libzypp = %{version} Requires: openssl-devel +Requires: popt-devel Requires: rpm-devel -Requires: glibc-devel Requires: zlib-devel -Requires: bzip2 -Requires: popt-devel -Requires: boost-devel -Requires: libstdc++-devel %if 0%{?suse_version} >= 1130 || 0%{?fedora_version} >= 16 Requires: libudev-devel %else @@ -177,24 +172,16 @@ Requires: libcurl-devel >= %{min_curl_version} %else Requires: libsolv-devel %endif -Summary: Package, Patch, Pattern, and Product Management - developers files -Group: System/Packages -Provides: yast2-packagemanager-devel -Obsoletes: yast2-packagemanager-devel -%description -n libzypp-devel +%description devel Package, Patch, Pattern, and Product Management - developers files -Authors: --------- - Michael Andres - Jiri Srain - Stefan Schubert - Duncan Mac-Vicar - Klaus Kaempf - Marius Tomaschewski - Stanislav Visnovsky - Ladislav Slezak +%package devel-doc +Summary: Package, Patch, Pattern, and Product Management - developers files +Group: Documentation/HTML + +%description devel-doc +Package, Patch, Pattern, and Product Management - developers files %prep %setup -q @@ -210,13 +197,20 @@ export CFLAGS="$RPM_OPT_FLAGS" export CXXFLAGS="$RPM_OPT_FLAGS" unset TRANSLATION_SET unset EXTRA_CMAKE_OPTIONS -# SLE11-* might want its own translation set: -%if 0%{?suse_version} == 1110 +# Same codebase, but SLES may use it's own translation set. +# suse_version +# 1110 SLES11 +# 1315 SLES12 +%if 0%{?suse_version} == 1110 || 0%{?suse_version} == 1315 if [ -f ../po/sle-zypp-po.tar.bz ]; then export TRANSLATION_SET=sle-zypp - export EXTRA_CMAKE_OPTIONS="-DDISABLE_LIBPROXY=ON" fi %endif +# No libproxy on SLE11 +%if 0%{?suse_version} == 1110 +export EXTRA_CMAKE_OPTIONS="-DDISABLE_LIBPROXY=ON" +%endif + cmake -DCMAKE_INSTALL_PREFIX=%{_prefix} \ -DDOC_INSTALL_DIR=%{_docdir} \ -DLIB=%{_lib} \ @@ -253,6 +247,7 @@ mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/vendors.d mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/multiversion.d mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins +mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins/appdata mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins/commit mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins/services mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins/system @@ -356,14 +351,18 @@ rm -rf "$RPM_BUILD_ROOT" %{_datadir}/zypp %{_bindir}/* %{_libdir}/libzypp*so.* -%doc %{_mandir}/man5/locks.5.* +%doc %{_mandir}/man1/*.1.* +%doc %{_mandir}/man5/*.5.* %files devel %defattr(-,root,root) %{_libdir}/libzypp.so -%{_docdir}/%{name} %{_includedir}/zypp %{_datadir}/cmake/Modules/* %{_libdir}/pkgconfig/libzypp.pc +%files devel-doc +%defattr(-,root,root) +%{_docdir}/%{name} + %changelog diff --git a/libzypp/mkChangelog b/libzypp/mkChangelog index 12a3a77..82ba368 100755 --- a/libzypp/mkChangelog +++ b/libzypp/mkChangelog @@ -84,10 +84,18 @@ function getversion() { printf "LAST_COMPAT='%s'\n", lastcompat printf "THIS_RELEASE='%s'\n", major"."minor"."patch printf "THIS_COMPAT='%s'\n", compatminor + printf "THIS_MINOR='%s'\n", minor + printf "THIS_PATCH='%s'\n", patch } ' } +function setversion() { + local KEY="$1" + local VAL="$2" + sed -i "s/^ *SET *( *${KEY} .*/SET(${KEY} \"${VAL}\")/" "$VERSIONFILE" +} + function sameVersion() { test "$LAST_RELEASE" == "$THIS_RELEASE" -a "$LAST_COMPAT" == "$THIS_COMPAT" } @@ -107,13 +115,35 @@ function newchangesentry() { echo "" } +function is_fast_forward() { + git fetch + test "$(git rev-list HEAD..origin/$(git name-rev --name-only HEAD) --count)" == "0" +} + +is_fast_forward || { + Recho "!!!" + Recho "!!! Branch is not fast-forward. Pull changes first." + Recho "!!!" + exit 7 +} + git status --porcelain | grep '^[^ ?]' | grep -v "$VERSIONFILE\|$CHANGESFILE" && { Becho "!!! Files other than version and changes are added to the index." Becho "!!! Doing dryrun..." DRYRUN=1 } + +# A tag for $LAST_RELEASE must exist! +eval $(getversion) +git rev-parse -q --verify "$LAST_RELEASE" >/dev/null || { + Recho "!!!" + Recho "!!! There is no LAST_RELEASE tag '$LAST_RELEASE'. Check manually. " + Recho "!!! (git tag -m 'tagging $LAST_RELEASE' '$LAST_RELEASE' ?commit?)" + Recho "!!!" + exit 8 +} + if [ "$DRYRUN" == "1" ]; then - eval $(getversion) newchangesentry sameVersion && { Becho "!!! Version is unchanged at $LAST_RELEASE ($LAST_COMPAT)." @@ -121,7 +151,6 @@ if [ "$DRYRUN" == "1" ]; then exit 0 fi - # check version file # while true; do @@ -129,21 +158,39 @@ while true; do # $LAST_COMPAT # $THIS_RELEASE # $THIS_COMPAT - eval $(getversion) sameVersion && { newchangesentry Becho "!!! Version is unchanged at $LAST_RELEASE ($LAST_COMPAT)." - read -n 1 -p "$(Gecho "(a)bort, (c)ontinue, (e)dit version: ")" RES + read -n 1 -p "$(Gecho "(a)bort, (c)ontinue, (P) patch, (M) minor, (I) incompat minor, (e)dit version [e]: ")" RES echo - case "$RES" in + case "${RES:-e}" in [eE]*) $EDITOR $VERSIONFILE + eval $(getversion) continue ;; [cC]) Becho "!!! Leave $VERSIONFILE untouched" break ;; + [P]) + setversion LIBZYPP_PATCH $(($THIS_PATCH + 1)) + eval $(getversion) + continue + ;; + [M]) + setversion LIBZYPP_MINOR $(($THIS_MINOR + 1)) + setversion LIBZYPP_PATCH 0 + eval $(getversion) + continue + ;; + [I]) + setversion LIBZYPP_COMPATMINOR $(($THIS_MINOR + 1)) + setversion LIBZYPP_MINOR $(($THIS_MINOR + 1)) + setversion LIBZYPP_PATCH 0 + eval $(getversion) + continue + ;; *) errexit "aborted" ;; @@ -163,15 +210,16 @@ while [ "$RES" == "e" ]; do $EDITOR $TMPFILE echo awk '{print}/^----------/{n=n+1; if ( n == 2 ) exit 0; }' $TMPFILE - read -n 1 -p "$(Gecho "(a)bort, (c)ontinue, (s)ubmitt, (e)dit : ")" RES + read -n 1 -p "$(Gecho "(a)bort, (c)ontinue, (s)ubmitt, (e)dit [e]: ")" RES echo - case "$RES" in + case "${RES:-e}" in [eE]*) RES=e ;; [cCsS]) Becho "!!! Store new $CHANGESFILE" mv $TMPFILE $CHANGESFILE + chmod 644 $CHANGESFILE test "$RES" == "s" && { if [ "$LAST_RELEASE" == "$THIS_RELEASE" ]; then diff --git a/libzypp/package/libzypp.changes b/libzypp/package/libzypp.changes index 7dd4800..cd3824e 100644 --- a/libzypp/package/libzypp.changes +++ b/libzypp/package/libzypp.changes @@ -1,3 +1,984 @@ +------------------------------------------------------------------- +Wed Jan 21 10:28:49 CET 2015 - ma@suse.de + +- PathInfo: Deprecate major/minor in favor of new devMajor/devMinor. + The old names clash with GNU libc macros. +- version 14.35.0 (30) + +------------------------------------------------------------------- +Sun Jan 18 01:13:09 CET 2015 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Jan 15 01:13:12 CET 2015 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Mon Jan 12 15:04:17 CET 2015 - ma@suse.de + +- Properly propagate repo variables in service refresh. +- Let $ZYPP_REPO_RELEASEVER overwrite $releasever in .repo files + (bnc#911658) +- Call pool_set_rootdir to properly check for file conflicts. +- Use xgettext --boost to support boost-format (%N%) +- version 14.34.0 (30) + +------------------------------------------------------------------- +Sun Jan 11 01:13:15 CET 2015 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Jan 8 01:13:23 CET 2015 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Jan 1 01:13:29 CET 2015 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Sun Dec 21 01:13:33 CET 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Fri Dec 19 10:05:00 CET 2014 - ma@suse.de + +- Parse and offer productRegisterFlavor attribute (bnc#896224) +- version 14.33.0 (30) + +------------------------------------------------------------------- +Thu Dec 18 01:13:20 CET 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Wed Dec 17 18:44:26 CET 2014 - ma@suse.de + +- Improve conflict message for locked packages (bnc#828631) +- Fix broken de-escaping in str::splitEscaped (bnc#909772) +- cleanup loging +- version 14.32.2 (30) + +------------------------------------------------------------------- +Fri Dec 12 14:00:01 CET 2014 - ma@suse.de + +- CheckAccessDeleted: Filter PIDs running in a container (bnc#909143) +- version 14.32.1 (30) + +------------------------------------------------------------------- +Wed Dec 10 16:06:04 CET 2014 - ma@suse.de + +- suppress informal license (no need to accept) upon update (bnc#908976) +- version 14.32.0 (30) + +------------------------------------------------------------------- +Mon Dec 8 14:53:00 CET 2014 - ma@suse.de + +- Adapt to gpg-2.1 (bnc#908135) +- rpm: do not obsolete yast2-packagemanager-devel by libzypp-devel-doc +- replaceAll: fix endless loop on empty search string +- version 14.31.0 (30) + +------------------------------------------------------------------- +Thu Nov 27 07:40:30 UTC 2014 - dimstar@opensuse.org + +- Do not provide/obsolete yast2-packagemanager-devel by the -doc + package: the -devel package already does that. +- Minor .spec cleanup (remove Authors section). + +------------------------------------------------------------------- +Tue Nov 11 17:09:28 CET 2014 - ma@suse.de + +- Call rpm with '--noglob' (bnc#892431) +- Downloader: unify workflow downloading a (signed) master index file +- Fix iostream includes (fixes #34) +- Explicitly call libsolv:pool_setdisttype (fixes #36) +- version 14.30.2 (30) + +------------------------------------------------------------------- +Sun Nov 9 01:13:17 CET 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Sun Nov 2 01:14:10 CET 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Mon Oct 27 11:38:00 CET 2014 - ma@suse.de + +- doc: add hint to code 12 pattern packages +- MediaCurl: Fix URL path concatenation (bnc#901590) +- Move doxygen html doc to libzypp-devel-doc (bnc#901691) +- Remove non-breaking spaces from changes file +- Control lifetime of downloaded mirrorlist +- version 14.30.1 (30) + +------------------------------------------------------------------- +Thu Oct 16 11:03:11 CEST 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Wed Oct 15 15:07:09 CEST 2014 - ma@suse.de + +- Store baseurls in list as order expresses preference +- Support parsing multiple baseurls from a repo file (bnc#899510) +- Fix handling local mirrorlist= files in .repo (bnc#899510) +- Provide missing man pages (fixes #33) +- Enable building autodocs, translations and test per default on debian +- Fix several typos in output messages and comments (fixes #29) +- Make the include dir path configurable (fixes #27) +- version 14.30.0 (30) + +------------------------------------------------------------------- +Fri Oct 10 16:01:31 CEST 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 (bnc#899603) + +------------------------------------------------------------------- +Thu Oct 9 01:13:15 CEST 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Sun Oct 5 01:14:42 CEST 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Sun Sep 28 01:13:30 CEST 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Sep 25 17:59:06 CEST 2014 - ma@suse.de + +- Trigger appdata plugin when system repos have changed (bnc#866257) +- Protect against race when destructing globals +- BuildRequire libsolv-tools as libsolv-devel no longer does +- version 14.29.4 (29) + +------------------------------------------------------------------- +Thu Sep 25 01:15:42 CEST 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Tue Sep 23 17:07:45 CEST 2014 - ma@suse.de + +- Fix computation of userinstalled items (bnc#897404) +- version 14.29.3 (29) + +------------------------------------------------------------------- +Tue Sep 23 10:55:08 CEST 2014 - ma@suse.de + +- Adapt to API changes in rpm.4.12 +- SLE-12 (suse_version 1315) uses it's own translations set + (bnc#897176) +- version 14.29.2 (29) + +------------------------------------------------------------------- +Sun Sep 21 01:13:25 CEST 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Sep 18 15:47:50 CEST 2014 - ma@suse.de + +- Update sle-zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Sep 18 15:47:34 CEST 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Sep 18 15:46:11 CEST 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Wed Sep 17 13:18:23 CEST 2014 - ma@suse.de + +- adjust BuildRequires +- version 14.29.1 (29) + +------------------------------------------------------------------- +Tue Sep 16 10:45:39 CEST 2014 - ma@suse.de + +- DiskUsageCounter: Set growonly on detetcted snapshotting btrfs + partitions (bnc#896176) +- DiskUsageCounter: Allow MountPoint to store fstype +- DiskUsageCounter: Support setting 'growonly' partition hint + (bnc#896176) +- version 14.29.0 (29) + +------------------------------------------------------------------- +Fri Sep 5 12:46:57 CEST 2014 - ma@suse.de + +- Make Repository::isUpdateRepo also check for being referenced + by products (bnc#892579) +- Report repositories skipped as nonroot due to insufficient + permission (bnc#893260) +- version 14.28.0 (28) + +------------------------------------------------------------------- +Thu Sep 4 01:14:34 CEST 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Fri Aug 29 14:46:25 CEST 2014 - ma@suse.de + +- PackageProvider: consider toplevel cache if --root or --pkg-cachedir + is used. +- Cleanup orpahned cache dirs only at zypp.conf default locations + (bnc#891515) +- Remove orphaned package caches on refresh (bnc#888919) +- version 14.27.2 (27) + +------------------------------------------------------------------- +Sun Aug 24 01:16:00 CEST 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Mon Aug 18 14:01:06 CEST 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Jul 31 19:22:56 CEST 2014 - ma@suse.de + +- Fix gpg key creation/modification date computation to properly + update trusted keys stored in the rpm database. +- version 14.27.1 (27) + +------------------------------------------------------------------- +Mon Jul 28 11:32:40 CEST 2014 - mls@suse.de + +- reverted last commit to make yast2-pkg-bindings build again + +------------------------------------------------------------------- +Fri Jul 25 12:56:17 CEST 2014 - ma@suse.de + +- JobReport: extend callback to allow passing UserData +- hardlinkCopy must not fail if proc/sys/fs/protected_hardlink is on +- adapt to changed boost::error_category throw specifier +- version 14.27.0 (27) + +------------------------------------------------------------------- +Fri Jul 18 08:57:39 CEST 2014 - ma@suse.de + +- Execute install scripts with cwd==/ (bnc#886764) +- fix wrong '//' when extending URLs with an empty path (bnc#885254) +- version 14.26.1 (26) + +------------------------------------------------------------------- +Mon Jul 14 17:46:14 CEST 2014 - ma@suse.de + +- refreshService: add option to force repo status reset +- Strip local filenames and args from URL. +- version 14.26.0 (26) + +------------------------------------------------------------------- +Fri Jul 11 13:42:43 CEST 2014 - ma@suse.de + +- Support RepoInfo content keywords (FATE#316287) +- fix parsing repomd.xml twice +- version 14.25.0 (23) + +------------------------------------------------------------------- +Wed Jun 11 07:36:48 CEST 2014 - ma@suse.de + +- Patch: add isCategory/isSeverity convenience +- If available provide info in ServiceException +- version 14.24.0 (23) + +------------------------------------------------------------------- +Wed Jun 4 11:49:32 CEST 2014 - ma@suse.de + +- Cleanup orphanded service repos on the fly (bnc#649846) +- Service refresh must not attempt to modify plugin services +- version 14.23.0 (23) + +------------------------------------------------------------------- +Wed May 28 13:41:22 CEST 2014 - ma@suse.de + +- Fix service methods to throw ServiceException, not RepoException. +- version 14.22.0 (22) + +------------------------------------------------------------------- +Tue May 27 16:31:21 CEST 2014 - ma@suse.de + +- Let ServiceRefresh en-/disable repos with respect to previous state + and user modifications. +- RepoindexFileReader: support variable substitution +- Parse optional autorefresh attribute from repoindex.xml +- version 14.21.0 (20) + +------------------------------------------------------------------- +Wed May 14 13:52:38 CEST 2014 - ma@suse.de + +- Add DownloadResolvableReport::infoInCache +- Adjust transfer timeout settings (bnc#877405) +- Fix computation of update candidate (bnc#834858) +- version 14.20.0 (20) + +------------------------------------------------------------------- +Thu May 8 18:54:25 CEST 2014 - ma@suse.de + +- KeyRingReport: New infoVerify callback showing the trusted key + that will be used for verification. +- version 14.19.0 (19) + +------------------------------------------------------------------- +Sun May 4 01:15:49 CEST 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu May 1 01:15:38 CEST 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Mon Apr 28 15:34:44 CEST 2014 - ma@suse.de + +- Derive initial AutoInstalled file from history +- Target: maintain AutoInstalled database file +- version 14.18.0 (17) + +------------------------------------------------------------------- +Tue Apr 15 17:03:30 CEST 2014 - ma@suse.de + +- Factor out CommitPackageCache for standalone usage. (Fate#317077) +- version 14.17.5 (17) + +------------------------------------------------------------------- +Fri Apr 11 16:16:11 CEST 2014 - ma@suse.de + +- history: log %posttrans errors and output +- adapt to libsolv cannges +- version 14.17.4 (17) + +------------------------------------------------------------------- +Fri Apr 4 14:29:13 CEST 2014 - ma@suse.de + +- Log warning if baseproduct symlink is dangling or missing +- version 14.17.3 (17) + +------------------------------------------------------------------- +Thu Apr 3 19:18:48 CEST 2014 - ma@suse.de + +- RepoManager: Fix RepoStatus computation and refresh of PLAINDIR repos. +- Recreate solv file caches if content may change even if raw metadata + are unchanged (here: new pattern, product and application data). +- version 14.17.2 (17) + +------------------------------------------------------------------- +Wed Apr 2 18:09:47 CEST 2014 - ma@suse.de + +- CpeId: Basic functionality incl. matching +- New SetRelationMixin +- version 14.17.1 (17) + +------------------------------------------------------------------- +Mon Mar 31 10:23:42 CEST 2014 - ma@suse.de + +- Use dummy licenses in test data (bnc#862471) +- Install zypp-NameReqPrv helper for evaluating testcases. +- version 14.17.0 (17) + +------------------------------------------------------------------- +Tue Mar 18 14:55:11 CET 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Wed Feb 26 15:06:06 CET 2014 - ma@suse.de + +- Ignore failed-eject-exception on media change (bnc#865705) +- version 14.16.1 (16) + +------------------------------------------------------------------- +Tue Feb 25 13:42:13 CET 2014 - ma@suse.de + +- Remove duplicate code detecting known kinds and move it to + ResKind::explicitBuiltin. +- version 14.16.0 (16) + +------------------------------------------------------------------- +Sun Feb 23 21:52:55 CET 2014 - ma@suse.de + +- Optionally exclude suggested packages from pattern content (bnc#857671) +- Fix pattern content for auto-pattens (bnc#864087) +- Don't report missing filelists for non-packages (bnc#864314) +- adapt to new rpm weak dependency tags +- version 14.15.0 (15) + +------------------------------------------------------------------- +Fri Feb 14 13:51:46 CET 2014 - ma@suse.de + +- Provide ContentIdentifier of required update repositories in Product + (Fate#316160) +- Support CpeId in Repository and Product attributes (Fate#316160) +- Add API for retrieving repository ContentRevision and ContentIdentifier + (Fate#316160) +- version 14.14.0 (14) + +------------------------------------------------------------------- +Thu Feb 13 10:28:24 CET 2014 - ma@suse.de + +- Adjust solver defaults to changed soft lock handling (bnc#863275) +- Avoid confusing solver decisions by not storing soft locks (bnc#863275) +- version 14.13.0 (13) + +------------------------------------------------------------------- +Tue Feb 11 21:22:58 CET 2014 - ma@suse.de + +- Add Product::endOfLife attribute (Fate#316172) +- Let Product::shortName fallback to name. +- Remove license text from test data (bnc#862471) +- version 14.12.0 (12) + +------------------------------------------------------------------- +Sun Feb 2 01:13:59 CET 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Fri Jan 31 19:09:28 CET 2014 - ma@suse.de + +- Introduce new solvable kind: Application (as provided by appdata.xml) +- version 14.11.0 (7) + +------------------------------------------------------------------- +Fri Jan 31 17:37:29 CET 2014 - ma@suse.de + +- String helper for printing indented text. +- Offer translated names for dependency types. +- version 14.10.0 (7) + +------------------------------------------------------------------- +Thu Jan 30 01:13:40 CET 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Wed Jan 29 10:28:16 CET 2014 - ma@suse.de + +- No fileconflict check if DownloadOnly. +- version 14.9.0 (7) + +------------------------------------------------------------------- +Sat Jan 25 17:07:45 CET 2014 - ma@suse.de + +- Collect and execute %posttrans scripts delayed (Fate#313506) +- BuildRequire libsolv implementing (Fate#309385) +- version 14.8.0 (7) + +------------------------------------------------------------------- +Fri Jan 24 11:26:52 CET 2014 - ma@suse.de + +- Patterns are no longer pseudo installed (Fate#309385) +- version 14.7.0 (7) + +------------------------------------------------------------------- +Fri Jan 24 08:41:13 CET 2014 - ma@suse.de + +- Check for file conflicts in commit (bnc#673720) +- Add asUserSting: human readable (translated) string representation +- Add file conflict detection during commit (bnc#673720) +- Add Transaction::installedResult +- version 14.6.0 (6) + +------------------------------------------------------------------- +Mon Jan 20 17:14:48 CET 2014 - ma@suse.de + +- Fix cleanup code removing the @System solv file. (bnc#853065) +- Fix missing priority in RepoInfo::dumpAsXML (bnc#855845) +- version 14.5.0 (4) + +------------------------------------------------------------------- +Tue Jan 14 18:38:49 CET 2014 - ma@suse.de + +- Improve ProgressData reporting. +- Allow xml::escape directly dumping to a stream. +- Add support for repo authentication using SSL client certificates + (bnc#683914) +- Enhance Queue to perform COW +- fix documentation +- version 14.4.0 (4) + +------------------------------------------------------------------- +Thu Jan 9 01:13:40 CET 2014 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Fri Dec 13 19:36:34 CET 2013 - ma@suse.de + +- Polish DiskUsageCounter +- Add Bitmap type (aka sat::Map) +- Remove obsolete DiskUsage class +- version 14.3.0 (3) + +------------------------------------------------------------------- +Thu Dec 12 18:01:18 CET 2013 - ma@suse.de + +- Fix disk usage computation for single packages (bnc#852943) +- version 14.2.1 (2) + +------------------------------------------------------------------- +Wed Dec 4 12:54:30 UTC 2013 - jreidinger@suse.com + +- Drop package-manager script as it is already deprecated and + packagekit usage in desktop invalidates it. If someone really + need it, then place it to proper top level package which can + decide what GUI is proper for given task. + +------------------------------------------------------------------- +Wed Nov 20 16:32:30 CET 2013 - ma@suse.de + +- Extend commit plugin to send the transaction list (Fate#316203) +- Add base/Json.h: JSON encoder for e.g. sending data to plugins +- Re-evaluate dropped packages list on upgrade, even if product + remains unchanged (bnc#849251). +- Add ppc64le architecture +- Add m68k architecture +- version 14.2.0 (2) + +------------------------------------------------------------------- +Fri Oct 25 14:21:31 CEST 2013 - ma@suse.de + +- Always properly initialize pool storage (bnc#846565) +- version 14.1.1 (0) + +------------------------------------------------------------------- +Thu Oct 17 17:57:54 CEST 2013 - ma@suse.de + +- Add Package isCached and cachedLocation methods +- fixed PluginFrame::hasKey +- version 14.1.0 (0) + +------------------------------------------------------------------- +Thu Oct 10 01:13:48 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Sun Oct 6 01:13:51 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Oct 3 01:14:59 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Wed Oct 2 19:25:58 CEST 2013 - ma@suse.de + +- fix handling symlinks in export pathname on NFSv4 (bnc#804544) +- Bump major version for Factory + 13.1 is continued on SuSE-Code-13_1-Branch +- version 14.0.0 (0) + +------------------------------------------------------------------- +Sun Sep 29 01:15:02 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Sun Sep 22 01:14:26 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Wed Sep 18 17:06:06 CEST 2013 - ma@suse.de + +- Allow multiversionSpec manipulation in ZConfig +- Fix string hexdecoding +- Avoid parsing gpg subkeys but still parse multiple keys +- version 13.7.0 (6) + +------------------------------------------------------------------- +Sun Sep 15 01:14:55 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Sep 12 01:15:29 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Sep 5 01:13:43 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Mon Sep 2 17:04:37 CEST 2013 - ma@suse.de + +- Avoid parsing gpg subkeys +- Use explicit operator bool in TmpPath +- Must keep legacy rpm level flag (bnc#838039) +- version 13.6.0 (6) + +------------------------------------------------------------------- +Sun Sep 1 01:14:03 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Aug 29 01:13:44 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Tue Aug 27 19:10:37 CEST 2013 - ma@suse.de + +- remove deprecated methods +- fix key expiry date parsing (bnc#828672) +- Provide additional keys data in case the ASCII armored blob + containes multiple keys +- No rpmdb key import in readony mode (bnc#828672) +- Fix rpmdb key import/export (bnc#828672) +- Reduce amount of gpg calls when importing/exporting keys. +- Add public accessible PublicKeyData/PublicKeyScanner classes +- fix ASCII armored PublicKey parsing (bnc#828672) +- fix typo (bnc#761985) +- Fix multiversion update candidate to respect an installed objects + arch and vendor (bnc#820444) +- fix logfile truncation introduced by previous fix for (bnc#825490) +- Swig can't handle move constructor +- Workaround bnc#819354 by executing rpm in /. (bnc#827609) +- Try to detect Arch_ppc64p7 (requires glibc-2.16: getauxval) +- Fix file probing via tftp:// (bnc#803316) +- Add armv7hl to armv6hl compat to be in sync with libsolv. +- Support for armv6hl +- version 13.5.0 (5) + +------------------------------------------------------------------- +Thu Aug 22 01:13:25 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Sun Aug 18 01:13:20 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Aug 15 01:13:27 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Aug 8 01:13:27 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Sun Aug 4 01:13:59 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Aug 1 01:13:52 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Jul 25 01:13:40 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Jul 18 01:13:43 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Sun Jul 14 01:13:38 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Jul 11 01:13:49 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Fri Jun 21 20:24:39 CEST 2013 - ma@suse.de + +- Fix testcases failing if local pathnames contain umlauts +- Pathname: add move constructor and fix assign +- Set logfile permission upon file creation only (bnc#825490) +- Add arch ppc64p7 +- version 13.4.0 (4) + +------------------------------------------------------------------- +Tue Jun 11 11:37:48 CEST 2013 - ma@suse.de + +- Speedup scanning for modaliases (bnc#824110) +- version 13.3.0 (2) + +------------------------------------------------------------------- +Sun May 26 01:13:15 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu May 23 01:13:13 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu May 16 12:22:48 CEST 2013 - ma@suse.de + +- Remove deprecated old stuff (aria2 support, + old InstallOrder, old History parser) +- version 13.2.0 (2) + +------------------------------------------------------------------- +Thu May 16 01:13:47 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Sun May 12 01:13:39 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu May 9 01:13:54 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu May 2 11:07:52 CEST 2013 - ma@suse.de + +- Discourage using SafeBool in favor of explicit operator bool +- version 13.1.0 (1) + +------------------------------------------------------------------- +Mon Apr 29 10:41:46 CEST 2013 - ma@suse.de + +- Testsuite: Workaround boost::thread being not header only since + boost-1.50 (boost ticket 7085) +- Adaptions to smart_pointer changes in boost-1.53; mainly introduce + explicit operator bool; constructible and comparable with nullptr_t. +- Bump major version for Factory + 12.x is continued on SuSE-Code-12_3-Branch +- version 13.0.0 (0) + +------------------------------------------------------------------- +Sun Apr 28 01:14:07 CEST 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Fri Apr 5 14:26:35 CEST 2013 - ma@suse.de + +- added new fuction zypp::ZYpp::provideSrcPackage +- Treat opensuse-education as separate vendor (bnc#812608) +- AArch64 support +- version 12.11.0 (0) + +------------------------------------------------------------------- +Wed Mar 27 12:31:17 CET 2013 - ma@suse.de + +- added tftp-support (bnc#803316) +- version 12.10.1 (0) + +------------------------------------------------------------------- +Tue Mar 26 13:06:21 CET 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Mar 21 01:13:45 CET 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Sun Mar 10 01:14:01 CET 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Mar 7 14:13:42 CET 2013 - ma@suse.de + +- Adapt to libsolv dataiterator fixes + (returning random data in some cases) +- Require and adapt to changes in libsolv-0.3.0 +- version 12.10.0 (0) + +------------------------------------------------------------------- +Thu Mar 7 01:13:25 CET 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Sun Mar 3 01:15:52 CET 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Wed Feb 27 08:41:18 CET 2013 - ma@suse.de + +- Rephrase error message if 'lsof' is not installed (bnc#694427) +- version 12.9.0 (0) + +------------------------------------------------------------------- +Fri Feb 15 12:49:18 CET 2013 - ma@suse.de + +- Handle dangling update script symlinks in instsys. (bnc#803751) +- version 12.8.1 (0) + +------------------------------------------------------------------- +Thu Feb 14 01:13:28 CET 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Feb 7 01:16:50 CET 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Mon Feb 4 12:35:51 CET 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Tue Jan 22 11:06:55 CET 2013 - ma@suse.de + +- make multicurl suppress progress reports for the metalink download +- work around libcurl bug that sometimes gives us old values in the + progress callback +- version 12.8.0 (0) + +------------------------------------------------------------------- +Fri Jan 18 14:07:50 CET 2013 - ma@suse.de + +- Reduce logging +- MediaMultiCurl: throw AbortRequestException if aborted by user +- version 12.7.0 (0) + +------------------------------------------------------------------- +Sun Jan 13 01:13:23 CET 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Sun Jan 6 01:13:17 CET 2013 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Thu Dec 27 01:13:27 CET 2012 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Mon Dec 17 13:31:15 CET 2012 - ma@suse.de + +- Add NamedValue<_Tp>: Simple value<>name mapping supporting aliases +- Enable zypper to remove zypp locks without evaluating the + query (bnc#792901) +- Configure curl to "not fix the BEAST attack" (bnc#779177) +- version 12.6.0 (0) + +------------------------------------------------------------------- +Sun Dec 16 01:13:16 CET 2012 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Mon Dec 3 14:31:59 CET 2012 - ma@suse.de + +- HistoryLogReader: new HistoryLogData based API for parsing the new + history file entries (fate#312521) + The old HistoryItem based API is deprecated but will + still be available for a while if you compile with + -DWITH_DEPRECATED_HISTORYITEM_API. +- Write userdata string to history log (fate#312521) +- Add HistoryLogReader testcases +- Adapt to libsolv 'medianr'-changes +- version 12.5.0 (0) + +------------------------------------------------------------------- +Thu Nov 22 01:14:42 CET 2012 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Sun Nov 18 01:13:44 CET 2012 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Tue Nov 13 15:40:10 CET 2012 - ma@suse.de + +- Forward userdata string to commit plugins in BEGINPLUGIN (fate#312521) +- Extend ZConfig to store a user defined string value (fate#312521) +- Add SIGSEGV handler trying to log a stack trace +- Add zypp::dumpBacktrace to dump current stack trace to a stream. +- Use gettext plural handling (bnc#784666) +- version 12.4.0 (0) + +------------------------------------------------------------------- +Sun Nov 4 01:13:21 CET 2012 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Wed Oct 24 10:40:38 CEST 2012 - ma@suse.de + +- Add simple sysconfig::write (bnc#766598) +- For installed products also filelists when trying to find the buddy + (bnc#784900) +- Provide information whether product license needs to be accepted. +- version 12.3.0 (0) + +------------------------------------------------------------------- +Thu Oct 18 01:13:43 CEST 2012 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Sun Oct 7 01:13:41 CEST 2012 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Mon Oct 1 11:00:42 CEST 2012 - ma@suse.de + +- Enable multiversion kernel and set multiversion.kernels in + /etc/zypp/zypp.conf to keep the latest, latest-1 and the running. +- Fix typo (bnc#782801) +- Relax evaluation of patch category tags (case insensitive) + +------------------------------------------------------------------- +Sun Sep 30 01:13:18 CEST 2012 - ma@suse.de + +- Update zypp-po.tar.bz2 + +------------------------------------------------------------------- +Sun Sep 16 01:14:34 CEST 2012 - ma@suse.de + +- Update zypp-po.tar.bz2 + ------------------------------------------------------------------- Wed Sep 12 10:28:00 CEST 2012 - ma@suse.de @@ -12,7 +993,7 @@ Sun Sep 9 01:13:25 CEST 2012 - ma@suse.de ------------------------------------------------------------------- Wed Sep 5 11:56:54 CEST 2012 - gs@suse.de -- Provide Target::reload() +- Provide Target::reload() - version 12.1.0 (0) ------------------------------------------------------------------- @@ -38,7 +1019,7 @@ Thu Aug 16 01:13:43 CEST 2012 - ma@suse.de ------------------------------------------------------------------- Fri Aug 10 12:53:47 CEST 2012 - ma@suse.de -- Implement $ZYPP_LOCK_TIMEOUT: number of seconds to wait for a +- Implement $ZYPP_LOCK_TIMEOUT: number of seconds to wait for a zypplock becoming available (bnc#772965) - Unify update-scripts with same content(md5sum) (bnc#773575) - version 12.0.1 (0) @@ -189,7 +1170,7 @@ Thu Apr 19 01:14:57 CEST 2012 - ma@suse.de Wed Apr 18 18:38:06 CEST 2012 - ma@suse.de - Fix install progress hopping back and forth -- Try to create a missing destination dir before switching to tmp +- Try to create a missing destination dir before switching to tmp space (bnc#755239) ------------------------------------------------------------------- @@ -312,7 +1293,7 @@ Thu Nov 17 01:13:15 CET 2011 - ma@suse.de ------------------------------------------------------------------- Fri Nov 11 13:38:42 CET 2011 - ma@suse.de -- Try to find and use some CD/DVD device even if HAL/UDEV detection +- Try to find and use some CD/DVD device even if HAL/UDEV detection fails (bnc#724807) - Static initialization problem fixes (by Harald Fernengel) - version 10.3.4 (3) @@ -7155,7 +8136,7 @@ Fri Aug 11 17:01:33 CEST 2006 - dmacvicar@suse.de - forward port 3924:3939 - Add explicit finish callbacks for subtasks during ProvidePackage -  to avoid UI confusion. + to avoid UI confusion. - rev3957 ------------------------------------------------------------------- @@ -7246,7 +8227,7 @@ Tue Jul 18 17:42:45 CEST 2006 - dmacvicar@suse.de Tue Jul 18 12:56:17 CEST 2006 - dmacvicar@suse.de - Digest: Don't read the stream character wise but reading blocks, -  as advised by matz profiling. + as advised by matz profiling. - r3819 ------------------------------------------------------------------- @@ -7439,7 +8420,7 @@ Wed Jun 7 01:00:05 CEST 2006 - dmacvicar@suse.de - Fixes unneeded file download, and add download callbacks (still need yast side) #181204 and #160206 - Fix stalle tmpdir due to cyclic references, using a master -  TmpDir for zypp. # 178292 + TmpDir for zypp. # 178292 ------------------------------------------------------------------- Wed Jun 7 00:02:18 CEST 2006 - ma@suse.de @@ -7542,11 +8523,11 @@ Wed May 24 15:30:32 CEST 2006 - dmacvicar@suse.de - dont pass root on init but before. - implement rpm db modification timestamp -  not used yet + not used yet - move Helix source to testsuite out of the solver so we can use it for target, storage tests - add Source_Ref::timestamp(), default to now() -  in order to implement smart sync of sources by zmd + in order to implement smart sync of sources by zmd - don't parse desc and summary twice - fix a segfault with tranlated text - fix broken size tag introduced in rev 3427 @@ -7759,7 +8740,7 @@ Wed May 3 17:40:45 CEST 2006 - dmacvicar@suse.de Wed May 3 15:34:00 CEST 2006 - dmacvicar@suse.de - use --no-default-keyring to avoid creating a -  default gpg dir in / (#171055) + default gpg dir in / (#171055) - rev 3335 ------------------------------------------------------------------- diff --git a/libzypp/po/createPot b/libzypp/po/createPot index 1fb1485..4629c23 100755 --- a/libzypp/po/createPot +++ b/libzypp/po/createPot @@ -10,4 +10,4 @@ SRCFILES=`find examples tools zypp \ -o -name "*.cc" \ -o -name "*.cpp"` #calling xgettext with the sourcefiles -xgettext -s --no-wrap --add-comments --add-location --keyword=_ --keyword=_:1,2 --keyword=__ --keyword=N_ --foreign-user --copyright-holder="SuSE Linux Products GmbH, Nuernberg" --default-domain=libzypp --output="$POTFILE" $SRCFILES +xgettext -L C++ --boost -s --no-wrap --add-comments --add-location --keyword=_ --keyword=_:1,2 --keyword=__ --keyword=N_ --foreign-user --copyright-holder="SuSE Linux Products GmbH, Nuernberg" --default-domain=libzypp --output="$POTFILE" $SRCFILES diff --git a/libzypp/po/sle-zypp-po.tar.bz2 b/libzypp/po/sle-zypp-po.tar.bz2 index ff9f10e..5057b68 100644 Binary files a/libzypp/po/sle-zypp-po.tar.bz2 and b/libzypp/po/sle-zypp-po.tar.bz2 differ diff --git a/libzypp/po/zypp-po.tar.bz2 b/libzypp/po/zypp-po.tar.bz2 index f133edb..07c62ea 100644 Binary files a/libzypp/po/zypp-po.tar.bz2 and b/libzypp/po/zypp-po.tar.bz2 differ diff --git a/libzypp/tests/CMakeLists.txt b/libzypp/tests/CMakeLists.txt index 6ba335d..356d7e5 100644 --- a/libzypp/tests/CMakeLists.txt +++ b/libzypp/tests/CMakeLists.txt @@ -13,5 +13,5 @@ ADD_SUBDIRECTORY( repo ) ADD_SUBDIRECTORY( sat ) ADD_CUSTOM_TARGET( ctest - COMMAND ctest -a + COMMAND ctest -VV -a ) diff --git a/libzypp/tests/data/openSUSE-11.1/content b/libzypp/tests/data/openSUSE-11.1/content index 6987b12..4c30fcf 100644 --- a/libzypp/tests/data/openSUSE-11.1/content +++ b/libzypp/tests/data/openSUSE-11.1/content @@ -18,7 +18,7 @@ META SHA1 1bfeb67fbb2e77f1309bd105d209549370d63184 packages.DU.gz META SHA1 2db9160217ca686f78a3e86de3de38955ad9fe3f packages.en.gz META SHA1 f4671fc99244c27e2a467a9bd11aa43a5fbe96b8 packages.gz META SHA1 73615d8e511ea4ad14bce617bfe18ea5de65395e patterns -HASH SHA1 cd4e142d292e299488a482144f38f9f8d4d61f01 license.tar.gz +#HASH SHA1 cd4e142d292e299488a482144f38f9f8d4d61f01 license.tar.gz HASH SHA1 7bd21d938f9fec0ec764ac4d46d80417baf5c94e control.xml HASH SHA1 e1499f54fba10d11ce6b6f0fc9c57c6a2ad49f83 media.1/info.txt HASH SHA1 d423ad41e93a51195a6264961e4a074c6d89359d boot/x86_64/bind diff --git a/libzypp/tests/data/openSUSE-11.1/license.tar.gz b/libzypp/tests/data/openSUSE-11.1/license.tar.gz deleted file mode 100644 index 87c8208..0000000 Binary files a/libzypp/tests/data/openSUSE-11.1/license.tar.gz and /dev/null differ diff --git a/libzypp/tests/lib/CMakeLists.txt b/libzypp/tests/lib/CMakeLists.txt index 5ff5932..6b9b324 100644 --- a/libzypp/tests/lib/CMakeLists.txt +++ b/libzypp/tests/lib/CMakeLists.txt @@ -7,4 +7,4 @@ ADD_LIBRARY(zypp_test_utils WebServer.cc ) -TARGET_LINK_LIBRARIES(zypp_test_utils mongoose zypp boost_thread-mt) +TARGET_LINK_LIBRARIES(zypp_test_utils mongoose zypp ${Boost_THREAD_LIBRARY}) diff --git a/libzypp/tests/lib/WebServer.cc b/libzypp/tests/lib/WebServer.cc index 4a215ed..f64492e 100644 --- a/libzypp/tests/lib/WebServer.cc +++ b/libzypp/tests/lib/WebServer.cc @@ -2,6 +2,8 @@ #include #include #include "boost/bind.hpp" +#include "boost/thread.hpp" +#include "boost/version.hpp" #include "zypp/base/Logger.h" #include "zypp/base/String.h" @@ -14,6 +16,35 @@ using namespace zypp; using namespace std; +#if ( BOOST_VERSION >= 105000 ) +// https://svn.boost.org/trac/boost/ticket/7085 +namespace boost +{ + namespace system + { + class fake_error_category : public error_category + { + virtual const char * name() const noexcept(true) + { return "falke_name"; } + virtual std::string message( int ev ) const + { return "falke_message"; } + }; + const error_category & generic_category() + { + static fake_error_category _e; + return _e; + throw std::exception(/*"boost/ticket/7085 workaound sucks :("*/); + } + const error_category & system_category() + { + static fake_error_category _e; + return _e; + throw std::exception(/*"boost/ticket/7085 workaound sucks :("*/); + } + } +} +#endif + static inline string hostname() { static char buf[256]; @@ -32,19 +63,19 @@ class WebServer::Impl public: Impl() {} - + virtual ~Impl() {} - + virtual string log() const { return string(); } - + virtual void start() {} virtual void stop() {} - + virtual void worker_thread() {} @@ -52,15 +83,15 @@ class WebServer::Impl { return 0; } - - + + private: friend Impl * rwcowClone( const Impl * rhs ); /** clone for RWCOW_pointer */ Impl * clone() const { return new Impl( *this ); } -}; +}; class WebServerWebrickImpl : public WebServer::Impl { @@ -69,7 +100,7 @@ class WebServerWebrickImpl : public WebServer::Impl : _docroot(root), _port(port), _stop(false), _stopped(true) { } - + ~WebServerWebrickImpl() { if ( ! _stopped ) @@ -81,15 +112,15 @@ class WebServerWebrickImpl : public WebServer::Impl return _port; } - + virtual void worker_thread() { _log.clear(); - + stringstream strlog(_log); string webrick_code = str::form("require \"webrick\"; s = WEBrick::HTTPServer.new(:Port => %d, :DocumentRoot => \"%s\"); trap(\"INT\"){ s.shutdown }; trap(\"SIGKILL\") { s.shutdown }; s.start;", _port, _docroot.c_str()); - + const char* argv[] = { "/usr/bin/ruby", @@ -100,18 +131,18 @@ class WebServerWebrickImpl : public WebServer::Impl ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true); string line; - + _stopped = false; - + while ( ! _stop ); - + MIL << "Thread end requested" << endl; //prog.close(); if ( prog.running() ) prog.kill(); MIL << "Thread about to finish" << endl; } - + virtual string log() const { return _log; @@ -126,12 +157,12 @@ class WebServerWebrickImpl : public WebServer::Impl _thrd.reset(); _stopped = true; } - + virtual void start() { - _thrd.reset( new boost::thread( boost::bind(&WebServerWebrickImpl::worker_thread, this) ) ); + //_thrd.reset( new boost::thread( boost::bind(&WebServerWebrickImpl::worker_thread, this) ) ); } - + zypp::Pathname _docroot; unsigned int _port; zypp::shared_ptr _thrd; @@ -149,15 +180,15 @@ class WebServerMongooseImpl : public WebServer::Impl , _stopped(true) { } - + ~WebServerMongooseImpl() { MIL << "Destroying web server" << endl; - + if ( ! _stopped ) stop(); } - + virtual void start() { if ( ! _stopped ) @@ -165,7 +196,7 @@ class WebServerMongooseImpl : public WebServer::Impl MIL << "mongoose server already running, stopping." << endl; stop(); } - + MIL << "Starting shttpd (mongoose)" << endl; _log.clear(); _ctx = mg_start(); @@ -174,7 +205,7 @@ class WebServerMongooseImpl : public WebServer::Impl ret = mg_set_option(_ctx, "ports", str::form("%d", _port).c_str()); if ( ret != 1 ) ZYPP_THROW(Exception(str::form("Failed to set port: %d", ret))); - + MIL << "Setting root directory to : '" << _docroot << "'" << endl; ret = mg_set_option(_ctx, "root", _docroot.c_str()); if ( ret != 1 ) @@ -188,12 +219,12 @@ class WebServerMongooseImpl : public WebServer::Impl return _port; } - + virtual string log() const { return _log; } - + virtual void stop() { MIL << "Stopping shttpd" << endl; @@ -202,7 +233,7 @@ class WebServerMongooseImpl : public WebServer::Impl _ctx = 0; _stopped = true; } - + mg_context *_ctx; zypp::Pathname _docroot; unsigned int _port; @@ -217,7 +248,7 @@ WebServer::WebServer(const Pathname &root, unsigned int port) #else : _pimpl(new WebServerMongooseImpl(root, port)) #endif -{ +{ } void WebServer::start() diff --git a/libzypp/tests/lib/WebServer.h b/libzypp/tests/lib/WebServer.h index ec62e41..be0f8e8 100644 --- a/libzypp/tests/lib/WebServer.h +++ b/libzypp/tests/lib/WebServer.h @@ -2,9 +2,6 @@ #ifndef ZYPP_TEST_WEBSERVER_H #define ZYPP_TEST_WEBSERVER_H -#include "boost/thread.hpp" -#include "boost/smart_ptr.hpp" - #include "zypp/Url.h" #include "zypp/Pathname.h" #include "zypp/base/PtrTypes.h" @@ -25,9 +22,9 @@ * web.start(); * * MediaSetAccess media( Url("http://localhost:9099"), "/" ); - * + * * // do something with the url - * + * * * web.stop(); * @@ -59,7 +56,7 @@ class WebServer * returns the base url where the webserver is listening */ zypp::Url url() const; - + /** * shows the log of last run */ diff --git a/libzypp/tests/parser/CMakeLists.txt b/libzypp/tests/parser/CMakeLists.txt index 92a1a8a..87949eb 100644 --- a/libzypp/tests/parser/CMakeLists.txt +++ b/libzypp/tests/parser/CMakeLists.txt @@ -5,4 +5,4 @@ ADD_SUBDIRECTORY(ws) ADD_TESTS( ProductFileReader ) ADD_TESTS( RepoFileReader ) ADD_TESTS( RepoindexFileReader ) - +ADD_TESTS( HistoryLogReader ) diff --git a/libzypp/tests/parser/HistoryLogReader_test.cc b/libzypp/tests/parser/HistoryLogReader_test.cc new file mode 100644 index 0000000..7300ab3 --- /dev/null +++ b/libzypp/tests/parser/HistoryLogReader_test.cc @@ -0,0 +1,49 @@ +#include "TestSetup.h" +#include "zypp/parser/HistoryLogReader.h" +#include "zypp/parser/ParseException.h" + +using namespace zypp; + +namespace +{ + bool ProcessData( const HistoryLogData::Ptr & ptr ) + { + DBG << ptr->date() << " | " << ptr << endl; + + return true; + } +} + + +BOOST_AUTO_TEST_CASE(basic) +{ + std::vector history; + parser::HistoryLogReader parser( TESTS_SRC_DIR "/parser/HistoryLogReader_test.dat", + parser::HistoryLogReader::Options(), + [&history]( HistoryLogData::Ptr ptr )->bool { + history.push_back( ptr ); + return true; + } ); + + BOOST_CHECK_EQUAL( parser.ignoreInvalidItems(), false ); + BOOST_CHECK_THROW( parser.readAll(), parser::ParseException ); + + parser.setIgnoreInvalidItems( true ); + BOOST_CHECK_EQUAL( parser.ignoreInvalidItems(), true ); + + history.clear(); + parser.readAll(); + + BOOST_CHECK_EQUAL( history.size(), 7 ); + BOOST_CHECK( dynamic_pointer_cast ( history[0] ) ); + BOOST_CHECK( dynamic_pointer_cast ( history[1] ) ); + BOOST_CHECK( dynamic_pointer_cast ( history[2] ) ); + BOOST_CHECK( dynamic_pointer_cast ( history[3] ) ); + BOOST_CHECK( dynamic_pointer_cast ( history[4] ) ); + BOOST_CHECK( dynamic_pointer_cast ( history[5] ) ); + BOOST_CHECK( dynamic_pointer_cast ( history[6] ) ); + + BOOST_CHECK_EQUAL( (*history[1])[HistoryLogDataInstall::USERDATA_INDEX], "trans|ID" ); // properly (un)escaped? + HistoryLogDataInstall::Ptr p = dynamic_pointer_cast( history[1] ); + BOOST_CHECK_EQUAL( p->userdata(), "trans|ID" ); // properly (un)escaped? +} diff --git a/libzypp/tests/parser/HistoryLogReader_test.dat b/libzypp/tests/parser/HistoryLogReader_test.dat new file mode 100644 index 0000000..26c7d67 --- /dev/null +++ b/libzypp/tests/parser/HistoryLogReader_test.dat @@ -0,0 +1,12 @@ +2009-09-29 07:24:46|radd |InstallationImage|file:/usr/src/packages/BUILD/openSUSE-images-11.2/gnome_cd/home/rpmdir| +2009-09-29 07:25:29|install|update-test-security|0-2.35|noarch|root@opensuse|InstallationImage|d99de2872270cbd436b0c10af85c286a1365a348|trans\|ID +2011-07-18 18:08:09|install|kernel-source|2.6.37.6-0.5.1|noarch||repo-update|7823612d9ca3de086c2cd4dca936f6a3f3e9313d| +# 2009-09-29 07:25:30 filesystem.rpm installed ok +# Additional rpm output: +# +2009-09-29 07:47:59|remove |PolicyKit-doc|0.9-15.20|x86_64|root@opensuse|trans\|ID +2009-09-29 07:47:32|rremove|InstallationImage| +2010-06-01 16:11:17|remove |xchat-python|2.8.6-43.13|x86_64|2848:y2base| +2010-06-01 16:11:17|bad |unknown action field +discard\|one field +discard|to fields but bad date diff --git a/libzypp/tests/parser/ProductFileReader_test.cc b/libzypp/tests/parser/ProductFileReader_test.cc index 3904883..e2b7246 100644 --- a/libzypp/tests/parser/ProductFileReader_test.cc +++ b/libzypp/tests/parser/ProductFileReader_test.cc @@ -19,6 +19,7 @@ BOOST_AUTO_TEST_CASE(basic) BOOST_CHECK_EQUAL( data.productline(), "" ); BOOST_CHECK_EQUAL( data.registerTarget(), "sle-11-i586" ); BOOST_CHECK_EQUAL( data.registerRelease(), "whatever" ); + BOOST_CHECK_EQUAL( data.registerFlavor(), "module" ); BOOST_CHECK_EQUAL( data.updaterepokey(), "A43242DKD" ); BOOST_REQUIRE_EQUAL( data.upgrades().size(), 2 ); diff --git a/libzypp/tests/parser/ProductFileReader_test.dat b/libzypp/tests/parser/ProductFileReader_test.dat index 3fe0033..74d36c0 100644 --- a/libzypp/tests/parser/ProductFileReader_test.dat +++ b/libzypp/tests/parser/ProductFileReader_test.dat @@ -39,6 +39,7 @@ This is the Server product of the SUSE Linux Enterprise edition. It is an altern sle-11-i586 whatever + module diff --git a/libzypp/tests/parser/RepoindexFileReader_test.cc b/libzypp/tests/parser/RepoindexFileReader_test.cc index dd1f25e..25b68ff 100644 --- a/libzypp/tests/parser/RepoindexFileReader_test.cc +++ b/libzypp/tests/parser/RepoindexFileReader_test.cc @@ -10,13 +10,13 @@ using std::stringstream; using std::string; using namespace zypp; -static string service = "" +static string service = "" "" + " path=\"products/foo\" distro_target=\"sle-%{distver}-%{arch}\" priority=\"20\"/>" "" + " path=\"products/bar\" distro_target=\"sle-%{distver}-%{arch}\" enabled=\"tRUe\" autorefresh=\"FaLsE\"/>" "" + " path=\"products/foo/updates\" distro_target=\"sle-%{distver}-%{arch}\" priority=\"1\"/>" ""; struct RepoCollector : private base::NonCopyable @@ -61,6 +61,8 @@ BOOST_AUTO_TEST_CASE(read_index_file) BOOST_CHECK_EQUAL(99, repo.priority()); // "Repository is explicitly enabled" BOOST_CHECK(repo.enabled()); + // "Repository autorefresh is explicitly disabled" + BOOST_CHECK(!repo.autorefresh()); } diff --git a/libzypp/tests/repo/CMakeLists.txt b/libzypp/tests/repo/CMakeLists.txt index 3f06bc0..53a3615 100644 --- a/libzypp/tests/repo/CMakeLists.txt +++ b/libzypp/tests/repo/CMakeLists.txt @@ -4,4 +4,4 @@ ADD_SUBDIRECTORY( susetags ) # to find the KeyRingTest receiver INCLUDE_DIRECTORIES( ${LIBZYPP_SOURCE_DIR}/tests/zypp ) -ADD_TESTS(RepoVariables ExtendedMetadata PluginServices MirrorList) +ADD_TESTS(RepoVariables ExtendedMetadata PluginServices MirrorList DUdata) diff --git a/libzypp/tests/repo/DUdata_test.cc b/libzypp/tests/repo/DUdata_test.cc new file mode 100644 index 0000000..27c56f1 --- /dev/null +++ b/libzypp/tests/repo/DUdata_test.cc @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include + +#include + +#include "zypp/base/Logger.h" +#include "zypp/base/Exception.h" +#include "zypp/RepoManager.h" +#include "zypp/ResPool.h" +#include "zypp/sat/Pool.h" +#include "zypp/PoolQuery.h" + +#include "KeyRingTestReceiver.h" +#include "TestSetup.h" + +using boost::unit_test::test_case; + +using namespace std; +using namespace zypp; +using namespace zypp::repo; +using namespace zypp::filesystem; + +#define TEST_DIR TESTS_SRC_DIR "/repo/susetags/data/dudata" + +PoolItem piFind( const std::string & name_r, const std::string & ver_r, bool installed_r = false ) +{ + PoolQuery q; + q.addDependency( sat::SolvAttr::name, name_r, Rel::EQ, Edition(ver_r) ); + q.setStatusFilterFlags( installed_r ? PoolQuery::INSTALLED_ONLY : PoolQuery::UNINSTALLED_ONLY ); + if ( q.size() != 1 ) + ZYPP_THROW(Exception(q.size()?"Ambiguous!":"Missing!")); + return PoolItem( *q.begin() ); +} + +typedef std::pair ByteSet; +namespace std +{ + inline std::ostream & operator<<( std::ostream & str, const ByteSet & obj ) + { return str << "<" << obj.first << "," << obj.second << ">"; } +} + +inline ByteSet mkByteSet( const DiskUsageCounter::MountPointSet & mps_r ) +{ return ByteSet( mps_r.begin()->commitDiff(), (++mps_r.begin())->commitDiff() ); } + +inline ByteSet mkByteSet( int grow_r , int norm_r ) +{ return ByteSet( ByteCount( grow_r, ByteCount::K ), ByteCount( norm_r, ByteCount::K ) ); } + +inline ByteSet getSize( const DiskUsageCounter & duc_r, const PoolItem & pi_r ) +{ return mkByteSet( duc_r.disk_usage( pi_r ) ); } + +inline ByteSet getSize( const DiskUsageCounter & duc_r, const ResPool & pool_r ) +{ return mkByteSet( duc_r.disk_usage( pool_r ) ); } + +inline void XLOG( const DiskUsageCounter & duc_r, const ResPool & pool_r ) +{ + for( const auto & pi : pool_r ) + { + USR << pi << endl; + } + WAR << duc_r.disk_usage( pool_r ) << endl; +} + +BOOST_AUTO_TEST_CASE(dudata) +{ + //KeyRingTestReceiver rec; + // rec.answerAcceptUnknownKey(true); + //rec.answerAcceptUnsignedFile(true); + // rec.answerImportKey(true); + + Pathname repodir( TEST_DIR ); + TestSetup test( Arch_x86_64 ); + test.loadTargetRepo( repodir/"system" ); + test.loadRepo( repodir/"repo", "repo" ); + + ResPool pool( ResPool::instance() ); + PoolItem ins( piFind( "dutest", "1.0", true ) ); + PoolItem up1( piFind( "dutest", "1.0" ) ); + PoolItem up2( piFind( "dutest", "2.0" ) ); + PoolItem up3( piFind( "dutest", "3.0" ) ); + + DiskUsageCounter duc( { DiskUsageCounter::MountPoint( "/grow", DiskUsageCounter::MountPoint::Hint_growonly ), + DiskUsageCounter::MountPoint( "/norm" ) } ); + //XLOG( duc, pool ); + + BOOST_CHECK_EQUAL( getSize( duc, ins ), mkByteSet( 5, 5 ) ); + BOOST_CHECK_EQUAL( getSize( duc, up1 ), mkByteSet( 15, 15 ) ); + BOOST_CHECK_EQUAL( getSize( duc, up2 ), mkByteSet( 45, 45 ) ); + BOOST_CHECK_EQUAL( getSize( duc, up3 ), mkByteSet( 0, 0 ) ); + + // delete installed size 5 g n + ins.status().setTransact( true, ResStatus::USER ); + BOOST_CHECK_EQUAL( getSize( duc, pool ), mkByteSet( 0, -5 ) ); + ins.status().setTransact( false, ResStatus::USER ); + + // install known DU size 15 g n + up1.status().setTransact( true, ResStatus::USER ); + BOOST_CHECK_EQUAL( getSize( duc, pool ), mkByteSet( 15, 15 ) ); // (multi)install (old stays) + ins.status().setTransact( true, ResStatus::USER ); + BOOST_CHECK_EQUAL( getSize( duc, pool ), mkByteSet( 15, 10 ) ); // update (old goes) + ins.status().setTransact( false, ResStatus::USER ); + up1.status().setTransact( false, ResStatus::USER ); + + // install unknown DU size 0/installed g n + up3.status().setTransact( true, ResStatus::USER ); + BOOST_CHECK_EQUAL( getSize( duc, pool ), mkByteSet( 5, 0 ) ); // (multi)install (n could be 5 too, but satsolver does not know about multinstall) + ins.status().setTransact( true, ResStatus::USER ); + BOOST_CHECK_EQUAL( getSize( duc, pool ), mkByteSet( 5, 0 ) ); // update (old goes) + ins.status().setTransact( false, ResStatus::USER ); + up3.status().setTransact( false, ResStatus::USER ); +} diff --git a/libzypp/tests/repo/ExtendedMetadata_test.cc b/libzypp/tests/repo/ExtendedMetadata_test.cc index 6160dd5..64d4de1 100644 --- a/libzypp/tests/repo/ExtendedMetadata_test.cc +++ b/libzypp/tests/repo/ExtendedMetadata_test.cc @@ -31,7 +31,7 @@ BOOST_AUTO_TEST_CASE(extended_metadata) KeyRingTestReceiver rec; //rec.answerAcceptUnknownKey(true); rec.answerAcceptUnsignedFile(true); - + // rec.answerImportKey(true); Pathname repodir(TEST_DIR ); @@ -39,16 +39,16 @@ BOOST_AUTO_TEST_CASE(extended_metadata) sat::Pool pool(sat::Pool::instance()); TestSetup test( Arch_x86_64 ); - test.loadRepo(Url(string("dir:") + repodir.absolutename().asString()), "updates"); + test.loadRepo(repodir.absolutename().asDirUrl(), "updates"); Repository repo = pool.reposFind("updates"); - + BOOST_CHECK_EQUAL( repo.generatedTimestamp(), Date(1227279057) ); - BOOST_CHECK_EQUAL( repo.suggestedExpirationTimestamp(), Date(1227279057 + 3600) ); + BOOST_CHECK_EQUAL( repo.suggestedExpirationTimestamp(), Date(1227279057 + 3600) ); // check that the attributes of product compatibility are ok int count = 0; - vector cpeids; + vector cpeids; vector labels; for_( it, @@ -62,8 +62,8 @@ BOOST_AUTO_TEST_CASE(extended_metadata) // there were 2 compatible products BOOST_CHECK_EQUAL( count, 2 ); - BOOST_CHECK_EQUAL( cpeids[0], "cpe://o:opensuse" ); - BOOST_CHECK_EQUAL( cpeids[1], "cpe://o:sle" ); + BOOST_CHECK_EQUAL( cpeids[0], "cpe:/o:opensuse" ); + BOOST_CHECK_EQUAL( cpeids[1], "cpe:/o:sle" ); BOOST_CHECK_EQUAL( labels[0], "openSUSE 11.0" ); BOOST_CHECK_EQUAL( labels[1], "SLE 11.0" ); @@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(extended_metadata) cpeids.clear(); labels.clear(); count = 0; - + for_( it, repo.updatesProductBegin(), repo.updatesProductEnd() ) @@ -83,18 +83,17 @@ BOOST_AUTO_TEST_CASE(extended_metadata) // the repo updates one product BOOST_CHECK_EQUAL( count, 1 ); - BOOST_CHECK_EQUAL( cpeids[0], "cpe://o:sle" ); + BOOST_CHECK_EQUAL( cpeids[0], "cpe:/o:sle" ); BOOST_CHECK_EQUAL( labels[0], "SLE 11.0" ); // because this product updates something, it _is_ an update repo BOOST_CHECK( repo.isUpdateRepo() ); - BOOST_CHECK( repo.providesUpdatesFor("cpe://o:sle") ); - BOOST_CHECK( ! repo.providesUpdatesFor("cpe://o:windows") ); - + BOOST_CHECK( repo.providesUpdatesFor(CpeId("cpe:/o:sle")) ); + BOOST_CHECK( ! repo.providesUpdatesFor(CpeId("cpe:/o:windows")) ); // reuse to count solvables count = 0; - + /** * Now check for the extended metadata of the packages */ @@ -110,14 +109,14 @@ BOOST_AUTO_TEST_CASE(extended_metadata) BOOST_CHECK(p); BOOST_CHECK(p->maybeUnsupported() ); BOOST_CHECK_EQUAL(p->vendorSupport(), VendorSupportUnknown ); - + } else if ( s.ident() == "foobar" ) { - count++; + count++; Package::Ptr p = asKind(makeResObject(s)); BOOST_CHECK(p); - BOOST_CHECK_EQUAL(p->vendorSupport(), VendorSupportUnsupported ); + BOOST_CHECK_EQUAL(p->vendorSupport(), VendorSupportUnsupported ); BOOST_CHECK(p->maybeUnsupported() ); } else if ( s.ident() == "foofoo" ) @@ -134,7 +133,7 @@ BOOST_AUTO_TEST_CASE(extended_metadata) { BOOST_FAIL(str::form("Repo has package not contemplated in test: %s", s.ident().c_str()).c_str()); } - + } // check that we actually found all testeable diff --git a/libzypp/tests/repo/susetags/Downloader_test.cc b/libzypp/tests/repo/susetags/Downloader_test.cc index 958d2d8..70fec59 100644 --- a/libzypp/tests/repo/susetags/Downloader_test.cc +++ b/libzypp/tests/repo/susetags/Downloader_test.cc @@ -28,26 +28,25 @@ BOOST_AUTO_TEST_CASE(susetags_download) keyring_callbacks.answerAcceptKey(KeyRingReport::KEY_TRUST_TEMPORARILY); Pathname p = DATADIR + "/stable-x86-subset"; - Url url("dir:" + p.asString()); - MediaSetAccess media(url); + MediaSetAccess media(p.asDirUrl()); RepoInfo repoinfo; repoinfo.setAlias("testrepo"); repoinfo.setPath("/"); susetags::Downloader downloader(repoinfo); filesystem::TmpDir tmp; - + Pathname localdir(tmp.path()); - + downloader.download(media,localdir); - + MIL << "All files downloaded" << endl; - + const char* files[] = { "/suse", "/suse/setup", "/suse/setup/descr", - "/suse/setup/descr/kde-10.3-71.i586.pat", + "/suse/setup/descr/kde-10.3-71.noarch.pat", "/suse/setup/descr/packages", "/suse/setup/descr/packages.DU", "/suse/setup/descr/packages.en", @@ -71,7 +70,7 @@ BOOST_AUTO_TEST_CASE(susetags_download) "/gpg-pubkey-0dfb3188-41ed929b.asc", NULL }; - + int i=0; while ( files[i] != NULL ) { @@ -87,24 +86,23 @@ BOOST_AUTO_TEST_CASE(susetags_gz_download) keyring_callbacks.answerAcceptKey(KeyRingReport::KEY_TRUST_TEMPORARILY); Pathname p = DATADIR + "/stable-x86-subset-gz"; - Url url("dir:" + p.asString()); - MediaSetAccess media(url); + MediaSetAccess media(p.asDirUrl()); RepoInfo repoinfo; repoinfo.setAlias("testrepo"); repoinfo.setPath("/"); susetags::Downloader downloader(repoinfo); filesystem::TmpDir tmp; - + Pathname localdir(tmp.path()); - + downloader.download(media,localdir); - + const char* files[] = { "/suse", "/suse/setup", "/suse/setup/descr", - "/suse/setup/descr/kde-10.3-71.i586.pat.gz", + "/suse/setup/descr/kde-10.3-71.noarch.pat.gz", "/suse/setup/descr/packages.gz", "/suse/setup/descr/packages.DU.gz", "/suse/setup/descr/packages.en.gz", @@ -130,7 +128,7 @@ BOOST_AUTO_TEST_CASE(susetags_gz_download) "/gpg-pubkey-0dfb3188-41ed929b.asc", NULL }; - + int i=0; while ( files[i] != NULL ) { diff --git a/libzypp/tests/repo/susetags/data/dudata/repo/content b/libzypp/tests/repo/susetags/data/dudata/repo/content new file mode 100644 index 0000000..f76a96e --- /dev/null +++ b/libzypp/tests/repo/susetags/data/dudata/repo/content @@ -0,0 +1,2 @@ +META SHA1 b75eeb1b3d231ccb6322c91417050520f992949c packages +META SHA1 cb96552f7a57eb21f3279310c1c339e6b22924d8 packages.DU diff --git a/libzypp/tests/repo/susetags/data/dudata/repo/media.1/media b/libzypp/tests/repo/susetags/data/dudata/repo/media.1/media new file mode 100644 index 0000000..d5aa1ef --- /dev/null +++ b/libzypp/tests/repo/susetags/data/dudata/repo/media.1/media @@ -0,0 +1,3 @@ +SUSE Linux Products GmbH +20070705102239 +1 diff --git a/libzypp/tests/repo/susetags/data/dudata/repo/suse/setup/descr/packages b/libzypp/tests/repo/susetags/data/dudata/repo/suse/setup/descr/packages new file mode 100644 index 0000000..0dce8f4 --- /dev/null +++ b/libzypp/tests/repo/susetags/data/dudata/repo/suse/setup/descr/packages @@ -0,0 +1,8 @@ +=Ver: 2.0 +##---------------------------------------- +=Pkg: dutest 1.0 1 x86_64 +##---------------------------------------- +=Pkg: dutest 2.0 1 x86_64 +##---------------------------------------- +=Pkg: dutest 3.0 1 x86_64 +##---------------------------------------- diff --git a/libzypp/tests/repo/susetags/data/dudata/repo/suse/setup/descr/packages.DU b/libzypp/tests/repo/susetags/data/dudata/repo/suse/setup/descr/packages.DU new file mode 100644 index 0000000..0cfa08e --- /dev/null +++ b/libzypp/tests/repo/susetags/data/dudata/repo/suse/setup/descr/packages.DU @@ -0,0 +1,16 @@ +=Ver: 2.0 +##---------------------------------------- +## / localK subK localF subF +##---------------------------------------- +=Pkg: dutest 1.0 1 x86_64 ++Dir: +/norm 15 0 1 0 +/grow 15 0 1 0 +-Dir: +##---------------------------------------- +=Pkg: dutest 2.0 1 x86_64 ++Dir: +/norm 45 0 1 0 +/grow 45 0 1 0 +-Dir: +##---------------------------------------- diff --git a/libzypp/tests/repo/susetags/data/dudata/system/content b/libzypp/tests/repo/susetags/data/dudata/system/content new file mode 100644 index 0000000..07033bc --- /dev/null +++ b/libzypp/tests/repo/susetags/data/dudata/system/content @@ -0,0 +1,2 @@ +META SHA1 95a347a40f621834a870e10b8914c9442c2dc355 packages +META SHA1 7d11955486b049be5f601b82acc18bfc73c22f39 packages.DU diff --git a/libzypp/tests/repo/susetags/data/dudata/system/media.1/media b/libzypp/tests/repo/susetags/data/dudata/system/media.1/media new file mode 100644 index 0000000..d5aa1ef --- /dev/null +++ b/libzypp/tests/repo/susetags/data/dudata/system/media.1/media @@ -0,0 +1,3 @@ +SUSE Linux Products GmbH +20070705102239 +1 diff --git a/libzypp/tests/repo/susetags/data/dudata/system/suse/setup/descr/packages b/libzypp/tests/repo/susetags/data/dudata/system/suse/setup/descr/packages new file mode 100644 index 0000000..350dc7f --- /dev/null +++ b/libzypp/tests/repo/susetags/data/dudata/system/suse/setup/descr/packages @@ -0,0 +1,4 @@ +=Ver: 2.0 +##---------------------------------------- +=Pkg: dutest 1.0 1 x86_64 +##---------------------------------------- diff --git a/libzypp/tests/repo/susetags/data/dudata/system/suse/setup/descr/packages.DU b/libzypp/tests/repo/susetags/data/dudata/system/suse/setup/descr/packages.DU new file mode 100644 index 0000000..c86c52e --- /dev/null +++ b/libzypp/tests/repo/susetags/data/dudata/system/suse/setup/descr/packages.DU @@ -0,0 +1,10 @@ +=Ver: 2.0 +##---------------------------------------- +## / localK subK localF subF +##---------------------------------------- +=Pkg: dutest 1.0 1 x86_64 ++Dir: +/norm 5 0 1 0 +/grow 5 0 1 0 +-Dir: +##---------------------------------------- diff --git a/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/content b/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/content index 9c02308..9bca45d 100644 --- a/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/content +++ b/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/content @@ -23,19 +23,19 @@ DESCRDIR suse/setup/descr DATADIR suse FLAGS update LANGUAGE en_US -META SHA1 3b3a4b0f085dd3605b61cdec06783b6b2a1f1d61 kde-10.3-71.i586.pat.gz +META SHA1 3b3a4b0f085dd3605b61cdec06783b6b2a1f1d61 kde-10.3-71.noarch.pat.gz META SHA1 2c351e103b347ef2984cb2aa638accfeadfaef58 packages.DU.gz META SHA1 208a6f8e1c96e9ba2ea7c74c05113c11c7378823 packages.en.gz META SHA1 59d65b8575ba1edde1813fef2e9949ae85f4d4c1 packages.es.gz META SHA1 061c361edf6157bc4273872055822e9d1766b8c4 packages.gz -META SHA1 14373553814a3f83c2dce6c6da40740ae03b3065 patterns.gz +META SHA1 8ae8446949182a9908c7d07b7bc58fb718cf3a92 patterns.gz KEY SHA1 c0354069c10819674da8706822e1d4bd0c1797e9 gpg-pubkey-0dfb3188-41ed929b.asc KEY SHA1 2e38e503c436c5d002bdc31755c82188044d9d21 gpg-pubkey-307e3d54-44201d5d.asc KEY SHA1 7025932e6866932f489421990075f3ed312023ea gpg-pubkey-3d25d3d9-36e12d04.asc KEY SHA1 fd6146cac8c1473c5b52548936de773d5bbd5610 gpg-pubkey-7e2e3b05-44748aba.asc KEY SHA1 cd7adceba1fe5d7ba27b5749718743192d82f802 gpg-pubkey-9c800aca-40d8063e.asc KEY SHA1 7535d79e31ef7b4232e5593bb49d9142978b2e95 gpg-pubkey-a1912208-446a0899.asc -HASH SHA1 172b3cf77268f46e783e78a653902e563cb91e9a license.tar.gz +HASH SHA1 875e73cf2ee139203208c860fbfd7fa5cb291c7e license.tar.gz HASH SHA1 4aa8ded6302e6ec85690a51af6044dffe9b21923 control.xml HASH SHA1 82f1f17ce74f0cd3fca4813c178196b317fc952d installation.xml HASH SHA1 68d9b548d61e31e82e8834690e884afa27751287 media.1/info.txt diff --git a/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/content.asc b/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/content.asc index 989ecc3..63684d6 100644 Binary files a/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/content.asc and b/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/content.asc differ diff --git a/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/content.key b/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/content.key index 8e52028..661d0e2 100644 --- a/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/content.key +++ b/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/content.key @@ -1,24 +1,135 @@ -----BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1.4.6 (GNU/Linux) +Version: GnuPG v2 -mQGiBEYjZk4RBACjIOtNaPzvKlC32b8R5TDRB0/FQ0tsMtt5dLwuq2ZYlEbT1YLF -110vZEl5IQAq5ldvD7MdR/6fqdXTdxBeYzZjeIEYbHzg3rN/N/+MkcG4W8IK1H6e -DAbL05HlQ1ueTp0mjgoGLYKt1igQe8h5uA6gEE7dv0tG0NJx2w5Gs2GpmwCgiRiu -s2ev221Pa65IpR1gsYuXLOEEAKJ1Bvjm+BfHJirqoH7iPq5HlABwn+s9sUmf6bjC -kfar/ySAsL0VUhHNCIoHUEZd2imA2ZA0kTBxB+BIX/HMRZzxPZEwYI8Q0UYsTVb/ -gnQt+mWaZs1/2teWR0wnUp+eO5MpOAO9QjFJTdIz0GegsfSOPCo55CUtktr3tJUK -fZ3gA/9mZe+b1Evi1/Us+klnERRKR2jjWXxwuPN6UivJbfXIZjuVUNclAhEqstzp -fnWJ3LhPxj0zJvhp/MnqSTaI6DQbr0f+JvwP+5k/4gbnqm+xxOocyhiVT45zOPAy -UYuG4t0m+9G7Vx6LC9tMukbdfHaRym42yC2s04GW2isKfta1ZbQsWllwcCBUZXN0 -IEtleSBQYWlyIDx6eXBwLWRldmVsQG9wZW5zdXNlLm9yZz6IYAQTEQIAIAUCRiNm -TgIbIwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEJvswrXdsDdWSVAAnjkR2lao -hb2Q4WnxamdHYWSf8ULKAJ4jjfZsFq0vmgPsO/YHaKTJN5sAL7kBDQRGI2ZREAQA -toB5TGT9K7NCv5D5dQw7jVHngnxp3NGTtAhwirYphBWaF2be3UJVTLbUFW14eMnr -VW9PKj/HNVLhQu0C6CaXtXy5LahIls+mFlSKwbiP74cFlNYcj69tzCnaFKgElQPH -cMOc31EgjySYcUIys421MxI++sugW+yHr5ByIsL6vfcAAwUEAILSwmLtD+Pwkues -73DPPyWIM3MA0exO7QmZeFwnbpiZYuZQ3GiPGrbeZVqHWB72dhW8+5ugR9CVQSsL -HC5wHMIQFU8RsiL06gZdIaJNgAr7ajhtUybP0WPVpXkzm5+VB8Che9m0Z0t2tK8Y -0KVapBcr3YDgx89F9VA0yny6q3WiiEkEGBECAAkFAkYjZlECGwwACgkQm+zCtd2w -N1apuACfUR+Daoo3N1fxxDa3A3t4OkAfpQgAn1UEvpQp+/4DnzSbEvwzLeoek3dz -=5nY9 +mQGiBDt3zUARBACCnzYUCVO/35iVN0T6J2Qb4GfDzrq8ZOqCamjD9tSylJ+UI4Co +YBks0HWnWty231Aoil6q76LRqE4bcEiJ/xuwinLFNC/S24B1cR98aq5tUEEbPJ44 +MBdY3LVbB4HCCMZH56nivx4thaTiCkVnyHpGkfKStk3lUkAVk2NR/C3uVwCgnp1D +qWaTn46JxIsEQMU8dczkeyED/j/J6QqCRwYR8XmlAUfI5ozIsQ7LuA1nY/NJ9Nnh +w2Wkq0UBZCqP/Nbfmr5EOri6MOPD9tIFRAy4qBqkxvgy/zKfX9qJkqx3o+DVrL4y +CFZHI0aUwqXvEAT6GJyDPi45gnHOVE9XJRL6BL9ZfFmOd4ajH2AJ4yy/ZqbX0GjR +opRuA/0SN8OK1ERDAA5AgZj9L2ZU7zMVmiWE8/Q+qz9p2TEfkfO8NyvvzK1Rv0iU +p0WuJn9gorBr93Sc9XtX3lINZ1PJUQg7KQbpfeWHMa1pxUMnIFVjpYZMmVFFGWZw +0q+45T9uMr50cvMr4pYtnvat5tyKM0igPtezMqSY2aY7LyZMmrQbTWljaGFlbCBB +bmRyZXMgPG1hQHN1c2UuZGU+iFcEExECABcFAjt3zUAFCwcKAwQDFQMCAxYCAQIX +gAAKCRA/uJ46J8aw5H+tAJ4ktFPz9sQGuec1LaX0pIB3oZVAvQCeP+jNfv9ZbVHI +Uz8bw8JBgwAe2w+IRgQQEQIABgUCO3fOdgAKCRDHUqoysN/3gB9xAKCLvhrIusLe +6wH0ByiA1ON3R5TNPACfY8W/eTeDSu9xNIlSCFMgDHw05cqIWgQTEQIAGgULBwoD +BAMVAwIDFgIBAheABQJIZg3kAhkBAAoJED+4njonxrDkE5oAni0UwlVNIaklPunu +iNb44D+AcgwRAJ47KCtevu20oesjoYkKhFNSLT14E4icBBMBAgAGBQI/xnvXAAoJ +EBlUT2RolefhXTwD/iXBc3oVl/jyeV2qoUB/cB1+quxpVSkjC/MnOjtmU7lXtNBj +dS7pZkMHyLDhT3VCTxvWTNM5sdS8hyQcSMATQ/axySFEy98tj5veZdMWcn9doyOP +OIpNhAv55iMsuvAP/cd26VYJDx4Amlv7BXlIw9prYZrePZrZVlSpXOnGQ9JoiQEh +BBABAgAMBQJCyOiqBQMAEnUAAAoJEJcQuJvKV618ALgH9igCYlbAeAAs+WTHoBgO +r4DFI7xREXf+AfPxraa/vLyH0cwDRej40aOnzEnwBSIC/DH+7Oy41aKunELyNtJ/ +DTkextRs2DzDhMGmYadHS8V1CPdLLA/q0rmtdGA6t2D2xhIdPXuO7+gHuaEydGTA +/KFmyE8XE0pDYHyhsrBeelSBPZS1dDcJx7vib1GQPHUydOI8PRKJbn+kxwjNqGzJ +m17sGJaxLPH8iWby8bEjmCFU31x+t+ia6sYSO7CsbwHL2mxuwfDE+f8QXiYFKDZB +t/pN0ky6iiBGoCyu/OrT7nqRmlmanRprotZ/2gW+pYGIQ1sHrcZQz/GMov7CWXGu +i4kBIgQQAQIADAUCQhcYbQUDABJ1AAAKCRCXELibyletfCOHB/92VkN0tLaC2nWJ +hOaMP2XGQbm8f09BphSdb8pxxMqnUH1W8YkCNjLvoRGN5exxb7cpfrymSqdjmSh1 +bVkREh4zzx5zd8Fhush5wqXq4PItV4Z+Es7kuZV/McG9mMoGqxI2WUyrZdXdOMFJ +O7ABEFtw7iCdzh9tVenX71U/2ePT/Ab8iWXcT5Xei4X1eQBtQ3c/2B6i9TDuH4Q0 +Cd8C89qyhzDaxrlX2dXfU/mwqIh/+6I4mwnAFBQ0RUtniXX4YARG5TuKYhDvfBod +vj6ACj518Kazlu8eOyUtZr+w1ntc22veQ8im7qpMqpMAqEYmpO7B6wYb/BOOxTBD ++pROcj3ziQEiBBABAgAMBQJCT68CBQMAEnUAAAoJEJcQuJvKV618IwIH/2pIkrl7 +OWSIoZADqVC7w6eXF17sV5TXLqJEPaHVuS6e+RnTbcRut7lPbx3wFVWQflFhn/fg +jkTUkTpcwbBrl199OA6k1yQPdYCJb1KuFP8aipWvlUjJcqUnHJS0ub7eSqWLeXcq +8cIufLMVNIcImU9yBoTVo4t7bezcO5LBC9l58B0uO11TwUlJ0pXAGUqznlAC7EuO +uLUnZr/6G+PzpWDEJN6QjBdRnn9qIflefkTXdsqUb2ByB5/SMJ3FgHkPZBx1Mqgm +IXvW05uQd4uyHJ0t9azvwxtgHgNH3y+FBkglP7yhRfBxwvMZbLJZft7xnXLMgdfH +M8Sj6pwmlSI9cnGJASIEEAECAAwFAkJiN0UFAwASdQAACgkQlxC4m8pXrXywowf/ +QzsKRLsWvMvNlYixCp2xF26ZKLpMUddmOxbqrJPCmITCkVO6fJjuegAwWBD9CEgg +2RfCZ4n2thwsbLWCRjYrwUzgbA0s4h0NE5mjsuOwQmKHjPXi0Fn3tx3teA7/GVPB +cqEGHnHVXx9guyGiwqugMRsYfYXEbDel68fo9Z7MraLwbTB2gSOJdEkCM0KtBNYd +ZUG7Q4m8qK8kBGjhBjCK0jgsaJK0FLRNlT5dGnwG1ggnnQEr9x6U2BwikfzaodDp +J80o3Z9PBr5OiDxXPb9kMgW9VwRpBBwvCi5ltAn8NtfIsPlQYwmb0FXyh7AXxlx0 +f2dS+IxMAd8POqhiABLJ0IkBIgQQAQIADAUCQmLeuwUDABJ1AAAKCRCXELibylet +fHGDB/9u0yi/Wk/mrFzrvwI4AOb92E7427Le3USIKUuWZSMqzAAVeNgCgKfy/NbY +gs6Kttb56+HnUJJ/C79YDh4qABe0hGiIgik+dUj/t2FBIz35cc2rS76hHXm1lWQC +0Si48AKPqhqzWCwzwt6aerQIg1IBkSmINKF6LrTIraYjh6UsDnLqLrlxnosXP4bT +byIKH2mTT3bboR8iaYyzxKV0ccydHE0jp0Dffx3x4wH5CKHrEJt1lhSKdDexM5yG +lAa+haUDKRulODNVljtx5m84vOgpwdg/JphLBJ24jGhHUS3PI3cXf+TV97J3YYQo +XITC9lRNqk3GZeWWyUu3r0XB/hp4iQEiBBABAgAMBQJCdVu9BQMAEnUAAAoJEJcQ +uJvKV618HHcIAKOHqHyRSw+4jg35JfVcLgrZn/3G4cDl35cAtZ5iz6ukEg8vpzH3 +rMfiFYV2WQNflQ2tIrD9ZwSjJVAXNEL1eX883HAL7HmHFCqaQTusZb7vpbzh18fU +Tjl4Nq3K9FqIIfJzJ8lPxGit6eL82OO/WUffjQAA9Ad+2yY/yWOyqUN4dqzxUWx4 +9F1Q2UDBGiu/QhcEhUlPf6B21I1nqsSkOMGtRiHf7RfrGDss2xRn+0PDrpRDcpmV +ZxJ4JpKQSDBKqbktlcdl95y9gI6llpJXFFQugxGwsC4qr6UYw4RloAdkpwz6aAlk +rfFgCZ5KhkLs4HQkdZLr+zq7zJh5njuBnJKJASIEEAECAAwFAkKHod8FAwASdQAA +CgkQlxC4m8pXrXxEdAf+Juexqg2/qC8vP+OnTuuDzTALHdSzt81Gq8a9jMHVs4rA +gAAEKbKzrRgnAjI7wyGSxU1kaPNh+RQB4qtZy4x7MlJtRfcfSlAWw7i3rqKQakpY +xUQEXLt/nK8kWxd2nC4gMW0105J+lBSMiCAw174/h36RjG//Cv17AhzGOckFE0n0 +7gZlW/+5YnjvFemP8lFnL5kb5BzPPiJy8J1VnqvXY95n3HxhkoiTSrXlS0MNNLgG +h27C+Kzl+p4X/T1esWoZe3pbq+qSb4xnglXOqzGJduQ0s585907ohm09m++e6NXK +hxxysu4cvcMv2Cc4ep9HglEY6sVrwY/0pMpBYdMLBIkBIgQQAQIADAUCQomcnAUD +ABJ1AAAKCRCXELibyletfDfnB/9ELbGLL7OIsOwCDidj1f/sabT/aFJ4LX15nm1B +mW0huKLRdJuzX7XZkcTx6SohTcTgFIfXxV1RLt/7wrW5TTRrYmDRyk0CR1EZlfgz +yLUaG+18ml7h97DZqSIaWnsqnryJB1QPyGO6yBUQTQ/KcGMyw2lzY2ovtl/UheIu +PT0v3v12kFxOo1xYeBn81YHQKPMWJhJ+iOmhjbj89W6RZ8swgSd9pczv0ptfUFIm +X5NbmIFxaiwWkRraUZYjdYYJGIainE9DpcMsSaSV7tq+mPl5NYVJPzW+llPPTqo6 +zIKxIByiVfH0zac/xecGyKe1RhBYJ34fdK+GcM8FYcWkpxOqiQEiBBABAgAMBQJC +m2c0BQMAEnUAAAoJEJcQuJvKV618OnMH/209R6nyz26CxVS4PtYYzMlOZ5VlOl/U +BEmRqmJeY/frgucejxX90qHUOy1dgBhJXQ05H5zHU7B0UHoha5KnSSyT2/p7owBu +AypZVvJB8PxxepPXUVfhiipR+7jWnYAsc6tjWn/+dE/ryO5iEWWAGDI0ZQ6dd/9C +sz4jDeffQusWB6g5ebfL6+SBHa5N2PCydGr047fG0KZm2jposMPsXbIuKh6LSTaL +QxGUyyJ+tTNfwstFYMlmawLMHtjb8F5r6FT7bywVlVHr7t2DctaoxULvlvogtCuE +7B9fG2EPg0sw6yK6P2zjGs+uv2qPO15vVWFLnQJ2eXrY1eNoUL/N+5KJASIEEAEC +AAwFAkKcuOMFAwASdQAACgkQlxC4m8pXrXw8Jgf/UKw9NzMIFXf1LfuKW3hH2dhd +OYyVnsYmuPy4HQTk0It579t0Mc8b4nrT4Bm5Id//SzxhKI0mGNxtLKXTiHOsTmEU +KLeBXRaw7snnq64vaYz5NU9LdW/GX1vt4QtiGaLvZq/INUwB2jobqqcMwfw9n295 +IEeKSuu0PcttZNfLGg06wBashAMl9h42ZakxlbYpbOPj0k/MdoB8EijdO3d2M4eV +DJKQNj7XiYE+yNmecEGkxaEJBma0xloA0iiGdPJHFlK3dHKKI93A/IU4KRhAE+iB +e+HlxOMyyGOk84+vWoT9IeQddYaxdlBm44TznYNN6en1lu2nqAA4s2XZEvw4rIkB +IgQQAQIADAUCQq/WegUDABJ1AAAKCRCXELibyletfNBuCACi6+OSvQrLBIeSmhIy +7Xgv2y/zfTKc1J++Nj2HFWC/X9pJCDHEyY5h0enHrePPoQzAlNY4Mz8sNzI2gc5V ++6B90XMJUCO4xz0wSlSTSMgX7sKO3zti6TaHi1dky89UDwOatrvxtRFeY957dInE +WDTyucTfDCIu7sQEHClXlTNTWXXs/MArjmtUfldCs6KWEvBiXec8YbAyC9gKZ3YV +ERrkMEJJYVWJiqp4jkCu7N7SUm2HS4GUIfacP+Qt+FJqHjkhYmGBJXfRSNcnOubb +S5gk1VJ7FKM7ZwQYDUZgouQUi6BiLoaJ3D0mHU+kxbg7PPhbT06u/MJh6v1B1Isa +2s/niQEiBBABAgAMBQJCtR/qBQMAEnUAAAoJEJcQuJvKV618R+oIAJj01Y/c/uq+ +4FqSfanoAGR5uqz3Ln+ijzycyMMQ8cY5fZpGaeeWzi3POlfnz35BsVXASWec9x7+ +bHVQY6Rn6DoQFRX5cQ6WwwRpsg8lAoL3uzN99Frj8rwGoLkTCJvRNZVbAaDmMHAa ++dAaq+ro1B22IGxvfR6N7EfjBHmeXfTHkSdszEBl9WnpsyziapSpkGFvcdzPWnBg +Dh70nybKseCDdcIdTRCmj5MIBn150nav/1SzX+oustuxoRxrjYZUFr8dOK52xHst +GgaSyNqKE8XJ8CCBvEI2x6pzIrle3vdBaXD9Yw3lOhNN0OZsqZWb/uQCW884tlDN +XhUExNhcHXqJASIEEAECAAwFAkK3GioFAwASdQAACgkQlxC4m8pXrXz+ugf+KMyj +rXp55VY5hSYZUoM1g+NW2ayOiT/pQNzOlVZt/fA64zwkmCGaRzEC6jB0rAi98b5o +mvgCEwXWqg6z9asSbOk6/kIStI8se4hxp0BQSXIB7sXyrpopugigET3yIwSOM7M6 +fez/WHJYF/8xOzA1VM5Fbs4M2V15hpjA0lwBRHgkxqBNaHl3FjhqO8SmcECCMART +IVamMKniOK8hOVH0NKbjj7Zbe21EFuyXsxa32ROCPIY4mspKNFXtT7ixXmLjMxj0 +P3yNUVBGkgjh86eP6QjT54V70nwVbjg6u7f5xeQoWHS+8dt4QhVOZDz3XSjKwgZq +NllQ5YCSu/AdHJfcM4kBIgQQAQIADAUCQszcBwUDABJ1AAAKCRCXELibyletfBsa +B/9HKXrv7HDwZ4LS4Sf/wrtlUZIEMmbojeF3G9QWBXp1D/SbSJHPTuXM9jsZcfTZ +VX+neDDB5FkaGtqLf3Wcm5AT06qTswKbCrg1XlFQ66YuyqgX3+Y2i4GloATDNlPS +Ho5g2YliIoZXxP6VzrmCHVDKBi/TWNxMaCgwPRtJvSRGUiitv/AJR4LCyz6T6QGJ ++WRPaHwviT2FX0aAjP3q3tZKaXNmGskNuX5WUUnThUuZWwFJ2eZcqF3Mr7ZTmf/v +QnwEoyEdULUNBWF15R5FD1EvK9ELQIEWOWBILv7Mt5ozNSqTYV78UpG5MiiM3DMh +QP3iaqLsVzHvCNxgDmPZ04mBiQEiBBABAgAMBQJC0XrQBQMAEnUAAAoJEJcQuJvK +V618EDYIAJgUg6kV4hU4Z8ML9Ka2GWazj34BmEMqkk6Jm6IRP2nVkHbe+/NN7vOZ +TA+ZHFJKy5zu144+o6PqR2W9ZkcbWplUz4bC4POXclEfbIywH/7coqUwa3RjvRrO +TmiYAZKV/Z7yngC3BLBIktlEvTZustX6LsqPrqLn6Wk8GI161HWYhwRCIXQ9Vs2e +BhSGPzHp/vEOJHdGMsXpxEakcCCnn2SBwYcrkV4AN+gOJhsoH55hD1/mXEK95zoc +S2uUaxxhn3jKEUFMOnCfcfuqZ52broV3OUczxozFloIGxxZv9xwBNHOMDfA0LI6Q +9YsL5uWDE1QKdwkIzqDC4mBzgOxp5C+IVwQTEQIAFwUCO3fNQAULBwoDBAMVAwID +FgIBAheAAAoJED+4njonxrDkf60AnRUchhESPbyQbSvy7sX1xunLHgRkAJ49jGt8 +9LQdh4lvqKfpj+RMqY1LI7Q0TWljaGFlbCBBbmRyZXMgKE1pY2hhZWwgQW5kcmVz +IHByaXZhdGUpIDxtYUBrbTEzLmRlPohgBBMRAgAgAhsjBgsJCAcDAgQVAggDBBYC +AwECHgECF4AFAkhmDeAACgkQP7ieOifGsOQDpwCdGxVwFjNt98OuylGNhhjm2GD0 +HUkAn19PVAoWFjmHhSadUJAehJVloqjbiGMEExECACMCGyMGCwkIBwMCBBUCCAME +FgIDAQIeAQIXgAUCSGYGFQIZAQAKCRA/uJ46J8aw5BvgAJ0Zo8czcPx39AUXGXIU +v+RzkBeujwCfYOXRCpThfRrd2FyuUAULu+/PNnu5Ag0EO3fNWhAIANoFOLBJ37Vr +9umFyQJk2jB1zHfh8p0wF/Tw1giR7LFgTTpgvy27JR1BTSqJkeW56sfeDfMkHcRF +SEsRl0SKHfpHLQANevwvygygx6OgeJrCdgJTkhWUdB7SgVC1yMSsWm0uYTPSOH+l +9PpICNH+tP1po0qoQsD387uY8XOwlLSAuFTOGGT0q7N1g/swF/5RwJhLtgj0viQR +/lzoZ9f5GB87Ih9ab8LgBj1XcddjtFe+Qr0pZ+0tT5Fqz9/muOzeW3z1nHvE/7di +LMorlevz1gD1JOPoFDaTmLsuWXdFP0aZoi/2Wx39HVD8Zpp8vN5M3Ta/11oXhoHG +AIuIQ3kFELcAAwUIALMbFRojYmYCl6TCZ23PB/+8fK2VjAu4vUzuvv78U17H26pO +G4mVbW7XXFBmN30viiqEVMdrm76odOe5VhF+lCB8irbvedL0al/C9vsAUGKRxJB0 +1Y/mXsDuPvxmiuGqcWrb8j3chBh129dCO+dR4MR1xfth23EnI/fncggAeXGT6+HD +oXfXTHoMolWKa9Fh3vRTZqFtBQTYPenr7lhUjPmM3cpswSTxkwIqC2pUmmDMekSu +IOCVIbe5w+f5OB8j2Bd3ZYgxsePcf20OWOXdLNucO1KPaM9zS7LxhmlzAOWcXj8E +EK9bAvdi1DXDgJA+AYmD6ol3uX+eoIDh3akYTTyIRgQYEQIABgUCO3fNWgAKCRA/ +uJ46J8aw5AtiAJkBhcP6w63v4r8niiOPjmgN6NbxxACeK/BBzQT+qgqQfHYEW0Sc +ixhE83U= +=Z5HF -----END PGP PUBLIC KEY BLOCK----- diff --git a/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/license.tar.gz b/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/license.tar.gz index ecd631d..5d513d1 100644 Binary files a/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/license.tar.gz and b/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/license.tar.gz differ diff --git a/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/media.1/license.zip b/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/media.1/license.zip deleted file mode 100644 index dd500d6..0000000 Binary files a/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/media.1/license.zip and /dev/null differ diff --git a/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/suse/setup/descr/kde-10.3-71.i586.pat.gz b/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/suse/setup/descr/kde-10.3-71.noarch.pat.gz similarity index 100% rename from libzypp/tests/repo/susetags/data/stable-x86-subset-gz/suse/setup/descr/kde-10.3-71.i586.pat.gz rename to libzypp/tests/repo/susetags/data/stable-x86-subset-gz/suse/setup/descr/kde-10.3-71.noarch.pat.gz diff --git a/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/suse/setup/descr/patterns.gz b/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/suse/setup/descr/patterns.gz index e14fee1..62e0eb3 100644 Binary files a/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/suse/setup/descr/patterns.gz and b/libzypp/tests/repo/susetags/data/stable-x86-subset-gz/suse/setup/descr/patterns.gz differ diff --git a/libzypp/tests/repo/susetags/data/stable-x86-subset/content b/libzypp/tests/repo/susetags/data/stable-x86-subset/content index fb211e2..215791f 100644 --- a/libzypp/tests/repo/susetags/data/stable-x86-subset/content +++ b/libzypp/tests/repo/susetags/data/stable-x86-subset/content @@ -23,19 +23,19 @@ DESCRDIR suse/setup/descr DATADIR suse FLAGS update LANGUAGE en_US -META SHA1 c37f4ba4225650844363711710c3824a58c901dd kde-10.3-71.i586.pat +META SHA1 c37f4ba4225650844363711710c3824a58c901dd kde-10.3-71.noarch.pat META SHA1 80f9bb1f9e95ebcebfd9b22f338f779e204cd50b packages META SHA1 9c341d93124860f03b001681513ca07b4d0ca873 packages.DU META SHA1 a48fa507afccbce76b549a07394e41d9813e6b01 packages.en META SHA1 765900f5513ce6bf496d5006bdff45f805e61997 packages.es -META SHA1 fbb6a2d6976c37c9a6beb52ca35f7594ae3eff1e patterns +META SHA1 d3c628ac67854629ff98432bebef6c00aad9bb98 patterns KEY SHA1 c0354069c10819674da8706822e1d4bd0c1797e9 gpg-pubkey-0dfb3188-41ed929b.asc KEY SHA1 2e38e503c436c5d002bdc31755c82188044d9d21 gpg-pubkey-307e3d54-44201d5d.asc KEY SHA1 7025932e6866932f489421990075f3ed312023ea gpg-pubkey-3d25d3d9-36e12d04.asc KEY SHA1 fd6146cac8c1473c5b52548936de773d5bbd5610 gpg-pubkey-7e2e3b05-44748aba.asc KEY SHA1 cd7adceba1fe5d7ba27b5749718743192d82f802 gpg-pubkey-9c800aca-40d8063e.asc KEY SHA1 7535d79e31ef7b4232e5593bb49d9142978b2e95 gpg-pubkey-a1912208-446a0899.asc -HASH SHA1 172b3cf77268f46e783e78a653902e563cb91e9a license.tar.gz +HASH SHA1 875e73cf2ee139203208c860fbfd7fa5cb291c7e license.tar.gz HASH SHA1 4aa8ded6302e6ec85690a51af6044dffe9b21923 control.xml HASH SHA1 82f1f17ce74f0cd3fca4813c178196b317fc952d installation.xml HASH SHA1 68d9b548d61e31e82e8834690e884afa27751287 media.1/info.txt diff --git a/libzypp/tests/repo/susetags/data/stable-x86-subset/content.asc b/libzypp/tests/repo/susetags/data/stable-x86-subset/content.asc index 8a3bd48..e02b8bb 100644 Binary files a/libzypp/tests/repo/susetags/data/stable-x86-subset/content.asc and b/libzypp/tests/repo/susetags/data/stable-x86-subset/content.asc differ diff --git a/libzypp/tests/repo/susetags/data/stable-x86-subset/content.key b/libzypp/tests/repo/susetags/data/stable-x86-subset/content.key index 8e52028..661d0e2 100644 --- a/libzypp/tests/repo/susetags/data/stable-x86-subset/content.key +++ b/libzypp/tests/repo/susetags/data/stable-x86-subset/content.key @@ -1,24 +1,135 @@ -----BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1.4.6 (GNU/Linux) +Version: GnuPG v2 -mQGiBEYjZk4RBACjIOtNaPzvKlC32b8R5TDRB0/FQ0tsMtt5dLwuq2ZYlEbT1YLF -110vZEl5IQAq5ldvD7MdR/6fqdXTdxBeYzZjeIEYbHzg3rN/N/+MkcG4W8IK1H6e -DAbL05HlQ1ueTp0mjgoGLYKt1igQe8h5uA6gEE7dv0tG0NJx2w5Gs2GpmwCgiRiu -s2ev221Pa65IpR1gsYuXLOEEAKJ1Bvjm+BfHJirqoH7iPq5HlABwn+s9sUmf6bjC -kfar/ySAsL0VUhHNCIoHUEZd2imA2ZA0kTBxB+BIX/HMRZzxPZEwYI8Q0UYsTVb/ -gnQt+mWaZs1/2teWR0wnUp+eO5MpOAO9QjFJTdIz0GegsfSOPCo55CUtktr3tJUK -fZ3gA/9mZe+b1Evi1/Us+klnERRKR2jjWXxwuPN6UivJbfXIZjuVUNclAhEqstzp -fnWJ3LhPxj0zJvhp/MnqSTaI6DQbr0f+JvwP+5k/4gbnqm+xxOocyhiVT45zOPAy -UYuG4t0m+9G7Vx6LC9tMukbdfHaRym42yC2s04GW2isKfta1ZbQsWllwcCBUZXN0 -IEtleSBQYWlyIDx6eXBwLWRldmVsQG9wZW5zdXNlLm9yZz6IYAQTEQIAIAUCRiNm -TgIbIwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEJvswrXdsDdWSVAAnjkR2lao -hb2Q4WnxamdHYWSf8ULKAJ4jjfZsFq0vmgPsO/YHaKTJN5sAL7kBDQRGI2ZREAQA -toB5TGT9K7NCv5D5dQw7jVHngnxp3NGTtAhwirYphBWaF2be3UJVTLbUFW14eMnr -VW9PKj/HNVLhQu0C6CaXtXy5LahIls+mFlSKwbiP74cFlNYcj69tzCnaFKgElQPH -cMOc31EgjySYcUIys421MxI++sugW+yHr5ByIsL6vfcAAwUEAILSwmLtD+Pwkues -73DPPyWIM3MA0exO7QmZeFwnbpiZYuZQ3GiPGrbeZVqHWB72dhW8+5ugR9CVQSsL -HC5wHMIQFU8RsiL06gZdIaJNgAr7ajhtUybP0WPVpXkzm5+VB8Che9m0Z0t2tK8Y -0KVapBcr3YDgx89F9VA0yny6q3WiiEkEGBECAAkFAkYjZlECGwwACgkQm+zCtd2w -N1apuACfUR+Daoo3N1fxxDa3A3t4OkAfpQgAn1UEvpQp+/4DnzSbEvwzLeoek3dz -=5nY9 +mQGiBDt3zUARBACCnzYUCVO/35iVN0T6J2Qb4GfDzrq8ZOqCamjD9tSylJ+UI4Co +YBks0HWnWty231Aoil6q76LRqE4bcEiJ/xuwinLFNC/S24B1cR98aq5tUEEbPJ44 +MBdY3LVbB4HCCMZH56nivx4thaTiCkVnyHpGkfKStk3lUkAVk2NR/C3uVwCgnp1D +qWaTn46JxIsEQMU8dczkeyED/j/J6QqCRwYR8XmlAUfI5ozIsQ7LuA1nY/NJ9Nnh +w2Wkq0UBZCqP/Nbfmr5EOri6MOPD9tIFRAy4qBqkxvgy/zKfX9qJkqx3o+DVrL4y +CFZHI0aUwqXvEAT6GJyDPi45gnHOVE9XJRL6BL9ZfFmOd4ajH2AJ4yy/ZqbX0GjR +opRuA/0SN8OK1ERDAA5AgZj9L2ZU7zMVmiWE8/Q+qz9p2TEfkfO8NyvvzK1Rv0iU +p0WuJn9gorBr93Sc9XtX3lINZ1PJUQg7KQbpfeWHMa1pxUMnIFVjpYZMmVFFGWZw +0q+45T9uMr50cvMr4pYtnvat5tyKM0igPtezMqSY2aY7LyZMmrQbTWljaGFlbCBB +bmRyZXMgPG1hQHN1c2UuZGU+iFcEExECABcFAjt3zUAFCwcKAwQDFQMCAxYCAQIX +gAAKCRA/uJ46J8aw5H+tAJ4ktFPz9sQGuec1LaX0pIB3oZVAvQCeP+jNfv9ZbVHI +Uz8bw8JBgwAe2w+IRgQQEQIABgUCO3fOdgAKCRDHUqoysN/3gB9xAKCLvhrIusLe +6wH0ByiA1ON3R5TNPACfY8W/eTeDSu9xNIlSCFMgDHw05cqIWgQTEQIAGgULBwoD +BAMVAwIDFgIBAheABQJIZg3kAhkBAAoJED+4njonxrDkE5oAni0UwlVNIaklPunu +iNb44D+AcgwRAJ47KCtevu20oesjoYkKhFNSLT14E4icBBMBAgAGBQI/xnvXAAoJ +EBlUT2RolefhXTwD/iXBc3oVl/jyeV2qoUB/cB1+quxpVSkjC/MnOjtmU7lXtNBj +dS7pZkMHyLDhT3VCTxvWTNM5sdS8hyQcSMATQ/axySFEy98tj5veZdMWcn9doyOP +OIpNhAv55iMsuvAP/cd26VYJDx4Amlv7BXlIw9prYZrePZrZVlSpXOnGQ9JoiQEh +BBABAgAMBQJCyOiqBQMAEnUAAAoJEJcQuJvKV618ALgH9igCYlbAeAAs+WTHoBgO +r4DFI7xREXf+AfPxraa/vLyH0cwDRej40aOnzEnwBSIC/DH+7Oy41aKunELyNtJ/ +DTkextRs2DzDhMGmYadHS8V1CPdLLA/q0rmtdGA6t2D2xhIdPXuO7+gHuaEydGTA +/KFmyE8XE0pDYHyhsrBeelSBPZS1dDcJx7vib1GQPHUydOI8PRKJbn+kxwjNqGzJ +m17sGJaxLPH8iWby8bEjmCFU31x+t+ia6sYSO7CsbwHL2mxuwfDE+f8QXiYFKDZB +t/pN0ky6iiBGoCyu/OrT7nqRmlmanRprotZ/2gW+pYGIQ1sHrcZQz/GMov7CWXGu +i4kBIgQQAQIADAUCQhcYbQUDABJ1AAAKCRCXELibyletfCOHB/92VkN0tLaC2nWJ +hOaMP2XGQbm8f09BphSdb8pxxMqnUH1W8YkCNjLvoRGN5exxb7cpfrymSqdjmSh1 +bVkREh4zzx5zd8Fhush5wqXq4PItV4Z+Es7kuZV/McG9mMoGqxI2WUyrZdXdOMFJ +O7ABEFtw7iCdzh9tVenX71U/2ePT/Ab8iWXcT5Xei4X1eQBtQ3c/2B6i9TDuH4Q0 +Cd8C89qyhzDaxrlX2dXfU/mwqIh/+6I4mwnAFBQ0RUtniXX4YARG5TuKYhDvfBod +vj6ACj518Kazlu8eOyUtZr+w1ntc22veQ8im7qpMqpMAqEYmpO7B6wYb/BOOxTBD ++pROcj3ziQEiBBABAgAMBQJCT68CBQMAEnUAAAoJEJcQuJvKV618IwIH/2pIkrl7 +OWSIoZADqVC7w6eXF17sV5TXLqJEPaHVuS6e+RnTbcRut7lPbx3wFVWQflFhn/fg +jkTUkTpcwbBrl199OA6k1yQPdYCJb1KuFP8aipWvlUjJcqUnHJS0ub7eSqWLeXcq +8cIufLMVNIcImU9yBoTVo4t7bezcO5LBC9l58B0uO11TwUlJ0pXAGUqznlAC7EuO +uLUnZr/6G+PzpWDEJN6QjBdRnn9qIflefkTXdsqUb2ByB5/SMJ3FgHkPZBx1Mqgm +IXvW05uQd4uyHJ0t9azvwxtgHgNH3y+FBkglP7yhRfBxwvMZbLJZft7xnXLMgdfH +M8Sj6pwmlSI9cnGJASIEEAECAAwFAkJiN0UFAwASdQAACgkQlxC4m8pXrXywowf/ +QzsKRLsWvMvNlYixCp2xF26ZKLpMUddmOxbqrJPCmITCkVO6fJjuegAwWBD9CEgg +2RfCZ4n2thwsbLWCRjYrwUzgbA0s4h0NE5mjsuOwQmKHjPXi0Fn3tx3teA7/GVPB +cqEGHnHVXx9guyGiwqugMRsYfYXEbDel68fo9Z7MraLwbTB2gSOJdEkCM0KtBNYd +ZUG7Q4m8qK8kBGjhBjCK0jgsaJK0FLRNlT5dGnwG1ggnnQEr9x6U2BwikfzaodDp +J80o3Z9PBr5OiDxXPb9kMgW9VwRpBBwvCi5ltAn8NtfIsPlQYwmb0FXyh7AXxlx0 +f2dS+IxMAd8POqhiABLJ0IkBIgQQAQIADAUCQmLeuwUDABJ1AAAKCRCXELibylet +fHGDB/9u0yi/Wk/mrFzrvwI4AOb92E7427Le3USIKUuWZSMqzAAVeNgCgKfy/NbY +gs6Kttb56+HnUJJ/C79YDh4qABe0hGiIgik+dUj/t2FBIz35cc2rS76hHXm1lWQC +0Si48AKPqhqzWCwzwt6aerQIg1IBkSmINKF6LrTIraYjh6UsDnLqLrlxnosXP4bT +byIKH2mTT3bboR8iaYyzxKV0ccydHE0jp0Dffx3x4wH5CKHrEJt1lhSKdDexM5yG +lAa+haUDKRulODNVljtx5m84vOgpwdg/JphLBJ24jGhHUS3PI3cXf+TV97J3YYQo +XITC9lRNqk3GZeWWyUu3r0XB/hp4iQEiBBABAgAMBQJCdVu9BQMAEnUAAAoJEJcQ +uJvKV618HHcIAKOHqHyRSw+4jg35JfVcLgrZn/3G4cDl35cAtZ5iz6ukEg8vpzH3 +rMfiFYV2WQNflQ2tIrD9ZwSjJVAXNEL1eX883HAL7HmHFCqaQTusZb7vpbzh18fU +Tjl4Nq3K9FqIIfJzJ8lPxGit6eL82OO/WUffjQAA9Ad+2yY/yWOyqUN4dqzxUWx4 +9F1Q2UDBGiu/QhcEhUlPf6B21I1nqsSkOMGtRiHf7RfrGDss2xRn+0PDrpRDcpmV +ZxJ4JpKQSDBKqbktlcdl95y9gI6llpJXFFQugxGwsC4qr6UYw4RloAdkpwz6aAlk +rfFgCZ5KhkLs4HQkdZLr+zq7zJh5njuBnJKJASIEEAECAAwFAkKHod8FAwASdQAA +CgkQlxC4m8pXrXxEdAf+Juexqg2/qC8vP+OnTuuDzTALHdSzt81Gq8a9jMHVs4rA +gAAEKbKzrRgnAjI7wyGSxU1kaPNh+RQB4qtZy4x7MlJtRfcfSlAWw7i3rqKQakpY +xUQEXLt/nK8kWxd2nC4gMW0105J+lBSMiCAw174/h36RjG//Cv17AhzGOckFE0n0 +7gZlW/+5YnjvFemP8lFnL5kb5BzPPiJy8J1VnqvXY95n3HxhkoiTSrXlS0MNNLgG +h27C+Kzl+p4X/T1esWoZe3pbq+qSb4xnglXOqzGJduQ0s585907ohm09m++e6NXK +hxxysu4cvcMv2Cc4ep9HglEY6sVrwY/0pMpBYdMLBIkBIgQQAQIADAUCQomcnAUD +ABJ1AAAKCRCXELibyletfDfnB/9ELbGLL7OIsOwCDidj1f/sabT/aFJ4LX15nm1B +mW0huKLRdJuzX7XZkcTx6SohTcTgFIfXxV1RLt/7wrW5TTRrYmDRyk0CR1EZlfgz +yLUaG+18ml7h97DZqSIaWnsqnryJB1QPyGO6yBUQTQ/KcGMyw2lzY2ovtl/UheIu +PT0v3v12kFxOo1xYeBn81YHQKPMWJhJ+iOmhjbj89W6RZ8swgSd9pczv0ptfUFIm +X5NbmIFxaiwWkRraUZYjdYYJGIainE9DpcMsSaSV7tq+mPl5NYVJPzW+llPPTqo6 +zIKxIByiVfH0zac/xecGyKe1RhBYJ34fdK+GcM8FYcWkpxOqiQEiBBABAgAMBQJC +m2c0BQMAEnUAAAoJEJcQuJvKV618OnMH/209R6nyz26CxVS4PtYYzMlOZ5VlOl/U +BEmRqmJeY/frgucejxX90qHUOy1dgBhJXQ05H5zHU7B0UHoha5KnSSyT2/p7owBu +AypZVvJB8PxxepPXUVfhiipR+7jWnYAsc6tjWn/+dE/ryO5iEWWAGDI0ZQ6dd/9C +sz4jDeffQusWB6g5ebfL6+SBHa5N2PCydGr047fG0KZm2jposMPsXbIuKh6LSTaL +QxGUyyJ+tTNfwstFYMlmawLMHtjb8F5r6FT7bywVlVHr7t2DctaoxULvlvogtCuE +7B9fG2EPg0sw6yK6P2zjGs+uv2qPO15vVWFLnQJ2eXrY1eNoUL/N+5KJASIEEAEC +AAwFAkKcuOMFAwASdQAACgkQlxC4m8pXrXw8Jgf/UKw9NzMIFXf1LfuKW3hH2dhd +OYyVnsYmuPy4HQTk0It579t0Mc8b4nrT4Bm5Id//SzxhKI0mGNxtLKXTiHOsTmEU +KLeBXRaw7snnq64vaYz5NU9LdW/GX1vt4QtiGaLvZq/INUwB2jobqqcMwfw9n295 +IEeKSuu0PcttZNfLGg06wBashAMl9h42ZakxlbYpbOPj0k/MdoB8EijdO3d2M4eV +DJKQNj7XiYE+yNmecEGkxaEJBma0xloA0iiGdPJHFlK3dHKKI93A/IU4KRhAE+iB +e+HlxOMyyGOk84+vWoT9IeQddYaxdlBm44TznYNN6en1lu2nqAA4s2XZEvw4rIkB +IgQQAQIADAUCQq/WegUDABJ1AAAKCRCXELibyletfNBuCACi6+OSvQrLBIeSmhIy +7Xgv2y/zfTKc1J++Nj2HFWC/X9pJCDHEyY5h0enHrePPoQzAlNY4Mz8sNzI2gc5V ++6B90XMJUCO4xz0wSlSTSMgX7sKO3zti6TaHi1dky89UDwOatrvxtRFeY957dInE +WDTyucTfDCIu7sQEHClXlTNTWXXs/MArjmtUfldCs6KWEvBiXec8YbAyC9gKZ3YV +ERrkMEJJYVWJiqp4jkCu7N7SUm2HS4GUIfacP+Qt+FJqHjkhYmGBJXfRSNcnOubb +S5gk1VJ7FKM7ZwQYDUZgouQUi6BiLoaJ3D0mHU+kxbg7PPhbT06u/MJh6v1B1Isa +2s/niQEiBBABAgAMBQJCtR/qBQMAEnUAAAoJEJcQuJvKV618R+oIAJj01Y/c/uq+ +4FqSfanoAGR5uqz3Ln+ijzycyMMQ8cY5fZpGaeeWzi3POlfnz35BsVXASWec9x7+ +bHVQY6Rn6DoQFRX5cQ6WwwRpsg8lAoL3uzN99Frj8rwGoLkTCJvRNZVbAaDmMHAa ++dAaq+ro1B22IGxvfR6N7EfjBHmeXfTHkSdszEBl9WnpsyziapSpkGFvcdzPWnBg +Dh70nybKseCDdcIdTRCmj5MIBn150nav/1SzX+oustuxoRxrjYZUFr8dOK52xHst +GgaSyNqKE8XJ8CCBvEI2x6pzIrle3vdBaXD9Yw3lOhNN0OZsqZWb/uQCW884tlDN +XhUExNhcHXqJASIEEAECAAwFAkK3GioFAwASdQAACgkQlxC4m8pXrXz+ugf+KMyj +rXp55VY5hSYZUoM1g+NW2ayOiT/pQNzOlVZt/fA64zwkmCGaRzEC6jB0rAi98b5o +mvgCEwXWqg6z9asSbOk6/kIStI8se4hxp0BQSXIB7sXyrpopugigET3yIwSOM7M6 +fez/WHJYF/8xOzA1VM5Fbs4M2V15hpjA0lwBRHgkxqBNaHl3FjhqO8SmcECCMART +IVamMKniOK8hOVH0NKbjj7Zbe21EFuyXsxa32ROCPIY4mspKNFXtT7ixXmLjMxj0 +P3yNUVBGkgjh86eP6QjT54V70nwVbjg6u7f5xeQoWHS+8dt4QhVOZDz3XSjKwgZq +NllQ5YCSu/AdHJfcM4kBIgQQAQIADAUCQszcBwUDABJ1AAAKCRCXELibyletfBsa +B/9HKXrv7HDwZ4LS4Sf/wrtlUZIEMmbojeF3G9QWBXp1D/SbSJHPTuXM9jsZcfTZ +VX+neDDB5FkaGtqLf3Wcm5AT06qTswKbCrg1XlFQ66YuyqgX3+Y2i4GloATDNlPS +Ho5g2YliIoZXxP6VzrmCHVDKBi/TWNxMaCgwPRtJvSRGUiitv/AJR4LCyz6T6QGJ ++WRPaHwviT2FX0aAjP3q3tZKaXNmGskNuX5WUUnThUuZWwFJ2eZcqF3Mr7ZTmf/v +QnwEoyEdULUNBWF15R5FD1EvK9ELQIEWOWBILv7Mt5ozNSqTYV78UpG5MiiM3DMh +QP3iaqLsVzHvCNxgDmPZ04mBiQEiBBABAgAMBQJC0XrQBQMAEnUAAAoJEJcQuJvK +V618EDYIAJgUg6kV4hU4Z8ML9Ka2GWazj34BmEMqkk6Jm6IRP2nVkHbe+/NN7vOZ +TA+ZHFJKy5zu144+o6PqR2W9ZkcbWplUz4bC4POXclEfbIywH/7coqUwa3RjvRrO +TmiYAZKV/Z7yngC3BLBIktlEvTZustX6LsqPrqLn6Wk8GI161HWYhwRCIXQ9Vs2e +BhSGPzHp/vEOJHdGMsXpxEakcCCnn2SBwYcrkV4AN+gOJhsoH55hD1/mXEK95zoc +S2uUaxxhn3jKEUFMOnCfcfuqZ52broV3OUczxozFloIGxxZv9xwBNHOMDfA0LI6Q +9YsL5uWDE1QKdwkIzqDC4mBzgOxp5C+IVwQTEQIAFwUCO3fNQAULBwoDBAMVAwID +FgIBAheAAAoJED+4njonxrDkf60AnRUchhESPbyQbSvy7sX1xunLHgRkAJ49jGt8 +9LQdh4lvqKfpj+RMqY1LI7Q0TWljaGFlbCBBbmRyZXMgKE1pY2hhZWwgQW5kcmVz +IHByaXZhdGUpIDxtYUBrbTEzLmRlPohgBBMRAgAgAhsjBgsJCAcDAgQVAggDBBYC +AwECHgECF4AFAkhmDeAACgkQP7ieOifGsOQDpwCdGxVwFjNt98OuylGNhhjm2GD0 +HUkAn19PVAoWFjmHhSadUJAehJVloqjbiGMEExECACMCGyMGCwkIBwMCBBUCCAME +FgIDAQIeAQIXgAUCSGYGFQIZAQAKCRA/uJ46J8aw5BvgAJ0Zo8czcPx39AUXGXIU +v+RzkBeujwCfYOXRCpThfRrd2FyuUAULu+/PNnu5Ag0EO3fNWhAIANoFOLBJ37Vr +9umFyQJk2jB1zHfh8p0wF/Tw1giR7LFgTTpgvy27JR1BTSqJkeW56sfeDfMkHcRF +SEsRl0SKHfpHLQANevwvygygx6OgeJrCdgJTkhWUdB7SgVC1yMSsWm0uYTPSOH+l +9PpICNH+tP1po0qoQsD387uY8XOwlLSAuFTOGGT0q7N1g/swF/5RwJhLtgj0viQR +/lzoZ9f5GB87Ih9ab8LgBj1XcddjtFe+Qr0pZ+0tT5Fqz9/muOzeW3z1nHvE/7di +LMorlevz1gD1JOPoFDaTmLsuWXdFP0aZoi/2Wx39HVD8Zpp8vN5M3Ta/11oXhoHG +AIuIQ3kFELcAAwUIALMbFRojYmYCl6TCZ23PB/+8fK2VjAu4vUzuvv78U17H26pO +G4mVbW7XXFBmN30viiqEVMdrm76odOe5VhF+lCB8irbvedL0al/C9vsAUGKRxJB0 +1Y/mXsDuPvxmiuGqcWrb8j3chBh129dCO+dR4MR1xfth23EnI/fncggAeXGT6+HD +oXfXTHoMolWKa9Fh3vRTZqFtBQTYPenr7lhUjPmM3cpswSTxkwIqC2pUmmDMekSu +IOCVIbe5w+f5OB8j2Bd3ZYgxsePcf20OWOXdLNucO1KPaM9zS7LxhmlzAOWcXj8E +EK9bAvdi1DXDgJA+AYmD6ol3uX+eoIDh3akYTTyIRgQYEQIABgUCO3fNWgAKCRA/ +uJ46J8aw5AtiAJkBhcP6w63v4r8niiOPjmgN6NbxxACeK/BBzQT+qgqQfHYEW0Sc +ixhE83U= +=Z5HF -----END PGP PUBLIC KEY BLOCK----- diff --git a/libzypp/tests/repo/susetags/data/stable-x86-subset/license.tar.gz b/libzypp/tests/repo/susetags/data/stable-x86-subset/license.tar.gz index ecd631d..5d513d1 100644 Binary files a/libzypp/tests/repo/susetags/data/stable-x86-subset/license.tar.gz and b/libzypp/tests/repo/susetags/data/stable-x86-subset/license.tar.gz differ diff --git a/libzypp/tests/repo/susetags/data/stable-x86-subset/media.1/license.zip b/libzypp/tests/repo/susetags/data/stable-x86-subset/media.1/license.zip deleted file mode 100644 index dd500d6..0000000 Binary files a/libzypp/tests/repo/susetags/data/stable-x86-subset/media.1/license.zip and /dev/null differ diff --git a/libzypp/tests/repo/susetags/data/stable-x86-subset/suse/setup/descr/kde-10.3-71.i586.pat b/libzypp/tests/repo/susetags/data/stable-x86-subset/suse/setup/descr/kde-10.3-71.noarch.pat similarity index 100% rename from libzypp/tests/repo/susetags/data/stable-x86-subset/suse/setup/descr/kde-10.3-71.i586.pat rename to libzypp/tests/repo/susetags/data/stable-x86-subset/suse/setup/descr/kde-10.3-71.noarch.pat diff --git a/libzypp/tests/repo/susetags/data/stable-x86-subset/suse/setup/descr/patterns b/libzypp/tests/repo/susetags/data/stable-x86-subset/suse/setup/descr/patterns index 82e92e9..43d428b 100644 --- a/libzypp/tests/repo/susetags/data/stable-x86-subset/suse/setup/descr/patterns +++ b/libzypp/tests/repo/susetags/data/stable-x86-subset/suse/setup/descr/patterns @@ -1,2 +1,2 @@ -kde-10.3-71.i586.pat +kde-10.3-71.noarch.pat diff --git a/libzypp/tests/repo/yum/YUMDownloader_test.cc b/libzypp/tests/repo/yum/YUMDownloader_test.cc index a7ac950..32a4f0c 100644 --- a/libzypp/tests/repo/yum/YUMDownloader_test.cc +++ b/libzypp/tests/repo/yum/YUMDownloader_test.cc @@ -28,7 +28,7 @@ BOOST_AUTO_TEST_CASE(yum_download) keyring_callbacks.answerAcceptKey(KeyRingReport::KEY_TRUST_TEMPORARILY); Pathname p = DATADIR + "/10.2-updates-subset"; - Url url("dir:" + p.asString()); + Url url(p.asDirUrl()); MediaSetAccess media(url); RepoInfo repoinfo; repoinfo.setAlias("testrepo"); @@ -37,9 +37,9 @@ BOOST_AUTO_TEST_CASE(yum_download) filesystem::TmpDir tmp; Pathname localdir(tmp.path()); - + yum.download(media, localdir); - + const char* files[] = { // "filelists.xml.gz", @@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE(yum_download) "repomd.xml.key", NULL }; - + int i=0; while ( files[i] != NULL ) { diff --git a/libzypp/tests/repo/yum/data/extensions/repodata/repomd.xml b/libzypp/tests/repo/yum/data/extensions/repodata/repomd.xml index 03af328..eee1c85 100644 --- a/libzypp/tests/repo/yum/data/extensions/repodata/repomd.xml +++ b/libzypp/tests/repo/yum/data/extensions/repodata/repomd.xml @@ -1,6 +1,15 @@ - + + obsrepository://build.suse.de/SUSE:openSUSE:11:standard + opensuse + i386 + other string + openSUSE 11.0 + SLE 11.0 + SLE 11.0 + + 603807e12e7418911fa9f158ef66b9c20f1df567 1215823452 @@ -18,14 +27,14 @@ 1215823454 c6bd3c6099de74d97ed045163235be10ffa8a85f - + 359396be40992603aecf6e2832839111e09eb080 1227279057.0 b17c055bef95bca397faffdf028cfa91dd1b24bc - + e0b9149c1b7f48c952e9b3ea996669d8d0d9e1e8 diff --git a/libzypp/tests/sat/CMakeLists.txt b/libzypp/tests/sat/CMakeLists.txt index 4bf1afd..0ec7547 100644 --- a/libzypp/tests/sat/CMakeLists.txt +++ b/libzypp/tests/sat/CMakeLists.txt @@ -6,6 +6,7 @@ ADD_TESTS( IdString LookupAttr Pool + Queue Map Solvable SolvParsing diff --git a/libzypp/tests/sat/Queue_test.cc b/libzypp/tests/sat/Queue_test.cc new file mode 100644 index 0000000..72025f1 --- /dev/null +++ b/libzypp/tests/sat/Queue_test.cc @@ -0,0 +1,51 @@ +#include +#include +#include + +#include "zypp/base/LogTools.h" +#include "zypp/base/Easy.h" +#include "zypp/sat/Queue.h" + + +#define BOOST_TEST_MODULE Queue + +using std::endl; +using std::cout; +using namespace zypp; +using namespace boost::unit_test; + + +BOOST_AUTO_TEST_CASE(basic) +{ + sat::Queue m; + BOOST_CHECK_EQUAL( m.empty(), true ); + BOOST_CHECK_EQUAL( m.size(), 0 ); + BOOST_CHECK_EQUAL( m.begin(), m.end() ); + BOOST_CHECK( m == sat::Queue() ); + BOOST_CHECK_EQUAL( m.first(), 0 ); + BOOST_CHECK_EQUAL( m.last(), 0 ); + + m.push( 13 ); + BOOST_CHECK_EQUAL( m.empty(), false ); + BOOST_CHECK_EQUAL( m.size(), 1 ); + BOOST_CHECK( m.begin() != m.end() ); + BOOST_CHECK_EQUAL( m.begin()+1, m.end() ); + + BOOST_CHECK_EQUAL( m.first(), 13 ); + BOOST_CHECK_EQUAL( m.last(), 13 ); + BOOST_CHECK_EQUAL( m.at(0), 13 ); + BOOST_CHECK_THROW( m.at(1), std::out_of_range ); + + BOOST_CHECK( m.contains(13) ); + BOOST_CHECK( !m.contains(14) ); + + BOOST_CHECK_EQUAL( m.find(13), m.begin() ); + BOOST_CHECK_EQUAL( m.find(14), m.end() ); + + m.pushUnique( 13 ); + BOOST_CHECK_EQUAL( m.size(), 1 ); + m.push( 13 ); + BOOST_CHECK_EQUAL( m.size(), 2 ); + m.remove( 13 ); + BOOST_CHECK_EQUAL( m.size(), 0 ); +} diff --git a/libzypp/tests/sat/Solvable_test.cc b/libzypp/tests/sat/Solvable_test.cc index 4f3396a..f4685ed 100644 --- a/libzypp/tests/sat/Solvable_test.cc +++ b/libzypp/tests/sat/Solvable_test.cc @@ -87,7 +87,7 @@ BOOST_AUTO_TEST_CASE(attributes) BOOST_CHECK_EQUAL(c, 2); } -BOOST_AUTO_TEST_CASE(asString) +BOOST_AUTO_TEST_CASE(asStringTest) { BOOST_CHECK_EQUAL( sat::Solvable(0).asString(), "noSolvable" ); BOOST_CHECK_EQUAL( sat::Solvable(1).asString(), "systemSolvable" ); @@ -203,4 +203,10 @@ BOOST_AUTO_TEST_CASE(SplitIdent) } +BOOST_AUTO_TEST_CASE(duData) +{ + DiskUsageCounter ducounter( DiskUsageCounter::justRootPartition() ); + sat::Solvable s = *sat::WhatProvides( Capability("glibc-devel.x86_64 == 2.8.90-2.3") ).begin(); + BOOST_CHECK_EQUAL( (*ducounter.disk_usage( s ).begin()).pkg_size, 30629 ); +} diff --git a/libzypp/tests/zypp/CMakeLists.txt b/libzypp/tests/zypp/CMakeLists.txt index b2cfee6..acafee6 100644 --- a/libzypp/tests/zypp/CMakeLists.txt +++ b/libzypp/tests/zypp/CMakeLists.txt @@ -9,6 +9,8 @@ ADD_TESTS( Arch Capabilities CheckSum + ContentType + CpeId Date Dup Digest @@ -35,6 +37,7 @@ ADD_TESTS( ResKind ResStatus Selectable + SetRelationMixin StrMatcher Target Url diff --git a/libzypp/tests/zypp/ContentType_test.cc b/libzypp/tests/zypp/ContentType_test.cc new file mode 100644 index 0000000..6d7cbcb --- /dev/null +++ b/libzypp/tests/zypp/ContentType_test.cc @@ -0,0 +1,66 @@ +#include +#include +#include +#include "zypp/ContentType.h" + +using std::cout; +using std::endl; + +using zypp::ContentType; + +BOOST_AUTO_TEST_CASE(contenttype_default) +{ + ContentType v; + BOOST_CHECK( !v ); + BOOST_CHECK( v.empty() ); + BOOST_CHECK( v.emptyType() ); + BOOST_CHECK( v.emptySubtype() ); + + ContentType w( "/" ); + BOOST_CHECK_EQUAL( v == w, true ); + BOOST_CHECK_EQUAL( v != w, false ); + BOOST_CHECK_EQUAL( v < w, false ); + BOOST_CHECK_EQUAL( v <= w, true ); + BOOST_CHECK_EQUAL( v > w, false ); + BOOST_CHECK_EQUAL( v >= w, true ); + + BOOST_CHECK_EQUAL( v.asString(), "" ); +} + +BOOST_AUTO_TEST_CASE(contenttype_val) +{ + BOOST_CHECK_THROW( ContentType( " " ), std::invalid_argument ); + + BOOST_CHECK_THROW( ContentType( "//" ), std::invalid_argument ); + BOOST_CHECK_THROW( ContentType( "/ " ), std::invalid_argument ); + + BOOST_CHECK_THROW( ContentType( "/", "a" ), std::invalid_argument ); + BOOST_CHECK_THROW( ContentType( "a", "/" ), std::invalid_argument ); + + BOOST_CHECK_THROW( ContentType( " ", "a" ), std::invalid_argument ); + BOOST_CHECK_THROW( ContentType( "a", " " ), std::invalid_argument ); +} + +BOOST_AUTO_TEST_CASE(contenttype_cmp) +{ + std::set c( { + ContentType( "" ), + ContentType( "/" ), // == "" + ContentType( "a" ), + ContentType( "a/" ), // == "a" + ContentType( "/a" ), + ContentType( "" , "a" ), // == "/a" + ContentType( "a/b" ), + ContentType( "b/b" ), + ContentType( "b/c" ) + }); + + std::set::const_iterator i = c.begin(); + BOOST_CHECK_EQUAL( *(i++), ContentType() ); + BOOST_CHECK_EQUAL( *(i++), ContentType( "", "a" ) ); + BOOST_CHECK_EQUAL( *(i++), ContentType( "a", "" ) ); + BOOST_CHECK_EQUAL( *(i++), ContentType( "a", "b" ) ); + BOOST_CHECK_EQUAL( *(i++), ContentType( "b", "b" ) ); + BOOST_CHECK_EQUAL( *(i++), ContentType( "b", "c" ) ); + BOOST_CHECK( i == c.end() ); +} diff --git a/libzypp/tests/zypp/CpeId_test.cc b/libzypp/tests/zypp/CpeId_test.cc new file mode 100644 index 0000000..2322b49 --- /dev/null +++ b/libzypp/tests/zypp/CpeId_test.cc @@ -0,0 +1,452 @@ +#include +#include +#include "zypp/CpeId.h" + +using std::cout; +using std::endl; + +using zypp::SetCompare; +using zypp::SetRelation; +using zypp::CpeId; +typedef CpeId::Value Value; + +/////////////////////////////////////////////////////////////////// +/// Symmetric attribute compare if wildcards are involved! +/// The specs define any comarison with a wildcarded attribute as +/// target to return \c uncomparable: +/// \code +/// wildcardfree <=> wildcarded ==> uncomparable, +/// wildcarded <=> wildcardfree ==> superset or disjoint +/// \endcode +/// But a symmetric result is much more intuitive: +/// \code +/// wildcardfree <=> wildcarded ==> subset or disjoint +/// wildcarded <=> wildcardfree ==> superset or disjoint +/// \endcode +/////////////////////////////////////////////////////////////////// +#define WFN_STRICT_SPEC 0 + +#define defVALUE(N,S) \ + const std::string N##Str( S ); \ + Value N( N##Str ); + +defVALUE( wildcardfree, "STrv\\*al\\?" ); // '\?' quoted? +const std::string wildcardfreeUri( "STrv%2aal%3f" ); +const std::string wildcardfreeFs( "STrv\\*al\\?" ); + +defVALUE( wildcardfree2, "stRV\\*al\\\\\\?" ); // '\\\?' backslash, quoted? + +defVALUE( wildcarded, "strv\\*AL?" ); // '?' ? +const std::string wildcardedUri( "strv%2aAL%01" ); +const std::string wildcardedFs( "strv\\*AL?" ); + +defVALUE( wildcarded2, "strv\\*AL\\\\?" ); // '\\?' backslash, ? + + + +BOOST_AUTO_TEST_CASE(cpeid_value_ANY) +{ + for ( const auto & c : { Value(), Value(nullptr), Value("*"), Value::ANY } ) + { + BOOST_CHECK( c.isANY() ); + BOOST_CHECK( ! c.isNA() ); + BOOST_CHECK( c.isLogical() ); + BOOST_CHECK( ! c.isString() ); + BOOST_CHECK( c == Value::ANY ); + BOOST_CHECK( c == nullptr ); // ANY + BOOST_CHECK( c != Value::NA ); + BOOST_CHECK( c != wildcardfree ); + BOOST_CHECK( c != wildcarded ); + BOOST_CHECK( ! c.isWildcardfree() ); + BOOST_CHECK( ! c.isWildcarded() ); + BOOST_CHECK_EQUAL( c.asFs(), "*" ); + BOOST_CHECK_EQUAL( c.asUri(), "" ); + BOOST_CHECK_EQUAL( c.asWfn(), "*" ); + BOOST_CHECK_EQUAL( c.asString(), c.asWfn() ); + } +} + +BOOST_AUTO_TEST_CASE(cpeid_value_NA) +{ + for ( const auto & c : { Value(""), Value::NA } ) + { + BOOST_CHECK( ! c.isANY() ); + BOOST_CHECK( c.isNA() ); + BOOST_CHECK( c.isLogical() ); + BOOST_CHECK( ! c.isString() ); + BOOST_CHECK( c != Value::ANY ); + BOOST_CHECK( c == Value::NA ); + BOOST_CHECK( c == std::string() ); // NA + BOOST_CHECK( c == "" ); // NA + BOOST_CHECK( c != wildcardfree ); + BOOST_CHECK( c != wildcarded ); + BOOST_CHECK( ! c.isWildcardfree() ); + BOOST_CHECK( ! c.isWildcarded() ); + BOOST_CHECK_EQUAL( c.asFs(), "-" ); + BOOST_CHECK_EQUAL( c.asUri(), "-" ); + BOOST_CHECK_EQUAL( c.asWfn(), "" ); + BOOST_CHECK_EQUAL( c.asString(), c.asWfn() ); + } +} + +BOOST_AUTO_TEST_CASE(cpeid_value_string_wildcardfree) +{ + for ( const auto & c : { wildcardfree } ) + { + BOOST_CHECK( ! c.isANY() ); + BOOST_CHECK( ! c.isNA() ); + BOOST_CHECK( ! c.isLogical() ); + BOOST_CHECK( c.isString() ); + BOOST_CHECK( c != Value::ANY ); + BOOST_CHECK( c != Value::NA ); + BOOST_CHECK( c == wildcardfree ); + BOOST_CHECK( c == wildcardfreeStr ); + BOOST_CHECK( c == wildcardfreeStr.c_str() ); + BOOST_CHECK( c != wildcarded ); + BOOST_CHECK( c.isWildcardfree() ); + BOOST_CHECK( ! c.isWildcarded() ); + BOOST_CHECK_EQUAL( c.asFs(), wildcardfreeFs ); + BOOST_CHECK_EQUAL( c.asUri(), wildcardfreeUri ); + BOOST_CHECK_EQUAL( c.asWfn(), wildcardfreeStr ); + BOOST_CHECK_EQUAL( c.asString(), c.asWfn() ); + } + + BOOST_CHECK( wildcardfree2 == wildcardfree2 ); + BOOST_CHECK( wildcardfree2 != wildcardfree ); + BOOST_CHECK( wildcardfree2 != wildcarded ); + BOOST_CHECK( wildcardfree2.isWildcardfree() ); + BOOST_CHECK( ! wildcardfree2.isWildcarded() ); +} + +BOOST_AUTO_TEST_CASE(cpeid_value_string_wildcarded) +{ + for ( const auto & c : { wildcarded } ) + { + BOOST_CHECK( ! c.isANY() ); + BOOST_CHECK( ! c.isNA() ); + BOOST_CHECK( ! c.isLogical() ); + BOOST_CHECK( c.isString() ); + BOOST_CHECK( c != Value::ANY ); + BOOST_CHECK( c != Value::NA ); + BOOST_CHECK( c != wildcardfree ); +#if WFN_STRICT_SPEC + BOOST_CHECK( c != wildcarded ); // !!! According to the CPE Name Matching Specification Version 2.3 + // unquoted wildcard characters yield an undefined result (not ==). +#else + BOOST_CHECK( c == wildcarded ); +#endif + BOOST_CHECK( ! c.isWildcardfree() ); + BOOST_CHECK( c.isWildcarded() ); + BOOST_CHECK_EQUAL( c.asFs(), wildcardedFs ); + BOOST_CHECK_EQUAL( c.asUri(), wildcardedUri ); + BOOST_CHECK_EQUAL( c.asWfn(), wildcardedStr ); + BOOST_CHECK_EQUAL( c.asString(), c.asWfn() ); + } + +#if WFN_STRICT_SPEC + BOOST_CHECK( wildcarded2 != wildcarded2 ); // unquoted wildcard characters yield an undefined result (not ==). +#else + BOOST_CHECK( wildcarded2 == wildcarded2 ); +#endif + BOOST_CHECK( wildcarded2 != wildcardfree ); + BOOST_CHECK( wildcarded2 != wildcarded ); + BOOST_CHECK( ! wildcarded2.isWildcardfree() ); + BOOST_CHECK( wildcarded2.isWildcarded() ); + + +} + +BOOST_AUTO_TEST_CASE(cpeid_value_valid) +{ + static const char *const hdig = "0123456789abcdef"; + + for ( char ch = 0; ch < CHAR_MAX; ++ch ) + { + // cout << "==== " << unsigned(ch) << endl; + char qchstr[] = { '\\', ch, '\0' }; + std::string chstr( qchstr+1 ); + char pchstr[] = { '%', hdig[(unsigned char)(ch)/16], hdig[(unsigned char)(ch)%16], '\0' }; + + if ( ch == '\0' ) + { + BOOST_CHECK( Value( chstr ).isNA() ); + BOOST_CHECK_THROW( (Value( chstr, Value::fsFormat )), std::invalid_argument ); + BOOST_CHECK( Value( chstr, Value::uriFormat ).isANY() ); + } + else if ( ch <= ' ' || '~' < ch ) + { + BOOST_CHECK_THROW( (Value( chstr )), std::invalid_argument ); + BOOST_CHECK_THROW( (Value( chstr, Value::fsFormat )), std::invalid_argument ); + BOOST_CHECK_THROW( (Value( chstr, Value::uriFormat )), std::invalid_argument ); + } + else if ( ( '0' <= ch && ch <= '9' ) + || ( 'A' <= ch && ch <= 'Z' ) + || ( 'a' <= ch && ch <= 'z' ) + || ch == '_' ) + { + BOOST_CHECK( Value( chstr ).isString() ); + BOOST_CHECK( Value( chstr, Value::fsFormat ).isString() ); + BOOST_CHECK( Value( chstr, Value::uriFormat ).isString() ); + + BOOST_CHECK_THROW( (Value( qchstr )), std::invalid_argument ); + BOOST_CHECK( Value( qchstr, Value::fsFormat ).isString() ); + BOOST_CHECK( Value( qchstr, Value::uriFormat ).isString() ); + + BOOST_CHECK( Value( pchstr, Value::uriFormat ).isString() ); + } + else if ( ch == '*' ) + { + BOOST_CHECK( Value( chstr ).isANY() ); + BOOST_CHECK( Value( chstr, Value::fsFormat ).isANY() ); + BOOST_CHECK( Value( chstr, Value::uriFormat ).isString() ); + + BOOST_CHECK( Value( qchstr ).isString() ); + BOOST_CHECK( Value( qchstr, Value::fsFormat ).isString() ); + BOOST_CHECK( Value( qchstr, Value::uriFormat ).isString() ); + + BOOST_CHECK( Value( pchstr, Value::uriFormat ).isString() ); + } + else if ( ch == '?' ) + { + BOOST_CHECK( Value( chstr ).isString() ); + BOOST_CHECK( Value( chstr, Value::fsFormat ).isString() ); + BOOST_CHECK( Value( chstr, Value::uriFormat ).isString() ); + + BOOST_CHECK( Value( qchstr ).isString() ); + BOOST_CHECK( Value( qchstr, Value::fsFormat ).isString() ); + BOOST_CHECK( Value( qchstr, Value::uriFormat ).isString() ); + + BOOST_CHECK( Value( pchstr, Value::uriFormat ).isString() ); + } + else if ( ch == '-' ) + { + BOOST_CHECK_THROW( (Value( chstr )), std::invalid_argument ); + BOOST_CHECK( Value( chstr, Value::fsFormat ).isNA() ); + BOOST_CHECK( Value( chstr, Value::uriFormat ).isNA() ); + + BOOST_CHECK_THROW( (Value( qchstr )), std::invalid_argument ); + BOOST_CHECK( Value( qchstr, Value::fsFormat ).isString() ); + BOOST_CHECK( Value( qchstr, Value::uriFormat ).isString() ); + + BOOST_CHECK( Value( pchstr, Value::uriFormat ).isString() ); + } + else if ( ch == '\\' ) + { + BOOST_CHECK_THROW( (Value( chstr )), std::invalid_argument ); + BOOST_CHECK_THROW( (Value( chstr, Value::fsFormat )), std::invalid_argument ); + BOOST_CHECK( (Value( chstr, Value::uriFormat )).isString() ); + + BOOST_CHECK( Value( qchstr ).isString() ); + BOOST_CHECK( Value( qchstr, Value::fsFormat ).isString() ); + BOOST_CHECK( Value( qchstr, Value::uriFormat ).isString() ); + + BOOST_CHECK( Value( pchstr, Value::uriFormat ).isString() ); + } + else + { + BOOST_CHECK_THROW( (Value( chstr )), std::invalid_argument ); + Value f( chstr, Value::fsFormat ); + BOOST_CHECK( f.isString() ); + Value u( chstr, Value::uriFormat ); + BOOST_CHECK( u.isString() ); + + BOOST_CHECK_EQUAL( f.asString(), u.asString() ); + if ( ch == '.' ) + { + BOOST_CHECK_EQUAL( f.asFs(), chstr ); + BOOST_CHECK_EQUAL( f.asUri(), chstr ); + } + else + { + BOOST_CHECK_EQUAL( f.asFs(), qchstr ); + BOOST_CHECK_EQUAL( f.asUri(), pchstr ); + } + + BOOST_CHECK( Value( qchstr ).isString() ); + BOOST_CHECK( Value( qchstr, Value::fsFormat ).isString() ); + BOOST_CHECK( Value( qchstr, Value::uriFormat ).isString() ); + + BOOST_CHECK( Value( pchstr, Value::uriFormat ).isString() ); + } + } + + BOOST_CHECK_THROW( Value( "\\!\\a\\-\\_\\.\\!" ), std::invalid_argument ); + BOOST_CHECK_EQUAL( Value( "\\!\\a\\-\\_\\.\\!", Value::fsFormat ).asFs(), "\\!a-_.\\!" ); +} + +BOOST_AUTO_TEST_CASE(cpeid_type_checks) +{ + for ( const auto & c : { Value::ANY, Value::NA, wildcardfree, wildcarded } ) + { + BOOST_CHECK_EQUAL( c.isANY(), c.type() == Value::Type::ANY ); + BOOST_CHECK_EQUAL( c.isNA(), c.type() == Value::Type::NA ); + BOOST_CHECK_EQUAL( c.isWildcardfree(), c.type() == Value::Type::wildcardfree ); + BOOST_CHECK_EQUAL( c.isWildcarded(), c.type() == Value::Type::wildcarded ); + BOOST_CHECK_EQUAL( c.isLogical(), c.isLogical( c.type() ) ); + BOOST_CHECK_EQUAL( c.isString(), c.isString( c.type() ) ); + BOOST_CHECK_EQUAL( c.isLogical(), ! c.isString() ); + } +} + +BOOST_AUTO_TEST_CASE(cpeid_compare) +{ + BOOST_CHECK( compare( Value::ANY, Value::ANY, SetCompare::equal ) ); + BOOST_CHECK( compare( Value::ANY, Value::NA, SetCompare::properSuperset ) ); + BOOST_CHECK( compare( Value::ANY, wildcardfree, SetCompare::properSuperset ) ); +#if WFN_STRICT_SPEC + BOOST_CHECK( compare( Value::ANY, wildcarded, SetCompare::uncomparable ) ); +#else + BOOST_CHECK( compare( Value::ANY, wildcarded, SetCompare::properSuperset ) ); +#endif + + BOOST_CHECK( compare( Value::NA, Value::ANY, SetCompare::properSubset ) ); + BOOST_CHECK( compare( Value::NA, Value::NA, SetCompare::equal ) ); + BOOST_CHECK( compare( Value::NA, wildcardfree, SetCompare::disjoint ) ); +#if WFN_STRICT_SPEC + BOOST_CHECK( compare( Value::NA, wildcarded, SetCompare::uncomparable ) ); +#else + BOOST_CHECK( compare( Value::NA, wildcarded, SetCompare::disjoint ) ); +#endif + + BOOST_CHECK( compare( wildcardfree, Value::ANY, SetCompare::properSubset ) ); + BOOST_CHECK( compare( wildcardfree, Value::NA, SetCompare::disjoint ) ); + //BOOST_CHECK( compare( wildcardfree, wildcardfree, _NeedsCloserLook, // equal or disjoint + BOOST_CHECK( compare( wildcardfree, wildcardfree, SetCompare::equal ) ); + BOOST_CHECK( compare( wildcardfree, wildcardfree2, SetCompare::disjoint ) ); +#if WFN_STRICT_SPEC + BOOST_CHECK( compare( wildcardfree, wildcarded, SetCompare::uncomparable ) ); +#else + //BOOST_CHECK( compare( wildcardfree, wildcarded, _NeedsCloserLook, // subset or disjoint + BOOST_CHECK( compare( wildcardfree, wildcarded, SetCompare::properSubset ) ); + BOOST_CHECK( compare( wildcardfree, wildcarded2, SetCompare::disjoint ) ); +#endif + + BOOST_CHECK( compare( wildcarded, Value::ANY, SetCompare::properSubset ) ); + BOOST_CHECK( compare( wildcarded, Value::NA, SetCompare::disjoint ) ); + //BOOST_CHECK( compare( wildcarded, wildcardfree, _NeedsCloserLook, // superset or disjoint + BOOST_CHECK( compare( wildcarded, wildcardfree, SetCompare::properSuperset ) ); + BOOST_CHECK( compare( wildcarded, wildcardfree2, SetCompare::disjoint ) ); +#if WFN_STRICT_SPEC + BOOST_CHECK( compare( wildcarded, wildcarded, SetCompare::uncomparable ) ); +#else + //BOOST_CHECK( compare( wildcarded, wildcarded, _NeedsCloserLook, // equal or uncomparable + BOOST_CHECK( compare( wildcarded, wildcarded, SetCompare::equal ) ); + BOOST_CHECK( compare( wildcarded, wildcarded2, SetCompare::uncomparable ) ); +#endif +} + + +BOOST_AUTO_TEST_CASE(cpeid_value_string_wildcard) +{ + for ( const auto & c : { Value( "a" ), Value( "\\*" ), Value( "\\?" ) } ) + { + BOOST_CHECK( c.isWildcardfree() ); + BOOST_CHECK( !c.isWildcarded() ); + } + + for ( const auto & c : { Value( "*\\*" ), Value( "\\**" ), Value( "?" ), Value( "??\\?" ), Value( "\\???" ) } ) + { + BOOST_CHECK( !c.isWildcardfree() ); + BOOST_CHECK( c.isWildcarded() ); + } +} + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// + +BOOST_AUTO_TEST_CASE(cpeid_basics) +{ + BOOST_CHECK_THROW( CpeId( "malformed" ), std::invalid_argument ); + CpeId none( "malformed", CpeId::noThrow ); + BOOST_CHECK_EQUAL( CpeId::NoThrowType::lastMalformed, "malformed" ); + CpeId( "", CpeId::noThrow ); + BOOST_CHECK_EQUAL( CpeId::NoThrowType::lastMalformed, "" ); + + for ( const auto & c : { CpeId(), CpeId( nullptr ), CpeId( "" ), CpeId( std::string() ), CpeId( "cpe:2.3:" ), CpeId( "cpe:/" ) } ) + { + BOOST_CHECK( ! c ); // evaluate false in boolean context + BOOST_CHECK_EQUAL( c.asString(), c.asFs() ); + BOOST_CHECK_EQUAL( c.asFs(), "cpe:2.3:*:*:*:*:*:*:*:*:*:*:*" ); + BOOST_CHECK_EQUAL( c.asUri(), "cpe:/" ); + BOOST_CHECK_EQUAL( c.asWfn(), "wfn:[]" ); + BOOST_CHECK_EQUAL( c, none ); // matching!! + } + + for ( const auto & c : { CpeId( "cpe:/o:sle" ), CpeId( "cpe:/o:*" ) } ) + { + BOOST_CHECK( c ); // evaluate true in boolean context + BOOST_CHECK( ! c.asString().empty() );// empty string rep + BOOST_CHECK_EQUAL( c, c ); // matching!! + } +} + +void testStrconv( const std::string & fs, const std::string & uri, const std::string & wfn ) +{ + CpeId fromFS( fs ) ; + CpeId fromURI( uri ); + + BOOST_CHECK_EQUAL( fromFS, fromURI ); + + for ( const auto & c : { fromFS, fromURI } ) + { + BOOST_CHECK_EQUAL( c.asFs(), fs ); + BOOST_CHECK_EQUAL( c.asUri(), uri ); + BOOST_CHECK_EQUAL( c.asWfn(), wfn ); + } +} + +BOOST_AUTO_TEST_CASE(cpeid_strconv) +{ + // colon embedded in product value + testStrconv ( "cpe:2.3:a:opensuse:lib\\:zypp:14.16.0:beta:*:*:*:*:*:-", + "cpe:/a:opensuse:lib%3azypp:14.16.0:beta:~~~~~-", + "wfn:[part=\"a\",vendor=\"opensuse\",product=\"lib\\:zypp\",version=\"14\\.16\\.0\",update=\"beta\",other=NA]" ); + + testStrconv ( "cpe:2.3:a:hp:insight_diagnostics:7.4.0.1570:-:*:*:online:win2003:x64:*", + "cpe:/a:hp:insight_diagnostics:7.4.0.1570:-:~~online~win2003~x64~", + "wfn:[part=\"a\",vendor=\"hp\",product=\"insight_diagnostics\",version=\"7\\.4\\.0\\.1570\",update=NA,sw_edition=\"online\",target_sw=\"win2003\",target_hw=\"x64\"]" ); + + testStrconv ( "cpe:2.3:a:hp:openview_network_manager:7.51:*:*:*:*:linux:*:*", + "cpe:/a:hp:openview_network_manager:7.51::~~~linux~~", + "wfn:[part=\"a\",vendor=\"hp\",product=\"openview_network_manager\",version=\"7\\.51\",target_sw=\"linux\"]" ); + + testStrconv ( "cpe:2.3:a:foo\\\\bar:big\\$money_manager_2010:*:*:*:*:special:ipod_touch:80gb:*", + "cpe:/a:foo%5cbar:big%24money_manager_2010:::~~special~ipod_touch~80gb~", + "wfn:[part=\"a\",vendor=\"foo\\\\bar\",product=\"big\\$money_manager_2010\",sw_edition=\"special\",target_sw=\"ipod_touch\",target_hw=\"80gb\"]" ); + + BOOST_CHECK_THROW( (CpeId( "cpe:/x:" )), std::invalid_argument ); // illegal part 'x' + BOOST_CHECK_THROW( CpeId( "cpe:/a:foo%5cbar:big%24money_2010%07:::~~special~ipod_touch~80gb~" ), std::invalid_argument ); // illegal %07 + BOOST_CHECK_EQUAL( CpeId( "cpe:/a:foo~bar:big%7emoney_2010" ).asUri(), "cpe:/a:foo%7ebar:big%7emoney_2010" ); // unescaped ~ is ok but not preferred +} + +BOOST_AUTO_TEST_CASE(cpeid_matches) +{ + CpeId sle( "cpe:/o:sles" ); + CpeId win( "cpe:/o:windows" ); + CpeId any; + CpeId ons( "cpe:2.3:o:??????s" ); + CpeId oops( "cpe:2.3:o:?????s" ); + + BOOST_CHECK_EQUAL( compare( sle, win ), SetRelation::disjoint ); + + BOOST_CHECK_EQUAL( compare( sle, any ), SetRelation::subset ); + BOOST_CHECK_EQUAL( compare( win, any ), SetRelation::subset ); + + BOOST_CHECK_EQUAL( compare( any, sle ), SetRelation::superset ); + BOOST_CHECK_EQUAL( compare( any, win ), SetRelation::superset ); + +#if WFN_STRICT_SPEC + BOOST_CHECK_EQUAL( compare( sle, ons ), SetRelation::uncomparable ); + BOOST_CHECK_EQUAL( compare( win, ons ), SetRelation::uncomparable ); +#else + BOOST_CHECK_EQUAL( compare( sle, ons ), SetRelation::subset ); + BOOST_CHECK_EQUAL( compare( win, ons ), SetRelation::subset ); +#endif + + BOOST_CHECK_EQUAL( compare( ons, sle ), SetRelation::superset ); + BOOST_CHECK_EQUAL( compare( ons, win ), SetRelation::superset ); + + BOOST_CHECK_EQUAL( compare( oops, sle ), SetRelation::superset ); + BOOST_CHECK_EQUAL( compare( oops, win ), SetRelation::disjoint ); + +} diff --git a/libzypp/tests/zypp/Fetcher_test.cc b/libzypp/tests/zypp/Fetcher_test.cc index 0adcb6f..48f4bd7 100644 --- a/libzypp/tests/zypp/Fetcher_test.cc +++ b/libzypp/tests/zypp/Fetcher_test.cc @@ -289,7 +289,7 @@ BOOST_AUTO_TEST_CASE(enqueue_digested_images_file_content_autoindex_unsigned) // it should throw because unsigned file throws BOOST_CHECK_THROW( fetcher.start( dest.path(), media ), FileCheckException); fetcher.reset(); - // the target file was NOT transfered + // the target file was NOT transferred BOOST_CHECK( ! PathInfo(dest.path() + "/images/images.xml").isExist() ); fetcher.reset(); } @@ -359,7 +359,7 @@ BOOST_AUTO_TEST_CASE(enqueuedir_http) BOOST_CHECK( ! PathInfo(dest.path() + "/complexdir-broken/subdir2/subdir2-file1.txt").isExist() ); - // this one got transfered before the failure, so it is there + // this one got transferred before the failure, so it is there BOOST_CHECK( PathInfo(dest.path() + "/complexdir-broken/subdir1/subdir1-file1.txt").isExist() ); BOOST_CHECK( ! PathInfo(dest.path() + "/complexdir-broken/subdir1/subdir1-file2.txt").isExist() ); diff --git a/libzypp/tests/zypp/Flags_test.cc b/libzypp/tests/zypp/Flags_test.cc index d6e4666..95dee3c 100644 --- a/libzypp/tests/zypp/Flags_test.cc +++ b/libzypp/tests/zypp/Flags_test.cc @@ -4,6 +4,7 @@ #include #include "zypp/base/Logger.h" #include "zypp/base/Flags.h" +#include using boost::unit_test::test_case; using std::cout; @@ -80,4 +81,4 @@ BOOST_AUTO_TEST_CASE(flags) t.unsetFlag( T_2 ); BOOST_CHECK( t.testFlag( T_1 ) ); t.setFlag( T_1, false ); BOOST_CHECK( t.testFlag( T_0 ) ); t.setFlag( T_3, true ); BOOST_CHECK( t.testFlag( T_3 ) ); -} \ No newline at end of file +} diff --git a/libzypp/tests/zypp/KeyRingTestReceiver.h b/libzypp/tests/zypp/KeyRingTestReceiver.h index dce6744..3595bdc 100644 --- a/libzypp/tests/zypp/KeyRingTestReceiver.h +++ b/libzypp/tests/zypp/KeyRingTestReceiver.h @@ -124,9 +124,9 @@ struct KeyRingTestSignalReceiver : zypp::callback::ReceiveReport /** Data class for shared_ptr */ struct NonIntrusive : private Trace { - Trace::numericId; + using Trace::numericId; }; /** Data class for intrusive_ptr */ struct Intrusive : public ReferenceCounted, private Trace { - Trace::numericId; + using Trace::numericId; }; namespace zypp @@ -54,8 +54,8 @@ namespace zypp /****************************************************************** ** */ -#define T_NULL assert( !ptr ) -#define T_NOT_NULL assert( ptr ) +#define T_NULL assert( !ptr ); assert( ptr == nullptr ) +#define T_NOT_NULL assert( ptr ); assert( ptr != nullptr ) #define T_UNIQUE assert( ptr.unique() ); assert( ptr.use_count() < 2 ) #define T_NOT_UNIQUE assert( !ptr.unique() ); assert( ptr.use_count() >= 2 ) // Also comapre with underlying shared ptr type. @@ -100,6 +100,18 @@ template ptr.reset( 0 ); T_NULL; T_UNIQUE; + // nullptr compatible + ptr.reset( nullptr ); + T_NULL; + T_UNIQUE; + ptr = nullptr; + T_NULL; + T_UNIQUE; + ptr = _RW( nullptr ); + T_NULL; + T_UNIQUE; + + } template diff --git a/libzypp/tests/zypp/PublicKey_test.cc b/libzypp/tests/zypp/PublicKey_test.cc index f2abbca..98c8b2d 100644 --- a/libzypp/tests/zypp/PublicKey_test.cc +++ b/libzypp/tests/zypp/PublicKey_test.cc @@ -18,248 +18,38 @@ using boost::unit_test::test_case; using namespace std; using namespace zypp; -/* ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1.4.2 (GNU/Linux) - -mQGiBDnu9IERBACT8Y35+2vv4MGVKiLEMOl9GdST6MCkYS3yEKeueNWc+z/0Kvff -4JctBsgs47tjmiI9sl0eHjm3gTR8rItXMN6sJEUHWzDP+Y0PFPboMvKx0FXl/A0d -M+HFrruCgBlWt6FA+okRySQiliuI5phwqkXefl9AhkwR8xocQSVCFxcwvwCglVcO -QliHu8jwRQHxlRE0tkwQQI0D+wfQwKdvhDplxHJ5nf7U8c/yE/vdvpN6lF0tmFrK -XBUX+K7u4ifrZlQvj/81M4INjtXreqDiJtr99Rs6xa0ScZqITuZC4CWxJa9GynBE -D3+D2t1V/f8l0smsuYoFOF7Ib49IkTdbtwAThlZp8bEhELBeGaPdNCcmfZ66rKUd -G5sRA/9ovnc1krSQF2+sqB9/o7w5/q2qiyzwOSTnkjtBUVKn4zLUOf6aeBAoV6NM -CC3Kj9aZHfA+ND0ehPaVGJgjaVNFhPi4x0e7BULdvgOoAqajLfvkURHAeSsxXIoE -myW/xC1sBbDkDUIBSx5oej73XCZgnj/inphRqGpsb+1nKFvF+rQoU3VTRSBQYWNr -YWdlIFNpZ25pbmcgS2V5IDxidWlsZEBzdXNlLmRlPohiBBMRAgAiBQJA2AY+AhsD -BQkObd+9BAsHAwIDFQIDAxYCAQIeAQIXgAAKCRCoTtronIAKypCfAJ9RuZ6ZSV7Q -W4pTgTIxQ+ABPp0sIwCffG9bCNnrETPlgOn+dGEkAWegKL+IRgQQEQIABgUCOnBe -UgAKCRCeQOMQAAqrpNzOAKCL512FZvv4VZx94TpbA9lxyoAejACeOO1HIbActAev -k5MUBhNeLZa/qM2JARUDBRA6cGBvd7LmAD0l09kBATWnB/9An5vfiUUE1VQnt+T/ -EYklES3tXXaJJp9pHMa4fzFa8jPVtv5UBHGee3XoUNDVwM2OgSEISZxbzdXGnqIl -cT08TzBUD9i579uifklLsnr35SJDZ6ram51/CWOnnaVhUzneOA9gTPSr+/fT3WeV -nwJiQCQ30kNLWVXWATMnsnT486eAOlT6UNBPYQLpUprF5Yryk23pQUPAgJENDEqe -U6iIO9Ot1ZPtB0lniw+/xCi13D360o1tZDYOp0hHHJN3D3EN8C1yPqZd5CvvznYv -B6bWBIpWcRgdn2DUVMmpU661jwqGlRz1F84JG/xe4jGuzgpJt9IXSzyohEJB6XG5 -+D0BuQINBDnu9JIQCACEkdBN6Mxf5WvqDWkcMRy6wnrd9DYJ8UUTmIT2iQf07tRU -KJJ9v0JXfx2Z4d08IQSMNRaq4VgSe+PdYgIy0fbj23Via5/gO7fJEpD2hd2f+pMn -OWvH2rOOIbeYfuhzAc6BQjAKtmgR0ERUTafTM9Wb6F13CNZZNZfDqnFDP6L12w3z -3F7FFXkz07Rs3AIto1ZfYZd4sCSpMr/0S5nLrHbIvGLp271hhQBeRmmoGEKO2JRe -lGgUJ2CUzOdtwDIKT0LbCpvaP8PVnYF5IFoYJIWRHqlEt5ucTXstZy7vYjL6vTP4 -l5xs+LIOkNmPhqmfsgLzVo0UaLt80hOwc4NvDCOLAAMGB/9g+9V3ORzw4LvO1pwR -YJqfDKUq/EJ0rNMMD4N8RLpZRhKHKJUm9nNHLbksnlZwrbSTM5LpC/U6sheLP+l0 -bLVoq0lmsCcUSyh+mY6PxWirLIWCn/IAZAGnXb6Zd6TtIJlGG6pqUN8QxGJYQnon -l0uTJKHJENbI9sWHQdcTtBMc34gorHFCo1Bcvpnc1LFLrWn7mfoGx6INQjf3HGQp -MXAWuSBQhzkazY6vaWFpa8bBJ+gKbBuySWzNm3rFtT5HRKMWpO+M9bHp4d+puY0L -1YwN1OMatcMMpcWnZpiWiR83oi32+xtWUY2U7Ae38mMag8zFbpeqPQUsDv9V7CAJ -1dbriEwEGBECAAwFAkDYBnoFCQ5t3+gACgkQqE7a6JyACspnpgCfRbYwxT3iq+9l -/PgNTUNTZOlof2oAn25y0eGi0371jap9kOV6uq71sUuO -=pJli ------END PGP PUBLIC KEY BLOCK----- -*/ - -/** - * Array version of the above key - */ -char susekey[]= -{ - 0x2d,0x2d,0x2d,0x2d,0x2d,0x42,0x45,0x47,0x49,0x4e,0x20,0x50,0x47, - 0x50,0x20,0x50,0x55,0x42,0x4c,0x49,0x43,0x20,0x4b,0x45,0x59,0x20, - 0x42,0x4c,0x4f,0x43,0x4b,0x2d,0x2d,0x2d,0x2d,0x2d,0x0a,0x56,0x65, - 0x72,0x73,0x69,0x6f,0x6e,0x3a,0x20,0x47,0x6e,0x75,0x50,0x47,0x20, - 0x76,0x31,0x2e,0x34,0x2e,0x32,0x20,0x28,0x47,0x4e,0x55,0x2f,0x4c, - 0x69,0x6e,0x75,0x78,0x29,0x0a,0x0a,0x6d,0x51,0x47,0x69,0x42,0x44, - 0x6e,0x75,0x39,0x49,0x45,0x52,0x42,0x41,0x43,0x54,0x38,0x59,0x33, - 0x35,0x2b,0x32,0x76,0x76,0x34,0x4d,0x47,0x56,0x4b,0x69,0x4c,0x45, - 0x4d,0x4f,0x6c,0x39,0x47,0x64,0x53,0x54,0x36,0x4d,0x43,0x6b,0x59, - 0x53,0x33,0x79,0x45,0x4b,0x65,0x75,0x65,0x4e,0x57,0x63,0x2b,0x7a, - 0x2f,0x30,0x4b,0x76,0x66,0x66,0x0a,0x34,0x4a,0x63,0x74,0x42,0x73, - 0x67,0x73,0x34,0x37,0x74,0x6a,0x6d,0x69,0x49,0x39,0x73,0x6c,0x30, - 0x65,0x48,0x6a,0x6d,0x33,0x67,0x54,0x52,0x38,0x72,0x49,0x74,0x58, - 0x4d,0x4e,0x36,0x73,0x4a,0x45,0x55,0x48,0x57,0x7a,0x44,0x50,0x2b, - 0x59,0x30,0x50,0x46,0x50,0x62,0x6f,0x4d,0x76,0x4b,0x78,0x30,0x46, - 0x58,0x6c,0x2f,0x41,0x30,0x64,0x0a,0x4d,0x2b,0x48,0x46,0x72,0x72, - 0x75,0x43,0x67,0x42,0x6c,0x57,0x74,0x36,0x46,0x41,0x2b,0x6f,0x6b, - 0x52,0x79,0x53,0x51,0x69,0x6c,0x69,0x75,0x49,0x35,0x70,0x68,0x77, - 0x71,0x6b,0x58,0x65,0x66,0x6c,0x39,0x41,0x68,0x6b,0x77,0x52,0x38, - 0x78,0x6f,0x63,0x51,0x53,0x56,0x43,0x46,0x78,0x63,0x77,0x76,0x77, - 0x43,0x67,0x6c,0x56,0x63,0x4f,0x0a,0x51,0x6c,0x69,0x48,0x75,0x38, - 0x6a,0x77,0x52,0x51,0x48,0x78,0x6c,0x52,0x45,0x30,0x74,0x6b,0x77, - 0x51,0x51,0x49,0x30,0x44,0x2b,0x77,0x66,0x51,0x77,0x4b,0x64,0x76, - 0x68,0x44,0x70,0x6c,0x78,0x48,0x4a,0x35,0x6e,0x66,0x37,0x55,0x38, - 0x63,0x2f,0x79,0x45,0x2f,0x76,0x64,0x76,0x70,0x4e,0x36,0x6c,0x46, - 0x30,0x74,0x6d,0x46,0x72,0x4b,0x0a,0x58,0x42,0x55,0x58,0x2b,0x4b, - 0x37,0x75,0x34,0x69,0x66,0x72,0x5a,0x6c,0x51,0x76,0x6a,0x2f,0x38, - 0x31,0x4d,0x34,0x49,0x4e,0x6a,0x74,0x58,0x72,0x65,0x71,0x44,0x69, - 0x4a,0x74,0x72,0x39,0x39,0x52,0x73,0x36,0x78,0x61,0x30,0x53,0x63, - 0x5a,0x71,0x49,0x54,0x75,0x5a,0x43,0x34,0x43,0x57,0x78,0x4a,0x61, - 0x39,0x47,0x79,0x6e,0x42,0x45,0x0a,0x44,0x33,0x2b,0x44,0x32,0x74, - 0x31,0x56,0x2f,0x66,0x38,0x6c,0x30,0x73,0x6d,0x73,0x75,0x59,0x6f, - 0x46,0x4f,0x46,0x37,0x49,0x62,0x34,0x39,0x49,0x6b,0x54,0x64,0x62, - 0x74,0x77,0x41,0x54,0x68,0x6c,0x5a,0x70,0x38,0x62,0x45,0x68,0x45, - 0x4c,0x42,0x65,0x47,0x61,0x50,0x64,0x4e,0x43,0x63,0x6d,0x66,0x5a, - 0x36,0x36,0x72,0x4b,0x55,0x64,0x0a,0x47,0x35,0x73,0x52,0x41,0x2f, - 0x39,0x6f,0x76,0x6e,0x63,0x31,0x6b,0x72,0x53,0x51,0x46,0x32,0x2b, - 0x73,0x71,0x42,0x39,0x2f,0x6f,0x37,0x77,0x35,0x2f,0x71,0x32,0x71, - 0x69,0x79,0x7a,0x77,0x4f,0x53,0x54,0x6e,0x6b,0x6a,0x74,0x42,0x55, - 0x56,0x4b,0x6e,0x34,0x7a,0x4c,0x55,0x4f,0x66,0x36,0x61,0x65,0x42, - 0x41,0x6f,0x56,0x36,0x4e,0x4d,0x0a,0x43,0x43,0x33,0x4b,0x6a,0x39, - 0x61,0x5a,0x48,0x66,0x41,0x2b,0x4e,0x44,0x30,0x65,0x68,0x50,0x61, - 0x56,0x47,0x4a,0x67,0x6a,0x61,0x56,0x4e,0x46,0x68,0x50,0x69,0x34, - 0x78,0x30,0x65,0x37,0x42,0x55,0x4c,0x64,0x76,0x67,0x4f,0x6f,0x41, - 0x71,0x61,0x6a,0x4c,0x66,0x76,0x6b,0x55,0x52,0x48,0x41,0x65,0x53, - 0x73,0x78,0x58,0x49,0x6f,0x45,0x0a,0x6d,0x79,0x57,0x2f,0x78,0x43, - 0x31,0x73,0x42,0x62,0x44,0x6b,0x44,0x55,0x49,0x42,0x53,0x78,0x35, - 0x6f,0x65,0x6a,0x37,0x33,0x58,0x43,0x5a,0x67,0x6e,0x6a,0x2f,0x69, - 0x6e,0x70,0x68,0x52,0x71,0x47,0x70,0x73,0x62,0x2b,0x31,0x6e,0x4b, - 0x46,0x76,0x46,0x2b,0x72,0x51,0x6f,0x55,0x33,0x56,0x54,0x52,0x53, - 0x42,0x51,0x59,0x57,0x4e,0x72,0x0a,0x59,0x57,0x64,0x6c,0x49,0x46, - 0x4e,0x70,0x5a,0x32,0x35,0x70,0x62,0x6d,0x63,0x67,0x53,0x32,0x56, - 0x35,0x49,0x44,0x78,0x69,0x64,0x57,0x6c,0x73,0x5a,0x45,0x42,0x7a, - 0x64,0x58,0x4e,0x6c,0x4c,0x6d,0x52,0x6c,0x50,0x6f,0x68,0x69,0x42, - 0x42,0x4d,0x52,0x41,0x67,0x41,0x69,0x42,0x51,0x4a,0x41,0x32,0x41, - 0x59,0x2b,0x41,0x68,0x73,0x44,0x0a,0x42,0x51,0x6b,0x4f,0x62,0x64, - 0x2b,0x39,0x42,0x41,0x73,0x48,0x41,0x77,0x49,0x44,0x46,0x51,0x49, - 0x44,0x41,0x78,0x59,0x43,0x41,0x51,0x49,0x65,0x41,0x51,0x49,0x58, - 0x67,0x41,0x41,0x4b,0x43,0x52,0x43,0x6f,0x54,0x74,0x72,0x6f,0x6e, - 0x49,0x41,0x4b,0x79,0x70,0x43,0x66,0x41,0x4a,0x39,0x52,0x75,0x5a, - 0x36,0x5a,0x53,0x56,0x37,0x51,0x0a,0x57,0x34,0x70,0x54,0x67,0x54, - 0x49,0x78,0x51,0x2b,0x41,0x42,0x50,0x70,0x30,0x73,0x49,0x77,0x43, - 0x66,0x66,0x47,0x39,0x62,0x43,0x4e,0x6e,0x72,0x45,0x54,0x50,0x6c, - 0x67,0x4f,0x6e,0x2b,0x64,0x47,0x45,0x6b,0x41,0x57,0x65,0x67,0x4b, - 0x4c,0x2b,0x49,0x52,0x67,0x51,0x51,0x45,0x51,0x49,0x41,0x42,0x67, - 0x55,0x43,0x4f,0x6e,0x42,0x65,0x0a,0x55,0x67,0x41,0x4b,0x43,0x52, - 0x43,0x65,0x51,0x4f,0x4d,0x51,0x41,0x41,0x71,0x72,0x70,0x4e,0x7a, - 0x4f,0x41,0x4b,0x43,0x4c,0x35,0x31,0x32,0x46,0x5a,0x76,0x76,0x34, - 0x56,0x5a,0x78,0x39,0x34,0x54,0x70,0x62,0x41,0x39,0x6c,0x78,0x79, - 0x6f,0x41,0x65,0x6a,0x41,0x43,0x65,0x4f,0x4f,0x31,0x48,0x49,0x62, - 0x41,0x63,0x74,0x41,0x65,0x76,0x0a,0x6b,0x35,0x4d,0x55,0x42,0x68, - 0x4e,0x65,0x4c,0x5a,0x61,0x2f,0x71,0x4d,0x32,0x4a,0x41,0x52,0x55, - 0x44,0x42,0x52,0x41,0x36,0x63,0x47,0x42,0x76,0x64,0x37,0x4c,0x6d, - 0x41,0x44,0x30,0x6c,0x30,0x39,0x6b,0x42,0x41,0x54,0x57,0x6e,0x42, - 0x2f,0x39,0x41,0x6e,0x35,0x76,0x66,0x69,0x55,0x55,0x45,0x31,0x56, - 0x51,0x6e,0x74,0x2b,0x54,0x2f,0x0a,0x45,0x59,0x6b,0x6c,0x45,0x53, - 0x33,0x74,0x58,0x58,0x61,0x4a,0x4a,0x70,0x39,0x70,0x48,0x4d,0x61, - 0x34,0x66,0x7a,0x46,0x61,0x38,0x6a,0x50,0x56,0x74,0x76,0x35,0x55, - 0x42,0x48,0x47,0x65,0x65,0x33,0x58,0x6f,0x55,0x4e,0x44,0x56,0x77, - 0x4d,0x32,0x4f,0x67,0x53,0x45,0x49,0x53,0x5a,0x78,0x62,0x7a,0x64, - 0x58,0x47,0x6e,0x71,0x49,0x6c,0x0a,0x63,0x54,0x30,0x38,0x54,0x7a, - 0x42,0x55,0x44,0x39,0x69,0x35,0x37,0x39,0x75,0x69,0x66,0x6b,0x6c, - 0x4c,0x73,0x6e,0x72,0x33,0x35,0x53,0x4a,0x44,0x5a,0x36,0x72,0x61, - 0x6d,0x35,0x31,0x2f,0x43,0x57,0x4f,0x6e,0x6e,0x61,0x56,0x68,0x55, - 0x7a,0x6e,0x65,0x4f,0x41,0x39,0x67,0x54,0x50,0x53,0x72,0x2b,0x2f, - 0x66,0x54,0x33,0x57,0x65,0x56,0x0a,0x6e,0x77,0x4a,0x69,0x51,0x43, - 0x51,0x33,0x30,0x6b,0x4e,0x4c,0x57,0x56,0x58,0x57,0x41,0x54,0x4d, - 0x6e,0x73,0x6e,0x54,0x34,0x38,0x36,0x65,0x41,0x4f,0x6c,0x54,0x36, - 0x55,0x4e,0x42,0x50,0x59,0x51,0x4c,0x70,0x55,0x70,0x72,0x46,0x35, - 0x59,0x72,0x79,0x6b,0x32,0x33,0x70,0x51,0x55,0x50,0x41,0x67,0x4a, - 0x45,0x4e,0x44,0x45,0x71,0x65,0x0a,0x55,0x36,0x69,0x49,0x4f,0x39, - 0x4f,0x74,0x31,0x5a,0x50,0x74,0x42,0x30,0x6c,0x6e,0x69,0x77,0x2b, - 0x2f,0x78,0x43,0x69,0x31,0x33,0x44,0x33,0x36,0x30,0x6f,0x31,0x74, - 0x5a,0x44,0x59,0x4f,0x70,0x30,0x68,0x48,0x48,0x4a,0x4e,0x33,0x44, - 0x33,0x45,0x4e,0x38,0x43,0x31,0x79,0x50,0x71,0x5a,0x64,0x35,0x43, - 0x76,0x76,0x7a,0x6e,0x59,0x76,0x0a,0x42,0x36,0x62,0x57,0x42,0x49, - 0x70,0x57,0x63,0x52,0x67,0x64,0x6e,0x32,0x44,0x55,0x56,0x4d,0x6d, - 0x70,0x55,0x36,0x36,0x31,0x6a,0x77,0x71,0x47,0x6c,0x52,0x7a,0x31, - 0x46,0x38,0x34,0x4a,0x47,0x2f,0x78,0x65,0x34,0x6a,0x47,0x75,0x7a, - 0x67,0x70,0x4a,0x74,0x39,0x49,0x58,0x53,0x7a,0x79,0x6f,0x68,0x45, - 0x4a,0x42,0x36,0x58,0x47,0x35,0x0a,0x2b,0x44,0x30,0x42,0x75,0x51, - 0x49,0x4e,0x42,0x44,0x6e,0x75,0x39,0x4a,0x49,0x51,0x43,0x41,0x43, - 0x45,0x6b,0x64,0x42,0x4e,0x36,0x4d,0x78,0x66,0x35,0x57,0x76,0x71, - 0x44,0x57,0x6b,0x63,0x4d,0x52,0x79,0x36,0x77,0x6e,0x72,0x64,0x39, - 0x44,0x59,0x4a,0x38,0x55,0x55,0x54,0x6d,0x49,0x54,0x32,0x69,0x51, - 0x66,0x30,0x37,0x74,0x52,0x55,0x0a,0x4b,0x4a,0x4a,0x39,0x76,0x30, - 0x4a,0x58,0x66,0x78,0x32,0x5a,0x34,0x64,0x30,0x38,0x49,0x51,0x53, - 0x4d,0x4e,0x52,0x61,0x71,0x34,0x56,0x67,0x53,0x65,0x2b,0x50,0x64, - 0x59,0x67,0x49,0x79,0x30,0x66,0x62,0x6a,0x32,0x33,0x56,0x69,0x61, - 0x35,0x2f,0x67,0x4f,0x37,0x66,0x4a,0x45,0x70,0x44,0x32,0x68,0x64, - 0x32,0x66,0x2b,0x70,0x4d,0x6e,0x0a,0x4f,0x57,0x76,0x48,0x32,0x72, - 0x4f,0x4f,0x49,0x62,0x65,0x59,0x66,0x75,0x68,0x7a,0x41,0x63,0x36, - 0x42,0x51,0x6a,0x41,0x4b,0x74,0x6d,0x67,0x52,0x30,0x45,0x52,0x55, - 0x54,0x61,0x66,0x54,0x4d,0x39,0x57,0x62,0x36,0x46,0x31,0x33,0x43, - 0x4e,0x5a,0x5a,0x4e,0x5a,0x66,0x44,0x71,0x6e,0x46,0x44,0x50,0x36, - 0x4c,0x31,0x32,0x77,0x33,0x7a,0x0a,0x33,0x46,0x37,0x46,0x46,0x58, - 0x6b,0x7a,0x30,0x37,0x52,0x73,0x33,0x41,0x49,0x74,0x6f,0x31,0x5a, - 0x66,0x59,0x5a,0x64,0x34,0x73,0x43,0x53,0x70,0x4d,0x72,0x2f,0x30, - 0x53,0x35,0x6e,0x4c,0x72,0x48,0x62,0x49,0x76,0x47,0x4c,0x70,0x32, - 0x37,0x31,0x68,0x68,0x51,0x42,0x65,0x52,0x6d,0x6d,0x6f,0x47,0x45, - 0x4b,0x4f,0x32,0x4a,0x52,0x65,0x0a,0x6c,0x47,0x67,0x55,0x4a,0x32, - 0x43,0x55,0x7a,0x4f,0x64,0x74,0x77,0x44,0x49,0x4b,0x54,0x30,0x4c, - 0x62,0x43,0x70,0x76,0x61,0x50,0x38,0x50,0x56,0x6e,0x59,0x46,0x35, - 0x49,0x46,0x6f,0x59,0x4a,0x49,0x57,0x52,0x48,0x71,0x6c,0x45,0x74, - 0x35,0x75,0x63,0x54,0x58,0x73,0x74,0x5a,0x79,0x37,0x76,0x59,0x6a, - 0x4c,0x36,0x76,0x54,0x50,0x34,0x0a,0x6c,0x35,0x78,0x73,0x2b,0x4c, - 0x49,0x4f,0x6b,0x4e,0x6d,0x50,0x68,0x71,0x6d,0x66,0x73,0x67,0x4c, - 0x7a,0x56,0x6f,0x30,0x55,0x61,0x4c,0x74,0x38,0x30,0x68,0x4f,0x77, - 0x63,0x34,0x4e,0x76,0x44,0x43,0x4f,0x4c,0x41,0x41,0x4d,0x47,0x42, - 0x2f,0x39,0x67,0x2b,0x39,0x56,0x33,0x4f,0x52,0x7a,0x77,0x34,0x4c, - 0x76,0x4f,0x31,0x70,0x77,0x52,0x0a,0x59,0x4a,0x71,0x66,0x44,0x4b, - 0x55,0x71,0x2f,0x45,0x4a,0x30,0x72,0x4e,0x4d,0x4d,0x44,0x34,0x4e, - 0x38,0x52,0x4c,0x70,0x5a,0x52,0x68,0x4b,0x48,0x4b,0x4a,0x55,0x6d, - 0x39,0x6e,0x4e,0x48,0x4c,0x62,0x6b,0x73,0x6e,0x6c,0x5a,0x77,0x72, - 0x62,0x53,0x54,0x4d,0x35,0x4c,0x70,0x43,0x2f,0x55,0x36,0x73,0x68, - 0x65,0x4c,0x50,0x2b,0x6c,0x30,0x0a,0x62,0x4c,0x56,0x6f,0x71,0x30, - 0x6c,0x6d,0x73,0x43,0x63,0x55,0x53,0x79,0x68,0x2b,0x6d,0x59,0x36, - 0x50,0x78,0x57,0x69,0x72,0x4c,0x49,0x57,0x43,0x6e,0x2f,0x49,0x41, - 0x5a,0x41,0x47,0x6e,0x58,0x62,0x36,0x5a,0x64,0x36,0x54,0x74,0x49, - 0x4a,0x6c,0x47,0x47,0x36,0x70,0x71,0x55,0x4e,0x38,0x51,0x78,0x47, - 0x4a,0x59,0x51,0x6e,0x6f,0x6e,0x0a,0x6c,0x30,0x75,0x54,0x4a,0x4b, - 0x48,0x4a,0x45,0x4e,0x62,0x49,0x39,0x73,0x57,0x48,0x51,0x64,0x63, - 0x54,0x74,0x42,0x4d,0x63,0x33,0x34,0x67,0x6f,0x72,0x48,0x46,0x43, - 0x6f,0x31,0x42,0x63,0x76,0x70,0x6e,0x63,0x31,0x4c,0x46,0x4c,0x72, - 0x57,0x6e,0x37,0x6d,0x66,0x6f,0x47,0x78,0x36,0x49,0x4e,0x51,0x6a, - 0x66,0x33,0x48,0x47,0x51,0x70,0x0a,0x4d,0x58,0x41,0x57,0x75,0x53, - 0x42,0x51,0x68,0x7a,0x6b,0x61,0x7a,0x59,0x36,0x76,0x61,0x57,0x46, - 0x70,0x61,0x38,0x62,0x42,0x4a,0x2b,0x67,0x4b,0x62,0x42,0x75,0x79, - 0x53,0x57,0x7a,0x4e,0x6d,0x33,0x72,0x46,0x74,0x54,0x35,0x48,0x52, - 0x4b,0x4d,0x57,0x70,0x4f,0x2b,0x4d,0x39,0x62,0x48,0x70,0x34,0x64, - 0x2b,0x70,0x75,0x59,0x30,0x4c,0x0a,0x31,0x59,0x77,0x4e,0x31,0x4f, - 0x4d,0x61,0x74,0x63,0x4d,0x4d,0x70,0x63,0x57,0x6e,0x5a,0x70,0x69, - 0x57,0x69,0x52,0x38,0x33,0x6f,0x69,0x33,0x32,0x2b,0x78,0x74,0x57, - 0x55,0x59,0x32,0x55,0x37,0x41,0x65,0x33,0x38,0x6d,0x4d,0x61,0x67, - 0x38,0x7a,0x46,0x62,0x70,0x65,0x71,0x50,0x51,0x55,0x73,0x44,0x76, - 0x39,0x56,0x37,0x43,0x41,0x4a,0x0a,0x31,0x64,0x62,0x72,0x69,0x45, - 0x77,0x45,0x47,0x42,0x45,0x43,0x41,0x41,0x77,0x46,0x41,0x6b,0x44, - 0x59,0x42,0x6e,0x6f,0x46,0x43,0x51,0x35,0x74,0x33,0x2b,0x67,0x41, - 0x43,0x67,0x6b,0x51,0x71,0x45,0x37,0x61,0x36,0x4a,0x79,0x41,0x43, - 0x73,0x70,0x6e,0x70,0x67,0x43,0x66,0x52,0x62,0x59,0x77,0x78,0x54, - 0x33,0x69,0x71,0x2b,0x39,0x6c,0x0a,0x2f,0x50,0x67,0x4e,0x54,0x55, - 0x4e,0x54,0x5a,0x4f,0x6c,0x6f,0x66,0x32,0x6f,0x41,0x6e,0x32,0x35, - 0x79,0x30,0x65,0x47,0x69,0x30,0x33,0x37,0x31,0x6a,0x61,0x70,0x39, - 0x6b,0x4f,0x56,0x36,0x75,0x71,0x37,0x31,0x73,0x55,0x75,0x4f,0x0a, - 0x3d,0x70,0x4a,0x6c,0x69,0x0a,0x2d,0x2d,0x2d,0x2d,0x2d,0x45,0x4e, - 0x44,0x20,0x50,0x47,0x50,0x20,0x50,0x55,0x42,0x4c,0x49,0x43,0x20, - 0x4b,0x45,0x59,0x20,0x42,0x4c,0x4f,0x43,0x4b,0x2d,0x2d,0x2d,0x2d, - 0x2d,0x0a,0x00, -}; - -size_t _susekey_size=2173; -size_t *susekey_size=&_susekey_size; +#define DATADIR (Pathname(TESTS_SRC_DIR) + "/zypp/data/PublicKey") BOOST_AUTO_TEST_CASE(publickey_test) { - BOOST_CHECK_THROW( zypp::PublicKey("nonexistant"), Exception ); - - filesystem::TmpFile file; - ofstream str(file.path().asString().c_str(),ofstream::out); + // test for a empty key + zypp::PublicKey empty_key; + BOOST_REQUIRE( ! empty_key.isValid() ); - if (!str.good()) - ZYPP_THROW(Exception("cant open file")); + BOOST_CHECK_THROW( zypp::PublicKey("nonexistant"), Exception ); - str << susekey; - str.flush(); - str.close(); - - zypp::PublicKey k2(file.path()); - + zypp::PublicKey k2(DATADIR/"susekey.asc"); BOOST_CHECK_EQUAL( k2.id(), "A84EDAE89C800ACA" ); BOOST_CHECK_EQUAL( k2.name(), "SuSE Package Signing Key " ); BOOST_CHECK_EQUAL( k2.fingerprint(), "79C179B2E1C820C1890F9994A84EDAE89C800ACA" ); + BOOST_CHECK_EQUAL( k2.gpgPubkeyVersion(), "9c800aca" ); + BOOST_CHECK_EQUAL( k2.gpgPubkeyRelease(), "40d8063e" ); BOOST_CHECK_EQUAL( k2.created(), zypp::Date(1087899198) ); + BOOST_CHECK_EQUAL( k2.expires(), zypp::Date(1214043198) ); +//BOOST_CHECK_EQUAL( k2.daysToLive(), "" ); BOOST_REQUIRE( k2.path() != Pathname() ); BOOST_REQUIRE( k2 == k2 ); - // test for a empty key - zypp::PublicKey empty_key; - BOOST_REQUIRE( ! empty_key.isValid() ); + + k2 = zypp::PublicKey(DATADIR/"multikey.asc"); + BOOST_CHECK_EQUAL( k2.id(), "27FA41BD8A7C64F9" ); + BOOST_CHECK_EQUAL( k2.name(), "Unsupported " ); + BOOST_CHECK_EQUAL( k2.fingerprint(), "D88811AF6B51852351DF538527FA41BD8A7C64F9" ); + BOOST_CHECK_EQUAL( k2.gpgPubkeyVersion(), "8a7c64f9" ); + BOOST_CHECK_EQUAL( k2.gpgPubkeyRelease(), "4be01af3" ); + BOOST_CHECK_EQUAL( k2.created(), zypp::Date(1272978163) ); + BOOST_CHECK_EQUAL( k2.expires(), zypp::Date(1399122163) ); + + k2 = zypp::PublicKey(DATADIR/"multikey2.asc"); + BOOST_CHECK_EQUAL( k2.hiddenKeys().size(), 8 ); } diff --git a/libzypp/tests/zypp/RepoInfo_test.cc b/libzypp/tests/zypp/RepoInfo_test.cc index 55ca91c..232e238 100644 --- a/libzypp/tests/zypp/RepoInfo_test.cc +++ b/libzypp/tests/zypp/RepoInfo_test.cc @@ -38,7 +38,7 @@ BOOST_AUTO_TEST_CASE(repoinfo_test) ri.setMirrorListUrl(weburl); - BOOST_CHECK(ri.url().asString() == "ftp://ftp-stud.hs-esslingen.de/pub/fedora/linux/updates/13/x86_64/"); + BOOST_CHECK(ri.url().asString() == "http://ftp-stud.hs-esslingen.de/pub/fedora/linux/updates/13/x86_64/"); ostringstream ostr; ri.dumpAsIniOn(ostr); diff --git a/libzypp/tests/zypp/RepoManager_test.cc b/libzypp/tests/zypp/RepoManager_test.cc index cae630d..329aa46 100644 --- a/libzypp/tests/zypp/RepoManager_test.cc +++ b/libzypp/tests/zypp/RepoManager_test.cc @@ -33,7 +33,6 @@ using namespace zypp::repo; #define REPODATADIR (Pathname(TESTS_SRC_DIR) + "/repo/susetags/data/addon_in_subdir") - BOOST_AUTO_TEST_CASE(refresh_addon_in_subdir) { KeyRingTestReceiver keyring_callbacks; @@ -47,7 +46,7 @@ BOOST_AUTO_TEST_CASE(refresh_addon_in_subdir) // make sure we can refresh an addon which is in a subpath in a media url TestSetup test( Arch_x86_64 ); RepoInfo info; - info.setBaseUrl(Url(string("dir:") + REPODATADIR.asString())); + info.setBaseUrl( REPODATADIR.asDirUrl() ); info.setPath("/updates"); info.setType(RepoType::YAST2); info.setAlias("boooh"); @@ -80,7 +79,7 @@ BOOST_AUTO_TEST_CASE(pluginservices_test) ServiceInfo service(*manager.serviceBegin()); BOOST_CHECK_EQUAL("service", service.alias()); - BOOST_CHECK_EQUAL( "file:" + DATADIR.asString() + "/plugin-service-lib-1/services/service", service.url().asString()); + BOOST_CHECK_EQUAL( (DATADIR / "/plugin-service-lib-1/services/service").asFileUrl(), service.url().asString()); // now refresh the service manager.refreshServices(); @@ -99,7 +98,7 @@ BOOST_AUTO_TEST_CASE(pluginservices_test) ServiceInfo service(*manager.serviceBegin()); BOOST_CHECK_EQUAL("service", service.alias()); - BOOST_CHECK_EQUAL( "file:" + DATADIR.asString() + "/plugin-service-lib-2/services/service", service.url().asString()); + BOOST_CHECK_EQUAL( (DATADIR / "/plugin-service-lib-2/services/service").asFileUrl(), service.url().asString()); // now refresh the service manager.refreshServices(); BOOST_CHECK_EQUAL((unsigned) 1, manager.repoSize()); @@ -120,10 +119,7 @@ BOOST_AUTO_TEST_CASE(service_file_link_bug) RepoManager manager(opts); //test service - Url urlS; - urlS.setPathName(DATADIR.asString()); - urlS.setScheme("dir"); - ServiceInfo service("test", urlS); + ServiceInfo service("test", DATADIR.asDirUrl() ); service.setEnabled(true); manager.addService(service); @@ -154,11 +150,7 @@ BOOST_AUTO_TEST_CASE(repomanager_test) BOOST_CHECK_EQUAL(repos.size(), (unsigned) 4); // now add a .repo file with 2 repositories in it - Url url; - url.setPathName((DATADIR + "/proprietary.repo").asString()); - url.setScheme("file"); - - manager.addRepositories(url); + manager.addRepositories( (DATADIR / "/proprietary.repo").asFileUrl() ); // check it was not overwriten the proprietary.repo file BOOST_CHECK( PathInfo(opts.knownReposPath + "/proprietary.repo_1").isExist() ); @@ -193,9 +185,7 @@ BOOST_AUTO_TEST_CASE(repomanager_test) //test service - Url urlS; - urlS.setPathName(DATADIR.asString()); - urlS.setScheme("dir"); + Url urlS( DATADIR.asDirUrl() ); ServiceInfo service("test", urlS); service.setEnabled(true); @@ -205,8 +195,8 @@ BOOST_AUTO_TEST_CASE(repomanager_test) BOOST_CHECK_EQUAL(manager.repoSize(), (unsigned) 7); // +3 from repoindex //simulate change of repoindex.xml - urlS.setPathName((DATADIR+"second").asString()); - urlS.setScheme("dir"); + urlS = (DATADIR / "second").asDirUrl(); + service.setUrl(urlS); service.setEnabled(true); @@ -224,10 +214,8 @@ BOOST_AUTO_TEST_CASE(repomanager_test) RepoInfo repo; repo.setAlias("foo"); - Url repourl("dir:" + string(TESTS_SRC_DIR) + "/repo/yum/data/10.2-updates-subset"); - //Url repourl("dir:/mounts/dist/install/stable-x86/suse"); //BOOST_CHECK_MESSAGE(0, repourl.asString()); - repo.setBaseUrl(repourl); + repo.setBaseUrl( (Pathname(TESTS_SRC_DIR) / "/repo/yum/data/10.2-updates-subset").asDirUrl() ); KeyRingTestReceiver keyring_callbacks; KeyRingTestSignalReceiver receiver; diff --git a/libzypp/tests/zypp/RepoStatus_test.cc b/libzypp/tests/zypp/RepoStatus_test.cc index 577befd..85df6b2 100644 --- a/libzypp/tests/zypp/RepoStatus_test.cc +++ b/libzypp/tests/zypp/RepoStatus_test.cc @@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(repostatus_test) BOOST_CHECK_EQUAL( fstatus.empty(), false ); BOOST_CHECK_EQUAL( (fstatus&&status).empty(), false ); - BOOST_CHECK_EQUAL( (fstatus&&status).checksum(), (status&&fstatus).checksum() ); - BOOST_CHECK_EQUAL( (fstatus&&fstatus2).checksum(), (fstatus2&&fstatus).checksum() ); + BOOST_CHECK_EQUAL( (fstatus&&status), (status&&fstatus) ); + BOOST_CHECK_EQUAL( (fstatus&&fstatus2), (fstatus2&&fstatus) ); } diff --git a/libzypp/tests/zypp/SetRelationMixin_test.cc b/libzypp/tests/zypp/SetRelationMixin_test.cc new file mode 100644 index 0000000..e3195f1 --- /dev/null +++ b/libzypp/tests/zypp/SetRelationMixin_test.cc @@ -0,0 +1,142 @@ +#include +#include "zypp/base/SetRelationMixin.h" + +using zypp::SetCompare; +using zypp::SetRelation; + +BOOST_AUTO_TEST_CASE(set_compare) +{ + BOOST_CHECK( SetCompare::uncomparable == SetCompare::uncomparable ); + BOOST_CHECK( SetCompare::uncomparable != SetCompare::equal ); + BOOST_CHECK( SetCompare::uncomparable != SetCompare::properSubset ); + BOOST_CHECK( SetCompare::uncomparable != SetCompare::properSuperset ); + BOOST_CHECK( SetCompare::uncomparable != SetCompare::disjoint ); + + BOOST_CHECK( SetCompare::equal != SetCompare::uncomparable ); + BOOST_CHECK( SetCompare::equal == SetCompare::equal ); + BOOST_CHECK( SetCompare::equal != SetCompare::properSubset ); + BOOST_CHECK( SetCompare::equal != SetCompare::properSuperset ); + BOOST_CHECK( SetCompare::equal != SetCompare::disjoint ); + + BOOST_CHECK( SetCompare::properSubset != SetCompare::uncomparable ); + BOOST_CHECK( SetCompare::properSubset != SetCompare::equal ); + BOOST_CHECK( SetCompare::properSubset == SetCompare::properSubset ); + BOOST_CHECK( SetCompare::properSubset != SetCompare::properSuperset ); + BOOST_CHECK( SetCompare::properSubset != SetCompare::disjoint ); + + BOOST_CHECK( SetCompare::properSuperset != SetCompare::uncomparable ); + BOOST_CHECK( SetCompare::properSuperset != SetCompare::equal ); + BOOST_CHECK( SetCompare::properSuperset != SetCompare::properSubset ); + BOOST_CHECK( SetCompare::properSuperset == SetCompare::properSuperset ); + BOOST_CHECK( SetCompare::properSuperset != SetCompare::disjoint ); + + BOOST_CHECK( SetCompare::disjoint != SetCompare::uncomparable ); + BOOST_CHECK( SetCompare::disjoint != SetCompare::equal ); + BOOST_CHECK( SetCompare::disjoint != SetCompare::properSubset ); + BOOST_CHECK( SetCompare::disjoint != SetCompare::properSuperset ); + BOOST_CHECK( SetCompare::disjoint == SetCompare::disjoint ); +} + +BOOST_AUTO_TEST_CASE(set_relation) +{ + BOOST_CHECK( SetRelation::uncomparable == SetRelation::uncomparable ); + BOOST_CHECK( SetRelation::uncomparable != SetRelation::equal ); + BOOST_CHECK( SetRelation::uncomparable != SetRelation::properSubset ); + BOOST_CHECK( SetRelation::uncomparable != SetRelation::properSuperset ); + BOOST_CHECK( SetRelation::uncomparable != SetRelation::disjoint ); + BOOST_CHECK( SetRelation::uncomparable != SetRelation::subset ); + BOOST_CHECK( SetRelation::uncomparable != SetRelation::superset ); + + BOOST_CHECK( SetRelation::equal != SetRelation::uncomparable ); + BOOST_CHECK( SetRelation::equal == SetRelation::equal ); + BOOST_CHECK( SetRelation::equal != SetRelation::properSubset ); + BOOST_CHECK( SetRelation::equal != SetRelation::properSuperset ); + BOOST_CHECK( SetRelation::equal != SetRelation::disjoint ); + BOOST_CHECK( SetRelation::equal != SetRelation::subset ); + BOOST_CHECK( SetRelation::equal != SetRelation::superset ); + + BOOST_CHECK( SetRelation::properSubset != SetRelation::uncomparable ); + BOOST_CHECK( SetRelation::properSubset != SetRelation::equal ); + BOOST_CHECK( SetRelation::properSubset == SetRelation::properSubset ); + BOOST_CHECK( SetRelation::properSubset != SetRelation::properSuperset ); + BOOST_CHECK( SetRelation::properSubset != SetRelation::disjoint ); + BOOST_CHECK( SetRelation::properSubset != SetRelation::subset ); + BOOST_CHECK( SetRelation::properSubset != SetRelation::superset ); + + BOOST_CHECK( SetRelation::properSuperset != SetRelation::uncomparable ); + BOOST_CHECK( SetRelation::properSuperset != SetRelation::equal ); + BOOST_CHECK( SetRelation::properSuperset != SetRelation::properSubset ); + BOOST_CHECK( SetRelation::properSuperset == SetRelation::properSuperset ); + BOOST_CHECK( SetRelation::properSuperset != SetRelation::disjoint ); + BOOST_CHECK( SetRelation::properSuperset != SetRelation::subset ); + BOOST_CHECK( SetRelation::properSuperset != SetRelation::superset ); + + BOOST_CHECK( SetRelation::disjoint != SetRelation::uncomparable ); + BOOST_CHECK( SetRelation::disjoint != SetRelation::equal ); + BOOST_CHECK( SetRelation::disjoint != SetRelation::properSubset ); + BOOST_CHECK( SetRelation::disjoint != SetRelation::properSuperset ); + BOOST_CHECK( SetRelation::disjoint == SetRelation::disjoint ); + BOOST_CHECK( SetRelation::disjoint != SetRelation::subset ); + BOOST_CHECK( SetRelation::disjoint != SetRelation::superset ); + + BOOST_CHECK( SetRelation::subset != SetRelation::uncomparable ); + BOOST_CHECK( SetRelation::subset != SetRelation::equal ); + BOOST_CHECK( SetRelation::subset != SetRelation::properSubset ); + BOOST_CHECK( SetRelation::subset != SetRelation::properSuperset ); + BOOST_CHECK( SetRelation::subset != SetRelation::disjoint ); + BOOST_CHECK( SetRelation::subset == SetRelation::subset ); + BOOST_CHECK( SetRelation::subset != SetRelation::superset ); + + BOOST_CHECK( SetRelation::superset != SetRelation::uncomparable ); + BOOST_CHECK( SetRelation::superset != SetRelation::equal ); + BOOST_CHECK( SetRelation::superset != SetRelation::properSubset ); + BOOST_CHECK( SetRelation::superset != SetRelation::properSuperset ); + BOOST_CHECK( SetRelation::superset != SetRelation::disjoint ); + BOOST_CHECK( SetRelation::superset != SetRelation::subset ); + BOOST_CHECK( SetRelation::superset == SetRelation::superset ); +} + +BOOST_AUTO_TEST_CASE(set_relation_comapre) +{ + BOOST_CHECK( SetRelation::uncomparable == SetCompare::uncomparable ); + BOOST_CHECK( SetRelation::uncomparable != SetCompare::equal ); + BOOST_CHECK( SetRelation::uncomparable != SetCompare::properSubset ); + BOOST_CHECK( SetRelation::uncomparable != SetCompare::properSuperset ); + BOOST_CHECK( SetRelation::uncomparable != SetCompare::disjoint ); + + BOOST_CHECK( SetRelation::equal != SetCompare::uncomparable ); + BOOST_CHECK( SetRelation::equal == SetCompare::equal ); + BOOST_CHECK( SetRelation::equal != SetCompare::properSubset ); + BOOST_CHECK( SetRelation::equal != SetCompare::properSuperset ); + BOOST_CHECK( SetRelation::equal != SetCompare::disjoint ); + + BOOST_CHECK( SetRelation::properSubset != SetCompare::uncomparable ); + BOOST_CHECK( SetRelation::properSubset != SetCompare::equal ); + BOOST_CHECK( SetRelation::properSubset == SetCompare::properSubset ); + BOOST_CHECK( SetRelation::properSubset != SetCompare::properSuperset ); + BOOST_CHECK( SetRelation::properSubset != SetCompare::disjoint ); + + BOOST_CHECK( SetRelation::properSuperset != SetCompare::uncomparable ); + BOOST_CHECK( SetRelation::properSuperset != SetCompare::equal ); + BOOST_CHECK( SetRelation::properSuperset != SetCompare::properSubset ); + BOOST_CHECK( SetRelation::properSuperset == SetCompare::properSuperset ); + BOOST_CHECK( SetRelation::properSuperset != SetCompare::disjoint ); + + BOOST_CHECK( SetRelation::disjoint != SetCompare::uncomparable ); + BOOST_CHECK( SetRelation::disjoint != SetCompare::equal ); + BOOST_CHECK( SetRelation::disjoint != SetCompare::properSubset ); + BOOST_CHECK( SetRelation::disjoint != SetCompare::properSuperset ); + BOOST_CHECK( SetRelation::disjoint == SetCompare::disjoint ); + + BOOST_CHECK( SetRelation::subset != SetCompare::uncomparable ); + BOOST_CHECK( SetRelation::subset == SetCompare::equal ); + BOOST_CHECK( SetRelation::subset == SetCompare::properSubset ); + BOOST_CHECK( SetRelation::subset != SetCompare::properSuperset ); + BOOST_CHECK( SetRelation::subset != SetCompare::disjoint ); + + BOOST_CHECK( SetRelation::superset != SetCompare::uncomparable ); + BOOST_CHECK( SetRelation::superset == SetCompare::equal ); + BOOST_CHECK( SetRelation::superset != SetCompare::properSubset ); + BOOST_CHECK( SetRelation::superset == SetCompare::properSuperset ); + BOOST_CHECK( SetRelation::superset != SetCompare::disjoint ); +} diff --git a/libzypp/tests/zypp/Url_test.cc b/libzypp/tests/zypp/Url_test.cc index c455c87..60d8e49 100644 --- a/libzypp/tests/zypp/Url_test.cc +++ b/libzypp/tests/zypp/Url_test.cc @@ -95,6 +95,10 @@ BOOST_AUTO_TEST_CASE(test_url1) BOOST_CHECK_EQUAL( one, url.asString() ); BOOST_CHECK_EQUAL( two, url.asCompleteString() ); + // absolute path defaults to 'file://' + str = "/some/local/path"; + BOOST_CHECK_EQUAL( zypp::Url(str).asString(), "file://"+str ); + str = "file:./srv/ftp"; BOOST_CHECK_EQUAL( zypp::Url(str).asString(), str ); diff --git a/libzypp/tests/zypp/Vendor_test.cc b/libzypp/tests/zypp/Vendor_test.cc index 4aad252..870a7b7 100644 --- a/libzypp/tests/zypp/Vendor_test.cc +++ b/libzypp/tests/zypp/Vendor_test.cc @@ -38,6 +38,9 @@ BOOST_AUTO_TEST_CASE(vendor_test1) // but "opensuse build service" gets its own class: BOOST_REQUIRE( !VendorAttr::instance().equivalent("opensuse build service", "suse") ); BOOST_REQUIRE( !VendorAttr::instance().equivalent("opensuse build service", "opensuse") ); - BOOST_REQUIRE( VendorAttr::instance().equivalent("opensuse build service", "opensuse build service 2") ); + // bnc#812608: All opensuse projects get their own class + BOOST_REQUIRE( !VendorAttr::instance().equivalent("opensuse-education", "suse") ); + BOOST_REQUIRE( !VendorAttr::instance().equivalent("opensuse-education", "opensuse") ); + BOOST_REQUIRE( !VendorAttr::instance().equivalent("opensuse-education", "opensuse build service") ); } diff --git a/libzypp/tests/zypp/base/String_test.cc b/libzypp/tests/zypp/base/String_test.cc index e01bb00..152a229 100644 --- a/libzypp/tests/zypp/base/String_test.cc +++ b/libzypp/tests/zypp/base/String_test.cc @@ -45,45 +45,88 @@ BOOST_AUTO_TEST_CASE(testsplitEscaped) string s( "simple non-escaped string" ); vector v; - insert_iterator > ii (v,v.end()); - splitEscaped( s, ii ); + splitEscaped( s, std::back_inserter(v) ); BOOST_CHECK_EQUAL( v.size(), 3 ); + BOOST_CHECK_EQUAL( v[0], "simple" ); + BOOST_CHECK_EQUAL( v[1], "non-escaped" ); + BOOST_CHECK_EQUAL( v[2], "string" ); v.clear(); s = string( "\"escaped sentence \"" ); - ii = insert_iterator >( v, v.end() ); - splitEscaped( s, ii ); + splitEscaped( s, std::back_inserter(v) ); BOOST_CHECK_EQUAL( v.size(), 1 ); - BOOST_CHECK_EQUAL( v.front(), string( "escaped sentence " ) ); + BOOST_CHECK_EQUAL( v[0], "escaped sentence " ); v.clear(); s = string( "\"escaped \\\\sent\\\"ence \\\\\"" ); - ii = insert_iterator >( v, v.end() ); - splitEscaped( s, ii ); + splitEscaped( s, std::back_inserter(v) ); BOOST_CHECK_EQUAL( v.size(), 1 ); - BOOST_CHECK_EQUAL( v.front(), string( "escaped \\sent\"ence \\" ) ); - + BOOST_CHECK_EQUAL( v[0], "escaped \\sent\"ence \\" ); v.clear(); s = string( "escaped sentence\\ with\\ space" ); - ii = insert_iterator >( v, v.end() ); - splitEscaped( s, ii ); + splitEscaped( s, std::back_inserter(v) ); BOOST_CHECK_EQUAL( v.size(), 2 ); - BOOST_CHECK_EQUAL( v[1], string( "sentence with space" ) ); + BOOST_CHECK_EQUAL( v[0], "escaped" ); + BOOST_CHECK_EQUAL( v[1], "sentence with space" ); // split - join v.clear(); s = "some line \"\" foo\\ a foo\\\\ b"; str::splitEscaped( s, std::back_inserter(v) ); + BOOST_CHECK_EQUAL( v.size(), 6 ); + BOOST_CHECK_EQUAL( v[0], "some" ); + BOOST_CHECK_EQUAL( v[1], "line" ); + BOOST_CHECK_EQUAL( v[2], "" ); + BOOST_CHECK_EQUAL( v[3], "foo a" ); + BOOST_CHECK_EQUAL( v[4], "foo\\" ); + BOOST_CHECK_EQUAL( v[5], "b" ); BOOST_CHECK_EQUAL( s, str::joinEscaped( v.begin(), v.end() ) ); // split - join using alternate sepchar s = str::joinEscaped( v.begin(), v.end(), 'o' ); v.clear(); str::splitEscaped( s, std::back_inserter(v), "o" ); + BOOST_CHECK_EQUAL( v.size(), 6 ); + BOOST_CHECK_EQUAL( v[0], "some" ); + BOOST_CHECK_EQUAL( v[1], "line" ); + BOOST_CHECK_EQUAL( v[2], "" ); + BOOST_CHECK_EQUAL( v[3], "foo a" ); + BOOST_CHECK_EQUAL( v[4], "foo\\" ); + BOOST_CHECK_EQUAL( v[5], "b" ); BOOST_CHECK_EQUAL( s, str::joinEscaped( v.begin(), v.end(), 'o' ) ); } +BOOST_AUTO_TEST_CASE(bnc_909772) +{ + // While \-escaping processes single-quote, double-quote, backslash and sepchar[ ] + // deescaping failed to process the quotes correctly. + std::string s; + std::vector v; + + v.clear(); + v.push_back(""); + v.push_back("'\" \\"); + v.push_back("\\'\\\"\\ \\\\"); + s = str::joinEscaped( v.begin(), v.end() ); + BOOST_CHECK_EQUAL( s, "\"\"" " " "\\'\\\"\\ \\\\" " " "\\\\\\'\\\\\\\"\\\\\\ \\\\\\\\" ); + + s += " "; + s += "'" "\\\\\" \\ \\\\" "'\\ single"; // single quote: all literal, no ' inside + + s += " "; + s += "\"" "\\'\\\" \\ \\\\" "\"\\ double";// double quote: all literal except \\ \" + + v.clear(); + splitEscaped( s, std::back_inserter(v) ); + BOOST_CHECK_EQUAL( v.size(), 5 ); + BOOST_CHECK_EQUAL( v[0], "" ); + BOOST_CHECK_EQUAL( v[1], "'\" \\" ); + BOOST_CHECK_EQUAL( v[2], "\\'\\\"\\ \\\\" ); + BOOST_CHECK_EQUAL( v[3], "\\\\\" \\ \\\\ single" ); + BOOST_CHECK_EQUAL( v[4], "\\'\" \\ \\ double" ); +} + BOOST_AUTO_TEST_CASE(testsplitEscapedWithEmpty) { string s( "simple:non-escaped:string" ); @@ -276,8 +319,30 @@ BOOST_AUTO_TEST_CASE(hexencode_hexdecode) } std::string d( str::hexdecode( e ) ); + // decoded equals original BOOST_CHECK( o == d ); -// for ( unsigned i = 0; i < 255; ++i ) -// if ( o[i] != d[i] ) -// WAR << i << " " << unsigned(o[i]) << " != " << unsigned(d[i]) << endl; + + // Test %XX is decoded for hexdigits only + const char *const dig = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + for ( const char * d1 = dig; *d1; ++d1 ) + for ( const char * d2 = dig; *d2; ++d2 ) + { + std::string eu( "%" ); + eu += *d1; eu += *d2; + std::string el( str::toLower(eu) ); + + std::string u( str::hexdecode( eu ) ); + std::string l( str::hexdecode( el ) ); + + if ( *d1 <= 'F' && *d2 <= 'F' ) + { + BOOST_CHECK_EQUAL( u, l ); // no matter if upper or lower case hexdigit + BOOST_CHECK_EQUAL( u.size(), 1 ); // size 1 == decoded + } + else + { + BOOST_CHECK_EQUAL( u, eu ); // no hexdigits remain unchanged + BOOST_CHECK_EQUAL( l, el ); + } + } } diff --git a/libzypp/tests/zypp/base/Sysconfig_test.cc b/libzypp/tests/zypp/base/Sysconfig_test.cc index 610555a..dfbd98f 100644 --- a/libzypp/tests/zypp/base/Sysconfig_test.cc +++ b/libzypp/tests/zypp/base/Sysconfig_test.cc @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -10,6 +11,7 @@ #include "zypp/base/Exception.h" #include "zypp/TmpPath.h" #include "zypp/PathInfo.h" +#include "zypp/ExternalProgram.h" #include "zypp/base/Sysconfig.h" @@ -24,7 +26,7 @@ using namespace zypp; BOOST_AUTO_TEST_CASE(Sysconfig) { - Pathname file = DATADIR + "proxy"; + Pathname file = DATADIR / "proxy"; map values = zypp::base::sysconfig::read(file); BOOST_CHECK_EQUAL( values.size(), 6 ); BOOST_CHECK_EQUAL( values["PROXY_ENABLED"], "no"); @@ -32,3 +34,43 @@ BOOST_AUTO_TEST_CASE(Sysconfig) BOOST_CHECK_EQUAL( values["NO_PROXY"], "localhost, 127.0.0.1"); } +BOOST_AUTO_TEST_CASE(SysconfigWrite) +{ + Pathname file = DATADIR / "proxy"; + filesystem::TmpFile tmpf( filesystem::TmpFile::makeSibling( file ) ); + filesystem::copy( file, tmpf.path() ); + + BOOST_REQUIRE_THROW( zypp::base::sysconfig::writeStringVal( "/tmp/wrzlprmpf", "PROXY_ENABLED", "yes", "# fifi\n fofo\n" ), + zypp::Exception ); + BOOST_CHECK( zypp::base::sysconfig::writeStringVal( tmpf.path(), "PROXY_ENABLED", "yes", "# fifi\n fofo\n" ) ); + BOOST_CHECK( !zypp::base::sysconfig::writeStringVal( tmpf.path(), "NEW1","12" ) ); + BOOST_CHECK( zypp::base::sysconfig::writeStringVal( tmpf.path(), "NEW2","13", "# fifi\n# fofo" ) ); + BOOST_CHECK( zypp::base::sysconfig::writeStringVal( tmpf.path(), "NEW3","13\"str\"", "fifi\nffofo" ) ); + + std::ostringstream s; + ExternalProgram( "diff -u " + file.asString() + " " + tmpf.path().asString() + " | tail -n +3" ) >> s; + BOOST_CHECK_EQUAL( s.str(), + "@@ -8,7 +8,7 @@\n" + " # This setting allows to turn the proxy on and off while\n" + " # preserving the particular proxy setup.\n" + " #\n" + "-PROXY_ENABLED=\"no\"\n" + "+PROXY_ENABLED=\"yes\"\n" + " \n" + " ## Type:\tstring\n" + " ## Default:\t\"\"\n" + "@@ -49,3 +49,11 @@\n" + " # Example: NO_PROXY=\"www.me.de, do.main, localhost\"\n" + " #\n" + " NO_PROXY=\"localhost, 127.0.0.1\"\n" + "+\n" + "+# fifi\n" + "+# fofo\n" + "+NEW2=\"13\"\n" + "+\n" + "+# fifi\n" + "+# ffofo\n" + "+NEW3=\"13\\\"str\\\"\"\n" + ); +} + diff --git a/libzypp/tests/zypp/base/data/Sysconfig/proxy b/libzypp/tests/zypp/base/data/Sysconfig/proxy index 0924e45..f3a6b9c 100644 --- a/libzypp/tests/zypp/base/data/Sysconfig/proxy +++ b/libzypp/tests/zypp/base/data/Sysconfig/proxy @@ -1,5 +1,5 @@ ## Path: Network/Proxy -## Description: +## Description: ## Type: yesno ## Default: no ## Config: kde,profiles @@ -7,7 +7,7 @@ # Enable a generation of the proxy settings to the profile. # This setting allows to turn the proxy on and off while # preserving the particular proxy setup. -# +# PROXY_ENABLED="no" ## Type: string diff --git a/libzypp/tests/zypp/data/PublicKey/multikey.asc b/libzypp/tests/zypp/data/PublicKey/multikey.asc new file mode 100644 index 0000000..b42b9c7 --- /dev/null +++ b/libzypp/tests/zypp/data/PublicKey/multikey.asc @@ -0,0 +1,38 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2.0.19 (GNU/Linux) + +mIsERCAdXQEEAL7MrBTz+3SBWpCm2ae2yaDqV3ezQcs2JlvqidJVhsZqQe9/jkxi +KTEQW5+TXF/+BlQSiebunRI7oo3+9U8GyRCgs1sf+yRQWMLzZqRaarzRhw9w+Ihl +edtqYl6/U2JZCb8Adp6d7RzlRliJdJ/VtsfXj2ef7Dwu7elOVSsmaBdtAAYptChT +dVNFIFBhY2thZ2UgU2lnbmluZyBLZXkgPGJ1aWxkQHN1c2UuZGU+iLgEEwECACIC +GwMECwcDAgMVAgMDFgIBAh4BAheABQJL4BplBQkPRMsIAAoJEOOlw2Awfj1UhOsD +/RkkEhOIC9NNad0F5O0rEJxvsI7Nm+6FnNJq8LjyR5+87epQCXgpaBXEGd4RcjjO +TukLaHHrC1T/h4biIyf253VZHr4oJ46sUivNUFq60gl4gk56aTGTNeUWOsgrU4jm +auFca3dbGcNfiJ7c7dF2CkOAR+CPMLPYTvuVIRQBAjeSmQGiBEjKO60RBACeqGqC +khF+Zmzln1G7Jj9EaX6qiigk1hbs5VLQ5205lBIFMocOOAcmB9GI6r9D4VdwTew9 +PaXur4cRi8otaF93DaCCgsBvLsBTVFC1sKgJMJkhB/BKV4GdSCAylSNAzASYelZE +7KJSD1KxdS29HBVN07BOcSCBjR9eRC6kmW9IWwCg0t9U+Jx+CX7Fa9Q5mZ0/OfI1 +Bd8D/joPsDKz2uAit3gEXGgGorQdXiFZIbppLe89Jz9fLq/J9GFdd6lz3Yv2Vsf/ +hsaWPXQl5IZE+p6UPWUDUCwLVioLPQKh1p95KFdLn6pxFwG94UTougtjmm10E2ND +0PdssakeVtdYtNoeagQC1fYKmWyxBgXd4/nfhiNq0wFGsUUEBACbx8MIv5umcIIx +TG8sJRouOjIgRdfmWPiWpxAql+qyPTwnkZytZ0zJrfdVEnKrfX8FkZ86oDN1pc0Z +Zht59PrwxZpC5Kt3x0jNnyztn0FGwkADDhaEdzu8ZFXpkxglbsBAF2jx8HBLEMjN +CFCEYHUoFrcIVfCO/fHJKWZquYKQuLQhVW5zdXBwb3J0ZWQgPHVuc3VwcG9ydGVk +QHN1c2UuZGU+iGYEExECACYCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAUCS+Aa +8wUJCpqtRgAKCRAn+kG9inxk+XmpAKCUcG9rb6yU4jZn8PudBfsuQNhQNgCghiHo +heeFc3pKA2PJ5tUKuPpTLya5Ag0ESMo7tBAIAJr+eL5b7DNd6oEcgMWR2yZieSpr +YMDRGc5lU7HOsApcH2kHleBUQynle5NyYI0LOCuzV5QtAd0gwDV99A8VAVvYrcJl +uuh6Wj2yoENBulEySUZ9LYuGA5ErFDGWEMMbXDLNvvb2MVCDXnLE34aXzRVnDjKd +2+/vzpNFuEECwGZBcf78+u0BNxCfxgLgdKdLZsAmdcFEONu8Zx6hxpoL5h+B1doI +FqgePcAqhw3m7O+R8PCsODBvoIgQfViwk21BNKpnfBSvLFpJTA+AnwnRAuyljmda +hI1LwB7VZ+TSplpsbt08HvmDDPzKsfgURPp+NzsQU0iFmjeaYf/9cDYgbA8AAwUH +/A2dQA0JymANMkViHUt8HHtMpRPfUBEAICRriMmkSIWoUK6hZ/rD8t8PkOG7pfLC +os/WdIPtuuh+56Cw1u48pwXe4nR0M3iqVTxizdldt197MeQejjBppcza7OH7nyga ++NXf/GsniuuHcanImyh8yugaobWeBVD8i2juuLZFmlKc88Z1XWTC1ndB0WduWca2 +XEIJgvPyk84y/r6ItB45R+Pn3b/mafl2ebhI+YG8ywY8lqBhSWnQTNXaKG/ijb+a +xSEPVvNAHonZyv81XUDRNDEO/Rwsxmgb12J41k+5jpcB5yKo4lc6qNdHAwyuxSUB +D/xATGUaSFmUE7mxFlzCr0+ITwQYEQIADwIbDAUCS+AbAwUJCpqtTwAKCRAn+kG9 +inxk+TQ4AKCUWlqp8CgtApaaV/KBmNMhcE9TzwCfcTpQER3EMh/4CgK8wSHFcTuG +QEk= +=Dkxe +-----END PGP PUBLIC KEY BLOCK----- diff --git a/libzypp/tests/zypp/data/PublicKey/multikey2.asc b/libzypp/tests/zypp/data/PublicKey/multikey2.asc new file mode 100644 index 0000000..1ee7f92 --- /dev/null +++ b/libzypp/tests/zypp/data/PublicKey/multikey2.asc @@ -0,0 +1,214 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.6 (GNU/Linux) + +mQGiBDsj/RYRBACQD/DCxkMgmEjBNYh53AfsV+zcMaz4nDmeEElANfHrVzVGx33N +Siiqs33RIjV35Gd8OH1iSnbA7ef0gWELgVSToK2ydv/3X5Cbcb1MOWYQKJE1dQz7 +fw7Ic9nP7NieM18YMsOYEmCvyL4sLZviQIlb3caP+OpI/GAoNINY8m9yowCgxgx1 +L+jnJznXyKy7v5WgwMyrE2cD/38Nvp62Rq1/IqhUDc3SDUp5+xPddwOZ/E7P9F73 +0Gb2ec2fhAm9QZyVvFvLa+SJq2/LvY+vITZSRI0HTBZf4Yrzd6eHu/cDp0m0o/BS +McuoaHmKeHYcyIa2w8LMREpchgdlY/LnHR83Yipc3iegBRUvoTtwUYMqpswwi+6i +50nhA/9MC5cPOZbPpqbaDbSz0NtAVM2gcvgiBx4VKCh/AhkZ+abzogeHn6uT2eaP +3Fnk4YOa0FEbO+YHg3Lu45tZV3pBQUZoY07r5niT0Sb6dAKO/j/omEt4q44OO3ba +fanEvFurtgpkszoD20yheQLhv7CVdS8IUfQ2R+r0eQjxtAfJWLQmRHVuY2FuIE1h +Yy1WaWNhciBQcmV0dCA8ZHVuY2FuQHB1Yy5jbD6IVwQTEQIAFwUCOyP9FgULBwoD +BAMVAwIDFgIBAheAAAoJEM0etqlmfkLRqZUAnA8SIsD1eQkhDR7GkekdXWtlbW1W +AJ0eAtcylAOTGf3AezgtP/vlWtLj5rkBDQQ7I/0vEAQAnZXsJoF43AMGs5ccBsfe +nbLa1GacjBA212+wJ/toRCbs9xzs5dozh+TnY4Px4cQSafdcsmm3jwMVeCdPdRZ0 +RuJ5qEm2e29qm9nj2MTLVMKEjbTS/FbK5SkxKuLUXHsgZyFLGssFjTWDKsX/jy8c +u0Kby++b6gPkO3Ft0BjwyRMAAwUEAJSn61N7TqyPOs5GSCxzUIAbsh4PlGeDZ3Uc +g+CY/+WZS7CzJlUZiDWqIFADmip5FcuF/MV0mYgcd8nMBVcy17maEf1OnfPhEhOj +spu8xBnSNBGWQHQx9h5CBy66riBSHG8czF9/IlKmWgyo+TGJXrxz1R2VIYgoato6 +BKZSduFZiEYEGBECAAYFAjsj/S8ACgkQzR62qWZ+QtFuBQCeMY2aH7t6yvVR6o1W +YopKmcxZw0UAn3iLjS38pR3qIfRN4Qhzktzu1ofBmQGiBDslJtURBADjFHks4HZl +ZIc3UjWQrICS2dKbbBWxbRIKmirXD0mOZsOCdmkMpIgy4BWM2HncN5BtP/1eyh+n +IwHHnFKgzqKxAIY3AjWzEDVLKPbJZ2xdQceEbKrx3Zrywt4KdyHG9DeAMYmhib8B +VZ9Gg0zyTD6/HqXmA0QUOfOHQKLBApVTVwCg/+F6iL4OlBX1xKlg17yHNbdAFsME +AIOH/1rBCnc2sIjyjFdgha5OxACwOJvrodAOLjDxRL/uRWnjOrKhM36A+TySc5Lv +PpaqnGYcPQMNm7hUThRoLU5rYf/rdUV49y/ARQZDAdZOFf4meYk0c735c7TTTcqw +f7Ri3gVGfrhsmRFwvU9JyNhkWJ/9HpOk1EZCYLgl8f4SA/sEI9CRWiLS+8PHf02p +PzVZkBZzTMZNIUlXKltPJ9hSsbn1P0PHAfk1hYxch0QAQWn786F5P8DBT7bY9/Fj +2Tuu9SReDg+hK1X3K/S8QpUZ3aDuQPBTvtzTryI0k7wsRioXl+dI7yJ5TrtmCUpl +J7QRTaEvpYRn1MuHorM8exqrxLQxRnJhbmNpc2NhIFF1aW50YW5hIE5hcmFuam8g +PGZyYW5jaXNjYUBob3Rwb3AuY29tPohgBBARAgAYBQI7JSbVCAsDCQgHAgEKAhkB +BRsDAAAAABIJEGcamjydIvodB2VHUEcAAQG0twCg462jbwEDWXbQkjp7BsOpn17h +NIgAoMTjKy9QT5pSPvCR2vg4O9DFKJJciEYEEBECAAYFAjslRYcACgkQzR62qWZ+ +QtGT6ACbBW2aYqhvqyE8UmOTpJNeSNa/HrkAoJr1/YGNLR0mOJ4Km5xZ8RprGHv7 +uQINBDslJtUQCAD2Qle3CH8IF3KiutapQvMF6PlTETlPtvFuuUs4INoBp1ajFOmP +QFXz0AfGy0OplK33TGSGSfgMg71l6RfUodNQ+PVZX9x2Uk89PY3bzpnhV5JZzf24 +rnRPxfx2vIPFRzBhznzJZv8V+bv9kV7HAarTW56NoKVyOtQa8L9GAFgr5fSI/VhO +SdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsYjY67VYy4XTjTNP18 +F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsC +RtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpMgs7AAICCADd3vdMio1+IrBMRxfHs5bw +qUTxQbHuGIrX4gFqQswWQHnihWPpotDIGwf+uuBWz1X9RiHKCPIOE0rTvXk6DsH1 +s/5iE0+zCLHsoGPSY4DU7WYQgrqumSBP0CqEBFzBJSUN/iCD4PP6lfjzlrmfDznE +Yn73KDJKXM5c0T4YJbs9NFBSmq8qzY9MAixlkty5jvz3GX8/EMTgSxG9ih68CTac +uq+u7fzbQszjKcrAqrPRAgJMtVwTuzBrpyTp/nelvOG8STR0z30yKu0kxaSPupi/ +BDCg/pTjRwAT6TmkdNm1uhebJzK8L6bKy8msqZVMuscxnS/hO2HZ651RvCysyRFh +iFQEGBECAAwFAjslJtUFGwwAAAAAEgkQZxqaPJ0i+h0HZUdQRwABAXlmAKD1P1CN +skD6H649PbY7THYFIgrgswCglmKY5nhOTdRIUsTi5cN37CHIob6ZAaIEOyU2WhEE +AMSfxMgHwElMwonNAeawUGT8NhqgfgRGCqJGHK3v6yx3/ms51sVA4PdA7jt6wG8/ +nbhszeeQCIwiqZtaxGoHZcTEu4219EdOPzMebbLcm2iCH57kXGAc/vn6VOGChNhw +Zt+VgdpEgy/+9gEORKC0cBDT0X93oa5im1O4q5030frvAKD/3pf4Bz4qmi35U9vW +YDan/NqIFwQAocSAWtfn2WtS6UlqHkIBdpc/Zu49DUWJ1rL4wagIhRgGlblyzqZO +GLEhnOrBsHXj3/yxXi+sF3mdDy9Z112DK+1L1taSf8LkRFsutbxsJqumH+bTU1mw +bjnJgd4D8/oz8ryUOc6OnwsmAqaGjWR/Mul+H8mtzKbFpVHjL8uiMs8D/R/mTe6t +GTIQCKaninTn9ovJbRgu4V2H4wB+gvpV463W7UtnY6ypCZOxgjsw+sdRfrOKiH+T +k5bSkRUeaJgFm3Ohfbx9g4CcnKbYLDR1M8TWAlVcb1kZqqrb4daYHz9e5jD2oeZQ +vancOBrsTg6jj2Nrmqzns2LkV+jf/AcMZ80StClNaWNoYWVsIE1hYy1WaWNhciBQ +cmV0dCA8bWltYWN2aWNAcHVjLmNsPohgBBARAgAYBQI7JTZaCAsDCQgHAgEKAhkB +BRsDAAAAABIJEG1K/bpUtQOCB2VHUEcAAQGmEwCeKa3LJJqxvSg2hF18+JQS4F7i +5mQAoMZeMPJWVSWmlU41imAGjwHoP4NyiEYEEBECAAYFAjslRx8ACgkQzR62qWZ+ +QtFkQACfbMS0sv/k91tVcXV5poK0CR+m9EsAn3ywd5cQw3eenCn1z+q3gwI3G99z +uQINBDslNloQCAD2Qle3CH8IF3KiutapQvMF6PlTETlPtvFuuUs4INoBp1ajFOmP +QFXz0AfGy0OplK33TGSGSfgMg71l6RfUodNQ+PVZX9x2Uk89PY3bzpnhV5JZzf24 +rnRPxfx2vIPFRzBhznzJZv8V+bv9kV7HAarTW56NoKVyOtQa8L9GAFgr5fSI/VhO +SdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsYjY67VYy4XTjTNP18 +F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsC +RtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpMgs7AAICB/46z7Jy+uxh4TiACldUV23L +pzj0laL/HhAn+Sv02xAZW7YVgHIq21ZwyiQ9ZbEo005HqvLPch7YymIXxoYiokia +nCgbncHtG0aeaX1T/IPPbJbwNRx2+2GCLongbNvmAO9bCWP9LVeVaT9D4LpsCium +hAtiOw5t/Q2cAPMgN03hTLkRI2LEdZnsapLDogQo5v6oOiLEZasSrft0MMwv3l1G +MUvxdfwrR2HM7WopJS6H4AK2W0tSBLPKFanW9KAsLVcAVFV6u3lEXjuXncOo9feF +WUf8A4LBJr5cQBu2kKuBcy0iayCz18s46KlqxCCCWLu+gnxcTU3YNEdQF41NjdgY +iFQEGBECAAwFAjslNloFGwwAAAAAEgkQbUr9ulS1A4IHZUdQRwABAWk6AKDmE88v +eFoum1b8bwCADKJjNX1WzgCgqJ61xnX80EBLtAO8rQZQSBKyABSZAaIEOyVASREE +AOANe2DTx2GMdCm/1KKy/O9E5yyvpBEU4tZ/3kZaHtzpIjs+PmZMKVRolcFGMu68 +5HQvvDyXmdUn/iTNKOV7Vp3Th4PM/ewHis0rXyXsYDBzSKNXSan8qX0XiKJtyjdw +IgyyPKxaBSaWT51hhZC5tAD8SBOzuQVCj1BHHOiOqdLLAKD/kJnlMnX2A1LySfK7 +zX2/plKRXwP/TUV6bZZl6OqyY0E2JjUmhbGdOh+LcCMy/qP/42PIG5T2jMiFSJzH +jL5GjTl4pRn5UAh5xVtWESof1VSuJfjxMOs3G7g4YmHrarnyzS7+2ohfk6u+umZ0 +4LVRN1xzYIzzy+yxO3yjFq5l4ztgCRj2sCldSeLJ+cnd913cWUIhu9oD/1deuUGM +b/cdBI9+SduouUK8RyV6VGabosBfx+5/8kWCPRy1EwAkoHoc4Tv+m+XfJEwwhPCZ +32UH+za75+pzBXVsOp+fJXyHcoWlMIYzWopP4RppP/wmEUmJ9gOMESdR72Zgbt1S +W34V/0WPplElCz2+zPNBywkPM2nKz6P8om61tC1EdW5jYW4gTWFjLVZpY2FyIEdh +cu1uIDxkdW5jYW5AbWFjLXZpY2FyLmNvbT6IYAQQEQIAGAUCOyVASQgLAwkIBwIB +CgIZAQUbAwAAAAASCRDBKokdV5ub1AdlR1BHAAEB4dEAmwYpphCnjg3NgSNL12wQ +BPixgrMOAKDDhzuQNqtkv+oqoW8du+w9Lp9G14hGBBARAgAGBQI7JUb1AAoJEM0e +tqlmfkLRY7sAoIFRQuTnl9H/Jq+RiBSEv0BfStKGAJ9DSONVqtVA1z9yPmKVN0qp +KR4nyrkCDQQ7JUBKEAgA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlLOCDaAadW +oxTpj0BV89AHxstDqZSt90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N286Z4VeS +Wc39uK50T8X8dryDxUcwYc58yWb/Ffm7/ZFexwGq01uejaClcjrUGvC/RgBYK+X0 +iP1YTknbzSC0neSRBzZrM2w4DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2Ou1WMuF04 +0zT9fBdXQ6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqVDNmWn6vQ +ClCbAkbTCD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwACAgf/c1hY0bD1ZrwHo7Do +3JLZZIGvHfdnEicOA5tl7vaY78ZLLHFmrE+KpMVOlqNMP4dYpC69J8wZl0PWQllO +s0Qj8w0vBUGGuDEtfaquarVomBZrlpFy/TnAe4hSvDaDbbShnT2BSFe4XdT+gNQI +Bffp3XoJo8IwlXVNFShzYvVags/YGPMiQCAqupQa8gU2y+1d7dw1Tl1JDMXSykTG +4LPVbLrv9Ph/MtImmJZp2X943rtynzd6Brl/JjL02khKZ6IVxXblQmptAzSS2KVn +MOHH56+Zh3o8c/uLw6qALWgdqMSiF+j2SbI78Bcn+/Tyy+dIlU7Qb/2pB64WnclV +4Eew3ohUBBgRAgAMBQI7JUBKBRsMAAAAABIJEMEqiR1Xm5vUB2VHUEcAAQFFEgCe +OFpL+b95gvDaDv0a4sP/XHXZeP0AoJbThxHBTGgiKvB0nEs1FPYagsB2mQGiBENE +9tQRBACoPUvSF0C3Gyg93BzfjPoQzfIG7KcH+X1PMd7wsaF48B53t2V7px4MGw5W +CwRy6S+bkz86Os3Ycxewm0a7/We/G0QmzmyOOD+f+L5s7Sr0rM1fmFVGZRKin1MX +0s7YpX40rSHouNSYXXX2vu+o7uJvkzI8/yf16Kac4b1nP3jT5wCguV6Gl1eWkOS9 +DfwBUuIdwLObzjcD/2B9rPsuN4mhbjTAnPxz8fMKI2r+68UvEkicVIeKKauEp9JW +defR5Yfv2koagqZC3F9550SjZw2r/Wmx0RhAA4mskuMXwIato39NK9+oXqgSVbyT +CAb8SEgPlw60f/MctlIveRpTmSaSL37tj+UEHqOUSPoRk0VNXTML0prWpuVxA/9A +YiJ62X/0CV3DksecKvr3hWdD3WZhoniRInYhkeokHJFP0V0WkWpHD1+brNgHE0ig +jnbkTLWfVYDhppRccKjMiB4CxlwNoreOc2uRvO2cAzo5d0zCdJDfTNi1Ibspuf3r +lnYFZ+Y2dhrP825FMvcS0dL2ZTVcOXPwDVVJRDB0l7QvV2lsbCdzIEdXIGNyeXB0 +byB0ZXN0IGtleSA8d3N0ZXBoZW5zb25Ac3VzZS5kZT6IYAQTEQIAIAUCQ0T21AIb +AwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEHfQbNrv1xE4iJkAn3W4/fWpkgZf +pit9du1vzKTaS+y6AJwLXPrzm5F9CDTX77AfCSPsvYOHYrkCDQRDRPbgEAgAveOV +KYqnKMeC9mZEzpYPFjwxMe0qSdVAqxPvAOknzbJpDHm0O9uIf8F/IQZC+Hq/COQk +9zowMkrHIBs93a0SSX4pV174XjshxDoYxDiUf/XTTDec43a420M3K3ji3ySj/MyI +gOr1zu1zCWN90nFIyhBbAUqWwiEO4tHtI96pMko6RvmMZb0gsC5ERMTd5iXfvEPC +437tNyuVokeZmZAPZ2QLJoms3rt1sRujF4vZeDORZXwrhUXGtscopNgg3C39Asw2 +eFS7waeblUdQbtH6iz3ofD+qz2PNc2wcnY5q6aeZTyB0USShG7PsQATLDhFwkeDP +qp8g5oI+JmvPgqyAYwADBQgApLDng/rWmEKEqaUEG5sgG2fqSe7Q8tSXD/OyjXGv +zjkurCe+gOUiWqUfPEtYRGBXGvE8VqYGveQZVjqiNxJ6l6tK8x4GKxMxC4hMFFTo +QWoBhEw1Jy5wvOY8KoqSLnDERjXFqqTQsDEnyFjMGBl4K2XWjOYMBmSqkaDJydtv +unqgH0yULu3ouxY7wk3ZKovDGmtt4i4MrthmYXq9W2tM1LutXh7PChJf4DVIo/0x +SghvMQvJIELAPoIIp8h4V07sjPdvGg+n4nSAhw67KLHCR/TEqgTULH5w83Aopwbr +yDnBKBXFh6zx3ArZu09YM19xW5J1ju4ureQG6jbly5Vmn4hIBBgRAgAJBQJDRPbg +AhsMAAoJEHfQbNrv1xE4qNsAn2soSMFX3ZErJ4Uwwk2pg7dvYlZ0AJUYWEKOTfAc +5kHox/B8rV0xDu90mQGiBDnu9IERBACT8Y35+2vv4MGVKiLEMOl9GdST6MCkYS3y +EKeueNWc+z/0Kvff4JctBsgs47tjmiI9sl0eHjm3gTR8rItXMN6sJEUHWzDP+Y0P +FPboMvKx0FXl/A0dM+HFrruCgBlWt6FA+okRySQiliuI5phwqkXefl9AhkwR8xoc +QSVCFxcwvwCglVcOQliHu8jwRQHxlRE0tkwQQI0D+wfQwKdvhDplxHJ5nf7U8c/y +E/vdvpN6lF0tmFrKXBUX+K7u4ifrZlQvj/81M4INjtXreqDiJtr99Rs6xa0ScZqI +TuZC4CWxJa9GynBED3+D2t1V/f8l0smsuYoFOF7Ib49IkTdbtwAThlZp8bEhELBe +GaPdNCcmfZ66rKUdG5sRA/9ovnc1krSQF2+sqB9/o7w5/q2qiyzwOSTnkjtBUVKn +4zLUOf6aeBAoV6NMCC3Kj9aZHfA+ND0ehPaVGJgjaVNFhPi4x0e7BULdvgOoAqaj +LfvkURHAeSsxXIoEmyW/xC1sBbDkDUIBSx5oej73XCZgnj/inphRqGpsb+1nKFvF ++rQoU3VTRSBQYWNrYWdlIFNpZ25pbmcgS2V5IDxidWlsZEBzdXNlLmRlPohiBBMR +AgAiBQJA2AY+AhsDBQkObd+9BAsHAwIDFQIDAxYCAQIeAQIXgAAKCRCoTtronIAK +ypCfAJ9RuZ6ZSV7QW4pTgTIxQ+ABPp0sIwCffG9bCNnrETPlgOn+dGEkAWegKL+I +RgQQEQIABgUCOnBeUgAKCRCeQOMQAAqrpNzOAKCL512FZvv4VZx94TpbA9lxyoAe +jACeOO1HIbActAevk5MUBhNeLZa/qM2JARUDBRA6cGBvd7LmAD0l09kBATWnB/9A +n5vfiUUE1VQnt+T/EYklES3tXXaJJp9pHMa4fzFa8jPVtv5UBHGee3XoUNDVwM2O +gSEISZxbzdXGnqIlcT08TzBUD9i579uifklLsnr35SJDZ6ram51/CWOnnaVhUzne +OA9gTPSr+/fT3WeVnwJiQCQ30kNLWVXWATMnsnT486eAOlT6UNBPYQLpUprF5Yry +k23pQUPAgJENDEqeU6iIO9Ot1ZPtB0lniw+/xCi13D360o1tZDYOp0hHHJN3D3EN +8C1yPqZd5CvvznYvB6bWBIpWcRgdn2DUVMmpU661jwqGlRz1F84JG/xe4jGuzgpJ +t9IXSzyohEJB6XG5+D0BuQINBDnu9JIQCACEkdBN6Mxf5WvqDWkcMRy6wnrd9DYJ +8UUTmIT2iQf07tRUKJJ9v0JXfx2Z4d08IQSMNRaq4VgSe+PdYgIy0fbj23Via5/g +O7fJEpD2hd2f+pMnOWvH2rOOIbeYfuhzAc6BQjAKtmgR0ERUTafTM9Wb6F13CNZZ +NZfDqnFDP6L12w3z3F7FFXkz07Rs3AIto1ZfYZd4sCSpMr/0S5nLrHbIvGLp271h +hQBeRmmoGEKO2JRelGgUJ2CUzOdtwDIKT0LbCpvaP8PVnYF5IFoYJIWRHqlEt5uc +TXstZy7vYjL6vTP4l5xs+LIOkNmPhqmfsgLzVo0UaLt80hOwc4NvDCOLAAMGB/9g ++9V3ORzw4LvO1pwRYJqfDKUq/EJ0rNMMD4N8RLpZRhKHKJUm9nNHLbksnlZwrbST +M5LpC/U6sheLP+l0bLVoq0lmsCcUSyh+mY6PxWirLIWCn/IAZAGnXb6Zd6TtIJlG +G6pqUN8QxGJYQnonl0uTJKHJENbI9sWHQdcTtBMc34gorHFCo1Bcvpnc1LFLrWn7 +mfoGx6INQjf3HGQpMXAWuSBQhzkazY6vaWFpa8bBJ+gKbBuySWzNm3rFtT5HRKMW +pO+M9bHp4d+puY0L1YwN1OMatcMMpcWnZpiWiR83oi32+xtWUY2U7Ae38mMag8zF +bpeqPQUsDv9V7CAJ1dbriEwEGBECAAwFAkDYBnoFCQ5t3+gACgkQqE7a6JyACspn +pgCfRbYwxT3iq+9l/PgNTUNTZOlof2oAn25y0eGi0371jap9kOV6uq71sUuOmQGi +BEYjZk4RBACjIOtNaPzvKlC32b8R5TDRB0/FQ0tsMtt5dLwuq2ZYlEbT1YLF110v +ZEl5IQAq5ldvD7MdR/6fqdXTdxBeYzZjeIEYbHzg3rN/N/+MkcG4W8IK1H6eDAbL +05HlQ1ueTp0mjgoGLYKt1igQe8h5uA6gEE7dv0tG0NJx2w5Gs2GpmwCgiRius2ev +221Pa65IpR1gsYuXLOEEAKJ1Bvjm+BfHJirqoH7iPq5HlABwn+s9sUmf6bjCkfar +/ySAsL0VUhHNCIoHUEZd2imA2ZA0kTBxB+BIX/HMRZzxPZEwYI8Q0UYsTVb/gnQt ++mWaZs1/2teWR0wnUp+eO5MpOAO9QjFJTdIz0GegsfSOPCo55CUtktr3tJUKfZ3g +A/9mZe+b1Evi1/Us+klnERRKR2jjWXxwuPN6UivJbfXIZjuVUNclAhEqstzpfnWJ +3LhPxj0zJvhp/MnqSTaI6DQbr0f+JvwP+5k/4gbnqm+xxOocyhiVT45zOPAyUYuG +4t0m+9G7Vx6LC9tMukbdfHaRym42yC2s04GW2isKfta1ZbQsWllwcCBUZXN0IEtl +eSBQYWlyIDx6eXBwLWRldmVsQG9wZW5zdXNlLm9yZz6IYAQTEQIAIAUCRiNmTgIb +IwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEJvswrXdsDdWSVAAnjkR2laohb2Q +4WnxamdHYWSf8ULKAJ4jjfZsFq0vmgPsO/YHaKTJN5sAL7kBDQRGI2ZREAQAtoB5 +TGT9K7NCv5D5dQw7jVHngnxp3NGTtAhwirYphBWaF2be3UJVTLbUFW14eMnrVW9P +Kj/HNVLhQu0C6CaXtXy5LahIls+mFlSKwbiP74cFlNYcj69tzCnaFKgElQPHcMOc +31EgjySYcUIys421MxI++sugW+yHr5ByIsL6vfcAAwUEAILSwmLtD+Pwkues73DP +PyWIM3MA0exO7QmZeFwnbpiZYuZQ3GiPGrbeZVqHWB72dhW8+5ugR9CVQSsLHC5w +HMIQFU8RsiL06gZdIaJNgAr7ajhtUybP0WPVpXkzm5+VB8Che9m0Z0t2tK8Y0KVa +pBcr3YDgx89F9VA0yny6q3WiiEkEGBECAAkFAkYjZlECGwwACgkQm+zCtd2wN1ap +uACfUR+Daoo3N1fxxDa3A3t4OkAfpQgAn1UEvpQp+/4DnzSbEvwzLeoek3dzmQGi +BEY/vAIRBAD2cxLY83P2G1h5TkkKYQYTLopgWQh7/7H5UK0cf62gLH7R6F7BwW4E +qmLsm8eGE8kIOob5wCQU6pxpBMv+1UYoO1bohtx4L2JUY5ycJiq4u1CNyRuciR3y +gsueMRkelkQ2hpNuKvmficOcoazvU3tZM6ITJjV/tQvYTQRGqwEfwwCgs0OY3q7e +R8NwWekaj23t8TV7hjMEANS6QMgjsp5CdLglX02oeiCG82oEKLDOWoZ2ajD++naz +SIflJE0DaZ0W26QXewh7IRzTomV98fJV6inQNanlk5/TNuAb1elXdaYFuNbnZ0yo +OaTJx/mb88vm63Ur8FTyKdcN+dau8yzuNlJggj5yBcNg+/8ZOAm1ZkDMlg9uAhgD +A/0RSjXu/YNmflePFxIKBCAJFJenz4dQUZeb5cuJv20eCqnKn5CFYFU6YYg3sYaE +tZeultDXweRveGwe28E/vpLUa7p+aZq+XwtjI6U6W5VqvkCKIUsQqwVWRHin1/4D +ABJ5rnU+yPeLXNH6jrMQ+jDG8RieI91/4n+gCX1nbwZQ/rQrWllwcCB0ZXN0Y2Fz +ZSBrZXkgPHp5cHAtZGV2ZWxAb3BlbnN1c2Uub3JnPohgBBMRAgAgBQJGP7wCAhsD +BgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQvWHYm9mIIb7TJQCfTe4MwrmOlWDx +WV3yZ6E4B9xQq0YAoIWvs4oYVzbaQzclStHai5kxuGn8uQINBEY/vAwQCAD4T11K +PE7CzkqgGMaNP+yNQzfUDbd/SaEQ5Wce5q3VvmVBpYORxyWjS8QMc9ge8WxezAsj +yTKsXl+u7e/QmMKspPzPhkVKyB6s5D8FhR1Pdo7bAi4xx+NLOu9DuuU+jqUkyHYl +t8QF2zX98OOcCIuQc2hjk12dvfHKmUiDoUnfuQPxvYrFAWnesgUJMqZo7Td5Ly4I +jfMJQlQ7A186BGU8bPWoV1QqUInVkNGNXLmglel/m+MTV05nT6+1KCBqCRUluHqD +aCiFHOUOFVWvtirmPJZ/67J78NJpF7huzXvkQraatXyHnAyhwiwTZLq2jabMjQgG +hV8QyKd4qniSBL+jAAMGCACfH4FGqrs9pGBURmSjZKlHAUdnGul0M2KuyJhv8ZBk +ApUtPcMhZJco50pFpkqjfH7f3xXMRVDP5FpjaRt67abbezp/Dgs8+691OtAREDWb +AzarNNR3FbB9fUebh1J2i4W7tfBcoKwKFWJCvqX2HGTzVy1k33vnuGCVwC/KiZ/C +6pc4DqUwCWNoZNd8hmFadJgx3CMlxSTllsaIyOXp8dMJ+FFsTmzONzZpFC9DDtpa +UeEChCptjWwy5WkQFPe+FOLUH1BnGScQYwGlE8l+cFkE7hW8tyOwcx4sk1J/tDCe +J1wE8we1LXMdIiD5ugf3Jej1/98o+hQTHjfkwGqCGWJViEkEGBECAAkFAkY/vAwC +GwwACgkQvWHYm9mIIb5O9wCfeI0Ro1UCK/CVT1/BH9NNB0TyYzAAmwdQFE6IaVSt +jbDRYEnTHQOGsVy9mQGiBER0ULcRBADZvvVUsUUSjMyQ2fUt8Uu4eGJuPbMhEtR/ +vF7pzF/8u9Br7kh6WASBZ02dMeNoqFzPTU7zv6PiP93iOLwy2MQNOSBLkS+MscR6 +fzS6ZL81mNr+DwgOF/rLZ4tucAsBY9Z3lgRx0mWhl+XunVPXHhkR9H9Rig4wOrrz +wBsYjjfXvwCguQ1PQ6+UQgL8STVqNaNnlVYzzUUD/336IftwogH/tKp6dV/FYP/V +pLHXtwFee0vcCh5FwcKP0vYo9NIfB6CR2g0pyYsHBWbheMWXRVTlCaUVOhaycd+D +XoyKl3FcxL61OD0F/feg2UEqH7n1csGV2MDGlqXsF5urKdPYcBRG56ynlWXs3W7D +zu9JN8skhWSnXdtBFa3BBACo+CAXSzLJnFrG7kg8AYT+0k+kTS/UydwAr57QSLUc +/blXR6seNd+TM4Kwj4Ij2pNL/LpZyzVrDS9BWNZHq3bQnERPrfXpK5XWX0quZn8z +g1ImFwxmJduHKmtyyxNjjPR1SUFzD1EXpPfCYgRL6kU4OflbgGoL2YpmgHO6LQ/O +GrQyb3BlblNVU0UgQnVpbGQgU2VydmljZSA8YnVpbGRzZXJ2aWNlQG9wZW5zdXNl +Lm9yZz6IZAQTEQIAJAUCRHRQtwIbAwUJA8JnAAYLCQgHAwIDFQIDAxYCAQIeAQIX +gAAKCRA7MBG3a51lI/ewAJkB4psDm44RckrzyMyjXEKBYXYKXQCcCLBW95t7ooAI +yqfsg94RICpbr50= +=NAat +-----END PGP PUBLIC KEY BLOCK----- diff --git a/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/repomd.xml.key b/libzypp/tests/zypp/data/PublicKey/susekey.asc similarity index 98% rename from libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/repomd.xml.key rename to libzypp/tests/zypp/data/PublicKey/susekey.asc index 91c316f..b49e52d 100644 --- a/libzypp/devel/devel.jkupec/data/deltarpm/updates/repodata/repomd.xml.key +++ b/libzypp/tests/zypp/data/PublicKey/susekey.asc @@ -1,5 +1,5 @@ -----BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1.4.0 (GNU/Linux) +Version: GnuPG v1.4.2 (GNU/Linux) mQGiBDnu9IERBACT8Y35+2vv4MGVKiLEMOl9GdST6MCkYS3yEKeueNWc+z/0Kvff 4JctBsgs47tjmiI9sl0eHjm3gTR8rItXMN6sJEUHWzDP+Y0PFPboMvKx0FXl/A0d diff --git a/libzypp/tools/CMakeLists.txt b/libzypp/tools/CMakeLists.txt index 2c2a3da..2528a05 100644 --- a/libzypp/tools/CMakeLists.txt +++ b/libzypp/tools/CMakeLists.txt @@ -1,6 +1,3 @@ - -ADD_SUBDIRECTORY( package-manager ) - INSTALL( FILES notify-message DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/zypp" ) ## ############################################################ @@ -20,3 +17,4 @@ ENDFOREACH( loop_var ) ## ############################################################ INSTALL(TARGETS zypp-CheckAccessDeleted DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") +INSTALL(TARGETS zypp-NameReqPrv DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/libzypp/tools/package-manager/CMakeLists.txt b/libzypp/tools/package-manager/CMakeLists.txt deleted file mode 100644 index ddae11a..0000000 --- a/libzypp/tools/package-manager/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ - -########### install files ############### -INSTALL(PROGRAMS package-manager package-manager-su DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/libzypp/tools/package-manager/package-manager b/libzypp/tools/package-manager/package-manager deleted file mode 100755 index 4c7b13a..0000000 --- a/libzypp/tools/package-manager/package-manager +++ /dev/null @@ -1,195 +0,0 @@ -#! /bin/sh -# by http://en.opensuse.org/User:Mvidner -# https://bugzilla.novell.com/show_bug.cgi?id=222757 -usage() { - cat >&2 <()$`\" \t*?#~=%[]\)/\\\1/g' -} - -function mkCmd() { - quote "$1" - shift - for ARG in "$@"; do - echo -n " $(quote "$ARG")" - done -} - -function check_installed() -{ - rpm -q "$1" >/dev/null - return $? -} - -function what_do_we_have() -{ - echo "Zlm: ${HAVE_ZLM}" - echo "openSUSE: ${HAVE_OPENSUSE}" - echo "KPackagekit: ${HAVE_KPACKAGEKIT}" - echo "GPackagekit: ${HAVE_GPACKAGEKIT}" - echo "KDE running: ${KDE_FULL_SESSION}" -} - -# check what we have -HAVE_ZLM=false -check_installed "zen-updater" -if [ "$?" == "0" ] -then - HAVE_ZLM=true -fi - -HAVE_OPENSUSE=false -check_installed "yast2-packager" -if [ $? == 0 ] -then - HAVE_OPENSUSE=true -fi - -HAVE_KPACKAGEKIT=false -check_installed "kpackagekit" -if [ "$?" == "0" ] -then - HAVE_KPACKAGEKIT=true -fi - -HAVE_GPACKAGEKIT=false -check_installed "gnome-packagekit" -if [ $? == 0 ] -then - HAVE_GPACKAGEKIT=true -fi - -if $HAVE_ZLM; then - if $HAVE_OPENSUSE; then - if [ -f /etc/sysconfig/sw_management ]; then - . /etc/sysconfig/sw_management - PSMS="$PREFERRED_SW_MANAGER_STACK" - fi - - if [ "x$PSMS" = "xzlm" ]; then - STACK=zlm - elif [ "x$PSMS" = "xopensuse" ]; then - STACK=opensuse - else - echo >&2 "/etc/sysconfig/sw_management:PREFERRED_SW_MANAGER_STACK should contain" - echo >&2 "'zlm' or 'opensuse'" - STACK=ugh - fi - else - STACK=zlm - fi -else - if $HAVE_OPENSUSE; then - STACK=opensuse - else - echo >&2 "No package manager installed?" - STACK=ugh - fi -fi - -METHOD=yast -# determine what we can use -if $HAVE_KPACKAGEKIT && [ "$KDE_FULL_SESSION" ]; then - METHOD=kpackagekit -elif $HAVE_GPACKAGEKIT && [ "$WINDOWMANAGER" == "/usr/bin/gnome" ]; then - METHOD=gnome-packagekit -else - if [ "$STACK" == "zlm" ]; then - METHOD="zlm" - else - METHOD="yast" - fi -fi - -echo $METHOD - -xsu() { - # a copy of xdg-su. - package-manager-su -c "$(mkCmd "$@")" -} - -# do_* fall back to yast for STACK=ugh - -do_update() { - case "${METHOD}" in - yast) - xsu /sbin/yast2 --update "$@" - ;; - zlm) - zen-updater --no-tray "$@" - ;; - kpackagekit) - kpackagekit --updates "$@" - ;; - gnome-packagekit) - if [ -e /usr/bin/gpk-update-viewer2 ]; then - /usr/bin/gpk-update-viewer2 "$@" - else - /usr/bin/gpk-update-viewer "$@" - fi - ;; - esac -} - -do_remove() { - # not all support remove - case "${METHOD}" in - yast|kpackagekit|gnome-packagekit) - xsu /sbin/yast2 --remove "$@" - ;; - zlm) - zen-remover "$@" - ;; - esac -} - -do_install() { - case "${METHOD}" in - yast) - xsu /sbin/yast2 --install "$@" - ;; - zlm) - zen-installer "$@" - ;; - kpackagekit) - if [ $# == 0 ]; then - xsu /sbin/yast2 --install - else - kpackagekit "$@" - fi - ;; - gnome-packagekit) - if [ $# == 0 ]; then - xsu /sbin/yast2 --install - else - /usr/bin/gpk-install-local-file "$@" - fi - ;; - esac -} - -if [ "x$1" = "x--update" -a $# = 2 ]; then - shift - do_update "$@" -elif [ "x$1" = "x--remove" -a $# = 2 ]; then - shift - do_remove "$@" -elif [ "x$1" = "x--install" ]; then - shift - do_install "$@" -elif [ $# = 0 ]; then - do_install -else - usage 1 -fi diff --git a/libzypp/tools/package-manager/package-manager-su b/libzypp/tools/package-manager/package-manager-su deleted file mode 100755 index e1521f3..0000000 --- a/libzypp/tools/package-manager/package-manager-su +++ /dev/null @@ -1,462 +0,0 @@ -#!/bin/sh -#--------------------------------------------- -# xdg-su -# -# Utility script to run a command as an alternate user, generally -# the root user, with a graphical prompt for the root -# password if needed -# -# Refer to the usage() function below for usage. -# -# Copyright 2006, Jeremy White -# Copyright 2006, Kevin Krammer -# -# LICENSE: -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -# -#--------------------------------------------- - -manualpage() -{ -cat << _MANUALPAGE -Name - -xdg-su - run a GUI program as root after prompting for the root password - -Synopsis - -xdg-su [-u user] -c command - -xdg-su { --help | --manual | --version } - -Description - -xdg-su provides a graphical dialog that prompts the user for a password to run -command as user or as root if no user was specified. - -xdg-su is for use inside a desktop session only. - -xdg-su discards any stdout and stderr output from command. - -Options - --u user - run command as user. The default is to run as root. ---help - Show command synopsis. ---manual - Show this manualpage. ---version - Show the xdg-utils version information. - -Exit Codes - -An exit code of 0 indicates success while a non-zero exit code indicates -failure. The following failure codes can be returned: - -1 - Error in command line syntax. -2 - One of the files passed on the command line did not exist. -3 - A required tool could not be found. -4 - The action failed. - -See Also - -su(1) - -Examples - -xdg-su -u root -c "/opt/shinythings/bin/install-GUI --install fast" - -Runs the /opt/shinythings/bin/install-GUI command with root permissions. - -_MANUALPAGE -} - -usage() -{ -cat << _USAGE -xdg-su - run a GUI program as root after prompting for the root password - -Synopsis - -xdg-su [-u user] -c command - -xdg-su { --help | --manual | --version } - -_USAGE -} - -#@xdg-utils-common@ - -#---------------------------------------------------------------------------- -# Common utility functions included in all XDG wrapper scripts -#---------------------------------------------------------------------------- - -DEBUG() -{ - [ ${XDG_UTILS_DEBUG_LEVEL-0} -lt $1 ] && return 0; - shift - echo "$@" >&2 -} - -#------------------------------------------------------------- -# Exit script on successfully completing the desired operation - -exit_success() -{ - if [ $# -gt 0 ]; then - echo "$@" - echo - fi - - exit 0 -} - - -#----------------------------------------- -# Exit script on malformed arguments, not enough arguments -# or missing required option. -# prints usage information - -exit_failure_syntax() -{ - if [ $# -gt 0 ]; then - echo "xdg-su: $@" >&2 - echo "Try 'xdg-su --help' for more information." >&2 - else - usage - echo "Use 'man xdg-su' or 'xdg-su --manual' for additional info." - fi - - exit 1 -} - -#------------------------------------------------------------- -# Exit script on missing file specified on command line - -exit_failure_file_missing() -{ - if [ $# -gt 0 ]; then - echo "xdg-su: $@" >&2 - fi - - exit 2 -} - -#------------------------------------------------------------- -# Exit script on failure to locate necessary tool applications - -exit_failure_operation_impossible() -{ - if [ $# -gt 0 ]; then - echo "xdg-su: $@" >&2 - fi - - exit 3 -} - -#------------------------------------------------------------- -# Exit script on failure returned by a tool application - -exit_failure_operation_failed() -{ - if [ $# -gt 0 ]; then - echo "xdg-su: $@" >&2 - fi - - exit 4 -} - -#------------------------------------------------------------ -# Exit script on insufficient permission to read a specified file - -exit_failure_file_permission_read() -{ - if [ $# -gt 0 ]; then - echo "xdg-su: $@" >&2 - fi - - exit 5 -} - -#------------------------------------------------------------ -# Exit script on insufficient permission to read a specified file - -exit_failure_file_permission_write() -{ - if [ $# -gt 0 ]; then - echo "xdg-su: $@" >&2 - fi - - exit 6 -} - -check_input_file() -{ - if [ ! -e "$1" ]; then - exit_failure_file_missing "file '$1' does not exist" - fi - if [ ! -r "$1" ]; then - exit_failure_file_permission_read "no permission to read file '$1'" - fi -} - -check_vendor_prefix() -{ - file=`basename "$1"` - case "$file" in - [a-zA-Z]*-*) - return - ;; - esac - - echo "xdg-su: filename '$file' does not have a proper vendor prefix" >&2 - echo 'A vendor prefix consists of alpha characters ([a-zA-Z]) and is terminated' >&2 - echo 'with a dash ("-"). An example filename is '"'example-$file'" >&2 - echo "Use --novendor to override or 'xdg-su --manual' for additional info." >&2 - exit 1 -} - -check_output_file() -{ - # if the file exists, check if it is writeable - # if it does not exists, check if we are allowed to write on the directory - if [ -e "$1" ]; then - if [ ! -w "$1" ]; then - exit_failure_file_permission_write "no permission to write to file '$1'" - fi - else - DIR=`dirname "$1"` - if [ ! -w "$DIR" -o ! -x "$DIR" ]; then - exit_failure_file_permission_write "no permission to create file '$1'" - fi - fi -} - -#---------------------------------------- -# Checks for shared commands, e.g. --help - -check_common_commands() -{ - while [ $# -gt 0 ] ; do - parm="$1" - shift - - case "$parm" in - --help) - usage - echo "Use 'man xdg-su' or 'xdg-su --manual' for additional info." - exit_success - ;; - - --manual) - manualpage - exit_success - ;; - - --version) - echo "xdg-su 1.0beta2" - exit_success - ;; - esac - done -} - -check_common_commands "$@" -if [ ${XDG_UTILS_DEBUG_LEVEL-0} -lt 1 ]; then - # Be silent - xdg_redirect_output=" > /dev/null 2> /dev/null" -else - # All output to stderr - xdg_redirect_output=" >&2" -fi - -#-------------------------------------- -# Checks for known desktop environments -# set variable DE to the desktop environments name, lowercase - -detectDE() -{ - if [ x"$KDE_FULL_SESSION" = x"true" ]; then DE=kde; - elif [ x"$GNOME_DESKTOP_SESSION_ID" != x"" ]; then DE=gnome; - elif xprop -root _DT_SAVE_MODE | grep ' = \"xfce4\"$' >/dev/null 2>&1; then DE=xfce; - elif [ x"$DESKTOP_SESSION" == x"LXDE" ]; then DE=lxde; - fi -} - -#---------------------------------------------------------------------------- - - - -su_kde() -{ - KDESU=`which kdesu 2>/dev/null` - if [ $? -eq 0 ] ; then - if [ -z "$user" ] ; then - $KDESU -c "$cmd" - else - $KDESU -u "$user" -c "$cmd" - fi - - if [ $? -eq 0 ]; then - exit_success - else - exit_failure_operation_failed - fi - else - su_generic - fi -} - -su_gnome() -{ - GSU=`which gnomesu 2>/dev/null` - if [ $? -ne 0 ] ; then - GSU=`which xsu 2>/dev/null` - fi - if [ $? -eq 0 ] ; then - if [ -z "$user" ] ; then - $GSU -c "$cmd" - else - $GSU -u "$user" -c "$cmd" - fi - - if [ $? -eq 0 ]; then - exit_success - else - exit_failure_operation_failed - fi - else - su_generic - fi -} - -su_generic() -{ - if [ -z "$user" ] ; then - xterm -geom 60x5 -T "xdg-su: $cmd" -e su -c "$cmd" - else - xterm -geom 60x5 -T "xdg-su: $cmd" -e su -u "$user" -c "$cmd" - fi - - if [ $? -eq 0 ]; then - exit_success - else - exit_failure_operation_failed - fi -} - - -su_xfce() -{ - if which gnomesu &>/dev/null ; then - su_gnome - else - su_generic - fi -} - -su_lxde() -{ - if which gnomesu &>/dev/null ; then - su_gnome - else - su_generic - fi -} - -[ x"$1" != x"" ] || exit_failure_syntax - -user= -cmd= -while [ $# -gt 0 ] ; do - parm="$1" - shift - - case "$parm" in - -u) - if [ -z "$1" ] ; then - exit_failure_syntax "user argument missing for -u" - fi - user="$1" - shift - ;; - - -c) - if [ -z "$1" ] ; then - exit_failure_syntax "command argument missing for -c" - fi - cmd="$1" - shift - ;; - - -*) - exit_failure_syntax "unexpected option '$parm'" - ;; - - *) - exit_failure_syntax "unexpected argument '$parm'" - ;; - esac -done - -if [ -z "${cmd}" ] ; then - exit_failure_syntax "command missing" -fi - -detectDE - -if [ x"$DE" = x"" ]; then - which xterm 2>/dev/null >&2 - if [ $? -eq 0 -a -n "$DISPLAY" ] ; then - DE=generic - fi -fi - -case "$DE" in - kde) - su_kde - ;; - - gnome) - su_gnome - ;; - - generic) - su_generic - ;; - - xfce) - su_xfce - ;; - - lxde) - su_lxde - ;; - - *) - [ x"$user" = x"" ] && user=root - exit_failure_operation_impossible "no graphical method available for invoking '$cmd' as '$user'" - ;; -esac diff --git a/libzypp/tools/package-manager/package-manager.desktop b/libzypp/tools/package-manager/package-manager.desktop deleted file mode 100644 index 1244e70..0000000 --- a/libzypp/tools/package-manager/package-manager.desktop +++ /dev/null @@ -1,11 +0,0 @@ -[Desktop Entry] -Encoding=UTF-8 -Name=Install/Remove Software -GenericName=Install Software -Exec=package-manager --install %F -#Icon=package-manager-icon -Terminal=false -Type=Application -Categories=PackageManager;X-SuSE-ControlCenter-System; -MimeType=application/x-rpm;application/x-redhat-package-manager; -StartupNotify=true diff --git a/libzypp/tools/NameReqPrv.cc b/libzypp/tools/zypp-NameReqPrv.cc similarity index 84% rename from libzypp/tools/NameReqPrv.cc rename to libzypp/tools/zypp-NameReqPrv.cc index 11c41bf..da23d21 100644 --- a/libzypp/tools/NameReqPrv.cc +++ b/libzypp/tools/zypp-NameReqPrv.cc @@ -4,6 +4,7 @@ #include #include +#include static std::string appname( "NameReqPrv" ); @@ -27,8 +28,7 @@ int usage( const std::string & msg_r = std::string(), int exit_r = 100 ) } cerr << "Usage: " << appname << " [--root ROOTDIR] [OPTIONS] NAME... [[OPTIONS] NAME...]..." << endl; cerr << " Load all enabled repositories (no refresh) and search for" << endl; - cerr << " occurrences of NAME (regex) in package names, provides or" << endl; - cerr << " requires." << endl; + cerr << " occurrences of NAME (regex) in package names or dependencies" << endl; cerr << " --root Load repos from the system located below ROOTDIR. If ROOTDIR" << endl; cerr << " denotes a sover testcase, the testcase is loaded." << endl; cerr << " --installed Process installed packages only." << endl; @@ -78,6 +78,10 @@ void dDump( const std::string & spec_r ) for ( const auto & el : q ) { message << endl << "==============================" << endl << dump(el); + if ( isKind(el) ) + { + message << endl << "CONTENT: " << make(el)->contents(); + } } message << endl << "}" << endl; } @@ -250,39 +254,49 @@ int main( int argc, char * argv[] ) } else { - q.addString( qstr ); - q.setMatchRegex(); - q.setCaseSensitive( ! ignorecase ); - - if ( names ) - q.addAttribute( sat::SolvAttr::name ); - if ( provides ) - q.addDependency( sat::SolvAttr::provides ); - if ( requires ) - q.addDependency( sat::SolvAttr::requires ); - if ( conflicts ) - q.addDependency( sat::SolvAttr::conflicts ); - if ( obsoletes ) - q.addDependency( sat::SolvAttr::obsoletes ); - if ( recommends ) - q.addDependency( sat::SolvAttr::recommends ); - if ( supplements ) - q.addDependency( sat::SolvAttr::supplements ); + sat::Solvable::SplitIdent ident( qstr ); + if ( ident.kind() != ResKind::package ) + { + q.addKind( ident.kind() ); + q.addString( ident.name().asString() ); + } + else + q.addString( qstr ); + + q.setMatchRegex(); + q.setCaseSensitive( ! ignorecase ); + + if ( names ) + q.addAttribute( sat::SolvAttr::name ); + if ( provides ) + q.addDependency( sat::SolvAttr::provides ); + if ( requires ) + q.addDependency( sat::SolvAttr::requires ); + if ( conflicts ) + q.addDependency( sat::SolvAttr::conflicts ); + if ( obsoletes ) + q.addDependency( sat::SolvAttr::obsoletes ); + if ( recommends ) + q.addDependency( sat::SolvAttr::recommends ); + if ( supplements ) + q.addDependency( sat::SolvAttr::supplements ); } message << *argv << " [" << (ignorecase?'i':'_') << (names?'n':'_') << (requires?'r':'_') << (provides?'p':'_') - << (conflicts?'c':'_') << (obsoletes?'o':'_') << (recommends?'m':'_') << (supplements?'s':'_') << "] {" << endl; + << (conflicts?'c':'_') << (obsoletes?'o':'_') << (recommends?'m':'_') << (supplements?'s':'_') << "] {" << endl; for_( it, q.begin(), q.end() ) { - tableOut( str::numstring( it->id() ), it->asString(), it->repository().name(), it->vendor().asString(), - str::numstring( PoolItem(*it)->buildtime() ) ); + tableOut( str::numstring( it->id() ), it->asString(), + str::form( "(%d)%s", it->repository().info().priority(), it->repository().name().c_str() ), + it->vendor().asString(), + str::numstring( PoolItem(*it)->buildtime() ) ); if ( ! it.matchesEmpty() ) { - for_( match, it.matchesBegin(), it.matchesEnd() ) - { - tableOut( "", "", "", match->inSolvAttr().asString().substr( 9, 3 )+": " +match->asString() ); - } + for_( match, it.matchesBegin(), it.matchesEnd() ) + { + tableOut( "", "", "", match->inSolvAttr().asString().substr( 9, 3 )+": " +match->asString() ); + } } } diff --git a/libzypp/tools/zypp-cpeid.cc b/libzypp/tools/zypp-cpeid.cc new file mode 100644 index 0000000..f653b2d --- /dev/null +++ b/libzypp/tools/zypp-cpeid.cc @@ -0,0 +1,66 @@ +#include +#include +#include + +using std::cout; +using std::endl; +using zypp::CpeId; +using zypp::Pathname; + +int main( int argc, const char * argv[] ) +{ + if ( argc == 1 || argv[1] == std::string( "--help" ) || argv[1] == std::string( "-h" ) ) + { + cout << + "Usage: " << Pathname::basename( argv[0] ) << " [CPEID]...\n" + "Check and print all supplied CPEIDs as FS, URI and WFN.\n" + "Afterwards compare them pairwise. \n" + "\n" + " (wfn:[part=\"a\",vendor=\"openSUSE\",product=\"libzypp\",version=\"14\\.17\\.3\"])\n" + " URI: cpe:/a:openSUSE:libzypp:14.17.3\n" + " FS: cpe:2.3:a:openSUSE:libzypp:14.17.3:*:*:*:*:*:*:*\n" + "\n"; + + return 0; + } + --argc, ++argv; + + + std::vector args; + args.reserve( argc ); + + for ( ; argc; --argc, ++argv ) + { + try { + CpeId cpe( argv[0] ); + cout << '[' << args.size() << "]-----------------------------------------------------------------------------" << endl; + cout << "arg: " << argv[0] << endl; + cout << " (" << cpe.asWfn() << ')' << endl; + cout << "URI: " << cpe.asUri() << endl; + cout << "FS: " << cpe<< endl; + args.push_back( cpe ); + } + catch ( const std::invalid_argument & exp ) + { + cout << "--------------------------------------------------------------------------------" << endl; + cout << "arg: " << argv[0] << endl; + cout << "ERR: " << exp.what() << endl; + } + } + + cout << "--------------------------------------------------------------------------------" << endl; + unsigned lhsidx = 0; + for ( const auto & lhs : args ) + { + unsigned rhsidx = 0; + for ( const auto & rhs : args ) + { + cout << "[" << lhsidx << "] " << lhs << endl; + cout << "[" << rhsidx << "] " << rhs << endl; + cout << " ==> " << compare( lhs, rhs ) << endl; + ++rhsidx; + } + ++lhsidx; + } + return 0; +} diff --git a/libzypp/zypp.conf b/libzypp/zypp.conf index 4abb5f2..dfe7f64 100644 --- a/libzypp/zypp.conf +++ b/libzypp/zypp.conf @@ -165,6 +165,18 @@ ## 0 means no limit (use with caution) # download.max_silent_tries = 5 +## +## Maximum time in seconds that you allow a transfer operation to take. +## +## This is useful for preventing your batch jobs from hanging for hours due +## to slow networks or links going down. Limiting operations to less than a +## few minutes risk aborting perfectly normal operations. +## +## Valid values: [0,3600] +## Default value: 180 +## +# download.transfer_timeout = 180 + ## ## Whether to consider using a .delta.rpm when downloading a package ## @@ -314,20 +326,10 @@ ## # solver.checkSystemFile = /etc/zypp/systemCheck -## -## This directory can contain files that contain requirements/conflicts -## which fulfill the needs of a running system (see checkSystemFile). -## -## Files are read in alphabetical order. -## -## Default value: {configdir}/systemCheck.d -## -# solver.checkSystemFileDir = /etc/zypp/systemCheck.d - ## ## When committing a dist upgrade (e.g. 'zypper dup') a solver testcase ## is written to /var/log/updateTestcase-. It is needed in bugreports. -## This optin returns the number of testcases to keep on the system. Old +## This option returns the number of testcases to keep on the system. Old ## cases will be deleted, as new ones are created. ## ## Use 0 to write no testcase at all, or -1 to keep all testcases. @@ -371,7 +373,7 @@ ## Default value: ## empty ## -# multiversion = provides:multiversion(kernel) +multiversion = provides:multiversion(kernel) ## ## Defining directory which may contain additional multiversion definitions. @@ -400,8 +402,11 @@ ## oldest - Keep kernel with the lowest version number (the GA kernel) ## oldest+N - Keep kernel with the Nth lowest version number ## +## Note: This entry is not evaluated by libzypp, but by the +## purge-kernels service (via /sbin/purge-kernels). +## ## Default: Do not delete any kernels if multiversion = provides:multiversion(kernel) is set -# multiversion.kernels = latest,running +multiversion.kernels = latest,latest-1,running ## ## Path to locks file. If not exist then is create. @@ -413,7 +418,7 @@ # locksfile.path = /etc/zypp/locks ## -## Whetever to apply locks in locks file after zypp start. +## Whether to apply locks in locks file after zypp start. ## ## Valid values: boolean ## Default value: true diff --git a/libzypp/zypp/Application.cc b/libzypp/zypp/Application.cc new file mode 100644 index 0000000..63251f1 --- /dev/null +++ b/libzypp/zypp/Application.cc @@ -0,0 +1,31 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/Application.cc + */ +#include + +//#include "zypp/base/LogTools.h" +#include "zypp/Application.h" + +using std::endl; + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + IMPL_PTR_TYPE( Application ); + + Application::Application( const sat::Solvable & solvable_r ) + : ResObject( solvable_r ) + {} + + Application::~Application() + {} + +} // namespace zypp +/////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/Application.h b/libzypp/zypp/Application.h new file mode 100644 index 0000000..77f25b7 --- /dev/null +++ b/libzypp/zypp/Application.h @@ -0,0 +1,48 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/Application.h + */ +#ifndef ZYPP_APPLICATION_H +#define ZYPP_APPLICATION_H + +#include + +#include "zypp/ResObject.h" + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + DEFINE_PTR_TYPE(Application); + + /////////////////////////////////////////////////////////////////// + /// \class Application + /// \brief Class representing an application (appdata.xml) + /////////////////////////////////////////////////////////////////// + class Application : public ResObject + { + public: + typedef Application Self; + typedef ResTraits TraitsType; + typedef TraitsType::PtrType Ptr; + typedef TraitsType::constPtrType constPtr; + + public: + // no attributes defined by now + + protected: + friend Ptr make( const sat::Solvable & solvable_r ); + /** Ctor */ + Application( const sat::Solvable & solvable_r ); + /** Dtor */ + virtual ~Application(); + }; + +} // namespace zypp +/////////////////////////////////////////////////////////////////// +#endif // ZYPP_APPLICATION_H diff --git a/libzypp/zypp/Arch.cc b/libzypp/zypp/Arch.cc index daf536e..37aea0e 100644 --- a/libzypp/zypp/Arch.cc +++ b/libzypp/zypp/Arch.cc @@ -82,7 +82,7 @@ namespace zypp break; } // This is a builtin: compatible if mentioned in targetEntry_r - return targetEntry_r._compatBits & _idBit; + return bool( targetEntry_r._compatBits & _idBit ); } /** compare by score, then archStr. */ @@ -137,75 +137,86 @@ ZYPP_DEFINE_ID_HASHABLE( zypp::Arch::CompatEntry ); namespace zypp { ///////////////////////////////////////////////////////////////// + // Builtin architecture STRING VALUES to be + // used in defCompatibleWith below! + // + // const IdString _foo( "foo" ); + // const Arch Arch_foo( _foo() ); + // + // NOTE: Builtin CLASS Arch CONSTANTS are defined below. + // You have to change them accordingly in Arch.h. + // + // NOTE: Thake care CompatBits::IntT is able to provide one + // bit for each architecture. + // + #define DEF_BUILTIN(A) \ + namespace { static inline const IdString & _##A () { static IdString __str(#A); return __str; } } \ + const Arch Arch_##A( _##A() ) + + DEF_BUILTIN( noarch ); + + DEF_BUILTIN( i386 ); + DEF_BUILTIN( i486 ); + DEF_BUILTIN( i586 ); + DEF_BUILTIN( i686 ); + DEF_BUILTIN( athlon ); + DEF_BUILTIN( x86_64 ); + + DEF_BUILTIN( pentium3 ); + DEF_BUILTIN( pentium4 ); + + DEF_BUILTIN( s390 ); + DEF_BUILTIN( s390x ); + + DEF_BUILTIN( ppc ); + DEF_BUILTIN( ppc64 ); + DEF_BUILTIN( ppc64p7 ); + + DEF_BUILTIN( ppc64le ); + + DEF_BUILTIN( ia64 ); + + DEF_BUILTIN( alphaev67 ); + DEF_BUILTIN( alphaev6 ); + DEF_BUILTIN( alphapca56 ); + DEF_BUILTIN( alphaev56 ); + DEF_BUILTIN( alphaev5 ); + DEF_BUILTIN( alpha ); + + DEF_BUILTIN( sparc64v ); + DEF_BUILTIN( sparcv9v ); + DEF_BUILTIN( sparc64 ); + DEF_BUILTIN( sparcv9 ); + DEF_BUILTIN( sparcv8 ); + DEF_BUILTIN( sparc ); + + DEF_BUILTIN( aarch64 ); + DEF_BUILTIN( armv7tnhl ); + DEF_BUILTIN( armv7thl ); + DEF_BUILTIN( armv7nhl ); + DEF_BUILTIN( armv7hl ); + DEF_BUILTIN( armv7l ); + DEF_BUILTIN( armv6hl ); + DEF_BUILTIN( armv6l ); + DEF_BUILTIN( armv5tejl ); + DEF_BUILTIN( armv5tel ); + DEF_BUILTIN( armv5l ); + DEF_BUILTIN( armv4tl ); + DEF_BUILTIN( armv4l ); + DEF_BUILTIN( armv3l ); + + DEF_BUILTIN( sh3 ); + + DEF_BUILTIN( sh4 ); + DEF_BUILTIN( sh4a ); + + DEF_BUILTIN(m68k); +#undef DEF_BUILTIN + /////////////////////////////////////////////////////////////////// namespace { ///////////////////////////////////////////////////////////////// - // Builtin architecture STRING VALUES to be - // used in defCompatibleWith below! - // - // const IdString _foo( "foo" ); - // - // NOTE: Builtin CLASS Arch CONSTANTS are defined below. - // You have to change them accordingly. - // - // NOTE: Thake care CompatBits::IntT is able to provide one - // bit for each architecture. - // -#define DEF_BUILTIN(A) static inline const IdString & _##A () { static IdString __str(#A); return __str; } - DEF_BUILTIN( noarch ); - - DEF_BUILTIN( i386 ); - DEF_BUILTIN( i486 ); - DEF_BUILTIN( i586 ); - DEF_BUILTIN( i686 ); - DEF_BUILTIN( athlon ); - DEF_BUILTIN( x86_64 ); - - DEF_BUILTIN( pentium3 ); - DEF_BUILTIN( pentium4 ); - - DEF_BUILTIN( s390 ); - DEF_BUILTIN( s390x ); - - DEF_BUILTIN( ppc ); - DEF_BUILTIN( ppc64 ); - - DEF_BUILTIN( ia64 ); - - DEF_BUILTIN( alphaev67 ); - DEF_BUILTIN( alphaev6 ); - DEF_BUILTIN( alphapca56 ); - DEF_BUILTIN( alphaev56 ); - DEF_BUILTIN( alphaev5 ); - DEF_BUILTIN( alpha ); - - DEF_BUILTIN( sparc64v ); - DEF_BUILTIN( sparcv9v ); - DEF_BUILTIN( sparc64 ); - DEF_BUILTIN( sparcv9 ); - DEF_BUILTIN( sparcv8 ); - DEF_BUILTIN( sparc ); - - DEF_BUILTIN( armv7tnhl ); - DEF_BUILTIN( armv7thl ); - DEF_BUILTIN( armv7nhl ); - DEF_BUILTIN( armv7hl ); - DEF_BUILTIN( armv7l ); - DEF_BUILTIN( armv6l ); - DEF_BUILTIN( armv5tejl ); - DEF_BUILTIN( armv5tel ); - DEF_BUILTIN( armv5l ); - DEF_BUILTIN( armv4tl ); - DEF_BUILTIN( armv4l ); - DEF_BUILTIN( armv3l ); - - DEF_BUILTIN( sh3 ); - - DEF_BUILTIN( sh4 ); - DEF_BUILTIN( sh4a ); -#undef DEF_BUILTIN - /////////////////////////////////////////////////////////////////// // // CLASS NAME : CompatSet @@ -297,6 +308,9 @@ namespace zypp // defCompatibleWith( _ppc(), _noarch() ); defCompatibleWith( _ppc64(), _noarch(),_ppc() ); + defCompatibleWith( _ppc64p7(), _noarch(),_ppc(),_ppc64() ); + // + defCompatibleWith( _ppc64le(), _noarch() ); // defCompatibleWith( _alpha(), _noarch() ); defCompatibleWith( _alphaev5(), _noarch(),_alpha() ); @@ -320,16 +334,20 @@ namespace zypp defCompatibleWith( _armv5tel(), _noarch(),_armv3l(),_armv4l(),_armv4tl(),_armv5l() ); defCompatibleWith( _armv5tejl(), _noarch(),_armv3l(),_armv4l(),_armv4tl(),_armv5l(),_armv5tel() ); defCompatibleWith( _armv6l(), _noarch(),_armv3l(),_armv4l(),_armv4tl(),_armv5l(),_armv5tel(),_armv5tejl() ); + defCompatibleWith( _armv6hl(), _noarch() ); defCompatibleWith( _armv7l(), _noarch(),_armv3l(),_armv4l(),_armv4tl(),_armv5l(),_armv5tel(),_armv5tejl(),_armv6l() ); - defCompatibleWith( _armv7hl(), _noarch() ); + defCompatibleWith( _armv7hl(), _noarch(),_armv6hl() ); defCompatibleWith( _armv7nhl(), _noarch(),_armv7hl() ); defCompatibleWith( _armv7thl(), _noarch(),_armv7hl() ); defCompatibleWith( _armv7tnhl(), _noarch(),_armv7hl(),_armv7nhl(),_armv7thl() ); + defCompatibleWith( _aarch64(), _noarch() ); // defCompatibleWith( _sh3(), _noarch() ); // defCompatibleWith( _sh4(), _noarch() ); defCompatibleWith( _sh4a(), _noarch(),_sh4() ); + + defCompatibleWith(_m68k(), _noarch()); // /////////////////////////////////////////////////////////////////// // dumpOn( USR ) << endl; @@ -396,57 +414,7 @@ namespace zypp /////////////////////////////////////////////////////////////////// const Arch Arch_empty ( IdString::Empty ); - const Arch Arch_noarch( _noarch() ); - - const Arch Arch_i386( _i386() ); - const Arch Arch_i486( _i486() ); - const Arch Arch_i586( _i586() ); - const Arch Arch_i686( _i686() ); - const Arch Arch_athlon( _athlon() ); - const Arch Arch_x86_64( _x86_64() ); - - const Arch Arch_pentium3( _pentium3() ); - const Arch Arch_pentium4( _pentium4() ); - - const Arch Arch_s390( _s390() ); - const Arch Arch_s390x( _s390x() ); - - const Arch Arch_ppc( _ppc() ); - const Arch Arch_ppc64( _ppc64() ); - - const Arch Arch_ia64( _ia64() ); - - const Arch Arch_alphaev67( _alphaev67() ); - const Arch Arch_alphaev6( _alphaev6() ); - const Arch Arch_alphapca56( _alphapca56() ); - const Arch Arch_alphaev56( _alphaev56() ); - const Arch Arch_alphaev5( _alphaev5() ); - const Arch Arch_alpha( _alpha() ); - - const Arch Arch_sparc64v( _sparc64v() ); - const Arch Arch_sparc64( _sparc64() ); - const Arch Arch_sparcv9v( _sparcv9v() ); - const Arch Arch_sparcv9( _sparcv9() ); - const Arch Arch_sparcv8( _sparcv8() ); - const Arch Arch_sparc( _sparc() ); - - const Arch Arch_armv7tnhl( _armv7tnhl() ); - const Arch Arch_armv7thl( _armv7thl() ); - const Arch Arch_armv7nhl ( _armv7nhl() ); - const Arch Arch_armv7hl ( _armv7hl() ); - const Arch Arch_armv7l( _armv7l() ); - const Arch Arch_armv6l( _armv6l() ); - const Arch Arch_armv5tejl( _armv5tejl() ); - const Arch Arch_armv5tel( _armv5tel() ); - const Arch Arch_armv5l( _armv5l() ); - const Arch Arch_armv4tl( _armv4tl() ); - const Arch Arch_armv4l( _armv4l() ); - const Arch Arch_armv3l( _armv3l() ); - - const Arch Arch_sh3( _sh3() ); - - const Arch Arch_sh4( _sh4() ); - const Arch Arch_sh4a( _sh4a() ); + // remaining Arch_* constants are defined by DEF_BUILTIN above. /////////////////////////////////////////////////////////////////// // diff --git a/libzypp/zypp/Arch.h b/libzypp/zypp/Arch.h index c55aca0..fb2a447 100644 --- a/libzypp/zypp/Arch.h +++ b/libzypp/zypp/Arch.h @@ -187,6 +187,11 @@ namespace zypp /** \relates Arch */ extern const Arch Arch_s390; + /** \relates Arch */ + extern const Arch Arch_ppc64le; + + /** \relates Arch */ + extern const Arch Arch_ppc64p7; /** \relates Arch */ extern const Arch Arch_ppc64; /** \relates Arch */ @@ -221,6 +226,8 @@ namespace zypp /** \relates Arch */ extern const Arch Arch_sparc; + /** \relates Arch */ + extern const Arch Arch_aarch64; /** \relates Arch */ extern const Arch Arch_armv7tnhl; /** \relates Arch */ @@ -232,6 +239,8 @@ namespace zypp /** \relates Arch */ extern const Arch Arch_armv7l; /** \relates Arch */ + extern const Arch Arch_armv6hl; + /** \relates Arch */ extern const Arch Arch_armv6l; /** \relates Arch */ extern const Arch Arch_armv5tejl; @@ -253,6 +262,9 @@ namespace zypp extern const Arch Arch_sh4; /** \relates Arch */ extern const Arch Arch_sh4a; + + /** \relates Arch */ + extern const Arch Arch_m68k; //@} /////////////////////////////////////////////////////////////////// @@ -261,6 +273,10 @@ namespace zypp inline std::ostream & operator<<( std::ostream & str, const Arch & obj ) { return str << obj.asString(); } + /** \relates Arch XML output. */ + inline std::ostream & dumpAsXmlOn( std::ostream & str, const Arch & obj ) + { return str << "" << obj << ""; } + /** \name Equality based on string value. */ //@{ /** \relates Arch */ diff --git a/libzypp/zypp/Bit.h b/libzypp/zypp/Bit.h index c12d0a1..a08a2b1 100644 --- a/libzypp/zypp/Bit.h +++ b/libzypp/zypp/Bit.h @@ -15,8 +15,6 @@ #include #include -#include "zypp/base/SafeBool.h" - /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -159,10 +157,7 @@ namespace zypp */ template class BitField : public Range<_IntT, 0, MaxBits<_IntT>::value> - , private base::SafeBool > { - typedef typename base::SafeBool >::bool_type bool_type; - public: /** Default ctor: zero. */ BitField() @@ -175,7 +170,8 @@ namespace zypp public: /** Validate in a boolean context. */ - using base::SafeBool >::operator bool_type; + explicit operator bool() const + { return _value != (_IntT)0; } public: /** Return the value. */ @@ -291,12 +287,6 @@ namespace zypp BitField operator~() const { return ~_value; } - private: - friend base::SafeBool >::operator bool_type() const; - /** \ref base::SafeBool test. */ - bool boolTest() const - { return _value; } - private: _IntT _value; }; diff --git a/libzypp/zypp/Bitmap.h b/libzypp/zypp/Bitmap.h new file mode 100644 index 0000000..3dddd1f --- /dev/null +++ b/libzypp/zypp/Bitmap.h @@ -0,0 +1,22 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/Bitmap.h + * +*/ +#ifndef ZYPP_BITMAP_H +#define ZYPP_BITMAP_H + +#include "zypp/sat/Map.h" +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + typedef sat::Map Bitmap; +} // namespace zypp +/////////////////////////////////////////////////////////////////// +#endif // ZYPP_BITMAP_H diff --git a/libzypp/zypp/CMakeLists.txt b/libzypp/zypp/CMakeLists.txt index cac4aee..9bd803d 100644 --- a/libzypp/zypp/CMakeLists.txt +++ b/libzypp/zypp/CMakeLists.txt @@ -8,16 +8,17 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) #FILE(WRITE filename "message to write"... ) SET( zypp_SRCS + Application.cc ByteCount.cc Capabilities.cc Capability.cc CapMatch.cc Changelog.cc CheckSum.cc + CpeId.cc Date.cc Dep.cc Digest.cc - DiskUsage.cc DiskUsageCounter.cc DownloadMode.cc Edition.cc @@ -90,9 +91,11 @@ SET( zypp_EARLY_SRCS SET( zypp_HEADERS APIConfig.h + Application.h Arch.h AutoDispose.h Bit.h + Bitmap.h ByteCount.h Callback.h Capabilities.h @@ -100,12 +103,13 @@ SET( zypp_HEADERS CapMatch.h Changelog.h CheckSum.h + ContentType.h CountryCode.h + CpeId.h Date.h Dep.h Digest.h DiskUsageCounter.h - DiskUsage.h DownloadMode.h Edition.h ExternalProgram.h @@ -176,6 +180,7 @@ SET( zypp_HEADERS TmpPath.h TriBool.h Url.h + UserData.h VendorAttr.h VendorSupportOptions.h ZConfig.h @@ -187,10 +192,11 @@ SET( zypp_HEADERS ZYpp.h ) -INSTALL( FILES ${zypp_HEADERS} DESTINATION "${CMAKE_INSTALL_PREFIX}/include/zypp" ) +INSTALL( FILES ${zypp_HEADERS} DESTINATION "${INCLUDE_INSTALL_DIR}/zypp" ) SET( zypp_base_SRCS base/InterProcessMutex.cc + base/Backtrace.cc base/SerialNumber.cc base/Random.cc base/Measure.cc @@ -200,6 +206,7 @@ SET( zypp_base_SRCS base/IOStream.cc base/InputStream.cc base/ReferenceCounted.cc + base/SetRelationMixin.cc base/String.cc base/StrMatcher.h base/StrMatcher.cc @@ -215,6 +222,7 @@ SET( zypp_base_SRCS SET( zypp_base_HEADERS base/InterProcessMutex.h + base/Backtrace.h base/Collector.h base/SerialNumber.h base/Easy.h @@ -227,6 +235,7 @@ SET( zypp_base_HEADERS base/DtorReset.h base/Exception.h base/UserRequestException.h + base/EnumClass.h base/ExternalDataSource.h base/Fd.h base/Flags.h @@ -237,16 +246,18 @@ SET( zypp_base_HEADERS base/IOStream.h base/InputStream.h base/Iterator.h + base/Json.h base/LogControl.h base/LogTools.h base/Logger.h base/Measure.h + base/NamedValue.h base/NonCopyable.h base/ProfilingFormater.h base/ProvideNumericId.h base/PtrTypes.h base/ReferenceCounted.h - base/SafeBool.h + base/SetRelationMixin.h base/Signal.h base/String.h base/StrMatcher.h @@ -255,11 +266,12 @@ SET( zypp_base_HEADERS base/Tr1hash.h base/Unit.h base/WatchFile.h + base/Xml.h ) INSTALL( FILES ${zypp_base_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/base + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/base ) SET( zypp_media_SRCS @@ -275,7 +287,6 @@ SET( zypp_media_SRCS media/ProxyInfo.cc media/MediaCurl.cc media/MediaMultiCurl.cc - media/MediaAria2c.cc media/MediaISO.cc media/MediaPlugin.cc media/MediaSource.cc @@ -298,7 +309,6 @@ SET( zypp_media_HEADERS media/MediaCIFS.h media/MediaCurl.h media/MediaMultiCurl.h - media/MediaAria2c.h media/MediaDIR.h media/MediaDISK.h media/MediaException.h @@ -324,7 +334,7 @@ SET( zypp_media_HEADERS INSTALL( FILES ${zypp_media_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/media + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/media ) IF ( LIBPROXY_FOUND ) @@ -346,7 +356,7 @@ SET( zypp_media_proxyinfo_HEADERS INSTALL( FILES ${zypp_media_proxyinfo_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/media/proxyinfo + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/media/proxyinfo ) SET( zypp_parser_SRCS @@ -374,7 +384,7 @@ SET( zypp_parser_HEADERS INSTALL( FILES ${zypp_parser_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/parser + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/parser ) SET( zypp_parser_susetags_SRCS @@ -389,20 +399,7 @@ SET( zypp_parser_susetags_HEADERS INSTALL( FILES ${zypp_parser_susetags_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/parser/susetags -) - -SET( zypp_parser_plaindir_SRCS - parser/plaindir/RepoParser.cc -) - -SET( zypp_parser_plaindir_HEADERS - parser/plaindir/RepoParser.h -) - -INSTALL( FILES - ${zypp_parser_plaindir_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/parser/plaindir + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/parser/susetags ) SET( zypp_parser_xml_SRCS @@ -431,7 +428,7 @@ SET( zypp_parser_xml_HEADERS INSTALL( FILES ${zypp_parser_xml_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/parser/xml + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/parser/xml ) SET( zypp_parser_yum_SRCS @@ -446,7 +443,7 @@ SET( zypp_parser_yum_HEADERS INSTALL( FILES ${zypp_parser_yum_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/parser/yum + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/parser/yum ) SET( zypp_parser_ws_SRCS @@ -459,18 +456,16 @@ SET( zypp_parser_ws_HEADERS INSTALL( FILES ${zypp_parser_ws_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/parser/ws + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/parser/ws ) SET( zypp_pool_SRCS - pool/GetResolvablesToInsDel.cc pool/PoolImpl.cc pool/PoolStats.cc ) SET( zypp_pool_HEADERS - pool/GetResolvablesToInsDel.h pool/PoolImpl.h pool/PoolStats.h pool/PoolTraits.h @@ -479,12 +474,11 @@ SET( zypp_pool_HEADERS INSTALL( FILES ${zypp_pool_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/pool + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/pool ) SET( zypp_solver_detail_SRCS solver/detail/Helper.cc - solver/detail/InstallOrder.cc solver/detail/ProblemSolutionIgnore.cc solver/detail/ProblemSolutionCombi.cc solver/detail/Resolver.cc @@ -502,7 +496,6 @@ SET( zypp_solver_detail_SRCS SET( zypp_solver_detail_HEADERS solver/detail/Helper.h - solver/detail/InstallOrder.h solver/detail/ProblemSolutionIgnore.h solver/detail/ProblemSolutionCombi.h solver/detail/Resolver.h @@ -521,7 +514,7 @@ SET( zypp_solver_detail_HEADERS INSTALL( FILES ${zypp_solver_detail_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/solver/detail + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/solver/detail ) SET( zypp_sat_SRCS @@ -531,6 +524,7 @@ SET( zypp_sat_SRCS sat/SolvIterMixin.cc sat/Map.cc sat/Queue.cc + sat/FileConflicts.cc sat/Transaction.cc sat/WhatProvides.cc sat/WhatObsoletes.cc @@ -546,6 +540,7 @@ SET( zypp_sat_HEADERS sat/SolvIterMixin.h sat/Map.h sat/Queue.h + sat/FileConflicts.h sat/Transaction.h sat/WhatProvides.h sat/WhatObsoletes.h @@ -557,7 +552,7 @@ SET( zypp_sat_HEADERS INSTALL( FILES ${zypp_sat_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/sat + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/sat ) SET( zypp_sat_detail_SRCS @@ -571,13 +566,14 @@ SET( zypp_sat_detail_HEADERS INSTALL( FILES ${zypp_sat_detail_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/sat/detail + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/sat/detail ) SET( zypp_target_SRCS + target/RpmPostTransCollector.cc target/RequestedLocalesFile.cc - target/SoftLocksFile.cc + target/SolvIdentFile.cc target/HardLocksFile.cc target/CommitPackageCache.cc target/CommitPackageCacheImpl.cc @@ -585,11 +581,14 @@ SET( zypp_target_SRCS target/TargetCallbackReceiver.cc target/TargetException.cc target/TargetImpl.cc + target/TargetImpl.commitFindFileConflicts.cc + ) SET( zypp_target_HEADERS + target/RpmPostTransCollector.h target/RequestedLocalesFile.h - target/SoftLocksFile.h + target/SolvIdentFile.h target/HardLocksFile.h target/CommitPackageCache.h target/CommitPackageCacheImpl.h @@ -601,7 +600,7 @@ SET( zypp_target_HEADERS INSTALL( FILES ${zypp_target_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/target + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/target ) IF(NOT UDEV_FOUND) @@ -627,7 +626,7 @@ SET( zypp_target_modalias_HEADERS INSTALL( FILES ${zypp_target_modalias_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/target/modalias + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/target/modalias ) SET( zypp_target_rpm_SRCS @@ -653,7 +652,7 @@ SET( zypp_target_rpm_HEADERS INSTALL( FILES ${zypp_target_rpm_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/target/rpm + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/target/rpm ) SET( zypp_thread_SRCS @@ -669,7 +668,7 @@ SET( zypp_thread_HEADERS INSTALL( FILES ${zypp_thread_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/thread + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/thread ) SET( zypp_ui_SRCS @@ -690,7 +689,7 @@ SET( zypp_ui_HEADERS INSTALL( FILES ${zypp_ui_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/ui + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/ui ) SET( zypp_url_SRCS @@ -706,7 +705,7 @@ SET( zypp_url_HEADERS INSTALL( FILES ${zypp_url_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/url + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/url ) SET( zypp_zypp_detail_SRCS @@ -720,7 +719,7 @@ SET( zypp_zypp_detail_HEADERS INSTALL( FILES ${zypp_zypp_detail_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/zypp_detail + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/zypp_detail ) SET( zypp_repo_SRCS @@ -759,14 +758,13 @@ SET( zypp_repo_HEADERS repo/Downloader.h repo/RepoVariables.h repo/RepoInfoBase.h - repo/RepoInfoBaseImpl.h repo/PluginServices.h repo/ServiceRepos.h ) INSTALL( FILES ${zypp_repo_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/repo + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/repo ) SET( zypp_repo_yum_SRCS @@ -810,7 +808,7 @@ SET( zypp_misc_SRCS INSTALL( FILES ${zypp_misc_HEADERS} - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/misc + DESTINATION ${INCLUDE_INSTALL_DIR}/zypp/misc ) #################################################################### @@ -821,7 +819,6 @@ ${zypp_pool_SRCS} ${zypp_parser_susetags_SRCS} ${zypp_parser_xml_SRCS} ${zypp_parser_yum_SRCS} -${zypp_parser_plaindir_SRCS} ${zypp_parser_ws_SRCS} ${zypp_parser_SRCS} ${zypp_media_proxyinfo_SRCS} @@ -852,7 +849,6 @@ ${zypp_target_rpm_HEADERS} ${zypp_parser_tagfile_HEADERS} ${zypp_parser_susetags_HEADERS} ${zypp_parser_yum_HEADERS} -${zypp_parser_plaindir_HEADERS} ${zypp_parser_xml_HEADERS} ${zypp_parser_ws_HEADERS} ${zypp_parser_HEADERS} @@ -920,14 +916,13 @@ ADD_LIBRARY(zypp SHARED ${zypp_lib_SRCS}) SET_TARGET_PROPERTIES( zypp PROPERTIES VERSION "${LIBZYPP_VERSION_INFO}" ) SET_TARGET_PROPERTIES( zypp PROPERTIES SOVERSION "${LIBZYPP_SOVERSION_INFO}" ) SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libzypp.map") -ADD_DEPENDENCIES(zypp schema_header) # System libraries SET(UTIL_LIBRARY util) TARGET_LINK_LIBRARIES(zypp ${UTIL_LIBRARY} ) TARGET_LINK_LIBRARIES(zypp ${RPM_LIBRARY} ) TARGET_LINK_LIBRARIES(zypp ${GETTEXT_LIBRARIES} ) -TARGET_LINK_LIBRARIES(zypp ${CURL_LIBRARY} ) -TARGET_LINK_LIBRARIES(zypp ${LIBXML_LIBRARY} ) +TARGET_LINK_LIBRARIES(zypp ${CURL_LIBRARIES} ) +TARGET_LINK_LIBRARIES(zypp ${LIBXML2_LIBRARIES} ) TARGET_LINK_LIBRARIES(zypp ${ZLIB_LIBRARY} ) TARGET_LINK_LIBRARIES(zypp ${LibSolv_LIBRARIES} ${EXPAT_LIBRARY}) TARGET_LINK_LIBRARIES(zypp ${OPENSSL_LIBRARIES} ) diff --git a/libzypp/zypp/Callback.h b/libzypp/zypp/Callback.h index b3eb516..54cf219 100644 --- a/libzypp/zypp/Callback.h +++ b/libzypp/zypp/Callback.h @@ -120,12 +120,16 @@ namespace zypp * a Callback light). * \li \c disconnect Disconnect this ReceiveReport in case it is * connected. If not connected nothing happens. - * \li \c connected Test wheter this ReceiveReport is currently + * \li \c connected Test whether this ReceiveReport is currently * connected. * \li \c whoIsConnected Return a 'ReceiveReport*' to the currently * connected ReceiveReport, or \c NULL if none is connected. * - */ + * \par Passing Userdata via Callbacks + * + * For typesafe passing of user data via callbacks \see \ref UserData. + * + */ namespace callback { ///////////////////////////////////////////////////////////////// @@ -222,6 +226,12 @@ namespace zypp ~SendReport() { Distributor::instance()->reportend(); } + static Receiver * whoIsConnected() + { return Distributor::instance().getReceiver(); } + + static bool connected() + { return whoIsConnected(); } + Distributor & operator->() { return Distributor::instance(); } }; diff --git a/libzypp/zypp/Capability.cc b/libzypp/zypp/Capability.cc index 271bd7f..dc75eaa 100644 --- a/libzypp/zypp/Capability.cc +++ b/libzypp/zypp/Capability.cc @@ -360,7 +360,7 @@ namespace zypp static str::smatch what; static const str::regex filenameRegex( "/(s?bin|lib(64)?|etc)/|^/usr/(games/|share/(dict/words|magic\\.mime)$)|^/opt/gnome/games/", - str::regex::optimize|str::regex::nosubs ); + str::regex::nosubs ); return str::regex_match( name_r, what, filenameRegex ); } diff --git a/libzypp/zypp/Capability.h b/libzypp/zypp/Capability.h index 9995fd6..c17b89f 100644 --- a/libzypp/zypp/Capability.h +++ b/libzypp/zypp/Capability.h @@ -14,9 +14,7 @@ #include -#include "zypp/base/SafeBool.h" #include "zypp/APIConfig.h" - #include "zypp/sat/detail/PoolMember.h" #include "zypp/IdString.h" @@ -58,8 +56,7 @@ namespace zypp * Capability( "package:foo", ResKind::pattern ) ==> 'foo' * \endcode */ - class Capability: protected sat::detail::PoolMember, - private base::SafeBool + class Capability: protected sat::detail::PoolMember { public: enum CtorFlag { PARSED, UNPARSED }; @@ -134,10 +131,10 @@ namespace zypp static const Capability Empty; public: -#ifndef SWIG // Swig treats it as syntax error /** Evaluate in a boolean context ( ! empty() ). */ - using base::SafeBool::operator bool_type; -#endif + explicit operator bool() const + { return ! empty(); } + /** Whether the \ref Capability is empty. * This is true for \ref Null and \ref Empty. */ @@ -250,11 +247,6 @@ namespace zypp /** Match two Capabilities */ static CapMatch _doMatch( sat::detail::IdType lhs, sat::detail::IdType rhs ); private: -#ifndef SWIG // Swig treats it as syntax error - friend base::SafeBool::operator bool_type() const; -#endif - bool boolTest() const { return ! empty(); } - private: sat::detail::IdType _id; }; /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/CheckSum.cc b/libzypp/zypp/CheckSum.cc index e491331..bd94b2d 100644 --- a/libzypp/zypp/CheckSum.cc +++ b/libzypp/zypp/CheckSum.cc @@ -38,14 +38,6 @@ namespace zypp { static std::string _type( "sha256" ); return _type; } - CheckSum::CheckSum() - {} - - CheckSum::CheckSum( const std::string & checksum ) - { - *this = CheckSum( std::string(), checksum ); - } - CheckSum::CheckSum( const std::string & type, const std::string & checksum ) : _type( str::toLower( type ) ) , _checksum( checksum ) @@ -154,6 +146,19 @@ namespace zypp return str << ( obj.type().empty() ? std::string("UNKNOWN") : obj.type() ) << '-' << obj.checksum(); } + std::ostream & dumpAsXmlOn( std::ostream & str, const CheckSum & obj ) + { + const std::string & type( obj.type() ); + const std::string & checksum( obj.checksum() ); + str << ""; + else + str << ">" << checksum << ""; + return str; + } + /** \relates CheckSum */ bool operator==( const CheckSum & lhs, const CheckSum & rhs ) { return lhs.checksum() == rhs.checksum() && lhs.type() == rhs.type(); } diff --git a/libzypp/zypp/CheckSum.h b/libzypp/zypp/CheckSum.h index 0a6f553..ed539d4 100644 --- a/libzypp/zypp/CheckSum.h +++ b/libzypp/zypp/CheckSum.h @@ -14,6 +14,7 @@ #include #include +#include #include "zypp/base/Exception.h" #include "zypp/Pathname.h" @@ -33,45 +34,68 @@ namespace zypp { public: /** Default Ctor: empty checksum. */ - CheckSum(); + CheckSum() + {} /** - * Creates a checksum auto probing the algorithm type. + * Creates a checksum for algorithm \param type. * \throws CheckSumException if the checksum is invalid and can't be constructed */ - CheckSum( const std::string & checksum ); + CheckSum( const std::string & type, const std::string & checksum ); /** - * Creates a checksum for algorithm \param type. + * Creates a checksum auto probing the algorithm type. * \throws CheckSumException if the checksum is invalid and can't be constructed */ - CheckSum( const std::string & type, const std::string & checksum ); + CheckSum( const std::string & checksum ) + : CheckSum( std::string(), checksum ) + {} + /** * Reads the content of \param input_r and computes the checksum. */ CheckSum( const std::string & type, std::istream & input_r ); +#ifndef SWIG // Swig treats it as syntax error0 + /** Ctor from temporary istream */ + CheckSum( const std::string & type, std::istream && input_r ) + : CheckSum( type, input_r ) + {} +#endif + public: static const std::string & md5Type(); static const std::string & shaType(); static const std::string & sha1Type(); static const std::string & sha256Type(); - static CheckSum md5( const std::string & checksum ) - { return CheckSum( md5Type(), checksum); } - static CheckSum sha( const std::string & checksum ) - { return CheckSum( shaType(), checksum); } - static CheckSum sha1( const std::string & checksum ) - { return CheckSum( sha1Type(), checksum); } - static CheckSum sha256( const std::string & checksum ) - { return CheckSum( sha256Type(), checksum); } - - static CheckSum md5( std::istream & input_r ) - { return CheckSum( md5Type(), input_r ); } - static CheckSum sha( std::istream & input_r ) - { return CheckSum( sha1Type(), input_r ); } - static CheckSum sha1( std::istream & input_r ) - { return CheckSum( sha1Type(), input_r ); } - static CheckSum sha256( std::istream & input_r ) - { return CheckSum( sha256Type(), input_r ); } + /** \name Creates a checksum for algorithm \param type. */ + //@{ + static CheckSum md5( const std::string & checksum ) { return CheckSum( md5Type(), checksum); } + static CheckSum sha( const std::string & checksum ) { return CheckSum( shaType(), checksum); } + static CheckSum sha1( const std::string & checksum ) { return CheckSum( sha1Type(), checksum); } + static CheckSum sha256( const std::string & checksum ) { return CheckSum( sha256Type(), checksum); } + //@} + + /** \name Reads the content of \param input_r and computes the checksum. */ + //@{ + static CheckSum md5( std::istream & input_r ) { return CheckSum( md5Type(), input_r ); } + static CheckSum sha( std::istream & input_r ) { return CheckSum( sha1Type(), input_r ); } + static CheckSum sha1( std::istream & input_r ) { return CheckSum( sha1Type(), input_r ); } + static CheckSum sha256( std::istream & input_r ) { return CheckSum( sha256Type(), input_r ); } +#ifndef SWIG // Swig treats it as syntax error + static CheckSum md5( std::istream && input_r ) { return CheckSum( md5Type(), input_r ); } + static CheckSum sha( std::istream && input_r ) { return CheckSum( sha1Type(), input_r ); } + static CheckSum sha1( std::istream && input_r ) { return CheckSum( sha1Type(), input_r ); } + static CheckSum sha256( std::istream && input_r ) { return CheckSum( sha256Type(), input_r ); } +#endif + //@} + + /** \name Reads the content of \param input_r and computes the checksum. */ + //@{ + static CheckSum md5FromString( const std::string & input_r ) { return md5( std::stringstream( input_r ) ); } + static CheckSum shaFromString( const std::string & input_r ) { return sha( std::stringstream( input_r ) ); } + static CheckSum sha1FromString( const std::string & input_r ) { return sha1( std::stringstream( input_r ) ); } + static CheckSum sha256FromString( const std::string & input_r ) { return sha256( std::stringstream( input_r ) ); } + //@} public: std::string type() const; @@ -89,6 +113,9 @@ namespace zypp /** \relates CheckSum Stream output. */ std::ostream & operator<<( std::ostream & str, const CheckSum & obj ); + /** \relates CheckSum XML output. */ + std::ostream & dumpAsXmlOn( std::ostream & str, const CheckSum & obj ); + /** \relates CheckSum */ bool operator==( const CheckSum & lhs, const CheckSum & rhs ); diff --git a/libzypp/zypp/ContentType.h b/libzypp/zypp/ContentType.h new file mode 100644 index 0000000..4254d06 --- /dev/null +++ b/libzypp/zypp/ContentType.h @@ -0,0 +1,145 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/ContentType.h + */ +#ifndef ZYPP_CONTENTTYPE_H +#define ZYPP_CONTENTTYPE_H + +#include +#include +#include + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + /////////////////////////////////////////////////////////////////// + /// \class ContentType + /// \brief Mime type like \c 'type/subtype' classification of content + /// + /// Used e.g. in \ref callback::UserData to describe the kind of + /// user data passed as \c void* to a callback. Neither type nor + /// subtype may contain a '/'. + /////////////////////////////////////////////////////////////////// + class ContentType + { + public: + /** Default ctor: empty */ + ContentType() + {} + + /** Ctor taking "type[/subtype]" + * \throws std::invalid_argument if string is malformed + */ + explicit ContentType( const std::string & type_r ) + { + std::string::size_type pos = type_r.find( "/" ); + if ( pos == std::string::npos ) + { + testAndSet( _type, type_r ); + } + else + { + testAndSet( _type, type_r.substr( 0, pos ) ); + testAndSet( _subtype, type_r.substr( pos+1 ) ); + } + } + + /** Ctor taking type and subtype + * \throws std::invalid_argument if string is malformed + */ + ContentType( const std::string & type_r, const std::string & subtype_r ) + { + testAndSet( _type, type_r ); + testAndSet( _subtype, subtype_r ); + } + + public: + /** Get type */ + const std::string & type() const + { return _type; } + + /** Set type + * \throws std::invalid_argument if string is malformed + */ + void type( const std::string & type_r ) + { _type = type_r; } + + /** Get subtype */ + const std::string & subtype() const + { return _subtype; } + + /** Set subtype + * \throws std::invalid_argument if string is malformed + */ + void subtype( const std::string & subtype_r ) + { _subtype = subtype_r; } + + public: + /** Whether type and subtype are empty */ + bool empty() const + { return emptyType() && emptySubtype(); } + /** Whether type is empty */ + bool emptyType() const + { return _type.empty(); } + /** Whether subtype is empty */ + bool emptySubtype() const + { return _subtype.empty(); } + + /** Validate object in a boolean context: !empty */ + explicit operator bool () const + { return !empty(); } + + /** String representation "type[/subtype]" */ + std::string asString() const + { std::string ret( type() ); if ( ! emptySubtype() ) { ret += "/"; ret += subtype(); } return ret; } + + private: + void testAndSet( std::string & var_r, const std::string & val_r ) + { + if ( val_r.find_first_of( "/ \t\r\n" ) != std::string::npos ) + throw std::invalid_argument( "ContentType: illegal char in '" + val_r + "'" ); + var_r = val_r; + } + private: + std::string _type; + std::string _subtype; + }; + + /** \relates ContentType Stream output */ + inline std::ostream & operator<<( std::ostream & str, const ContentType & obj ) + { return str << obj.asString(); } + + /** \relates ContentType */ + inline bool operator==( const ContentType & lhs, const ContentType & rhs ) + { return lhs.type() == rhs.type() && lhs.subtype() == rhs.subtype(); } + + /** \relates ContentType */ + inline bool operator!=( const ContentType & lhs, const ContentType & rhs ) + { return !( lhs == rhs ); } + + /** \relates ContentType */ + inline bool operator<( const ContentType & lhs, const ContentType & rhs ) + { int cmp = lhs.type().compare( rhs.type() ); return cmp < 0 || ( cmp == 0 && lhs.subtype() < rhs.subtype() ); } + + /** \relates ContentType */ + inline bool operator<=( const ContentType & lhs, const ContentType & rhs ) + { return lhs < rhs || lhs == rhs; } + + /** \relates ContentType */ + inline bool operator>( const ContentType & lhs, const ContentType & rhs ) + { return !( lhs <= rhs ); } + + /** \relates ContentType */ + inline bool operator>=( const ContentType & lhs, const ContentType & rhs ) + { return !( lhs < rhs ); } + + +} // namespace zypp +/////////////////////////////////////////////////////////////////// +#endif // ZYPP_CONTENTTYPE_H diff --git a/libzypp/zypp/CpeId.cc b/libzypp/zypp/CpeId.cc new file mode 100644 index 0000000..776b8c5 --- /dev/null +++ b/libzypp/zypp/CpeId.cc @@ -0,0 +1,1051 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/CpeId.cc + */ +#include +#include + +#include "zypp/base/String.h" +#include "zypp/base/LogTools.h" +#include "zypp/base/NonCopyable.h" + +#include "zypp/CpeId.h" + +using std::endl; + +/** Initializer list with all wfn attributes */ +#define WFN_ATTRIBUTES {\ + Attribute::part, \ + Attribute::vendor, \ + Attribute::product, \ + Attribute::version, \ + Attribute::update, \ + Attribute::edition, \ + Attribute::language, \ + Attribute::sw_edition,\ + Attribute::target_sw, \ + Attribute::target_hw, \ + Attribute::other, \ +} + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + /////////////////////////////////////////////////////////////////// + namespace + { + /** Hex-digit to number or -1. */ + inline int heDecodeCh( char ch ) + { + if ( '0' <= ch && ch <= '9' ) + return( ch - '0' ); + if ( 'A' <= ch && ch <= 'F' ) + return( ch - 'A' + 10 ); + if ( 'a' <= ch && ch <= 'f' ) + return( ch - 'a' + 10 ); + return -1; + } + + /** Printable non whitespace in [0x00,0x7f] valid in WFN */ + inline bool chIsValidRange( char ch ) + { return( '!' <= ch && ch <= '~' ); } + + /** Alpha */ + inline bool chIsAlpha( char ch ) + { return( ( 'a' <= ch && ch <= 'z' ) || ( 'A' <= ch && ch <= 'Z' ) ); } + + /** Digit */ + inline bool chIsNum( char ch ) + { return( '0' <= ch && ch <= '9' ); } + + /** Alphanum */ + inline bool chIsAlNum( char ch ) + { return( chIsAlpha( ch ) || chIsNum( ch ) ); } + + /** Alphanum or \c underscore are unescaped in WFN */ + inline bool chIsWfnUnescaped( char ch ) + { return( chIsAlNum( ch ) || ch == '_' ); } + + } // namespace + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + /// \class CpeId::Impl + /// \brief CpeId implementation. + /////////////////////////////////////////////////////////////////// + class CpeId::Impl : private base::NonCopyable + { + typedef std::array Wfn; + + public: + Impl() {} + + Impl( const std::string & cpe_r ) + : _wfn( unbind( cpe_r ) ) + {} + + public: + explicit operator bool() const + { for ( const auto & val : _wfn ) if ( ! val.isANY() ) return true; return false; } + + std::string asFs() const + { + str::Str ret; + ret << "cpe:2.3"; + for ( auto ai : WFN_ATTRIBUTES ) + { + ret << ':' << _wfn[ai].asFs(); + } + return ret; + } + + std::string asUri() const + { + str::Str ret; + ret << "cpe:/"; + std::string val; + unsigned colon = 0; // to remember trailing colons + for ( auto ai : WFN_ATTRIBUTES ) + { + val = _wfn[ai].asUri(); + + if ( ai == Attribute::edition ) + { + if ( ! ( _wfn[Attribute::sw_edition].isANY() + && _wfn[Attribute::target_sw].isANY() + && _wfn[Attribute::target_hw].isANY() + && _wfn[Attribute::other].isANY() ) ) + { + // packing is needed + val = str::Str() + << '~' << val//Attribute::edition + << '~' << _wfn[Attribute::sw_edition].asUri() + << '~' << _wfn[Attribute::target_sw].asUri() + << '~' << _wfn[Attribute::target_hw].asUri() + << '~' << _wfn[Attribute::other].asUri(); + } + } + + if ( ! val.empty() ) + { + if ( colon ) + ret << std::string( colon, ':' ); + ret << val; + colon = 1; + } + else + ++colon; + + if ( ai == Attribute::language ) + break; // remaining attrs packaed in edition + } + return ret; + } + + std::string asWfn() const + { + str::Str ret; + ret << "wfn:["; + for ( auto ai : WFN_ATTRIBUTES ) + { + const Value & val( _wfn[ai] ); + if ( ! val.isANY() ) + { + if ( ai ) ret << ','; + ret << Attribute::asString( ai ) << '='; + if ( val.isString() ) + ret << '"' << val << '"'; + else + ret << "NA"; // as ANY is omitted, it must be NA + } + } + return ret << "]"; + } + + public: + SetCompare setRelationMixinCompare( const Impl & trg ) const + { + SetCompare ret = SetCompare::equal; + for ( auto ai : WFN_ATTRIBUTES ) + { + switch ( _wfn[ai].compare( trg._wfn[ai] ).asEnum() ) + { + case SetCompare::uncomparable: + ret = SetCompare::uncomparable; + break; + + case SetCompare::equal: + break; + + case SetCompare::properSubset: + if ( ret == SetCompare::equal ) + ret = SetCompare::properSubset; + else if ( ret != SetCompare::properSubset ) + ret = SetCompare::uncomparable; + break; + + case SetCompare::properSuperset: + if ( ret == SetCompare::equal ) + ret = SetCompare::properSuperset; + else if ( ret != SetCompare::properSuperset ) + ret = SetCompare::uncomparable; + break; + + case SetCompare::disjoint: + ret = SetCompare::disjoint; + break; + } + if ( ret == SetCompare::uncomparable || ret == SetCompare::disjoint ) + break; + } + return ret; + } + + private: + /** Assign \a val_r if it meets \a attr_r specific contraints. + * \throws std::invalid_argument if string is malformed + */ + static void assignAttr( Wfn & wfn_r, Attribute attr_r, const Value & val_r ) + { + if ( val_r.isString() ) + { + switch ( attr_r.asEnum() ) + { + case Attribute::part: + { + const std::string & wfn( val_r.asWfn() ); + switch ( wfn[0] ) + { + case 'h': + case 'o': + case 'a': + if ( wfn[1] == '\0' ) + break; + // else: fallthrough + default: + throw std::invalid_argument( str::Str() << "CpeId:Wfn:part: '" << wfn << "' illegal value; expected: 'h' | 'o' | 'a'" ); + break; + } + } + break; + + case Attribute::language: + { + const std::string & wfn( val_r.asWfn() ); + std::string::size_type len = 0; + // (2*3ALPHA) ["-" (2ALPHA / 3DIGIT)] + if ( chIsAlpha( wfn[0] ) && chIsAlpha( wfn[1] ) ) + { + len = chIsAlpha( wfn[2] ) ? 3 : 2; + if ( wfn[len] == '-' ) + { + if ( chIsAlpha( wfn[len+1] ) && chIsAlpha( wfn[len+2] ) ) + len += 3; + else if ( chIsNum( wfn[len+1] ) && chIsNum( wfn[len+2] ) && chIsNum( wfn[len+3] ) ) + len += 4; + } + } + if ( wfn.size() != len ) + throw std::invalid_argument( str::Str() << "CpeId:Wfn:language: '" << wfn << "' illegal value; expected RFC5646 conform: language ['-' region]" ); + } + break; + + default: + // no contraints + break; + } + } + wfn_r[attr_r.asIntegral()] = val_r; + } + + private: + /** Parse magic and unbind accordingly + * \throws std::invalid_argument if string is malformed + */ + static Wfn unbind( const std::string & cpe_r ); + + /** Parse Uri and unbind + * \throws std::invalid_argument if string is malformed + */ + static Wfn unbindUri( const std::string & cpe_r ); + + /** Parse Fs and unbind + * \throws std::invalid_argument if string is malformed + */ + static Wfn unbindFs( const std::string & cpe_r ); + + private: + Wfn _wfn; + }; + + CpeId::Impl::Wfn CpeId::Impl::unbind( const std::string & cpe_r ) + { + Wfn ret; + if ( cpe_r[0] == 'c' + && cpe_r[1] == 'p' + && cpe_r[2] == 'e' + && cpe_r[3] == ':' ) + { + if ( cpe_r[4] == '/' ) + { + ret = unbindUri( cpe_r ); + } + else if ( cpe_r[4] == '2' + && cpe_r[5] == '.' + && cpe_r[6] == '3' + && cpe_r[7] == ':' ) + { + ret = unbindFs( cpe_r ); + } + else + throw std::invalid_argument( "CpeId: bad magic; expected: 'cpe:2.3:' | 'cpe:/'" ); + } + else if ( cpe_r[0] != '\0' ) + throw std::invalid_argument( "CpeId: bad magic; expected: 'cpe:2.3:' | 'cpe:/'" ); + return ret; + } + + CpeId::Impl::Wfn CpeId::Impl::unbindUri( const std::string & cpe_r ) + { + Wfn ret; + + static constexpr unsigned numUriAttr = 7u; // basic URI attibutes + std::vector field; + field.reserve( Attribute::numAttributes ); // reserve 7 + 4 for packed extened attrs in edition + if ( str::splitFields( cpe_r.c_str()+5/* skip magic 'cpe:/' */, std::back_inserter(field), ":" ) > numUriAttr ) + throw std::invalid_argument( str::Str() << "CpeId:Uri: too many fields (" << field.size() << "); expected " << numUriAttr ); + field.resize( Attribute::numAttributes ); // fillup with ANY(""), + + for ( auto ai : WFN_ATTRIBUTES ) + { + if ( ai == Attribute::edition && field[ai][0] == '~' ) + { + // unpacking is needed + static constexpr unsigned numPacks = 6u; // dummy_before_~ + edition + 4 extended attributes + std::vector pack; + pack.reserve( numPacks ); + if ( str::splitFields( field[ai], std::back_inserter(pack), "~" ) > numPacks ) + throw std::invalid_argument( str::Str() << "CpeId:Uri:edition: too many packs (" << pack.size() << "); expected " << numPacks ); + pack.resize( numPacks ); // fillup with ANY(""), should be noOP + + pack[1].swap( field[Attribute::edition] ); + pack[2].swap( field[Attribute::sw_edition] ); + pack[3].swap( field[Attribute::target_sw] ); + pack[4].swap( field[Attribute::target_hw] ); + pack[5].swap( field[Attribute::other] ); + } + assignAttr( ret, ai, Value( field[ai], Value::uriFormat ) ); + } + return ret; + } + + CpeId::Impl::Wfn CpeId::Impl::unbindFs( const std::string & cpe_r ) + { + Wfn ret; + + std::vector field; + field.reserve( Attribute::numAttributes ); + if ( str::splitFields( cpe_r.c_str()+8/* skip magic 'cpe:2.3:' */, std::back_inserter(field), ":" ) > Attribute::numAttributes ) + throw std::invalid_argument( str::Str() << "CpeId:Fs: too many fields (" << field.size() << "); expected 11" /*<< Attribute::numAttributes but g++ currently can't resoolve this as constexpr*/ ); + if ( !field.empty() && field.back().empty() ) // A trailing ':' leads to an empty (illegal) field, but we fillup missing fields with ANY|"*" + field.back() = "*"; + field.resize( Attribute::numAttributes, "*" ); // fillup with ANY|"*" + + for ( auto ai : WFN_ATTRIBUTES ) + { + assignAttr( ret, ai, Value( field[ai], Value::fsFormat ) ); + } + return ret; + } + + + /////////////////////////////////////////////////////////////////// + // class CpeId + /////////////////////////////////////////////////////////////////// + + std::string CpeId::NoThrowType::lastMalformed; + + CpeId::CpeId() + : _pimpl( new Impl ) + {} + + CpeId::CpeId( const std::string & cpe_r ) + : _pimpl( new Impl( cpe_r ) ) + {} + + CpeId::CpeId( const std::string & cpe_r, NoThrowType ) + { + try + { + _pimpl.reset( new Impl( cpe_r ) ); + NoThrowType::lastMalformed.clear(); + } + catch(...) + { + _pimpl.reset( new Impl ); + NoThrowType::lastMalformed = cpe_r; + } + } + + CpeId::~CpeId() + {} + + CpeId::operator bool() const + { return bool(*_pimpl); } + + std::string CpeId::asFs() const + { return _pimpl->asFs(); } + + std::string CpeId::asUri() const + { return _pimpl->asUri(); } + + std::string CpeId::asWfn() const + { return _pimpl->asWfn(); } + + SetCompare CpeId::setRelationMixinCompare( const CpeId & trg ) const + { return _pimpl->setRelationMixinCompare( *trg._pimpl ); } + + /////////////////////////////////////////////////////////////////// + // class CpeId::WfnAttribute + /////////////////////////////////////////////////////////////////// + + const std::string & CpeId::_AttributeDef::asString( Enum val_r ) + { + static std::map _table = { +#define OUTS(N) { N, #N } + OUTS( part ), + OUTS( vendor ), + OUTS( product ), + OUTS( version ), + OUTS( update ), + OUTS( edition ), + OUTS( language ), + OUTS( sw_edition ), + OUTS( target_sw ), + OUTS( target_hw ), + OUTS( other ), +#undef OUTS + }; + return _table[val_r]; + } + + /////////////////////////////////////////////////////////////////// + // class CpeId::Value + /////////////////////////////////////////////////////////////////// + + const CpeId::Value CpeId::Value::ANY; + const CpeId::Value CpeId::Value::NA( "" ); + + CpeId::Value::Value( const std::string & value_r ) + { + if ( value_r.empty() ) // NA + { + if ( ! CpeId::Value::NA._value ) // initialized by this ctor! + _value.reset( new std::string ); + else + _value = CpeId::Value::NA._value; + } + else if ( value_r != "*" ) // ANY is default constructed + { + bool starting = true; // false after the 1st non-? + for_( chp, value_r.begin(), value_r.end() ) + { + switch ( *chp ) + { + case '\\': // quoted + ++chp; + if ( ! chIsValidRange( *chp ) ) + { + if ( *chp ) + throw std::invalid_argument( str::Str() << "CpeId:Wfn: illegal quoted character '\\" << reinterpret_cast(*chp) << "'" ); + else + throw std::invalid_argument( "CpeId:Wfn: Backslash escapes nothing" ); + } + else if ( chIsWfnUnescaped( *chp ) ) + throw std::invalid_argument( str::Str() << "CpeId:Wfn: unnecessarily quoted character '\\" << *chp << "'" ); + else if ( starting && *chp == '-' && chp+1 == value_r.end() ) + throw std::invalid_argument( str::Str() << "CpeId:Wfn: '\\-' is illegal value" ); + break; + + case '?': // sequence at beginning or end of string + while ( *(chp+1) == '?' ) + ++chp; + if ( ! ( starting || chp+1 == value_r.end() ) ) + throw std::invalid_argument( "CpeId:Wfn: embedded ?" ); + break; + + case '*': // single at beginning or end of string + if ( ! ( starting || chp+1 == value_r.end() ) ) + throw std::invalid_argument( "CpeId:Wfn: embedded *" ); + break; + + default: // everything else unquoted + if ( ! chIsWfnUnescaped( *chp ) ) + { + if ( chIsValidRange( *chp ) ) + throw std::invalid_argument( str::Str() << "CpeId:Wfn: missing quote before '" << *chp << "'" ); + else + throw std::invalid_argument( str::Str() << "CpeId:Wfn: illegal character '" << reinterpret_cast(*chp) << "'" ); + } + break; + } + if ( starting ) + starting = false; + } + _value.reset( new std::string( value_r ) ); + } + } + + CpeId::Value::Value( const std::string & encoded_r, FsFormatType ) + { + if ( encoded_r != "*" ) // ANY is default constructed + { + if ( encoded_r == "-" ) // NA + { + _value = CpeId::Value::NA._value; + } + else + { + str::Str result; + bool starting = true; // false after the 1st non-? + for_( chp, encoded_r.begin(), encoded_r.end() ) + { + switch ( *chp ) + { + case '\\': // may stay quoted + ++chp; + if ( chIsWfnUnescaped( *chp ) ) + result << *chp; + else if ( chIsValidRange( *chp ) ) + result << '\\' << *chp; + else if ( *chp ) + throw std::invalid_argument( str::Str() << "CpeId:Fs: illegal quoted character '\\" << *chp << "'" ); + else + throw std::invalid_argument( "CpeId:Fs: Backslash escapes nothing" ); + break; + + case '?': // sequence at beginning or end of string + result << '?'; + while ( *(chp+1) == '?' ) + { + ++chp; + result << '?'; + } + if ( ! ( starting || chp+1 == encoded_r.end() ) ) + throw std::invalid_argument( "CpeId:Fs: embedded ?" ); + break; + + case '*': // single at beginning or end of string + if ( starting || chp+1 == encoded_r.end() ) + result << '*'; + else + throw std::invalid_argument( "CpeId:Fs: embedded *" ); + break; + + default: + if ( chIsWfnUnescaped( *chp ) ) + result << *chp; + else if ( chIsValidRange( *chp ) ) + result << '\\' << *chp; + else + throw std::invalid_argument( str::Str() << "CpeId:Fs: illegal character '" << reinterpret_cast(*chp) << "'" ); + break; + } + if ( starting ) + starting = false; + } + if ( starting ) + throw std::invalid_argument( "CpeId:Fs: '' value is illegal" ); + _value.reset( new std::string( result ) ); + } + } + } + + CpeId::Value::Value( const std::string & encoded_r, UriFormatType ) + { + if ( ! encoded_r.empty() ) // ANY is default constructed + { + if ( encoded_r == "-" ) // NA + { + _value = CpeId::Value::NA._value; + } + else + { + str::Str result; + bool starting = true; // false after the 1st non-? (%01) + for_( chp, encoded_r.begin(), encoded_r.end() ) + { + char ch = *chp; + + if ( ch == '%' ) // legal '%xx' sequence first + { + int d1 = heDecodeCh( *(chp+1) ); + if ( d1 != -1 ) + { + int d2 = heDecodeCh( *(chp+2) ); + if ( d2 != -1 ) + { + chp += 2; // skip sequence + if ( d1 == 0 ) + { + if ( d2 == 1 ) // %01 - ? valid sequence at begin or end + { + result << '?'; + while ( *(chp+1) == '%' && *(chp+2) == '0' && *(chp+3) == '1' ) + { + chp += 3; + result << '?'; + } + if ( starting || chp+1 == encoded_r.end() ) + { + starting = false; + continue; // -> continue; + } + else + throw std::invalid_argument( "CpeId:Uri: embedded %01" ); + } + else if ( d2 == 2 ) // %02 - * valid at begin or end + { + if ( starting || chp+1 == encoded_r.end() ) + { + result << '*'; + starting = false; + continue; // -> continue; + } + else + throw std::invalid_argument( "CpeId:Uri: embedded %02" ); + } + } + ch = (d1<<4)|d2; + if ( ! chIsValidRange( ch ) ) + throw std::invalid_argument( str::Str() << "CpeId:Uri: illegal % encoded character '" << reinterpret_cast(ch) << "'" ); + } + } + } + else if ( ! chIsValidRange( ch ) ) + throw std::invalid_argument( str::Str() << "CpeId:Uri: illegal character '" << reinterpret_cast(ch) << "'" ); + + if ( chIsWfnUnescaped( ch ) ) + result << ch; + else + result << '\\' << ch; + + if ( starting ) + starting = false; + } + _value.reset( new std::string( result ) ); + } + } + } + + std::string CpeId::Value::asWfn() const + { + std::string ret; + if ( ! _value ) + { + static const std::string any( "*" ); + ret = any; + } + else + ret = *_value; // includes "" for NA + return ret; + } + + std::string CpeId::Value::asFs() const + { + std::string ret; + if ( isANY() ) + { + static const std::string asterisk( "*" ); + ret = asterisk; + } + else if ( isNA() ) + { + static const std::string dash( "-" ); + ret = dash; + } + else + { + str::Str result; + for_( chp, _value->begin(), _value->end() ) + { + if ( *chp != '\\' ) + result << *chp; + else + { + ++chp; + switch ( *chp ) + { + case '-': + case '.': + case '_': + result << *chp; // without escaping + break; + + case '\0': + throw std::invalid_argument( "CpeId:Wfn: Backslash escapes nothing" ); + break; + + default: + result << '\\' << *chp; + break; + } + } + } + ret = result; + } + return ret; + } + + std::string CpeId::Value::asUri() const + { + std::string ret; // ANY + if ( ! isANY() ) + { + if ( isNA() ) + { + static const std::string dash( "-" ); + ret = dash; + } + else + { + str::Str result; + for_( chp, _value->begin(), _value->end() ) + { + if ( chIsWfnUnescaped( *chp ) ) + { + result << *chp; + } + else + { + static const char *const hdig = "0123456789abcdef"; + switch ( *chp ) + { + case '\\': + ++chp; + switch ( *chp ) + { + case '-': + case '.': + result << *chp; // without encodeing + break; + + case '\0': + throw std::invalid_argument( "CpeId:Wfn: Backslash escapes nothing" ); + break; + + default: + result << '%' << hdig[(unsigned char)(*chp)/16] << hdig[(unsigned char)(*chp)%16]; + break; + } + break; + + case '?': + result << "%01"; + break; + + case '*': + result << "%02"; + break; + + default: + throw std::invalid_argument( str::Str() << "CpeId:Wfn: illegal char '" << *chp << "' in WFN" ); + break; + } + } + } + ret = result; + } + } + return ret; + } + + /////////////////////////////////////////////////////////////////// + namespace + { + /** Whether it's a wildcard character ([*?]). */ + inline bool isWildchar( char ch_r ) + { return( ch_r == '*' || ch_r == '?' ); } + + /** Whether there is an even number of consecutive backslashes before and including \a rbegin_r + * An even number of backslashes means the character following is unescaped. + */ + inline bool evenNumberOfBackslashes( std::string::const_reverse_iterator rbegin_r, std::string::const_reverse_iterator rend_r ) + { + unsigned backslashes = 0; + for_( it, rbegin_r, rend_r ) + { + if ( *it == '\\' ) + ++backslashes; + else + break; + } + return !(backslashes & 1U); + } + + /** Number of chars (not counting escaping backslashes) in [begin_r,end_r[ */ + inline unsigned trueCharsIn( const std::string & str_r, std::string::size_type begin_r, std::string::size_type end_r ) + { + unsigned chars = 0; + for_( it, begin_r, end_r ) + { + ++chars; + if ( str_r[it] == '\\' ) + { + if ( ++it == end_r ) + break; + } + } + return chars; + } + + /** Match helper comparing 2 Wildcardfree string values (case insensitive). */ + inline bool matchWildcardfreeString( const std::string & lhs, const std::string & rhs ) + { return( str::compareCI( lhs, rhs ) == 0 ); } + + /** Match helper matching Wildcarded source against Wildcardfree target. + * + * Constraints on usage of the unquoted question mark (zero or one char in \a trg): + * 1. An unquoted question mark MAY be used at the beginning and/or the end of an + * attribute-value string. + * 2. A contiguous sequence of unquoted question marks MAY appear at the beginning + * and/or the end of an attribute-value string. + * 3. An unquoted question mark SHALL NOT be used in any other place in an + * attribute-value string. + * + * Constraints on usage of the unquoted asterisk (zero or more chars in \a trg): + * 1. A single unquoted asterisk MAY be used as the entire attribute-value string. + * 2. A single unquoted asterisk MAY be used at the beginning and/or end of an + * attribute-value string. + * 3. An unquoted asterisk SHALL NOT be used in any other place in an attribute-value + * string. + * + * Unquoted question marks and asterisks MAY appear in the same attribute-value string + * as long as they meet the constraints above. + * + * Example of illegal usage: "foo?bar", "bar??baz", "q??x", + * "foo*bar", "**foo", "bar***", + * "*?foobar", "foobar*?" + * + * \note Relies on \a src and \a trg being wellformed. + */ + inline bool matchWildcardedString( std::string src, std::string trg ) + { + // std::string::npos remembers an asterisk + // unescaped wildcard prefix + std::string::size_type prefx = 0; + switch ( *src.begin() ) // wellformed implies not empty + { + case '*': + if ( src.size() == 1 ) + return true; // "*" matches always: superset + else + prefx = std::string::npos; + src.erase( 0, 1 ); + break; + case '?': + ++prefx; + for_( it, ++src.begin(), src.end() ) + { if ( *it == '?' ) ++prefx; else break; } + if ( src.size() == prefx ) + return( trg.size() <= prefx ); // "??..?": superset if at most #prefx chars + else + src.erase( 0, prefx ); + break; + default: + break; + } + // unescaped wildcard suffix + std::string::size_type suffx = 0; + if ( ! src.empty() ) + { + switch ( *src.rbegin() ) + { + case '*': + if ( evenNumberOfBackslashes( ++src.rbegin(), src.rend() ) ) + { + suffx = std::string::npos; + src.erase( src.size()-1 ); + } + break; + case '?': + ++suffx; + for_( it, ++src.rbegin(), src.rend() ) + { if ( *it == '?' ) ++suffx; else break; } + if ( ! evenNumberOfBackslashes( src.rbegin()+suffx, src.rend() ) ) + --suffx; // last '?' was escaped. + src.erase( src.size()-suffx ); + break; + default: + break; + } + } + // now match; find src in trg an check surrounding wildcards + src = str::toLower( src ); + trg = str::toLower( trg ); + for ( std::string::size_type match = trg.find( src, 0 ); + match != std::string::npos; + match = trg.find( src, match+1 ) ) + { + if ( prefx != std::string::npos && trueCharsIn( trg, 0, match ) > prefx ) + break; // not "*", and already more chars than "?"s before match: disjoint + std::string::size_type frontSize = match + src.size(); + if ( suffx != std::string::npos && trueCharsIn( trg, frontSize, trg.size() ) > suffx ) + continue; // not "*", and still more chars than "?"s after match: check next match + return true; // match: superset + } + return false; // disjoint + } + } // namespace + /////////////////////////////////////////////////////////////////// + + bool CpeId::Value::containsWildcard() const + { + const std::string & value( *_value ); + return ( isWildchar( *value.begin() ) + || ( isWildchar( *value.rbegin() ) && evenNumberOfBackslashes( ++value.rbegin(), value.rend() ) ) ); + } + + /////////////////////////////////////////////////////////////////// + /// Symmetric attribute compare if wildcards are involved! + /// The specs define any comarison with a wildcarded attribute as + /// target to return \c uncomparable: + /// \code + /// wildcardfree <=> wildcarded ==> uncomparable, + /// wildcarded <=> wildcardfree ==> superset or disjoint + /// \endcode + /// But a symmetric result is much more intuitive: + /// \code + /// wildcardfree <=> wildcarded ==> subset or disjoint + /// wildcarded <=> wildcardfree ==> superset or disjoint + /// \endcode + /////////////////////////////////////////////////////////////////// +#define WFN_STRICT_SPEC 0 +#if WFN_STRICT_SPEC + //SetCompare CpeId::Value::setRelationMixinCompare( const CpeId::Value & trg ) const + { + static const SetCompare _NeedsCloserLook( SetCompare::Enum(-1) ); // artificial Compare value + static const SetCompare matchTabel[4][4] = {{ + /* ANY, ANY */ SetCompare::equal, + /* ANY, NA */ SetCompare::properSuperset, + /* ANY, wildcardfree */ SetCompare::properSuperset, + /* ANY, wildcarded */ SetCompare::uncomparable, + },{ + /* NA, ANY */ SetCompare::properSubset, + /* NA, NA */ SetCompare::equal, + /* NA, wildcardfree */ SetCompare::disjoint, + /* NA, wildcarded */ SetCompare::uncomparable, + },{ + /* wildcardfree, ANY */ SetCompare::properSubset, + /* wildcardfree, NA */ SetCompare::disjoint, + /* wildcardfree, wildcardfree */ _NeedsCloserLook, // equal or disjoint + /* wildcardfree, wildcarded */ SetCompare::uncomparable, + },{ + /* wildcarded, ANY */ SetCompare::properSubset, + /* wildcarded, NA */ SetCompare::disjoint, + /* wildcarded, wildcardfree */ _NeedsCloserLook, // superset or disjoint + /* wildcarded, wildcarded */ SetCompare::uncomparable, + }}; + + Type srcType = type(); + Type trgType = trg.type(); + SetCompare ret = matchTabel[srcType.asIntegral()][trgType.asIntegral()]; + if ( ret == _NeedsCloserLook ) + { + if ( srcType == Type::wildcardfree ) // trgType == Type::wildcardfree + { + // simple string compare + ret = matchWildcardfreeString( *_value, *trg._value ) ? SetCompare::equal : SetCompare::disjoint; + } + else if ( srcType == Type::wildcarded ) // trgType == Type::wildcardfree + { + // Needs wildcard compare + ret = matchWildcardedString( *_value, *trg._value ) ? SetCompare::properSuperset : SetCompare::disjoint; + } + } + return ret; + } +#else + SetCompare CpeId::Value::setRelationMixinCompare( const CpeId::Value & trg ) const + { + /////////////////////////////////////////////////////////////////// + // ANY, ANY => equal + // ANY, NA => properSuperset + // ANY, wildcardfree => properSuperset + // ANY, wildcarded => properSuperset + // + // NA, ANY => properSubset + // NA, NA => equal + // NA, wildcardfree => disjoint + // NA, wildcarded => disjoint + // + // wildcardfree, ANY => properSubset + // wildcardfree, NA => disjoint + // wildcardfree, wildcardfree => NeedsCloserLook: equal or disjoint + // wildcardfree, wildcarded => NeedsCloserLook: subset or disjoint + // + // wildcarded, ANY => properSubset + // wildcarded, NA => disjoint + // wildcarded, wildcardfree => NeedsCloserLook: superset or disjoint + // wildcarded, wildcarded => NeedsCloserLook" equal or uncomparable + /////////////////////////////////////////////////////////////////// + + SetCompare ret = SetCompare::disjoint; + + if ( isANY() ) + { + ret = trg.isANY() ? SetCompare::equal : SetCompare::properSuperset; + } + else if ( trg.isANY() ) + { + ret = SetCompare::properSubset; + } + else if ( isNA() ) + { + if ( trg.isNA() ) ret = SetCompare::equal; // else: SetCompare::disjoint; + } + else if ( ! trg.isNA() ) // else: SetCompare::disjoint; + { + // NeedsCloserLook: + if ( isWildcarded() ) + { + if ( trg.isWildcarded() ) + { + // simple string compare just to detect 'equal' + ret = matchWildcardfreeString( *_value, *trg._value ) ? SetCompare::equal : SetCompare::uncomparable; + } + else + { + // Needs wildcard compare (src,trg) + if ( matchWildcardedString( *_value, *trg._value ) ) ret = SetCompare::properSuperset; // else: SetCompare::disjoint; + } + } + else + { + if ( trg.isWildcarded() ) + { + // Needs wildcard compare (trg,src) + if ( matchWildcardedString( *trg._value, *_value ) ) ret = SetCompare::properSubset; // else: SetCompare::disjoint; + } + else + { + // simple string compare + if ( matchWildcardfreeString( *_value, *trg._value ) ) ret = SetCompare::equal; // else: SetCompare::disjoint; + } + } + } + return ret; + } +#endif // WFN_STRICT_SPEC + + std::ostream & operator<<( std::ostream & str, const CpeId::Value & obj ) + { return str << obj.asString(); } + +} // namespace zypp +/////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/CpeId.h b/libzypp/zypp/CpeId.h new file mode 100644 index 0000000..a5204d1 --- /dev/null +++ b/libzypp/zypp/CpeId.h @@ -0,0 +1,303 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/CpeId.h + */ +#ifndef ZYPP_CPEID_H +#define ZYPP_CPEID_H + +#include +#include + +#include "zypp/base/PtrTypes.h" +#include "zypp/base/Flags.h" +#include "zypp/base/EnumClass.h" +#include "zypp/base/SetRelationMixin.h" + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + /////////////////////////////////////////////////////////////////// + /// \class CpeId + /// \brief Common Platform Enumearation (2.3) + /// See http://cpe.mitre.org/ for more information on the + /// Common Platform Enumearation. + /////////////////////////////////////////////////////////////////// + class CpeId : public base::SetRelationMixin + { + public: + /** WFN attribute value */ + class Value; + + public: + /** WFN attributes (use like 'enum class \ref Attribute') */ + struct _AttributeDef { + enum Enum { + part, //< attribute (2.2) + vendor, //< attribute (2.2) + product, //< attribute (2.2) + version, //< attribute (2.2) + update, //< attribute (2.2) + edition, //< attribute (2.2) + language, //< attribute (2.2) + sw_edition, //< extended attribute (2.3) + target_sw, //< extended attribute (2.3) + target_hw, //< extended attribute (2.3) + other //< extended attribute (2.3) + }; + static constexpr unsigned numAttributes = other+1; ///< number of attributes + static const std::string & asString( Enum val_r ); ///< string representantion + }; + typedef base::EnumClass<_AttributeDef> Attribute; ///< 'enum class Attribute' + + public: + /** Indicator type for non-trowing ctor. */ + struct NoThrowType { static std::string lastMalformed; }; + /** Indicator argument for non-trowing ctor. */ + static constexpr NoThrowType noThrow = NoThrowType(); + + public: + /** Default ctor: ANY-Cpeid, all attribute values are ANY */ + CpeId(); + + /** Ctor parsing from string representation (empty or URI or FS) + * \throws std::invalid_argument if string is malformed + */ + explicit CpeId( const std::string & cpe_r ); + + /** Ctor parsing from string representation (empty or URI or FS) + * \throws std::invalid_argument if string is malformed + */ + explicit CpeId( const char * cpe_r ) + : CpeId( std::string( cpe_r ? cpe_r : "" ) ) + {} + + /** Ctor parsing from string (empty or URI or FS, non throwing) + * Creates an empty CpeId if string is malformed. + */ + CpeId( const std::string & cpe_r, NoThrowType ); + + /** Dtor */ + ~CpeId(); + + public: + /** Evaluate in boolean context: not an ANY-CpeId */ + explicit operator bool() const; + + /** Default string representation [\ref asFS]. */ + std::string asString() const + { return asFs(); } + + /** String representation as Formated-String (in/out). + * \code + * cpe:2.3:a:opensuse:libzypp:14.16.0:beta:*:*:*:*:*:* + * \endcode + */ + std::string asFs() const; + + /** String representation as URI (in/out). + * \code + * cpe:/a:opensuse:libzypp:14.16.0:beta + * \endcode + */ + std::string asUri() const; + + /** String representation as Well-Formed-Name (internal format, out only). + * \code + * wfn:[part="a",vendor="opensuse",product="libzypp", version="14\.16\.0",update="beta"] + * \endcode + */ + std::string asWfn() const; + + private: + friend SetCompare base::SetRelationMixin::compare( const CpeId & ) const; + /** CPE name matching hook for \ref SetRelationMixin */ + SetCompare setRelationMixinCompare( const CpeId & trg ) const; + + public: + class Impl; ///< Implementation class. + private: + RWCOW_pointer _pimpl; ///< Pointer to implementation. + }; + + SETRELATIONMIXIN_DEFINE_COMPARE_BETWEEN( CpeId, const char * ); + SETRELATIONMIXIN_DEFINE_COMPARE_BETWEEN( CpeId, const std::string & ); + + /** \relates CpeId Stream output */ + inline std::ostream & operator<<( std::ostream & str, const CpeId & obj ) + { return str << obj.asString(); } + + /** \relates CpeId::Attribute Stream output */ + inline std::ostream & operator<<( std::ostream & str, const CpeId::Attribute & obj ) + { return str << CpeId::Attribute::asString( obj.asEnum() ); } + + + /////////////////////////////////////////////////////////////////// + /// \class CpeId::Value + /// \brief WFN attribute value + /// + /// Valid WFN string values are not empty, contain alphanumeric chars, underscore, + /// no whitespace, printable non-alphanumeric characters must be quoted by a + /// backslash. + /// + /// Unescaped asterisk and question mark are special characters and may occur at + /// the beginning and or end of the string. The asterisk must not be used more than + /// once in asequense. The question mark may be used more than once in a sequence. + /// + /// A single asterisk must not be used as attribute value, nor a single quoted hyphen. + /// + /// A single question mark may be used as value. + /// + /// \see http://cpe.mitre.org/ for more information on the Common Platform Enumeration. + /////////////////////////////////////////////////////////////////// + class CpeId::Value : public base::SetRelationMixin + { + public: + /** Logical value matching ANY value. */ + static const Value ANY; + + /** Logical value indicating “not applicable/not used" */ + static const Value NA; + + public: + /** Indicator type for ctor arg in FS format. */ + struct FsFormatType {}; + /** Indicator argument for ctor arg in FS format. */ + static constexpr FsFormatType fsFormat = FsFormatType(); + + /** Indicator type for ctor arg in URI format. */ + struct UriFormatType {}; + /** Indicator argument for ctor arg in URI format. */ + static constexpr UriFormatType uriFormat = UriFormatType(); + + public: + /** Default ctor: ANY */ + Value() + {} + + /** Ctor from string (WFN format; \c "*" represents ANY; \c "" represents NA) + * \throws std::invalid_argument if string is malformed (\see \ref isValidWfn). + */ + explicit Value( const std::string & value_r ); + + /** Ctor from char* (WFN format; \c nullptr or \c "*" represent ANY; \c "" represents NA) + * \throws std::invalid_argument if string is malformed (\see \ref isValidWfn). + */ + explicit Value( const char * value_r ) + : Value( std::string( value_r ? value_r : "*" ) ) + {} + + /** Ctor from string (FS format, \c "*" represents ANY; \c "-" represents NA) + * \throws std::invalid_argument if string is malformed. + */ + Value( const std::string & encoded_r, FsFormatType ); + + /** Ctor from string (URI format, \c "" represents ANY; \c "-" represents NA) + * \throws std::invalid_argument if string is malformed. + */ + Value( const std::string & encoded_r, UriFormatType ); + + public: + /** Classification of \ref Value types mostly for \ref match (use like 'enum class \ref Type') */ + struct _TypeDef { + enum Enum { + ANY, + NA, + wildcardfree, + wildcarded, + }; + }; + typedef base::EnumClass<_TypeDef> Type; ///< 'enum class Type' + + /** Return the \ref Type of this \ref Value. */ + Type type() const + { + if ( !_value ) return Type::ANY; + if ( _value->empty() ) return Type::NA; + return( isWildcarded() ? Type::wildcarded : Type::wildcardfree ); + } + + /** Whether value is ANY. ) */ + bool isANY() const + { return !_value; } + + /** Whether value is NA. ) */ + bool isNA() const + { return _value && _value->empty(); } + + /** Whether it's a logical value (ANY|NA). */ + bool isLogical() const + { return !_value || _value->empty(); } + /** \overload for Type */ + bool isLogical( Type type_r ) const + { return( type_r == Type::ANY || type_r == Type::NA ); } + + /** Whether it's an attribute value string (not logical value). */ + bool isString() const + { return _value && !_value->empty(); } + /** \overload for Type */ + bool isString( Type type_r ) const + { return( type_r == Type::wildcardfree || type_r == Type::wildcarded ); } + + /** An attribute value string without wildcards ([*?] at begin and/or end) */ + bool isWildcardfree() const + { return isString() && ! containsWildcard(); } + + /** An attribute value string with wildcards ([*?] at begin and/or end) */ + bool isWildcarded() const + { return isString() && containsWildcard(); } + + public: + /** Default string representation [\ref asWfn]. */ + std::string asString() const + { return asWfn(); } + + /** String representation as in Well-Formed-Name (ANY:"*", NA:""). + * \code + * wfn:[part="a",vendor="opensuse",product="libzypp", version="14\.16\.0",update="beta"] + * \endcode + */ + std::string asWfn() const; + + /** String representation as in Formated-String (ANY:"*", NA:"-") + * \code + * cpe:2.3:a:opensuse:libzypp:14.16.0:beta:*:*:*:*:*:* + * \endcode + */ + std::string asFs() const; + + /** String representation as in URI (ANY:"", NA:"-") + * \code + * cpe:/a:opensuse:libzypp:14.16.0:beta + * \endcode + */ + std::string asUri() const; + + private: + friend SetCompare base::SetRelationMixin::compare( const Value & ) const; + /** CPE name matching hook for \ref SetRelationMixin */ + SetCompare setRelationMixinCompare( const Value & trg ) const; + + /** HAs unquoted [*?] at begin and/or end of value. + * \note \ref isString() must be asserted! + */ + bool containsWildcard() const; + + private: + RWCOW_pointer _value; + }; + + SETRELATIONMIXIN_DEFINE_COMPARE_BETWEEN( CpeId::Value, const char * ); + SETRELATIONMIXIN_DEFINE_COMPARE_BETWEEN( CpeId::Value, const std::string & ); + + /** \relates CpeId::Value Stream output */ + std::ostream & operator<<( std::ostream & str, const CpeId::Value & obj ); + +} // namespace zypp +/////////////////////////////////////////////////////////////////// +#endif // ZYPP_CPEID_H diff --git a/libzypp/zypp/Date.cc b/libzypp/zypp/Date.cc index 9344254..4651e72 100644 --- a/libzypp/zypp/Date.cc +++ b/libzypp/zypp/Date.cc @@ -13,6 +13,7 @@ //#include "zypp/base/Logger.h" #include "zypp/base/String.h" +#include "zypp/base/Xml.h" #include "zypp/Date.h" @@ -20,20 +21,131 @@ using std::endl; /////////////////////////////////////////////////////////////////// namespace zypp -{ ///////////////////////////////////////////////////////////////// - - static std::string adjustLocale(); - static void restoreLocale(const std::string & locale); - +{ + /////////////////////////////////////////////////////////////////// namespace { + /////////////////////////////////////////////////////////////////// + /// \class LocaleGuard + /// \brief Temporarily adjust Locale + /// \ingroup RAII + struct LocaleGuard + { + LocaleGuard() + { + const char * tmp = ::setlocale( LC_TIME, NULL ); + _mylocale = tmp ? tmp : ""; + + if ( _mylocale.find( "UTF-8" ) == std::string::npos + && _mylocale.find( "utf-8" ) == std::string::npos + && _mylocale != "POSIX" + && _mylocale != "C" + && _mylocale != "" ) + { + // language[_territory][.codeset][@modifier] + // add/exchange codeset with UTF-8 + std::string needLocale = ".UTF-8"; + std::string::size_type loc = _mylocale.find_first_of( ".@" ); + if ( loc != std::string::npos ) + { + // prepend language[_territory] + needLocale = _mylocale.substr( 0, loc ) + needLocale; + loc = _mylocale.find_last_of( "@" ); + if ( loc != std::string::npos ) + { + // append [@modifier] + needLocale += _mylocale.substr( loc ); + } + } + else + { + // append ".UTF-8" + needLocale = _mylocale + needLocale; + } + ::setlocale( LC_TIME, needLocale.c_str() ); + } + else + { + // no need to change the locale + _mylocale.clear(); + } + } + + ~LocaleGuard() + { + if ( ! _mylocale.empty() ) + ::setlocale( LC_TIME, _mylocale.c_str() ); + } + private: + std::string _mylocale; + }; + /////////////////////////////////////////////////////////////////// + inline bool isDST( struct tm & tm ) { time_t t = ::mktime( &tm ); struct tm *tm2 = ::localtime( &t ); return ( tm2 && tm2->tm_isdst > 0 ); } - } + + inline const char * _dateFormat( Date::DateFormat dateFormat_r ) + { + static const char * fmt[] = { + "", ///< "" + "%Y-%m-%d", ///< 2014-02-07 + "%Y-%m", ///< 2014-02 + "%Y", ///< 2014 + "%G-W%V", ///< 2014-W06 + "%G-W%V-%u", ///< 2014-W06-5 (1 is Monday) + "%Y-%j", ///< 2014-038 + }; + return fmt[dateFormat_r.asIntegral()]; + } + + inline const char * _timeFormat( Date::TimeFormat timeFormat_r ) + { + static const char * fmt[] = { + "", ///< "" + "%H:%M:%S", ///< 07:06:41 + "%H:%M", ///< 07:06 + "%H", ///< 07 + }; + return fmt[timeFormat_r.asIntegral()]; + } + + inline const char * _timeZoneFormat( Date::TimeZoneFormat timeZoneFormat_r ) + { + static const char * fmt[] = { + "", ///< "" + " %Z", ///< UTC, CET, ... + "%z", ///< +0000 + }; + return fmt[timeZoneFormat_r.asIntegral()]; + } + + inline std::string doForm( const std::string & format_r, Date::TimeBase base_r, const Date::ValueType & date_r ) + { + if ( ! date_r ) + return "0"; + + LocaleGuard guard; + static char buf[512]; + if ( ! strftime( buf, 512, format_r.c_str(), (base_r == Date::TB_UTC ? gmtime : localtime)( &date_r ) ) ) + *buf = '\0'; + else + { + // strip a trailing '00' in a timeZoneFormat + unsigned l = ::strlen( buf ); + if ( l >= 5 + && ( buf[l-1] == '0' ) + && ( buf[l-2] == '0' ) + && ( buf[l-5] == '+' || buf[l-5] == '-') ) + buf[l-2] = '\0'; + } + return buf; + } + } // namespace + /////////////////////////////////////////////////////////////////// const Date::ValueType Date::second; const Date::ValueType Date::minute; @@ -48,11 +160,6 @@ namespace zypp const Date::ValueType Date::year366; const Date::ValueType Date::year; - /////////////////////////////////////////////////////////////////// - // - // METHOD NAME : Date::Date - // METHOD TYPE : Constructor - // Date::Date( const std::string & seconds_r ) { str::strtonum( seconds_r, _date ); } @@ -63,89 +170,73 @@ namespace zypp Date::Date( const std::string & date_str, const std::string & format, Date::TimeBase base_r ) : _date(0) { - struct tm tm = {0,0,0,0,0,0,0,0,0,0,0}; - std::string thisLocale = adjustLocale(); + LocaleGuard guard; + struct tm tm = {0,0,0,0,0,0,0,0,0,0,0}; char * res = ::strptime( date_str.c_str(), format.c_str(), &tm ); + if (res == NULL) + throw DateFormatException( str::form( "Invalid date format: '%s'", date_str.c_str() ) ); + if ( isDST(tm) ) tm.tm_isdst = 1; - if ( res != NULL ) - _date = (base_r == TB_UTC ? ::timegm : ::timelocal)( &tm ); - - restoreLocale(thisLocale); - - if (res == NULL) - throw DateFormatException( - str::form( "Invalid date format: '%s'", date_str.c_str() ) ); + _date = (base_r == TB_UTC ? ::timegm : ::timelocal)( &tm ); } - - /////////////////////////////////////////////////////////////////// - // - // METHOD NAME : Date::form - // METHOD TYPE : std::string - // std::string Date::form( const std::string & format_r, Date::TimeBase base_r ) const - { - static char buf[1024]; - std::string thisLocale = adjustLocale(); - - if ( ! strftime( buf, 1024, format_r.c_str(), (base_r == TB_UTC ? gmtime : localtime)( &_date ) ) ) - *buf = '\0'; - - restoreLocale(thisLocale); + { return doForm( format_r, base_r, _date ); } - return buf; + std::string Date::print( DateFormat dateFormat_r, TimeFormat timeFormat_r, TimeZoneFormat timeZoneFormat_r, TimeBase base_r ) const + { + str::Str str; + if ( dateFormat_r != DateFormat::none ) + str << _dateFormat( dateFormat_r ); + if ( timeFormat_r != TimeFormat::none ) + { + if ( dateFormat_r != DateFormat::none ) + str << ' '; + str << _timeFormat( timeFormat_r ); + if ( timeZoneFormat_r != TimeZoneFormat::none ) + str << _timeZoneFormat( timeZoneFormat_r ); + } + return doForm( str, base_r, _date ); } - static std::string adjustLocale() + std::string Date::printISO( DateFormat dateFormat_r, TimeFormat timeFormat_r, TimeZoneFormat timeZoneFormat_r, TimeBase base_r ) const { - const char * tmp = ::setlocale( LC_TIME, NULL ); - std::string thisLocale( tmp ? tmp : "" ); - - if ( thisLocale.find( "UTF-8" ) == std::string::npos - && thisLocale.find( "utf-8" ) == std::string::npos - && thisLocale != "POSIX" - && thisLocale != "C" - && thisLocale != "" ) + str::Str str; + if ( dateFormat_r != DateFormat::none ) + str << _dateFormat( dateFormat_r ); + if ( timeFormat_r != TimeFormat::none ) { - // language[_territory][.codeset][@modifier] - // add/exchange codeset with UTF-8 - std::string needLocale = ".UTF-8"; - std::string::size_type loc = thisLocale.find_first_of( ".@" ); - if ( loc != std::string::npos ) + if ( dateFormat_r != DateFormat::none ) + str << 'T'; + str << _timeFormat( timeFormat_r ); + switch ( timeZoneFormat_r.asEnum() ) { - // prepend language[_territory] - needLocale = thisLocale.substr( 0, loc ) + needLocale; - loc = thisLocale.find_last_of( "@" ); - if ( loc != std::string::npos ) - { - // append [@modifier] - needLocale += thisLocale.substr( loc ); - } + case TimeZoneFormat::none: + break; + case TimeZoneFormat::name: + if ( base_r == TB_UTC ) + { + str << 'Z'; + break; + } + // else: FALLTHROUGH and print offset! + case TimeZoneFormat::offset: + str << _timeZoneFormat( TimeZoneFormat::offset ); + break; } - else - { - // append ".UTF-8" - needLocale = thisLocale + needLocale; - } - ::setlocale( LC_TIME, needLocale.c_str() ); } - else - { - // no need to change the locale - thisLocale.clear(); - } - - return thisLocale; + return doForm( str, base_r, _date ); } - static void restoreLocale(const std::string & locale) + std::ostream & dumpAsXmlOn( std::ostream & str, const Date & obj, const std::string & name_r ) { - if ( ! locale.empty() ) - ::setlocale( LC_TIME, locale.c_str() ); + return xmlout::node( str, name_r, { + { "time_t", Date::ValueType(obj) }, + { "text", obj.printISO() }, + } ); } - ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/Date.h b/libzypp/zypp/Date.h index 9fe7cb9..e002c2c 100644 --- a/libzypp/zypp/Date.h +++ b/libzypp/zypp/Date.h @@ -17,6 +17,7 @@ #include #include "zypp/base/Exception.h" +#include "zypp/base/EnumClass.h" /////////////////////////////////////////////////////////////////// namespace zypp @@ -60,7 +61,7 @@ namespace zypp : _date( date_r ) {} /** Ctor taking time_t value as string. */ - Date( const std::string & seconds_r ); + explicit Date( const std::string & seconds_r ); /** * Ctor from a \a date_str (in localtime) formatted using \a format. @@ -81,10 +82,13 @@ namespace zypp operator ValueType() const { return _date; } - /** \name Arithmetic operations. - * \c + \c - \c * \c / are provided via conversion to time_t. - */ + /** \name Arithmetic operations. */ //@{ + Date operator+( const time_t rhs ) const { return _date + rhs; } + Date operator-( const time_t rhs ) const { return _date - rhs; } + Date operator*( const time_t rhs ) const { return _date * rhs; } + Date operator/( const time_t rhs ) const { return _date / rhs; } + Date & operator+=( const time_t rhs ) { _date += rhs; return *this; } Date & operator-=( const time_t rhs ) { _date -= rhs; return *this; } Date & operator*=( const time_t rhs ) { _date *= rhs; return *this; } @@ -102,7 +106,7 @@ namespace zypp * \see 'man strftime' (which is used internaly) for valid * conversion specifiers in format. * - * \return An empty string on illegal format. + * \return An empty string on illegal format, "0" if date is unspecified. **/ std::string form( const std::string & format_r ) const { return form( format_r, TB_LOCALTIME ); } @@ -121,7 +125,120 @@ namespace zypp std::string asSeconds() const { return form( "%s" ); } - private: + public: + /** \name Printing in various predefined formats */ + //@{ + /** Date formats for printing (use like 'enum class \ref DateFormat') */ + struct _DateFormatDef { enum Enum { + none, ///< "" + calendar, ///< 2014-02-07 + month, ///< 2014-02 + year, ///< 2014 + week, ///< 2014-W06 + weekday, ///< 2014-W06-5 (1 is Monday) + ordinal, ///< 2014-038 + };}; + typedef base::EnumClass<_DateFormatDef> DateFormat; ///< 'enum class DateFormat' + + /** Time formats for printing (use like 'enum class \ref TimeFormat') */ + struct _TimeFormatDef { enum Enum { + none, ///< "" + seconds, ///< 07:06:41 + minutes, ///< 07:06 + hours, ///< 07 + };}; + typedef base::EnumClass<_TimeFormatDef> TimeFormat; ///< 'enum class TimeFormat' + + /** Timezone indicator for printing (use like 'enum class \ref TimeZoneFormat') */ + struct _TimeZoneFormatDef { enum Enum { + none, ///< "" + name, ///< UTC, CET, ... + offset, ///< +00[:00] + };}; + typedef base::EnumClass<_TimeZoneFormatDef> TimeZoneFormat; ///< 'enum class TimeZoneFormat' + + /** Default format is '2014-02-07 07:06:41 CET' + * The default is \ref DateFormat::calendar, \ref TimeFormat::seconds, \ref TimeZoneFormat::name and + * \ref TB_LOCALTIME. For other formats you don't have to repeat all the defaults, just pass the + * values where you differ. + */ + std::string print( DateFormat dateFormat_r = DateFormat::calendar, TimeFormat timeFormat_r = TimeFormat::seconds, TimeZoneFormat timeZoneFormat_r = TimeZoneFormat::name, TimeBase base_r = TB_LOCALTIME ) const; + /** \overload */ + std::string print( TimeFormat timeFormat_r, TimeZoneFormat timeZoneFormat_r = TimeZoneFormat::name, TimeBase base_r = TB_LOCALTIME ) const + { return print( DateFormat::calendar, timeFormat_r, timeZoneFormat_r, base_r ); } + /** \overload */ + std::string print( DateFormat dateFormat_r, TimeZoneFormat timeZoneFormat_r, TimeBase base_r = TB_LOCALTIME ) const + { return print( dateFormat_r, TimeFormat::seconds, timeZoneFormat_r, base_r ); } + /** \overload */ + std::string print( DateFormat dateFormat_r, TimeFormat timeFormat_r, TimeBase base_r ) const + { return print( dateFormat_r, timeFormat_r, TimeZoneFormat::name, base_r ); } + /** \overload */ + std::string print( TimeZoneFormat timeZoneFormat_r, TimeBase base_r = TB_LOCALTIME ) const + { return print( DateFormat::calendar, TimeFormat::seconds, timeZoneFormat_r, base_r ); } + /** \overload */ + std::string print( TimeFormat timeFormat_r, TimeBase base_r ) const + { return print( DateFormat::calendar, timeFormat_r, TimeZoneFormat::name, base_r ); } + /** \overload */ + std::string print( DateFormat dateFormat_r, TimeBase base_r ) const + { return print( dateFormat_r, TimeFormat::seconds, TimeZoneFormat::name, base_r ); } + /** \overload */ + std::string print( TimeBase base_r ) const + { return print( DateFormat::calendar, TimeFormat::seconds, TimeZoneFormat::name, base_r ); } + + /** Convenience for printing the date only ['2014-02-07'] + * The default is \ref DateFormat::calendar and \ref TB_LOCALTIME + */ + std::string printDate( DateFormat dateFormat_r = DateFormat::calendar, TimeBase base_r = TB_LOCALTIME ) const + { return print( dateFormat_r, TimeFormat::none, TimeZoneFormat::none, base_r ); } + /** \overload */ + std::string printDate( TimeBase base_r ) const + { return printDate( DateFormat::calendar, base_r ); } + + /** Convenience for printing the time only ['07:06:41 CET'] + * The default is \ref DateFormat::calendar and \ref TB_LOCALTIME + */ + std::string printTime( TimeFormat timeFormat_r = TimeFormat::seconds, TimeZoneFormat timeZoneFormat_r = TimeZoneFormat::name, TimeBase base_r = TB_LOCALTIME ) const + { return print( DateFormat::none, timeFormat_r, timeZoneFormat_r, base_r ); } + /** \overload */ + std::string printTime( TimeZoneFormat timeZoneFormat_r , TimeBase base_r = TB_LOCALTIME ) const + { return printTime( TimeFormat::seconds, timeZoneFormat_r, base_r ); } + /** \overload */ + std::string printTime( TimeFormat timeFormat_r , TimeBase base_r ) const + { return printTime( timeFormat_r, TimeZoneFormat::name, base_r ); } + /** \overload */ + std::string printTime( TimeBase base_r ) const + { return printTime( TimeFormat::seconds, TimeZoneFormat::name, base_r ); } + + /** Default ISO 8601 format is '2014-02-07T07:06:41+01' + * \note As timezone names are not used in ISO, \ref TimeZoneFormat::name is the same as + * \ref TimeZoneFormat::offset when printing in \ref TB_LOCALTIME. When printing \ref TB_UTC + * it uses a \c 'Z' to indicate UTC (Zulu time) rather than printing \c '+00'. + */ + std::string printISO( DateFormat dateFormat_r = DateFormat::calendar, TimeFormat timeFormat_r = TimeFormat::seconds, TimeZoneFormat timeZoneFormat_r = TimeZoneFormat::name, TimeBase base_r = TB_LOCALTIME ) const; + /** \overload */ + std::string printISO( TimeFormat timeFormat_r, TimeZoneFormat timeZoneFormat_r = TimeZoneFormat::name, TimeBase base_r = TB_LOCALTIME ) const + { return printISO( DateFormat::calendar, timeFormat_r, timeZoneFormat_r, base_r ); } + /** \overload */ + std::string printISO( DateFormat dateFormat_r, TimeZoneFormat timeZoneFormat_r, TimeBase base_r = TB_LOCALTIME ) const + { return printISO( dateFormat_r, TimeFormat::seconds, timeZoneFormat_r, base_r ); } + /** \overload */ + std::string printISO( DateFormat dateFormat_r, TimeFormat timeFormat_r, TimeBase base_r ) const + { return printISO( dateFormat_r, timeFormat_r, TimeZoneFormat::name, base_r ); } + /** \overload */ + std::string printISO( TimeZoneFormat timeZoneFormat_r, TimeBase base_r = TB_LOCALTIME ) const + { return printISO( DateFormat::calendar, TimeFormat::seconds, timeZoneFormat_r, base_r ); } + /** \overload */ + std::string printISO( TimeFormat timeFormat_r, TimeBase base_r ) const + { return printISO( DateFormat::calendar, timeFormat_r, TimeZoneFormat::name, base_r ); } + /** \overload */ + std::string printISO( DateFormat dateFormat_r, TimeBase base_r ) const + { return printISO( dateFormat_r, TimeFormat::seconds, TimeZoneFormat::name, base_r ); } + /** \overload */ + std::string printISO( TimeBase base_r ) const + { return printISO( DateFormat::calendar, TimeFormat::seconds, TimeZoneFormat::name, base_r ); } + //@} + + private: /** Calendar time. * The number of seconds elapsed since 00:00:00 on January 1, 1970, * Coordinated Universal Time (UTC). @@ -134,6 +251,12 @@ namespace zypp inline std::ostream & operator<<( std::ostream & str, const Date & obj ) { return str << obj.asString(); } + /** \relates Date XML output. + * Print \c time_t and \c text attribute. Allow alternate node name [date]. + */ + std::ostream & dumpAsXmlOn( std::ostream & str, const Date & obj, const std::string & name_r = "date" ); + + /////////////////////////////////////////////////////////////////// class DateFormatException : public Exception { public: diff --git a/libzypp/zypp/Dep.cc b/libzypp/zypp/Dep.cc index 5ec642a..3a32472 100644 --- a/libzypp/zypp/Dep.cc +++ b/libzypp/zypp/Dep.cc @@ -13,6 +13,7 @@ #include #include "zypp/base/Exception.h" +#include "zypp/base/Gettext.h" #include "zypp/base/String.h" #include "zypp/Dep.h" @@ -23,31 +24,25 @@ namespace zypp namespace { - - std::map _table; - - Dep::for_use_in_switch parse( const std::string & strval_r ) + inline Dep::for_use_in_switch parse( const std::string & strval_r ) { - if ( _table.empty() ) - { - // initialize it - _table["provides"] = Dep::PROVIDES_e; - _table["prerequires"] = Dep::PREREQUIRES_e; - _table["requires"] = Dep::REQUIRES_e; - _table["conflicts"] = Dep::CONFLICTS_e; - _table["obsoletes"] = Dep::OBSOLETES_e; - _table["recommends"] = Dep::RECOMMENDS_e; - _table["suggests"] = Dep::SUGGESTS_e; - _table["enhances"] = Dep::ENHANCES_e; - _table["supplements"] = Dep::SUPPLEMENTS_e; - } + const std::map _table = { + { "provides", Dep::PROVIDES_e }, + { "prerequires", Dep::PREREQUIRES_e }, + { "requires", Dep::REQUIRES_e }, + { "conflicts", Dep::CONFLICTS_e }, + { "obsoletes", Dep::OBSOLETES_e }, + { "recommends", Dep::RECOMMENDS_e }, + { "suggests", Dep::SUGGESTS_e }, + { "enhances", Dep::ENHANCES_e }, + { "supplements", Dep::SUPPLEMENTS_e } + }; - std::map::const_iterator it - = _table.find( str::toLower( strval_r ) ); + auto it = _table.find( str::toLower( strval_r ) ); if ( it == _table.end() ) - { - ZYPP_THROW( Exception("Dep parse: illegal string value '"+strval_r+"'") ); - } + { + ZYPP_THROW( Exception("Dep parse: illegal string value '"+strval_r+"'") ); + } return it->second; } } @@ -80,21 +75,35 @@ namespace zypp // const std::string & Dep::asString() const { - static std::map _table; - if ( _table.empty() ) - { - // initialize it - _table[PROVIDES_e] = "provides"; - _table[PREREQUIRES_e] = "prerequires"; - _table[REQUIRES_e] = "requires"; - _table[CONFLICTS_e] = "conflicts"; - _table[OBSOLETES_e] = "obsoletes"; - _table[RECOMMENDS_e] = "recommends"; - _table[SUGGESTS_e] = "suggests"; - _table[ENHANCES_e] = "enhances"; - _table[SUPPLEMENTS_e] = "supplements"; - } - return _table[_type]; + static const std::map _table = { + { PROVIDES_e, "provides" }, + { PREREQUIRES_e, "prerequires" }, + { REQUIRES_e, "requires" }, + { CONFLICTS_e, "conflicts" }, + { OBSOLETES_e, "obsoletes" }, + { RECOMMENDS_e, "recommends" }, + { SUGGESTS_e, "suggests" }, + { ENHANCES_e, "enhances" }, + { SUPPLEMENTS_e, "supplements" } + }; + return _table.at(_type); + } + + std::string Dep::asUserString() const + { + switch ( inSwitch() ) + { + case PROVIDES_e: return _("Provides"); break; + case PREREQUIRES_e: return _("Prerequires"); break; + case REQUIRES_e: return _("Requires"); break; + case CONFLICTS_e: return _("Conflicts"); break; + case OBSOLETES_e: return _("Obsoletes"); break; + case RECOMMENDS_e: return _("Recommends"); break; + case SUGGESTS_e: return _("Suggests"); break; + case ENHANCES_e: return _("Enhances"); break; + case SUPPLEMENTS_e: return _("Supplements"); break; + } + return ""; } ///////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/Dep.h b/libzypp/zypp/Dep.h index 5ff7d85..5a0445d 100644 --- a/libzypp/zypp/Dep.h +++ b/libzypp/zypp/Dep.h @@ -80,6 +80,11 @@ namespace zypp */ const std::string & asString() const; + /** Translated dependency type (capitalized). + * \return The capitalized constants names translated. + */ + std::string asUserString() const; + /** Enumarator provided for use in \c switch statement. */ for_use_in_switch inSwitch() const { return _type; } diff --git a/libzypp/zypp/DiskUsage.cc b/libzypp/zypp/DiskUsage.cc deleted file mode 100644 index 61af853..0000000 --- a/libzypp/zypp/DiskUsage.cc +++ /dev/null @@ -1,91 +0,0 @@ -/*---------------------------------------------------------------------\ -| ____ _ __ __ ___ | -| |__ / \ / / . \ . \ | -| / / \ V /| _/ _/ | -| / /__ | | | | | | | -| /_____||_| |_| |_| | -| | -\---------------------------------------------------------------------*/ -/** \file zypp/DiskUsage.cc - * -*/ -#include "zypp/DiskUsage.h" -#include - -using namespace std; - -/////////////////////////////////////////////////////////////////// -namespace zypp -{ ///////////////////////////////////////////////////////////////// - std::ostream & operator<<( std::ostream & str, const DiskUsage::Entry & obj ) - { - return str << obj.path << '\t' << obj._size << "; files " << obj._files; - } - - DiskUsage::Entry DiskUsage::extract( const std::string & dirname_r ) - { - Entry ret( dirname_r ); - - iterator fst = begin(); - for ( ; fst != end() && !fst->isBelow( ret ); ++fst ) - ; // seek 1st equal or below - - bool found = false; - if ( fst != end() ) { - iterator lst = fst; - found = true; - // return the first found, the value is sum of all subdirectories below - ret += *lst; - for ( ; lst != end() && lst->isBelow( ret ); ++lst ) { - } - // remove - _dirs.erase( fst, lst ); - } - - // the dir entry has been found, update all parent entries - if (found) - { - std::string dname = dirname_r; - if (dname.size() > 1 && dname[0] != '/') - { - dname.insert(dname.begin(), '/'); - } - - Entry tmp( dname ); - - tmp._size = ret._size; - tmp._files = ret._files; - // subtract du from directories above - iterator fst = begin(); - for ( ; fst != end(); ++fst ) - { - // add slash if it's missing - std::string dd = fst->path; - if (dd.size() > 1 && dd[0] != '/') - { - dd.insert(dd.begin(), '/'); - } - - // update the entry - if (tmp.isBelow(dd)) - { - *fst -= tmp; - } - } - } - - return ret; - } - - std::ostream & operator<<( std::ostream & str, const DiskUsage & obj ) - { - str << "Package Disk Usage {" << endl; - for ( DiskUsage::EntrySet::const_iterator it = obj._dirs.begin(); it != obj._dirs.end(); ++it ) { - str << " " << *it << endl; - } - return str << "}"; - } - - -} // namespace zypp -/////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/DiskUsage.h b/libzypp/zypp/DiskUsage.h deleted file mode 100644 index 18fe1a9..0000000 --- a/libzypp/zypp/DiskUsage.h +++ /dev/null @@ -1,178 +0,0 @@ -/*---------------------------------------------------------------------\ -| ____ _ __ __ ___ | -| |__ / \ / / . \ . \ | -| / / \ V /| _/ _/ | -| / /__ | | | | | | | -| /_____||_| |_| |_| | -| | -\---------------------------------------------------------------------*/ -/** \file zypp/DiskUsage.h - * -*/ -#ifndef ZYPP_DISKUSAGE_H -#define ZYPP_DISKUSAGE_H - -#include -#include - -/////////////////////////////////////////////////////////////////// -namespace zypp -{ ///////////////////////////////////////////////////////////////// - - class DiskUsage { - public: - /** - * @short Holds data about how much space will be needed per directory. - **/ - struct Entry { - Entry() : _size(0), _files(0) {}; - Entry(const std::string& path_r, - const unsigned size_r = 0, - const unsigned files_r = 0) - : path(path_r), _size(size_r), _files(files_r) - { - // assert leading and trailing '/' - if ( ! path.empty() ) - { - if ( *path.begin() != '/' ) path.insert( path.begin(), '/' ); - if ( *path.rbegin() != '/' ) path.insert( path.end(), '/' ); - } - } - std::string path; - mutable unsigned _size; - mutable unsigned _files; - friend std::ostream & operator<<( std::ostream & str, const Entry & obj ); - /** - * Test for equality based on directory name. - **/ - bool operator==( const Entry & rhs ) const { - return path == rhs.path; - } - /** - * Order based on directory name. - **/ - bool operator<( const Entry & rhs ) const { - return path < rhs.path; - } - /** - * Return true if this entry denotes a directory equal to or below rhs._dirname. - **/ - bool isBelow( const Entry & rhs ) const { - // whether _dirname has prefix rhs._dirname - return( path.compare( 0, rhs.path.size(), rhs.path ) == 0 ); - } - /** - * Return true if this entry denotes a directory equal to or below dirname_r. - **/ - bool isBelow( const std::string & dirname_r ) const { - return isBelow( Entry( dirname_r ) ); - } - - /** - * Numerical operation based on size and files values. - **/ - const Entry & operator+=( const Entry & rhs ) const { - _size += rhs._size; - _files += rhs._files; - return *this; - } - /** - * Numerical operation based on size and files values. - **/ - const Entry & operator-=( const Entry & rhs ) const { - _size -= rhs._size; - _files -= rhs._files; - return *this; - } - }; - private: - typedef std::set EntrySet; - EntrySet _dirs; - public: - - DiskUsage() {}; - /** - * Add an entry. If already present, sum up the new entries size and files value. - **/ - void add( const Entry & newent_r ) { - std::pair res = _dirs.insert( newent_r ); - if ( !res.second ) { - *res.first += newent_r; - } - } - /** - * Add an entry. If already present, sum up the new entries size and files value. - **/ - void add( const std::string & dirname_r, const unsigned & size_r = 0, const unsigned & files_r = 0 ) { - add( Entry( dirname_r, size_r, files_r ) ); - } - /** - * Whether there is no entry available. - */ - bool empty() const { return _dirs.empty(); } - /** - * Number of entries - **/ - unsigned size() const { return _dirs.size(); } - /** - * Clear EntrySet - **/ - void clear() { _dirs.clear(); } - /** - * Sum up any entries for dirname_r and its descendants and remove them - * on the fly. Return the result. - **/ - Entry extract( const std::string & dirname_r ); - - public: - - typedef EntrySet::iterator iterator; - typedef EntrySet::reverse_iterator reverse_iterator; - - /** - * Forward iterator pointing to the first entry (if any) - **/ - iterator begin() { return _dirs.begin(); } - /** - * Forward iterator pointing behind the last entry. - **/ - iterator end() { return _dirs.end(); } - /** - * Reverse iterator pointing to the last entry (if any) - **/ - reverse_iterator rbegin() { return _dirs.rbegin(); } - /** - * Reverse iterator pointing before the first entry. - **/ - reverse_iterator rend() { return _dirs.rend(); } - - typedef EntrySet::const_iterator const_iterator; - typedef EntrySet::const_reverse_iterator const_reverse_iterator; - - /** - * Forward const iterator pointing to the first entry (if any) - **/ - const_iterator begin() const { return _dirs.begin(); } - /** - * Forward const iterator pointing behind the last entry. - **/ - const_iterator end() const { return _dirs.end(); } - /** - * Reverse const iterator pointing to the last entry (if any) - **/ - const_reverse_iterator rbegin() const { return _dirs.rbegin(); } - /** - * Reverse const iterator pointing before the first entry. - **/ - const_reverse_iterator rend()const { return _dirs.rend(); } - - public: - - friend std::ostream & operator<<( std::ostream & str, const DiskUsage & obj ); - - }; - /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////// -} // namespace zypp -/////////////////////////////////////////////////////////////////// -#endif // ZYPP_DISKUSAGE_H diff --git a/libzypp/zypp/DiskUsageCounter.cc b/libzypp/zypp/DiskUsageCounter.cc index aa33a75..6ce9c07 100644 --- a/libzypp/zypp/DiskUsageCounter.cc +++ b/libzypp/zypp/DiskUsageCounter.cc @@ -19,9 +19,11 @@ extern "C" #include "zypp/base/Easy.h" #include "zypp/base/LogTools.h" +#include "zypp/base/DtorReset.h" #include "zypp/base/String.h" #include "zypp/DiskUsageCounter.h" +#include "zypp/ExternalProgram.h" #include "zypp/sat/Pool.h" #include "zypp/sat/detail/PoolImpl.h" @@ -35,31 +37,8 @@ namespace zypp namespace { ///////////////////////////////////////////////////////////////// - struct SatMap : private base::NonCopyable + DiskUsageCounter::MountPointSet calcDiskUsage( DiskUsageCounter::MountPointSet result, const Bitmap & installedmap_r ) { - SatMap( unsigned capacity_r = 1 ) - { - ::map_init( &_installedmap, sat::Pool::instance().capacity() ); - } - - void add( sat::Solvable solv_r ) - { - MAPSET( &_installedmap, solv_r.id() ); - } - - void add( const PoolItem & pi_r ) - { add( pi_r->satSolvable() ); } - - void add( const ResObject::constPtr & obj_r ) - { add( obj_r->satSolvable() ); } - - mutable ::Map _installedmap; - }; - - DiskUsageCounter::MountPointSet calcDiskUsage( const DiskUsageCounter::MountPointSet & mps_r, const SatMap & installedmap_r ) - { - DiskUsageCounter::MountPointSet result = mps_r; - if ( result.empty() ) { // partitioning is not set @@ -69,20 +48,21 @@ namespace zypp sat::Pool satpool( sat::Pool::instance() ); // init libsolv result vector with mountpoints - static const ::DUChanges _initdu = { 0, 0, 0 }; + static const ::DUChanges _initdu = { 0, 0, 0, 0 }; std::vector< ::DUChanges> duchanges( result.size(), _initdu ); { unsigned idx = 0; for_( it, result.begin(), result.end() ) { duchanges[idx].path = it->dir.c_str(); + if ( it->growonly ) + duchanges[idx].flags |= DUCHANGES_ONLYADD; ++idx; } } - // now calc... ::pool_calc_duchanges( satpool.get(), - &installedmap_r._installedmap, + const_cast(installedmap_r), &duchanges[0], duchanges.size() ); @@ -92,7 +72,6 @@ namespace zypp for_( it, result.begin(), result.end() ) { static const ByteCount blockAdjust( 2, ByteCount::K ); // (files * blocksize) / (2 * 1K) - it->pkg_size = it->used_size // current usage + duchanges[idx].kbytes // package data size + ( duchanges[idx].files * it->block_size / blockAdjust ); // half block per file @@ -107,29 +86,44 @@ namespace zypp } // namespace /////////////////////////////////////////////////////////////////// - DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage( const ResPool & pool_r ) + DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage( const ResPool & pool_r ) const { - SatMap installedmap( sat::Pool::instance().capacity() ); + Bitmap bitmap( Bitmap::poolSize ); + // build installedmap (installed != transact) // stays installed or gets installed for_( it, pool_r.begin(), pool_r.end() ) { if ( it->status().isInstalled() != it->status().transacts() ) { - installedmap.add( *it ); + bitmap.set( sat::asSolvable()(*it).id() ); } } - return calcDiskUsage( mps, installedmap ); + return calcDiskUsage( _mps, bitmap ); } - DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage( sat::Solvable solv_r ) + DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage( sat::Solvable solv_r ) const { - SatMap installedmap; - installedmap.add( solv_r ); - return calcDiskUsage( mps, installedmap ); + Bitmap bitmap( Bitmap::poolSize ); + bitmap.set( solv_r.id() ); + + // temp. unset @system Repo + DtorReset tmp( sat::Pool::instance().get()->installed ); + sat::Pool::instance().get()->installed = nullptr; + + return calcDiskUsage( _mps, bitmap ); } - DiskUsageCounter::MountPointSet DiskUsageCounter::detectMountPoints(const std::string &rootdir) + DiskUsageCounter::MountPointSet DiskUsageCounter::disk_usage( const Bitmap & bitmap_r ) const + { + // temp. unset @system Repo + DtorReset tmp( sat::Pool::instance().get()->installed ); + sat::Pool::instance().get()->installed = nullptr; + + return calcDiskUsage( _mps, bitmap_r ); + } + + DiskUsageCounter::MountPointSet DiskUsageCounter::detectMountPoints( const std::string & rootdir ) { DiskUsageCounter::MountPointSet ret; @@ -148,12 +142,12 @@ namespace zypp if ( !(procmounts.fail() || procmounts.bad()) ) { // data to consume - // rootfs / rootfs rw 0 0 + // rootfs / rootfs rw 0 0 // /dev/root / reiserfs rw 0 0 - // proc /proc proc rw 0 0 - // devpts /dev/pts devpts rw 0 0 + // proc /proc proc rw 0 0 + // devpts /dev/pts devpts rw 0 0 // /dev/hda5 /boot ext2 rw 0 0 - // shmfs /dev/shm shm rw 0 0 + // shmfs /dev/shm shm rw 0 0 // usbdevfs /proc/bus/usb usbdevfs rw 0 0 std::vector words; @@ -239,28 +233,54 @@ namespace zypp // // Check whether mounted readonly // - bool ro = false; + MountPoint::HintFlags hints; + std::vector flags; str::split( words[3], std::back_inserter(flags), "," ); for ( unsigned i = 0; i < flags.size(); ++i ) { if ( flags[i] == "ro" ) { - ro = true; + hints |= MountPoint::Hint_readonly; break; } } - if ( ro ) { + if ( hints.testFlag( MountPoint::Hint_readonly ) ) { DBG << "Filter ro mount point : " << l << std::endl; continue; } + // + // check for snapshotting btrfs + // + if ( words[2] == "btrfs" ) + { + if ( geteuid() != 0 ) + { + DBG << "Assume snapshots on " << words[1] << ": non-root user can't check" << std::endl; + hints |= MountPoint::Hint_growonly; + } + else + { + // For now just check whether there is + // at least one snapshot on the volume: + ExternalProgram prog({"btrfs","subvolume","list","-s",words[1]}); + std::string line( prog.receiveLine() ); + if ( ! line.empty() ) + { + DBG << "Found a snapshot on " << words[1] << ": " << line; // has trailing std::endl + hints |= MountPoint::Hint_growonly; + } + prog.kill(); + } + } + // // statvfs (full path!) and get the data // struct statvfs sb; if ( statvfs( words[1].c_str(), &sb ) != 0 ) { WAR << "Unable to statvfs(" << words[1] << "); errno " << errno << std::endl; - ret.insert( DiskUsageCounter::MountPoint( mp ) ); + ret.insert( DiskUsageCounter::MountPoint( mp, words[2], 0LL, 0LL, 0LL, 0LL, hints ) ); } else { @@ -272,9 +292,9 @@ namespace zypp DBG << "Filter zero-sized mount point : " << l << std::endl; continue; } - ret.insert( DiskUsageCounter::MountPoint( mp, sb.f_bsize, + ret.insert( DiskUsageCounter::MountPoint( mp, words[2], sb.f_bsize, ((long long)sb.f_blocks)*sb.f_bsize/1024, - ((long long)(sb.f_blocks - sb.f_bfree))*sb.f_bsize/1024, 0LL, ro ) ); + ((long long)(sb.f_blocks - sb.f_bfree))*sb.f_bsize/1024, 0LL, hints ) ); } } } @@ -296,10 +316,13 @@ namespace zypp << " ts: " << obj.totalSize() << " us: " << obj.usedSize() << " (+-: " << obj.commitDiff() - << ")]"; + << ")" << (obj.readonly?"r":"") << (obj.growonly?"g":"") << " " << obj.fstype << "]"; return str; } + std::ostream & operator<<( std::ostream & str, const DiskUsageCounter::MountPointSet & obj ) + { return dumpRange( str, obj.begin(), obj.end() ); } + ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/DiskUsageCounter.h b/libzypp/zypp/DiskUsageCounter.h index 439e78a..224bac1 100644 --- a/libzypp/zypp/DiskUsageCounter.h +++ b/libzypp/zypp/DiskUsageCounter.h @@ -12,141 +12,236 @@ #ifndef ZYPP_DISKUSAGE_COUNTER_H #define ZYPP_DISKUSAGE_COUNTER_H -#include "zypp/ResPool.h" - #include #include #include +#include "zypp/ResPool.h" +#include "zypp/Bitmap.h" +#include "zypp/base/Flags.h" + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// + /// \class DiskUsageCounter + /// \brief Compute disk space occupied by packages across partitions/directories + /////////////////////////////////////////////////////////////////// class DiskUsageCounter { public: - - /** - * @short Mount point description - **/ + /////////////////////////////////////////////////////////////////// + /// \class MountPoint + /// \brief Mount point description + /// If \ref block_size is set \ref DiskUsageCoutner will assume + /// half a block_size is wasted per file, in case a package + /// provides detailed isk usage information. + /////////////////////////////////////////////////////////////////// struct MountPoint { - /** - * Directory name - **/ - std::string dir; - - /** - * Block size of the mount point - **/ - long long block_size; - - /** - * Total size in K (1024) - **/ - long long total_size; - - /** - * Used size in K (1024) - **/ - long long used_size; - - /** - * Used size after commiting the pool (in K) - **/ - mutable long long pkg_size; - - bool readonly; - - /** - * Ctor - initialize directory and package size - **/ - MountPoint(std::string d = "/", long long bs = 0LL, long long total = 0LL, long long used = 0LL, long long pkg = 0LL, bool ro=false) : - dir(d), block_size(bs), total_size(total), used_size(used), pkg_size(pkg), readonly(ro) + friend std::ostream & operator<<( std::ostream & str, const MountPoint & obj ); + std::string dir; ///< Directory name + std::string fstype; ///< Filesystem type (provided by \ref detectMountPoints) + long long block_size; ///< Block size of the filesystem in B (0 if you don't care) + long long total_size; ///< Total size of the filesystem in KiB (0 if you don't care) + long long used_size; ///< Used size of the filesystem in KiB (0 if you don't care) + mutable long long pkg_size; ///< Used size after installation in KiB (computed by \ref DiskUsageCoutner) + // hint bits: + bool readonly:1; ///< hint for readonly partitions + bool growonly:1; ///< hint for growonly partitions (e.g. snapshotting btrfs) + + + /** HinFlags for ctor */ + enum Hint + { + NoHint = 0, + Hint_readonly = (1<<0), ///< readonly partitions + Hint_growonly = (1<<1), ///< growonly partitions (e.g. snapshotting btrfs) + }; + ZYPP_DECLARE_FLAGS(HintFlags,Hint); + + /** Ctor initialize directory, fstype and sizes */ + MountPoint( const std::string & d = "/", + const std::string & f = std::string(), + long long bs = 0LL, long long total = 0LL, long long used = 0LL, long long pkg = 0LL, + HintFlags hints = NoHint ) + : dir(d), fstype(f) + , block_size(bs), total_size(total), used_size(used), pkg_size(pkg) + , readonly(hints.testFlag(Hint_readonly)) + , growonly(hints.testFlag(Hint_growonly)) + {} + /** \overload const char * to allow e.g. initiailzer lists + * \code + * MountPointSet( { "/", "/usr", "/var" } ) + * \endcode + */ + MountPoint( const char * d, + const std::string & f = std::string(), + long long bs = 0LL, long long total = 0LL, long long used = 0LL, long long pkg = 0LL, + HintFlags hints = NoHint ) + : MountPoint( std::string(d?d:""), f, bs, total, used, pkg, hints ) + {} + + + /** Ctor initialize directory and sizes */ + MountPoint( const std::string & d, + long long bs, long long total = 0LL, long long used = 0LL, long long pkg = 0LL, + HintFlags hints = NoHint ) + : MountPoint( d, std::string(), bs, total, used, pkg, hints ) + {} + /** \overload const char * */ + MountPoint( const char * d, + long long bs, long long total = 0LL, long long used = 0LL, long long pkg = 0LL, + HintFlags hints = NoHint ) + : MountPoint( std::string(d?d:""), bs, total, used, pkg, hints ) + {} + + + /** Ctor just name and hints, all sizes 0 */ + MountPoint( const std::string & d, HintFlags hints ) + : MountPoint( d, std::string(), 0LL, 0LL, 0LL, 0LL, hints ) + {} + /** \overload const char * */ + MountPoint( const char * d, HintFlags hints ) + : MountPoint( std::string(d?d:""), hints ) + {} + /** \overload to prevent propagation Hint -> long long */ + MountPoint( const std::string & d, Hint hint ) + : MountPoint( d, HintFlags(hint) ) + {} + /** \overload to prevent propagation Hint -> long long */ + MountPoint( const char * d, Hint hint ) + : MountPoint( std::string(d?d:""), HintFlags(hint) ) {} - // sort by directory name + + /** \deprecated Use HintFlags instead of a trailing 'bool ro' argument. + * \code + * - MountPoint( "/usr", ..., true ); // readonly + * + MountPoint( "/usr", ..., MountPoint::Hint_readonly ); + * \endcode + */ + ZYPP_DEPRECATED MountPoint( const std::string & d, long long bs, long long total, long long used, long long pkg, bool ro ) + : MountPoint( d, bs, total, used, pkg, HintFlags(ro?Hint_readonly:NoHint) ) + {} + /** \deprecated Use HintFlags instead of a trailing 'bool ro' argument. + * \code + * - MountPoint( "/usr", ..., true ); // readonly + * + MountPoint( "/usr", ..., MountPoint::Hint_readonly ); + * \endcode + */ + ZYPP_DEPRECATED MountPoint( const char * d, long long bs, long long total, long long used, long long pkg, bool ro ) + : MountPoint( d, bs, total, used, pkg, HintFlags(ro?Hint_readonly:NoHint) ) + {} + + + /** Sort by directory name */ bool operator<( const MountPoint & rhs ) const - { - return dir < rhs.dir; - } + { return dir < rhs.dir; } + /** Block size of the filesystem as \ref ByteCount for convenience. */ ByteCount blockSize() const { return ByteCount( block_size, ByteCount::B ); } + /** Total size of the filesystem as \ref ByteCount for convenience. */ ByteCount totalSize() const { return ByteCount( total_size, ByteCount::K ); } + /** Used size of the filesystem as \ref ByteCount for convenience. */ ByteCount usedSize() const { return ByteCount( used_size, ByteCount::K ); } + /** Free size of the filesystem as \ref ByteCount for convenience. */ ByteCount freeSize() const { return ByteCount( total_size-used_size, ByteCount::K ); } + /** Used size after installation as \ref ByteCount for convenience. */ ByteCount usedAfterCommit() const { return ByteCount( pkg_size, ByteCount::K ); } + /** Free size after installation as \ref ByteCount for convenience. */ ByteCount freeAfterCommit() const { return ByteCount( total_size-pkg_size, ByteCount::K ); } + /** Size change due to installation as \ref ByteCount for convenience. */ ByteCount commitDiff() const { return ByteCount( pkg_size-used_size, ByteCount::K ); } }; + /////////////////////////////////////////////////////////////////// typedef std::set MountPointSet; DiskUsageCounter() {} - DiskUsageCounter( const MountPointSet & m ) - : mps( m ) + /** Ctor taking the MountPointSet to compute */ + DiskUsageCounter( const MountPointSet & mps_r ) + : _mps( mps_r ) {} - bool setMountPoints( const MountPointSet & m ) - { - mps = m; - return true; - } + /** Set a MountPointSet to compute */ + void setMountPoints( const MountPointSet & mps_r ) + { _mps = mps_r; } + /** Get the current MountPointSet */ const MountPointSet & getMountPoints() const - { - return mps; - } + { return _mps; } - static MountPointSet detectMountPoints(const std::string &rootdir = "/"); + /** Get mountpoints of system below \a rootdir + * If we happen to detect snapshotting btrfs partitions, the MountPoint::growonly + * hint is set. Disk usage computation will assume that deleted packages will not + * free any space (kept in a snapshot). + */ + static MountPointSet detectMountPoints( const std::string & rootdir = "/" ); + /** Only one entry for "/" to collect total sizes */ static MountPointSet justRootPartition(); - /** - * Compute disk usage of the pool - **/ - MountPointSet disk_usage( const ResPool & pool ); - /** - * Compute disk usage of one solvable - */ - MountPointSet disk_usage( sat::Solvable solv_r ); - /** \overload */ - MountPointSet disk_usage( const PoolItem & pi_r ) - { return disk_usage( pi_r.satSolvable() ); } - /** \overload */ - MountPointSet disk_usage( const ResObject::constPtr & obj_r ) + /** Compute disk usage if the current transaction woud be commited. */ + MountPointSet disk_usage( const ResPool & pool ) const; + + /** Compute disk usage of a single Solvable */ + MountPointSet disk_usage( sat::Solvable solv_r ) const; + /** \overload for PoolItem */ + MountPointSet disk_usage( const PoolItem & pi_r ) const + { return disk_usage( sat::asSolvable()( pi_r ) ); } + /** \overload for ResObject */ + MountPointSet disk_usage( const ResObject::constPtr & obj_r ) const + { return disk_usage( sat::asSolvable()( obj_r ) ); } + + /** Compute disk usage of a collection defined by a solvable bitmap. */ + MountPointSet disk_usage( const Bitmap & bitmap_r ) const; + + /** Compute disk usage of a collection (convertible by \ref asSolvable). */ + template + MountPointSet disk_usage( Iterator begin_r, Iterator end_r ) const { - if ( ! obj_r ) - return MountPointSet(); - return disk_usage( obj_r->satSolvable() ); + Bitmap bitmap( Bitmap::poolSize ); + for_( it, begin_r, end_r ) + bitmap.set( sat::asSolvable()( *it ).id() ); + return disk_usage( bitmap ); } private: - - MountPointSet mps; + MountPointSet _mps; }; /////////////////////////////////////////////////////////////////// + ZYPP_DECLARE_OPERATORS_FOR_FLAGS(DiskUsageCounter::MountPoint::HintFlags); + /** \relates DiskUsageCounter::MountPoint Stream output */ std::ostream & operator<<( std::ostream & str, const DiskUsageCounter::MountPoint & obj ); + /** \relates DiskUsageCounter::MountPointSet Stream output */ + std::ostream & operator<<( std::ostream & str, const DiskUsageCounter::MountPointSet & obj ); + + /** \relates DiskUsageCounter Stream output */ + inline std::ostream & operator<<( std::ostream & str, const DiskUsageCounter & obj ) + { return str << obj.getMountPoints(); } + ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/Edition.h b/libzypp/zypp/Edition.h index dec2bc7..165cf54 100644 --- a/libzypp/zypp/Edition.h +++ b/libzypp/zypp/Edition.h @@ -178,6 +178,15 @@ namespace zypp }; /////////////////////////////////////////////////////////////////// + /** \relates Edition XML output. */ + inline std::ostream & dumpAsXmlOn( std::ostream & str, const Edition & obj ) + { return str << ""; + } + ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/ExternalProgram.cc b/libzypp/zypp/ExternalProgram.cc index c319192..d415298 100644 --- a/libzypp/zypp/ExternalProgram.cc +++ b/libzypp/zypp/ExternalProgram.cc @@ -35,8 +35,7 @@ namespace zypp { ExternalProgram::ExternalProgram() : use_pty (false) , pid( -1 ) - { - } + {} ExternalProgram::ExternalProgram( std::string commandline, @@ -54,73 +53,56 @@ namespace zypp { argv[2] = commandline.c_str(); argv[3] = 0; - const char* rootdir = NULL; - if(!root.empty() && root != "/") - { - rootdir = root.asString().c_str(); - } - Environment environment; - start_program (argv, environment, stderr_disp, stderr_fd, default_locale, rootdir); + start_program( argv, Environment(), stderr_disp, stderr_fd, default_locale, root.c_str() ); } - ExternalProgram::ExternalProgram (const Arguments &argv, + ExternalProgram::ExternalProgram( const Arguments & argv, Stderr_Disposition stderr_disp, - bool use_pty, int stderr_fd, + bool use_pty, + int stderr_fd, bool default_locale, - const Pathname& root) + const Pathname & root ) : use_pty (use_pty) , pid( -1 ) { - const char * argvp[argv.size() + 1]; - unsigned c = 0; - for_( i, argv.begin(), argv.end() ) - { - argvp[c] = i->c_str(); - ++c; - } - argvp[c] = 0; + const char * argvp[argv.size() + 1]; + unsigned c = 0; + for_( i, argv.begin(), argv.end() ) + { + argvp[c] = i->c_str(); + ++c; + } + argvp[c] = 0; - Environment environment; - const char* rootdir = NULL; - if(!root.empty() && root != "/") - { - rootdir = root.asString().c_str(); - } - start_program (argvp, environment, stderr_disp, stderr_fd, default_locale, rootdir); + start_program( argvp, Environment(), stderr_disp, stderr_fd, default_locale, root.c_str() ); } - ExternalProgram::ExternalProgram (const Arguments &argv, + ExternalProgram::ExternalProgram( const Arguments & argv, const Environment & environment, Stderr_Disposition stderr_disp, - bool use_pty, int stderr_fd, + bool use_pty, + int stderr_fd, bool default_locale, - const Pathname& root) + const Pathname & root ) : use_pty (use_pty) , pid( -1 ) { - const char * argvp[argv.size() + 1]; - unsigned c = 0; - for_( i, argv.begin(), argv.end() ) - { - argvp[c] = i->c_str(); - ++c; - } - argvp[c] = 0; - - const char* rootdir = NULL; - if(!root.empty() && root != "/") - { - rootdir = root.asString().c_str(); - } - start_program (argvp, environment, stderr_disp, stderr_fd, default_locale, rootdir); + const char * argvp[argv.size() + 1]; + unsigned c = 0; + for_( i, argv.begin(), argv.end() ) + { + argvp[c] = i->c_str(); + ++c; + } + argvp[c] = 0; + start_program( argvp, environment, stderr_disp, stderr_fd, default_locale, root.c_str() ); } - ExternalProgram::ExternalProgram( const char *const *argv, Stderr_Disposition stderr_disp, bool use_pty, @@ -130,34 +112,27 @@ namespace zypp { : use_pty (use_pty) , pid( -1 ) { - const char* rootdir = NULL; - if(!root.empty() && root != "/") - { - rootdir = root.asString().c_str(); - } - Environment environment; - start_program (argv, environment, stderr_disp, stderr_fd, default_locale, rootdir); + start_program( argv, Environment(), stderr_disp, stderr_fd, default_locale, root.c_str() ); } - ExternalProgram::ExternalProgram (const char *const *argv, const Environment & environment, - Stderr_Disposition stderr_disp, bool use_pty, - int stderr_fd, bool default_locale, - const Pathname& root) + ExternalProgram::ExternalProgram( const char *const * argv, + const Environment & environment, + Stderr_Disposition stderr_disp, + bool use_pty, + int stderr_fd, + bool default_locale, + const Pathname & root ) : use_pty (use_pty) , pid( -1 ) { - const char* rootdir = NULL; - if(!root.empty() && root != "/") - { - rootdir = root.asString().c_str(); - } - start_program (argv, environment, stderr_disp, stderr_fd, default_locale, rootdir); + start_program( argv, environment, stderr_disp, stderr_fd, default_locale, root.c_str() ); } - ExternalProgram::ExternalProgram (const char *binpath, const char *const *argv_1, - bool use_pty) + ExternalProgram::ExternalProgram( const char *binpath, + const char *const *argv_1, + bool use_pty ) : use_pty (use_pty) , pid( -1 ) { @@ -166,14 +141,15 @@ namespace zypp { ; const char *argv[i + 1]; argv[0] = binpath; - memcpy (&argv[1], argv_1, (i - 1) * sizeof (char *)); - Environment environment; - start_program (argv, environment); + memcpy( &argv[1], argv_1, (i - 1) * sizeof (char *) ); + start_program( argv, Environment() ); } - ExternalProgram::ExternalProgram (const char *binpath, const char *const *argv_1, const Environment & environment, - bool use_pty) + ExternalProgram::ExternalProgram( const char *binpath, + const char *const *argv_1, + const Environment & environment, + bool use_pty ) : use_pty (use_pty) , pid( -1 ) { @@ -182,33 +158,75 @@ namespace zypp { ; const char *argv[i + 1]; argv[0] = binpath; - memcpy (&argv[1], argv_1, (i - 1) * sizeof (char *)); - start_program (argv, environment); + memcpy( &argv[1], argv_1, (i - 1) * sizeof (char *) ); + start_program( argv, environment ); } ExternalProgram::~ExternalProgram() - { - } + {} - void - ExternalProgram::start_program (const char *const *argv, const Environment & environment, - Stderr_Disposition stderr_disp, - int stderr_fd, bool default_locale, const char* root) + + void ExternalProgram::start_program( const char *const *argv, + const Environment & environment, + Stderr_Disposition stderr_disp, + int stderr_fd, + bool default_locale, + const char * root ) { pid = -1; _exitStatus = 0; - int to_external[2], from_external[2]; // fds for pair of pipes - int master_tty, slave_tty; // fds for pair of ttys + int to_external[2], from_external[2]; // fds for pair of pipes + int master_tty, slave_tty; // fds for pair of ttys + + // retrieve options at beginning of arglist + const char * redirectStdin = nullptr; // <[file] + const char * redirectStdout = nullptr; // >[file] + const char * chdirTo = nullptr; // #/[path] - const char * redirectStdin = 0; - if ( argv[0] && *argv[0] == '<' ) + if ( root ) { - redirectStdin = argv[0]+1; - if ( *redirectStdin == '\0' ) - redirectStdin = "/dev/null"; - ++argv; + if ( root[0] == '\0' ) + { + root = nullptr; // ignore empty root + } + else if ( root[0] == '/' && root[1] == '\0' ) + { + // If root is '/' do not chroot, but chdir to '/' + // unless arglist defines another dir. + chdirTo = "/"; + root = nullptr; + } + } + + for ( bool strip = false; argv[0]; ++argv ) + { + strip = false; + switch ( argv[0][0] ) + { + case '<': + strip = true; + redirectStdin = argv[0]+1; + if ( *redirectStdin == '\0' ) + redirectStdin = "/dev/null"; + break; + + case '>': + strip = true; + redirectStdout = argv[0]+1; + if ( *redirectStdout == '\0' ) + redirectStdout = "/dev/null"; + break; + + case '#': + strip = true; + if ( argv[0][1] == '/' ) // #/[path] + chdirTo = argv[0]+1; + break; + } + if ( ! strip ) + break; } // do not remove the single quotes around every argument, copy&paste of @@ -224,6 +242,8 @@ namespace zypp { } if ( redirectStdin ) cmdstr << " < '" << redirectStdin << "'"; + if ( redirectStdout ) + cmdstr << " > '" << redirectStdout << "'"; _command = cmdstr.str(); } DBG << "Executing " << _command << endl; @@ -291,6 +311,13 @@ namespace zypp { dup2( inp_fd, 0 ); } + if ( redirectStdout ) + { + ::close( 1 ); + int inp_fd = open( redirectStdout, O_WRONLY|O_CREAT|O_APPEND, 0600 ); + dup2( inp_fd, 1 ); + } + // Handle stderr if (stderr_disp == Discard_Stderr) { @@ -324,14 +351,18 @@ namespace zypp { std::cerr << _execError << endl;// After fork log on stderr too _exit (128); // No sense in returning! I am forked away!! } - if(chdir("/") == -1) - { - _execError = str::form( _("Can't chdir to '/' inside chroot (%s)."), strerror(errno) ); - std::cerr << _execError << endl;// After fork log on stderr too - _exit (128); // No sense in returning! I am forked away!! - } + if ( ! chdirTo ) + chdirTo = "/"; } + if ( chdirTo && chdir( chdirTo ) == -1 ) + { + _execError = root ? str::form( _("Can't chdir to '%s' inside chroot '%s' (%s)."), chdirTo, root, strerror(errno) ) + : str::form( _("Can't chdir to '%s' (%s)."), chdirTo, strerror(errno) ); + std::cerr << _execError << endl;// After fork log on stderr too + _exit (128); // No sense in returning! I am forked away!! + } + // close all filedesctiptors above stderr for ( int i = ::getdtablesize() - 1; i > 2; --i ) { ::close( i ); diff --git a/libzypp/zypp/ExternalProgram.h b/libzypp/zypp/ExternalProgram.h index d5f37c5..bc62a4c 100644 --- a/libzypp/zypp/ExternalProgram.h +++ b/libzypp/zypp/ExternalProgram.h @@ -85,7 +85,7 @@ namespace zypp { * @param commandline a shell commandline that is appended to * /bin/sh -c. * @param default_locale whether to set LC_ALL=C before starting - * @param root directory to chroot into, / or empty to not chroot + * @param root directory to chroot into; or just 'cd' if '/'l; nothing if empty */ ExternalProgram (std::string commandline, Stderr_Disposition stderr_disp = Normal_Stderr, @@ -97,6 +97,9 @@ namespace zypp { * If environment is provided, varaiables will be added to the childs environment, * overwriting existing ones. * + * Initial args starting with \c # are discarded but some are treated specially: + * #/[path] - chdir to /[path] before executing + * * Stdin redirection: If the \b 1st argument starts with a \b '<', the remaining * part is treated as file opened for reading on standard input (or \c /dev/null * if empty). @@ -105,6 +108,10 @@ namespace zypp { * const char* argv[] = { "', the remaining + * part is treated as file opened for writing on standard output (or \c /dev/null + * if empty). */ ExternalProgram(); diff --git a/libzypp/zypp/Fetcher.cc b/libzypp/zypp/Fetcher.cc index 5f16dbf..03924d6 100644 --- a/libzypp/zypp/Fetcher.cc +++ b/libzypp/zypp/Fetcher.cc @@ -573,7 +573,7 @@ namespace zypp if ( resource.optional() ) { ZYPP_CAUGHT(excpt_r); - WAR << "optional resource " << resource << " could not be transfered" << endl; + WAR << "optional resource " << resource << " could not be transferred" << endl; return; } else @@ -798,7 +798,7 @@ namespace zypp provideToDest(media, (*it_res)->location, dest_dir, (*it_res)->deltafile); - // if the file was not transfered, and no exception, just + // if the file was not transferred, and no exception, just // return, as it was an optional file if ( ! PathInfo(dest_dir + (*it_res)->location.filename()).isExist() ) return; diff --git a/libzypp/zypp/Fetcher.h b/libzypp/zypp/Fetcher.h index 0267967..777ce85 100644 --- a/libzypp/zypp/Fetcher.h +++ b/libzypp/zypp/Fetcher.h @@ -158,7 +158,7 @@ namespace zypp * checksums ) that will be retrieved and read * before the job processing starts. * - * Nothing will be transfered or checked + * Nothing will be transferred or checked * until \ref start() is called. * * The index is relative to the media path, and @@ -181,7 +181,7 @@ namespace zypp /** * Enqueue a object for transferal, they will not - * be transfered until \ref start() is called + * be transferred until \ref start() is called * */ void enqueue( const OnMediaLocation &resource, @@ -189,7 +189,7 @@ namespace zypp /** * Enqueue a object for transferal, they will not - * be transfered until \ref start() is called + * be transferred until \ref start() is called * * \note As \ref OnMediaLocation contains the digest information, * a \ref ChecksumFileChecker is automatically added to the @@ -244,7 +244,7 @@ namespace zypp * in each subdirectory. * * \note Every file CHECKSUMS.* except of CHECKSUMS.(asc|key|(void)) will - * not be transfered and will be ignored. + * not be transferred and will be ignored. * */ void enqueueDir( const OnMediaLocation &resource, @@ -288,7 +288,7 @@ namespace zypp * in each subdirectory. * * \note Every file CHECKSUMS.* except of CHECKSUMS.(asc|key|(void)) will - * not be transfered and will be ignored. + * not be transferred and will be ignored. * */ void enqueueDigestedDir( const OnMediaLocation &resource, diff --git a/libzypp/zypp/HistoryLog.cc b/libzypp/zypp/HistoryLog.cc index d1c96ba..5f1a8fd 100644 --- a/libzypp/zypp/HistoryLog.cc +++ b/libzypp/zypp/HistoryLog.cc @@ -192,27 +192,25 @@ namespace zypp return; _log - << timestamp() // 1 timestamp - << _sep << HistoryActionID::INSTALL.asString(true) // 2 action - << _sep << p->name() // 3 name - << _sep << p->edition() // 4 evr - << _sep << p->arch(); // 5 arch + << timestamp() // 1 timestamp + << _sep << HistoryActionID::INSTALL.asString(true) // 2 action + << _sep << p->name() // 3 name + << _sep << p->edition() // 4 evr + << _sep << p->arch(); // 5 arch // ApplLow is what the solver selected on behalf of the user. if (pi.status().isByUser() || pi.status().isByApplLow() ) - _log << _sep << userAtHostname(); // 6 reqested by + _log << _sep << userAtHostname(); // 6 reqested by else if (pi.status().isByApplHigh()) _log << _sep << pidAndAppname(); else _log << _sep; _log - << _sep << p->repoInfo().alias() // 7 repo alias - << _sep << p->checksum().checksum(); // 8 checksum - - _log << endl; - - //_log << pi << endl; + << _sep << p->repoInfo().alias() // 7 repo alias + << _sep << p->checksum().checksum() // 8 checksum + << _sep << str::escape(ZConfig::instance().userData(), _sep) // 9 userdata + << endl; } @@ -223,26 +221,23 @@ namespace zypp return; _log - << timestamp() // 1 timestamp - << _sep << HistoryActionID::REMOVE.asString(true) // 2 action - << _sep << p->name() // 3 name - << _sep << p->edition() // 4 evr - << _sep << p->arch(); // 5 arch + << timestamp() // 1 timestamp + << _sep << HistoryActionID::REMOVE.asString(true) // 2 action + << _sep << p->name() // 3 name + << _sep << p->edition() // 4 evr + << _sep << p->arch(); // 5 arch // ApplLow is what the solver selected on behalf of the user. if ( pi.status().isByUser() || pi.status().isByApplLow() ) - _log << _sep << userAtHostname(); // 6 reqested by + _log << _sep << userAtHostname(); // 6 reqested by else if (pi.status().isByApplHigh()) _log << _sep << pidAndAppname(); else _log << _sep; - // we don't have checksum in rpm db - // << _sep << p->checksum().checksum(); // x checksum - - _log << endl; - - //_log << pi << endl; + _log + << _sep << str::escape(ZConfig::instance().userData(), _sep) // 7 userdata + << endl; } ///////////////////////////////////////////////////////////////////////// @@ -250,11 +245,11 @@ namespace zypp void HistoryLog::addRepository(const RepoInfo & repo) { _log - << timestamp() // 1 timestamp - << _sep << HistoryActionID::REPO_ADD.asString(true) // 2 action - << _sep << str::escape(repo.alias(), _sep) // 3 alias - // what about the rest of the URLs?? - << _sep << *repo.baseUrlsBegin() // 4 primary URL + << timestamp() // 1 timestamp + << _sep << HistoryActionID::REPO_ADD.asString(true) // 2 action + << _sep << str::escape(repo.alias(), _sep) // 3 alias + << _sep << *repo.baseUrlsBegin() // 4 primary URL + << _sep << str::escape(ZConfig::instance().userData(), _sep) // 5 userdata << endl; } @@ -262,9 +257,10 @@ namespace zypp void HistoryLog::removeRepository(const RepoInfo & repo) { _log - << timestamp() // 1 timestamp - << _sep << HistoryActionID::REPO_REMOVE.asString(true) // 2 action - << _sep << str::escape(repo.alias(), _sep) // 3 alias + << 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 << endl; } @@ -275,20 +271,21 @@ namespace zypp if (oldrepo.alias() != newrepo.alias()) { _log - << timestamp() // 1 timestamp - << _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 + << timestamp() // 1 timestamp + << _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 << endl; } - if (*oldrepo.baseUrlsBegin() != *newrepo.baseUrlsBegin()) { _log - << timestamp() //1 timestamp - << _sep << HistoryActionID::REPO_CHANGE_URL.asString(true) // 2 action - << _sep << str::escape(oldrepo.alias(), _sep) // 3 old url - << _sep << *newrepo.baseUrlsBegin() // 4 new url + << timestamp() // 1 timestamp + << _sep << HistoryActionID::REPO_CHANGE_URL.asString(true) // 2 action + << _sep << str::escape(oldrepo.alias(), _sep) // 3 old url + << _sep << *newrepo.baseUrlsBegin() // 4 new url + << _sep << str::escape(ZConfig::instance().userData(), _sep) // 5 userdata << endl; } } diff --git a/libzypp/zypp/HistoryLog.h b/libzypp/zypp/HistoryLog.h index e2c0152..9ac4959 100644 --- a/libzypp/zypp/HistoryLog.h +++ b/libzypp/zypp/HistoryLog.h @@ -22,40 +22,36 @@ namespace zypp class RepoInfo; /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : HistoryLog - /** - * Simple wrapper for progress log. Refcnt, filename and corresponding - * ofstream are static members. Logfile constructor raises, destructor - * lowers refcounter. On refcounter changing from 0->1, file is opened. - * Changing from 1->0 the file is closed. Thus Logfile objects should be - * local to those functions, writing the log, and must not be stored - * permanently. - * - * Usage: - * - * some method () - * { - * PoolItem pi; - * ... - * HistoryLog().install(pi); - * ... - * HistoryLog().comment(someMessage); - * } - * - * - * \note Take care to set proper target root dir if needed. Either pass - * it via the constructor, or set it via setRoot(Pathname) method. - * The default location of the file is determined by - * \ref ZConfig::historyLogPath() which defaults to - * /var/log/zypp/history. - * - * \see http://en.opensuse.org/Libzypp/Package_History - * - * \todo The implementation as pseudo signleton is questionable. - * Use shared_ptr instead of handcrafted ref/unref. Manage multiple - * logs at different locations. - */ + /// \class HistoryLog + /// \brief Writing the zypp history file + /// \ingroup g_ZyppHistory + /// + /// Reference counted signleton for writhing the zypp history file. + /// The history file is opened on demand and closed when the last + /// HistoryLog object drops its reference. Thus HistoryLog objects + /// should be local to those functions, writing the log, and must + /// not be stored permanently. + /// + /// \code + /// some method () + /// { + /// PoolItem pi; + /// ... + /// HistoryLog().install(pi); + /// ... + /// HistoryLog().comment(someMessage); + /// } + /// \endcode + /// + /// \note Take care to set proper target root dir if needed. Either pass + /// it via the constructor, or set it via setRoot(Pathname) method. + /// The default location of the file is determined by + /// \ref zypp::ZConfig::historyLogPath (default: \c /var/log/zypp/history). + /// + /// \todo The implementation as pseudo signleton is questionable. + /// Use shared_ptr instead of handcrafted ref/unref. Manage multiple + /// logs at different locations. + /////////////////////////////////////////////////////////////////// class HistoryLog { HistoryLog( const HistoryLog & ); diff --git a/libzypp/zypp/HistoryLogData.cc b/libzypp/zypp/HistoryLogData.cc index 5a4163e..6ad34ce 100644 --- a/libzypp/zypp/HistoryLogData.cc +++ b/libzypp/zypp/HistoryLogData.cc @@ -21,73 +21,72 @@ using namespace std; +/////////////////////////////////////////////////////////////////// namespace zypp { using parser::ParseException; - /////////////////////////////////////////////////////////////////// // - // CLASS NAME : HistoryActionID + // class HistoryActionID // /////////////////////////////////////////////////////////////////// - static std::map _table; - - const HistoryActionID HistoryActionID::NONE(HistoryActionID::NONE_e); - const HistoryActionID HistoryActionID::INSTALL(HistoryActionID::INSTALL_e); - const HistoryActionID HistoryActionID::REMOVE(HistoryActionID::REMOVE_e); - const HistoryActionID HistoryActionID::REPO_ADD(HistoryActionID::REPO_ADD_e); - const HistoryActionID HistoryActionID::REPO_REMOVE(HistoryActionID::REPO_REMOVE_e); - const HistoryActionID HistoryActionID::REPO_CHANGE_ALIAS(HistoryActionID::REPO_CHANGE_ALIAS_e); - const HistoryActionID HistoryActionID::REPO_CHANGE_URL(HistoryActionID::REPO_CHANGE_URL_e); + const HistoryActionID HistoryActionID::NONE (HistoryActionID::NONE_e); + const HistoryActionID HistoryActionID::INSTALL (HistoryActionID::INSTALL_e); + const HistoryActionID HistoryActionID::REMOVE (HistoryActionID::REMOVE_e); + const HistoryActionID HistoryActionID::REPO_ADD (HistoryActionID::REPO_ADD_e); + const HistoryActionID HistoryActionID::REPO_REMOVE (HistoryActionID::REPO_REMOVE_e); + const HistoryActionID HistoryActionID::REPO_CHANGE_ALIAS (HistoryActionID::REPO_CHANGE_ALIAS_e); + const HistoryActionID HistoryActionID::REPO_CHANGE_URL (HistoryActionID::REPO_CHANGE_URL_e); HistoryActionID::HistoryActionID(const std::string & strval_r) : _id(parse(strval_r)) {} - HistoryActionID::ID HistoryActionID::parse(const std::string & strval_r) + HistoryActionID::ID HistoryActionID::parse( const std::string & strval_r ) { - if (_table.empty()) + typedef std::map MapType; + static MapType _table; + if ( _table.empty() ) { // initialize it - _table["install"] = INSTALL_e; - _table["remove"] = REMOVE_e; - _table["radd"] = REPO_ADD_e; - _table["rremove"] = REPO_REMOVE_e; - _table["ralias"] = REPO_CHANGE_ALIAS_e; - _table["rurl"] = REPO_CHANGE_URL_e; - _table["NONE"] = _table["none"] = HistoryActionID::NONE_e; + _table["install"] = INSTALL_e; + _table["remove"] = REMOVE_e; + _table["radd"] = REPO_ADD_e; + _table["rremove"] = REPO_REMOVE_e; + _table["ralias"] = REPO_CHANGE_ALIAS_e; + _table["rurl"] = REPO_CHANGE_URL_e; + _table["NONE"] = _table["none"] = NONE_e; } - std::map::const_iterator it = - _table.find(strval_r); - - if (it == _table.end()) - WAR << "Unknown history action ID '" + strval_r + "'"; - - return it->second; + MapType::const_iterator it = _table.find( strval_r ); + if ( it != _table.end() ) + return it->second; + // else: + WAR << "Unknown history action ID '" + strval_r + "'" << endl; + return NONE_e; } - const std::string & HistoryActionID::asString(bool pad) const + const std::string & HistoryActionID::asString( bool pad ) const { - static std::map _table; + typedef std::pair PairType; + typedef std::map MapType; + static MapType _table; if ( _table.empty() ) { - // initialize it - _table[INSTALL_e] = "install"; - _table[REMOVE_e] = "remove"; - _table[REPO_ADD_e] = "radd"; - _table[REPO_REMOVE_e] = "rremove"; - _table[REPO_CHANGE_ALIAS_e] = "ralias"; - _table[REPO_CHANGE_URL_e] = "rurl"; - _table[NONE_e] = "NONE"; + // initialize it pad(7) (for now) + _table[INSTALL_e] = PairType( "install" , "install" ); + _table[REMOVE_e] = PairType( "remove" , "remove " ); + _table[REPO_ADD_e] = PairType( "radd" , "radd " ); + _table[REPO_REMOVE_e] = PairType( "rremove" , "rremove" ); + _table[REPO_CHANGE_ALIAS_e] = PairType( "ralias" , "ralias " ); + _table[REPO_CHANGE_URL_e] = PairType( "rurl" , "rurl " ); + _table[NONE_e] = PairType( "NONE" , "NONE " ); } - // add spaces so that the size of the returned string is always 7 (for now) - if (pad) - return _table[_id].append(7 - _table[_id].size(), ' '); - return _table[_id]; + + return( pad ? _table[_id].second : _table[_id].first ); } std::ostream & operator << (std::ostream & str, const HistoryActionID & id) @@ -95,237 +94,206 @@ namespace zypp /////////////////////////////////////////////////////////////////// - - ///////////////////////////////////////////////////////////////////// - // - // CLASS NAME: HistoryItem - // - ///////////////////////////////////////////////////////////////////// - - HistoryItem::HistoryItem(FieldVector & fields) - { - if (fields.size() <= 2) - ZYPP_THROW(ParseException( - str::form("Bad number of fields. Got %zd, expected more than %d.", - fields.size(), 2))); - - date = Date(fields[0], HISTORY_LOG_DATE_FORMAT); - action = HistoryActionID(str::trim(fields[1])); - } - - void HistoryItem::dumpTo(ostream & str) const - { - str << date.form(HISTORY_LOG_DATE_FORMAT) << "|" << action.asString(); - } - - ostream & operator<<(ostream & str, const HistoryItem & obj) - { - obj.dumpTo(str); - return str; - } - - - ///////////////////////////////////////////////////////////////////// - // - // CLASS NAME: HistoryItemInstall - // - ///////////////////////////////////////////////////////////////////// - - HistoryItemInstall::HistoryItemInstall(FieldVector & fields) - : HistoryItem(fields) - { - if (fields.size() != 8) - ZYPP_THROW(ParseException( - str::form("Bad number of fields. Got %zu, expected %u.", - fields.size(), 8))); - - name = fields[2]; - edition = Edition(fields[3]); - arch = Arch(fields[4]); - reqby = fields[5]; - repoalias = fields[6]; - checksum = CheckSum::sha(fields[7]); - } - - void HistoryItemInstall::dumpTo(ostream & str) const - { - HistoryItem::dumpTo(str); - str << "|" - << name << "|" - << edition << "|" - << arch << "|" - << reqby << "|" - << repoalias << "|" - << checksum; - } - - ostream & operator<<(ostream & str, const HistoryItemInstall & obj) - { - obj.dumpTo(str); - return str; - } - - - ///////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// // - // CLASS NAME: HistoryItemRemove + // class HistoryLogData::Impl // - ///////////////////////////////////////////////////////////////////// - - HistoryItemRemove::HistoryItemRemove(FieldVector & fields) - : HistoryItem(fields) + /////////////////////////////////////////////////////////////////// + class HistoryLogData::Impl { - if (fields.size() != 6) - ZYPP_THROW(ParseException( - str::form("Bad number of fields. Got %zu, expected %u.", - fields.size(), 6))); - - name = fields[2]; - edition = Edition(fields[3]); - arch = Arch(fields[4]); - reqby = fields[5]; - } + public: + Impl( FieldVector & fields_r, size_type expect_r ) + { + _checkFields( fields_r, expect_r ); + _field.swap( fields_r ); + // For whatever reason writer is ' '-padding the action field + // but we don't want to modify the vector before we moved it. + _field[ACTION_INDEX] = str::trim( _field[ACTION_INDEX] ); + _action = HistoryActionID( _field[ACTION_INDEX] ); + } - void HistoryItemRemove::dumpTo(ostream & str) const - { - HistoryItem::dumpTo(str); - str << "|" - << name << "|" - << edition << "|" - << arch << "|" - << reqby; - } + Impl( FieldVector & fields_r, HistoryActionID action_r, size_type expect_r ) + { + _checkFields( fields_r, expect_r ); + // For whatever reason writer is ' '-padding the action field + // but we don't want to modify the vector before we moved it. + std::string trimmed( str::trim( fields_r[ACTION_INDEX] ) ); + _action = HistoryActionID( trimmed ); + if ( _action != action_r ) + { + ZYPP_THROW( ParseException( str::form( "Bad action id. Got %s, expected %s.", + _action.asString().c_str(), + action_r.asString().c_str() ) ) ); + } + _field.swap( fields_r ); + // now adjust action field: + _field[ACTION_INDEX] = trimmed; + } - ostream & operator<<(ostream & str, const HistoryItemRemove & obj) - { - obj.dumpTo(str); - return str; - } + void _checkFields( const FieldVector & fields_r, size_type expect_r ) + { + if ( expect_r < 2 ) // at least 2 fields (date and action) are required + expect_r = 2; + if ( fields_r.size() < expect_r ) + { + ZYPP_THROW( ParseException( str::form( "Bad number of fields. Got %zd, expected at least %zd.", + fields_r.size(), + expect_r ) ) ); + } + try + { + _date = Date( fields_r[DATE_INDEX], HISTORY_LOG_DATE_FORMAT ); + } + catch ( const std::exception & excpt ) + { + ZYPP_THROW( ParseException( excpt.what() ) ); // invalid date format + } + // _action handled later + } + public: + FieldVector _field; + Date _date; + HistoryActionID _action; + }; - ///////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// // - // CLASS NAME: HistoryItemRepoAdd + // class HistoryLogData // - ///////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// - HistoryItemRepoAdd::HistoryItemRepoAdd(FieldVector & fields) - : HistoryItem(fields) - { - if (fields.size() != 4) - ZYPP_THROW(ParseException( - str::form("Bad number of fields. Got %zu, expected %u.", - fields.size(), 4))); + HistoryLogData::HistoryLogData( FieldVector & fields_r, size_type expect_r ) + : _pimpl( new Impl( fields_r, expect_r ) ) + {} - alias = fields[2]; - url = Url(fields[3]); - } + HistoryLogData::HistoryLogData( FieldVector & fields_r, HistoryActionID expectedId_r, size_type expect_r ) + : _pimpl( new Impl( fields_r, expectedId_r, expect_r ) ) + {} - void HistoryItemRepoAdd::dumpTo(ostream & str) const - { - HistoryItem::dumpTo(str); - str << "|" - << alias << "|" - << url; - } + HistoryLogData::~HistoryLogData() + {} - ostream & operator<<(ostream & str, const HistoryItemRepoAdd & obj) + HistoryLogData::Ptr HistoryLogData::create( FieldVector & fields_r ) { - obj.dumpTo(str); - return str; + if ( fields_r.size() >= 2 ) + { + // str::trim( _field[ACTION_INDEX] ); + switch ( HistoryActionID( str::trim( fields_r[ACTION_INDEX] ) ).toEnum() ) + { +#define OUTS(E,T) case HistoryActionID::E: return Ptr( new T( fields_r ) ); break; + OUTS( INSTALL_e, HistoryLogDataInstall ); + OUTS( REMOVE_e, HistoryLogDataRemove ); + OUTS( REPO_ADD_e, HistoryLogDataRepoAdd ); + OUTS( REPO_REMOVE_e, HistoryLogDataRepoRemove ); + OUTS( REPO_CHANGE_ALIAS_e, HistoryLogDataRepoAliasChange ); + OUTS( REPO_CHANGE_URL_e, HistoryLogDataRepoUrlChange ); +#undef OUTS + // intentionally no default: + case HistoryActionID::NONE_e: + break; + } + } + // unknown action or invalid fields? Ctor will accept or throw. + return Ptr( new HistoryLogData( fields_r ) ); } + bool HistoryLogData::empty() const + { return _pimpl->_field.empty(); } - ///////////////////////////////////////////////////////////////////// - // - // CLASS NAME: HistoryItemRepoRemove - // - ///////////////////////////////////////////////////////////////////// - - HistoryItemRepoRemove::HistoryItemRepoRemove(FieldVector & fields) - : HistoryItem(fields) - { - if (fields.size() != 3) - ZYPP_THROW(ParseException( - str::form("Bad number of fields. Got %zu, expected %u.", - fields.size(), 3))); + HistoryLogData::size_type HistoryLogData::size() const + { return _pimpl->_field.size(); } - alias = fields[2]; - } + HistoryLogData::const_iterator HistoryLogData::begin() const + { return _pimpl->_field.begin(); } - void HistoryItemRepoRemove::dumpTo(ostream & str) const - { - HistoryItem::dumpTo(str); - str << "|" << alias; - } + HistoryLogData::const_iterator HistoryLogData::end() const + { return _pimpl->_field.end(); } - ostream & operator<<(ostream & str, const HistoryItemRepoRemove & obj) + const std::string & HistoryLogData::optionalAt( size_type idx_r ) const { - obj.dumpTo(str); - return str; + static const std::string _empty; + return( idx_r < size() ? _pimpl->_field[idx_r] : _empty ); } + const std::string & HistoryLogData::at( size_type idx_r ) const + { return _pimpl->_field.at( idx_r ); } - ///////////////////////////////////////////////////////////////////// - // - // CLASS NAME: HistoryItemRepoAliasChange - // - ///////////////////////////////////////////////////////////////////// - - HistoryItemRepoAliasChange::HistoryItemRepoAliasChange(FieldVector & fields) - : HistoryItem(fields) - { - if (fields.size() != 4) - ZYPP_THROW(ParseException( - str::form("Bad number of fields. Got %zu, expected %u.", - fields.size(), 4))); - - oldalias = fields[2]; - newalias = fields[3]; - } - void HistoryItemRepoAliasChange::dumpTo(ostream & str) const - { - HistoryItem::dumpTo(str); - str << "|" << oldalias << "|" << newalias; - } + Date HistoryLogData::date() const + { return _pimpl->_date; } - ostream & operator<<(ostream & str, const HistoryItemRepoAliasChange & obj) - { - obj.dumpTo(str); - return str; - } + HistoryActionID HistoryLogData::action() const + { return _pimpl->_action; } - ///////////////////////////////////////////////////////////////////// - // - // CLASS NAME: HistoryItemRepoUrlChange - // - ///////////////////////////////////////////////////////////////////// + std::ostream & operator<<( std::ostream & str, const HistoryLogData & obj ) + { return str << str::joinEscaped( obj.begin(), obj.end(), '|' ); } - HistoryItemRepoUrlChange::HistoryItemRepoUrlChange(FieldVector & fields) - : HistoryItem(fields) - { - if (fields.size() != 4) - ZYPP_THROW(ParseException( - str::form("Bad number of fields. Got %zu, expected %u.", - fields.size(), 4))); + /////////////////////////////////////////////////////////////////// + // class HistoryLogDataInstall + /////////////////////////////////////////////////////////////////// + HistoryLogDataInstall::HistoryLogDataInstall( FieldVector & fields_r ) + : HistoryLogData( fields_r ) + {} + std::string HistoryLogDataInstall::name() const { return optionalAt( NAME_INDEX ); } + Edition HistoryLogDataInstall::edition() const { return Edition( optionalAt( EDITION_INDEX ) ); } + Arch HistoryLogDataInstall::arch() const { return Arch( optionalAt( ARCH_INDEX ) ); } + std::string HistoryLogDataInstall::reqby() const { return optionalAt( REQBY_INDEX ); } + std::string HistoryLogDataInstall::repoAlias() const { return optionalAt( REPOALIAS_INDEX ); } + CheckSum HistoryLogDataInstall::checksum() const { return optionalAt( CHEKSUM_INDEX ); } + std::string HistoryLogDataInstall::userdata() const { return optionalAt( USERDATA_INDEX ); } - alias = fields[2]; - newurl = Url(fields[3]); - } + /////////////////////////////////////////////////////////////////// + // class HistoryLogDataRemove + /////////////////////////////////////////////////////////////////// + HistoryLogDataRemove::HistoryLogDataRemove( FieldVector & fields_r ) + : HistoryLogData( fields_r ) + {} + std::string HistoryLogDataRemove::name() const { return optionalAt( NAME_INDEX ); } + Edition HistoryLogDataRemove::edition() const { return Edition( optionalAt( EDITION_INDEX ) ); } + Arch HistoryLogDataRemove::arch() const { return Arch( optionalAt( ARCH_INDEX ) ); } + std::string HistoryLogDataRemove::reqby() const { return optionalAt( REQBY_INDEX ); } + std::string HistoryLogDataRemove::userdata() const { return optionalAt( USERDATA_INDEX ); } - void HistoryItemRepoUrlChange::dumpTo(ostream & str) const - { - HistoryItem::dumpTo(str); - str << "|" << alias << "|" << newurl; - } + /////////////////////////////////////////////////////////////////// + // class HistoryLogDataRepoAdd + /////////////////////////////////////////////////////////////////// + HistoryLogDataRepoAdd::HistoryLogDataRepoAdd( FieldVector & fields_r ) + : HistoryLogData( fields_r ) + {} + std::string HistoryLogDataRepoAdd::alias() const { return optionalAt( ALIAS_INDEX ); } + Url HistoryLogDataRepoAdd::url() const { return optionalAt( URL_INDEX ); } + std::string HistoryLogDataRepoAdd::userdata() const { return optionalAt( USERDATA_INDEX ); } - ostream & operator<<(ostream & str, const HistoryItemRepoUrlChange & obj) - { - obj.dumpTo(str); - return str; - } + /////////////////////////////////////////////////////////////////// + // class HistoryLogDataRepoRemove + /////////////////////////////////////////////////////////////////// + HistoryLogDataRepoRemove::HistoryLogDataRepoRemove( FieldVector & fields_r ) + : HistoryLogData( fields_r ) + {} + std::string HistoryLogDataRepoRemove::alias() const { return optionalAt( ALIAS_INDEX ); } + std::string HistoryLogDataRepoRemove::userdata() const { return optionalAt( USERDATA_INDEX ); } + /////////////////////////////////////////////////////////////////// + // class HistoryLogDataRepoAliasChange + /////////////////////////////////////////////////////////////////// + HistoryLogDataRepoAliasChange::HistoryLogDataRepoAliasChange( FieldVector & fields_r ) + : HistoryLogData( fields_r ) + {} + std::string HistoryLogDataRepoAliasChange::oldAlias() const { return optionalAt( OLDALIAS_INDEX ); } + std::string HistoryLogDataRepoAliasChange::newAlias() const { return optionalAt( NEWALIAS_INDEX ); } + std::string HistoryLogDataRepoAliasChange::userdata() const { return optionalAt( USERDATA_INDEX ); } -} + /////////////////////////////////////////////////////////////////// + // class HistoryLogDataRepoUrlChange + /////////////////////////////////////////////////////////////////// + HistoryLogDataRepoUrlChange::HistoryLogDataRepoUrlChange( FieldVector & fields_r ) + : HistoryLogData( fields_r ) + {} + std::string HistoryLogDataRepoUrlChange::alias() const { return optionalAt( ALIAS_INDEX ); } + Url HistoryLogDataRepoUrlChange::newUrl() const { return optionalAt( NEWURL_INDEX ); } + std::string HistoryLogDataRepoUrlChange::userdata() const { return optionalAt( USERDATA_INDEX ); } + +} // namespace zypp +/////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/HistoryLogData.h b/libzypp/zypp/HistoryLogData.h index c542ef4..0428589 100644 --- a/libzypp/zypp/HistoryLogData.h +++ b/libzypp/zypp/HistoryLogData.h @@ -15,6 +15,7 @@ #include +#include "zypp/APIConfig.h" #include "zypp/Date.h" #include "zypp/Edition.h" #include "zypp/Arch.h" @@ -23,19 +24,15 @@ #define HISTORY_LOG_DATE_FORMAT "%Y-%m-%d %H:%M:%S" +/////////////////////////////////////////////////////////////////// namespace zypp { - - /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : HistoryActionID - // - /** - * Enumeration of known history actions. - * - * \ingroup g_EnumerationClass - */ + /// \class HistoryActionID + /// \brief Enumeration of known history actions. + /// \ingroup g_EnumerationClass + /// \ingroup g_ZyppHistory + /////////////////////////////////////////////////////////////////// struct HistoryActionID { static const HistoryActionID NONE; @@ -75,173 +72,316 @@ namespace zypp ID _id; }; + /** \relates HistoryActionID */ + inline bool operator==( const HistoryActionID & lhs, const HistoryActionID & rhs ) + { return lhs.toEnum() == rhs.toEnum(); } + + /** \relates HistoryActionID */ + inline bool operator!=( const HistoryActionID & lhs, const HistoryActionID & rhs ) + { return lhs.toEnum() != rhs.toEnum(); } + /** \relates HistoryActionID */ std::ostream & operator << (std::ostream & str, const HistoryActionID & id); /////////////////////////////////////////////////////////////////// - - ///////////////////////////////////////////////////////////////////// - // - // CLASS NAME: HistoryItem - // - class HistoryItem + /////////////////////////////////////////////////////////////////// + /// \class HistoryLogData + /// \brief A zypp history log line split into fields + /// \ingroup g_ZyppHistory + /// + /// Each valid history log line starts with a date and HistoryActionID + /// field. Subsequent fields depend on the kind of action. See derived + /// classes for convenient access to those flields. + /// + /// HistoryLogData itself provides mostly generic access to the fields + /// plain string values. Derived classes for well known entries tell + /// + /////////////////////////////////////////////////////////////////// + class HistoryLogData { public: - typedef shared_ptr Ptr; - typedef std::vector FieldVector; + typedef shared_ptr Ptr; + typedef shared_ptr constPtr; - public: - HistoryItem(FieldVector & fields); - virtual ~HistoryItem() - {} + typedef std::vector FieldVector; + typedef FieldVector::size_type size_type; + typedef FieldVector::const_iterator const_iterator; - virtual void dumpTo(std::ostream & str) const; + public: + /** Ctor \b moving \a FieldVector (via swap). + * \throws ParseException if \a fields_r has not at least \a expect_r entries + * \note 2 fields (date and action) are always required. + */ + explicit HistoryLogData( FieldVector & fields_r, size_type expect_r = 2 ); + + /** Ctor \b moving \a FieldVector (via swap). + * \throws ParseException if \a fields_r has the wrong \ref HistoryActionID or not at least \a expect_r entries. + * \note 2 fields (date and action) are always required. + */ + HistoryLogData( FieldVector & fields_r, HistoryActionID action_r, size_type expect_r = 2 ); + + /** Dtor */ + virtual ~HistoryLogData(); + + /** Factory method creating HistoryLogData classes. + * + * Moves \a fields_r into a HistoryLogData or derived object, depending on the + * HistoryActionID. For known action ids a coresponing HistoryLogData class + * is created, to allow convenient access to the field values. For unknown + * action ids a plain HistoryLogData object is created. \ref HistoryActionID + * \ref NONE_e id used in this case. + * + * \throws ParseException if \a fields_r does not contain the required format. + */ + static Ptr create( FieldVector & fields_r ); public: - Date date; - HistoryActionID action; - }; - ///////////////////////////////////////////////////////////////////// + /** Whether FieldVector is empty. */ + bool empty() const; + /** Number of fields in vector. */ + size_type size() const; - ///////////////////////////////////////////////////////////////////// - // - // CLASS NAME: HistoryItemInstall - // - class HistoryItemInstall : public HistoryItem - { - public: - typedef shared_ptr Ptr; + /** Iterator pointing to 1st element in vector (or end()). */ + const_iterator begin() const; - HistoryItemInstall(FieldVector & fields); - virtual ~HistoryItemInstall() - {} + /** Iterator pointing behind the last element in vector. */ + const_iterator end() const; - virtual void dumpTo(std::ostream & str) const; + /** Access (optional) field by number. + * \returns an empty string if \a idx_r is out of range. + * \see \ref at + */ + const std::string & optionalAt( size_type idx_r ) const; + /** \overload */ + const std::string & operator[]( size_type idx_r ) const + { return optionalAt( idx_r ); } + + /** Access (required) field by number. + * \throws std::out_of_range if \a idx_r is out of range. + * \see \ref optionalAt + */ + const std::string & at( size_type idx_r ) const; public: - std::string name; - Edition edition; - Arch arch; - std::string reqby; // TODO make this a class ReqBy - std::string repoalias; - CheckSum checksum; - }; - ///////////////////////////////////////////////////////////////////// + enum Index ///< indices of known fields + { + DATE_INDEX = 0, ///< date + ACTION_INDEX = 1, ///< HistoryActionID + }; + public: + Date date() const; ///< date + HistoryActionID action() const; ///< HistoryActionID (or \c NONE_e if unknown) - ///////////////////////////////////////////////////////////////////// - // - // CLASS NAME: HistoryItemRemove - // - class HistoryItemRemove : public HistoryItem - { public: - typedef shared_ptr Ptr; + class Impl; ///< Implementation class + private: + RWCOW_pointer _pimpl; ///< Pointer to implementation + protected: + HistoryLogData & operator=( const HistoryLogData & ); ///< no base class assign + }; - HistoryItemRemove(FieldVector & fields); - virtual ~HistoryItemRemove() - {} + /** \relates HistoryLogData Stream output */ + std::ostream & operator<<( std::ostream & str, const HistoryLogData & obj ); + /////////////////////////////////////////////////////////////////// - virtual void dumpTo(std::ostream & str) const; + /////////////////////////////////////////////////////////////////// + /// \class HistoryLogDataInstall + /// \brief A zypp history log line for an installed packaged. + /// \ingroup g_ZyppHistory + /////////////////////////////////////////////////////////////////// + class HistoryLogDataInstall : public HistoryLogData + { + public: + typedef shared_ptr Ptr; + typedef shared_ptr constPtr; + /** Ctor \b moving \a FieldVector (via swap). + * \throws ParseException if \a fields_r has the wrong \ref HistoryActionID or number of fields. + */ + HistoryLogDataInstall( FieldVector & fields_r ); public: - std::string name; - Edition edition; - Arch arch; - std::string reqby; - }; - ///////////////////////////////////////////////////////////////////// + enum Index ///< indices of known fields + { + DATE_INDEX = HistoryLogData::DATE_INDEX, + ACTION_INDEX = HistoryLogData::ACTION_INDEX, + NAME_INDEX, ///< package name + EDITION_INDEX, ///< package edition + ARCH_INDEX, ///< package architecture + REQBY_INDEX, ///< requested by (user@hostname, pid:appname, or empty (solver)) + REPOALIAS_INDEX, ///< repository providing the package + CHEKSUM_INDEX, ///< package checksum + USERDATA_INDEX, ///< userdata/transactionID + }; + public: + std::string name() const; ///< package name + Edition edition() const; ///< package edition + Arch arch() const; ///< package architecture + std::string reqby() const; ///< requested by (user@hostname, pid:appname, or empty (solver)) + std::string repoAlias() const; ///< repository providing the package + CheckSum checksum() const; ///< package checksum + std::string userdata() const; ///< userdata/transactionID + }; - ///////////////////////////////////////////////////////////////////// - // - // CLASS NAME: HistoryItemRepoAdd - // - class HistoryItemRepoAdd : public HistoryItem + /////////////////////////////////////////////////////////////////// + /// \class HistoryLogDataRemove + /// \brief A zypp history log line for a removed packge. + /// \ingroup g_ZyppHistory + /////////////////////////////////////////////////////////////////// + class HistoryLogDataRemove : public HistoryLogData { public: - typedef shared_ptr Ptr; + typedef shared_ptr Ptr; + typedef shared_ptr constPtr; + /** Ctor \b moving \a FieldVector (via swap). + * \throws ParseException if \a fields_r has the wrong \ref HistoryActionID or number of fields. + */ + HistoryLogDataRemove( FieldVector & fields_r ); - HistoryItemRepoAdd(FieldVector & fields); - virtual ~HistoryItemRepoAdd() - {} - - virtual void dumpTo(std::ostream & str) const; + public: + enum Index ///< indices of known fields + { + DATE_INDEX = HistoryLogData::DATE_INDEX, + ACTION_INDEX = HistoryLogData::ACTION_INDEX, + NAME_INDEX, ///< package name + EDITION_INDEX, ///< package edition + ARCH_INDEX, ///< package architecture + REQBY_INDEX, ///< requested by (user@hostname, pid:appname, or empty (solver)) + USERDATA_INDEX, ///< userdata/transactionID + }; public: - std::string alias; - Url url; + std::string name() const; ///< package name + Edition edition() const; ///< package edition + Arch arch() const; ///< package architecture + std::string reqby() const; ///< requested by (user@hostname, pid:appname, or empty (solver)) + std::string userdata() const; ///< userdata/transactionID }; - ///////////////////////////////////////////////////////////////////// - - ///////////////////////////////////////////////////////////////////// - // - // CLASS NAME: HistoryItemRepoRemove - // - class HistoryItemRepoRemove : public HistoryItem + /////////////////////////////////////////////////////////////////// + /// \class HistoryLogDataRepoAdd + /// \brief A zypp history log line for an added repository. + /// \ingroup g_ZyppHistory + /////////////////////////////////////////////////////////////////// + class HistoryLogDataRepoAdd : public HistoryLogData { public: - typedef shared_ptr Ptr; + typedef shared_ptr Ptr; + typedef shared_ptr constPtr; + /** Ctor \b moving \a FieldVector (via swap). + * \throws ParseException if \a fields_r has the wrong \ref HistoryActionID or number of fields. + */ + HistoryLogDataRepoAdd( FieldVector & fields_r ); - HistoryItemRepoRemove(FieldVector & fields); - virtual ~HistoryItemRepoRemove() - {} - - virtual void dumpTo(std::ostream & str) const; + public: + enum Index ///< indices of known fields + { + DATE_INDEX = HistoryLogData::DATE_INDEX, + ACTION_INDEX = HistoryLogData::ACTION_INDEX, + ALIAS_INDEX, ///< repository alias + URL_INDEX, ///< repository url + USERDATA_INDEX, ///< userdata/transactionID + }; public: - std::string alias; + std::string alias() const; ///< repository alias + Url url() const; ///< repository url + std::string userdata() const; ///< userdata/transactionID }; - ///////////////////////////////////////////////////////////////////// - - ///////////////////////////////////////////////////////////////////// - // - // CLASS NAME: HistoryItemRepoAliasChange - // - class HistoryItemRepoAliasChange : public HistoryItem + /////////////////////////////////////////////////////////////////// + /// \class HistoryLogDataRepoRemove + /// \brief A zypp history log line for a removed repository. + /// \ingroup g_ZyppHistory + /////////////////////////////////////////////////////////////////// + class HistoryLogDataRepoRemove : public HistoryLogData { public: - typedef shared_ptr Ptr; - - HistoryItemRepoAliasChange(FieldVector & fields); - virtual ~HistoryItemRepoAliasChange() - {} + typedef shared_ptr Ptr; + typedef shared_ptr constPtr; + /** Ctor \b moving \a FieldVector (via swap). + * \throws ParseException if \a fields_r has the wrong \ref HistoryActionID or number of fields. + */ + HistoryLogDataRepoRemove( FieldVector & fields_r ); - virtual void dumpTo(std::ostream & str) const; + public: + enum Index ///< indices of known fields + { + DATE_INDEX = HistoryLogData::DATE_INDEX, + ACTION_INDEX = HistoryLogData::ACTION_INDEX, + ALIAS_INDEX, ///< repository alias + USERDATA_INDEX, ///< userdata/transactionID + }; public: - std::string oldalias; - std::string newalias; + std::string alias() const; ///< repository alias + std::string userdata() const; ///< userdata/transactionID }; - ///////////////////////////////////////////////////////////////////// - - ///////////////////////////////////////////////////////////////////// - // - // CLASS NAME: HistoryItemRepoUrlChange - // - class HistoryItemRepoUrlChange : public HistoryItem + /////////////////////////////////////////////////////////////////// + /// \class HistoryLogDataRepoAliasChange + /// \brief A zypp history log line for a repo alias change. + /// \ingroup g_ZyppHistory + /////////////////////////////////////////////////////////////////// + class HistoryLogDataRepoAliasChange : public HistoryLogData { public: - typedef shared_ptr Ptr; + typedef shared_ptr Ptr; + typedef shared_ptr constPtr; + /** Ctor \b moving \a FieldVector (via swap). + * \throws ParseException if \a fields_r has the wrong \ref HistoryActionID or number of fields. + */ + HistoryLogDataRepoAliasChange( FieldVector & fields_r ); - HistoryItemRepoUrlChange(FieldVector & fields); - virtual ~HistoryItemRepoUrlChange() - {} - - virtual void dumpTo(std::ostream & str) const; + public: + enum Index ///< indices of known fields + { + DATE_INDEX = HistoryLogData::DATE_INDEX, + ACTION_INDEX = HistoryLogData::ACTION_INDEX, + OLDALIAS_INDEX, ///< repositories old alias + NEWALIAS_INDEX, ///< repositories new alias + USERDATA_INDEX, ///< userdata/transactionID + }; public: - std::string alias; - Url newurl; + std::string oldAlias() const; ///< repositories old alias + std::string newAlias() const; ///< repositories new alias + std::string userdata() const; ///< userdata/transactionID }; - ///////////////////////////////////////////////////////////////////// - std::ostream & operator<<(std::ostream & str, const HistoryItem & obj); + /////////////////////////////////////////////////////////////////// + /// \class HistoryLogDataRepoUrlChange + /// \brief A zypp history log line for a repo url change. + /// \ingroup g_ZyppHistory + /////////////////////////////////////////////////////////////////// + class HistoryLogDataRepoUrlChange : public HistoryLogData + { + public: + typedef shared_ptr Ptr; + typedef shared_ptr constPtr; + /** Ctor \b moving \a FieldVector (via swap). + * \throws ParseException if \a fields_r has the wrong \ref HistoryActionID or number of fields. + */ + HistoryLogDataRepoUrlChange( FieldVector & fields_r ); + + public: + enum Index ///< indices of known fields + { + DATE_INDEX = HistoryLogData::DATE_INDEX, + ACTION_INDEX = HistoryLogData::ACTION_INDEX, + ALIAS_INDEX, ///< repository alias + NEWURL_INDEX, ///< repositories new url + USERDATA_INDEX, ///< userdata/transactionID + }; -} + public: + std::string alias() const; ///< repository alias + Url newUrl() const; ///< repositories new url + std::string userdata() const; ///< userdata/transactionID + }; +} // namespace zypp +/////////////////////////////////////////////////////////////////// #endif /* ZYPP_HISTORYLOGDATA_H_ */ diff --git a/libzypp/zypp/IdString.h b/libzypp/zypp/IdString.h index 42c1fcc..407a113 100644 --- a/libzypp/zypp/IdString.h +++ b/libzypp/zypp/IdString.h @@ -15,8 +15,6 @@ #include #include -#include "zypp/base/SafeBool.h" - #include "zypp/sat/detail/PoolMember.h" /////////////////////////////////////////////////////////////////// @@ -38,8 +36,7 @@ namespace zypp * While comparison differs between \ref IdString::Null and \ref IdString::Empty * ( \c NULL and \c "" ), both are represented by an empty string \c "". */ - class IdString : protected sat::detail::PoolMember, - private base::SafeBool + class IdString : protected sat::detail::PoolMember { public: typedef sat::detail::IdType IdType; @@ -65,10 +62,10 @@ namespace zypp static const IdString Empty; public: -#ifndef SWIG // Swig treats it as syntax error /** Evaluate in a boolean context ( != \c Null ). */ - using base::SafeBool::operator bool_type; -#endif + explicit operator bool() const + { return _id; } + /** Whether the string is empty. * This is true for \ref Null and \ref Empty. */ @@ -105,11 +102,7 @@ namespace zypp /** Expert backdoor. */ IdType id() const { return _id; } - private: -#ifndef SWIG // Swig treats it as syntax error - friend base::SafeBool::operator bool_type() const; -#endif - bool boolTest() const { return _id; } + private: IdType _id; }; diff --git a/libzypp/zypp/IdStringType.h b/libzypp/zypp/IdStringType.h index f75cbbf..c590c60 100644 --- a/libzypp/zypp/IdStringType.h +++ b/libzypp/zypp/IdStringType.h @@ -83,10 +83,8 @@ namespace zypp * \ingroup g_CRTP */ template - class IdStringType : protected sat::detail::PoolMember, - private base::SafeBool + class IdStringType : protected sat::detail::PoolMember { - typedef typename base::SafeBool::bool_type bool_type; public: typedef IdString::IdType IdType; @@ -110,10 +108,10 @@ namespace zypp IdType id() const { return idStr().id(); } public: -#ifndef SWIG // Swig treats it as syntax error /** Evaluate in a boolean context ( ! empty() ). */ - using base::SafeBool::operator bool_type; -#endif + explicit operator bool() const + { return ! empty(); } + public: // - break it down to idString/const char* <=> idString/cont char* // - handle idString(0)/NULL being the least value @@ -152,12 +150,6 @@ namespace zypp if ( ! lhs ) return rhs ? -1 : 0; return rhs ? ::strcmp( lhs, rhs ) : 1; } - - private: -#ifndef SWIG // Swig treats it as syntax error - friend base::SafeBool::operator bool_type() const; -#endif - bool boolTest() const { return ! empty(); } }; /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/KeyRing.cc b/libzypp/zypp/KeyRing.cc index 87c166b..13cae3d 100644 --- a/libzypp/zypp/KeyRing.cc +++ b/libzypp/zypp/KeyRing.cc @@ -21,18 +21,18 @@ #include "zypp/ZYppFactory.h" #include "zypp/ZYpp.h" -#include "zypp/base/Logger.h" +#include "zypp/base/LogTools.h" #include "zypp/base/IOStream.h" #include "zypp/base/String.h" #include "zypp/base/Regex.h" #include "zypp/base/Gettext.h" +#include "zypp/base/WatchFile.h" #include "zypp/PathInfo.h" #include "zypp/KeyRing.h" #include "zypp/ExternalProgram.h" #include "zypp/TmpPath.h" -using namespace std; -using namespace zypp::filesystem; +using std::endl; #undef ZYPP_BASE_LOGGER_LOGGROUP #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing" @@ -59,11 +59,14 @@ namespace zypp _keyRingDefaultAccept = value_r; } - bool KeyRingReport::askUserToAcceptUnsignedFile( const string &file, const KeyContext &keycontext ) + void KeyRingReport::infoVerify( const std::string & file_r, const PublicKeyData & keyData_r, const KeyContext & keycontext ) + {} + + bool KeyRingReport::askUserToAcceptUnsignedFile( const std::string & file, const KeyContext & keycontext ) { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_UNSIGNED_FILE ); } KeyRingReport::KeyTrust - KeyRingReport::askUserToAcceptKey( const PublicKey &key, const KeyContext &keycontext ) + KeyRingReport::askUserToAcceptKey( const PublicKey & key, const KeyContext & keycontext ) { if ( _keyRingDefaultAccept.testFlag( KeyRing::TRUST_KEY_TEMPORARILY ) ) return KEY_TRUST_TEMPORARILY; @@ -72,12 +75,108 @@ namespace zypp return KEY_DONT_TRUST; } - bool KeyRingReport::askUserToAcceptUnknownKey( const string &file, const string &id, const KeyContext &keycontext ) + bool KeyRingReport::askUserToAcceptUnknownKey( const std::string & file, const std::string & id, const KeyContext & keycontext ) { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_UNKNOWNKEY ); } - bool KeyRingReport::askUserToAcceptVerificationFailed( const string &file, const PublicKey &key, const KeyContext &keycontext ) + bool KeyRingReport::askUserToAcceptVerificationFailed( const std::string & file, const PublicKey & key, const KeyContext & keycontext ) { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_VERIFICATION_FAILED ); } + namespace + { + /////////////////////////////////////////////////////////////////// + /// \class CachedPublicKeyData + /// \brief Functor returning the keyrings data (cached). + /// \code + /// const std::list & cachedPublicKeyData( const Pathname & keyring ); + /// \endcode + /////////////////////////////////////////////////////////////////// + struct CachedPublicKeyData // : private base::NonCopyable - but KeyRing uses RWCOW though also NonCopyable :( + { + const std::list & operator()( const Pathname & keyring_r ) const + { return getData( keyring_r ); } + + private: + struct Cache + { + // Empty copy ctor to allow insert into std::map as + // scoped_ptr is noncopyable. + Cache() {} + Cache( const Cache & rhs ) {} + + void assertCache( const Pathname & keyring_r ) + { + // .kbx since gpg2-2.1 + if ( !_keyringK ) + _keyringK.reset( new WatchFile( keyring_r/"pubring.kbx", WatchFile::NO_INIT ) ); + if ( !_keyringP ) + _keyringP.reset( new WatchFile( keyring_r/"pubring.gpg", WatchFile::NO_INIT ) ); + } + + bool hasChanged() const + { + bool k = _keyringK->hasChanged(); // be sure both files are checked + bool p = _keyringP->hasChanged(); + return k || p; + } + + std::list _data; + + private: + scoped_ptr _keyringK; + scoped_ptr _keyringP; + }; + + typedef std::map CacheMap; + + const std::list & getData( const Pathname & keyring_r ) const + { + Cache & cache( _cacheMap[keyring_r] ); + // init new cache entry + cache.assertCache( keyring_r ); + return getData( keyring_r, cache ); + } + + const std::list & getData( const Pathname & keyring_r, Cache & cache_r ) const + { + if ( cache_r.hasChanged() ) + { + const char* argv[] = + { + GPG_BINARY, + "--list-public-keys", + "--homedir", keyring_r.c_str(), + "--no-default-keyring", + "--quiet", + "--with-colons", + "--fixed-list-mode", + "--with-fingerprint", + "--with-sig-list", + "--no-tty", + "--no-greeting", + "--batch", + "--status-fd", "1", + NULL + }; + + PublicKeyScanner scanner; + ExternalProgram prog( argv ,ExternalProgram::Discard_Stderr, false, -1, true ); + for( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() ) + { + scanner.scan( line ); + } + prog.close(); + + cache_r._data.swap( scanner._keys ); + MIL << "Found keys: " << cache_r._data << endl; + } + return cache_r._data; + } + + mutable CacheMap _cacheMap; + }; + /////////////////////////////////////////////////////////////////// + } + /////////////////////////////////////////////////////////////////// // // CLASS NAME : KeyRing::Impl @@ -93,86 +192,95 @@ namespace zypp MIL << "Current KeyRing::DefaultAccept: " << _keyRingDefaultAccept << endl; } - void importKey( const PublicKey &key, bool trusted = false); - void multiKeyImport( const Pathname & keyfile_r, bool trusted_r = false); - void deleteKey( const string &id, bool trusted ); + void importKey( const PublicKey & key, bool trusted = false ); + void multiKeyImport( const Pathname & keyfile_r, bool trusted_r = false ); + void deleteKey( const std::string & id, bool trusted ); + + std::string readSignatureKeyId( const Pathname & signature ); - string readSignatureKeyId( const Pathname &signature ); + bool isKeyTrusted( const std::string & id ) + { return bool(publicKeyExists( id, trustedKeyRing() )); } + bool isKeyKnown( const std::string & id ) + { return publicKeyExists( id, trustedKeyRing() ) || publicKeyExists( id, generalKeyRing() ); } - bool isKeyTrusted( const string &id); - bool isKeyKnown( const string &id ); + std::list trustedPublicKeys() + { return publicKeys( trustedKeyRing() ); } + std::list publicKeys() + { return publicKeys( generalKeyRing() ); } - list trustedPublicKeys(); - list publicKeys(); + const std::list & trustedPublicKeyData() + { return publicKeyData( trustedKeyRing() ); } + const std::list & publicKeyData() + { return publicKeyData( generalKeyRing() ); } - list trustedPublicKeyIds(); - list publicKeyIds(); + void dumpPublicKey( const std::string & id, bool trusted, std::ostream & stream ) + { dumpPublicKey( id, ( trusted ? trustedKeyRing() : generalKeyRing() ), stream ); } - void dumpPublicKey( const string &id, bool trusted, ostream &stream ); + PublicKey exportPublicKey( const PublicKeyData & keyData ) + { return exportKey( keyData, generalKeyRing() ); } + PublicKey exportTrustedPublicKey( const PublicKeyData & keyData ) + { return exportKey( keyData, trustedKeyRing() ); } bool verifyFileSignatureWorkflow( - const Pathname &file, - const string filedesc, - const Pathname &signature, - const KeyContext &keycontext = KeyContext()); + const Pathname & file, + const std::string & filedesc, + const Pathname & signature, + const KeyContext & keycontext = KeyContext()); + + bool verifyFileSignature( const Pathname & file, const Pathname & signature ) + { return verifyFile( file, signature, generalKeyRing() ); } + bool verifyFileTrustedSignature( const Pathname & file, const Pathname & signature ) + { return verifyFile( file, signature, trustedKeyRing() ); } - bool verifyFileSignature( const Pathname &file, const Pathname &signature); - bool verifyFileTrustedSignature( const Pathname &file, const Pathname &signature); private: - //mutable map translations; - bool verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring); - void importKey( const Pathname &keyfile, const Pathname &keyring); - PublicKey exportKey( string id, const Pathname &keyring); - void dumpPublicKey( const string &id, const Pathname &keyring, ostream &stream ); - void deleteKey( const string &id, const Pathname &keyring ); + bool verifyFile( const Pathname & file, const Pathname & signature, const Pathname & keyring ); + void importKey( const Pathname & keyfile, const Pathname & keyring ); - list publicKeys(const Pathname &keyring); - list publicKeyIds(const Pathname &keyring); + PublicKey exportKey( const std::string & id, const Pathname & keyring ); + PublicKey exportKey( const PublicKeyData & keyData, const Pathname & keyring ); - bool publicKeyExists( string id, const Pathname &keyring); + void dumpPublicKey( const std::string & id, const Pathname & keyring, std::ostream & stream ); + filesystem::TmpFile dumpPublicKeyToTmp( const std::string & id, const Pathname & keyring ); - const Pathname generalKeyRing() const; - const Pathname trustedKeyRing() const; + void deleteKey( const std::string & id, const Pathname & keyring ); + + std::list publicKeys( const Pathname & keyring); + const std::list & publicKeyData( const Pathname & keyring ) + { return cachedPublicKeyData( keyring ); } + + /** Get \ref PublicKeyData for ID (\c false if ID is not found). */ + PublicKeyData publicKeyExists( const std::string & id, const Pathname & keyring ); + + const Pathname generalKeyRing() const + { return _general_tmp_dir.path(); } + const Pathname trustedKeyRing() const + { return _trusted_tmp_dir.path(); } // Used for trusted and untrusted keyrings - TmpDir _trusted_tmp_dir; - TmpDir _general_tmp_dir; + filesystem::TmpDir _trusted_tmp_dir; + filesystem::TmpDir _general_tmp_dir; Pathname _base_dir; - public: - /** Offer default Impl. */ - static shared_ptr nullimpl() - { - static shared_ptr _nullimpl( new Impl( TmpPath::defaultLocation() ) ); - return _nullimpl; - } private: - friend Impl * rwcowClone( const Impl * rhs ); - /** clone for RWCOW_pointer */ - Impl * clone() const - { return new Impl( *this ); } + /** Functor returning the keyrings data (cached). + * \code + * const std::list & cachedPublicKeyData( const Pathname & keyring ); + * \endcode + */ + CachedPublicKeyData cachedPublicKeyData; }; + /////////////////////////////////////////////////////////////////// - const Pathname KeyRing::Impl::generalKeyRing() const - { - return _general_tmp_dir.path(); - } - - const Pathname KeyRing::Impl::trustedKeyRing() const - { - return _trusted_tmp_dir.path(); - } - - void KeyRing::Impl::importKey( const PublicKey &key, bool trusted) + void KeyRing::Impl::importKey( const PublicKey & key, bool trusted ) { - callback::SendReport rpmdbEmitSignal; - callback::SendReport emitSignal; - importKey( key.path(), trusted ? trustedKeyRing() : generalKeyRing() ); if ( trusted ) { + callback::SendReport rpmdbEmitSignal; + callback::SendReport emitSignal; + rpmdbEmitSignal->trustedKeyAdded( key ); emitSignal->trustedKeyAdded( key ); } @@ -183,13 +291,13 @@ namespace zypp importKey( keyfile_r, trusted_r ? trustedKeyRing() : generalKeyRing() ); } - void KeyRing::Impl::deleteKey( const string &id, bool trusted) + void KeyRing::Impl::deleteKey( const std::string & id, bool trusted ) { PublicKey key; - if (trusted) + if ( trusted ) { - key = exportKey(id, trustedKeyRing()); + key = exportKey( id, trustedKeyRing() ); } deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() ); @@ -204,136 +312,84 @@ namespace zypp } } - list KeyRing::Impl::publicKeys() - { - return publicKeys( generalKeyRing() ); - } - - list KeyRing::Impl::trustedPublicKeys() - { - return publicKeys( trustedKeyRing() ); - } - - list KeyRing::Impl::publicKeyIds() - { - return publicKeyIds( generalKeyRing() ); - } - - list KeyRing::Impl::trustedPublicKeyIds() - { - return publicKeyIds( trustedKeyRing() ); - } - - bool KeyRing::Impl::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature) - { - return verifyFile( file, signature, trustedKeyRing() ); - } - - bool KeyRing::Impl::verifyFileSignature( const Pathname &file, const Pathname &signature) - { - return verifyFile( file, signature, generalKeyRing() ); - } - - bool KeyRing::Impl::isKeyTrusted( const string &id) - { - return publicKeyExists( id, trustedKeyRing() ); - } - - bool KeyRing::Impl::isKeyKnown( const string &id ) - { - MIL << endl; - if ( publicKeyExists( id, trustedKeyRing() ) ) - return true; - else - return publicKeyExists( id, generalKeyRing() ); - } - - bool KeyRing::Impl::publicKeyExists( string id, const Pathname &keyring) + PublicKeyData KeyRing::Impl::publicKeyExists( const std::string & id, const Pathname & keyring ) { MIL << "Searching key [" << id << "] in keyring " << keyring << endl; - list keys = publicKeys(keyring); - for (list::const_iterator it = keys.begin(); it != keys.end(); it++) + const std::list & keys( publicKeyData( keyring ) ); + for_( it, keys.begin(), keys.end() ) { if ( id == (*it).id() ) - - return true; + { + return *it; + } } - return false; + return PublicKeyData(); } - PublicKey KeyRing::Impl::exportKey( string id, const Pathname &keyring) + PublicKey KeyRing::Impl::exportKey( const PublicKeyData & keyData, const Pathname & keyring ) { - TmpFile tmp_file( _base_dir, "pubkey-"+id+"-" ); - MIL << "Going to export key " << id << " from " << keyring << " to " << tmp_file.path() << endl; - - try { - ofstream os(tmp_file.path().c_str()); - dumpPublicKey( id, keyring, os ); - os.close(); - return PublicKey( tmp_file ); - } - catch (BadKeyException &e) - { - ERR << "Cannot create public key " << id << " from " << keyring << " keyring to file " << e.keyFile() << endl; - // TranslatorExplanation first %s is key name, second is keyring name - // and third is keyfile name - ZYPP_THROW(Exception(boost::str(boost::format( - _("Cannot create public key %s from %s keyring to file %s")) - % id % keyring.asString() % e.keyFile().asString()))); - } - catch (exception &e) - { - ERR << "Cannot export key " << id << " from " << keyring << " keyring to file " << tmp_file.path() << endl; - } - return PublicKey(); + return PublicKey( dumpPublicKeyToTmp( keyData.id(), keyring ), keyData ); } - void KeyRing::Impl::dumpPublicKey( const string &id, bool trusted, ostream &stream ) + PublicKey KeyRing::Impl::exportKey( const std::string & id, const Pathname & keyring ) { - dumpPublicKey( id, ( trusted ? trustedKeyRing() : generalKeyRing() ), stream ); + PublicKeyData keyData( publicKeyExists( id, keyring ) ); + if ( keyData ) + return PublicKey( dumpPublicKeyToTmp( keyData.id(), keyring ), keyData ); + + // Here: key not found + WAR << "No key " << id << " to export from " << keyring << endl; + return PublicKey(); } - void KeyRing::Impl::dumpPublicKey( const string &id, const Pathname &keyring, ostream &stream ) + + void KeyRing::Impl::dumpPublicKey( const std::string & id, const Pathname & keyring, std::ostream & stream ) { const char* argv[] = { GPG_BINARY, + "-a", + "--export", + "--homedir", keyring.asString().c_str(), "--no-default-keyring", "--quiet", "--no-tty", "--no-greeting", "--no-permission-warning", "--batch", - "--homedir", - keyring.asString().c_str(), - "-a", - "--export", id.c_str(), NULL }; - ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true); - string line; - int count; - for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ ) + ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true ); + for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() ) { stream << line; } prog.close(); } + filesystem::TmpFile KeyRing::Impl::dumpPublicKeyToTmp( const std::string & id, const Pathname & keyring ) + { + filesystem::TmpFile tmpFile( _base_dir, "pubkey-"+id+"-" ); + MIL << "Going to export key " << id << " from " << keyring << " to " << tmpFile.path() << endl; + + std::ofstream os( tmpFile.path().c_str() ); + dumpPublicKey( id, keyring, os ); + os.close(); + return tmpFile; + } bool KeyRing::Impl::verifyFileSignatureWorkflow( - const Pathname &file, - const string filedesc, - const Pathname &signature, - const KeyContext &context) + const Pathname & file, + const std::string & filedesc, + const Pathname & signature, + const KeyContext & context ) { callback::SendReport report; - //callback::SendReport emitSignal; MIL << "Going to verify signature for " << filedesc << " ( " << file << " ) with " << signature << endl; // if signature does not exists, ask user if he wants to accept unsigned file. - if( signature.empty() || (!PathInfo(signature).isExist()) ) + if( signature.empty() || (!PathInfo( signature ).isExist()) ) { bool res = report->askUserToAcceptUnsignedFile( filedesc, context ); MIL << "User decision on unsigned file: " << res << endl; @@ -341,64 +397,71 @@ namespace zypp } // get the id of the signature - string id = readSignatureKeyId(signature); + std::string id = readSignatureKeyId( signature ); // doeskey exists in trusted keyring - if ( publicKeyExists( id, trustedKeyRing() ) ) + PublicKeyData trustedKeyData( publicKeyExists( id, trustedKeyRing() ) ); + if ( trustedKeyData ) { - PublicKey key = exportKey( id, trustedKeyRing() ); + MIL << "Key is trusted: " << trustedKeyData << endl; // lets look if there is an updated key in the // general keyring - if ( publicKeyExists( id, generalKeyRing() ) ) + PublicKeyData generalKeyData( publicKeyExists( id, generalKeyRing() ) ); + if ( generalKeyData ) { // bnc #393160: Comment #30: Compare at least the fingerprint // in case an attacker created a key the the same id. - PublicKey untkey = exportKey( id, generalKeyRing() ); - if ( untkey.fingerprint() == key.fingerprint() - && untkey.created() > key.created() ) + if ( trustedKeyData.fingerprint() == generalKeyData.fingerprint() + && trustedKeyData.created() < generalKeyData.created() ) { - MIL << "Key " << key << " was updated. Saving new version into trusted keyring." << endl; - importKey( untkey, true ); - key = untkey; - } + MIL << "Key was updated. Saving new version into trusted keyring: " << generalKeyData << endl; + importKey( exportKey( generalKeyData, generalKeyRing() ), true ); + trustedKeyData = generalKeyData = PublicKeyData(); // invalidated by import. + } } - MIL << "Key " << id << " " << key.name() << " is trusted" << endl; + if ( ! trustedKeyData ) // invalidated by previous import + trustedKeyData = publicKeyExists( id, trustedKeyRing() ); + report->infoVerify( filedesc, trustedKeyData, context ); + // it exists, is trusted, does it validates? if ( verifyFile( file, signature, trustedKeyRing() ) ) return true; else - return report->askUserToAcceptVerificationFailed( filedesc, key, context ); + { + return report->askUserToAcceptVerificationFailed( filedesc, exportKey( trustedKeyData, trustedKeyRing() ), context ); + } } else { - if ( publicKeyExists( id, generalKeyRing() ) ) + PublicKeyData generalKeyData( publicKeyExists( id, generalKeyRing() ) ); + if ( generalKeyData ) { - PublicKey key = exportKey( id, generalKeyRing()); + PublicKey key( exportKey( generalKeyData, generalKeyRing() ) ); MIL << "Exported key " << id << " to " << key.path() << endl; MIL << "Key " << id << " " << key.name() << " is not trusted" << endl; // ok the key is not trusted, ask the user to trust it or not - KeyRingReport::KeyTrust reply = report->askUserToAcceptKey(key, context); - if (reply == KeyRingReport::KEY_TRUST_TEMPORARILY || - reply == KeyRingReport::KEY_TRUST_AND_IMPORT) + KeyRingReport::KeyTrust reply = report->askUserToAcceptKey( key, context ); + if ( reply == KeyRingReport::KEY_TRUST_TEMPORARILY || + reply == KeyRingReport::KEY_TRUST_AND_IMPORT ) { MIL << "User wants to trust key " << id << " " << key.name() << endl; - //dumpFile(unKey.path()); + //dumpFile( unKey.path() ); - Pathname which_keyring; - if (reply == KeyRingReport::KEY_TRUST_AND_IMPORT) + Pathname whichKeyring; + if ( reply == KeyRingReport::KEY_TRUST_AND_IMPORT ) { MIL << "User wants to import key " << id << " " << key.name() << endl; importKey( key, true ); - which_keyring = trustedKeyRing(); + whichKeyring = trustedKeyRing(); } else - which_keyring = generalKeyRing(); + whichKeyring = generalKeyRing(); // emit key added - if ( verifyFile( file, signature, which_keyring ) ) + if ( verifyFile( file, signature, whichKeyring ) ) { MIL << "File signature is verified" << endl; return true; @@ -443,136 +506,65 @@ namespace zypp return false; } - list KeyRing::Impl::publicKeyIds(const Pathname &keyring) - { - static str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$"); - static str::regex rxColonsFpr("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$"); - - list ids; - - const char* argv[] = - { - GPG_BINARY, - "--no-default-keyring", - "--quiet", - "--list-public-keys", - "--with-colons", - "--with-fingerprint", - "--no-tty", - "--no-greeting", - "--batch", - "--status-fd", - "1", - "--homedir", - keyring.asString().c_str(), - NULL - }; - - ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true); - string line; - int count = 0; - - for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ ) - { - //MIL << line << endl; - str::smatch what; - if(str::regex_match(line, what, rxColons)) - { - string id; - string fingerprint; - if ( what[1] == "pub" ) - { - id = what[5]; - - string line2; - for(line2 = prog.receiveLine(); !line2.empty(); line2 = prog.receiveLine(), count++ ) - { - str::smatch what2; - if (str::regex_match(line2, what2, rxColonsFpr)) - { - if ( (what2[1] == "fpr") && (what2[1] != "pub") && (what2[1] !="sub")) - { - fingerprint = what2[10]; - break; - } - } - } - - ids.push_back(id); - MIL << "Found key " << "[" << id << "]" << endl; - } - //dumpRegexpResults(what); - } - } - prog.close(); - return ids; - } - - list KeyRing::Impl::publicKeys(const Pathname &keyring) + std::list KeyRing::Impl::publicKeys( const Pathname & keyring ) { + const std::list & keys( publicKeyData( keyring ) ); + std::list ret; - list keys; - - list ids = publicKeyIds(keyring); - - for ( list::const_iterator it = ids.begin(); it != ids.end(); ++it ) + for_( it, keys.begin(), keys.end() ) { - PublicKey key(exportKey( *it, keyring )); - keys.push_back(key); - MIL << "Found key " << "[" << key.id() << "]" << " [" << key.name() << "]" << " [" << key.fingerprint() << "]" << endl; + PublicKey key( exportKey( *it, keyring ) ); + ret.push_back( key ); + MIL << "Found key " << key << endl; } - return keys; + return ret; } - void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring) + void KeyRing::Impl::importKey( const Pathname & keyfile, const Pathname & keyring ) { - if ( ! PathInfo(keyfile).isExist() ) + if ( ! PathInfo( keyfile ).isExist() ) // TranslatorExplanation first %s is key name, second is keyring name ZYPP_THROW(KeyRingException(boost::str(boost::format( - _("Tried to import not existant key %s into keyring %s")) + _("Tried to import not existent key %s into keyring %s")) % keyfile.asString() % keyring.asString()))); const char* argv[] = { GPG_BINARY, + "--import", + "--homedir", keyring.asString().c_str(), "--no-default-keyring", "--quiet", "--no-tty", "--no-greeting", "--no-permission-warning", - "--status-fd", - "1", - "--homedir", - keyring.asString().c_str(), - "--import", + "--status-fd", "1", keyfile.asString().c_str(), NULL }; - ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true); + ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true ); prog.close(); } - void KeyRing::Impl::deleteKey( const string &id, const Pathname &keyring ) + void KeyRing::Impl::deleteKey( const std::string & id, const Pathname & keyring ) { const char* argv[] = { GPG_BINARY, + "--delete-keys", + "--homedir", keyring.asString().c_str(), "--no-default-keyring", "--yes", "--quiet", "--no-tty", "--batch", - "--status-fd", - "1", - "--homedir", - keyring.asString().c_str(), - "--delete-keys", + "--status-fd", "1", id.c_str(), NULL }; - ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true); + ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true ); int code = prog.close(); if ( code ) @@ -582,51 +574,49 @@ namespace zypp } - string KeyRing::Impl::readSignatureKeyId(const Pathname &signature ) + std::string KeyRing::Impl::readSignatureKeyId( const Pathname & signature ) { - if ( ! PathInfo(signature).isFile() ) + if ( ! PathInfo( signature ).isFile() ) ZYPP_THROW(Exception(boost::str(boost::format( _("Signature file %s not found"))% signature.asString()))); MIL << "Determining key id if signature " << signature << endl; // HACK create a tmp keyring with no keys - TmpDir dir(_base_dir, "fake-keyring"); + filesystem::TmpDir dir( _base_dir, "fake-keyring" ); const char* argv[] = { GPG_BINARY, + "--homedir", dir.path().asString().c_str(), "--no-default-keyring", "--quiet", "--no-tty", "--no-greeting", "--batch", - "--status-fd", - "1", - "--homedir", - dir.path().asString().c_str(), + "--status-fd", "1", signature.asString().c_str(), NULL }; - ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true); + ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true ); - string line; + std::string line; int count = 0; - str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$"); - string id; - for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ ) + str::regex rxNoKey( "^\\[GNUPG:\\] NO_PUBKEY (.+)\n$" ); + std::string id; + for( line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ ) { //MIL << "[" << line << "]" << endl; str::smatch what; - if(str::regex_match(line, what, rxNoKey)) + if( str::regex_match( line, what, rxNoKey ) ) { if ( what.size() >= 1 ) { id = what[1]; break; } - //dumpRegexpResults(what); + //dumpRegexpResults( what ); } } @@ -640,21 +630,19 @@ namespace zypp return id; } - bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring) + bool KeyRing::Impl::verifyFile( const Pathname & file, const Pathname & signature, const Pathname & keyring ) { const char* argv[] = { GPG_BINARY, + "--verify", + "--homedir", keyring.asString().c_str(), "--no-default-keyring", "--quiet", "--no-tty", "--batch", "--no-greeting", - "--status-fd", - "1", - "--homedir", - keyring.asString().c_str(), - "--verify", + "--status-fd", "1", signature.asString().c_str(), file.asString().c_str(), NULL @@ -670,9 +658,9 @@ namespace zypp // [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9 // [GNUPG:] NO_PUBKEY A84EDAE89C800ACA - ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true); + ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true ); - return (prog.close() == 0) ? true : false; + return ( prog.close() == 0 ) ? true : false; } /////////////////////////////////////////////////////////////////// @@ -683,112 +671,65 @@ namespace zypp // /////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////// - // - // METHOD NAME : KeyRing::KeyRing - // METHOD TYPE : Ctor - // - KeyRing::KeyRing(const Pathname &baseTmpDir) - : _pimpl( new Impl(baseTmpDir) ) + KeyRing::KeyRing( const Pathname & baseTmpDir ) + : _pimpl( new Impl( baseTmpDir ) ) {} - /////////////////////////////////////////////////////////////////// - // - // METHOD NAME : KeyRing::KeyRing - // METHOD TYPE : Ctor - // - //KeyRing::KeyRing( const Pathname &general_kr, const Pathname &trusted_kr ) - //: _pimpl( new Impl(general_kr, trusted_kr) ) - //{} - - /////////////////////////////////////////////////////////////////// - // - // METHOD NAME : KeyRing::~KeyRing - // METHOD TYPE : Dtor - // KeyRing::~KeyRing() {} - /////////////////////////////////////////////////////////////////// - // - // Forward to implementation: - // - /////////////////////////////////////////////////////////////////// - - void KeyRing::importKey( const PublicKey &key, bool trusted ) - { - _pimpl->importKey( key, trusted ); - } + void KeyRing::importKey( const PublicKey & key, bool trusted ) + { _pimpl->importKey( key, trusted ); } void KeyRing::multiKeyImport( const Pathname & keyfile_r, bool trusted_r ) - { - _pimpl->multiKeyImport( keyfile_r, trusted_r ); - } + { _pimpl->multiKeyImport( keyfile_r, trusted_r ); } - string KeyRing::readSignatureKeyId( const Pathname &signature ) - { - return _pimpl->readSignatureKeyId(signature); - } + std::string KeyRing::readSignatureKeyId( const Pathname & signature ) + { return _pimpl->readSignatureKeyId( signature ); } - void KeyRing::deleteKey( const string &id, bool trusted ) - { - _pimpl->deleteKey(id, trusted); - } + void KeyRing::deleteKey( const std::string & id, bool trusted ) + { _pimpl->deleteKey( id, trusted ); } - list KeyRing::publicKeys() - { - return _pimpl->publicKeys(); - } + std::list KeyRing::publicKeys() + { return _pimpl->publicKeys(); } - list KeyRing::trustedPublicKeys() - { - return _pimpl->trustedPublicKeys(); - } + std:: list KeyRing::trustedPublicKeys() + { return _pimpl->trustedPublicKeys(); } - list KeyRing::publicKeyIds() - { - return _pimpl->publicKeyIds(); - } + std::list KeyRing::publicKeyData() + { return _pimpl->publicKeyData(); } - list KeyRing::trustedPublicKeyIds() - { - return _pimpl->trustedPublicKeyIds(); - } + std::list KeyRing::trustedPublicKeyData() + { return _pimpl->trustedPublicKeyData(); } bool KeyRing::verifyFileSignatureWorkflow( - const Pathname &file, - const string filedesc, - const Pathname &signature, - const KeyContext &keycontext) - { - return _pimpl->verifyFileSignatureWorkflow(file, filedesc, signature, keycontext); - } + const Pathname & file, + const std::string filedesc, + const Pathname & signature, + const KeyContext & keycontext ) + { return _pimpl->verifyFileSignatureWorkflow( file, filedesc, signature, keycontext ); } - bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature) - { - return _pimpl->verifyFileSignature(file, signature); - } + bool KeyRing::verifyFileSignature( const Pathname & file, const Pathname & signature ) + { return _pimpl->verifyFileSignature( file, signature ); } - bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature) - { - return _pimpl->verifyFileTrustedSignature(file, signature); - } + bool KeyRing::verifyFileTrustedSignature( const Pathname & file, const Pathname & signature ) + { return _pimpl->verifyFileTrustedSignature( file, signature ); } - void KeyRing::dumpPublicKey( const string &id, bool trusted, ostream &stream ) - { - _pimpl->dumpPublicKey( id, trusted, stream); - } + void KeyRing::dumpPublicKey( const std::string & id, bool trusted, std::ostream & stream ) + { _pimpl->dumpPublicKey( id, trusted, stream ); } - bool KeyRing::isKeyTrusted( const string &id ) - { - return _pimpl->isKeyTrusted(id); - } + PublicKey KeyRing::exportPublicKey( const PublicKeyData & keyData ) + { return _pimpl->exportPublicKey( keyData ); } - bool KeyRing::isKeyKnown( const string &id ) - { - return _pimpl->isKeyKnown(id); - } + PublicKey KeyRing::exportTrustedPublicKey( const PublicKeyData & keyData ) + { return _pimpl->exportTrustedPublicKey( keyData ); } + + bool KeyRing::isKeyTrusted( const std::string & id ) + { return _pimpl->isKeyTrusted( id ); } + + bool KeyRing::isKeyKnown( const std::string & id ) + { return _pimpl->isKeyKnown( id ); } ///////////////////////////////////////////////////////////////// } // namespace zypp diff --git a/libzypp/zypp/KeyRing.h b/libzypp/zypp/KeyRing.h index c5ce8a7..f193ad6 100644 --- a/libzypp/zypp/KeyRing.h +++ b/libzypp/zypp/KeyRing.h @@ -76,6 +76,9 @@ namespace zypp */ virtual KeyTrust askUserToAcceptKey( const PublicKey &key, const KeyContext &keycontext = KeyContext() ); + /** Informal callback showing the trusted key that will be used for verification. */ + virtual void infoVerify( const std::string & file_r, const PublicKeyData & keyData_r, const KeyContext &keycontext = KeyContext() ); + virtual bool askUserToAcceptUnsignedFile( const std::string &file, const KeyContext &keycontext = KeyContext() ); /** @@ -188,6 +191,12 @@ namespace zypp void dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream ); + /** Export a public key identified by its key data. */ + PublicKey exportPublicKey( const PublicKeyData & keyData ); + + /** Export a trusted public key identified by its key data. */ + PublicKey exportTrustedPublicKey( const PublicKeyData & keyData ); + /** * reads the public key id from a signature */ @@ -196,7 +205,7 @@ namespace zypp /** * true if the key id is trusted */ - bool isKeyTrusted( const std::string &id); + bool isKeyTrusted( const std::string &id ); /** * true if the key id is knows, that means @@ -208,27 +217,27 @@ namespace zypp * removes a key from the keyring. * If trusted is true, Remove it from trusted keyring too. */ - void deleteKey( const std::string &id, bool trusted = false); + void deleteKey( const std::string &id, bool trusted = false ); /** - * Get a list of public keys in the keyring + * Get a list of public keys in the keyring (incl. ASCII armored keys in tmpfiles) */ std::list publicKeys(); /** - * Get a list of trusted public keys in the keyring + * Get a list of trusted public keys in the keyring (incl. ASCII armored keys in tmpfiles) */ std::list trustedPublicKeys(); /** - * Get a list of public key ids in the keyring + * Get a list of public key data in the keyring (key data only) */ - std::list publicKeyIds(); + std::list publicKeyData(); /** - * Get a list of trusted public key ids in the keyring + * Get a list of trusted public key data in the keyring (key data only) */ - std::list trustedPublicKeyIds(); + std::list trustedPublicKeyData(); /** * Follows a signature verification interacting with the user. @@ -267,16 +276,16 @@ namespace zypp * \param file Path of the file to be verified * \param signature Signature to verify the file against */ - bool verifyFileSignature( const Pathname &file, const Pathname &signature); + bool verifyFileSignature( const Pathname &file, const Pathname &signature ); - bool verifyFileTrustedSignature( const Pathname &file, const Pathname &signature); + bool verifyFileTrustedSignature( const Pathname &file, const Pathname &signature ); /** Dtor */ ~KeyRing(); private: /** Pointer to implementation */ - RWCOW_pointer _pimpl; + RW_pointer _pimpl; }; /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/MediaSetAccess.cc b/libzypp/zypp/MediaSetAccess.cc index c063563..a7c5f8d 100644 --- a/libzypp/zypp/MediaSetAccess.cc +++ b/libzypp/zypp/MediaSetAccess.cc @@ -256,9 +256,10 @@ IMPL_PTR_TYPE(MediaSetAccess); reason = media::MediaChangeReport::IO_SOFT; } - // non interactive only bother the user if wrong medium is in the drive - // otherwise propagate the error - if ( ( options & PROVIDE_NON_INTERACTIVE ) && reason != media::MediaChangeReport::WRONG) + // Propagate the original error if _no_ callback receiver is connected, or + // non_interactive mode (for optional files) is used (except for wrong media). + if ( ! callback::SendReport::connected() + || (( options & PROVIDE_NON_INTERACTIVE ) && reason != media::MediaChangeReport::WRONG ) ) { MIL << "Can't provide file. Non-Interactive mode." << endl; ZYPP_RETHROW(excp); @@ -284,7 +285,9 @@ IMPL_PTR_TYPE(MediaSetAccess); if( user == media::MediaChangeReport::ABORT ) { DBG << "Aborting" << endl; - ZYPP_RETHROW ( excp ); + AbortRequestException aexcp("Aborting requested by user"); + aexcp.remember(excp); + ZYPP_THROW(aexcp); } else if ( user == media::MediaChangeReport::IGNORE ) { @@ -296,10 +299,15 @@ IMPL_PTR_TYPE(MediaSetAccess); else if ( user == media::MediaChangeReport::EJECT ) { DBG << "Eject: try to release" << endl; - media_mgr.releaseAll(); - // eject - media_mgr.release (media, - devindex < devices.size() ? devices[devindex] : ""); + try + { + media_mgr.releaseAll(); + media_mgr.release (media, devindex < devices.size() ? devices[devindex] : ""); + } + catch ( const Exception & e) + { + ZYPP_CAUGHT(e); + } } else if ( user == media::MediaChangeReport::RETRY || user == media::MediaChangeReport::CHANGE_URL ) diff --git a/libzypp/zypp/OnMediaLocation.h b/libzypp/zypp/OnMediaLocation.h index d8faf52..2a34f4f 100644 --- a/libzypp/zypp/OnMediaLocation.h +++ b/libzypp/zypp/OnMediaLocation.h @@ -126,7 +126,7 @@ namespace zypp { _openchecksum = val_r; return *this; } /** - * Set the wether the resource is optional or not + * Set the whether the resource is optional or not * \see optional */ OnMediaLocation & setOptional( bool val ) diff --git a/libzypp/zypp/Package.cc b/libzypp/zypp/Package.cc index fd138af..db58620 100644 --- a/libzypp/zypp/Package.cc +++ b/libzypp/zypp/Package.cc @@ -9,6 +9,9 @@ /** \file zypp/Package.cc * */ +#include +#include + #include "zypp/base/Logger.h" #include "zypp/base/String.h" #include "zypp/Package.h" @@ -148,6 +151,43 @@ namespace zypp OnMediaLocation Package::location() const { return lookupLocation(); } + namespace + { + bool schemeIsLocalDir( const Url & url_r ) + { + std::string s( url_r.getScheme() ); + return s == "dir" || s == "file"; + } + } + + Pathname Package::cachedLocation() const + { + OnMediaLocation loc( location() ); + PathInfo pi( repoInfo().packagesPath() / loc.filename() ); + + if ( ! pi.isExist() ) + return Pathname(); // no file in cache + + if ( loc.checksum().empty() ) + { + Url url( repoInfo().url() ); + if ( ! schemeIsLocalDir( url ) ) + return Pathname(); // same name but no checksum to verify + + // for local repos compare with the checksum in repo + if ( CheckSum( CheckSum::md5Type(), std::ifstream( (url.getPathName() / loc.filename()).c_str() ) ) + != CheckSum( CheckSum::md5Type(), std::ifstream( pi.c_str() ) ) ) + return Pathname(); // same name but wrong checksum + } + else + { + if ( loc.checksum() != CheckSum( loc.checksum().type(), std::ifstream( pi.c_str() ) ) ) + return Pathname(); // same name but wrong checksum + } + + return pi.path(); // the right one + } + std::string Package::sourcePkgName() const { // no id means same as package diff --git a/libzypp/zypp/Package.h b/libzypp/zypp/Package.h index de515c7..2219b8d 100644 --- a/libzypp/zypp/Package.h +++ b/libzypp/zypp/Package.h @@ -122,6 +122,13 @@ namespace zypp */ OnMediaLocation location() const; + /** Location of the downloaded package in cache or an empty path. */ + Pathname cachedLocation() const; + + /** Whether the package is cached. */ + bool isCached() const + { return ! cachedLocation().empty(); } + protected: friend Ptr make( const sat::Solvable & solvable_r ); /** Ctor */ diff --git a/libzypp/zypp/Patch.cc b/libzypp/zypp/Patch.cc index 25057da..a7d81dc 100644 --- a/libzypp/zypp/Patch.cc +++ b/libzypp/zypp/Patch.cc @@ -41,72 +41,120 @@ namespace zypp Patch::~Patch() {} - /////////////////////////////////////////////////////////////////// - // - // Patch interface forwarded to implementation - // /////////////////////////////////////////////////////////////////// + std::string Patch::category() const + { return lookupStrAttribute( sat::SolvAttr::patchcategory ); } + Patch::Category Patch::categoryEnum() const + { return categoryEnum( category() ); } + + bool Patch::isCategory( const std::string & category_r ) const + { return( str::compareCI( category_r, category() ) == 0 ); } + + Patch::Category Patch::categoryEnum( const std::string & category_r ) { - static const IdString cat_yast ( "yast" ); - static const IdString cat_security ( "security" ); - static const IdString cat_recommended ( "recommended" ); - static const IdString cat_bugfix ( "bugfix" ); // rhn - static const IdString cat_optional ( "optional" ); - static const IdString cat_feature ( "feature" ); - static const IdString cat_enhancement ( "enhancement" ); // rnh - static const IdString cat_document ( "document" ); - - // patch category is not poolized in the solv file (i.e. an IdString) ;( - IdString cat( sat::LookupAttr( sat::SolvAttr::patchcategory, satSolvable() ).begin().c_str() ); - - if ( cat == cat_yast ) - return CAT_YAST; - if ( cat == cat_security ) - return CAT_SECURITY; - if ( cat == cat_recommended || cat == cat_bugfix ) - return CAT_RECOMMENDED; - if ( cat == cat_optional || cat == cat_enhancement || cat == cat_feature ) - return CAT_OPTIONAL; - if ( cat == cat_document ) - return CAT_DOCUMENT; + switch ( category_r[0] ) + { + // CAT_YAST + case 'y': + case 'Y': + if ( str::compareCI( category_r, "yast" ) == 0 ) + return CAT_YAST; + break; + + // CAT_SECURITY + case 's': + case 'S': + if ( str::compareCI( category_r, "security" ) == 0 ) + return CAT_SECURITY; + break; + + // CAT_RECOMMENDED + case 'r': + case 'R': + if ( str::compareCI( category_r, "recommended" ) == 0 ) + return CAT_RECOMMENDED; + break; + case 'b': + case 'B': + if ( str::compareCI( category_r, "bugfix" ) == 0 ) // rhn + return CAT_RECOMMENDED; + break; + // CAT_OPTIONAL + case 'o': + case 'O': + if ( str::compareCI( category_r, "optional" ) == 0 ) + return CAT_OPTIONAL; + break; + case 'f': + case 'F': + if ( str::compareCI( category_r, "feature" ) == 0 ) + return CAT_OPTIONAL; + break; + case 'e': + case 'E': + if ( str::compareCI( category_r, "enhancement" ) == 0 ) // rhn + return CAT_OPTIONAL; + break; + + // CAT_DOCUMENT + case 'd': + case 'D': + if ( str::compareCI( category_r, "document" ) == 0 ) + return CAT_DOCUMENT; + break; + } + // default: return CAT_OTHER; } + /////////////////////////////////////////////////////////////////// + std::string Patch::severity() const { return lookupStrAttribute( sat::SolvAttr::severity ); } Patch::SeverityFlag Patch::severityFlag() const + { return severityFlag( severity() ); } + + bool Patch::isSeverity( const std::string & severity_r ) const + { return( str::compareCI( severity_r, severity() ) == 0 ); } + + Patch::SeverityFlag Patch::severityFlag( const std::string & severity_r ) { - std::string sev( severity() ); - switch ( sev[0] ) + switch ( severity_r[0] ) { case 'l': case 'L': - if ( str::compareCI( sev, "low" ) == 0 ) + if ( str::compareCI( severity_r, "low" ) == 0 ) return SEV_LOW; break; case 'm': case 'M': - if ( str::compareCI( sev, "moderate" ) == 0 ) + if ( str::compareCI( severity_r, "moderate" ) == 0 ) return SEV_MODERATE; break; case 'i': case 'I': - if ( str::compareCI( sev, "important" ) == 0 ) + if ( str::compareCI( severity_r, "important" ) == 0 ) return SEV_IMPORTANT; break; case 'c': case 'C': - if ( str::compareCI( sev, "critical" ) == 0 ) + if ( str::compareCI( severity_r, "critical" ) == 0 ) return SEV_CRITICAL; break; + case 'u': + case 'U': + if ( str::compareCI( severity_r, "unspecified" ) == 0 ) + return SEV_NONE; + break; + case '\0': return SEV_NONE; break; @@ -130,12 +178,11 @@ namespace zypp return std::string( "unknown" ); } + /////////////////////////////////////////////////////////////////// + std::string Patch::message( const Locale & lang_r ) const { return lookupStrAttribute( sat::SolvAttr::message, lang_r ); } - std::string Patch::category() const - { return lookupStrAttribute( sat::SolvAttr::patchcategory ); } - bool Patch::rebootSuggested() const { return lookupBoolAttribute( sat::SolvAttr::rebootSuggested ); } @@ -220,7 +267,6 @@ namespace zypp continue; } -#warning definition of patch contents is poor - needs review /* find exact providers first (this matches the _real_ 'collection content' of the patch */ providers = sat::WhatProvides( Capability( arch, name.c_str(), Rel::EQ, edition, ResKind::package ) ); if ( providers.empty() ) diff --git a/libzypp/zypp/Patch.h b/libzypp/zypp/Patch.h index 253d5c0..31782a8 100644 --- a/libzypp/zypp/Patch.h +++ b/libzypp/zypp/Patch.h @@ -89,16 +89,29 @@ namespace zypp Date timestamp() const { return buildtime(); } + /** \name Patch Category */ + //@{ /** * Patch category (recommended, security,...) */ std::string category() const; - /** Patch category as enum of wellknown categories. + /** This patch's category as enum of wellknown categories. * Unknown values are mapped to \ref CAT_OTHER. */ Category categoryEnum() const; + /** Whether this patch's category matches \a category_r */ + bool isCategory( const std::string & category_r ) const; + + /** Patch category as enum of wellknown categories. + * Unknown values are mapped to \ref CAT_OTHER. + */ + static Category categoryEnum( const std::string & category_r ); + //@} + + /** \name Patch Severity */ + //@{ /** * Severity string as specified in metadata. * For use in computaions see \ref severityFlag. @@ -111,6 +124,15 @@ namespace zypp */ SeverityFlag severityFlag() const; + /** Whether this patch's severity matches \a severity_r */ + bool isSeverity( const std::string & severity_r ) const; + + /** Severity string mapped to an enum. + * Unknown string values are mapped to \ref SEV_OTHER + */ + static SeverityFlag severityFlag( const std::string & category_r ); + //@} + /** * Does the system need to reboot to finish the update process? */ diff --git a/libzypp/zypp/PathInfo.cc b/libzypp/zypp/PathInfo.cc index 1a0f4ff..08c1a10 100644 --- a/libzypp/zypp/PathInfo.cc +++ b/libzypp/zypp/PathInfo.cc @@ -18,10 +18,11 @@ #include #include -#include "zypp/base/Logger.h" +#include "zypp/base/LogTools.h" #include "zypp/base/String.h" #include "zypp/base/IOStream.h" #include "zypp/base/StrMatcher.h" +#include "zypp/base/Errno.h" #include "zypp/AutoDispose.h" #include "zypp/ExternalProgram.h" @@ -225,9 +226,9 @@ namespace zypp { if ( !isExist() ) return 0; - if ( owner() == getuid() ) { + if ( owner() == geteuid() ) { return( uperm()/0100 ); - } else if ( group() == getgid() ) { + } else if ( group() == getegid() ) { return( gperm()/010 ); } return operm(); @@ -235,24 +236,29 @@ namespace zypp /****************************************************************** ** - ** FUNCTION NAME : PathInfo::major + ** FUNCTION NAME : PathInfo::devMajor ** FUNCTION TYPE : unsigned int */ - unsigned int PathInfo::major() const + unsigned int PathInfo::devMajor() const { return isBlk() || isChr() ? ::major(statbuf_C.st_rdev) : 0; } /****************************************************************** ** - ** FUNCTION NAME : PathInfo::minor + ** FUNCTION NAME : PathInfo::devMinor ** FUNCTION TYPE : unsigned int */ - unsigned int PathInfo::minor() const + unsigned int PathInfo::devMinor() const { return isBlk() || isChr() ? ::minor(statbuf_C.st_rdev) : 0; } + unsigned int PathInfo::major() const + { INT << "Cleanup the code: This method is deprecated" << endl; return devMajor(); } + unsigned int PathInfo::minor() const + { INT << "Cleanup the code: This method is deprecated" << endl; return devMinor(); } + /****************************************************************** ** ** FUNCTION NAME : operator<< @@ -264,17 +270,15 @@ namespace zypp str << obj.asString() << "{"; if ( !obj.isExist() ) { - str << "does not exist}"; + str << Errno( obj.error() ); } else { str << obj.asStatMode() << " " << std::dec << obj.owner() << "/" << obj.group(); if ( obj.isFile() ) str << " size " << obj.size(); - - str << "}"; } - return str; + return str << "}"; } /////////////////////////////////////////////////////////////////// @@ -642,6 +646,9 @@ namespace zypp } ); } + std::ostream & operator<<( std::ostream & str, const DirContent & obj ) + { return dumpRange( str, obj.begin(), obj.end() ); } + /////////////////////////////////////////////////////////////////// // is_empty_dir /////////////////////////////////////////////////////////////////// @@ -837,6 +844,7 @@ namespace zypp { switch ( errno ) { + case EPERM: // /proc/sys/fs/protected_hardlink in proc(5) case EXDEV: // oldpath and newpath are not on the same mounted file system return copy( oldpath, newpath ); break; diff --git a/libzypp/zypp/PathInfo.h b/libzypp/zypp/PathInfo.h index 8209bad..248614f 100644 --- a/libzypp/zypp/PathInfo.h +++ b/libzypp/zypp/PathInfo.h @@ -27,6 +27,7 @@ extern "C" #include #include +#include "zypp/APIConfig.h" #include "zypp/Pathname.h" #include "zypp/CheckSum.h" #include "zypp/ByteCount.h" @@ -359,8 +360,13 @@ namespace zypp dev_t dev() const { return isExist() ? statbuf_C.st_dev : 0; } dev_t rdev() const { return isExist() ? statbuf_C.st_rdev : 0; } - unsigned int major() const; - unsigned int minor() const; + unsigned int devMajor() const; + unsigned int devMinor() const; + + /** \deprecated Name clashes with GNU libc macro, use \ref devMajor instead. */ + unsigned int major() const ZYPP_DEPRECATED; + /** \deprecated Name clashes with GNU libc macro, use \ref devMinor instead. */ + unsigned int minor() const ZYPP_DEPRECATED; //@} /** \name Size info. */ @@ -540,9 +546,14 @@ namespace zypp bool operator==( const DirEntry &rhs ) const; }; + inline std::ostream & operator<<( std::ostream & str, const DirEntry & obj ) + { return str << '[' << obj.type << "] " << obj.name; } + /** Returned by readdir. */ typedef std::list DirContent; + std::ostream & operator<<( std::ostream & str, const DirContent & obj ); + /** * Return content of directory via retlist. If dots is false * entries starting with '.' are not reported. "." and ".." diff --git a/libzypp/zypp/Pathname.cc b/libzypp/zypp/Pathname.cc index fb8037d..91656b9 100644 --- a/libzypp/zypp/Pathname.cc +++ b/libzypp/zypp/Pathname.cc @@ -29,13 +29,12 @@ namespace zypp // METHOD NAME : Pathname::_assign // METHOD TYPE : void // - void Pathname::_assign( const string & name_tv ) + void Pathname::_assign( const string & name_r ) { - prfx_i = 0; - name_t.clear(); - if ( name_tv.empty() ) + _name.clear(); + if ( name_r.empty() ) return; - name_t.reserve( name_tv.size() ); + _name.reserve( name_r.size() ); // Collect up to "/.." enum Pending { @@ -47,9 +46,9 @@ namespace zypp // Assert relative path starting with "./" // We rely on this below! - if ( name_tv[0] != '/' ) + if ( name_r[0] != '/' ) { - name_t += '.'; + _name += '.'; pending = P_slash; } @@ -60,21 +59,21 @@ namespace zypp // [*/..] + "/.." ==> [*/../..] // [*/foo] + "/.." ==> [*] auto goParent_f = [&](){ - if ( name_t.empty() ) + if ( _name.empty() ) /*NOOP*/; - else if ( name_t.size() == 1 ) // content is '.' - name_t += "/.."; + else if ( _name.size() == 1 ) // content is '.' + _name += "/.."; else { - std::string::size_type pos = name_t.rfind( "/" ); - if ( pos == name_t.size() - 3 && name_t[pos+1] == '.' && name_t[pos+2] == '.' ) - name_t += "/.."; + std::string::size_type pos = _name.rfind( "/" ); + if ( pos == _name.size() - 3 && _name[pos+1] == '.' && _name[pos+2] == '.' ) + _name += "/.."; else - name_t.erase( pos ); + _name.erase( pos ); } }; - for ( auto ch : name_tv ) + for ( auto ch : name_r ) { switch ( ch ) { @@ -91,10 +90,10 @@ namespace zypp case '.': switch ( pending ) { - case P_none: name_t += '.'; break; + case P_none: _name += '.'; break; case P_slash: pending = P_dot1; break; case P_dot1: pending = P_dot2; break; - case P_dot2: name_t += "/..."; pending = P_none; break; + case P_dot2: _name += "/..."; pending = P_none; break; } break; @@ -102,11 +101,11 @@ namespace zypp switch ( pending ) { case P_none: break; - case P_slash: name_t += '/'; pending = P_none; break; - case P_dot1: name_t += "/."; pending = P_none; break; - case P_dot2: name_t += "/.."; pending = P_none; break; + case P_slash: _name += '/'; pending = P_none; break; + case P_dot1: _name += "/."; pending = P_none; break; + case P_dot2: _name += "/.."; pending = P_none; break; } - name_t += ch; + _name += ch; break; } } @@ -114,9 +113,9 @@ namespace zypp switch ( pending ) { case P_none: break; - case P_slash: if ( name_t.empty() ) name_t = "/"; break; - case P_dot1: if ( name_t.empty() ) name_t = "/"; break; - case P_dot2: goParent_f(); if ( name_t.empty() ) name_t = "/"; break; + case P_slash: if ( _name.empty() ) _name = "/"; break; + case P_dot1: if ( _name.empty() ) _name = "/"; break; + case P_dot2: goParent_f(); if ( _name.empty() ) _name = "/"; break; } return; } @@ -126,20 +125,20 @@ namespace zypp // METHOD NAME : Pathname::dirname // METHOD TYPE : Pathname // - Pathname Pathname::dirname( const Pathname & name_tv ) + Pathname Pathname::dirname( const Pathname & name_r ) { - if ( name_tv.empty() ) + if ( name_r.empty() ) return Pathname(); - Pathname ret_t( name_tv ); - string::size_type idx = ret_t.name_t.find_last_of( '/' ); + Pathname ret_t( name_r ); + string::size_type idx = ret_t._name.find_last_of( '/' ); if ( idx == string::npos ) { - ret_t.name_t = "."; + ret_t._name = "."; } else if ( idx == 0 ) { - ret_t.name_t = "/"; + ret_t._name = "/"; } else { - ret_t.name_t.erase( idx ); + ret_t._name.erase( idx ); } return ret_t; @@ -150,12 +149,12 @@ namespace zypp // METHOD NAME : Pathname::basename // METHOD TYPE : string // - string Pathname::basename( const Pathname & name_tv ) + string Pathname::basename( const Pathname & name_r ) { - if ( name_tv.empty() ) + if ( name_r.empty() ) return string(); - string ret_t( name_tv.asString() ); + string ret_t( name_r.asString() ); string::size_type idx = ret_t.find_last_of( '/' ); if ( idx != string::npos && ( idx != 0 || ret_t.size() != 1 ) ) { ret_t.erase( 0, idx+1 ); @@ -169,13 +168,24 @@ namespace zypp // METHOD NAME : Pathname::asUrl // METHOD TYPE : Url // - Url Pathname::asUrl() const + Url Pathname::asUrl( const std::string & scheme_r ) const { - Url ret( "dir:///" ); + Url ret; ret.setPathName( asString() ); + ret.setScheme( scheme_r ); return ret; } + Url Pathname::asUrl() const + { return asUrl( "dir" ); } + + Url Pathname::asDirUrl() const + { return asUrl( "dir" ); } + + Url Pathname::asFileUrl() const + { return asUrl( "file" ); } + + std::string Pathname::showRoot( const Pathname & root_r, const Pathname & path_r ) { return str::Str() << "(" << root_r << ")" << path_r; @@ -193,12 +203,12 @@ namespace zypp // METHOD NAME : Pathname::extension // METHOD TYPE : string // - string Pathname::extension( const Pathname & name_tv ) + string Pathname::extension( const Pathname & name_r ) { - if ( name_tv.empty() ) + if ( name_r.empty() ) return string(); - string base( basename( name_tv ) ); + string base( basename( name_r ) ); string::size_type pos = base.rfind( '.' ); switch ( pos ) { @@ -236,17 +246,17 @@ namespace zypp // METHOD NAME : Pathname::cat // METHOD TYPE : Pathname // - Pathname Pathname::cat( const Pathname & name_tv, const Pathname & add_tv ) + Pathname Pathname::cat( const Pathname & name_r, const Pathname & add_tv ) { if ( add_tv.empty() ) - return name_tv; - if ( name_tv.empty() ) + return name_r; + if ( name_r.empty() ) return add_tv; - string ret_ti( name_tv.name_t ); - if( add_tv.name_t[0] != '/' ) + string ret_ti( name_r._name ); + if( add_tv._name[0] != '/' ) ret_ti += '/'; - return ret_ti + add_tv.name_t; + return ret_ti + add_tv._name; } /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/Pathname.h b/libzypp/zypp/Pathname.h index eedd7a5..a0375f7 100644 --- a/libzypp/zypp/Pathname.h +++ b/libzypp/zypp/Pathname.h @@ -39,32 +39,42 @@ namespace zypp * * \todo Add support for handling extensions incl. stripping * extensions from basename (basename("/path/foo.baa", ".baa") ==> "foo") - * \todo Review. Maybe use COW pimpl, check storage. - * \todo remove prfx_i */ class Pathname { public: /** Default ctor: an empty path. */ Pathname() - : prfx_i( 0 ) {} /** Ctor from string. */ - Pathname( const std::string & name_tv ) - { _assign( name_tv ); } + Pathname( const std::string & name_r ) + { _assign( name_r ); } /** Ctor from char*. */ - Pathname( const char * name_tv ) - { _assign( name_tv ? name_tv : "" ); } + Pathname( const char * name_r ) + { _assign( name_r ? name_r : "" ); } - /** Assign */ - Pathname & operator=( const Pathname & path_tv ) + /** Copy Ctor */ + Pathname( const Pathname & rhs ) + : _name( rhs._name ) + {} + + /** Swap */ + friend void swap( Pathname & lhs, Pathname & rhs ) { - prfx_i = path_tv.prfx_i; - name_t = path_tv.name_t; - return *this; + using std::swap; + swap( lhs._name, rhs._name ); } +#ifndef SWIG // Swig treats it as syntax error + /** Move Ctor */ + Pathname( Pathname && tmp ) + : _name( std::move( tmp._name ) ) + {} +#endif + /** Assign */ + Pathname & operator=( Pathname rhs ) + { swap( *this, rhs ); return *this; } /** Concatenate and assing. \see cat */ Pathname & operator/=( const Pathname & path_tv ) @@ -78,7 +88,7 @@ namespace zypp /** String representation. */ const std::string & asString() const - { return name_t; } + { return _name; } /** String representation as "(root)/path" */ static std::string showRoot( const Pathname & root_r, const Pathname & path_r ); @@ -86,44 +96,50 @@ namespace zypp /** String representation as "(root)/path", unless \a root is \c "/" or empty. */ static std::string showRootIf( const Pathname & root_r, const Pathname & path_r ); - /** Url representation using \c dir schema. */ + /** Url representation using \c scheme_r schema . */ + Url asUrl( const std::string & scheme_r ) const; + /** \overload using \c dir schema. */ Url asUrl() const; + /** \overload using \c dir schema. */ + Url asDirUrl() const; + /** \overload using \c file schema. */ + Url asFileUrl() const; /** String representation. */ const char * c_str() const - { return name_t.c_str(); } + { return _name.c_str(); } /** Test for an empty path. */ - bool empty() const { return name_t.empty(); } + bool empty() const { return _name.empty(); } /** Test for an absolute path. */ - bool absolute() const { return !empty() && name_t[prfx_i] == '/'; } + bool absolute() const { return *_name.c_str() == '/'; } /** Test for a relative path. */ - bool relative() const { return !empty() && name_t[prfx_i] != '/'; } + bool relative() const { return !( absolute() || empty() ); } /** Return all but the last component od this path. */ Pathname dirname() const { return dirname( *this ); } - static Pathname dirname( const Pathname & name_tv ); + static Pathname dirname( const Pathname & name_r ); /** Return the last component of this path. */ std::string basename() const { return basename( *this ); } - static std::string basename( const Pathname & name_tv ); + static std::string basename( const Pathname & name_r ); /** Return all of the characters in name after and including * the last dot in the last element of name. If there is no dot * in the last element of name then returns the empty string. */ std::string extension() const { return extension( *this ); } - static std::string extension( const Pathname & name_tv ); + static std::string extension( const Pathname & name_r ); /** Return this path, adding a leading '/' if relative. */ Pathname absolutename() const { return absolutename( *this ); } - static Pathname absolutename( const Pathname & name_tv ) - { return name_tv.relative() ? cat( "/", name_tv ) : name_tv; } + static Pathname absolutename( const Pathname & name_r ) + { return name_r.relative() ? cat( "/", name_r ) : name_r; } /** Return this path, removing a leading '/' if absolute.*/ Pathname relativename() const { return relativename( *this ); } - static Pathname relativename( const Pathname & name_tv ) - { return name_tv.absolute() ? cat( ".", name_tv ) : name_tv; } + static Pathname relativename( const Pathname & name_r ) + { return name_r.absolute() ? cat( ".", name_r ) : name_r; } /** Return \c path_r prefixed with \c root_r, unless it is already prefixed. */ static Pathname assertprefix( const Pathname & root_r, const Pathname & path_r ); @@ -148,10 +164,8 @@ namespace zypp static Pathname extend( const Pathname & l, const std::string & r ); private: - std::string::size_type prfx_i; - std::string name_t; - - void _assign( const std::string & name_tv ); + std::string _name; + void _assign( const std::string & name_r ); }; /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/Pattern.cc b/libzypp/zypp/Pattern.cc index 9d748a8..45562f0 100644 --- a/libzypp/zypp/Pattern.cc +++ b/libzypp/zypp/Pattern.cc @@ -20,11 +20,19 @@ using std::endl; /////////////////////////////////////////////////////////////////// namespace zypp -{ ///////////////////////////////////////////////////////////////// - +{ /////////////////////////////////////////////////////////////////// namespace - { ///////////////////////////////////////////////////////////////// + { + inline Capability autoCapability( const Capabilities & provides_r ) + { + static const Capability autopattern( "autopattern()" ); + for ( const auto & cap : provides_r ) + if ( cap.matches( autopattern ) == CapMatch::yes ) + return cap; + return Capability(); + } + /////////////////////////////////////////////////////////////////// // // CLASS NAME : PatternExpander @@ -153,78 +161,112 @@ namespace zypp private: PatternMap _patternMap; }; - ///////////////////////////////////////////////////////////////// } // namespace /////////////////////////////////////////////////////////////////// - IMPL_PTR_TYPE(Pattern); /////////////////////////////////////////////////////////////////// - // - // METHOD NAME : Pattern::Pattern - // METHOD TYPE : Ctor - // + // Pattern + /////////////////////////////////////////////////////////////////// + + IMPL_PTR_TYPE(Pattern); + Pattern::Pattern( const sat::Solvable & solvable_r ) : ResObject( solvable_r ) {} - /////////////////////////////////////////////////////////////////// - // - // METHOD NAME : Pattern::~Pattern - // METHOD TYPE : Dtor - // Pattern::~Pattern() {} - /////////////////////////////////////////////////////////////////// - // - // Pattern interface forwarded to implementation - // - /////////////////////////////////////////////////////////////////// - /** */ bool Pattern::isDefault() const { return lookupBoolAttribute( sat::SolvAttr::isdefault ); } - /** */ + bool Pattern::userVisible() const { return lookupBoolAttribute( sat::SolvAttr::isvisible ); } - /** */ + std::string Pattern::category( const Locale & lang_r ) const { return lookupStrAttribute( sat::SolvAttr::category, lang_r ); } - /** */ + Pathname Pattern::icon() const { return lookupStrAttribute( sat::SolvAttr::icon ); } - /** */ + Pathname Pattern::script() const { return lookupStrAttribute( sat::SolvAttr::script ); } std::string Pattern::order() const { return lookupStrAttribute( sat::SolvAttr::order ); } + bool Pattern::isAutoPattern() const + { return bool(autoCapability( provides() )); } + + sat::Solvable Pattern::autoPackage() const + { + Capability autocap( autoCapability( provides() ) ); + if ( autocap ) + { + Capability pkgCap( arch(), autocap.detail().ed().asString(), Rel::EQ, edition() ); + for ( const auto & solv: sat::WhatProvides( pkgCap ) ) + if ( solv.repository() == repository() ) + return solv; + } + return sat::Solvable(); + } + Pattern::NameList Pattern::includes() const { return NameList( sat::SolvAttr::includes, satSolvable() ); } Pattern::NameList Pattern::extends() const { return NameList( sat::SolvAttr::extends, satSolvable() ); } + /////////////////////////////////////////////////////////////////// + namespace + { + inline void addCaps( CapabilitySet & caps_r, sat::Solvable solv_r, Dep dep_r ) + { + Capabilities c( solv_r[dep_r] ); + if ( ! c.empty() ) + { + caps_r.insert( c.begin(),c.end() ); + } + } + } //namespace + /////////////////////////////////////////////////////////////////// + Pattern::Contents Pattern::core() const { + // Content dependencies are either associated with + // the autoPackage or the (oldstype) pattern itself. + // load requires + CapabilitySet caps; + addCaps( caps, *this, Dep::REQUIRES ); + + sat::Solvable depKeeper( autoPackage() ); + if ( depKeeper ) + addCaps( caps, depKeeper, Dep::REQUIRES ); // get items providing the requirements - sat::WhatProvides prv( requires() ); + sat::WhatProvides prv( caps ); // return packages only. return Pattern::Contents( make_filter_begin( filter::byKind(), prv ), make_filter_end( filter::byKind(), prv ) ); } - Pattern::Contents Pattern::depends() const + Pattern::Contents Pattern::depends( bool includeSuggests_r ) const { - // load requires, recommends, suggests + // Content dependencies are either associated with + // the autoPackage or the (oldstype) pattern itself. + // load requires, recommends[, suggests] CapabilitySet caps; + addCaps( caps, *this, Dep::REQUIRES ); + addCaps( caps, *this, Dep::RECOMMENDS ); + if ( includeSuggests_r ) + addCaps( caps, *this, Dep::SUGGESTS ); + + sat::Solvable depKeeper( autoPackage() ); + if ( depKeeper ) { - Capabilities c( requires() ); - caps.insert( c.begin(),c.end() ); - c = recommends(); - caps.insert( c.begin(),c.end() ); - c = suggests(); - caps.insert( c.begin(),c.end() ); + addCaps( caps, depKeeper, Dep::REQUIRES ); + addCaps( caps, depKeeper, Dep::RECOMMENDS ); + if ( includeSuggests_r ) + addCaps( caps, depKeeper, Dep::SUGGESTS ); } // get items providing the above sat::WhatProvides prv( caps ); @@ -233,7 +275,7 @@ namespace zypp make_filter_end( filter::byKind(), prv ) ); } - Pattern::Contents Pattern::contents() const + Pattern::Contents Pattern::contents( bool includeSuggests_r ) const { PatternExpander expander; if ( ! expander.doExpand( this ) ) @@ -242,7 +284,7 @@ namespace zypp Contents result; for_( it, expander.begin(), expander.end() ) { - Contents c( (*it)->depends() ); + Contents c( (*it)->depends( includeSuggests_r ) ); result.get().insert( c.begin(), c.end() ); } return result; diff --git a/libzypp/zypp/Pattern.h b/libzypp/zypp/Pattern.h index 2a3fefd..36b14a5 100644 --- a/libzypp/zypp/Pattern.h +++ b/libzypp/zypp/Pattern.h @@ -53,6 +53,22 @@ namespace zypp /** */ std::string order() const; + public: + /** \name Auto pattens (libyzpp-14) + * Patterns are no longer defined by separate metadate files, but via + * special dependencies provided by a corresponding patterns- package. + * The pattern itself requires only it's patterns- package, the package + * contains all further dependencies. + * This way pattens are no longer pseudo installed objects with a computed + * status, but installed, iff the corresponding patterns- package is + * installed. + */ + //@{ + /** This patterns is auto-defined by a patterns- package. */ + bool isAutoPattern() const; + /** The corresponding patterns- package if \ref isAutoPattern. */ + sat::Solvable autoPackage() const; + //@} public: /** Ui hint: included patterns. */ NameList includes() const; @@ -64,14 +80,21 @@ namespace zypp Contents core() const; /** Ui hint: Dependent packages. - * This also includes recommended and suugested packages. + * This also includes recommended and suggested (optionally exclude) packages. */ - Contents depends() const; + Contents depends( bool includeSuggests_r = true ) const; + /** \overload Without SUGGESTS. */ + Contents dependsNoSuggests() const + { return depends( false ); } /** The collection of packages associated with this pattern. * This also evaluates the patterns includes/extends relation. + * Optionally exclude \c SUGGESTED packages. */ - Contents contents() const; + Contents contents( bool includeSuggests_r = true ) const; + /** \overload Without SUGGESTS. */ + Contents contentsNoSuggests() const + { return contents( false ); } protected: friend Ptr make( const sat::Solvable & solvable_r ); diff --git a/libzypp/zypp/PluginFrame.cc b/libzypp/zypp/PluginFrame.cc index b05815b..6e4e4ad 100644 --- a/libzypp/zypp/PluginFrame.cc +++ b/libzypp/zypp/PluginFrame.cc @@ -17,6 +17,9 @@ using std::endl; +#undef ZYPP_BASE_LOGGER_LOGGROUP +#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::plugin" + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -35,10 +38,17 @@ namespace zypp Impl( const std::string & command_r ) { setCommand( command_r ); } - Impl( const std::string & command_r, const std::string body_r ) + Impl( const std::string & command_r, const std::string & body_r ) : _body( body_r ) { setCommand( command_r ); } + Impl( const std::string & command_r, HeaderInitializerList contents_r ) + { setCommand( command_r ); addHeader( contents_r ); } + + Impl( const std::string & command_r, const std::string & body_r, HeaderInitializerList contents_r ) + : _body( body_r ) + { setCommand( command_r ); addHeader( contents_r ); } + Impl( std::istream & stream_r ); public: @@ -122,6 +132,12 @@ namespace zypp _header.insert( mkHeaderPair( key_r, value_r ) ); } + void addHeader( HeaderInitializerList contents_r ) + { + for ( const auto & el : contents_r ) + addHeader( el.first, el.second ); + } + void clearHeader( const std::string & key_r ) { _header.erase( key_r ); @@ -234,6 +250,12 @@ namespace zypp return _val; } + const std::string & PluginFrame::enomethodCommand() + { + static std::string _val( "_ENOMETHOD" ); + return _val; + } + PluginFrame::PluginFrame() : _pimpl( Impl::nullimpl() ) {} @@ -242,10 +264,18 @@ namespace zypp : _pimpl( new Impl( command_r ) ) {} - PluginFrame::PluginFrame( const std::string & command_r, const std::string body_r ) + PluginFrame::PluginFrame( const std::string & command_r, const std::string & body_r ) : _pimpl( new Impl( command_r, body_r ) ) {} + PluginFrame::PluginFrame( const std::string & command_r, HeaderInitializerList contents_r ) + : _pimpl( new Impl( command_r, contents_r ) ) + {} + + PluginFrame::PluginFrame( const std::string & command_r, const std::string & body_r, HeaderInitializerList contents_r ) + : _pimpl( new Impl( command_r, body_r, contents_r ) ) + {} + PluginFrame::PluginFrame( std::istream & stream_r ) : _pimpl( new Impl( stream_r ) ) {} @@ -292,6 +322,9 @@ namespace zypp void PluginFrame::addHeader( const std::string & key_r, const std::string & value_r ) { _pimpl->addHeader( key_r, value_r ); } + void PluginFrame::addHeader( HeaderInitializerList contents_r ) + { _pimpl->addHeader( contents_r ); } + void PluginFrame::clearHeader( const std::string & key_r ) { _pimpl->clearHeader( key_r ); } diff --git a/libzypp/zypp/PluginFrame.h b/libzypp/zypp/PluginFrame.h index 3eaf84c..8683fe2 100644 --- a/libzypp/zypp/PluginFrame.h +++ b/libzypp/zypp/PluginFrame.h @@ -17,7 +17,6 @@ #include #include "zypp/base/PtrTypes.h" -#include "zypp/base/SafeBool.h" #include "zypp/PluginFrameException.h" @@ -38,16 +37,20 @@ namespace zypp * * \see PluginScript */ - class PluginFrame : private base::SafeBool + class PluginFrame { friend std::ostream & operator<<( std::ostream & str, const PluginFrame & obj ); friend bool operator==( const PluginFrame & lhs, const PluginFrame & rhs ); + typedef const std::initializer_list> & HeaderInitializerList; + public: /** "ACK" command. */ static const std::string & ackCommand(); /** "ERROR" command. */ static const std::string & errorCommand(); + /** "_ENOMETHOD" command. */ + static const std::string & enomethodCommand(); public: /** Default exception type */ @@ -64,7 +67,17 @@ namespace zypp /** Ctor taking command and body * \throw PluginFrameException If \ref setCommand throws */ - PluginFrame( const std::string & command_r, const std::string body_r ); + PluginFrame( const std::string & command_r, const std::string & body_r ); + + /** Ctor taking the command and a HeaderInitializerList + * \throw PluginFrameException If \ref setCommand throws + */ + PluginFrame( const std::string & command_r, HeaderInitializerList contents_r ); + + /** Ctor taking command, body and a HeaderInitializerList + * \throw PluginFrameException If \ref setCommand throws + */ + PluginFrame( const std::string & command_r, const std::string & body_r, HeaderInitializerList contents_r ); /** Ctor reading frame data from a stream * \throw PluginFrameException On error reading from stream @@ -77,7 +90,8 @@ namespace zypp bool empty() const; /** Evaluate in a boolean context (empty frame) */ - using base::SafeBool::operator bool_type; + explicit operator bool() const + { return empty(); } public: /** Return the frame command. */ @@ -96,6 +110,10 @@ namespace zypp bool isErrorCommand() const {return command() == errorCommand(); } + /** Convenience to identify an _ENOMETHOD command. */ + bool isEnomethodCommand() const + {return command() == enomethodCommand(); } + /** Return the frame body. */ const std::string & body() const; @@ -150,7 +168,7 @@ namespace zypp /** Whether the header list contains at least one entry for \c key_r. */ bool hasKey( const std::string & key_r ) const - { return keyEmpty( key_r ); } + { return ! keyEmpty( key_r ); } /** \overload */ bool keyEmpty( const std::string & key_r ) const @@ -189,11 +207,20 @@ namespace zypp */ void setHeader( const std::string & key_r, const std::string & value_r = std::string() ); + /** Set a new header list + * \throw PluginFrameException If key contains illegal chars (\c NL or \c :) + * \throw PluginFrameException If value contains illegal chars (\c NL) + */ + void setHeader( HeaderInitializerList contents_r ) + { headerList().clear(); addHeader( contents_r ); } + /** Add header for \c key_r leaving already existing headers for \c key_r unchanged. * \throw PluginFrameException If key contains illegal chars (\c NL or \c :) * \throw PluginFrameException If value contains illegal chars (\c NL) */ void addHeader( const std::string & key_r, const std::string & value_r = std::string() ); + /** \overload taking an initializer_list */ + void addHeader( HeaderInitializerList contents_r ); /** Remove all headers for \c key_r. */ void clearHeader( const std::string & key_r ); @@ -218,11 +245,6 @@ namespace zypp static std::istream & readFrom( std::istream & stream_r, PluginFrame & frame_r ) { frame_r = PluginFrame( stream_r ); return stream_r; } - private: - friend base::SafeBool::operator bool_type() const; - /** Evaluate in a boolean context */ - bool boolTest() const - { return empty(); } public: /** Implementation */ class Impl; diff --git a/libzypp/zypp/PluginScript.cc b/libzypp/zypp/PluginScript.cc index a080c4f..4024bc7 100644 --- a/libzypp/zypp/PluginScript.cc +++ b/libzypp/zypp/PluginScript.cc @@ -27,6 +27,9 @@ using std::endl; +#undef ZYPP_BASE_LOGGER_LOGGROUP +#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::plugin" + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -137,7 +140,7 @@ namespace zypp { return _cmd ? _cmd->getpid() : NotConnected; } bool isOpen() const - { return _cmd; } + { return _cmd != nullptr; } int lastReturn() const { return _lastReturn; } @@ -166,8 +169,7 @@ namespace zypp /** \relates PluginScrip::Impl Stream output */ inline std::ostream & operator<<( std::ostream & str, const PluginScript::Impl & obj ) { - return dumpRangeLine( str << "PluginScript[" << obj.getPid() << "] " << obj.script(), - obj.args().begin(), obj.args().end() ); + return str << "PluginScript[" << obj.getPid() << "] " << obj.script(); } /////////////////////////////////////////////////////////////////// @@ -217,7 +219,7 @@ namespace zypp _lastReturn.reset(); _lastExecError.clear(); - DBG << *this << endl; + dumpRangeLine( DBG << *this, _args.begin(), _args.end() ) << endl; } int PluginScript::Impl::close() @@ -267,7 +269,7 @@ namespace zypp frame_r.writeTo( datas ); datas.str().swap( data ); } - DBG << "->send " << frame_r << endl; + DBG << *this << " ->send " << frame_r << endl; if ( PLUGIN_DEBUG ) { @@ -421,7 +423,7 @@ namespace zypp // DBG << " <-read " << data.size() << endl; std::istringstream datas( data ); PluginFrame ret( datas ); - DBG << "<-" << ret << endl; + DBG << *this << " <-" << ret << endl; return ret; } diff --git a/libzypp/zypp/PoolItem.h b/libzypp/zypp/PoolItem.h index 363cb44..878cf8a 100644 --- a/libzypp/zypp/PoolItem.h +++ b/libzypp/zypp/PoolItem.h @@ -137,8 +137,8 @@ namespace zypp /** Conversion to bool to allow pointer style tests * for nonNULL \ref resolvable. */ - operator ResObject::constPtr::unspecified_bool_type() const - { return resolvable(); } + explicit operator bool() const + { return bool(resolvable()); } private: friend class Impl; diff --git a/libzypp/zypp/PoolQuery.cc b/libzypp/zypp/PoolQuery.cc index ec7bc45..4e286b2 100644 --- a/libzypp/zypp/PoolQuery.cc +++ b/libzypp/zypp/PoolQuery.cc @@ -401,17 +401,30 @@ namespace zypp bool operator==( const PoolQuery::Impl & rhs ) const { - return ( _strings == rhs._strings - && _attrs == rhs._attrs - && _uncompiledPredicated == rhs._uncompiledPredicated - && _flags == rhs._flags - && _match_word == rhs._match_word - && _require_all == rhs._require_all - && _status_flags == rhs._status_flags - && _edition == rhs._edition - && _op == rhs._op - && _repos == rhs._repos - && _kinds == rhs._kinds ); + if ( _flags == rhs._flags + // bnc#792901: while libzypp uses exact match mode for a single + // package name lock, zypper always uses glob. :( + // We unify those two forms to enable zypper to remove zypp locks + // without need to actually evaluate the query (which would require + // repos to be loaded). + || ( ( ( _flags.isModeString() && rhs._flags.isModeGlob() ) + || ( _flags.isModeGlob() && rhs._flags.isModeString() ) ) + && _strings.empty() + && _attrs.size() == 1 + && _attrs.begin()->first == sat::SolvAttr::name ) ) + { + return ( _strings == rhs._strings + && _attrs == rhs._attrs + && _uncompiledPredicated == rhs._uncompiledPredicated + && _match_word == rhs._match_word + && _require_all == rhs._require_all + && _status_flags == rhs._status_flags + && _edition == rhs._edition + && _op == rhs._op + && _repos == rhs._repos + && _kinds == rhs._kinds ); + } + return false; } bool operator!=( const PoolQuery::Impl & rhs ) const @@ -1127,8 +1140,6 @@ namespace zypp PoolQueryAttr attribute( attrName ); - MIL << "attribute name: " << attrName << endl; - if ( attribute==PoolQueryAttr::repoAttr ) { addRepo( attrValue ); diff --git a/libzypp/zypp/ProblemSolution.cc b/libzypp/zypp/ProblemSolution.cc index cbaf555..b5ae8da 100644 --- a/libzypp/zypp/ProblemSolution.cc +++ b/libzypp/zypp/ProblemSolution.cc @@ -42,7 +42,8 @@ operator<<( ostream& os, const ProblemSolution & solution) { os << "Solution:" << endl; os << solution._description << endl; - os << solution._details << endl; + if ( ! solution._details.empty() ) + os << solution._details << endl; os << solution._actions; return os; } @@ -51,7 +52,7 @@ ostream& operator<<( ostream& os, const ProblemSolutionList & solutionlist) { for (ProblemSolutionList::const_iterator iter = solutionlist.begin(); iter != solutionlist.end(); ++iter) { - os << *(*iter) << endl; + os << *(*iter); } return os; } diff --git a/libzypp/zypp/ProblemSolution.h b/libzypp/zypp/ProblemSolution.h index 5bedec3..a239817 100644 --- a/libzypp/zypp/ProblemSolution.h +++ b/libzypp/zypp/ProblemSolution.h @@ -23,7 +23,7 @@ namespace zypp { /////////////////////////////////////////////////////////////////////// - + /** * Class representing one possible solution to one problem found during resolving * @@ -42,13 +42,13 @@ namespace zypp class ProblemSolution : public base::ReferenceCounted { protected: - + /** * Clear all data. * In particular, delete all members of _actions. **/ void clear(); - + // // Data members // @@ -103,7 +103,7 @@ namespace zypp /** * Add an action to the actions list. - **/ + **/ void addAction( solver::detail::SolutionAction_constPtr action ); solver::detail::CSolutionActionList actions() {return _actions;} diff --git a/libzypp/zypp/Product.cc b/libzypp/zypp/Product.cc index b8c0441..75def80 100644 --- a/libzypp/zypp/Product.cc +++ b/libzypp/zypp/Product.cc @@ -11,6 +11,7 @@ */ #include #include "zypp/base/LogTools.h" +#include "zypp/base/StrMatcher.h" #include "zypp/Product.h" #include "zypp/Url.h" @@ -94,6 +95,24 @@ namespace zypp found = *it; } } + + if ( ! found && isSystem() ) + { + // bnc#784900: for installed products check whether the file is owned by + // some package. If so, ust this as buddy. + sat::LookupAttr q( sat::SolvAttr::filelist, repository() ); + std::string refFile( referenceFilename() ); + if ( ! refFile.empty() ) + { + StrMatcher matcher( referenceFilename() ); + q.setStrMatcher( matcher ); + if ( ! q.empty() ) + found = q.begin().inSolvable(); + } + else + INT << "Product referenceFilename unexpectedly empty!" << endl; + } + if ( ! found ) WAR << *this << ": no reference package found: " << identCap << endl; return found; @@ -137,7 +156,12 @@ namespace zypp /////////////////////////////////////////////////////////////////// std::string Product::shortName() const - { return lookupStrAttribute( sat::SolvAttr::productShortlabel ); } + { + std::string ret( lookupStrAttribute( sat::SolvAttr::productShortlabel ) ); + if ( ret.empty() ) ret = name(); + return ret; + + } std::string Product::flavor() const { @@ -178,6 +202,33 @@ namespace zypp return ret; } + Date Product::endOfLife() const + { return Date( lookupNumAttribute( sat::SolvAttr::productEndOfLife ) );} + + std::vector Product::updateContentIdentifier() const + { + std::vector ret; + sat::LookupAttr q( sat::SolvAttr::productUpdatesRepoid, sat::SolvAttr::productUpdates, *this ); + if ( ! q.empty() ) + { + ret.reserve( 2 ); + for_( it, q.begin(), q.end() ) + ret.push_back( it.asString() ); + } + return ret; + } + + bool Product::hasUpdateContentIdentifier( const Repository::ContentIdentifier & cident_r ) const + { + sat::LookupAttr q( sat::SolvAttr::productUpdatesRepoid, sat::SolvAttr::productUpdates, *this ); + for_( it, q.begin(), q.end() ) + { + if ( it.asString() == cident_r ) + return true; + } + return false; + } + bool Product::isTargetDistribution() const { return isSystem() && lookupStrAttribute( sat::SolvAttr::productType ) == "base"; } @@ -187,6 +238,9 @@ namespace zypp std::string Product::registerRelease() const { return lookupStrAttribute( sat::SolvAttr::productRegisterRelease ); } + std::string Product::registerFlavor() const + { return lookupStrAttribute( sat::SolvAttr::productRegisterFlavor ); } + ///////////////////////////////////////////////////////////////// Product::UrlList Product::urls( const std::string & key_r ) const diff --git a/libzypp/zypp/Product.h b/libzypp/zypp/Product.h index 7632803..7c9bb3f 100644 --- a/libzypp/zypp/Product.h +++ b/libzypp/zypp/Product.h @@ -81,7 +81,7 @@ namespace zypp std::string productLine() const; public: - /** Untranslated short name like SLES 10*/ + /** Untranslated short name like SLES 10 (fallback: name) */ std::string shortName() const; /** The product flavor (LiveCD Demo, FTP edition,...). */ @@ -91,22 +91,39 @@ namespace zypp * Well, in an ideal world there is only one base product. * It's the installed product denoted by a symlink in * \c /etc/products.d. - * \deprecated Use isTargetDistribution to test for the installed base product, - * other wise type is empty for almost all products. - */ - std::string type() const ZYPP_DEPRECATED; + */ + std::string type() const; /** The product flags */ std::list flags() const; + /** The date when this Product goes out of support as indicated by it's medadata. */ + Date endOfLife() const; + + /** ContentIdentifier of required update repositories. */ + std::vector updateContentIdentifier() const; + + /** Whether \a cident_r is listed as required update repository. */ + bool hasUpdateContentIdentifier( const Repository::ContentIdentifier & cident_r ) const; + + /** Whether one of the ContentIdentifier is listed as required update repository. */ + template + bool hasUpdateContentIdentifier( _Iterator begin, _Iterator end ) const + { + for_( it, begin, end ) + if ( hasUpdateContentIdentifier( *it ) ) + return true; + return false; + } + public: /** This is the \b installed product that is also targeted by the * \c /etc/products.d/baseproduct symlink. */ bool isTargetDistribution() const; - /** This is \c register.target attribute of an \b installed product. - * Used for registration. + /** This is \c register.target attribute of a product. + * Used for registration and filtering service repos. */ std::string registerTarget() const; @@ -115,6 +132,11 @@ namespace zypp */ std::string registerRelease() const; + /** This is \c register.flavor attribute of a product. + * Used for registration. + */ + std::string registerFlavor() const; + public: /***/ class UrlList; diff --git a/libzypp/zypp/ProgressData.cc b/libzypp/zypp/ProgressData.cc index c08fe0d..251ab3d 100644 --- a/libzypp/zypp/ProgressData.cc +++ b/libzypp/zypp/ProgressData.cc @@ -32,71 +32,63 @@ namespace zypp // bool ProgressData::report() { - bool goOn = true; // continue per default - bool doReport = false; + Date now = Date::now(); // compute value and check whether to report it if ( hasRange() ) { - value_type newVal = _d->_val * 100; - newVal /= ( _d->_max - _d->_min ); - - if ( newVal - _d->_last_val > 20 - || Date::now() - _d->_last_send > 1 - || ( newVal == 100 && _d->_last_send != 100 ) - || _d->_state == END ) + value_type newVal = _d->_val * 100 / ( _d->_max - _d->_min ); + + if ( newVal - _d->_last_val > 10 + || now - _d->_last_send > 1 + || ( _d->_last_val == 0 && newVal > 0 ) + || ( newVal == 100 && _d->_last_val != 100 ) + || ( newVal != 100 && _d->_last_val == 100 ) + || _d->_state != RUN /*INIT||END*/ ) { _d->_last_val = newVal; - _d->_last_send = Date::now(); - doReport = true; + _d->_last_send = now; } + else + return true; // skip report, continue per default } else { - if ( Date::now() - _d->_last_send > 1 || _d->_state == END ) + if ( now - _d->_last_send > 1 || _d->_state != RUN /*INIT||END*/ ) { _d->_last_val = _d->_val; - _d->_last_send = Date::now(); - doReport = true; + _d->_last_send = now; } + else + return true; // skip report, continue per default } - // report if necessary - if ( doReport ) + // now send report + if ( _d->_state == INIT ) { - if ( _d->_state == INIT ) - { - _d->_state = RUN; - } + _d->_state = RUN; + } + // XXX << str::form( "{#%u|%s}(%lld%s)", numericId(), name().c_str(), _d->_last_val, ( hasRange() ? "%" : "!" ) ) << endl; - if ( _d->_receiver ) - { - goOn = _d->_receiver( *this ); - } - else + if ( _d->_receiver ) + { + if ( ! _d->_receiver( *this ) ) { if ( _d->_state != END ) { - XXX << str::form( "{#%u|%s}(%lld%s)", - numericId(), name().c_str(), - _d->_last_val, ( hasRange() ? "%" : "!" ) ) << endl; - } - else - { - DBG << str::form( "{#%u|%s}END", numericId(), name().c_str() ) << endl; + WAR << "User request to ABORT pending action. " + << str::form( "{#%u|%s}(%lld%s)", numericId(), name().c_str(), + _d->_last_val, ( hasRange() ? "%" : "!" ) ) << endl; } + return false; // aborted by user } } - - // log abort request and return - if ( ! goOn && _d->_state != END ) + else if ( _d->_state == END ) { - WAR << "User request to ABORT pending action. " - << str::form( "{#%u|%s}(%lld%s)", - numericId(), name().c_str(), - _d->_last_val, ( hasRange() ? "%" : "!" ) ) << endl; + DBG << str::form( "{#%u|%s}END", numericId(), name().c_str() ) << endl; } - return goOn; + + return true; // continue per default } /****************************************************************** diff --git a/libzypp/zypp/ProgressData.h b/libzypp/zypp/ProgressData.h index 818258d..1cb757a 100644 --- a/libzypp/zypp/ProgressData.h +++ b/libzypp/zypp/ProgressData.h @@ -35,7 +35,7 @@ namespace zypp * needs. As a convention, a zero sizes range indicates that you are just * able to send 'still alive' triggers. * - * The counter should be updated in reasonable intervals. Don't mind wheter + * The counter should be updated in reasonable intervals. Don't mind whether * the counter value actually increased or not. ProgressData will recognize * your triggers and knows when to actually send notification to a consumer. * @@ -126,11 +126,6 @@ namespace zypp * * The different ammount of triggers is due to different rules for sending * percent or 'still alive' messages. - * - * \todo Complete the progess sending. - * \todo Tell recipient whether percentage or keepalive is sent, - * the id and name might be helpfull, and maybe tell whether task - * is abortable or not; i.e extend the ReceiverFnc signature. */ class ProgressData : public base::ProvideNumericId { @@ -254,6 +249,14 @@ namespace zypp return report(); } + /** Set range and counter from an other \ref ProgressData. */ + bool set( const ProgressData & rhs ) + { + min( rhs.min() ); + max( rhs.max() ); + return set( rhs.val() ); + } + /** Increment counter \c value (default by 1). */ bool incr( value_type val_r = 1 ) { return set( val() + val_r ); } @@ -268,11 +271,11 @@ namespace zypp /** Set counter value to current \c max value (unless no range). */ bool toMax() - { return set( hasRange() ? max() : val() ); } + { return hasRange() ? set( max() ) : tick(); } /** Leave counter value unchanged (still alive). */ bool tick() - { return set( val() ); } + { return report(); } //@} @@ -292,18 +295,18 @@ namespace zypp value_type val() const { return _d->_val; } - /** @return Wheter [min,max] defines a nonempty range. */ + /** @return Whether [min,max] defines a nonempty range. */ bool hasRange() const { return min() != max(); } - /** @return Wheter \ref reportValue will return a percent value. + /** @return Whether \ref reportValue will return a percent value. * Same as \ref hasRange. * \see \ref reportAlive */ bool reportPercent() const { return hasRange(); } - /** @return Wheter \ref reportValue always returns -1, because we + /** @return Whether \ref reportValue always returns -1, because we * trigger 'still alive' messages. I.e. \ref hasrange is \c false. * \see \ref reportPercent */ @@ -324,9 +327,9 @@ namespace zypp const ReceiverFnc & receiver() const { return _d->_receiver; } - /** @return Retrun \c true if this the final report sent by the + /** @return Return \c true if this is the final report sent by the * ProgressData dtor. - */ + */ bool finalReport() const { return( _d->_state == END ); } diff --git a/libzypp/zypp/PublicKey.cc b/libzypp/zypp/PublicKey.cc index 5b79878..4d3d773 100644 --- a/libzypp/zypp/PublicKey.cc +++ b/libzypp/zypp/PublicKey.cc @@ -14,8 +14,6 @@ #include #include -//#include "zypp/base/Logger.h" - #include "zypp/base/Gettext.h" #include "zypp/base/String.h" #include "zypp/base/Regex.h" @@ -24,7 +22,7 @@ #include "zypp/TmpPath.h" #include "zypp/PathInfo.h" #include "zypp/base/Exception.h" -#include "zypp/base/Logger.h" +#include "zypp/base/LogTools.h" #include "zypp/Date.h" #include "zypp/TmpPath.h" @@ -36,128 +34,322 @@ using std::endl; namespace zypp { ///////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////// - // - // CLASS NAME : PublicKey::Impl - // - /** PublicKey implementation. */ - struct PublicKey::Impl + /////////////////////////////////////////////////////////////////// + /// \class PublicKeyData::Impl + /// \brief PublicKeyData implementation. + /////////////////////////////////////////////////////////////////// + struct PublicKeyData::Impl { - Impl() - {} - - Impl( const Pathname & keyfile ) + std::string _id; + std::string _name; + std::string _fingerprint; + Date _created; + Date _expires; + + public: + /** Offer default Impl. */ + static shared_ptr nullimpl() { - PathInfo info( keyfile ); - MIL << "Takeing pubkey from " << keyfile << " of size " << info.size() << " and sha1 " << filesystem::checksum(keyfile, "sha1") << endl; + static shared_ptr _nullimpl( new Impl ); + return _nullimpl; + } - if ( !info.isExist() ) - ZYPP_THROW(Exception("Can't read public key from " + keyfile.asString() + ", file not found")); + private: + friend Impl * rwcowClone( const Impl * rhs ); + /** clone for RWCOW_pointer */ + Impl * clone() const + { return new Impl( *this ); } + }; + /////////////////////////////////////////////////////////////////// - if ( copy( keyfile, _data_file.path() ) != 0 ) - ZYPP_THROW(Exception("Can't copy public key data from " + keyfile.asString() + " to " + _data_file.path().asString() )); + /////////////////////////////////////////////////////////////////// + /// class PublicKeyData + /////////////////////////////////////////////////////////////////// - readFromFile(); - } + PublicKeyData::PublicKeyData() + : _pimpl( Impl::nullimpl() ) + {} - Impl( const filesystem::TmpFile & sharedfile ) - : _data_file( sharedfile ) - { readFromFile(); } + PublicKeyData::~PublicKeyData() + {} - public: - /** Offer default Impl. */ - static shared_ptr nullimpl() - { - static shared_ptr _nullimpl( new Impl ); - return _nullimpl; - } + PublicKeyData::operator bool() const + { return !_pimpl->_fingerprint.empty(); } - std::string asString() const - { - return str::form( "[%s-%s] [%s] [%s] [TTL %d]", - id().c_str(), str::hexstring(created(),8).substr(2).c_str(), - name().c_str(), - fingerprint().c_str(), - daysToLive() ); + std::string PublicKeyData::id() const + { return _pimpl->_id; } + + std::string PublicKeyData::name() const + { return _pimpl->_name; } + + std::string PublicKeyData::fingerprint() const + { return _pimpl->_fingerprint; } + + Date PublicKeyData::created() const + { return _pimpl->_created; } + + Date PublicKeyData::expires() const + { return _pimpl->_expires; } + + bool PublicKeyData::expired() const + { return( _pimpl->_expires && _pimpl->_expires < Date::now() ); } + + int PublicKeyData::daysToLive() const + { + if ( _pimpl->_expires ) + { + Date exp( _pimpl->_expires - Date::now() ); + int ret = exp / Date::day; + if ( exp < 0 ) ret -= 1; + return ret; + } + return INT_MAX; + } + + std::string PublicKeyData::expiresAsString() const + { + if ( !_pimpl->_expires ) + { // translators: an annotation to a gpg keys expiry date + return _("(does not expire)"); + } + std::string ret( _pimpl->_expires.asString() ); + int ttl( daysToLive() ); + if ( ttl <= 90 ) + { + ret += " "; + if ( ttl < 0 ) + { // translators: an annotation to a gpg keys expiry date + ret += _("(EXPIRED)"); } + else if ( ttl == 0 ) + { // translators: an annotation to a gpg keys expiry date + ret += _("(expires within 24h)"); + } + else + { // translators: an annotation to a gpg keys expiry date + ret += str::form( _PL("(expires in %d day)", "(expires in %d days)", ttl ), ttl ); + } + } + return ret; + } - std::string id() const - { return _id; } + std::string PublicKeyData::gpgPubkeyVersion() const + { return _pimpl->_id.empty() ? _pimpl->_id : str::toLower( _pimpl->_id.substr(8,8) ); } - std::string name() const - { return _name; } + std::string PublicKeyData::gpgPubkeyRelease() const + { return _pimpl->_created ? str::hexstring( _pimpl->_created ).substr(2) : std::string(); } - std::string fingerprint() const - { return _fingerprint; } + std::string PublicKeyData::asString() const + { + return str::form( "[%s-%s] [%s] [%s] [TTL %d]", + _pimpl->_id.c_str(), + gpgPubkeyRelease().c_str(), + _pimpl->_name.c_str(), + _pimpl->_fingerprint.c_str(), + daysToLive() ); + } - std::string gpgPubkeyVersion() const - { return _id.empty() ? _id : str::toLower( _id.substr(8,8) ); } + std::ostream & dumpOn( std::ostream & str, const PublicKeyData & obj ) + { + str << "[" << obj.name() << "]" << endl; + str << " fpr " << obj.fingerprint() << endl; + str << " id " << obj.id() << endl; + str << " cre " << Date::ValueType(obj.created()) << ' ' << obj.created() << endl; + str << " exp " << Date::ValueType(obj.expires()) << ' ' << obj.expiresAsString() << endl; + str << " ttl " << obj.daysToLive() << endl; + str << " rpm " << obj.gpgPubkeyVersion() << "-" << obj.gpgPubkeyRelease() << endl; + str << "]"; + return str; + } + + bool operator==( const PublicKeyData & lhs, const PublicKeyData & rhs ) + { return ( lhs.fingerprint() == rhs.fingerprint() && lhs.created() == rhs.created() ); } - std::string gpgPubkeyRelease() const - { return _created ? str::hexstring( _created ).substr(2) : std::string(); } - Date created() const - { return _created; } + /////////////////////////////////////////////////////////////////// + /// \class PublicKeyScanner::Impl + /// \brief PublicKeyScanner implementation. + /////////////////////////////////////////////////////////////////// + struct PublicKeyScanner::Impl + { + std::vector _words; + enum { pNONE, pPUB, pSIG, pFPR, pUID } _parseEntry; + bool _parseOff; // no 'sub:' key parsing - Date expires() const - { return _expires; } + Impl() + : _parseEntry( pNONE ) + , _parseOff( false ) + {} - std::string expiresAsString() const + void scan( std::string & line_r, std::list & keys_r ) + { + // pub:-:1024:17:A84EDAE89C800ACA:971961473:1214043198::-:SuSE Package Signing Key : + // fpr:::::::::79C179B2E1C820C1890F9994A84EDAE89C800ACA: + // sig:::17:A84EDAE89C800ACA:1087899198:::::[selfsig]::13x: + // sig:::17:9E40E310000AABA4:980442706::::[User ID not found]:10x: + // sig:::1:77B2E6003D25D3D9:980443247::::[User ID not found]:10x: + // sig:::17:A84EDAE89C800ACA:1318348291:::::[selfsig]::13x: + // sub:-:2048:16:197448E88495160C:971961490:1214043258::: [expires: 2008-06-21] + // sig:::17:A84EDAE89C800ACA:1087899258:::::[keybind]::18x: + if ( line_r.empty() ) + return; + + // quick check for interesting entries, no parsing in subkeys + _parseEntry = pNONE; + switch ( line_r[0] ) { - if ( !_expires ) - { // translators: an annotation to a gpg keys expiry date - return _("(does not expire)"); - } - std::string ret( _expires.asString() ); - int ttl( daysToLive() ); - if ( ttl <= 90 ) - { - ret += " "; - if ( ttl < 0 ) - { // translators: an annotation to a gpg keys expiry date - ret += _("(EXPIRED)"); - } - else if ( ttl == 0 ) - { // translators: an annotation to a gpg keys expiry date - ret += _("(expires within 24h)"); + case 'p': + if ( line_r[1] == 'u' && line_r[2] == 'b' && line_r[3] == ':' ) + { + _parseEntry = pPUB; + _parseOff = false; } - else - { // translators: an annotation to a gpg keys expiry date - ret += str::form( _PL("(expires in %d day)", "(expires in %d days)", ttl ), ttl ); - } - } - return ret; + break; + + case 'f': + if ( line_r[1] == 'p' && line_r[2] == 'r' && line_r[3] == ':' ) + _parseEntry = pFPR; + break; + + case 'u': + if ( line_r[1] == 'i' && line_r[2] == 'd' && line_r[3] == ':' ) + _parseEntry = pUID; + break; + + case 's': + if ( line_r[1] == 'i' && line_r[2] == 'g' && line_r[3] == ':' ) + _parseEntry = pSIG; + else if ( line_r[1] == 'u' && line_r[2] == 'b' && line_r[3] == ':' ) + _parseOff = true; + break; + + default: + return; } + if ( _parseOff || _parseEntry == pNONE ) + return; - Pathname path() const - { return _data_file.path(); } + if ( line_r[line_r.size()-1] == '\n' ) + line_r.erase( line_r.size()-1 ); + // DBG << line_r << endl; + + _words.clear(); + str::splitFields( line_r, std::back_inserter(_words), ":" ); + + PublicKeyData * key( &keys_r.back() ); - bool expired() const + switch ( _parseEntry ) { - Date exp( expires() ); - return( exp && exp < Date::now() ); + case pPUB: + keys_r.push_back( PublicKeyData() ); // reset upon new key + key = &keys_r.back(); + key->_pimpl->_id = _words[4]; + key->_pimpl->_name = str::replaceAll( _words[9], "\\x3a", ":" ); + key->_pimpl->_created = Date(str::strtonum(_words[5])); + key->_pimpl->_expires = Date(str::strtonum(_words[6])); + break; + + case pSIG: + // Update creation/modification date from signatures type "13x". + if ( ( _words.size() > 10 && _words[10] == "13x" ) + || ( _words.size() > 12 && _words[12] == "13x" ) ) + { + Date cdate(str::strtonum(_words[5])); + if ( key->_pimpl->_created < cdate ) + key->_pimpl->_created = cdate; + } + break; + + case pFPR: + if ( key->_pimpl->_fingerprint.empty() ) + key->_pimpl->_fingerprint = _words[9]; + break; + + case pUID: + if ( ! _words[9].empty() ) + key->_pimpl->_name = str::replaceAll( _words[9], "\\x3a", ":" ); + break; + + case pNONE: + break; // intentionally no default: } + } + }; + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + // class PublicKeyScanner + /////////////////////////////////////////////////////////////////// + + PublicKeyScanner::PublicKeyScanner() + : _pimpl( new Impl ) + {} - int daysToLive() const + PublicKeyScanner::~PublicKeyScanner() + {} + + void PublicKeyScanner::scan( std::string line_r ) + { _pimpl->scan( line_r, _keys ); } + + + /////////////////////////////////////////////////////////////////// + /// \class PublicKey::Impl + /// \brief PublicKey implementation. + /////////////////////////////////////////////////////////////////// + struct PublicKey::Impl + { + Impl() + {} + + Impl( const Pathname & keyFile_r ) + { + PathInfo info( keyFile_r ); + MIL << "Taking pubkey from " << keyFile_r << " of size " << info.size() << " and sha1 " << filesystem::checksum(keyFile_r, "sha1") << endl; + + if ( !info.isExist() ) + ZYPP_THROW(Exception("Can't read public key from " + keyFile_r.asString() + ", file not found")); + + if ( filesystem::hardlinkCopy( keyFile_r, _dataFile.path() ) != 0 ) + ZYPP_THROW(Exception("Can't copy public key data from " + keyFile_r.asString() + " to " + _dataFile.path().asString() )); + + readFromFile(); + } + + Impl( const filesystem::TmpFile & sharedFile_r ) + : _dataFile( sharedFile_r ) + { readFromFile(); } + + Impl( const filesystem::TmpFile & sharedFile_r, const PublicKeyData & keyData_r ) + : _dataFile( sharedFile_r ) + , _keyData( keyData_r ) + { + if ( ! keyData_r ) { - Date exp( expires() ); - if ( ! expires() ) - return INT_MAX; - exp -= Date::now(); - return exp < 0 ? exp / Date::day - 1 : exp / Date::day; + WAR << "Invalid PublicKeyData supplied: scanning from file" << endl; + readFromFile(); } + } - protected: + public: + const PublicKeyData & keyData() const + { return _keyData; } + + Pathname path() const + { return _dataFile.path(); } + + const std::list & hiddenKeys() const + { return _hiddenKeys; } + protected: void readFromFile() { - PathInfo info( _data_file.path() ); + PathInfo info( _dataFile.path() ); MIL << "Reading pubkey from " << info.path() << " of size " << info.size() << " and sha1 " << filesystem::checksum(info.path(), "sha1") << endl; static filesystem::TmpDir dir; const char* argv[] = { - "gpg2", + "gpg", "-v", "--no-default-keyring", "--fixed-list-mode", @@ -169,92 +361,54 @@ namespace zypp "--no-tty", "--no-greeting", "--batch", - "--status-fd", - "1", - _data_file.path().asString().c_str(), + "--status-fd", "1", + _dataFile.path().asString().c_str(), NULL }; + ExternalProgram prog( argv, ExternalProgram::Discard_Stderr, false, -1, true ); - ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true); - - std::string line; - bool sawpub = false; - bool sawsig = false; - - // pub:-:1024:17:A84EDAE89C800ACA:971961473:1214043198::-:SuSE Package Signing Key : - // fpr:::::::::79C179B2E1C820C1890F9994A84EDAE89C800ACA: - // sig:::17:A84EDAE89C800ACA:1087899198:::::[selfsig]::13x: - // sig:::17:9E40E310000AABA4:980442706::::[User ID not found]:10x: - // sig:::1:77B2E6003D25D3D9:980443247::::[User ID not found]:10x: - // sub:-:2048:16:197448E88495160C:971961490:1214043258::: [expires: 2008-06-21] - // sig:::17:A84EDAE89C800ACA:1087899258:::::[keybind]::18x: - - for ( line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() ) + PublicKeyScanner scanner; + for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() ) { - // trim trailing NL. - if ( line.empty() ) - continue; - if ( line[line.size()-1] == '\n' ) - line.erase( line.size()-1 ); - - // split at ':' - std::vector words; - str::splitFields( line, std::back_inserter(words), ":" ); - if( words.empty() ) - continue; - - if ( words[0] == "pub" ) - { - if ( sawpub ) - continue; - sawpub = true; - // take default from pub - _id = words[4]; - _name = words[9]; - _created = Date(str::strtonum(words[5])); - _expires = Date(str::strtonum(words[6])); - - } - else if ( words[0] == "sig" ) - { - if ( sawsig || words[words.size()-2] != "13x" ) - continue; - sawsig = true; - // update creation and expire dates from 1st signature type "13x" - if ( ! words[5].empty() ) - _created = Date(str::strtonum(words[5])); - if ( ! words[6].empty() ) - _expires = Date(str::strtonum(words[6])); - } - else if ( words[0] == "fpr" ) - { - _fingerprint = words[9]; - } - else if ( words[0] == "uid" ) - { - if ( ! words[9].empty() ) - _name = words[9]; - } - } + scanner.scan( line ); + } prog.close(); - if ( _id.size() == 0 ) - ZYPP_THROW( BadKeyException( "File " + _data_file.path().asString() + " doesn't contain public key data" , _data_file.path() ) ); - - //replace all escaped semicolon with real ':' - str::replaceAll( _name, "\\x3a", ":" ); + switch ( scanner._keys.size() ) + { + case 0: + ZYPP_THROW( BadKeyException( "File " + _dataFile.path().asString() + " doesn't contain public key data" , _dataFile.path() ) ); + break; + + case 1: + // ok. + _keyData = scanner._keys.back(); + _hiddenKeys.clear(); + break; + + default: + WAR << "File " << _dataFile.path().asString() << " contains multiple keys: " << scanner._keys << endl; + _keyData = scanner._keys.back(); + scanner._keys.pop_back(); + _hiddenKeys.swap( scanner._keys ); + break; + } - MIL << "Read pubkey from " << info.path() << ": " << asString() << endl; + MIL << "Read pubkey from " << info.path() << ": " << _keyData << endl; } private: - filesystem::TmpFile _data_file; + filesystem::TmpFile _dataFile; + PublicKeyData _keyData; + std::list _hiddenKeys; - std::string _id; - std::string _name; - std::string _fingerprint; - Date _created; - Date _expires; + public: + /** Offer default Impl. */ + static shared_ptr nullimpl() + { + static shared_ptr _nullimpl( new Impl ); + return _nullimpl; + } private: friend Impl * rwcowClone( const Impl * rhs ); @@ -265,96 +419,77 @@ namespace zypp /////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// - // - // METHOD NAME : PublicKey::PublicKey - // METHOD TYPE : Ctor - // + // class PublicKey + /////////////////////////////////////////////////////////////////// PublicKey::PublicKey() : _pimpl( Impl::nullimpl() ) {} PublicKey::PublicKey( const Pathname & file ) - : _pimpl( new Impl(file) ) + : _pimpl( new Impl( file ) ) {} PublicKey::PublicKey( const filesystem::TmpFile & sharedfile ) - : _pimpl( new Impl(sharedfile) ) + : _pimpl( new Impl( sharedfile ) ) + {} + + PublicKey::PublicKey( const filesystem::TmpFile & sharedfile, const PublicKeyData & keydata ) + : _pimpl( new Impl( sharedfile, keydata ) ) {} - /////////////////////////////////////////////////////////////////// - // - // METHOD NAME : PublicKey::~PublicKey - // METHOD TYPE : Dtor - // PublicKey::~PublicKey() {} - /////////////////////////////////////////////////////////////////// - // - // Forward to implementation: - // - /////////////////////////////////////////////////////////////////// + const PublicKeyData & PublicKey::keyData() const + { return _pimpl->keyData(); } - std::string PublicKey::asString() const - { return _pimpl->asString(); } + Pathname PublicKey::path() const + { return _pimpl->path(); } + + const std::list & PublicKey::hiddenKeys() const + { return _pimpl->hiddenKeys(); } std::string PublicKey::id() const - { return _pimpl->id(); } + { return keyData().id(); } std::string PublicKey::name() const - { return _pimpl->name(); } + { return keyData().name(); } std::string PublicKey::fingerprint() const - { return _pimpl->fingerprint(); } - - std::string PublicKey::gpgPubkeyVersion() const - { return _pimpl->gpgPubkeyVersion(); } - - std::string PublicKey::gpgPubkeyRelease() const - { return _pimpl->gpgPubkeyRelease(); } + { return keyData().fingerprint(); } Date PublicKey::created() const - { return _pimpl->created(); } + { return keyData().created(); } Date PublicKey::expires() const - { return _pimpl->expires(); } - - std::string PublicKey::expiresAsString() const - { return _pimpl->expiresAsString(); } + { return keyData().expires(); } bool PublicKey::expired() const - { return _pimpl->expired(); } + { return keyData().expired(); } int PublicKey::daysToLive() const - { return _pimpl->daysToLive(); } + { return keyData().daysToLive(); } - Pathname PublicKey::path() const - { return _pimpl->path(); } + std::string PublicKey::expiresAsString() const + { return keyData().expiresAsString(); } - bool PublicKey::operator==( PublicKey b ) const - { - return ( b.id() == id() - && b.fingerprint() == fingerprint() - && b.created() == created() ); - } + std::string PublicKey::gpgPubkeyVersion() const + { return keyData().gpgPubkeyVersion(); } - bool PublicKey::operator==( std::string sid ) const - { - return sid == id(); - } + std::string PublicKey::gpgPubkeyRelease() const + { return keyData().gpgPubkeyRelease(); } + + std::string PublicKey::asString() const + { return keyData().asString(); } + + bool PublicKey::operator==( const PublicKey & rhs ) const + { return rhs.keyData() == keyData(); } + + bool PublicKey::operator==( const std::string & sid ) const + { return sid == id(); } std::ostream & dumpOn( std::ostream & str, const PublicKey & obj ) - { - str << "[" << obj.name() << "]" << endl; - str << " fpr " << obj.fingerprint() << endl; - str << " id " << obj.id() << endl; - str << " cre " << obj.created() << endl; - str << " exp " << obj.expiresAsString() << endl; - str << " ttl " << obj.daysToLive() << endl; - str << " rpm " << obj.gpgPubkeyVersion() << "-" << obj.gpgPubkeyRelease() << endl; - str << "]"; - return str; - } + { return dumpOn( str, obj.keyData() ); } ///////////////////////////////////////////////////////////////// } // namespace zypp diff --git a/libzypp/zypp/PublicKey.h b/libzypp/zypp/PublicKey.h index 480d925..9ba6bad 100644 --- a/libzypp/zypp/PublicKey.h +++ b/libzypp/zypp/PublicKey.h @@ -21,6 +21,7 @@ #include "zypp/base/PtrTypes.h" #include "zypp/base/Exception.h" #include "zypp/Pathname.h" +#include "zypp/Date.h" /////////////////////////////////////////////////////////////////// namespace zypp @@ -31,10 +32,10 @@ namespace zypp class TmpFile; } - /** - * Exception thrown when the supplied key is - * not a valid gpg key - */ + /////////////////////////////////////////////////////////////////// + /// \class BadKeyException + /// \brief Exception thrown when the supplied key is not a valid gpg key + /////////////////////////////////////////////////////////////////// class BadKeyException : public Exception { public: @@ -59,24 +60,153 @@ namespace zypp private: Pathname _keyfile; }; + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + /// \class PublicKeyData + /// \brief Class representing one GPG Public Keys data. + /// \ref PublicKeyData are provided e.g. by a \ref PublicKey or + /// a \ref KeyRing. \ref PublicKeyData are usually easier to + /// retrieve and sufficient unless you actually need an ASCII + /// armored version of the key placed in a tempfile. In this + /// case use \ref PublicKey. + /////////////////////////////////////////////////////////////////// + class PublicKeyData + { + public: + /** Default constructed: empty data. */ + PublicKeyData(); + + ~PublicKeyData(); + + /** Scan data from 'gpg --with-colons' key listings. */ + friend class PublicKeyScanner; + + /** Whether this contains valid data (not default constructed). */ + explicit operator bool() const; + + public: + /** Key ID. */ + std::string id() const; + + /** Key name. */ + std::string name() const; + + /** Key fingerprint.*/ + std::string fingerprint() const; + + /** Creation / last modification date (latest selfsig). */ + Date created() const; + + /** Expiry date, or \c Date() if the key never expires. */ + Date expires() const; + + /** Whether the key has expired. */ + bool expired() const; + + /** Number of days (24h) until the key expires (or since it exired). + * A value of \c 0 means the key will expire within the next 24h. + * Negative values indicate the key has expired less than \c N days ago. + * For keys without expiration date \c INT_MAX is returned. + */ + int daysToLive() const; + /** * Expiry info in a human readable form. + * The exipry daye plus an annotation if the key has expired, or will + * expire within 90 days. + * \code + * (does not expire) + * Tue May 11 13:37:33 CEST 2010 + * Tue May 11 13:37:33 CEST 2010 (expires in 90 days) + * Tue May 11 13:37:33 CEST 2010 (expires in 1 day) + * Tue May 11 13:37:33 CEST 2010 (expires within 24h) + * Tue May 11 13:37:33 CEST 2010 (EXPIRED) + * \endcode + */ + std::string expiresAsString() const; - // forward declaration of class Date - class Date; + /** Gpg-pubkey version as computed by rpm (trailing 8 byte \ref id) */ + std::string gpgPubkeyVersion() const; + + /** Gpg-pubkey release as computed by rpm (hexencoded \ref created) */ + std::string gpgPubkeyRelease() const; + /** Simple string representation. + * Encodes \ref id, \ref gpgPubkeyRelease, \ref name and \ref fingerprint. + * \code + * [E3A5C360307E3D54-4be01a65] [SuSE Package Signing Key ] [4E98E67519D98DC7362A5990E3A5C360307E3D54] + * \endcode + */ + std::string asString() const; + + private: + class Impl; + RWCOW_pointer _pimpl; + }; /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : PublicKey - // - /** - * Class that represent a GPG Public Key. - * - * - */ - class PublicKey + + /** \relates PublicKeyData Stream output */ + inline std::ostream & operator<<( std::ostream & str, const PublicKeyData & obj ) + { return str << obj.asString(); } + + /** \relates PublicKeyData Detailed stream output */ + std::ostream & dumpOn( std::ostream & str, const PublicKeyData & obj ); + + /** \relates PublicKeyData Equal based on fingerprint anf creation date. */ + bool operator==( const PublicKeyData & lhs, const PublicKeyData & rhs ); + + /** \relates PublicKeyData NotEqual. */ + inline bool operator!=( const PublicKeyData & lhs, const PublicKeyData & rhs ) + { return !( lhs == rhs ); } + + /////////////////////////////////////////////////////////////////// + /// \class PublicKeyScanner + /// \brief Scan abstract from 'gpg --with-colons' key listings. + /// Feed gpg output line by line into \ref scan. The collected \ref PublicKeyData + /// contain the keys data (fingerprint, uid,...) but not the key itself (ASCII + /// armored stored in a file). + /// \code + /// std::list result; + /// { + /// PublicKeyScanner scanner; + /// for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() ) + /// scanner.scan( line ); + /// result.swap( scanner._keys ); + /// } + /// \endcode + /// \relates PublicKeyData + /////////////////////////////////////////////////////////////////// + struct PublicKeyScanner { - friend std::ostream & operator<<( std::ostream & str, const PublicKey & obj ); + PublicKeyScanner(); + ~PublicKeyScanner(); + + /** Feed gpg output line by line into \ref scan. */ + void scan( std::string line_r ); + + /** Extracted keys. */ + std::list _keys; + + private: + class Impl; + RW_pointer > _pimpl; + }; + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + /// \class PublicKey + /// \brief Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile). + /// + /// If you don't need the ASCII armored version of the key stored in + /// a tempfile, using \ref PublicKeyData might be sufficient. + /// + /// \note In case the ASCII armored blob actually contains multiple + /// keys, the \b last keys data are made available via the API. The + /// additional keys data are made available via \ref hiddenKeys. + /////////////////////////////////////////////////////////////////// + class PublicKey + { public: /** Implementation */ class Impl; @@ -93,8 +223,7 @@ namespace zypp * * \throws when data does not make a key */ - explicit - PublicKey( const Pathname & file ); + explicit PublicKey( const Pathname & keyFile_r ); /** Ctor reading the key from a \ref TmpFile. * @@ -102,86 +231,44 @@ namespace zypp * * \throws when data does not make a key */ - explicit - PublicKey( const filesystem::TmpFile & sharedfile ); + explicit PublicKey( const filesystem::TmpFile & sharedFile_r ); ~PublicKey(); - bool isValid() const - { return ( ! id().empty() && ! fingerprint().empty() && !path().empty() ); } - - std::string asString() const; - std::string id() const; - std::string name() const; - std::string fingerprint() const; - - /** Version rpm would assign to this key if imported into the rpm database. - * Rpm uses the lowercased trailing 8 byte from \ref id as \c version, and the - * creations dates lowercased hexadecimal representation as \c release. - * \see \ref gpgPubkeyRelease - * \code - * [zypp OBS Project ] - * fpr 47D7CE1DD600935B3B90365733D38EBC7FB7F464 - * id 33D38EBC7FB7F464 <-- trailing 8 byte - * cre Thu Mar 13 19:15:40 2008 <-- converted to hex - * exp Sat May 22 20:15:40 2010 - * ] - * - * Converting the creation date to its hexadecimal representation: - * $ bc <<<"obase=16;$(date -d 'Thu Mar 13 19:15:40 2008' +%s)" - * 47D96F4C - * - * Rpms name for this key: gpg-pubkey-7fb7f464-47d96f4c - * \endcode - */ - std::string gpgPubkeyVersion() const; - - /** Release rpm would assign to this key if imported into the rpm database. - * This is the creations dates hexadecimal representation as \c release lowercased. - * \see \ref gpgPubkeyVersion - */ - std::string gpgPubkeyRelease() const; - - /** - * Date when the key was created. - */ - Date created() const; + public: + /** The public keys data (\see \ref PublicKeyData).*/ + const PublicKeyData & keyData() const; - /** - * Date when the key expires. - * If the key never expires the date is Date() (i.e. 0 seconds since the epoch (1.1.1970)) - */ - Date expires() const; + bool isValid() const + { return ! ( id().empty() || fingerprint().empty() ); } - /** - * Expiry info in a human readable form. - * The exipry daye plus an annotation if the key has expired, or will - * expire within 90 days. - * \code - * (does not expire) - * Tue May 11 13:37:33 CEST 2010 - * Tue May 11 13:37:33 CEST 2010 (expires in 90 days) - * Tue May 11 13:37:33 CEST 2010 (expires in 1 day) - * Tue May 11 13:37:33 CEST 2010 (expires within 24h) - * Tue May 11 13:37:33 CEST 2010 (EXPIRED) - * \endcode - */ - std::string expiresAsString() const; + std::string id() const; //!< \see \ref PublicKeyData + std::string name() const; //!< \see \ref PublicKeyData + std::string fingerprint() const; //!< \see \ref PublicKeyData + Date created() const; //!< \see \ref PublicKeyData + Date expires() const; //!< \see \ref PublicKeyData + std::string expiresAsString() const; //!< \see \ref PublicKeyData + bool expired() const; //!< \see \ref PublicKeyData + int daysToLive() const; //!< \see \ref PublicKeyData + std::string gpgPubkeyVersion() const; //!< \see \ref PublicKeyData + std::string gpgPubkeyRelease() const; //!< \see \ref PublicKeyData + std::string asString() const; //!< \see \ref PublicKeyData - /** Whether the key has expired. */ - bool expired() const; + public: + /** File containig the ASCII armored key. */ + Pathname path() const; - /** Number of days (24h) until the key expires (or since it exired). - * A value of \c 0 means the key will expire within the next 24h. - * Negative values indicate the key has expired less than \c N days ago. - * For keys without expiration date \c INT_MAX is returned. - */ - int daysToLive() const; + /** Additional keys data in case the ASCII armored blob containes multiple keys. */ + const std::list & hiddenKeys() const; - Pathname path() const; + public: + bool operator==( const PublicKey & rhs ) const; + bool operator==( const std::string & sid ) const; - bool operator==( PublicKey b ) const; - bool operator==( std::string sid ) const; + private: + friend class KeyRing; + /** KeyRing ctor: No need to parse file if KeyRing already had valid KeyData. */ + PublicKey( const filesystem::TmpFile & sharedFile_r, const PublicKeyData & keyData_r ); private: /** Pointer to implementation */ diff --git a/libzypp/zypp/RepoInfo.cc b/libzypp/zypp/RepoInfo.cc index 91d72c2..cd20b96 100644 --- a/libzypp/zypp/RepoInfo.cc +++ b/libzypp/zypp/RepoInfo.cc @@ -12,17 +12,22 @@ #include #include -#include "zypp/base/Logger.h" +#include "zypp/base/LogTools.h" #include "zypp/base/DefaultIntegral.h" #include "zypp/parser/xml/XmlEscape.h" #include "zypp/RepoInfo.h" -#include "zypp/repo/RepoInfoBaseImpl.h" +#include "zypp/TriBool.h" +#include "zypp/Pathname.h" #include "zypp/repo/RepoMirrorList.h" #include "zypp/ExternalProgram.h" #include "zypp/media/MediaAccess.h" -using namespace std; +#include "zypp/base/IOStream.h" +#include "zypp/base/InputStream.h" +#include "zypp/parser/xml/Reader.h" + +using std::endl; using zypp::xml::escape; /////////////////////////////////////////////////////////////////// @@ -34,11 +39,10 @@ namespace zypp // CLASS NAME : RepoInfo::Impl // /** RepoInfo implementation. */ - struct RepoInfo::Impl : public repo::RepoInfoBase::Impl + struct RepoInfo::Impl { Impl() - : repo::RepoInfoBase::Impl() - , gpgcheck(indeterminate) + : gpgcheck(indeterminate) , keeppackages(indeterminate) , type(repo::RepoType::NONE_e) , emptybaseurls(false) @@ -64,39 +68,83 @@ namespace zypp Pathname licenseTgz() const { return metadatapath.empty() ? Pathname() : metadatapath / path / "license.tar.gz"; } - Url getmirrorListUrl() const + Url mirrorListUrl() const { return replacer(mirrorlist_url); } - Url &setmirrorListUrl() + void mirrorListUrl( const Url & url_r ) + { mirrorlist_url = url_r; } + + const Url & rawMirrorListUrl() const { return mirrorlist_url; } - const std::set &baseUrls() const + const url_set & baseUrls() const { - if ( _baseUrls.empty() && ! (getmirrorListUrl().asString().empty()) ) + if ( _baseUrls.empty() && ! mirrorListUrl().asString().empty() ) { emptybaseurls = true; - repo::RepoMirrorList *rmirrorlist = NULL; - DBG << "MetadataPath: " << metadatapath << endl; - if( metadatapath.empty() ) - rmirrorlist = new repo::RepoMirrorList (getmirrorListUrl() ); - else - rmirrorlist = new repo::RepoMirrorList (getmirrorListUrl(), metadatapath ); - - std::vector rmurls = rmirrorlist->getUrls(); - delete rmirrorlist; - rmirrorlist = NULL; - _baseUrls.insert(rmurls.begin(), rmurls.end()); + repo::RepoMirrorList rmurls( mirrorListUrl(), metadatapath ); + _baseUrls.insert( _baseUrls.end(), rmurls.getUrls().begin(), rmurls.getUrls().end() ); } return _baseUrls; } - std::set &baseUrls() + url_set & baseUrls() { return _baseUrls; } bool baseurl2dump() const { return !emptybaseurls && !_baseUrls.empty(); } + + void addContent( const std::string & keyword_r ) + { _keywords.insert( keyword_r ); } + + bool hasContent( const std::string & keyword_r ) const + { + if ( _keywords.empty() && ! metadatapath.empty() ) + { + // HACK directly check master index file until RepoManager offers + // some content probing ans zypepr 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.insert( reader.nodeText().asString() ); + reader.seekToEndNode( 2, "content" ); + } + _keywords.insert( "" ); // 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, 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.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.insert( "" ); + } + ///////////////////////////////////////////////////////////////// + } + return( _keywords.find( keyword_r ) != _keywords.end() ); + + } + public: TriBool gpgcheck; TriBool keeppackages; @@ -113,7 +161,8 @@ namespace zypp private: Url mirrorlist_url; - mutable std::set _baseUrls; + mutable url_set _baseUrls; + mutable std::set _keywords; friend Impl * rwcowClone( const Impl * rhs ); /** clone for RWCOW_pointer */ @@ -167,19 +216,24 @@ namespace zypp void RepoInfo::setGpgCheck( bool check ) { _pimpl->gpgcheck = check; } - void RepoInfo::setMirrorListUrl( const Url &url ) - { _pimpl->setmirrorListUrl() = url; } + void RepoInfo::setMirrorListUrl( const Url & url_r ) + { _pimpl->mirrorListUrl( url_r ); } - void RepoInfo::setGpgKeyUrl( const Url &url ) - { _pimpl->gpgkey_url = url; } + void RepoInfo::setGpgKeyUrl( const Url & url_r ) + { _pimpl->gpgkey_url = url_r; } - void RepoInfo::addBaseUrl( const Url &url ) - { _pimpl->baseUrls().insert(url); } + void RepoInfo::addBaseUrl( const Url & url_r ) + { + for ( const auto & url : _pimpl->baseUrls() ) // unique! + if ( url == url_r ) + return; + _pimpl->baseUrls().push_back( url_r ); + } - void RepoInfo::setBaseUrl( const Url &url ) + void RepoInfo::setBaseUrl( const Url & url_r ) { _pimpl->baseUrls().clear(); - addBaseUrl(url); + _pimpl->baseUrls().push_back( url_r ); } void RepoInfo::setPath( const Pathname &path ) @@ -223,22 +277,16 @@ namespace zypp { return _pimpl->type; } Url RepoInfo::mirrorListUrl() const - { return _pimpl->getmirrorListUrl(); } + { return _pimpl->mirrorListUrl(); } + + Url RepoInfo::rawMirrorListUrl() const + { return _pimpl->rawMirrorListUrl(); } Url RepoInfo::gpgKeyUrl() const { return _pimpl->gpgkey_url; } - std::set RepoInfo::baseUrls() const - { - RepoInfo::url_set replaced_urls; - for ( url_set::const_iterator it = _pimpl->baseUrls().begin(); - it != _pimpl->baseUrls().end(); - ++it ) - { - replaced_urls.insert(_pimpl->replacer(*it)); - } - return replaced_urls; - } + RepoInfo::url_set RepoInfo::baseUrls() const + { return url_set( baseUrlsBegin(), baseUrlsEnd() ); } // Variables replaced! Pathname RepoInfo::path() const { return _pimpl->path; } @@ -249,16 +297,17 @@ namespace zypp std::string RepoInfo::targetDistribution() const { return _pimpl->targetDistro; } + Url RepoInfo::rawUrl() const + { return( _pimpl->baseUrls().empty() ? Url() : *_pimpl->baseUrls().begin() ); } + RepoInfo::urls_const_iterator RepoInfo::baseUrlsBegin() const { return make_transform_iterator( _pimpl->baseUrls().begin(), _pimpl->replacer ); - //return _pimpl->baseUrls.begin(); } RepoInfo::urls_const_iterator RepoInfo::baseUrlsEnd() const { - //return _pimpl->baseUrls.end(); return make_transform_iterator( _pimpl->baseUrls().end(), _pimpl->replacer ); } @@ -272,18 +321,53 @@ namespace zypp bool RepoInfo::baseUrlSet() const { return _pimpl->baseurl2dump(); } + + void RepoInfo::addContent( const std::string & keyword_r ) + { _pimpl->addContent( keyword_r ); } + + bool RepoInfo::hasContent( const std::string & keyword_r ) const + { return _pimpl->hasContent( keyword_r ); } + /////////////////////////////////////////////////////////////////// bool RepoInfo::hasLicense() const { Pathname licenseTgz( _pimpl->licenseTgz() ); - SEC << licenseTgz << endl; - SEC << PathInfo(licenseTgz) << endl; - return ! licenseTgz.empty() && PathInfo(licenseTgz).isFile(); } + bool RepoInfo::needToAcceptLicense() const + { + static const std::string noAcceptanceFile = "no-acceptance-needed\n"; + bool accept = true; + + Pathname licenseTgz( _pimpl->licenseTgz() ); + if ( licenseTgz.empty() || ! PathInfo( licenseTgz ).isFile() ) + 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 ); + for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) + { + if ( output == noAcceptanceFile ) + { + accept = false; + } + } + MIL << "License for " << name() << " has to be accepted: " << (accept?"true":"false" ) << endl; + return accept; + } + std::string RepoInfo::getLicense( const Locale & lang_r ) + { return const_cast(this)->getLicense( lang_r ); } + + std::string RepoInfo::getLicense( const Locale & lang_r ) const { LocaleSet avlocales( getLicenseLocales() ); if ( avlocales.empty() ) @@ -351,10 +435,6 @@ namespace zypp else ret.insert( Locale( std::string( output.c_str()+license.size(), output.size()- license.size() - dotTxt.size() ) ) ); } - else - { - WAR << " " << output; - } } prog.close(); return ret; @@ -367,11 +447,9 @@ namespace zypp RepoInfoBase::dumpOn(str); if ( _pimpl->baseurl2dump() ) { - for ( urls_const_iterator it = baseUrlsBegin(); - it != baseUrlsEnd(); - ++it ) + for ( const auto & url : _pimpl->baseUrls() ) { - str << "- url : " << *it << std::endl; + str << "- url : " << url << std::endl; } } @@ -381,7 +459,7 @@ namespace zypp str << tag_r << value_r << std::endl; }); - strif( "- mirrorlist : ", _pimpl->getmirrorListUrl().asString() ); + strif( "- mirrorlist : ", _pimpl->rawMirrorListUrl().asString() ); strif( "- path : ", path().asString() ); str << "- type : " << type() << std::endl; str << "- priority : " << priority() << std::endl; @@ -406,19 +484,19 @@ namespace zypp if ( _pimpl->baseurl2dump() ) { str << "baseurl="; - for ( url_set::const_iterator it = _pimpl->baseUrls().begin(); - it != _pimpl->baseUrls().end(); - ++it ) + std::string indent; + for ( const auto & url : _pimpl->baseUrls() ) { - str << *it << endl; + str << indent << url << endl; + if ( indent.empty() ) indent = " "; // "baseurl=" } } if ( ! _pimpl->path.empty() ) str << "path="<< path() << endl; - if ( ! (_pimpl->getmirrorListUrl().asString().empty()) ) - str << "mirrorlist=" << _pimpl->getmirrorListUrl() << endl; + if ( ! (_pimpl->rawMirrorListUrl().asString().empty()) ) + str << "mirrorlist=" << _pimpl->rawMirrorListUrl() << endl; str << "type=" << type().asString() << endl; @@ -439,12 +517,9 @@ namespace zypp return str; } - std::ostream & RepoInfo::dumpAsXMLOn( std::ostream & str) const - { return dumpAsXMLOn(str, ""); } - - std::ostream & RepoInfo::dumpAsXMLOn( std::ostream & str, const std::string & content) const + std::ostream & RepoInfo::dumpAsXmlOn( std::ostream & str, const std::string & content ) const { - string tmpstr; + std::string tmpstr; str << "baseurl2dump() ) { - for (RepoInfo::urls_const_iterator urlit = baseUrlsBegin(); - urlit != baseUrlsEnd(); ++urlit) - str << "" << escape(urlit->asString()) << "" << endl; + for_( it, baseUrlsBegin(), baseUrlsEnd() ) // !transform iterator replaces variables + str << "" << escape((*it).asString()) << "" << endl; } str << "" << endl; diff --git a/libzypp/zypp/RepoInfo.h b/libzypp/zypp/RepoInfo.h index 8ac20f5..b757edb 100644 --- a/libzypp/zypp/RepoInfo.h +++ b/libzypp/zypp/RepoInfo.h @@ -54,6 +54,7 @@ namespace zypp * 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 @@ -62,6 +63,9 @@ namespace zypp * * \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 { @@ -91,7 +95,7 @@ namespace zypp */ void setPriority( unsigned newval_r ); - typedef std::set url_set; + typedef std::list url_set; typedef url_set::size_type urls_size_type; typedef transform_iterator urls_const_iterator; /** @@ -99,7 +103,8 @@ namespace zypp */ bool baseUrlsEmpty() const; /** - * whether there are manualy configured repository urls + * Whether there are manualy configured repository urls. + * If \c false, a mirrorlist might be used. */ bool baseUrlSet() const; /** @@ -119,16 +124,18 @@ namespace zypp */ Url url() const { return( baseUrlsEmpty() ? Url() : *baseUrlsBegin()); } + /** + * Pars pro toto: The first repository url (no variables replaced) + */ + Url rawUrl() const; /** * A Url under which the metadata are located, or a set of mirrors. * * This can't be empty in order the repository to be valid * unless the download of the mirror list succeeds and it * contains a valid url. - * - * \deprecated IMO superfluous as we provide begin/end iterator. */ - std::set baseUrls() const; + url_set baseUrls() const; /** * Add a base url. \see baseUrls * \param url The base url for the repository. @@ -174,6 +181,10 @@ namespace zypp * If empty, the base url will be used. */ Url mirrorListUrl() const; + /** + * The raw mirrorListUrl (no variables replaced). + */ + Url rawMirrorListUrl() const; /** * Set mirror list url. \see mirrorListUrl * \param url The base url for the list @@ -302,6 +313,40 @@ namespace zypp */ void setTargetDistribution(const std::string & targetDistribution); + /** Add content keywords */ + void addContent( const std::string & keyword_r ); + /** \overload add keywords from container */ + template + void addContentFrom( _Iterator begin_r, _Iterator end_r ) + { for_( it, begin_r, end_r ) addContent( *it ); } + /** \overload */ + template + void addContentFrom( const _Container & container_r ) + { addContentFrom( container_r.begin(), container_r.end() ); } + + /** Check for content keywords. + * Checking for an empty string returns whether content kewords are + * known at all. They may be missing due to missing metadata in disabled + * repos. + */ + bool hasContent( const std::string & keyword_r = std::string() ) const; + /** \overload check for \b all keywords being present */ + template + bool hasContentAll( _Iterator begin_r, _Iterator end_r ) const + { for_( it, begin_r, end_r ) if ( ! hasContent( *it ) ) return false; return true; } + /** \overload */ + template + bool hasContentAll( const _Container & container_r ) const + { return hasContentAll( container_r.begin(), container_r.end() ); } + /** \overload check for \b any keyword being present */ + template + bool hasContentAny( _Iterator begin_r, _Iterator end_r ) const + { for_( it, begin_r, end_r ) if ( hasContent( *it ) ) return true; return false; } + /** \overload */ + template + bool hasContentAny( const _Container & container_r ) const + { return hasContentAny( container_r.begin(), container_r.end() ); } + public: /** \name Repository license */ @@ -309,8 +354,14 @@ namespace zypp /** Whether there is a license associated with the repo. */ bool hasLicense() const; + /** Whether the repo license has to be accepted, e.g. there is no + * no acceptance needed for openSUSE. + */ + bool needToAcceptLicense() const; + /** Return the best license for the current (or a specified) locale. */ - std::string getLicense( const Locale & lang_r = Locale() ); + std::string getLicense( const Locale & lang_r = Locale() ) const; + std::string getLicense( const Locale & lang_r = Locale() ); // LEGACY API /** Return the locales the license is available for. * \ref Locale::noCode is included in case of \c license.txt which does @@ -335,22 +386,22 @@ namespace zypp /** * Write this RepoInfo object into \a str in a .repo file format. + * Raw values, no variable replacement. */ virtual std::ostream & dumpAsIniOn( std::ostream & str ) const; /** * Write an XML representation of this RepoInfo object. - */ - virtual std::ostream & dumpAsXMLOn(std::ostream & str) const; - - /** - * 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. */ - virtual std::ostream & dumpAsXMLOn( std::ostream & str, const std::string & content ) const; + virtual std::ostream & dumpAsXmlOn( std::ostream & str, const std::string & content = "" ) const; + + /** \deprecated Use camel cased dumpAsXmlOn */ + ZYPP_DEPRECATED std::ostream & dumpAsXMLOn( std::ostream & str, const std::string & content = "" ) const { return dumpAsXmlOn( str, content ); } class Impl; private: diff --git a/libzypp/zypp/RepoManager.cc b/libzypp/zypp/RepoManager.cc index 7e01bc6..5f2a672 100644 --- a/libzypp/zypp/RepoManager.cc +++ b/libzypp/zypp/RepoManager.cc @@ -21,6 +21,7 @@ #include "zypp/base/InputStream.h" #include "zypp/base/LogTools.h" #include "zypp/base/Gettext.h" +#include "zypp/base/DefaultIntegral.h" #include "zypp/base/Function.h" #include "zypp/base/Regex.h" #include "zypp/PathInfo.h" @@ -41,7 +42,6 @@ #include "zypp/repo/ServiceRepos.h" #include "zypp/repo/yum/Downloader.h" #include "zypp/repo/susetags/Downloader.h" -#include "zypp/parser/plaindir/RepoParser.h" #include "zypp/repo/PluginServices.h" #include "zypp/Target.h" // for Target::targetDistribution() for repo index services @@ -56,15 +56,17 @@ using std::endl; using std::string; using namespace zypp::repo; +#define OPT_PROGRESS const ProgressData::ReceiverFnc & = ProgressData::ReceiverFnc() + /////////////////////////////////////////////////////////////////// namespace zypp -{ ///////////////////////////////////////////////////////////////// - +{ + /////////////////////////////////////////////////////////////////// namespace { /** Simple media mounter to access non-downloading URLs e.g. for non-local plaindir repos. * \ingroup g_RAII - */ + */ class MediaMounter { public: @@ -97,6 +99,7 @@ namespace zypp private: media::MediaAccessId _mid; }; + /////////////////////////////////////////////////////////////////// /** Check if alias_r is present in repo/service container. */ template @@ -129,59 +132,35 @@ namespace zypp template inline typename Container::const_iterator findAlias( const std::string & alias_r, const Container & cont_r ) { return findAlias( alias_r, cont_r.begin(), cont_r.end() ); } - } - /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : RepoManagerOptions - // - /////////////////////////////////////////////////////////////////// - RepoManagerOptions::RepoManagerOptions( const Pathname & root_r ) - { - repoCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoCachePath() ); - repoRawCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoMetadataPath() ); - repoSolvCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoSolvfilesPath() ); - repoPackagesCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoPackagesPath() ); - 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; - } - - RepoManagerOptions RepoManagerOptions::makeTestSetup( const Pathname & root_r ) - { - RepoManagerOptions ret; - ret.repoCachePath = root_r; - ret.repoRawCachePath = root_r/"raw"; - ret.repoSolvCachePath = root_r/"solv"; - ret.repoPackagesCachePath = root_r/"packages"; - ret.knownReposPath = root_r/"repos.d"; - ret.knownServicesPath = root_r/"services.d"; - ret.pluginsPath = root_r/"plugins"; - ret.rootDir = root_r; - return ret; - } - - //////////////////////////////////////////////////////////////////////////// - - /** - * \short Simple callback to collect the results - * - * Classes like RepoFileParser call the callback - * once per each repo in a file. - * - * Passing this functor as callback, you can collect - * all results at the end, without dealing with async - * code. - * - * If targetDistro is set, all repos with non-empty RepoInfo::targetDistribution() - * will be skipped. - * - * \todo do this through a separate filter - */ + /** \short Generate a related filename from a repo/service infos alias */ + inline std::string filenameFromAlias( const std::string & alias_r, const std::string & stem_r ) + { + std::string filename( alias_r ); + // replace slashes with underscores + str::replaceAll( filename, "/", "_" ); + + filename = Pathname(filename).extend("."+stem_r).asString(); + MIL << "generating filename for " << stem_r << " [" << alias_r << "] : '" << filename << "'" << endl; + return filename; + } + + /** + * \short Simple callback to collect the results + * + * Classes like RepoFileReader call the callback + * once per each repo in a file. + * + * Passing this functor as callback, you can collect + * all results at the end, without dealing with async + * code. + * + * If targetDistro is set, all repos with non-empty RepoInfo::targetDistribution() + * will be skipped. + * + * \todo do this through a separate filter + */ struct RepoCollector : private base::NonCopyable { RepoCollector() @@ -199,9 +178,9 @@ namespace zypp && repo.targetDistribution() != targetDistro) { MIL - << "Skipping repository meant for '" << targetDistro + << "Skipping repository meant for '" << repo.targetDistribution() << "' distribution (current distro is '" - << repo.targetDistribution() << "')." << endl; + << targetDistro << "')." << endl; return true; } @@ -213,163 +192,156 @@ namespace zypp RepoInfoList repos; std::string targetDistro; }; + //////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////// - - /** - * Reads RepoInfo's from a repo file. - * - * \param file pathname of the file to read. - */ - static std::list repositories_in_file( const Pathname & file ) - { - MIL << "repo file: " << file << endl; - RepoCollector collector; - parser::RepoFileReader parser( file, bind( &RepoCollector::collect, &collector, _1 ) ); - return collector.repos; - } - - //////////////////////////////////////////////////////////////////////////// - - /** - * \short List of RepoInfo's from a directory - * - * Goes trough every file ending with ".repo" in a directory and adds all - * RepoInfo's contained in that file. - * - * \param dir pathname of the directory to read. - */ - static std::list repositories_in_dir( const Pathname &dir ) - { - MIL << "directory " << dir << endl; - std::list repos; - std::list entries; - if ( filesystem::readdir( entries, dir, false ) != 0 ) + /** + * Reads RepoInfo's from a repo file. + * + * \param file pathname of the file to read. + */ + std::list repositories_in_file( const Pathname & file ) { - // TranslatorExplanation '%s' is a pathname - ZYPP_THROW(Exception(str::form(_("Failed to read directory '%s'"), dir.c_str()))); + MIL << "repo file: " << file << endl; + RepoCollector collector; + parser::RepoFileReader parser( file, bind( &RepoCollector::collect, &collector, _1 ) ); + return std::move(collector.repos); } - str::regex allowedRepoExt("^\\.repo(_[0-9]+)?$"); - for ( std::list::const_iterator it = entries.begin(); it != entries.end(); ++it ) - { - if (str::regex_match(it->extension(), allowedRepoExt)) - { - std::list tmp = repositories_in_file( *it ); - repos.insert( repos.end(), tmp.begin(), tmp.end() ); + //////////////////////////////////////////////////////////////////////////// - //std::copy( collector.repos.begin(), collector.repos.end(), std::back_inserter(repos)); - //MIL << "ok" << endl; + /** + * \short List of RepoInfo's from a directory + * + * Goes trough every file ending with ".repo" in a directory and adds all + * RepoInfo's contained in that file. + * + * \param dir pathname of the directory to read. + */ + std::list repositories_in_dir( const Pathname &dir ) + { + MIL << "directory " << dir << endl; + std::list repos; + bool nonroot( geteuid() != 0 ); + if ( nonroot && ! PathInfo(dir).userMayRX() ) + { + JobReport::warning( formatNAC(_("Cannot read repo directory '%1%': Permission denied")) % dir ); } + else + { + std::list entries; + if ( filesystem::readdir( entries, dir, false ) != 0 ) + { + // TranslatorExplanation '%s' is a pathname + ZYPP_THROW(Exception(str::form(_("Failed to read directory '%s'"), dir.c_str()))); + } + + str::regex allowedRepoExt("^\\.repo(_[0-9]+)?$"); + for ( std::list::const_iterator it = entries.begin(); it != entries.end(); ++it ) + { + if ( str::regex_match(it->extension(), allowedRepoExt) ) + { + if ( nonroot && ! PathInfo(*it).userMayR() ) + { + JobReport::warning( formatNAC(_("Cannot read repo file '%1%': Permission denied")) % *it ); + } + else + { + const std::list & tmp( repositories_in_file( *it ) ); + repos.insert( repos.end(), tmp.begin(), tmp.end() ); + } + } + } + } + return repos; } - return repos; - } - - //////////////////////////////////////////////////////////////////////////// - - std::list readRepoFile(const Url & repo_file) - { - // no interface to download a specific file, using workaround: - //! \todo add MediaManager::provideFile(Url file_url) to easily access any file URLs? (no need for media access id or media_nr) - Url url(repo_file); - Pathname path(url.getPathName()); - url.setPathName ("/"); - MediaSetAccess access(url); - Pathname local = access.provideFile(path); - - DBG << "reading repo file " << repo_file << ", local path: " << local << endl; - - return repositories_in_file(local); - } - - //////////////////////////////////////////////////////////////////////////// - inline void assert_alias( const RepoInfo & info ) - { - if ( info.alias().empty() ) - ZYPP_THROW( RepoNoAliasException() ); - // bnc #473834. Maybe we can match the alias against a regex to define - // and check for valid aliases - if ( info.alias()[0] == '.') - ZYPP_THROW(RepoInvalidAliasException( - info, _("Repository alias cannot start with dot."))); - } + //////////////////////////////////////////////////////////////////////////// - inline void assert_alias( const ServiceInfo & info ) - { - if ( info.alias().empty() ) - ZYPP_THROW( ServiceNoAliasException() ); - // bnc #473834. Maybe we can match the alias against a regex to define - // and check for valid aliases - if ( info.alias()[0] == '.') - ZYPP_THROW(ServiceInvalidAliasException( - info, _("Service alias cannot start with dot."))); - } + inline void assert_alias( const RepoInfo & info ) + { + if ( info.alias().empty() ) + ZYPP_THROW( RepoNoAliasException( info ) ); + // bnc #473834. Maybe we can match the alias against a regex to define + // and check for valid aliases + if ( info.alias()[0] == '.') + ZYPP_THROW(RepoInvalidAliasException( + info, _("Repository alias cannot start with dot."))); + } - //////////////////////////////////////////////////////////////////////////// + inline void assert_alias( const ServiceInfo & info ) + { + if ( info.alias().empty() ) + ZYPP_THROW( ServiceNoAliasException( info ) ); + // bnc #473834. Maybe we can match the alias against a regex to define + // and check for valid aliases + if ( info.alias()[0] == '.') + ZYPP_THROW(ServiceInvalidAliasException( + info, _("Service alias cannot start with dot."))); + } - inline void assert_urls( const RepoInfo & info ) - { - if ( info.baseUrlsEmpty() ) - ZYPP_THROW( RepoNoUrlException( info ) ); - } + //////////////////////////////////////////////////////////////////////////// - inline void assert_url( const ServiceInfo & info ) - { - if ( ! info.url().isValid() ) - ZYPP_THROW( ServiceNoUrlException( info ) ); - } + inline void assert_urls( const RepoInfo & info ) + { + if ( info.baseUrlsEmpty() ) + ZYPP_THROW( RepoNoUrlException( info ) ); + } - //////////////////////////////////////////////////////////////////////////// + inline void assert_url( const ServiceInfo & info ) + { + if ( ! info.url().isValid() ) + ZYPP_THROW( ServiceNoUrlException( info ) ); + } - /** - * \short Calculates the raw cache path for a repository, this is usually - * /var/cache/zypp/alias - */ - inline Pathname rawcache_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info ) - { - assert_alias(info); - return opt.repoRawCachePath / info.escaped_alias(); - } + //////////////////////////////////////////////////////////////////////////// - /** - * \short Calculates the raw product metadata path for a repository, this is - * inside the raw cache dir, plus an optional path where the metadata is. - * - * It should be different only for repositories that are not in the root of - * the media. - * for example /var/cache/zypp/alias/addondir - */ - inline Pathname rawproductdata_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info ) - { - assert_alias(info); - return opt.repoRawCachePath / info.escaped_alias() / info.path(); - } + /** + * \short Calculates the raw cache path for a repository, this is usually + * /var/cache/zypp/alias + */ + inline Pathname rawcache_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info ) + { + assert_alias(info); + return opt.repoRawCachePath / info.escaped_alias(); + } + /** + * \short Calculates the raw product metadata path for a repository, this is + * inside the raw cache dir, plus an optional path where the metadata is. + * + * It should be different only for repositories that are not in the root of + * the media. + * for example /var/cache/zypp/alias/addondir + */ + inline Pathname rawproductdata_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info ) + { + assert_alias(info); + return opt.repoRawCachePath / info.escaped_alias() / info.path(); + } - /** - * \short Calculates the packages cache path for a repository - */ - inline Pathname packagescache_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info ) - { - assert_alias(info); - return opt.repoPackagesCachePath / info.escaped_alias(); - } + /** + * \short Calculates the packages cache path for a repository + */ + inline Pathname packagescache_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info ) + { + assert_alias(info); + return opt.repoPackagesCachePath / info.escaped_alias(); + } - /** - * \short Calculates the solv cache path for a repository - */ - inline Pathname solv_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info) - { - assert_alias(info); - return opt.repoSolvCachePath / info.escaped_alias(); - } + /** + * \short Calculates the solv cache path for a repository + */ + inline Pathname solv_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info) + { + assert_alias(info); + return opt.repoSolvCachePath / info.escaped_alias(); + } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// - /** Functor collecting ServiceInfos into a ServiceSet. */ - class ServiceCollector - { + /** Functor collecting ServiceInfos into a ServiceSet. */ + class ServiceCollector + { public: typedef std::set ServiceSet; @@ -379,77 +351,294 @@ namespace zypp bool operator()( const ServiceInfo & service_r ) const { - _services.insert( service_r ); - return true; + _services.insert( service_r ); + return true; } private: ServiceSet & _services; - }; + }; + //////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////// + } // namespace + /////////////////////////////////////////////////////////////////// + + std::list readRepoFile( const Url & repo_file ) + { + // no interface to download a specific file, using workaround: + //! \todo add MediaManager::provideFile(Url file_url) to easily access any file URLs? (no need for media access id or media_nr) + Url url(repo_file); + Pathname path(url.getPathName()); + url.setPathName ("/"); + MediaSetAccess access(url); + Pathname local = access.provideFile(path); + + DBG << "reading repo file " << repo_file << ", local path: " << local << endl; + + return repositories_in_file(local); + } /////////////////////////////////////////////////////////////////// // - // CLASS NAME : RepoManager::Impl + // class RepoManagerOptions // - /////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////// - /** - * \short RepoManager implementation. - */ + RepoManagerOptions::RepoManagerOptions( const Pathname & root_r ) + { + repoCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoCachePath() ); + repoRawCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoMetadataPath() ); + repoSolvCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoSolvfilesPath() ); + repoPackagesCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoPackagesPath() ); + 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; + } + + RepoManagerOptions RepoManagerOptions::makeTestSetup( const Pathname & root_r ) + { + RepoManagerOptions ret; + ret.repoCachePath = root_r; + ret.repoRawCachePath = root_r/"raw"; + ret.repoSolvCachePath = root_r/"solv"; + ret.repoPackagesCachePath = root_r/"packages"; + ret.knownReposPath = root_r/"repos.d"; + ret.knownServicesPath = root_r/"services.d"; + ret.pluginsPath = root_r/"plugins"; + ret.rootDir = root_r; + return ret; + } + + std:: ostream & operator<<( std::ostream & str, const RepoManagerOptions & obj ) + { +#define OUTS(X) str << " " #X "\t" << obj.X << endl + str << "RepoManagerOptions (" << obj.rootDir << ") {" << endl; + OUTS( repoRawCachePath ); + OUTS( repoSolvCachePath ); + OUTS( repoPackagesCachePath ); + OUTS( knownReposPath ); + OUTS( knownServicesPath ); + OUTS( pluginsPath ); + str << "}" << endl; +#undef OUTS + return str; + } + + /////////////////////////////////////////////////////////////////// + /// \class RepoManager::Impl + /// \brief RepoManager implementation. + /// + /////////////////////////////////////////////////////////////////// struct RepoManager::Impl { + public: Impl( const RepoManagerOptions &opt ) - : options(opt) + : _options(opt) { init_knownServices(); init_knownRepositories(); } + ~Impl() + { + // trigger appdata refresh if some repos change + if ( _reposDirty && geteuid() == 0 && ( _options.rootDir.empty() || _options.rootDir == "/" ) ) + { + try { + std::list entries; + filesystem::readdir( entries, _options.pluginsPath/"appdata", false ); + if ( ! entries.empty() ) + { + ExternalProgram::Arguments cmd; + cmd.push_back( "<" ); // discard stdin + cmd.push_back( ">" ); // discard stdout + cmd.push_back( "PROGRAM" ); // [2] - fix index below if changing! + for ( const auto & rinfo : repos() ) + { + if ( ! rinfo.enabled() ) + continue; + cmd.push_back( "-R" ); + cmd.push_back( rinfo.alias() ); + cmd.push_back( "-t" ); + cmd.push_back( rinfo.type().asString() ); + cmd.push_back( "-p" ); + cmd.push_back( rinfo.metadataPath().asString() ); + } + + for_( it, entries.begin(), entries.end() ) + { + PathInfo pi( *it ); + //DBG << "/tmp/xx ->" << pi << endl; + if ( pi.isFile() && pi.userMayRX() ) + { + // trigger plugin + cmd[2] = pi.asString(); // [2] - PROGRAM + ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout ); + } + } + } + } + catch (...) {} // no throw in dtor + } + } - RepoManagerOptions options; + public: + bool repoEmpty() const { return repos().empty(); } + RepoSizeType repoSize() const { return repos().size(); } + RepoConstIterator repoBegin() const { return repos().begin(); } + RepoConstIterator repoEnd() const { return repos().end(); } - RepoSet repos; + bool hasRepo( const std::string & alias ) const + { return foundAliasIn( alias, repos() ); } - ServiceSet services; + RepoInfo getRepo( const std::string & alias ) const + { + RepoConstIterator it( findAlias( alias, repos() ) ); + return it == repos().end() ? RepoInfo::noRepo : *it; + } public: + Pathname metadataPath( const RepoInfo & info ) const + { return rawcache_path_for_repoinfo( _options, info ); } + + Pathname packagesPath( const RepoInfo & info ) const + { return packagescache_path_for_repoinfo( _options, info ); } + + RepoStatus metadataStatus( const RepoInfo & info ) const; + + RefreshCheckStatus checkIfToRefreshMetadata( const RepoInfo & info, const Url & url, RawMetadataRefreshPolicy policy ); + + void refreshMetadata( const RepoInfo & info, RawMetadataRefreshPolicy policy, OPT_PROGRESS ); + + void cleanMetadata( const RepoInfo & info, OPT_PROGRESS ); + + void cleanPackages( const RepoInfo & info, OPT_PROGRESS ); + + void buildCache( const RepoInfo & info, CacheBuildPolicy policy, OPT_PROGRESS ); + + repo::RepoType probe( const Url & url, const Pathname & path = Pathname() ) const; + + void cleanCacheDirGarbage( OPT_PROGRESS ); + + void cleanCache( const RepoInfo & info, OPT_PROGRESS ); + + bool isCached( const RepoInfo & info ) const + { return PathInfo(solv_path_for_repoinfo( _options, info ) / "solv").isExist(); } + + RepoStatus cacheStatus( const RepoInfo & info ) const + { return RepoStatus::fromCookieFile(solv_path_for_repoinfo(_options, info) / "cookie"); } + + void loadFromCache( const RepoInfo & info, OPT_PROGRESS ); + + void addRepository( const RepoInfo & info, OPT_PROGRESS ); + + void addRepositories( const Url & url, OPT_PROGRESS ); + + void removeRepository( const RepoInfo & info, OPT_PROGRESS ); + + void modifyRepository( const std::string & alias, const RepoInfo & newinfo_r, OPT_PROGRESS ); + RepoInfo getRepositoryInfo( const std::string & alias, OPT_PROGRESS ); + RepoInfo getRepositoryInfo( const Url & url, const url::ViewOption & urlview, OPT_PROGRESS ); + + public: + bool serviceEmpty() const { return _services.empty(); } + ServiceSizeType serviceSize() const { return _services.size(); } + ServiceConstIterator serviceBegin() const { return _services.begin(); } + ServiceConstIterator serviceEnd() const { return _services.end(); } + + bool hasService( const std::string & alias ) const + { return foundAliasIn( alias, _services ); } + + ServiceInfo getService( const std::string & alias ) const + { + ServiceConstIterator it( findAlias( alias, _services ) ); + return it == _services.end() ? ServiceInfo::noService : *it; + } + + public: + void addService( const ServiceInfo & service ); + void addService( const std::string & alias, const Url & url ) + { addService( ServiceInfo( alias, url ) ); } + + void removeService( const std::string & alias ); + void removeService( const ServiceInfo & service ) + { removeService( service.alias() ); } + + void refreshServices( const RefreshServiceOptions & options_r ); + + void refreshService( const std::string & alias, const RefreshServiceOptions & options_r ); + void refreshService( const ServiceInfo & service, const RefreshServiceOptions & options_r ) + { refreshService( service.alias(), options_r ); } + + void modifyService( const std::string & oldAlias, const ServiceInfo & newService ); + + repo::ServiceType probeService( const Url & url ) const; + + private: void saveService( ServiceInfo & service ) const; - Pathname generateNonExistingName( const Pathname &dir, - const std::string &basefilename ) const; + Pathname generateNonExistingName( const Pathname & dir, const std::string & basefilename ) const; + + std::string generateFilename( const RepoInfo & info ) const + { return filenameFromAlias( info.alias(), "repo" ); } - std::string generateFilename( const RepoInfo & info ) const; - std::string generateFilename( const ServiceInfo & info ) const; + std::string generateFilename( const ServiceInfo & info ) const + { return filenameFromAlias( info.alias(), "service" ); } + void setCacheStatus( const RepoInfo & info, const RepoStatus & status ) + { + Pathname base = solv_path_for_repoinfo( _options, info ); + filesystem::assert_dir(base); + status.saveToCookieFile( base / "cookie" ); + } + + void touchIndexFile( const RepoInfo & info ); + + 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); + } private: void init_knownServices(); void init_knownRepositories(); + const RepoSet & repos() const { return _reposX; } + RepoSet & reposManip() { if ( ! _reposDirty ) _reposDirty = true; return _reposX; } + + private: + RepoManagerOptions _options; + RepoSet _reposX; + ServiceSet _services; + + DefaultIntegral _reposDirty; + private: friend Impl * rwcowClone( const Impl * rhs ); /** clone for RWCOW_pointer */ Impl * clone() const { return new Impl( *this ); } }; - /////////////////////////////////////////////////////////////////// /** \relates RepoManager::Impl Stream output */ inline std::ostream & operator<<( std::ostream & str, const RepoManager::Impl & obj ) - { - return str << "RepoManager::Impl"; - } + { return str << "RepoManager::Impl"; } /////////////////////////////////////////////////////////////////// void RepoManager::Impl::saveService( ServiceInfo & service ) const { - filesystem::assert_dir( options.knownServicesPath ); - Pathname servfile = generateNonExistingName( options.knownServicesPath, + filesystem::assert_dir( _options.knownServicesPath ); + Pathname servfile = generateNonExistingName( _options.knownServicesPath, generateFilename( service ) ); service.setFilepath( servfile ); @@ -488,46 +677,16 @@ namespace zypp while ( PathInfo(dir + final_filename).isExist() ) { final_filename = basefilename + "_" + str::numstring(counter); - counter++; + ++counter; } return dir + Pathname(final_filename); } //////////////////////////////////////////////////////////////////////////// - /** - * \short Generate a related filename from a repo info - * - * From a repo info, it will try to use the alias as a filename - * escaping it if necessary. Other fallbacks can be added to - * this function in case there is no way to use the alias - */ - std::string RepoManager::Impl::generateFilename( const RepoInfo & info ) const - { - std::string filename = info.alias(); - // replace slashes with underscores - str::replaceAll( filename, "/", "_" ); - - filename = Pathname(filename).extend(".repo").asString(); - MIL << "generating filename for repo [" << info.alias() << "] : '" << filename << "'" << endl; - return filename; - } - - std::string RepoManager::Impl::generateFilename( const ServiceInfo & info ) const - { - std::string filename = info.alias(); - // replace slashes with underscores - str::replaceAll( filename, "/", "_" ); - - filename = Pathname(filename).extend(".service").asString(); - MIL << "generating filename for service [" << info.alias() << "] : '" << filename << "'" << endl; - return filename; - } - - void RepoManager::Impl::init_knownServices() { - Pathname dir = options.knownServicesPath; + Pathname dir = _options.knownServicesPath; std::list entries; if (PathInfo(dir).isExist()) { @@ -540,171 +699,135 @@ namespace zypp //str::regex allowedServiceExt("^\\.service(_[0-9]+)?$"); for_(it, entries.begin(), entries.end() ) { - parser::ServiceFileReader(*it, ServiceCollector(services)); + parser::ServiceFileReader(*it, ServiceCollector(_services)); } } - repo::PluginServices(options.pluginsPath/"services", ServiceCollector(services)); + repo::PluginServices(_options.pluginsPath/"services", ServiceCollector(_services)); } + /////////////////////////////////////////////////////////////////// + namespace { + /** Delete \a cachePath_r subdirs not matching known aliases in \a repoEscAliases_r (must be sorted!) + * \note bnc#891515: Auto-cleanup only zypp.conf default locations. Otherwise + * we'd need some magic file to identify zypp cache directories. Without this + * we may easily remove user data (zypper --pkg-cache-dir . download ...) + */ + inline void cleanupNonRepoMetadtaFolders( const Pathname & cachePath_r, + const Pathname & defaultCachePath_r, + const std::list & repoEscAliases_r ) + { + if ( cachePath_r != defaultCachePath_r ) + return; + + std::list entries; + if ( filesystem::readdir( entries, cachePath_r, false ) == 0 ) + { + entries.sort(); + std::set oldfiles; + set_difference( entries.begin(), entries.end(), repoEscAliases_r.begin(), repoEscAliases_r.end(), + std::inserter( oldfiles, oldfiles.end() ) ); + for ( const std::string & old : oldfiles ) + { + if ( old == Repository::systemRepoAlias() ) // don't remove the @System solv file + continue; + filesystem::recursive_rmdir( cachePath_r / old ); + } + } + } + } // namespace + /////////////////////////////////////////////////////////////////// void RepoManager::Impl::init_knownRepositories() { MIL << "start construct known repos" << endl; - if ( PathInfo(options.knownReposPath).isExist() ) + if ( PathInfo(_options.knownReposPath).isExist() ) { - RepoInfoList repol = repositories_in_dir(options.knownReposPath); - std::list repo_esc_aliases; - std::list entries; - for ( RepoInfoList::iterator it = repol.begin(); - it != repol.end(); - ++it ) + std::list repoEscAliases; + std::list orphanedRepos; + for ( RepoInfo & repoInfo : repositories_in_dir(_options.knownReposPath) ) { // set the metadata path for the repo - Pathname metadata_path = rawcache_path_for_repoinfo(options, (*it)); - (*it).setMetadataPath(metadata_path); - + repoInfo.setMetadataPath( rawcache_path_for_repoinfo(_options, repoInfo) ); // set the downloaded packages path for the repo - Pathname packages_path = packagescache_path_for_repoinfo(options, (*it)); - (*it).setPackagesPath(packages_path); - - repos.insert(*it); - repo_esc_aliases.push_back(it->escaped_alias()); + repoInfo.setPackagesPath( packagescache_path_for_repoinfo(_options, repoInfo) ); + // remember it + _reposX.insert( repoInfo ); // direct access via _reposX in ctor! no reposManip. + + // detect orphaned repos belonging to a deleted service + const std::string & serviceAlias( repoInfo.service() ); + if ( ! ( serviceAlias.empty() || hasService( serviceAlias ) ) ) + { + WAR << "Schedule orphaned service repo for deletion: " << repoInfo << endl; + orphanedRepos.push_back( repoInfo ); + continue; // don't remember it in repoEscAliases + } + + repoEscAliases.push_back(repoInfo.escaped_alias()); } - // delete metadata folders without corresponding repo (e.g. old tmp directories) - if ( filesystem::readdir( entries, options.repoRawCachePath, false ) == 0 ) + // Cleanup orphanded service repos: + if ( ! orphanedRepos.empty() ) { - std::set oldfiles; - repo_esc_aliases.sort(); - entries.sort(); - set_difference(entries.begin(), entries.end(), repo_esc_aliases.begin(), repo_esc_aliases.end(), std::inserter(oldfiles, oldfiles.end())); - for_(it, oldfiles.begin(), oldfiles.end()) - { - filesystem::recursive_rmdir(options.repoRawCachePath / *it); - } + for ( auto & repoInfo : orphanedRepos ) + { + MIL << "Delete orphaned service repo " << repoInfo.alias() << endl; + // translators: Cleanup a repository previously owned by a meanwhile unknown (deleted) service. + // %1% = service name + // %2% = repository name + JobReport::warning( formatNAC(_("Unknown service '%1%': Removing orphaned service repository '%2%'" )) + % repoInfo.service() + % repoInfo.alias() ); + try { + removeRepository( repoInfo ); + } + catch ( const Exception & caugth ) + { + JobReport::error( caugth.asUserHistory() ); + } + } } - } + // delete metadata folders without corresponding repo (e.g. old tmp directories) + // + // bnc#891515: Auto-cleanup only zypp.conf default locations. Otherwise + // we'd need somemagic file to identify zypp cache directories. Without this + // we may easily remove user data (zypper --pkg-cache-dir . download ...) + repoEscAliases.sort(); + RepoManagerOptions defaultCache( _options.rootDir ); + cleanupNonRepoMetadtaFolders( _options.repoRawCachePath, defaultCache.repoRawCachePath, repoEscAliases ); + cleanupNonRepoMetadtaFolders( _options.repoSolvCachePath, defaultCache.repoSolvCachePath, repoEscAliases ); + cleanupNonRepoMetadtaFolders( _options.repoPackagesCachePath, defaultCache.repoPackagesCachePath, repoEscAliases ); + } MIL << "end construct known repos" << endl; } - /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : RepoManager - // /////////////////////////////////////////////////////////////////// - RepoManager::RepoManager( const RepoManagerOptions &opt ) - : _pimpl( new Impl(opt) ) - {} - - //////////////////////////////////////////////////////////////////////////// - - RepoManager::~RepoManager() - {} - - //////////////////////////////////////////////////////////////////////////// - - bool RepoManager::repoEmpty() const - { return _pimpl->repos.empty(); } - - RepoManager::RepoSizeType RepoManager::repoSize() const - { return _pimpl->repos.size(); } - - RepoManager::RepoConstIterator RepoManager::repoBegin() const - { return _pimpl->repos.begin(); } - - RepoManager::RepoConstIterator RepoManager::repoEnd() const - { return _pimpl->repos.end(); } - - RepoInfo RepoManager::getRepo( const std::string & alias ) const - { - for_( it, repoBegin(), repoEnd() ) - if ( it->alias() == alias ) - return *it; - return RepoInfo::noRepo; - } - - bool RepoManager::hasRepo( const std::string & alias ) const - { - for_( it, repoBegin(), repoEnd() ) - if ( it->alias() == alias ) - return true; - return false; - } - - std::string RepoManager::makeStupidAlias( const Url & url_r ) - { - std::string ret( url_r.getScheme() ); - if ( ret.empty() ) - ret = "repo-"; - else - ret += "-"; - - std::string host( url_r.getHost() ); - if ( ! host.empty() ) - { - ret += host; - ret += "-"; - } - - static Date::ValueType serial = Date::now(); - ret += Digest::digest( Digest::sha1(), str::hexstring( ++serial ) +url_r.asCompleteString() ).substr(0,8); - return ret; - } - - //////////////////////////////////////////////////////////////////////////// - - Pathname RepoManager::metadataPath( const RepoInfo &info ) const + RepoStatus RepoManager::Impl::metadataStatus( const RepoInfo & info ) const { - return rawcache_path_for_repoinfo(_pimpl->options, info ); - } - - Pathname RepoManager::packagesPath( const RepoInfo &info ) const - { - return packagescache_path_for_repoinfo(_pimpl->options, info ); - } - - //////////////////////////////////////////////////////////////////////////// + Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info ); + Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info ); - RepoStatus RepoManager::metadataStatus( const RepoInfo &info ) const - { - Pathname mediarootpath = rawcache_path_for_repoinfo( _pimpl->options, info ); - Pathname productdatapath = rawproductdata_path_for_repoinfo( _pimpl->options, info ); RepoType repokind = info.type(); - RepoStatus status; - - switch ( repokind.toEnum() ) - { - case RepoType::NONE_e: - // unknown, probe the local metadata - repokind = probe( productdatapath.asUrl() ); - break; - default: - break; - } + // If unknown, probe the local metadata + if ( repokind == RepoType::NONE ) + repokind = probe( productdatapath.asUrl() ); + RepoStatus status; switch ( repokind.toEnum() ) { case RepoType::RPMMD_e : - { - status = RepoStatus( productdatapath + "/repodata/repomd.xml"); - } - break; + status = RepoStatus( productdatapath/"repodata/repomd.xml"); + break; case RepoType::YAST2_e : - { - status = RepoStatus( productdatapath + "/content") && (RepoStatus( mediarootpath + "/media.1/media")); - } - break; + status = RepoStatus( productdatapath/"content" ) && RepoStatus( mediarootpath/"media.1/media" ); + break; case RepoType::RPMPLAINDIR_e : - { - if ( PathInfo(Pathname(productdatapath + "/cookie")).isExist() ) - status = RepoStatus( productdatapath + "/cookie"); - } - break; + status = RepoStatus::fromCookieFile( productdatapath/"cookie" ); + break; case RepoType::NONE_e : // Return default RepoStatus in case of RepoType::NONE @@ -715,9 +838,10 @@ namespace zypp return status; } - void RepoManager::touchIndexFile(const RepoInfo & info) + + void RepoManager::Impl::touchIndexFile( const RepoInfo & info ) { - Pathname productdatapath = rawproductdata_path_for_repoinfo( _pimpl->options, info ); + Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info ); RepoType repokind = info.type(); if ( repokind.toEnum() == RepoType::NONE_e ) @@ -751,24 +875,18 @@ namespace zypp filesystem::touch(p); } - RepoManager::RefreshCheckStatus RepoManager::checkIfToRefreshMetadata( - const RepoInfo &info, - const Url &url, - RawMetadataRefreshPolicy policy ) + + RepoManager::RefreshCheckStatus RepoManager::Impl::checkIfToRefreshMetadata( const RepoInfo & info, const Url & url, RawMetadataRefreshPolicy policy ) { assert_alias(info); - - RepoStatus oldstatus; - RepoStatus newstatus; - try { MIL << "Going to try to check whether refresh is needed for " << url << endl; // first check old (cached) metadata - Pathname mediarootpath = rawcache_path_for_repoinfo( _pimpl->options, info ); - filesystem::assert_dir(mediarootpath); - oldstatus = metadataStatus(info); + Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info ); + filesystem::assert_dir( mediarootpath ); + RepoStatus oldstatus = metadataStatus( info ); if ( oldstatus.empty() ) { @@ -777,12 +895,15 @@ namespace zypp } { - std::string scheme( url.getScheme() ); - if ( scheme == "cd" || scheme == "dvd" ) - { - MIL << "never refresh CD/DVD" << endl; + if ( url.schemeIsVolatile() ) + { + MIL << "never refresh CD/DVD" << endl; return REPO_UP_TO_DATE; - } + } + if ( url.schemeIsLocal() ) + { + policy = RefreshIfNeededIgnoreDelay; + } } // now we've got the old (cached) status, we can decide repo.refresh.delay @@ -814,83 +935,61 @@ namespace zypp } } - // To test the new matadta create temp dir as sibling of mediarootpath - filesystem::TmpDir tmpdir( filesystem::TmpDir::makeSibling( mediarootpath ) ); - repo::RepoType repokind = info.type(); - // if the type is unknown, try probing. - switch ( repokind.toEnum() ) - { - case RepoType::NONE_e: - // unknown, probe it \todo respect productdir - repokind = probe( url, info.path() ); - break; - default: - break; - } + // if unknown: probe it + if ( repokind == RepoType::NONE ) + repokind = probe( url, info.path() ); - if ( ( repokind.toEnum() == RepoType::RPMMD_e ) || - ( repokind.toEnum() == RepoType::YAST2_e ) ) + // retrieve newstatus + RepoStatus newstatus; + switch ( repokind.toEnum() ) { - MediaSetAccess media(url); - shared_ptr downloader_ptr; - - if ( repokind.toEnum() == RepoType::RPMMD_e ) - downloader_ptr.reset(new yum::Downloader(info, mediarootpath)); - else - downloader_ptr.reset( new susetags::Downloader(info, mediarootpath)); + case RepoType::RPMMD_e: + { + MediaSetAccess media( url ); + newstatus = yum::Downloader( info, mediarootpath ).status( media ); + } + break; - RepoStatus newstatus = downloader_ptr->status(media); - bool refresh = false; - if ( oldstatus.checksum() == newstatus.checksum() ) - { - MIL << "repo has not changed" << endl; - if ( policy == RefreshForced ) - { - MIL << "refresh set to forced" << endl; - refresh = true; - } - } - else - { - MIL << "repo has changed, going to refresh" << endl; - refresh = true; - } + case RepoType::YAST2_e: + { + MediaSetAccess media( url ); + newstatus = susetags::Downloader( info, mediarootpath ).status( media ); + } + break; - if (!refresh) - touchIndexFile(info); + case RepoType::RPMPLAINDIR_e: + newstatus = RepoStatus( MediaMounter(url).getPathName(info.path()) ); // dir status + break; - return refresh ? REFRESH_NEEDED : REPO_UP_TO_DATE; + default: + case RepoType::NONE_e: + ZYPP_THROW( RepoUnknownTypeException( info ) ); + break; } - else if ( repokind.toEnum() == RepoType::RPMPLAINDIR_e ) - { - MediaMounter media( url ); - RepoStatus newstatus = parser::plaindir::dirStatus( media.getPathName( info.path() ) ); - bool refresh = false; - if ( oldstatus.checksum() == newstatus.checksum() ) - { - MIL << "repo has not changed" << endl; - if ( policy == RefreshForced ) - { - MIL << "refresh set to forced" << endl; - refresh = true; - } - } - else - { - MIL << "repo has changed, going to refresh" << endl; - refresh = true; - } - if (!refresh) - touchIndexFile(info); - - return refresh ? REFRESH_NEEDED : REPO_UP_TO_DATE; + // check status + bool refresh = false; + if ( oldstatus == newstatus ) + { + MIL << "repo has not changed" << endl; + if ( policy == RefreshForced ) + { + MIL << "refresh set to forced" << endl; + refresh = true; + } } else { - ZYPP_THROW(RepoUnknownTypeException(info)); + MIL << "repo has changed, going to refresh" << endl; + refresh = true; } + + if (!refresh) + touchIndexFile(info); + + return refresh ? REFRESH_NEEDED : REPO_UP_TO_DATE; + } catch ( const Exception &e ) { @@ -902,15 +1001,16 @@ namespace zypp return REFRESH_NEEDED; // default } - void RepoManager::refreshMetadata( const RepoInfo &info, - RawMetadataRefreshPolicy policy, - const ProgressData::ReceiverFnc & progress ) + + void RepoManager::Impl::refreshMetadata( const RepoInfo & info, RawMetadataRefreshPolicy policy, const ProgressData::ReceiverFnc & progress ) { assert_alias(info); assert_urls(info); // we will throw this later if no URL checks out fine - RepoException rexception(_("Valid metadata not found at specified URL(s)")); + RepoException rexception( info, _PL("Valid metadata not found at specified URL", + "Valid metadata not found at specified URLs", + info.baseUrlsSize() ) ); // try urls one by one for ( RepoInfo::urls_const_iterator it = info.baseUrlsBegin(); it != info.baseUrlsEnd(); ++it ) @@ -929,34 +1029,30 @@ namespace zypp repo::RepoType repokind = info.type(); // if the type is unknown, try probing. - switch ( repokind.toEnum() ) - { - case RepoType::NONE_e: - // unknown, probe it - repokind = probe( *it, info.path() ); - - if (repokind.toEnum() != RepoType::NONE_e) - { - // Adjust the probed type in RepoInfo - info.setProbedType( repokind ); // lazy init! - //save probed type only for repos in system - for_( it, repoBegin(), repoEnd() ) - { - if ( info.alias() == (*it).alias() ) - { - RepoInfo modifiedrepo = info; - modifiedrepo.setType( repokind ); - modifyRepository( info.alias(), modifiedrepo ); - break; - } - } - } - break; - default: - break; - } + if ( repokind == RepoType::NONE ) + { + // unknown, probe it + repokind = probe( *it, info.path() ); + + if (repokind.toEnum() != RepoType::NONE_e) + { + // Adjust the probed type in RepoInfo + info.setProbedType( repokind ); // lazy init! + //save probed type only for repos in system + for_( it, repoBegin(), repoEnd() ) + { + if ( info.alias() == (*it).alias() ) + { + RepoInfo modifiedrepo = info; + modifiedrepo.setType( repokind ); + modifyRepository( info.alias(), modifiedrepo ); + break; + } + } + } + } - Pathname mediarootpath = rawcache_path_for_repoinfo( _pimpl->options, info ); + Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info ); if( filesystem::assert_dir(mediarootpath) ) { Exception ex(str::form( _("Can't create %s"), mediarootpath.c_str()) ); @@ -992,7 +1088,7 @@ namespace zypp */ for_( it, repoBegin(), repoEnd() ) { - Pathname cachepath(rawcache_path_for_repoinfo( _pimpl->options, *it )); + Pathname cachepath(rawcache_path_for_repoinfo( _options, *it )); if ( PathInfo(cachepath).isExist() ) downloader_ptr->addCachePath(cachepath); } @@ -1002,32 +1098,21 @@ namespace zypp else if ( repokind.toEnum() == RepoType::RPMPLAINDIR_e ) { MediaMounter media( url ); - RepoStatus newstatus = parser::plaindir::dirStatus( media.getPathName( info.path() ) ); + RepoStatus newstatus = RepoStatus( media.getPathName( info.path() ) ); // dir status Pathname productpath( tmpdir.path() / info.path() ); filesystem::assert_dir( productpath ); - std::ofstream file( (productpath/"cookie").c_str() ); - if ( !file ) - { - // TranslatorExplanation '%s' is a filename - ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), (productpath/"cookie").c_str() ))); - } - file << url; - if ( ! info.path().empty() && info.path() != "/" ) - file << " (" << info.path() << ")"; - file << endl; - file << newstatus.checksum() << endl; - - file.close(); + newstatus.saveToCookieFile( productpath/"cookie" ); } else { - ZYPP_THROW(RepoUnknownTypeException()); + ZYPP_THROW(RepoUnknownTypeException( info )); } // ok we have the metadata, now exchange // the contents filesystem::exchange( tmpdir.path(), mediarootpath ); + reposManip(); // remember to trigger appdata refresh // we are done. return; @@ -1050,37 +1135,35 @@ namespace zypp //////////////////////////////////////////////////////////////////////////// - void RepoManager::cleanMetadata( const RepoInfo &info, - const ProgressData::ReceiverFnc & progressfnc ) + void RepoManager::Impl::cleanMetadata( const RepoInfo & info, const ProgressData::ReceiverFnc & progressfnc ) { ProgressData progress(100); progress.sendTo(progressfnc); - filesystem::recursive_rmdir(rawcache_path_for_repoinfo(_pimpl->options, info)); + filesystem::recursive_rmdir(rawcache_path_for_repoinfo(_options, info)); progress.toMax(); } - void RepoManager::cleanPackages( const RepoInfo &info, - const ProgressData::ReceiverFnc & progressfnc ) + + void RepoManager::Impl::cleanPackages( const RepoInfo & info, const ProgressData::ReceiverFnc & progressfnc ) { ProgressData progress(100); progress.sendTo(progressfnc); - filesystem::recursive_rmdir(packagescache_path_for_repoinfo(_pimpl->options, info)); + filesystem::recursive_rmdir(packagescache_path_for_repoinfo(_options, info)); progress.toMax(); } - void RepoManager::buildCache( const RepoInfo &info, - CacheBuildPolicy policy, - const ProgressData::ReceiverFnc & progressrcv ) + + void RepoManager::Impl::buildCache( const RepoInfo & info, CacheBuildPolicy policy, const ProgressData::ReceiverFnc & progressrcv ) { assert_alias(info); - Pathname mediarootpath = rawcache_path_for_repoinfo( _pimpl->options, info ); - Pathname productdatapath = rawproductdata_path_for_repoinfo( _pimpl->options, info ); + Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info ); + Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info ); - if( filesystem::assert_dir(_pimpl->options.repoCachePath) ) + if( filesystem::assert_dir(_options.repoCachePath) ) { - Exception ex(str::form( _("Can't create %s"), _pimpl->options.repoCachePath.c_str()) ); + Exception ex(str::form( _("Can't create %s"), _options.repoCachePath.c_str()) ); ZYPP_THROW(ex); } RepoStatus raw_metadata_status = metadataStatus(info); @@ -1099,7 +1182,7 @@ namespace zypp MIL << info.alias() << " is already cached." << endl; RepoStatus cache_status = cacheStatus(info); - if ( cache_status.checksum() == raw_metadata_status.checksum() ) + if ( cache_status == raw_metadata_status ) { MIL << info.alias() << " cache is up to date with metadata." << endl; if ( policy == BuildIfNeeded ) { @@ -1126,7 +1209,7 @@ namespace zypp MIL << info.alias() << " building cache..." << info.type() << endl; - Pathname base = solv_path_for_repoinfo( _pimpl->options, info); + Pathname base = solv_path_for_repoinfo( _options, info); if( filesystem::assert_dir(base) ) { @@ -1169,10 +1252,10 @@ namespace zypp ExternalProgram::Arguments cmd; cmd.push_back( "repo2solv.sh" ); - // repo2solv expects -o as 1st arg! cmd.push_back( "-o" ); cmd.push_back( solvfile.asString() ); + cmd.push_back( "-X" ); // autogenerate pattern from pattern-package if ( repokind == RepoType::RPMPLAINDIR ) { @@ -1210,7 +1293,7 @@ namespace zypp } break; default: - ZYPP_THROW(RepoUnknownTypeException( _("Unhandled repository type") )); + ZYPP_THROW(RepoUnknownTypeException( info, _("Unhandled repository type") )); break; } // update timestamp and checksum @@ -1221,10 +1304,7 @@ namespace zypp //////////////////////////////////////////////////////////////////////////// - repo::RepoType RepoManager::probe( const Url & url ) const - { return probe( url, Pathname() ); } - - repo::RepoType RepoManager::probe( const Url & url, const Pathname & path ) const + repo::RepoType RepoManager::Impl::probe( const Url & url, const Pathname & path ) const { MIL << "going to probe the repo type at " << url << " (" << path << ")" << endl; @@ -1310,7 +1390,7 @@ namespace zypp //////////////////////////////////////////////////////////////////////////// - void RepoManager::cleanCacheDirGarbage( const ProgressData::ReceiverFnc & progressrcv ) + void RepoManager::Impl::cleanCacheDirGarbage( const ProgressData::ReceiverFnc & progressrcv ) { MIL << "Going to clean up garbage in cache dirs" << endl; @@ -1319,9 +1399,9 @@ namespace zypp progress.toMin(); std::list cachedirs; - cachedirs.push_back(_pimpl->options.repoRawCachePath); - cachedirs.push_back(_pimpl->options.repoPackagesCachePath); - cachedirs.push_back(_pimpl->options.repoSolvCachePath); + cachedirs.push_back(_options.repoRawCachePath); + cachedirs.push_back(_options.repoPackagesCachePath); + cachedirs.push_back(_options.repoSolvCachePath); for_( dir, cachedirs.begin(), cachedirs.end() ) { @@ -1342,7 +1422,7 @@ namespace zypp if ( subdir->basename() == r->escaped_alias() ) { found = true; break; } - if ( ! found ) + if ( ! found && ( Date::now()-PathInfo(*subdir).mtime() > Date::day ) ) filesystem::recursive_rmdir( *subdir ); progress.set( progress.val() + sdircurrent * 100 / sdircount ); @@ -1357,48 +1437,24 @@ namespace zypp //////////////////////////////////////////////////////////////////////////// - void RepoManager::cleanCache( const RepoInfo &info, - const ProgressData::ReceiverFnc & progressrcv ) + void RepoManager::Impl::cleanCache( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv ) { ProgressData progress(100); progress.sendTo(progressrcv); progress.toMin(); MIL << "Removing raw metadata cache for " << info.alias() << endl; - filesystem::recursive_rmdir(solv_path_for_repoinfo(_pimpl->options, info)); + filesystem::recursive_rmdir(solv_path_for_repoinfo(_options, info)); progress.toMax(); } //////////////////////////////////////////////////////////////////////////// - bool RepoManager::isCached( const RepoInfo &info ) const - { - return PathInfo(solv_path_for_repoinfo( _pimpl->options, info ) / "solv").isExist(); - } - - RepoStatus RepoManager::cacheStatus( const RepoInfo &info ) const - { - - Pathname cookiefile = solv_path_for_repoinfo(_pimpl->options, info) / "cookie"; - - return RepoStatus::fromCookieFile(cookiefile); - } - - void RepoManager::setCacheStatus( const RepoInfo &info, const RepoStatus &status ) - { - Pathname base = solv_path_for_repoinfo(_pimpl->options, info); - filesystem::assert_dir(base); - Pathname cookiefile = base / "cookie"; - - status.saveToCookieFile(cookiefile); - } - - void RepoManager::loadFromCache( const RepoInfo & info, - const ProgressData::ReceiverFnc & progressrcv ) + void RepoManager::Impl::loadFromCache( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv ) { assert_alias(info); - Pathname solvfile = solv_path_for_repoinfo(_pimpl->options, info) / "solv"; + Pathname solvfile = solv_path_for_repoinfo(_options, info) / "solv"; if ( ! PathInfo(solvfile).isExist() ) ZYPP_THROW(RepoNotCachedException(info)); @@ -1435,8 +1491,7 @@ namespace zypp //////////////////////////////////////////////////////////////////////////// - void RepoManager::addRepository( const RepoInfo &info, - const ProgressData::ReceiverFnc & progressrcv ) + void RepoManager::Impl::addRepository( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv ) { assert_alias(info); @@ -1449,11 +1504,11 @@ namespace zypp MIL << "Try adding repo " << info << endl; RepoInfo tosave = info; - if(_pimpl->repos.find(tosave)!= _pimpl->repos.end()) - ZYPP_THROW(RepoAlreadyExistsException(info)); + if ( repos().find(tosave) != repos().end() ) + ZYPP_THROW(RepoAlreadyExistsException(info)); // check the first url for now - if ( _pimpl->options.probe ) + if ( _options.probe ) { DBG << "unknown repository type, probing" << endl; @@ -1462,7 +1517,7 @@ namespace zypp if ( tosave.baseUrlsSize() > 0 ) { if ( probedtype == RepoType::NONE ) - ZYPP_THROW(RepoUnknownTypeException()); + ZYPP_THROW(RepoUnknownTypeException(info)); else tosave.setType(probedtype); } @@ -1471,10 +1526,10 @@ namespace zypp progress.set(50); // assert the directory exists - filesystem::assert_dir(_pimpl->options.knownReposPath); + filesystem::assert_dir(_options.knownReposPath); - Pathname repofile = _pimpl->generateNonExistingName( - _pimpl->options.knownReposPath, _pimpl->generateFilename(tosave)); + Pathname repofile = generateNonExistingName( + _options.knownReposPath, generateFilename(tosave)); // now we have a filename that does not exists MIL << "Saving repo in " << repofile << endl; @@ -1496,7 +1551,7 @@ namespace zypp oinfo.setMetadataPath( metadataPath( tosave ) ); oinfo.setPackagesPath( packagesPath( tosave ) ); } - _pimpl->repos.insert(tosave); + reposManip().insert(tosave); progress.set(90); @@ -1512,7 +1567,7 @@ namespace zypp if ( havePasswords ) { media::CredentialManager cm( - media::CredManagerOptions(_pimpl->options.rootDir) ); + media::CredManagerOptions(_options.rootDir) ); for_(urlit, tosave.baseUrlsBegin(), tosave.baseUrlsEnd()) if (urlit->hasCredentialsInAuthority()) @@ -1526,8 +1581,8 @@ namespace zypp MIL << "done" << endl; } - void RepoManager::addRepositories( const Url &url, - const ProgressData::ReceiverFnc & progressrcv ) + + void RepoManager::Impl::addRepositories( const Url & url, const ProgressData::ReceiverFnc & progressrcv ) { std::list repos = readRepoFile(url); for ( std::list::const_iterator it = repos.begin(); @@ -1554,9 +1609,9 @@ namespace zypp } // assert the directory exists - filesystem::assert_dir(_pimpl->options.knownReposPath); + filesystem::assert_dir(_options.knownReposPath); - Pathname repofile = _pimpl->generateNonExistingName(_pimpl->options.knownReposPath, filename); + Pathname repofile = generateNonExistingName(_options.knownReposPath, filename); // now we have a filename that does not exists MIL << "Saving " << repos.size() << " repo" << ( repos.size() ? "s" : "" ) << " in " << repofile << endl; @@ -1574,9 +1629,9 @@ namespace zypp MIL << "Saving " << (*it).alias() << endl; it->setFilepath(repofile.asString()); it->dumpAsIniOn(file); - _pimpl->repos.insert(*it); + reposManip().insert(*it); - HistoryLog(_pimpl->options.rootDir).addRepository(*it); + HistoryLog(_options.rootDir).addRepository(*it); } MIL << "done" << endl; @@ -1584,8 +1639,7 @@ namespace zypp //////////////////////////////////////////////////////////////////////////// - void RepoManager::removeRepository( const RepoInfo & info, - const ProgressData::ReceiverFnc & progressrcv) + void RepoManager::Impl::removeRepository( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv ) { ProgressData progress; callback::SendReport report; @@ -1609,7 +1663,7 @@ namespace zypp RepoInfo todelete = *it; if (todelete.filepath().empty()) { - ZYPP_THROW(RepoException( _("Can't figure out where the repo is stored.") )); + ZYPP_THROW(RepoException( todelete, _("Can't figure out where the repo is stored.") )); } else { @@ -1621,9 +1675,9 @@ namespace zypp if ( filesystem::unlink(todelete.filepath()) != 0 ) { // TranslatorExplanation '%s' is a filename - ZYPP_THROW(RepoException(str::form( _("Can't delete '%s'"), todelete.filepath().c_str() ))); + ZYPP_THROW(RepoException( todelete, str::form( _("Can't delete '%s'"), todelete.filepath().c_str() ))); } - MIL << todelete.alias() << " sucessfully deleted." << endl; + MIL << todelete.alias() << " successfully deleted." << endl; } else { @@ -1650,16 +1704,18 @@ namespace zypp } } - CombinedProgressData subprogrcv(progress, 70); - CombinedProgressData cleansubprogrcv(progress, 30); + CombinedProgressData cSubprogrcv(progress, 20); + CombinedProgressData mSubprogrcv(progress, 40); + CombinedProgressData pSubprogrcv(progress, 40); // now delete it from cache if ( isCached(todelete) ) - cleanCache( todelete, subprogrcv); + cleanCache( todelete, cSubprogrcv); // now delete metadata (#301037) - cleanMetadata( todelete, cleansubprogrcv); - _pimpl->repos.erase(todelete); - MIL << todelete.alias() << " sucessfully deleted." << endl; - HistoryLog(_pimpl->options.rootDir).removeRepository(todelete); + cleanMetadata( todelete, mSubprogrcv ); + cleanPackages( todelete, pSubprogrcv ); + reposManip().erase(todelete); + MIL << todelete.alias() << " successfully deleted." << endl; + HistoryLog(_options.rootDir).removeRepository(todelete); return; } // else filepath is empty @@ -1670,9 +1726,7 @@ namespace zypp //////////////////////////////////////////////////////////////////////////// - void RepoManager::modifyRepository( const std::string &alias, - const RepoInfo & newinfo_r, - const ProgressData::ReceiverFnc & progressrcv ) + void RepoManager::Impl::modifyRepository( const std::string & alias, const RepoInfo & newinfo_r, const ProgressData::ReceiverFnc & progressrcv ) { RepoInfo toedit = getRepositoryInfo(alias); RepoInfo newinfo( newinfo_r ); // need writable copy to upadte housekeeping data @@ -1685,7 +1739,7 @@ namespace zypp if (toedit.filepath().empty()) { - ZYPP_THROW(RepoException( _("Can't figure out where the repo is stored.") )); + ZYPP_THROW(RepoException( toedit, _("Can't figure out where the repo is stored.") )); } else { @@ -1719,46 +1773,39 @@ namespace zypp } newinfo.setFilepath(toedit.filepath()); - _pimpl->repos.erase(toedit); - _pimpl->repos.insert(newinfo); - HistoryLog(_pimpl->options.rootDir).modifyRepository(toedit, newinfo); + reposManip().erase(toedit); + reposManip().insert(newinfo); + HistoryLog(_options.rootDir).modifyRepository(toedit, newinfo); MIL << "repo " << alias << " modified" << endl; } } //////////////////////////////////////////////////////////////////////////// - RepoInfo RepoManager::getRepositoryInfo( const std::string &alias, - const ProgressData::ReceiverFnc & progressrcv ) + RepoInfo RepoManager::Impl::getRepositoryInfo( const std::string & alias, const ProgressData::ReceiverFnc & progressrcv ) { - RepoInfo info; - info.setAlias(alias); - RepoConstIterator it = _pimpl->repos.find( info ); - if( it == repoEnd() ) - ZYPP_THROW(RepoNotFoundException(info)); - else + RepoConstIterator it( findAlias( alias, repos() ) ); + if ( it != repos().end() ) return *it; + RepoInfo info; + info.setAlias( alias ); + ZYPP_THROW( RepoNotFoundException(info) ); } - //////////////////////////////////////////////////////////////////////////// - RepoInfo RepoManager::getRepositoryInfo( const Url & url, - const url::ViewOption & urlview, - const ProgressData::ReceiverFnc & progressrcv ) + RepoInfo RepoManager::Impl::getRepositoryInfo( const Url & url, const url::ViewOption & urlview, const ProgressData::ReceiverFnc & progressrcv ) { for_( it, repoBegin(), repoEnd() ) { - for(RepoInfo::urls_const_iterator urlit = (*it).baseUrlsBegin(); - urlit != (*it).baseUrlsEnd(); - ++urlit) + for_( urlit, (*it).baseUrlsBegin(), (*it).baseUrlsEnd() ) { - if ((*urlit).asString(urlview) == url.asString(urlview)) - return *it; + if ( (*urlit).asString(urlview) == url.asString(urlview) ) + return *it; } } RepoInfo info; - info.setBaseUrl(url); - ZYPP_THROW(RepoNotFoundException(info)); + info.setBaseUrl( url ); + ZYPP_THROW( RepoNotFoundException(info) ); } //////////////////////////////////////////////////////////////////////////// @@ -1767,42 +1814,7 @@ namespace zypp // //////////////////////////////////////////////////////////////////////////// - bool RepoManager::serviceEmpty() const - { return _pimpl->services.empty(); } - - RepoManager::ServiceSizeType RepoManager::serviceSize() const - { return _pimpl->services.size(); } - - RepoManager::ServiceConstIterator RepoManager::serviceBegin() const - { return _pimpl->services.begin(); } - - RepoManager::ServiceConstIterator RepoManager::serviceEnd() const - { return _pimpl->services.end(); } - - ServiceInfo RepoManager::getService( const std::string & alias ) const - { - for_( it, serviceBegin(), serviceEnd() ) - if ( it->alias() == alias ) - return *it; - return ServiceInfo::noService; - } - - bool RepoManager::hasService( const std::string & alias ) const - { - for_( it, serviceBegin(), serviceEnd() ) - if ( it->alias() == alias ) - return true; - return false; - } - - //////////////////////////////////////////////////////////////////////////// - - void RepoManager::addService( const std::string & alias, const Url & url ) - { - addService( ServiceInfo(alias, url) ); - } - - void RepoManager::addService( const ServiceInfo & service ) + void RepoManager::Impl::addService( const ServiceInfo & service ) { assert_alias( service ); @@ -1813,14 +1825,14 @@ namespace zypp // Writable ServiceInfo is needed to save the location // of the .service file. Finaly insert into the service list. ServiceInfo toSave( service ); - _pimpl->saveService( toSave ); - _pimpl->services.insert( toSave ); + saveService( toSave ); + _services.insert( toSave ); // check for credentials in Url (username:password, not ?credentials param) if ( toSave.url().hasCredentialsInAuthority() ) { media::CredentialManager cm( - media::CredManagerOptions(_pimpl->options.rootDir) ); + media::CredManagerOptions(_options.rootDir) ); //! \todo use a method calling UI callbacks to ask where to save creds? cm.saveInUser(media::AuthData(toSave.url())); @@ -1831,16 +1843,16 @@ namespace zypp //////////////////////////////////////////////////////////////////////////// - void RepoManager::removeService( const std::string & alias ) + void RepoManager::Impl::removeService( const std::string & alias ) { - MIL << "Going to delete repo " << alias << endl; + MIL << "Going to delete service " << alias << endl; const ServiceInfo & service = getService( alias ); Pathname location = service.filepath(); if( location.empty() ) { - ZYPP_THROW(RepoException( _("Can't figure out where the service is stored.") )); + ZYPP_THROW(ServiceException( service, _("Can't figure out where the service is stored.") )); } ServiceSet tmpSet; @@ -1852,9 +1864,9 @@ namespace zypp if ( filesystem::unlink(location) != 0 ) { // TranslatorExplanation '%s' is a filename - ZYPP_THROW(RepoException(str::form( _("Can't delete '%s'"), location.c_str() ))); + ZYPP_THROW(ServiceException( service, str::form( _("Can't delete '%s'"), location.c_str() ) )); } - MIL << alias << " sucessfully deleted." << endl; + MIL << alias << " successfully deleted." << endl; } else { @@ -1873,25 +1885,21 @@ namespace zypp it->dumpAsIniOn(file); } - MIL << alias << " sucessfully deleted from file " << location << endl; + MIL << alias << " successfully deleted from file " << location << endl; } // now remove all repositories added by this service RepoCollector rcollector; getRepositoriesInService( alias, - boost::make_function_output_iterator( - bind( &RepoCollector::collect, &rcollector, _1 ) ) ); + boost::make_function_output_iterator( bind( &RepoCollector::collect, &rcollector, _1 ) ) ); // cannot do this directly in getRepositoriesInService - would invalidate iterators for_(rit, rcollector.repos.begin(), rcollector.repos.end()) removeRepository(*rit); } - void RepoManager::removeService( const ServiceInfo & service ) - { removeService(service.alias()); } - //////////////////////////////////////////////////////////////////////////// - void RepoManager::refreshServices() + void RepoManager::Impl::refreshServices( const RefreshServiceOptions & options_r ) { // copy the set of services since refreshService // can eventually invalidate the iterator @@ -1902,17 +1910,14 @@ namespace zypp continue; try { - refreshService(*it); + refreshService(*it, options_r); } catch ( const repo::ServicePluginInformalException & e ) { ;/* ignore ServicePluginInformalException */ } } } - void RepoManager::refreshService( const ServiceInfo & service ) - { refreshService( service.alias() ); } - - void RepoManager::refreshService( const std::string & alias ) + void RepoManager::Impl::refreshService( const std::string & alias, const RefreshServiceOptions & options_r ) { ServiceInfo service( getService( alias ) ); assert_alias( service ); @@ -1921,7 +1926,7 @@ namespace zypp // Either when probing the type, or when adjusting the repositories // enable/disable state.: bool serviceModified = false; - MIL << "Going to refresh service '" << service.alias() << "', url: "<< service.url() << endl; + MIL << "Going to refresh service '" << service.alias() << "', url: "<< service.url() << ", opts: " << options_r << endl; //! \todo add callbacks for apps (start, end, repo removed, repo added, repo changed) @@ -1937,7 +1942,7 @@ namespace zypp } // get target distro identifier - std::string servicesTargetDistro = _pimpl->options.servicesTargetDistro; + std::string servicesTargetDistro = _options.servicesTargetDistro; if ( servicesTargetDistro.empty() ) { servicesTargetDistro = Target::targetDistribution( Pathname() ); @@ -1961,18 +1966,30 @@ namespace zypp uglyHack.second = e; } + //////////////////////////////////////////////////////////////////////////// + // On the fly remember the new repo states as defined the reopoindex.xml. + // Move into ServiceInfo later. + ServiceInfo::RepoStates newRepoStates; + // set service alias and base url for all collected repositories for_( it, collector.repos.begin(), collector.repos.end() ) { + // First of all: Prepend service alias: + it->setAlias( str::form( "%s:%s", service.alias().c_str(), it->alias().c_str() ) ); + // set refrence to the parent service + it->setService( service.alias() ); + + // remember the new parsed repo state + newRepoStates[it->alias()] = *it; + // if the repo url was not set by the repoindex parser, set service's url Url url; - if ( it->baseUrlsEmpty() ) url = service.url(); else { // service repo can contain only one URL now, so no need to iterate. - url = *it->baseUrlsBegin(); + url = it->rawUrl(); // raw! } // libzypp currently has problem with separate url + path handling @@ -1985,13 +2002,8 @@ namespace zypp it->setPath(""); } - // Prepend service alias: - it->setAlias( str::form( "%s:%s", service.alias().c_str(), it->alias().c_str() ) ); - // save the url it->setBaseUrl( url ); - // set refrence to the parent service - it->setService( service.alias() ); } //////////////////////////////////////////////////////////////////////////// @@ -2000,22 +2012,29 @@ namespace zypp RepoInfoList oldRepos; getRepositoriesInService( service.alias(), std::back_inserter( oldRepos ) ); + //////////////////////////////////////////////////////////////////////////// // find old repositories to remove... - for_( it, oldRepos.begin(), oldRepos.end() ) + for_( oldRepo, oldRepos.begin(), oldRepos.end() ) { - if ( ! foundAliasIn( it->alias(), collector.repos ) ) + if ( ! foundAliasIn( oldRepo->alias(), collector.repos ) ) { - if ( it->enabled() && ! service.repoToDisableFind( it->alias() ) ) - { - DBG << "Service removes enabled repo " << it->alias() << endl; - service.addRepoToEnable( it->alias() ); - serviceModified = true; - } - else - { - DBG << "Service removes disabled repo " << it->alias() << endl; - } - removeRepository( *it ); + if ( oldRepo->enabled() ) + { + // Currently enabled. If this was a user modification remember the state. + const auto & last = service.repoStates().find( oldRepo->alias() ); + if ( last != service.repoStates().end() && ! last->second.enabled ) + { + DBG << "Service removes user enabled repo " << oldRepo->alias() << endl; + service.addRepoToEnable( oldRepo->alias() ); + serviceModified = true; + } + else + DBG << "Service removes enabled repo " << oldRepo->alias() << endl; + } + else + DBG << "Service removes disabled repo " << oldRepo->alias() << endl; + + removeRepository( *oldRepo ); } } @@ -2023,24 +2042,40 @@ namespace zypp // create missing repositories and modify exising ones if needed... for_( it, collector.repos.begin(), collector.repos.end() ) { - // Service explicitly requests the repo being enabled? - // Service explicitly requests the repo being disabled? + // User explicitly requested the repo being enabled? + // User explicitly requested the repo being disabled? // And hopefully not both ;) If so, enable wins. - bool beEnabled = service.repoToEnableFind( it->alias() ); - bool beDisabled = service.repoToDisableFind( it->alias() ); - // Make sure the service repo is created with the - // appropriate enable - if ( beEnabled ) it->setEnabled(true); - if ( beDisabled ) it->setEnabled(false); + TriBool toBeEnabled( indeterminate ); // indeterminate - follow the service request + DBG << "Service request to " << (it->enabled()?"enable":"disable") << " service repo " << it->alias() << endl; - if ( beEnabled ) + if ( options_r.testFlag( RefreshService_restoreStatus ) ) { - // Remove from enable request list. - // NOTE: repoToDisable is handled differently. - // It gets cleared on each refresh. - service.delRepoToEnable( it->alias() ); - serviceModified = true; + DBG << "Opt RefreshService_restoreStatus " << it->alias() << 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() ) ) + { + DBG << "User request to enable service repo " << it->alias() << endl; + toBeEnabled = true; + // Remove from enable request list. + // NOTE: repoToDisable is handled differently. + // It gets cleared on each refresh. + service.delRepoToEnable( it->alias() ); + serviceModified = true; + } + else if ( service.repoToDisableFind( it->alias() ) ) + { + DBG << "User request to disable service repo " << it->alias() << endl; + toBeEnabled = false; + } } RepoInfoList::iterator oldRepo( findAlias( it->alias(), oldRepos ) ); @@ -2048,58 +2083,92 @@ namespace zypp { // Not found in oldRepos ==> a new repo to add - // At that point check whether a repo with the same alias - // exists outside this service. Maybe forcefully re-alias - // the existing repo? + // Make sure the service repo is created with the appropriate enablement + if ( ! indeterminate(toBeEnabled) ) + it->setEnabled( toBeEnabled ); + DBG << "Service adds repo " << it->alias() << " " << (it->enabled()?"enabled":"disabled") << endl; addRepository( *it ); - - // save repo credentials - // ma@: task for modifyRepository? } else { // ==> an exising repo to check bool oldRepoModified = false; + 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() == it->enabled() ) + toBeEnabled = it->enabled(); // service requests no change to the system + else if (options_r.testFlag( RefreshService_restoreStatus ) ) + { + toBeEnabled = it->enabled(); // RefreshService_restoreStatus forced + DBG << "Opt RefreshService_restoreStatus " << it->alias() << " forces " << (toBeEnabled?"enabled":"disabled") << endl; + } + else + { + 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") << endl; + } + } + } + // changed enable? - if ( beEnabled ) + if ( toBeEnabled == oldRepo->enabled() ) + { + DBG << "Service repo " << it->alias() << " stays " << (oldRepo->enabled()?"enabled":"disabled") << endl; + } + else if ( toBeEnabled ) + { + DBG << "Service repo " << it->alias() << " gets enabled" << endl; + oldRepo->setEnabled( true ); + oldRepoModified = true; + } + else { - if ( ! oldRepo->enabled() ) - { - DBG << "Service repo " << it->alias() << " gets enabled" << endl; - oldRepo->setEnabled( true ); - oldRepoModified = true; - } - else - { - DBG << "Service repo " << it->alias() << " stays enabled" << endl; - } - } - else if ( beDisabled ) - { - if ( oldRepo->enabled() ) - { - DBG << "Service repo " << it->alias() << " gets disabled" << endl; - oldRepo->setEnabled( false ); - oldRepoModified = true; - } - else - { - DBG << "Service repo " << it->alias() << " stays disabled" << endl; - } - } - else - { - DBG << "Service repo " << it->alias() << " stays " << (oldRepo->enabled()?"enabled":"disabled") << endl; - } + DBG << "Service repo " << it->alias() << " gets disabled" << endl; + oldRepo->setEnabled( false ); + oldRepoModified = true; + } + + // all other attributes follow the service request: + + // changed name (raw!) + if ( oldRepo->rawName() != it->rawName() ) + { + DBG << "Service repo " << it->alias() << " gets new NAME " << it->rawName() << endl; + oldRepo->setName( it->rawName() ); + oldRepoModified = true; + } + + // changed autorefresh + if ( oldRepo->autorefresh() != it->autorefresh() ) + { + DBG << "Service repo " << it->alias() << " gets new AUTOREFRESH " << it->autorefresh() << endl; + oldRepo->setAutorefresh( it->autorefresh() ); + oldRepoModified = true; + } + + // changed priority? + if ( oldRepo->priority() != it->priority() ) + { + DBG << "Service repo " << it->alias() << " gets new PRIORITY " << it->priority() << endl; + oldRepo->setPriority( it->priority() ); + oldRepoModified = true; + } // changed url? // service repo can contain only one URL now, so no need to iterate. - if ( oldRepo->url() != it->url() ) + if ( oldRepo->rawUrl() != it->rawUrl() ) { - DBG << "Service repo " << it->alias() << " gets new URL " << it->url() << endl; - oldRepo->setBaseUrl( it->url() ); + DBG << "Service repo " << it->alias() << " gets new URL " << it->rawUrl() << endl; + oldRepo->setBaseUrl( it->rawUrl() ); oldRepoModified = true; } @@ -2118,9 +2187,16 @@ namespace zypp serviceModified = true; } + // Remember original service request for next refresh + if ( service.repoStates() != newRepoStates ) + { + service.setRepoStates( std::move(newRepoStates) ); + serviceModified = true; + } + //////////////////////////////////////////////////////////////////////////// - // save service if modified: - if ( serviceModified ) + // save service if modified: (unless a plugin service) + if ( serviceModified && service.type() != ServiceType::PLUGIN ) { // write out modified service file. modifyService( service.alias(), service ); @@ -2134,7 +2210,7 @@ namespace zypp //////////////////////////////////////////////////////////////////////////// - void RepoManager::modifyService(const std::string & oldAlias, const ServiceInfo & newService) + void RepoManager::Impl::modifyService( const std::string & oldAlias, const ServiceInfo & newService ) { MIL << "Going to modify service " << oldAlias << endl; @@ -2144,8 +2220,7 @@ namespace zypp if ( service.type() == ServiceType::PLUGIN ) { - MIL << "Not modifying plugin service '" << oldAlias << "'" << endl; - return; + ZYPP_THROW(ServicePluginImmutableException( service )); } const ServiceInfo & oldService = getService(oldAlias); @@ -2153,7 +2228,7 @@ namespace zypp Pathname location = oldService.filepath(); if( location.empty() ) { - ZYPP_THROW(RepoException( _("Can't figure out where the service is stored.") )); + ZYPP_THROW(ServiceException( oldService, _("Can't figure out where the service is stored.") )); } // remember: there may multiple services being defined in one file: @@ -2171,27 +2246,33 @@ namespace zypp file.close(); service.setFilepath(location); - _pimpl->services.erase(oldAlias); - _pimpl->services.insert(service); + _services.erase(oldAlias); + _services.insert(service); // changed properties affecting also repositories - if( oldAlias != service.alias() // changed alias - || oldService.enabled() != service.enabled() // changed enabled status - ) + if ( oldAlias != service.alias() // changed alias + || oldService.enabled() != service.enabled() ) // changed enabled status { std::vector toModify; getRepositoriesInService(oldAlias, std::back_inserter(toModify)); for_( it, toModify.begin(), toModify.end() ) { - if (oldService.enabled() && !service.enabled()) - it->setEnabled(false); - else if (!oldService.enabled() && service.enabled()) - { - //! \todo do nothing? the repos will be enabled on service refresh - //! \todo how to know the service needs a (auto) refresh???? - } - else + if ( oldService.enabled() != service.enabled() ) + { + if ( service.enabled() ) + { + // reset to last refreshs state + const auto & last = service.repoStates().find( it->alias() ); + if ( last != service.repoStates().end() ) + it->setEnabled( last->second.enabled ); + } + else + it->setEnabled( false ); + } + + if ( oldAlias != service.alias() ) it->setService(service.alias()); + modifyRepository(it->alias(), *it); } } @@ -2201,7 +2282,7 @@ namespace zypp //////////////////////////////////////////////////////////////////////////// - repo::ServiceType RepoManager::probeService( const Url &url ) const + repo::ServiceType RepoManager::Impl::probeService( const Url & url ) const { try { @@ -2229,13 +2310,170 @@ namespace zypp return repo::ServiceType::NONE; } - //////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// + // + // CLASS NAME : RepoManager + // + /////////////////////////////////////////////////////////////////// - std::ostream & operator<<( std::ostream & str, const RepoManager & obj ) + RepoManager::RepoManager( const RepoManagerOptions & opt ) + : _pimpl( new Impl(opt) ) + {} + + RepoManager::~RepoManager() + {} + + bool RepoManager::repoEmpty() const + { return _pimpl->repoEmpty(); } + + RepoManager::RepoSizeType RepoManager::repoSize() const + { return _pimpl->repoSize(); } + + RepoManager::RepoConstIterator RepoManager::repoBegin() const + { return _pimpl->repoBegin(); } + + RepoManager::RepoConstIterator RepoManager::repoEnd() const + { return _pimpl->repoEnd(); } + + RepoInfo RepoManager::getRepo( const std::string & alias ) const + { return _pimpl->getRepo( alias ); } + + bool RepoManager::hasRepo( const std::string & alias ) const + { return _pimpl->hasRepo( alias ); } + + std::string RepoManager::makeStupidAlias( const Url & url_r ) { - return str << *obj._pimpl; + std::string ret( url_r.getScheme() ); + if ( ret.empty() ) + ret = "repo-"; + else + ret += "-"; + + std::string host( url_r.getHost() ); + if ( ! host.empty() ) + { + ret += host; + ret += "-"; + } + + static Date::ValueType serial = Date::now(); + ret += Digest::digest( Digest::sha1(), str::hexstring( ++serial ) +url_r.asCompleteString() ).substr(0,8); + return ret; } + RepoStatus RepoManager::metadataStatus( const RepoInfo & info ) const + { return _pimpl->metadataStatus( info ); } + + RepoManager::RefreshCheckStatus RepoManager::checkIfToRefreshMetadata( const RepoInfo &info, const Url &url, RawMetadataRefreshPolicy policy ) + { return _pimpl->checkIfToRefreshMetadata( info, url, policy ); } + + Pathname RepoManager::metadataPath( const RepoInfo &info ) const + { return _pimpl->metadataPath( info ); } + + Pathname RepoManager::packagesPath( const RepoInfo &info ) const + { return _pimpl->packagesPath( info ); } + + void RepoManager::refreshMetadata( const RepoInfo &info, RawMetadataRefreshPolicy policy, const ProgressData::ReceiverFnc & progressrcv ) + { return _pimpl->refreshMetadata( info, policy, progressrcv ); } + + void RepoManager::cleanMetadata( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv ) + { return _pimpl->cleanMetadata( info, progressrcv ); } + + void RepoManager::cleanPackages( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv ) + { return _pimpl->cleanPackages( info, progressrcv ); } + + RepoStatus RepoManager::cacheStatus( const RepoInfo &info ) const + { return _pimpl->cacheStatus( info ); } + + void RepoManager::buildCache( const RepoInfo &info, CacheBuildPolicy policy, const ProgressData::ReceiverFnc & progressrcv ) + { return _pimpl->buildCache( info, policy, progressrcv ); } + + void RepoManager::cleanCache( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv ) + { return _pimpl->cleanCache( info, progressrcv ); } + + bool RepoManager::isCached( const RepoInfo &info ) const + { return _pimpl->isCached( info ); } + + void RepoManager::loadFromCache( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv ) + { return _pimpl->loadFromCache( info, progressrcv ); } + + void RepoManager::cleanCacheDirGarbage( const ProgressData::ReceiverFnc & progressrcv ) + { return _pimpl->cleanCacheDirGarbage( progressrcv ); } + + repo::RepoType RepoManager::probe( const Url & url, const Pathname & path ) const + { return _pimpl->probe( url, path ); } + + repo::RepoType RepoManager::probe( const Url & url ) const + { return _pimpl->probe( url ); } + + void RepoManager::addRepository( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv ) + { return _pimpl->addRepository( info, progressrcv ); } + + void RepoManager::addRepositories( const Url &url, const ProgressData::ReceiverFnc & progressrcv ) + { return _pimpl->addRepositories( url, progressrcv ); } + + void RepoManager::removeRepository( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv ) + { return _pimpl->removeRepository( info, progressrcv ); } + + void RepoManager::modifyRepository( const std::string &alias, const RepoInfo & newinfo, const ProgressData::ReceiverFnc & progressrcv ) + { return _pimpl->modifyRepository( alias, newinfo, progressrcv ); } + + RepoInfo RepoManager::getRepositoryInfo( const std::string &alias, const ProgressData::ReceiverFnc & progressrcv ) + { return _pimpl->getRepositoryInfo( alias, progressrcv ); } + + RepoInfo RepoManager::getRepositoryInfo( const Url & url, const url::ViewOption & urlview, const ProgressData::ReceiverFnc & progressrcv ) + { return _pimpl->getRepositoryInfo( url, urlview, progressrcv ); } + + bool RepoManager::serviceEmpty() const + { return _pimpl->serviceEmpty(); } + + RepoManager::ServiceSizeType RepoManager::serviceSize() const + { return _pimpl->serviceSize(); } + + RepoManager::ServiceConstIterator RepoManager::serviceBegin() const + { return _pimpl->serviceBegin(); } + + RepoManager::ServiceConstIterator RepoManager::serviceEnd() const + { return _pimpl->serviceEnd(); } + + ServiceInfo RepoManager::getService( const std::string & alias ) const + { return _pimpl->getService( alias ); } + + bool RepoManager::hasService( const std::string & alias ) const + { return _pimpl->hasService( alias ); } + + repo::ServiceType RepoManager::probeService( const Url &url ) const + { return _pimpl->probeService( url ); } + + void RepoManager::addService( const std::string & alias, const Url& url ) + { return _pimpl->addService( alias, url ); } + + void RepoManager::addService( const ServiceInfo & service ) + { return _pimpl->addService( service ); } + + void RepoManager::removeService( const std::string & alias ) + { return _pimpl->removeService( alias ); } + + void RepoManager::removeService( const ServiceInfo & service ) + { return _pimpl->removeService( service ); } + + void RepoManager::refreshServices( const RefreshServiceOptions & options_r ) + { return _pimpl->refreshServices( options_r ); } + + void RepoManager::refreshService( const std::string & alias, const RefreshServiceOptions & options_r ) + { return _pimpl->refreshService( alias, options_r ); } + + void RepoManager::refreshService( const ServiceInfo & service, const RefreshServiceOptions & options_r ) + { return _pimpl->refreshService( service, options_r ); } + + void RepoManager::modifyService( const std::string & oldAlias, const ServiceInfo & service ) + { return _pimpl->modifyService( oldAlias, service ); } + + //////////////////////////////////////////////////////////////////////////// + + std::ostream & operator<<( std::ostream & str, const RepoManager & obj ) + { return str << *obj._pimpl; } + ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/RepoManager.h b/libzypp/zypp/RepoManager.h index 5d4119f..8717b9f 100644 --- a/libzypp/zypp/RepoManager.h +++ b/libzypp/zypp/RepoManager.h @@ -17,6 +17,7 @@ #include "zypp/base/PtrTypes.h" #include "zypp/base/Iterator.h" +#include "zypp/base/Flags.h" #include "zypp/Pathname.h" #include "zypp/ZConfig.h" @@ -141,10 +142,16 @@ namespace zypp BuildForced }; - enum RepoRemovePolicy + /** Flags for tuning RefreshService */ + enum RefreshServiceBit { - + RefreshService_restoreStatus = (1<<0) ///< Force restoring repo enabled/disabled staus }; + ZYPP_DECLARE_FLAGS(RefreshServiceFlags,RefreshServiceBit); + + /** Options tuning RefreshService */ + typedef RefreshServiceFlags RefreshServiceOptions; + /** \name Known repositories. * @@ -591,7 +598,7 @@ namespace zypp * * \see refreshService(ServiceInfo) */ - void refreshServices(); + void refreshServices( const RefreshServiceOptions & options_r = RefreshServiceOptions() ); /** * Refresh specific service. @@ -601,9 +608,9 @@ namespace zypp * \throws RepoException if service is not found. * \throws MediaException If there's a problem downloading the repo index file. */ - void refreshService( const std::string & alias ); + void refreshService( const std::string & alias, const RefreshServiceOptions & options_r = RefreshServiceOptions() ); /** \overload Take alias from ServiceInfo */ - void refreshService( const ServiceInfo & service ); + void refreshService( const ServiceInfo & service, const RefreshServiceOptions & options_r = RefreshServiceOptions() ); /** * Modifies service file (rewrites it with new values) and underlying @@ -685,22 +692,11 @@ namespace zypp out); } - protected: - RepoStatus rawMetadataStatus( const RepoInfo &info ); - void setCacheStatus( const RepoInfo &info, const RepoStatus &status ); - - /** - * Update timestamp of repository index file for the specified repository \a info. - * Used in \ref checkIfToRefreshMetadata() for repo.refresh.delay feature. - */ - void touchIndexFile(const RepoInfo & info); - - public: - private: /** Pointer to implementation */ RWCOW_pointer _pimpl; }; + ZYPP_DECLARE_OPERATORS_FOR_FLAGS(RepoManager::RefreshServiceFlags); /////////////////////////////////////////////////////////////////// /** \relates RepoManager Stream output */ diff --git a/libzypp/zypp/RepoStatus.cc b/libzypp/zypp/RepoStatus.cc index 7ff4241..b51b25c 100644 --- a/libzypp/zypp/RepoStatus.cc +++ b/libzypp/zypp/RepoStatus.cc @@ -30,17 +30,27 @@ namespace zypp /** RepoStatus implementation. */ struct RepoStatus::Impl { - public: + string _checksum; + Date _timestamp; - string checksum; - Date timestamp; - - /** Offer default Impl. */ - static shared_ptr nullimpl() + /** Recursive computation of max dir timestamp. */ + static void recursive_timestamp( const Pathname & dir_r, time_t & max_r ) { - static shared_ptr _nullimpl( new Impl ); - return _nullimpl; + std::list dircontent; + if ( filesystem::readdir( dircontent, dir_r, false/*no dots*/ ) != 0 ) + return; // readdir logged the error + + for_( it, dircontent.begin(), dircontent.end() ) + { + PathInfo pi( dir_r + *it, PathInfo::LSTAT ); + if ( pi.isDir() ) + { + if ( pi.mtime() > max_r ) + max_r = pi.mtime(); + recursive_timestamp( pi.path(), max_r ); + } + } } private: @@ -53,9 +63,7 @@ namespace zypp /** \relates RepoStatus::Impl Stream output */ inline std::ostream & operator<<( std::ostream & str, const RepoStatus::Impl & obj ) - { - return str << obj.checksum << " " << (time_t) obj.timestamp; - } + { return str << obj._checksum << " " << (time_t)obj._timestamp; } /////////////////////////////////////////////////////////////////// // @@ -63,114 +71,100 @@ namespace zypp // /////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////// - // - // METHOD NAME : RepoStatus::RepoStatus - // METHOD TYPE : Ctor - // RepoStatus::RepoStatus() : _pimpl( new Impl() ) {} - RepoStatus::RepoStatus( const Pathname &path ) + RepoStatus::RepoStatus( const Pathname & path_r ) : _pimpl( new Impl() ) { - PathInfo info(path); - if ( info.isExist() ) + PathInfo info( path_r ); + if ( info.isExist() ) + { + if ( info.isFile() ) { - _pimpl->timestamp = Date(info.mtime()); - if ( info.isFile() ) - _pimpl->checksum = filesystem::sha1sum(path); - else // non files - _pimpl->checksum = str::numstring(info.mtime()); + _pimpl->_timestamp = Date( info.mtime() ); + _pimpl->_checksum = filesystem::sha1sum( path_r ); } + else if ( info.isDir() ) + { + time_t t = info.mtime(); + Impl::recursive_timestamp( path_r, t ); + _pimpl->_timestamp = Date(t); + _pimpl->_checksum = CheckSum::sha1FromString( str::numstring( t ) ).checksum(); + } + + // NOTE: changing magic will once invalidate all solv file caches + // Helpfull if solv file content must be refreshed (e.g. due to different + // repo2* arguments) even if raw metadata are unchanged. + static const std::string magic( "42" ); + _pimpl->_checksum += magic; + } } - /////////////////////////////////////////////////////////////////// - // - // METHOD NAME : RepoStatus::~RepoStatus - // METHOD TYPE : Dtor - // RepoStatus::~RepoStatus() {} - RepoStatus RepoStatus::fromCookieFile( const Pathname &cookiefile ) + RepoStatus RepoStatus::fromCookieFile( const Pathname & path_r ) { - std::ifstream file(cookiefile.c_str()); - if (!file) { - WAR << "No cookie file " << cookiefile << endl; - return RepoStatus(); + RepoStatus ret; + std::ifstream file( path_r.c_str() ); + if ( !file ) + { + WAR << "No cookie file " << path_r << endl; } - - RepoStatus status; - std::string buffer; - file >> buffer; - status.setChecksum(buffer); - file >> buffer; - status.setTimestamp(Date(str::strtonum(buffer))); - return status; + else + { + // line := "[checksum] time_t" + std::string line( str::getline( file ) ); + ret._pimpl->_timestamp = Date( str::strtonum( str::stripLastWord( line ) ) ); + ret._pimpl->_checksum = line; + } + return ret; } - void RepoStatus::saveToCookieFile( const Pathname &cookiefile ) const + void RepoStatus::saveToCookieFile( const Pathname & path_r ) const { - std::ofstream file(cookiefile.c_str()); + std::ofstream file(path_r.c_str()); if (!file) { - ZYPP_THROW (Exception( "Can't open " + cookiefile.asString() ) ); + ZYPP_THROW (Exception( "Can't open " + path_r.asString() ) ); } - file << this->checksum() << " " << (int) this->timestamp() << endl << endl; + file << _pimpl->_checksum << " " << (time_t)_pimpl->_timestamp << endl; file.close(); } bool RepoStatus::empty() const - { - return _pimpl->checksum.empty(); - } - - RepoStatus & RepoStatus::setChecksum( const string &checksum ) - { - _pimpl->checksum = checksum; - return *this; - } - - RepoStatus & RepoStatus::setTimestamp( const Date ×tamp ) - { - _pimpl->timestamp = timestamp; - return *this; - } - - string RepoStatus::checksum() const - { return _pimpl->checksum; } + { return _pimpl->_checksum.empty(); } Date RepoStatus::timestamp() const - { return _pimpl->timestamp; } + { return _pimpl->_timestamp; } + + std::ostream & operator<<( std::ostream & str, const RepoStatus & obj ) + { return str << *obj._pimpl; } RepoStatus operator&&( const RepoStatus & lhs, const RepoStatus & rhs ) { - if ( lhs.empty() ) - return rhs; - if ( rhs.empty() ) - return lhs; + RepoStatus result; - std::string lchk( lhs.checksum() ); - std::string rchk( rhs.checksum() ); - // order strings to assert && is kommutativ - stringstream ss( lchk < rchk ? lchk+rchk : rchk+lchk ); + if ( lhs.empty() ) + result = rhs; + else if ( rhs.empty() ) + result = lhs; + else + { + // order strings to assert && is kommutativ + std::string lchk( lhs._pimpl->_checksum ); + std::string rchk( rhs._pimpl->_checksum ); + stringstream ss( lchk < rchk ? lchk+rchk : rchk+lchk ); - RepoStatus result; - result.setChecksum( CheckSum::sha1(ss).checksum() ); - result.setTimestamp( lhs.timestamp() < rhs.timestamp() ? rhs.timestamp() : lhs.timestamp() ); + result._pimpl->_checksum = CheckSum::sha1(ss).checksum(); + result._pimpl->_timestamp = std::max( lhs._pimpl->_timestamp, rhs._pimpl->_timestamp ); + } return result; } - /****************************************************************** - ** - ** FUNCTION NAME : operator<< - ** FUNCTION TYPE : std::ostream & - */ - std::ostream & operator<<( std::ostream & str, const RepoStatus & obj ) - { - return str << *obj._pimpl; - } + bool operator==( const RepoStatus & lhs, const RepoStatus & rhs ) + { return lhs._pimpl->_checksum == rhs._pimpl->_checksum; } ///////////////////////////////////////////////////////////////// } // namespace zypp diff --git a/libzypp/zypp/RepoStatus.h b/libzypp/zypp/RepoStatus.h index 5e4caeb..587a507 100644 --- a/libzypp/zypp/RepoStatus.h +++ b/libzypp/zypp/RepoStatus.h @@ -22,119 +22,79 @@ namespace zypp { ///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : RepoStatus - // - /** - * \short Local facts about a repository - * This class represents the status of a - * repository on the system. - * - * Anything that is not provided on the metadata - * files, like the timestamp of the downloaded - * metadata, and its checksum. - */ + /// \class RepoStatus + /// \brief Track changing files or directories. + /// + /// Compute timestamp and checksum for individual files or + /// directories (recursively) to track changing content. + /// + /// The timestamp most probably denotes the time the data were + /// changed the last time, that's why it is exposed. + /// + /// The checksum however is an implementation detail and of no + /// use outside this class. \ref operator== tells if the checksums + /// of two rRepoStatus are the same. + /////////////////////////////////////////////////////////////////// class RepoStatus { friend std::ostream & operator<<( std::ostream & str, const RepoStatus & obj ); + friend RepoStatus operator&&( const RepoStatus & lhs, const RepoStatus & rhs ); + friend bool operator==( const RepoStatus & lhs, const RepoStatus & rhs ); public: + /** Default ctor */ + RepoStatus(); - /** - * reads the status from a file which contains the - * checksum and timestamp in each line. + /** Compute status for single file or directory (recursively) * - * \returns An empty \ref RepoStatus if the file does not - * exist or is not readable. - */ - static RepoStatus fromCookieFile( const Pathname &path ); - - /** - * save the status information to a cookie file - * \throws Exception if the file can't be saved - */ - void saveToCookieFile( const Pathname &path ) const; - - /** - * Checksum of the repository. - * Usually the checksum of the index, but any - * checksum that changes when the repository changes - * in any way is sufficient. + * \note Construction from a non existing file will result + * in an empty status. */ - std::string checksum() const; + explicit RepoStatus( const Pathname & path_r ); - /** - * timestamp of the repository. If the repository - * changes, it has to be updated as well with the - * new timestamp. - */ - Date timestamp() const; - - /** - * \short Is the status empty? - * - * An empty status means that the status - * was not calculated. - */ - bool empty() const; + /** Dtor */ + ~RepoStatus(); - /** - * set the repository checksum \see checksum - * \param checksum + public: + /** Reads the status from a cookie file + * \returns An empty \ref RepoStatus if the file does not + * exist or is not readable. + * \see \ref saveToCookieFile */ - RepoStatus & setChecksum( const std::string &checksum ); + static RepoStatus fromCookieFile( const Pathname & path ); - /** - * set the repository timestamp \see timestamp - * \param timestamp + /** Save the status information to a cookie file + * \throws Exception if the file can't be saved + * \see \ref fromCookieFile */ - RepoStatus & setTimestamp( const Date ×tamp ); - - /** Implementation */ - class Impl; + void saveToCookieFile( const Pathname & path_r ) const; public: - /** Default ctor */ - RepoStatus(); - - /** - * \short Status from a single file - * As most repository state is represented - * by the status of the index file, you can - * construct the status from a file. - * - * \note construct from a non existing - * file will result in an empty status - * - * \note construct from a directory, the - * directories mtime will be also used as - * checksum. - * - * \todo Add recursive option for dirs so we finaly get - * the same as \ref parser::plaindir::dirStatus and can - * unify both. - */ - RepoStatus( const Pathname &file ); + /** Whether the status is empty (default constucted) */ + bool empty() const; - /** Dtor */ - ~RepoStatus(); + /** The time the data were changed the last time */ + Date timestamp() const; public: - + class Impl; ///< Implementation private: - /** Pointer to implementation */ - RWCOW_pointer _pimpl; + RWCOW_pointer _pimpl; ///< Pointer to implementation }; /////////////////////////////////////////////////////////////////// /** \relates RepoStatus Stream output */ std::ostream & operator<<( std::ostream & str, const RepoStatus & obj ); - /** - * combines 2 repostatus with a checksum based on both - * checksums and the newest timestamp - */ - RepoStatus operator&&( const RepoStatus &lhs, const RepoStatus &rhs ); + /** \relates RepoStatus Combine two RepoStatus (combined checksum and newest timestamp) */ + RepoStatus operator&&( const RepoStatus & lhs, const RepoStatus & rhs ); + + /** \relates RepoStatus Whether 2 RepoStatus refer to the same content checksum */ + bool operator==( const RepoStatus & lhs, const RepoStatus & rhs ); + + /** \relates RepoStatus Whether 2 RepoStatus refer to different content checksums */ + inline bool operator!=( const RepoStatus & lhs, const RepoStatus & rhs ) + { return ! ( lhs == rhs ); } ///////////////////////////////////////////////////////////////// } // namespace zypp diff --git a/libzypp/zypp/Repository.cc b/libzypp/zypp/Repository.cc index 39c3806..ae31925 100644 --- a/libzypp/zypp/Repository.cc +++ b/libzypp/zypp/Repository.cc @@ -15,12 +15,15 @@ #include "zypp/base/Logger.h" #include "zypp/base/Gettext.h" #include "zypp/base/Exception.h" +#include "zypp/base/Xml.h" #include "zypp/AutoDispose.h" #include "zypp/Pathname.h" #include "zypp/sat/detail/PoolImpl.h" #include "zypp/Repository.h" +#include "zypp/ResPool.h" +#include "zypp/Product.h" #include "zypp/sat/Pool.h" using std::endl; @@ -64,6 +67,9 @@ namespace zypp std::string Repository::name() const { return info().name(); } + std::string Repository::label() const + { return info().label(); } + int Repository::satInternalPriority() const { NO_REPOSITORY_RETURN( INT_MIN ); @@ -76,6 +82,29 @@ namespace zypp return _repo->subpriority; } + Repository::ContentRevision Repository::contentRevision() const + { + NO_REPOSITORY_RETURN( ContentRevision() ); + sat::LookupRepoAttr q( sat::SolvAttr::repositoryRevision, *this ); + return q.empty() ? std::string() : q.begin().asString(); + } + + Repository::ContentIdentifier Repository::contentIdentifier() const + { + NO_REPOSITORY_RETURN( ContentIdentifier() ); + sat::LookupRepoAttr q( sat::SolvAttr::repositoryRepoid, *this ); + return q.empty() ? std::string() : q.begin().asString(); + } + + bool Repository::hasContentIdentifier( const ContentIdentifier & id_r ) const + { + NO_REPOSITORY_RETURN( false ); + sat::LookupRepoAttr q( sat::SolvAttr::repositoryRepoid, *this ); + for_( it, q.begin(), q.end() ) + if ( it.asString() == id_r ) + return true; + return false; + } zypp::Date Repository::generatedTimestamp() const { @@ -95,7 +124,7 @@ namespace zypp if ( q.empty() ) return 0; - return generated + q.begin().asUnsigned(); + return generated + Date(q.begin().asUnsigned()); } Repository::Keywords Repository::keywords() const @@ -104,6 +133,14 @@ namespace zypp return Keywords( sat::SolvAttr::repositoryKeywords, *this, sat::LookupAttr::REPO_ATTR ); } + bool Repository::hasKeyword( const std::string & val_r ) const + { + for ( const auto & val : keywords() ) + if ( val == val_r ) + return true; + return false; + } + bool Repository::maybeOutdated() const { NO_REPOSITORY_RETURN( false ); @@ -120,27 +157,63 @@ namespace zypp return suggestedExpirationTimestamp() < Date::now(); } - bool Repository::providesUpdatesFor( const std::string &key ) const + bool Repository::providesUpdatesFor( const CpeId & cpeid_r ) const { NO_REPOSITORY_RETURN( false ); + if ( ! cpeid_r ) + return false; // filter queries/products without CpeId, as an empty CpeId matches ANYthing. - for_( it, - updatesProductBegin(), - updatesProductEnd() ) + // check in repository metadata + for_( it, updatesProductBegin(), updatesProductEnd() ) { - // FIXME implement real CPE matching here - // someday - if ( key == it.cpeId() ) - return true; + if ( compare( cpeid_r, it.cpeId(), SetRelation::subset ) ) + return true; } + // check whether known products refer to this as update repo + sat::LookupRepoAttr myIds( sat::SolvAttr::repositoryRepoid, *this ); // usually just one, but... + if ( ! myIds.empty() ) + { + const ResPool & pool( ResPool::instance() ); + for_( it, pool.byKindBegin(), pool.byKindEnd() ) + { + Product::constPtr prod( (*it)->asKind() ); + if ( compare( cpeid_r, prod->cpeId(), SetRelation::superset ) ) + { + for_( myId, myIds.begin(), myIds.end() ) + { + if ( prod->hasUpdateContentIdentifier( myId.asString() ) ) + return true; + } + } + } + } return false; } bool Repository::isUpdateRepo() const { NO_REPOSITORY_RETURN( false ); - return ( updatesProductBegin() != updatesProductEnd() ); + + // check in repository metadata + if ( updatesProductBegin() != updatesProductEnd() ) + return true; + + // check whether known products refer to this as update repo + sat::LookupRepoAttr myIds( sat::SolvAttr::repositoryRepoid, *this ); // usually just one, but... + if ( ! myIds.empty() ) + { + const ResPool & pool( ResPool::instance() ); + for_( it, pool.byKindBegin(), pool.byKindEnd() ) + { + for_( myId, myIds.begin(), myIds.end() ) + { + if ( (*it)->asKind()->hasUpdateContentIdentifier( myId.asString() ) ) + return true; + } + } + } + return false; } bool Repository::solvablesEmpty() const @@ -308,6 +381,14 @@ namespace zypp << "}"; } + std::ostream & dumpAsXmlOn( std::ostream & str, const Repository & obj ) + { + return xmlout::node( str, "repository", { + { "name", obj.name() }, + { "alias", obj.alias() } + } ); + } + ////////////////////////////////////////////////////////////////// namespace detail { @@ -336,8 +417,8 @@ namespace zypp std::string Repository::ProductInfoIterator::label() const { return base_reference().subFind( sat::SolvAttr::repositoryProductLabel ).asString(); } - std::string Repository::ProductInfoIterator::cpeId() const - { return base_reference().subFind( sat::SolvAttr::repositoryProductCpeid ).asString(); } + CpeId Repository::ProductInfoIterator::cpeId() const + { return CpeId( base_reference().subFind( sat::SolvAttr::repositoryProductCpeid ).asString(), CpeId::noThrow ); } ///////////////////////////////////////////////////////////////// } // namespace zypp diff --git a/libzypp/zypp/Repository.h b/libzypp/zypp/Repository.h index 03a2660..6ed1725 100644 --- a/libzypp/zypp/Repository.h +++ b/libzypp/zypp/Repository.h @@ -13,13 +13,13 @@ #define ZYPP_SAT_REPOSITORY_H #include -#include "zypp/base/SafeBool.h" #include "zypp/Pathname.h" #include "zypp/sat/detail/PoolMember.h" #include "zypp/sat/LookupAttr.h" // LookupAttrTools.h included at EOF #include "zypp/sat/Solvable.h" #include "zypp/RepoInfo.h" #include "zypp/Date.h" +#include "zypp/CpeId.h" /////////////////////////////////////////////////////////////////// namespace zypp @@ -35,8 +35,7 @@ namespace zypp // CLASS NAME : Repository // /** */ - class Repository : protected sat::detail::PoolMember, - private base::SafeBool + class Repository : protected sat::detail::PoolMember { public: typedef filter_iterator SolvableIterator; @@ -45,6 +44,9 @@ namespace zypp typedef sat::ArrayAttr Keywords; + typedef std::string ContentRevision; + typedef std::string ContentIdentifier; + public: /** Default ctor creates \ref noRepository.*/ Repository() @@ -58,10 +60,10 @@ namespace zypp /** Represents no \ref Repository. */ static const Repository noRepository; -#ifndef SWIG // Swig treats it as syntax error /** Evaluate \ref Repository in a boolean context (\c != \c noRepository). */ - using base::SafeBool::operator bool_type; -#endif + explicit operator bool() const + { return get() != nullptr; } + /** Reserved system repository alias \c @System. */ static const std::string & systemRepoAlias(); @@ -83,6 +85,35 @@ namespace zypp /** Label to display for this repo. */ std::string name() const; + /** Alias or name, according to \ref ZConfig::repoLabelIsAlias */ + std::string label() const; + + /** User string: \ref label (alias or name) */ + std::string asUserString() const + { return label(); } + + public: + /** Timestamp or arbitrary user supplied string. + * \c /repomd/revision/text() in \c repomd.xml. + */ + ContentRevision contentRevision() const; + + /** Unique string identifying a repositories content. + * \c /repomd/tags/repo/text() in \c repomd.xml. + * \code + * + * + * obsrepository://build.suse.de/SUSE:Factory:Head:Internal/standard + * \endcode + * Semantically the value is just a plain string, even + * if OBS often uses the location of the project as + * unique identifyer. + */ + ContentIdentifier contentIdentifier() const; + + /** Whether \a id_r matches this repos content identifier. */ + bool hasContentIdentifier( const ContentIdentifier & id_r ) const; + /** * Timestamp when this repository was generated * @@ -124,6 +155,9 @@ namespace zypp */ Keywords keywords() const; + /** Whether \a val_r is present in keywords. */ + bool hasKeyword( const std::string & val_r ) const; + /** * The suggested expiration date of this repository * already passed @@ -134,26 +168,21 @@ namespace zypp */ bool maybeOutdated() const; - /** - * if the repository claims to update something then - * it is an update repository - * - * This is implemented by looking at the repository updates - * tag. - * \see http://en.opensuse.org/Standards/Rpm_Metadata#SUSE_repository_info_.28suseinfo.xml.29.2C_extensions_to_repomd.xml + /** Hint whether the Repo may provide updates for a product. + * + * Either the repository claims to update a product via a repository updates + * tag in it's metadata or a known product lists the repositories ContentIdentifier + * as required update repo. */ bool isUpdateRepo() const; - /** - * wether the repository claims to update something \ref prod - * with key \ref cpeid - * - * \see zypp::Product::cpeId() - * - * See http://cpe.mitre.org/ for more information on the - * Common Platform Enumearation. - */ - bool providesUpdatesFor( const std::string &cpeid ) const; + /** Hint whether the Repo may provide updates for a product identified by it's \ref CpeId + * + * Either the repository claims to update a product via a repository updates + * tag in it's metadata or a known product lists the repositories ContentIdentifier + * as required update repo. + */ + bool providesUpdatesFor( const CpeId & cpeid_r ) const; /** Whether \ref Repository contains solvables. */ bool solvablesEmpty() const; @@ -169,7 +198,7 @@ namespace zypp public: - /** Query class for Repository */ + /** Query class for Repository related products */ class ProductInfoIterator; /** @@ -189,15 +218,18 @@ namespace zypp ProductInfoIterator compatibleWithProductEnd() const; /** - * Get an iterator to the beginning of the repository - * compatible distros. + * Get an iterator to the beginning of distos the repository + * provides upadates for. + * \note This is only a hint within the repositories metadata. + * The same realation might be expressed by a product listing + * this repositories ContentIdentifier as required update repo. * \see Repository::ProductInfoIterator */ ProductInfoIterator updatesProductBegin() const; /** - * Get an iterator to the end of the repository - * compatible distros. + * Get an iterator to the end of distos the repository + * provides upadates for. * \see Repository::ProductInfoIterator */ ProductInfoIterator updatesProductEnd() const; @@ -273,11 +305,7 @@ namespace zypp int satInternalPriority() const; int satInternalSubPriority() const; //@} - private: -#ifndef SWIG // Swig treats it as syntax error - friend base::SafeBool::operator bool_type() const; -#endif - bool boolTest() const { return get(); } + private: IdType _id; }; @@ -286,6 +314,9 @@ namespace zypp /** \relates Repository Stream output */ std::ostream & operator<<( std::ostream & str, const Repository & obj ); + /** \relates Repository XML output */ + std::ostream & dumpAsXmlOn( std::ostream & str, const Repository & obj ); + /** \relates Repository */ inline bool operator==( const Repository & lhs, const Repository & rhs ) { return lhs.get() == rhs.get(); } @@ -302,6 +333,9 @@ namespace zypp /** * Query class for Repository related products * + * Products are identified by CpeIds within the repositories metadata. + * \see http://en.opensuse.org/Standards/Rpm_Metadata#SUSE_repository_info_.28suseinfo.xml.29.2C_extensions_to_repomd.xml + * * The iterator does not provide a dereference * operator so you can do * on it, but you can * access the attributes of each related product @@ -310,7 +344,7 @@ namespace zypp * \code * for_( it, repo.compatibleWithProductBegin(), repo.compatibleWithProductEnd() ) * { - * cout << it.cpeid() << endl; + * cout << it.label() << ": " << it.cpeid() << endl; * } * \endcode * @@ -327,18 +361,11 @@ namespace zypp ProductInfoIterator() {} - /** - * Product label - */ + /** Product label */ std::string label() const; - /** - * The Common Platform Enumeration name - * for this product. - * - * See http://cpe.mitre.org - */ - std::string cpeId() const; + /** The Common Platform Enumeration name for this product. */ + CpeId cpeId() const; private: friend class Repository; diff --git a/libzypp/zypp/ResFilters.h b/libzypp/zypp/ResFilters.h index 194a419..c7a6db2 100644 --- a/libzypp/zypp/ResFilters.h +++ b/libzypp/zypp/ResFilters.h @@ -151,8 +151,6 @@ namespace zypp typedef std::unary_function ResObjectFilterFunctor; typedef boost::function ResFilter; - /** Select ResObject by kind. \deprecated include filter.h and use filter::ByKind. */ - ZYPP_DEPRECATED typedef filter::ByKind ByKind; /** */ template inline filter::ByKind byKind() diff --git a/libzypp/zypp/ResKind.cc b/libzypp/zypp/ResKind.cc index 437a385..ad0fb7e 100644 --- a/libzypp/zypp/ResKind.cc +++ b/libzypp/zypp/ResKind.cc @@ -23,22 +23,47 @@ namespace zypp { ///////////////////////////////////////////////////////////////// const ResKind ResKind::nokind; - const ResKind ResKind::package ( "package" ); - const ResKind ResKind::patch ( "patch" ); - const ResKind ResKind::pattern ( "pattern" ); - const ResKind ResKind::product ( "product" ); - const ResKind ResKind::srcpackage( "srcpackage" ); + const ResKind ResKind::package ( "package" ); + const ResKind ResKind::patch ( "patch" ); + const ResKind ResKind::pattern ( "pattern" ); + const ResKind ResKind::product ( "product" ); + const ResKind ResKind::srcpackage ( "srcpackage" ); + const ResKind ResKind::application ( "application" ); template<> - const ResKind ResTraits ::kind( ResKind::package ); + const ResKind ResTraits ::kind( ResKind::package ); template<> - const ResKind ResTraits ::kind( ResKind::patch ); + const ResKind ResTraits ::kind( ResKind::patch ); template<> - const ResKind ResTraits ::kind( ResKind::pattern ); + const ResKind ResTraits ::kind( ResKind::pattern ); template<> - const ResKind ResTraits ::kind( ResKind::product ); + const ResKind ResTraits ::kind( ResKind::product ); template<> - const ResKind ResTraits::kind( ResKind::srcpackage ); + const ResKind ResTraits ::kind( ResKind::srcpackage ); + template<> + const ResKind ResTraits::kind( ResKind::application ); + + ResKind ResKind::explicitBuiltin( const char * str_r ) + { + if ( str_r && str_r[0] && str_r[1] && str_r[2] ) + { + switch ( str_r[3] ) + { + // NOTE: it needs to be assertd that the separating ':' is present + // if a known kind is retuirned. Dependent code relies on this! + #define OUTS(K,S) if ( !::strncmp( str_r, ResKind::K.c_str(), S ) && str_r[S] == ':' ) return ResKind::K + // ----v + case 'c': OUTS( patch, 5 ); break; + case 'd': OUTS( product, 7 ); break; + case 'k': OUTS( package, 7 ); break; + case 'l': OUTS( application, 11 );break; + case 'p': OUTS( srcpackage, 10 ); break; + case 't': OUTS( pattern, 7 ); break; + #undef OUTS + } + } + return nokind; + } std::string ResKind::satIdent( const ResKind & refers_r, const std::string & name_r ) { diff --git a/libzypp/zypp/ResKind.h b/libzypp/zypp/ResKind.h index 39c11d9..c47498a 100644 --- a/libzypp/zypp/ResKind.h +++ b/libzypp/zypp/ResKind.h @@ -24,14 +24,11 @@ namespace zypp { ///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : ResKind - // - /** Resolvable kinds. - * A \b lowercased string and used as identification. - * Comparison against string values is always case - * insensitive. - */ + /// \class ResKind + /// \brief Resolvable kinds. + /// A \b lowercased string and used as identification. Comparison + /// against string values is always case insensitive. + /////////////////////////////////////////////////////////////////// class ResKind : public IdStringType { public: @@ -45,8 +42,22 @@ namespace zypp static const ResKind pattern; static const ResKind product; static const ResKind srcpackage; + static const ResKind application; //@} + /** Return the builtin kind if \a str_r explicitly prefixed. + * \a str_r must start with a builtin kind followed by a \c ':'. + * If no builtin kind is detected, \ref nokind is returned, + * which usually indicates a \ref package or \ref srcpackage. + */ + static ResKind explicitBuiltin( const char * str_r ); + /** \overload */ + static ResKind explicitBuiltin( const std::string & str_r ) + { return explicitBuiltin( str_r.c_str() ); } + /** \overload */ + static ResKind explicitBuiltin( const IdString & str_r ) + { return explicitBuiltin( str_r.c_str() ); } + public: /** Default ctor: \ref nokind */ ResKind() {} @@ -81,6 +92,10 @@ namespace zypp IdString _str; }; + /** \relates ResKind XML output. */ + inline std::ostream & dumpAsXmlOn( std::ostream & str, const ResKind & obj ) + { return str << "" << obj << ""; } + ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/ResObject.cc b/libzypp/zypp/ResObject.cc index 37b6fa5..5407b3a 100644 --- a/libzypp/zypp/ResObject.cc +++ b/libzypp/zypp/ResObject.cc @@ -17,6 +17,8 @@ #include "zypp/RepoInfo.h" #include "zypp/IdString.h" +#include "zypp/ui/Selectable.h" + using namespace zypp; using namespace std; @@ -71,15 +73,26 @@ namespace zypp { std::string ret = lookupStrAttribute( sat::SolvAttr::eula, lang_r ); if ( ret.empty() && isKind() ) - return repoInfo().getLicense( lang_r ); + { + const RepoInfo & ri( repoInfo() ); + if ( ri.needToAcceptLicense() || ! ui::Selectable::get( *this )->hasInstalledObj() ) + ret = ri.getLicense( lang_r ); // bnc#908976: suppress informal license upon update + } return ret; } + bool ResObject::needToAcceptLicense() const + { + if ( isKind() ) + return repoInfo().needToAcceptLicense( ); + return true; + } + std::string ResObject::distribution() const { return lookupStrAttribute( sat::SolvAttr::distribution ); } - std::string ResObject::cpeId() const - { return lookupStrAttribute( sat::SolvAttr::cpeid ); } + CpeId ResObject::cpeId() const + { return CpeId( lookupStrAttribute( sat::SolvAttr::cpeid ), CpeId::noThrow ); } ByteCount ResObject::installSize() const { return ByteCount( lookupNumAttribute( sat::SolvAttr::installsize ) ); } @@ -96,13 +109,6 @@ namespace zypp Date ResObject::installtime() const { return Date( lookupNumAttribute( sat::SolvAttr::installtime ) ); } -#warning DUMMY diskusage - const DiskUsage & ResObject::diskusage() const - { - static DiskUsage _du; - return _du; - } - ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// @@ -125,6 +131,7 @@ namespace zypp OUTS( Pattern ); OUTS( Product ); OUTS( SrcPackage ); + OUTS( Application ); #undef OUTS // unknow => return a plain ResObject return new ResObject( solvable_r ); diff --git a/libzypp/zypp/ResObject.h b/libzypp/zypp/ResObject.h index 286db0d..9bdb6bc 100644 --- a/libzypp/zypp/ResObject.h +++ b/libzypp/zypp/ResObject.h @@ -19,9 +19,9 @@ #include "zypp/Locale.h" #include "zypp/Vendor.h" #include "zypp/ByteCount.h" -#include "zypp/DiskUsage.h" #include "zypp/OnMediaLocation.h" #include "zypp/Repository.h" +#include "zypp/CpeId.h" #include "zypp/sat/LookupAttr.h" #include "zypp/sat/SolvableSet.h" @@ -130,6 +130,14 @@ namespace zypp */ std::string licenseToConfirm( const Locale & lang_r = Locale() ) const; + /** + * \short Acceptance of Product License needed? + * + * Returns whether a product license has to be accepted + * (no acceptance is needed for openSUSE) + */ + bool needToAcceptLicense() const; + /** * \short Vendor * @@ -143,18 +151,33 @@ namespace zypp */ std::string distribution() const; - /** - * The Common Platform Enumeration name - * for this product. + /** The Common Platform Enumeration name for this product. */ + CpeId cpeId() const; + + /** Installed (unpacked) size. + * This is just a total number. Many objects provide even more detailed + * disk usage data. You can use \ref DiskUsageCounter to find out + * how objects data are distributed across partitions/directories. + * \code + * // Load directory set into ducounter + * DiskUsageCounter ducounter( { "/", "/usr", "/var" } ); * - * See http://cpe.mitre.org + * // see how noch space the packages use + * for ( const PoolItem & pi : pool ) + * { + * cout << pi << ducounter.disk_usage( pi ) << endl; + * // I__s_(7)GeoIP-1.4.8-3.1.2.x86_64(@System) { + * // dir:[/] [ bs: 0 B ts: 0 B us: 0 B (+-: 1.0 KiB)] + * // dir:[/usr] [ bs: 0 B ts: 0 B us: 0 B (+-: 133.0 KiB)] + * // dir:[/var] [ bs: 0 B ts: 0 B us: 0 B (+-: 1.1 MiB)] + * // } + * } + * \endcode + * \see \ref DiskUsageCounter */ - std::string cpeId() const; - - /** Installed size. */ ByteCount installSize() const; - /** Size of the rpm package. */ + /** Download size. */ ByteCount downloadSize() const; /** \see \ref sat::Solvable::repository */ @@ -184,14 +207,6 @@ namespace zypp */ Date installtime() const; - /** - * \short Disk usage per directory - * A common attribute, although mostly packages require - * noticeable disk space. An e.g product could try to reserve - * a certain ammount of diskspace by providing DiskUsage data. - */ - const DiskUsage & diskusage() const; - protected: friend ResObject::Ptr makeResObject( const sat::Solvable & solvable_r ); /** Ctor */ @@ -265,11 +280,11 @@ namespace zypp template inline typename ResTraits<_Res>::constPtrType ResObject::asKind() const - { return make<_Res>( *this ); } + { return dynamic_cast( this ); } template inline typename ResTraits<_Res>::PtrType ResObject::asKind() - { return make<_Res>( *this ); } + { return dynamic_cast<_Res *>( this ); } ///////////////////////////////////////////////////////////////// } // namespace zypp diff --git a/libzypp/zypp/ResObjects.h b/libzypp/zypp/ResObjects.h index 073008c..1545085 100644 --- a/libzypp/zypp/ResObjects.h +++ b/libzypp/zypp/ResObjects.h @@ -17,5 +17,6 @@ #include "zypp/Pattern.h" #include "zypp/Product.h" #include "zypp/SrcPackage.h" +#include "zypp/Application.h" #endif // ZYPP_RESOBJECTS_H diff --git a/libzypp/zypp/ResPool.cc b/libzypp/zypp/ResPool.cc index dc84a24..fa708ee 100644 --- a/libzypp/zypp/ResPool.cc +++ b/libzypp/zypp/ResPool.cc @@ -83,25 +83,6 @@ namespace zypp Repository ResPool::reposFind( const std::string & alias_r ) const { return _pimpl->reposFind( alias_r ); } - bool ResPool::autoSoftLocksEmpty() const - { return _pimpl->autoSoftLocks().empty(); } - - ResPool::size_type ResPool::autoSoftLocksSize() const - { return _pimpl->autoSoftLocks().size(); } - - ResPool::autoSoftLocks_iterator ResPool::autoSoftLocksBegin() const - { return _pimpl->autoSoftLocks().begin(); } - - ResPool::autoSoftLocks_iterator ResPool::autoSoftLocksEnd() const - { return _pimpl->autoSoftLocks().end(); } - - void ResPool::setAutoSoftLocks( const AutoSoftLocks & newLocks_r ) - { _pimpl->setAutoSoftLocks( newLocks_r ); } - - void ResPool::getActiveSoftLocks( AutoSoftLocks & activeLocks_r ) - { _pimpl->getActiveSoftLocks( activeLocks_r ); } - - bool ResPool::hardLockQueriesEmpty() const { return _pimpl->hardLockQueries().empty(); } diff --git a/libzypp/zypp/ResPool.h b/libzypp/zypp/ResPool.h index 58f0bf9..a8d37d9 100644 --- a/libzypp/zypp/ResPool.h +++ b/libzypp/zypp/ResPool.h @@ -307,7 +307,7 @@ namespace zypp */ const LocaleSet & getRequestedLocales() const; - /** Wheter this \ref Locale is in the set of requested locales. */ + /** Whether this \ref Locale is in the set of requested locales. */ bool isRequestedLocale( const Locale & locale_r ) const; /** Get the set of available locales. @@ -316,45 +316,10 @@ namespace zypp */ const LocaleSet & getAvailableLocales() const; - /** Wheter this \ref Locale is in the set of available locales. */ + /** Whether this \ref Locale is in the set of available locales. */ bool isAvailableLocale( const Locale & locale_r ) const; //@} - public: - /** \name Handle automatic soft-locks. - * - * Solvables with and ident listed here are per default created with - * a setSoftLock applied. I.e. the \ref Resolver should not automatically - * select them, if they are just recommended. - * - * This list is considered when adding new repos to the pool. It is - * \b not the list of currently softLocked items. - * - * Mainly used to re-apply soft-locks remembered during the last commit. - */ - //@{ - typedef pool::PoolTraits::AutoSoftLocks AutoSoftLocks; - typedef pool::PoolTraits::autoSoftLocks_iterator autoSoftLocks_iterator; - - bool autoSoftLocksEmpty() const; - size_type autoSoftLocksSize() const; - autoSoftLocks_iterator autoSoftLocksBegin() const; - autoSoftLocks_iterator autoSoftLocksEnd() const; - - /** Set a new soft-lock list. - * The soft-locks of existing PoolItems are adjusted according - * to the list. (usually called on target load) - */ - void setAutoSoftLocks( const AutoSoftLocks & newLocks_r ); - - /** Suggest a new soft-lock list based on the current selection. - * Based on the the current soft-lock list. Items tagged to be - * installed are removed, and those tagged to be deleted are added. - * (usually remembered on commit). - */ - void getActiveSoftLocks( AutoSoftLocks & activeLocks_r ); - //@} - public: /** \name Handle hard locks (e.g set from /etc/zypp/locks). * diff --git a/libzypp/zypp/ResStatus.h b/libzypp/zypp/ResStatus.h index 0724fe3..908e05b 100644 --- a/libzypp/zypp/ResStatus.h +++ b/libzypp/zypp/ResStatus.h @@ -37,7 +37,7 @@ namespace zypp * nonrelevant: it is unimportant for the user * satisfied: it important nothing has to be done * broken: it is incomplete. So e.g. an update is needed - * \li \c TransactField Wheter to transact this resolvable + * \li \c TransactField Whether to transact this resolvable * (delete if installed install if uninstalled). * In case the resolvable is locked, only USER may modify the * transact bit. diff --git a/libzypp/zypp/ResTraits.h b/libzypp/zypp/ResTraits.h index e61dd08..42e4324 100644 --- a/libzypp/zypp/ResTraits.h +++ b/libzypp/zypp/ResTraits.h @@ -26,7 +26,7 @@ namespace zypp /** Those are denoted to be installed, if the * solver verifies them as being satisfied. */ inline bool isPseudoInstalled( ResKind kind_r ) - { return( kind_r == ResKind::patch || kind_r == ResKind::pattern ); } + { return( kind_r == ResKind::patch ); } ///////////////////////////////////////////////////////////////// } // namespace traits @@ -57,6 +57,7 @@ namespace zypp * * \note When adding a \c NewResolvable type here, dont forgett to * put IMPL_PTR_TYPE(NewResolvable); into the \c NewResolvable.cc. + * Also check class \ref ResKind, ResKind.cc, ResObject.cc(makeResObject) */ //@{ DEFINE_PTR_TYPE( Resolvable ); @@ -67,6 +68,7 @@ namespace zypp DEFINE_PTR_TYPE( Pattern ); DEFINE_PTR_TYPE( Product ); DEFINE_PTR_TYPE( Patch ); + DEFINE_PTR_TYPE( Application ); //@} /** Frequently associated. */ @@ -80,7 +82,7 @@ namespace zypp typedef intrusive_ptr<_Res> PtrType; typedef intrusive_ptr constPtrType; - static const ResKind kind; + static const ResKind kind; ///< Defined in ResKind.cc /** Those are denoted to be installed, if the * solver verifies them as being satisfied. */ diff --git a/libzypp/zypp/Resolvable.h b/libzypp/zypp/Resolvable.h index eaca5aa..907a17f 100644 --- a/libzypp/zypp/Resolvable.h +++ b/libzypp/zypp/Resolvable.h @@ -49,10 +49,6 @@ namespace zypp typedef TraitsType::constPtrType constPtr; public: -#ifndef SWIG // Swig treats it as syntax error - /** Whether this represents a valid- or no-solvable. */ - using zypp::sat::Solvable::operator bool_type; // Note: gcc bug #52841 prohibits using just sat::Solvable -#endif /** Whether this represents an installed solvable. */ bool isSystem() const { return sat::Solvable::isSystem(); } @@ -172,12 +168,12 @@ namespace zypp // Specialization for Resolvable: Always true. template<> inline bool isKind( const Resolvable::constPtr & p ) - { return p; } + { return !!p; } // Specialization for ResObject: Always true. template<> inline bool isKind( const Resolvable::constPtr & p ) - { return p; } + { return !!p; } /** Convert Resolvable::Ptr into Ptr of a certain Kind. diff --git a/libzypp/zypp/ResolverProblem.cc b/libzypp/zypp/ResolverProblem.cc index 41969de..4c86f13 100644 --- a/libzypp/zypp/ResolverProblem.cc +++ b/libzypp/zypp/ResolverProblem.cc @@ -38,9 +38,12 @@ ostream& operator<<( ostream& os, const ResolverProblem & problem) { os << "Problem:" << endl; + os << "==============================" << endl; os << problem._description << endl; os << problem._details << endl; + os << "------------------------------" << endl; os << problem._solutions; + os << "==============================" << endl; return os; } diff --git a/libzypp/zypp/ServiceInfo.cc b/libzypp/zypp/ServiceInfo.cc index 175caf2..470396c 100644 --- a/libzypp/zypp/ServiceInfo.cc +++ b/libzypp/zypp/ServiceInfo.cc @@ -16,8 +16,6 @@ #include "zypp/parser/xml/XmlEscape.h" #include "zypp/RepoInfo.h" -#include "zypp/repo/RepoInfoBaseImpl.h" - #include "zypp/ServiceInfo.h" using namespace std; @@ -31,7 +29,7 @@ namespace zypp // // CLASS NAME : ServiceInfo::Impl // - struct ServiceInfo::Impl : public repo::RepoInfoBase::Impl + struct ServiceInfo::Impl { typedef ServiceInfo::ReposToEnable ReposToEnable; typedef ServiceInfo::ReposToDisable ReposToDisable; @@ -41,16 +39,16 @@ namespace zypp repo::ServiceType type; ReposToEnable reposToEnable; ReposToDisable reposToDisable; + RepoStates repoStates; + public: Impl() - : repo::RepoInfoBase::Impl() - , type(repo::ServiceType::NONE_e) + : type(repo::ServiceType::NONE_e) {} Impl(const Url & url_) - : repo::RepoInfoBase::Impl() - , url(url_) + : url(url_) , type(repo::ServiceType::NONE_e) {} @@ -164,6 +162,19 @@ namespace zypp 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 & operator<<( std::ostream & str, const ServiceInfo::RepoState & obj ) + { + return str + << "enabled=" << obj.enabled << " " + << "autorefresh=" << obj.autorefresh << " " + << "priority=" << obj.priority; + } std::ostream & ServiceInfo::dumpAsIniOn( std::ostream & str ) const { @@ -171,6 +182,24 @@ namespace zypp << "url = " << url() << endl << "type = " << type() << 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() ) @@ -178,10 +207,7 @@ namespace zypp return str; } - std::ostream & ServiceInfo::dumpAsXMLOn(std::ostream & str) const - { return dumpAsXMLOn(str, ""); } - - ostream & ServiceInfo::dumpAsXMLOn( ostream & str, const string & content) const + ostream & ServiceInfo::dumpAsXmlOn( ostream & str, const string & content ) const { str << " RepoStates; + + /** 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 @@ -145,11 +179,6 @@ namespace zypp */ virtual std::ostream & dumpAsIniOn( std::ostream & str ) const; - /** - * Write an XML representation of this ServiceInfo object. - */ - virtual std::ostream & dumpAsXMLOn(std::ostream & str) const; - /** * Write an XML representation of this ServiceInfo object. * @@ -157,8 +186,10 @@ namespace zypp * \param content if not empty, produces content * otherwise */ - virtual std::ostream & dumpAsXMLOn( - std::ostream & str, const std::string & content) const; + virtual std::ostream & dumpAsXmlOn( std::ostream & str, const std::string & content = "" ) const; + + /** \deprecated Use camel cased dumpAsXmlOn */ + ZYPP_DEPRECATED std::ostream & dumpAsXMLOn( std::ostream & str, const std::string & content = "" ) const { return dumpAsXmlOn( str, content ); } class Impl; diff --git a/libzypp/zypp/SysContent.cc b/libzypp/zypp/SysContent.cc index ee0f920..3e33bdc 100644 --- a/libzypp/zypp/SysContent.cc +++ b/libzypp/zypp/SysContent.cc @@ -335,7 +335,7 @@ namespace zypp virtual void text( const Node & node_r ) { - *_value = node_r.value().asString(); + *_value = Date(node_r.value().asString()); } Date *_value; diff --git a/libzypp/zypp/Target.cc b/libzypp/zypp/Target.cc index 0f22236..26a22f8 100644 --- a/libzypp/zypp/Target.cc +++ b/libzypp/zypp/Target.cc @@ -121,6 +121,11 @@ namespace zypp std::string Target::targetDistributionRelease( const Pathname & root_r ) { return target::TargetImpl::targetDistributionRelease( root_r ); } + std::string Target::targetDistributionFlavor() const + { return _pimpl->targetDistributionFlavor(); } + std::string Target::targetDistributionFlavor( const Pathname & root_r ) + { return target::TargetImpl::targetDistributionFlavor( root_r ); } + Target::DistributionLabel Target::distributionLabel() const { return _pimpl->distributionLabel(); } Target::DistributionLabel Target::distributionLabel( const Pathname & root_r ) diff --git a/libzypp/zypp/Target.h b/libzypp/zypp/Target.h index 322e9e3..10f1119 100644 --- a/libzypp/zypp/Target.h +++ b/libzypp/zypp/Target.h @@ -153,6 +153,14 @@ namespace zypp /** \overload */ static std::string targetDistributionRelease( const Pathname & root_r ); + /** This is \c register.flavor attribute of the installed base product. + * Used for registration. + * \note don't mistake this for \ref distributionFlavor + */ + std::string targetDistributionFlavor() const; + /** \overload */ + static std::string targetDistributionFlavor( const Pathname & root_r ); + struct DistributionLabel { std::string shortName; std::string summary; }; /** This is \c shortName and \c summary attribute of the installed base product. * Used e.g. for the bootloader menu. @@ -175,6 +183,7 @@ namespace zypp * the last used one. It can be empty is the target has never * been loaded, as the value is not present in the system * but computer from a package provides + * \note don't mistake this for \ref targetDistributionFlavor */ std::string distributionFlavor() const; /** \overload */ diff --git a/libzypp/zypp/TmpPath.cc b/libzypp/zypp/TmpPath.cc index 350382d..a8334cd 100644 --- a/libzypp/zypp/TmpPath.cc +++ b/libzypp/zypp/TmpPath.cc @@ -106,9 +106,7 @@ namespace zypp { // METHOD TYPE : Constructor // TmpPath::TmpPath() - :_impl( 0 ) // empty Pathname - { - } + {} /////////////////////////////////////////////////////////////////// // @@ -116,9 +114,8 @@ namespace zypp { // METHOD TYPE : Constructor // TmpPath::TmpPath( const Pathname & tmpPath_r ) - :_impl( tmpPath_r.empty() ? 0 : new Impl( tmpPath_r ) ) - { - } + :_impl( tmpPath_r.empty() ? nullptr : new Impl( tmpPath_r ) ) + {} /////////////////////////////////////////////////////////////////// // @@ -135,7 +132,7 @@ namespace zypp { // METHOD NAME : TmpPath::operator const void * // METHOD TYPE : // - TmpPath::operator const void * () const + TmpPath::operator bool() const { return _impl.get(); } diff --git a/libzypp/zypp/TmpPath.h b/libzypp/zypp/TmpPath.h index bb58f6c..39f6371 100644 --- a/libzypp/zypp/TmpPath.h +++ b/libzypp/zypp/TmpPath.h @@ -60,7 +60,7 @@ namespace zypp { * Test whether the Pathname is valid (i.e. not empty. NOT whether * it really denotes an existing file or directory). **/ - operator const void * () const; + explicit operator bool() const; /** * @return The Pathname. diff --git a/libzypp/zypp/Url.cc b/libzypp/zypp/Url.cc index d81508c..1eede89 100644 --- a/libzypp/zypp/Url.cc +++ b/libzypp/zypp/Url.cc @@ -215,6 +215,7 @@ namespace zypp ref->config("path_encode_slash2", "y"); // always encode 2. slash addUrlByScheme("ftp", ref); addUrlByScheme("sftp", ref); + addUrlByScheme("tftp", ref); } bool @@ -460,7 +461,7 @@ namespace zypp bool Url::schemeIsRemote( const std::string & scheme_r ) { - static const char * val[] = { "http", "https", "nfs", "nfs4", "smb", "cifs", "ftp", "sftp" }; + static const char * val[] = { "http", "https", "nfs", "nfs4", "smb", "cifs", "ftp", "sftp", "tftp" }; return isInList( arrayBegin(val), arrayEnd(val), scheme_r ); } @@ -472,7 +473,7 @@ namespace zypp bool Url::schemeIsDownloading( const std::string & scheme_r ) { - static const char * val[] = { "http", "https", "ftp", "sftp" }; + static const char * val[] = { "http", "https", "ftp", "sftp", "tftp" }; return isInList( arrayBegin(val), arrayEnd(val), scheme_r ); } /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/Url.h b/libzypp/zypp/Url.h index e99dada..277b879 100644 --- a/libzypp/zypp/Url.h +++ b/libzypp/zypp/Url.h @@ -256,7 +256,7 @@ namespace zypp /** \overload nonstatic version */ bool schemeIsLocal() const { return schemeIsLocal( getScheme() ); } - /** nfs nfs4 smb cifs http https ftp sftp */ + /** nfs nfs4 smb cifs http https ftp sftp tftp */ static bool schemeIsRemote( const std::string & scheme_r ); /** \overload nonstatic version */ bool schemeIsRemote() const { return schemeIsRemote( getScheme() ); } @@ -266,7 +266,7 @@ namespace zypp /** \overload nonstatic version */ bool schemeIsVolatile() const { return schemeIsVolatile( getScheme() ); } - /** http https ftp sftp */ + /** http https ftp sftp tftp */ static bool schemeIsDownloading( const std::string & scheme_r ); /** \overload nonstatic version */ bool schemeIsDownloading() const { return schemeIsDownloading( getScheme() ); } diff --git a/libzypp/zypp/UserData.h b/libzypp/zypp/UserData.h new file mode 100644 index 0000000..acb5526 --- /dev/null +++ b/libzypp/zypp/UserData.h @@ -0,0 +1,70 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/UserData.h + */ +#ifndef ZYPP_USERDATA_H +#define ZYPP_USERDATA_H + +#include +#include +#include +#include + +#include "zypp/base/PtrTypes.h" +#include "zypp/ContentType.h" + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + /////////////////////////////////////////////////////////////////// + namespace callback + { + /////////////////////////////////////////////////////////////////// + /// \class UserData + /// \brief Typesafe passing of user data via callbacks + /// + /// Basically a std::map plus + /// associated \ref ContentType. + /////////////////////////////////////////////////////////////////// + class UserData + { + typedef std::map DataType; + public: + /** Default ctor */ + UserData() + {} + + public: + /** Get type */ + const ContentType & type() const + { return _type; } + + /** Set type */ + void type( const ContentType & type_r ) + { _type = type_r; } + + public: + /** Validate object in a boolean context: has data */ + explicit operator bool() const + { return ! ( _dataP == nullptr || _dataP->empty() ); } + + private: + ContentType _type; + shared_ptr _dataP; + }; + + /** \relates UserData Stream output */ + inline std::ostream & operator<<( std::ostream & str, const UserData & obj ) + { return str << "UserData(" << obj.type() << ")";} + + } // namespace callback + /////////////////////////////////////////////////////////////////// +} // namespace zypp +/////////////////////////////////////////////////////////////////// +#endif // ZYPP_USERDATA_H diff --git a/libzypp/zypp/VendorAttr.cc b/libzypp/zypp/VendorAttr.cc index d111b41..2cef434 100644 --- a/libzypp/zypp/VendorAttr.cc +++ b/libzypp/zypp/VendorAttr.cc @@ -88,17 +88,22 @@ namespace zypp if ( ! lcent ) { unsigned myid = 0; - // Compare this entry with the global vendor map. - // Reversed to get the longes prefix. - for ( VendorMap::reverse_iterator it = _vendorMap.rbegin(); it != _vendorMap.rend(); ++it ) - { - if ( str::hasPrefix( lcvendor.c_str(), it->first ) ) - { - myid = it->second; - break; // found - } - } - if ( ! myid ) + // bnc#812608: no pefix compare in opensuse namespace + static const IdString openSUSE( "opensuse" ); + if ( lcvendor == openSUSE || ! str::hasPrefix( lcvendor.c_str(), openSUSE.c_str() ) ) + { + // Compare this entry with the global vendor map. + // Reversed to get the longest prefix. + for ( VendorMap::reverse_iterator it = _vendorMap.rbegin(); it != _vendorMap.rend(); ++it ) + { + if ( str::hasPrefix( lcvendor.c_str(), it->first ) ) + { + myid = it->second; + break; // found + } + } + } + if ( ! myid ) { myid = --_nextId; // get a new class ID } @@ -107,7 +112,7 @@ namespace zypp else { ent = lcent; // take the ID from the lowercased vendor string - } + } } return ent; } @@ -125,17 +130,11 @@ namespace zypp { vendorGroupCounter = 1; Pathname vendorPath (ZConfig::instance().vendorPath()); - try - { - Target_Ptr trg( getZYpp()->target() ); - if ( trg ) - vendorPath = trg->root() / vendorPath; - } - catch ( ... ) { - // noop: Someone decided to let target() throw if the ptr is NULL ;( + Target_Ptr trg( getZYpp()->getTarget() ); + if ( trg ) + vendorPath = trg->root() / vendorPath; } - // creating entries addVendorDirectory (vendorPath); @@ -164,14 +163,6 @@ namespace zypp _vendorMap["opensuse"] = suseit->second; } - // Take care 'opensuse build service' gets it's own class. - VendorMap::const_iterator obsit( _vendorMap.find("opensuse build service") ); - if ( obsit == _vendorMap.end() ) - { - _vendorMap["opensuse build service"] = ++vendorGroupCounter; - } - - MIL << *this << endl; } @@ -189,7 +180,7 @@ namespace zypp if (nextId != vendorGroupCounter + 1 && nextId != _vendorMap[*it]) { - // We have at least 3 groups which has to be mixed --> mix the third group to the first + // We have at least 3 groups which has to be mixed --> mix the third group to the first unsigned int moveID = _vendorMap[*it]; for_( itMap, _vendorMap.begin(), _vendorMap.end() ) { @@ -262,14 +253,7 @@ namespace zypp bool VendorAttr::addVendorDirectory( const Pathname & dirname ) const { - parser::IniDict dict; - - if ( PathInfo(dirname).isExist()) - { - InputStream is(dirname); - dict.read(is); - } - else + if ( ! PathInfo(dirname).isExist() ) { MIL << dirname << " not found." << endl; return false; diff --git a/libzypp/zypp/ZConfig.cc b/libzypp/zypp/ZConfig.cc index 7b383ab..ef6edc8 100644 --- a/libzypp/zypp/ZConfig.cc +++ b/libzypp/zypp/ZConfig.cc @@ -11,7 +11,11 @@ */ extern "C" { +#include #include +#if __GLIBC_PREREQ (2,16) +#include // getauxval for PPC64P7 detection +#endif #include #include } @@ -127,7 +131,7 @@ namespace zypp ERR << "Cant open " << PathInfo("/proc/cpuinfo") << endl; } } - else if ( architecture == Arch_armv7l) + else if ( architecture == Arch_armv7l || architecture == Arch_armv6l ) { std::ifstream platform( "/etc/rpm/platform" ); if (platform) @@ -140,16 +144,24 @@ namespace zypp WAR << "/etc/rpm/platform contains armv7hl-: architecture upgraded to '" << architecture << "'" << endl; break; } - if ( str::hasPrefix( *in, "armv7tnhl-" ) ) + if ( str::hasPrefix( *in, "armv6hl-" ) ) { - architecture = Arch_armv7tnhl; - WAR << "/etc/rpm/platform contains armv7tnhl-: architecture upgraded to '" << architecture << "'" << endl; + architecture = Arch_armv6hl; + WAR << "/etc/rpm/platform contains armv6hl-: architecture upgraded to '" << architecture << "'" << endl; break; } - } } } +#if __GLIBC_PREREQ (2,16) + else if ( architecture == Arch_ppc64 ) + { + const char * platform = (const char *)getauxval( AT_PLATFORM ); + int powerlvl; + if ( platform && sscanf( platform, "power%d", &powerlvl ) == 1 && powerlvl > 6 ) + architecture = Arch_ppc64p7; + } +#endif return architecture; } @@ -291,6 +303,7 @@ namespace zypp , download_min_download_speed ( 0 ) , download_max_download_speed ( 0 ) , download_max_silent_tries ( 5 ) + , download_transfer_timeout ( 180 ) , commit_downloadMode ( DownloadDefault ) , solver_onlyRequires ( false ) , solver_allowVendorChange ( false ) @@ -300,7 +313,7 @@ namespace zypp , apply_locks_file ( true ) , pluginsPath ( "/usr/lib/zypp/plugins" ) { - MIL << "libzypp: " << VERSION << " built in OBS, see rpm -q --info libzypp for more information" << endl; + MIL << "libzypp: " << VERSION << " built " << __DATE__ << " " << __TIME__ << endl; // override_r has higest prio // ZYPP_CONF might override /etc/zypp/zypp.conf if ( _parsedZyppConf.empty() ) @@ -417,6 +430,12 @@ namespace zypp { str::strtonum(value, download_max_silent_tries); } + else if ( entry == "download.transfer_timeout" ) + { + str::strtonum(value, download_transfer_timeout); + if ( download_transfer_timeout < 0 ) download_transfer_timeout = 0; + else if ( download_transfer_timeout > 3600 ) download_transfer_timeout = 3600; + } else if ( entry == "commit.downloadMode" ) { commit_downloadMode.set( deserializeDownloadMode( value ) ); @@ -453,10 +472,6 @@ namespace zypp { solver_checkSystemFile = Pathname(value); } - else if ( entry == "solver.checkSystemFileDir" ) - { - solver_checkSystemFileDir = Pathname(value); - } else if ( entry == "multiversion" ) { str::split( value, inserter( _multiversion, _multiversion.end() ), ", \t" ); @@ -566,6 +581,7 @@ namespace zypp int download_min_download_speed; int download_max_download_speed; int download_max_silent_tries; + int download_transfer_timeout; Option commit_downloadMode; @@ -576,7 +592,6 @@ namespace zypp DefaultOption solverUpgradeRemoveDroppedPackages; Pathname solver_checkSystemFile; - Pathname solver_checkSystemFileDir; std::set & multiversion() { return getMultiversion(); } const std::set & multiversion() const { return getMultiversion(); } @@ -589,6 +604,8 @@ namespace zypp Pathname credentials_global_dir_path; Pathname credentials_global_file_path; + std::string userData; + Option pluginsPath; private: @@ -716,6 +733,31 @@ namespace zypp } } + /////////////////////////////////////////////////////////////////// + // user data + /////////////////////////////////////////////////////////////////// + + bool ZConfig::hasUserData() const + { return !_pimpl->userData.empty(); } + + std::string ZConfig::userData() const + { return _pimpl->userData; } + + 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; + } + /////////////////////////////////////////////////////////////////// Pathname ZConfig::repoCachePath() const @@ -818,6 +860,9 @@ namespace zypp long ZConfig::download_max_silent_tries() const { return _pimpl->download_max_silent_tries; } + long ZConfig::download_transfer_timeout() const + { return _pimpl->download_transfer_timeout; } + DownloadMode ZConfig::commit_downloadMode() const { return _pimpl->commit_downloadMode; } @@ -834,10 +879,6 @@ namespace zypp { return ( _pimpl->solver_checkSystemFile.empty() ? (configPath()/"systemCheck") : _pimpl->solver_checkSystemFile ); } - Pathname ZConfig::solver_checkSystemFileDir() const - { return ( _pimpl->solver_checkSystemFileDir.empty() - ? (configPath()/"systemCheck.d") : _pimpl->solver_checkSystemFileDir ); } - unsigned ZConfig::solver_upgradeTestcasesToKeep() const { return _pimpl->solver_upgradeTestcasesToKeep; } @@ -846,6 +887,8 @@ namespace zypp void ZConfig::resetSolverUpgradeRemoveDroppedPackages() { _pimpl->solverUpgradeRemoveDroppedPackages.restoreToDefault(); } const std::set & ZConfig::multiversionSpec() const { return _pimpl->multiversion(); } + void ZConfig::multiversionSpec( std::set new_r ) { _pimpl->multiversion().swap( new_r ); } + void ZConfig::clearMultiversionSpec() { _pimpl->multiversion().clear(); } void ZConfig::addMultiversionSpec( const std::string & name_r ) { _pimpl->multiversion().insert( name_r ); } void ZConfig::removeMultiversionSpec( const std::string & name_r ) { _pimpl->multiversion().erase( name_r ); } @@ -917,7 +960,7 @@ namespace zypp std::ostream & ZConfig::about( std::ostream & str ) const { - str << "libzypp: " << VERSION << " built in OBS, see rpm -q --info libzypp for more information" << endl; + str << "libzypp: " << VERSION << " built " << __DATE__ << " " << __TIME__ << endl; str << "libsolv: " << solv_version; if ( ::strcmp( solv_version, LIBSOLV_VERSION_STRING ) ) diff --git a/libzypp/zypp/ZConfig.h b/libzypp/zypp/ZConfig.h index ac76052..b380138 100644 --- a/libzypp/zypp/ZConfig.h +++ b/libzypp/zypp/ZConfig.h @@ -108,6 +108,24 @@ namespace zypp void resetTextLocale() { setTextLocale( defaultTextLocale() ); } + public: + /** \name Maintain user data + * \see \ref zypp-userdata + */ + //@{ + /** Whether a (non empty) user data sting is defined. */ + bool hasUserData() const; + + /** User defined string value to be passed to log, history, plugins... */ + std::string userData() const; + + /** Set a new \ref userData string. + * \returns \c TRUE if the string was accepted; \c FALSE if the + * string was rejected due to nonprintable characters or newlines. + */ + bool setUserData( const std::string & str_r ); + //@} + public: /** * Path where the caches are kept (/var/cache/zypp) @@ -205,6 +223,11 @@ namespace zypp */ long download_max_silent_tries() const; + /** + * Maximum time in seconds that you allow a transfer operation to take. + */ + long download_transfer_timeout() const; + /** Whether to consider using a deltarpm when downloading a package. * Config option download.use_deltarpm (true) @@ -256,13 +279,6 @@ namespace zypp */ Pathname solver_checkSystemFile() const; - /** - * Directory, which may or may not contain files in which - * dependencies described which has to be fulfilled for a - * running system. - */ - Pathname solver_checkSystemFileDir() const; - /** * Whether vendor check is by default enabled. */ @@ -308,6 +324,8 @@ namespace zypp */ //@{ const std::set & multiversionSpec() const; + void multiversionSpec( std::set new_r ); + void clearMultiversionSpec(); void addMultiversionSpec( const std::string & name_r ); void removeMultiversionSpec( const std::string & name_r ); //@} diff --git a/libzypp/zypp/ZYpp.cc b/libzypp/zypp/ZYpp.cc index 08900fb..ffa5895 100644 --- a/libzypp/zypp/ZYpp.cc +++ b/libzypp/zypp/ZYpp.cc @@ -15,6 +15,7 @@ #include "zypp/ZYpp.h" #include "zypp/zypp_detail/ZYppImpl.h" #include "zypp/sat/Pool.h" +#include "zypp/ManagedFile.h" using std::endl; @@ -100,18 +101,10 @@ namespace zypp void ZYpp::installSrcPackage( const SrcPackage_constPtr & srcPackage_r ) { _pimpl->installSrcPackage( srcPackage_r ); } + ManagedFile ZYpp::provideSrcPackage( const SrcPackage_constPtr & srcPackage_r ) + {return _pimpl->provideSrcPackage( srcPackage_r ); } /////////////////////////////////////////////////////////////////// - void ZYpp::setRequestedLocales( const LocaleSet & locales_r ) - { sat::Pool::instance().setRequestedLocales( locales_r ); } - - const LocaleSet & ZYpp::getRequestedLocales() const - { return sat::Pool::instance().getRequestedLocales(); } - - const LocaleSet & ZYpp::getAvailableLocales() const - { return sat::Pool::instance().getAvailableLocales(); } - - Pathname ZYpp::homePath() const { return _pimpl->homePath(); } diff --git a/libzypp/zypp/ZYpp.h b/libzypp/zypp/ZYpp.h index a5f6e09..f193f97 100644 --- a/libzypp/zypp/ZYpp.h +++ b/libzypp/zypp/ZYpp.h @@ -20,6 +20,7 @@ #include "zypp/APIConfig.h" #include "zypp/ZConfig.h" +#include "zypp/ManagedFile.h" #include "zypp/ZYppCommit.h" #include "zypp/ResTraits.h" @@ -118,46 +119,15 @@ namespace zypp */ void installSrcPackage( const SrcPackage_constPtr & srcPackage_r ); + /** Provides a source package on the Target. + * \throws Exception + */ + ManagedFile provideSrcPackage( const SrcPackage_constPtr & srcPackage_r ); + public: /** */ Resolver_Ptr resolver() const; KeyRing_Ptr keyRing() const; - public: - /** Set the preferred locale for translated labels, descriptions, - * etc. passed to the UI. - * \deprecated Use ZConfig diretcly. - */ - ZYPP_DEPRECATED void setTextLocale( const Locale & textLocale_r ) - { ZConfig::instance().setTextLocale( textLocale_r ); } - /** \deprecated Use ZConfig diretcly. */ - ZYPP_DEPRECATED Locale getTextLocale() const - { return ZConfig::instance().textLocale(); } - - public: - /** \name move to pool - * \deprecated Use ResPool diretcly. - */ - //@{ - /** Set the requested locales. - * Languages to be supported by the system, e.g. language specific - * packages to be installed. This function operates on the pool, - * so only the locales that are available as resolvables - * are marked as requested. The rest is ignored. - * \deprecated Use ResPool diretcly. - */ - void setRequestedLocales( const LocaleSet & locales_r ) ZYPP_DEPRECATED; - - /** \deprecated Use ResPool diretcly. */ - const LocaleSet & getRequestedLocales() const ZYPP_DEPRECATED; - - /** - * Get the set of available locales. - * This is computed from the package data so it actually - * represents all locales packages claim to support. - * \deprecated Use ResPool diretcly. - */ - const LocaleSet & getAvailableLocales() const ZYPP_DEPRECATED; - //@} public: /** Get the path where zypp related plugins store persistent data and caches */ @@ -169,28 +139,6 @@ namespace zypp /** set the home, if you need to change it */ void setHomePath( const Pathname & path ); - /** Get the system architecture. - * \deprecated Use ZConfig diretcly. - */ - ZYPP_DEPRECATED Arch architecture() const - { return ZConfig::instance().systemArchitecture(); } - /** Set the system architecture. - * This should be used for testing/debugging only since the Target backend - * won't be able to install incompatible packages ;-) - * \deprecated Use ZConfig diretcly. - */ - ZYPP_DEPRECATED void setArchitecture( const Arch & arch ) - { ZConfig::instance().setSystemArchitecture( arch ); } - - public: - - /** - * \deprecated Persistent locks are automatically maintained, kept in the pool, loaded and saved together with the Target. - * \ref ZConfig::apply_locks_file tells whether locks are applied or not. - */ - ZYPP_DEPRECATED int applyLocks() - { return 0; } - protected: /** Dtor */ virtual ~ZYpp(); diff --git a/libzypp/zypp/ZYppCallbacks.h b/libzypp/zypp/ZYppCallbacks.h index d894717..9f0a96a 100644 --- a/libzypp/zypp/ZYppCallbacks.h +++ b/libzypp/zypp/ZYppCallbacks.h @@ -12,7 +12,9 @@ #ifndef ZYPP_ZYPPCALLBACKS_H #define ZYPP_ZYPPCALLBACKS_H +#include "zypp/base/EnumClass.h" #include "zypp/Callback.h" +#include "zypp/UserData.h" #include "zypp/Resolvable.h" #include "zypp/RepoInfo.h" #include "zypp/Pathname.h" @@ -26,6 +28,14 @@ namespace zypp { ///////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// + namespace sat + { + class Queue; + class FileConflicts; + } // namespace sat + /////////////////////////////////////////////////////////////////// + struct ProgressReport : public callback::ReportBase { virtual void start( const ProgressData &/*task*/ ) @@ -102,6 +112,12 @@ namespace zypp INVALID // the downloaded file is invalid }; + /** Hint that package is available in the local cache (no download needed). + * This will be the only trigger for an already cached package. + */ + virtual void infoInCache( Resolvable::constPtr res_r, const Pathname & localfile_r ) + {} + virtual void start( Resolvable::constPtr /*resolvable_ptr*/ , const Url &/*url*/ @@ -141,20 +157,20 @@ namespace zypp virtual void finishDeltaApply() {} - // Dowmload patch rpm: - // - path below url reported on start() - // - expected download size (0 if unknown) - // - download is interruptable - virtual void startPatchDownload( const Pathname & /*filename*/, const ByteCount & /*downloadsize*/ ) + /** \deprecated Unused since 2008 */ + virtual ZYPP_DEPRECATED void startPatchDownload( const Pathname & /*filename*/, const ByteCount & /*downloadsize*/ ) {} - virtual bool progressPatchDownload( int /*value*/ ) + /** \deprecated Unused since 2008 */ + virtual ZYPP_DEPRECATED bool progressPatchDownload( int /*value*/ ) { return true; } - virtual void problemPatchDownload( const std::string &/*description*/ ) + /** \deprecated Unused since 2008 */ + virtual ZYPP_DEPRECATED void problemPatchDownload( const std::string &/*description*/ ) {} - virtual void finishPatchDownload() + /** \deprecated Unused since 2008 */ + virtual ZYPP_DEPRECATED void finishPatchDownload() {} @@ -441,6 +457,44 @@ namespace zypp {} }; + /////////////////////////////////////////////////////////////////// + /// \class FindFileConflictstReport + /// \brief Check for package file conflicts in commit (after download) + /// + /// File conflict check requires that all packages are downloaded and + /// now available in the cache (need to access the filelists). Missing + /// packages are omitted from check and their number is reported in + /// \a noFilelist_r. This usually happens if download mode 'as-needed' + /// is used. + /////////////////////////////////////////////////////////////////// + struct FindFileConflictstReport : public callback::ReportBase + { + /** + * \param progress_r Progress counter for packages to check. + * \return \c true to continue, \c false upon user abort request. + */ + virtual bool start( const ProgressData & progress_r ) + { return true; } + + /** + * \param progress_r Progress counter for packages to check. + * \param noFilelist_r Queue of so far skipped solvables (no filelist/not yet downloaded). + * \return \c true to continue, \c false upon user abort request. + */ + virtual bool progress( const ProgressData & progress_r, const sat::Queue & noFilelist_r ) + { return true; } + + /** + * \param progress_r Progress counter for packages to check. + * \param noFilelist_r Queue of skipped solvables (no filelist/not yet downloaded). + * \param conflicts_r File conflits queue. + * \return \c true to continue, \c false upon user abort request. + */ + virtual bool result( const ProgressData & progress_r, const sat::Queue & noFilelist_r, const sat::FileConflicts & conflicts_r ) + { return true; } + }; + + /////////////////////////////////////////////////////////////////// namespace rpm { @@ -466,7 +520,7 @@ namespace zypp enum RpmLevel { RPM, RPM_NODEPS, - RPM_NODEPS_FORCE + RPM_NODEPS_FORCE //!< only this one used }; virtual void start( @@ -712,6 +766,59 @@ namespace zypp ) {} }; + /////////////////////////////////////////////////////////////////// + /// \class JobReport + /// \brief Generic report for sending messages. + /////////////////////////////////////////////////////////////////// + struct JobReport : public callback::ReportBase + { + public: + /** message type (use like 'enum class \ref MsgType') */ + struct _MsgTypeDef { + enum Enum { debug, info, warning, error, important, data }; + }; + typedef base::EnumClass<_MsgTypeDef> MsgType; ///< 'enum class MsgType' + + /** typsafe map of userdata */ + typedef callback::UserData UserData; + + public: + /** Send a ready to show message text. */ + virtual bool message( MsgType type_r, const std::string & msg_r, const UserData & userData_r ) const + { return true; } + + + /** \name Static sender instance */ + //@{ + /** Singleton sender instance */ + static callback::SendReport & instance(); // impl in ZYppImpl.cc + + /** send debug message text */ + static bool debug( const MessageString & msg_r, const UserData & userData_r = UserData() ) + { return instance()->message( MsgType::debug, msg_r, userData_r ); } + + /** send message text */ + static bool info( const MessageString & msg_r, const UserData & userData_r = UserData() ) + { return instance()->message( MsgType::info, msg_r, userData_r ); } + + /** send warning text */ + static bool warning( const MessageString & msg_r, const UserData & userData_r = UserData() ) + { return instance()->message( MsgType::warning, msg_r, userData_r ); } + + /** send error text */ + static bool error( const MessageString & msg_r, const UserData & userData_r = UserData() ) + { return instance()->message( MsgType::error, msg_r, userData_r ); } + + /** send important message text */ + static bool important( const MessageString & msg_r, const UserData & userData_r = UserData() ) + { return instance()->message( MsgType::important, msg_r, userData_r ); } + + /** send data message */ + static bool data( const MessageString & msg_r, const UserData & userData_r = UserData() ) + { return instance()->message( MsgType::data, msg_r, userData_r ); } + //@} + }; + ///////////////////////////////////////////////////////////////// } // namespace zypp diff --git a/libzypp/zypp/ZYppCommitResult.cc b/libzypp/zypp/ZYppCommitResult.cc index ff3da49..4834760 100644 --- a/libzypp/zypp/ZYppCommitResult.cc +++ b/libzypp/zypp/ZYppCommitResult.cc @@ -50,19 +50,15 @@ namespace zypp /////////////////////////////////////////////////////////////////// ZYppCommitResult::ZYppCommitResult() - : _result(0), _pimpl( new Impl ) + : _pimpl( new Impl ) {} ZYppCommitResult::ZYppCommitResult( const ZYppCommitResult & lhs_r ) - : _result(0) - , _errors( lhs_r._errors ) - , _remaining( lhs_r._remaining ) - , _srcremaining( lhs_r._srcremaining ) - , _pimpl( lhs_r._pimpl ) + : _pimpl( lhs_r._pimpl ) {} ZYppCommitResult::ZYppCommitResult( const Pathname & root_r ) - : _result(0), _pimpl( new Impl ) + : _pimpl( new Impl ) { _pimpl->_root = root_r; } ZYppCommitResult::~ZYppCommitResult() diff --git a/libzypp/zypp/ZYppCommitResult.h b/libzypp/zypp/ZYppCommitResult.h index ae16b1c..1769cab 100644 --- a/libzypp/zypp/ZYppCommitResult.h +++ b/libzypp/zypp/ZYppCommitResult.h @@ -163,32 +163,6 @@ namespace zypp { return transaction().actionEmpty( sat::Transaction::STEP_ERROR ); } //@} - public: - /** \name Oldstlye interface to be removed asap. - * \deprecated PoolItem is not suitable for reporting errors about - * packages to be deteled, as reloading the rpm database after commit - * invalidates them. - */ - //@{ - typedef std::list PoolItemList; - /** - * number of committed resolvables - **/ - int _result ZYPP_DEPRECATED; - /** - * list of resolvables with error - **/ - PoolItemList _errors ZYPP_DEPRECATED; - /** - * list of resolvables remaining (due to wrong media) - **/ - PoolItemList _remaining ZYPP_DEPRECATED; - /** - * list of kind:source resolvables remaining (due to wrong media) - **/ - PoolItemList _srcremaining ZYPP_DEPRECATED; - //@} - public: /** Implementation */ class Impl; diff --git a/libzypp/zypp/ZYppFactory.cc b/libzypp/zypp/ZYppFactory.cc index 11130fd..45fc1c2 100644 --- a/libzypp/zypp/ZYppFactory.cc +++ b/libzypp/zypp/ZYppFactory.cc @@ -15,11 +15,13 @@ extern "C" } #include #include +#include #include "zypp/base/Logger.h" #include "zypp/base/Gettext.h" #include "zypp/base/IOStream.h" #include "zypp/base/Functional.h" +#include "zypp/base/Backtrace.h" #include "zypp/PathInfo.h" #include "zypp/ZYppFactory.h" @@ -40,6 +42,19 @@ using std::endl; namespace zypp { ///////////////////////////////////////////////////////////////// + namespace + { + void sigsegvHandler( int sig ); + ::sighandler_t lastSigsegvHandler = ::signal( SIGSEGV, sigsegvHandler ); + + /** SIGSEGV handler to log stack trace */ + void sigsegvHandler( int sig ) + { + INT << "Error: signal " << sig << endl << dumpBacktrace << endl; + ::signal( SIGSEGV, lastSigsegvHandler ); + } + } + namespace env { /** Hack to circumvent the currently poor --root support. */ @@ -51,7 +66,7 @@ namespace zypp namespace zypp_readonly_hack { ///////////////////////////////////////////////////////////////// - static bool active = false; + static bool active = getenv("ZYPP_READONLY_HACK"); void IWantIt() { @@ -59,6 +74,11 @@ namespace zypp MIL << "ZYPP_READONLY promised." << endl; } + bool IGotIt() + { + return active; + } + ///////////////////////////////////////////////////////////////// } // namespace zypp_readonly_hack /////////////////////////////////////////////////////////////////// @@ -72,10 +92,10 @@ namespace zypp { public: ZYppGlobalLock() - : _cleanLock( false ) - , _zyppLockFilePath( env::ZYPP_LOCKFILE_ROOT() / "/var/run/zypp.pid" ) + : _zyppLockFilePath( env::ZYPP_LOCKFILE_ROOT() / "/var/run/zypp.pid" ) , _zyppLockFile( NULL ) , _lockerPid( 0 ) + , _cleanLock( false ) { filesystem::assert_dir(_zyppLockFilePath.dirname() ); } diff --git a/libzypp/zypp/ZYppFactory.h b/libzypp/zypp/ZYppFactory.h index 5ef9d01..8cfbf3f 100644 --- a/libzypp/zypp/ZYppFactory.h +++ b/libzypp/zypp/ZYppFactory.h @@ -29,8 +29,6 @@ namespace zypp public: pid_t lockerPid() const { return _lockerPid; } const std::string & lockerName() const { return _lockerName; } - /** \deprecated User lockerPid */ - ZYPP_DEPRECATED pid_t locker_pid() const { return lockerPid(); } private: pid_t _lockerPid; std::string _lockerName; diff --git a/libzypp/zypp/base/Backtrace.cc b/libzypp/zypp/base/Backtrace.cc new file mode 100644 index 0000000..9c3ba96 --- /dev/null +++ b/libzypp/zypp/base/Backtrace.cc @@ -0,0 +1,106 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/base/Backtrace.cc + */ +#include +#include + +#include +#include "zypp/base/LogTools.h" +#include "zypp/base/String.h" +#include "zypp/base/Backtrace.h" + +using std::endl; + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + std::ostream & dumpBacktrace( std::ostream & stream_r ) + { + // get void*'s for all entries on the stack + static const size_t arraySize = 50; + void *array[arraySize]; + size_t size = ::backtrace( array, arraySize ); + + // Print out all frames to stderr. Separate sigsegvHandler stack + // [dumpBacktrace][sigsegvHandler][libc throwing] from actual + // code stack. + char ** messages = ::backtrace_symbols( array, size ); + if ( messages ) + { + static const size_t handlerStack = 3; // [dumpBacktrace][sigsegvHandler][libc throwing] + static const size_t first = 0; + for ( size_t i = first; i < size; ++i ) + { + char * mangled_name = 0; + char * offset_begin = 0; + char * offset_end = 0; + + // find parentheses and +address offset surrounding mangled name + for ( char * p = messages[i]; *p; ++p ) + { + if ( *p == '(' ) + { + mangled_name = p; + } + else if ( *p == '+' ) + { + offset_begin = p; + } + else if ( *p == ')' ) + { + offset_end = p; + break; + } + } + + int btLevel = i-handlerStack; // negative level in sigsegvHandler + if ( i > first ) + { + stream_r << endl; + if ( btLevel == 0 ) + stream_r << "vvvvvvvvvv----------------------------------------" << endl; + } + stream_r << "[" << (btLevel<0 ?"hd":"bt") << "]: (" << btLevel << ") "; + + // if the line could be processed, attempt to demangle the symbol + if ( mangled_name && offset_begin && offset_end && mangled_name < offset_begin ) + { + *mangled_name++ = '\0'; + *offset_begin++ = '\0'; + *offset_end++ = '\0'; + + int status; + char * real_name = ::abi::__cxa_demangle( mangled_name, 0, 0, &status ); + + // if demangling is successful, output the demangled function name + if ( status == 0 ) + { + stream_r << messages[i] << " : " << real_name << "+" << offset_begin << offset_end; + } + // otherwise, output the mangled function name + else + { + stream_r << messages[i] << " : " << mangled_name << "+" << offset_begin << offset_end; + } + ::free( real_name ); + } + else + { + // otherwise, print the whole line + stream_r << messages[i]; + } + } + ::free( messages ); + } + return stream_r; + } + +} // namespace zypp +/////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/base/Backtrace.h b/libzypp/zypp/base/Backtrace.h new file mode 100644 index 0000000..b94a9ef --- /dev/null +++ b/libzypp/zypp/base/Backtrace.h @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/base/Backtrace.h + */ +#ifndef ZYPP_BASE_BACKTRACE_H +#define ZYPP_BASE_BACKTRACE_H + +#include +#include + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + + /** Dump current stack trace to a stream. + * Thanks to http://stackoverflow.com/questions/77005. + * \code + * #include + * std::cerr << zypp::dumpBacktrace << std::endl; + * \endcode + * \code + * #include + * std::string trace( str::Str() << zypp::dumpBacktrace ); + * \endcode + */ + std::ostream & dumpBacktrace( std::ostream & stream_r ); + +} // namespace zypp +/////////////////////////////////////////////////////////////////// +#endif // ZYPP_BASE_BACKTRACE_H diff --git a/libzypp/zypp/base/Easy.h b/libzypp/zypp/base/Easy.h index 41a1961..018b399 100644 --- a/libzypp/zypp/base/Easy.h +++ b/libzypp/zypp/base/Easy.h @@ -41,11 +41,54 @@ #define arraySize(A) (sizeof(A)/sizeof(*A)) #define arrayEnd(A) (&A[0] + arraySize(A)) +/** + * \code + * defConstStr( strANY(), "ANY" ); + * std::str str = strANY(); + * \endcode + */ +#define defConstStr(FNC,STR) inline const std::string & FNC { static const std::string val( STR ); return val; } + #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #if GCC_VERSION < 40600 || not defined(__GXX_EXPERIMENTAL_CXX0X__) #define nullptr NULL #endif +/** Delete copy ctor and copy assign */ +#define NON_COPYABLE(CLASS) \ + CLASS( const CLASS & ) = delete; \ + CLASS & operator=( const CLASS & ) = delete + +/** Default copy ctor and copy assign */ +#define DEFAULT_COPYABLE(CLASS) \ + CLASS( const CLASS & ) = default; \ + CLASS & operator=( const CLASS & ) = default + +#ifndef SWIG // Swig treats it as syntax error +/** Delete move ctor and move assign */ +#define NON_MOVABLE(CLASS) \ + CLASS( CLASS && ) = delete; \ + CLASS & operator=( CLASS && ) = delete + +/** Default move ctor and move assign */ +#define DEFAULT_MOVABLE(CLASS) \ + CLASS( CLASS && ) = default; \ + CLASS & operator=( CLASS && ) = default +#else +#define NON_MOVABLE(CLASS) +#define DEFAULT_MOVABLE(CLASS) +#endif + +/** Delete copy ctor and copy assign but enable default move */ +#define NON_COPYABLE_BUT_MOVE( CLASS ) \ + NON_COPYABLE(CLASS); \ + DEFAULT_MOVABLE(CLASS) + +/** Default move ctor and move assign but enable default copy */ +#define NON_MOVABLE_BUT_COPY( CLASS ) \ + NON_MOVABLE(CLASS); \ + DEFAULT_COPYABLE(CLASS) + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/base/EnumClass.h b/libzypp/zypp/base/EnumClass.h new file mode 100644 index 0000000..747b413 --- /dev/null +++ b/libzypp/zypp/base/EnumClass.h @@ -0,0 +1,91 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/base/EnumClass.h + */ +#ifndef ZYPP_BASE_ENUMCLASS_H +#define ZYPP_BASE_ENUMCLASS_H + +#include + +#include "zypp/base/PtrTypes.h" + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + /////////////////////////////////////////////////////////////////// + namespace base + { + /////////////////////////////////////////////////////////////////// + /// \class EnumClass + /// \brief Type safe enum (workaround SWIG not supporting enum class) + /// \code + /// struct _ColorDef { enum Enum { R, G ,B }; }; + /// typedef EnumClass<_ColorDef> Color; + /// \endcode + /// Conversion to from string can be easily added, e.g. like this: + /// \code + /// struct _ColorDef { + /// enum Enum { R, G ,B }; + /// static Enum fromString( const std::string & val_r ); + /// static const std::string & asString( Enum val_r ); + /// }; + /// std::ostream & operator<<( std::ostream & str, const _ColorDef & obj ) + /// { return str << _ColorDef::asString( obj.inSwitch() ); } + /// + /// typedef EnumClass<_ColorDef> Color; + /// Color red = Color::fromString("red"); + /// cout << red << endl; // "red" + /// \endcode + /////////////////////////////////////////////////////////////////// + template + class EnumClass : public _EnumDef + { + public: + typedef typename _EnumDef::Enum Enum; ///< The underlying enum type + typedef typename std::underlying_type::type Integral;///< The underlying integral type + + EnumClass( Enum val_r ) : _val( val_r ) {} + + /** Underlying enum value for use in switch + * \code + * struct _ColorDef { enum Enum { R, G ,B }; } + * typedef EnumClass<_ColorDef> Color; + * + * Color a; + * switch ( a.asEnum() ) + * \endcode + */ + Enum asEnum() const { return _val; } + + /** Underlying integral value (e.g. array index) + * \code + * struct _ColorDef { enum Enum { R, G ,B }; } + * typedef EnumClass<_ColorDef> Color; + * + * Color a; + * std::string table[] = { "red", "green", "blue" }; + * std::cout << table[a.asIntegral()] << std::endl; + */ + Integral asIntegral() const { return static_cast(_val); } + + friend bool operator==( const EnumClass & lhs, const EnumClass & rhs ) { return lhs._val == rhs._val; } + friend bool operator!=( const EnumClass & lhs, const EnumClass & rhs ) { return lhs._val != rhs._val; } + friend bool operator< ( const EnumClass & lhs, const EnumClass & rhs ) { return lhs._val < rhs._val; } + friend bool operator<=( const EnumClass & lhs, const EnumClass & rhs ) { return lhs._val <= rhs._val; } + friend bool operator> ( const EnumClass & lhs, const EnumClass & rhs ) { return lhs._val > rhs._val; } + friend bool operator>=( const EnumClass & lhs, const EnumClass & rhs ) { return lhs._val >= rhs._val; } + + private: + Enum _val; + }; + } // namespace base + /////////////////////////////////////////////////////////////////// +} // namespace zypp +/////////////////////////////////////////////////////////////////// +#endif // ZYPP_BASE_ENUMCLASS_H diff --git a/libzypp/zypp/base/ExternalDataSource.cc b/libzypp/zypp/base/ExternalDataSource.cc index d503ba3..35023e9 100644 --- a/libzypp/zypp/base/ExternalDataSource.cc +++ b/libzypp/zypp/base/ExternalDataSource.cc @@ -7,10 +7,7 @@ | | \---------------------------------------------------------------------*/ /** \file zypp/base/ExternalDataSource.cc - * - * \todo replace by Blocxx - * -*/ + */ #define _GNU_SOURCE 1 // for ::getline diff --git a/libzypp/zypp/base/ExternalDataSource.h b/libzypp/zypp/base/ExternalDataSource.h index ffdf502..ed2773b 100644 --- a/libzypp/zypp/base/ExternalDataSource.h +++ b/libzypp/zypp/base/ExternalDataSource.h @@ -7,10 +7,7 @@ | | \---------------------------------------------------------------------*/ /** \file zypp/base/ExternalDataSource.h - * - * \todo replace by Blocxx - * -*/ + */ #ifndef ZYPP_EXTERNALDATASOURCE_H #define ZYPP_EXTERNALDATASOURCE_H @@ -30,11 +27,11 @@ namespace zypp { protected: FILE *inputfile; FILE *outputfile; - + private: char *linebuffer; size_t linebuffer_size; - + public: /** * Create a new instance. @@ -43,25 +40,25 @@ namespace zypp { * Either can be NULL if no reading/writing is allowed. */ ExternalDataSource(FILE *inputfile = 0, FILE *outputfile = 0); - + /** * Implicitly close the connection. */ virtual ~ExternalDataSource(); - + /** * Send some data to the output stream. * @param buffer The data to send * @param length The size of it */ bool send (const char *buffer, size_t length); - + /** * Send some data down the stream. * @param string The data to send */ bool send (std::string s); - + /** * Read some data from the input stream. * @param buffer Where to put the data @@ -69,13 +66,13 @@ namespace zypp { * Returns the amount actually received */ size_t receive(char *buffer, size_t length); - + /** * Read one line from the input stream. * Returns the line read, including the terminator. */ std::string receiveLine(); - + /** * Read characters into a string until character c is * read. C is put at the end of the string. @@ -87,17 +84,17 @@ namespace zypp { * This is the initial default. */ void setBlocking(bool mode); - + /** * Close the input and output streams. */ virtual int close(); - + /** * Return the input stream. */ FILE *inputFile() const { return inputfile; } - + /** * Return the output stream. */ diff --git a/libzypp/zypp/base/Flags.h b/libzypp/zypp/base/Flags.h index 70b3a8a..6bf7f10 100644 --- a/libzypp/zypp/base/Flags.h +++ b/libzypp/zypp/base/Flags.h @@ -54,16 +54,17 @@ namespace zypp * } * \endcode */ - template + template class Flags { public: - typedef Enum enum_type; + typedef _Enum Enum; ///< The underlying enum type + typedef typename std::underlying_type::type Integral; ///< The underlying integral type public: - Flags() : _val( 0 ) {} - Flags( Enum flag_r ) : _val( flag_r ) {} - explicit Flags( unsigned flag_r ) : _val( flag_r ) {} + constexpr Flags() : _val( 0 ) {} + constexpr Flags( Enum flag_r ) : _val( flag_r ) {} + explicit constexpr Flags( Integral flag_r ) : _val( flag_r ) {} Flags & operator&=( Flags rhs ) { _val &= rhs._val; return *this; } Flags & operator&=( Enum rhs ) { _val &= rhs; return *this; } @@ -75,18 +76,18 @@ namespace zypp Flags & operator^=( Enum rhs ) { _val ^= rhs; return *this; } public: - operator unsigned() const { return _val; } + constexpr operator Integral() const { return _val; } - Flags operator&( Flags rhs ) const { return Flags( *this ) &= rhs; } - Flags operator&( Enum rhs ) const { return Flags( *this ) &= rhs; } + constexpr Flags operator&( Flags rhs ) const { return Flags( _val & rhs._val ); } + constexpr Flags operator&( Enum rhs ) const { return Flags( _val & rhs ); } - Flags operator|( Flags rhs ) const { return Flags( *this ) |= rhs; } - Flags operator|( Enum rhs ) const { return Flags( *this ) |= rhs; } + constexpr Flags operator|( Flags rhs ) const { return Flags( _val | rhs._val ); } + constexpr Flags operator|( Enum rhs ) const { return Flags( _val | rhs ); } - Flags operator^( Flags rhs ) const { return Flags( *this ) ^= rhs; } - Flags operator^( Enum rhs ) const { return Flags( *this ) ^= rhs; } + constexpr Flags operator^( Flags rhs ) const { return Flags( _val ^ rhs._val ); } + constexpr Flags operator^( Enum rhs ) const { return Flags( _val ^ rhs ); } - Flags operator~() const { return Flags( ~_val ); } + constexpr Flags operator~() const { return Flags( ~_val ); } public: Flags & setFlag( Flags flag_r, bool newval_r ) { return( newval_r ? setFlag(flag_r) : unsetFlag(flag_r) ); } @@ -102,7 +103,7 @@ namespace zypp bool testFlag( Enum flag_r ) const { return ( _val & flag_r ) == flag_r; } private: - unsigned _val; + Integral _val; }; /////////////////////////////////////////////////////////////////// @@ -115,13 +116,13 @@ namespace zypp /** \relates Flags */ #define ZYPP_DECLARE_OPERATORS_FOR_FLAGS(Name) \ -inline Name operator&( Name::enum_type lhs, Name::enum_type rhs ) { return Name( lhs ) &= rhs; } \ -inline Name operator&( Name::enum_type lhs, Name rhs ) { return rhs &= lhs; } \ -inline Name operator|( Name::enum_type lhs, Name::enum_type rhs ) { return Name( lhs ) |= rhs; } \ -inline Name operator|( Name::enum_type lhs, Name rhs ) { return rhs |= lhs; } \ -inline Name operator^( Name::enum_type lhs, Name::enum_type rhs ) { return Name( lhs ) ^= rhs; } \ -inline Name operator^( Name::enum_type lhs, Name rhs ) { return rhs ^= lhs; } \ -inline Name operator~( Name::enum_type lhs ) { return ~Name( lhs ); } +inline constexpr Name operator&( Name::Enum lhs, Name::Enum rhs ) { return Name( lhs ) & rhs; } \ +inline constexpr Name operator&( Name::Enum lhs, Name rhs ) { return rhs & lhs; } \ +inline constexpr Name operator|( Name::Enum lhs, Name::Enum rhs ) { return Name( lhs ) | rhs; } \ +inline constexpr Name operator|( Name::Enum lhs, Name rhs ) { return rhs | lhs; } \ +inline constexpr Name operator^( Name::Enum lhs, Name::Enum rhs ) { return Name( lhs ) ^ rhs; } \ +inline constexpr Name operator^( Name::Enum lhs, Name rhs ) { return rhs ^ lhs; } \ +inline constexpr Name operator~( Name::Enum lhs ) { return ~Name( lhs ); } /** \relates Flags */ #define ZYPP_DECLARE_FLAGS_AND_OPERATORS(Name,Enum) \ diff --git a/libzypp/zypp/base/IOStream.h b/libzypp/zypp/base/IOStream.h index 70d6288..f19f6d6 100644 --- a/libzypp/zypp/base/IOStream.h +++ b/libzypp/zypp/base/IOStream.h @@ -17,7 +17,6 @@ #include "zypp/base/Flags.h" #include "zypp/base/PtrTypes.h" -#include "zypp/base/SafeBool.h" #include "zypp/base/Function.h" #include "zypp/base/NonCopyable.h" @@ -109,20 +108,19 @@ namespace zypp * } * \endcode */ - class EachLine : private base::SafeBool, private base::NonCopyable + class EachLine : private base::NonCopyable { - typedef base::SafeBool SafeBool; - public: /** Ctor taking a stream and reading the 1st line from it. */ EachLine( std::istream & str_r, unsigned lineNo_r = 0 ); - /** Evaluate class in a boolean context. */ - using SafeBool::operator bool_type; - /** Whether \c this contains a valid line to consume. */ bool valid() const - { return boolTest(); } + { return _valid; } + + /** Evaluate class in a boolean context. */ + explicit operator bool() const + { return _valid; } /** Return the current line number. */ unsigned lineNo() const @@ -157,11 +155,6 @@ namespace zypp return valid(); } - private: - friend SafeBool::operator bool_type() const; - bool boolTest() const - { return _valid; } - private: std::istream & _str; std::string _line; diff --git a/libzypp/zypp/base/Json.h b/libzypp/zypp/base/Json.h new file mode 100644 index 0000000..7957af9 --- /dev/null +++ b/libzypp/zypp/base/Json.h @@ -0,0 +1,383 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/base/Json.h + * +*/ +#ifndef ZYPP_BASE_JSON_H +#define ZYPP_BASE_JSON_H + +#include +#include +#include +#include +#include +#include + +#include "zypp/base/Easy.h" +#include "zypp/base/String.h" + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + /////////////////////////////////////////////////////////////////// + namespace json + { + // JSN Keywords + inline static const std::string & nullJSON() { static const std::string _s( "null" ); return _s; } + inline static const std::string & trueJSON() { static const std::string _s( "true" ); return _s; } + inline static const std::string & falseJSON() { static const std::string _s( "false" ); return _s; } + + /////////////////////////////////////////////////////////////////// + namespace detail + { + inline std::string strEncode( std::string val_r ) + { + typedef unsigned char uchar; + + std::string::size_type add = 2; // enclosing "s + for_( r, val_r.begin(), val_r.end() ) + { + if ( uchar(*r) < 32u ) + { + switch ( *r ) + { + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + add += 1; // "\c" + break; + default: + add += 5; // "\uXXXX" + break; + } + } + else + { + switch ( *r ) + { + case '"': + case '/': + case '\\': + add += 1; // \-escape + break; + } + } + } + + val_r.resize( val_r.size() + add, '@' ); + auto w( val_r.rbegin() ); + auto r( w + add ); + + *w++ = '"'; + for ( ; r != val_r.rend(); ++r ) + { + if ( uchar(*r) < 32u ) + { + static const char * digit = "0123456789abcdef"; + switch ( *r ) + { + case '\b': // "\c" + *w++ = 'b'; + *w++ = '\\'; + break; + case '\f': // "\c" + *w++ = 'f'; + *w++ = '\\'; + break; + case '\n': // "\c" + *w++ = 'n'; + *w++ = '\\'; + break; + case '\r': // "\c" + *w++ = 'r'; + *w++ = '\\'; + break; + case '\t': // "\c" + *w++ = 't'; + *w++ = '\\'; + break; + default: // "\uXXXX" + *w++ = digit[uchar(*r) % 15]; + *w++ = digit[uchar(*r) / 16]; + *w++ = '0'; + *w++ = '0'; + *w++ = 'u'; + *w++ = '\\'; + break; + } + } + else + { + switch ( (*w++ = *r) ) + { + case '"': + case '/': + case '\\': // \-escape + *w++ = '\\'; + break; + } + } + } + *w++ = '"'; + return val_r; + } + } // namespace detail + /////////////////////////////////////////////////////////////////// + + // null + inline std::string toJSON( void ) { return nullJSON(); } + inline std::string toJSON( std::nullptr_t ) { return nullJSON(); } + + // bool + inline std::string toJSON( bool val_r ) { return val_r ? trueJSON() : falseJSON(); } + inline std::string toJSON( const void * val_r ) { return val_r ? trueJSON() : falseJSON(); } + + // numbers + inline std::string toJSON( short val_r ) { return str::numstring( val_r ); } + inline std::string toJSON( unsigned short val_r ) { return str::numstring( val_r ); } + inline std::string toJSON( int val_r ) { return str::numstring( val_r ); } + inline std::string toJSON( unsigned val_r ) { return str::numstring( val_r ); } + inline std::string toJSON( long val_r ) { return str::numstring( val_r ); } + inline std::string toJSON( unsigned long val_r ) { return str::numstring( val_r ); } + inline std::string toJSON( long long val_r ) { return str::numstring( val_r ); } + inline std::string toJSON( unsigned long long val_r ){ return str::numstring( val_r ); } + + // strings + inline std::string toJSON( const char val_r ) { return detail::strEncode( std::string( 1, val_r ) ); } + inline std::string toJSON( const char * val_r ) { return val_r ? detail::strEncode( val_r ) : nullJSON(); } + inline std::string toJSON( const std::string & val_r ){ return detail::strEncode( val_r ); } + + // container to Array + template std::string toJSON( const std::vector & cont_r ); + template std::string toJSON( const std::list & cont_r ); + template std::string toJSON( const std::set & cont_r ); + + // map to Object + template std::string toJSON( const std::map & cont_r ); + + /** Type to JSON string representation. + * This can be implemented as non-static memberfunction \c asJSON, + * or as non-memberfunction \c toJSON; + * \code + * class Type; + * std::string Type::asJSON() const; + * std::string toJSON( const Type & ); + * \endcode + */ + template + std::string toJSON( const T & val_r ) { return val_r.asJSON(); } + + /////////////////////////////////////////////////////////////////// + /// \class Value + /// \brief JSON representation of datatypes via \ref toJSON + /// \code + /// namespace mynamspace + /// { + /// struct Mydata + /// {...}; + /// + /// std::string toJSON( const Mydata & ) + /// { return json::Array{ "answer", 42 }.asJSON(); } + /// } + /// + /// mynamspace::Mydata data; + /// json::Object bigone { + /// { "mydata", data }, + /// { "panic", false }, + /// { "nested", json::Object{ {"one",1}, {"two",2}, {"three",3} } } + /// }; + /// + /// cout << bigone << endl; + ///\endcode + /// \see http://www.json.org/ + /////////////////////////////////////////////////////////////////// + struct Value + { + /** Default ctor (null) */ + Value() : _data( toJSON() ) {} + + /** Copy ctor */ + Value( const Value & rhs ) : _data( rhs._data ) {} + + /** Ctor creating a JSON representation of \a T via \ref toJSON(T) */ + template + Value( const T & val_r ) : _data( toJSON( val_r ) ) {} + + /** JSON representation */ + const std::string & asJSON() const + { return _data; } + + /** String representation */ + const std::string & asString() const + { return asJSON(); } + + /** Stream output */ + std::ostream & dumpOn( std::ostream & str ) const + { return str << _data; } + + private: + std::string _data; + }; + + /** \relates Value Stream output */ + inline std::ostream & operator<<( std::ostream & str, const Value & obj ) + { return obj.dumpOn( str ); } + + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + /// \class String + /// \brief JSON string + /// Force representation as JSON string, mapping e.g. \c null values + /// to an empty string. Maninly used in \ref Object as key. + /////////////////////////////////////////////////////////////////// + struct String : public Value + { + String() : Value( "" ) {} + String( std::nullptr_t ) : Value( "" ) {} + + String( const char val_r ) : Value( val_r ) {} + String( const char * val_r ) : Value( val_r ? val_r : "" ) {} + String( const std::string & val_r ): Value( val_r ) {} + }; + + /////////////////////////////////////////////////////////////////// + /// \class Array + /// \brief JSON array + /////////////////////////////////////////////////////////////////// + struct Array + { + Array() {} + + /** Construct from container iterator */ + template + Array( Iterator begin, Iterator end ) + { for_( it, begin, end ) add( *it ); } + + /** Construct from container initializer list { v1, v2,... } */ + Array( const std::initializer_list & contents_r ) + : Array( contents_r.begin(), contents_r.end() ) + {} + + /** Push JSON Value to Array */ + void add( const Value & val_r ) + { _data.push_back( val_r.asJSON() ); } + + /** \overload from container initializer list { v1, v2,... } */ + void add( const std::initializer_list & contents_r ) + { for_( it, contents_r.begin(), contents_r.end() ) add( *it ); } + + /** JSON representation */ + std::string asJSON() const + { return str::Str() << *this; } + + /** String representation */ + std::string asString() const + { return asJSON(); } + + /** Stream output */ + std::ostream & dumpOn( std::ostream & str ) const + { + if ( _data.empty() ) + return str << "[]"; + str << '[' << *_data.begin(); + for_( val, ++_data.begin(), _data.end() ) + str << ", " << *val; + return str << ']'; + } + + private: + std::list _data; + }; + + /** \relates Array Stream output */ + inline std::ostream & operator<<( std::ostream & str, const Array & obj ) + { return obj.dumpOn( str ); } + + template + std::string toJSON( const std::vector & cont_r ) + { return json::Array( cont_r.begin(), cont_r.end() ).asJSON(); } + + template + std::string toJSON( const std::list & cont_r ) + { return json::Array( cont_r.begin(), cont_r.end() ).asJSON(); } + + template + std::string toJSON( const std::set & cont_r ) + { return json::Array( cont_r.begin(), cont_r.end() ).asJSON(); } + + /////////////////////////////////////////////////////////////////// + /// \class Object + /// \brief JSON object + /////////////////////////////////////////////////////////////////// + struct Object + { + Object() {} + + /** Construct from map-iterator */ + template + Object( Iterator begin, Iterator end ) + { for_( it, begin, end ) add( it->first, it->second ); } + + /** Construct from map-initializer list { {k1,v1}, {k2,v2},... } */ + Object( const std::initializer_list> & contents_r ) + : Object( contents_r.begin(), contents_r.end() ) + {} + + /** Add key/value pair */ + void add( const String & key_r, const Value & val_r ) + { _data[key_r.asJSON()] = val_r.asJSON(); } + + /** \overload from map-initializer list { {k1,v1}, {k2,v2},... } */ + void add( const std::initializer_list> & contents_r ) + { for_( it, contents_r.begin(), contents_r.end() ) add( it->first, it->second ); } + + /** JSON representation */ + std::string asJSON() const + { return str::Str() << *this; } + + /** String representation */ + std::string asString() const + { return asJSON(); } + + /** Stream output */ + std::ostream & dumpOn( std::ostream & str ) const + { + using std::endl; + if ( _data.empty() ) + return str << "{}"; + dumpOn( str << '{' << endl, _data.begin() ); + for_ ( val, ++_data.begin(), _data.end() ) + dumpOn( str << ',' << endl, val ); + return str << endl << '}'; + } + + private: + std::ostream & dumpOn( std::ostream & str, std::map::const_iterator val_r ) const + { return str << val_r->first << ": " << val_r->second; } + + std::map _data; + }; + + /** \relates Object Stream output */ + inline std::ostream & operator<<( std::ostream & str, const Object & obj ) + { return obj.dumpOn( str ); } + + template + std::string toJSON( const std::map & cont_r ) + { return json::Object( cont_r.begin(), cont_r.end() ).asJSON(); } + + + } // namespace json + /////////////////////////////////////////////////////////////////// +} // namespace zypp +/////////////////////////////////////////////////////////////////// +#endif // ZYPP_BASE_JSON_H diff --git a/libzypp/zypp/base/LogControl.cc b/libzypp/zypp/base/LogControl.cc index 4c9628a..03080bb 100644 --- a/libzypp/zypp/base/LogControl.cc +++ b/libzypp/zypp/base/LogControl.cc @@ -46,17 +46,19 @@ namespace zypp } else { + if ( mode_r ) + { + // not filesystem::assert_file as filesystem:: functions log, + // and this FileWriter is not yet in place. + int fd = ::open( file_r.c_str(), O_CREAT|O_EXCL, mode_r ); + if ( fd != -1 ) + ::close( fd ); + } // set unbuffered write std::ofstream * fstr = 0; _outs.reset( (fstr = new std::ofstream( file_r.asString().c_str(), std::ios_base::app )) ); fstr->rdbuf()->pubsetbuf(0,0); _str = &(*fstr); - if ( mode_r ) - { - // not filesystem::chmod, as filesystem:: functions log, - // and this FileWriter is not yet in place. - ::chmod( file_r.asString().c_str(), mode_r ); - } } } diff --git a/libzypp/zypp/base/LogTools.h b/libzypp/zypp/base/LogTools.h index b73013c..0e9b9cf 100644 --- a/libzypp/zypp/base/LogTools.h +++ b/libzypp/zypp/base/LogTools.h @@ -120,8 +120,8 @@ namespace zypp std::ostream & operator<<( std::ostream & str, const std::vector<_Tp> & obj ) { return dumpRange( str, obj.begin(), obj.end() ); } - template - std::ostream & operator<<( std::ostream & str, const std::set<_Tp> & obj ) + template + std::ostream & operator<<( std::ostream & str, const std::set<_Tp,_Cmp,_Alloc> & obj ) { return dumpRange( str, obj.begin(), obj.end() ); } template diff --git a/libzypp/zypp/base/NamedValue.h b/libzypp/zypp/base/NamedValue.h new file mode 100644 index 0000000..db3c724 --- /dev/null +++ b/libzypp/zypp/base/NamedValue.h @@ -0,0 +1,161 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/base/NamedValue.h + * +*/ +#ifndef ZYPP_BASE_NAMEDVALUE_H +#define ZYPP_BASE_NAMEDVALUE_H + +#include +#include +#include + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + + /////////////////////////////////////////////////////////////////// + /// \class NamedValue<_Tp> + /// \brief Simple value<>name mapping supporting aliases. + /// \code + /// enum Commands { + /// CMD_1, + /// CMD_2 + /// }; + /// NamedValue clist; + /// // Value | Name | Alias... + /// clist( CMD_1 ) | "cmd1"; + /// clist( CMD_2 ) | "cmd2" | "second"; + /// + /// std::string name( clist.getName( CMD_1 ) ); + /// Commands cmd( clist.getValue( "second" ) ); + /// \endcode + /////////////////////////////////////////////////////////////////// + template< class _Tp, const bool _WithAlias = true > + class NamedValue + { + typedef std::map< std::string, _Tp > NameMap; + typedef std::map< _Tp, std::string > ValueMap; + + public: + /** Whether not initialized (no (name,value) pair remembered) */ + bool empty() const + { return( _nameMap.empty() && _valueMap.empty() ); } + + public: + /** \name Get value for name or alias. */ + //@{ + /** Whether there is a \c value mapped for \a name_r. + */ + bool haveValue( const std::string & name_r ) const + { + typename NameMap::const_iterator it( _nameMap.find( name_r ) ); + return( it != _nameMap.end() ); + } + + /** Get value mapped for name or alias. + * \return \c true if name or alias was found. + */ + bool getValue( const std::string & name_r, _Tp & value_r ) const + { + typename NameMap::const_iterator it( _nameMap.find( name_r ) ); + if ( it == _nameMap.end() ) + return false; + value_r = it->second; + return true; + } + /** \overload \throws std::out_of_range exception if \a name_r was not found. */ + const _Tp & getValue( const std::string & name_r ) const + { return _nameMap.at( name_r ); } + //@} + + + /** \name Get name for value. */ + //@{ + /** Whether there is a \c name mapped for \a value_r. + */ + bool haveName( const std::string & value_r ) const + { + typename ValueMap::const_iterator it( _valueMap.find( value_r ) ); + return( it != _valueMap.end() ); + } + + /** Get name of value. + * \return \c true if name or alias was found. + */ + bool getName( const _Tp & value_r, std::string & name_r ) const + { + typename ValueMap::const_iterator it( _valueMap.find( value_r ) ); + if ( it == _valueMap.end() ) + return false; + value_r = it->second; + return true; + } + /** \overload \throws std::out_of_range exception if \a value_r was not found. */ + const std::string & getName( const _Tp & value_r ) const + { return _valueMap.at( value_r ); } + //@} + + public: + /** \name Inserter + */ + //@{ + class _Inserter + { + public: + _Inserter( NamedValue & parent_r, const _Tp & value_r ) + : _parent( &parent_r ) + , _value( value_r ) + {} + _Inserter & operator|( const std::string & name_r ) + { _parent->insert( _value, name_r ); return *this; } + private: + NamedValue * _parent; + _Tp _value; + }; + + _Inserter operator()( const _Tp & value_r ) + { return _Inserter( *this, value_r ); } + //@} + + /** Remember name (1st call) or alias (subsequent calls). + * \return \C true if this is the 1st call for \a value_r. + * \throws std::logic_error if \a name_r is already used as name or alias. + * \throws std::logic_error if \c _WithAlias is \c false and a name for \a value_r is already defined. + */ + bool insert( const _Tp & value_r, const std::string & name_r ) + { + typename NameMap::const_iterator nit( _nameMap.find( name_r ) ); + if ( nit != _nameMap.end() ) // duplicate name + throw std::logic_error( "NamedValue::insert name" ); + + typename ValueMap::const_iterator tit( _valueMap.find( value_r ) ); + if ( tit != _valueMap.end() ) // duplicate value, i.e. an alias + { + if ( !_WithAlias ) + throw std::logic_error( "NamedValue::insert alias" ); + + _nameMap[name_r] = value_r; + return false; + } + // here: 1st entry for value_r + _nameMap[name_r] = value_r; + _valueMap[value_r] = name_r; + return true; + } + + private: + NameMap _nameMap; + ValueMap _valueMap; + }; + /////////////////////////////////////////////////////////////////// + +} // namespace zypp +/////////////////////////////////////////////////////////////////// +#endif // ZYPP_BASE_NAMEDVALUE_H diff --git a/libzypp/zypp/base/PtrTypes.h b/libzypp/zypp/base/PtrTypes.h index e80e285..e6d26d1 100644 --- a/libzypp/zypp/base/PtrTypes.h +++ b/libzypp/zypp/base/PtrTypes.h @@ -13,6 +13,7 @@ #ifndef ZYPP_BASE_PTRTYPES_H #define ZYPP_BASE_PTRTYPES_H +#include #include #include @@ -24,6 +25,12 @@ namespace zypp { ///////////////////////////////////////////////////////////////// + namespace str + { + // printing void* (prevents us from including ) + std::string form( const char * format, ... ) __attribute__ ((format (printf, 1, 2))); + } + /** \defgroup ZYPP_SMART_PTR Smart pointer types * Smart pointer types. * @@ -122,6 +129,15 @@ namespace std return str << *obj; return str << std::string("NULL"); } + /** \overload specialize for void */ + template<> + inline std::ostream & operator<<( std::ostream & str, const zypp::shared_ptr & obj ) + { + if ( obj ) + return str << zypp::str::form( "%p", (void*)obj.get() ); + return str << std::string("NULL"); + } + /** \relates zypp::shared_ptr Stream output. */ template inline std::ostream & dumpOn( std::ostream & str, const zypp::shared_ptr<_D> & obj ) @@ -130,6 +146,10 @@ namespace std return dumpOn( str, *obj ); return str << std::string("NULL"); } + /** \overload specialize for void */ + template<> + inline std::ostream & dumpOn( std::ostream & str, const zypp::shared_ptr & obj ) + { return str << obj; } /** \relates zypp::intrusive_ptr Stream output. */ template @@ -266,10 +286,15 @@ namespace zypp { typedef typename _Traits::_Ptr _Ptr; typedef typename _Traits::_constPtr _constPtr; - typedef typename _Ptr::unspecified_bool_type unspecified_bool_type; + + RW_pointer() + {} + + RW_pointer( std::nullptr_t ) + {} explicit - RW_pointer( typename _Ptr::element_type * dptr = 0 ) + RW_pointer( typename _Ptr::element_type * dptr ) : _dptr( dptr ) {} @@ -278,6 +303,9 @@ namespace zypp : _dptr( dptr ) {} + RW_pointer & operator=( std::nullptr_t ) + { reset(); return *this; } + void reset() { _Ptr().swap( _dptr ); } @@ -290,14 +318,14 @@ namespace zypp void swap( _Ptr & rhs ) { _dptr.swap( rhs ); } - operator unspecified_bool_type() const - { return _dptr; } + explicit operator bool() const + { return _dptr.get() != nullptr; } const _D & operator*() const { return *_dptr; }; const _D * operator->() const - { return _dptr.get(); } + { return _dptr.operator->(); } const _D * get() const { return _dptr.get(); } @@ -306,7 +334,7 @@ namespace zypp { return *_dptr; } _D * operator->() - { return _dptr.get(); } + { return _dptr.operator->(); } _D * get() { return _dptr.get(); } @@ -336,7 +364,7 @@ namespace zypp * * Print the \c _D object the RW_pointer refers, or \c "NULL" * if the pointer is \c NULL. - */ + */ template inline std::ostream & operator<<( std::ostream & str, const RW_pointer<_D, _Ptr> & obj ) { @@ -350,21 +378,29 @@ namespace zypp inline bool operator==( const RW_pointer<_D, _Ptr> & lhs, const RW_pointer<_D, _Ptr> & rhs ) { return( lhs.get() == rhs.get() ); } /** \relates RW_pointer */ - template - inline bool operator==( const RW_pointer<_D, _Ptr> & lhs, const typename _Ptr::_Ptr & rhs ) - { return( lhs.get() == rhs.get() ); } + template + inline bool operator==( const RW_pointer<_D, _Ptr> & lhs, const typename _Ptr::_Ptr & rhs ) + { return( lhs.get() == rhs.get() ); } + /** \relates RW_pointer */ + template + inline bool operator==( const typename _Ptr::_Ptr & lhs, const RW_pointer<_D, _Ptr> & rhs ) + { return( lhs.get() == rhs.get() ); } + /** \relates RW_pointer */ + template + inline bool operator==( const RW_pointer<_D, _Ptr> & lhs, const typename _Ptr::_constPtr & rhs ) + { return( lhs.get() == rhs.get() ); } /** \relates RW_pointer */ - template - inline bool operator==( const typename _Ptr::_Ptr & lhs, const RW_pointer<_D, _Ptr> & rhs ) - { return( lhs.get() == rhs.get() ); } + template + inline bool operator==( const typename _Ptr::_constPtr & lhs, const RW_pointer<_D, _Ptr> & rhs ) + { return( lhs.get() == rhs.get() ); } /** \relates RW_pointer */ - template - inline bool operator==( const RW_pointer<_D, _Ptr> & lhs, const typename _Ptr::_constPtr & rhs ) - { return( lhs.get() == rhs.get() ); } + template + inline bool operator==( const RW_pointer<_D, _Ptr> & lhs, std::nullptr_t ) + { return( lhs.get() == nullptr ); } /** \relates RW_pointer */ - template - inline bool operator==( const typename _Ptr::_constPtr & lhs, const RW_pointer<_D, _Ptr> & rhs ) - { return( lhs.get() == rhs.get() ); } + template + inline bool operator==( std::nullptr_t, const RW_pointer<_D, _Ptr> & rhs ) + { return( nullptr == rhs.get() ); } /** \relates RW_pointer */ @@ -372,21 +408,29 @@ namespace zypp inline bool operator!=( const RW_pointer<_D, _Ptr> & lhs, const RW_pointer<_D, _Ptr> & rhs ) { return ! ( lhs == rhs ); } /** \relates RW_pointer */ - template - inline bool operator!=( const RW_pointer<_D, _Ptr> & lhs, const typename _Ptr::_Ptr & rhs ) - { return ! ( lhs == rhs ); } + template + inline bool operator!=( const RW_pointer<_D, _Ptr> & lhs, const typename _Ptr::_Ptr & rhs ) + { return ! ( lhs == rhs ); } + /** \relates RW_pointer */ + template + inline bool operator!=( const typename _Ptr::_Ptr & lhs, const RW_pointer<_D, _Ptr> & rhs ) + { return ! ( lhs == rhs ); } + /** \relates RW_pointer */ + template + inline bool operator!=( const RW_pointer<_D, _Ptr> & lhs, const typename _Ptr::_constPtr & rhs ) + { return ! ( lhs == rhs ); } /** \relates RW_pointer */ - template - inline bool operator!=( const typename _Ptr::_Ptr & lhs, const RW_pointer<_D, _Ptr> & rhs ) - { return ! ( lhs == rhs ); } + template + inline bool operator!=( const typename _Ptr::_constPtr & lhs, const RW_pointer<_D, _Ptr> & rhs ) + { return ! ( lhs == rhs ); } /** \relates RW_pointer */ - template - inline bool operator!=( const RW_pointer<_D, _Ptr> & lhs, const typename _Ptr::_constPtr & rhs ) - { return ! ( lhs == rhs ); } + template + inline bool operator!=( const RW_pointer<_D, _Ptr> & lhs, std::nullptr_t ) + { return( lhs.get() != nullptr ); } /** \relates RW_pointer */ - template - inline bool operator!=( const typename _Ptr::_constPtr & lhs, const RW_pointer<_D, _Ptr> & rhs ) - { return ! ( lhs == rhs ); } + template + inline bool operator!=( std::nullptr_t, const RW_pointer<_D, _Ptr> & rhs ) + { return( nullptr != rhs.get() ); } /////////////////////////////////////////////////////////////////// @@ -394,7 +438,7 @@ namespace zypp * Calls \a rhs -\>clone(). Being defined as a * function outside \ref RWCOW_pointer allows to overload * it, in case a specific \a _D does not have clone(). - */ + */ template inline _D * rwcowClone( const _D * rhs ) { return rhs->clone(); } @@ -415,10 +459,15 @@ namespace zypp { typedef typename _Traits::_Ptr _Ptr; typedef typename _Traits::_constPtr _constPtr; - typedef typename _Ptr::unspecified_bool_type unspecified_bool_type; + + RWCOW_pointer() + {} + + RWCOW_pointer( std::nullptr_t ) + {} explicit - RWCOW_pointer( typename _Ptr::element_type * dptr = 0 ) + RWCOW_pointer( typename _Ptr::element_type * dptr ) : _dptr( dptr ) {} @@ -427,6 +476,9 @@ namespace zypp : _dptr( dptr ) {} + RWCOW_pointer & operator=( std::nullptr_t ) + { reset(); return *this; } + void reset() { _Ptr().swap( _dptr ); } @@ -439,14 +491,14 @@ namespace zypp void swap( _Ptr & rhs ) { _dptr.swap( rhs ); } - operator unspecified_bool_type() const - { return _dptr; } + explicit operator bool() const + { return _dptr.get() != nullptr; } const _D & operator*() const { return *_dptr; }; const _D * operator->() const - { return _dptr.get(); } + { return _dptr.operator->(); } const _D * get() const { return _dptr.get(); } @@ -455,7 +507,7 @@ namespace zypp { assertUnshared(); return *_dptr; } _D * operator->() - { assertUnshared(); return _dptr.get(); } + { assertUnshared(); return _dptr.operator->(); } _D * get() { assertUnshared(); return _dptr.get(); } @@ -493,7 +545,7 @@ namespace zypp * * Print the \c _D object the RWCOW_pointer refers, or \c "NULL" * if the pointer is \c NULL. - */ + */ template inline std::ostream & operator<<( std::ostream & str, const RWCOW_pointer<_D, _Ptr> & obj ) { @@ -522,6 +574,14 @@ namespace zypp template inline bool operator==( const typename _Ptr::_constPtr & lhs, const RWCOW_pointer<_D, _Ptr> & rhs ) { return( lhs.get() == rhs.get() ); } + /** \relates RWCOW_pointer */ + template + inline bool operator==( const RWCOW_pointer<_D, _Ptr> & lhs, std::nullptr_t ) + { return( lhs.get() == nullptr ); } + /** \relates RWCOW_pointer */ + template + inline bool operator==( std::nullptr_t, const RWCOW_pointer<_D, _Ptr> & rhs ) + { return( nullptr == rhs.get() ); } /** \relates RWCOW_pointer */ template @@ -543,6 +603,14 @@ namespace zypp template inline bool operator!=( const typename _Ptr::_constPtr & lhs, const RWCOW_pointer<_D, _Ptr> & rhs ) { return ! ( lhs == rhs ); } + /** \relates RWCOW_pointer */ + template + inline bool operator!=( const RWCOW_pointer<_D, _Ptr> & lhs, std::nullptr_t ) + { return( lhs.get() != nullptr ); } + /** \relates RWCOW_pointer */ + template + inline bool operator!=( std::nullptr_t, const RWCOW_pointer<_D, _Ptr> & rhs ) + { return( nullptr != rhs.get() ); } /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/base/Regex.cc b/libzypp/zypp/base/Regex.cc index 1609c39..13adc4f 100644 --- a/libzypp/zypp/base/Regex.cc +++ b/libzypp/zypp/base/Regex.cc @@ -33,6 +33,7 @@ void regex::assign(const std::string& str,int flags) m_flags = flags; int err; char errbuff[100]; + static const int normal = 1<<16; // deprecated legacy, use match_extended if (!(flags & normal)) { flags |= match_extended; flags &= ~(normal); diff --git a/libzypp/zypp/base/Regex.h b/libzypp/zypp/base/Regex.h index 1eca7ff..f66f07b 100644 --- a/libzypp/zypp/base/Regex.h +++ b/libzypp/zypp/base/Regex.h @@ -88,12 +88,9 @@ namespace zypp public: enum RegFlags { - optimize = 0, ///< \deprecated legacy, obsolete - match_extra = 0, ///< \deprecated legacy, obsolete icase = REG_ICASE, ///< Do not differentiate case nosubs = REG_NOSUB, ///< Support for substring addressing of matches is not required match_extended = REG_EXTENDED, ///< Use POSIX Extended Regular Expression syntax when interpreting regex. - normal = 1<<16 ///< \deprecated legacy, use match_extended }; regex(); diff --git a/libzypp/zypp/base/SafeBool.h b/libzypp/zypp/base/SafeBool.h deleted file mode 100644 index a2aef6b..0000000 --- a/libzypp/zypp/base/SafeBool.h +++ /dev/null @@ -1,90 +0,0 @@ -/*---------------------------------------------------------------------\ -| ____ _ __ __ ___ | -| |__ / \ / / . \ . \ | -| / / \ V /| _/ _/ | -| / /__ | | | | | | | -| /_____||_| |_| |_| | -| | -\---------------------------------------------------------------------*/ -/** \file zypp/base/SafeBool.h - * -*/ -#ifndef ZYPP_BASE_SAFEBOOL_H -#define ZYPP_BASE_SAFEBOOL_H - -/////////////////////////////////////////////////////////////////// -namespace zypp -{ ///////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////// - namespace base - { ///////////////////////////////////////////////////////////////// - - namespace safebool_detail - { - class SafeBoolBase - { - protected: - typedef void (SafeBoolBase::*bool_type)() const; - void theTrueBoolType() const {} - - SafeBoolBase() {} - SafeBoolBase( const SafeBoolBase & ) {} - ~SafeBoolBase() {} - SafeBoolBase & operator=( const SafeBoolBase & ) { return *this; } - }; - } - - /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : SafeBool - // - /** Validate objects in a boolean context without harmful side effects. - * \see http://www.artima.com/cppsource/safebool.html - * - * Uses CRTP to avoid a virtual function. \c _Derived must provide - * bool boolTest() const preformong the test. - * - * \note Using SafeBool enables ==/!= comparision for \c Foo, based on - * the bool_type values. Make shure you overload \b both operators, in - * case an other semantic is desired for ==/!=. - * - * \code - * class Foo : protected base::SafeBool - * { - * public: - * using base::SafeBool::operator bool_type; - * - * private: - * friend SafeBool::operator bool_type() const; - * bool boolTest() const - * { - * // Perform Boolean logic here - * } - * }; - * \endcode - * \todo Investigate why Bit refuses private inheritance - * and exposition of operator bool_type. Seems to be a gcc - * bug. protected works. - */ - template - struct SafeBool : private safebool_detail::SafeBoolBase - { - using safebool_detail::SafeBoolBase::bool_type; - operator bool_type() const - { - return( (static_cast(this))->boolTest() - ? &safebool_detail::SafeBoolBase::theTrueBoolType - : 0 ); - } - protected: - ~SafeBool() {} - }; - /////////////////////////////////////////////////////////////////// - - ///////////////////////////////////////////////////////////////// - } // namespace base - /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////// -} // namespace zypp -/////////////////////////////////////////////////////////////////// -#endif // ZYPP_BASE_SAFEBOOL_H diff --git a/libzypp/zypp/base/SetRelationMixin.cc b/libzypp/zypp/base/SetRelationMixin.cc new file mode 100644 index 0000000..5b37830 --- /dev/null +++ b/libzypp/zypp/base/SetRelationMixin.cc @@ -0,0 +1,44 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/base/SetRelationMixin.cc + */ + +#include +#include "zypp/base/SetRelationMixin.h" + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + const std::string & _SetCompareDef::asString( Enum val_r ) + { + static std::map _table = { + { uncomparable, "{?}" }, + { equal, "{=}" }, + { properSubset, "{<}" }, + { properSuperset, "{>}" }, + { disjoint, "{ }" }, + }; + return _table[val_r]; + } + + const std::string & _SetRelationDef::asString( Enum val_r ) + { + static std::map _table = { + { uncomparable, "{??}" }, + { equal, "{==}" }, + { properSubset, "{<<}" }, + { properSuperset, "{>>}" }, + { disjoint, "{ }" }, + { subset, "{<=}" }, + { superset, "{>=}" }, + }; + return _table[val_r]; + } +} // namespace zypp +/////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/base/SetRelationMixin.h b/libzypp/zypp/base/SetRelationMixin.h new file mode 100644 index 0000000..7ca5479 --- /dev/null +++ b/libzypp/zypp/base/SetRelationMixin.h @@ -0,0 +1,242 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/base/SetRelationMixin.h + */ +#ifndef ZYPP_BASE_SETRELATIONMIXIN_H +#define ZYPP_BASE_SETRELATIONMIXIN_H + +#include +#include + +#include "zypp/base/Easy.h" +#include "zypp/base/EnumClass.h" + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + /////////////////////////////////////////////////////////////////// + /// \class _SetCompareDef + /// \brief Result of set comparison (use like 'enum class \ref SetCompare') + /// This is the type a \c compare function should return. + /////////////////////////////////////////////////////////////////// + struct _SetCompareDef { + enum Enum { + uncomparable = 0, ///< "{?}" + equal = (1<<0), ///< "{=}" + properSubset = (1<<1), ///< "{<}" + properSuperset = (1<<2), ///< "{>}" + disjoint = (1<<3), ///< "{ }" + }; + /** String representantion */ + static const std::string & asString( Enum val_r ); + }; + /** \relates _SetCompareDef typedef 'enum class SetCompare' */ + typedef base::EnumClass<_SetCompareDef> SetCompare; + + /** \relates SetCompare Stream output */ + inline std::ostream & operator<<( std::ostream & str, const SetCompare::Enum & obj ) + { return str << SetCompare::asString( obj ); } + /** \overload */ + inline std::ostream & operator<<( std::ostream & str, const SetCompare & obj ) + { return str << obj.asEnum(); } + + /////////////////////////////////////////////////////////////////// + /// \class _SetRelationDef + /// \brief Set Relation based on \ref SetCompare (use like 'enum class \ref SetRelation') + /// Comparison (\c== \c!=) between \ref SetRelation and \ref SetCompare + /// is defined to let \c SetRelation::subset match \c SetCompare::equal + /// as well as \c SetCompare::properSubset. Accordingly \c SetRelation::subset + /// matches \c SetCompare::equal as well as \c SetCompare::properSuperset. + /////////////////////////////////////////////////////////////////// + struct _SetRelationDef { + enum Enum { + uncomparable = SetCompare::uncomparable, ///< "{??}" + equal = SetCompare::equal, ///< "{==}" + properSubset = SetCompare::properSubset, ///< "{<<}" + properSuperset = SetCompare::properSuperset, ///< "{>>}" + disjoint = SetCompare::disjoint, ///< "{ }" + subset = properSubset|equal, ///< "{<=}" + superset = properSuperset|equal, ///< "{>=}" + }; + /** String representantion */ + static const std::string & asString( Enum val_r ); + }; + /** \relates _SetRelationDef typedef 'enum class SetRelation' */ + typedef base::EnumClass<_SetRelationDef> SetRelation; + + /** \relates SetRelation Stream output */ + inline std::ostream & operator<<( std::ostream & str, const SetRelation::Enum & obj ) + { return str << SetRelation::asString( obj ); } + /** \overload */ + inline std::ostream & operator<<( std::ostream & str, const SetRelation & obj ) + { return str << obj.asEnum(); } + + /** \relates SetRelation \relates SetCompare Matching \ref SetCompare and \ref SetRelation */ + inline bool operator==( const SetRelation::Enum & lhs, const SetCompare::Enum & rhs ) + { return( lhs&rhs || !(lhs|rhs) ); } + /** \overload */ + inline bool operator==( const SetRelation::Enum & lhs, const SetCompare & rhs ) + { return( lhs == rhs.asEnum() ); } + /** \overload */ + inline bool operator==( const SetRelation & lhs, const SetCompare::Enum & rhs ) + { return( lhs.asEnum() == rhs ); } + /** \overload */ + inline bool operator==( const SetRelation & lhs, const SetCompare & rhs ) + { return( lhs.asEnum() == rhs.asEnum() ); } + /** \overload */ + inline bool operator==( const SetCompare::Enum & lhs, const SetRelation::Enum & rhs ) + { return( rhs == lhs ); } + /** \overload */ + inline bool operator==( const SetCompare::Enum & lhs, const SetRelation & rhs ) + { return( rhs == lhs ); } + /** \overload */ + inline bool operator==( const SetCompare & lhs, const SetRelation::Enum & rhs ) + { return( rhs == lhs ); } + /** \overload */ + inline bool operator==( const SetCompare & lhs, const SetRelation & rhs ) + { return( rhs == lhs ); } + + /** \relates SetRelation \relates SetCompare Matching \ref SetCompare and \ref SetRelation */ + inline bool operator!=( const SetRelation::Enum & lhs, const SetCompare::Enum & rhs ) + { return !( lhs == rhs ); } + /** \overload */ + inline bool operator!=( const SetRelation::Enum & lhs, const SetCompare & rhs ) + { return !( lhs == rhs ); } + /** \overload */ + inline bool operator!=( const SetRelation & lhs, const SetCompare::Enum & rhs ) + { return !( lhs == rhs ); } + /** \overload */ + inline bool operator!=( const SetRelation & lhs, const SetCompare & rhs ) + { return !( lhs == rhs ); } + /** \overload */ + inline bool operator!=( const SetCompare::Enum & lhs, const SetRelation::Enum & rhs ) + { return !( lhs == rhs ); } + /** \overload */ + inline bool operator!=( const SetCompare::Enum & lhs, const SetRelation & rhs ) + { return !( lhs == rhs ); } + /** \overload */ + inline bool operator!=( const SetCompare & lhs, const SetRelation::Enum & rhs ) + { return !( lhs == rhs ); } + /** \overload */ + inline bool operator!=( const SetCompare & lhs, const SetRelation & rhs ) + { return !( lhs == rhs ); } + + /////////////////////////////////////////////////////////////////// + namespace base + { + /////////////////////////////////////////////////////////////////// + /// \class SetRelationMixin + /// \brief Provide set relation methods based on Derived::setRelationMixinCompare + /// A class using this mixin must provide: + /// \code + /// SetCompare setRelationMixinCompare( const Derived & rhs ) const; + /// \endcode + /// \see \ref SETRELATIONMIXIN_DEFINE_COMPARE_BETWEEN + /// \ingroup g_CRTP + /////////////////////////////////////////////////////////////////// + template + class SetRelationMixin + { + public: + /** Compare sets */ + SetCompare compare( const Derived & trg ) const + { return derived().setRelationMixinCompare( trg ); } + /** \overload */ + SetCompare compare( const SetRelationMixin & trg ) const + { return compare( trg.derived() ); } + + /** Compare sets and match against \ref SetCompare */ + bool compare( const Derived & trg, SetCompare cmp ) const + { return compare( trg ) == cmp; } + /** \overload */ + bool compare( const SetRelationMixin & trg, SetCompare cmp ) const + { return compare( trg ) == cmp; } + + /** Compare sets and match against \ref SetRelation */ + bool compare( const Derived & trg, SetRelation rel ) const + { return compare( trg ) == rel; } + /** \overload */ + bool compare( const SetRelationMixin & trg, SetRelation rel ) const + { return compare( trg ) == rel; } + + protected: + SetRelationMixin() {} + DEFAULT_COPYABLE( SetRelationMixin ); + DEFAULT_MOVABLE( SetRelationMixin ); + ~SetRelationMixin() {} + + private: + /** Access to sublass Derived*/ + const Derived & derived() const + { return *static_cast( this ); } + }; + + /** \relates SetRelationMixin Compare sets */ + template + inline SetCompare compare( const SetRelationMixin & src, const SetRelationMixin & trg ) + { return src.compare( trg ); } + + /** \relates SetRelationMixin Compare sets and match against \ref SetCompare */ + template + inline bool compare( const SetRelationMixin & src, const SetRelationMixin & trg, SetCompare cmp ) + { return src.compare( trg, cmp ); } + + /** \relates SetRelationMixin Compare sets and match against \ref SetRelation */ + template + inline bool compare( const SetRelationMixin & src, const SetRelationMixin & trg, SetRelation rel ) + { return src.compare( trg, rel ); } + + /** \relates SetRelationMixin Equal */ + template + inline bool operator==( const SetRelationMixin & src, const SetRelationMixin & trg ) + { return src.compare( trg, SetRelation::equal ); } + + /** \relates SetRelationMixin Unequal */ + template + inline bool operator!=( const SetRelationMixin & src, const SetRelationMixin & trg ) + { return !( src == trg ); } + + /** \relates SetRelationMixin Define compare between Derived and some other type (e.g. std::string) + * \code + * class Foo : public base::SetRelationMixin {...}; + * SETRELATIONMIXIN_DEFINE_COMPARE_BETWEEN( Foo, const char * ); + * SETRELATIONMIXIN_DEFINE_COMPARE_BETWEEN( Foo, const std::string & ); + * \endcode + */ +#define SETRELATIONMIXIN_DEFINE_COMPARE_BETWEEN(DERIVED_TYPE,OTHER_TYPE) \ + inline SetCompare compare( const base::SetRelationMixin & src, OTHER_TYPE trg ) \ + { return src.compare( DERIVED_TYPE(trg) ); } \ + inline SetCompare compare( OTHER_TYPE src, const base::SetRelationMixin & trg ) \ + { return DERIVED_TYPE(src).compare( trg ); } \ + \ + inline bool compare( const base::SetRelationMixin & src, OTHER_TYPE trg, SetCompare cmp ) \ + { return src.compare( DERIVED_TYPE(trg), cmp ); } \ + inline bool compare( OTHER_TYPE src, const base::SetRelationMixin & trg, SetCompare cmp ) \ + { return DERIVED_TYPE(src).compare( trg, cmp ); } \ + \ + inline bool compare( const base::SetRelationMixin & src, OTHER_TYPE trg, SetRelation rel ) \ + { return src.compare( DERIVED_TYPE(trg), rel ); } \ + inline bool compare( OTHER_TYPE src, const base::SetRelationMixin & trg, SetRelation rel ) \ + { return DERIVED_TYPE(src).compare( trg, rel ); } \ + \ + inline bool operator==( const base::SetRelationMixin & src, OTHER_TYPE trg ) \ + { return src.compare( DERIVED_TYPE(trg), SetRelation::equal ); } \ + inline bool operator==( OTHER_TYPE src, const base::SetRelationMixin & trg ) \ + { return DERIVED_TYPE(src).compare( trg, SetRelation::equal ); } \ + \ + inline bool operator!=( const base::SetRelationMixin & src, OTHER_TYPE trg ) \ + { return !( src == trg ); } \ + inline bool operator!=( OTHER_TYPE src, const base::SetRelationMixin & trg ) \ + { return !( src == trg ); } + + } // namespace base + /////////////////////////////////////////////////////////////////// +} // namespace zypp +/////////////////////////////////////////////////////////////////// +#endif // ZYPP_BASE_SETRELATIONMIXIN_H diff --git a/libzypp/zypp/base/StrMatcher.cc b/libzypp/zypp/base/StrMatcher.cc index 2c5dfb3..0315364 100644 --- a/libzypp/zypp/base/StrMatcher.cc +++ b/libzypp/zypp/base/StrMatcher.cc @@ -197,7 +197,7 @@ namespace zypp /** Whether the pattern is already compiled. */ bool isCompiled() const - { return _matcher; } + { return _matcher != nullptr; } /** Return whether string matches. */ bool doMatch( const char * string_r ) const diff --git a/libzypp/zypp/base/StrMatcher.h b/libzypp/zypp/base/StrMatcher.h index 5fdfb3a..6b4114a 100644 --- a/libzypp/zypp/base/StrMatcher.h +++ b/libzypp/zypp/base/StrMatcher.h @@ -16,7 +16,6 @@ #include #include "zypp/base/PtrTypes.h" -#include "zypp/base/SafeBool.h" #include "zypp/base/Exception.h" /////////////////////////////////////////////////////////////////// @@ -30,7 +29,7 @@ namespace zypp /// Match mode( Match::GLOB | Match::NOCASE ); /// \endcode /////////////////////////////////////////////////////////////////// - class Match : private base::SafeBool + class Match { private: static const int _modemask; @@ -93,10 +92,9 @@ namespace zypp : _val( val_r ) {} -#ifndef SWIG // Swig treats it as syntax error /** Evaluate in a boolean context ( != 0 ). */ - using base::SafeBool::operator bool_type; -#endif + explicit operator bool() const + { return _val; } public: /** Test whether \c all of the \a rhs bits are set (same mode if \a rhs has one). */ @@ -208,9 +206,6 @@ namespace zypp std::string asString() const; private: - friend base::SafeBool::operator bool_type() const; - bool boolTest() const { return _val; } - /** Numeric value for enum (short for Match(m).get()). */ static int modeval( Mode mode_r ); @@ -299,7 +294,7 @@ namespace zypp /// /// \Note Those flags are always set: REG_EXTENDED | REG_NOSUB | REG_NEWLINE /////////////////////////////////////////////////////////////////// - class StrMatcher : private base::SafeBool + class StrMatcher { friend std::ostream & operator<<( std::ostream & str, const StrMatcher & obj ); @@ -329,10 +324,9 @@ namespace zypp /** Low level interface wraps \a flags into \ref Match. */ StrMatcher( const std::string & search_r, int flags_r ); - #ifndef SWIG // Swig treats it as syntax error /** Evaluate in a boolean context ( ! searchstring().empty() ). */ - using base::SafeBool::operator bool_type; - #endif + explicit operator bool() const + { return !searchstring().empty(); } public: /** Return whether string matches. @@ -381,11 +375,6 @@ namespace zypp */ bool doMatch( const char * string_r ) const; - private: - friend base::SafeBool::operator bool_type() const; - bool boolTest() const - { return !searchstring().empty(); } - private: /** Pointer to implementation */ RWCOW_pointer _pimpl; diff --git a/libzypp/zypp/base/String.cc b/libzypp/zypp/base/String.cc index f332d3f..666e79a 100644 --- a/libzypp/zypp/base/String.cc +++ b/libzypp/zypp/base/String.cc @@ -102,10 +102,10 @@ namespace zypp { if ( '0' <= ch && ch <= '9' ) return( ch - '0' ); - if ( 'A' <= ch && ch <= 'Z' ) - return( ch - 'A' + 10 ); - if ( 'a' <= ch && ch <= 'z' ) + if ( 'A' <= ch && ch <= 'F' ) return( ch - 'A' + 10 ); + if ( 'a' <= ch && ch <= 'f' ) + return( ch - 'a' + 10 ); return -1; } } @@ -303,14 +303,17 @@ namespace zypp std::string & replaceAll( std::string & str_r, const std::string & from_r, const std::string & to_r ) { - std::string::size_type pos = 0; - while ( (pos = str_r.find( from_r, pos )) != std::string::npos ) + if ( ! from_r.empty() ) { - str_r.replace( pos, from_r.size(), to_r ); - pos += to_r.size(); + std::string::size_type pos = 0; + while ( (pos = str_r.find( from_r, pos )) != std::string::npos ) + { + str_r.replace( pos, from_r.size(), to_r ); + pos += to_r.size(); - if ( pos >= str_r.length() ) - break; + if ( pos >= str_r.length() ) + break; + } } return str_r; } @@ -323,15 +326,18 @@ namespace zypp std::string & replaceAllFun( std::string & str_r, const std::string & from_r, function to_r ) { - std::string::size_type pos = 0; - while ( (pos = str_r.find( from_r, pos )) != std::string::npos ) + if ( ! from_r.empty() ) { - std::string to( to_r() ); - str_r.replace( pos, from_r.size(), to ); - pos += to.size(); + std::string::size_type pos = 0; + while ( (pos = str_r.find( from_r, pos )) != std::string::npos ) + { + std::string to( to_r() ); + str_r.replace( pos, from_r.size(), to ); + pos += to.size(); - if ( pos >= str_r.length() ) - break; + if ( pos >= str_r.length() ) + break; + } } return str_r; } diff --git a/libzypp/zypp/base/String.h b/libzypp/zypp/base/String.h index df2e332..e69a106 100644 --- a/libzypp/zypp/base/String.h +++ b/libzypp/zypp/base/String.h @@ -18,15 +18,58 @@ #include #include #include +#include #include "zypp/base/Easy.h" #include "zypp/base/PtrTypes.h" #include "zypp/base/Function.h" + +/////////////////////////////////////////////////////////////////// +namespace boost +{ + /** A formater with (N)o (A)rgument (C)heck. + * It won't complain about missing or excess arguments. Sometimes + * usefull when dealing with translations or classes providing a + * default formater. + */ + inline format formatNAC( const std::string & string_r ) { + using namespace boost::io; + format fmter( string_r ); + fmter.exceptions( all_error_bits ^ ( too_many_args_bit | too_few_args_bit ) ); + return fmter; + } +} // namespace boost +namespace zypp { using boost::formatNAC; } +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + /** Request a human readable (translated) string representation of _Tp [_Tp.asUserString()] + * Classes may implement a default as member function. + */ + template + std::string asUserString( const _Tp & val_r ) + { return val_r.asUserString(); } + +}// namespace zypp +/////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// + struct MessageString : public std::string + { + MessageString() {} + MessageString( const char * str_r ) : std::string( str_r ? str_r : "" ) {} + MessageString( const std::string & str_r ) : std::string( str_r ) {} + // boost::format, std::ostringstream, str::Str ... + template + MessageString( const _Str & str_r ) : std::string( str_r.str() ) {} + }; + /** Convenience \c char* constructible from \c std::string and \c char*, * it maps \c (char*)0 to an empty string. * @@ -102,6 +145,7 @@ namespace zypp /** String related utilities and \ref ZYPP_STR_REGEX. \see \ref ZYPP_STR_REGEX */ + namespace str { ///////////////////////////////////////////////////////////////// @@ -112,9 +156,17 @@ namespace zypp inline std::string asString( const std::string &t ) { return t; } +#ifndef SWIG // Swig treats it as syntax error + inline std::string asString( std::string && t ) + { return std::move(t); } +#endif + inline std::string asString( const char * t ) { return t; } + inline std::string asString( char * t ) + { return t; } + template inline std::string asString( const _T &t ) { return t.asString(); } @@ -129,7 +181,7 @@ namespace zypp template<> inline std::string asString( const bool &t ) - { return t ? "+" : "-"; } + { return t ? "true" : "false"; } /////////////////////////////////////////////////////////////////// /** Printf style construction of std::string. */ @@ -183,9 +235,21 @@ namespace zypp operator std::string() const { return _str.str(); } + std::string str() const + { return _str.str(); } + + std::ostream & stream() + { return _str; } + + void clear() + { _str.str( std::string() ); } + std::ostringstream _str; }; + inline std::ostream & operator<<( std::ostream & str, const Str & obj ) + { return str << (std::string)obj; } + /////////////////////////////////////////////////////////////////// /** \name String representation of number. * @@ -361,6 +425,28 @@ namespace zypp */ std::string & replaceAllFun( std::string & str_r, const std::string & from_r, function to_r ); + /** Enhance readability: insert gaps at regular distance + * \code + * // no gaps + * Key Fingerprint: 22C07BA534178CD02EFE22AAB88B2FD43DBDC284 + * // gapify 8 + * Key Fingerprint: 22C07BA5 34178CD0 2EFE22AA B88B2FD4 3DBDC284 + * // gapify 4 + * Key Fingerprint: 22C0 7BA5 3417 8CD0 2EFE 22AA B88B 2FD4 3DBD C284 + * // gapify 4, '-' + * Key Fingerprint: 22C0-7BA5-3417-8CD0-2EFE-22AA-B88B-2FD4-3DBD-C284 + * \endcode + */ + inline std::string gapify( std::string inp_r, std::string::size_type gap_r = 1, char gapchar = ' ' ) + { + if ( gap_r && inp_r.size() > gap_r ) + { + inp_r.reserve( inp_r.size() + (inp_r.size()-1)/gap_r ); + for ( std::string::size_type pos = gap_r; pos < inp_r.size(); pos += gap_r+1 ) + inp_r.insert( pos, 1, gapchar ); + } + return inp_r; + } /////////////////////////////////////////////////////////////////// /** \name Split. */ @@ -401,7 +487,16 @@ namespace zypp /** Split \a line_r into words with respect to escape delimeters. * Any sequence of characters in \a sepchars_r is treated as - * delimiter if not inside "" or "" or escaped by \, but not \\. + * delimiter if not inside \c "" or \c '' or escaped by \c \. + * + * \li A non-quoted backslash (\) preserves the literal value of the next character. + * \li Enclosing characters in single quotes preserves the literal value of each + * character within the quotes. A single quote may not occur between single + * quotes, even when preceded by a backslash. + * \li Enclosing characters in double quotes preserves the literal value of all + * characters within the quotes, with the exception of \c \. The backslash + * retains its special meaning only when followed by \c " or \c \. + * * The words are passed to OutputIterator \a result_r. * * \see \ref splitEscaped @@ -414,10 +509,10 @@ namespace zypp * \code * example splitted strings * normal line -> 2 elements ( "normal", "line" ) - * escaped\ line -> 1 element( "escaped line" ) + * escaped\ line -> 1 element(escaped line) * "quoted line" -> 1 element same as above * 'quoted line' -> 1 element same as above - * "escaped quote\'" -> 1 element ( "escaped quote'" ) + * "escaped quote\"" -> 1 element (escaped quote") * * \param line_r The string to parse. * \param result_r @@ -455,97 +550,93 @@ namespace zypp } // after the leading sepchars + enum class Quote { None, Slash, Single, Double, DoubleSlash }; + std::vector buf; + Quote quoting = Quote::None; for ( beg = cur; *beg; beg = cur, ++result_r, ++ret ) - { - if ( *cur == '"' || *cur == '\'' ) - { - char closeChar = *cur; - ++cur; - bool cont = true; - while (cont) - { - while ( *cur && *cur != closeChar) - ++cur; - if ( *cur == '\0' ) - { - return ret; //TODO parsing exception no closing quote - } - int escCount = 0; - const char * esc = cur-1; - while ( esc != beg && *esc == '\\' ) - { - escCount++; - --esc; - } - cont = (escCount % 2 == 1); // find some non escaped escape char - cur++; //skip quote - } - - std::string s( beg+1, cur-beg-2 ); //without quotes - //transform escaped escape - replaceAll( s, "\\\\", "\\" ); - //transform escaped quotes (only same as open - char tmpn[2] = { closeChar, 0 }; - char tmpo[3] = { '\\', closeChar, 0 }; - replaceAll( s, tmpo, tmpn ); - - *result_r = s; - } - else - { - // skip non sepchars - while( *cur && !::strchr( sepchars_r, *cur ) ) - { - //ignore char after backslash - if ( *cur == '\\' ) - { - ++cur; - } - ++cur; - } - // build string - std::string s( beg, cur-beg ); - //transform escaped escape - replaceAll( s, "\\\\", "\\" ); - - const char *delimeter = sepchars_r; - while ( *delimeter ) - { - std::string ds("\\"); - const char tmp[2] = { *delimeter, '\0' }; - std::string del(tmp); - ds+= del; - replaceAll( s, ds, del ); - ++delimeter; - } - - *result_r = s; - } - // skip sepchars - if ( *cur && ::strchr( sepchars_r, *cur ) ) - ++cur; - while ( *cur && ::strchr( sepchars_r, *cur ) ) - { - ++cur; - if (withEmpty) - { - *result_r = ""; - ++ret; - } - } - // the last was a separator => one more field - if ( !*cur && withEmpty && ::strchr( sepchars_r, *(cur-1) ) ) - { - *result_r = ""; - ++ret; - } - } + { + // read next value until unquoted sepchar + buf.clear(); + quoting = Quote::None; + do { + switch ( quoting ) + { + case Quote::None: + switch ( *cur ) + { + case '\\': quoting = Quote::Slash; break; + case '\'': quoting = Quote::Single; break; + case '"': quoting = Quote::Double; break; + default: buf.push_back( *cur ); break; + } + break; + + case Quote::Slash: + buf.push_back( *cur ); + quoting = Quote::None; + break; + + case Quote::Single: + switch ( *cur ) + { + case '\'': quoting = Quote::None; break; + default: buf.push_back( *cur ); break; + } + break; + + case Quote::Double: + switch ( *cur ) + { + case '\"': quoting = Quote::None; break; + case '\\': quoting = Quote::DoubleSlash; break; + default: buf.push_back( *cur ); break; + } + break; + + case Quote::DoubleSlash: + switch ( *cur ) + { + case '\"': /*fallthrough*/ + case '\\': buf.push_back( *cur ); break; + default: + buf.push_back( '\\' ); + buf.push_back( *cur ); + break; + } + quoting = Quote::Double; + break; + } + ++cur; + } while ( *cur && ( quoting != Quote::None || !::strchr( sepchars_r, *cur ) ) ); + *result_r = std::string( buf.begin(), buf.end() ); + + + // skip sepchars + if ( *cur && ::strchr( sepchars_r, *cur ) ) + ++cur; + while ( *cur && ::strchr( sepchars_r, *cur ) ) + { + ++cur; + if (withEmpty) + { + *result_r = ""; + ++ret; + } + } + // the last was a separator => one more field + if ( !*cur && withEmpty && ::strchr( sepchars_r, *(cur-1) ) ) + { + *result_r = ""; + ++ret; + } + } return ret; } /** Split \a line_r into fields. * Any single character in \a sepchars_r is treated as a - * field separator. The words are passed to OutputIterator + * field separator unless \-escaped. The words are passed + * to OutputIterator. * \a result_r. * \code * "" -> words 0 @@ -575,7 +666,11 @@ namespace zypp { // skip non sepchars while( *cur && !::strchr( sepchars_r, *cur ) ) + { + if ( *cur == '\\' && *(cur+1) ) + ++cur; ++cur; + } // build string *result_r = std::string( beg, cur-beg ); ++ret; @@ -681,6 +776,78 @@ namespace zypp //@} + /////////////////////////////////////////////////////////////////// + /** \name Indent. */ + //@{ + /** Indent by string [" "] optionally wrap. + * Prints nothing for an empty string. Asserts a trainling '\n' on + * the last line. Optionally wrap lines at ' ' at a given length. + */ + inline std::ostream & printIndented( std::ostream & str, const std::string & text_r, const std::string & indent_r = " ", unsigned maxWitdh_r = 0 ) + { + if ( maxWitdh_r ) + { + if ( indent_r.size() >= maxWitdh_r ) + maxWitdh_r = 0; // nonsense: indent larger than line witdh + else + maxWitdh_r -= indent_r.size(); + } + unsigned width = 0; + for ( const char * e = text_r.c_str(), * s = e; *e; s = ++e ) + { + for ( ; *e && *e != '\n'; ++e ) ;/*searching*/ + width = e-s; + if ( maxWitdh_r && width > maxWitdh_r ) + { + // must break line + width = maxWitdh_r; + for ( e = s+width; e > s && *e != ' '; --e ) ;/*searching*/ + if ( e > s ) + width = e-s; // on a ' ', replaced by '\n' + else + e = s+width-1; // cut line; + } + str << indent_r; + str.write( s, width ); + str << "\n"; + if ( !*e ) // on '\0' + break; + } + return str; + } + /** \overload Indent by number of chars [' '] optionally wrap. */ + inline std::ostream & printIndented( std::ostream & str, const std::string & text_r, unsigned indent_r, char indentch_r = ' ', unsigned maxWitdh_r = 0 ) + { return printIndented( str, text_r, std::string( indent_r, indentch_r ), maxWitdh_r ); } + /** \overload Indent by number of chars [' '] wrap. */ + inline std::ostream & printIndented( std::ostream & str, const std::string & text_r, unsigned indent_r, unsigned maxWitdh_r, char indentch_r = ' ' ) + { return printIndented( str, text_r, std::string( indent_r, indentch_r ), maxWitdh_r ); } + + /** Prefix lines by string computed by function taking line begin/end [std::string(const char*, const char*)] + * Prints nothing for an empty string. Asserts a trainling '\n' on the last line. + */ + inline std::ostream & autoPrefix( std::ostream & str, const std::string & text_r, function fnc_r ) + { + for ( const char * e = text_r.c_str(); *e; ++e ) + { + const char * s = e; + for ( ; *e && *e != '\n'; ++e ) /*searching*/; + str << fnc_r( s, e ); + str.write( s, e-s ); + str << "\n"; + if ( !*e ) // on '\0' + break; + } + return str; + } + /** \overload Prefix lines by string generated by function [std::string()] */ + inline std::ostream & autoPrefix0( std::ostream & str, const std::string & text_r, function fnc_r ) + { + auto wrap = [&fnc_r]( const char*, const char* )-> std::string { + return fnc_r(); + }; + return autoPrefix( str, text_r, wrap ); + } + //@} /////////////////////////////////////////////////////////////////// /** \name Escape. */ //@{ @@ -780,9 +947,9 @@ namespace zypp { return trim( s, R_TRIM ); } //@} - std::string stripFirstWord( std::string & line, const bool ltrim_first ); + std::string stripFirstWord( std::string & line, const bool ltrim_first = true ); - std::string stripLastWord( std::string & line, const bool rtrim_first ); + std::string stripLastWord( std::string & line, const bool rtrim_first = true ); /** Return stream content up to (but not returning) the next newline. * \see \ref receiveUpTo @@ -845,10 +1012,12 @@ namespace zypp inline bool endsWith( const C_Str & str_r, const C_Str & prefix_r ) { return hasSuffix( str_r, prefix_r ); } //@} - ///////////////////////////////////////////////////////////////// } // namespace str /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////// + + // drag into zypp:: namespace + using str::asString; + } // namespace zypp /////////////////////////////////////////////////////////////////// #endif // ZYPP_BASE_STRING_H diff --git a/libzypp/zypp/base/Sysconfig.cc b/libzypp/zypp/base/Sysconfig.cc index 253c44d..0d11ec4 100644 --- a/libzypp/zypp/base/Sysconfig.cc +++ b/libzypp/zypp/base/Sysconfig.cc @@ -15,7 +15,12 @@ #include "zypp/base/Logger.h" #include "zypp/base/String.h" +#include "zypp/base/StrMatcher.h" +#include "zypp/base/IOStream.h" +#include "zypp/base/InputStream.h" #include "zypp/Pathname.h" +#include "zypp/PathInfo.h" +#include "zypp/TmpPath.h" #include "zypp/base/Sysconfig.h" @@ -24,13 +29,13 @@ using namespace zypp::base; namespace zypp { namespace base { - namespace sysconfig { + map read( const Pathname & _path ) { DBG << "Load '" << _path << "'" << endl; map ret; - + string line; ifstream in( _path.asString().c_str() ); if ( in.fail() ) { @@ -68,10 +73,83 @@ namespace zypp { } // not comment } // while getline - MIL << "done reading '" << _path << "'" << endl; + MIL << "done reading '" << _path << "'" << endl; return ret; } + bool write( const Pathname & path_r, const std::string & key_r, const std::string & val_r, const std::string & newcomment_r ) + { + if ( key_r.empty() ) + { + WAR << "Empty key in write " << path_r << endl; + return false; + } + + PathInfo pi( path_r ); + if ( ! pi.isFile() ) + ZYPP_THROW( Exception( str::Str() << path_r << ": " << Errno(ENOENT) ) ); + if ( ! pi.userMayRW() ) + ZYPP_THROW( Exception( str::Str() << path_r << ": " << Errno(EACCES) ) ); + + bool found = false; + filesystem::TmpFile tmpf( filesystem::TmpFile::makeSibling( path_r ) ); + { + StrMatcher matches( "^[ \t]*"+key_r+"[ \t]*=", Match::REGEX ); + std::ofstream o( tmpf.path().c_str() ); + iostr::forEachLine( InputStream( path_r ), + [&]( int num_r, std::string line_r )->bool + { + if ( !found && matches( line_r ) ) + { + o << key_r << '=' << val_r << endl; + found = true; + MIL << path_r << ": " << key_r << '=' << val_r << " changed on line " << num_r << endl; + } + else + o << line_r << endl; + return true; + } ); + if ( !found ) + { + if ( newcomment_r.empty() ) + { + WAR << path_r << ": " << key_r << '=' << val_r << " can not be added (no comment provided)." << endl; + } + else + { + std::vector lines; + str::split( newcomment_r, std::back_inserter(lines), "\r\n" ); + o << endl; + for ( auto line : lines ) + { + if ( line[0] != '#' ) + o << "# "; + o << line << endl; + } + o << key_r << '=' << val_r << endl; + found = true; + MIL << path_r << ": " << key_r << '=' << val_r << " appended. " << endl; + } + } + + if ( ! o ) + ZYPP_THROW( Exception( str::Str() << tmpf.path() << ": " << Errno(EIO) ) ); + } + + // If everything is fine, exchange the files: + int res = exchange( tmpf.path(), path_r ); + if ( res ) + { + ZYPP_THROW( Exception( str::Str() << tmpf.path() << ": " << Errno(res) ) ); + } + return found; + } + + bool writeStringVal( const Pathname & path_r, const std::string & key_r, const std::string & val_r, const std::string & newcomment_r ) + { + return write( path_r, key_r, str::Str() << '"' << str::escape( val_r, '"' )<< '"', newcomment_r ); + } + } // namespace sysconfig } // namespace base } // namespace zypp diff --git a/libzypp/zypp/base/Sysconfig.h b/libzypp/zypp/base/Sysconfig.h index 5d511dc..c9ae7cb 100644 --- a/libzypp/zypp/base/Sysconfig.h +++ b/libzypp/zypp/base/Sysconfig.h @@ -20,8 +20,51 @@ namespace zypp { namespace base { namespace sysconfig { + /** Read sysconfig file \a path_r and return (key,valye) pairs. */ std::map read( const Pathname & _path ); + /** Add or change a value in sysconfig file \a path_r. + * + * If \a key_r already exists, only the \a val_r is changed accordingly. + * + * In case \a key_r is not yet present in the file, a new entry may be created + * at the end of the file, using the lines in \a newcomment_r as comment + * block. If \a newcomment_r is not provided or empty, a new value is not + * created and \c false is returned. + * + * \returns \c TRUE if an entry was changed or created. + * + * \throws Exception if \a path_r can not be read or written. + * + * \note \a val_r is written as it is. The caller is responsible for escaping and + * enclosing in '"', in case this is needed (\see \ref writeStringVal and \ref str::escape). + * + * \note Lines in \a newcomment_r which do not already start with a '#', + * are prefixes with "# ". + * + * \code + * ## Type: string + * ## Default: "" + * # + * # A multiline description of + * # the options purpose. + * # + * KEY="value" + * \endcode + */ + bool write( const Pathname & path_r, const std::string & key_r, const std::string & val_r, + const std::string & newcomment_r = std::string() ); + + /** Convenience to add or change a string-value in sysconfig file \a path_r. + * + * \a val_r is expected to be a plain string value, so it is propery escaped and enclosed in + * double quotes before it is written to the sysconfig file \a path_r. + * + * \see \ref write + */ + bool writeStringVal( const Pathname & path_r, const std::string & key_r, const std::string & val_r, + const std::string & newcomment_r = std::string() ); + } // namespace sysconfig } // namespace base } // namespace zypp diff --git a/libzypp/zypp/base/Xml.h b/libzypp/zypp/base/Xml.h new file mode 100644 index 0000000..717a9f3 --- /dev/null +++ b/libzypp/zypp/base/Xml.h @@ -0,0 +1,196 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/base/Xml.h + * +*/ +#ifndef ZYPP_BASE_XML_H +#define ZYPP_BASE_XML_H + +#include +#include +#include +#include +#include +#include + +#include "zypp/base/Easy.h" +#include "zypp/base/String.h" +#include "zypp/parser/xml/XmlEscape.h" + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + /////////////////////////////////////////////////////////////////// + namespace xmlout + { + using xml::escape; + using xml::unescape; + + /** \relates NodeAttr NODE ATTRIBUTE representation of types [asString] */ + template + std::string asXmlNodeAttr( const _Tp & val_r ) + { return asString( val_r ); } + + /////////////////////////////////////////////////////////////////// + /// \class NodeAttr + /// \brief (Key, Value) string pair of XML node attributes + struct NodeAttr : public std::pair + { + typedef std::pair Pair; + + template + NodeAttr( std::string key_r, const _Type & val_r ) + : Pair( std::move(key_r), asXmlNodeAttr(val_r) ) + {} + + NodeAttr( std::string key_r, std::string val_r ) + : Pair( std::move(key_r), std::move(val_r) ) + {} + }; + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + /// \class Node + /// \brief RAII writing a nodes start/end tag + /// \code + /// { + /// Node node( std::cout, "node", { "attr", "val" } ); // + /// *node << "write nodes body...." + /// } // + /// \endcode + /// \note If the \ref optionalContent flag is passed to the \c ctor, the start + /// node is kept open, until the first call to \ref operator*. The start node + /// is closed before returning the stream. + /// \code + /// { + /// Node node( std::cout, "node", Node::optionalContent, { "attr", "val" } ); + /// // + /// { + /// Node node( std::cout, "node", Node::optionalContent, { "attr", "val" } ); + /// // write nodes body... + /// } // + /// \endcode + /// + /// \note If the nodename is empty or starts with an \c !, a comment is written. + /// + struct Node + { + NON_COPYABLE_BUT_MOVE( Node ); + typedef NodeAttr Attr; + + struct OptionalContentType {}; ///< Ctor arg type + static constexpr OptionalContentType optionalContent = OptionalContentType(); + + /** Ctor taking nodename and attribute list */ + Node( std::ostream & out_r, std::string name_r, const std::initializer_list & attrs_r = {} ) + : _out( out_r ), _name( std::move(name_r) ), _hasContent( true ) + { printStart( attrs_r ); } + + /** Convenience ctor for one attribute pair */ + Node( std::ostream & out_r, std::string name_r, Attr attr_r ) + : Node( out_r, std::move(name_r), { attr_r } ) + {} + + /** Optional content ctor taking nodename and attribute list */ + Node( std::ostream & out_r, std::string name_r, OptionalContentType, const std::initializer_list & attrs_r = {} ) + : _out( out_r ), _name( std::move(name_r) ), _hasContent( false ) + { printStart( attrs_r ); } + + /** Optional content Convenience ctor for one attribute pair */ + Node( std::ostream & out_r, std::string name_r, OptionalContentType, Attr attr_r ) + : Node( out_r, std::move(name_r), optionalContent, { attr_r } ) + {} + + /** Dtor wrting end tag */ + ~Node() + { + if ( _name.empty() ) + _out << "-->"; + else + { + if ( _hasContent ) + _out << ""; + else + _out << "/>"; + } + } + + /** Return the output stream */ + std::ostream & operator*() + { + if ( ! _hasContent ) + { + _hasContent = true; + if ( _name.empty() ) + _out << "|"; + else + _out << ">"; + } + return _out; + } + + private: + void printStart( const std::initializer_list & attrs_r ) + { + if ( _name.empty() || _name[0] == '!' ) + { + _out << " nothing to do - - // These are all installed packages obsoleted by any package to be installed. - // Actually we expect all of them to appear in the deleteList_r, and we want - // to kick them out. Rpm will delete them when the obsoleter gets installed. - sat::WhatObsoletes obsoleted( instlist_r.begin(), instlist_r.end() ); - for_( it, obsoleted.poolItemBegin(), obsoleted.poolItemEnd() ) - { - DBG << "Ignore appl_delete (should be obsoleted): " << *it << endl; - deleteList_r.remove( *it ); - } - - MIL << "Undelayed deletes: " << deleteList_r << endl; - } - - /////////////////////////////////////////////////////////////////// - // - // METHOD NAME : GetResolvablesToInsDel::GetResolvablesToInsDel - // METHOD TYPE : Ctor - // - GetResolvablesToInsDel::GetResolvablesToInsDel( ResPool pool_r, Order order_r ) - { - zypp::base::LogControl::TmpLineWriter shutUp; - typedef std::set PoolItemSet; - - PoolItemList & dellist_r( _toDelete ); - PoolItemList & instlist_r( _toInstall ); - PoolItemList & srclist_r( _toSrcinstall ); - - for ( ResPool::const_iterator it = pool_r.begin(); it != pool_r.end(); ++it ) - { - if (it->status().isToBeInstalled()) - { - if ((*it)->kind() == ResKind::srcpackage) { - srclist_r.push_back( *it ); - } - else - instlist_r.push_back( *it ); - } - else if (it->status().isToBeUninstalled()) - { - if ( it->status().isToBeUninstalledDueToObsolete() ) - { - DBG << "Ignore auto_delete (should be obsoleted): " << *it << endl; - } - else if ( it->status().isToBeUninstalledDueToUpgrade() ) - { - DBG << "Ignore auto_delete (should be upgraded): " << *it << endl; - } - else { - dellist_r.push_back( *it ); - } - } - } - - MIL << "ResolvablesToInsDel: delete " << dellist_r.size() - << ", install " << instlist_r.size() - << ", srcinstall " << srclist_r.size() << endl; - - /////////////////////////////////////////////////////////////////// - // - // strip packages to_delete which get obsoleted by - // to_install (i.e. delay deletion in case the - // obsoleting package likes to save whatever... - // - /////////////////////////////////////////////////////////////////// - strip_obsoleted_to_delete( dellist_r, instlist_r ); - - if ( dellist_r.size() ) { - /////////////////////////////////////////////////////////////////// - // - // sort delete list... - // - /////////////////////////////////////////////////////////////////// - PoolItemSet delset( dellist_r.begin(), dellist_r.end() ); // for delete order - PoolItemSet dummy; // dummy, empty, should contain already installed - - InstallOrder order( pool_r, delset, dummy ); // sort according top prereq - order.init(); - const PoolItemList dsorted( order.getTopSorted() ); - - dellist_r.clear(); - for ( PoolItemList::const_reverse_iterator cit = dsorted.rbegin(); - cit != dsorted.rend(); ++cit ) - { - dellist_r.push_back( *cit ); - } - } - - /////////////////////////////////////////////////////////////////// - // - // sort installed list... - // - /////////////////////////////////////////////////////////////////// - if ( instlist_r.empty() ) - return; - - /////////////////////////////////////////////////////////////////// - // Compute install order according to packages prereq. - // Try to group packages with respect to the desired install order - /////////////////////////////////////////////////////////////////// - // backup list for debug purpose. - // You can as well build the set, clear the list and rebuild it in install order. - PoolItemList instbackup_r; - instbackup_r.swap( instlist_r ); - - PoolItemSet insset( instbackup_r.begin(), instbackup_r.end() ); // for install order - PoolItemSet installed; // dummy, empty, should contain already installed - - InstallOrder order( pool_r, insset, installed ); - // start recursive depth-first-search - order.init(); - MIL << "order.init() done" << endl; - order.printAdj( XXX, false ); - /////////////////////////////////////////////////////////////////// - // build install list in install order - /////////////////////////////////////////////////////////////////// - PoolItemList best_list; - sat::detail::RepoIdType best_prio = 0; - unsigned best_medianum = 0; - - PoolItemList last_list; - sat::detail::RepoIdType last_prio = 0; - unsigned last_medianum = 0; - - PoolItemList other_list; - - for ( PoolItemList items = order.computeNextSet(); ! items.empty(); items = order.computeNextSet() ) - { - XXX << "order.computeNextSet: " << items.size() << " resolvables" << endl; - /////////////////////////////////////////////////////////////////// - // items contains all objects we could install now. Pick all objects - // from current media, or best media if none for current. Alwayys pick - // objects that do not require media access. - /////////////////////////////////////////////////////////////////// - - best_list.clear(); - last_list.clear(); - other_list.clear(); - - for ( PoolItemList::iterator cit = items.begin(); cit != items.end(); ++cit ) - { - ResObject::constPtr cobj( cit->resolvable() ); - if (!cobj) - continue; - - if ( ! cobj->mediaNr() ) { - XXX << "No media access required for " << *cit << endl; - order.setInstalled( *cit ); - other_list.push_back( *cit ); - continue; - } - - if ( cobj->satSolvable().repository().id() == last_prio && - cobj->mediaNr() == last_medianum ) { - // prefer packages on current media. - XXX << "Stay with current media " << *cit << endl; - last_list.push_back( *cit ); - continue; - } - - if ( last_list.empty() ) { - // check for best media as long as there are no packages for current media. - - if ( ! best_list.empty() ) { - - if ( order_r == ORDER_BY_MEDIANR ) - { - if ( cobj->mediaNr() < best_medianum ) { - best_list.clear(); // new best - } else if ( cobj->mediaNr() == best_medianum ) { - if ( cobj->satSolvable().repository().id() < best_prio ) { - best_list.clear(); // new best - } else if ( cobj->satSolvable().repository().id() == best_prio ) { - XXX << "Add to best list " << *cit << endl; - best_list.push_back( *cit ); // same as best -> add - continue; - } else { - continue; // worse - } - } else { - continue; // worse - } - } - else // default: ORDER_BY_SOURCE - { - if ( cobj->satSolvable().repository().id() < best_prio ) { - best_list.clear(); // new best - } else if ( cobj->satSolvable().repository().id() == best_prio ) { - if ( cobj->mediaNr() < best_medianum ) { - best_list.clear(); // new best - } else if ( cobj->mediaNr() == best_medianum ) { - XXX << "Add to best list " << *cit << endl; - best_list.push_back( *cit ); // same as best -> add - continue; - } else { - continue; // worse - } - } else { - continue; // worse - } - } - } - - if ( best_list.empty() ) - { - XXX << "NEW BEST LIST [S" << cobj->satSolvable().repository().id() << ":" << cobj->mediaNr() - << "] (last [S" << best_prio << ":" << best_medianum << "])" << endl; - best_prio = cobj->satSolvable().repository().id(); - best_medianum = cobj->mediaNr(); - // first package or new best - XXX << "Add to best list " << *cit << endl; - best_list.push_back( *cit ); - continue; - } - } - - } // for all objects in current set - - /////////////////////////////////////////////////////////////////// - // remove objects picked from install order and append them to - // install list. - /////////////////////////////////////////////////////////////////// - PoolItemList & take_list( last_list.empty() ? best_list : last_list ); - if ( last_list.empty() ) - { - MIL << "SET NEW media [S" << best_prio << ":" << best_medianum << "]" << endl; - last_prio = best_prio; - last_medianum = best_medianum; - } - else - { - XXX << "SET CONTINUE [S" << best_prio << ":" << best_medianum << "]" << endl; - } - - for ( PoolItemList::iterator it = take_list.begin(); it != take_list.end(); ++it ) - { - order.setInstalled( *it ); - XXX << "SET collect " << (*it) << endl; - } - // move everthing from take_list to the end of instlist_r, clean take_list - instlist_r.splice( instlist_r.end(), take_list ); - // same for other_list - instlist_r.splice( instlist_r.end(), other_list ); - - } // for all sets computed - - - MIL << "order done" << endl; - if ( instbackup_r.size() != instlist_r.size() ) - { - ERR << "***************** Lost packages in InstallOrder sort." << endl; - } - - } - - void GetResolvablesToInsDel::debugDiffTransaction() const - { - SEC << "START debugDiffTransaction" << endl; - sat::Transaction trans( ResPool::instance().resolver().getTransaction() ); - - { - const PoolItemList & clist( _toDelete ); - for_( it, clist.begin(), clist.end() ) - { - sat::Transaction::const_iterator ci( trans.find( *it ) ); - if ( ci == trans.end() ) - ERR << "Missing to del in NEW trans: " << *it << endl; - } - } - { - const PoolItemList & clist( _toInstall ); - for_( it, clist.begin(), clist.end() ) - { - sat::Transaction::const_iterator ci( trans.find( *it ) ); - if ( ci == trans.end() ) - ERR << "Missing to ins in NEW trans: " << *it << endl; - } - } - { - const PoolItemList & clist( _toSrcinstall ); - for_( it, clist.begin(), clist.end() ) - { - sat::Transaction::const_iterator ci( trans.find( *it ) ); - if ( ci == trans.end() ) - ERR << "Missing srcins in NEW trans: " << *it << endl; - } - } - - SEC << "END debugDiffTransaction" << endl; - } - - /****************************************************************** - ** - ** FUNCTION NAME : operator<< - ** FUNCTION TYPE : std::ostream & - */ - std::ostream & operator<<( std::ostream & str, const GetResolvablesToInsDel & obj ) - { - dumpPoolStats( str << "toInstall: " << endl, - obj._toInstall.begin(), obj._toInstall.end() ) << endl; - dumpPoolStats( str << "toDelete: " << endl, - obj._toDelete.begin(), obj._toDelete.end() ) << endl; - return str; - } - - ///////////////////////////////////////////////////////////////// - } // namespace pool - /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////// -} // namespace zypp -/////////////////////////////////////////////////////////////////// - diff --git a/libzypp/zypp/pool/GetResolvablesToInsDel.h b/libzypp/zypp/pool/GetResolvablesToInsDel.h deleted file mode 100644 index 5c184f7..0000000 --- a/libzypp/zypp/pool/GetResolvablesToInsDel.h +++ /dev/null @@ -1,74 +0,0 @@ -/*---------------------------------------------------------------------\ -| ____ _ __ __ ___ | -| |__ / \ / / . \ . \ | -| / / \ V /| _/ _/ | -| / /__ | | | | | | | -| /_____||_| |_| |_| | -| | -\---------------------------------------------------------------------*/ -/** \file zypp/pool/GetResolvablesToInsDel.h - * -*/ -#ifndef ZYPP_POOL_GETRESOLVABLESTOINSDEL_H -#define ZYPP_POOL_GETRESOLVABLESTOINSDEL_H - -#include -#include - -#include "zypp/ResPool.h" -#include "zypp/APIConfig.h" - -/////////////////////////////////////////////////////////////////// -namespace zypp -{ ///////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////// - namespace pool - { ///////////////////////////////////////////////////////////////// - - /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : GetResolvablesToInsDel - // - /** Collect transacting items and sort according to prereqs and - * media access. - * - * \deprecated Use class \ref sat::Transaction which does a better job - * esp. when packages are to be deleted. - */ - struct ZYPP_DEPRECATED GetResolvablesToInsDel - { - typedef std::list PoolItemList; - - /** Influences the sequence of sources and media proscessed. - * If true prefer a better source, otherwise a better media. - * \code - * ORDER_BY_SOURCE: [S1:1], [S1:2], ... , [S2:1], [S2:2], ... - * ORDER_BY_MEDIANR: [S1:1], [S2:1], ... , [S1:2], [S2:2], ... - * \endcode - */ - enum Order { ORDER_BY_SOURCE, ORDER_BY_MEDIANR }; - - /** */ - GetResolvablesToInsDel( ResPool pool_r, - Order order_r = ORDER_BY_SOURCE ); - - /** Diff with new style \ref Transacrion and write result to log. */ - void debugDiffTransaction() const; - - PoolItemList _toDelete; - PoolItemList _toInstall; - PoolItemList _toSrcinstall; - }; - /////////////////////////////////////////////////////////////////// - - /** \relates GetResolvablesToInsDel Stream output */ - std::ostream & operator<<( std::ostream & str, const GetResolvablesToInsDel & obj ); - - ///////////////////////////////////////////////////////////////// - } // namespace pool - /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////// -} // namespace zypp -/////////////////////////////////////////////////////////////////// -#endif // ZYPP_POOL_GETRESOLVABLESTOINSDEL_H - diff --git a/libzypp/zypp/pool/PoolImpl.h b/libzypp/zypp/pool/PoolImpl.h index e3d1365..9c0aeb5 100644 --- a/libzypp/zypp/pool/PoolImpl.h +++ b/libzypp/zypp/pool/PoolImpl.h @@ -298,71 +298,6 @@ namespace zypp return setChanged; } - public: - typedef PoolTraits::AutoSoftLocks AutoSoftLocks; - typedef PoolTraits::autoSoftLocks_iterator autoSoftLocks_iterator; - - const AutoSoftLocks & autoSoftLocks() const - { return _autoSoftLocks; } - - bool autoSoftLockAppliesTo( sat::Solvable solv_r ) const - { return( _autoSoftLocks.find( solv_r.ident() ) != _autoSoftLocks.end() ); } - - void setAutoSoftLocks( const AutoSoftLocks & newLocks_r ) - { - MIL << "Apply " << newLocks_r.size() << " AutoSoftLocks: " << newLocks_r << endl; - _autoSoftLocks = newLocks_r; - // now adjust the pool status - for_( it, begin(), end() ) - { - if ( ! it->status().isKept() ) - continue; - - if ( autoSoftLockAppliesTo( it->satSolvable() ) ) - it->status().setSoftLock( ResStatus::USER ); - else - it->status().resetTransact( ResStatus::USER ); - } - } - - void getActiveSoftLocks( AutoSoftLocks & activeLocks_r ) - { - activeLocks_r = _autoSoftLocks; // current soft-locks - AutoSoftLocks todel; // + names to be deleted - AutoSoftLocks toins; // - names to be installed - - for_( it, begin(), end() ) - { - ResStatus & status( it->status() ); - if ( ! ( status.isByUser() || status.isByApplLow() ) ) - continue; // ignore non-user requests; ApplLow means selected - // by solver, but on behalf of a user request. - - switch ( status.getTransactValue() ) - { - case ResStatus::KEEP_STATE: - // Filter only items included in the last recommended set. - if ( status.isRecommended() ) - activeLocks_r.insert( it->satSolvable().ident() ); - break; - case ResStatus::LOCKED: - // NOOP - break; - case ResStatus::TRANSACT: - (status.isInstalled() ? todel : toins).insert( it->satSolvable().ident() ); - break; - } - } - for_( it, todel.begin(), todel.end() ) - { - activeLocks_r.insert( *it ); - } - for_( it, toins.begin(), toins.end() ) - { - activeLocks_r.erase( *it ); - } - } - public: const ContainerT & store() const { @@ -373,10 +308,7 @@ namespace zypp bool addedItems = false; std::list addedProducts; - if ( pool.capacity() != _store.capacity() ) - { - _store.resize( pool.capacity() ); - } + _store.resize( pool.capacity() ); if ( pool.capacity() ) { @@ -396,11 +328,6 @@ namespace zypp // remember products for buddy processing (requires clean store) if ( s.isKind( ResKind::product ) ) addedProducts.push_back( pi ); - // and on the fly check for weak locks... - if ( autoSoftLockAppliesTo( s ) ) - { - pi.status().setSoftLock( ResStatus::USER ); - } if ( !addedItems ) addedItems = true; } @@ -480,8 +407,6 @@ namespace zypp mutable shared_ptr _poolProxy; private: - /** Set of solvable idents that should be soft locked per default. */ - AutoSoftLocks _autoSoftLocks; /** Set of queries that define hardlocks. */ HardLockQueries _hardLockQueries; }; diff --git a/libzypp/zypp/pool/PoolTraits.h b/libzypp/zypp/pool/PoolTraits.h index 37b96b7..5b2770b 100644 --- a/libzypp/zypp/pool/PoolTraits.h +++ b/libzypp/zypp/pool/PoolTraits.h @@ -40,7 +40,7 @@ namespace zypp struct ByPoolItem { bool operator()( const PoolItem & pi ) const - { return pi; } + { return bool(pi); } }; /** In CXX0X std::_Select2nd does no longer derive from std::unary_function @@ -84,10 +84,6 @@ namespace zypp /** list of known Repositories */ typedef sat::Pool::RepositoryIterator repository_iterator; - /** soft locks */ - typedef std::tr1::unordered_set AutoSoftLocks; - typedef AutoSoftLocks::const_iterator autoSoftLocks_iterator; - /** hard locks from etc/zypp/locks */ typedef std::list HardLockQueries; typedef HardLockQueries::const_iterator hardLockQueries_iterator; diff --git a/libzypp/zypp/repo/Downloader.cc b/libzypp/zypp/repo/Downloader.cc index 319e86d..2bf752c 100644 --- a/libzypp/zypp/repo/Downloader.cc +++ b/libzypp/zypp/repo/Downloader.cc @@ -10,13 +10,11 @@ #include #include "zypp/base/String.h" #include "zypp/base/Logger.h" -#include "zypp/base/Function.h" - -#include "zypp/Date.h" +#include "zypp/base/Gettext.h" #include "Downloader.h" -#include "zypp/repo/MediaInfoDownloader.h" -#include "zypp/base/UserRequestException.h" +#include "zypp/KeyContext.h" +#include "zypp/ZYppCallbacks.h" using namespace std; @@ -29,7 +27,7 @@ Downloader::Downloader() { } Downloader::Downloader(const RepoInfo & repoinfo) : _repoinfo(repoinfo) -{ +{ } Downloader::~Downloader() { @@ -48,6 +46,46 @@ void Downloader::download( MediaSetAccess &media, WAR << "Non implemented" << endl; } +void Downloader::defaultDownloadMasterIndex( MediaSetAccess & media_r, const Pathname & destdir_r, const Pathname & masterIndex_r ) +{ + Pathname sigpath = masterIndex_r.extend( ".asc" ); + Pathname keypath = masterIndex_r.extend( ".key" ); + + SignatureFileChecker sigchecker; + + enqueue( OnMediaLocation( sigpath, 1 ).setOptional( true ) ); + start( destdir_r, media_r ); + reset(); + + // only add the signature if it exists + if ( PathInfo(destdir_r / sigpath).isExist() ) + sigchecker = SignatureFileChecker( destdir_r / sigpath ); + + enqueue( OnMediaLocation( keypath, 1 ).setOptional( true ) ); + start( destdir_r, media_r ); + reset(); + + KeyContext context; + context.setRepoInfo( repoInfo() ); + // only add the key if it exists + if ( PathInfo(destdir_r / keypath).isExist() ) + sigchecker.addPublicKey( destdir_r / keypath, context ); + else + // set the checker context even if the key is not known (unsigned repo, key + // file missing; bnc #495977) + sigchecker.setKeyContext( context ); + + if ( ! repoInfo().gpgCheck() ) + { + WAR << "Signature checking disabled in config of repository " << repoInfo().alias() << endl; + } + enqueue( OnMediaLocation( masterIndex_r, 1 ), + repoInfo().gpgCheck() ? FileChecker(sigchecker) : FileChecker(NullFileChecker()) ); + start( destdir_r, media_r ); + reset(); +} + + }// ns repo } // ns zypp diff --git a/libzypp/zypp/repo/Downloader.h b/libzypp/zypp/repo/Downloader.h index ff4cf07..64c6a41 100644 --- a/libzypp/zypp/repo/Downloader.h +++ b/libzypp/zypp/repo/Downloader.h @@ -25,7 +25,7 @@ namespace zypp /** * \short Downloader base class * - * a Downloader encapsulates all the knowledge of + * a Downloader encapsulates all the knowledge of * which files have to be downloaded to the local disk. * */ @@ -57,6 +57,10 @@ namespace zypp const RepoInfo & repoInfo() const { return _repoinfo; } + protected: + /** Common workflow downloading a (signed) master index file */ + void defaultDownloadMasterIndex( MediaSetAccess & media_r, const Pathname & destdir_r, const Pathname & masterIndex_r ); + private: RepoInfo _repoinfo; }; diff --git a/libzypp/zypp/repo/PackageProvider.cc b/libzypp/zypp/repo/PackageProvider.cc index 8d5a5bf..0557284 100644 --- a/libzypp/zypp/repo/PackageProvider.cc +++ b/libzypp/zypp/repo/PackageProvider.cc @@ -10,6 +10,7 @@ * */ #include +#include #include #include "zypp/repo/PackageDelta.h" #include "zypp/base/Logger.h" @@ -23,6 +24,7 @@ #include "zypp/TmpPath.h" #include "zypp/ZConfig.h" #include "zypp/RepoInfo.h" +#include "zypp/RepoManager.h" using std::endl; @@ -83,19 +85,34 @@ namespace zypp */ ManagedFile providePackage() const; + /** Provide the package if it is cached. */ + ManagedFile providePackageFromCache() const + { + ManagedFile ret( doProvidePackageFromCache() ); + if ( ! ( ret->empty() || _package->repoInfo().keepPackages() ) ) + ret.setDispose( filesystem::unlink ); + return ret; + } + + /** Whether the package is cached. */ + bool isCached() const + { return ! doProvidePackageFromCache()->empty(); } + protected: typedef PackageProvider::Impl Base; typedef callback::SendReport Report; /** Lookup the final rpm in cache. * - * A non empty ManagedFile will be returned to the caller. File disposal - * depending on the repos keepPackages setting are handled in \ref providePackage. + * A non empty ManagedFile will be returned to the caller. + * + * \note File disposal depending on the repos keepPackages setting + * are not set here, but in \ref providePackage or \ref providePackageFromCache. * * \note The provoided default implementation returns an empty ManagedFile * (cache miss). */ - virtual ManagedFile providePackageFromCache() const = 0; + virtual ManagedFile doProvidePackageFromCache() const = 0; /** Actually provide the final rpm. * Report start/problem/finish and retry loop are hadled by \ref providePackage. @@ -174,7 +191,7 @@ namespace zypp /////////////////////////////////////////////////////////////////// /** Default implementation (cache miss). */ - ManagedFile PackageProvider::Impl::providePackageFromCache() const + ManagedFile PackageProvider::Impl::doProvidePackageFromCache() const { return ManagedFile(); } /** Default implementation (provide full package) */ @@ -193,29 +210,54 @@ namespace zypp ManagedFile PackageProvider::Impl::providePackage() const { - Url url; - RepoInfo info = _package->repoInfo(); - // FIXME we only support the first url for now. - if ( info.baseUrlsEmpty() ) - ZYPP_THROW(Exception("No url in repository.")); - else - url = * info.baseUrlsBegin(); + ScopedGuard guardReport( newReport() ); // check for cache hit: ManagedFile ret( providePackageFromCache() ); - if ( ! ret.value().empty() ) + if ( ! ret->empty() ) { - if ( ! info.keepPackages() ) - { - ret.setDispose( filesystem::unlink ); - } MIL << "provided Package from cache " << _package << " at " << ret << endl; + report()->infoInCache( _package, ret ); return ret; // <-- cache hit } - // HERE: cache misss, do download: + // HERE: cache misss, check toplevel cache or do download: + RepoInfo info = _package->repoInfo(); + + // Check toplevel cache + { + RepoManagerOptions topCache; + 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() / 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() / loc.filename() ); + if ( filesystem::assert_dir( dest.dirname() ) == 0 && filesystem::hardlinkCopy( pi.path(), dest ) == 0 ) + { + ret = ManagedFile( dest ); + if ( ! info.keepPackages() ) + ret.setDispose( filesystem::unlink ); + + MIL << "provided Package from toplevel cache " << _package << " at " << ret << endl; + report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() ); + return ret; // <-- toplevel cache hit + } + } + } + } + } + + // FIXME we only support the first url for now. + if ( info.baseUrlsEmpty() ) + ZYPP_THROW(Exception("No url in repository.")); + MIL << "provide Package " << _package << endl; - ScopedGuard guardReport( newReport() ); + Url url = * info.baseUrlsBegin(); do { _retry = false; report()->start( _package, url ); @@ -284,7 +326,7 @@ namespace zypp {} protected: - virtual ManagedFile providePackageFromCache() const; + virtual ManagedFile doProvidePackageFromCache() const; virtual ManagedFile doProvidePackage() const; @@ -304,24 +346,9 @@ namespace zypp }; /////////////////////////////////////////////////////////////////// - ManagedFile RpmPackageProvider::providePackageFromCache() const + ManagedFile RpmPackageProvider::doProvidePackageFromCache() const { - RepoInfo info = _package->repoInfo(); - OnMediaLocation loc( _package->location() ); - PathInfo cachepath( info.packagesPath() / loc.filename() ); - - if ( cachepath.isFile() && ! loc.checksum().empty() ) // accept cache hit with matching checksum only! - // Tempting to do a quick check for matching .rpm-filesize before computing checksum, - // but real life shows that loc.downloadSize() and the .rpm-filesize frequently do not - // match, even if loc.checksum() and the .rpm-files checksum do. Blame the metadata generator(s). - { - CheckSum cachechecksum( loc.checksum().type(), filesystem::checksum( cachepath.path(), loc.checksum().type() ) ); - if ( cachechecksum == loc.checksum() ) - { - return ManagedFile( cachepath.path() ); // <-- cache hit - } - } - return ManagedFile(); // <-- cache miss + return ManagedFile( _package->cachedLocation() ); } ManagedFile RpmPackageProvider::doProvidePackage() const @@ -335,30 +362,23 @@ namespace zypp url = * info.baseUrlsBegin(); // check whether to process patch/delta rpms - if ( url.schemeIsDownloading() || ZConfig::instance().download_use_deltarpm_always() ) - { - std::list deltaRpms; - if ( ZConfig::instance().download_use_deltarpm() ) - { - _deltas.deltaRpms( _package ).swap( deltaRpms ); - } + if ( ZConfig::instance().download_use_deltarpm() + && ( url.schemeIsDownloading() || ZConfig::instance().download_use_deltarpm_always() ) ) + { + std::list deltaRpms; + _deltas.deltaRpms( _package ).swap( deltaRpms ); - if ( ! ( deltaRpms.empty() ) - && queryInstalled() ) - { - if ( ! deltaRpms.empty() && applydeltarpm::haveApplydeltarpm() ) - { - for( std::list::const_iterator it = deltaRpms.begin(); - it != deltaRpms.end(); ++it ) - { - DBG << "tryDelta " << *it << endl; - ManagedFile ret( tryDelta( *it ) ); - if ( ! ret->empty() ) - return ret; - } - } - } - } + if ( ! deltaRpms.empty() && queryInstalled() && applydeltarpm::haveApplydeltarpm() ) + { + for_( it, deltaRpms.begin(), deltaRpms.end()) + { + DBG << "tryDelta " << *it << endl; + ManagedFile ret( tryDelta( *it ) ); + if ( ! ret->empty() ) + return ret; + } + } + } // no patch/delta -> provide full package return Base::doProvidePackage(); @@ -410,7 +430,7 @@ namespace zypp return ManagedFile( destination, filesystem::unlink ); } - +#if 0 /////////////////////////////////////////////////////////////////// /// \class PluginPackageProvider /// \brief Plugin PackageProvider implementation. @@ -430,9 +450,9 @@ namespace zypp {} protected: - virtual ManagedFile providePackageFromCache() const + virtual ManagedFile doProvidePackageFromCache() const { - return Base::providePackageFromCache(); + return Base::doProvidePackageFromCache(); } virtual ManagedFile doProvidePackage() const @@ -441,7 +461,7 @@ namespace zypp } }; /////////////////////////////////////////////////////////////////// - +#endif /////////////////////////////////////////////////////////////////// // class PackageProvider @@ -468,6 +488,11 @@ namespace zypp ManagedFile PackageProvider::providePackage() const { return _pimpl->providePackage(); } + ManagedFile PackageProvider::providePackageFromCache() const + { return _pimpl->providePackageFromCache(); } + + bool PackageProvider::isCached() const + { return _pimpl->isCached(); } } // namespace repo /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/repo/PackageProvider.h b/libzypp/zypp/repo/PackageProvider.h index 7dae714..ee1c8e7 100644 --- a/libzypp/zypp/repo/PackageProvider.h +++ b/libzypp/zypp/repo/PackageProvider.h @@ -70,9 +70,15 @@ namespace zypp public: /** Provide the package. * \throws Exception. - */ + */ ManagedFile providePackage() const; + /** Provide the package if it is cached. */ + ManagedFile providePackageFromCache() const; + + /** Whether the package is cached. */ + bool isCached() const; + public: class Impl; ///< Implementation class. private: diff --git a/libzypp/zypp/repo/RepoException.cc b/libzypp/zypp/repo/RepoException.cc index cb25498..b4c19cc 100644 --- a/libzypp/zypp/repo/RepoException.cc +++ b/libzypp/zypp/repo/RepoException.cc @@ -12,6 +12,7 @@ #include #include "zypp/repo/RepoException.h" #include "zypp/base/String.h" +#include "zypp/base/Gettext.h" using std::endl; @@ -106,19 +107,28 @@ namespace zypp /////////////////////////////////////////////////////////////////// #define DEF_CTORS( CLASS, MSG ) \ - CLASS::CLASS() : ServiceException( MSG ) {} \ - CLASS::CLASS( const std::string & msg_r ) : ServiceException( msg_r ) {} \ - CLASS::CLASS( const ServiceInfo & service_r ) : ServiceException( service_r, MSG ) {} \ - CLASS::CLASS( const ServiceInfo & service_r, const std::string & msg_r ) : ServiceException( service_r, msg_r ) {} + 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 ) {} +#define DEF_BASECLASS ServiceException DEF_CTORS( ServiceNoAliasException, "Service has no alias defined." ); DEF_CTORS( ServiceInvalidAliasException, "Service has an invalid alias." ); DEF_CTORS( ServiceAlreadyExistsException, "Service already exists." ); DEF_CTORS( ServiceNoUrlException, "Service has no or invalid url defined." ); - DEF_CTORS( ServicePluginInformalException,"Service plugin has trouble providing the metadata but this should not be treated as error." ); -#undef DEF_CTORS + // sub classes: + DEF_CTORS( ServicePluginException, "PLUGIN service exception." ); + + /////////////////////////////////////////////////////////////////// + // sub class: ServicePluginException +#undef DEF_BASECLASS +#define DEF_BASECLASS ServicePluginException + DEF_CTORS( ServicePluginInformalException, "Service plugin has trouble providing the metadata but this should not be treated as error." ); + DEF_CTORS( ServicePluginImmutableException, _("Service plugin does not support changing an attribute.") ); +#undef DEF_CTORS ///////////////////////////////////////////////////////////////// } // namespace repo /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/repo/RepoException.h b/libzypp/zypp/repo/RepoException.h index 00d5a94..daf97a3 100644 --- a/libzypp/zypp/repo/RepoException.h +++ b/libzypp/zypp/repo/RepoException.h @@ -239,10 +239,27 @@ namespace zypp ServiceNoUrlException( const ServiceInfo & service_r ); ServiceNoUrlException( const ServiceInfo & service_r, const std::string & msg_r ); }; + //@} + + + /** \name PLUGIN Service related exceptions. + */ + //@{ + + /** PLUGIN Service related exceptions + */ + class ServicePluginException : public ServiceException + { + public: + ServicePluginException(); + ServicePluginException( const std::string & msg_r ); + ServicePluginException( const ServiceInfo & service_r ); + ServicePluginException( const ServiceInfo & service_r, const std::string & msg_r ); + }; /** Service plugin has trouble providing the metadata but this should not be treated as error. */ - class ServicePluginInformalException : public ServiceException + class ServicePluginInformalException : public ServicePluginException { public: ServicePluginInformalException(); @@ -251,6 +268,16 @@ namespace zypp ServicePluginInformalException( const ServiceInfo & service_r, const std::string & msg_r ); }; + /** Service plugin is immutable. + */ + class ServicePluginImmutableException : public ServicePluginException + { + public: + ServicePluginImmutableException(); + ServicePluginImmutableException( const std::string & msg_r ); + ServicePluginImmutableException( const ServiceInfo & service_r ); + ServicePluginImmutableException( const ServiceInfo & service_r, const std::string & msg_r ); + }; //@} ///////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/repo/RepoInfoBase.cc b/libzypp/zypp/repo/RepoInfoBase.cc index bac195b..f3bf4ff 100644 --- a/libzypp/zypp/repo/RepoInfoBase.cc +++ b/libzypp/zypp/repo/RepoInfoBase.cc @@ -15,44 +15,58 @@ #include "zypp/repo/RepoVariables.h" #include "zypp/repo/RepoInfoBase.h" -#include "zypp/repo/RepoInfoBaseImpl.h" +#include "zypp/TriBool.h" +#include "zypp/Pathname.h" using namespace std; /////////////////////////////////////////////////////////////////// namespace zypp -{ ///////////////////////////////////////////////////////////////// +{ /////////////////////////////////////////////////////////////////// namespace repo - { ///////////////////////////////////////////////////////////////// + { /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : RepoInfoBase::Impl - // + /// \class RepoInfoBase::Impl + /// \brief RepoInfoBase data /////////////////////////////////////////////////////////////////// - - /** \relates RepoInfo::Impl Stream output */ - inline std::ostream & operator<<( std::ostream & str, const RepoInfoBase::Impl & obj ) + struct RepoInfoBase::Impl { - return str << "RepoInfo::Impl"; - } - - void RepoInfoBase::Impl::setAlias(const string & alias_) - { - this->alias = alias_; - // replace slashes with underscores - std::string fnd="/"; - std::string rep="_"; - std::string escaped_alias = alias_; - size_t pos = escaped_alias.find(fnd); - while (pos != string::npos) + 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; + std::string _name; + Pathname _filepath; + + public: + + void setAlias( const std::string & alias_r ) { - escaped_alias.replace(pos, fnd.length(), rep); - pos = escaped_alias.find(fnd, pos+rep.length()); + _alias = _escaped_alias = alias_r; + // replace slashes with underscores + str::replaceAll( _escaped_alias, "/", "_" ); } - this->escaped_alias = escaped_alias; - } + + private: + friend Impl * rwcowClone( const Impl * rhs ); + /** clone for RWCOW_pointer */ + Impl * clone() const + { return new Impl( *this ); } + }; + /////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// // @@ -60,82 +74,56 @@ namespace zypp // /////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////// - // - // METHOD NAME : RepoInfoBase::RepoInfoBase - // METHOD TYPE : Ctor - // RepoInfoBase::RepoInfoBase() : _pimpl( new Impl() ) {} - /////////////////////////////////////////////////////////////////// - // - // METHOD NAME : RepoInfoBase::RepoInfoBase - // METHOD TYPE : Ctor - // RepoInfoBase::RepoInfoBase(const string & alias) : _pimpl( new Impl(alias) ) {} - /////////////////////////////////////////////////////////////////// - // - // METHOD NAME : RepoInfoBase::~RepoInfoBase - // METHOD TYPE : Dtor - // RepoInfoBase::~RepoInfoBase() {} void RepoInfoBase::setEnabled( bool enabled ) - { - _pimpl->enabled = enabled; - } + { _pimpl->_enabled = enabled; } void RepoInfoBase::setAutorefresh( bool autorefresh ) - { - _pimpl->autorefresh = autorefresh; - } + { _pimpl->_autorefresh = autorefresh; } void RepoInfoBase::setAlias( const std::string &alias ) - { - _pimpl->setAlias(alias); - } + { _pimpl->setAlias(alias); } void RepoInfoBase::setName( const std::string &name ) - { - _pimpl->name = name; - } + { _pimpl->_name = name; } void RepoInfoBase::setFilepath( const Pathname &filepath ) - { - _pimpl->filepath = filepath; - } + { _pimpl->_filepath = filepath; } // true by default (if not set by setEnabled()) bool RepoInfoBase::enabled() const - { return indeterminate(_pimpl->enabled) ? true : (bool) _pimpl->enabled; } + { 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; } + { return indeterminate(_pimpl->_autorefresh) ? false : (bool) _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 ( _pimpl->name.empty() ) - { + if ( rawName().empty() ) return alias(); - } - - repo::RepoVariablesStringReplacer replacer; - return replacer(_pimpl->name); + return repo::RepoVariablesStringReplacer()( rawName() ); } + std::string RepoInfoBase::rawName() const + { return _pimpl->_name; } + std::string RepoInfoBase::label() const { if ( ZConfig::instance().repoLabelIsAlias() ) @@ -144,14 +132,15 @@ namespace zypp } Pathname RepoInfoBase::filepath() const - { return _pimpl->filepath; } + { return _pimpl->_filepath; } std::ostream & RepoInfoBase::dumpOn( std::ostream & str ) const { str << "--------------------------------------" << std::endl; str << "- alias : " << alias() << std::endl; - str << "- name : " << name() << std::endl; + if ( ! rawName().empty() ) + str << "- name : " << rawName() << std::endl; str << "- enabled : " << enabled() << std::endl; str << "- autorefresh : " << autorefresh() << std::endl; @@ -162,17 +151,15 @@ namespace zypp { // we save the original data without variable replacement str << "[" << alias() << "]" << endl; - str << "name=" << name() << 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 - { return dumpAsXMLOn(str, ""); } - - std::ostream & RepoInfoBase::dumpAsXMLOn( std::ostream & str, const std::string & content) const + std::ostream & RepoInfoBase::dumpAsXmlOn( std::ostream & str, const std::string & content ) const { return str << "" << endl; } @@ -181,11 +168,8 @@ namespace zypp { return obj.dumpOn(str); } - /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////// } // namespace repo /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/repo/RepoInfoBase.h b/libzypp/zypp/repo/RepoInfoBase.h index e348b87..a3dfd49 100644 --- a/libzypp/zypp/repo/RepoInfoBase.h +++ b/libzypp/zypp/repo/RepoInfoBase.h @@ -15,7 +15,7 @@ #include #include "zypp/base/PtrTypes.h" - +#include "zypp/APIConfig.h" #include "zypp/Pathname.h" /////////////////////////////////////////////////////////////////// @@ -32,6 +32,9 @@ namespace zypp /** * \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 { @@ -57,13 +60,17 @@ namespace zypp std::string escaped_alias() const; /** - * \short Repository short label + * \short Repository name * - * Short label or description of the repository. + * 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). */ + std::string rawName() const; + /** * \short Label for use in messages for the user interface. * @@ -71,6 +78,10 @@ namespace zypp */ 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. @@ -135,22 +146,19 @@ namespace zypp virtual std::ostream & dumpOn( std::ostream & str ) const; /** - * Write this RepoInfoBase object into \a str in - * a .repo (ini) file format. + * 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. Implement in - * derived classes. - */ - virtual std::ostream & dumpAsXMLOn(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; + virtual std::ostream & dumpAsXmlOn( std::ostream & str, const std::string & content = "" ) const; + + /** \deprecated Use camel cased dumpAsXmlOn */ + ZYPP_DEPRECATED std::ostream & dumpAsXMLOn( std::ostream & str, const std::string & content = "" ) const { return dumpAsXmlOn( str, content ); } class Impl; private: diff --git a/libzypp/zypp/repo/RepoInfoBaseImpl.h b/libzypp/zypp/repo/RepoInfoBaseImpl.h deleted file mode 100644 index 7d0592e..0000000 --- a/libzypp/zypp/repo/RepoInfoBaseImpl.h +++ /dev/null @@ -1,72 +0,0 @@ -/*---------------------------------------------------------------------\ -| ____ _ __ __ ___ | -| |__ / \ / / . \ . \ | -| / / \ V /| _/ _/ | -| / /__ | | | | | | | -| /_____||_| |_| |_| | -| | -\---------------------------------------------------------------------*/ -/** \file zypp/repo/RepoInfoBaseImpl.h - * - */ -#ifndef REPOINFOBASEIMPL_H_ -#define REPOINFOBASEIMPL_H_ - -#include - -#include "zypp/TriBool.h" -#include "zypp/Pathname.h" - -/////////////////////////////////////////////////////////////////// -namespace zypp -{ ///////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////// - namespace repo - { ///////////////////////////////////////////////////////////////// - - /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : RepoInfoBase::Impl - // - struct RepoInfoBase::Impl - { - Impl() - : enabled (indeterminate) - , autorefresh (indeterminate) - {} - - Impl(const std::string & alias_) - : enabled(indeterminate) - , autorefresh(indeterminate) - { setAlias(alias_); } - - ~Impl() - {} - - public: - TriBool enabled; - TriBool autorefresh; - std::string alias; - std::string escaped_alias; - std::string name; - Pathname filepath; - public: - - void setAlias(const std::string & alias_); - - private: - friend Impl * rwcowClone( const Impl * rhs ); - /** clone for RWCOW_pointer */ - Impl * clone() const - { return new Impl( *this ); } - }; - /////////////////////////////////////////////////////////////////// - - ///////////////////////////////////////////////////////////////// - } // namespace repo - /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////// -} // namespace zypp -/////////////////////////////////////////////////////////////////// - -#endif /*REPOINFOBASEIMPL_H_*/ diff --git a/libzypp/zypp/repo/RepoMirrorList.cc b/libzypp/zypp/repo/RepoMirrorList.cc index 15b1c45..ad44f25 100644 --- a/libzypp/zypp/repo/RepoMirrorList.cc +++ b/libzypp/zypp/repo/RepoMirrorList.cc @@ -29,131 +29,140 @@ namespace zypp namespace repo { ///////////////////////////////////////////////////////////////// - RepoMirrorList::RepoMirrorList( const Url &url, const Pathname &metadatapath ) + /////////////////////////////////////////////////////////////////// + namespace { - std::vector my_urls; - Pathname tmpfile, cachefile; - - if ( url.asString().find("/metalink") != string::npos ) - cachefile = metadatapath / "mirrorlist.xml"; - else - cachefile = metadatapath / "mirrorlist.txt"; - //cachefile = ZConfig::instance().repoMetadataPath() / Pathname(escaped_alias) / "mirrorlist.txt"; - - zypp::filesystem::PathInfo cacheinfo (cachefile); - - if ( !cacheinfo.isFile() || cacheinfo.mtime() < time(NULL) - (long) ZConfig::instance().repo_refresh_delay() * 60 ) + /////////////////////////////////////////////////////////////////// + /// \class RepoMirrorListTempProvider + /// \brief Provide access to downloaded mirror list (in temp space) + /// \ingroup g_RAII + /// + /// Tempspace (and mirror list) are deleted when provider goes out + /// of scope. + struct RepoMirrorListTempProvider { - Pathname filepath (url.getPathName()); - Url abs_url (url); - - DBG << "Getting MirrorList from URL: " << abs_url << endl; - - abs_url.setPathName(""); - abs_url.setQueryParam("mediahandler", "curl"); - - MediaSetAccess access (abs_url); - tmpfile = access.provideFile(filepath); - - // Create directory, if not existing - zypp::filesystem::assert_dir(metadatapath); - - DBG << "Copy MirrorList file to " << cachefile << endl; - zypp::filesystem::copy(tmpfile, cachefile); - } - - if ( url.asString().find("/metalink") != string::npos ) + RepoMirrorListTempProvider() + {} + RepoMirrorListTempProvider( const Pathname & localfile_r ) + : _localfile( localfile_r ) + {} + RepoMirrorListTempProvider( const Url & url_r ) + { + Url abs_url( url_r ); + abs_url.setPathName( "/" ); + abs_url.setQueryParam( "mediahandler", "curl" ); + _access.reset( new MediaSetAccess( abs_url ) ); + _localfile = _access->provideFile( url_r.getPathName() ); + } + + const Pathname & localfile() const + { return _localfile; } + + private: + shared_ptr _access; + Pathname _localfile; + }; + /////////////////////////////////////////////////////////////////// + + inline std::vector RepoMirrorListParseXML( const Pathname &tmpfile ) { - my_urls = parseXML(cachefile); + InputStream tmpfstream (tmpfile); + media::MetaLinkParser metalink; + metalink.parse(tmpfstream); + return metalink.getUrls(); } - else + + inline std::vector RepoMirrorListParseTXT( const Pathname &tmpfile ) { - my_urls = parseTXT(cachefile); + InputStream tmpfstream (tmpfile); + std::vector my_urls; + string tmpurl; + while (getline(tmpfstream.stream(), tmpurl)) + { + my_urls.push_back(Url(tmpurl)); + } + return my_urls; } - setUrls( my_urls ); - if( urls.empty() ) + /** Parse a local mirrorlist \a listfile_r and return usable URLs */ + inline std::vector RepoMirrorListParse( const Url & url_r, const Pathname & listfile_r ) { - DBG << "Removing Cachefile as it contains no URLs" << endl; - zypp::filesystem::unlink(cachefile); + USR << url_r << " " << listfile_r << endl; + + std::vector mirrorurls; + if ( url_r.asString().find( "/metalink" ) != string::npos ) + mirrorurls = RepoMirrorListParseXML( listfile_r ); + else + mirrorurls = RepoMirrorListParseTXT( listfile_r ); + + + std::vector ret; + for ( auto & murl : mirrorurls ) + { + if ( murl.getScheme() != "rsync" ) + { + size_t delpos = murl.getPathName().find("repodata/repomd.xml"); + if( delpos != string::npos ) + { + murl.setPathName( murl.getPathName().erase(delpos) ); + } + ret.push_back( murl ); + + if ( ret.size() >= 4 ) // why 4? + break; + } + } + return ret; } - } - - RepoMirrorList::RepoMirrorList( const Url &url ) - { - std::vector my_urls; - Pathname tmpfile; - - Pathname filepath (url.getPathName()); - Url abs_url (url); - - DBG << "Getting MirrorList from URL: " << abs_url << endl; - abs_url.setPathName(""); - abs_url.setQueryParam("mediahandler", "curl"); + } // namespace + /////////////////////////////////////////////////////////////////// - MediaSetAccess access (abs_url); - tmpfile = access.provideFile(filepath); - if ( url.asString().find("/metalink") != string::npos ) + RepoMirrorList::RepoMirrorList( const Url & url_r, const Pathname & metadatapath_r ) + { + if ( url_r.getScheme() == "file" ) { - my_urls = parseXML(tmpfile); + // never cache for local mirrorlist + _urls = RepoMirrorListParse( url_r, url_r.getPathName() ); } - else + else if ( ! PathInfo( metadatapath_r).isDir() ) { - my_urls = parseTXT(tmpfile); + // no cachedir + RepoMirrorListTempProvider provider( url_r ); // RAII: lifetime of any downloaded files + _urls = RepoMirrorListParse( url_r, provider.localfile() ); } - - setUrls( my_urls ); - } - - void RepoMirrorList::setUrls( std::vector my_urls ) - { - int valid_urls = 0; - for (std::vector::iterator it = my_urls.begin() ; it != my_urls.end() and valid_urls < 4 ; ++it) - { - if ( it->getScheme() != "rsync" ) - { - size_t delpos = it->getPathName().find("repodata/repomd.xml"); - if( delpos != string::npos ) - { - it->setPathName( it->getPathName().erase(delpos) ); - } - urls.push_back(*it); - ++valid_urls; - } - } - } - - std::vector RepoMirrorList::parseXML( const Pathname &tmpfile ) const - { - InputStream tmpfstream (tmpfile); - media::MetaLinkParser metalink; - metalink.parse(tmpfstream); - return metalink.getUrls(); - } - - std::vector RepoMirrorList::parseTXT( const Pathname &tmpfile ) const - { - InputStream tmpfstream (tmpfile); - std::vector my_urls; - string tmpurl; - while (getline(tmpfstream.stream(), tmpurl)) + else { - my_urls.push_back(Url(tmpurl)); + // have cachedir + Pathname cachefile( metadatapath_r ); + if ( url_r.asString().find( "/metalink" ) != string::npos ) + cachefile /= "mirrorlist.xml"; + else + cachefile /= "mirrorlist.txt"; + + zypp::filesystem::PathInfo cacheinfo( cachefile ); + if ( !cacheinfo.isFile() || cacheinfo.mtime() < time(NULL) - (long) ZConfig::instance().repo_refresh_delay() * 60 ) + { + DBG << "Getting MirrorList from URL: " << url_r << endl; + RepoMirrorListTempProvider provider( url_r ); // RAII: lifetime of downloaded file + + // Create directory, if not existing + DBG << "Copy MirrorList file to " << cachefile << endl; + zypp::filesystem::assert_dir( metadatapath_r ); + zypp::filesystem::hardlinkCopy( provider.localfile(), cachefile ); + } + + _urls = RepoMirrorListParse( url_r, cachefile ); + if( _urls.empty() ) + { + DBG << "Removing Cachefile as it contains no URLs" << endl; + zypp::filesystem::unlink( cachefile ); + } } - return my_urls; - } - - std::vector RepoMirrorList::getUrls() const - { - return urls; } - RepoMirrorList::~RepoMirrorList() - {} - - ///////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////// } // namespace repo /////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/repo/RepoMirrorList.h b/libzypp/zypp/repo/RepoMirrorList.h index dfc2ca6..e6ad1fd 100644 --- a/libzypp/zypp/repo/RepoMirrorList.h +++ b/libzypp/zypp/repo/RepoMirrorList.h @@ -21,19 +21,17 @@ namespace zypp class RepoMirrorList { public: - RepoMirrorList( const Url &url ); - RepoMirrorList( const Url &url, const Pathname &metadatapath ); - virtual ~RepoMirrorList(); - - std::vector getUrls() const; + RepoMirrorList( const Url & url_r, const Pathname & metadatapath_r = Pathname() ); + + const std::vector & getUrls() const + { return _urls; } + + std::vector & getUrls() + { return _urls; } private: - std::vector urls; - void setUrls( std::vector my_urls ); - std::vector parseXML( const Pathname &tmpfile ) const; - std::vector parseTXT( const Pathname &tmpfile ) const; + std::vector _urls; }; - } // ns repo } // ns zypp diff --git a/libzypp/zypp/repo/RepoType.cc b/libzypp/zypp/repo/RepoType.cc index c10f827..390e406 100644 --- a/libzypp/zypp/repo/RepoType.cc +++ b/libzypp/zypp/repo/RepoType.cc @@ -8,7 +8,7 @@ \---------------------------------------------------------------------*/ #include -#include +#include "zypp/base/NamedValue.h" #include "zypp/repo/RepoException.h" #include "RepoType.h" @@ -16,72 +16,46 @@ namespace zypp { namespace repo { + /////////////////////////////////////////////////////////////////// + namespace + { + static NamedValue & table() + { + static NamedValue & _t( *new NamedValue ); + if ( _t.empty() ) + { + _t( RepoType::RPMMD_e ) | "rpm-md" | "rpmmd"|"repomd"|"yum"|"up2date"; + _t( RepoType::YAST2_e ) | "yast2" | "yast"|"susetags"; + _t( RepoType::RPMPLAINDIR_e ) | "plaindir"; + _t( RepoType::NONE_e ) | "NONE" | "none"; + } + return _t; + } + } // namespace + /////////////////////////////////////////////////////////////////// - static std::map _table; - - const RepoType RepoType::RPMMD(RepoType::RPMMD_e); - const RepoType RepoType::YAST2(RepoType::YAST2_e); - const RepoType RepoType::RPMPLAINDIR(RepoType::RPMPLAINDIR_e); - const RepoType RepoType::NONE(RepoType::NONE_e); + const RepoType RepoType::RPMMD ( RepoType::RPMMD_e ); + const RepoType RepoType::YAST2 ( RepoType::YAST2_e ); + const RepoType RepoType::RPMPLAINDIR ( RepoType::RPMPLAINDIR_e ); + const RepoType RepoType::NONE ( RepoType::NONE_e ); RepoType::RepoType(const std::string & strval_r) : _type(parse(strval_r)) {} - RepoType::Type RepoType::parse(const std::string & strval_r) + RepoType::Type RepoType::parse( const std::string & strval_r ) { - if (_table.empty()) + RepoType::Type type; + if ( ! table().getValue( str::toLower( strval_r ), type ) ) { - // initialize it - _table["repomd"] - = _table["rpmmd"] - = _table["rpm-md"] - = _table["yum"] - = _table["YUM"] - = _table["up2date"] - = RepoType::RPMMD_e; - - _table["susetags"] - = _table["yast"] - = _table["YaST"] - = _table["YaST2"] - = _table["YAST"] - = _table["YAST2"] - = _table["yast2"] - = RepoType::YAST2_e; - - _table["plaindir"] - = _table["Plaindir"] - = RepoType::RPMPLAINDIR_e; - - _table["NONE"] - = _table["none"] - = RepoType::NONE_e; + ZYPP_THROW( RepoUnknownTypeException( "Unknown repository type '" + strval_r + "'") ); } - - std::map::const_iterator it - = _table.find(strval_r); - if (it == _table.end()) - { - ZYPP_THROW(RepoUnknownTypeException( - "Unknown repository type '" + strval_r + "'")); - } - return it->second; + return type; } - const std::string & RepoType::asString() const { - static std::map _table; - if ( _table.empty() ) - { - // initialize it - _table[RPMMD_e] = "rpm-md"; - _table[YAST2_e] = "yast2"; - _table[RPMPLAINDIR_e] = "plaindir"; - _table[NONE_e] = "NONE"; - } - return _table[_type]; + return table().getName( _type ); } diff --git a/libzypp/zypp/repo/RepoVariables.cc b/libzypp/zypp/repo/RepoVariables.cc index 8c83b61..f4edc87 100644 --- a/libzypp/zypp/repo/RepoVariables.cc +++ b/libzypp/zypp/repo/RepoVariables.cc @@ -19,6 +19,16 @@ /////////////////////////////////////////////////////////////////// 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 { @@ -46,7 +56,13 @@ namespace zypp const std::string & releasever() const { if( _releasever.empty() ) - _releasever = Target::distributionVersion( Pathname()/*guess*/ ); + { + _releasever = env::ZYPP_REPO_RELEASEVER(); + if( _releasever.empty() ) + _releasever = Target::distributionVersion( Pathname()/*guess*/ ); + else + WAR << "ENV overwrites $releasever=" << _releasever << endl; + } return _releasever; } diff --git a/libzypp/zypp/repo/RepoVariables.h b/libzypp/zypp/repo/RepoVariables.h index bec57b5..a5c7efa 100644 --- a/libzypp/zypp/repo/RepoVariables.h +++ b/libzypp/zypp/repo/RepoVariables.h @@ -25,6 +25,18 @@ namespace zypp * * Replaces '$arch', '$basearch' and $releasever in a string * with the global ZYpp values. + * + * \note The $releasever value is overwritten by the environment + * variable \c ZYPP_REPO_RELEASEVER. This might be handy for + * distribution upogrades like this: + * \code + * $ export ZYPP_REPO_RELEASEVER=13.2 + * $ zypper lr -u + * $ zypper dup + * ....upgrades to 13.2... + * \endcode + * (see \ref zypp-envars) + * * \code * Example: * ftp://user:secret@site.net/$arch/ -> ftp://user:secret@site.net/i686/ diff --git a/libzypp/zypp/repo/ServiceRepos.cc b/libzypp/zypp/repo/ServiceRepos.cc index 041c448..86d0dc5 100644 --- a/libzypp/zypp/repo/ServiceRepos.cc +++ b/libzypp/zypp/repo/ServiceRepos.cc @@ -88,7 +88,7 @@ class PluginServiceRepos : public ServiceRepos::Impl std::string errbuffer; prog.stderrGetUpTo( errbuffer, '\0' ); ERR << "Capture plugin error:[" << endl << errbuffer << endl << ']' << endl; - ZYPP_THROW( repo::ServicePluginInformalException(errbuffer)); + ZYPP_THROW( repo::ServicePluginInformalException( service, errbuffer ) ); } parser::RepoFileReader parser(buffer, _callback); diff --git a/libzypp/zypp/repo/susetags/Downloader.cc b/libzypp/zypp/repo/susetags/Downloader.cc index 9652a3e..c6b1c58 100644 --- a/libzypp/zypp/repo/susetags/Downloader.cc +++ b/libzypp/zypp/repo/susetags/Downloader.cc @@ -3,6 +3,7 @@ #include #include "zypp/base/LogTools.h" +#include "zypp/base/Gettext.h" #include "zypp/base/String.h" #include "zypp/base/Regex.h" #include "zypp/OnMediaLocation.h" @@ -15,7 +16,6 @@ #include "zypp/parser/ParseException.h" #include "zypp/parser/susetags/RepoIndex.h" #include "zypp/base/UserRequestException.h" -#include "zypp/KeyContext.h" // for SignatureFileChecker using namespace std; using namespace zypp::parser; @@ -52,54 +52,20 @@ static Pathname search_deltafile( const Pathname &dir, const Pathname &file ) return Pathname(); } + +/** \todo: Downloading/sigcheck of master index shoudl be common in base class */ void Downloader::download( MediaSetAccess &media, const Pathname &dest_dir, const ProgressData::ReceiverFnc & progress ) { downloadMediaInfo( dest_dir, media ); - SignatureFileChecker sigchecker/*(repoInfo().name())*/; - - Pathname sig = repoInfo().path() + "/content.asc"; - - enqueue( OnMediaLocation( sig, 1 ).setOptional(true) ); - start( dest_dir, media ); - // only if there is a signature in the destination directory - if ( PathInfo(dest_dir / sig ).isExist() ) - sigchecker = SignatureFileChecker( dest_dir + sig/*, repoInfo().name() */); - reset(); - - Pathname key = repoInfo().path() + "/content.key"; - - enqueue( OnMediaLocation( key, 1 ).setOptional(true) ); - start( dest_dir, media ); - - KeyContext context; - context.setRepoInfo(repoInfo()); - // only if there is a key in the destination directory - if ( PathInfo(dest_dir / key).isExist() ) - sigchecker.addPublicKey(dest_dir + key, context); - // set the checker context even if the key is not known (unsigned repo, key - // file missing; bnc #495977) - else - sigchecker.setKeyContext(context); - - reset(); - - if ( ! repoInfo().gpgCheck() ) - { - WAR << "Signature checking disabled in config of repository " << repoInfo().alias() << endl; - } - enqueue( OnMediaLocation( repoInfo().path() + "/content", 1 ), - repoInfo().gpgCheck() ? FileChecker(sigchecker) : FileChecker(NullFileChecker()) ); - start( dest_dir, media ); - reset(); - - Pathname descr_dir; + Pathname masterIndex( repoInfo().path() / "/content" ); + defaultDownloadMasterIndex( media, dest_dir, masterIndex ); // Content file first to get the repoindex { - Pathname inputfile( dest_dir + repoInfo().path() + "/content" ); + Pathname inputfile( dest_dir / masterIndex ); ContentFileReader content; content.setRepoIndexConsumer( bind( &Downloader::consumeIndex, this, _1 ) ); content.parse( inputfile ); @@ -119,7 +85,7 @@ void Downloader::download( MediaSetAccess &media, } // Prepare parsing - descr_dir = _repoindex->descrdir; // path below reporoot + Pathname descr_dir = _repoindex->descrdir; // path below reporoot //_datadir = _repoIndex->datadir; // path below reporoot std::map availablePackageTranslations; diff --git a/libzypp/zypp/repo/yum/Downloader.cc b/libzypp/zypp/repo/yum/Downloader.cc index 529f091..a27dd2f 100644 --- a/libzypp/zypp/repo/yum/Downloader.cc +++ b/libzypp/zypp/repo/yum/Downloader.cc @@ -12,15 +12,12 @@ #include "zypp/base/Logger.h" #include "zypp/base/Function.h" -#include "zypp/Date.h" - #include "zypp/parser/yum/RepomdFileReader.h" #include "zypp/parser/yum/PatchesFileReader.h" #include "Downloader.h" #include "zypp/repo/MediaInfoDownloader.h" #include "zypp/base/UserRequestException.h" #include "zypp/parser/xml/Reader.h" -#include "zypp/KeyContext.h" using namespace std; using namespace zypp::xml; @@ -126,70 +123,20 @@ bool Downloader::repomd_Callback( const OnMediaLocation &loc, return true; } +/** \todo: Downloading/sigcheck of master index shoudl be common in base class */ void Downloader::download( MediaSetAccess &media, const Pathname &dest_dir, const ProgressData::ReceiverFnc & progressrcv ) { - Pathname repomdpath = repoInfo().path() + "/repodata/repomd.xml"; - Pathname keypath = repoInfo().path() + "/repodata/repomd.xml.key"; - Pathname sigpath = repoInfo().path() + "/repodata/repomd.xml.asc"; + Pathname masterIndex( repoInfo().path() / "/repodata/repomd.xml" ); + defaultDownloadMasterIndex( media, dest_dir, masterIndex ); _media_ptr = (&media); - - ProgressData progress; - progress.sendTo(progressrcv); - progress.toMin(); - - //downloadMediaInfo( dest_dir, _media ); - _dest_dir = dest_dir; - -#warning Do we need SignatureFileChecker(string descr)? - SignatureFileChecker sigchecker/*(repoInfo().name())*/; - - this->enqueue( OnMediaLocation(sigpath,1).setOptional(true) ); - this->start( dest_dir, *_media_ptr); - // only add the signature if it exists - if ( PathInfo(dest_dir / sigpath).isExist() ) - sigchecker = SignatureFileChecker(dest_dir / sigpath); - this->reset(); - - this->enqueue( OnMediaLocation(keypath,1).setOptional(true) ); - this->start( dest_dir, *_media_ptr); - - KeyContext context; - context.setRepoInfo(repoInfo()); - // only add the key if it exists - if ( PathInfo(dest_dir / keypath).isExist() ) - sigchecker.addPublicKey(dest_dir + keypath, context); - // set the checker context even if the key is not known (unsigned repo, key - // file missing; bnc #495977) - else - sigchecker.setKeyContext(context); - - this->reset(); - - if ( ! progress.tick() ) - ZYPP_THROW(AbortRequestException()); - - if ( ! repoInfo().gpgCheck() ) - WAR << "Signature checking disabled in config of repository " << repoInfo().alias() << endl; - - this->enqueue( OnMediaLocation(repomdpath,1), - repoInfo().gpgCheck() ? FileChecker(sigchecker) : FileChecker(NullFileChecker()) ); - this->start( dest_dir, *_media_ptr); - - if ( ! progress.tick() ) - ZYPP_THROW(AbortRequestException()); - - this->reset(); - - Reader reader( dest_dir + repoInfo().path() + "/repodata/repomd.xml" ); - RepomdFileReader( dest_dir + repoInfo().path() + "/repodata/repomd.xml", bind( &Downloader::repomd_Callback, this, _1, _2)); + RepomdFileReader( dest_dir / masterIndex, bind( &Downloader::repomd_Callback, this, _1, _2)); // ready, go! - this->start( dest_dir, *_media_ptr); - progress.toMax(); + start( dest_dir, media ); } }// ns yum diff --git a/libzypp/zypp/sat/FileConflicts.cc b/libzypp/zypp/sat/FileConflicts.cc new file mode 100644 index 0000000..2bffaad --- /dev/null +++ b/libzypp/zypp/sat/FileConflicts.cc @@ -0,0 +1,169 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/sat/FileConflicts.cc + */ +#include +#include + +#include "zypp/sat/FileConflicts.h" +#include "zypp/base/LogTools.h" +#include "zypp/base/Gettext.h" +#include "zypp/base/Xml.h" +#include "zypp/CheckSum.h" + +using std::endl; + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + /////////////////////////////////////////////////////////////////// + namespace sat + { + std::string FileConflicts::Conflict::asUserString() const + { + if ( lhsFilename() == rhsFilename() ) + { + static const char * text[2][2] = {{ // [lhs][rhs] 0 = installed; 1 = to be installed + // TranslatorExplanation %1%(filename) %2%(package1) %3%(package2) + N_( "File %1%\n" + " from package\n" + " %2%\n" + " conflicts with file from package\n" + " %3%" ), + // TranslatorExplanation %1%(filename) %2%(package1) %3%(package2) + N_( "File %1%\n" + " from package\n" + " %2%\n" + " conflicts with file from install of\n" + " %3%" ) + },{ + // TranslatorExplanation %1%(filename) %2%(package1) %3%(package2) + N_( "File %1%\n" + " from install of\n" + " %2%\n" + " conflicts with file from package\n" + " %3%" ), + // TranslatorExplanation %1%(filename) %2%(package1) %3%(package2) + N_( "File %1%\n" + " from install of\n" + " %2%\n" + " conflicts with file from install of\n" + " %3%" ) + }}; + return( boost::formatNAC( text[lhsSolvable().isSystem()?0:1][rhsSolvable().isSystem()?0:1] ) + % lhsFilename() + % lhsSolvable().asUserString() + % rhsSolvable().asUserString() + ).str(); + } + else + { + static const char * text[2][2] = {{ // [lhs][rhs] 0 = installed; 1 = to be installed + // TranslatorExplanation %1%(filename1) %2%(package1) %%3%(filename2) 4%(package2) + N_( "File %1%\n" + " from package\n" + " %2%\n" + " conflicts with file\n" + " %3%\n" + " from package\n" + " %4%" ), + // TranslatorExplanation %1%(filename1) %2%(package1) %3%(filename2) %4%(package2) + N_( "File %1%\n" + " from package\n" + " %2%\n" + " conflicts with file\n" + " %3%\n" + " from install of\n" + " %4%" ) + },{ + // TranslatorExplanation %1%(filename1) %2%(package1) %3%(filename2) %4%(package2) + N_( "File %1%\n" + " from install of\n" + " %2%\n" + " conflicts with file\n" + " %3%\n" + " from package\n" + " %4%" ), + // TranslatorExplanation %1%(filename1) %2%(package1) %3%(filename2) %4%(package2) + N_( "File %1%\n" + " from install of\n" + " %2%\n" + " conflicts with file\n" + " %3%\n" + " from install of\n" + " %4%" ) + }}; + return( boost::formatNAC( text[lhsSolvable().isSystem()?0:1][rhsSolvable().isSystem()?0:1] ) + % lhsFilename() + % lhsSolvable().asUserString() + % rhsFilename() + % rhsSolvable().asUserString() + ).str(); + } + } + + std::ostream & operator<<( std::ostream & str, const FileConflicts & obj ) + { return dumpRange( str << "(" << obj.size() << ") ", obj.begin(), obj.end() ); } + + std::ostream & operator<<( std::ostream & str, const FileConflicts::Conflict & obj ) + { + if ( obj.lhsFilename() == obj.rhsFilename() ) + return str << boost::format( "%s:\n %s[%s]\n %s[%s]" ) + % obj.lhsFilename() + % obj.lhsSolvable() + % obj.lhsFilemd5() + % obj.rhsSolvable() + % obj.rhsFilemd5(); + + return str << boost::format( "%s - %s:\n %s[%s]\n %s[%s]" ) + % obj.lhsFilename() + % obj.rhsFilename() + % obj.lhsSolvable() + % obj.lhsFilemd5() + % obj.rhsSolvable() + % obj.rhsFilemd5(); + } + + + std::ostream & dumpAsXmlOn( std::ostream & str, const FileConflicts & obj ) + { + xmlout::Node guard( str, "fileconflicts", { "size", obj.size() } ); + if ( ! obj.empty() ) + { + *guard << "\n"; + for ( const auto & el : obj ) + dumpAsXmlOn( *guard, el ) << "\n"; + } + return str; + } + + namespace + { + std::ostream & dumpAsXmlHelper( std::ostream & str, const std::string & tag_r, IdString filename_r, IdString md5sum_r, Solvable solv_r ) + { + xmlout::Node guard( str, tag_r ); + *xmlout::Node( *guard, "file" ) << filename_r; + dumpAsXmlOn( *guard, CheckSum( md5sum_r.asString() ) ); + dumpAsXmlOn( *guard, solv_r ); + return str; + } + } + + std::ostream & dumpAsXmlOn( std::ostream & str, const FileConflicts::Conflict & obj ) + { + xmlout::Node guard( str, "fileconflict" ); + dumpAsXmlHelper( *guard<<"\n", "lhs", obj.lhsFilename(), obj.lhsFilemd5(), obj.lhsSolvable() ); + dumpAsXmlHelper( *guard<<"\n", "rhs", obj.rhsFilename(), obj.rhsFilemd5(), obj.rhsSolvable() ); + return str; + } + + } // namespace sat + /////////////////////////////////////////////////////////////////// +} // namespace zypp +/////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/sat/FileConflicts.h b/libzypp/zypp/sat/FileConflicts.h new file mode 100644 index 0000000..783d6c8 --- /dev/null +++ b/libzypp/zypp/sat/FileConflicts.h @@ -0,0 +1,96 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/sat/FileConflicts.h + */ +#ifndef ZYPP_SAT_FILECONFLICTS_H +#define ZYPP_SAT_FILECONFLICTS_H + +#include + +#include "zypp/base/PtrTypes.h" +#include "zypp/sat/Queue.h" +#include "zypp/sat/Solvable.h" + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + /////////////////////////////////////////////////////////////////// + namespace sat + { + /////////////////////////////////////////////////////////////////// + /// \class FileConflicts + /// \brief Libsolv queue representing file conflicts. + /////////////////////////////////////////////////////////////////// + class FileConflicts : private Queue + { + friend bool operator==( const FileConflicts & lhs, const FileConflicts & rhs ); + static constexpr size_type queueBlockSize = 6; + + public: + /** + * \class Conflict + * \brief A file conflict. + */ + struct Conflict + { + IdString lhsFilename() const { return IdString( _data[0] ); } + Solvable lhsSolvable() const { return Solvable( _data[1] ); } + IdString lhsFilemd5() const { return IdString( _data[2] ); } + + IdString rhsFilename() const { return IdString( _data[3] ); } + Solvable rhsSolvable() const { return Solvable( _data[4] ); } + IdString rhsFilemd5() const { return IdString( _data[5] ); } + + /** Ready to use (translated) string describing the Conflict */ + std::string asUserString() const; + + private: + detail::IdType _data[queueBlockSize]; + }; + + public: + using Queue::size_type; + typedef Conflict value_type; + typedef const value_type* const_iterator; + + using Queue::empty; + size_type size() const { return Queue::size()/queueBlockSize; } + const_iterator begin() const { return reinterpret_cast(Queue::begin()); } + const_iterator end() const { return reinterpret_cast(Queue::end()); } + + public: + using Queue::operator struct ::_Queue *; ///< libsolv backdoor + using Queue::operator const struct ::_Queue *; ///< libsolv backdoor + }; + + /** \relates FileConflicts Stream output */ + std::ostream & operator<<( std::ostream & str, const FileConflicts & obj ); + + /** \relates FileConflicts::Conflict Stream output */ + std::ostream & operator<<( std::ostream & str, const FileConflicts::Conflict & obj ); + + /** \relates FileConflicts XML output */ + std::ostream & dumpAsXmlOn( std::ostream & str, const FileConflicts & obj ); + + /** \relates FileConflicts::Conflict XML output */ + std::ostream & dumpAsXmlOn( std::ostream & str, const FileConflicts::Conflict & obj ); + + /** \relates FileConflicts */ + inline bool operator==( const FileConflicts & lhs, const FileConflicts & rhs ) + { return static_cast(lhs) == static_cast(rhs); } + + /** \relates FileConflicts */ + inline bool operator!=( const FileConflicts & lhs, const FileConflicts & rhs ) + { return !( lhs == rhs ); } + + } // namespace sat + /////////////////////////////////////////////////////////////////// +} // namespace zypp +/////////////////////////////////////////////////////////////////// +#endif // ZYPP_SAT_FILECONFLICTS_H diff --git a/libzypp/zypp/sat/LookupAttr.cc b/libzypp/zypp/sat/LookupAttr.cc index 741119a..627b3e4 100644 --- a/libzypp/zypp/sat/LookupAttr.cc +++ b/libzypp/zypp/sat/LookupAttr.cc @@ -321,6 +321,7 @@ namespace zypp { _dip = new ::Dataiterator; ::dataiterator_init_clone( _dip, rhs._dip ); + ::dataiterator_strdup( _dip ); } } @@ -599,7 +600,10 @@ namespace zypp break; case REPOKEY_TYPE_DIRSTRARRAY: - return ::repodata_dir2str( _dip->data, _dip->kv.id, _dip->kv.str ); + // may or may not be stringified depending on SEARCH_FILES flag + return( _dip->flags & SEARCH_FILES + ? _dip->kv.str + : ::repodata_dir2str( _dip->data, _dip->kv.id, _dip->kv.str ) ); break; } } @@ -752,10 +756,17 @@ namespace zypp void LookupAttr::iterator::increment() { - if ( _dip && ! ::dataiterator_step( _dip.get() ) ) + if ( _dip ) { - _dip.reset(); - base_reference() = 0; + if ( ! ::dataiterator_step( _dip.get() ) ) + { + _dip.reset(); + base_reference() = 0; + } + else + { + ::dataiterator_strdup( _dip.get() ); + } } } diff --git a/libzypp/zypp/sat/LookupAttr.h b/libzypp/zypp/sat/LookupAttr.h index d7e45db..86500a0 100644 --- a/libzypp/zypp/sat/LookupAttr.h +++ b/libzypp/zypp/sat/LookupAttr.h @@ -200,19 +200,19 @@ namespace zypp public: /** \name Where to search. */ //@{ - /** Wheter to search in \ref Pool. */ + /** Whether to search in \ref Pool. */ bool pool() const; /** Set search in \ref Pool (all repositories). */ void setPool( Location = SOLV_ATTR ); - /** Wheter to search in one \ref Repository. */ + /** Whether to search in one \ref Repository. */ Repository repo() const; /** Set search in one \ref Repository. */ void setRepo( Repository repo_r, Location = SOLV_ATTR ); - /** Wheter to search in one \ref Solvable. */ + /** Whether to search in one \ref Solvable. */ Solvable solvable() const; /** Set search in one \ref Solvable. */ @@ -292,7 +292,7 @@ namespace zypp * Also maintains a copy of the matchstring in order to * keep the char* passed to the dataiterator valid. */ - class DIWrap : private base::SafeBool + class DIWrap { public: /** \c NULL \c ::_Dataiterator */ @@ -325,19 +325,16 @@ namespace zypp void reset() { DIWrap().swap( *this ); } public: -#ifndef SWIG // Swig treats it as syntax error /** Evaluate in a boolean context ( _dip != NULL ). */ - using base::SafeBool::operator bool_type; -#endif + explicit operator bool() const + { return _dip; } + public: ::_Dataiterator * operator->() const { return _dip; } ::_Dataiterator * get() const { return _dip; } const std::string & getstr() const { return _mstring; } - private: - friend base::SafeBool::operator bool_type() const; - bool boolTest() const - { return _dip; } - private: + + private: ::_Dataiterator * _dip; std::string _mstring; }; @@ -462,7 +459,7 @@ namespace zypp * \endcode */ //@{ - /** Wheter the sub-structure is empty. */ + /** Whether the sub-structure is empty. */ bool subEmpty() const; /** Ammount of attributes in the sub-structure. diff --git a/libzypp/zypp/sat/Map.cc b/libzypp/zypp/sat/Map.cc index 964e29a..66afad2 100644 --- a/libzypp/zypp/sat/Map.cc +++ b/libzypp/zypp/sat/Map.cc @@ -18,6 +18,7 @@ extern "C" #include "zypp/base/String.h" #include "zypp/sat/Map.h" +#include "zypp/sat/Pool.h" using std::endl; @@ -45,6 +46,10 @@ namespace zypp : _pimpl( new ::_Map ) { ::map_init( _pimpl.get(), size_r ); } + Map::Map( PoolSizeType ) + : _pimpl( new ::_Map ) + { ::map_init( _pimpl.get(), Pool::instance().capacity() ); } + Map::~Map() { ::map_free( _pimpl.get() ); } diff --git a/libzypp/zypp/sat/Map.h b/libzypp/zypp/sat/Map.h index ddf587e..9eaddea 100644 --- a/libzypp/zypp/sat/Map.h +++ b/libzypp/zypp/sat/Map.h @@ -38,6 +38,11 @@ namespace zypp public: typedef unsigned long size_type; + /** Type to indicate the bitmap should match the current pools capacity. */ + struct PoolSizeType {}; + /** An object indicating the bitmap should match the current pools capacity. */ + static constexpr PoolSizeType poolSize = PoolSizeType(); + public: /** Default ctor: empty Map */ Map(); @@ -45,6 +50,9 @@ namespace zypp /** Ctor taking the Map size */ explicit Map( size_type size_r ); + /** Ctor creating a Map matching the current pools capacity */ + Map( PoolSizeType ); + /** Dtor */ ~Map(); @@ -68,20 +76,30 @@ namespace zypp /** Assign \c val_r to all bits. */ void assignAll( bool val_r ); - /** Set bit \c idx_r. */ + /** Set bit \c idx_r. + * \throws std::out_of_range if \a idx_r is out of range + */ void set( size_type idx_r ); - /** Clear bit \c idx_r. */ + /** Clear bit \c idx_r. + * \throws std::out_of_range if \a idx_r is out of range + */ void clear( size_type idx_r ); - /** Assign \c val_r to bit \c idx_r. */ + /** Assign \c val_r to bit \c idx_r. + * \throws std::out_of_range if \a idx_r is out of range + */ void assign( size_type idx_r, bool val_r ); public: - /** Test bit \c idx_r.*/ + /** Test bit \c idx_r. + * \throws std::out_of_range if \a idx_r is out of range + */ bool test( size_type idx_r ) const; - /** Test bit \c idx_r.*/ + /** Test bit \c idx_r. + * \throws std::out_of_range if \a idx_r is out of range + */ bool operator[]( size_type idx_r ) const { return test( idx_r ); } @@ -114,6 +132,8 @@ namespace zypp /** \relates Map Clone function for RWCOW_pointer */ template<> struct ::_Map * rwcowClone( const struct ::_Map * rhs ); + typedef sat::Map Bitmap; + } // namespace zypp /////////////////////////////////////////////////////////////////// #endif // ZYPP_SAT_MAP_H diff --git a/libzypp/zypp/sat/Pool.cc b/libzypp/zypp/sat/Pool.cc index 9c4a2e3..35d8621 100644 --- a/libzypp/zypp/sat/Pool.cc +++ b/libzypp/zypp/sat/Pool.cc @@ -48,6 +48,12 @@ namespace zypp void Pool::prepareForSolving() const { return myPool().prepareForSolving(); } + Pathname Pool::rootDir() const + { return myPool().rootDir(); } + + void Pool::rootDir( const Pathname & root_r ) + { return myPool().rootDir( root_r ); } + bool Pool::reposEmpty() const { return ! myPool()->urepos; } @@ -220,11 +226,8 @@ namespace zypp Pool::MultiversionIterator Pool::multiversionEnd() const { return myPool().multiversionList().end(); } bool Pool::isMultiversion( IdString ident_r ) const { return myPool().isMultiversion( ident_r ); } - bool Pool::onSystemByUserEmpty() const { return myPool().onSystemByUserList().empty(); } - size_t Pool::onSystemByUserSize() const { return myPool().onSystemByUserList().size(); } - Pool::OnSystemByUserIterator Pool::onSystemByUserBegin() const { return myPool().onSystemByUserList().begin(); } - Pool::OnSystemByUserIterator Pool::onSystemByUserEnd() const { return myPool().onSystemByUserList().end(); } - bool Pool::isOnSystemByUser( IdString ident_r ) const { return myPool().isOnSystemByUser( ident_r ); } + Queue Pool::autoInstalled() const { return myPool().autoInstalled(); } + void Pool::setAutoInstalled( const Queue & autoInstalled_r ){ myPool().setAutoInstalled( autoInstalled_r ); } /****************************************************************** ** diff --git a/libzypp/zypp/sat/Pool.h b/libzypp/zypp/sat/Pool.h index df86592..9a29f33 100644 --- a/libzypp/zypp/sat/Pool.h +++ b/libzypp/zypp/sat/Pool.h @@ -19,6 +19,7 @@ #include "zypp/sat/detail/PoolMember.h" #include "zypp/Repository.h" #include "zypp/sat/WhatProvides.h" +#include "zypp/sat/Queue.h" /////////////////////////////////////////////////////////////////// namespace zypp @@ -68,6 +69,12 @@ namespace zypp /** \ref prepare plus some expensive checks done before solving only. */ void prepareForSolving() const; + /** Get rootdir (for file conflicts check) */ + Pathname rootDir() const; + + /** Set rootdir (for file conflicts check) */ + void rootDir( const Pathname & root_r ); + public: /** Whether \ref Pool contains repos. */ bool reposEmpty() const; @@ -196,7 +203,7 @@ namespace zypp */ const LocaleSet & getRequestedLocales() const; - /** Wheter this \ref Locale is in the set of requested locales. */ + /** Whether this \ref Locale is in the set of requested locales. */ bool isRequestedLocale( const Locale & locale_r ) const; /** Get the set of available locales. @@ -205,7 +212,7 @@ namespace zypp */ const LocaleSet & getAvailableLocales() const; - /** Wheter this \ref Locale is in the set of available locales. */ + /** Whether this \ref Locale is in the set of available locales. */ bool isAvailableLocale( const Locale & locale_r ) const; //@} @@ -226,18 +233,12 @@ namespace zypp //@} public: - /** \name Installed on behalf of a user request hint. - * This is a hint guessed by evaluating an available install history. - */ + /** \name Autoinstalled */ //@{ - typedef IdStringSet::const_iterator OnSystemByUserIterator; - - bool onSystemByUserEmpty() const; - size_t onSystemByUserSize() const; - OnSystemByUserIterator onSystemByUserBegin() const; - OnSystemByUserIterator onSystemByUserEnd() const; - - bool isOnSystemByUser( IdString ident_r ) const; + /** Get ident list of all autoinstalled solvables. */ + Queue autoInstalled() const; + /** Set ident list of all autoinstalled solvables. */ + void setAutoInstalled( const Queue & autoInstalled_r ); //@} public: diff --git a/libzypp/zypp/sat/Queue.cc b/libzypp/zypp/sat/Queue.cc index 0856e71..13458ba 100644 --- a/libzypp/zypp/sat/Queue.cc +++ b/libzypp/zypp/sat/Queue.cc @@ -22,22 +22,26 @@ using std::endl; /////////////////////////////////////////////////////////////////// namespace zypp -{ ///////////////////////////////////////////////////////////////// +{ + + template<> + struct ::_Queue * rwcowClone( const struct ::_Queue * rhs ) + { + struct ::_Queue * ret = new ::_Queue; + ::queue_init_clone( ret, const_cast(rhs) ); + return ret; + } + /////////////////////////////////////////////////////////////////// namespace sat - { ///////////////////////////////////////////////////////////////// + { Queue::Queue() - : _pimpl( new struct ::_Queue ) - { - ::queue_init( _pimpl ); - } + : _pimpl( new ::_Queue ) + { ::queue_init( _pimpl.get() ); } Queue::~Queue() - { - ::queue_free( _pimpl ); - delete( _pimpl ); - } + { ::queue_free( _pimpl.get() ); } bool Queue::empty() const { return( _pimpl->count == 0 ); } @@ -54,48 +58,65 @@ namespace zypp Queue::const_iterator Queue::find( value_type val_r ) const { for_( it, begin(), end() ) - if ( *it != val_r ) + if ( *it == val_r ) return it; return end(); } Queue::value_type Queue::first() const { - if ( empty() ) - return 0; - return *_pimpl->elements; + if ( _pimpl->count ) + return *_pimpl->elements; + return 0; } Queue::value_type Queue::last() const { - if ( empty() ) - return 0; - return _pimpl->elements[_pimpl->count-1]; + if ( _pimpl->count ) + return _pimpl->elements[_pimpl->count-1]; + return 0; } +#define M_RANGE_CKECK(IDX,LOC) if ( IDX >= size_type(_pimpl->count) ) throw std::out_of_range( "zypp::sat::Queue::" LOC ) + + const Queue::value_type & Queue::at( size_type idx_r ) const + { M_RANGE_CKECK( idx_r, "at" ); return _pimpl->elements[idx_r]; } + + Queue::value_type & Queue::at( size_type idx_r ) + { M_RANGE_CKECK( idx_r, "at" ); return _pimpl->elements[idx_r]; } + + const Queue::value_type & Queue::operator[]( size_type idx_r ) const + { return _pimpl->elements[idx_r]; } + + Queue::value_type & Queue::operator[]( size_type idx_r ) + { return _pimpl->elements[idx_r]; } + void Queue::clear() { ::queue_empty( *this ); } void Queue::remove( value_type val_r ) { - const_iterator it( find( val_r ) ); - if ( it != end() ) - { - ::queue_delete( _pimpl, it - begin() ); - } + for ( const_iterator it( find( val_r ) ); it != end(); it = find( val_r ) ) + ::queue_delete( _pimpl.get(), it - begin() ); } void Queue::push( value_type val_r ) - { ::queue_push( _pimpl, val_r ); } + { ::queue_push( _pimpl.get(), val_r ); } + + void Queue::pushUnique( value_type val_r ) + { ::queue_pushunique( _pimpl.get(), val_r ); } Queue::value_type Queue::pop() - { return ::queue_pop( _pimpl ); } + { return ::queue_pop( _pimpl.get() ); } void Queue::push_front( value_type val_r ) - { ::queue_unshift( _pimpl, val_r ); } + { ::queue_unshift( _pimpl.get(), val_r ); } Queue::value_type Queue::pop_front() - { return ::queue_shift( _pimpl ); } + { return ::queue_shift( _pimpl.get() ); } + + Queue::operator struct ::_Queue *() // COW: nonconst version can't be inlined + { return _pimpl.get(); } // without exposing struct ::_Queue std::ostream & operator<<( std::ostream & str, const Queue & obj ) { return dumpRangeLine( str << "Queue ", obj.begin(), obj.end() ); } @@ -119,9 +140,7 @@ namespace zypp return( l == r || ( l->count == r->count && ::memcmp( l->elements, r->elements, l->count ) == 0 ) ); } - ///////////////////////////////////////////////////////////////// } // namespace sat /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/sat/Queue.h b/libzypp/zypp/sat/Queue.h index ec0af1d..c8563b6 100644 --- a/libzypp/zypp/sat/Queue.h +++ b/libzypp/zypp/sat/Queue.h @@ -17,19 +17,25 @@ extern "C" } #include -#include "zypp/base/NonCopyable.h" +#include "zypp/base/PtrTypes.h" #include "zypp/sat/detail/PoolMember.h" /////////////////////////////////////////////////////////////////// namespace zypp -{ ///////////////////////////////////////////////////////////////// +{ /////////////////////////////////////////////////////////////////// namespace sat - { ///////////////////////////////////////////////////////////////// - - /** Libsolv Id queue wrapper. - */ - class Queue : private base::NonCopyable + { + class Queue; + typedef Queue SolvableQueue; ///< Queue with Solvable ids + typedef Queue StringQueue; ///< Queue with String ids + + /////////////////////////////////////////////////////////////////// + /// \class Queue + /// \brief Libsolv Id queue wrapper. + /// \todo template value_type to work with IString and other Id based types + /////////////////////////////////////////////////////////////////// + class Queue { public: typedef unsigned size_type; @@ -61,6 +67,22 @@ namespace zypp /** Return the last Id in the queue or \c 0 if empty. */ value_type last() const; + /** Return the Id at \a idx_r in the queue + * \throws std::out_of_range if \a idx_r is out of range + */ + const value_type & at( size_type idx_r ) const; + + /** Return the Id at \a idx_r in the queue + * \throws std::out_of_range if \a idx_r is out of range + */ + value_type & at( size_type idx_r ); + + /** Return the Id at \a idx_r in the queue (no range check) */ + const value_type & operator[]( size_type idx_r ) const; + + /** Return the Id at \a idx_r in the queue (no range check) */ + value_type & operator[]( size_type idx_r ); + /** Clear the queue. */ void clear(); @@ -73,6 +95,9 @@ namespace zypp void push_back( value_type val_r ) { push( val_r ); } + /** Push a value if it's not yet in the Queue. */ + void pushUnique( value_type val_r ); + /** Pop and return the last Id from the queue or \c 0 if empty. */ value_type pop(); /** \overload */ @@ -86,22 +111,17 @@ namespace zypp value_type pop_front(); public: - /** Backdoor */ - operator struct ::_Queue *() - { return _pimpl; } - /** Backdoor */ - operator const struct ::_Queue *() const - { return _pimpl; } - + operator struct ::_Queue *(); ///< libsolv backdoor + operator const struct ::_Queue *() const ///< libsolv backdoor + { return _pimpl.get(); } private: - /** Pointer to implementation */ - struct ::_Queue * _pimpl; + RWCOW_pointer _pimpl; ///< Pointer to implementation }; /** \relates Queue Stream output */ std::ostream & operator<<( std::ostream & str, const Queue & obj ); - /** \relates Queue Verbose stream output */ + /** \relates Queue Stream output assuming a Solvable queue. */ std::ostream & dumpOn( std::ostream & str, const Queue & obj ); /** \relates Queue */ @@ -111,10 +131,12 @@ namespace zypp inline bool operator!=( const Queue & lhs, const Queue & rhs ) { return !( lhs == rhs ); } - ///////////////////////////////////////////////////////////////// } // namespace sat /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////// + + /** \relates Queue Clone function for RWCOW_pointer */ + template<> struct ::_Queue * rwcowClone( const struct ::_Queue * rhs ); + } // namespace zypp /////////////////////////////////////////////////////////////////// #endif // ZYPP_SAT_QUEUE_H diff --git a/libzypp/zypp/sat/SolvAttr.cc b/libzypp/zypp/sat/SolvAttr.cc index d4ae322..0233959 100644 --- a/libzypp/zypp/sat/SolvAttr.cc +++ b/libzypp/zypp/sat/SolvAttr.cc @@ -117,27 +117,34 @@ namespace sat const SolvAttr SolvAttr::productDistversion ( PRODUCT_DISTVERSION ); const SolvAttr SolvAttr::productType ( PRODUCT_TYPE ); const SolvAttr SolvAttr::productFlags ( PRODUCT_FLAGS ); + const SolvAttr SolvAttr::productEndOfLife ( PRODUCT_ENDOFLIFE ); const SolvAttr SolvAttr::productRegisterTarget ( PRODUCT_REGISTER_TARGET ); const SolvAttr SolvAttr::productRegisterRelease( PRODUCT_REGISTER_RELEASE ); + const SolvAttr SolvAttr::productRegisterFlavor ( PRODUCT_REGISTER_FLAVOR ); const SolvAttr SolvAttr::productUrl ( PRODUCT_URL ); const SolvAttr SolvAttr::productUrlType ( PRODUCT_URL_TYPE ); + /** array of repoids, hopefully label s too */ + const SolvAttr SolvAttr::productUpdates ( PRODUCT_UPDATES ); + const SolvAttr SolvAttr::productUpdatesRepoid ( PRODUCT_UPDATES_REPOID ); // repository - const SolvAttr SolvAttr::repositoryTimestamp ( REPOSITORY_TIMESTAMP ); - const SolvAttr SolvAttr::repositoryExpire ( REPOSITORY_EXPIRE ); + const SolvAttr SolvAttr::repositoryDeltaInfo ( REPOSITORY_DELTAINFO ); + const SolvAttr SolvAttr::repositoryAddedFileProvides ( REPOSITORY_ADDEDFILEPROVIDES ); + const SolvAttr SolvAttr::repositoryRpmDbCookie ( REPOSITORY_RPMDBCOOKIE ); + const SolvAttr SolvAttr::repositoryTimestamp ( REPOSITORY_TIMESTAMP ); + const SolvAttr SolvAttr::repositoryExpire ( REPOSITORY_EXPIRE ); /** array of repositoryProductLabel repositoryProductCpeid pairs */ - const SolvAttr SolvAttr::repositoryUpdates ( REPOSITORY_UPDATES ); + const SolvAttr SolvAttr::repositoryUpdates ( REPOSITORY_UPDATES ); /** array of repositoryProductLabel repositoryProductCpeid pairs */ - const SolvAttr SolvAttr::repositoryDistros ( REPOSITORY_DISTROS ); - const SolvAttr SolvAttr::repositoryProductLabel( REPOSITORY_PRODUCT_LABEL ); - const SolvAttr SolvAttr::repositoryProductCpeid( REPOSITORY_PRODUCT_CPEID ); - const SolvAttr SolvAttr::repositoryKeywords ( REPOSITORY_KEYWORDS ); + const SolvAttr SolvAttr::repositoryDistros ( REPOSITORY_DISTROS ); + const SolvAttr SolvAttr::repositoryProductLabel ( REPOSITORY_PRODUCT_LABEL ); + const SolvAttr SolvAttr::repositoryProductCpeid ( REPOSITORY_PRODUCT_CPEID ); + const SolvAttr SolvAttr::repositoryRepoid ( REPOSITORY_REPOID ); + const SolvAttr SolvAttr::repositoryKeywords ( REPOSITORY_KEYWORDS ); + const SolvAttr SolvAttr::repositoryRevision ( REPOSITORY_REVISION ); + const SolvAttr SolvAttr::repositoryToolVersion ( REPOSITORY_TOOLVERSION ); - const SolvAttr SolvAttr::repositoryAddedFileProvides( REPOSITORY_ADDEDFILEPROVIDES ); - const SolvAttr SolvAttr::repositoryRpmDbCookie ( REPOSITORY_RPMDBCOOKIE ); - const SolvAttr SolvAttr::repositoryDeltaInfo ( REPOSITORY_DELTAINFO ); - const SolvAttr SolvAttr::repositoryToolVersion ( REPOSITORY_TOOLVERSION ); ///////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/sat/SolvAttr.h b/libzypp/zypp/sat/SolvAttr.h index 92db5ca..fed49d8 100644 --- a/libzypp/zypp/sat/SolvAttr.h +++ b/libzypp/zypp/sat/SolvAttr.h @@ -146,26 +146,30 @@ namespace sat static const SolvAttr productDistversion; static const SolvAttr productType; static const SolvAttr productFlags; + static const SolvAttr productEndOfLife; static const SolvAttr productRegisterTarget; static const SolvAttr productRegisterRelease; + static const SolvAttr productRegisterFlavor; static const SolvAttr productUrl; static const SolvAttr productUrlType; - + static const SolvAttr productUpdates; // SUB-STRUCTURE: + static const SolvAttr productUpdatesRepoid; // repoid //@} /** \name repository */ //@{ + static const SolvAttr repositoryDeltaInfo; + static const SolvAttr repositoryAddedFileProvides; + static const SolvAttr repositoryRpmDbCookie; static const SolvAttr repositoryTimestamp; static const SolvAttr repositoryExpire; - static const SolvAttr repositoryKeywords; static const SolvAttr repositoryUpdates; static const SolvAttr repositoryDistros; static const SolvAttr repositoryProductLabel; static const SolvAttr repositoryProductCpeid; + static const SolvAttr repositoryRepoid; + static const SolvAttr repositoryKeywords; static const SolvAttr repositoryRevision; - static const SolvAttr repositoryAddedFileProvides; - static const SolvAttr repositoryRpmDbCookie; - static const SolvAttr repositoryDeltaInfo; static const SolvAttr repositoryToolVersion; //@} diff --git a/libzypp/zypp/sat/Solvable.cc b/libzypp/zypp/sat/Solvable.cc index 66dca77..0e84a0b 100644 --- a/libzypp/zypp/sat/Solvable.cc +++ b/libzypp/zypp/sat/Solvable.cc @@ -16,6 +16,7 @@ #include "zypp/base/Exception.h" #include "zypp/base/Functional.h" #include "zypp/base/Collector.h" +#include "zypp/base/Xml.h" #include "zypp/sat/detail/PoolImpl.h" #include "zypp/sat/Solvable.h" @@ -42,7 +43,7 @@ namespace zypp if ( ! _ident ) return; - ResKind explicitKind = Solvable::SplitIdent::explicitKind( _ident.c_str() ); + ResKind explicitKind = ResKind::explicitBuiltin( _ident.c_str() ); // NOTE: kind package and srcpackage do not have namespaced ident! if ( ! explicitKind ) { @@ -50,7 +51,7 @@ namespace zypp // No kind defaults to package if ( !_kind ) _kind = ResKind::package; - if ( ! ( _kind == ResKind::package || _kind == ResKind::srcpackage ) ) + else if ( ! ( _kind == ResKind::package || _kind == ResKind::srcpackage ) ) _ident = IdString( str::form( "%s:%s", _kind.c_str(), _ident.c_str() ) ); } else @@ -87,33 +88,6 @@ namespace zypp , _kind( kind_r ) { _doSplit( _ident, _kind, _name ); } - ResKind Solvable::SplitIdent::explicitKind( const char * ident_r ) - { - if ( ! ident_r ) - return ResKind(); - - const char * sep = ::strchr( ident_r, ':' ); - if ( ! sep ) - return ResKind(); - - ResKind ret; - if ( sep-ident_r >= 4 ) - { - switch ( ident_r[3] ) - { - #define OUTS(K,S) if ( !::strncmp( ident_r, ResKind::K.c_str(), S ) && ident_r[S] == ':' ) ret = ResKind::K - // ----v - case 'c': OUTS( patch, 5 ); break; - case 'd': OUTS( product, 7 ); break; - case 'k': OUTS( package, 7 ); break; - case 'p': OUTS( srcpackage, 10 ); break; - case 't': OUTS( pattern, 7 ); break; - #undef OUTS - } - } - return ret; - } - ///////////////////////////////////////////////////////////////// const Solvable Solvable::noSolvable; @@ -255,9 +229,11 @@ namespace zypp NO_SOLVABLE_RETURN( OnMediaLocation() ); // medianumber and path unsigned medianr; - char * file = ::solvable_get_location( _solvable, &medianr ); + const char * file = ::solvable_lookup_location( _solvable, &medianr ); if ( ! file ) return OnMediaLocation(); + if ( ! medianr ) + medianr = 1; OnMediaLocation ret; @@ -304,30 +280,18 @@ namespace zypp break; } + // either explicitly prefixed... const char * ident = IdString( _solvable->name ).c_str(); - const char * sep = ::strchr( ident, ':' ); + ResKind knownKind( ResKind::explicitBuiltin( ident ) ); + if ( knownKind ) + return knownKind; - // no ':' in package names (hopefully) + // ...or no ':' in package names (hopefully)... + const char * sep = ::strchr( ident, ':' ); if ( ! sep ) - return ResKind::package; + return ResKind::package; - // quick check for well known kinds - if ( sep-ident >= 4 ) - { - switch ( ident[3] ) - { -#define OUTS(K,S) if ( !::strncmp( ident, ResKind::K.c_str(), S ) ) return ResKind::K - // ----v - case 'c': OUTS( patch, 5 ); break; - case 'd': OUTS( product, 7 ); break; - case 'k': OUTS( package, 7 ); break; - case 'p': OUTS( srcpackage, 10 ); break; - case 't': OUTS( pattern, 7 ); break; -#undef OUTS - } - } - - // an unknown kind + // ...or something unknown. return ResKind( std::string( ident, sep-ident ) ); } @@ -509,6 +473,16 @@ namespace zypp IdString( _solvable->arch ).c_str() ); } + std::string Solvable::asUserString() const\ + { + NO_SOLVABLE_RETURN( (_id == detail::systemSolvableId ? "systemSolvable" : "noSolvable") ); + return str::form( "%s-%s.%s(%s)", + IdString( _solvable->name ).c_str(), + IdString( _solvable->evr ).c_str(), + IdString( _solvable->arch ).c_str(), + repository().asUserString().c_str() ); + } + bool Solvable::identical( Solvable rhs ) const { NO_SOLVABLE_RETURN( ! rhs.get() ); @@ -663,6 +637,18 @@ namespace zypp return str; } + std::ostream & dumpAsXmlOn( std::ostream & str, const Solvable & obj ) + { + xmlout::Node guard( str, "solvable" ); + + dumpAsXmlOn( *guard, obj.kind() ); + *xmlout::Node( *guard, "name" ) << obj.name(); + dumpAsXmlOn( *guard, obj.edition() ); + dumpAsXmlOn( *guard, obj.arch() ); + dumpAsXmlOn( *guard, obj.repository() ); + return str; + } + ///////////////////////////////////////////////////////////////// } // namespace sat /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/sat/Solvable.h b/libzypp/zypp/sat/Solvable.h index 0e71c5e..ffefa01 100644 --- a/libzypp/zypp/sat/Solvable.h +++ b/libzypp/zypp/sat/Solvable.h @@ -14,8 +14,6 @@ #include -#include "zypp/base/SafeBool.h" - #include "zypp/sat/detail/PoolMember.h" #include "zypp/sat/SolvAttr.h" #include "zypp/ResTraits.h" @@ -54,8 +52,7 @@ namespace zypp * packages as an own kind of solvable and map their arch to * \ref Arch_noarch. */ - class Solvable : protected detail::PoolMember, - private base::SafeBool + class Solvable : protected detail::PoolMember { public: typedef sat::detail::SolvableIdType IdType; @@ -73,10 +70,9 @@ namespace zypp /** Represents no \ref Solvable. */ static const Solvable noSolvable; -#ifndef SWIG // Swig treats it as syntax error /** Evaluate \ref Solvable in a boolean context (\c != \c noSolvable). */ - using base::SafeBool::operator bool_type; -#endif + explicit operator bool() const + { return get(); } /** Return whether this \ref Solvable belongs to the system repo. * \note This includes the otherwise hidden systemSolvable. @@ -190,6 +186,9 @@ namespace zypp */ std::string asString() const; + /** String representation "ident-edition.arch(repo)" or \c "noSolvable" */ + std::string asUserString() const; + /** Test whether two Solvables have the same content. * Basically the same name, edition, arch, vendor and buildtime. */ @@ -276,14 +275,6 @@ namespace zypp ResKind kind() const { return _kind; } IdString name() const { return _name; } - /** Return an idents explicit kind prefix, or \ref ResKind() if none. - * Mainly to detect wheter a given ident string is explicitly prefixed - * by a known kind (e.g \c pattern:foo or \c package:foo). - */ - static ResKind explicitKind( IdString ident_r ) { return explicitKind( ident_r.c_str() ); } - static ResKind explicitKind( const char * ident_r ); - static ResKind explicitKind( const std::string & ident_r ) { return explicitKind( ident_r.c_str() ); } - private: IdString _ident; ResKind _kind; @@ -295,11 +286,7 @@ namespace zypp ::_Solvable * get() const; /** Expert backdoor. */ IdType id() const { return _id; } - private: -#ifndef SWIG // Swig treats it as syntax error - friend base::SafeBool::operator bool_type() const; -#endif - bool boolTest() const { return get(); } + private: IdType _id; }; @@ -311,6 +298,9 @@ namespace zypp /** \relates Solvable More verbose stream output including dependencies */ std::ostream & dumpOn( std::ostream & str, const Solvable & obj ); + /** \relates Solvable XML output */ + std::ostream & dumpAsXmlOn( std::ostream & str, const Solvable & obj ); + /** \relates Solvable */ inline bool operator==( const Solvable & lhs, const Solvable & rhs ) { return lhs.get() == rhs.get(); } diff --git a/libzypp/zypp/sat/Transaction.cc b/libzypp/zypp/sat/Transaction.cc index 334ea5b..560c7b1 100644 --- a/libzypp/zypp/sat/Transaction.cc +++ b/libzypp/zypp/sat/Transaction.cc @@ -72,9 +72,9 @@ namespace zypp public: Impl() : _trans( ::transaction_create( nullptr ) ) - { memset( _trans, 0, sizeof(_trans) ); } + { memset( _trans, 0, sizeof(*_trans) ); } - Impl( Default ) + Impl( LoadFromPoolType ) : _watcher( myPool().serial() ) , _trans( nullptr ) { @@ -185,6 +185,16 @@ namespace zypp iterator find(const RW_pointer & self_r, const sat::Solvable & solv_r ) { detail::IdType * it( _find( solv_r ) ); return it ? iterator( self_r, it ) : end( self_r ); } + public: + int installedResult( Queue & result_r ) const + { return ::transaction_installedresult( _trans, result_r ); } + + StringQueue autoInstalled() const + { return _autoInstalled; } + + void autoInstalled( const StringQueue & queue_r ) + { _autoInstalled = queue_r; } + public: StepType stepType( Solvable solv_r ) const { @@ -277,6 +287,8 @@ namespace zypp set_type _systemErase; // @System packages to be eased (otherse are TRANSACTION_IGNORE) pmmap_type _pmMap; // Post mortem data of deleted @System solvables + StringQueue _autoInstalled; // ident strings of all packages that would be auto-installed after the transaction is run. + public: /** Offer default Impl. */ static shared_ptr nullimpl() @@ -302,8 +314,8 @@ namespace zypp : _pimpl( Impl::nullimpl() ) {} - Transaction::Transaction( Default ) - : _pimpl( new Impl( Default() ) ) + Transaction::Transaction( LoadFromPoolType ) + : _pimpl( new Impl( loadFromPool ) ) {} Transaction::~Transaction() @@ -339,6 +351,15 @@ namespace zypp Transaction::iterator Transaction::find( const sat::Solvable & solv_r ) { return _pimpl->find( _pimpl, solv_r ); } + int Transaction::installedResult( Queue & result_r ) const + { return _pimpl->installedResult( result_r ); } + + StringQueue Transaction::autoInstalled() const + { return _pimpl->autoInstalled(); } + + void Transaction::autoInstalled( const StringQueue & queue_r ) + { _pimpl->autoInstalled( queue_r ); } + std::ostream & operator<<( std::ostream & str, const Transaction & obj ) { return str << *obj._pimpl; } diff --git a/libzypp/zypp/sat/Transaction.h b/libzypp/zypp/sat/Transaction.h index f9bff55..fcb843f 100644 --- a/libzypp/zypp/sat/Transaction.h +++ b/libzypp/zypp/sat/Transaction.h @@ -19,12 +19,12 @@ extern "C" #include "zypp/base/PtrTypes.h" #include "zypp/base/Flags.h" -#include "zypp/base/SafeBool.h" #include "zypp/base/Iterator.h" #include "zypp/base/DefaultIntegral.h" #include "zypp/sat/SolvIterMixin.h" #include "zypp/sat/Solvable.h" +#include "zypp/sat/Queue.h" #include "zypp/PoolItem.h" @@ -53,7 +53,6 @@ namespace zypp * when iterating, use the \ref actionBegin /\ref actionEnd methods. */ class Transaction : public SolvIterMixin - , protected base::SafeBool { friend std::ostream & operator<<( std::ostream & str, const Transaction & obj ); friend std::ostream & dumpOn( std::ostream & str, const Transaction & obj ); @@ -83,14 +82,15 @@ namespace zypp ZYPP_DECLARE_FLAGS(StepStages,StepStage); public: - struct Default {}; ///< Ctor arg type + struct LoadFromPoolType {}; ///< Ctor arg type + static constexpr LoadFromPoolType loadFromPool = LoadFromPoolType(); public: /** Default ctor: empty transaction. */ Transaction(); /** Ctor loading the default pools transaction. */ - Transaction( Default ); + Transaction( LoadFromPoolType ); /** Dtor */ ~Transaction(); @@ -100,7 +100,8 @@ namespace zypp bool valid() const; /** Validate object in a boolean context: valid */ - using base::SafeBool::operator bool_type; + explicit operator bool() const + { return valid(); } /** Order transaction steps for commit. * It's cheap to call it for an aleready ordered \ref Transaction. @@ -170,11 +171,18 @@ namespace zypp //@} - private: - friend base::SafeBool::operator bool_type() const; - /** Validate object in a boolean context. */ - bool boolTest() const - { return valid(); } + public: + /** Return all packages that would be installed after the transaction is run. + * The new packages are put at the head of the queue, the number of new + * packages is returned. (wraps libsolv::transaction_installedresult) */ + int installedResult( Queue & result_r ) const; + + /** Return the ident strings of all packages that would be auto-installed after the transaction is run. */ + StringQueue autoInstalled() const; + + /** Set the ident strings of all packages that would be auto-installed after the transaction is run. */ + void autoInstalled( const StringQueue & queue_r ); + public: /** Implementation */ class Impl; diff --git a/libzypp/zypp/sat/WhatObsoletes.cc b/libzypp/zypp/sat/WhatObsoletes.cc index 740e4b5..52679fb 100644 --- a/libzypp/zypp/sat/WhatObsoletes.cc +++ b/libzypp/zypp/sat/WhatObsoletes.cc @@ -28,7 +28,11 @@ namespace zypp // Obsoletes may either match against provides, or names. // Configuration depends on the behaviour of rpm. +#ifdef _RPM_5 + bool obsoleteUsesProvides = true; +#else bool obsoleteUsesProvides = false; +#endif /////////////////////////////////////////////////////////////////// namespace diff --git a/libzypp/zypp/sat/detail/PoolImpl.cc b/libzypp/zypp/sat/detail/PoolImpl.cc index 622d199..eb77b4e 100644 --- a/libzypp/zypp/sat/detail/PoolImpl.cc +++ b/libzypp/zypp/sat/detail/PoolImpl.cc @@ -48,7 +48,17 @@ using std::endl; // /////////////////////////////////////////////////////////////////// namespace zypp -{ ///////////////////////////////////////////////////////////////// +{ + ///////////////////////////////////////////////////////////////// + namespace env + { + /** */ + inline int LIBSOLV_DEBUGMASK() + { + const char * envp = getenv("LIBSOLV_DEBUGMASK"); + return envp ? str::strtonum( envp ) : 0; + } + } // namespace env /////////////////////////////////////////////////////////////////// namespace sat { ///////////////////////////////////////////////////////////////// @@ -143,13 +153,6 @@ namespace zypp } break; - case NAMESPACE_PRODUCTBUDDY: - { - PoolItem pi( (Solvable(rhs)) ); - return( pi ? pi.buddy().id() : noId ); - } - - break; } WAR << "Unhandled " << Capability( lhs ) << " vs. " << Capability( rhs ) << endl; @@ -180,13 +183,23 @@ namespace zypp { ZYPP_THROW( Exception( _("Can not create sat-pool.") ) ); } + // by now we support only a RPM backend + ::pool_setdisttype(_pool, DISTTYPE_RPM ); + // initialialize logging - if ( getenv("ZYPP_LIBSOLV_FULLLOG") || getenv("ZYPP_LIBSAT_FULLLOG") ) - ::pool_setdebuglevel( _pool, 4 ); - else if ( getenv("ZYPP_FULLLOG") ) - ::pool_setdebuglevel( _pool, 2 ); + if ( env::LIBSOLV_DEBUGMASK() ) + { + ::pool_setdebugmask(_pool, env::LIBSOLV_DEBUGMASK() ); + } else - ::pool_setdebugmask(_pool, SOLV_DEBUG_JOB|SOLV_DEBUG_STATS); + { + if ( getenv("ZYPP_LIBSOLV_FULLLOG") || getenv("ZYPP_LIBSAT_FULLLOG") ) + ::pool_setdebuglevel( _pool, 3 ); + else if ( getenv("ZYPP_FULLLOG") ) + ::pool_setdebuglevel( _pool, 2 ); + else + ::pool_setdebugmask(_pool, SOLV_DEBUG_JOB|SOLV_DEBUG_STATS ); + } ::pool_setdebugcallback( _pool, logSat, NULL ); @@ -283,13 +296,10 @@ namespace zypp void PoolImpl::_deleteRepo( ::_Repo * repo_r ) { setDirty(__FUNCTION__, repo_r->name ); - ::repo_free( repo_r, /*reuseids*/false ); - eraseRepoInfo( repo_r ); if ( isSystemRepo( repo_r ) ) - { - // systemRepo added - _onSystemByUserListPtr.reset(); // re-evaluate - } + _autoinstalled.clear(); + eraseRepoInfo( repo_r ); + ::repo_free( repo_r, /*reuseids*/false ); } int PoolImpl::_addSolv( ::_Repo * repo_r, FILE * file_r ) @@ -352,11 +362,6 @@ namespace zypp blockBegin = blockSize = 0; } } - else - { - // systemRepo added - _onSystemByUserListPtr.reset(); // re-evaluate - } } detail::SolvableIdType PoolImpl::_addSolvables( ::_Repo * repo_r, unsigned count_r ) @@ -545,74 +550,6 @@ namespace zypp } } - void PoolImpl::onSystemByUserListInit() const - { - _onSystemByUserListPtr.reset( new OnSystemByUserList ); - OnSystemByUserList & onSystemByUserList( *_onSystemByUserListPtr ); - - Pathname root( ZConfig::instance().systemRoot() ); - if ( root.empty() ) - { - MIL << "Target not initialized." << endl; - return; - } - PathInfo pi( root / ZConfig::instance().historyLogFile() ); - MIL << "onSystemByUserList from history: " << pi << endl; - if ( ! pi.isFile() ) - return; - - // go and parse it: 'who' must constain an '@', then it was installed by user request. - // 2009-09-29 07:25:19|install|lirc-remotes|0.8.5-3.2|x86_64|root@opensuse|InstallationImage|a204211eb0... - std::ifstream infile( pi.path().c_str() ); - for( iostr::EachLine in( infile ); in; in.next() ) - { - const char * ch( (*in).c_str() ); - // start with year - if ( *ch < '1' || '9' < *ch ) - continue; - const char * sep1 = ::strchr( ch, '|' ); // | after date - if ( !sep1 ) - continue; - ++sep1; - // if logs an install or delete - bool installs = true; - if ( ::strncmp( sep1, "install|", 8 ) ) - { - if ( ::strncmp( sep1, "remove |", 8 ) ) - continue; // no install and no remove - else - installs = false; // remove - } - sep1 += 8; // | after what - // get the package name - const char * sep2 = ::strchr( sep1, '|' ); // | after name - if ( !sep2 || sep1 == sep2 ) - continue; - (*in)[sep2-ch] = '\0'; - IdString pkg( sep1 ); - // we're done, if a delete - if ( !installs ) - { - onSystemByUserList.erase( pkg ); - continue; - } - // now guess whether user installed or not (3rd next field contains 'user@host') - if ( (sep1 = ::strchr( sep2+1, '|' )) // | after version - && (sep1 = ::strchr( sep1+1, '|' )) // | after arch - && (sep2 = ::strchr( sep1+1, '|' )) ) // | after who - { - (*in)[sep2-ch] = '\0'; - if ( ::strchr( sep1+1, '@' ) ) - { - // by user - onSystemByUserList.insert( pkg ); - continue; - } - } - } - MIL << "onSystemByUserList found: " << onSystemByUserList.size() << endl; - } - const std::set & PoolImpl::requiredFilesystems() const { if ( ! _requiredFilesystemsPtr ) diff --git a/libzypp/zypp/sat/detail/PoolImpl.h b/libzypp/zypp/sat/detail/PoolImpl.h index d4a248f..8b4035a 100644 --- a/libzypp/zypp/sat/detail/PoolImpl.h +++ b/libzypp/zypp/sat/detail/PoolImpl.h @@ -25,6 +25,7 @@ extern "C" #include "zypp/base/NonCopyable.h" #include "zypp/base/SerialNumber.h" #include "zypp/sat/detail/PoolMember.h" +#include "zypp/sat/Queue.h" #include "zypp/RepoInfo.h" #include "zypp/Locale.h" #include "zypp/Capability.h" @@ -93,6 +94,22 @@ namespace zypp ::_Repo * systemRepo() const { return _pool->installed; } + /** Get rootdir (for file conflicts check) */ + Pathname rootDir() const + { + const char * rd = ::pool_get_rootdir( _pool ); + return( rd ? rd : "/" ); + } + + /** Set rootdir (for file conflicts check) */ + void rootDir( const Pathname & root_r ) + { + if ( root_r.empty() || root_r == "/" ) + ::pool_set_rootdir( _pool, nullptr ); + else + ::pool_set_rootdir( _pool, root_r.c_str() ); + } + public: /** \name Actions invalidating housekeeping data. * @@ -247,20 +264,16 @@ namespace zypp public: /** \name Installed on behalf of a user request hint. */ //@{ - typedef IdStringSet OnSystemByUserList; + /** Get ident list of all autoinstalled solvables. */ + StringQueue autoInstalled() const + { return _autoinstalled; } - const OnSystemByUserList & onSystemByUserList() const - { - if ( ! _onSystemByUserListPtr ) - onSystemByUserListInit(); - return *_onSystemByUserListPtr; - } + /** Set ident list of all autoinstalled solvables. */ + void setAutoInstalled( const StringQueue & autoInstalled_r ) + { _autoinstalled = autoInstalled_r; } bool isOnSystemByUser( IdString ident_r ) const - { - const OnSystemByUserList & l( onSystemByUserList() ); - return l.find( ident_r ) != l.end(); - } + { return !_autoinstalled.contains( ident_r.id() ); } //@} public: @@ -287,8 +300,7 @@ namespace zypp mutable scoped_ptr _multiversionListPtr; /** */ - void onSystemByUserListInit() const; - mutable scoped_ptr _onSystemByUserListPtr; + sat::StringQueue _autoinstalled; /** filesystems mentioned in /etc/sysconfig/storage */ mutable scoped_ptr > _requiredFilesystemsPtr; diff --git a/libzypp/zypp/solver/detail/InstallOrder.cc b/libzypp/zypp/solver/detail/InstallOrder.cc deleted file mode 100644 index b2d89db..0000000 --- a/libzypp/zypp/solver/detail/InstallOrder.cc +++ /dev/null @@ -1,376 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* InstallOrder.cc - * - * Copyright (C) 2005 SUSE Linux Products GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License, - * version 2, 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA. - */ - -// stolen from yast2-packagemanager -/* - File: InstallOrder.h - Purpose: Determine order for installing packages - Author: Ludwig Nussel - Maintainer: Ludwig Nussel - -/-*/ - -#include "zypp/solver/detail/InstallOrder.h" -#include "zypp/base/LogTools.h" -#include "zypp/base/Iterator.h" -#include "zypp/base/Algorithm.h" - -#include "zypp/solver/detail/SATResolver.h" - -#include "zypp/ResFilters.h" -#include "zypp/ResStatus.h" -#include "zypp/sat/Pool.h" -#include "zypp/sat/WhatObsoletes.h" - -///////////////////////////////////////////////////////////////////////// -namespace zypp -{ /////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////// - namespace solver - { ///////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////// - namespace detail - { /////////////////////////////////////////////////////////////////// - -using namespace std; -using namespace zypp; - -#define ITEMNAME(item) (item)->name() -//----------------------------------------------------------------------------- - -InstallOrder::InstallOrder( const ResPool & pool, const PoolItemSet & toinstall, const PoolItemSet & installed ) - : _pool( pool ) - , _toinstall( toinstall ) - , _installed( installed ) - , _dirty (true) - , _numrun (0) -{ - _DEBUG("InstallOrder::InstallOrder(_toinstall " << _toinstall.size() << " items, _installed " << _installed.size() << " items)"); -} - - -//----------------------------------------------------------------------------- - -void -InstallOrder::printAdj (std::ostream& os, bool reversed) const -{ - const Graph& g = (reversed ? _rgraph : _graph); - os << "digraph pkgdeps {" << endl; - for (Graph::const_iterator gcit = g.begin(); gcit != g.end(); ++gcit) - { - Nodes::const_iterator niit = _nodes.find(gcit->first); - int order = niit->second.order; - string name = gcit->first->name(); - os << "\"" << name << "\"" << "[label=\"" << name << "\\n" << order << "\""; - os << "] " << endl; - for (PoolItemList::const_iterator scit = gcit->second.begin(); scit != gcit->second.end(); ++scit) - { - os << "\"" << name << "\" -> \"" << (*scit)->name() << "\"" << endl; - } - } - os << "}" << endl; -} - - -//----------------------------------------------------------------------------- - -// yea, that stuff is suboptimal. there should be a heap sorted by order -PoolItemList -InstallOrder::computeNextSet() -{ - PoolItemList newlist; - - if (_dirty) startrdfs(); - - for (Nodes::iterator it = _nodes.begin(); it != _nodes.end(); ++it) - { - if (it->second.order == 0 - && it->second.item) // the default Nodes constructor leaves this empty - { - XXX << "InstallOrder::computeNextSet found " << ITEMNAME(it->second.item) << endl; - - newlist.push_back(it->second.item); - } - } - - return newlist; -} - - -// decrease order of every adjacent node -void -InstallOrder::setInstalled(PoolItem item ) -{ - _dirty = true; - - PoolItemList adj = _rgraph[item]; - - XXX << "InstallOrder::setInstalled " << ITEMNAME(item) << endl; - - // order will be < 0 - _nodes[item].order--; - _installed.insert( item ); - _toinstall.erase( item ); - - for (PoolItemList::iterator it = adj.begin(); it != adj.end(); ++it) - { - NodeInfo& info = _nodes[*it]; - info.order--; - if (info.order < 0) - { - WAR << "order of node " << (*it) << " is < 0" << endl; - } - } -} - - -void -InstallOrder::setInstalled( const PoolItemList & rl ) -{ - for (PoolItemList::const_iterator it = rl.begin(); it != rl.end(); ++it) - { - setInstalled(*it); - } -} - -//----------------------------------------------------------------------------- - -bool -InstallOrder::doesProvide( const Capability requirement, PoolItem item ) const -{ - Capabilities::const_iterator pend = item->dep( Dep::PROVIDES ).end(); - for( Capabilities::const_iterator pit = item->dep( Dep::PROVIDES ).begin(); pit != pend; ++pit) { - if( pit->matches( requirement ) == CapMatch::yes ) { - return item; - } - } - return PoolItem(); -} - - -PoolItem -InstallOrder::findProviderInSet( const Capability requirement, const PoolItemSet & candidates ) const -{ - for( PoolItemSet::const_iterator citer = candidates.begin(); citer != candidates.end(); citer++) { - if( doesProvide( requirement, *citer ) ) { - return *citer; - } - } - - return PoolItem(); -} - -//----------------------------------------------------------------------------- - - -void -InstallOrder::rdfsvisit (const PoolItem item) -{ - typedef list CapList; - CapList requires; - - XXX << "InstallOrder::rdfsvisit, visiting " << ITEMNAME(item) << endl; - - NodeInfo& nodeinfo = _nodes[item]; - - nodeinfo.visited = true; - nodeinfo.begintime = _rdfstime; - _rdfstime++; - - // items prereq - CapabilitySet prq( item->dep(Dep::PREREQUIRES).begin(), item->dep(Dep::PREREQUIRES).end() ); - // an installed items prereq (in case they are reqired for uninstall scripts) - ui::Selectable::Ptr sel( ui::Selectable::get( item ) ); - for_( it, sel->installedBegin(), sel->installedEnd() ) - { - Capabilities p( it->satSolvable().prerequires() ); - prq.insert( p.begin(), p.end() ); - } - // any obsoleted items prereq (in case they are reqired for uninstall scripts) - sat::WhatObsoletes obs( item ); - for_( it, obs.begin(), obs.end() ) - { - Capabilities p( it->prerequires() ); - prq.insert( p.begin(), p.end() ); - } - // put prerequires first and requires last on list to ensure - // that prerequires are processed first - for (CapabilitySet::const_iterator it = prq.begin(); it != prq.end(); ++it) - { - requires.push_back(*it); - } - - // Product requirements are ignored to assert Product gets installed - // as early as possible. Some stuff depends on it (e.g. registration). - if ( ! isKind( item.resolvable() ) ) - { - for (Capabilities::const_iterator it = item->dep (Dep::REQUIRES).begin(); it != item->dep (Dep::REQUIRES).end(); ++it) - { - requires.push_back(*it); - } - } - - for (CapList::const_iterator iter = requires.begin(); iter != requires.end(); ++iter) - { - bool goBack = false; - const Capability requirement = *iter; - PoolItemList providers; - - XXX << "check requirement " << requirement << " of " << ITEMNAME(item) << endl; - SATResolver satResolver(_pool, sat::Pool::instance().get()); - PoolItemList tovisit; - sat::WhatProvides possibleProviders(requirement); - - // first, look in _installed - for_( iter, possibleProviders.begin(), possibleProviders.end() ) { - PoolItem provider = ResPool::instance().find( *iter ); - if ( provider == item ) - { - goBack = true; - break; - } - if (_installed.find( provider ) != _installed.end()) // and is not installed - { - XXX << "tovisit " << ITEMNAME(provider) << endl; - providers.push_back (provider); - } - } - - if ( goBack ) - continue; - - // if not found in _installed, look in _toinstall - - if (providers.empty()) { - for_( iter, possibleProviders.begin(), possibleProviders.end() ) { - PoolItem provider = ResPool::instance().find( *iter ); - if ((provider.resolvable() != item.resolvable()) // resolvable could provide its own requirement - && (_toinstall.find( provider ) != _toinstall.end())) // and is not to be installed - { - XXX << "tovisit " << ITEMNAME(provider) << endl; - tovisit.push_back (provider); - } - } - } - - for (PoolItemList::iterator it = tovisit.begin(); it != tovisit.end(); ++it) - { - const PoolItem must_visit = *it; - if (_nodes[must_visit].visited == false) - { - nodeinfo.order++; - _rgraph[must_visit].push_back( item ); - _graph[item].push_back( must_visit ); - rdfsvisit( must_visit ); - } - else if (_nodes[must_visit].endtime == 0) - { - if (must_visit != item) - { - // log only the 1st occurrence. - std::string lstr( ITEMNAME(item) ); - lstr += " -> "; - lstr += ITEMNAME(must_visit); - if ( _logset.insert( lstr ).second ) - { - WAR << "** dependency loop: " << lstr << endl; - } - } - } - else - { - // filter multiple depends on same item (cosmetic) - PoolItemList & lrg = _rgraph[must_visit]; - if( find( lrg.begin(), lrg.end(), item) == lrg.end() ) - { - nodeinfo.order++; - lrg.push_back( item ); - - PoolItemList & lg = _graph[item]; - if( find( lg.begin(), lg.end(), must_visit ) == lg.end() ) - lg.push_back( must_visit ); - } - } - } - } - _topsorted.push_back(item); - _nodes[item].endtime = _rdfstime; - _rdfstime++; - - XXX << ITEMNAME(item) << " done" << endl; -} - - -void -InstallOrder::startrdfs() -{ - _nodes.clear(); - _rgraph.clear(); - _graph.clear(); - - _rdfstime = 1; - - _topsorted.clear(); - - _numrun++; - XXX << "run #" << _numrun << endl; - - // initialize all nodes - for (PoolItemSet::iterator it = _toinstall.begin(); it != _toinstall.end(); ++it) - { - PoolItem item = *it; - _nodes[item] = NodeInfo (item); - _rgraph[item] = PoolItemList(); - _graph[item] = PoolItemList(); - } - - // visit all nodes - for (PoolItemSet::iterator it = _toinstall.begin(); it != _toinstall.end(); ++it) - { - const PoolItem item = *it; - if (_nodes[item].visited == false) - { - XXX << "start recursion on " << ITEMNAME(item) << endl; - rdfsvisit (item); - } - } - - _dirty = false; -} - - -//----------------------------------------------------------------------------- - -const PoolItemList -InstallOrder::getTopSorted() const -{ - return _topsorted; -} - - -/////////////////////////////////////////////////////////////////// - };// namespace detail - ///////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////// - };// namespace solver - /////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////// -};// namespace zypp -///////////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/solver/detail/InstallOrder.h b/libzypp/zypp/solver/detail/InstallOrder.h deleted file mode 100644 index ce9fa8e..0000000 --- a/libzypp/zypp/solver/detail/InstallOrder.h +++ /dev/null @@ -1,169 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* InstallOrder.h - * - * Copyright (C) 2005 SUSE Linux Products GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License, - * version 2, 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA. - */ - -// stolen from yast2-packagemanager -/* - File: InstallOrder.h - Purpose: Determine order for installing packages - Author: Ludwig Nussel - Maintainer: Ludwig Nussel - -/-*/ - -#ifndef ZYPP_SOLVER_DETAIL_INSTALLORDER_H -#define ZYPP_SOLVER_DETAIL_INSTALLORDER_H - -#include -#include -#include -#include - -#include "zypp/PoolItem.h" -#include "zypp/ResPool.h" -#include "zypp/Capabilities.h" - -#include "zypp/solver/detail/Types.h" - -///////////////////////////////////////////////////////////////////////// -namespace zypp -{ /////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////// - namespace solver - { ///////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////// - namespace detail - { /////////////////////////////////////////////////////////////////// - -/** - * compute Installation order.
- * - * There are two Interfaces:
- * - getTopSorted: return flat list of packages in proper order
- * - computeNextSet: return only packages without requirements, see comment below
- * */ - -class InstallOrder -{ - private: - const ResPool & _pool; - PoolItemSet _toinstall; - PoolItemSet _installed; - - /** adjacency list type */ - typedef std::map Graph; - - /** adjacency list, package -> requirements */ - Graph _graph; - - /** reversed graph, package -> referers */ - Graph _rgraph; - - struct NodeInfo - { - unsigned begintime; - unsigned endtime; - bool visited; - int order; // number of incoming edges in reverse graph - - PoolItem item; - - NodeInfo() : begintime(0), endtime(0), visited(false), order(0) {} - NodeInfo(PoolItem item) : begintime(0), endtime(0), visited(false), order(0), item(item) {} - }; - - typedef std::map Nodes; - - Nodes _nodes; - - unsigned _rdfstime; - - PoolItemList _topsorted; - - bool _dirty; - - unsigned _numrun; - - std::set _logset; - - private: - void rdfsvisit (PoolItem item); - - PoolItem findProviderInSet( const Capability requirement, const PoolItemSet & candidates ) const; - bool doesProvide( const Capability requirement, PoolItem item ) const; - - public: - - /** - * Constructor - * - * @param toinstall Set of ResItems that have to be installed - * @param installed Set of ResItems that are already installed - * */ - InstallOrder( const ResPool & pool, const PoolItemSet & toinstall, const PoolItemSet & installed); - - /** - * Compute a list of ResItems which have no requirements and can be - * installed in parallel without conflicts. Use setInstalled to make - * computation of a different set possible */ - PoolItemList computeNextSet(); - - /** - * set a Solvable as installed, computeNextSet is able to compute a new - * set then - * */ - void setInstalled( PoolItem item ); - - /** - * like above, for convenience - * */ - void setInstalled( const PoolItemList & list ); - - /** - * recoursive depth first search, build internal trees - * */ - void startrdfs(); - - /** - * Initialize data structures. Must be called before any other - * function. - * */ - void init() { startrdfs(); } - - /** - * compute topological sorted list - * - * @return list of resolvables in an installable order - * */ - const PoolItemList getTopSorted() const; - - void printAdj (std::ostream & os, bool reversed = false) const; -}; - -/////////////////////////////////////////////////////////////////// - };// namespace detail - ///////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////// - };// namespace solver - /////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////// -};// namespace zypp -///////////////////////////////////////////////////////////////////////// - -#endif // ZYPP_SOLVER_DETAIL_INSTALLORDER_H diff --git a/libzypp/zypp/solver/detail/Resolver.cc b/libzypp/zypp/solver/detail/Resolver.cc index 2c4a9f3..1658e88 100644 --- a/libzypp/zypp/solver/detail/Resolver.cc +++ b/libzypp/zypp/solver/detail/Resolver.cc @@ -90,7 +90,7 @@ Resolver::Resolver (const ResPool & pool) , _allowVendorChange ( ZConfig::instance().solver_allowVendorChange() ) , _solveSrcPackages ( false ) , _cleandepsOnRemove ( ZConfig::instance().solver_cleandepsOnRemove() ) - , _ignoreAlreadyRecommended ( false ) + , _ignoreAlreadyRecommended ( true ) { sat::Pool satPool( sat::Pool::instance() ); @@ -361,7 +361,10 @@ bool Resolver::resolveQueue( solver::detail::SolverQueueItemList & queue ) sat::Transaction Resolver::getTransaction() { - return sat::Transaction( sat::Transaction::Default() ); + // FIXME: That's an ugly way of pushing autoInstalled into the transaction. + sat::Transaction ret( sat::Transaction::loadFromPool ); + ret.autoInstalled( _satResolver->autoInstalled() ); + return ret; } diff --git a/libzypp/zypp/solver/detail/SATResolver.cc b/libzypp/zypp/solver/detail/SATResolver.cc index 31cb87b..82a7e4f 100644 --- a/libzypp/zypp/solver/detail/SATResolver.cc +++ b/libzypp/zypp/solver/detail/SATResolver.cc @@ -57,6 +57,25 @@ extern "C" ///////////////////////////////////////////////////////////////////////// namespace zypp { /////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////// + namespace env + { + inline bool HACKENV( const char * var_r, bool default_r ) + { + bool ret = default_r; + const char * val = ::getenv( var_r ); + if ( val ) + { + ret = str::strToBool( val, default_r ); + if ( ret != default_r ) + INT << "HACKENV " << var_r << " = " << ret << endl; + } + return ret; + } + } // namespace env + ///////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////// namespace solver { ///////////////////////////////////////////////////////////////////// @@ -112,20 +131,34 @@ SATResolver::dumpOn( std::ostream & os ) const { os << "" << endl; if (_solv) { - // os << " fixsystem = " << _solv->fixsystem << endl; - // os << " updatesystem = " << _solv->updatesystem << endl; - os << " allowdowngrade = " << solver_get_flag(_solv, SOLVER_FLAG_ALLOW_DOWNGRADE) << endl; - os << " allowarchchange = " << solver_get_flag(_solv, SOLVER_FLAG_ALLOW_ARCHCHANGE) << endl; - os << " allowvendorchange = " << solver_get_flag(_solv, SOLVER_FLAG_ALLOW_VENDORCHANGE) << endl; - os << " allowuninstall = " << solver_get_flag(_solv, SOLVER_FLAG_ALLOW_UNINSTALL) << endl; - os << " noupdateprovide = " << solver_get_flag(_solv, SOLVER_FLAG_NO_UPDATEPROVIDE) << endl; - os << " dosplitprovides = " << solver_get_flag(_solv, SOLVER_FLAG_SPLITPROVIDES) << endl; - os << " onlyRequires = " << solver_get_flag(_solv, SOLVER_FLAG_IGNORE_RECOMMENDED) << endl; - os << " ignorealreadyrecommended = " << !solver_get_flag(_solv, SOLVER_FLAG_ADD_ALREADY_RECOMMENDED) << endl; - os << " distupgrade = " << _distupgrade << endl; - os << " distupgrade_removeunsupported = " << _distupgrade_removeunsupported << endl; - os << " solveSrcPackages = " << _solveSrcPackages << endl; - os << " cleandepsOnRemove = " << _cleandepsOnRemove << endl; +#define OUTS(X) os << " " << #X << "\t= " << solver_get_flag(_solv, SOLVER_FLAG_##X) << endl + OUTS( ALLOW_DOWNGRADE ); + OUTS( ALLOW_ARCHCHANGE ); + OUTS( ALLOW_VENDORCHANGE ); + OUTS( ALLOW_UNINSTALL ); + OUTS( NO_UPDATEPROVIDE ); + OUTS( SPLITPROVIDES ); + OUTS( IGNORE_RECOMMENDED ); + OUTS( ADD_ALREADY_RECOMMENDED ); + OUTS( NO_INFARCHCHECK ); + OUTS( ALLOW_NAMECHANGE ); + OUTS( KEEP_EXPLICIT_OBSOLETES ); + OUTS( BEST_OBEY_POLICY ); + OUTS( NO_AUTOTARGET ); + OUTS( DUP_ALLOW_DOWNGRADE ); + OUTS( DUP_ALLOW_ARCHCHANGE ); + OUTS( DUP_ALLOW_VENDORCHANGE ); + OUTS( DUP_ALLOW_NAMECHANGE ); + OUTS( KEEP_ORPHANS ); + OUTS( BREAK_ORPHANS ); + OUTS( FOCUS_INSTALLED ); + OUTS( YUM_OBSOLETES ); +#undef OUTS + os << " distupgrade = " << _distupgrade << endl; + os << " distupgrade_removeunsupported = " << _distupgrade_removeunsupported << endl; + os << " solveSrcPackages = " << _solveSrcPackages << endl; + os << " cleandepsOnRemove = " << _cleandepsOnRemove << endl; + os << " fixsystem = " << _fixsystem << endl; } else { os << ""; } @@ -147,7 +180,7 @@ SATResolver::SATResolver (const ResPool & pool, Pool *SATPool) , _noupdateprovide(false) , _dosplitprovides(false) , _onlyRequires(ZConfig::instance().solver_onlyRequires()) - , _ignorealreadyrecommended(false) + , _ignorealreadyrecommended(true) , _distupgrade(false) , _distupgrade_removeunsupported(false) , _solveSrcPackages(false) @@ -422,7 +455,7 @@ SATResolver::solving(const CapabilitySet & requires_caps, const CapabilitySet & conflict_caps) { _solv = solver_create( _SATPool ); - _solv->vendorCheckCb = &vendorCheck; + ::pool_set_custom_vendorcheck( _SATPool, &vendorCheck ); if (_fixsystem) { queue_push( &(_jobQueue), SOLVER_VERIFY|SOLVER_SOLVABLE_ALL); queue_push( &(_jobQueue), 0 ); @@ -448,6 +481,13 @@ SATResolver::solving(const CapabilitySet & requires_caps, solver_set_flag(_solv, SOLVER_FLAG_NO_UPDATEPROVIDE, _noupdateprovide); solver_set_flag(_solv, SOLVER_FLAG_IGNORE_RECOMMENDED, _onlyRequires); +#define HACKENV(X,D) solver_set_flag(_solv, X, env::HACKENV( #X, D ) ); + HACKENV( SOLVER_FLAG_DUP_ALLOW_DOWNGRADE, true ); + HACKENV( SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE, true ); + HACKENV( SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE,true ); + HACKENV( SOLVER_FLAG_DUP_ALLOW_NAMECHANGE, true ); +#undef HACKENV + sat::Pool::instance().prepareForSolving(); // Solve ! @@ -663,15 +703,7 @@ SATResolver::solverInit(const PoolItemList & weakItems) queue_push( &(_jobQueue), it->id() ); } - if ( cleandepsOnRemove() ) - { - // Add all items known to be installed by user request (not solver selected). - for_( it, sat::Pool::instance().onSystemByUserBegin(), sat::Pool::instance().onSystemByUserEnd() ) - { - queue_push( &(_jobQueue), SOLVER_USERINSTALLED | SOLVER_SOLVABLE_NAME ); - queue_push( &(_jobQueue), it->id() ); - } - } + ::pool_add_userinstalled_jobs(_SATPool, sat::Pool::instance().autoInstalled(), &(_jobQueue), GET_USERINSTALLED_NAMES|GET_USERINSTALLED_INVERTED); if ( _distupgrade ) { @@ -686,8 +718,8 @@ SATResolver::solverInit(const PoolItemList & weakItems) if ( (*it)->onSystem() ) // (to install) or (not to delete) { Product::constPtr prodCand( (*it)->candidateAsKind() ); - if ( ! prodCand || (*it)->identicalInstalledCandidate() ) - continue; // product no longer available or unchanged + if ( ! prodCand ) + continue; // product no longer available CapabilitySet droplist( prodCand->droplist() ); dumpRangeLine( MIL << "Droplist for " << (*it)->candidateObj() << ": " << droplist.size() << " ", droplist.begin(), droplist.end() ) << endl; @@ -845,7 +877,7 @@ void SATResolver::doUpdate() setLocks(); _solv = solver_create( _SATPool ); - _solv->vendorCheckCb = &vendorCheck; + ::pool_set_custom_vendorcheck( _SATPool, &vendorCheck ); if (_fixsystem) { queue_push( &(_jobQueue), SOLVER_VERIFY|SOLVER_SOLVABLE_ALL); queue_push( &(_jobQueue), 0 ); @@ -997,6 +1029,9 @@ string SATResolver::SATprobleminfoString(Id problem, string &detail, Id &ignoreI sat::Solvable s, s2; ignoreId = 0; + + // FIXME: solver_findallproblemrules to get all rules for this problem + // (the 'most relevabt' one returned by solver_findproblemrule is embedded probr = solver_findproblemrule(_solv, problem); switch (solver_ruleinfo(_solv, probr, &source, &target, &dep)) { @@ -1022,6 +1057,16 @@ string SATResolver::SATprobleminfoString(Id problem, string &detail, Id &ignoreI ret = str::form (_("nothing provides requested %s"), pool_dep2str(pool, dep)); detail += _("Have you enabled all requested repositories?"); break; + case SOLVER_RULE_JOB_UNKNOWN_PACKAGE: + ret = str::form (_("package %s does not exist"), pool_dep2str(pool, dep)); + detail += _("Have you enabled all requested repositories?"); + break; + case SOLVER_RULE_JOB_UNSUPPORTED: + ret = _("unsupported request"); + break; + case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM: + ret = str::form (_("%s is provided by the system and cannot be erased"), pool_dep2str(pool, dep)); + break; case SOLVER_RULE_RPM_NOT_INSTALLABLE: s = mapSolvable (source); ret = str::form (_("%s is not installable"), s.asString().c_str()); @@ -1156,7 +1201,7 @@ SATResolver::problems () if (poolItem) { if (pool->installed && s.get()->repo == pool->installed) { problemSolution->addSingleAction (poolItem, REMOVE); - string description = str::form (_("do not keep %s installed"), s.asString().c_str() ); + string description = str::form (_("remove lock to allow removal of %s"), s.asString().c_str() ); MIL << description << endl; problemSolution->addDescription (description); } else { @@ -1181,7 +1226,7 @@ SATResolver::problems () problemSolution->addDescription (description); } else { problemSolution->addSingleAction (poolItem, UNLOCK); - string description = str::form (_("do not forbid installation of %s"), itemToString( poolItem ).c_str()); + string description = str::form (_("remove lock to allow installation of %s"), itemToString( poolItem ).c_str()); MIL << description << endl; problemSolution->addDescription (description); } @@ -1481,6 +1526,22 @@ void SATResolver::setSystemRequirements() } } +sat::StringQueue SATResolver::autoInstalled() const +{ + sat::StringQueue ret; + if ( _solv ) + ::solver_get_userinstalled( _solv, ret, GET_USERINSTALLED_NAMES|GET_USERINSTALLED_INVERTED ); + return ret; +} + +sat::StringQueue SATResolver::userInstalled() const +{ + sat::StringQueue ret; + if ( _solv ) + ::solver_get_userinstalled( _solv, ret, GET_USERINSTALLED_NAMES ); + return ret; +} + /////////////////////////////////////////////////////////////////// };// namespace detail diff --git a/libzypp/zypp/solver/detail/SATResolver.h b/libzypp/zypp/solver/detail/SATResolver.h index 7aaef03..2d645da 100644 --- a/libzypp/zypp/solver/detail/SATResolver.h +++ b/libzypp/zypp/solver/detail/SATResolver.h @@ -216,6 +216,8 @@ class SATResolver : public base::ReferenceCounted, private base::NonCopyable { PoolItemList resultItemsToRemove () { return _result_items_to_remove; } PoolItemList problematicUpdateItems() { return _problem_items; } + sat::StringQueue autoInstalled() const; + sat::StringQueue userInstalled() const; }; /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/solver/detail/SolutionAction.cc b/libzypp/zypp/solver/detail/SolutionAction.cc index c2498ea..77d3b39 100644 --- a/libzypp/zypp/solver/detail/SolutionAction.cc +++ b/libzypp/zypp/solver/detail/SolutionAction.cc @@ -71,8 +71,6 @@ TransactionSolutionAction::dumpOn( ostream& os) const case ADD_SOLVE_QUEUE_ITEM: os << "Add SolveQueueItem " << _solverQueueItem; break; case REMOVE_SOLVE_QUEUE_ITEM: os << "Remove SolveQueueItem " << _solverQueueItem; break; } - - os << endl; return os; } @@ -110,7 +108,6 @@ InjectSolutionAction::dumpOn( ostream& os ) const } os << " "; os << _item; - os << endl; return os; } @@ -159,7 +156,7 @@ TransactionSolutionAction::execute(Resolver & resolver) const _item.status().resetTransact (ResStatus::USER); ret = _item.status().setLock (true, ResStatus::APPL_HIGH); // APPL_HIGH: Locking should not be saved permanently if (!ret) ERR << "Cannot lock " << _item << endl; - break; + break; case REMOVE_EXTRA_REQUIRE: resolver.removeExtraRequire (_capability); break; diff --git a/libzypp/zypp/solver/detail/SolutionAction.h b/libzypp/zypp/solver/detail/SolutionAction.h index 2b03a6c..84b49db 100644 --- a/libzypp/zypp/solver/detail/SolutionAction.h +++ b/libzypp/zypp/solver/detail/SolutionAction.h @@ -108,7 +108,7 @@ namespace zypp // ---------------------------------- accessors const PoolItem item() const { return _item; } - const Capability capability() const { return _capability; } + const Capability capability() const { return _capability; } TransactionKind action() const { return _action; } // ---------------------------------- methods @@ -119,7 +119,7 @@ namespace zypp PoolItem _item; Capability _capability; SolverQueueItem_Ptr _solverQueueItem; - + const TransactionKind _action; }; @@ -148,7 +148,7 @@ namespace zypp InjectSolutionAction( PoolItem item, const InjectSolutionKind & kind) : SolutionAction(), - _item( item ), + _item( item ), _kind( kind ) {} // ---------------------------------- I/O diff --git a/libzypp/zypp/solver/detail/SystemCheck.cc b/libzypp/zypp/solver/detail/SystemCheck.cc index 3bc58cc..cd6da86 100644 --- a/libzypp/zypp/solver/detail/SystemCheck.cc +++ b/libzypp/zypp/solver/detail/SystemCheck.cc @@ -30,7 +30,6 @@ namespace zypp { ///////////////////////////////////////////////////////////////// Pathname _file = ""; - Pathname _dir = ""; CapabilitySet _require; CapabilitySet _conflict; @@ -43,40 +42,24 @@ namespace zypp } - SystemCheck::SystemCheck() { + SystemCheck::SystemCheck() { if (_file.empty()) { _file = ZConfig::instance().solver_checkSystemFile(); - loadFile(_file); + loadFile(); } - if (_dir.empty()) { - _dir = ZConfig::instance().solver_checkSystemFileDir(); - loadFiles(); - } } bool SystemCheck::setFile(const Pathname & file) const{ MIL << "Setting checkFile to : " << file << endl; _file = file; - loadFile(_file); + loadFile(); return true; } - bool SystemCheck::setDir(const Pathname & dir) const { - MIL << "Setting checkFile directory to : " << dir << endl; - loadFile(_file); - _dir = dir; - loadFiles(); - return true; - } - const Pathname & SystemCheck::file() { return _file; } - const Pathname & SystemCheck::dir() { - return _dir; - } - const CapabilitySet & SystemCheck::requiredSystemCap() const{ return _require; } @@ -85,23 +68,21 @@ namespace zypp return _conflict; } - bool SystemCheck::loadFile(Pathname & file, bool reset_caps) const{ + bool SystemCheck::loadFile() const{ Target_Ptr trg( getZYpp()->getTarget() ); if ( trg ) - file = trg->assertRootPrefix( file ); + _file = trg->assertRootPrefix( _file ); - PathInfo pi( file ); + PathInfo pi( _file ); if ( ! pi.isFile() ) { - WAR << "Can't read " << file << " " << pi << endl; + WAR << "Can't read " << _file << " " << pi << endl; return false; } - if (reset_caps) { - _require.clear(); - _conflict.clear(); - } + _require.clear(); + _conflict.clear(); - std::ifstream infile( file.c_str() ); + std::ifstream infile( _file.c_str() ); for( iostr::EachLine in( infile ); in; in.next() ) { std::string l( str::trim(*in) ); if ( ! l.empty() && l[0] != '#' ) @@ -126,25 +107,6 @@ namespace zypp return true; } - bool SystemCheck::loadFiles() const { - - filesystem::dirForEach(_dir, - [this](const Pathname & dir_r, const char *const & name_r)->bool - { - const std::string wanted = ".check"; - Pathname pth = dir_r/name_r; - if (pth.extension() != wanted) { - MIL << "Skipping " << pth << " (not a *.check file)" << endl; - return true; - } - else { - MIL << "Reading " << pth << endl; - return loadFile(pth, false /* do not reset caps */); - } - }); - return true; - } - /****************************************************************** ** diff --git a/libzypp/zypp/solver/detail/SystemCheck.h b/libzypp/zypp/solver/detail/SystemCheck.h index 41cdd3d..92a8659 100644 --- a/libzypp/zypp/solver/detail/SystemCheck.h +++ b/libzypp/zypp/solver/detail/SystemCheck.h @@ -38,20 +38,11 @@ namespace zypp /** Return the file path. */ const Pathname & file(); - /** Return the directory path. */ - const Pathname & dir(); - /** Set configuration file of system requirements * Should be used for testcase only */ bool setFile(const Pathname & file) const; - /** Set configuration directory for files of system - * requirements. - * Should be used for testcase only - */ - bool setDir(const Pathname & dir) const; - /** Returns a list of required system capabilities. */ const CapabilitySet & requiredSystemCap() const; @@ -63,8 +54,8 @@ namespace zypp private: /** Ctor taking the file to read. */ SystemCheck(); - bool loadFile(Pathname &file, bool reset_caps = true) const; - bool loadFiles() const; + bool loadFile() const; + }; /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/solver/detail/Testcase.cc b/libzypp/zypp/solver/detail/Testcase.cc index c5ff70c..c25ebab 100644 --- a/libzypp/zypp/solver/detail/Testcase.cc +++ b/libzypp/zypp/solver/detail/Testcase.cc @@ -29,6 +29,7 @@ #include "zypp/PathInfo.h" #include "zypp/ResPool.h" #include "zypp/Repository.h" +#include "zypp/target/modalias/Modalias.h" #include "zypp/sat/detail/PoolImpl.h" #include "zypp/solver/detail/SystemCheck.h" @@ -119,6 +120,10 @@ std::string helixXML( const Capability &cap ) str << "" << endl; + } else if (detail.capRel() == CapDetail::CAP_NAMESPACE + && detail.lhs().id() == NAMESPACE_OTHERPROVIDERS) { + str << "" << endl; } else { // modalias ? IdString packageName; @@ -275,10 +280,12 @@ class HelixControl { const RepositoryTable & sourceTable, const Arch & systemArchitecture, const LocaleSet &languages, - const std::string & systemPath = "solver-system.xml.gz", - const bool forceResolve = false, - const bool onlyRequires = false, - const bool ignorealreadyrecommended = false); + const target::Modalias::ModaliasList & modaliasList, + const std::set & multiversionSpec, + const std::string & systemPath, + const bool forceResolve, + const bool onlyRequires, + const bool ignorealreadyrecommended); HelixControl (); ~HelixControl (); @@ -304,6 +311,8 @@ HelixControl::HelixControl(const std::string & controlPath, const RepositoryTable & repoTable, const Arch & systemArchitecture, const LocaleSet &languages, + const target::Modalias::ModaliasList & modaliasList, + const std::set & multiversionSpec, const std::string & systemPath, const bool forceResolve, const bool onlyRequires, @@ -342,16 +351,26 @@ HelixControl::HelixControl(const std::string & controlPath, << " priority=\"" << repo.priority() << "\" />" << endl << endl; } + for (LocaleSet::const_iterator iter = languages.begin(); iter != languages.end(); iter++) { *file << TAB << "code() << "\" />" << endl; } + for_( it, modaliasList.begin(), modaliasList.end() ) { + *file << TAB << "" << endl; + } + + for_( it, multiversionSpec.begin(), multiversionSpec.end() ) { + *file << TAB << "" << endl; + } + if (forceResolve) *file << TAB << "" << endl; if (onlyRequires) *file << TAB << "" << endl; - if (ignorealreadyrecommended) *file << TAB << "" << endl; @@ -538,6 +557,8 @@ bool Testcase::createTestcase(Resolver & resolver, bool dumpPool, bool runSolver repoTable, ZConfig::instance().systemArchitecture(), pool.getRequestedLocales(), + target::Modalias::instance().modaliasList(), + ZConfig::instance().multiversionSpec(), "solver-system.xml.gz", resolver.forceResolve(), resolver.onlyRequires(), diff --git a/libzypp/zypp/solver/libzypp_solver.h b/libzypp/zypp/solver/libzypp_solver.h index fab8352..2c864ed 100644 --- a/libzypp/zypp/solver/libzypp_solver.h +++ b/libzypp/zypp/solver/libzypp_solver.h @@ -26,6 +26,5 @@ #include "zypp/solver/detail/ResolverProblem.h" #include "zypp/solver/detail/ProblemSolution.h" #include "zypp/solver/detail/SolutionAction.h" -#include "zypp/solver/detail/InstallOrder.h" #endif // ZYPP_SOLVER_DETAIL_LIBZYPP_H diff --git a/libzypp/zypp/target/CommitPackageCache.cc b/libzypp/zypp/target/CommitPackageCache.cc index 11425c0..07a51c4 100644 --- a/libzypp/zypp/target/CommitPackageCache.cc +++ b/libzypp/zypp/target/CommitPackageCache.cc @@ -19,6 +19,11 @@ using std::endl; +#include "zypp/target/rpm/librpmDb.h" +#include "zypp/repo/PackageProvider.h" +#include "zypp/repo/DeltaCandidates.h" +#include "zypp/ResPool.h" + /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// @@ -26,6 +31,71 @@ namespace zypp namespace target { ///////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// + namespace { + /////////////////////////////////////////////////////////////////// + /// \class QueryInstalledEditionHelper + /// \short Helper for PackageProvider queries during download. + /////////////////////////////////////////////////////////////////// + struct QueryInstalledEditionHelper + { + bool operator()( const std::string & name_r, const Edition & ed_r, const Arch & arch_r ) const + { + rpm::librpmDb::db_const_iterator it; + for ( it.findByName( name_r ); *it; ++it ) + { + if ( arch_r == it->tag_arch() + && ( ed_r == Edition::noedition || ed_r == it->tag_edition() ) ) + { + return true; + } + } + return false; + } + }; + } // namespace + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + // + // class RepoProvidePackage + // + /////////////////////////////////////////////////////////////////// + + struct RepoProvidePackage::Impl + { + repo::RepoMediaAccess _access; + std::list _repos; + repo::PackageProviderPolicy _packageProviderPolicy; + }; + + RepoProvidePackage::RepoProvidePackage() + : _impl( new Impl ) + { + const ResPool & pool( ResPool::instance() ); + _impl->_repos.insert( _impl->_repos.begin(), pool.knownRepositoriesBegin(), pool.knownRepositoriesEnd() ); + _impl->_packageProviderPolicy.queryInstalledCB( QueryInstalledEditionHelper() ); + } + + RepoProvidePackage::~RepoProvidePackage() + {} + + ManagedFile RepoProvidePackage::operator()( const PoolItem & pi, bool fromCache_r ) + { + Package::constPtr p = asKind(pi.resolvable()); + if ( fromCache_r ) + { + repo::PackageProvider pkgProvider( _impl->_access, p, repo::DeltaCandidates(), _impl->_packageProviderPolicy ); + return pkgProvider.providePackageFromCache(); + } + else + { + repo::DeltaCandidates deltas( _impl->_repos, p->name() ); + repo::PackageProvider pkgProvider( _impl->_access, p, deltas, _impl->_packageProviderPolicy ); + return pkgProvider.providePackage(); + } + } + /////////////////////////////////////////////////////////////////// // // CLASS NAME : CommitPackageCache @@ -57,13 +127,17 @@ namespace zypp {} void CommitPackageCache::setCommitList( std::vector commitList_r ) - { - _pimpl->setCommitList( commitList_r ); - } + { _pimpl->setCommitList( commitList_r ); } ManagedFile CommitPackageCache::get( const PoolItem & citem_r ) { return _pimpl->get( citem_r ); } + bool CommitPackageCache::preloaded() const + { return _pimpl->preloaded(); } + + void CommitPackageCache::preloaded( bool newval_r ) + { _pimpl->preloaded( newval_r ); } + /****************************************************************** ** ** FUNCTION NAME : operator<< diff --git a/libzypp/zypp/target/CommitPackageCache.h b/libzypp/zypp/target/CommitPackageCache.h index c1c5797..2cf6220 100644 --- a/libzypp/zypp/target/CommitPackageCache.h +++ b/libzypp/zypp/target/CommitPackageCache.h @@ -28,6 +28,27 @@ namespace zypp namespace target { ///////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// + /// \class RepoProvidePackage + /// \short Default PackageProvider for \ref CommitPackageCache + /// + /// \p pool_r \ref ResPool used to get candidates + /// \p pi item to be commited + /////////////////////////////////////////////////////////////////// + class RepoProvidePackage + { + public: + RepoProvidePackage(); + ~RepoProvidePackage(); + + /** Provide package optionally fron cache only. */ + ManagedFile operator()( const PoolItem & pi, bool fromCache_r ); + + private: + struct Impl; + RW_pointer _impl; + }; + /////////////////////////////////////////////////////////////////// // // CLASS NAME : CommitPackageCache @@ -39,12 +60,12 @@ namespace zypp friend std::ostream & operator<<( std::ostream & str, const CommitPackageCache & obj ); public: - typedef function PackageProvider; + typedef function PackageProvider; public: /** Ctor */ CommitPackageCache( const Pathname & rootDir_r, - const PackageProvider & packageProvider_r ); + const PackageProvider & packageProvider_r = RepoProvidePackage() ); /** Dtor */ ~CommitPackageCache(); @@ -59,6 +80,17 @@ namespace zypp /** Provide a package. */ ManagedFile get( const PoolItem & citem_r ); + /** \overload */ + ManagedFile get( sat::Solvable citem_r ) + { return get( PoolItem(citem_r) ); } + + /** Whether preloaded hint is set. + * If preloaded the cache tries to avoid trigering the infoInCache CB, + * based on the assumption this was already done when preloading the cache. + */ + bool preloaded() const; + /** Set preloaded hint. */ + void preloaded( bool newval_r ); public: /** Implementation. */ diff --git a/libzypp/zypp/target/CommitPackageCacheImpl.h b/libzypp/zypp/target/CommitPackageCacheImpl.h index 41f8c1e..c7ac702 100644 --- a/libzypp/zypp/target/CommitPackageCacheImpl.h +++ b/libzypp/zypp/target/CommitPackageCacheImpl.h @@ -61,6 +61,15 @@ namespace zypp void setCommitList( std::vector commitList_r ) { _commitList = commitList_r; } + const std::vector & commitList() const + { return _commitList; } + + bool preloaded() const + { return _preloaded; } + + void preloaded( bool newval_r ) + { _preloaded = newval_r; } + protected: /** Let the Source provide the package. */ virtual ManagedFile sourceProvidePackage( const PoolItem & pi ) const @@ -70,7 +79,7 @@ namespace zypp ZYPP_THROW( Exception("No package provider configured.") ); } - ManagedFile ret( _packageProvider( pi ) ); + ManagedFile ret( _packageProvider( pi, /*cached only*/false ) ); if ( ret.value().empty() ) { ZYPP_THROW( Exception("Package provider failed.") ); @@ -79,11 +88,21 @@ namespace zypp return ret; } - protected: - std::vector _commitList; + /** Let the Source provide an already cached package. */ + virtual ManagedFile sourceProvideCachedPackage( const PoolItem & pi ) const + { + if ( ! _packageProvider ) + { + ZYPP_THROW( Exception("No package provider configured.") ); + } + + return _packageProvider( pi, /*cached only*/true ); + } private: + std::vector _commitList; PackageProvider _packageProvider; + DefaultIntegral _preloaded; }; /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/target/CommitPackageCacheReadAhead.cc b/libzypp/zypp/target/CommitPackageCacheReadAhead.cc index e55c082..826f5d2 100644 --- a/libzypp/zypp/target/CommitPackageCacheReadAhead.cc +++ b/libzypp/zypp/target/CommitPackageCacheReadAhead.cc @@ -15,6 +15,7 @@ #include "zypp/base/Exception.h" #include "zypp/PathInfo.h" #include "zypp/RepoInfo.h" +#include "zypp/Package.h" #include "zypp/target/CommitPackageCacheReadAhead.h" using std::endl; @@ -49,10 +50,10 @@ namespace zypp // METHOD NAME : CommitPackageCacheReadAhead::CommitPackageCacheReadAhead // METHOD TYPE : Ctor // - CommitPackageCacheReadAhead::CommitPackageCacheReadAhead( const Pathname & rootDir_r, + CommitPackageCacheReadAhead::CommitPackageCacheReadAhead( const Pathname & /*rootDir_r*/, const PackageProvider & packageProvider_r ) : CommitPackageCache::Impl( packageProvider_r ) - , _rootDir( rootDir_r ) + //, _rootDir( rootDir_r ) {} /////////////////////////////////////////////////////////////////// @@ -96,91 +97,40 @@ namespace zypp // void CommitPackageCacheReadAhead::doCacheLastInteractive( const PoolItem & citem_r ) { - CacheMap addToCache; - ByteCount addSize; + unsigned addToCache = 0; + bool sawCitem = false; // Collect all remaining packages to install from // _lastInteractive media. (just the PoolItem data) - for_( it,_commitList.begin(), _commitList.end() ) - { - PoolItem pi( *it ); - if ( IMediaKey( pi ) == _lastInteractive - && isKind(pi.resolvable()) - && pi.status().isToBeInstalled() ) - { - if ( _cacheMap.find( pi ) == _cacheMap.end() ) - { - addToCache[pi]; - addSize += pi->downloadSize(); - } - } - } - - if ( addToCache.empty() ) - return; - MIL << "could cache " << _lastInteractive << ": " << addToCache.size() << " items: " << addSize << endl; - - // Check whether we can afford caching the items. We cache them all or - // nothing. It does not make sense to cache only some packages, if a - // CD change can't be avoided. - if ( ! _cacheDir ) - { - _cacheDir.reset( new filesystem::TmpDir( _rootDir, "commitCache." ) ); - PathInfo pi( _cacheDir->path() ); - if ( ! pi.isDir() ) - { - ERR << "Can not initialize cache dir " << pi << endl; - return; - } - } - - // In case someone removes cacheDir behind our back, df will be - // -1, so we won't cache. - ByteCount df( filesystem::df( _cacheDir->path() ) ); - MIL << "available disk space in " << _cacheDir->path() << ": " << df << endl; - - if ( df / 10 < addSize ) - { - WAR << "cache would require more than 10% of the available " << df << " disk space " << endl; - WAR << "not caching " << _lastInteractive << endl; - return; - } - - // Get all files to cache from the Source and copy them to - // the cache. - // NOTE: All files copied to the cache directory are stored in addToCache, - // which is a local variable. If we throw on error, addToCache will be - // deleted and all the ManagedFiles stored so far will delete themself. - // THIS IS EXACTLY WHAT WE WANT. - for ( CacheMap::iterator it = addToCache.begin(); it != addToCache.end(); ++it ) - { - // let the source provide the file - ManagedFile fromSource( sourceProvidePackage( it->first ) ); - - // copy it to the cachedir - std::string destName( str::form( "S%p_%u_%s", - it->first->repository().id(), - it->first->mediaNr(), - fromSource.value().basename().c_str() ) ); - - ManagedFile fileInCache( _cacheDir->path() / destName, - filesystem::unlink ); - - if ( filesystem::copy( fromSource.value(), fileInCache ) != 0 ) - { - // copy to cache failed. - ERR << "Copy to cache failed on " << fromSource.value() << endl; - ZYPP_THROW( Exception("Copy to cache failed.") ); - } - - // remember the cached file. - it->second = fileInCache; - } - - // Here: All files are sucessfully copied to the cache. - // Update the real cache map. - _cacheMap.insert( addToCache.begin(), addToCache.end() ); - return; + for_( it, commitList().begin(), commitList().end() ) + { + PoolItem pi( *it ); + if ( ! sawCitem ) + { + if ( pi == citem_r ) + sawCitem = true; + continue; + } + if ( IMediaKey( pi ) == _lastInteractive + && pi.status().isToBeInstalled() + && isKind(pi.resolvable()) ) + { + if ( ! pi->asKind()->isCached() ) + { + ManagedFile fromSource( sourceProvidePackage( pi ) ); + if ( fromSource->empty() ) + { + ERR << "Copy to cache failed on " << fromSource << endl; + ZYPP_THROW( Exception("Copy to cache failed.") ); + } + fromSource.resetDispose(); // keep the package file in the cache + ++addToCache; + } + } + } + + if ( addToCache ) + MIL << "Cached " << _lastInteractive << ": " << addToCache << " items." << endl; } /////////////////////////////////////////////////////////////////// @@ -190,49 +140,40 @@ namespace zypp // ManagedFile CommitPackageCacheReadAhead::get( const PoolItem & citem_r ) { - // Non CD/DVD media provide their packages without cache. - if ( ! onInteractiveMedia( citem_r ) ) - { - return sourceProvidePackage( citem_r ); - } - - // Check whether it's cached. - CacheMap::iterator it = _cacheMap.find( citem_r ); - if ( it != _cacheMap.end() ) - { - // ManagedFile delivered to the application is removed - // from the cache. So if the application releases the - // file, it actually gets deleted from disk. - ManagedFile cacheHit( it->second ); - _cacheMap.erase( it ); - - // safety check whether the file still exists - PathInfo pi( cacheHit.value() ); - if ( pi.isFile() ) - { - MIL << "Cache package provide " << cacheHit << endl; - return cacheHit; - } - - WAR << "Cached file vanished: " << pi << endl; - } - - // HERE: It's not in the cache. - // In case we have to change the media to provide the requested - // file, try to cache files from the current media, that are - // required later. - IMediaKey current( citem_r ); - if ( current != _lastInteractive ) - { - if ( _lastInteractive != IMediaKey() ) - { - cacheLastInteractive( citem_r ); - } - - DBG << "Interactive change [" << ++_dbgChanges << "] from " << _lastInteractive - << " to " << current << endl; - _lastInteractive = current; - } + ManagedFile ret; + if ( preloaded() ) + { + // Check whether it's cached. + ManagedFile ret( sourceProvideCachedPackage( citem_r ) ); + if ( ! ret->empty() ) + return ret; + } + // else: we head for sourceProvidePackage(), even if the package + // was cached. The actual difference is that sourceProvidePackage + // will trigger the infoInCache CB that informs the application. + // Once the cache is preloaded we try to avoid this CB. + + + // Preload cache if a CD/DVD change is pending to avoid + // switching back and forth... + if ( onInteractiveMedia( citem_r ) ) + { + ret = sourceProvideCachedPackage( citem_r ); + if ( ! ret->empty() ) + return ret; + + IMediaKey current( citem_r ); + if ( current != _lastInteractive ) + { + if ( _lastInteractive != IMediaKey() ) + { + cacheLastInteractive( citem_r ); + } + + DBG << "Interactive change [" << ++_dbgChanges << "] from " << _lastInteractive << " to " << current << endl; + _lastInteractive = current; + } + } // Provide and return the file from media. return sourceProvidePackage( citem_r ); diff --git a/libzypp/zypp/target/CommitPackageCacheReadAhead.h b/libzypp/zypp/target/CommitPackageCacheReadAhead.h index 007951b..9ba707a 100644 --- a/libzypp/zypp/target/CommitPackageCacheReadAhead.h +++ b/libzypp/zypp/target/CommitPackageCacheReadAhead.h @@ -82,10 +82,8 @@ namespace zypp /** */ class CommitPackageCacheReadAhead : public CommitPackageCache::Impl { - typedef std::map CacheMap; - public: - CommitPackageCacheReadAhead( const Pathname & rootDir_r, + CommitPackageCacheReadAhead( const Pathname & /*rootDir_r*/, const PackageProvider & packageProvider_r ); public: @@ -109,12 +107,8 @@ namespace zypp private: DefaultIntegral _dbgChanges; - - IMediaKey _lastInteractive; - - Pathname _rootDir; - shared_ptr _cacheDir; - CacheMap _cacheMap; + IMediaKey _lastInteractive; + //Pathname _rootDir; }; /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/target/RpmPostTransCollector.cc b/libzypp/zypp/target/RpmPostTransCollector.cc new file mode 100644 index 0000000..14ceab8 --- /dev/null +++ b/libzypp/zypp/target/RpmPostTransCollector.cc @@ -0,0 +1,202 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/target/RpmPostTransCollector.cc + */ +#include +#include +#include "zypp/base/LogTools.h" +#include "zypp/base/NonCopyable.h" +#include "zypp/target/RpmPostTransCollector.h" + +#include "zypp/TmpPath.h" +#include "zypp/PathInfo.h" +#include "zypp/HistoryLog.h" +#include "zypp/ZYppCallbacks.h" +#include "zypp/ExternalProgram.h" +#include "zypp/target/rpm/RpmHeader.h" + + +using std::endl; +#undef ZYPP_BASE_LOGGER_LOGGROUP +#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::posttrans" + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + /////////////////////////////////////////////////////////////////// + namespace target + { + + /////////////////////////////////////////////////////////////////// + /// \class RpmPostTransCollector::Impl + /// \brief RpmPostTransCollector implementation. + /////////////////////////////////////////////////////////////////// + class RpmPostTransCollector::Impl : private base::NonCopyable + { + friend std::ostream & operator<<( std::ostream & str, const Impl & obj ); + friend std::ostream & dumpOn( std::ostream & str, const Impl & obj ); + public: + Impl( const Pathname & root_r ) + : _root( root_r ) + {} + + ~Impl() + { if ( !_scripts.empty() ) discardScripts(); } + + /** Extract and remember a packages %posttrans script for later execution. */ + bool collectScriptFromPackage( ManagedFile rpmPackage_r ) + { + rpm::RpmHeader::constPtr pkg( rpm::RpmHeader::readPackage( rpmPackage_r, rpm::RpmHeader::NOVERIFY ) ); + + std::string prog( pkg->tag_posttransprog() ); + if ( prog.empty() || prog == "" ) // by now leave lua to rpm + return false; + + filesystem::TmpFile script( tmpDir(), rpmPackage_r->basename() ); + filesystem::addmod( script.path(), 0500 ); + script.autoCleanup( false ); // no autodelete; within a tmpdir + { + std::ofstream out( script.path().c_str() ); + out << "# " << pkg->tag_posttransprog() << endl + << pkg->tag_posttrans() << endl; + } + _scripts.push_back( script.path().basename() ); + MIL << "COLLECT posttrans: " << PathInfo( script.path() ) << endl; + //DBG << "PROG: " << pkg->tag_posttransprog() << endl; + //DBG << "SCRPT: " << pkg->tag_posttrans() << endl; + return true; + } + + /** Execute te remembered scripts. */ + void executeScripts() + { + if ( _scripts.empty() ) + return; + + HistoryLog historylog; + + Pathname noRootScriptDir( filesystem::TmpDir::defaultLocation() / tmpDir().basename() ); + + for ( auto && script : _scripts ) + { + MIL << "EXECUTE posttrans: " << script << endl; + ExternalProgram prog( (noRootScriptDir/script).asString(), ExternalProgram::Stderr_To_Stdout, false, -1, true, _root ); + + str::Str collect; + for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() ) + { + DBG << line; + collect << " " << line; + } + int ret = prog.close(); + const std::string & scriptmsg( collect ); + + if ( ret != 0 || ! scriptmsg.empty() ) + { + const std::string & pkgident( script.substr( 0, script.size()-6 ) ); // strip tmp file suffix + + if ( ! scriptmsg.empty() ) + { + str::Str msg; + msg << "Output of " << pkgident << " %posttrans script:\n" << scriptmsg; + historylog.comment( msg, true /*timestamp*/); + JobReport::info( msg ); + } + + if ( ret != 0 ) + { + str::Str msg; + msg << pkgident << " %posttrans script failed (returned " << ret << ")"; + WAR << msg << endl; + historylog.comment( msg, true /*timestamp*/); + JobReport::warning( msg ); + } + } + } + _scripts.clear(); + } + + /** Discard all remembered scrips. */ + void discardScripts() + { + if ( _scripts.empty() ) + return; + + HistoryLog historylog; + + str::Str msg; + msg << "%posttrans scripts skipped while aborting:\n"; + for ( auto && script : _scripts ) + { + const std::string & pkgident( script.substr( 0, script.size()-6 ) ); // strip tmp file suffix + WAR << "UNEXECUTED posttrans: " << script << endl; + msg << " " << pkgident << "\n"; + } + + historylog.comment( msg, true /*timestamp*/); + JobReport::warning( msg ); + + _scripts.clear(); + } + + private: + /** Lazy create tmpdir on demand. */ + Pathname tmpDir() + { + if ( !_ptrTmpdir ) _ptrTmpdir.reset( new filesystem::TmpDir( _root / filesystem::TmpDir::defaultLocation(), "posttrans" ) ); + DBG << _ptrTmpdir->path() << endl; + return _ptrTmpdir->path(); + } + + private: + Pathname _root; + std::list _scripts; + boost::scoped_ptr _ptrTmpdir; + }; + + /** \relates RpmPostTransCollector::Impl Stream output */ + inline std::ostream & operator<<( std::ostream & str, const RpmPostTransCollector::Impl & obj ) + { return str << "RpmPostTransCollector::Impl"; } + + /** \relates RpmPostTransCollector::Impl Verbose stream output */ + inline std::ostream & dumpOn( std::ostream & str, const RpmPostTransCollector::Impl & obj ) + { return str << obj; } + + /////////////////////////////////////////////////////////////////// + // + // CLASS NAME : RpmPostTransCollector + // + /////////////////////////////////////////////////////////////////// + + RpmPostTransCollector::RpmPostTransCollector( const Pathname & root_r ) + : _pimpl( new Impl( root_r ) ) + {} + + RpmPostTransCollector::~RpmPostTransCollector() + {} + + bool RpmPostTransCollector::collectScriptFromPackage( ManagedFile rpmPackage_r ) + { return _pimpl->collectScriptFromPackage( rpmPackage_r ); } + + void RpmPostTransCollector::executeScripts() + { return _pimpl->executeScripts(); } + + void RpmPostTransCollector::discardScripts() + { return _pimpl->discardScripts(); } + + std::ostream & operator<<( std::ostream & str, const RpmPostTransCollector & obj ) + { return str << *obj._pimpl; } + + std::ostream & dumpOn( std::ostream & str, const RpmPostTransCollector & obj ) + { return dumpOn( str, *obj._pimpl ); } + + } // namespace target + /////////////////////////////////////////////////////////////////// +} // namespace zypp +/////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/target/RpmPostTransCollector.h b/libzypp/zypp/target/RpmPostTransCollector.h new file mode 100644 index 0000000..de0de60 --- /dev/null +++ b/libzypp/zypp/target/RpmPostTransCollector.h @@ -0,0 +1,71 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/target/RpmPostTransCollector.h + */ +#ifndef ZYPP_TARGET_RPMPOSTTRANSCOLLECTOR_H +#define ZYPP_TARGET_RPMPOSTTRANSCOLLECTOR_H + +#include + +#include "zypp/base/PtrTypes.h" +#include "zypp/ManagedFile.h" +#include "zypp/Pathname.h" + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + /////////////////////////////////////////////////////////////////// + namespace target + { + /////////////////////////////////////////////////////////////////// + /// \class RpmPostTransCollector + /// \brief Extract and remember %posttrans scripts for later execution + /// \todo Maybe embedd this into the TransactionSteps. + /////////////////////////////////////////////////////////////////// + class RpmPostTransCollector + { + friend std::ostream & operator<<( std::ostream & str, const RpmPostTransCollector & obj ); + friend std::ostream & dumpOn( std::ostream & str, const RpmPostTransCollector & obj ); + + public: + /** Default ctor */ + RpmPostTransCollector( const Pathname & root_r ); + + /** Dtor */ + ~RpmPostTransCollector(); + + public: + /** Extract and remember a packages %posttrans script for later execution. + * \return whether a script was collected. + */ + bool collectScriptFromPackage( ManagedFile rpmPackage_r ); + + /** Execute te remembered scripts. */ + void executeScripts(); + + /** Discard all remembered scrips. */ + void discardScripts(); + + public: + class Impl; ///< Implementation class. + private: + RW_pointer _pimpl; ///< Pointer to implementation. + }; + + /** \relates RpmPostTransCollector Stream output */ + std::ostream & operator<<( std::ostream & str, const RpmPostTransCollector & obj ); + + /** \relates RpmPostTransCollector Verbose stream output */ + std::ostream & dumOn( std::ostream & str, const RpmPostTransCollector & obj ); + + } // namespace target + /////////////////////////////////////////////////////////////////// +} // namespace zypp +/////////////////////////////////////////////////////////////////// +#endif // ZYPP_TARGET_RPMPOSTTRANSCOLLECTOR_H diff --git a/libzypp/zypp/target/SoftLocksFile.cc b/libzypp/zypp/target/SolvIdentFile.cc similarity index 88% rename from libzypp/zypp/target/SoftLocksFile.cc rename to libzypp/zypp/target/SolvIdentFile.cc index 4e117d2..f09074a 100644 --- a/libzypp/zypp/target/SoftLocksFile.cc +++ b/libzypp/zypp/target/SolvIdentFile.cc @@ -6,7 +6,7 @@ | /_____||_| |_| |_| | | | \---------------------------------------------------------------------*/ -/** \file zypp/target/SoftLocksFile.cc +/** \file zypp/target/SolvIdentFile.cc * */ #include @@ -20,7 +20,7 @@ #include "zypp/TmpPath.h" #include "zypp/Date.h" -#include "zypp/target/SoftLocksFile.h" +#include "zypp/target/SolvIdentFile.h" using std::endl; @@ -31,7 +31,7 @@ namespace zypp namespace target { ///////////////////////////////////////////////////////////////// - void SoftLocksFile::load( const Pathname & file_r, Data & data_r ) + void SolvIdentFile::load( const Pathname & file_r, Data & data_r ) { PathInfo pi( file_r ); if ( ! pi.isFile() ) @@ -51,13 +51,13 @@ namespace zypp MIL << "Read " << pi << endl; } - void SoftLocksFile::store( const Pathname & file_r, const Data & data_r ) + void SolvIdentFile::store( const Pathname & file_r, const Data & data_r ) { filesystem::TmpFile tmp( filesystem::TmpFile::makeSibling( file_r ) ); filesystem::chmod( tmp.path(), 0644 ); std::ofstream outs( tmp.path().c_str() ); - outs << "# zypp::SoftLocksFile generated " << Date::now() << endl; + outs << "# " << file_r.basename() << " generated " << Date::now() << endl; dumpRange( outs, data_r.begin(), data_r.end(), "#", "\n", "\n", "\n", "#\n" ); outs.close(); @@ -77,7 +77,7 @@ namespace zypp ** FUNCTION NAME : operator<< ** FUNCTION TYPE : std::ostream & */ - std::ostream & operator<<( std::ostream & str, const SoftLocksFile & obj ) + std::ostream & operator<<( std::ostream & str, const SolvIdentFile & obj ) { str << obj.file() << ' '; if ( obj._dataPtr ) diff --git a/libzypp/zypp/target/SoftLocksFile.h b/libzypp/zypp/target/SolvIdentFile.h similarity index 86% rename from libzypp/zypp/target/SoftLocksFile.h rename to libzypp/zypp/target/SolvIdentFile.h index bd91d6a..b44e2dd 100644 --- a/libzypp/zypp/target/SoftLocksFile.h +++ b/libzypp/zypp/target/SolvIdentFile.h @@ -6,11 +6,11 @@ | /_____||_| |_| |_| | | | \---------------------------------------------------------------------*/ -/** \file zypp/target/SoftLocksFile.h +/** \file zypp/target/SolvIdentFile.h * */ -#ifndef ZYPP_TARGET_SOFTLOCKSFILE_H -#define ZYPP_TARGET_SOFTLOCKSFILE_H +#ifndef ZYPP_TARGET_SOLVIDENTFILE_H +#define ZYPP_TARGET_SOLVIDENTFILE_H #include @@ -27,20 +27,18 @@ namespace zypp { ///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : SoftLocksFile - // - /** Save and restore soft locks. - */ - class SoftLocksFile + /// \class SolvIdentFile + /// \short Save and restore a list of solvable names (ident IdString) + /////////////////////////////////////////////////////////////////// + class SolvIdentFile { - friend std::ostream & operator<<( std::ostream & str, const SoftLocksFile & obj ); + friend std::ostream & operator<<( std::ostream & str, const SolvIdentFile & obj ); public: typedef std::tr1::unordered_set Data; public: /** Ctor taking the file to read/write. */ - SoftLocksFile( const Pathname & file_r ) + SolvIdentFile( const Pathname & file_r ) : _file( file_r ) {} @@ -105,8 +103,8 @@ namespace zypp }; /////////////////////////////////////////////////////////////////// - /** \relates SoftLocksFile Stream output */ - std::ostream & operator<<( std::ostream & str, const SoftLocksFile & obj ); + /** \relates SolvIdentFile Stream output */ + std::ostream & operator<<( std::ostream & str, const SolvIdentFile & obj ); ///////////////////////////////////////////////////////////////// } // namespace target @@ -114,4 +112,4 @@ namespace zypp ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// -#endif // ZYPP_TARGET_SOFTLOCKSFILE_H +#endif // ZYPP_TARGET_SOLVIDENTFILE_H diff --git a/libzypp/zypp/target/TargetCallbackReceiver.cc b/libzypp/zypp/target/TargetCallbackReceiver.cc index 0d02f92..2f53a4f 100644 --- a/libzypp/zypp/target/TargetCallbackReceiver.cc +++ b/libzypp/zypp/target/TargetCallbackReceiver.cc @@ -9,6 +9,7 @@ /** \file zypp/target/TargetCallbackReceiver.cc * */ +#include #include "zypp/target/TargetCallbackReceiver.h" diff --git a/libzypp/zypp/target/TargetImpl.cc b/libzypp/zypp/target/TargetImpl.cc index b451f50..89506ed 100644 --- a/libzypp/zypp/target/TargetImpl.cc +++ b/libzypp/zypp/target/TargetImpl.cc @@ -26,6 +26,7 @@ #include "zypp/base/IOStream.h" #include "zypp/base/Functional.h" #include "zypp/base/UserRequestException.h" +#include "zypp/base/Json.h" #include "zypp/ZConfig.h" #include "zypp/ZYppFactory.h" @@ -44,14 +45,12 @@ #include "zypp/target/TargetCallbackReceiver.h" #include "zypp/target/rpm/librpmDb.h" #include "zypp/target/CommitPackageCache.h" +#include "zypp/target/RpmPostTransCollector.h" #include "zypp/parser/ProductFileReader.h" -#include "zypp/pool/GetResolvablesToInsDel.h" #include "zypp/solver/detail/Testcase.h" -#include "zypp/repo/DeltaCandidates.h" -#include "zypp/repo/PackageProvider.h" #include "zypp/repo/SrcPackageProvider.h" #include "zypp/sat/Pool.h" @@ -64,17 +63,168 @@ using namespace std; /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// + namespace json + { + // Lazy via template specialisation / should switch to overloading + + template<> + inline std::string toJSON( const ZYppCommitResult::TransactionStepList & steps_r ) + { + using sat::Transaction; + json::Array ret; + + for ( const Transaction::Step & step : steps_r ) + // ignore implicit deletes due to obsoletes and non-package actions + if ( step.stepType() != Transaction::TRANSACTION_IGNORE ) + ret.add( step ); + + return ret.asJSON(); + } + + /** See \ref commitbegin on page \ref plugin-commit for the specs. */ + template<> + inline std::string toJSON( const sat::Transaction::Step & step_r ) + { + static const std::string strType( "type" ); + static const std::string strStage( "stage" ); + static const std::string strSolvable( "solvable" ); + + static const std::string strTypeDel( "-" ); + static const std::string strTypeIns( "+" ); + static const std::string strTypeMul( "M" ); + + static const std::string strStageDone( "ok" ); + static const std::string strStageFailed( "err" ); + + static const std::string strSolvableN( "n" ); + static const std::string strSolvableE( "e" ); + static const std::string strSolvableV( "v" ); + static const std::string strSolvableR( "r" ); + static const std::string strSolvableA( "a" ); + + using sat::Transaction; + json::Object ret; + + switch ( step_r.stepType() ) + { + case Transaction::TRANSACTION_IGNORE: /*empty*/ break; + case Transaction::TRANSACTION_ERASE: ret.add( strType, strTypeDel ); break; + case Transaction::TRANSACTION_INSTALL: ret.add( strType, strTypeIns ); break; + case Transaction::TRANSACTION_MULTIINSTALL: ret.add( strType, strTypeMul ); break; + } + + switch ( step_r.stepStage() ) + { + case Transaction::STEP_TODO: /*empty*/ break; + case Transaction::STEP_DONE: ret.add( strStage, strStageDone ); break; + case Transaction::STEP_ERROR: ret.add( strStage, strStageFailed ); break; + } + + { + IdString ident; + Edition ed; + Arch arch; + if ( sat::Solvable solv = step_r.satSolvable() ) + { + ident = solv.ident(); + ed = solv.edition(); + arch = solv.arch(); + } + else + { + // deleted package; post mortem data stored in Transaction::Step + ident = step_r.ident(); + ed = step_r.edition(); + arch = step_r.arch(); + } + + json::Object s { + { strSolvableN, ident.asString() }, + { strSolvableV, ed.version() }, + { strSolvableR, ed.release() }, + { strSolvableA, arch.asString() } + }; + if ( Edition::epoch_t epoch = ed.epoch() ) + s.add( strSolvableE, epoch ); + + ret.add( strSolvable, s ); + } + + return ret.asJSON(); + } + } // namespace json + /////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// namespace target - { ///////////////////////////////////////////////////////////////// + { + /////////////////////////////////////////////////////////////////// + namespace + { + SolvIdentFile::Data getUserInstalledFromHistory( const Pathname & historyFile_r ) + { + SolvIdentFile::Data onSystemByUserList; + // go and parse it: 'who' must constain an '@', then it was installed by user request. + // 2009-09-29 07:25:19|install|lirc-remotes|0.8.5-3.2|x86_64|root@opensuse|InstallationImage|a204211eb0... + std::ifstream infile( historyFile_r.c_str() ); + for( iostr::EachLine in( infile ); in; in.next() ) + { + const char * ch( (*in).c_str() ); + // start with year + if ( *ch < '1' || '9' < *ch ) + continue; + const char * sep1 = ::strchr( ch, '|' ); // | after date + if ( !sep1 ) + continue; + ++sep1; + // if logs an install or delete + bool installs = true; + if ( ::strncmp( sep1, "install|", 8 ) ) + { + if ( ::strncmp( sep1, "remove |", 8 ) ) + continue; // no install and no remove + else + installs = false; // remove + } + sep1 += 8; // | after what + // get the package name + const char * sep2 = ::strchr( sep1, '|' ); // | after name + if ( !sep2 || sep1 == sep2 ) + continue; + (*in)[sep2-ch] = '\0'; + IdString pkg( sep1 ); + // we're done, if a delete + if ( !installs ) + { + onSystemByUserList.erase( pkg ); + continue; + } + // now guess whether user installed or not (3rd next field contains 'user@host') + if ( (sep1 = ::strchr( sep2+1, '|' )) // | after version + && (sep1 = ::strchr( sep1+1, '|' )) // | after arch + && (sep2 = ::strchr( sep1+1, '|' )) ) // | after who + { + (*in)[sep2-ch] = '\0'; + if ( ::strchr( sep1+1, '@' ) ) + { + // by user + onSystemByUserList.insert( pkg ); + continue; + } + } + } + MIL << "onSystemByUserList found: " << onSystemByUserList.size() << endl; + return onSystemByUserList; + } + } // namespace + /////////////////////////////////////////////////////////////////// /** Helper for commit plugin execution. * \ingroup g_RAII */ class CommitPlugins : private base::NonCopyable { - public: - public: /** Default ctor: Empty plugin list */ CommitPlugins() @@ -83,24 +233,31 @@ namespace zypp /** Dtor: Send PLUGINEND message and close plugins. */ ~CommitPlugins() { - for_( it, _scripts.begin(), _scripts.end() ) + if ( ! _scripts.empty() ) + send( PluginFrame( "PLUGINEND" ) ); + // ~PluginScript will disconnect all remaining plugins! + } + + /** Whether no plugins are waiting */ + bool empty() const + { return _scripts.empty(); } + + + /** Send \ref PluginFrame to all open plugins. + * Failed plugins are removed from the execution list. + */ + void send( const PluginFrame & frame_r ) + { + DBG << "+++++++++++++++ send " << frame_r << endl; + for ( auto it = _scripts.begin(); it != _scripts.end(); ) { - MIL << "Unload plugin: " << *it << endl; - try { - it->send( PluginFrame( "PLUGINEND" ) ); - PluginFrame ret( it->receive() ); - if ( ! ret.isAckCommand() ) - { - WAR << "Failed to unload plugin: Bad plugin response." << endl; - } - it->close(); - } - catch( const zypp::Exception & ) - { - WAR << "Failed to unload plugin." << endl; - } + doSend( *it, frame_r ); + if ( it->isOpen() ) + ++it; + else + it = _scripts.erase( it ); } - // _scripts dtor will disconnect all remaining plugins! + DBG << "--------------- send " << frame_r << endl; } /** Find and launch plugins sending PLUGINSTART message. @@ -112,6 +269,7 @@ namespace zypp void load( const Pathname & path_r ) { PathInfo pi( path_r ); + DBG << "+++++++++++++++ load " << pi << endl; if ( pi.isDir() ) { std::list entries; @@ -138,29 +296,55 @@ namespace zypp { WAR << "Plugin path is neither dir nor file: " << pi << endl; } + DBG << "--------------- load " << pi << endl; } private: + /** Send \ref PluginFrame and expect valid answer (ACK|_ENOMETHOD). + * Upon invalid answer or error, close the plugin. and remove it from the + * execution list. + * \returns the received \ref PluginFrame (empty Frame upon Exception) + */ + PluginFrame doSend( PluginScript & script_r, const PluginFrame & frame_r ) + { + PluginFrame ret; + + try { + script_r.send( frame_r ); + ret = script_r.receive(); + } + catch( const zypp::Exception & e ) + { ZYPP_CAUGHT(e); } + + if ( ! ( ret.isAckCommand() || ret.isEnomethodCommand() ) ) + { + WAR << "Bad plugin response from " << script_r << endl; + WAR << dump(ret) << endl; + script_r.close(); + } + + return ret; + } + + /** Launch a plugin sending PLUGINSTART message. */ void doLoad( const PathInfo & pi_r ) { MIL << "Load plugin: " << pi_r << endl; try { PluginScript plugin( pi_r.path() ); plugin.open(); - plugin.send( PluginFrame( "PLUGINBEGIN" ) ); - PluginFrame ret( plugin.receive() ); - if ( ret.isAckCommand() ) - { + + PluginFrame frame( "PLUGINBEGIN" ); + if ( ZConfig::instance().hasUserData() ) + frame.setHeader( "userdata", ZConfig::instance().userData() ); + + doSend( plugin, frame ); // closes on error + if ( plugin.isOpen() ) _scripts.push_back( plugin ); - } - else - { - WAR << "Failed to load plugin: Bad plugin response." << endl; - } } - catch( const zypp::Exception & ) + catch( const zypp::Exception & e ) { - WAR << "Failed to load plugin." << endl; + WAR << "Failed to load plugin " << pi_r << endl; } } @@ -179,6 +363,16 @@ namespace zypp USR << "-----" << endl; } + /////////////////////////////////////////////////////////////////// + namespace + { + inline PluginFrame transactionPluginFrame( const std::string & command_r, ZYppCommitResult::TransactionStepList & steps_r ) + { + return PluginFrame( command_r, json::Object { + { "TransactionStepList", steps_r } + }.asJSON() ); + } + } // namespace /////////////////////////////////////////////////////////////////// /** \internal Manage writing a new testcase when doing an upgrade. */ @@ -354,26 +548,37 @@ namespace zypp continue; // if not exact match it had to continue with '-' PathInfo script( scriptsDir / *sit ); - if ( ! script.isFile() ) - continue; + Pathname localPath( scriptsPath_r/(*sit) ); // without root prefix + std::string unifytag; // must not stay empty - // Assert it's set executable - filesystem::addmod( script.path(), 0500 ); + if ( script.isFile() ) + { + // Assert it's set executable, unify by md5sum. + filesystem::addmod( script.path(), 0500 ); + unifytag = filesystem::md5sum( script.path() ); + } + else if ( ! script.isExist() ) + { + // Might be a dangling symlink, might be ok if we are in + // instsys (absolute symlink within the system below /mnt). + // readlink will tell.... + unifytag = filesystem::readlink( script.path() ).asString(); + } - Pathname localPath( scriptsPath_r/(*sit) ); // without root prefix + if ( unifytag.empty() ) + continue; - // Unify scripts by md5sum - std::string md5sum( filesystem::md5sum( script.path() ) ); - if ( unify[md5sum].empty() ) + // Unify scripts + if ( unify[unifytag].empty() ) { - unify[md5sum] = localPath; + unify[unifytag] = localPath; } else { // translators: We may find the same script content in files with different names. // Only the first occurence is executed, subsequent ones are skipped. It's a one-line // message for a log file. Preferably start translation with "%s" - std::string msg( str::form(_("%s already executed as %s)"), localPath.asString().c_str(), unify[md5sum].c_str() ) ); + std::string msg( str::form(_("%s already executed as %s)"), localPath.asString().c_str(), unify[unifytag].c_str() ) ); MIL << "Skip update script: " << msg << endl; HistoryLog().comment( msg, /*timestamp*/true ); continue; @@ -598,59 +803,6 @@ namespace zypp ZYppCommitResult & result_r ) { RunUpdateMessages( root_r, messagesPath_r, checkPackages_r, result_r ); } - /** Helper for PackageProvider queries during commit. */ - struct QueryInstalledEditionHelper - { - bool operator()( const std::string & name_r, - const Edition & ed_r, - const Arch & arch_r ) const - { - rpm::librpmDb::db_const_iterator it; - for ( it.findByName( name_r ); *it; ++it ) - { - if ( arch_r == it->tag_arch() - && ( ed_r == Edition::noedition || ed_r == it->tag_edition() ) ) - { - return true; - } - } - return false; - } - }; - - /** - * \short Let the Source provide the package. - * \p pool_r \ref ResPool used to get candidates - * \p pi item to be commited - */ - struct RepoProvidePackage - { - ResPool _pool; - repo::RepoMediaAccess &_access; - - RepoProvidePackage( repo::RepoMediaAccess &access, ResPool pool_r ) - : _pool(pool_r), _access(access) - {} - - ManagedFile operator()( const PoolItem & pi ) - { - // Redirect PackageProvider queries for installed editions - // (in case of patch/delta rpm processing) to rpmDb. - repo::PackageProviderPolicy packageProviderPolicy; - packageProviderPolicy.queryInstalledCB( QueryInstalledEditionHelper() ); - - Package::constPtr p = asKind(pi.resolvable()); - - // Build a repository list for repos - // contributing to the pool - std::list repos( _pool.knownRepositoriesBegin(), _pool.knownRepositoriesEnd() ); - repo::DeltaCandidates deltas(repos, p->name()); - repo::PackageProvider pkgProvider( _access, p, deltas, packageProviderPolicy ); - - ManagedFile ret( pkgProvider.providePackage() ); - return ret; - } - }; /////////////////////////////////////////////////////////////////// IMPL_PTR_TYPE(TargetImpl); @@ -673,7 +825,7 @@ namespace zypp TargetImpl::TargetImpl( const Pathname & root_r, bool doRebuild_r ) : _root( root_r ) , _requestedLocalesFile( home() / "RequestedLocales" ) - , _softLocksFile( home() / "SoftLocks" ) + , _autoInstalledFile( home() / "AutoInstalled" ) , _hardLocksFile( Pathname::assertprefix( _root, ZConfig::instance().locksFile() ) ) { _rpm.initDatabase( root_r, Pathname(), doRebuild_r ); @@ -827,8 +979,7 @@ namespace zypp bool build_rpm_solv = true; // lets see if the rpm solv cache exists - RepoStatus rpmstatus( RepoStatus( _root/"/var/lib/rpm/Name" ) - && (_root/"/etc/products.d") ); + RepoStatus rpmstatus( RepoStatus(_root/"var/lib/rpm/Name") && RepoStatus(_root/"etc/products.d") ); bool solvexisted = PathInfo(rpmsolv).isExist(); if ( solvexisted ) @@ -840,10 +991,10 @@ namespace zypp { RepoStatus status = RepoStatus::fromCookieFile(rpmsolvcookie); // now compare it with the rpm database - if ( status.checksum() == rpmstatus.checksum() ) - build_rpm_solv = false; - MIL << "Read cookie: " << rpmsolvcookie << " says: " - << (build_rpm_solv ? "outdated" : "uptodate") << endl; + if ( status == rpmstatus ) + build_rpm_solv = false; + MIL << "Read cookie: " << rpmsolvcookie << " says: " + << (build_rpm_solv ? "outdated" : "uptodate") << endl; } } @@ -899,7 +1050,8 @@ namespace zypp cmd << "rpmdb2solv"; if ( ! _root.empty() ) cmd << " -r '" << _root << "'"; - + cmd << " -X"; // autogenerate pattern/product/... from -package + cmd << " -A"; // autogenerate application pseudo packages cmd << " -p '" << Pathname::assertprefix( _root, "/etc/products.d" ) << "'"; if ( ! oldSolvFile.empty() ) @@ -978,7 +1130,7 @@ namespace zypp bool newCache = buildCache(); MIL << "New cache built: " << (newCache?"true":"false") << ", force loading: " << (force?"true":"false") << endl; - + // now add the repos to the pool sat::Pool satpool( sat::Pool::instance() ); Pathname rpmsolv( solvfilesPath() / "solv" ); @@ -998,7 +1150,7 @@ namespace zypp return; // nothing to do } } - + if ( ! system ) { system = satpool.systemRepo(); @@ -1018,6 +1170,7 @@ namespace zypp system.addSolv( rpmsolv ); } + sat::Pool::instance().rootDir( _root ); // (Re)Load the requested locales et al. // If the requested locales are empty, we leave the pool untouched @@ -1032,16 +1185,30 @@ namespace zypp } } { - SoftLocksFile::Data softLocks( _softLocksFile.data() ); - if ( ! softLocks.empty() ) - { - // Don't soft lock any installed item. - for_( it, system.solvablesBegin(), system.solvablesEnd() ) - { - softLocks.erase( it->ident() ); - } - ResPool::instance().setAutoSoftLocks( softLocks ); - } + if ( ! PathInfo( _autoInstalledFile.file() ).isExist() ) + { + // Initialize from history, if it does not exist + Pathname historyFile( Pathname::assertprefix( _root, ZConfig::instance().historyLogFile() ) ); + if ( PathInfo( historyFile ).isExist() ) + { + SolvIdentFile::Data onSystemByUser( getUserInstalledFromHistory( historyFile ) ); + SolvIdentFile::Data onSystemByAuto; + for_( it, system.solvablesBegin(), system.solvablesEnd() ) + { + IdString ident( (*it).ident() ); + if ( onSystemByUser.find( ident ) == onSystemByUser.end() ) + onSystemByAuto.insert( ident ); + } + _autoInstalledFile.setData( onSystemByAuto ); + } + // on the fly removed any obsolete SoftLocks file + filesystem::unlink( home() / "SoftLocks" ); + } + // read from AutoInstalled file + sat::StringQueue q; + for ( const auto & idstr : _autoInstalledFile.data() ) + q.push( idstr.id() ); + satpool.setAutoInstalled( q ); } if ( ZConfig::instance().apply_locks_file() ) { @@ -1086,6 +1253,32 @@ namespace zypp MIL << "TargetImpl::commit(, " << policy_r << ")" << endl; + /////////////////////////////////////////////////////////////////// + // Compute transaction: + /////////////////////////////////////////////////////////////////// + ZYppCommitResult result( root() ); + result.rTransaction() = pool_r.resolver().getTransaction(); + result.rTransaction().order(); + // steps: this is our todo-list + ZYppCommitResult::TransactionStepList & steps( result.rTransactionStepList() ); + if ( policy_r.restrictToMedia() ) + { + // Collect until the 1st package from an unwanted media occurs. + // Further collection could violate install order. + MIL << "Restrict to media number " << policy_r.restrictToMedia() << endl; + for_( it, result.transaction().begin(), result.transaction().end() ) + { + if ( makeResObject( *it )->mediaNr() > 1 ) + break; + steps.push_back( *it ); + } + } + else + { + result.rTransactionStepList().insert( steps.end(), result.transaction().begin(), result.transaction().end() ); + } + MIL << "Todo: " << result << endl; + /////////////////////////////////////////////////////////////////// // Prepare execution of commit plugins: /////////////////////////////////////////////////////////////////// @@ -1095,6 +1288,8 @@ namespace zypp Pathname plugindir( Pathname::assertprefix( _root, ZConfig::instance().pluginsPath()/"commit" ) ); commitPlugins.load( plugindir ); } + if ( ! commitPlugins.empty() ) + commitPlugins.send( transactionPluginFrame( "COMMITBEGIN", steps ) ); /////////////////////////////////////////////////////////////////// // Write out a testcase if we're in dist upgrade mode. @@ -1111,7 +1306,7 @@ namespace zypp } } - /////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// // Store non-package data: /////////////////////////////////////////////////////////////////// if ( ! policy_r.dryRun() ) @@ -1119,11 +1314,12 @@ namespace zypp filesystem::assert_dir( home() ); // requested locales _requestedLocalesFile.setLocales( pool_r.getRequestedLocales() ); - // weak locks + // autoinstalled { - SoftLocksFile::Data newdata; - pool_r.getActiveSoftLocks( newdata ); - _softLocksFile.setData( newdata ); + SolvIdentFile::Data newdata; + for ( sat::Queue::value_type id : result.rTransaction().autoInstalled() ) + newdata.insert( IdString(id) ); + _autoInstalledFile.setData( newdata ); } // hard locks if ( ZConfig::instance().apply_locks_file() ) @@ -1138,32 +1334,6 @@ namespace zypp DBG << "dryRun: Not stroring non-package data." << endl; } - /////////////////////////////////////////////////////////////////// - // Compute transaction: - /////////////////////////////////////////////////////////////////// - ZYppCommitResult result( root() ); - result.rTransaction() = pool_r.resolver().getTransaction(); - result.rTransaction().order(); - // steps: this is our todo-list - ZYppCommitResult::TransactionStepList & steps( result.rTransactionStepList() ); - if ( policy_r.restrictToMedia() ) - { - // Collect until the 1st package from an unwanted media occurs. - // Further collection could violate install order. - MIL << "Restrict to media number " << policy_r.restrictToMedia() << endl; - for_( it, result.transaction().begin(), result.transaction().end() ) - { - if ( makeResObject( *it )->mediaNr() > 1 ) - break; - steps.push_back( *it ); - } - } - else - { - result.rTransactionStepList().insert( steps.end(), result.transaction().begin(), result.transaction().end() ); - } - MIL << "Todo: " << result << endl; - /////////////////////////////////////////////////////////////////// // First collect and display all messages // associated with patches to be installed. @@ -1204,9 +1374,7 @@ namespace zypp if ( ! policy_r.dryRun() || policy_r.downloadMode() == DownloadOnly ) { // Prepare the package cache. Pass all items requiring download. - repo::RepoMediaAccess access; - RepoProvidePackage repoProvidePackage( access, pool_r ); - CommitPackageCache packageCache( root() / "tmp", repoProvidePackage ); + CommitPackageCache packageCache( root() ); packageCache.setCommitList( steps.begin(), steps.end() ); bool miss = false; @@ -1282,20 +1450,26 @@ namespace zypp } } } + packageCache.preloaded( true ); // try to avoid duplicate infoInCache CBs in commit } if ( miss ) { ERR << "Some packages could not be provided. Aborting commit."<< endl; } - else if ( ! policy_r.dryRun() ) - { - commit( policy_r, packageCache, result ); - } else - { - DBG << "dryRun: Not installing/deleting anything." << endl; - } + { + if ( ! policy_r.dryRun() ) + { + // if cache is preloaded, check for file conflicts + commitFindFileConflicts( policy_r, result ); + commit( policy_r, packageCache, result ); + } + else + { + DBG << "dryRun/downloadOnly: Not installing/deleting anything." << endl; + } + } } else { @@ -1303,54 +1477,18 @@ namespace zypp } /////////////////////////////////////////////////////////////////// - // Try to rebuild solv file while rpm database is still in cache + // Send result to commit plugins: /////////////////////////////////////////////////////////////////// - if ( ! policy_r.dryRun() ) - { - buildCache(); - } + if ( ! commitPlugins.empty() ) + commitPlugins.send( transactionPluginFrame( "COMMITEND", steps ) ); - // for DEPRECATED old ZyppCommitResult results: /////////////////////////////////////////////////////////////////// - // build return statistics + // Try to rebuild solv file while rpm database is still in cache /////////////////////////////////////////////////////////////////// - result._errors.clear(); - result._remaining.clear(); - result._srcremaining.clear(); - unsigned toInstall = 0; - for_( step, steps.begin(), steps.end() ) + if ( ! policy_r.dryRun() ) { - if ( step->stepType() == sat::Transaction::TRANSACTION_IGNORE ) - { - // For non-packages only products might have beed installed. - // All the rest is ignored. - if ( step->satSolvable().isSystem() || ! step->satSolvable().isKind() ) - continue; - } - else if ( step->stepType() == sat::Transaction::TRANSACTION_ERASE ) - { - continue; - } - // to be installed: - ++toInstall; - switch ( step->stepStage() ) - { - case sat::Transaction::STEP_TODO: - if ( step->satSolvable().isKind() ) - result._remaining.push_back( PoolItem( *step ) ); - else if ( step->satSolvable().isKind() ) - result._srcremaining.push_back( PoolItem( *step ) ); - break; - case sat::Transaction::STEP_DONE: - // NOOP - break; - case sat::Transaction::STEP_ERROR: - result._errors.push_back( PoolItem( *step ) ); - break; - } + buildCache(); } - result._result = (toInstall - result._remaining.size()); - /////////////////////////////////////////////////////////////////// MIL << "TargetImpl::commit(, " << policy_r << ") returns: " << result << endl; return result; @@ -1370,6 +1508,7 @@ namespace zypp MIL << "TargetImpl::commit(" << policy_r << ")" << steps.size() << endl; bool abort = false; + RpmPostTransCollector postTransCollector( _root ); std::vector successfullyInstalledPackages; TargetImpl::PoolItemList remaining; @@ -1446,6 +1585,8 @@ namespace zypp try { progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE ); + if ( postTransCollector.collectScriptFromPackage( localfile ) ) + flags |= rpm::RPMINST_NOPOSTTRANS; rpm().installPackage( localfile, flags ); HistoryLog().install(citem); @@ -1590,6 +1731,12 @@ namespace zypp } // for + // process all remembered posttrans scripts. + if ( !abort ) + postTransCollector.executeScripts(); + else + postTransCollector.discardScripts(); + // Check presence of update scripts/messages. If aborting, // at least log omitted scripts. if ( ! successfullyInstalledPackages.empty() ) @@ -1636,19 +1783,25 @@ namespace zypp { parser::ProductFileData baseproductdata( const Pathname & root_r ) { + parser::ProductFileData ret; PathInfo baseproduct( Pathname::assertprefix( root_r, "/etc/products.d/baseproduct" ) ); + if ( baseproduct.isFile() ) { try { - return parser::ProductFileReader::scanFile( baseproduct.path() ); + ret = parser::ProductFileReader::scanFile( baseproduct.path() ); } catch ( const Exception & excpt ) { ZYPP_CAUGHT( excpt ); } } - return parser::ProductFileData(); + else if ( PathInfo( Pathname::assertprefix( root_r, "/etc/products.d" ) ).isDir() ) + { + ERR << "baseproduct symlink is dangling or missing: " << baseproduct << endl; + } + return ret; } inline Pathname staticGuessRoot( const Pathname & root_r ) @@ -1711,6 +1864,12 @@ namespace zypp std::string TargetImpl::targetDistributionRelease( const Pathname & root_r ) { return baseproductdata( staticGuessRoot(root_r) ).registerRelease();} + std::string TargetImpl::targetDistributionFlavor() const + { return baseproductdata( _root ).registerFlavor(); } + // static version: + std::string TargetImpl::targetDistributionFlavor( const Pathname & root_r ) + { return baseproductdata( staticGuessRoot(root_r) ).registerFlavor();} + Target::DistributionLabel TargetImpl::distributionLabel() const { Target::DistributionLabel ret; @@ -1797,14 +1956,19 @@ namespace zypp void TargetImpl::installSrcPackage( const SrcPackage_constPtr & srcPackage_r ) { // provide on local disk - repo::RepoMediaAccess access_r; - repo::SrcPackageProvider prov( access_r ); - ManagedFile localfile = prov.provideSrcPackage( srcPackage_r ); + ManagedFile localfile = provideSrcPackage(srcPackage_r); // install it rpm().installPackage ( localfile ); } - ///////////////////////////////////////////////////////////////// + ManagedFile TargetImpl::provideSrcPackage( const SrcPackage_constPtr & srcPackage_r ) + { + // provide on local disk + repo::RepoMediaAccess access_r; + repo::SrcPackageProvider prov( access_r ); + return prov.provideSrcPackage( srcPackage_r ); + } + //////////////////////////////////////////////////////////////// } // namespace target /////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/target/TargetImpl.commitFindFileConflicts.cc b/libzypp/zypp/target/TargetImpl.commitFindFileConflicts.cc new file mode 100644 index 0000000..399567c --- /dev/null +++ b/libzypp/zypp/target/TargetImpl.commitFindFileConflicts.cc @@ -0,0 +1,172 @@ +/*---------------------------------------------------------------------\ +| ____ _ __ __ ___ | +| |__ / \ / / . \ . \ | +| / / \ V /| _/ _/ | +| / /__ | | | | | | | +| /_____||_| |_| |_| | +| | +\---------------------------------------------------------------------*/ +/** \file zypp/target/TargetImpl.commitFindFileConflicts.cc + */ +extern "C" +{ +#include +#include +#include +#include +#include +#include +#include +} +#include +#include +#include + +#include "zypp/base/LogTools.h" +#include "zypp/base/Gettext.h" +#include "zypp/base/Exception.h" +#include "zypp/base/UserRequestException.h" + +#include "zypp/sat/Queue.h" +#include "zypp/sat/FileConflicts.h" +#include "zypp/sat/Pool.h" + +#include "zypp/target/TargetImpl.h" +#include "zypp/target/CommitPackageCache.h" + +#include "zypp/ZYppCallbacks.h" + +using std::endl; + +/////////////////////////////////////////////////////////////////// +namespace zypp +{ + /////////////////////////////////////////////////////////////////// + namespace target + { + /////////////////////////////////////////////////////////////////// + namespace + { + /** libsolv::pool_findfileconflicts callback providing package header. */ + struct FileConflictsCB + { + FileConflictsCB( ::_Pool * pool_r, ProgressData & progress_r ) + : _progress( progress_r ) + , _state( ::rpm_state_create( pool_r, ::pool_get_rootdir(pool_r) ), ::rpm_state_free ) + {} + + void * operator()( ::_Pool * pool_r, sat::detail::IdType id_r ) + { + void * ret = lookup( id_r ); + + // report progress on 1st visit only, ticks later + // (there may be up to 3 visits) + if ( _visited.find( id_r ) == _visited.end() ) + { + //DBG << "FCCB: " << sat::Solvable( id_r ) << " " << ret << endl; + _visited.insert( id_r ); + if ( ! ret && sat::Solvable( id_r ).isKind() ) // only packages have filelists + _noFilelist.push( id_r ); + _progress.incr(); + } + else + { + _progress.tick(); + } + return ret; + } + + const sat::Queue & noFilelist() const + { return _noFilelist; } + + static void * invoke( ::_Pool * pool_r, sat::detail::IdType id_r, void * cbdata_r ) + { return (*reinterpret_cast(cbdata_r))( pool_r, id_r ); } + + private: + void * lookup( sat::detail::IdType id_r ) + { + sat::Solvable solv( id_r ); + if ( solv.isSystem() ) + { + Solvable * s = solv.get(); + if ( ! s->repo->rpmdbid ) + return nullptr; + sat::detail::IdType rpmdbid = s->repo->rpmdbid[id_r - s->repo->start]; + if ( ! rpmdbid ) + return nullptr; + return ::rpm_byrpmdbid( _state, rpmdbid ); + } + else + { + Package::Ptr pkg( make( solv ) ); + if ( ! pkg ) + return nullptr; + Pathname localfile( pkg->cachedLocation() ); + if ( localfile.empty() ) + return nullptr; + AutoDispose fp( ::fopen( localfile.c_str(), "re" ), ::fclose ); + return ::rpm_byfp( _state, fp, localfile.c_str() ); + } + } + + private: + ProgressData & _progress; + AutoDispose _state; + std::unordered_set _visited; + sat::Queue _noFilelist; + }; + + } // namespace + /////////////////////////////////////////////////////////////////// + + void TargetImpl::commitFindFileConflicts( const ZYppCommitPolicy & policy_r, ZYppCommitResult & result_r ) + { + sat::Queue todo; + sat::FileConflicts conflicts; + int newpkgs = result_r.transaction().installedResult( todo ); + MIL << "Checking for file conflicts in " << newpkgs << " new packages..." << endl; + if ( ! newpkgs ) + return; + + try { + callback::SendReport report; + ProgressData progress( todo.size() ); + if ( ! report->start( progress ) ) + ZYPP_THROW( AbortRequestException() ); + + FileConflictsCB cb( sat::Pool::instance().get(), progress ); + // lambda receives progress trigger and translates into report + auto sendProgress = [&]( const ProgressData & progress_r )->bool { + if ( ! report->progress( progress_r, cb.noFilelist() ) ) + ZYPP_THROW( AbortRequestException() ); + return true; + }; + progress.sendTo( sendProgress ); + + unsigned count = + ::pool_findfileconflicts( sat::Pool::instance().get(), + todo, + newpkgs, + conflicts, + FINDFILECONFLICTS_USE_SOLVABLEFILELIST | FINDFILECONFLICTS_CHECK_DIRALIASING | FINDFILECONFLICTS_USE_ROOTDIR, + &FileConflictsCB::invoke, + &cb ); + progress.toMax(); + progress.noSend(); + + (count?WAR:MIL) << "Found " << count << " file conflicts." << endl; + if ( ! report->result( progress, cb.noFilelist(), conflicts ) ) + ZYPP_THROW( AbortRequestException() ); + } + catch ( const AbortRequestException & e ) + { + TargetAbortedException excpt( N_("Installation has been aborted as directed.") ); + excpt.remember( e ); + ZYPP_THROW( excpt ); + } + } + + } // namespace target + /////////////////////////////////////////////////////////////////// +} // namespace zypp +/////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/target/TargetImpl.h b/libzypp/zypp/target/TargetImpl.h index 371b8a4..0b6c015 100644 --- a/libzypp/zypp/target/TargetImpl.h +++ b/libzypp/zypp/target/TargetImpl.h @@ -27,8 +27,9 @@ #include "zypp/target/rpm/RpmDb.h" #include "zypp/target/TargetException.h" #include "zypp/target/RequestedLocalesFile.h" -#include "zypp/target/SoftLocksFile.h" +#include "zypp/target/SolvIdentFile.h" #include "zypp/target/HardLocksFile.h" +#include "zypp/ManagedFile.h" /////////////////////////////////////////////////////////////////// namespace zypp @@ -106,7 +107,7 @@ namespace zypp void unload(); void reload(); - + void clearCache(); bool buildCache(); @@ -131,6 +132,9 @@ namespace zypp /** Install a source package on the Target. */ void installSrcPackage( const SrcPackage_constPtr & srcPackage_r ); + /** Provides a source package on the Target. */ + ManagedFile provideSrcPackage( const SrcPackage_constPtr & srcPackage_r ); + /** Overload to realize stream output. */ virtual std::ostream & dumpOn( std::ostream & str ) const { @@ -171,6 +175,11 @@ namespace zypp /** \overload */ static std::string targetDistributionRelease( const Pathname & root_r ); + /** \copydoc Target::targetDistributionFlavor()*/ + std::string targetDistributionFlavor() const; + /** \overload */ + static std::string targetDistributionFlavor( const Pathname & root_r ); + /** \copydoc Target::distributionVersion()*/ Target::DistributionLabel distributionLabel() const; /** \overload */ @@ -197,6 +206,8 @@ namespace zypp CommitPackageCache & packageCache_r, ZYppCommitResult & result_r ); + /** Commit helper checking for file conflicts after download. */ + void commitFindFileConflicts( const ZYppCommitPolicy & policy_r, ZYppCommitResult & result_r ); protected: /** Path to the target */ Pathname _root; @@ -204,8 +215,8 @@ namespace zypp rpm::RpmDb _rpm; /** Requested Locales database */ RequestedLocalesFile _requestedLocalesFile; - /** Soft-locks database */ - SoftLocksFile _softLocksFile; + /** user/auto installed database */ + SolvIdentFile _autoInstalledFile; /** Hard-Locks database */ HardLocksFile _hardLocksFile; /** Cache distributionVersion */ diff --git a/libzypp/zypp/target/modalias/Modalias.cc b/libzypp/zypp/target/modalias/Modalias.cc index ae7c919..8533a28 100644 --- a/libzypp/zypp/target/modalias/Modalias.cc +++ b/libzypp/zypp/target/modalias/Modalias.cc @@ -11,278 +11,210 @@ */ extern "C" { -#include -#include -#include -#include -#include #include } -#include -#include -#include -#include #include +#include +#include #undef ZYPP_BASE_LOGGER_LOGGROUP #define ZYPP_BASE_LOGGER_LOGGROUP "MODALIAS" -#include "zypp/base/Logger.h" -#include "zypp/target/modalias/Modalias.h" +#include "zypp/base/LogTools.h" +#include "zypp/base/IOStream.h" +#include "zypp/base/InputStream.h" +#include "zypp/AutoDispose.h" #include "zypp/PathInfo.h" +#include "zypp/target/modalias/Modalias.h" using std::endl; -using std::string; - /////////////////////////////////////////////////////////////////// namespace zypp -{ ///////////////////////////////////////////////////////////////// +{ /////////////////////////////////////////////////////////////////// namespace target - { ///////////////////////////////////////////////////////////////// - -struct modalias_list { - char *modalias; - struct modalias_list *next; -}; - + { /////////////////////////////////////////////////////////////////// namespace - { ///////////////////////////////////////////////////////////////// - -/* - * For each file in the directory PATH other than . and .., call - * FUNC with the arguments PATH, the file's name, and ARG. - * - * If FUNC returns a non-zero return value, stop reading the directory - * and return that value. Returns -1 if an error occurs. - */ - -int -foreach_file_recursive(const char *path_rec, int (*func)(const char *, const char *, void *), - void *arg) -{ - DIR *dir; - struct dirent *dirent; - char path_tmp[PATH_MAX]; - int ret = 0; - - if (!(dir = opendir(path_rec))) - return -1; - while ((dirent = readdir(dir)) != NULL) { - - if (strcmp(dirent->d_name, ".") == 0 || - strcmp(dirent->d_name, "..") == 0) - continue; - snprintf(path_tmp, sizeof(path_tmp), "%s/%s", path_rec, dirent->d_name); - - PathInfo path(path_tmp, PathInfo::LSTAT); - - if (path.isLink ()) { - continue; - } - if (path.isDir ()){ - (void) foreach_file_recursive(path_tmp, func, arg); - }else if (path.isFile ()){ - if ((ret = func(path_rec, dirent->d_name, arg)) != 0) - break; - }else{ - continue; - } - } - if (closedir(dir) != 0) - return -1; - return ret; -} - -/* - * If DIR/FILE/modalias exists, remember this modalias on the linked modalias list - * passed in in ARG. Never returns an error. - */ -int -read_modalias(const char *dir, const char *file, void *arg) -{ - char path[PATH_MAX]; - int fd; - ssize_t len; - char modalias[PATH_MAX]; - struct modalias_list **list = (struct modalias_list **)arg, *entry; - - if (strcmp(file, "modalias") != 0){ - return 0; + { + /** Filter subtrees known to contain no modalias files */ + inline bool isBlackListed( const Pathname & dir_r, const char * file_r ) + { +#define PATH_IS( D, F ) ( ::strcmp( file_r, F ) == 0 && ::strcmp( dir_r.c_str(), D ) == 0 ) + switch ( file_r[0] ) + { + case 'm': + return PATH_IS( "/sys/devices/system", "memory" ); // bnc#824110: huge tree for systems with large RAM + break; } - snprintf(path, sizeof(path), "%s/%s", dir, file); - if ((fd = open(path, O_RDONLY|O_CLOEXEC)) == -1) - return 0; - len = read(fd, modalias, sizeof(modalias) - 1); - if (len < 0) - goto out; - while (len > 0 && modalias[len - 1] == '\n') - len--; - modalias[len] = 0; - - if ((entry = (struct modalias_list *)malloc(sizeof(*entry))) == NULL) - goto out; - if ((entry->modalias = strdup(modalias)) == NULL) { - free(entry); - goto out; + return false; +#undef PATH_IS + } + + /** Recursively scan for modalias files and scan them to \a arg. */ + void foreach_file_recursive( const Pathname & dir_r, Modalias::ModaliasList & arg ) + { + AutoDispose dir( ::opendir( dir_r.c_str() ), ::closedir ); + if ( ! dir ) + return; + + struct dirent * dirent = NULL; + while ( (dirent = ::readdir(dir)) != NULL ) + { + if ( dirent->d_name[0] == '.' ) + continue; + + if ( isBlackListed( dir_r, dirent->d_name ) ) + continue; + + PathInfo pi( dir_r / dirent->d_name, PathInfo::LSTAT ); + + if ( pi.isDir() ) + { + foreach_file_recursive( pi.path(), arg ); + } + else if ( pi.isFile() && ::strcmp( dirent->d_name, "modalias" ) == 0 ) + { + // read modalias line from file + std::ifstream str( pi.path().c_str() ); + std::string line( iostr::getline( str ) ); + if ( ! line.empty() ) + arg.push_back( line ); + } } - entry->next = *list; - *list = entry; - XXX << "system modalias: " << entry->modalias << endl; - -out: - (void) close(fd); - return 0; -} - - ///////////////////////////////////////////////////////////////// + } } // namespace /////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////// -// -// CLASS NAME : Modalias::Impl -// -/** Modalias implementation. */ -struct Modalias::Impl -{ - struct modalias_list *_modaliases; - - /** Ctor. */ - Impl() - : _modaliases(0) + /////////////////////////////////////////////////////////////////// + // + // CLASS NAME : Modalias::Impl + // + /** Modalias implementation. */ + struct Modalias::Impl { - const char *dir; - char path[PATH_MAX]; - - dir = getenv("ZYPP_MODALIAS_SYSFS"); - if (!dir) - dir = "/sys"; - DBG << "Using /sys directory : " << dir << endl; - - snprintf(path, sizeof(path), "%s", dir); - foreach_file_recursive( path, read_modalias, &_modaliases ); - - } + /** Ctor. */ + Impl() + { + const char * dir = getenv("ZYPP_MODALIAS_SYSFS"); + if ( dir ) + { + PathInfo pi( dir ); + if ( pi.isFile() ) + { + // Debug/testcases: + // find /sys/ -type f -name modalias -print0 | xargs -0 cat >/tmp/modaliases + // ZYPP_MODALIAS_SYSFS=/tmp/modaliases + DBG << "Using $ZYPP_MODALIAS_SYSFS modalias file: " << dir << endl; + iostr::forEachLine( InputStream( pi.path() ), + [&]( int num_r, std::string line_r )->bool + { + this->_modaliases.push_back( line_r ); + return true; + } ); + return; + } + DBG << "Using $ZYPP_MODALIAS_SYSFS: " << dir << endl; + } + else + { + dir = "/sys"; + DBG << "Using /sys directory." << endl; + } - /** Dtor. */ - ~Impl() - { - while (_modaliases != NULL) { - struct modalias_list *l = _modaliases; - _modaliases = _modaliases->next; - free(l->modalias); - free(l); + foreach_file_recursive( dir, _modaliases ); + } + + /** Dtor. */ + ~Impl() + {} + + /* + * Check if a device on the system matches a modalias PATTERN. + * + * Returns NULL if no matching device is found, and the modalias + * of the first matching device otherwise. (More than one device + * may match a given pattern.) + * + * On a system that has the following device, + * + * pci:v00008086d0000265Asv00008086sd00004556bc0Csc03i00 + * + * modalias_matches("pci:v00008086d0000265Asv*sd*bc*sc*i*") will + * return a non-NULL value. + */ + bool query( const char * cap_r ) const + { + if ( cap_r && *cap_r ) + { + for_( it, _modaliases.begin(), _modaliases.end() ) + { + if ( fnmatch( cap_r, (*it).c_str(), 0 ) == 0 ) + return true; + } } - } + return false; + } - /* - * Check if a device on the system matches a modalias PATTERN. - * - * Returns NULL if no matching device is found, and the modalias - * of the first matching device otherwise. (More than one device - * may match a given pattern.) - * - * On a system that has the following device, - * - * pci:v00008086d0000265Asv00008086sd00004556bc0Csc03i00 - * - * modalias_matches("pci:v00008086d0000265Asv*sd*bc*sc*i*") will - * return a non-NULL value. - */ - bool query( const char * cap_r ) const - { - if ( cap_r ) - { - struct modalias_list *l; - for (l = _modaliases; l; l = l->next) { - if ( fnmatch( cap_r, l->modalias, 0 ) == 0 ) - return true; - } - } - return false; - } + public: + ModaliasList _modaliases; - public: - /** Offer default Impl. */ - static shared_ptr nullimpl() - { + public: + /** Offer default Impl. */ + static shared_ptr nullimpl() + { static shared_ptr _nullimpl( new Impl ); return _nullimpl; - } - -}; // struct Modalias::Impl + } -/////////////////////////////////////////////////////////////////// + }; + /////////////////////////////////////////////////////////////////// -/** \relates Modalias::Impl Stream output + /** \relates Modalias::Impl Stream output * And maybe std::ostream & operator<< Modalias::Impl below too. * return libhal version or something like that. - */ -inline std::ostream & operator<<( std::ostream & str, const Modalias::Impl & obj ) -{ - return str << "Modalias::Impl"; -} + */ + inline std::ostream & operator<<( std::ostream & str, const Modalias::Impl & obj ) + { + return dumpRange( str << "Modaliases: (" << obj._modaliases.size() << ") ", obj._modaliases.begin(), obj._modaliases.end() ); + } -/////////////////////////////////////////////////////////////////// -// -// CLASS NAME : Modalias -// -/////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// + // + // CLASS NAME : Modalias + // + /////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////// -// -// METHOD NAME : Modalias::Modalias -// METHOD TYPE : Ctor -// -Modalias::Modalias() -: _pimpl( Impl::nullimpl() ) -{} + Modalias::Modalias() + : _pimpl( Impl::nullimpl() ) + {} -/////////////////////////////////////////////////////////////////// -// -// METHOD NAME : Modalias::~Modalias -// METHOD TYPE : Dtor -// -Modalias::~Modalias() -{} + Modalias::~Modalias() + {} -/////////////////////////////////////////////////////////////////// -// -// METHOD NAME : Modalias::instance -// METHOD TYPE : Modalias & -// -Modalias & Modalias::instance() -{ - static Modalias _singleton; - return _singleton; -} + Modalias & Modalias::instance() + { + static Modalias _singleton; + return _singleton; + } -/////////////////////////////////////////////////////////////////// -// Foreward to implenemtation -/////////////////////////////////////////////////////////////////// + bool Modalias::query( const char * cap_r ) const + { return _pimpl->query( cap_r ); } -bool Modalias::query( const char * cap_r ) const -{ return _pimpl->query( cap_r ); } + const Modalias::ModaliasList & Modalias::modaliasList() const + { return _pimpl->_modaliases; } -/****************************************************************** -** -** FUNCTION NAME : operator<< -** FUNCTION TYPE : std::ostream & -*/ -std::ostream & operator<<( std::ostream & str, const Modalias & obj ) -{ - return str << *obj._pimpl; -} + void Modalias::modaliasList( ModaliasList newlist_r ) + { _pimpl->_modaliases.swap( newlist_r ); } + + std::ostream & operator<<( std::ostream & str, const Modalias & obj ) + { return str << *obj._pimpl; } - ///////////////////////////////////////////////////////////////// } // namespace target /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// diff --git a/libzypp/zypp/target/modalias/Modalias.h b/libzypp/zypp/target/modalias/Modalias.h index 35688bb..eb446af 100644 --- a/libzypp/zypp/target/modalias/Modalias.h +++ b/libzypp/zypp/target/modalias/Modalias.h @@ -13,6 +13,7 @@ #define ZYPP_TARGET_MODALIAS_MODALIAS_H #include +#include #include #include "zypp/base/PtrTypes.h" @@ -40,6 +41,8 @@ namespace zypp class Impl; public: + typedef std::vector ModaliasList; + /** Singleton access. */ static Modalias & instance(); @@ -71,6 +74,12 @@ namespace zypp bool query( const std::string & cap_r ) const { return query( cap_r.c_str() ); } + /** List of modaliases found on system */ + const ModaliasList & modaliasList() const; + + /** Manually set list of modaliases to use */ + void modaliasList( ModaliasList newlist_r ); + private: /** Singleton ctor. */ Modalias(); diff --git a/libzypp/zypp/target/rpm/RpmDb.cc b/libzypp/zypp/target/rpm/RpmDb.cc index 9ca2b49..67b47e1 100644 --- a/libzypp/zypp/target/rpm/RpmDb.cc +++ b/libzypp/zypp/target/rpm/RpmDb.cc @@ -54,8 +54,14 @@ using namespace zypp::filesystem; #define FILEFORBACKUPFILES "YaSTBackupModifiedFiles" #define MAXRPMMESSAGELINES 10000 +#define WORKAROUNDRPMPWDBUG + namespace zypp { + namespace zypp_readonly_hack + { + bool IGotIt(); // in readonly-mode + } namespace target { namespace rpm @@ -79,6 +85,26 @@ inline string rpmQuoteFilename( const Pathname & path_r ) } return path; } + + + /** Workaround bnc#827609 - rpm needs a readable pwd so we + * chdir to /. Turn realtive pathnames into absolute ones + * by prepending cwd so rpm still finds them + */ + inline Pathname workaroundRpmPwdBug( Pathname path_r ) + { +#if defined(WORKAROUNDRPMPWDBUG) + if ( path_r.relative() ) + { + // try to prepend cwd + AutoDispose cwd( ::get_current_dir_name(), ::free ); + if ( cwd ) + return Pathname( cwd ) / path_r; + WAR << "Can't get cwd!" << endl; + } +#endif + return path_r; // no problem with absolute pathnames + } } struct KeyRingSignalReceiver : callback::ReceiveReport @@ -400,10 +426,8 @@ void RpmDb::initDatabase( Pathname root_r, Pathname dbPath_r, bool doRebuild_r ) } } - MIL << "Syncronizing keys with zypp keyring" << endl; - // we do this one by one now. - importZyppKeyRingTrustedKeys(); - exportTrustedKeysInZyppKeyRing(); + MIL << "Synchronizing keys with zypp keyring" << endl; + syncTrustedKeys(); // Close the database in case any write acces (create/convert) // happened during init. This should drop any lock acquired @@ -828,87 +852,179 @@ void RpmDb::doRebuildDatabase(callback::SendReport & report) } } -void RpmDb::importZyppKeyRingTrustedKeys() +/////////////////////////////////////////////////////////////////// +namespace { - MIL << "Importing zypp trusted keyring" << std::endl; - - std::list zypp_keys; - zypp_keys = getZYpp()->keyRing()->trustedPublicKeys(); - /* The pubkeys() call below is expensive. It calls gpg2 for each - gpg-pubkey in the rpm db. Useless if we don't have any keys in - zypp yet. */ - if (zypp_keys.empty()) - return; + /** \ref RpmDb::syncTrustedKeys helper + * Compute which keys need to be exprted to / imported from the zypp keyring. + * Return result via argument list. + */ + void computeKeyRingSync( std::set & rpmKeys_r, std::list & zyppKeys_r ) + { + /////////////////////////////////////////////////////////////////// + // Remember latest release and where it ocurred + struct Key + { + Key() + : _inRpmKeys( nullptr ) + , _inZyppKeys( nullptr ) + {} + + void updateIf( const Edition & rpmKey_r ) + { + std::string keyRelease( rpmKey_r.release() ); + int comp = _release.compare( keyRelease ); + if ( comp < 0 ) + { + // update to newer release + _release.swap( keyRelease ); + _inRpmKeys = &rpmKey_r; + _inZyppKeys = nullptr; + if ( !keyRelease.empty() ) + DBG << "Old key in R: gpg-pubkey-" << rpmKey_r.version() << "-" << keyRelease << endl; + } + else if ( comp == 0 ) + { + // stay with this release + if ( ! _inRpmKeys ) + _inRpmKeys = &rpmKey_r; + } + // else: this is an old release + else + DBG << "Old key in R: gpg-pubkey-" << rpmKey_r.version() << "-" << keyRelease << endl; + } + + void updateIf( const PublicKeyData & zyppKey_r ) + { + std::string keyRelease( zyppKey_r.gpgPubkeyRelease() ); + int comp = _release.compare( keyRelease ); + if ( comp < 0 ) + { + // update to newer release + _release.swap( keyRelease ); + _inRpmKeys = nullptr; + _inZyppKeys = &zyppKey_r; + if ( !keyRelease.empty() ) + DBG << "Old key in Z: gpg-pubkey-" << zyppKey_r.gpgPubkeyVersion() << "-" << keyRelease << endl; + } + else if ( comp == 0 ) + { + // stay with this release + if ( ! _inZyppKeys ) + _inZyppKeys = &zyppKey_r; + } + // else: this is an old release + else + DBG << "Old key in Z: gpg-pubkey-" << zyppKey_r.gpgPubkeyVersion() << "-" << keyRelease << endl; + } - std::list rpm_keys = pubkeys(); - for_( it, zypp_keys.begin(), zypp_keys.end() ) + std::string _release; + const Edition * _inRpmKeys; + const PublicKeyData * _inZyppKeys; + }; + /////////////////////////////////////////////////////////////////// + + // collect keys by ID(version) and latest creation(release) + std::map _keymap; + + for_( it, rpmKeys_r.begin(), rpmKeys_r.end() ) { - // we find only the left part of the long gpg key, as rpm does not support long ids - std::list::iterator ik = find( rpm_keys.begin(), rpm_keys.end(), (*it)); - if ( ik != rpm_keys.end() ) - { - MIL << "Key " << (*it).id() << " (" << (*it).name() << ") is already in rpm database." << std::endl; - } - else - { - // now import the key in rpm - try - { - importPubkey( *it ); - MIL << "Trusted key " << (*it).id() << " (" << (*it).name() << ") imported in rpm database." << std::endl; - } - catch (RpmException &e) - { - ERR << "Could not import key " << (*it).id() << " (" << (*it).name() << " from " << (*it).path() << " in rpm database" << std::endl; - } - } + _keymap[(*it).version()].updateIf( *it ); } -} -void RpmDb::exportTrustedKeysInZyppKeyRing() -{ - MIL << "Exporting rpm keyring into zypp trusted keyring" < rpm_keys( pubkeyEditions() ); - list zypp_keys( getZYpp()->keyRing()->trustedPublicKeys() ); + // compute missing keys + std::set rpmKeys; + std::list zyppKeys; + for_( it, _keymap.begin(), _keymap.end() ) + { + DBG << "gpg-pubkey-" << (*it).first << "-" << (*it).second._release << " " + << ( (*it).second._inRpmKeys ? "R" : "_" ) + << ( (*it).second._inZyppKeys ? "Z" : "_" ) << endl; + if ( ! (*it).second._inRpmKeys ) + { + zyppKeys.push_back( *(*it).second._inZyppKeys ); + } + if ( ! (*it).second._inZyppKeys ) + { + rpmKeys.insert( *(*it).second._inRpmKeys ); + } + } + rpmKeys_r.swap( rpmKeys ); + zyppKeys_r.swap( zyppKeys ); + } +} // namespace +/////////////////////////////////////////////////////////////////// - // Temporarily disconnect to prevent the attemt to re-import the exported keys. - callback::TempConnect tempDisconnect; +void RpmDb::syncTrustedKeys( SyncTrustedKeyBits mode_r ) +{ + MIL << "Going to sync trusted keys..." << endl; + std::set rpmKeys( pubkeyEditions() ); + std::list zyppKeys( getZYpp()->keyRing()->trustedPublicKeyData() ); + computeKeyRingSync( rpmKeys, zyppKeys ); + MIL << (mode_r & SYNC_TO_KEYRING ? "" : "(skip) ") << "Rpm keys to export into zypp trusted keyring: " << rpmKeys.size() << endl; + MIL << (mode_r & SYNC_FROM_KEYRING ? "" : "(skip) ") << "Zypp trusted keys to import into rpm database: " << zyppKeys.size() << endl; - TmpFile tmpfile( getZYpp()->tmpPath() ); + /////////////////////////////////////////////////////////////////// + if ( (mode_r & SYNC_TO_KEYRING) && ! rpmKeys.empty() ) { - ofstream tmpos( tmpfile.path().c_str() ); - for_( it, rpm_keys.begin(), rpm_keys.end() ) + // export to zypp keyring + MIL << "Exporting rpm keyring into zypp trusted keyring" < tempDisconnect; + librpmDb::db_const_iterator keepDbOpen; // just to keep a ref. + + TmpFile tmpfile( getZYpp()->tmpPath() ); { - // search the zypp key into the rpm keys - // long id is edition version + release - string id = str::toUpper( (*it).version() + (*it).release()); - list::iterator ik( find( zypp_keys.begin(), zypp_keys.end(), id) ); - if ( ik != zypp_keys.end() ) - { - MIL << "Key " << (*it) << " is already in zypp database." << endl; - } - else + ofstream tmpos( tmpfile.path().c_str() ); + for_( it, rpmKeys.begin(), rpmKeys.end() ) { // we export the rpm key into a file - RpmHeader::constPtr result( new RpmHeader() ); + RpmHeader::constPtr result; getData( string("gpg-pubkey"), *it, result ); - MIL << "Will export trusted key " << (*it) << " to zypp keyring." << endl; tmpos << result->tag_description() << endl; } } + try + { + getZYpp()->keyRing()->multiKeyImport( tmpfile.path(), true /*trusted*/); + } + catch (Exception &e) + { + ERR << "Could not import keys into in zypp keyring" << endl; + } } - try - { - getZYpp()->keyRing()->multiKeyImport( tmpfile.path(), true /*trusted*/); - } - catch (Exception &e) + + /////////////////////////////////////////////////////////////////// + if ( (mode_r & SYNC_FROM_KEYRING) && ! zyppKeys.empty() ) { - ERR << "Could not import keys into in zypp keyring" << endl; + // import from zypp keyring + MIL << "Importing zypp trusted keyring" << std::endl; + for_( it, zyppKeys.begin(), zyppKeys.end() ) + { + try + { + importPubkey( getZYpp()->keyRing()->exportTrustedPublicKey( *it ) ); + } + catch ( const RpmException & exp ) + { + ZYPP_CAUGHT( exp ); + } + } } + MIL << "Trusted keys synced." << endl; } +void RpmDb::importZyppKeyRingTrustedKeys() +{ syncTrustedKeys( SYNC_FROM_KEYRING ); } + +void RpmDb::exportTrustedKeysInZyppKeyRing() +{ syncTrustedKeys( SYNC_TO_KEYRING ); } + /////////////////////////////////////////////////////////////////// // // @@ -919,37 +1035,72 @@ void RpmDb::importPubkey( const PublicKey & pubkey_r ) { FAILIFNOTINITIALIZED; - // check if the key is already in the rpm database and just - // return if it does. - set rpm_keys = pubkeyEditions(); - string keyshortid = pubkey_r.id().substr(8,8); - MIL << "Comparing '" << keyshortid << "' to: "; - for ( set::const_iterator it = rpm_keys.begin(); it != rpm_keys.end(); ++it) - { - string id = str::toUpper( (*it).version() ); - MIL << ", '" << id << "'"; - if ( id == keyshortid ) - { - // they match id - // now check if timestamp is different - Date date = Date(str::strtonum("0x" + (*it).release())); - if ( date == pubkey_r.created() ) - { + // bnc#828672: On the fly key import in READONLY + if ( zypp_readonly_hack::IGotIt() ) + { + WAR << "Key " << pubkey_r << " can not be imported. (READONLY MODE)" << endl; + return; + } - MIL << endl << "Key " << pubkey_r << " is already in the rpm trusted keyring." << endl; - return; - } - else - { - MIL << endl << "Key " << pubkey_r << " has another version in keyring. ( " << date << " & " << pubkey_r.created() << ")" << endl; + // check if the key is already in the rpm database + Edition keyEd( pubkey_r.gpgPubkeyVersion(), pubkey_r.gpgPubkeyRelease() ); + set rpmKeys = pubkeyEditions(); + bool hasOldkeys = false; - } + for_( it, rpmKeys.begin(), rpmKeys.end() ) + { + if ( keyEd == *it ) // quick test (Edition is IdStringType!) + { + MIL << "Key " << pubkey_r << " is already in the rpm trusted keyring. (skip import)" << endl; + return; + } + + if ( keyEd.version() != (*it).version() ) + continue; // different key ID (version) + if ( keyEd.release() < (*it).release() ) + { + MIL << "Key " << pubkey_r << " is older than one in the rpm trusted keyring. (skip import)" << endl; + return; + } + else + { + hasOldkeys = true; + } + } + MIL << "Key " << pubkey_r << " will be imported into the rpm trusted keyring." << (hasOldkeys?"(update)":"(new)") << endl; + + if ( hasOldkeys ) + { + // We must explicitly delete old key IDs first (all releases, + // that's why we don't call removePubkey here). + std::string keyName( "gpg-pubkey-" + keyEd.version() ); + RpmArgVec opts; + opts.push_back ( "-e" ); + opts.push_back ( "--allmatches" ); + opts.push_back ( "--" ); + opts.push_back ( keyName.c_str() ); + // don't call modifyDatabase because it would remove the old + // rpm3 database, if the current database is a temporary one. + run_rpm( opts, ExternalProgram::Stderr_To_Stdout ); + + string line; + while ( systemReadLine( line ) ) + { + ( str::startsWith( line, "error:" ) ? WAR : DBG ) << line << endl; + } + + if ( systemStatus() != 0 ) + { + ERR << "Failed to remove key " << pubkey_r << " from RPM trusted keyring (ignored)" << endl; + } + else + { + MIL << "Key " << pubkey_r << " has been removed from RPM trusted keyring" << endl; } } - // key does not exists, lets import it - MIL << endl; + // import the new key RpmArgVec opts; opts.push_back ( "--import" ); opts.push_back ( "--" ); @@ -962,19 +1113,10 @@ void RpmDb::importPubkey( const PublicKey & pubkey_r ) string line; while ( systemReadLine( line ) ) { - if ( line.substr( 0, 6 ) == "error:" ) - { - WAR << line << endl; - } - else - { - DBG << line << endl; - } + ( str::startsWith( line, "error:" ) ? WAR : DBG ) << line << endl; } - int rpm_status = systemStatus(); - - if ( rpm_status != 0 ) + if ( systemStatus() != 0 ) { //TranslatorExplanation first %s is file name, second is error message ZYPP_THROW(RpmSubprocessException(boost::str(boost::format( @@ -1000,16 +1142,12 @@ void RpmDb::removePubkey( const PublicKey & pubkey_r ) // check if the key is in the rpm database and just // return if it does not. set rpm_keys = pubkeyEditions(); - - // search the key set::const_iterator found_edition = rpm_keys.end(); + std::string pubkeyVersion( pubkey_r.gpgPubkeyVersion() ); - for ( set::const_iterator it = rpm_keys.begin(); it != rpm_keys.end(); ++it) + for_( it, rpm_keys.begin(), rpm_keys.end() ) { - string id = str::toUpper( (*it).version() ); - string keyshortid = pubkey_r.id().substr(8,8); - MIL << "Comparing '" << id << "' to '" << keyshortid << "'" << endl; - if ( id == keyshortid ) + if ( (*it).version() == pubkeyVersion ) { found_edition = it; break; @@ -1079,7 +1217,7 @@ list RpmDb::pubkeys() const if (edition != Edition::noedition) { // we export the rpm key into a file - RpmHeader::constPtr result = new RpmHeader(); + RpmHeader::constPtr result; getData( string("gpg-pubkey"), edition, result ); TmpFile file(getZYpp()->tmpPath()); ofstream os; @@ -1444,6 +1582,9 @@ RpmDb::run_rpm (const RpmArgVec& opts, RpmArgVec args; // always set root and dbpath +#if defined(WORKAROUNDRPMPWDBUG) + args.push_back("#/"); // chdir to / to workaround bnc#819354 +#endif args.push_back("rpm"); args.push_back("--root"); args.push_back(_root.asString().c_str()); @@ -1728,6 +1869,7 @@ void RpmDb::doInstallPackage( const Pathname & filename, RpmInstFlags flags, cal opts.push_back("-U"); opts.push_back("--percent"); + opts.push_back("--noglob"); // ZConfig defines cross-arch installation if ( ! ZConfig::instance().systemArchitecture().compatibleWith( ZConfig::instance().defaultSystemArchitecture() ) ) @@ -1751,11 +1893,13 @@ void RpmDb::doInstallPackage( const Pathname & filename, RpmInstFlags flags, cal opts.push_back ("--justdb"); if (flags & RPMINST_TEST) opts.push_back ("--test"); + if (flags & RPMINST_NOPOSTTRANS) + opts.push_back ("--noposttrans"); opts.push_back("--"); // rpm requires additional quoting of special chars: - string quotedFilename( rpmQuoteFilename( filename ) ); + string quotedFilename( rpmQuoteFilename( workaroundRpmPwdBug( filename ) ) ); opts.push_back ( quotedFilename.c_str() ); modifyDatabase(); // BEFORE run_rpm diff --git a/libzypp/zypp/target/rpm/RpmDb.h b/libzypp/zypp/target/rpm/RpmDb.h index 23666e3..956ba25 100644 --- a/libzypp/zypp/target/rpm/RpmDb.h +++ b/libzypp/zypp/target/rpm/RpmDb.h @@ -323,6 +323,17 @@ class RpmDb : public base::ReferenceCounted, private base::NonCopyable // /////////////////////////////////////////////////////////////////// public: + /** Sync mode for \ref syncTrustedKeys */ + enum SyncTrustedKeyBits + { + SYNC_TO_KEYRING = 1<<0, //! export rpm trusted keys into zypp trusted keyring + SYNC_FROM_KEYRING = 1<<1, //! import zypp trusted keys into rpm database. + SYNC_BOTH = SYNC_TO_KEYRING | SYNC_FROM_KEYRING + }; + /** + * Sync trusted keys stored in rpm database and zypp trusted keyring. + */ + void syncTrustedKeys( SyncTrustedKeyBits mode_r = SYNC_BOTH ); /** * iterates through zypp keyring and import all non existant keys * into rpm keyring @@ -332,6 +343,7 @@ class RpmDb : public base::ReferenceCounted, private base::NonCopyable * insert all rpm trusted keys into zypp trusted keyring */ void exportTrustedKeysInZyppKeyRing(); + private: /** * The connection to the rpm process. diff --git a/libzypp/zypp/target/rpm/RpmFlags.h b/libzypp/zypp/target/rpm/RpmFlags.h index 3d89fe4..f24a676 100644 --- a/libzypp/zypp/target/rpm/RpmFlags.h +++ b/libzypp/zypp/target/rpm/RpmFlags.h @@ -46,7 +46,8 @@ namespace zypp RPMINST_NODIGEST = 0x0040, RPMINST_NOSIGNATURE= 0x0080, RPMINST_NOUPGRADE = 0x0100, - RPMINST_TEST = 0x0200 + RPMINST_TEST = 0x0200, + RPMINST_NOPOSTTRANS= 0x0400 }; /** \relates RpmInstFlag Type-safe way of storing OR-combinations. */ diff --git a/libzypp/zypp/target/rpm/RpmHeader.cc b/libzypp/zypp/target/rpm/RpmHeader.cc index 2ea29fa..e4327e5 100644 --- a/libzypp/zypp/target/rpm/RpmHeader.cc +++ b/libzypp/zypp/target/rpm/RpmHeader.cc @@ -285,6 +285,11 @@ bool RpmHeader::isSrc() const return has_tag( RPMTAG_SOURCEPACKAGE ); } +bool RpmHeader::isNosrc() const +{ + return has_tag( RPMTAG_SOURCEPACKAGE ) && ( has_tag( RPMTAG_NOSOURCE ) || has_tag( RPMTAG_NOPATCH ) ); +} + /////////////////////////////////////////////////////////////////// // // @@ -422,6 +427,32 @@ CapabilitySet RpmHeader::PkgRelList_val( tag tag_r, bool pre, std::set * freq_r ) const // CapabilitySet RpmHeader::tag_enhances( std::set * freq_r ) const { +#ifdef RPMTAG_OLDSUGGESTS + return PkgRelList_val( RPMTAG_ENHANCENAME, false, freq_r ); +#else return PkgRelList_val( RPMTAG_ENHANCESNAME, false, freq_r ); +#endif } /////////////////////////////////////////////////////////////////// @@ -594,7 +630,45 @@ CapabilitySet RpmHeader::tag_enhances( std::set * freq_r ) const // CapabilitySet RpmHeader::tag_suggests( std::set * freq_r ) const { +#ifdef RPMTAG_OLDSUGGESTS + return PkgRelList_val( RPMTAG_SUGGESTNAME, false, freq_r ); +#else return PkgRelList_val( RPMTAG_SUGGESTSNAME, false, freq_r ); +#endif + } + +/////////////////////////////////////////////////////////////////// +// +// +// METHOD NAME : RpmHeader::tag_supplements +// METHOD TYPE : CapabilitySet +// +// DESCRIPTION : +// +CapabilitySet RpmHeader::tag_supplements( std::set * freq_r ) const + { +#ifdef RPMTAG_OLDSUGGESTS + return PkgRelList_val( RPMTAG_SUPPLEMENTNAME, false, freq_r ); +#else + return CapabilitySet(); +#endif + } + +/////////////////////////////////////////////////////////////////// +// +// +// METHOD NAME : RpmHeader::tag_recommends +// METHOD TYPE : CapabilitySet +// +// DESCRIPTION : +// +CapabilitySet RpmHeader::tag_recommends( std::set * freq_r ) const + { +#ifdef RPMTAG_OLDSUGGESTS + return PkgRelList_val( RPMTAG_RECOMMENDNAME, false, freq_r ); +#else + return CapabilitySet(); +#endif } /////////////////////////////////////////////////////////////////// @@ -751,59 +825,44 @@ std::string RpmHeader::tag_url() const std::string RpmHeader::tag_os() const { return string_val( RPMTAG_OS ); + } -/////////////////////////////////////////////////////////////////// -// -// -// METHOD NAME : RpmHeader::tag_prein -// METHOD TYPE : std::string -// -// DESCRIPTION : -// std::string RpmHeader::tag_prein() const -{ - return string_val( RPMTAG_PREIN ); -} +{ return string_val( RPMTAG_PREIN ); } + +std::string RpmHeader::tag_preinprog() const +{ return string_val( RPMTAG_PREINPROG ); } -/////////////////////////////////////////////////////////////////// -// -// -// METHOD NAME : RpmHeader::tag_postin -// METHOD TYPE : std::string -// -// DESCRIPTION : -// std::string RpmHeader::tag_postin() const -{ - return string_val( RPMTAG_POSTIN ); -} +{ return string_val( RPMTAG_POSTIN ); } + +std::string RpmHeader::tag_postinprog() const +{ return string_val( RPMTAG_POSTINPROG ); } -/////////////////////////////////////////////////////////////////// -// -// -// METHOD NAME : RpmHeader::tag_preun -// METHOD TYPE : std::string -// -// DESCRIPTION : -// std::string RpmHeader::tag_preun() const -{ - return string_val( RPMTAG_PREUN ); -} +{ return string_val( RPMTAG_PREUN ); } + +std::string RpmHeader::tag_preunprog() const +{ return string_val( RPMTAG_PREUNPROG ); } -/////////////////////////////////////////////////////////////////// -// -// -// METHOD NAME : RpmHeader::tag_postun -// METHOD TYPE : std::string -// -// DESCRIPTION : -// std::string RpmHeader::tag_postun() const -{ - return string_val( RPMTAG_POSTUN ); -} +{ return string_val( RPMTAG_POSTUN ); } + +std::string RpmHeader::tag_postunprog() const +{ return string_val( RPMTAG_POSTUNPROG ); } + +std::string RpmHeader::tag_pretrans() const +{ return string_val( RPMTAG_PRETRANS ); } + +std::string RpmHeader::tag_pretransprog() const +{ return string_val( RPMTAG_PRETRANSPROG ); } + +std::string RpmHeader::tag_posttrans() const +{ return string_val( RPMTAG_POSTTRANS ); } + +std::string RpmHeader::tag_posttransprog() const +{ return string_val( RPMTAG_POSTTRANSPROG ); } /////////////////////////////////////////////////////////////////// // @@ -955,108 +1014,6 @@ Changelog RpmHeader::tag_changelog() const return ret; } -/////////////////////////////////////////////////////////////////// -// -// -// METHOD NAME : RpmHeader::tag_du -// METHOD TYPE : PkgDu & -// -// DESCRIPTION : -// -DiskUsage & RpmHeader::tag_du( DiskUsage & dudata_r ) const -{ - dudata_r.clear(); - stringList basenames; - if ( string_list( RPMTAG_BASENAMES, basenames ) ) - { - stringList dirnames; - string_list( RPMTAG_DIRNAMES, dirnames ); - intList dirindexes; - int_list( RPMTAG_DIRINDEXES, dirindexes ); - - intList filedevices; - int_list( RPMTAG_FILEDEVICES, filedevices ); - intList fileinodes; - int_list( RPMTAG_FILEINODES, fileinodes ); - intList filesizes; - int_list( RPMTAG_FILESIZES, filesizes ); - intList filemodes; - int_list( RPMTAG_FILEMODES, filemodes ); - - /////////////////////////////////////////////////////////////////// - // Create and collect Entries by index. devino_cache is used to - // filter out hardliks ( different name but same device and inode ). - /////////////////////////////////////////////////////////////////// - filesystem::DevInoCache trace; - std::vector entries; - entries.resize( dirnames.size() ); - for ( unsigned i = 0; i < dirnames.size(); ++i ) - { - entries[i] = DiskUsage::Entry( dirnames[i] ); - - // cut off deeper directory levels in DiskUsage::Entry - unsigned level = 3; // number of '/' incl. a trailing one - std::string::size_type pos = 0; // we know rpm stores absolute pathnames - while ( --level && pos != std::string::npos ) - { - pos = entries[i].path.find( "/", pos+1 ); - } - if ( pos != std::string::npos ) - { - entries[i].path.erase( pos+1 ); - } - } - - for ( unsigned i = 0; i < basenames.size(); ++ i ) - { - filesystem::StatMode mode( filemodes[i] ); - if ( mode.isFile() ) - { - if ( trace.insert( filedevices[i], fileinodes[i] ) ) - { - // Count full 1K blocks - entries[dirindexes[i]]._size += ByteCount( filesizes[i] ).blocks( ByteCount::K ); - ++(entries[dirindexes[i]]._files); - } - // else: hardlink; already counted this device/inode - } - } - - /////////////////////////////////////////////////////////////////// - // Collect all enties. We first unify the duplicate entries that - // were created by cutting off deeper levels. Then the size of each - // directory must also be added to each of it's parent directories. - /////////////////////////////////////////////////////////////////// - DiskUsage tmpdata; - for ( unsigned i = 0; i < entries.size(); ++i ) - { - if ( entries[i]._size ) - tmpdata.add( entries[i] ); - } - - for_( it, tmpdata.begin(), tmpdata.end() ) - { - DiskUsage::Entry ent( *it ); - - do { - dudata_r.add( ent ); - if ( ent.path.size() <= 1 ) // "" or "/" - break; - - // set path to parent dir. Note that DiskUsage::Entry - // has leading and trailing '/' on pathnmes. - std::string::size_type rstart = ent.path.size() - 2; // trailing '/' ! - std::string::size_type lpos = ent.path.rfind( '/', rstart ); // one but last '/' - if ( lpos == std::string::npos ) - break; - - ent.path.erase( lpos + 1 ); - } while( true ); - } - } - return dudata_r; -} - } // namespace rpm } // namespace target } // namespace zypp diff --git a/libzypp/zypp/target/rpm/RpmHeader.h b/libzypp/zypp/target/rpm/RpmHeader.h index aa6d8b2..697b2cb 100644 --- a/libzypp/zypp/target/rpm/RpmHeader.h +++ b/libzypp/zypp/target/rpm/RpmHeader.h @@ -20,7 +20,6 @@ #include "zypp/Package.h" #include "zypp/Changelog.h" #include "zypp/Pathname.h" -#include "zypp/DiskUsage.h" namespace zypp @@ -83,7 +82,8 @@ class RpmHeader : public BinHeader virtual ~RpmHeader(); - bool isSrc() const; + bool isSrc() const; //< Either 'src' or 'nosrc' + bool isNosrc() const; //< Only 'nosrc' public: @@ -125,11 +125,14 @@ class RpmHeader : public BinHeader * @see #tag_provides **/ CapabilitySet tag_suggests( std::set * freq_r = 0 ) const; - /** Unsupported by rpm. + /** + * @see #tag_provides + **/ + CapabilitySet tag_supplements( std::set * freq_r = 0 ) const; + /** * @see #tag_provides **/ - CapabilitySet tag_supplements( std::set * freq_r = 0 ) const - { return CapabilitySet(); } + CapabilitySet tag_recommends( std::set * freq_r = 0 ) const; ByteCount tag_size() const; ByteCount tag_archivesize() const; @@ -145,9 +148,17 @@ class RpmHeader : public BinHeader std::string tag_url() const; std::string tag_os() const; std::string tag_prein() const; + std::string tag_preinprog() const; std::string tag_postin() const; + std::string tag_postinprog() const; std::string tag_preun() const; + std::string tag_preunprog() const; std::string tag_postun() const; + std::string tag_postunprog() const; + std::string tag_pretrans() const; + std::string tag_pretransprog() const; + std::string tag_posttrans() const; + std::string tag_posttransprog()const; std::string tag_sourcerpm() const; /** just the list of names */ @@ -161,11 +172,6 @@ class RpmHeader : public BinHeader Changelog tag_changelog() const; - /** - * Returns reference to arg dudata_r. - **/ - DiskUsage & tag_du( DiskUsage & dudata_r ) const; - public: virtual std::ostream & dumpOn( std::ostream & str ) const; diff --git a/libzypp/zypp/target/rpm/librpm.h b/libzypp/zypp/target/rpm/librpm.h index 2d7425d..17e801d 100644 --- a/libzypp/zypp/target/rpm/librpm.h +++ b/libzypp/zypp/target/rpm/librpm.h @@ -28,6 +28,7 @@ extern "C" #include #include #include +#include #include } diff --git a/libzypp/zypp/target/rpm/librpmDb.cc b/libzypp/zypp/target/rpm/librpmDb.cc index 3f472f4..cc419dd 100644 --- a/libzypp/zypp/target/rpm/librpmDb.cc +++ b/libzypp/zypp/target/rpm/librpmDb.cc @@ -679,7 +679,11 @@ class librpmDb::db_const_iterator::D if ( ! create( RPMDBI_PACKAGES ) ) return false; #warning TESTCASE: rpmdbAppendIterator and (non)sequential access? +#ifdef RPMFILEITERMAX // since rpm.4.12 + ::rpmdbAppendIterator( _mi, (const unsigned *)&off_r, 1 ); +#else ::rpmdbAppendIterator( _mi, &off_r, 1 ); +#endif return advance(); } diff --git a/libzypp/zypp/target/rpm/librpmDb.h b/libzypp/zypp/target/rpm/librpmDb.h index 7bfbd34..50dfc81 100644 --- a/libzypp/zypp/target/rpm/librpmDb.h +++ b/libzypp/zypp/target/rpm/librpmDb.h @@ -79,7 +79,7 @@ class librpmDb : public base::ReferenceCounted, private base::NonCopyable static librpmDb::constPtr _defaultDb; /** - * Wheter access is blocked (no _defaultDb will be available). + * Whether access is blocked (no _defaultDb will be available). **/ static bool _dbBlocked; diff --git a/libzypp/zypp/ui/Selectable.h b/libzypp/zypp/ui/Selectable.h index 897155e..3743e96 100644 --- a/libzypp/zypp/ui/Selectable.h +++ b/libzypp/zypp/ui/Selectable.h @@ -222,7 +222,7 @@ namespace zypp * If the specified candidate is not already installed (\ref identicalInstalled), * and the \a causer_r has sufficient permisssion, then \a newCandidate_r is set as the new * candidate (\ref setCandidate) and selected for installation. - * \returns \c True if \a newCandidate_r is already installed or sucessfully selected for installation. + * \returns \c True if \a newCandidate_r is already installed or successfully selected for installation. */ bool setOnSystem( const PoolItem & newCandidate_r, ResStatus::TransactByValue causer_r = ResStatus::USER ); @@ -286,7 +286,7 @@ namespace zypp /** True if candidate object is present. */ bool hasCandidateObj() const - { return candidateObj(); } + { return bool(candidateObj()); } /** True if installed and candidate object is present */ bool hasBothObjects() const diff --git a/libzypp/zypp/ui/SelectableImpl.cc b/libzypp/zypp/ui/SelectableImpl.cc index 9c02863..ebcfc31 100644 --- a/libzypp/zypp/ui/SelectableImpl.cc +++ b/libzypp/zypp/ui/SelectableImpl.cc @@ -140,10 +140,10 @@ namespace zypp // Queries // bool hasInstalled() const - { return inst; } + { return bool(inst); } bool hasCandidate() const - { return cand; } + { return bool(cand); } bool hasInstalledOnly() const { return inst && !cand; } diff --git a/libzypp/zypp/ui/SelectableImpl.h b/libzypp/zypp/ui/SelectableImpl.h index c765204..4bafbf0 100644 --- a/libzypp/zypp/ui/SelectableImpl.h +++ b/libzypp/zypp/ui/SelectableImpl.h @@ -145,18 +145,14 @@ namespace zypp { PoolItem defaultCand( defaultCandidate() ); - if ( multiversionInstall() ) - return identicalInstalled( defaultCand ) ? PoolItem() : defaultCand; + // multiversionInstall: This returns the candidate for the last + // instance installed. Actually we'd need a list here. if ( installedEmpty() || ! defaultCand ) return defaultCand; // Here: installed and defaultCand are non NULL and it's not a // multiversion install. - // update candidate must come from the highest priority repo - if ( defaultCand->repoInfo().priority() != (*availableBegin())->repoInfo().priority() ) - return PoolItem(); - PoolItem installed( installedObj() ); // check vendor change if ( ! ( ResPool::instance().resolver().allowVendorChange() @@ -189,11 +185,11 @@ namespace zypp /** \copydoc Selectable::identicalAvailable( const PoolItem & )const */ bool identicalAvailable( const PoolItem & rhs ) const - { return identicalAvailableObj( rhs ); } + { return bool(identicalAvailableObj( rhs )); } /** \copydoc Selectable::identicalInstalled( const PoolItem & )const */ bool identicalInstalled( const PoolItem & rhs ) const - { return identicalInstalledObj( rhs ); } + { return bool(identicalInstalledObj( rhs )); } /** \copydoc Selectable::identicalAvailableObj( const PoolItem & rhs ) const */ PoolItem identicalAvailableObj( const PoolItem & rhs ) const @@ -363,7 +359,7 @@ namespace zypp PoolItem defaultCandidate() const { - if ( ! ( multiversionInstall() || installedEmpty() ) ) + if ( ! installedEmpty() ) { // prefer the installed objects arch and vendor bool solver_allowVendorChange( ResPool::instance().resolver().allowVendorChange() ); diff --git a/libzypp/zypp/url/UrlBase.cc b/libzypp/zypp/url/UrlBase.cc index 34ab0bd..5238d52 100644 --- a/libzypp/zypp/url/UrlBase.cc +++ b/libzypp/zypp/url/UrlBase.cc @@ -231,7 +231,11 @@ namespace zypp const std::string &querystr, const std::string &fragment) { - setScheme(scheme); + if ( scheme.empty() && *pathdata.c_str() == '/' ) + setScheme("file"); + else + setScheme(scheme); + setAuthority(authority); setPathData(pathdata); setQueryString(querystr); diff --git a/libzypp/zypp/zypp_detail/ZYppImpl.cc b/libzypp/zypp/zypp_detail/ZYppImpl.cc index 7c6589f..f0023e7 100644 --- a/libzypp/zypp/zypp_detail/ZYppImpl.cc +++ b/libzypp/zypp/zypp_detail/ZYppImpl.cc @@ -24,11 +24,20 @@ #include "zypp/sat/Pool.h" #include "zypp/PoolItem.h" +#include "zypp/ZYppCallbacks.h" // JobReport::instance + using std::endl; /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// + + callback::SendReport & JobReport::instance() + { + static callback::SendReport _report; + return _report; + } + /////////////////////////////////////////////////////////////////// namespace zypp_detail { ///////////////////////////////////////////////////////////////// @@ -162,6 +171,13 @@ namespace zypp _target->_pimpl->installSrcPackage( srcPackage_r ); } + ManagedFile ZYppImpl::provideSrcPackage( const SrcPackage_constPtr & srcPackage_r ) + { + if (! _target) + ZYPP_THROW( Exception("Target not initialized.") ); + return _target->_pimpl->provideSrcPackage( srcPackage_r ); + } + //------------------------------------------------------------------------ // target store path diff --git a/libzypp/zypp/zypp_detail/ZYppImpl.h b/libzypp/zypp/zypp_detail/ZYppImpl.h index 2294d8c..fc70cfa 100644 --- a/libzypp/zypp/zypp_detail/ZYppImpl.h +++ b/libzypp/zypp/zypp_detail/ZYppImpl.h @@ -21,6 +21,7 @@ #include "zypp/ZYppCommit.h" #include "zypp/ResTraits.h" #include "zypp/DiskUsageCounter.h" +#include "zypp/ManagedFile.h" using namespace zypp::filesystem; @@ -92,6 +93,9 @@ namespace zypp /** Install a source package on the Target. */ void installSrcPackage( const SrcPackage_constPtr & srcPackage_r ); + /** Install a source package on the Target. */ + ManagedFile provideSrcPackage( const SrcPackage_constPtr & srcPackage_r ); + public: /** Get the path where zypp related plugins store persistent data and caches */ Pathname homePath() const; diff --git a/rpm/libzypp.spec b/rpm/libzypp.spec index eff271e..b617b2c 100644 --- a/rpm/libzypp.spec +++ b/rpm/libzypp.spec @@ -2,7 +2,7 @@ Name: libzypp License: GPL v2 or later Group: System/Packages Summary: Package, Patch, Pattern, and Product Management -Version: 12.2.0 +Version: 14.35.0 Release: 1 Source: %{name}-%{version}.tar.bz2 Source1: %{name}-rpmlintrc @@ -217,4 +217,4 @@ fi %{_includedir}/zypp %{_datadir}/cmake/Modules/* %{_libdir}/pkgconfig/libzypp.pc -%doc %_mandir/man5/locks.5.* +%doc %{_mandir}/man?/*.?.gz diff --git a/upstream b/upstream index 8b5d5f8..9c54d1b 160000 --- a/upstream +++ b/upstream @@ -1 +1 @@ -Subproject commit 8b5d5f8a897a51d7d1adefe9d5602be9be56cdbe +Subproject commit 9c54d1b85fe5f0e9784b685bcf31ad9330227f27