remove old solver
[platform/upstream/libzypp.git] / zypp / solver / detail / Testcase.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/solver/detail/Testcase.cc
10  *
11 */
12 #include <iostream>
13 #include <fstream>
14 #include <sstream>
15 #include <streambuf>
16
17 #include "zypp/solver/detail/Testcase.h"
18 #include "zypp/base/Logger.h"
19 #include "zypp/base/LogControl.h"
20 #include "zypp/PathInfo.h"
21 #include "zypp/Product.h"
22 #include "zypp/Package.h"
23 #include "zypp/Edition.h"
24 #include "zypp/target/store/xml_escape_parser.hpp"
25 #include "zypp/base/String.h"
26 #include "zypp/base/PtrTypes.h"
27 #include "zypp/Capabilities.h"
28
29
30 /////////////////////////////////////////////////////////////////////////
31 namespace zypp
32 { ///////////////////////////////////////////////////////////////////////
33
34   namespace zypp_detail
35   { /////////////////////////////////////////////////////////////////
36     Arch defaultArchitecture();
37     /////////////////////////////////////////////////////////////////
38   } // namespace zypp_detail
39   ///////////////////////////////////////////////////////////////////
40   ///////////////////////////////////////////////////////////////////////
41   namespace solver
42   { /////////////////////////////////////////////////////////////////////
43     /////////////////////////////////////////////////////////////////////
44     namespace detail
45     { ///////////////////////////////////////////////////////////////////
46         
47 #define TAB "\t"
48 #define TAB2 "\t\t"
49         
50 using namespace std;
51 using namespace zypp::str;
52
53 IMPL_PTR_TYPE(HelixResolvable); 
54
55 static std::string xml_escape( const std::string &text )
56 {
57   iobind::parser::xml_escape_parser parser;
58   return parser.escape(text);
59 }
60
61 static std::string xml_tag_enclose( const std::string &text, const std::string &tag, bool escape = false )
62 {
63   string result;
64   result += "<" + tag + ">";
65
66   if ( escape)
67    result += xml_escape(text);
68   else
69    result += text;
70
71   result += "</" + tag + ">";
72   return result;
73 }
74
75         
76 template<class T>
77 std::string helixXML( const T &obj ); //undefined
78
79 template<> 
80 std::string helixXML( const Edition &edition )
81 {
82     stringstream str;
83     str << xml_tag_enclose(edition.version(), "version");
84     if (!edition.release().empty())
85         str << xml_tag_enclose(edition.release(), "release");
86     if (edition.epoch() != Edition::noepoch)
87         str << xml_tag_enclose(numstring(edition.epoch()), "epoch");    
88     return str.str();
89 }
90
91 template<> 
92 std::string helixXML( const Arch &arch )
93 {
94     stringstream str;
95     str << xml_tag_enclose(arch.asString(), "arch");        
96     return str.str();    
97 }
98
99 template<> 
100 std::string helixXML( const Capability &cap )
101 {
102     stringstream str;
103     str << "<dep name='" << xml_escape(cap.asString()) << "'  />" << endl;
104         
105     return str.str();    
106 }
107
108 template<> 
109 std::string helixXML( const Capabilities &caps )
110 {
111     stringstream str;
112     Capabilities::const_iterator it = caps.begin();
113     str << endl;
114     for ( ; it != caps.end(); ++it)
115     {
116         str << TAB2 << helixXML((*it));
117     }
118     str << TAB;
119     return str.str();
120 }
121
122 template<> 
123 std::string helixXML( const Dependencies &dep )
124 {
125     stringstream str;
126     if ( dep[Dep::PROVIDES].size() > 0 )
127         str << TAB << xml_tag_enclose(helixXML(dep[Dep::PROVIDES]), "provides") << endl;
128     if ( dep[Dep::CONFLICTS].size() > 0 )
129         str << TAB << xml_tag_enclose(helixXML(dep[Dep::CONFLICTS]), "conflicts") << endl;
130     if ( dep[Dep::OBSOLETES].size() > 0 )
131         str << TAB << xml_tag_enclose(helixXML(dep[Dep::OBSOLETES]), "obsoletes") << endl;
132     if ( dep[Dep::FRESHENS].size() > 0 )
133         str << TAB << xml_tag_enclose(helixXML(dep[Dep::FRESHENS]), "freshens") << endl;
134     if ( dep[Dep::REQUIRES].size() > 0 )
135         str << TAB << xml_tag_enclose(helixXML(dep[Dep::REQUIRES]), "requires") << endl;  
136     if ( dep[Dep::RECOMMENDS].size() > 0 )
137         str << TAB << xml_tag_enclose(helixXML(dep[Dep::RECOMMENDS]), "recommends") << endl;
138     if ( dep[Dep::ENHANCES].size() > 0 )
139         str << TAB << xml_tag_enclose(helixXML(dep[Dep::ENHANCES]), "enhances") << endl;
140     if ( dep[Dep::SUPPLEMENTS].size() > 0 )
141         str << TAB << xml_tag_enclose(helixXML(dep[Dep::SUPPLEMENTS]), "supplements") << endl;
142     if ( dep[Dep::SUGGESTS].size() > 0 )
143         str << TAB << xml_tag_enclose(helixXML(dep[Dep::SUGGESTS]), "suggests") << endl;
144     return str.str();    
145 }
146
147 std::string helixXML( const PoolItem_Ref &item )
148 {
149   const Resolvable::constPtr resolvable = item.resolvable();
150   stringstream str;
151   if ( isKind<Language>(resolvable) ) {
152       // language dependencies will be written in another part
153       return str.str();
154   }
155   
156   str << "<" << toLower (resolvable->kind().asString()) << ">" << endl;
157   str << TAB << xml_tag_enclose (resolvable->name(), "name", true) << endl;
158   str << TAB << xml_tag_enclose (item->vendor(), "vendor", true) << endl;    
159   if ( isKind<Package>(resolvable) ) {
160       str << TAB << "<history>" << endl << TAB << "<update>" << endl;
161       str << TAB2 << helixXML (resolvable->arch()) << endl;
162       str << TAB2 << helixXML (resolvable->edition()) << endl;      
163       str << TAB << "</update>" << endl << TAB << "</history>" << endl;
164   } else {
165       str << TAB << helixXML (resolvable->arch()) << endl;      
166       str << TAB << helixXML (resolvable->edition()) << endl;            
167   }
168   str << helixXML (resolvable->deps());              
169
170   str << "</" << toLower (resolvable->kind().asString()) << ">" << endl;  
171   return str.str();
172 }
173
174 //---------------------------------------------------------------------------
175
176 Testcase::Testcase()
177     :dumpPath("/var/log/YaST2/solverTestcase")    
178 {
179 }
180
181 Testcase::Testcase(const std::string & path)
182     :dumpPath(path)
183 {
184 }
185         
186
187 Testcase::~Testcase()
188 {
189 }
190
191 bool Testcase::createTestcase(Resolver & resolver)
192 {
193     PathInfo path (dumpPath);
194
195     if ( !path.isExist() ) {
196         if (zypp::filesystem::mkdir (dumpPath)!=0) {
197             ERR << "Cannot create directory " << dumpPath << endl;
198             return false;
199         }
200     } else {
201         if (!path.isDir()) {
202             ERR << dumpPath << " is not a directory." << endl;
203             return false;
204         }
205         // remove old stuff
206         zypp::filesystem::clean_dir (dumpPath);
207     }
208     
209     zypp::base::LogControl::instance().logfile( dumpPath +"/y2log" );
210     zypp::base::LogControl::TmpExcessive excessive;
211
212     resolver.reset(true); // true = resetting all valid solverresults
213     resolver.resolvePool();
214
215     zypp::base::LogControl::instance().logfile( "/var/log/YaST2/y2log" );    
216
217     ResPool pool        = resolver.pool();
218     RepositoryTable             repoTable;
219     PoolItemList        items_to_install;
220     PoolItemList        items_to_remove;
221     PoolItemList        items_locked;
222     PoolItemList        items_keep;    
223     PoolItemList        language;
224     HelixResolvable     system (dumpPath + "/solver-system.xml");    
225
226     for ( ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it )
227     {
228         Resolvable::constPtr res = it->resolvable();
229
230         if (isKind<Language>(res)) {
231             if ( it->status().isInstalled()
232                  || it->status().isToBeInstalled()) {
233                 language.push_back (*it);               
234             }
235         } else {
236             if ( it->status().isInstalled() ) {
237                 // system channel
238                 system.addResolvable (*it);
239             } else {
240                 // repo channels
241                 ResObject::constPtr repoItem = it->resolvable();
242                 Repository repo  = repoItem->repository();
243                 if (repoTable.find (repo) == repoTable.end()) {
244                     repoTable[repo] = new HelixResolvable(dumpPath + "/"
245                                                           + numstring(repo.numericId())
246                                                           + "-package.xml");
247                 }
248                 repoTable[repo]->addResolvable (*it);
249             }
250         
251             if ( it->status().isToBeInstalled()
252                  && !(it->status().isBySolver())) {
253                 items_to_install.push_back (*it);
254             }
255             if ( it->status().isKept()
256                  && !(it->status().isBySolver())) {
257                 items_keep.push_back (*it);
258             }       
259             if ( it->status().isToBeUninstalled()
260                  && !(it->status().isBySolver())) {
261                 items_to_remove.push_back (*it);
262             }
263             if ( it->status().isLocked()
264                  && !(it->status().isBySolver())) {
265                 items_locked.push_back (*it);
266             }
267             
268         }
269     }
270
271     // writing control file "*-test.xml"
272
273     HelixControl control (dumpPath + "/solver-test.xml",
274                           repoTable,
275                           zypp_detail::defaultArchitecture(),
276                           language);
277
278     for (PoolItemList::const_iterator iter = items_to_install.begin(); iter != items_to_install.end(); iter++) {
279         control.installResolvable (iter->resolvable()); 
280     }
281
282     for (PoolItemList::const_iterator iter = items_locked.begin(); iter != items_locked.end(); iter++) {
283         control.lockResolvable (iter->resolvable());    
284     }
285     
286     for (PoolItemList::const_iterator iter = items_keep.begin(); iter != items_keep.end(); iter++) {
287         control.keepResolvable (iter->resolvable());    
288     }
289
290     for (PoolItemList::const_iterator iter = items_to_remove.begin(); iter != items_to_remove.end(); iter++) {
291         control.deleteResolvable (iter->resolvable());  
292     }
293
294     control.addDependencies (resolver.extraRequires(), resolver.extraConflicts());
295
296     return true;
297 }
298
299 //---------------------------------------------------------------------------
300
301 HelixResolvable::HelixResolvable(const std::string & path)
302     :dumpFile (path)    
303 {
304     file = new ofstream(path.c_str());
305     if (!file) {
306         ZYPP_THROW (Exception( "Can't open " + path ) );
307     }
308
309     *file << "<channel><subchannel>" << endl;
310 }
311
312 HelixResolvable::~HelixResolvable()
313 {
314     *file << "</subchannel></channel>" << endl;
315 }
316     
317
318 void HelixResolvable::addResolvable(const PoolItem_Ref item)
319 {
320     *file << helixXML (item);
321 }
322
323 //---------------------------------------------------------------------------
324
325 HelixControl::HelixControl(const std::string & controlPath,
326                            const RepositoryTable & repoTable,
327                            const Arch & systemArchitecture,
328                            const PoolItemList &languages,
329                            const std::string & systemPath)
330     :dumpFile (controlPath) 
331 {
332     file = new ofstream(controlPath.c_str());
333     if (!file) {
334         ZYPP_THROW (Exception( "Can't open " + controlPath ) );
335     }
336
337     *file << "<?xml version=\"1.0\"?>" << endl
338           << "<!-- testcase generated by YaST -->" << endl
339           << "<test>" << endl
340           << "<setup arch=\"" << systemArchitecture << "\">" << endl
341           << TAB << "<system file=\"" << systemPath << "\"/>" << endl << endl;
342     for ( RepositoryTable::const_iterator it = repoTable.begin();
343           it != repoTable.end(); ++it ) {
344         Repository repo = it->first;
345         *file << TAB << "<!-- " << endl
346               << TAB << "- alias       : " << repo.info().alias() << endl;
347         for ( RepoInfo::urls_const_iterator itUrl = repo.info().baseUrlsBegin();
348               itUrl != repo.info().baseUrlsEnd();
349               ++itUrl )
350         {
351             *file << TAB << "- url         : " << *itUrl << endl;
352         }       
353         *file << TAB << "- path        : " << repo.info().path() << endl;
354         *file << TAB << "- type        : " << repo.info().type() << endl;       
355         *file << TAB << " -->" << endl;
356         
357         *file << TAB << "<channel file=\"" << numstring(repo.numericId())
358               << "-package.xml\" name=\"" << numstring(repo.numericId())
359               << "\" />" << endl << endl;
360     }
361     for (PoolItemList::const_iterator iter = languages.begin(); iter != languages.end(); iter++) {
362         *file << TAB << "<locale name=\"" <<  iter->resolvable()->name()
363               << "\" />" << endl;
364     }    
365     *file << "</setup>" << endl
366           << "<trial>" << endl
367           << "<showpool all=\"yes\"/>" << endl
368           << "<establish/>" << endl
369           << "<showpool all=\"true\" prefix=\">!> ESTABLISHED:\"/>" << endl;
370 }
371
372 HelixControl::HelixControl()
373     :dumpFile ("/var/log/YaST2/solverTestcase/solver-test.xml")
374 {
375     HelixControl (dumpFile);
376 }
377
378 HelixControl::~HelixControl()
379 {
380     *file << "</trial>" << endl
381           << "</test>" << endl;
382 }
383
384 void HelixControl::installResolvable(const ResObject::constPtr &resObject)
385 {
386     Repository repo  = resObject->repository();
387     *file << "<install channel=\"" << numstring(repo.numericId()) << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
388           << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
389           << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\"" 
390           << "/>" << endl;
391 }
392
393 void HelixControl::lockResolvable(const ResObject::constPtr &resObject)
394 {
395     Repository repo  = resObject->repository();
396     *file << "<lock channel=\"" << numstring(repo.numericId()) << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
397           << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
398           << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\"" 
399           << "/>" << endl;
400 }
401
402 void HelixControl::keepResolvable(const ResObject::constPtr &resObject)
403 {
404     Repository repo  = resObject->repository();
405     *file << "<keep channel=\"" << numstring(repo.numericId()) << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
406           << " name=\"" << resObject->name() << "\"" << " arch=\"" << resObject->arch().asString() << "\""
407           << " version=\"" << resObject->edition().version() << "\"" << " release=\"" << resObject->edition().release() << "\"" 
408           << "/>" << endl;
409 }
410     
411 void HelixControl::deleteResolvable(const ResObject::constPtr &resObject)
412 {
413     Repository repo  = resObject->repository();    
414     *file << "<uninstall " << " kind=\"" << toLower (resObject->kind().asString()) << "\""
415           << " name=\"" << resObject->name() << "\"" << "/>" << endl;    
416 }
417
418 void HelixControl::addDependencies (const CapabilitySet & capRequire, const CapabilitySet & capConflict)
419 {
420     for (CapabilitySet::const_iterator iter = capRequire.begin(); iter != capRequire.end(); iter++) {
421         *file << "<addRequire " <<  " name=\"" << iter->asString() << "\"" << "/>" << endl;    
422     }
423     for (CapabilitySet::const_iterator iter = capConflict.begin(); iter != capConflict.end(); iter++) {
424         *file << "<addConflict " << " name=\"" << iter->asString() << "\"" << "/>" << endl;    
425     }    
426 }
427
428
429       ///////////////////////////////////////////////////////////////////
430     };// namespace detail
431     /////////////////////////////////////////////////////////////////////
432     /////////////////////////////////////////////////////////////////////
433   };// namespace solver
434   ///////////////////////////////////////////////////////////////////////
435   ///////////////////////////////////////////////////////////////////////
436 };// namespace zypp
437 /////////////////////////////////////////////////////////////////////////