Service handling fixes. Added ServiceException.
authorMichael Andres <ma@suse.de>
Tue, 16 Sep 2008 16:42:58 +0000 (16:42 +0000)
committerMichael Andres <ma@suse.de>
Tue, 16 Sep 2008 16:42:58 +0000 (16:42 +0000)
12 files changed:
devel/devel.ma/NewPool.cc
devel/devel.ma/Tools.h
package/libzypp.changes
zypp/RepoInfo.cc
zypp/RepoInfo.h
zypp/RepoManager.cc
zypp/RepoManager.h
zypp/ServiceInfo.cc
zypp/ServiceInfo.h
zypp/repo/RepoException.cc
zypp/repo/RepoException.h
zypp/repo/RepoInfoBase.h

index 0cebe04..8aef177 100644 (file)
@@ -444,20 +444,48 @@ try {
   INT << "===[START]==========================================" << endl;
   ZConfig::instance();
 
-#if 0
-  ServiceInfo s( "STest", Url("dir:///somewhere") );
-  DBG << s << endl;
-  s.addCatalogToEnable( "foo" );
-  s.addCatalogToEnable( "ba a" );
-  s.addCatalogToEnable( "kaa" );
+#if 1
 
   RepoManager repoManager( makeRepoManager( sysRoot ) );
-  RepoInfoList repos = repoManager.knownRepositories();
-  RepoInfoList services = repoManager.knownServices();
 
+  ServiceInfoList services = repoManager.knownServices();
+  WAR << services << endl;
+
+  //RepoInfoList repos = repoManager.knownRepositories();
+  //DBG << repos << endl;
+
+
+  ServiceInfo s( repoManager.getService( "STest" ) );
+  if ( s == ServiceInfo::noService )
+  {
+    Measure x( "Add service STest" );
+    repoManager.addService( "STest", Url("dir:///Local/Service") );
+    s = repoManager.getService( "STest" );
+    USR << "Add service " << s << endl;
+  }
+
+  {
+    Measure x( "Refresh service STest" );
+    repoManager.refreshService( s );
+  }
+
+#if 0
+
+  RepoInfo nrepo;
+  nrepo.setAlias( alias );
+  nrepo.setName( alias );
+  nrepo.setEnabled( true );
+  nrepo.setAutorefresh( false );
+  nrepo.addBaseUrl( Url(url) );
 
+  if ( ! repoManager.isCached( nrepo ) )
+  {
+    repoManager.buildCache( nrepo );
+  }
+
+  repoManager.loadFromCache( nrepo );
+#endif
 
-  DBG << s << endl;
 
   ///////////////////////////////////////////////////////////////////
   INT << "===[END]============================================" << endl << endl;
index 937dcce..c3aecd8 100644 (file)
@@ -132,14 +132,8 @@ template<class _Container>
 
 inline RepoManager makeRepoManager( const Pathname & mgrdir_r )
 {
+  // set via zypp.conf
   return RepoManager();
-
-  RepoManagerOptions mgropt;
-  mgropt.repoCachePath    = mgrdir_r/"cache";
-  mgropt.repoRawCachePath = mgrdir_r/"raw_cache";
-  mgropt.knownReposPath   = mgrdir_r/"repos.d/";
-
-  return RepoManager( mgropt );
 }
 
 ///////////////////////////////////////////////////////////////////
index 3eb3623..316dc7f 100644 (file)
@@ -1,4 +1,10 @@
 -------------------------------------------------------------------
+Tue Sep 16 18:41:39 CEST 2008 - ma@suse.de
+
+- Service handling fixes. Added ServiceException. 
+- revision 11077
+
+-------------------------------------------------------------------
 Mon Sep 15 11:40:04 CEST 2008 - ma@suse.de
 
 - Fix building of transaltions.
index c3c892a..5034a78 100644 (file)
@@ -91,6 +91,8 @@ namespace zypp
   //
   ///////////////////////////////////////////////////////////////////
 
+  const RepoInfo RepoInfo::noRepo;
+
   ///////////////////////////////////////////////////////////////////
   //
   //   METHOD NAME : RepoInfo::RepoInfo
@@ -178,7 +180,7 @@ namespace zypp
   {
     _pimpl->service = name;
   }
-  
+
   void RepoInfo::setTargetDistribution(
       const std::string & targetDistribution)
   {
@@ -223,7 +225,7 @@ namespace zypp
 
   std::string RepoInfo::service() const
   { return _pimpl->service; }
-  
+
   std::string RepoInfo::targetDistribution() const
   { return _pimpl->targetDistro; }
 
index f22eb8e..276fe2d 100644 (file)
@@ -70,6 +70,9 @@ namespace zypp
     RepoInfo();
     virtual ~RepoInfo();
 
+    /** Represents no Repository (one with an empty alias). */
+    static const RepoInfo noRepo;
+
     /**
      * Repository priority for solver.
      * Some number between \c 1 (highest priority) and \c 99 (\ref defaultPriority).
@@ -323,12 +326,12 @@ namespace zypp
 
     /**
      * Write an XML representation of this RepoInfo object.
-     */ 
+     */
     virtual std::ostream & dumpAsXMLOn(std::ostream & str) const;
 
     /**
      * Write an XML representation of this RepoInfo object.
-     * 
+     *
      * \param str
      * \param content this argument is ignored (used in other classed derived
      *                from RepoInfoBase.
@@ -343,8 +346,11 @@ namespace zypp
   };
   ///////////////////////////////////////////////////////////////////
 
+  /** \relates RepoInfo */
   typedef shared_ptr<RepoInfo> RepoInfo_Ptr;
-
+  /** \relates RepoInfo */
+  typedef shared_ptr<const RepoInfo> RepoInfo_constPtr;
+  /** \relates RepoInfo */
   typedef std::list<RepoInfo> RepoInfoList;
 
   /** \relates RepoInfo Stream output */
index d9c89fa..8fbb50d 100644 (file)
@@ -66,7 +66,7 @@ namespace zypp
   {
     /** Check if alias_r is present in repo/service container. */
     template <class Iterator>
-    inline bool findAliasIn( const std::string & alias_r, Iterator begin_r, Iterator end_r )
+    inline bool foundAliasIn( const std::string & alias_r, Iterator begin_r, Iterator end_r )
     {
       for_( it, begin_r, end_r )
         if ( it->alias() == alias_r )
@@ -75,9 +75,27 @@ namespace zypp
     }
     /** \overload */
     template <class Container>
-    inline bool findAliasIn( const std::string & alias_r, const Container & cont_r )
-    { return findAliasIn( alias_r, cont_r.begin(), cont_r.end() ); }
- }
+    inline bool foundAliasIn( const std::string & alias_r, const Container & cont_r )
+    { return foundAliasIn( alias_r, cont_r.begin(), cont_r.end() ); }
+
+    /** Find alias_r in repo/service container. */
+    template <class Iterator>
+    inline Iterator findAlias( const std::string & alias_r, Iterator begin_r, Iterator end_r )
+    {
+      for_( it, begin_r, end_r )
+        if ( it->alias() == alias_r )
+          return it;
+      return end_r;
+    }
+    /** \overload */
+    template <class Container>
+    inline typename Container::iterator findAlias( const std::string & alias_r, Container & cont_r )
+    { return findAlias( alias_r, cont_r.begin(), cont_r.end() ); }
+    /** \overload */
+    template <class Container>
+    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() ); }
+  }
 
   ///////////////////////////////////////////////////////////////////
   //
@@ -130,9 +148,10 @@ namespace zypp
     *
     * If targetDistro is set, all repos with non-empty RepoInfo::targetDistribution()
     * will be skipped.
+    *
     * \todo do this through a separate filter
     */
-    struct RepoCollector
+    struct RepoCollector : private base::NonCopyable
     {
       RepoCollector()
       {}
@@ -141,9 +160,6 @@ namespace zypp
         : targetDistro(targetDistro_)
       {}
 
-      ~RepoCollector()
-      {}
-
       bool collect( const RepoInfo &repo )
       {
         // skip repositories meant for other distros than specified
@@ -184,23 +200,6 @@ namespace zypp
 
   ////////////////////////////////////////////////////////////////////////////
 
-  std::list<RepoInfo> 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);
-   }
-
-  ////////////////////////////////////////////////////////////////////////////
-
   /**
    * \short List of RepoInfo's from a directory
    *
@@ -234,18 +233,47 @@ namespace zypp
 
   ////////////////////////////////////////////////////////////////////////////
 
-  static void assert_alias( const RepoInfo &info )
+   std::list<RepoInfo> 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() );
+  }
+
+  inline void assert_alias( const ServiceInfo & info )
   {
-    if (info.alias().empty())
-        ZYPP_THROW(RepoNoAliasException());
+    if ( info.alias().empty() )
+      ZYPP_THROW( ServiceNoAliasException() );
   }
 
   ////////////////////////////////////////////////////////////////////////////
 
-  static void assert_urls( const RepoInfo &info )
+  inline void assert_urls( const RepoInfo & info )
   {
-    if (info.baseUrlsEmpty())
-        ZYPP_THROW(RepoNoUrlException());
+    if ( info.baseUrlsEmpty() )
+      ZYPP_THROW( RepoNoUrlException( info ) );
+  }
+
+  inline void assert_url( const ServiceInfo & info )
+  {
+    if ( ! info.url().isValid() )
+      ZYPP_THROW( ServiceNoUrlException( info ) );
   }
 
   ////////////////////////////////////////////////////////////////////////////
@@ -253,7 +281,7 @@ namespace zypp
   /**
    * \short Calculates the raw cache path for a repository
    */
-  static Pathname rawcache_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info )
+  inline Pathname rawcache_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info )
   {
     assert_alias(info);
     return opt.repoRawCachePath / info.escaped_alias();
@@ -262,18 +290,45 @@ namespace zypp
   /**
    * \short Calculates the packages cache path for a repository
    */
-  static Pathname packagescache_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info )
+  inline Pathname packagescache_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info )
   {
     assert_alias(info);
     return opt.repoPackagesCachePath / info.escaped_alias();
   }
 
-  static Pathname solv_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info)
+  /**
+   * \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
+  {
+    public:
+      typedef std::set<ServiceInfo> ServiceSet;
+
+      ServiceCollector( ServiceSet & services_r )
+      : _services( services_r )
+      {}
+
+      bool operator()( const ServiceInfo & service_r ) const
+      {
+        _services.insert( service_r );
+        return true;
+      }
+
+    private:
+      ServiceSet & _services;
+  };
+
+  ////////////////////////////////////////////////////////////////////////////
+
   ///////////////////////////////////////////////////////////////////
   //
   //   CLASS NAME : RepoManager::Impl
@@ -288,13 +343,8 @@ namespace zypp
     Impl( const RepoManagerOptions &opt )
       : options(opt)
     {
-      knownServices();
-      knownRepositories();
-    }
-
-    Impl()
-    {
-
+      init_knownServices();
+      init_knownRepositories();
     }
 
     RepoManagerOptions options;
@@ -304,14 +354,8 @@ namespace zypp
     ServiceSet services;
 
   public:
-    /** Offer default Impl. */
-    static shared_ptr<Impl> nullimpl()
-    {
-      static shared_ptr<Impl> _nullimpl( new Impl );
-      return _nullimpl;
-    }
 
-    void saveService( const ServiceInfo & service ) const;
+    void saveService( ServiceInfo & service ) const;
 
     Pathname generateNonExistingName( const Pathname &dir,
                                       const std::string &basefilename ) const;
@@ -319,19 +363,10 @@ namespace zypp
     std::string generateFilename( const RepoInfo & info ) const;
     std::string generateFilename( const ServiceInfo & info ) const;
 
-    struct ServiceCollector
-    {
-      ServiceCollector(ServiceSet & services_) : services(services_) {}
-
-      bool collect(ServiceInfo service) { services.insert(service); return true; }
-
-    private:
-      ServiceSet & services;
-    };
-
-    void knownServices();
 
-    void knownRepositories();
+  private:
+    void init_knownServices();
+    void init_knownRepositories();
 
   private:
     friend Impl * rwcowClone<Impl>( const Impl * rhs );
@@ -349,37 +384,103 @@ namespace zypp
   }
 
   ///////////////////////////////////////////////////////////////////
-  //
-  //   CLASS NAME : RepoManager
-  //
-  ///////////////////////////////////////////////////////////////////
 
-  RepoManager::RepoManager( const RepoManagerOptions &opt )
-  : _pimpl( new Impl(opt) )
-  {}
+  void RepoManager::Impl::saveService( ServiceInfo & service ) const
+  {
+    filesystem::assert_dir( options.knownServicesPath );
+    Pathname servfile = generateNonExistingName( options.knownServicesPath,
+                                                 generateFilename( service ) );
+    service.setFilepath( servfile );
 
-  ////////////////////////////////////////////////////////////////////////////
+    MIL << "saving service in " << servfile << endl;
 
-  RepoManager::~RepoManager()
-  {}
+    std::ofstream file( servfile.c_str() );
+    if ( !file )
+    {
+      ZYPP_THROW( Exception( "Can't open " + servfile.asString() ) );
+    }
+    service.dumpAsIniOn( file );
+    MIL << "done" << endl;
+  }
+
+  /**
+   * Generate a non existing filename in a directory, using a base
+   * name. For example if a directory contains 3 files
+   *
+   * |-- bar
+   * |-- foo
+   * `-- moo
+   *
+   * If you try to generate a unique filename for this directory,
+   * based on "ruu" you will get "ruu", but if you use the base
+   * "foo" you will get "foo_1"
+   *
+   * \param dir Directory where the file needs to be unique
+   * \param basefilename string to base the filename on.
+   */
+  Pathname RepoManager::Impl::generateNonExistingName( const Pathname & dir,
+                                                       const std::string & basefilename ) const
+  {
+    string final_filename = basefilename;
+    int counter = 1;
+    while ( PathInfo(dir + final_filename).isExist() )
+    {
+      final_filename = basefilename + "_" + str::numstring(counter);
+      counter++;
+    }
+    return dir + Pathname(final_filename);
+  }
 
   ////////////////////////////////////////////////////////////////////////////
 
-  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(); }
+  /**
+   * \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;
+  }
 
 
-  std::list<RepoInfo> RepoManager::knownRepositories() const
+  void RepoManager::Impl::init_knownServices()
   {
-    return std::list<RepoInfo>(repoBegin(),repoEnd());
+    Pathname dir = options.knownServicesPath;
+    list<Pathname> entries;
+    if (PathInfo(dir).isExist())
+    {
+      if ( filesystem::readdir( entries, Pathname(dir), false ) != 0 )
+          ZYPP_THROW(Exception("failed to read directory"));
+
+      //str::regex allowedServiceExt("^\\.service(_[0-9]+)?$");
+      for_(it, entries.begin(), entries.end() )
+      {
+        parser::ServiceFileReader(*it, ServiceCollector(services));
+      }
+    }
   }
 
-  void RepoManager::Impl::knownRepositories()
+  void RepoManager::Impl::init_knownRepositories()
   {
     MIL << "start construct known repos" << endl;
 
@@ -405,6 +506,51 @@ namespace zypp
     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;
+  }
+
   ////////////////////////////////////////////////////////////////////////////
 
   Pathname RepoManager::metadataPath( const RepoInfo &info ) const
@@ -1021,67 +1167,6 @@ namespace zypp
 
   ////////////////////////////////////////////////////////////////////////////
 
-  /**
-   * Generate a non existing filename in a directory, using a base
-   * name. For example if a directory contains 3 files
-   *
-   * |-- bar
-   * |-- foo
-   * `-- moo
-   *
-   * If you try to generate a unique filename for this directory,
-   * based on "ruu" you will get "ruu", but if you use the base
-   * "foo" you will get "foo_1"
-   *
-   * \param dir Directory where the file needs to be unique
-   * \param basefilename string to base the filename on.
-   */
-  Pathname RepoManager::Impl::generateNonExistingName( const Pathname &dir,
-                                       const std::string &basefilename ) const
-  {
-    string final_filename = basefilename;
-    int counter = 1;
-    while ( PathInfo(dir + final_filename).isExist() )
-    {
-      final_filename = basefilename + "_" + str::numstring(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::addRepository( const RepoInfo &info,
                                    const ProgressData::ReceiverFnc & progressrcv )
   {
@@ -1359,29 +1444,67 @@ namespace zypp
     ZYPP_THROW(RepoNotFoundException(info));
   }
 
+  ////////////////////////////////////////////////////////////////////////////
+  //
+  // Services
+  //
+  ////////////////////////////////////////////////////////////////////////////
+
+  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 )
   {
-    // check if service already exists
-    if( _pimpl->services.find(service) != _pimpl->services.end() )
-      return; //FIXME ZYPP_THROW(RepoAlreadyExistsException(service.name()));
+    assert_alias( service );
 
-    // this is need to save location to correct service
-    const ServiceInfo & savedService =
-      *(_pimpl->services.insert( service )).first;
+    // check if service already exists
+    if ( hasService( service.alias() ) )
+      ZYPP_THROW( ServiceAlreadyExistsException( service ) );
 
-    MIL << "added service " << savedService.alias() << endl;
+    // 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 );
 
-    _pimpl->saveService( savedService );
+    MIL << "added service " << toSave.alias() << endl;
   }
 
+  ////////////////////////////////////////////////////////////////////////////
 
-  void RepoManager::removeService( const string & alias)
+  void RepoManager::removeService( const string & alias )
   {
     MIL << "Going to delete repo " << alias << endl;
 
@@ -1394,10 +1517,7 @@ namespace zypp
     }
 
     ServiceSet tmpSet;
-    Impl::ServiceCollector collector(tmpSet);
-
-    parser::ServiceFileReader reader( location,
-        bind(&Impl::ServiceCollector::collect,collector,_1) );
+    parser::ServiceFileReader( location, ServiceCollector(tmpSet) );
 
     // only one service definition in the file
     if ( tmpSet.size() == 1 )
@@ -1439,59 +1559,12 @@ namespace zypp
   void RepoManager::removeService( const ServiceInfo & service )
   { removeService(service.alias()); }
 
-
-  void RepoManager::Impl::saveService( const ServiceInfo & service ) const
-  {
-    filesystem::assert_dir( options.knownServicesPath );
-
-    Pathname servfile = generateNonExistingName( options.knownServicesPath,
-        generateFilename( service ) );
-
-    MIL << "saving service in " << servfile << endl;
-
-    std::ofstream file(servfile.c_str());
-    if (!file) {
-      ZYPP_THROW (Exception( "Can't open " + servfile.asString() ) );
-    }
-
-    service.dumpAsIniOn( file );
-
-    const_cast<ServiceInfo&>(service).setFilepath( servfile );
-    MIL << "done" << endl;
-  }
-
-  ServiceInfo RepoManager::getService( const std::string & alias ) const
-  {
-    for_ (it, serviceBegin(), serviceEnd())
-      if ( it->alias() == alias )
-        return *it;
-    return ServiceInfo::noService;
-  }
-
-  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();
-  }
-
   void RepoManager::refreshServices()
   {
     // copy the set of services since refreshService
     // can eventually invalidate the iterator
-    ServiceSet services;
-    services.insert(serviceBegin(), serviceEnd());
-    for_(it, services.begin(), services.end())
+    ServiceSet services( serviceBegin(), serviceEnd() );
+    for_( it, services.begin(), services.end() )
     {
       if ( !it->enabled() )
         continue;
@@ -1500,42 +1573,33 @@ namespace zypp
     }
   }
 
-  void RepoManager::refreshService( const ServiceInfo & service )
+  void RepoManager::refreshService( const ServiceInfo & dont_use_service_r )
   {
-    MIL << "going to refresh service '" << service.alias()
-        << "', url: "<< service.url().asString() << endl;
+    assert_alias( dont_use_service_r );
+    assert_url( dont_use_service_r );
+
+    // 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. Thus 'dont_use_service_r' but 'service':
+    ServiceInfo service( dont_use_service_r );
+    bool serviceModified = false;
+    MIL << "going to refresh service '" << service.alias() << "', url: "<< service.url() << endl;
 
     //! \todo add callbacks for apps (start, end, repo removed, repo added, repo changed)
 
-    repo::ServiceType type = service.type();
     // if the type is unknown, try probing.
-    if ( type == repo::ServiceType::NONE )
+    if ( service.type() == repo::ServiceType::NONE )
     {
-      // unknown, probe it
-      type = probeService(service.url());
-
-      if (type != ServiceType::NONE)
+      repo::ServiceType type = probeService( service.url() );
+      if ( type != ServiceType::NONE )
       {
-        // Adjust the probed type in ServiceInfo
         service.setProbedType( type ); // lazy init!
-        // save probed type only for repos in system
-        for_( sit, serviceBegin(), serviceEnd() )
-        {
-          if ( service.alias() == sit->alias() )
-          {
-            ServiceInfo modifiedservice = service;
-            modifiedservice.setType(type);
-            modifyService(service.alias(), modifiedservice);
-            break;
-          }
-        }
+        serviceModified = true;
       }
     }
 
     // download the repo index file
     media::MediaManager mediamanager;
-    //if (service.url().empty())
-    //  throw RepoNoUrlException();
     media::MediaAccessId mid = mediamanager.open( service.url() );
     mediamanager.attachDesiredMedia( mid );
     mediamanager.provideFile( mid, "repo/repoindex.xml" );
@@ -1543,17 +1607,15 @@ namespace zypp
 
     // parse it
     RepoCollector collector(_pimpl->options.servicesTargetDistro);
-    parser::RepoindexFileReader reader( path,
-      bind( &RepoCollector::collect, &collector, _1 ) );
+    parser::RepoindexFileReader reader( path, bind( &RepoCollector::collect, &collector, _1 ) );
     mediamanager.release( mid );
     mediamanager.close( mid );
 
     // set service alias and base url for all collected repositories
     for_( it, collector.repos.begin(), collector.repos.end() )
     {
-      Url url;
-
       // if the repo url was not set by the repoindex parser, set service's url
+      Url url;
       if ( it->baseUrlsEmpty() )
         url = service.url();
       else
@@ -1562,7 +1624,7 @@ namespace zypp
 
       // libzypp currently has problem with separate url + path handling
       // so just append the path to the baseurl
-      if (!it->path().empty())
+      if ( !it->path().empty() )
       {
         Pathname path(url.getPathName());
         path /= it->path();
@@ -1576,41 +1638,75 @@ namespace zypp
       it->setService( service.alias() );
     }
 
-    // compare old and new repositories (hope not too much, if it change
-    // then construct set and use set operation on it)
-    std::list<RepoInfo> oldRepos;
-    getRepositoriesInService(service.alias(),
-        insert_iterator<std::list<RepoInfo> > (oldRepos, oldRepos.begin()));
-
-    //! \todo fix enabled/disable with respect to ServiceInfo reposTo...
+    //
+    // Now compare collected repos with the ones in the system...
+    //
+    RepoInfoList oldRepos;
+    getRepositoriesInService( service.alias(), std::back_inserter( oldRepos ) );
 
-    // find old to remove
+    // find old repositories to remove...
     for_( it, oldRepos.begin(), oldRepos.end() )
     {
-      if ( ! findAliasIn( it->alias(), collector.repos ) )
+      if ( ! foundAliasIn( it->alias(), collector.repos ) )
       {
         removeRepository( *it );
       }
     }
 
-    //find new to add
+    // create missing repositories and modify exising ones if needed...
     for_( it, collector.repos.begin(), collector.repos.end() )
     {
-      if ( ! findAliasIn( it->alias(), oldRepos ) )
+      // Service explicitly requests the repo being enabled?
+      bool beEnabled = service.repoToEnableFind( it->alias() );
+      if ( beEnabled )
+      {
+        service.delRepoToEnable( it->alias() );
+        serviceModified = true;
+      }
+#warning also handle toDelete list and afterwards clear it
+
+      RepoInfoList::iterator oldRepo( findAlias( it->alias(), oldRepos ) );
+      if ( oldRepo == oldRepos.end() )
       {
+        // Not found in oldRepos ==> a new repo to add
+
+        // Make sure the service repo is created with the
+        // appropriate enable and autorefresh true.
+        it->setEnabled( beEnabled );
+        it->setAutorefresh( true );
+
 #warning check whether a repo with the same alias exists
         // At that point check whether a repo with the same alias
         // exists outside this service. Maybe forcefully re-alias
         // the existing repo?
+        addRepository( *it );
+      }
+      else
+      {
+        // ==> an exising repo to check
+        bool oldRepoModified = false;
 
-        // make sure the service is created in disabled
-        // autorefresh true.
-        it->setEnabled( false );
-        it->setAutorefresh( true );
+        if ( beEnabled && ! oldRepo->enabled() )
+        {
+          oldRepo->setEnabled( true );
+          oldRepoModified = true;
+        }
 
-        addRepository( *it );
+#warning also check changed URL due to PATH change in service
+        // save if modified:
+        if ( oldRepoModified )
+        {
+          modifyRepository( oldRepo->alias(), *oldRepo );
+        }
       }
     }
+
+   // Save service if modified:
+   if ( serviceModified )
+    {
+      // write out modified service file.
+      modifyService( service.alias(), service );
+    }
   }
 
   void RepoManager::modifyService(const std::string & oldAlias, const ServiceInfo & service)
@@ -1626,24 +1722,18 @@ namespace zypp
           "Cannot figure out where the service file is stored."));
     }
 
+    // remember: there may multiple services being defined in one file:
     ServiceSet tmpSet;
-    Impl::ServiceCollector collector(tmpSet);
-
-    parser::ServiceFileReader reader( location,
-        bind(&Impl::ServiceCollector::collect,collector,_1) );
+    parser::ServiceFileReader( location, ServiceCollector(tmpSet) );
 
     filesystem::assert_dir(location.dirname());
-
     std::ofstream file(location.c_str());
-
     for_(it, tmpSet.begin(), tmpSet.end())
     {
       if( *it != oldAlias )
         it->dumpAsIniOn(file);
     }
-
     service.dumpAsIniOn(file);
-
     file.close();
 
     _pimpl->services.erase(oldAlias);
@@ -1671,25 +1761,6 @@ namespace zypp
     //! \todo refresh the service automatically if url is changed?
   }
 
-  void RepoManager::Impl::knownServices()
-  {
-    ServiceCollector collector(services);
-    Pathname dir = options.knownServicesPath;
-    list<Pathname> entries;
-    if (PathInfo(dir).isExist())
-    {
-      if ( filesystem::readdir( entries, Pathname(dir), false ) != 0 )
-          ZYPP_THROW(Exception("failed to read directory"));
-
-      //str::regex allowedServiceExt("^\\.service(_[0-9]+)?$");
-      for_(it, entries.begin(), entries.end() )
-      {
-        parser::ServiceFileReader reader(*it,
-            bind(&ServiceCollector::collect, collector, _1) );
-      }
-    }
-  }
-
   repo::ServiceType RepoManager::probeService( const Url &url ) const
   {
     try
index 201447c..d0d1bc1 100644 (file)
 #include "zypp/repo/RepoException.h"
 #include "zypp/repo/RepoType.h"
 #include "zypp/repo/ServiceType.h"
+#include "zypp/ServiceInfo.h"
 #include "zypp/RepoStatus.h"
 #include "zypp/ProgressData.h"
 
 ///////////////////////////////////////////////////////////////////
 namespace zypp
 { /////////////////////////////////////////////////////////////////
-  class ServiceInfo; //predef
 
    /**
     * Parses \a repo_file and returns a list of \ref RepoInfo objects
@@ -142,21 +142,28 @@ namespace zypp
 
     };
 
-   /**
-    * \short List known repositories.
-    *
-    * The known repositories are read from
-    * \ref RepoManagerOptions::knownReposPath passed on the Ctor.
-    * Which defaults to ZYpp global settings.
-    * \return found list<RepoInfo>
-    */
-   std::list<RepoInfo> knownRepositories() const;
+    /** \name Known repositories.
+     *
+     * The known repositories are read from
+     * \ref RepoManagerOptions::knownReposPath passed on the Ctor.
+     * Which defaults to ZYpp global settings.
+     */
+   //@{
+    bool repoEmpty() const;
+    RepoSizeType repoSize() const;
+    RepoConstIterator repoBegin() const;
+    RepoConstIterator repoEnd() const;
+
+    /** List of known repositories. */
+    std::list<RepoInfo> knownRepositories() const
+    { return std::list<RepoInfo>(repoBegin(),repoEnd()); }
 
-   bool repoEmpty() const;
-   RepoSizeType repoSize() const;
-   RepoConstIterator repoBegin() const;
-   RepoConstIterator repoEnd() const;
+    /** Find RepoInfo by alias or return \ref RepoInfo::noRepo. */
+    RepoInfo getRepo( const std::string & alias ) const;
 
+    /** Return whether there is a known repository for \c alias. */
+    bool hasRepo( const std::string & alias ) const;
+   //@}
 
    /**
     * \short Status of local metadata
@@ -455,42 +462,14 @@ namespace zypp
                                 const url::ViewOption & urlview = url::ViewOption::DEFAULTS,
                                 const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
 
-    /**
-     * \short Probe the type or the service.
-     */
-    repo::ServiceType probeService( const Url &url ) const;
-
-    /**
-     * Adds new service by it's alias and url
-     *
-     * \param alias unique identifier of the service
-     * \param url url to service
-     *
-     * \throws FIXME RepoAlreadyExistException and as reponame is service name
-     */
-    void addService( const std::string & alias, const Url& url );
-
-    /**
-     * Adds new service
-     *
-     * \param service service info
-     *
-     * \throws FIXME RepoAlreadyExistException and as reponame is service name
-     */
-    void addService( const ServiceInfo & service );
 
-    /**
-     * Removes service specified by its name
+    /** \name Known services.
      *
-     * \param alias unique indientifier of the service to remove
-     *
-     * \throws RepoException if service is not found or file with ServiceInfo cannot be deleted
-     * \throws Exception if file contain more services and rewrite file failed
+     * The known services are read from
+     * \ref RepoManagerOptions::knownServicesPath passed on the Ctor.
+     * Which defaults to ZYpp global settings.
      */
-    void removeService( const std::string & alias );
-
-    void removeService( const ServiceInfo & service );
-
+    //@{
     /**
      * Gets true if no service is in RepoManager (so no one in specified location)
      *
@@ -518,14 +497,59 @@ namespace zypp
      */
     ServiceConstIterator serviceEnd() const;
 
+    /** List of known services. */
+    std::list<ServiceInfo> knownServices() const
+    { return std::list<ServiceInfo>(serviceBegin(),serviceEnd()); }
+
     /**
-     * Finds ServiceInfo by alias or return noService
+     * \short Finds ServiceInfo by alias or return \ref ServiceInfo::noService
      *
      * \param alias unique identifier of service
      * \return information about service
      */
     ServiceInfo getService( const std::string & alias ) const;
 
+    /** Return whether there is a known service for \c alias. */
+    bool hasService( const std::string & alias ) const;
+    //@}
+
+    /**
+     * \short Probe the type or the service.
+     */
+    repo::ServiceType probeService( const Url &url ) const;
+
+    /**
+     * Adds new service by it's alias and url
+     *
+     * \param alias unique identifier of the service
+     * \param url url to service
+     *
+     * \throws FIXME RepoAlreadyExistException and as reponame is service name
+     */
+    void addService( const std::string & alias, const Url& url );
+
+    /**
+     * Adds new service
+     *
+     * \param service service info
+     *
+     * \throws FIXME RepoAlreadyExistException and as reponame is service name
+     */
+    void addService( const ServiceInfo & service );
+
+    /**
+     * Removes service specified by its name
+     *
+     * \param alias unique indientifier of the service to remove
+     *
+     * \throws RepoException if service is not found or file with ServiceInfo cannot be deleted
+     * \throws Exception if file contain more services and rewrite file failed
+     */
+    void removeService( const std::string & alias );
+
+    void removeService( const ServiceInfo & service );
+
+
     /**
      * Refreshes all enabled services.
      *
index 5505298..f0c04e2 100644 (file)
@@ -28,17 +28,6 @@ using zypp::xml::escape;
 namespace zypp
 {//////////////////////////////////////////////////////////////////////////////
 
-
-  struct RepoInfoCollector
-  {
-    vector<RepoInfo> repos;
-    bool collect(const RepoInfo & info)
-    {
-      repos.push_back(info);
-      return true;
-    }
-  };
-
   ///////////////////////////////////////////////////////////////////
   //
   //  CLASS NAME : ServiceInfo::Impl
@@ -68,7 +57,7 @@ namespace zypp
 
     ~Impl()
     {}
-    
+
     void setProbedType( const repo::ServiceType & t ) const
     {
       if ( type == repo::ServiceType::NONE
index d2c4583..c6706f5 100644 (file)
@@ -74,13 +74,13 @@ namespace zypp
     void setUrl( const Url& url );
 
     /**
-     * 
+     *
      */
     repo::ServiceType type() const;
-    
+
     /**
      * Set service type.
-     * 
+     *
      * \param type the new type
      */
     void setType( const repo::ServiceType & type );
@@ -167,7 +167,12 @@ namespace zypp
   };
   ///////////////////////////////////////////////////////////////////
 
+  /** \relates ServiceInfo */
   typedef shared_ptr<ServiceInfo> ServiceInfo_Ptr;
+  /** \relates ServiceInfo */
+  typedef shared_ptr<const ServiceInfo> ServiceInfo_constPtr;
+  /** \relates ServiceInfo */
+  typedef std::list<ServiceInfo> ServiceInfoList;
 
   /** \relates ServiceInfo Stream output */
   std::ostream & operator<<( std::ostream & str, const ServiceInfo & obj );
index 945620d..c99383a 100644 (file)
@@ -22,7 +22,13 @@ namespace zypp
   ///////////////////////////////////////////////////////////////////
   namespace repo
   { /////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // Repository related exceptions
+    //
+    ///////////////////////////////////////////////////////////////////
+
     RepoException::RepoException()
     : Exception( "Repo exception" )
     {}
@@ -44,7 +50,7 @@ namespace zypp
     : RepoException( info, "Repository not Cached" )
     {}
 
-    RepoNotCachedException::RepoNotCachedException(  const RepoInfo& info, 
+    RepoNotCachedException::RepoNotCachedException(  const RepoInfo& info,
         const std::string & msg_r )
     : RepoException( info, msg_r )
     {}
@@ -54,13 +60,57 @@ namespace zypp
         str::form("Cannot determine type for repository %s.",info.alias().c_str()))
     {}
 
-
     std::ostream & RepoException::dumpOn( std::ostream & str ) const
     {
       return Exception::dumpOn( str );
     }
-    
-    /////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // Service related exceptions
+    //
+    ///////////////////////////////////////////////////////////////////
+
+    ServiceException::ServiceException()
+    : Exception( "Service exception" )
+    {}
+
+    ServiceException::ServiceException( const std::string & msg_r )
+    : Exception( msg_r )
+    {}
+
+    ServiceException::ServiceException( const ServiceInfo & service_r )
+    : Exception( "Service exception" ), _service( service_r )
+    {}
+
+    ServiceException::ServiceException( const ServiceInfo & service_r, const std::string & msg_r )
+    : Exception( msg_r ), _service( service_r )
+    {}
+
+    ServiceException::~ServiceException() throw()
+    {}
+
+    std::ostream & ServiceException::dumpOn( std::ostream & str ) const
+    {
+      str << "[" << _service.alias() << "|" << _service.url() << "] ";
+      return Exception::dumpOn( str );
+    }
+
+    ///////////////////////////////////////////////////////////////////
+
+#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 ) {}
+
+    DEF_CTORS( ServiceNoAliasException,       "Service has no alias defined." );
+    DEF_CTORS( ServiceAlreadyExistsException, "Service already exists." );
+    DEF_CTORS( ServiceNoUrlException,         "Service has no or invalid url defined." );
+
+#undef DEF_CTORS
+
+   /////////////////////////////////////////////////////////////////
   } // namespace repo
   ///////////////////////////////////////////////////////////////////
   /////////////////////////////////////////////////////////////////
index d6afbc9..4ced39e 100644 (file)
@@ -18,6 +18,8 @@
 #include "zypp/base/Exception.h"
 #include "zypp/base/UserRequestException.h"
 #include "zypp/RepoInfo.h"
+#include "zypp/ServiceInfo.h"
+
 ///////////////////////////////////////////////////////////////////
 namespace zypp
 { /////////////////////////////////////////////////////////////////
@@ -25,6 +27,10 @@ namespace zypp
   namespace repo
   { /////////////////////////////////////////////////////////////////
 
+    /** \name Repository related exceptions.
+    */
+    //@{
+
     /**
      * \short Exception for repository handling.
      */
@@ -41,7 +47,7 @@ namespace zypp
       RepoException( const RepoInfo & info, const std::string & msg_r );
 
       virtual ~RepoException() throw() {}
-      
+
       RepoInfo info()
       { return _info; }
 
@@ -64,7 +70,7 @@ namespace zypp
       RepoNotCachedException( const RepoInfo& info );
       RepoNotCachedException( const RepoInfo& info, const std::string & msg_r );
     };
-    
+
     /**
      * thrown when it was impossible to
      * determine one url for this repo.
@@ -74,22 +80,22 @@ namespace zypp
       public:
       RepoNoUrlException()
       {}
-      
+
       RepoNoUrlException( const RepoInfo &info)
         : RepoException(info)
         {}
-      
+
     };
-    
+
     /**
      * thrown when it was impossible to
      * determine an alias for this repo.
      */
     class RepoNoAliasException : public RepoException
     {
-    
+
     };
-    
+
     /**
      * thrown when it was impossible to
      * match a repository
@@ -101,7 +107,7 @@ namespace zypp
         : RepoException(info)
       {}
     };
-    
+
     /**
      * Repository already exists and some unique
      * attribute can't be duplicated.
@@ -113,15 +119,15 @@ namespace zypp
                                   const std::string & msg_r )
         : RepoException(info,msg_r)
       {}
-        
+
       RepoAlreadyExistsException( const RepoInfo &info )
         : RepoException(info)
       {}
-      
+
       std::string alias()
       { return info().alias(); }
     };
-    
+
     /**
      * thrown when it was impossible to
      * determine this repo type.
@@ -154,7 +160,73 @@ namespace zypp
       RepoMetadataException()
       {}
     };
-    
+
+    //@}
+    ///////////////////////////////////////////////////////////////////
+    ///////////////////////////////////////////////////////////////////
+    ///////////////////////////////////////////////////////////////////
+
+    /** \name Service related exceptions.
+    */
+    //@{
+
+    /** Base Exception for service handling.
+     */
+    class ServiceException : public Exception
+    {
+      public:
+        ServiceException();
+        ServiceException( const std::string & msg_r );
+        ServiceException( const ServiceInfo & service_r );
+        ServiceException( const ServiceInfo & service_r, const std::string & msg_r );
+        virtual ~ServiceException() throw();
+
+        ServiceInfo service()
+        { return _service; }
+
+      protected:
+        virtual std::ostream & dumpOn( std::ostream & str ) const;
+
+      private:
+        ServiceInfo _service;
+    };
+    ///////////////////////////////////////////////////////////////////
+
+    /** Service without alias was used in an operation.
+     */
+    class ServiceNoAliasException : public ServiceException
+    {
+      public:
+        ServiceNoAliasException();
+        ServiceNoAliasException( const std::string & msg_r );
+        ServiceNoAliasException( const ServiceInfo & service_r );
+        ServiceNoAliasException( const ServiceInfo & service_r, const std::string & msg_r );
+    };
+
+    /** Service already exists and some unique attribute can't be duplicated.
+     */
+    class ServiceAlreadyExistsException : public ServiceException
+    {
+      public:
+        ServiceAlreadyExistsException();
+        ServiceAlreadyExistsException( const std::string & msg_r );
+        ServiceAlreadyExistsException( const ServiceInfo & service_r );
+        ServiceAlreadyExistsException( const ServiceInfo & service_r, const std::string & msg_r );
+    };
+
+    /** Service has no or invalid url defined.
+     */
+    class ServiceNoUrlException : public ServiceException
+    {
+      public:
+        ServiceNoUrlException();
+        ServiceNoUrlException( const std::string & msg_r );
+        ServiceNoUrlException( const ServiceInfo & service_r );
+        ServiceNoUrlException( const ServiceInfo & service_r, const std::string & msg_r );
+    };
+
+    //@}
+
     /////////////////////////////////////////////////////////////////
   } // namespace parser
   ///////////////////////////////////////////////////////////////////
index 014698f..27b8408 100644 (file)
@@ -139,7 +139,7 @@ namespace zypp
        * derived classes.
        */
       virtual std::ostream & dumpAsXMLOn(std::ostream & str) const;
-      
+
       /**
        * Write an XML representation of this object with content (if available).
        */
@@ -167,7 +167,10 @@ namespace zypp
     /** \relates RepoInfoBase Stream output */
     std::ostream & operator<<( std::ostream & str, const RepoInfoBase & obj );
 
+    /** \relates RepoInfoBase */
     typedef shared_ptr<RepoInfoBase> RepoInfoBase_Ptr;
+    /** \relates RepoInfoBase */
+    typedef shared_ptr<const RepoInfoBase> RepoInfoBase_constPtr;
 
 
     /////////////////////////////////////////////////////////////////