1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file devel/devel.dmacvicar/XMLFilesBackend.cc
18 #include "zypp/base/Logger.h"
19 #include "zypp/base/Exception.h"
21 #include "zypp/CapFactory.h"
23 #include "zypp/target/store/xml/XMLPatchImpl.h"
24 #include "zypp/target/store/xml/XMLMessageImpl.h"
25 #include "zypp/target/store/xml/XMLScriptImpl.h"
26 #include "zypp/target/store/xml/XMLSelectionImpl.h"
27 #include "zypp/target/store/xml/XMLProductImpl.h"
36 #include <zypp/target/store/xml/XMLSourceCacheParser.h>
38 #include "boost/filesystem/operations.hpp" // includes boost/filesystem/path.hpp
39 #include "boost/filesystem/fstream.hpp" // ditto
41 #include "XMLFilesBackend.h"
42 #include "serialize.h"
46 #define ZYPP_DB_DIR "/var/lib/zypp_db"
49 using namespace boost::filesystem;
51 using namespace zypp::parser::yum;
53 ///////////////////////////////////////////////////////////////////
55 { /////////////////////////////////////////////////////////////////
57 { /////////////////////////////////////////////////////////////////
60 ///////////////////////////////////////////////////////////////////
62 // CLASS NAME : XMLFilesBackend::Private
64 ///////////////////////////////////////////////////////////////////
65 class XMLFilesBackend::Private
71 std::set<Resolvable::Kind> kinds;
75 ///////////////////////////////////////////////////////////////////
77 // CLASS NAME : XMLFilesBackend
79 ///////////////////////////////////////////////////////////////////
81 ///////////////////////////////////////////////////////////////////
83 // METHOD NAME : XMLFilesBackend::XMLFilesBackend
86 XMLFilesBackend::XMLFilesBackend(const Pathname &root) : Backend(root)
89 d->randomFileName = false;
91 // types of resolvables stored (supported)
92 d->kinds.insert(ResTraits<zypp::Patch>::kind);
93 //d->kinds.insert(ResTraits<zypp::Message>::kind);
94 //d->kinds.insert(ResTraits<zypp::Script>::kind);
95 d->kinds.insert(ResTraits<zypp::Selection>::kind);
96 d->kinds.insert(ResTraits<zypp::Product>::kind);
98 // check if the db exists
99 if (!isBackendInitialized())
101 DBG << "Database not initialized" << std::endl;
103 // should be initialized now...
104 if (!isBackendInitialized())
105 DBG << "Error, cant init database" << std::endl;
107 DBG << "Database initialized" << std::endl;
111 DBG << "Database already initialized" << std::endl;
115 // Taken from KApplication
116 int XMLFilesBackend::random() const
118 static bool init = false;
123 int fd = open("/dev/urandom", O_RDONLY);
124 if (fd < 0 || ::read(fd, &seed, sizeof(seed)) != sizeof(seed))
126 // No /dev/urandom... try something else.
128 seed = rand()+time(0);
130 if (fd >= 0) close(fd);
136 // Taken from KApplication
137 std::string XMLFilesBackend::randomString(int length) const
139 if (length <=0 ) return std::string();
141 std::string str; str.resize( length );
150 // so what if I work backwards?
157 XMLFilesBackend::isBackendInitialized() const
160 ok = ok && exists( ZYPP_DB_DIR );
161 std::set<Resolvable::Kind>::const_iterator it_kinds;
162 for ( it_kinds = d->kinds.begin() ; it_kinds != d->kinds.end(); ++it_kinds )
164 Resolvable::Kind kind = (*it_kinds);
165 ok = ok && exists(dirForResolvableKind(kind));
167 ok = ok && exists( path(d->root.asString()) / path(ZYPP_DB_DIR) / path ("source-cache") );
172 XMLFilesBackend::initBackend()
174 // FIXME duncan * handle exceptions
175 DBG << "Creating directory structure..." << std::endl;
178 path topdir = path(d->root.asString()) / path(ZYPP_DB_DIR);
180 create_directory(topdir);
181 MIL << "Created..." << topdir.string() << std::endl;
182 std::set<Resolvable::Kind>::const_iterator it_kinds;
183 for ( it_kinds = d->kinds.begin() ; it_kinds != d->kinds.end(); ++it_kinds )
185 Resolvable::Kind kind = (*it_kinds);
186 # warning "add exception handling here"
187 path p(topdir / path(resolvableKindToString(kind, true /* plural */)));
191 MIL << "Created..." << p.string() << std::endl;
194 // create source-cache
195 path source_p = path(d->root.asString()) / path(ZYPP_DB_DIR) / path ("source-cache");
196 if (!exists(source_p))
198 create_directory(source_p);
199 MIL << "Created..." << source_p.string() << std::endl;
202 catch(std::exception &e)
204 ZYPP_RETHROW(Exception(e.what()));
208 void XMLFilesBackend::setRandomFileNameEnabled( bool enabled )
210 d->randomFileName = enabled;
214 XMLFilesBackend::dirForResolvableKind( Resolvable::Kind kind ) const
217 dir += path( path(d->root.asString()) / path(ZYPP_DB_DIR) / path(resolvableKindToString(kind, true)) ).string();
222 XMLFilesBackend::dirForResolvable( Resolvable::constPtr resolvable ) const
224 return dirForResolvableKind(resolvable->kind());
228 XMLFilesBackend::fullPathForResolvable( Resolvable::constPtr resolvable ) const
230 std::string filename;
231 // only append edition if there is one
232 std::string suffix = ( (resolvable->edition() == Edition::noedition) ? std::string() : ("-" + resolvable->edition().version() + "-" + resolvable->edition().release()) );
233 filename = d->randomFileName ? randomString(40) : (resolvable->name() + suffix);
234 return path( path(dirForResolvable(resolvable)) / path(filename)).string();
238 XMLFilesBackend::storeObject( Resolvable::constPtr resolvable )
240 std::string xml = castedToXML(resolvable);
241 std::string filename = fullPathForResolvable(resolvable);
242 //DBG << std::endl << xml << std::endl;
244 //DBG << filename << std::endl;
247 file.open(filename.c_str());
251 catch(std::exception &e)
253 ERR << "Error saving resolvable " << resolvable << std::endl;
254 ZYPP_THROW(Exception(e.what()));
259 XMLFilesBackend::deleteObject( Resolvable::Ptr resolvable )
261 // only remove the file
262 std::string filename = fullPathForResolvable(resolvable);
265 remove(path(filename));
267 catch(std::exception &e)
269 ERR << "Error removing resolvable " << resolvable << std::endl;
270 ZYPP_THROW(Exception(e.what()));
274 Resolvable::Ptr XMLFilesBackend::resolvableFromFile( std::string file_path, Resolvable::Kind kind ) const
276 //DBG << "[" << resolvableKindToString( kind, false ) << "] - " << file_path << std::endl;
277 Resolvable::Ptr resolvable;
278 std::ifstream res_file(file_path.c_str());
279 if ( kind == ResTraits<zypp::Patch>::kind )
281 // a patch file can contain more than one patch, but we store only
282 // one patch, so we break at the first
283 // FIXME how can we avoid creating this for every object?
284 YUMPatchParser iter(res_file,"");
285 for (; !iter.atEnd(); ++iter)
287 DBG << "here..." << std::endl;
288 resolvable = createPatch(**iter);
292 else if ( kind == ResTraits<zypp::Product>::kind )
294 YUMProductParser iter(res_file,"");
295 for (; !iter.atEnd(); ++iter)
297 DBG << "here..." << std::endl;
298 resolvable = createProduct(**iter);
302 else if ( kind == ResTraits<zypp::Selection>::kind )
304 YUMGroupParser iter(res_file,"");
305 for (; !iter.atEnd(); ++iter)
307 DBG << "here..." << std::endl;
308 resolvable = createSelection(**iter);
313 else if ( kind == ResTraits<zypp::Message>::kind )
315 YUMMessageParser iter(res_file,"");
316 for (; !iter.atEnd(); ++iter)
318 DBG << "here..." << std::endl;
319 resolvable = createMessage(**iter);
323 else if ( kind == ResTraits<zypp::Script>::kind )
325 YUMScriptParser iter(res_file,"");
326 for (; !iter.atEnd(); ++iter)
328 DBG << "here..." << std::endl;
329 resolvable = createScript(**iter);
341 std::list<Resolvable::Ptr>
342 XMLFilesBackend::storedObjects() const
345 std::list<Resolvable::Ptr> objects;
347 std::set<Resolvable::Kind>::const_iterator it_kinds;
348 for ( it_kinds = d->kinds.begin() ; it_kinds != d->kinds.end(); ++it_kinds )
350 Resolvable::Kind kind = (*it_kinds);
351 std::list<Resolvable::Ptr> objects_for_kind = storedObjects(kind);
352 std::list<Resolvable::Ptr>::iterator it;
353 for( it = objects_for_kind.begin(); it != objects_for_kind.end(); ++it)
355 //DBG << "adding objects back" << std::endl;
356 objects.push_back(*it);
362 std::list<Resolvable::Ptr>
363 XMLFilesBackend::storedObjects(const Resolvable::Kind kind) const
365 std::list<Resolvable::Ptr> objects;
366 std::string dir_path = dirForResolvableKind(kind);
367 DBG << "Reading objects of kind " << resolvableKindToString(kind) << " in " << dir_path << std::endl;
368 directory_iterator end_iter;
369 // return empty list if the dir does not exist
370 if ( !exists( dir_path ) )
372 ERR << "path " << dir_path << " does not exists. Required to read objects of kind " << resolvableKindToString(kind) << std::endl;
373 return std::list<Resolvable::Ptr>();
376 for ( directory_iterator dir_itr( dir_path ); dir_itr != end_iter; ++dir_itr )
378 DBG << "[" << resolvableKindToString( kind, false ) << "] - " << dir_itr->leaf() << std::endl;
379 objects.push_back( resolvableFromFile( dir_path + "/" + dir_itr->leaf(), kind) );
381 MIL << "done reading stored objecs of kind " << resolvableKindToString(kind) << std::endl;
385 std::list<Resolvable::Ptr>
386 XMLFilesBackend::storedObjects(const Resolvable::Kind kind, const std::string & name, bool partial_match) const
388 std::list<Resolvable::Ptr> result;
389 std::list<Resolvable::Ptr> all;
390 all = storedObjects(kind);
391 std::list<Resolvable::Ptr>::const_iterator it;
392 for( it = all.begin(); it != all.end(); ++it)
394 Resolvable::Ptr item = *it;
395 if (item->name() == name )
396 result.push_back(item);
398 MIL << "done reading stored objecs of kind " << resolvableKindToString(kind) << " and keyword [" << name <<"]" << std::endl;
403 XMLFilesBackend::createPatch( const zypp::parser::yum::YUMPatchData & parsed ) const
407 shared_ptr<XMLPatchImpl> impl(new XMLPatchImpl());
408 impl->_patch_id = parsed.patchId;
409 impl->_timestamp = str::strtonum<time_t>(parsed.timestamp);
410 impl->_category = parsed.category;
411 impl->_reboot_needed = parsed.rebootNeeded;
412 impl->_affects_pkg_manager = parsed.packageManager;
413 // impl._atoms -> std::list<shared_ptr<YUMPatchAtom> > parsed.atoms */
415 impl->_summary = parsed.summary;
416 impl->_description = parsed.summary;
418 // Collect basic Resolvable data
419 NVRAD dataCollect( parsed.name,
420 Edition( parsed.ver, parsed.rel, parsed.epoch ), Arch_noarch,
421 createDependencies(parsed, ResTraits<Patch>::kind) );
422 Patch::Ptr patch = detail::makeResolvableFromImpl( dataCollect, impl );
425 catch (const Exception & excpt_r)
427 ERR << excpt_r << endl;
428 throw "Cannot create patch object";
433 XMLFilesBackend::createMessage( const zypp::parser::yum::YUMPatchMessage & parsed ) const
437 shared_ptr<XMLMessageImpl> impl(new XMLMessageImpl());
438 impl->_text = parsed.text;
440 // Collect basic Resolvable data
441 NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), Arch_noarch, createDependencies(parsed, ResTraits<Message>::kind) );
442 Message::Ptr message = detail::makeResolvableFromImpl( dataCollect, impl);
445 catch (const Exception & excpt_r)
447 ERR << excpt_r << endl;
448 throw "Cannot create message object";
453 XMLFilesBackend::createScript(const zypp::parser::yum::YUMPatchScript & parsed ) const
457 shared_ptr<XMLScriptImpl> impl(new XMLScriptImpl());
458 impl->_do_script = parsed.do_script;
459 impl->_undo_script = parsed.undo_script;
460 // Collect basic Resolvable data
461 NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), Arch_noarch, createDependencies(parsed, ResTraits<Script>::kind));
462 Script::Ptr script = detail::makeResolvableFromImpl( dataCollect, impl );
465 catch (const Exception & excpt_r)
467 ERR << excpt_r << endl;
468 throw "Cannot create script object";
474 std::list<MultiLang> name;
475 std::string default_;
476 std::string userVisible;
477 std::list<MultiLang> description;
478 std::list<MetaPkg> grouplist;
479 std::list<PackageReq> package_list;
483 XMLFilesBackend::createProduct( const zypp::parser::yum::YUMProductData & parsed ) const
487 shared_ptr<XMLProductImpl> impl(new XMLProductImpl());
489 impl->_category = parsed.type;
490 impl->_vendor = parsed.vendor;
491 #warning "FIX when YUM parser uses TranslatedString"
492 //impl->_displayname = parsed.displayname;
493 //impl->_description = parsed.description;
495 // Collect basic Resolvable data
496 NVRAD dataCollect( parsed.name, Edition( parsed.ver, parsed.rel, parsed.epoch ), Arch_noarch, createDependencies(parsed, ResTraits<Product>::kind) );
497 Product::Ptr product = detail::makeResolvableFromImpl( dataCollect, impl );
500 catch (const Exception & excpt_r)
502 ERR << excpt_r << endl;
503 throw "Cannot create product object";
508 XMLFilesBackend::createSelection( const zypp::parser::yum::YUMGroupData & parsed ) const
512 DBG << parsed << std::endl;
513 shared_ptr<XMLSelectionImpl> impl(new XMLSelectionImpl());
517 std::list<MultiLang> name;
518 std::string default_;
519 std::string userVisible;
520 std::list<MultiLang> description;
521 std::list<MetaPkg> grouplist;
522 std::list<PackageReq> packageList;
524 impl->_summary = parsed.description;
525 //impl->_description = parsed.description;
526 impl->_name = parsed.groupId;
527 //impl->_order = parsed.summary;
528 //impl->_category = parsed.summary;
529 impl->_visible = ((parsed.userVisible == "true") ? true : false);
531 for( std::list<MetaPkg>::const_iterator it = parsed.grouplist.begin(); it != parsed.grouplist.end(); ++it)
533 DBG << "Selection dependencies" << std::endl;
534 if ((*it).type == "optional" )
535 impl->_suggests.insert((*it).name);
536 if ((*it).type == "mandatory" )
537 impl->_recommends.insert((*it).name);
539 for( std::list<PackageReq>::const_iterator it = parsed.packageList.begin(); it != parsed.packageList.end(); ++it)
541 DBG << "Selection package dependencies" << std::endl;
542 impl->_install_packages.insert((*it).name);
544 // Collect basic Resolvable data
545 NVRAD dataCollect( parsed.groupId, Edition::noedition, Arch_noarch, createGroupDependencies(parsed) );
546 Selection::Ptr selection = detail::makeResolvableFromImpl( dataCollect, impl );
549 catch (const Exception & excpt_r)
551 ERR << excpt_r << endl;
552 throw "Cannot create selection object";
557 XMLFilesBackend::createDependencies( const zypp::parser::yum::YUMObjectData & parsed, const Resolvable::Kind my_kind ) const
560 for (std::list<YUMDependency>::const_iterator it = parsed.provides.begin(); it != parsed.provides.end(); it++)
562 _deps[Dep::PROVIDES].insert(createCapability(*it, my_kind));
565 for (std::list<YUMDependency>::const_iterator it = parsed.conflicts.begin(); it != parsed.conflicts.end(); it++)
567 _deps[Dep::CONFLICTS].insert(createCapability(*it, my_kind));
570 for (std::list<YUMDependency>::const_iterator it = parsed.obsoletes.begin(); it != parsed.obsoletes.end(); it++)
572 _deps[Dep::OBSOLETES].insert(createCapability(*it, my_kind));
575 for (std::list<YUMDependency>::const_iterator it = parsed.freshen.begin(); it != parsed.freshen.end(); it++)
577 _deps[Dep::FRESHENS].insert(createCapability(*it, my_kind));
580 for (std::list<YUMDependency>::const_iterator it = parsed.requires.begin(); it != parsed.requires.end(); it++)
583 _deps[Dep::PREREQUIRES].insert(createCapability(*it, my_kind));
585 _deps[Dep::REQUIRES].insert(createCapability(*it, my_kind));
592 XMLFilesBackend::createGroupDependencies( const zypp::parser::yum::YUMGroupData & parsed ) const
596 for (std::list<PackageReq>::const_iterator it = parsed.packageList.begin(); it != parsed.packageList.end(); it++)
598 if (it->type == "mandatory" || it->type == "")
600 _deps[Dep::REQUIRES].insert(createCapability(YUMDependency( "", it->name, "EQ", it->epoch, it->ver, it->rel, "" ), ResTraits<Package>::kind));
603 for (std::list<MetaPkg>::const_iterator it = parsed.grouplist.begin(); it != parsed.grouplist.end(); it++)
605 if (it->type == "mandatory" || it->type == "")
607 _deps[Dep::REQUIRES].insert(createCapability(YUMDependency("", it->name, "", "", "", "", "" ), ResTraits<Selection>::kind));
614 XMLFilesBackend::createPatternDependencies( const zypp::parser::yum::YUMPatternData & parsed ) const
618 for (std::list<PackageReq>::const_iterator it = parsed.packageList.begin(); it != parsed.packageList.end(); it++)
620 if (it->type == "mandatory" || it->type == "")
622 _deps[Dep::REQUIRES].insert(createCapability(YUMDependency( "", it->name, "EQ", it->epoch, it->ver, it->rel, "" ), ResTraits<Package>::kind));
625 for (std::list<MetaPkg>::const_iterator it = parsed.patternlist.begin(); it != parsed.patternlist.end(); it++)
627 if (it->type == "mandatory" || it->type == "")
629 _deps[Dep::REQUIRES].insert(createCapability(YUMDependency( "", it->name, "", "", "", "", "" ), ResTraits<Selection>::kind));
636 XMLFilesBackend::createCapability(const YUMDependency & dep, const Resolvable::Kind & my_kind) const
639 Resolvable::Kind _kind = dep.kind == "" ? my_kind : Resolvable::Kind(dep.kind);
641 if ( ! dep.isEncoded() )
643 cap = _f.parse( _kind, dep.name, Rel(dep.flags), Edition(dep.ver, dep.rel, dep.epoch) );
647 cap = _f.parse( _kind, dep.encoded );
652 ///////////////////////////////////////////////////////////////////
654 // METHOD NAME : XMLFilesBackend::~XMLFilesBackend
655 // METHOD TYPE : Dtor
657 XMLFilesBackend::~XMLFilesBackend()
662 ///////////////////////////////////////////////////////////////////
664 // METHOD NAME : XMLFilesBackend::doTest()
665 // METHOD TYPE : Dtor
667 void XMLFilesBackend::doTest()
670 /******************************************************************
672 ** FUNCTION NAME : operator<<
673 ** FUNCTION TYPE : std::ostream &
675 std::ostream & operator<<( std::ostream & str, const XMLFilesBackend & obj )
680 /////////////////////////////////////////////////////////
682 ////////////////////////////////////////////////////////
684 std::list<PersistentStorage::SourceData>
685 XMLFilesBackend::storedSources() const
687 path source_p = path(d->root.asString()) / path(ZYPP_DB_DIR) / path ("source-cache");
688 std::list<PersistentStorage::SourceData> sources;
689 DBG << "Reading source cache in " << source_p.string() << std::endl;
690 directory_iterator end_iter;
691 // return empty list if the dir does not exist
692 if ( !exists( source_p ) )
694 ERR << "path " << source_p.string() << " does not exists. Required to read source cache " << std::endl;
695 return std::list<PersistentStorage::SourceData>();
698 for ( directory_iterator dir_itr( source_p ); dir_itr != end_iter; ++dir_itr )
700 DBG << "[source-cache] - " << dir_itr->leaf() << std::endl;
701 //sources.insert( sourceDataFromCacheFile( source_p + "/" + dir_itr->leaf() ) );
702 std::string full_path = (source_p / dir_itr->leaf()).string();
703 std::ifstream anIstream(full_path.c_str());
704 XMLSourceCacheParser iter(anIstream, "");
705 for (; ! iter.atEnd(); ++iter) {
706 PersistentStorage::SourceData data = **iter;
707 sources.push_back(data);
710 MIL << "done reading source cache" << std::endl;
715 static std::string hexDigest(const std::string &message)
718 md5_byte_t digest[16];
721 /* Append a string to the message. */
722 md5_append(&state, (md5_byte_t*) message.c_str(), message.size()); /* Finish the message and return the digest. */
723 md5_finish(&state, digest);
728 sprintf(s+i*2, "%02x", digest[i]);
731 return std::string(s);
735 XMLFilesBackend::storeSource(const PersistentStorage::SourceData &data)
737 // serialize and save a file
738 std::string xml = toXML(data);
739 path source_p = path(d->root.asString()) / path(ZYPP_DB_DIR) / path ("source-cache");
741 // generate a filename
742 if (data.alias.size() == 0)
744 ZYPP_THROW(Exception("Cant save source with empty alias"));
747 //DBG << std::endl << xml << std::endl;
749 //DBG << filename << std::endl;
752 std::string full_path = (source_p / hexDigest(data.alias)).string();
754 file.open(full_path.c_str());
758 catch ( std::exception &e )
760 ERR << "Error saving source " << data.alias << " in the cache" << std::endl;
761 ZYPP_THROW(Exception(e.what()));
766 XMLFilesBackend::deleteSource(const std::string &alias)
768 // just delete the files
769 path source_p = path(d->root.asString()) / path(ZYPP_DB_DIR) / path ("source-cache");
772 std::string full_path = (source_p / hexDigest(alias)).string();
775 catch ( std::exception &e )
777 ERR << "Error deleting source " << alias << " in the cache" << std::endl;
778 ZYPP_THROW(Exception(e.what()));
782 /////////////////////////////////////////////////////////////////
783 } // namespace storage
784 ///////////////////////////////////////////////////////////////////
785 /////////////////////////////////////////////////////////////////
787 ///////////////////////////////////////////////////////////////////