]>
git.saurik.com Git - apt.git/blob - apt-pkg/edsp.cc
e37ab04b4731497e0ec6668f8b2d01d793f03443
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>
20 #include <apt-pkg/string_view.h>
21 #include <apt-pkg/pkgsystem.h>
39 // we could use pkgCache::DepType and ::Priority, but these would be localized strings…
40 constexpr char const * const PrioMap
[] = {
41 nullptr , "important" , "required" , "standard" ,
44 constexpr char const * const DepMap
[] = {
45 nullptr , "Depends" , "Pre-Depends" , "Suggests" ,
46 "Recommends" , "Conflicts" , "Replaces" ,
47 "Obsoletes" , "Breaks" , "Enhances"
50 // WriteOkay - varaidic helper to easily Write to a FileFd /*{{{*/
51 static bool WriteOkay_fn ( FileFd
&) { return true ; }
52 template < typename
... Tail
> static bool WriteOkay_fn ( FileFd
& output
, APT :: StringView data
, Tail
... more_data
)
54 return likely ( output
. Write ( data
. data (), data
. length ()) && WriteOkay_fn ( output
, more_data
...));
56 template < typename
... Tail
> static bool WriteOkay_fn ( FileFd
& output
, unsigned int data
, Tail
... more_data
)
59 strprintf ( number
, " %d " , data
);
60 return likely ( output
. Write ( number
. data (), number
. length ()) && WriteOkay_fn ( output
, more_data
...));
62 template < typename
... Data
> static bool WriteOkay ( bool & Okay
, FileFd
& output
, Data
&&... data
)
64 Okay
= likely ( Okay
&& WriteOkay_fn ( output
, std :: forward
< Data
>( data
)...));
67 template < typename
... Data
> static bool WriteOkay ( FileFd
& output
, Data
&&... data
)
69 bool Okay
= likely ( output
. Failed () == false );
70 return WriteOkay ( Okay
, output
, std :: forward
< Data
>( data
)...);
73 // WriteScenarioVersion /*{{{*/
74 static void WriteScenarioVersion ( pkgDepCache
& Cache
, FILE * output
, pkgCache :: PkgIterator
const & Pkg
,
75 pkgCache :: VerIterator
const & Ver
)
77 fprintf ( output
, "Package: %s \n " , Pkg
. Name ());
78 fprintf ( output
, "Source: %s \n " , Ver
. SourcePkgName ());
79 fprintf ( output
, "Architecture: %s \n " , Ver
. Arch ());
80 fprintf ( output
, "Version: %s \n " , Ver
. VerStr ());
81 fprintf ( output
, "Source-Version: %s \n " , Ver
. SourceVerStr ());
82 if ( Pkg
. CurrentVer () == Ver
)
83 fprintf ( output
, "Installed: yes \n " );
84 if ( Pkg
-> SelectedState
== pkgCache :: State :: Hold
||
85 ( Cache
[ Pkg
]. Keep () == true && Cache
[ Pkg
]. Protect () == true ))
86 fprintf ( output
, "Hold: yes \n " );
87 fprintf ( output
, "APT-ID: %d \n " , Ver
-> ID
);
88 if ( PrioMap
[ Ver
-> Priority
] != nullptr )
89 fprintf ( output
, "Priority: %s \n " , PrioMap
[ Ver
-> Priority
]);
90 if (( Pkg
-> Flags
& pkgCache :: Flag :: Essential
) == pkgCache :: Flag :: Essential
)
91 fprintf ( output
, "Essential: yes \n " );
92 if ( Ver
-> Section
!= 0 )
93 fprintf ( output
, "Section: %s \n " , Ver
. Section ());
94 if (( Ver
-> MultiArch
& pkgCache :: Version :: Allowed
) == pkgCache :: Version :: Allowed
)
95 fprintf ( output
, "Multi-Arch: allowed \n " );
96 else if (( Ver
-> MultiArch
& pkgCache :: Version :: Foreign
) == pkgCache :: Version :: Foreign
)
97 fprintf ( output
, "Multi-Arch: foreign \n " );
98 else if (( Ver
-> MultiArch
& pkgCache :: Version :: Same
) == pkgCache :: Version :: Same
)
99 fprintf ( output
, "Multi-Arch: same \n " );
100 std :: set
< string
> Releases
;
101 for ( pkgCache :: VerFileIterator I
= Ver
. FileList (); I
. end () == false ; ++ I
) {
102 pkgCache :: PkgFileIterator File
= I
. File ();
103 if ( File
. Flagged ( pkgCache :: Flag :: NotSource
) == false ) {
104 string Release
= File
. RelStr ();
105 if (! Release
. empty ())
106 Releases
. insert ( Release
);
109 if (! Releases
. empty ()) {
110 fprintf ( output
, "APT-Release: \n " );
111 for ( std :: set
< string
>:: iterator R
= Releases
. begin (); R
!= Releases
. end (); ++ R
)
112 fprintf ( output
, " %s \n " , R
-> c_str ());
114 fprintf ( output
, "APT-Pin: %d \n " , Cache
. GetPolicy (). GetPriority ( Ver
));
115 if ( Cache
. GetCandidateVersion ( Pkg
) == Ver
)
116 fprintf ( output
, "APT-Candidate: yes \n " );
117 if (( Cache
[ Pkg
]. Flags
& pkgCache :: Flag :: Auto
) == pkgCache :: Flag :: Auto
)
118 fprintf ( output
, "APT-Automatic: yes \n " );
120 static bool WriteScenarioVersion ( FileFd
& output
, pkgCache :: PkgIterator
const & Pkg
,
121 pkgCache :: VerIterator
const & Ver
)
123 bool Okay
= WriteOkay ( output
, "Package: " , Pkg
. Name (),
124 " \n Architecture: " , Ver
. Arch (),
125 " \n Version: " , Ver
. VerStr ());
126 WriteOkay ( Okay
, output
, " \n APT-ID: " , Ver
-> ID
);
127 if (( Pkg
-> Flags
& pkgCache :: Flag :: Essential
) == pkgCache :: Flag :: Essential
)
128 WriteOkay ( Okay
, output
, " \n Essential: yes" );
129 if (( Ver
-> MultiArch
& pkgCache :: Version :: Allowed
) == pkgCache :: Version :: Allowed
)
130 WriteOkay ( Okay
, output
, " \n Multi-Arch: allowed" );
131 else if (( Ver
-> MultiArch
& pkgCache :: Version :: Foreign
) == pkgCache :: Version :: Foreign
)
132 WriteOkay ( Okay
, output
, " \n Multi-Arch: foreign" );
133 else if (( Ver
-> MultiArch
& pkgCache :: Version :: Same
) == pkgCache :: Version :: Same
)
134 WriteOkay ( Okay
, output
, " \n Multi-Arch: same" );
138 // WriteScenarioDependency /*{{{*/
139 static void WriteScenarioDependency ( FILE * output
, pkgCache :: VerIterator
const & Ver
)
141 std :: array
< std :: string
, _count ( DepMap
)> dependencies
;
142 bool orGroup
= false ;
143 for ( pkgCache :: DepIterator Dep
= Ver
. DependsList (); Dep
. end () == false ; ++ Dep
)
145 if ( Dep
. IsImplicit () == true )
147 if ( orGroup
== false )
148 dependencies
[ Dep
-> Type
]. append ( ", " );
149 dependencies
[ Dep
-> Type
]. append ( Dep
. TargetPkg (). Name ());
150 if ( Dep
-> Version
!= 0 )
151 dependencies
[ Dep
-> Type
]. append ( " (" ). append ( pkgCache :: CompTypeDeb ( Dep
-> CompareOp
)). append ( " " ). append ( Dep
. TargetVer ()). append ( ")" );
152 if (( Dep
-> CompareOp
& pkgCache :: Dep :: Or
) == pkgCache :: Dep :: Or
)
154 dependencies
[ Dep
-> Type
]. append ( " | " );
160 for ( size_t i
= 1 ; i
< dependencies
. size (); ++ i
)
161 if ( dependencies
[ i
]. empty () == false )
162 fprintf ( output
, " %s : %s \n " , DepMap
[ i
], dependencies
[ i
]. c_str ()+ 2 );
164 for ( pkgCache :: PrvIterator Prv
= Ver
. ProvidesList (); Prv
. end () == false ; ++ Prv
)
166 if ( Prv
. IsMultiArchImplicit () == true )
168 if ( provides
. empty () == false )
169 provides
. append ( ", " );
170 provides
. append ( Prv
. Name ());
171 if ( Prv
-> ProvideVersion
!= 0 )
172 provides
. append ( " (= " ). append ( Prv
. ProvideVersion ()). append ( ")" );
174 if ( provides
. empty () == false )
175 fprintf ( output
, "Provides: %s \n " , provides
. c_str ());
177 static bool WriteScenarioDependency ( FileFd
& output
, pkgCache :: VerIterator
const & Ver
, bool const OnlyCritical
)
179 std :: array
< std :: string
, _count ( DepMap
)> dependencies
;
180 bool orGroup
= false ;
181 for ( pkgCache :: DepIterator Dep
= Ver
. DependsList (); Dep
. end () == false ; ++ Dep
)
183 if ( Dep
. IsImplicit () == true )
185 if ( OnlyCritical
&& Dep
. IsCritical () == false )
187 if ( orGroup
== false && dependencies
[ Dep
-> Type
]. empty () == false )
188 dependencies
[ Dep
-> Type
]. append ( ", " );
189 dependencies
[ Dep
-> Type
]. append ( Dep
. TargetPkg (). Name ());
190 if ( Dep
-> Version
!= 0 )
191 dependencies
[ Dep
-> Type
]. append ( " (" ). append ( pkgCache :: CompTypeDeb ( Dep
-> CompareOp
)). append ( " " ). append ( Dep
. TargetVer ()). append ( ")" );
192 if (( Dep
-> CompareOp
& pkgCache :: Dep :: Or
) == pkgCache :: Dep :: Or
)
194 dependencies
[ Dep
-> Type
]. append ( " | " );
200 bool Okay
= output
. Failed () == false ;
201 for ( size_t i
= 1 ; i
< dependencies
. size (); ++ i
)
202 if ( dependencies
[ i
]. empty () == false )
203 WriteOkay ( Okay
, output
, " \n " , DepMap
[ i
], ": " , dependencies
[ i
]);
205 for ( pkgCache :: PrvIterator Prv
= Ver
. ProvidesList (); Prv
. end () == false ; ++ Prv
)
207 if ( Prv
. IsMultiArchImplicit () == true )
209 if ( provides
. empty () == false )
210 provides
. append ( ", " );
211 provides
. append ( Prv
. Name ());
212 if ( Prv
-> ProvideVersion
!= 0 )
213 provides
. append ( " (= " ). append ( Prv
. ProvideVersion ()). append ( ")" );
215 if ( provides
. empty () == false )
216 WriteOkay ( Okay
, output
, " \n Provides: " , provides
);
217 return WriteOkay ( Okay
, output
, " \n " );
220 // WriteScenarioLimitedDependency /*{{{*/
221 static void WriteScenarioLimitedDependency ( FILE * output
,
222 pkgCache :: VerIterator
const & Ver
,
223 APT :: PackageSet
const & pkgset
)
225 std :: array
< std :: string
, _count ( DepMap
)> dependencies
;
226 bool orGroup
= false ;
227 for ( pkgCache :: DepIterator Dep
= Ver
. DependsList (); Dep
. end () == false ; ++ Dep
)
229 if ( Dep
. IsImplicit () == true )
231 if ( orGroup
== false )
233 if ( pkgset
. find ( Dep
. TargetPkg ()) == pkgset
. end ())
235 if ( dependencies
[ Dep
-> Type
]. empty () == false )
236 dependencies
[ Dep
-> Type
]. append ( ", " );
238 else if ( pkgset
. find ( Dep
. TargetPkg ()) == pkgset
. end ())
240 if (( Dep
-> CompareOp
& pkgCache :: Dep :: Or
) == pkgCache :: Dep :: Or
)
242 dependencies
[ Dep
-> Type
]. erase ( dependencies
[ Dep
-> Type
]. end ()- 3 , dependencies
[ Dep
-> Type
]. end ());
246 dependencies
[ Dep
-> Type
]. append ( Dep
. TargetPkg (). Name ());
247 if ( Dep
-> Version
!= 0 )
248 dependencies
[ Dep
-> Type
]. append ( " (" ). append ( pkgCache :: CompTypeDeb ( Dep
-> CompareOp
)). append ( " " ). append ( Dep
. TargetVer ()). append ( ")" );
249 if (( Dep
-> CompareOp
& pkgCache :: Dep :: Or
) == pkgCache :: Dep :: Or
)
251 dependencies
[ Dep
-> Type
]. append ( " | " );
257 for ( size_t i
= 1 ; i
< dependencies
. size (); ++ i
)
258 if ( dependencies
[ i
]. empty () == false )
259 fprintf ( output
, " %s : %s \n " , DepMap
[ i
], dependencies
[ i
]. c_str ());
261 for ( pkgCache :: PrvIterator Prv
= Ver
. ProvidesList (); Prv
. end () == false ; ++ Prv
)
263 if ( Prv
. IsMultiArchImplicit () == true )
265 if ( pkgset
. find ( Prv
. ParentPkg ()) == pkgset
. end ())
267 if ( provides
. empty () == false )
268 provides
. append ( ", " );
269 provides
. append ( Prv
. Name ());
270 if ( Prv
-> ProvideVersion
!= 0 )
271 provides
. append ( " (= " ). append ( Prv
. ProvideVersion ()). append ( ")" );
273 if ( provides
. empty () == false )
274 fprintf ( output
, "Provides: %s \n " , provides
. c_str ());
276 static bool WriteScenarioLimitedDependency ( FileFd
& output
,
277 pkgCache :: VerIterator
const & Ver
,
278 std :: vector
< bool > const & pkgset
,
279 bool const OnlyCritical
)
281 std :: array
< std :: string
, _count ( DepMap
)> dependencies
;
282 bool orGroup
= false ;
283 for ( pkgCache :: DepIterator Dep
= Ver
. DependsList (); Dep
. end () == false ; ++ Dep
)
285 if ( Dep
. IsImplicit () == true )
287 if ( OnlyCritical
&& Dep
. IsCritical () == false )
289 if ( orGroup
== false )
291 if ( pkgset
[ Dep
. TargetPkg ()-> ID
] == false )
293 if ( dependencies
[ Dep
-> Type
]. empty () == false )
294 dependencies
[ Dep
-> Type
]. append ( ", " );
296 else if ( pkgset
[ Dep
. TargetPkg ()-> ID
] == false )
298 if (( Dep
-> CompareOp
& pkgCache :: Dep :: Or
) == pkgCache :: Dep :: Or
)
300 dependencies
[ Dep
-> Type
]. erase ( dependencies
[ Dep
-> Type
]. end ()- 3 , dependencies
[ Dep
-> Type
]. end ());
304 dependencies
[ Dep
-> Type
]. append ( Dep
. TargetPkg (). Name ());
305 if ( Dep
-> Version
!= 0 )
306 dependencies
[ Dep
-> Type
]. append ( " (" ). append ( pkgCache :: CompTypeDeb ( Dep
-> CompareOp
)). append ( " " ). append ( Dep
. TargetVer ()). append ( ")" );
307 if (( Dep
-> CompareOp
& pkgCache :: Dep :: Or
) == pkgCache :: Dep :: Or
)
309 dependencies
[ Dep
-> Type
]. append ( " | " );
315 bool Okay
= output
. Failed () == false ;
316 for ( size_t i
= 1 ; i
< dependencies
. size (); ++ i
)
317 if ( dependencies
[ i
]. empty () == false )
318 WriteOkay ( Okay
, output
, " \n " , DepMap
[ i
], ": " , dependencies
[ i
]);
320 for ( pkgCache :: PrvIterator Prv
= Ver
. ProvidesList (); Prv
. end () == false ; ++ Prv
)
322 if ( Prv
. IsMultiArchImplicit () == true )
324 if ( pkgset
[ Prv
. ParentPkg ()-> ID
] == false )
326 if ( provides
. empty () == false )
327 provides
. append ( ", " );
328 provides
. append ( Prv
. Name ());
329 if ( Prv
-> ProvideVersion
!= 0 )
330 provides
. append ( " (= " ). append ( Prv
. ProvideVersion ()). append ( ")" );
332 if ( provides
. empty () == false )
333 WriteOkay ( Okay
, output
, " \n Provides: " , provides
);
334 return WriteOkay ( Okay
, output
, " \n " );
337 static bool SkipUnavailableVersions ( pkgDepCache
& Cache
, pkgCache :: PkgIterator
const & Pkg
, pkgCache :: VerIterator
const & Ver
) /*{{{*/
339 /* versions which aren't current and aren't available in
340 any "online" source file are bad, expect if they are the choosen
341 candidate: The exception is for build-dep implementation as it creates
342 such pseudo (package) versions and removes them later on again.
343 We filter out versions at all so packages in 'rc' state only available
344 in dpkg/status aren't passed to solvers as they can't be installed. */
345 if ( Pkg
-> CurrentVer
!= 0 )
347 if ( Cache
. GetCandidateVersion ( Pkg
) == Ver
)
349 for ( pkgCache :: VerFileIterator I
= Ver
. FileList (); I
. end () == false ; ++ I
)
350 if ( I
. File (). Flagged ( pkgCache :: Flag :: NotSource
) == false )
355 static bool WriteScenarioEDSPVersion ( pkgDepCache
& Cache
, FileFd
& output
, pkgCache :: PkgIterator
const & Pkg
, /*{{{*/
356 pkgCache :: VerIterator
const & Ver
)
358 bool Okay
= WriteOkay ( output
, " \n Source: " , Ver
. SourcePkgName (),
359 " \n Source-Version: " , Ver
. SourceVerStr ());
360 if ( PrioMap
[ Ver
-> Priority
] != nullptr )
361 WriteOkay ( Okay
, output
, " \n Priority: " , PrioMap
[ Ver
-> Priority
]);
362 if ( Ver
-> Section
!= 0 )
363 WriteOkay ( Okay
, output
, " \n Section: " , Ver
. Section ());
364 if ( Pkg
. CurrentVer () == Ver
)
365 WriteOkay ( Okay
, output
, " \n Installed: yes" );
366 if ( Pkg
-> SelectedState
== pkgCache :: State :: Hold
||
367 ( Cache
[ Pkg
]. Keep () == true && Cache
[ Pkg
]. Protect () == true ))
368 WriteOkay ( Okay
, output
, " \n Hold: yes" );
369 std :: set
< string
> Releases
;
370 for ( pkgCache :: VerFileIterator I
= Ver
. FileList (); I
. end () == false ; ++ I
) {
371 pkgCache :: PkgFileIterator File
= I
. File ();
372 if ( File
. Flagged ( pkgCache :: Flag :: NotSource
) == false ) {
373 string Release
= File
. RelStr ();
374 if (! Release
. empty ())
375 Releases
. insert ( Release
);
378 if (! Releases
. empty ()) {
379 WriteOkay ( Okay
, output
, " \n APT-Release:" );
380 for ( std :: set
< string
>:: iterator R
= Releases
. begin (); R
!= Releases
. end (); ++ R
)
381 WriteOkay ( Okay
, output
, " \n " , * R
);
383 WriteOkay ( Okay
, output
, " \n APT-Pin: " , Cache
. GetPolicy (). GetPriority ( Ver
));
384 if ( Cache
. GetCandidateVersion ( Pkg
) == Ver
)
385 WriteOkay ( Okay
, output
, " \n APT-Candidate: yes" );
386 if (( Cache
[ Pkg
]. Flags
& pkgCache :: Flag :: Auto
) == pkgCache :: Flag :: Auto
)
387 WriteOkay ( Okay
, output
, " \n APT-Automatic: yes" );
391 // EDSP::WriteScenario - to the given file descriptor /*{{{*/
392 bool EDSP :: WriteScenario ( pkgDepCache
& Cache
, FILE * output
, OpProgress
* Progress
)
394 if ( Progress
!= NULL
)
395 Progress
-> SubProgress ( Cache
. Head (). VersionCount
, _ ( "Send scenario to solver" ));
397 std :: vector
< std :: string
> archs
= APT :: Configuration :: getArchitectures ();
398 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false ; ++ Pkg
)
400 std :: string
const arch
= Pkg
. Arch ();
401 if ( std :: find ( archs
. begin (), archs
. end (), arch
) == archs
. end ())
403 for ( pkgCache :: VerIterator Ver
= Pkg
. VersionList (); Ver
. end () == false ; ++ Ver
, ++ p
)
405 if ( SkipUnavailableVersions ( Cache
, Pkg
, Ver
))
407 WriteScenarioVersion ( Cache
, output
, Pkg
, Ver
);
408 WriteScenarioDependency ( output
, Ver
);
409 fprintf ( output
, " \n " );
410 if ( Progress
!= NULL
&& p
% 100 == 0 )
411 Progress
-> Progress ( p
);
416 bool EDSP :: WriteScenario ( pkgDepCache
& Cache
, FileFd
& output
, OpProgress
* Progress
)
418 if ( Progress
!= NULL
)
419 Progress
-> SubProgress ( Cache
. Head (). VersionCount
, _ ( "Send scenario to solver" ));
421 bool Okay
= output
. Failed () == false ;
422 std :: vector
< std :: string
> archs
= APT :: Configuration :: getArchitectures ();
423 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false && likely ( Okay
); ++ Pkg
)
425 std :: string
const arch
= Pkg
. Arch ();
426 if ( std :: find ( archs
. begin (), archs
. end (), arch
) == archs
. end ())
428 for ( pkgCache :: VerIterator Ver
= Pkg
. VersionList (); Ver
. end () == false && likely ( Okay
); ++ Ver
, ++ p
)
430 if ( SkipUnavailableVersions ( Cache
, Pkg
, Ver
))
432 Okay
&= WriteScenarioVersion ( output
, Pkg
, Ver
);
433 Okay
&= WriteScenarioEDSPVersion ( Cache
, output
, Pkg
, Ver
);
434 Okay
&= WriteScenarioDependency ( output
, Ver
, false );
435 WriteOkay ( Okay
, output
, " \n " );
436 if ( Progress
!= NULL
&& p
% 100 == 0 )
437 Progress
-> Progress ( p
);
443 // EDSP::WriteLimitedScenario - to the given file descriptor /*{{{*/
444 bool EDSP :: WriteLimitedScenario ( pkgDepCache
& Cache
, FILE * output
,
445 APT :: PackageSet
const & pkgset
,
446 OpProgress
* Progress
)
448 if ( Progress
!= NULL
)
449 Progress
-> SubProgress ( Cache
. Head (). VersionCount
, _ ( "Send scenario to solver" ));
451 for ( APT :: PackageSet :: const_iterator Pkg
= pkgset
. begin (); Pkg
!= pkgset
. end (); ++ Pkg
, ++ p
)
452 for ( pkgCache :: VerIterator Ver
= Pkg
. VersionList (); Ver
. end () == false ; ++ Ver
)
454 if ( SkipUnavailableVersions ( Cache
, Pkg
, Ver
))
456 WriteScenarioVersion ( Cache
, output
, Pkg
, Ver
);
457 WriteScenarioLimitedDependency ( output
, Ver
, pkgset
);
458 fprintf ( output
, " \n " );
459 if ( Progress
!= NULL
&& p
% 100 == 0 )
460 Progress
-> Progress ( p
);
462 if ( Progress
!= NULL
)
466 bool EDSP :: WriteLimitedScenario ( pkgDepCache
& Cache
, FileFd
& output
,
467 std :: vector
< bool > const & pkgset
,
468 OpProgress
* Progress
)
470 if ( Progress
!= NULL
)
471 Progress
-> SubProgress ( Cache
. Head (). VersionCount
, _ ( "Send scenario to solver" ));
473 bool Okay
= output
. Failed () == false ;
474 for ( auto Pkg
= Cache
. PkgBegin (); Pkg
. end () == false && likely ( Okay
); ++ Pkg
, ++ p
)
476 if ( pkgset
[ Pkg
-> ID
] == false )
478 for ( pkgCache :: VerIterator Ver
= Pkg
. VersionList (); Ver
. end () == false && likely ( Okay
); ++ Ver
)
480 if ( SkipUnavailableVersions ( Cache
, Pkg
, Ver
))
482 Okay
&= WriteScenarioVersion ( output
, Pkg
, Ver
);
483 Okay
&= WriteScenarioEDSPVersion ( Cache
, output
, Pkg
, Ver
);
484 Okay
&= WriteScenarioLimitedDependency ( output
, Ver
, pkgset
, false );
485 WriteOkay ( Okay
, output
, " \n " );
486 if ( Progress
!= NULL
&& p
% 100 == 0 )
487 Progress
-> Progress ( p
);
490 if ( Progress
!= NULL
)
495 // EDSP::WriteRequest - to the given file descriptor /*{{{*/
496 bool EDSP :: WriteRequest ( pkgDepCache
& Cache
, FILE * output
, bool const Upgrade
,
497 bool const DistUpgrade
, bool const AutoRemove
,
498 OpProgress
* Progress
)
500 if ( Progress
!= NULL
)
501 Progress
-> SubProgress ( Cache
. Head (). PackageCount
, _ ( "Send request to solver" ));
504 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false ; ++ Pkg
, ++ p
)
506 if ( Progress
!= NULL
&& p
% 100 == 0 )
507 Progress
-> Progress ( p
);
509 pkgDepCache :: StateCache
& P
= Cache
[ Pkg
];
510 if ( P
. Delete () == true )
512 else if ( P
. NewInstall () == true || P
. Upgrade () == true || P
. ReInstall () == true ||
513 ( P
. Mode
== pkgDepCache :: ModeKeep
&& ( P
. iFlags
& pkgDepCache :: Protected
) == pkgDepCache :: Protected
))
517 req
-> append ( " " ). append ( Pkg
. FullName ());
519 fprintf ( output
, "Request: EDSP 0.5 \n " );
521 const char * arch
= _config
-> Find ( "APT::Architecture" ). c_str ();
522 std :: vector
< string
> archs
= APT :: Configuration :: getArchitectures ();
523 fprintf ( output
, "Architecture: %s \n " , arch
);
524 fprintf ( output
, "Architectures:" );
525 for ( std :: vector
< string
>:: const_iterator a
= archs
. begin (); a
!= archs
. end (); ++ a
)
526 fprintf ( output
, " %s " , a
-> c_str ());
527 fprintf ( output
, " \n " );
529 if ( del
. empty () == false )
530 fprintf ( output
, "Remove: %s \n " , del
. c_str ()+ 1 );
531 if ( inst
. empty () == false )
532 fprintf ( output
, "Install: %s \n " , inst
. c_str ()+ 1 );
534 fprintf ( output
, "Upgrade: yes \n " );
535 if ( DistUpgrade
== true )
536 fprintf ( output
, "Dist-Upgrade: yes \n " );
537 if ( AutoRemove
== true )
538 fprintf ( output
, "Autoremove: yes \n " );
539 auto const solver
= _config
-> Find ( "APT::Solver" , "internal" );
540 fprintf ( output
, "Solver: %s \n " , solver
. c_str ());
541 auto const solverconf
= std :: string ( "APT::Solver::" ) + solver
+ "::" ;
542 if ( _config
-> FindB ( solverconf
+ "Strict-Pinning" , _config
-> FindB ( "APT::Solver::Strict-Pinning" , true )) == false )
543 fprintf ( output
, "Strict-Pinning: no \n " );
544 auto const solverpref
= _config
-> Find ( solverconf
+ "Preferences" , _config
-> Find ( "APT::Solver::Preferences" , "" ));
545 if ( solverpref
. empty () == false )
546 fprintf ( output
, "Preferences: %s \n " , solverpref
. c_str ());
547 fprintf ( output
, " \n " );
550 bool EDSP :: WriteRequest ( pkgDepCache
& Cache
, FileFd
& output
,
551 unsigned int const flags
,
552 OpProgress
* Progress
)
554 if ( Progress
!= NULL
)
555 Progress
-> SubProgress ( Cache
. Head (). PackageCount
, _ ( "Send request to solver" ));
558 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false ; ++ Pkg
, ++ p
)
560 if ( Progress
!= NULL
&& p
% 100 == 0 )
561 Progress
-> Progress ( p
);
563 pkgDepCache :: StateCache
& P
= Cache
[ Pkg
];
564 if ( P
. Delete () == true )
566 else if ( P
. NewInstall () == true || P
. Upgrade () == true || P
. ReInstall () == true ||
567 ( P
. Mode
== pkgDepCache :: ModeKeep
&& ( P
. iFlags
& pkgDepCache :: Protected
) == pkgDepCache :: Protected
))
571 req
-> append ( " " ). append ( Pkg
. FullName ());
573 bool Okay
= WriteOkay ( output
, "Request: EDSP 0.5 \n " );
575 const char * arch
= _config
-> Find ( "APT::Architecture" ). c_str ();
576 std :: vector
< string
> archs
= APT :: Configuration :: getArchitectures ();
577 WriteOkay ( Okay
, output
, "Architecture: " , arch
, " \n " ,
579 for ( std :: vector
< string
>:: const_iterator a
= archs
. begin (); a
!= archs
. end (); ++ a
)
580 WriteOkay ( Okay
, output
, " " , * a
);
581 WriteOkay ( Okay
, output
, " \n " );
583 if ( del
. empty () == false )
584 WriteOkay ( Okay
, output
, "Remove:" , del
, " \n " );
585 if ( inst
. empty () == false )
586 WriteOkay ( Okay
, output
, "Install:" , inst
, " \n " );
587 if ( flags
& Request :: AUTOREMOVE
)
588 WriteOkay ( Okay
, output
, "Autoremove: yes \n " );
589 if ( flags
& Request :: UPGRADE_ALL
)
591 WriteOkay ( Okay
, output
, "Upgrade-All: yes \n " );
592 if ( flags
& ( Request :: FORBID_NEW_INSTALL
| Request :: FORBID_REMOVE
))
593 WriteOkay ( Okay
, output
, "Upgrade: yes \n " );
595 WriteOkay ( Okay
, output
, "Dist-Upgrade: yes \n " );
597 if ( flags
& Request :: FORBID_NEW_INSTALL
)
598 WriteOkay ( Okay
, output
, "Forbid-New-Install: yes \n " );
599 if ( flags
& Request :: FORBID_REMOVE
)
600 WriteOkay ( Okay
, output
, "Forbid-Remove: yes \n " );
601 auto const solver
= _config
-> Find ( "APT::Solver" , "internal" );
602 WriteOkay ( Okay
, output
, "Solver: " , solver
, " \n " );
603 if ( _config
-> FindB ( "APT::Solver::Strict-Pinning" , true ) == false )
604 WriteOkay ( Okay
, output
, "Strict-Pinning: no \n " );
605 string
solverpref ( "APT::Solver::" );
606 solverpref
. append ( solver
). append ( "::Preferences" );
607 if ( _config
-> Exists ( solverpref
) == true )
608 WriteOkay ( Okay
, output
, "Preferences: " , _config
-> Find ( solverpref
, "" ), " \n " );
609 return WriteOkay ( Okay
, output
, " \n " );
612 // EDSP::ReadResponse - from the given file descriptor /*{{{*/
613 bool EDSP :: ReadResponse ( int const input
, pkgDepCache
& Cache
, OpProgress
* Progress
) {
614 /* We build an map id to mmap offset here
615 In theory we could use the offset as ID, but then VersionCount
616 couldn't be used to create other versionmappings anymore and it
617 would be too easy for a (buggy) solver to segfault APT… */
618 unsigned long long const VersionCount
= Cache
. Head (). VersionCount
;
619 unsigned long VerIdx
[ VersionCount
];
620 for ( pkgCache :: PkgIterator P
= Cache
. PkgBegin (); P
. end () == false ; ++ P
) {
621 for ( pkgCache :: VerIterator V
= P
. VersionList (); V
. end () == false ; ++ V
)
622 VerIdx
[ V
-> ID
] = V
. Index ();
623 Cache
[ P
]. Marked
= true ;
624 Cache
[ P
]. Garbage
= false ;
628 in
. OpenDescriptor ( input
, FileFd :: ReadOnly
, true );
629 pkgTagFile
response (& in
, 100 );
630 pkgTagSection section
;
632 std :: set
< decltype ( Cache
. PkgBegin ()-> ID
)> seenOnce
;
633 while ( response
. Step ( section
) == true ) {
635 if ( section
. Exists ( "Install" ) == true )
637 else if ( section
. Exists ( "Remove" ) == true )
639 else if ( section
. Exists ( "Progress" ) == true ) {
640 if ( Progress
!= NULL
) {
641 string msg
= section
. FindS ( "Message" );
642 if ( msg
. empty () == true )
643 msg
= _ ( "Prepare for receiving solution" );
644 Progress
-> SubProgress ( 100 , msg
, section
. FindI ( "Percentage" , 0 ));
647 } else if ( section
. Exists ( "Error" ) == true ) {
648 std :: string msg
= SubstVar ( SubstVar ( section
. FindS ( "Message" ), " \n . \n " , " \n\n " ), " \n " , " \n " );
649 if ( msg
. empty () == true ) {
650 msg
= _ ( "External solver failed without a proper error message" );
651 _error
-> Error ( " %s " , msg
. c_str ());
653 _error
-> Error ( "External solver failed with: %s " , msg
. substr ( 0 , msg
. find ( ' \n ' )). c_str ());
654 if ( Progress
!= NULL
)
656 std :: cerr
<< "The solver encountered an error of type: " << section
. FindS ( "Error" ) << std :: endl
;
657 std :: cerr
<< "The following information might help you to understand what is wrong:" << std :: endl
;
658 std :: cerr
<< msg
<< std :: endl
<< std :: endl
;
660 } else if ( section
. Exists ( "Autoremove" ) == true )
665 size_t const id
= section
. FindULL ( type
. c_str (), VersionCount
);
666 if ( id
== VersionCount
) {
667 _error
-> Warning ( "Unable to parse %s request with id value ' %s '!" , type
. c_str (), section
. FindS ( type
. c_str ()). c_str ());
669 } else if ( id
> Cache
. Head (). VersionCount
) {
670 _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 ());
674 pkgCache :: VerIterator
Ver ( Cache
. GetCache (), Cache
. GetCache (). VerP
+ VerIdx
[ id
]);
675 auto const Pkg
= Ver
. ParentPkg ();
676 if ( type
== "Autoremove" ) {
677 Cache
[ Pkg
]. Marked
= false ;
678 Cache
[ Pkg
]. Garbage
= true ;
679 } else if ( seenOnce
. emplace ( Pkg
-> ID
). second
== false ) {
680 _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 ());
681 } else if ( type
== "Install" ) {
682 if ( Pkg
. CurrentVer () == Ver
) {
683 _error
-> Warning ( "Ignoring Install stanza received for version %s of package %s which is already installed!" ,
684 Ver
. VerStr (), Pkg
. FullName ( false ). c_str ());
686 Cache
. SetCandidateVersion ( Ver
);
687 Cache
. MarkInstall ( Pkg
, false , 0 , false );
689 } else if ( type
== "Remove" ) {
690 if ( Pkg
-> CurrentVer
== 0 )
691 _error
-> Warning ( "Ignoring Remove stanza received for version %s of package %s which isn't installed!" ,
692 Ver
. VerStr (), Pkg
. FullName ( false ). c_str ());
693 else if ( Pkg
. CurrentVer () != Ver
)
694 _error
-> Warning ( "Ignoring Remove stanza received for version %s of package %s which isn't the installed version %s !" ,
695 Ver
. VerStr (), Pkg
. FullName ( false ). c_str (), Pkg
. CurrentVer (). VerStr ());
697 Cache
. MarkDelete ( Ver
. ParentPkg (), false );
703 // ReadLine - first line from the given file descriptor /*{{{*/
704 // ---------------------------------------------------------------------
705 /* Little helper method to read a complete line into a string. Similar to
706 fgets but we need to use the low-level read() here as otherwise the
707 listparser will be confused later on as mixing of fgets and read isn't
708 a supported action according to the manpages and results are undefined */
709 static bool ReadLine ( int const input
, std :: string
& line
) {
714 while (( data
= read ( input
, & one
, sizeof ( one
))) != - 1 ) {
721 if ( line
. empty () == true && isblank ( one
) != 0 )
728 // StringToBool - convert yes/no to bool /*{{{*/
729 // ---------------------------------------------------------------------
730 /* we are not as lazy as we are in the global StringToBool as we really
731 only accept yes/no here */
732 static bool localStringToBool ( std :: string answer
, bool const defValue
) {
733 std :: transform ( answer
. begin (), answer
. end (), answer
. begin (), :: tolower
);
736 else if ( answer
== "no" )
739 _error
-> Warning ( "Value ' %s ' is not a boolean 'yes' or 'no'!" , answer
. c_str ());
743 static bool LineStartsWithAndStrip ( std :: string
& line
, APT :: StringView
const with
) /*{{{*/
745 if ( line
. compare ( 0 , with
. size (), with
. data ()) != 0 )
747 line
= APT :: String :: Strip ( line
. substr ( with
. length ()));
751 static bool ReadFlag ( unsigned int & flags
, std :: string
& line
, APT :: StringView
const name
, unsigned int const setflag
) /*{{{*/
753 if ( LineStartsWithAndStrip ( line
, name
) == false )
755 if ( localStringToBool ( line
, false ))
762 // EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
763 bool EDSP :: ReadRequest ( int const input
, std :: list
< std :: string
> & install
,
764 std :: list
< std :: string
> & remove
, unsigned int & flags
)
770 while ( ReadLine ( input
, line
) == true )
772 // Skip empty lines before request
773 if ( line
. empty () == true )
775 // The first Tag must be a request, so search for it
776 if ( LineStartsWithAndStrip ( line
, "Request:" ))
779 while ( ReadLine ( input
, line
) == true )
781 // empty lines are the end of the request
782 if ( line
. empty () == true )
785 std :: list
< std :: string
> * request
= NULL
;
786 if ( LineStartsWithAndStrip ( line
, "Install:" ))
788 else if ( LineStartsWithAndStrip ( line
, "Remove:" ))
790 else if ( ReadFlag ( flags
, line
, "Upgrade:" , ( Request :: UPGRADE_ALL
| Request :: FORBID_REMOVE
| Request :: FORBID_NEW_INSTALL
)) ||
791 ReadFlag ( flags
, line
, "Dist-Upgrade:" , Request :: UPGRADE_ALL
) ||
792 ReadFlag ( flags
, line
, "Upgrade-All:" , Request :: UPGRADE_ALL
) ||
793 ReadFlag ( flags
, line
, "Forbid-New-Install:" , Request :: FORBID_NEW_INSTALL
) ||
794 ReadFlag ( flags
, line
, "Forbid-Remove:" , Request :: FORBID_REMOVE
) ||
795 ReadFlag ( flags
, line
, "Autoremove:" , Request :: AUTOREMOVE
))
797 else if ( LineStartsWithAndStrip ( line
, "Architecture:" ))
798 _config
-> Set ( "APT::Architecture" , line
);
799 else if ( LineStartsWithAndStrip ( line
, "Architectures:" ))
800 _config
-> Set ( "APT::Architectures" , SubstVar ( line
, " " , "," ));
801 else if ( LineStartsWithAndStrip ( line
, "Solver:" ))
802 ; // purely informational line
804 _error
-> Warning ( "Unknown line in EDSP Request stanza: %s " , line
. c_str ());
808 auto const pkgs
= VectorizeString ( line
, ' ' );
809 std :: move ( pkgs
. begin (), pkgs
. end (), std :: back_inserter (* request
));
814 bool EDSP :: ReadRequest ( int const input
, std :: list
< std :: string
> & install
,
815 std :: list
< std :: string
> & remove
, bool & upgrade
,
816 bool & distUpgrade
, bool & autoRemove
)
819 auto const ret
= ReadRequest ( input
, install
, remove
, flags
);
820 autoRemove
= ( flags
& Request :: AUTOREMOVE
);
821 if ( flags
& Request :: UPGRADE_ALL
)
823 if ( flags
& ( Request :: FORBID_NEW_INSTALL
| Request :: FORBID_REMOVE
))
840 // EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/
841 bool EDSP :: ApplyRequest ( std :: list
< std :: string
> const & install
,
842 std :: list
< std :: string
> const & remove
,
845 for ( std :: list
< std :: string
>:: const_iterator i
= install
. begin ();
846 i
!= install
. end (); ++ i
) {
847 pkgCache :: PkgIterator P
= Cache
. FindPkg (* i
);
849 _error
-> Warning ( "Package %s is not known, so can't be installed" , i
-> c_str ());
851 Cache
. MarkInstall ( P
, false );
854 for ( std :: list
< std :: string
>:: const_iterator i
= remove
. begin ();
855 i
!= remove
. end (); ++ i
) {
856 pkgCache :: PkgIterator P
= Cache
. FindPkg (* i
);
858 _error
-> Warning ( "Package %s is not known, so can't be installed" , i
-> c_str ());
865 // EDSP::WriteSolutionStanza - to the given file descriptor /*{{{*/
866 bool EDSP :: WriteSolution ( pkgDepCache
& Cache
, FILE * output
)
868 bool const Debug
= _config
-> FindB ( "Debug::EDSP::WriteSolution" , false );
869 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false ; ++ Pkg
)
871 if ( Cache
[ Pkg
]. Delete () == true )
873 fprintf ( output
, "Remove: %d \n " , _system
-> GetVersionMapping ( Pkg
. CurrentVer ()-> ID
));
875 fprintf ( output
, "Package: %s \n Version: %s \n " , Pkg
. FullName (). c_str (), Pkg
. CurrentVer (). VerStr ());
877 else if ( Cache
[ Pkg
]. NewInstall () == true || Cache
[ Pkg
]. Upgrade () == true )
879 pkgCache :: VerIterator
const CandVer
= Cache
. GetCandidateVersion ( Pkg
);
880 fprintf ( output
, "Install: %d \n " , _system
-> GetVersionMapping ( CandVer
-> ID
));
882 fprintf ( output
, "Package: %s \n Version: %s \n " , Pkg
. FullName (). c_str (), CandVer
. VerStr ());
884 else if ( Cache
[ Pkg
]. Garbage
== true )
886 fprintf ( output
, "Autoremove: %d \n " , _system
-> GetVersionMapping ( Pkg
. CurrentVer ()-> ID
));
888 fprintf ( output
, "Package: %s \n Version: %s \n " , Pkg
. FullName (). c_str (), Pkg
. CurrentVer (). VerStr ());
892 fprintf ( output
, " \n " );
897 bool EDSP :: WriteSolutionStanza ( FileFd
& output
, char const * const Type
, pkgCache :: VerIterator
const & Ver
)
899 bool Okay
= output
. Failed () == false ;
900 WriteOkay ( Okay
, output
, Type
, ": " , _system
-> GetVersionMapping ( Ver
-> ID
));
901 if ( _config
-> FindB ( "Debug::EDSP::WriteSolution" , false ) == true )
902 WriteOkay ( Okay
, output
, " \n Package: " , Ver
. ParentPkg (). FullName (), " \n Version: " , Ver
. VerStr ());
903 return WriteOkay ( Okay
, output
, " \n\n " );
906 // EDSP::WriteProgess - pulse to the given file descriptor /*{{{*/
907 bool EDSP :: WriteProgress ( unsigned short const percent
, const char * const message
, FILE * output
) {
908 fprintf ( output
, "Progress: %s \n " , TimeRFC1123 ( time ( NULL
)). c_str ());
909 fprintf ( output
, "Percentage: %d \n " , percent
);
910 fprintf ( output
, "Message: %s \n\n " , message
);
914 bool EDSP :: WriteProgress ( unsigned short const percent
, const char * const message
, FileFd
& output
) {
915 return WriteOkay ( output
, "Progress: " , TimeRFC1123 ( time ( NULL
)), " \n " ,
916 "Percentage: " , percent
, " \n " ,
917 "Message: " , message
, " \n\n " ) && output
. Flush ();
920 // EDSP::WriteError - format an error message to be send to file descriptor /*{{{*/
921 bool EDSP :: WriteError ( char const * const uuid
, std :: string
const & message
, FILE * output
) {
922 fprintf ( output
, "Error: %s \n " , uuid
);
923 fprintf ( output
, "Message: %s \n\n " , SubstVar ( SubstVar ( message
, " \n\n " , " \n . \n " ), " \n " , " \n " ). c_str ());
926 bool EDSP :: WriteError ( char const * const uuid
, std :: string
const & message
, FileFd
& output
) {
927 return WriteOkay ( output
, "Error: " , uuid
, " \n " ,
928 "Message: " , SubstVar ( SubstVar ( message
, " \n\n " , " \n . \n " ), " \n " , " \n " ),
932 static std :: string
findExecutable ( std :: vector
< std :: string
> const & dirs
, char const * const binary
) { /*{{{*/
933 for ( auto && dir
: dirs
) {
934 std :: string
const file
= flCombine ( dir
, binary
);
935 if ( RealFileExists ( file
) == true )
941 static pid_t
ExecuteExternal ( char const * const type
, char const * const binary
, char const * const configdir
, int * const solver_in
, int * const solver_out
) { /*{{{*/
942 auto const solverDirs
= _config
-> FindVector ( configdir
);
943 auto const file
= findExecutable ( solverDirs
, binary
);
946 dumper
= findExecutable ( solverDirs
, "apt-dump-solver" );
948 dumper
= findExecutable ( solverDirs
, "dump" );
951 if ( file
. empty () == true )
953 _error
-> Error ( "Can't call external %s ' %s ' as it is not in a configured directory!" , type
, binary
);
956 int external
[ 4 ] = {- 1 , - 1 , - 1 , - 1 };
957 if ( pipe ( external
) != 0 || pipe ( external
+ 2 ) != 0 )
959 _error
-> Errno ( "Resolve" , "Can't create needed IPC pipes for EDSP" );
962 for ( int i
= 0 ; i
< 4 ; ++ i
)
963 SetCloseExec ( external
[ i
], true );
965 pid_t Solver
= ExecFork ();
967 dup2 ( external
[ 0 ], STDIN_FILENO
);
968 dup2 ( external
[ 3 ], STDOUT_FILENO
);
969 auto const dumpfile
= _config
-> FindFile (( std :: string ( "Dir::Log::" ) + type
). c_str ());
970 auto const dumpdir
= flNotFile ( dumpfile
);
971 auto const runasuser
= _config
-> Find ( std :: string ( "APT::" ) + type
+ "::" + binary
+ "::RunAsUser" ,
972 _config
-> Find ( std :: string ( "APT::" ) + type
+ "::RunAsUser" ,
973 _config
-> Find ( "APT::Sandbox::User" )));
974 if ( dumper
. empty () || dumpfile
. empty () || dumper
== file
|| CreateAPTDirectoryIfNeeded ( dumpdir
, dumpdir
) == false )
976 _config
-> Set ( "APT::Sandbox::User" , runasuser
);
978 char const * const calling
[] = { file
. c_str (), nullptr };
979 execv ( calling
[ 0 ], const_cast < char **>( calling
));
983 char const * const calling
[] = { dumper
. c_str (), "--user" , runasuser
. c_str (), dumpfile
. c_str (), file
. c_str (), nullptr };
984 execv ( calling
[ 0 ], const_cast < char **>( calling
));
986 std :: cerr
<< "Failed to execute " << type
<< " '" << binary
<< "'!" << std :: endl
;
992 if ( WaitFd ( external
[ 1 ], true , 5 ) == false )
994 _error
-> Errno ( "Resolve" , "Timed out while Waiting on availability of %s stdin" , type
);
998 * solver_in
= external
[ 1 ];
999 * solver_out
= external
[ 2 ];
1003 // EDSP::ExecuteSolver - fork requested solver and setup ipc pipes {{{*/
1004 pid_t
EDSP :: ExecuteSolver ( const char * const solver
, int * const solver_in
, int * const solver_out
, bool ) {
1005 return ExecuteExternal ( "solver" , solver
, "Dir::Bin::Solvers" , solver_in
, solver_out
);
1007 bool EDSP :: ExecuteSolver ( const char * const solver
, int * solver_in
, int * solver_out
) {
1008 if ( ExecuteSolver ( solver
, solver_in
, solver_out
, true ) == 0 )
1013 // EDSP::ResolveExternal - resolve problems by asking external for help {{{*/
1014 bool EDSP :: ResolveExternal ( const char * const solver
, pkgDepCache
& Cache
,
1015 unsigned int const flags
, OpProgress
* Progress
) {
1016 if ( strcmp ( solver
, "internal" ) == 0 )
1018 auto const dumpfile
= _config
-> FindFile ( "Dir::Log::Solver" );
1019 if ( dumpfile
. empty ())
1021 auto const dumpdir
= flNotFile ( dumpfile
);
1023 if ( CreateAPTDirectoryIfNeeded ( dumpdir
, dumpdir
) == false ||
1024 output
. Open ( dumpfile
, FileFd :: WriteOnly
| FileFd :: Exclusive
| FileFd :: Create
, FileFd :: Extension
, 0644 ) == false )
1025 return _error
-> WarningE ( "EDSP::Resolve" , _ ( "Could not open file ' %s '" ), dumpfile
. c_str ());
1026 bool Okay
= EDSP :: WriteRequest ( Cache
, output
, flags
, nullptr );
1027 return Okay
&& EDSP :: WriteScenario ( Cache
, output
, nullptr );
1029 int solver_in
, solver_out
;
1030 pid_t
const solver_pid
= EDSP :: ExecuteSolver ( solver
, & solver_in
, & solver_out
, true );
1031 if ( solver_pid
== 0 )
1035 if ( output
. OpenDescriptor ( solver_in
, FileFd :: WriteOnly
| FileFd :: BufferedWrite
, true ) == false )
1036 return _error
-> Errno ( "ResolveExternal" , "Opening solver %s stdin on fd %d for writing failed" , solver
, solver_in
);
1038 bool Okay
= output
. Failed () == false ;
1039 if ( Progress
!= NULL
)
1040 Progress
-> OverallProgress ( 0 , 100 , 5 , _ ( "Execute external solver" ));
1041 Okay
&= EDSP :: WriteRequest ( Cache
, output
, flags
, Progress
);
1042 if ( Progress
!= NULL
)
1043 Progress
-> OverallProgress ( 5 , 100 , 20 , _ ( "Execute external solver" ));
1044 Okay
&= EDSP :: WriteScenario ( Cache
, output
, Progress
);
1047 if ( Progress
!= NULL
)
1048 Progress
-> OverallProgress ( 25 , 100 , 75 , _ ( "Execute external solver" ));
1049 if ( Okay
&& EDSP :: ReadResponse ( solver_out
, Cache
, Progress
) == false )
1052 return ExecWait ( solver_pid
, solver
);
1054 bool EDSP :: ResolveExternal ( const char * const solver
, pkgDepCache
& Cache
,
1055 bool const upgrade
, bool const distUpgrade
,
1056 bool const autoRemove
, OpProgress
* Progress
) {
1057 unsigned int flags
= 0 ;
1059 flags
|= Request :: AUTOREMOVE
;
1061 flags
|= Request :: UPGRADE_ALL
| Request :: FORBID_REMOVE
| Request :: FORBID_NEW_INSTALL
;
1063 flags
|= Request :: UPGRADE_ALL
;
1064 return ResolveExternal ( solver
, Cache
, flags
, Progress
);
1068 bool EIPP :: OrderInstall ( char const * const solver
, pkgDepCache
& Cache
, /*{{{*/
1069 unsigned int const flags
, OpProgress
* const Progress
)
1071 int solver_in
, solver_out
;
1072 pid_t
const solver_pid
= ExecuteExternal ( "planer" , solver
, "Dir::Bin::Planers" , & solver_in
, & solver_out
);
1073 if ( solver_pid
== 0 )
1077 if ( output
. OpenDescriptor ( solver_in
, FileFd :: WriteOnly
| FileFd :: BufferedWrite
, true ) == false )
1078 return _error
-> Errno ( "OrderInstall" , "Opening planer %s stdin on fd %d for writing failed" , solver
, solver_in
);
1080 bool Okay
= output
. Failed () == false ;
1081 if ( Progress
!= NULL
)
1082 Progress
-> OverallProgress ( 0 , 100 , 5 , _ ( "Execute external planer" ));
1083 Okay
&= EIPP :: WriteRequest ( Cache
, output
, flags
, Progress
);
1084 if ( Progress
!= NULL
)
1085 Progress
-> OverallProgress ( 5 , 100 , 20 , _ ( "Execute external planer" ));
1086 Okay
&= EIPP :: WriteScenario ( Cache
, output
, Progress
);
1089 if ( Progress
!= NULL
)
1090 Progress
-> OverallProgress ( 25 , 100 , 75 , _ ( "Execute external planer" ));
1091 if ( Okay
&& EIPP :: ReadResponse ( solver_out
, Cache
, Progress
) == false )
1094 return ExecWait ( solver_pid
, solver
);
1097 bool EIPP :: WriteRequest ( pkgDepCache
& Cache
, FileFd
& output
, /*{{{*/
1098 unsigned int const flags
,
1099 OpProgress
* const Progress
)
1102 if ( Progress
!= NULL
)
1103 Progress
-> SubProgress ( Cache
. Head (). PackageCount
, _ ( "Send request to planer" ));
1104 unsigned long p
= 0 ;
1105 string del
, purge
, inst
, reinst
;
1106 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false ; ++ Pkg
, ++ p
)
1108 if ( Progress
!= NULL
&& p
% 100 == 0 )
1109 Progress
-> Progress ( p
);
1111 pkgDepCache :: StateCache
& P
= Cache
[ Pkg
];
1112 if ( P
. Purge () == true )
1114 if ( P
. Delete () == true )
1116 else if ( P
. NewInstall () == true || P
. Upgrade () == true )
1118 else if ( P
. ReInstall () == true )
1122 req
-> append ( " " ). append ( Pkg
. FullName ());
1124 bool Okay
= WriteOkay ( output
, "Request: EIPP 0.1 \n " );
1126 const char * arch
= _config
-> Find ( "APT::Architecture" ). c_str ();
1127 std :: vector
< string
> archs
= APT :: Configuration :: getArchitectures ();
1128 WriteOkay ( Okay
, output
, "Architecture: " , arch
, " \n " ,
1130 for ( std :: vector
< string
>:: const_iterator a
= archs
. begin (); a
!= archs
. end (); ++ a
)
1131 WriteOkay ( Okay
, output
, " " , * a
);
1132 WriteOkay ( Okay
, output
, " \n " );
1134 if ( purge
. empty () == false )
1135 WriteOkay ( Okay
, output
, "Purge:" , purge
, " \n " );
1136 if ( del
. empty () == false )
1137 WriteOkay ( Okay
, output
, "Remove:" , del
, " \n " );
1138 if ( inst
. empty () == false )
1139 WriteOkay ( Okay
, output
, "Install:" , inst
, " \n " );
1140 if ( reinst
. empty () == false )
1141 WriteOkay ( Okay
, output
, "ReInstall:" , reinst
, " \n " );
1142 WriteOkay ( Okay
, output
, "Planer: " , _config
-> Find ( "APT::Planer" , "internal" ), " \n " );
1143 return WriteOkay ( Okay
, output
, " \n " );
1146 static bool WriteScenarioEIPPVersion ( pkgDepCache
&, FileFd
& output
, pkgCache :: PkgIterator
const & Pkg
, /*{{{*/
1147 pkgCache :: VerIterator
const & Ver
)
1150 if ( Pkg
. CurrentVer () == Ver
)
1151 switch ( Pkg
-> CurrentState
)
1153 case pkgCache :: State :: NotInstalled
: WriteOkay ( Okay
, output
, " \n Status: not-installed" ); break ;
1154 case pkgCache :: State :: ConfigFiles
: WriteOkay ( Okay
, output
, " \n Status: config-files" ); break ;
1155 case pkgCache :: State :: HalfInstalled
: WriteOkay ( Okay
, output
, " \n Status: half-installed" ); break ;
1156 case pkgCache :: State :: UnPacked
: WriteOkay ( Okay
, output
, " \n Status: unpacked" ); break ;
1157 case pkgCache :: State :: HalfConfigured
: WriteOkay ( Okay
, output
, " \n Status: half-configured" ); break ;
1158 case pkgCache :: State :: TriggersAwaited
: WriteOkay ( Okay
, output
, " \n Status: triggers-awaited" ); break ;
1159 case pkgCache :: State :: TriggersPending
: WriteOkay ( Okay
, output
, " \n Status: triggers-pending" ); break ;
1160 case pkgCache :: State :: Installed
: WriteOkay ( Okay
, output
, " \n Status: installed" ); break ;
1165 // EIPP::WriteScenario - to the given file descriptor /*{{{*/
1166 template < typename forVersion
> void forAllInterestingVersions ( pkgDepCache
& Cache
, pkgCache :: PkgIterator
const & Pkg
, forVersion
const & func
)
1168 if ( Pkg
-> CurrentState
== pkgCache :: State :: NotInstalled
)
1170 auto P
= Cache
[ Pkg
];
1171 if ( P
. Install () == false )
1173 func ( Pkg
, P
. InstVerIter ( Cache
));
1177 if ( Pkg
-> CurrentVer
!= 0 )
1178 func ( Pkg
, Pkg
. CurrentVer ());
1179 auto P
= Cache
[ Pkg
];
1180 auto const V
= P
. InstVerIter ( Cache
);
1181 if ( P
. Delete () == false && Pkg
. CurrentVer () != V
)
1186 bool EIPP :: WriteScenario ( pkgDepCache
& Cache
, FileFd
& output
, OpProgress
* const Progress
)
1188 if ( Progress
!= NULL
)
1189 Progress
-> SubProgress ( Cache
. Head (). PackageCount
, _ ( "Send scenario to planer" ));
1190 unsigned long p
= 0 ;
1191 bool Okay
= output
. Failed () == false ;
1192 std :: vector
< std :: string
> archs
= APT :: Configuration :: getArchitectures ();
1193 std :: vector
< bool > pkgset ( Cache
. Head (). PackageCount
, false );
1194 auto const MarkVersion
= [&]( pkgCache :: PkgIterator
const & Pkg
, pkgCache :: VerIterator
const & Ver
) {
1195 pkgset
[ Pkg
-> ID
] = true ;
1196 for ( auto D
= Ver
. DependsList (); D
. end () == false ; ++ D
)
1198 if ( D
. IsCritical () == false )
1200 auto const P
= D
. TargetPkg ();
1201 for ( auto Prv
= P
. ProvidesList (); Prv
. end () == false ; ++ Prv
)
1203 auto const V
= Prv
. OwnerVer ();
1204 auto const PV
= V
. ParentPkg ();
1205 if ( V
== PV
. CurrentVer () || V
== Cache
[ PV
]. InstVerIter ( Cache
))
1206 pkgset
[ PV
-> ID
] = true ;
1208 pkgset
[ P
-> ID
] = true ;
1211 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false ; ++ Pkg
)
1212 forAllInterestingVersions ( Cache
, Pkg
, MarkVersion
);
1213 auto const WriteVersion
= [&]( pkgCache :: PkgIterator
const & Pkg
, pkgCache :: VerIterator
const & Ver
) {
1214 Okay
&= WriteScenarioVersion ( output
, Pkg
, Ver
);
1215 Okay
&= WriteScenarioEIPPVersion ( Cache
, output
, Pkg
, Ver
);
1216 Okay
&= WriteScenarioLimitedDependency ( output
, Ver
, pkgset
, true );
1217 WriteOkay ( Okay
, output
, " \n " );
1218 if ( Progress
!= NULL
&& p
% 100 == 0 )
1219 Progress
-> Progress ( p
);
1221 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false && likely ( Okay
); ++ Pkg
, ++ p
)
1223 if ( pkgset
[ Pkg
-> ID
] == false || Pkg
-> VersionList
== 0 )
1225 forAllInterestingVersions ( Cache
, Pkg
, WriteVersion
);
1230 // EIPP::ReadResponse - from the given file descriptor /*{{{*/
1231 bool EIPP :: ReadResponse ( int const input
, pkgDepCache
& Cache
, OpProgress
* Progress
) {
1232 /* We build an map id to mmap offset here
1233 In theory we could use the offset as ID, but then VersionCount
1234 couldn't be used to create other versionmappings anymore and it
1235 would be too easy for a (buggy) solver to segfault APT… */
1237 unsigned long long const VersionCount = Cache.Head().VersionCount;
1238 unsigned long VerIdx[VersionCount];
1239 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; ++P) {
1240 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
1241 VerIdx[V->ID] = V.Index();
1246 in
. OpenDescriptor ( input
, FileFd :: ReadOnly
);
1247 pkgTagFile
response (& in
, 100 );
1248 pkgTagSection section
;
1250 std :: set
< decltype ( Cache
. PkgBegin ()-> ID
)> seenOnce
;
1251 while ( response
. Step ( section
) == true ) {
1252 if ( section
. Exists ( "Progress" ) == true ) {
1253 if ( Progress
!= NULL
) {
1254 string msg
= section
. FindS ( "Message" );
1255 if ( msg
. empty () == true )
1256 msg
= _ ( "Prepare for receiving solution" );
1257 Progress
-> SubProgress ( 100 , msg
, section
. FindI ( "Percentage" , 0 ));
1260 } else if ( section
. Exists ( "Error" ) == true ) {
1261 std :: string msg
= SubstVar ( SubstVar ( section
. FindS ( "Message" ), " \n . \n " , " \n\n " ), " \n " , " \n " );
1262 if ( msg
. empty () == true ) {
1263 msg
= _ ( "External planer failed without a proper error message" );
1264 _error
-> Error ( " %s " , msg
. c_str ());
1266 _error
-> Error ( "External planer failed with: %s " , msg
. substr ( 0 , msg
. find ( ' \n ' )). c_str ());
1267 if ( Progress
!= NULL
)
1269 std :: cerr
<< "The planer encountered an error of type: " << section
. FindS ( "Error" ) << std :: endl
;
1270 std :: cerr
<< "The following information might help you to understand what is wrong:" << std :: endl
;
1271 std :: cerr
<< msg
<< std :: endl
<< std :: endl
;
1274 _error
-> Warning ( "Encountered an unexpected section with %d fields" , section
. Count ());