]>
git.saurik.com Git - apt.git/blob - apt-pkg/edsp.cc
9596a9eb359f37daa445e4fe4d5099e7363de93d
1 // -*- mode: cpp; mode: fold -*-
3 /* ######################################################################
4 Set of methods to help writing and reading everything needed for EDSP
5 ##################################################################### */
7 // Include Files /*{{{*/
10 #include <apt-pkg/error.h>
11 #include <apt-pkg/cacheset.h>
12 #include <apt-pkg/depcache.h>
13 #include <apt-pkg/pkgcache.h>
14 #include <apt-pkg/cacheiterators.h>
15 #include <apt-pkg/progress.h>
16 #include <apt-pkg/fileutl.h>
17 #include <apt-pkg/edsp.h>
18 #include <apt-pkg/tagfile.h>
19 #include <apt-pkg/strutl.h>
36 // we could use pkgCache::DepType and ::Priority, but these would be localized stringsā¦
37 constexpr char const * const PrioMap
[] = {
38 nullptr , "important" , "required" , "standard" ,
41 constexpr char const * const DepMap
[] = {
42 nullptr , "Depends" , "Pre-Depends" , "Suggests" ,
43 "Recommends" , "Conflicts" , "Replaces" ,
44 "Obsoletes" , "Breaks" , "Enhances"
47 // WriteOkay - varaidic helper to easily Write to a FileFd /*{{{*/
48 static bool WriteOkay_fn ( FileFd
&) { return true ; }
49 template < typename
... Tail
> static bool WriteOkay_fn ( FileFd
& output
, APT :: StringView data
, Tail
... more_data
)
51 return likely ( output
. Write ( data
. data (), data
. length ()) && WriteOkay_fn ( output
, more_data
...));
53 template < typename
... Tail
> static bool WriteOkay_fn ( FileFd
& output
, unsigned int data
, Tail
... more_data
)
56 strprintf ( number
, " %d " , data
);
57 return likely ( output
. Write ( number
. data (), number
. length ()) && WriteOkay_fn ( output
, more_data
...));
59 template < typename
... Data
> static bool WriteOkay ( bool & Okay
, FileFd
& output
, Data
&&... data
)
61 Okay
= likely ( Okay
&& WriteOkay_fn ( output
, std :: forward
< Data
>( data
)...));
64 template < typename
... Data
> static bool WriteOkay ( FileFd
& output
, Data
&&... data
)
66 bool Okay
= likely ( output
. Failed () == false );
67 return WriteOkay ( Okay
, output
, std :: forward
< Data
>( data
)...);
70 // WriteScenarioVersion /*{{{*/
71 static void WriteScenarioVersion ( pkgDepCache
& Cache
, FILE * output
, pkgCache :: PkgIterator
const & Pkg
,
72 pkgCache :: VerIterator
const & Ver
)
74 fprintf ( output
, "Package: %s \n " , Pkg
. Name ());
75 fprintf ( output
, "Source: %s \n " , Ver
. SourcePkgName ());
76 fprintf ( output
, "Architecture: %s \n " , Ver
. Arch ());
77 fprintf ( output
, "Version: %s \n " , Ver
. VerStr ());
78 fprintf ( output
, "Source-Version: %s \n " , Ver
. SourceVerStr ());
79 if ( Pkg
. CurrentVer () == Ver
)
80 fprintf ( output
, "Installed: yes \n " );
81 if ( Pkg
-> SelectedState
== pkgCache :: State :: Hold
||
82 ( Cache
[ Pkg
]. Keep () == true && Cache
[ Pkg
]. Protect () == true ))
83 fprintf ( output
, "Hold: yes \n " );
84 fprintf ( output
, "APT-ID: %d \n " , Ver
-> ID
);
85 if ( PrioMap
[ Ver
-> Priority
] != nullptr )
86 fprintf ( output
, "Priority: %s \n " , PrioMap
[ Ver
-> Priority
]);
87 if (( Pkg
-> Flags
& pkgCache :: Flag :: Essential
) == pkgCache :: Flag :: Essential
)
88 fprintf ( output
, "Essential: yes \n " );
89 if ( Ver
-> Section
!= 0 )
90 fprintf ( output
, "Section: %s \n " , Ver
. Section ());
91 if (( Ver
-> MultiArch
& pkgCache :: Version :: Allowed
) == pkgCache :: Version :: Allowed
)
92 fprintf ( output
, "Multi-Arch: allowed \n " );
93 else if (( Ver
-> MultiArch
& pkgCache :: Version :: Foreign
) == pkgCache :: Version :: Foreign
)
94 fprintf ( output
, "Multi-Arch: foreign \n " );
95 else if (( Ver
-> MultiArch
& pkgCache :: Version :: Same
) == pkgCache :: Version :: Same
)
96 fprintf ( output
, "Multi-Arch: same \n " );
97 std :: set
< string
> Releases
;
98 for ( pkgCache :: VerFileIterator I
= Ver
. FileList (); I
. end () == false ; ++ I
) {
99 pkgCache :: PkgFileIterator File
= I
. File ();
100 if ( File
. Flagged ( pkgCache :: Flag :: NotSource
) == false ) {
101 string Release
= File
. RelStr ();
102 if (! Release
. empty ())
103 Releases
. insert ( Release
);
106 if (! Releases
. empty ()) {
107 fprintf ( output
, "APT-Release: \n " );
108 for ( std :: set
< string
>:: iterator R
= Releases
. begin (); R
!= Releases
. end (); ++ R
)
109 fprintf ( output
, " %s \n " , R
-> c_str ());
111 fprintf ( output
, "APT-Pin: %d \n " , Cache
. GetPolicy (). GetPriority ( Ver
));
112 if ( Cache
. GetCandidateVersion ( Pkg
) == Ver
)
113 fprintf ( output
, "APT-Candidate: yes \n " );
114 if (( Cache
[ Pkg
]. Flags
& pkgCache :: Flag :: Auto
) == pkgCache :: Flag :: Auto
)
115 fprintf ( output
, "APT-Automatic: yes \n " );
117 static bool WriteScenarioVersion ( pkgDepCache
& Cache
, FileFd
& output
, pkgCache :: PkgIterator
const & Pkg
,
118 pkgCache :: VerIterator
const & Ver
)
120 bool Okay
= WriteOkay ( output
, "Package: " , Pkg
. Name (),
121 " \n Source: " , Ver
. SourcePkgName (),
122 " \n Architecture: " , Ver
. Arch (),
123 " \n Version: " , Ver
. VerStr (),
124 " \n Source-Version: " , Ver
. SourceVerStr ());
125 if ( Pkg
. CurrentVer () == Ver
)
126 WriteOkay ( Okay
, output
, " \n Installed: yes" );
127 if ( Pkg
-> SelectedState
== pkgCache :: State :: Hold
||
128 ( Cache
[ Pkg
]. Keep () == true && Cache
[ Pkg
]. Protect () == true ))
129 WriteOkay ( Okay
, output
, " \n Hold: yes" );
130 WriteOkay ( Okay
, output
, " \n APT-ID: " , Ver
-> ID
);
131 if ( PrioMap
[ Ver
-> Priority
] != nullptr )
132 WriteOkay ( Okay
, output
, " \n Priority: " , PrioMap
[ Ver
-> Priority
]);
133 if (( Pkg
-> Flags
& pkgCache :: Flag :: Essential
) == pkgCache :: Flag :: Essential
)
134 WriteOkay ( Okay
, output
, " \n Essential: yes" );
135 if ( Ver
-> Section
!= 0 )
136 WriteOkay ( Okay
, output
, " \n Section: " , Ver
. Section ());
137 if (( Ver
-> MultiArch
& pkgCache :: Version :: Allowed
) == pkgCache :: Version :: Allowed
)
138 WriteOkay ( Okay
, output
, " \n Multi-Arch: allowed" );
139 else if (( Ver
-> MultiArch
& pkgCache :: Version :: Foreign
) == pkgCache :: Version :: Foreign
)
140 WriteOkay ( Okay
, output
, " \n Multi-Arch: foreign" );
141 else if (( Ver
-> MultiArch
& pkgCache :: Version :: Same
) == pkgCache :: Version :: Same
)
142 WriteOkay ( Okay
, output
, " \n Multi-Arch: same" );
143 std :: set
< string
> Releases
;
144 for ( pkgCache :: VerFileIterator I
= Ver
. FileList (); I
. end () == false ; ++ I
) {
145 pkgCache :: PkgFileIterator File
= I
. File ();
146 if ( File
. Flagged ( pkgCache :: Flag :: NotSource
) == false ) {
147 string Release
= File
. RelStr ();
148 if (! Release
. empty ())
149 Releases
. insert ( Release
);
152 if (! Releases
. empty ()) {
153 WriteOkay ( Okay
, output
, " \n APT-Release:" );
154 for ( std :: set
< string
>:: iterator R
= Releases
. begin (); R
!= Releases
. end (); ++ R
)
155 WriteOkay ( Okay
, output
, " \n " , * R
);
157 WriteOkay ( Okay
, output
, " \n APT-Pin: " , Cache
. GetPolicy (). GetPriority ( Ver
));
158 if ( Cache
. GetCandidateVersion ( Pkg
) == Ver
)
159 WriteOkay ( Okay
, output
, " \n APT-Candidate: yes" );
160 if (( Cache
[ Pkg
]. Flags
& pkgCache :: Flag :: Auto
) == pkgCache :: Flag :: Auto
)
161 WriteOkay ( Okay
, output
, " \n APT-Automatic: yes" );
165 // WriteScenarioDependency /*{{{*/
166 static void WriteScenarioDependency ( FILE * output
, pkgCache :: VerIterator
const & Ver
)
168 std :: array
< std :: string
, _count ( DepMap
)> dependencies
;
169 bool orGroup
= false ;
170 for ( pkgCache :: DepIterator Dep
= Ver
. DependsList (); Dep
. end () == false ; ++ Dep
)
172 if ( Dep
. IsImplicit () == true )
174 if ( orGroup
== false )
175 dependencies
[ Dep
-> Type
]. append ( ", " );
176 dependencies
[ Dep
-> Type
]. append ( Dep
. TargetPkg (). Name ());
177 if ( Dep
-> Version
!= 0 )
178 dependencies
[ Dep
-> Type
]. append ( " (" ). append ( pkgCache :: CompTypeDeb ( Dep
-> CompareOp
)). append ( " " ). append ( Dep
. TargetVer ()). append ( ")" );
179 if (( Dep
-> CompareOp
& pkgCache :: Dep :: Or
) == pkgCache :: Dep :: Or
)
181 dependencies
[ Dep
-> Type
]. append ( " | " );
187 for ( size_t i
= 1 ; i
< dependencies
. size (); ++ i
)
188 if ( dependencies
[ i
]. empty () == false )
189 fprintf ( output
, " %s : %s \n " , DepMap
[ i
], dependencies
[ i
]. c_str ()+ 2 );
191 for ( pkgCache :: PrvIterator Prv
= Ver
. ProvidesList (); Prv
. end () == false ; ++ Prv
)
193 if ( Prv
. IsMultiArchImplicit () == true )
195 if ( provides
. empty () == false )
196 provides
. append ( ", " );
197 provides
. append ( Prv
. Name ());
198 if ( Prv
-> ProvideVersion
!= 0 )
199 provides
. append ( " (= " ). append ( Prv
. ProvideVersion ()). append ( ")" );
201 if ( provides
. empty () == false )
202 fprintf ( output
, "Provides: %s \n " , provides
. c_str ());
204 static bool WriteScenarioDependency ( FileFd
& output
, pkgCache :: VerIterator
const & Ver
)
206 std :: array
< std :: string
, _count ( DepMap
)> dependencies
;
207 bool orGroup
= false ;
208 for ( pkgCache :: DepIterator Dep
= Ver
. DependsList (); Dep
. end () == false ; ++ Dep
)
210 if ( Dep
. IsImplicit () == true )
212 if ( orGroup
== false && dependencies
[ Dep
-> Type
]. empty () == false )
213 dependencies
[ Dep
-> Type
]. append ( ", " );
214 dependencies
[ Dep
-> Type
]. append ( Dep
. TargetPkg (). Name ());
215 if ( Dep
-> Version
!= 0 )
216 dependencies
[ Dep
-> Type
]. append ( " (" ). append ( pkgCache :: CompTypeDeb ( Dep
-> CompareOp
)). append ( " " ). append ( Dep
. TargetVer ()). append ( ")" );
217 if (( Dep
-> CompareOp
& pkgCache :: Dep :: Or
) == pkgCache :: Dep :: Or
)
219 dependencies
[ Dep
-> Type
]. append ( " | " );
225 bool Okay
= output
. Failed () == false ;
226 for ( size_t i
= 1 ; i
< dependencies
. size (); ++ i
)
227 if ( dependencies
[ i
]. empty () == false )
228 WriteOkay ( Okay
, output
, " \n " , DepMap
[ i
], ": " , dependencies
[ i
]);
230 for ( pkgCache :: PrvIterator Prv
= Ver
. ProvidesList (); Prv
. end () == false ; ++ Prv
)
232 if ( Prv
. IsMultiArchImplicit () == true )
234 if ( provides
. empty () == false )
235 provides
. append ( ", " );
236 provides
. append ( Prv
. Name ());
237 if ( Prv
-> ProvideVersion
!= 0 )
238 provides
. append ( " (= " ). append ( Prv
. ProvideVersion ()). append ( ")" );
240 if ( provides
. empty () == false )
241 WriteOkay ( Okay
, output
, " \n Provides: " , provides
);
242 return WriteOkay ( Okay
, output
, " \n " );
245 // WriteScenarioLimitedDependency /*{{{*/
246 static void WriteScenarioLimitedDependency ( FILE * output
,
247 pkgCache :: VerIterator
const & Ver
,
248 APT :: PackageSet
const & pkgset
)
250 std :: array
< std :: string
, _count ( DepMap
)> dependencies
;
251 bool orGroup
= false ;
252 for ( pkgCache :: DepIterator Dep
= Ver
. DependsList (); Dep
. end () == false ; ++ Dep
)
254 if ( Dep
. IsImplicit () == true )
256 if ( orGroup
== false )
258 if ( pkgset
. find ( Dep
. TargetPkg ()) == pkgset
. end ())
260 if ( dependencies
[ Dep
-> Type
]. empty () == false )
261 dependencies
[ Dep
-> Type
]. append ( ", " );
263 else if ( pkgset
. find ( Dep
. TargetPkg ()) == pkgset
. end ())
265 if (( Dep
-> CompareOp
& pkgCache :: Dep :: Or
) == pkgCache :: Dep :: Or
)
267 dependencies
[ Dep
-> Type
]. erase ( dependencies
[ Dep
-> Type
]. end ()- 3 , dependencies
[ Dep
-> Type
]. end ());
271 dependencies
[ Dep
-> Type
]. append ( Dep
. TargetPkg (). Name ());
272 if ( Dep
-> Version
!= 0 )
273 dependencies
[ Dep
-> Type
]. append ( " (" ). append ( pkgCache :: CompTypeDeb ( Dep
-> CompareOp
)). append ( " " ). append ( Dep
. TargetVer ()). append ( ")" );
274 if (( Dep
-> CompareOp
& pkgCache :: Dep :: Or
) == pkgCache :: Dep :: Or
)
276 dependencies
[ Dep
-> Type
]. append ( " | " );
282 for ( size_t i
= 1 ; i
< dependencies
. size (); ++ i
)
283 if ( dependencies
[ i
]. empty () == false )
284 fprintf ( output
, " %s : %s \n " , DepMap
[ i
], dependencies
[ i
]. c_str ());
286 for ( pkgCache :: PrvIterator Prv
= Ver
. ProvidesList (); Prv
. end () == false ; ++ Prv
)
288 if ( Prv
. IsMultiArchImplicit () == true )
290 if ( pkgset
. find ( Prv
. ParentPkg ()) == pkgset
. end ())
292 if ( provides
. empty () == false )
293 provides
. append ( ", " );
294 provides
. append ( Prv
. Name ());
295 if ( Prv
-> ProvideVersion
!= 0 )
296 provides
. append ( " (= " ). append ( Prv
. ProvideVersion ()). append ( ")" );
298 if ( provides
. empty () == false )
299 fprintf ( output
, "Provides: %s \n " , provides
. c_str ());
301 static bool WriteScenarioLimitedDependency ( FileFd
& output
,
302 pkgCache :: VerIterator
const & Ver
,
303 APT :: PackageSet
const & pkgset
)
305 std :: array
< std :: string
, _count ( DepMap
)> dependencies
;
306 bool orGroup
= false ;
307 for ( pkgCache :: DepIterator Dep
= Ver
. DependsList (); Dep
. end () == false ; ++ Dep
)
309 if ( Dep
. IsImplicit () == true )
311 if ( orGroup
== false )
313 if ( pkgset
. find ( Dep
. TargetPkg ()) == pkgset
. end ())
315 if ( dependencies
[ Dep
-> Type
]. empty () == false )
316 dependencies
[ Dep
-> Type
]. append ( ", " );
318 else if ( pkgset
. find ( Dep
. TargetPkg ()) == pkgset
. end ())
320 if (( Dep
-> CompareOp
& pkgCache :: Dep :: Or
) == pkgCache :: Dep :: Or
)
322 dependencies
[ Dep
-> Type
]. erase ( dependencies
[ Dep
-> Type
]. end ()- 3 , dependencies
[ Dep
-> Type
]. end ());
326 dependencies
[ Dep
-> Type
]. append ( Dep
. TargetPkg (). Name ());
327 if ( Dep
-> Version
!= 0 )
328 dependencies
[ Dep
-> Type
]. append ( " (" ). append ( pkgCache :: CompTypeDeb ( Dep
-> CompareOp
)). append ( " " ). append ( Dep
. TargetVer ()). append ( ")" );
329 if (( Dep
-> CompareOp
& pkgCache :: Dep :: Or
) == pkgCache :: Dep :: Or
)
331 dependencies
[ Dep
-> Type
]. append ( " | " );
337 bool Okay
= output
. Failed () == false ;
338 for ( size_t i
= 1 ; i
< dependencies
. size (); ++ i
)
339 if ( dependencies
[ i
]. empty () == false )
340 WriteOkay ( Okay
, output
, " \n " , DepMap
[ i
], ": " , dependencies
[ i
]);
342 for ( pkgCache :: PrvIterator Prv
= Ver
. ProvidesList (); Prv
. end () == false ; ++ Prv
)
344 if ( Prv
. IsMultiArchImplicit () == true )
346 if ( pkgset
. find ( Prv
. ParentPkg ()) == pkgset
. end ())
348 if ( provides
. empty () == false )
349 provides
. append ( ", " );
350 provides
. append ( Prv
. Name ());
351 if ( Prv
-> ProvideVersion
!= 0 )
352 provides
. append ( " (= " ). append ( Prv
. ProvideVersion ()). append ( ")" );
354 if ( provides
. empty () == false )
355 WriteOkay ( Okay
, output
, " \n Provides: " , provides
);
356 return WriteOkay ( Okay
, output
, " \n " );
359 static bool SkipUnavailableVersions ( pkgDepCache
& Cache
, pkgCache :: PkgIterator
const & Pkg
, pkgCache :: VerIterator
const & Ver
) /*{{{*/
361 /* versions which aren't current and aren't available in
362 any "online" source file are bad, expect if they are the choosen
363 candidate: The exception is for build-dep implementation as it creates
364 such pseudo (package) versions and removes them later on again.
365 We filter out versions at all so packages in 'rc' state only available
366 in dpkg/status aren't passed to solvers as they can't be installed. */
367 if ( Pkg
-> CurrentVer
!= 0 )
369 if ( Cache
. GetCandidateVersion ( Pkg
) == Ver
)
371 for ( pkgCache :: VerFileIterator I
= Ver
. FileList (); I
. end () == false ; ++ I
)
372 if ( I
. File (). Flagged ( pkgCache :: Flag :: NotSource
) == false )
377 // EDSP::WriteScenario - to the given file descriptor /*{{{*/
378 bool EDSP :: WriteScenario ( pkgDepCache
& Cache
, FILE * output
, OpProgress
* Progress
)
380 if ( Progress
!= NULL
)
381 Progress
-> SubProgress ( Cache
. Head (). VersionCount
, _ ( "Send scenario to solver" ));
383 std :: vector
< std :: string
> archs
= APT :: Configuration :: getArchitectures ();
384 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false ; ++ Pkg
)
386 std :: string
const arch
= Pkg
. Arch ();
387 if ( std :: find ( archs
. begin (), archs
. end (), arch
) == archs
. end ())
389 for ( pkgCache :: VerIterator Ver
= Pkg
. VersionList (); Ver
. end () == false ; ++ Ver
, ++ p
)
391 if ( SkipUnavailableVersions ( Cache
, Pkg
, Ver
))
393 WriteScenarioVersion ( Cache
, output
, Pkg
, Ver
);
394 WriteScenarioDependency ( output
, Ver
);
395 fprintf ( output
, " \n " );
396 if ( Progress
!= NULL
&& p
% 100 == 0 )
397 Progress
-> Progress ( p
);
402 bool EDSP :: WriteScenario ( pkgDepCache
& Cache
, FileFd
& output
, OpProgress
* Progress
)
404 if ( Progress
!= NULL
)
405 Progress
-> SubProgress ( Cache
. Head (). VersionCount
, _ ( "Send scenario to solver" ));
407 bool Okay
= output
. Failed () == false ;
408 std :: vector
< std :: string
> archs
= APT :: Configuration :: getArchitectures ();
409 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false && likely ( Okay
); ++ Pkg
)
411 std :: string
const arch
= Pkg
. Arch ();
412 if ( std :: find ( archs
. begin (), archs
. end (), arch
) == archs
. end ())
414 for ( pkgCache :: VerIterator Ver
= Pkg
. VersionList (); Ver
. end () == false && likely ( Okay
); ++ Ver
, ++ p
)
416 if ( SkipUnavailableVersions ( Cache
, Pkg
, Ver
))
418 Okay
&= WriteScenarioVersion ( Cache
, output
, Pkg
, Ver
);
419 Okay
&= WriteScenarioDependency ( output
, Ver
);
420 WriteOkay ( Okay
, output
, " \n " );
421 if ( Progress
!= NULL
&& p
% 100 == 0 )
422 Progress
-> Progress ( p
);
428 // EDSP::WriteLimitedScenario - to the given file descriptor /*{{{*/
429 bool EDSP :: WriteLimitedScenario ( pkgDepCache
& Cache
, FILE * output
,
430 APT :: PackageSet
const & pkgset
,
431 OpProgress
* Progress
)
433 if ( Progress
!= NULL
)
434 Progress
-> SubProgress ( Cache
. Head (). VersionCount
, _ ( "Send scenario to solver" ));
436 for ( APT :: PackageSet :: const_iterator Pkg
= pkgset
. begin (); Pkg
!= pkgset
. end (); ++ Pkg
, ++ p
)
437 for ( pkgCache :: VerIterator Ver
= Pkg
. VersionList (); Ver
. end () == false ; ++ Ver
)
439 if ( SkipUnavailableVersions ( Cache
, Pkg
, Ver
))
441 WriteScenarioVersion ( Cache
, output
, Pkg
, Ver
);
442 WriteScenarioLimitedDependency ( output
, Ver
, pkgset
);
443 fprintf ( output
, " \n " );
444 if ( Progress
!= NULL
&& p
% 100 == 0 )
445 Progress
-> Progress ( p
);
447 if ( Progress
!= NULL
)
451 bool EDSP :: WriteLimitedScenario ( pkgDepCache
& Cache
, FileFd
& output
,
452 APT :: PackageSet
const & pkgset
,
453 OpProgress
* Progress
)
455 if ( Progress
!= NULL
)
456 Progress
-> SubProgress ( Cache
. Head (). VersionCount
, _ ( "Send scenario to solver" ));
458 bool Okay
= output
. Failed () == false ;
459 for ( APT :: PackageSet :: const_iterator Pkg
= pkgset
. begin (); Pkg
!= pkgset
. end () && likely ( Okay
); ++ Pkg
, ++ p
)
460 for ( pkgCache :: VerIterator Ver
= Pkg
. VersionList (); Ver
. end () == false && likely ( Okay
); ++ Ver
)
462 if ( SkipUnavailableVersions ( Cache
, Pkg
, Ver
))
464 Okay
&= WriteScenarioVersion ( Cache
, output
, Pkg
, Ver
);
465 Okay
&= WriteScenarioLimitedDependency ( output
, Ver
, pkgset
);
466 WriteOkay ( Okay
, output
, " \n " );
467 if ( Progress
!= NULL
&& p
% 100 == 0 )
468 Progress
-> Progress ( p
);
470 if ( Progress
!= NULL
)
475 // EDSP::WriteRequest - to the given file descriptor /*{{{*/
476 bool EDSP :: WriteRequest ( pkgDepCache
& Cache
, FILE * output
, bool const Upgrade
,
477 bool const DistUpgrade
, bool const AutoRemove
,
478 OpProgress
* Progress
)
480 if ( Progress
!= NULL
)
481 Progress
-> SubProgress ( Cache
. Head (). PackageCount
, _ ( "Send request to solver" ));
484 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false ; ++ Pkg
, ++ p
)
486 if ( Progress
!= NULL
&& p
% 100 == 0 )
487 Progress
-> Progress ( p
);
489 pkgDepCache :: StateCache
& P
= Cache
[ Pkg
];
490 if ( P
. Delete () == true )
492 else if ( P
. NewInstall () == true || P
. Upgrade () == true || P
. ReInstall () == true ||
493 ( P
. Mode
== pkgDepCache :: ModeKeep
&& ( P
. iFlags
& pkgDepCache :: Protected
) == pkgDepCache :: Protected
))
497 req
-> append ( " " ). append ( Pkg
. FullName ());
499 fprintf ( output
, "Request: EDSP 0.5 \n " );
501 const char * arch
= _config
-> Find ( "APT::Architecture" ). c_str ();
502 std :: vector
< string
> archs
= APT :: Configuration :: getArchitectures ();
503 fprintf ( output
, "Architecture: %s \n " , arch
);
504 fprintf ( output
, "Architectures:" );
505 for ( std :: vector
< string
>:: const_iterator a
= archs
. begin (); a
!= archs
. end (); ++ a
)
506 fprintf ( output
, " %s " , a
-> c_str ());
507 fprintf ( output
, " \n " );
509 if ( del
. empty () == false )
510 fprintf ( output
, "Remove: %s \n " , del
. c_str ()+ 1 );
511 if ( inst
. empty () == false )
512 fprintf ( output
, "Install: %s \n " , inst
. c_str ()+ 1 );
514 fprintf ( output
, "Upgrade: yes \n " );
515 if ( DistUpgrade
== true )
516 fprintf ( output
, "Dist-Upgrade: yes \n " );
517 if ( AutoRemove
== true )
518 fprintf ( output
, "Autoremove: yes \n " );
519 auto const solver
= _config
-> Find ( "APT::Solver" , "internal" );
520 fprintf ( output
, "Solver: %s \n " , solver
. c_str ());
521 auto const solverconf
= std :: string ( "APT::Solver::" ) + solver
+ "::" ;
522 if ( _config
-> FindB ( solverconf
+ "Strict-Pinning" , _config
-> FindB ( "APT::Solver::Strict-Pinning" , true )) == false )
523 fprintf ( output
, "Strict-Pinning: no \n " );
524 auto const solverpref
= _config
-> Find ( solverconf
+ "Preferences" , _config
-> Find ( "APT::Solver::Preferences" , "" ));
525 if ( solverpref
. empty () == false )
526 fprintf ( output
, "Preferences: %s \n " , solverpref
. c_str ());
527 fprintf ( output
, " \n " );
530 bool EDSP :: WriteRequest ( pkgDepCache
& Cache
, FileFd
& output
, bool const Upgrade
,
531 bool const DistUpgrade
, bool const AutoRemove
,
532 OpProgress
* Progress
)
534 if ( Progress
!= NULL
)
535 Progress
-> SubProgress ( Cache
. Head (). PackageCount
, _ ( "Send request to solver" ));
538 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false ; ++ Pkg
, ++ p
)
540 if ( Progress
!= NULL
&& p
% 100 == 0 )
541 Progress
-> Progress ( p
);
543 pkgDepCache :: StateCache
& P
= Cache
[ Pkg
];
544 if ( P
. Delete () == true )
546 else if ( P
. NewInstall () == true || P
. Upgrade () == true || P
. ReInstall () == true ||
547 ( P
. Mode
== pkgDepCache :: ModeKeep
&& ( P
. iFlags
& pkgDepCache :: Protected
) == pkgDepCache :: Protected
))
551 req
-> append ( " " ). append ( Pkg
. FullName ());
553 bool Okay
= WriteOkay ( output
, "Request: EDSP 0.5 \n " );
555 const char * arch
= _config
-> Find ( "APT::Architecture" ). c_str ();
556 std :: vector
< string
> archs
= APT :: Configuration :: getArchitectures ();
557 WriteOkay ( Okay
, output
, "Architecture: " , arch
, " \n " ,
559 for ( std :: vector
< string
>:: const_iterator a
= archs
. begin (); a
!= archs
. end (); ++ a
)
560 WriteOkay ( Okay
, output
, " " , * a
);
561 WriteOkay ( Okay
, output
, " \n " );
563 if ( del
. empty () == false )
564 WriteOkay ( Okay
, output
, "Remove:" , del
, " \n " );
565 if ( inst
. empty () == false )
566 WriteOkay ( Okay
, output
, "Install:" , inst
, " \n " );
568 WriteOkay ( Okay
, output
, "Upgrade: yes \n " );
569 if ( DistUpgrade
== true )
570 WriteOkay ( Okay
, output
, "Dist-Upgrade: yes \n " );
571 if ( AutoRemove
== true )
572 WriteOkay ( Okay
, output
, "Autoremove: yes \n " );
573 if ( _config
-> FindB ( "APT::Solver::Strict-Pinning" , true ) == false )
574 WriteOkay ( Okay
, output
, "Strict-Pinning: no \n " );
575 string
solverpref ( "APT::Solver::" );
576 solverpref
. append ( _config
-> Find ( "APT::Solver" , "internal" )). append ( "::Preferences" );
577 if ( _config
-> Exists ( solverpref
) == true )
578 WriteOkay ( Okay
, output
, "Preferences: " , _config
-> Find ( solverpref
, "" ), " \n " );
579 return WriteOkay ( Okay
, output
, " \n " );
582 // EDSP::ReadResponse - from the given file descriptor /*{{{*/
583 bool EDSP :: ReadResponse ( int const input
, pkgDepCache
& Cache
, OpProgress
* Progress
) {
584 /* We build an map id to mmap offset here
585 In theory we could use the offset as ID, but then VersionCount
586 couldn't be used to create other versionmappings anymore and it
587 would be too easy for a (buggy) solver to segfault APT⦠*/
588 unsigned long long const VersionCount
= Cache
. Head (). VersionCount
;
589 unsigned long VerIdx
[ VersionCount
];
590 for ( pkgCache :: PkgIterator P
= Cache
. PkgBegin (); P
. end () == false ; ++ P
) {
591 for ( pkgCache :: VerIterator V
= P
. VersionList (); V
. end () == false ; ++ V
)
592 VerIdx
[ V
-> ID
] = V
. Index ();
593 Cache
[ P
]. Marked
= true ;
594 Cache
[ P
]. Garbage
= false ;
598 in
. OpenDescriptor ( input
, FileFd :: ReadOnly
);
599 pkgTagFile
response (& in
, 100 );
600 pkgTagSection section
;
602 std :: set
< decltype ( Cache
. PkgBegin ()-> ID
)> seenOnce
;
603 while ( response
. Step ( section
) == true ) {
605 if ( section
. Exists ( "Install" ) == true )
607 else if ( section
. Exists ( "Remove" ) == true )
609 else if ( section
. Exists ( "Progress" ) == true ) {
610 if ( Progress
!= NULL
) {
611 string msg
= section
. FindS ( "Message" );
612 if ( msg
. empty () == true )
613 msg
= _ ( "Prepare for receiving solution" );
614 Progress
-> SubProgress ( 100 , msg
, section
. FindI ( "Percentage" , 0 ));
617 } else if ( section
. Exists ( "Error" ) == true ) {
618 std :: string msg
= SubstVar ( SubstVar ( section
. FindS ( "Message" ), " \n . \n " , " \n\n " ), " \n " , " \n " );
619 if ( msg
. empty () == true ) {
620 msg
= _ ( "External solver failed without a proper error message" );
621 _error
-> Error ( " %s " , msg
. c_str ());
623 _error
-> Error ( "External solver failed with: %s " , msg
. substr ( 0 , msg
. find ( ' \n ' )). c_str ());
624 if ( Progress
!= NULL
)
626 std :: cerr
<< "The solver encountered an error of type: " << section
. FindS ( "Error" ) << std :: endl
;
627 std :: cerr
<< "The following information might help you to understand what is wrong:" << std :: endl
;
628 std :: cerr
<< msg
<< std :: endl
<< std :: endl
;
630 } else if ( section
. Exists ( "Autoremove" ) == true )
635 size_t const id
= section
. FindULL ( type
. c_str (), VersionCount
);
636 if ( id
== VersionCount
) {
637 _error
-> Warning ( "Unable to parse %s request with id value ' %s '!" , type
. c_str (), section
. FindS ( type
. c_str ()). c_str ());
639 } else if ( id
> Cache
. Head (). VersionCount
) {
640 _error
-> Warning ( "ID value ' %s ' in %s request stanza is to high to refer to a known version!" , section
. FindS ( type
. c_str ()). c_str (), type
. c_str ());
644 pkgCache :: VerIterator
Ver ( Cache
. GetCache (), Cache
. GetCache (). VerP
+ VerIdx
[ id
]);
645 auto const Pkg
= Ver
. ParentPkg ();
646 if ( type
== "Autoremove" ) {
647 Cache
[ Pkg
]. Marked
= false ;
648 Cache
[ Pkg
]. Garbage
= true ;
649 } else if ( seenOnce
. emplace ( Pkg
-> ID
). second
== false ) {
650 _error
-> Warning ( "Ignoring %s stanza received for package %s which already had a previous stanza effecting it!" , type
. c_str (), Pkg
. FullName ( false ). c_str ());
651 } else if ( type
== "Install" ) {
652 if ( Pkg
. CurrentVer () == Ver
) {
653 _error
-> Warning ( "Ignoring Install stanza received for version %s of package %s which is already installed!" ,
654 Ver
. VerStr (), Pkg
. FullName ( false ). c_str ());
656 Cache
. SetCandidateVersion ( Ver
);
657 Cache
. MarkInstall ( Pkg
, false , 0 , false );
659 } else if ( type
== "Remove" ) {
660 if ( Pkg
-> CurrentVer
== 0 )
661 _error
-> Warning ( "Ignoring Remove stanza received for version %s of package %s which isn't installed!" ,
662 Ver
. VerStr (), Pkg
. FullName ( false ). c_str ());
663 else if ( Pkg
. CurrentVer () != Ver
)
664 _error
-> Warning ( "Ignoring Remove stanza received for version %s of package %s which isn't the installed version %s !" ,
665 Ver
. VerStr (), Pkg
. FullName ( false ). c_str (), Pkg
. CurrentVer (). VerStr ());
667 Cache
. MarkDelete ( Ver
. ParentPkg (), false );
673 // ReadLine - first line from the given file descriptor /*{{{*/
674 // ---------------------------------------------------------------------
675 /* Little helper method to read a complete line into a string. Similar to
676 fgets but we need to use the low-level read() here as otherwise the
677 listparser will be confused later on as mixing of fgets and read isn't
678 a supported action according to the manpages and results are undefined */
679 static bool ReadLine ( int const input
, std :: string
& line
) {
684 while (( data
= read ( input
, & one
, sizeof ( one
))) != - 1 ) {
691 if ( line
. empty () == true && isblank ( one
) != 0 )
698 // StringToBool - convert yes/no to bool /*{{{*/
699 // ---------------------------------------------------------------------
700 /* we are not as lazy as we are in the global StringToBool as we really
701 only accept yes/no here - but we will ignore leading spaces */
702 static bool StringToBool ( char const * answer
, bool const defValue
) {
703 for (; isspace (* answer
) != 0 ; ++ answer
);
704 if ( strncasecmp ( answer
, "yes" , 3 ) == 0 )
706 else if ( strncasecmp ( answer
, "no" , 2 ) == 0 )
709 _error
-> Warning ( "Value ' %s ' is not a boolean 'yes' or 'no'!" , answer
);
713 // EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
714 bool EDSP :: ReadRequest ( int const input
, std :: list
< std :: string
> & install
,
715 std :: list
< std :: string
> & remove
, bool & upgrade
,
716 bool & distUpgrade
, bool & autoRemove
)
724 while ( ReadLine ( input
, line
) == true )
726 // Skip empty lines before request
727 if ( line
. empty () == true )
729 // The first Tag must be a request, so search for it
730 if ( line
. compare ( 0 , 8 , "Request:" ) != 0 )
733 while ( ReadLine ( input
, line
) == true )
735 // empty lines are the end of the request
736 if ( line
. empty () == true )
739 std :: list
< std :: string
> * request
= NULL
;
740 if ( line
. compare ( 0 , 8 , "Install:" ) == 0 )
745 else if ( line
. compare ( 0 , 7 , "Remove:" ) == 0 )
750 else if ( line
. compare ( 0 , 8 , "Upgrade:" ) == 0 )
751 upgrade
= StringToBool ( line
. c_str () + 9 , false );
752 else if ( line
. compare ( 0 , 13 , "Dist-Upgrade:" ) == 0 )
753 distUpgrade
= StringToBool ( line
. c_str () + 14 , false );
754 else if ( line
. compare ( 0 , 11 , "Autoremove:" ) == 0 )
755 autoRemove
= StringToBool ( line
. c_str () + 12 , false );
756 else if ( line
. compare ( 0 , 13 , "Architecture:" ) == 0 )
757 _config
-> Set ( "APT::Architecture" , line
. c_str () + 14 );
758 else if ( line
. compare ( 0 , 14 , "Architectures:" ) == 0 )
760 std :: string
const archs
= line
. c_str () + 15 ;
761 _config
-> Set ( "APT::Architectures" , SubstVar ( archs
, " " , "," ));
763 else if ( line
. compare ( 0 , 7 , "Solver:" ) == 0 )
764 ; // purely informational line
766 _error
-> Warning ( "Unknown line in EDSP Request stanza: %s " , line
. c_str ());
770 size_t end
= line
. length ();
772 size_t begin
= line
. rfind ( ' ' );
773 if ( begin
== std :: string :: npos
)
775 request
-> push_back ( line
. substr ( 0 , end
));
778 else if ( begin
< end
)
779 request
-> push_back ( line
. substr ( begin
+ 1 , end
));
781 end
= line
. find_last_not_of ( ' ' );
782 } while ( end
!= std :: string :: npos
);
788 // EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/
789 bool EDSP :: ApplyRequest ( std :: list
< std :: string
> const & install
,
790 std :: list
< std :: string
> const & remove
,
793 for ( std :: list
< std :: string
>:: const_iterator i
= install
. begin ();
794 i
!= install
. end (); ++ i
) {
795 pkgCache :: PkgIterator P
= Cache
. FindPkg (* i
);
797 _error
-> Warning ( "Package %s is not known, so can't be installed" , i
-> c_str ());
799 Cache
. MarkInstall ( P
, false );
802 for ( std :: list
< std :: string
>:: const_iterator i
= remove
. begin ();
803 i
!= remove
. end (); ++ i
) {
804 pkgCache :: PkgIterator P
= Cache
. FindPkg (* i
);
806 _error
-> Warning ( "Package %s is not known, so can't be installed" , i
-> c_str ());
813 // EDSP::WriteSolution - to the given file descriptor /*{{{*/
814 bool EDSP :: WriteSolution ( pkgDepCache
& Cache
, FILE * output
)
816 bool const Debug
= _config
-> FindB ( "Debug::EDSP::WriteSolution" , false );
817 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false ; ++ Pkg
)
819 if ( Cache
[ Pkg
]. Delete () == true )
821 fprintf ( output
, "Remove: %d \n " , Pkg
. CurrentVer ()-> ID
);
823 fprintf ( output
, "Package: %s \n Version: %s \n " , Pkg
. FullName (). c_str (), Pkg
. CurrentVer (). VerStr ());
825 else if ( Cache
[ Pkg
]. NewInstall () == true || Cache
[ Pkg
]. Upgrade () == true )
827 pkgCache :: VerIterator
const CandVer
= Cache
. GetCandidateVersion ( Pkg
);
828 fprintf ( output
, "Install: %d \n " , CandVer
-> ID
);
830 fprintf ( output
, "Package: %s \n Version: %s \n " , Pkg
. FullName (). c_str (), CandVer
. VerStr ());
832 else if ( Cache
[ Pkg
]. Garbage
== true )
834 fprintf ( output
, "Autoremove: %d \n " , Pkg
. CurrentVer ()-> ID
);
836 fprintf ( output
, "Package: %s \n Version: %s \n " , Pkg
. FullName (). c_str (), Pkg
. CurrentVer (). VerStr ());
840 fprintf ( output
, " \n " );
845 bool EDSP :: WriteSolution ( pkgDepCache
& Cache
, FileFd
& output
)
847 bool const Debug
= _config
-> FindB ( "Debug::EDSP::WriteSolution" , false );
848 bool Okay
= output
. Failed () == false ;
849 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false && likely ( Okay
); ++ Pkg
)
852 if ( Cache
[ Pkg
]. Delete () == true )
853 WriteOkay ( Okay
, output
, "Remove: " , Pkg
. CurrentVer ()-> ID
, " \n " );
854 else if ( Cache
[ Pkg
]. NewInstall () == true || Cache
[ Pkg
]. Upgrade () == true )
855 WriteOkay ( Okay
, output
, "Install: " , Cache
. GetCandidateVersion ( Pkg
)-> ID
, " \n " );
856 else if ( Cache
[ Pkg
]. Garbage
== true )
857 WriteOkay ( Okay
, output
, "Autoremove: " , Pkg
. CurrentVer ()-> ID
, " \n " );
863 WriteOkay ( Okay
, output
, "Package: " , Pkg
. FullName (), " \n Version: " );
864 if ( Cache
[ Pkg
]. Delete () == true || Cache
[ Pkg
]. Garbage
== true )
865 WriteOkay ( Okay
, output
, Pkg
. CurrentVer (). VerStr (), " \n\n " );
867 WriteOkay ( Okay
, output
, Cache
. GetCandidateVersion ( Pkg
). VerStr (), " \n\n " );
870 WriteOkay ( Okay
, output
, " \n " );
875 // EDSP::WriteProgess - pulse to the given file descriptor /*{{{*/
876 bool EDSP :: WriteProgress ( unsigned short const percent
, const char * const message
, FILE * output
) {
877 fprintf ( output
, "Progress: %s \n " , TimeRFC1123 ( time ( NULL
)). c_str ());
878 fprintf ( output
, "Percentage: %d \n " , percent
);
879 fprintf ( output
, "Message: %s \n\n " , message
);
883 bool EDSP :: WriteProgress ( unsigned short const percent
, const char * const message
, FileFd
& output
) {
884 return WriteOkay ( output
, "Progress: " , TimeRFC1123 ( time ( NULL
)), " \n " ,
885 "Percentage: " , percent
, " \n " ,
886 "Message: " , message
, " \n\n " ) && output
. Flush ();
889 // EDSP::WriteError - format an error message to be send to file descriptor /*{{{*/
890 bool EDSP :: WriteError ( char const * const uuid
, std :: string
const & message
, FILE * output
) {
891 fprintf ( output
, "Error: %s \n " , uuid
);
892 fprintf ( output
, "Message: %s \n\n " , SubstVar ( SubstVar ( message
, " \n\n " , " \n . \n " ), " \n " , " \n " ). c_str ());
895 bool EDSP :: WriteError ( char const * const uuid
, std :: string
const & message
, FileFd
& output
) {
896 return WriteOkay ( output
, "Error: " , uuid
, " \n " ,
897 "Message: " , SubstVar ( SubstVar ( message
, " \n\n " , " \n . \n " ), " \n " , " \n " ),
901 // EDSP::ExecuteSolver - fork requested solver and setup ipc pipes {{{*/
902 pid_t
EDSP :: ExecuteSolver ( const char * const solver
, int * const solver_in
, int * const solver_out
, bool ) {
903 std :: vector
< std :: string
> const solverDirs
= _config
-> FindVector ( "Dir::Bin::Solvers" );
905 for ( std :: vector
< std :: string
>:: const_iterator dir
= solverDirs
. begin ();
906 dir
!= solverDirs
. end (); ++ dir
) {
907 file
= flCombine (* dir
, solver
);
908 if ( RealFileExists ( file
. c_str ()) == true )
913 if ( file
. empty () == true )
915 _error
-> Error ( "Can't call external solver ' %s ' as it is not in a configured directory!" , solver
);
918 int external
[ 4 ] = {- 1 , - 1 , - 1 , - 1 };
919 if ( pipe ( external
) != 0 || pipe ( external
+ 2 ) != 0 )
921 _error
-> Errno ( "Resolve" , "Can't create needed IPC pipes for EDSP" );
924 for ( int i
= 0 ; i
< 4 ; ++ i
)
925 SetCloseExec ( external
[ i
], true );
927 pid_t Solver
= ExecFork ();
929 dup2 ( external
[ 0 ], STDIN_FILENO
);
930 dup2 ( external
[ 3 ], STDOUT_FILENO
);
931 const char * calling
[ 2 ] = { file
. c_str (), 0 };
932 execv ( calling
[ 0 ], ( char **) calling
);
933 std :: cerr
<< "Failed to execute solver '" << solver
<< "'!" << std :: endl
;
939 if ( WaitFd ( external
[ 1 ], true , 5 ) == false )
941 _error
-> Errno ( "Resolve" , "Timed out while Waiting on availability of solver stdin" );
945 * solver_in
= external
[ 1 ];
946 * solver_out
= external
[ 2 ];
949 bool EDSP :: ExecuteSolver ( const char * const solver
, int * solver_in
, int * solver_out
) {
950 if ( ExecuteSolver ( solver
, solver_in
, solver_out
, true ) == 0 )
955 // EDSP::ResolveExternal - resolve problems by asking external for help {{{*/
956 bool EDSP :: ResolveExternal ( const char * const solver
, pkgDepCache
& Cache
,
957 bool const upgrade
, bool const distUpgrade
,
958 bool const autoRemove
, OpProgress
* Progress
) {
959 int solver_in
, solver_out
;
960 pid_t
const solver_pid
= EDSP :: ExecuteSolver ( solver
, & solver_in
, & solver_out
, true );
965 if ( output
. OpenDescriptor ( solver_in
, FileFd :: WriteOnly
| FileFd :: BufferedWrite
, true ) == false )
966 return _error
-> Errno ( "ResolveExternal" , "Opening solver %s stdin on fd %d for writing failed" , solver
, solver_in
);
968 bool Okay
= output
. Failed () == false ;
969 if ( Progress
!= NULL
)
970 Progress
-> OverallProgress ( 0 , 100 , 5 , _ ( "Execute external solver" ));
971 Okay
&= EDSP :: WriteRequest ( Cache
, output
, upgrade
, distUpgrade
, autoRemove
, Progress
);
972 if ( Progress
!= NULL
)
973 Progress
-> OverallProgress ( 5 , 100 , 20 , _ ( "Execute external solver" ));
974 Okay
&= EDSP :: WriteScenario ( Cache
, output
, Progress
);
977 if ( Progress
!= NULL
)
978 Progress
-> OverallProgress ( 25 , 100 , 75 , _ ( "Execute external solver" ));
979 if ( Okay
&& EDSP :: ReadResponse ( solver_out
, Cache
, Progress
) == false )
982 return ExecWait ( solver_pid
, solver
);