initial Service implementation. Also little refactor of RepoManager.
authorJosef Reidinger <jreidinger@suse.cz>
Thu, 19 Jun 2008 13:50:48 +0000 (13:50 +0000)
committerJosef Reidinger <jreidinger@suse.cz>
Thu, 19 Jun 2008 13:50:48 +0000 (13:50 +0000)
20 files changed:
zypp.conf
zypp/CMakeLists.txt
zypp/RepoManager.cc
zypp/RepoManager.h
zypp/Service.cc [new file with mode: 0644]
zypp/Service.h [new file with mode: 0644]
zypp/ZConfig.cc
zypp/ZConfig.h
zypp/parser/RepoindexFileReader.cc [new file with mode: 0644]
zypp/parser/RepoindexFileReader.h [new file with mode: 0644]
zypp/parser/ServiceFileReader.cc [new file with mode: 0644]
zypp/parser/ServiceFileReader.h [new file with mode: 0644]
zypp/parser/yum/schema/patch.rng
zypp/parser/yum/schema/primary.rng
zypp/parser/yum/schema/products.rng
zypp/parser/yum/schema/repoindex.rnc [new file with mode: 0644]
zypp/parser/yum/schema/repoindex.rng [new file with mode: 0644]
zypp/parser/yum/schema/rpm-ns.rng
zypp/parser/yum/schema/suse-primary.rng
zypp/parser/yum/schemanames.h

index 8c09b0f..4f6b3bf 100644 (file)
--- a/zypp.conf
+++ b/zypp.conf
 ##
 # reposdir = /etc/zypp/repos.d
 
+##
+## Path where the known services .service files are kept
+##
+## Valid values: A directory
+## Default value: {configdir}/services.d
+##
+## Changing this invalidates all known services
+##
+# reposdir = /etc/zypp/service.d
+
 
 ##
 ## Whether repository urls should be probed when added
index a151df9..fbdd2d5 100644 (file)
@@ -64,6 +64,7 @@ SET( zypp_SRCS
   ResPoolProxy.cc
   ResStatus.cc
   Script.cc
+  Service.cc
   Signature.cc
   SrcPackage.cc
   SysContent.cc
@@ -162,6 +163,7 @@ SET( zypp_HEADERS
   ResStatus.h
   ResTraits.h
   Script.h
+  Service.h
   Signature.h
   SrcPackage.h
   SysContent.h
@@ -338,7 +340,9 @@ SET( zypp_parser_SRCS
   parser/LibXMLHelper.cc
   parser/XMLNodeIterator.cc
   parser/RepoFileReader.cc
+  parser/RepoindexFileReader.cc
   parser/ProductConfReader.cc
+  parser/ServiceFileReader.cc
   parser/xml_escape_parser.cpp
 )
 
@@ -354,6 +358,8 @@ SET( zypp_parser_HEADERS
   parser/RepoFileReader.h
   parser/ProductConfReader.h
   parser/xml_escape_parser.hpp
+  parser/RepoindexFileReader.h
+  parser/ServiceFileReader.h
 )
 
 INSTALL(  FILES
index 557d452..77ede0a 100644 (file)
@@ -24,6 +24,7 @@
 #include "zypp/base/Regex.h"
 #include "zypp/PathInfo.h"
 #include "zypp/TmpPath.h"
+#include "zypp/Service.h"
 
 #include "zypp/repo/RepoException.h"
 #include "zypp/RepoManager.h"
@@ -34,6 +35,7 @@
 #include "zypp/ManagedFile.h"
 
 #include "zypp/parser/RepoFileReader.h"
+#include "zypp/parser/ServiceFileReader.h"
 #include "zypp/repo/yum/Downloader.h"
 #include "zypp/parser/yum/RepoParser.h"
 #include "zypp/repo/susetags/Downloader.h"
@@ -71,6 +73,7 @@ namespace zypp
     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() );
     probe                 = ZConfig::instance().repo_add_probe();
   }
 
@@ -82,6 +85,7 @@ namespace zypp
     ret.repoSolvCachePath     = root_r/"solv";
     ret.repoPackagesCachePath = root_r/"packages";
     ret.knownReposPath        = root_r/"repos.d";
+    ret.knownServicesPath        = root_r/"services.d";
     return ret;
   }
 
@@ -246,6 +250,8 @@ namespace zypp
     RepoManagerOptions options;
 
     map<string, RepoInfo> _repoinfos;
+    
+    ServiceSet services;
 
   public:
     /** Offer default Impl. */
@@ -255,6 +261,23 @@ namespace zypp
       return _nullimpl;
     }
 
+    void saveService( const Service& service );
+  
+    Pathname generateNonExistingName( const Pathname &dir,
+                                         const std::string &basefilename ) const;
+  
+    std::string generateFilename( const RepoInfo &info ) const;
+    std::string generateFilename( const Service &info ) const;
+
+    struct ServiceCollector {
+      ServiceCollector(ServiceSet& services_) : services(services_) {}
+      bool collect(Service service) { services.insert(service); return true; }
+      private:
+        ServiceSet& services;
+    };
+
+    void knownServices();
+
   private:
     friend Impl * rwcowClone<Impl>( const Impl * rhs );
     /** clone for RWCOW_pointer */
@@ -976,8 +999,8 @@ namespace zypp
    * \param dir Directory where the file needs to be unique
    * \param basefilename string to base the filename on.
    */
-  static Pathname generate_non_existing_name( const Pathname &dir,
-                                              const std::string &basefilename )
+  Pathname RepoManager::Impl::generateNonExistingName( const Pathname &dir,
+                                       const std::string &basefilename ) const
   {
     string final_filename = basefilename;
     int counter = 1;
@@ -998,23 +1021,27 @@ namespace zypp
    * escaping it if necessary. Other fallbacks can be added to
    * this function in case there is no way to use the alias
    */
-  static std::string generate_filename( const RepoInfo &info )
+  std::string RepoManager::Impl::generateFilename( const RepoInfo &info ) const
   {
-    std::string fnd="/";
-    std::string rep="_";
     std::string filename = info.alias();
     // replace slashes with underscores
-    size_t pos = filename.find(fnd);
-    while(pos!=string::npos)
-    {
-      filename.replace(pos,fnd.length(),rep);
-      pos = filename.find(fnd,pos+rep.length());
-    }
+    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 Service &info ) const
+  {
+    std::string filename = info.name();
+    // replace slashes with underscores
+    str::replaceAll( filename, "/", "_" );
+
+    filename = Pathname(filename).extend(".service").asString();
+    MIL << "generating filename for service [" << info.name() << "] : '" << filename << "'" << endl;
+    return filename;
+  }
 
   ////////////////////////////////////////////////////////////////////////////
 
@@ -1061,8 +1088,8 @@ namespace zypp
     // assert the directory exists
     filesystem::assert_dir(_pimpl->options.knownReposPath);
 
-    Pathname repofile = generate_non_existing_name(_pimpl->options.knownReposPath,
-                                                    generate_filename(tosave));
+    Pathname repofile = _pimpl->generateNonExistingName(
+        _pimpl->options.knownReposPath, _pimpl->generateFilename(tosave));
     // now we have a filename that does not exists
     MIL << "Saving repo in " << repofile << endl;
 
@@ -1106,7 +1133,7 @@ namespace zypp
     // assert the directory exists
     filesystem::assert_dir(_pimpl->options.knownReposPath);
 
-    Pathname repofile = generate_non_existing_name(_pimpl->options.knownReposPath, filename);
+    Pathname repofile = _pimpl->generateNonExistingName(_pimpl->options.knownReposPath, filename);
     // now we have a filename that does not exists
     MIL << "Saving " << repos.size() << " repo" << ( repos.size() ? "s" : "" ) << " in " << repofile << endl;
 
@@ -1310,6 +1337,140 @@ namespace zypp
     ZYPP_THROW(RepoNotFoundException(info));
   }
 
+  void RepoManager::addService( const std::string& name, const Url& url )
+  {
+    Service service(name, url);
+
+    //check if service isn't already exist
+    if( _pimpl->services.find(service)!= _pimpl->services.end() )
+      return; //TODO throw exception
+
+    _pimpl->services.insert( service );
+
+    _pimpl->saveService( service );
+  }
+
+  void RepoManager::removeService( const string& name)
+  {
+    MIL << "Going to delete repo " << name << endl;
+
+    const Service& service = getService( name );
+
+    Pathname location = service.location();
+    if( location.empty() )
+    {
+      ZYPP_THROW(RepoException("Can't figure where the service is stored"));
+    }
+
+    ServiceSet tmpSet;
+    Impl::ServiceCollector collector(tmpSet);
+
+    parser::ServiceFileReader reader( location,
+        bind(&Impl::ServiceCollector::collect,collector,_1) );
+
+    if ( tmpSet.size() == 1 ) //only one record
+    {
+      if ( filesystem::unlink(location) != 0 )
+      {
+        ZYPP_THROW(RepoException("Can't delete " + location.asString()));
+      }
+      MIL << name << " sucessfully deleted." << endl;
+    }
+    else
+    {
+      filesystem::assert_dir(location.dirname());
+
+      std::ofstream file(location.c_str());
+
+      for_(it, tmpSet.begin(), tmpSet.end())
+      {
+        if( it->name() != name )
+          it->dumpServiceOn(file);
+      }
+    }
+
+    //now remove all repositories added by this service
+    for_( it, service.begin(), service.end() )
+      removeRepository(getRepositoryInfo(*it));
+  }
+
+
+  void RepoManager::Impl::saveService( const Service& service )
+  {
+    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.dumpServiceOn( file );
+
+    service.setLocation( servfile );
+    MIL << "done" << endl;
+  }
+
+  const Service& RepoManager::getService( const std::string& name ) const
+  {
+    //little trick for Set, because it is sorted by Service name
+    Service tmpServ(name);
+
+    ServiceConstIterator it = _pimpl->services.find(name);
+    if ( it == serviceEnd() )
+      return Service::noService;
+    else
+      return *it;
+  }
+
+  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()
+  {
+    //cannot user for_, because it uses const version
+    for (std::set<Service>::iterator it = _pimpl->services.begin();
+      it != _pimpl->services.end(); ++it)
+    {
+      it->refresh(*this);
+    }
+  }
+
+  void RepoManager::Impl::knownServices()
+  {
+    ServiceCollector collector(services);
+    Pathname dir = options.knownServicesPath;
+    list<Pathname> entries;
+    
+    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) );
+    }
+  }
+
   ////////////////////////////////////////////////////////////////////////////
 
   std::ostream & operator<<( std::ostream & str, const RepoManager & obj )
index d361a20..c91d2a2 100644 (file)
@@ -27,6 +27,7 @@
 ///////////////////////////////////////////////////////////////////
 namespace zypp
 { /////////////////////////////////////////////////////////////////
+  class Service; //predef
 
    /**
     * Parses \a repo_file and returns a list of \ref RepoInfo objects
@@ -76,6 +77,7 @@ namespace zypp
     Pathname repoSolvCachePath;
     Pathname repoPackagesCachePath;
     Pathname knownReposPath;
+    Pathname knownServicesPath;
     bool probe;
   };
 
@@ -93,6 +95,11 @@ namespace zypp
     /** Implementation  */
     class Impl;
 
+    /** service typedefs */
+    typedef std::set<Service> ServiceSet;
+    typedef ServiceSet::const_iterator ServiceConstIterator;
+    typedef ServiceSet::size_type ServiceSizeType;
+
   public:
    RepoManager( const RepoManagerOptions &options = RepoManagerOptions() );
    /** Dtor */
@@ -423,6 +430,22 @@ namespace zypp
                                 const url::ViewOption & urlview = url::ViewOption::DEFAULTS,
                                 const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() );
 
+    void addService( const std::string& name, const Url& url );
+
+    void removeService( const std::string& name );
+
+    bool serviceEmpty() const;
+
+    ServiceSizeType serviceSize() const;
+
+    ServiceConstIterator serviceBegin() const;
+
+    ServiceConstIterator serviceEnd() const;
+
+    const Service& getService( const std::string& name ) const;
+
+    void refreshServices();
+
   protected:
     RepoStatus rawMetadataStatus( const RepoInfo &info );
     void setCacheStatus( const RepoInfo &info, const RepoStatus &status );
diff --git a/zypp/Service.cc b/zypp/Service.cc
new file mode 100644 (file)
index 0000000..5292dec
--- /dev/null
@@ -0,0 +1,156 @@
+#include "zypp/Service.h"
+
+#include <ostream>
+
+#include "zypp/Url.h"
+#include "zypp/RepoInfo.h"
+#include "zypp/media/MediaManager.h"
+#include "zypp/parser/RepoindexFileReader.h"
+
+using namespace std;
+///////////////////////////////////////////////////////////////////////////////
+namespace zypp 
+{//////////////////////////////////////////////////////////////////////////////
+
+  struct RepoInfoCollector {
+    std::vector<RepoInfo> repos;
+    bool collect(const RepoInfo& info)
+    {
+      repos.push_back(info);
+      return true;
+    }
+
+  };
+
+  class Service::Impl{
+    public:
+      RepoContainer repos;
+      string name;
+      Url url;
+      Pathname loc;
+      Impl() : name("") {};
+      Impl(const string& name_) : name(name_) {};
+      Impl(const string& name_, const Url& url_) : name(name_), url(url_) {};
+  };
+
+  Service::Service() : _pimpl( new Impl() ) {};
+
+  Service::Service(const string& name) : _pimpl( new Impl(name) ) {};
+  Service::Service(const string& name, const Url& url)
+    : _pimpl( new Impl(name,url) ) {};
+
+  const Service Service::noService;
+
+  string Service::name() const { return _pimpl->name; }
+  Url Service::url() const { return _pimpl->url; }
+
+  void Service::setUrl( const Url& url ) { _pimpl->url = url; }
+
+  bool Service::empty() const { return _pimpl->repos.empty(); }
+  Service::size_type Service::size() const { return _pimpl->repos.size(); }
+  Service::const_iterator Service::begin() const { return _pimpl->repos.begin(); }
+  Service::const_iterator Service::end() const { return _pimpl->repos.end(); }
+
+  void Service::addRepo( const std::string& alias )
+  {
+    _pimpl->repos.push_back(alias);
+  }
+
+  void Service::dumpServiceOn( std::ostream& str ) const
+  {
+    str << endl;
+    str << "[" << name() << "]" << endl;
+    str << "url = " << url() << endl;
+    for_( it, begin(), end() )
+    {
+      str << "alias = " << *it << endl;
+    }
+    str << endl;
+  }
+
+  void Service::refresh( RepoManager& repomanager ) const
+  {
+    //download index file
+    media::MediaManager mediamanager;
+    media::MediaAccessId mid = mediamanager.open( url() );
+    mediamanager.provideFile( mid, "repo/repoindex.xml" );
+    Pathname path = mediamanager.localPath(mid, "repo/repoindex.xml" );
+
+    //parse it
+    RepoInfoCollector collector;
+    parser::RepoindexFileReader reader( path,
+      bind( &RepoInfoCollector::collect, &collector, _1 ) );
+
+    // set base url for all collected repositories
+    for_( it, collector.repos.begin(), collector.repos.end())
+    {
+      it->setBaseUrl( url() );
+    }
+
+    //compare old and new repositories (hope not to much, if it change
+    // then construct set and use set operation on it)
+
+    std::list<RepoInfo> krepos = repomanager.knownRepositories();
+
+    //find old to remove
+    for_( it, begin(), end() )
+    {
+      bool found = false;
+
+      for_( it2, collector.repos.begin(), collector.repos.end() )
+        if ( *it == it2->alias() )
+        {
+          found = true;
+          break;
+        }
+
+      if( !found )
+        repomanager.removeRepository( repomanager.getRepositoryInfo( *it ) );
+    }
+
+    //find new to add
+    for_( it, collector.repos.begin(), collector.repos.end() )
+    {
+      bool found = false;
+
+      for_( it2, begin(), end() )
+        if( it->alias() == *it2 )
+        {
+          found = true;
+          break;
+        }
+
+      if (!found)
+        repomanager.addRepository( *it );
+    }
+
+    //update internal alias storage
+    _pimpl->repos.clear();
+    for_( it, collector.repos.begin(), collector.repos.end() )
+    {
+      _pimpl->repos.push_back(it->alias());
+    }
+    
+    mediamanager.close( mid );
+  }
+
+  Pathname Service::location() const
+  {
+    return _pimpl->loc;
+  }
+
+  void Service::setLocation( const Pathname& location ) const
+  {
+    _pimpl->loc = location;
+  }
+
+  std::ostream & operator<<( std::ostream& str, const Service &obj )
+  {
+    obj.dumpServiceOn(str);
+    return str;
+  }
+
+
+///////////////////////////////////////////////////////////////////////////////
+} //namespace zypp
+///////////////////////////////////////////////////////////////////////////////
diff --git a/zypp/Service.h b/zypp/Service.h
new file mode 100644 (file)
index 0000000..ced5093
--- /dev/null
@@ -0,0 +1,132 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/Service.h
+ *
+*/
+#ifndef ZYPP_SERVICE_H
+#define ZYPP_SERVICE_H
+
+#include <string>
+#include "zypp/Url.h"
+#include "zypp/RepoManager.h"
+
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // CLASS NAME : Service
+    //
+    /** */
+    class Service
+    {
+    public:
+        typedef std::vector<std::string> RepoContainer;
+        typedef RepoContainer::const_iterator const_iterator;
+        typedef RepoContainer::size_type size_type;
+
+    public:
+        /** Default ctor creates \ref noService.*/
+        Service();
+
+        /**
+         *  Service with this name.
+         */
+        Service( const std::string& name );
+
+        /**
+         * Creates service with name and it's url.
+         * Used for adding new services.
+         * \note internal, do not used outside libzypp
+         */
+        Service( const std::string& name, const Url& url );
+
+    public:
+        /** Represents no \ref Service. */
+        static const Service noService;
+
+    public:
+        std::string name() const;
+
+        Url url() const;
+
+        Pathname location() const;
+
+        void setLocation( const Pathname& location ) const;
+
+        void setUrl( const Url& url );
+
+    public:
+
+        /** Whether \ref Service contains solvables. */
+        bool empty() const;
+
+        /** Number of solvables in \ref Service. */
+        size_type size() const;
+
+        /** Iterator to the first \ref Solvable. */
+        const_iterator begin() const;
+
+        /** Iterator behind the last \ref Solvable. */
+        const_iterator end() const;
+
+   public:
+        /**
+         * Refreshes local information about service.
+         * It can addi, remove or modify repositories.
+         * it is const due to use Service in set or map and name doesn't change
+         */
+        void refresh( RepoManager& repomanager) const;
+
+        /**
+         * Writes Service to stream in ".service" format
+         */
+        void dumpServiceOn( std::ostream & str ) const;
+
+        /**
+         * set repositories by alias.
+         * Used only during local loading, for update repository use refresh
+         */
+        template<typename InputIterator>
+        void setRepos(InputIterator begin, InputIterator end)
+        {
+          for_(it,begin,end)
+            addRepo(*it);
+        }
+
+        void addRepo(const std::string& alias);
+
+        class Impl;
+
+    private:
+        mutable RW_pointer<Impl> _pimpl;
+    };
+    ///////////////////////////////////////////////////////////////////
+
+    /** \relates Service Stream output */
+    std::ostream & operator<<( std::ostream & str, const Service & obj );
+
+    /** \relates Service */
+    inline bool operator==( const Service & lhs, const Service & rhs )
+    { return lhs.name() == rhs.name(); }
+
+    /** \relates Service */
+    inline bool operator!=( const Service & lhs, const Service & rhs )
+    { return lhs.name() != rhs.name(); }
+
+    /** \relates Service */
+    inline bool operator<( const Service & lhs, const Service & rhs )
+    { return lhs.name() < rhs.name(); }
+
+    /////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
+#endif // ZYPP_SAT_REPOSITORY_H
index 52cec69..52ec469 100644 (file)
@@ -310,6 +310,7 @@ namespace zypp
 
     Pathname cfg_config_path;
     Pathname cfg_known_repos_path;
+    Pathname cfg_known_services_path;
     Pathname cfg_vendor_path;
     Pathname cfg_products_path;
     Pathname locks_file;
@@ -454,6 +455,13 @@ namespace zypp
     return ( _pimpl->cfg_known_repos_path.empty()
         ? (configPath()/"repos.d") : _pimpl->cfg_known_repos_path );
   }
+
+  Pathname ZConfig::knownServicesPath() const
+  {
+    return ( _pimpl->cfg_known_services_path.empty()
+        ? (configPath()/"services.d") : _pimpl->cfg_known_repos_path );
+  }
+
   Pathname ZConfig::vendorPath() const
   {
     return ( _pimpl->cfg_vendor_path.empty()
index ad623e7..6a45494 100644 (file)
@@ -129,6 +129,12 @@ namespace zypp
       Pathname knownReposPath() const;
 
       /**
+       * Path where the known services .service files are kept (configPath()/services.d).
+       * \ingroup g_ZC_CONFIGFILES
+       */
+      Pathname knownServicesPath() const;
+
+      /**
        * Separator string for storing/reading sets of strings to/from
        * metadata cache DB.
        */
diff --git a/zypp/parser/RepoindexFileReader.cc b/zypp/parser/RepoindexFileReader.cc
new file mode 100644 (file)
index 0000000..538c8c2
--- /dev/null
@@ -0,0 +1,131 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file zypp/parser/yum/RepoindexFileReader.cc
+ * Implementation of repoindex.xml file reader.
+ */
+#include <iostream>
+
+#include "zypp/base/String.h"
+#include "zypp/base/Logger.h"
+
+#include "zypp/Pathname.h"
+#include "zypp/parser/xml/Reader.h"
+
+#include "zypp/parser/RepoindexFileReader.h"
+
+#undef ZYPP_BASE_LOGGER_LOGGROUP
+#define ZYPP_BASE_LOGGER_LOGGROUP "parser"
+
+using namespace std;
+using namespace zypp::xml;
+
+namespace zypp
+{
+  namespace parser
+  {
+
+
+  ///////////////////////////////////////////////////////////////////////
+  //
+  //  CLASS NAME : RepoindexFileReader::Impl
+  //
+  class RepoindexFileReader::Impl : private base::NonCopyable
+  {
+  public:
+    /**
+     * CTOR
+     *
+     * \see RepoindexFileReader::RepoindexFileReader(Pathname,ProcessResource)
+     */
+    Impl(const Pathname &repoindex_file, const ProcessResource & callback);
+
+    /**
+     * Callback provided to the XML parser.
+     */
+    bool consumeNode( Reader & reader_r );
+
+
+  private:
+    /** Function for processing collected data. Passed-in through constructor. */
+    ProcessResource _callback;
+  };
+  ///////////////////////////////////////////////////////////////////////
+
+  RepoindexFileReader::Impl::Impl(
+      const Pathname &repoindex_file, const ProcessResource & callback)
+    : _callback(callback)
+  {
+    Reader reader( repoindex_file );
+    MIL << "Reading " << repoindex_file << endl;
+    reader.foreachNode( bind( &RepoindexFileReader::Impl::consumeNode, this, _1 ) );
+  }
+
+  // --------------------------------------------------------------------------
+
+  /*
+   * xpath and multiplicity of processed nodes are included in the code
+   * for convenience:
+   *
+   * // xpath: <xpath> (?|*|+)
+   *
+   * if multiplicity is ommited, then the node has multiplicity 'one'.
+   */
+
+  // --------------------------------------------------------------------------
+
+  bool RepoindexFileReader::Impl::consumeNode( Reader & reader_r )
+  {
+    if ( reader_r->nodeType() == XML_READER_TYPE_ELEMENT )
+    {
+      // xpath: /repoindex
+      if ( reader_r->name() == "repoindex" )
+      {
+        return true;
+      }
+
+      // xpath: /repoindex/data (+)
+      if ( reader_r->name() == "repo" )
+      {
+        RepoInfo info;
+        info.setPath(Pathname(string("/repo/")+reader_r->getAttribute("path").asString()));
+        info.setAlias(reader_r->getAttribute("alias").asString());
+        info.setType(repo::RepoType::RPMMD_e); //TODO hardwired rpmmd???
+        XmlString s = reader_r->getAttribute("name");
+        if (s.get()) //name setted so also set it
+          info.setName(s.asString());
+        //ignore rest
+        _callback(info);
+        return true;
+      }
+    }
+
+    return true;
+  }
+
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  //  CLASS NAME : RepoindexFileReader
+  //
+  ///////////////////////////////////////////////////////////////////
+
+  RepoindexFileReader::RepoindexFileReader(
+      const Pathname & repoindex_file, const ProcessResource & callback)
+    :
+      _pimpl(new Impl(repoindex_file, callback))
+  {}
+
+  RepoindexFileReader::~RepoindexFileReader()
+  {}
+
+
+  } // ns parser
+} // ns zypp
+
+// vim: set ts=2 sts=2 sw=2 et ai:
diff --git a/zypp/parser/RepoindexFileReader.h b/zypp/parser/RepoindexFileReader.h
new file mode 100644 (file)
index 0000000..fd18461
--- /dev/null
@@ -0,0 +1,80 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file zypp/parser/yum/RepoindexFileReader.h
+ * Interface of repoindex.xml file reader.
+ */
+#ifndef zypp_source_yum_RepoindexFileReader_H
+#define zypp_source_yum_RepoindexFileReader_H
+
+#include "zypp/base/PtrTypes.h"
+#include "zypp/base/NonCopyable.h"
+#include "zypp/base/Function.h"
+
+#include "zypp/RepoInfo.h"
+
+namespace zypp
+{
+  namespace parser
+  {
+
+  /**
+   * Reads through a repoindex.xml file and collects repositories.
+   *
+   * After each repository is read, a \ref RepoInfo
+   * is prepared and \ref _callback
+   * is called with these two objects passed in.
+   *
+   * The \ref _callback is provided on construction.
+   *
+   *
+   * \code
+   * RepoindexFileReader reader(repoindex_file, 
+   *                  bind( &SomeClass::callbackfunc, &SomeClassInstance, _1) );
+   * \endcode
+   */
+  class RepoindexFileReader : private base::NonCopyable
+  {
+  public:
+   /**
+    * Callback definition.
+    * First parameter is a \ref RepoInfo object with the resource
+    * second parameter is the resource type.
+    */
+    typedef function< bool(
+        const RepoInfo & )>
+      ProcessResource;
+
+   /**
+    * CTOR. Creates also \ref xml::Reader and starts reading.
+    * 
+    * \param repoindex_file is the repoindex.xml file you want to read
+    * \param callback is a function.
+    *
+    * \see RepoindexFileReader::ProcessResource
+    */
+    RepoindexFileReader(
+      const Pathname & repoindex_file, const ProcessResource & callback);
+
+    /**
+     * DTOR
+     */
+    ~RepoindexFileReader();
+
+  private:
+    class Impl;
+    RW_pointer<Impl,rw_pointer::Scoped<Impl> > _pimpl;
+  };
+
+
+  } // ns parser
+} // ns zypp
+
+#endif /*zypp_source_yum_RepoindexFileReader_H*/
+
+// vim: set ts=2 sts=2 sw=2 et ai:
diff --git a/zypp/parser/ServiceFileReader.cc b/zypp/parser/ServiceFileReader.cc
new file mode 100644 (file)
index 0000000..d1d249f
--- /dev/null
@@ -0,0 +1,99 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/repo/RepoFileReader.cc
+ *
+*/
+#include <iostream>
+#include "zypp/base/Logger.h"
+#include "zypp/base/String.h"
+#include "zypp/base/InputStream.h"
+#include "zypp/base/UserRequestException.h"
+
+#include "zypp/parser/IniDict.h"
+#include "zypp/parser/ServiceFileReader.h"
+#include "zypp/Service.h"
+
+using std::endl;
+using zypp::parser::IniDict;
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////
+  namespace parser
+  { /////////////////////////////////////////////////////////////////
+
+    class ServiceFileReader::Impl {
+      public:
+      static void parseServices( const Pathname &file,
+          const ServiceFileReader::ProcessService& callback );
+    };
+
+    void ServiceFileReader::Impl::parseServices( const Pathname &file,
+                                  const ServiceFileReader::ProcessService &callback/*,
+                                  const ProgressData::ReceiverFnc &progress*/ )
+    {
+      InputStream is(file);
+      parser::IniDict dict(is);
+      for ( parser::IniDict::section_const_iterator its = dict.sectionsBegin();
+            its != dict.sectionsEnd();
+            ++its )
+      {
+        MIL << (*its) << endl;
+
+        Service service(*its);
+
+        for ( IniDict::entry_const_iterator it = dict.entriesBegin(*its);
+              it != dict.entriesEnd(*its);
+              ++it )
+        {
+          //MIL << (*it).first << endl;
+          if (it->first == "url" )
+            service.setUrl( Url (it->second) );
+          else if ( it->first == "alias" )
+            service.addRepo( it->second );
+          else
+            ERR << "Unknown attribute " << it->second << " ignored" << endl;
+        }
+        MIL << "Linking repo info with file " << file << endl;
+        service.setLocation(file);
+        // add it to the list.
+        if ( !callback(service) )
+          break;
+      }
+    }
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // CLASS NAME : RepoFileReader
+    //
+    ///////////////////////////////////////////////////////////////////
+
+    ServiceFileReader::ServiceFileReader( const Pathname & repo_file,
+                                    const ProcessService & callback/*,
+                                    const ProgressData::ReceiverFnc &progress */)
+    {
+      Impl::parseServices(repo_file, callback/*, progress*/);
+      //MIL << "Done" << endl;
+    }
+
+    ServiceFileReader::~ServiceFileReader()
+    {}
+
+    std::ostream & operator<<( std::ostream & str, const ServiceFileReader & obj )
+    {
+      return str;
+    }
+
+    /////////////////////////////////////////////////////////////////
+  } // namespace parser
+  ///////////////////////////////////////////////////////////////////
+  /////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
diff --git a/zypp/parser/ServiceFileReader.h b/zypp/parser/ServiceFileReader.h
new file mode 100644 (file)
index 0000000..137c0fd
--- /dev/null
@@ -0,0 +1,93 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/repo/ServiceFileReader.h
+ *
+*/
+#ifndef ZYPP_REPO_SERVICEFILEREADER_H
+#define ZYPP_REPO_SERVICEFILEREADER_H
+
+#include <iosfwd>
+
+#include "zypp/base/PtrTypes.h"
+#include "zypp/ProgressData.h"
+#include "zypp/Pathname.h"
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+
+  class Service;
+  ///////////////////////////////////////////////////////////////////
+  namespace parser
+  { /////////////////////////////////////////////////////////////////
+
+    /**
+     * \short Read repository data from a .repo file
+     *
+     * After each repo is read, a \ref RepoInfo is prepared and \ref _callback
+     * is called with the object passed in.
+     *
+     * The \ref _callback is provided on construction.
+     *
+     * \code
+     * ServiceFileReader reader(repo_file, 
+     *                bind( &SomeClass::callbackfunc, &SomeClassInstance, _1, _2 ) );
+     * \endcode
+     */
+    class ServiceFileReader
+    {
+      friend std::ostream & operator<<( std::ostream & str, const ServiceFileReader & obj );
+    public:
+      
+     /**
+      * Callback definition.
+      * First parameter is a \ref RepoInfo object with the resource
+      * second parameter is the resource type.
+      *
+      * Return false from the callback to get a \ref AbortRequestException
+      * to be thrown and the processing to be cancelled.
+      */
+      typedef function< bool( const Service & )> ProcessService;
+      
+      /** Implementation  */
+      class Impl;
+
+    public:
+     /**
+      * \short Constructor. Creates the reader and start reading.
+      *
+      * \param repo_file A valid .repo file
+      * \param callback Callback that will be called for each repository.
+      * \param progress Optional progress function. \see ProgressData
+      *
+      * \throws AbortRequestException If the callback returns false
+      * \throws Exception If a error occurs at reading / parsing
+      *
+      */
+      ServiceFileReader( const Pathname & repo_file,
+                      const ProcessService & callback/*,
+                      const ProgressData::ReceiverFnc &progress = ProgressData::ReceiverFnc()*/);
+     
+      /**
+       * Dtor
+       */
+      ~ServiceFileReader();
+    };
+    ///////////////////////////////////////////////////////////////////
+
+    /** \relates ServiceFileReader Stream output */
+    std::ostream & operator<<( std::ostream & str, const ServiceFileReader & obj );
+
+    /////////////////////////////////////////////////////////////////
+  } // namespace parser
+  ///////////////////////////////////////////////////////////////////
+  /////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
+#endif // ZYPP_REPO_SERVICEFILEREADER_H
index fd32f03..78b48f6 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<grammar ns="http://novell.com/package/metadata/suse/patch" xmlns:yum="http://linux.duke.edu/metadata/common" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+<grammar xmlns:yum="http://linux.duke.edu/metadata/common" ns="http://novell.com/package/metadata/suse/patch" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   <include href="suse-primary.rng">
     <start>
       <ref name="element-patch"/>
index d38f13b..1eb2d5f 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<grammar ns="http://linux.duke.edu/metadata/common" xmlns:suse="http://novell.com/package/metadata/suse/common" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+<grammar xmlns:suse="http://novell.com/package/metadata/suse/common" ns="http://linux.duke.edu/metadata/common" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   <!-- defines element-format and format -->
   <include href="rpm-ns.rng"/>
   <start>
index 6fc53f7..8248552 100644 (file)
               <ref name="localized-string"/>
             </element>
           </zeroOrMore>
+          <element name="ns1:distribution-name">
+            <text/>
+          </element>
+          <element name="ns1:distribution-edition">
+            <text/>
+          </element>
           <oneOrMore>
             <element name="ns1:description">
               <ref name="localized-string"/>
             </element>
           </oneOrMore>
+          <optional>
+            <element name="ns1:release-notes-url">
+              <text/>
+            </element>
+          </optional>
+          <zeroOrMore>
+            <element name="ns1:update-url">
+              <text/>
+            </element>
+          </zeroOrMore>
+          <zeroOrMore>
+            <element name="ns1:optional-url">
+              <text/>
+            </element>
+          </zeroOrMore>
+          <zeroOrMore>
+            <element name="ns1:extra-url">
+              <text/>
+            </element>
+          </zeroOrMore>
           <ref name="dependencies"/>
         </element>
       </oneOrMore>
diff --git a/zypp/parser/yum/schema/repoindex.rnc b/zypp/parser/yum/schema/repoindex.rnc
new file mode 100644 (file)
index 0000000..bc32693
--- /dev/null
@@ -0,0 +1,28 @@
+# NU service index file schema.
+#
+# Elements:
+#
+# repoindex
+#   Root element. Contains only repo elements.
+#   repo element contains only attributes - 
+#     name - name of repository
+#     alias - unique alias of repository
+#     description - description of repository
+#     distro_target - target distribution
+#     priority - priority of repository
+#     pub - ???
+#     path - relative path to repository
+#
+
+element repoindex {
+  element repo {
+    attribute name { xsd:string }?,
+    attribute alias { xsd:string },
+    attribute description { xsd:string }?,
+    attribute distro_target { xsd:string },
+    attribute priority { xsd:integer }?,
+    attribute pub { xsd:integer }?,
+    attribute path { xsd:string }
+  }+,
+  empty
+}
diff --git a/zypp/parser/yum/schema/repoindex.rng b/zypp/parser/yum/schema/repoindex.rng
new file mode 100644 (file)
index 0000000..5b7ae26
--- /dev/null
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  NU service index file schema.
+  
+  Elements:
+  
+  repoindex
+    Root element. Contains only repo elements.
+    repo element contains only attributes - 
+      name - name of repository
+      alias - unique alias of repository
+      description - description of repository
+      distro_target - target distribution
+      priority - priority of repository
+      pub - ???
+      path - relative path to repository
+  
+-->
+<element name="repoindex" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  <oneOrMore>
+    <element name="repo">
+      <optional>
+        <attribute name="name">
+          <data type="string"/>
+        </attribute>
+      </optional>
+      <attribute name="alias">
+        <data type="string"/>
+      </attribute>
+      <optional>
+        <attribute name="description">
+          <data type="string"/>
+        </attribute>
+      </optional>
+      <attribute name="distro_target">
+        <data type="string"/>
+      </attribute>
+      <optional>
+        <attribute name="priority">
+          <data type="integer"/>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="pub">
+          <data type="integer"/>
+        </attribute>
+      </optional>
+      <attribute name="path">
+        <data type="string"/>
+      </attribute>
+    </element>
+  </oneOrMore>
+  <empty/>
+</element>
index 09b488f..9451201 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<grammar ns="http://linux.duke.edu/metadata/rpm" xmlns:ns1="http://linux.duke.edu/metadata/common" xmlns:rpm="http://linux.duke.edu/metadata/rpm" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+<grammar xmlns:ns1="http://linux.duke.edu/metadata/common" xmlns:rpm="http://linux.duke.edu/metadata/rpm" ns="http://linux.duke.edu/metadata/rpm" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   <define name="element-format">
     <element name="ns1:format">
       <ref name="format"/>
       <ref name="element-entry"/>
     </zeroOrMore>
   </define>
+  <!-- treat as 'provides' file capability -->
   <define name="element-file">
     <element name="ns1:file">
       <ref name="file"/>
index aa69bbc..f3029b8 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<grammar ns="http://novell.com/package/metadata/suse/common" xmlns:ns1="http://linux.duke.edu/metadata/common" xmlns:suse="http://novell.com/package/metadata/suse/common" xmlns="http://relaxng.org/ns/structure/1.0">
+<grammar xmlns:suse="http://novell.com/package/metadata/suse/common" xmlns:ns1="http://linux.duke.edu/metadata/common" ns="http://novell.com/package/metadata/suse/common" xmlns="http://relaxng.org/ns/structure/1.0">
   <include href="primary.rng">
     <define name="element-format">
       <element name="ns1:format">
index 47c90f6..54629c6 100644 (file)
@@ -31,6 +31,7 @@ namespace yum
 #define PATCHSCHEMA (SCHEMABASE "patch.rng")
 #define PATCHESSCHEMA (SCHEMABASE "patches.rng")
 #define PRODUCTSCHEMA (SCHEMABASE "product.rng")
+#define REPOINDEXSCHEMA (SCHEMABASE "product.rng")
 } // namespace yum
 } // namespace parser
 } // namespace zypp