XMLFilesBackend.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <ctime>
00014 #include <cstdlib>
00015 #include <cstdio>
00016 #include <fcntl.h>
00017 
00018 #include "zypp/base/Logger.h"
00019 #include "zypp/base/Exception.h"
00020 
00021 #include "zypp/CapFactory.h"
00022 #include "zypp/Digest.h"
00023 #include "zypp/Source.h"
00024 #include "zypp/SourceManager.h"
00025 #include "zypp/ExternalProgram.h"
00026 
00027 #include "zypp/target/store/xml/XMLPatchImpl.h"
00028 #include "zypp/target/store/xml/XMLMessageImpl.h"
00029 #include "zypp/target/store/xml/XMLScriptImpl.h"
00030 #include "zypp/target/store/xml/XMLSelectionImpl.h"
00031 #include "zypp/target/store/xml/XMLProductImpl.h"
00032 #include "zypp/target/store/xml/XMLPatternImpl.h"
00033 #include "zypp/target/store/xml/XMLAtomImpl.h"
00034 
00035 #include "zypp/parser/xmlstore/XMLProductParser.h"
00036 #include "zypp/parser/xmlstore/XMLPatternParser.h"
00037 #include "zypp/parser/xmlstore/XMLPatchParser.h"
00038 #include "zypp/parser/xmlstore/XMLLanguageParser.h"
00039 
00040 #include <iostream>
00041 #include <fstream>
00042 #include <sstream>
00043 #include <streambuf>
00044 
00045 #include <list>
00046 
00047 #include <zypp/TmpPath.h>
00048 #include <zypp/ZYppFactory.h>
00049 #include <zypp/ZYpp.h>
00050 #include <zypp/PathInfo.h>
00051 
00052 #include "zypp/parser/xmlstore/XMLSourceCacheParser.h"
00053 
00054 #include "boost/filesystem/operations.hpp" // includes boost/filesystem/path.hpp
00055 #include "boost/filesystem/fstream.hpp"    // ditto
00056 
00057 #include "XMLFilesBackend.h"
00058 #include "serialize.h"
00059 
00060 //#define ZYPP_DB_DIR "/var/lib/zypp_db/"
00061 #define ZYPP_DB_DIR ( getZYpp()->homePath().asString()+"/db/" )
00062 
00063 using std::endl;
00064 using std::string;
00065 using std::list;
00066 using namespace boost::filesystem;
00067 using namespace zypp;
00068 using namespace zypp::filesystem;
00069 
00071 namespace zypp
00072 { 
00073 namespace storage
00074 { 
00075 
00088 typedef struct
00089 {
00090   char * dist_name;
00091   char * dist_version;
00092   char * product_name;
00093   char * product_version;
00094 } PRODUCT_TABLE_ENTRY;
00095 
00101 PRODUCT_TABLE_ENTRY* products_table()
00102 {
00103   static PRODUCT_TABLE_ENTRY products[] = {
00104     { "SUSE-Linux-Enterprise-Desktop-i386", "10-0", "SUSE SLED" , "10" },
00105     { "SUSE-Linux-Enterprise-Desktop-x86_64", "10-0", "SUSE SLED", "10" },
00106     { "SUSE-Linux-Enterprise-Server-i386", "10-0", "SUSE SLES", "10" },
00107     { "SUSE-Linux-Enterprise-Server-x86_64", "10-0", "SUSE SLES", "10" },
00108     { "SUSE-Linux-Enterprise-Server-ppc", "10-0", "SUSE SLES", "10" },
00109     { "SUSE-Linux-Enterprise-Server-ia64", "10-0", "SUSE SLES", "10" },
00110     { "SUSE-Linux-Enterprise-Server-s390x", "10-0", "SUSE SLES", "10" },
00111     { "SUSE-Linux-10.1-CD-download-x86", "10.1-0", "SUSE LINUX", "10.1" },
00112     { "SUSE-Linux-10.1-CD-download-ppc", "10.1-0", "SUSE LINUX", "10.1" },
00113     { "SUSE-Linux-10.1-CD-download-x86_64", "10.1-0", "SUSE LINUX", "10.1" },
00114     { "SUSE-Linux-10.1-CD-x86", "10.1-0", "SUSE LINUX", "10.1" },
00115     { "SUSE-Linux-10.1-CD-ppc", "10.1-0", "SUSE LINUX", "10.1" },
00116     { "SUSE-Linux-10.1-CD-x86_64", "10.1-0", "SUSE LINUX", "10.1" },
00117     { "SUSE-Linux-10.1-DVD9-x86-x86_64", "10.1-0", "SUSE LINUX", "10.1" },
00118     { "SUSE-Linux-10.1-OSS-DVD-x86", "10.1-0", "SUSE LINUX", "10.1" },
00119     { "SUSE-Linux-10.1-DVD-OSS-i386", "10.1-0", "SUSE LINUX", "10.1" },
00120     { "SUSE-Linux-10.1-DVD-OSS-ppc", "10.1-0", "SUSE LINUX", "10.1" },
00121     { "SUSE-Linux-10.1-DVD-OSS-x86_64", "10.1-0", "SUSE LINUX", "10.1" },
00122     { "SUSE-Linux-10.1-FTP", "10.1-0", "SUSE LINUX", "10.1" },
00123     { "SUSE-Linux-10.1-DVD-i386", "10.1-0", "SUSE LINUX", "10.1" },
00124     { "SUSE-Linux-10.1-DVD-x86_64", "10.1-0", "SUSE LINUX", "10.1" },
00125     { "SuSE-Linux-10.1-PromoDVD-i386", "10.1-0", "SUSE LINUX", "10.1" },
00126     { "SUSE-Linux-10.1-DVD9-CTMAGAZIN-x86-x86_64", "10.1-0", "SUSE LINUX", "10.1" },
00127     { "SUSE-Linux-Enterprise-SDK-i386", "10-0", "SLE SDK", "10" },
00128     { "SUSE-Linux-Enterprise-SDK-x86_64", "10-0", "SLE SDK", "10" },
00129     { "SUSE-Linux-Enterprise-SDK-ia64", "10-0", "SLE SDK", "10" },
00130     { "SUSE-Linux-Enterprise-SDK-s390x", "10-0", "SLE SDK", "10" },
00131     { "SUSE-Linux-Enterprise-SDK-ppc", "10-0", "SLE SDK", "10" },
00132     { "SUSE-Linux-Enterprise-RT", "10-0", "SLE RT", "10" },
00133     { 0L, 0L, 0L, 0L }
00134   };
00135   
00136   return products;
00137 }
00138 
00140 //
00141 //      CLASS NAME : XMLFilesBackend::Private
00142 //
00144 class XMLFilesBackend::Private
00145 {
00146   public:
00147   Private()
00148   { }
00149   bool randomFileName;
00150   std::set<Resolvable::Kind> kinds;
00151   std::set<Resolvable::Kind> kinds_flags;
00152   Pathname root;
00153 };
00154 
00156 //
00157 //      CLASS NAME : XMLFilesBackend
00158 //
00160 
00162 //
00163 //      METHOD NAME : XMLFilesBackend::XMLFilesBackend
00164 //      METHOD TYPE : Ctor
00165 //
00166 XMLFilesBackend::XMLFilesBackend(const Pathname &root) : Backend(root)
00167 {
00168   d = new Private;
00169   d->randomFileName = false;
00170   d->root = root;
00171 
00172   // types of resolvables stored (supported)
00173   d->kinds.insert(ResTraits<zypp::Patch>::kind);
00174   //d->kinds.insert(ResTraits<zypp::Message>::kind);
00175   //d->kinds.insert(ResTraits<zypp::Script>::kind);
00176   d->kinds.insert(ResTraits<zypp::Selection>::kind);
00177   d->kinds.insert(ResTraits<zypp::Product>::kind);
00178   d->kinds.insert(ResTraits<zypp::Pattern>::kind);
00179   d->kinds.insert(ResTraits<zypp::Language>::kind);
00180 
00181   // types of resolvables stored (supported)
00182   d->kinds_flags.insert(ResTraits<zypp::Package>::kind);
00183   d->kinds_flags.insert(ResTraits<zypp::Patch>::kind);
00184   //d->kinds.insert(ResTraits<zypp::Message>::kind);
00185   //d->kinds.insert(ResTraits<zypp::Script>::kind);
00186   d->kinds_flags.insert(ResTraits<zypp::Selection>::kind);
00187   d->kinds_flags.insert(ResTraits<zypp::Product>::kind);
00188   d->kinds_flags.insert(ResTraits<zypp::Pattern>::kind);
00189   d->kinds_flags.insert(ResTraits<zypp::Language>::kind);
00190 
00191 
00192   // check if the db exists
00193   if (!isBackendInitialized())
00194   {
00195     DBG << "Database not initialized" << std::endl;
00196     initBackend();
00197     // should be initialized now...
00198     if (!isBackendInitialized())
00199       DBG << "Error, cant init database" << std::endl;
00200     else
00201       DBG << "Database initialized" << std::endl;
00202    }
00203    else
00204    {
00205      DBG << "Database already initialized" << std::endl;
00206    }
00207 }
00208 
00209 Date XMLFilesBackend::timestamp() const
00210 {
00211   PathInfo ts_info = PathInfo( d->root + Pathname(ZYPP_DB_DIR) + "timestamp" );
00212   if ( ts_info.isExist() )
00213   {
00214     return Date(ts_info.mtime());
00215   }
00216   else
00217   {
00218     updateTimestamp();
00219     return Date::now();
00220   }
00221 }
00222 
00223 // Taken from KApplication
00224 int XMLFilesBackend::random() const
00225 {
00226    static bool init = false;
00227    if (!init)
00228    {
00229       unsigned int seed;
00230       init = true;
00231       int fd = open("/dev/urandom", O_RDONLY);
00232       if (fd < 0 || ::read(fd, &seed, sizeof(seed)) != sizeof(seed))
00233       {
00234             // No /dev/urandom... try something else.
00235             srand(getpid());
00236             seed = rand()+time(0);
00237       }
00238       if (fd >= 0) close(fd);
00239       srand(seed);
00240    }
00241    return rand();
00242 }
00243 
00244 // Taken from KApplication
00245 std::string XMLFilesBackend::randomString(int length) const
00246 {
00247    if (length <=0 ) return std::string();
00248 
00249    std::string str; str.resize( length );
00250    int i = 0;
00251    while (length--)
00252    {
00253       int r=random() % 62;
00254       r+=48;
00255       if (r>57) r+=7;
00256       if (r>90) r+=6;
00257       str[i++] =  char(r);
00258       // so what if I work backwards?
00259    }
00260    return str;
00261 }
00262 
00263 bool
00264 XMLFilesBackend::isBackendInitialized() const
00265 {
00266   bool ok = true;
00267   Pathname dbdir = d->root +  ZYPP_DB_DIR;
00268   ok = ok && PathInfo(dbdir).isExist();
00269 
00270   bool fixperms = false;
00271 
00272   // The db dir was created with 700 permissions
00273   // see bug #169094
00274   if ( ok && PathInfo(dbdir).perm() == 0700 )
00275   {
00276     if ( geteuid() == 0 )
00277     {
00278       fixperms = true;
00279       WAR << "Wrong permissions for /var/lib/zypp, will fix" << std::endl;
00280 
00281       const char* argv[] =
00282       {
00283         "chmod",
00284         "-R",
00285         "0755",
00286         "/var/lib/zypp",
00287         NULL
00288       };
00289 
00290       ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00291       prog.close();
00292     }
00293     else
00294     {
00295       WAR << "Wrong permissions for /var/lib/zypp, but can't fix unless you run as root." << std::endl;
00296     }
00297 
00298   }
00299 
00300   // folders for resolvables
00301   std::set<Resolvable::Kind>::const_iterator it_kinds;
00302   for ( it_kinds = d->kinds.begin() ; it_kinds != d->kinds.end(); ++it_kinds )
00303   {
00304     Resolvable::Kind kind = (*it_kinds);
00305     bool isthere = exists(dirForResolvableKind(kind));
00306     ok = ok && isthere;
00307   }
00308 
00309   // resolvable flags folder flags
00310   for ( it_kinds = d->kinds_flags.begin() ; it_kinds != d->kinds_flags.end(); ++it_kinds )
00311   {
00312     Resolvable::Kind kind = (*it_kinds);
00313     bool isthere = exists(dirForResolvableKindFlags(kind));
00314     ok = ok && isthere;
00315   }
00316 
00317   // named flags
00318   bool nmthere = exists(dirForNamedFlags());
00319   ok = ok && nmthere;
00320 
00321   Pathname sourcesdir = d->root + ZYPP_DB_DIR + "/sources";
00322   bool srcthere = PathInfo(sourcesdir).isExist();
00323   ok = ok && srcthere;
00324 
00325   if (srcthere && fixperms)
00326   {
00327     MIL << "Making " << sourcesdir << " not readable by others (0700)" << std::endl;
00328     filesystem::chmod( sourcesdir, 0700);
00329   }
00330 
00331   return ok;
00332 }
00333 
00334 void
00335 XMLFilesBackend::initBackend()
00336 {
00337   // all directories are 755 except the sources directory which can contain passwords
00338   // in urls.
00339 
00340   Pathname topdir = d->root + Pathname(ZYPP_DB_DIR);
00341   DBG << "Creating directory structure " << topdir << std::endl;
00342 
00343   if (0 != assert_dir(topdir, 0755))
00344       ZYPP_THROW(Exception("Cannot create XMLBackend db directory " + topdir.asString()));
00345 
00346   // create dir for resolvables
00347   std::set<Resolvable::Kind>::const_iterator it_kinds;
00348   for ( it_kinds = d->kinds.begin() ; it_kinds != d->kinds.end(); ++it_kinds )
00349   {
00350     Resolvable::Kind kind = (*it_kinds);
00351     Pathname p(dirForResolvableKind(kind));
00352     if (0 != assert_dir(p, 0755))
00353       ZYPP_THROW(Exception("Cannot create directory " + p.asString()));
00354     else
00355       MIL << "Created " << p.asString() << std::endl;
00356   }
00357 
00358   // create dir for resolvables flags
00359   for ( it_kinds = d->kinds_flags.begin() ; it_kinds != d->kinds_flags.end(); ++it_kinds )
00360   {
00361     Resolvable::Kind kind = (*it_kinds);
00362     Pathname p(dirForResolvableKindFlags(kind));
00363     if (0 != assert_dir(p, 0755))
00364       ZYPP_THROW(Exception("Cannot create directory " + p.asString()));
00365     else
00366       MIL << "Created " << p.asString() << std::endl;
00367   }
00368 
00369   // dir for named flags
00370   Pathname namedflags(dirForNamedFlags());
00371   if (0 != assert_dir(namedflags, 0755))
00372     ZYPP_THROW(Exception("Cannot create directory " + namedflags.asString()));
00373   else
00374     MIL << "Created " << namedflags.asString() << std::endl;
00375 
00376   // create dir for source list
00377   Pathname source_p = d->root + Pathname(ZYPP_DB_DIR) + Pathname("/sources/");
00378   if (0 != assert_dir(source_p, 0700))
00379     ZYPP_THROW(Exception("Cannot create directory " + source_p.asString()));
00380   else
00381     MIL << "Created " << source_p.asString() << std::endl;
00382 }
00383 
00384 void XMLFilesBackend::setRandomFileNameEnabled( bool enabled )
00385 {
00386   d->randomFileName = enabled;
00387 }
00388 
00389 std::string
00390 XMLFilesBackend::dirForResolvableKind( Resolvable::Kind kind ) const
00391 {
00392   std::string dir;
00393   dir += Pathname( d->root + Pathname(ZYPP_DB_DIR) + Pathname(resolvableKindToString(kind, true)) ).asString();
00394   return dir;
00395 }
00396 
00397 std::string
00398 XMLFilesBackend::dirForResolvableKindFlags( Resolvable::Kind kind ) const
00399 {
00400   std::string dir;
00401   dir += Pathname( d->root + Pathname(ZYPP_DB_DIR) + Pathname("flags") + Pathname(resolvableKindToString(kind, true)) ).asString();
00402   return dir;
00403 }
00404 
00405 std::string
00406 XMLFilesBackend::dirForNamedFlags() const
00407 {
00408   std::string dir;
00409   dir += Pathname( d->root + Pathname(ZYPP_DB_DIR) + Pathname("named-flags")).asString();
00410   return dir;
00411 }
00412 
00413 std::string
00414 XMLFilesBackend::dirForResolvable( ResObject::constPtr resolvable ) const
00415 {
00416   return dirForResolvableKind(resolvable->kind());
00417 }
00418 
00419 std::string
00420 XMLFilesBackend::dirForResolvableFlags( ResObject::constPtr resolvable ) const
00421 {
00422   return dirForResolvableKindFlags(resolvable->kind());
00423 }
00424 
00425 std::string
00426 XMLFilesBackend::fileNameForNVR( const NVR &nvr ) const
00427 {
00428   std::string filename;
00429   filename = nvr.name;
00430   if ( nvr.edition != Edition::noedition )
00431   {
00432      filename += "-" + nvr.edition.asString();
00433   }
00434   // get rid of spaces and other characters
00435   std::stringstream filename_stream(filename);
00436   std::string filename_encoded = Digest::digest("MD5", filename_stream);
00437   return filename_encoded;
00438 }
00439 
00440 std::string
00441 XMLFilesBackend::fileNameForResolvable( ResObject::constPtr resolvable ) const
00442 {
00443   return fileNameForNVR( NVR( resolvable->name(), resolvable->edition() ) );
00444 }
00445 
00446 std::string
00447 XMLFilesBackend::fullPathForResolvable( ResObject::constPtr resolvable ) const
00448 {
00449   return path( path(dirForResolvable(resolvable)) / path(fileNameForResolvable(resolvable))).string();
00450 }
00451 
00452 std::string
00453 XMLFilesBackend::fullPathForNamedFlags( const std::string &key ) const
00454 {
00455   std::stringstream key_stream(key);
00456   std::string key_encoded = Digest::digest("MD5", key_stream);
00457   return path( path(dirForNamedFlags()) / path(key_encoded)).string();
00458 }
00459 
00460 std::string
00461 XMLFilesBackend::fullPathForResolvableFlags( ResObject::constPtr resolvable ) const
00462 {
00463   // flags are in a hidden file with the same name
00464   return path( path(dirForResolvableFlags(resolvable)) / path(fileNameForResolvable(resolvable))).string();
00465 }
00466 
00467 void
00468 XMLFilesBackend::setObjectFlag( ResObject::constPtr resolvable, const std::string &flag )
00469 {
00470   std::set<std::string> flags = objectFlags(resolvable);
00471   flags.insert(flag);
00472   writeObjectFlags(resolvable, flags);
00473 }
00474 
00475 void
00476 XMLFilesBackend::removeObjectFlag( ResObject::constPtr resolvable, const std::string &flag )
00477 {
00478   std::set<std::string> flags = objectFlags(resolvable);
00479   flags.erase(flag);
00480   writeObjectFlags(resolvable, flags);
00481 }
00482 
00483 void
00484 XMLFilesBackend::writeObjectFlags( ResObject::constPtr resolvable, const std::set<std::string> &flags )
00485 {
00486   std::string filename = fullPathForResolvableFlags(resolvable);
00487   writeFlagsInFile( filename, flags );
00488   MIL << "Wrote " << flags.size() << " flags for " << resolvable->name() << " " << resolvable->edition() << std::endl;
00489 }
00490 
00491 std::set<std::string>
00492 XMLFilesBackend::objectFlags( ResObject::constPtr resolvable ) const
00493 {
00494   std::string filename = fullPathForResolvableFlags(resolvable);
00495   return flagsFromFile(filename);
00496 }
00497 
00498 bool
00499 XMLFilesBackend::doesObjectHasFlag( ResObject::constPtr resolvable, const std::string &flag ) const
00500 {
00501   std::set<std::string> flags = objectFlags(resolvable);
00502   return (find(flags.begin(), flags.end(), flag) != flags.end());
00503 }
00504 
00506 // Named Flags API
00508 
00509 void
00510 XMLFilesBackend::setFlag( const std::string &key, const std::string &flag )
00511 {
00512   std::set<std::string> _flags = flags(key);
00513   _flags.insert(flag);
00514   writeFlags(key, _flags);
00515 }
00516 
00517 void
00518 XMLFilesBackend::removeFlag( const std::string &key, const std::string &flag )
00519 {
00520   std::set<std::string> _flags = flags(key);
00521   _flags.erase(flag);
00522   writeFlags(key, _flags);
00523 }
00524 
00525 std::set<std::string>
00526 XMLFilesBackend::flags( const std::string &key ) const
00527 {
00528   std::string filename = fullPathForNamedFlags(key);
00529   return flagsFromFile(filename);
00530 }
00531 
00532 bool
00533 XMLFilesBackend::hasFlag( const std::string &key, const std::string &flag ) const
00534 {
00535   std::set<std::string> _flags = flags(key);
00536   return (find(_flags.begin(), _flags.end(), flag) != _flags.end());
00537 }
00538 
00539 void
00540 XMLFilesBackend::writeFlags( const std::string &key, const std::set<std::string> &pflags )
00541 {
00542   std::string filename = fullPathForNamedFlags(key);
00543   writeFlagsInFile( filename, pflags );
00544   MIL << "Wrote " << pflags.size() << " flags for " << key << std::endl;
00545 }
00546 
00548 // Common functions for both named and resolvable flags
00550 
00551 void
00552 XMLFilesBackend::writeFlagsInFile( const std::string &filename, const std::set<std::string> &pflags )
00553 {
00554   std::ofstream file(filename.c_str());
00555   if (!file) {
00556     ZYPP_THROW (Exception( "Can't open " + filename ) );
00557   }
00558 
00559   try
00560   {
00561     for ( std::set<std::string>::const_iterator it = pflags.begin(); it != pflags.end(); it++)
00562     {
00563       // dont save empty strings
00564       if ( *it == std::string() )
00565         continue;
00566       else
00567         file << *it << std::endl;
00568     }
00569     file << std::endl;
00570     MIL << "Wrote " << pflags.size() << " flags in " << filename << std::endl;
00571   }
00572   catch( std::exception &e )
00573   {
00574     ZYPP_THROW (Exception( "Can't write flags to store") );
00575   }
00576   updateTimestamp();
00577 }
00578 
00579 std::set<std::string>
00580 XMLFilesBackend::flagsFromFile( const std::string &filename ) const
00581 {
00582   std::set<std::string> _flags;
00583   // do we have previous saved flags?
00584   if (!exists(path(filename)))
00585     return _flags;
00586 
00587   std::ifstream file(filename.c_str());
00588   if (!file) {
00589     ZYPP_THROW (Exception( "Can't open " + filename ) );
00590   }
00591 
00592   std::string buffer;
00593   while(file && !file.eof())
00594   {
00595     getline(file, buffer);
00596     if (buffer == std::string())
00597       continue;
00598 
00599     _flags.insert(buffer);
00600   }
00601   //MIL << "Read " << flags.size() << " flags for " << resolvable->name() << " " << resolvable->edition() << std::endl;
00602   return _flags;
00603 }
00604 
00605 void
00606 XMLFilesBackend::updateTimestamp() const
00607 {
00608   Pathname filename = d->root + Pathname(ZYPP_DB_DIR) + "timestamp";
00609   std::ofstream file(filename.asString().c_str(), std::ios::out);
00610   if (!file)
00611   {
00612     ZYPP_THROW (Exception( "Can't open timestamp file " + filename.asString() ) );
00613   }
00614   file.close();
00615 }
00616 
00618 // Resolvables storage
00620 
00621 void
00622 XMLFilesBackend::storeObject( ResObject::constPtr resolvable )
00623 {
00624   // only ignore if it is not a supported resolvable kind
00625   std::set<Resolvable::Kind>::const_iterator it;
00626   it = find(d->kinds.begin(), d->kinds.end(), resolvable->kind() );
00627   if (it == d->kinds.end())
00628   {
00629     ERR << "This backend was not designed to store resolvable of kind " << resolvableKindToString(resolvable->kind()) << ", ignoring..." << std::endl;
00630     return;
00631   }
00632 
00633   std::string xml = castedToXML(resolvable);
00634   std::string filename = fullPathForResolvable(resolvable);
00635   //DBG << std::endl << xml << std::endl;
00636   std::ofstream file;
00637   //DBG << filename << std::endl;
00638   try
00639   {
00640     file.open(filename.c_str());
00641     file << xml;
00642     file.close();
00643   }
00644   catch(std::exception &e)
00645   {
00646     ERR << "Error saving resolvable " << resolvable << std::endl;
00647     ZYPP_THROW(Exception(e.what()));
00648   }
00649   updateTimestamp();
00650 }
00651 
00652 void
00653 XMLFilesBackend::deleteFileObject( const Pathname &filename ) const
00654 {
00655   try
00656   {
00657     int ret = filesystem::unlink(Pathname(filename));
00658     if ( ret != 0 )
00659     {
00660       ERR << "Error removing resolvable file " << filename << std::endl;
00661       ZYPP_THROW(Exception("Error deleting " + filename.asString()));
00662     }
00663     updateTimestamp();
00664   }
00665   catch(std::exception &e)
00666   {
00667     ERR << "Error removing resolvable file " << filename << std::endl;
00668     ZYPP_THROW(Exception(e.what()));
00669   }
00670 }
00671 
00672 void
00673 XMLFilesBackend::deleteObject( ResObject::constPtr resolvable )
00674 {
00675   // only ignore if it is not a supported resolvable kind
00676   std::set<Resolvable::Kind>::const_iterator it;
00677   it = find(d->kinds.begin(), d->kinds.end(), resolvable->kind() );
00678   if (it == d->kinds.end())
00679   {
00680     ERR << "This backend was not designed to store resolvable of kind " << resolvableKindToString(resolvable->kind()) << ", ignoring..." << std::endl;
00681     return;
00682   }
00683 
00684   // only remove the file
00685   try
00686   {
00687     deleteFileObject( fullPathForResolvable(resolvable) );
00688   }
00689   catch ( const Exception &e )
00690   {
00691     ERR << "Error removing resolvable " << resolvable << std::endl;
00692     ZYPP_RETHROW(e);
00693   }
00694 }
00695 
00696 std::list<ResObject::Ptr> XMLFilesBackend::resolvablesFromFile( std::string file_path, Resolvable::Kind kind ) const
00697 {
00698   MIL << "[" << resolvableKindToString( kind, false ) << "] - " << file_path << std::endl;
00699   std::list<ResObject::Ptr> resolvables;
00700   std::ifstream res_file(file_path.c_str());
00701   if ( kind == ResTraits<zypp::Patch>::kind )
00702   {
00703     // a patch file can contain more than one patch, but we store only
00704     // one patch, so we break at the first
00705     // FIXME how can we avoid creating this for every object?
00706     try {
00707     XMLPatchParser iter(res_file,"");
00708     for (; !iter.atEnd(); ++iter)
00709     {
00710       Patch::Ptr patch = createPatch(**iter);
00711       resolvables.push_back(patch);
00712       Patch::AtomList atoms = patch->atoms();
00713       for (Patch::AtomList::iterator at = atoms.begin(); at != atoms.end(); at++)
00714         resolvables.push_back(*at);
00715 
00716       break;
00717     }
00718     }
00719     catch (const Exception & excpt_r) {
00720         ZYPP_CAUGHT( excpt_r );
00721         WAR << "Skipping invalid patch file " << file_path << endl;
00722     }
00723   }
00724   else if ( kind == ResTraits<zypp::Product>::kind )
00725   {
00726     XMLProductParser iter(res_file,"");
00727     for (; !iter.atEnd(); ++iter)
00728     {
00729       resolvables.push_back(createProduct(**iter));
00730       break;
00731     }
00732   }
00733   else if ( kind == ResTraits<zypp::Selection>::kind )
00734   {
00735     XMLPatternParser iter(res_file,"");
00736     for (; !iter.atEnd(); ++iter)
00737     {
00738       resolvables.push_back(createSelection(**iter));
00739       break;
00740     }
00741   }
00742   else if ( kind == ResTraits<zypp::Pattern>::kind )
00743   {
00744     XMLPatternParser iter(res_file,"");
00745     for (; !iter.atEnd(); ++iter)
00746     {
00747       resolvables.push_back(createPattern(**iter));
00748       break;
00749     }
00750   }
00751   else if ( kind == ResTraits<zypp::Language>::kind )
00752   {
00753     XMLLanguageParser iter(res_file,"");
00754     for (; !iter.atEnd(); ++iter)
00755     {
00756       resolvables.push_back(createLanguage(**iter));
00757       break;
00758     }
00759   }
00760   else
00761   {
00762     /* nothing for now */
00763   }
00764   return resolvables;
00765 }
00766 
00767 std::list<ResObject::Ptr>
00768 XMLFilesBackend::storedObjects() const
00769 {
00770   DBG << std::endl;
00771   std::list<ResObject::Ptr> objects;
00772 
00773   std::set<Resolvable::Kind>::const_iterator it_kinds;
00774   for ( it_kinds = d->kinds.begin() ; it_kinds != d->kinds.end(); ++it_kinds )
00775   {
00776     Resolvable::Kind kind = (*it_kinds);
00777     std::list<ResObject::Ptr> objects_for_kind = storedObjects(kind);
00778     std::list<ResObject::Ptr>::iterator it;
00779     for( it = objects_for_kind.begin(); it != objects_for_kind.end(); ++it)
00780     {
00781       //DBG << "adding objects back" << std::endl;
00782       objects.push_back(*it);
00783     }
00784   }
00785   return objects;
00786 }
00787 
00788 std::list<ResObject::Ptr>
00789 XMLFilesBackend::storedObjects(const Resolvable::Kind kind) const
00790 {
00791   std::list<ResObject::Ptr> objects;
00792   Pathname dir_path(dirForResolvableKind(kind));
00793   DBG << "Reading objects of kind " << resolvableKindToString(kind) << " in " << dir_path << std::endl;
00794   // return empty list if the dir does not exist
00795   if ( ! PathInfo( dir_path ).isExist() )
00796   {
00797     ERR << "path " << dir_path << " does not exists. Required to read objects of kind " << resolvableKindToString(kind) << std::endl;
00798     return std::list<ResObject::Ptr>();
00799   }
00800 
00801   list<string> files;
00802   filesystem::readdir( files, dir_path, false /* ignore hidden .name files */ );
00803   
00804   for ( list<string>::const_iterator it = files.begin(); it != files.end(); ++it )
00805   {
00806     Pathname curr_file = dir_path + (*it);
00807     DBG << "[" << resolvableKindToString( kind, false ) << "] - " << curr_file << std::endl;
00808     std::list<ResObject::Ptr> objects_for_file;
00809     objects_for_file = resolvablesFromFile( curr_file.asString(), kind);
00810     for ( std::list<ResObject::Ptr>::iterator it = objects_for_file.begin(); it != objects_for_file.end(); ++it)
00811       objects.push_back(*it);
00812   }
00813   
00814   MIL << "done reading " <<  objects.size() << " stored objects for file of kind " << resolvableKindToString(kind) << std::endl;
00815   return objects;
00816 }
00817 
00818 std::list<ResObject::Ptr>
00819 XMLFilesBackend::storedObjects(const Resolvable::Kind kind, const std::string & name, bool partial_match) const
00820 {
00821   std::list<ResObject::Ptr> result;
00822   std::list<ResObject::Ptr> all;
00823   all = storedObjects(kind);
00824   std::list<ResObject::Ptr>::const_iterator it;
00825   for( it = all.begin(); it != all.end(); ++it)
00826   {
00827     ResObject::Ptr item = *it;
00828     if (item->name() == name )
00829       result.push_back(item);
00830   }
00831   MIL << "done reading stored objects of kind " << resolvableKindToString(kind) << " and keyword [" << name <<"]" << std::endl;
00832   return result;
00833 }
00834 
00835 Patch::Ptr
00836 XMLFilesBackend::createPatch( const zypp::parser::xmlstore::XMLPatchData & parsed ) const
00837 {
00838   try
00839   {
00840     detail::ResImplTraits<XMLPatchImpl>::Ptr impl(new XMLPatchImpl());
00841     impl->_patch_id = parsed.patchId;
00842     impl->_timestamp = str::strtonum<time_t>(parsed.timestamp);
00843     impl->_category = parsed.category;
00844     impl->_reboot_needed = parsed.rebootNeeded;
00845     impl->_affects_pkg_manager = parsed.packageManager;
00846     // impl._atoms -> std::list<shared_ptr<YUMPatchAtom> > parsed.atoms */
00847 
00848     impl->_summary = parsed.summary;
00849     impl->_description = parsed.summary;
00850 
00851     impl->_install_notify = parsed.install_notify;
00852     impl->_delete_notify = parsed.delete_notify;
00853     impl->_license_to_confirm = parsed.license_to_confirm;
00854     impl->_size = parsed.size;
00855     impl->_archive_size = parsed.archive_size;
00856     impl->_install_only = parsed.install_only;
00857     impl->_build_time = parsed.build_time;
00858     impl->_install_time = parsed.install_time;
00859 
00860     Arch arch;
00861     if (!parsed.arch.empty())
00862       arch = Arch(parsed.arch);
00863 
00864     // Collect basic Resolvable data
00865     NVRAD dataCollect( parsed.name,
00866                        Edition( parsed.ver, parsed.rel, parsed.epoch ), arch,
00867                        createDependencies(parsed, ResTraits<Patch>::kind) );
00868     Patch::Ptr patch = detail::makeResolvableFromImpl( dataCollect, impl );
00869     CapFactory _f;
00870 
00871     //MIL << parsed.atoms.size() << " to process" << std::endl;
00872 
00873     // now process the atoms
00874     ResObject::Ptr atom;
00875     for (std::list<XMLPatchAtomData_Ptr >::const_iterator it = parsed.atoms.begin(); it != parsed.atoms.end(); it++)
00876     {
00877       switch ((*it)->atomType())
00878       {
00879         case XMLPatchAtomData::Atom:
00880         {
00881           // atoms are mostly used for packages
00882           // we dont create a package resolvable and then add it to the atoms list, because we
00883           // dont know if the package is in the pool or not. It is different to Scripts and Messages
00884           // that are actually contributed to the Patch itself, instead we create and atom, make
00885           // the patch require the atom, the atom require and freshens the package.
00886 
00887           // get the parsed patch atom data
00888           XMLPatchAtomData_Ptr atom_data = dynamic_pointer_cast<XMLPatchAtomData>(*it);
00889           atom = createAtom(*atom_data);
00890           impl->_atoms.push_back(atom);
00891           break;
00892         }
00893         case XMLPatchAtomData::Message:
00894         {
00895           XMLPatchMessageData_Ptr message_data = dynamic_pointer_cast<XMLPatchMessageData>(*it);
00896           atom = createMessage(*message_data);
00897           impl->_atoms.push_back(atom);
00898           break;
00899         }
00900         case XMLPatchAtomData::Script:
00901         {
00902           XMLPatchScriptData_Ptr script_data = dynamic_pointer_cast<XMLPatchScriptData>(*it);
00903           atom = createScript(*script_data);
00904           impl->_atoms.push_back(atom);
00905           break;
00906         }
00907         default:
00908           ERR << "Unknown type of atom" << endl;
00909       }
00910       // the patch should depends on its atoms, so we inject a requires on the just created atom resolvable
00911       Capability cap( _f.parse(atom->kind(), atom->name(), Rel::EQ, atom->edition() ));
00912       patch->injectRequires(cap);
00913     }
00914     return patch;
00915   }
00916   catch (const Exception & excpt_r)
00917   {
00918     ZYPP_CAUGHT(excpt_r);
00919     ZYPP_THROW(Exception("Cannot create patch object"));
00920   }
00921   return 0L;
00922 }
00923 
00924 Atom::Ptr
00925 XMLFilesBackend::createAtom( const zypp::parser::xmlstore::XMLPatchAtomData & parsed ) const
00926 {
00927   try
00928   {
00929     detail::ResImplTraits<XMLAtomImpl>::Ptr impl(new XMLAtomImpl());
00930 
00931     Arch arch;
00932     if (!parsed.arch.empty())
00933       arch = Arch(parsed.arch);
00934 
00935     // Collect basic Resolvable data
00936     NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), arch, createDependencies(parsed, ResTraits<Atom>::kind) );
00937 
00938     impl->_summary = parsed.summary;
00939     impl->_description = parsed.summary;
00940 
00941     impl->_install_notify = parsed.install_notify;
00942     impl->_delete_notify = parsed.delete_notify;
00943     impl->_license_to_confirm = parsed.license_to_confirm;
00944     impl->_size = parsed.size;
00945     impl->_archive_size = parsed.archive_size;
00946     impl->_install_only = parsed.install_only;
00947     impl->_build_time = parsed.build_time;
00948     impl->_install_time = parsed.install_time;
00949 
00950     Atom::Ptr atom = detail::makeResolvableFromImpl( dataCollect, impl);
00951     return atom;
00952   }
00953   catch (const Exception & excpt_r)
00954   {
00955     ZYPP_CAUGHT(excpt_r);
00956     ZYPP_THROW(Exception("Cannot create atom object"));
00957   }
00958   return 0L;
00959 }
00960 
00961 Message::Ptr
00962 XMLFilesBackend::createMessage( const zypp::parser::xmlstore::XMLPatchMessageData & parsed ) const
00963 {
00964   try
00965   {
00966     detail::ResImplTraits<XMLMessageImpl>::Ptr impl(new XMLMessageImpl());
00967     impl->_text = parsed.text;
00968 
00969     Arch arch;
00970     if (!parsed.arch.empty())
00971       arch = Arch(parsed.arch);
00972 
00973     impl->_summary = parsed.summary;
00974     impl->_description = parsed.summary;
00975 
00976     impl->_install_notify = parsed.install_notify;
00977     impl->_delete_notify = parsed.delete_notify;
00978     impl->_license_to_confirm = parsed.license_to_confirm;
00979     impl->_size = parsed.size;
00980     impl->_archive_size = parsed.archive_size;
00981     impl->_install_only = parsed.install_only;
00982     impl->_build_time = parsed.build_time;
00983     impl->_install_time = parsed.install_time;
00984 
00985     // Collect basic Resolvable data
00986     NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), arch, createDependencies(parsed, ResTraits<Message>::kind) );
00987     Message::Ptr message = detail::makeResolvableFromImpl( dataCollect, impl);
00988     return message;
00989   }
00990   catch (const Exception & excpt_r)
00991   {
00992     ZYPP_CAUGHT(excpt_r);
00993     ZYPP_THROW(Exception("Cannot create message object"));
00994   }
00995   return 0L;
00996 }
00997 
00998 Script::Ptr
00999 XMLFilesBackend::createScript(const zypp::parser::xmlstore::XMLPatchScriptData & parsed ) const
01000 {
01001   try
01002   {
01003     detail::ResImplTraits<XMLScriptImpl>::Ptr impl(new XMLScriptImpl());
01004 
01005     ofstream file;
01006     file.open(impl->_do_script->path().asString().c_str());
01007 
01008     if ( ! file )
01009       ZYPP_THROW(Exception(N_("Can't write the patch script to a temporary file.")));
01010 
01011     file << parsed.do_script;;
01012     file.close();
01013 
01014     file.open(impl->_undo_script->path().asString().c_str());
01015     if ( ! file )
01016       ZYPP_THROW(Exception(N_("Can't write the patch script to a temporary file.")));
01017 
01018     file << parsed.undo_script;;
01019     file.close();
01020 
01021     Arch arch;
01022     if (!parsed.arch.empty())
01023       arch = Arch(parsed.arch);
01024 
01025     impl->_summary = parsed.summary;
01026     impl->_description = parsed.summary;
01027 
01028     impl->_install_notify = parsed.install_notify;
01029     impl->_delete_notify = parsed.delete_notify;
01030     impl->_license_to_confirm = parsed.license_to_confirm;
01031     impl->_size = parsed.size;
01032     impl->_archive_size = parsed.archive_size;
01033     impl->_install_only = parsed.install_only;
01034     impl->_build_time = parsed.build_time;
01035     impl->_install_time = parsed.install_time;
01036 
01037     // Collect basic Resolvable data
01038     NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), arch, createDependencies(parsed, ResTraits<Script>::kind));
01039     Script::Ptr script = detail::makeResolvableFromImpl( dataCollect, impl );
01040     return script;
01041   }
01042   catch (const Exception & excpt_r)
01043   {
01044     ZYPP_CAUGHT(excpt_r);
01045     ZYPP_THROW(Exception("Cannot create script object"));
01046   }
01047   catch (const std::exception & excpt_r)
01048   {
01049     ERR << excpt_r.what() << endl;
01050     ZYPP_THROW(Exception("Cannot create script object"));
01051   }
01052   return 0L;
01053 }
01054 
01055 Language::Ptr
01056 XMLFilesBackend::createLanguage( const zypp::parser::xmlstore::XMLLanguageData & parsed ) const
01057 {
01058   try
01059   {
01060     return Language::installedInstance( Locale(parsed.name) );
01061   }
01062   catch (const Exception & excpt_r)
01063   {
01064     ZYPP_CAUGHT(excpt_r);
01065     ZYPP_THROW(Exception("Cannot create language object"));
01066   }
01067   return 0L;
01068 }
01069 
01070 
01071 Product::Ptr
01072 XMLFilesBackend::createProduct( const zypp::parser::xmlstore::XMLProductData & parsed ) const
01073 {
01074   try
01075   {
01076     detail::ResImplTraits<XMLProductImpl>::Ptr impl(new XMLProductImpl());
01077     
01078     Edition parser_edition = ( parsed.parser_version.empty() ? Edition::noedition : Edition(parsed.parser_version) );
01079     
01080     impl->_summary = parsed.summary;
01081     impl->_description = parsed.summary;
01082 
01083     impl->_install_notify = parsed.install_notify;
01084     impl->_delete_notify = parsed.delete_notify;
01085     impl->_license_to_confirm = parsed.license_to_confirm;
01086     impl->_size = parsed.size;
01087     impl->_archive_size = parsed.archive_size;
01088     impl->_install_only = parsed.install_only;
01089     impl->_build_time = parsed.build_time;
01090     impl->_install_time = parsed.install_time;
01091 
01092     impl->_category = parsed.type;
01093     impl->_short_name = parsed.short_name;
01094     impl->_dist_name = parsed.dist_name;
01095     impl->_dist_version = parsed.dist_version;
01096 
01097     if ( parsed.releasenotesurl.size() > 0 )
01098       impl->_release_notes_url = parsed.releasenotesurl;
01099     else
01100       impl->_release_notes_url = Url();
01101 
01102     // update_urls
01103     list<string> update_urls = parsed.update_urls;
01104     for ( list<string>::const_iterator it = update_urls.begin(); it != update_urls.end(); ++it )
01105     {
01106       try
01107       {
01108         Url u(*it);
01109         impl->_update_urls.push_back (u);
01110       }
01111       catch ( const Exception &e )
01112       {
01113         ZYPP_THROW(Exception("Error parsing update url: " + e.msg()));
01114       }      
01115     }
01116 
01117     // extra_urls
01118     list<string> extra_urls = parsed.extra_urls;
01119     for ( list<string>::const_iterator it = extra_urls.begin(); it != extra_urls.end(); ++it )
01120     {
01121       try
01122       {
01123         Url u(*it);
01124         impl->_extra_urls.push_back (u);
01125       }
01126       catch ( const Exception &e )
01127       {
01128         ZYPP_THROW(Exception("Error parsing extra url: " + e.msg()));
01129       }      
01130     }
01131     
01132     // extra_urls
01133     list<string> optional_urls = parsed.optional_urls;
01134     for ( list<string>::const_iterator it = optional_urls.begin(); it != optional_urls.end(); ++it )
01135     {
01136       try
01137       {
01138         Url u(*it);
01139         impl->_optional_urls.push_back (u);
01140       }
01141       catch ( const Exception &e )
01142       {
01143         ZYPP_THROW(Exception("Error parsing optional url: " + e.msg()));
01144       }      
01145     }
01146     
01147     impl->_flags = parsed.flags;
01148 
01149     Arch arch;
01150     if (!parsed.arch.empty())
01151       arch = Arch(parsed.arch);
01152 
01153     Edition prod_edition( parsed.ver, parsed.rel, parsed.epoch );
01154     string prod_name(parsed.name);
01155     // check for product name to see if it was written with distname
01156     // as name as part of https://bugzilla.novell.com/show_bug.cgi?id=205392
01157     bool save_new_product_again_workaround = false;
01158     if ( parser_edition == Edition::noedition )
01159     {
01160       MIL << "Product " << parsed.name << " " << prod_edition << " possibly suffers from bug #205392. checking..." << endl;
01161       PRODUCT_TABLE_ENTRY *all_products = products_table();
01162       while ( all_products->dist_name != 0L )
01163       {
01164         //MIL << "Checking " << parsed.name << " " << prod_edition << " with " << all_products->dist_name << " " << all_products->dist_version << endl;
01165         if ( ( parsed.name == all_products->dist_name ) && ( prod_edition.asString() == all_products->dist_version ) )
01166         {
01167           MIL << "[ATTENTION] Detected bug #205392. Product " << parsed.name << " " << prod_edition << " will be changed to " << all_products->product_name << " " << all_products->product_version << std::endl;
01168           
01169           // save pathname of the old wrong product
01170           Pathname wrong_product = Pathname(dirForResolvableKind(ResTraits<zypp::Product>::kind)) + fileNameForNVR( NVR( parsed.name, prod_edition) );
01171           
01172           // ok, potentially this is a wrong product, well, IT IS!
01173           // overwrte those here as they are used in dataCollect
01174           prod_name = string(all_products->product_name);
01175           prod_edition = Edition(all_products->product_version);
01176           
01177           // those were already set, so reset them.
01178           impl->_dist_name = all_products->dist_name;
01179           impl->_dist_version = Edition(all_products->dist_version);
01180           
01181           // ok, now mark for save this product and delete the old one
01182           deleteFileObject( wrong_product );
01183           MIL << "Fix for bug #205392 Old product deleted." << std::endl;
01184           save_new_product_again_workaround = true;
01185           break;
01186         }
01187         ++all_products;
01188       }
01189       
01190     }
01191     
01192     // replace spaces to underscores
01193     std::replace(prod_name.begin(), prod_name.end(), ' ', '_');
01194     
01195     // Collect basic Resolvable data
01196     NVRAD dataCollect( prod_name, prod_edition, arch, createDependencies(parsed, ResTraits<Product>::kind) );
01197     Product::Ptr product = detail::makeResolvableFromImpl( dataCollect, impl );
01198     
01199     if ( save_new_product_again_workaround )
01200     {
01201       const_cast<XMLFilesBackend *>(this)->storeObject(product);
01202       MIL << "Fixed Product saved. Fix for bug #205392. complete" << std::endl;
01203     }
01204     
01205     return product;
01206   }
01207   catch (const Exception & excpt_r)
01208   {
01209     ZYPP_CAUGHT(excpt_r);
01210     ZYPP_THROW(Exception("Cannot create product object"));
01211   }
01212   return 0L;
01213 }
01214 
01215 Pattern::Ptr
01216 XMLFilesBackend::createPattern( const zypp::parser::xmlstore::XMLPatternData & parsed ) const
01217 {
01218   try
01219   {
01220     detail::ResImplTraits<XMLPatternImpl>::Ptr impl(new XMLPatternImpl());
01221 
01222     impl->_summary = parsed.summary;
01223     impl->_description = parsed.summary;
01224 
01225     impl->_install_notify = parsed.install_notify;
01226     impl->_delete_notify = parsed.delete_notify;
01227     impl->_license_to_confirm = parsed.license_to_confirm;
01228     impl->_size = parsed.size;
01229     impl->_archive_size = parsed.archive_size;
01230     impl->_install_only = parsed.install_only;
01231     impl->_build_time = parsed.build_time;
01232     impl->_install_time = parsed.install_time;
01233 
01234     impl->_user_visible = parsed.userVisible;
01235     impl->_default = ((parsed.default_ == "false" ) ? false : true );
01236     impl->_category = parsed.category;
01237     impl->_icon = parsed.icon;
01238     impl->_script = parsed.script;
01239 
01240     Arch arch;
01241     if (!parsed.arch.empty())
01242       arch = Arch(parsed.arch);
01243 
01244     // Collect basic Resolvable data
01245     NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), arch, createDependencies( parsed, ResTraits<Pattern>::kind));
01246     Pattern::Ptr pattern = detail::makeResolvableFromImpl( dataCollect, impl );
01247     return pattern;
01248   }
01249   catch (const Exception & excpt_r)
01250   {
01251     ZYPP_CAUGHT(excpt_r);
01252     ZYPP_THROW(Exception("Cannot create installation pattern object"));
01253   }
01254   return 0L;
01255 }
01256 
01257 Selection::Ptr
01258 XMLFilesBackend::createSelection( const zypp::parser::xmlstore::XMLPatternData & parsed ) const
01259 {
01260   try
01261   {
01262     detail::ResImplTraits<XMLSelectionImpl>::Ptr impl(new XMLSelectionImpl());
01263 
01264     impl->_summary = parsed.summary;
01265     impl->_description = parsed.summary;
01266 
01267     impl->_install_notify = parsed.install_notify;
01268     impl->_delete_notify = parsed.delete_notify;
01269     impl->_license_to_confirm = parsed.license_to_confirm;
01270     impl->_size = parsed.size;
01271     impl->_archive_size = parsed.archive_size;
01272     impl->_install_only = parsed.install_only;
01273     impl->_build_time = parsed.build_time;
01274     impl->_install_time = parsed.install_time;
01275 
01276     impl->_visible = parsed.userVisible;
01277     impl->_name = parsed.name;
01278     //impl->_default = ((parsed.default_ == "false" ) ? false : true );
01279     impl->_category = parsed.category;
01280 
01281     Arch arch;
01282     if (!parsed.arch.empty())
01283       arch = Arch(parsed.arch);
01284 
01285     // Collect basic Resolvable data
01286     NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), arch, createDependencies( parsed, ResTraits<Pattern>::kind));
01287     Selection::Ptr selection = detail::makeResolvableFromImpl( dataCollect, impl );
01288     return selection;
01289   }
01290   catch (const Exception & excpt_r)
01291   {
01292     ZYPP_CAUGHT(excpt_r);
01293     ZYPP_THROW(Exception("Cannot create installation selection object"));
01294   }
01295   return 0L;
01296 }
01297 
01298 Dependencies
01299 XMLFilesBackend::createDependencies( const zypp::parser::xmlstore::XMLResObjectData & parsed, const Resolvable::Kind my_kind ) const
01300 {
01301   Dependencies _deps;
01302   for (std::list<XMLDependency>::const_iterator it = parsed.provides.begin(); it != parsed.provides.end(); it++)
01303   {
01304     _deps[Dep::PROVIDES].insert(createCapability(*it, my_kind));
01305   }
01306   for (std::list<XMLDependency>::const_iterator it = parsed.conflicts.begin(); it != parsed.conflicts.end(); it++)
01307   {
01308     _deps[Dep::CONFLICTS].insert(createCapability(*it, my_kind));
01309   }
01310 
01311   for (std::list<XMLDependency>::const_iterator it = parsed.obsoletes.begin(); it != parsed.obsoletes.end(); it++)
01312   {
01313     _deps[Dep::OBSOLETES].insert(createCapability(*it, my_kind));
01314   }
01315 
01316   for (std::list<XMLDependency>::const_iterator it = parsed.freshens.begin(); it != parsed.freshens.end(); it++)
01317   {
01318     _deps[Dep::FRESHENS].insert(createCapability(*it, my_kind));
01319   }
01320 
01321   for (std::list<XMLDependency>::const_iterator it = parsed.recommends.begin(); it != parsed.recommends.end(); it++)
01322   {
01323     _deps[Dep::RECOMMENDS].insert(createCapability(*it, my_kind));
01324   }
01325 
01326   for (std::list<XMLDependency>::const_iterator it = parsed.suggests.begin(); it != parsed.suggests.end(); it++)
01327   {
01328     _deps[Dep::SUGGESTS].insert(createCapability(*it, my_kind));
01329   }
01330 
01331   for (std::list<XMLDependency>::const_iterator it = parsed.enhances.begin(); it != parsed.enhances.end(); it++)
01332   {
01333     _deps[Dep::ENHANCES].insert(createCapability(*it, my_kind));
01334   }
01335 
01336   for (std::list<XMLDependency>::const_iterator it = parsed.requires.begin(); it != parsed.requires.end(); it++)
01337   {
01338     _deps[Dep::REQUIRES].insert(createCapability(*it, my_kind));
01339   }
01340 
01341   for (std::list<XMLDependency>::const_iterator it = parsed.prerequires.begin(); it != parsed.prerequires.end(); it++)
01342   {
01343     _deps[Dep::PREREQUIRES].insert(createCapability(*it, my_kind));
01344   }
01345   return _deps;
01346 }
01347 
01348 Capability
01349 XMLFilesBackend::createCapability(const XMLDependency & dep, const Resolvable::Kind & my_kind) const
01350 {
01351   CapFactory _f;
01352   Resolvable::Kind _kind = dep.kind == "" ? my_kind : Resolvable::Kind(dep.kind);
01353   Capability cap;
01354   cap = _f.parse( _kind, dep.encoded );
01355   return cap;
01356 }
01357 
01359 //
01360 //      METHOD NAME : XMLFilesBackend::~XMLFilesBackend
01361 //      METHOD TYPE : Dtor
01362 //
01363 XMLFilesBackend::~XMLFilesBackend()
01364 {
01365   delete d;
01366 }
01367 
01369 //
01370 //      METHOD NAME : XMLFilesBackend::doTest()
01371 //      METHOD TYPE : Dtor
01372 //
01373 void XMLFilesBackend::doTest()
01374 {}
01375 
01376 /******************************************************************
01377 **
01378 **      FUNCTION NAME : operator<<
01379 **      FUNCTION TYPE : std::ostream &
01380 */
01381 std::ostream & operator<<( std::ostream & str, const XMLFilesBackend & obj )
01382 {
01383         return str;
01384 }
01385 
01387 // SOURCES API
01389 
01390 source::SourceInfoList
01391 XMLFilesBackend::storedSources() const
01392 {
01393   path source_p = path(d->root.asString()) / path(ZYPP_DB_DIR) / path ("sources");
01394   source::SourceInfoList sources;
01395   DBG << "Reading source cache in " << source_p.string() << std::endl;
01396   directory_iterator end_iter;
01397   // return empty list if the dir does not exist
01398   if ( !exists( source_p ) )
01399   {
01400     ERR << "path " << source_p.string() << " does not exists. Required to read source cache " << std::endl;
01401     return source::SourceInfoList();
01402   }
01403 
01404   for ( directory_iterator dir_itr( source_p ); dir_itr != end_iter; ++dir_itr )
01405   {
01406     DBG << "[source-list] - " << dir_itr->leaf() << std::endl;
01407     //sources.insert( sourceDataFromCacheFile( source_p + "/" + dir_itr->leaf() ) );
01408     std::string full_path = (source_p / dir_itr->leaf()).string();
01409     std::ifstream anIstream(full_path.c_str());
01410     zypp::parser::xmlstore::XMLSourceCacheParser iter(anIstream, "");
01411     for (; ! iter.atEnd(); ++iter) {
01412       source::SourceInfo data = **iter;
01413       sources.push_back(data);
01414     }
01415   }
01416   MIL << "done reading source cache" << std::endl;
01417   return sources;
01418 
01419 }
01420 
01421 void
01422 XMLFilesBackend::storeSource(const source::SourceInfo &data)
01423 {
01424   // serialize and save a file
01425   std::string xml = toXML(data);
01426   path source_p = path(d->root.asString()) / path(ZYPP_DB_DIR) / path ("sources");
01427 
01428   // generate a filename
01429   if (data.alias().size() == 0)
01430   {
01431     ZYPP_THROW(Exception("Cant save source with empty alias"));
01432   }
01433 
01434   //DBG << std::endl << xml << std::endl;
01435   std::ofstream file;
01436   //DBG << filename << std::endl;
01437   try
01438   {
01439     std::stringstream message_stream(data.alias());
01440     std::string full_path = (source_p / Digest::digest("MD5", message_stream)).string();
01441 
01442     file.open(full_path.c_str());
01443     file << xml;
01444     file.close();
01445   }
01446   catch ( std::exception &e )
01447   {
01448     ERR << "Error saving source " << data.alias() << " in the cache" << std::endl;
01449     ZYPP_THROW(Exception(e.what()));
01450   }
01451   updateTimestamp();
01452 }
01453 
01454 void
01455 XMLFilesBackend::deleteSource(const std::string &alias)
01456 {
01457   // just delete the files
01458   path source_p = path(d->root.asString()) / path(ZYPP_DB_DIR) / path ("sources");
01459   try
01460   {
01461     std::stringstream message_stream(alias);
01462     std::string full_path = (source_p / Digest::digest("MD5", message_stream)).string();
01463     remove(full_path);
01464   }
01465   catch ( std::exception &e )
01466   {
01467     ERR << "Error deleting source " << alias << " in the cache" << std::endl;
01468     ZYPP_THROW(Exception(e.what()));
01469   }
01470   updateTimestamp();
01471 }
01472 
01474 } // namespace storage
01477 } // namespace zypp

Generated on Tue Nov 28 16:49:34 2006 for zypp by  doxygen 1.5.0