Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / RepoManager.cc
index 6ba57a3..3225ad8 100644 (file)
@@ -18,6 +18,8 @@
 #include <map>
 #include <algorithm>
 
+#include <solv/solvversion.h>
+
 #include "zypp/base/InputStream.h"
 #include "zypp/base/LogTools.h"
 #include "zypp/base/Gettext.h"
@@ -840,7 +842,7 @@ namespace zypp
       // Cleanup orphanded service repos:
       if ( ! orphanedRepos.empty() )
       {
-       for ( auto & repoInfo : orphanedRepos )
+       for ( const auto & repoInfo : orphanedRepos )
        {
          MIL << "Delete orphaned service repo " << repoInfo.alias() << endl;
          // translators: Cleanup a repository previously owned by a meanwhile unknown (deleted) service.
@@ -952,7 +954,7 @@ namespace zypp
     assert_alias(info);
     try
     {
-      MIL << "Going to try to check whether refresh is needed for " << url << " (" << info.type() << ")" << endl;
+      MIL << "Going to try to check whether refresh is needed for " << url << endl;
 
       // first check old (cached) metadata
       Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
@@ -1050,7 +1052,7 @@ namespace zypp
          refresh = true;
        }
       }
-      else // includes newstatus.empty() if e.g. repo format changed
+      else
       {
        MIL << "repo has changed, going to refresh" << endl;
        refresh = true;
@@ -1079,12 +1081,13 @@ namespace zypp
     assert_urls(info);
 
     // we will throw this later if no URL checks out fine
-    RepoException rexception( info, _PL("Valid metadata not found at specified URL",
+    RepoException rexception( info, PL_("Valid metadata not found at specified URL",
                                        "Valid metadata not found at specified URLs",
                                        info.baseUrlsSize() ) );
 
     // Suppress (interactive) media::MediaChangeReport if we in have multiple basurls (>1)
     media::ScopedDisableMediaChangeReport guard( info.baseUrlsSize() > 1 );
+
     // try urls one by one
     for ( RepoInfo::urls_const_iterator it = info.baseUrlsBegin(); it != info.baseUrlsEnd(); ++it )
     {
@@ -1099,15 +1102,16 @@ namespace zypp
 
         MIL << "Going to refresh metadata from " << url << endl;
 
-       // bsc#1048315: Always re-probe in case of repo format change.
-       // TODO: Would be sufficient to verify the type and re-probe
-       // if verification failed (or type is RepoType::NONE)
         repo::RepoType repokind = info.type();
+
+        // if the type is unknown, try probing.
+       if ( repokind == RepoType::NONE )
        {
-         repo::RepoType probed = probe( *it, info.path() );
-         if ( repokind != probed )
+         // unknown, probe it
+         repokind = probe( *it, info.path() );
+
+         if (repokind.toEnum() != RepoType::NONE_e)
          {
-           repokind = probed;
            // Adjust the probed type in RepoInfo
            info.setProbedType( repokind ); // lazy init!
            //save probed type only for repos in system
@@ -1260,8 +1264,14 @@ namespace zypp
       if ( cache_status == raw_metadata_status )
       {
         MIL << info.alias() << " cache is up to date with metadata." << endl;
-        if ( policy == BuildIfNeeded ) {
-          return;
+        if ( policy == BuildIfNeeded )
+       {
+         // On the fly add missing solv.idx files for bash completion.
+         const Pathname & base = solv_path_for_repoinfo( _options, info);
+         if ( ! PathInfo(base/"solv.idx").isExist() )
+           sat::updateSolvFileIndex( base/"solv" );
+
+         return;
         }
         else {
           MIL << info.alias() << " cache rebuild is forced" << endl;
@@ -1326,16 +1336,15 @@ namespace zypp
         scoped_ptr<MediaMounter> forPlainDirs;
 
         ExternalProgram::Arguments cmd;
-        cmd.push_back( PathInfo( "/usr/bin/repo2solv" ).isFile() ? "repo2solv" : "repo2solv.sh" );
+        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
-        cmd.push_back( "-A" ); // autogenerate application pseudo packages
 
         if ( repokind == RepoType::RPMPLAINDIR )
         {
-          forPlainDirs.reset( new MediaMounter( info.url() ) );
+          forPlainDirs.reset( new MediaMounter( *info.baseUrlsBegin() ) );
           // recusive for plaindir as 2nd arg!
           cmd.push_back( "-R" );
           // FIXME this does only work form dir: URLs
@@ -1366,6 +1375,7 @@ namespace zypp
 
         // We keep it.
         guard.resetDispose();
+       sat::updateSolvFileIndex( solvfile );   // content digest for zypper bash completion
       }
       break;
       default:
@@ -1569,19 +1579,13 @@ namespace zypp
     {
       Repository repo = sat::Pool::instance().addRepoSolv( solvfile, info );
       // test toolversion in order to rebuild solv file in case
-      // it was written by an old libsolv-tool parser.
-      //
-      // Known version strings used:
-      //  - <no string>
-      //  - "1.0"
-      //
-      sat::LookupRepoAttr toolversion( sat::SolvAttr::repositoryToolVersion, repo );
-      if ( toolversion.begin().asString().empty() )
+      // it was written by a different libsolv-tool parser.
+      const std::string & toolversion( sat::LookupRepoAttr( sat::SolvAttr::repositoryToolVersion, repo ).begin().asString() );
+      if ( toolversion != LIBSOLV_TOOLVERSION )
       {
         repo.eraseFromPool();
-        ZYPP_THROW(Exception("Solv-file was created by old parser."));
+        ZYPP_THROW(Exception(str::Str() << "Solv-file was created by '"<<toolversion<<"'-parser (want "<<LIBSOLV_TOOLVERSION<<")."));
       }
-      // else: up-to-date (or even newer).
     }
     catch ( const Exception & exp )
     {
@@ -1616,13 +1620,16 @@ namespace zypp
     if ( _options.probe )
     {
       DBG << "unknown repository type, probing" << endl;
-      assert_urls(tosave);
 
-      RepoType probedtype( probe( tosave.url(), info.path() ) );
-      if ( probedtype == RepoType::NONE )
-       ZYPP_THROW(RepoUnknownTypeException(info));
-      else
-       tosave.setType(probedtype);
+      RepoType probedtype;
+      probedtype = probe( *tosave.baseUrlsBegin(), info.path() );
+      if ( tosave.baseUrlsSize() > 0 )
+      {
+        if ( probedtype == RepoType::NONE )
+          ZYPP_THROW(RepoUnknownTypeException(info));
+        else
+          tosave.setType(probedtype);
+      }
     }
 
     progress.set(50);
@@ -1859,6 +1866,14 @@ namespace zypp
             newinfo.dumpAsIniOn(file);
       }
 
+      if ( toedit.enabled() && !newinfo.enabled() )
+      {
+       // On the fly remove solv.idx files for bash completion if a repo gets disabled.
+       const Pathname & solvidx = solv_path_for_repoinfo(_options, newinfo)/"solv.idx";
+       if ( PathInfo(solvidx).isExist() )
+         filesystem::unlink( solvidx );
+      }
+
       newinfo.setFilepath(toedit.filepath());
       reposManip().erase(toedit);
       reposManip().insert(newinfo);
@@ -2004,13 +2019,34 @@ namespace zypp
     ServiceInfo service( getService( alias ) );
     assert_alias( service );
     assert_url( service );
+    MIL << "Going to refresh service '" << service.alias() <<  "', url: " << service.url() << ", opts: " << options_r << endl;
+
+    if ( service.ttl() && !( options_r.testFlag( RefreshService_forceRefresh) || options_r.testFlag( RefreshService_restoreStatus ) ) )
+    {
+      // Service defines a TTL; maybe we can re-use existing data without refresh.
+      Date lrf = service.lrf();
+      if ( lrf )
+      {
+       Date now( Date::now() );
+       if ( lrf <= now )
+       {
+         if ( (lrf+=service.ttl()) > now ) // lrf+= !
+         {
+           MIL << "Skip: '" << service.alias() << "' metadata valid until " << lrf << endl;
+           return;
+         }
+       }
+       else
+         WAR << "Force: '" << service.alias() << "' metadata last refresh in the future: " << lrf << endl;
+      }
+    }
+
     // NOTE: It might be necessary to modify and rewrite the service info.
     // 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() << ", opts: " << options_r << endl;
 
-    //! \todo add callbacks for apps (start, end, repo removed, repo added, repo changed)
+    //! \todo add callbacks for apps (start, end, repo removed, repo added, repo changed)?
 
     // if the type is unknown, try probing.
     if ( service.type() == repo::ServiceType::NONE )
@@ -2032,6 +2068,7 @@ namespace zypp
     DBG << "ServicesTargetDistro: " << servicesTargetDistro << endl;
 
     // parse it
+    Date::Duration origTtl = service.ttl();    // FIXME Ugly hack: const service.ttl modified when parsing
     RepoCollector collector(servicesTargetDistro);
     // FIXME Ugly hack: ServiceRepos may throw ServicePluginInformalException
     // which is actually a notification. Using an exception for this
@@ -2039,7 +2076,7 @@ namespace zypp
     // and in zypper.
     std::pair<DefaultIntegral<bool,false>, repo::ServicePluginInformalException> uglyHack;
     try {
-      ServiceRepos repos(service, bind( &RepoCollector::collect, &collector, _1 ));
+      ServiceRepos( service, bind( &RepoCollector::collect, &collector, _1 ) );
     }
     catch ( const repo::ServicePluginInformalException & e )
     {
@@ -2047,7 +2084,12 @@ namespace zypp
       uglyHack.first = true;
       uglyHack.second = e;
     }
-
+    if ( service.ttl() != origTtl )    // repoindex.xml changed ttl
+    {
+      if ( !service.ttl() )
+       service.setLrf( Date() );       // don't need lrf when zero ttl
+      serviceModified = true;
+    }
     ////////////////////////////////////////////////////////////////////////////
     // On the fly remember the new repo states as defined the reopoindex.xml.
     // Move into ServiceInfo later.
@@ -2310,10 +2352,19 @@ namespace zypp
 
     ////////////////////////////////////////////////////////////////////////////
     // save service if modified: (unless a plugin service)
-    if ( serviceModified && service.type() != ServiceType::PLUGIN )
+    if ( service.type() != ServiceType::PLUGIN )
     {
-      // write out modified service file.
-      modifyService( service.alias(), service );
+      if ( service.ttl() )
+      {
+       service.setLrf( Date::now() );  // remember last refresh
+       serviceModified =  true;        // or use a cookie file
+      }
+
+      if ( serviceModified )
+      {
+       // write out modified service file.
+       modifyService( service.alias(), service );
+      }
     }
 
     if ( uglyHack.first )