Re: gdselect alpha 3 [libapt]
1) How do I startup the library
This is much longer than I would like it to be, but can't be simplified
without loosing something :< The sequence can be divided into 3 stages,
- Configuration
- Cache load+parse
- Dependency correction (optional)
Omitting error checking this sequence looks like:
// Configuration phase, read config file and sourcelist
pkgInitialize(*_config);
OpTextProgress Progress(*_config);
pkgSourceList List;
List.ReadMainList();
// Parse (if necessary) the package files
pkgMakeStatusCache(List,Progress);
Progress.Done();
// Open and associate the cache file
FileFd *File = new FileFd(_config->FindDir("Dir::Cache::pkgcache"),
FileFd::ReadOnly);
MMap *Map = new MMap(*File,MMap::Public | MMap::ReadOnly);
pkgDepCache *Cache = new pkgDepCache(*Map,Progress);
Progress.Done();
A complete example of this can be found int cmdline/apt-get.cc inside the
CacheFile::Open function. Error checking makes it considerably larger.
You can create your own Progress class to interface with a GTK progress
meter, an example of this is in gui/progress.cc.
2) How do I get a list of packages
- Packages that a package depends on
- With some sort of filter criteria
Package lists of all sorts are derived by iterating over the cache with
a Package Iterator. There are many examples of this in cmbline/apt-get.cc
functions Show*. An example:
// Print the name of every package
pkgCache::PkgIterator I = Cache.PkgBegin();
for (; I.end() == false; I++)
cout << I.Name() << endl;
In the usual configuration there are a pair of main datastructures, the
'Cache' which contains static information derived from the pacage lists
and the 'DepCache' which contains runtime generated information such as
dependency state values, selected versions, the install/remove flag,
etc. The iterators only iterate over the 'Cache' but you can access the
associated DepCache record for an Iterator with something like:
cout << "Version " << Cache[I].CurVersion << " is installed." << endl;
cout << "Version " << Cache[I].CandVersion << " is available for install." << endl;
The DepCache contains test members to determine if a package has broken
deps, if it is being upgraded, and other things like that [see the
header]
Varios other specialized classes have their own Extension Structures
which allow them to associate some data with static records from the
cache.
Dependencies are directed through the version list for each package and
to get at them you need to decide on a version that you want to see the
Dependencies for. [Read section 3 to make some sense of this]. Typically
GUI's display the Candidate Version's Dependency list which would be
achived like:
pkgCache::DepIterator Dep = Cache[I].CandiateVerIter(Cache);
for (; Dep.end() == false; Dep++)
<something>
- Remeber to verify *VerIter is not at 'end', this single problem
has caused the majority of APT crashes.
3) How do I install/remove/keep a package
The DepCache keeps track of two versions for every package and an
indicator of what version is selected in the target state.
The two versions are called the InstallVersion and the CandidateVersion.
It is critical to understand their meaning and roles. InstallVersion is
the version of the package that is installed in the system, it never
changes. The CandidateVersion is selected from the version set and
represents the newest version of the package. A package can either
select the Null version, the InstallVersion or the CandidateVersion as
it's desired desintation.
That said, installing a package is simple. If you have an iterator
for the package,
Cache.MarkInstall(i,true|false);
The parameter indicates if AutoInstalling is desired. If true the
library will make a trivial attempt to correct any -direct- problems
caused by installing the package. Typically this means it installs the
dependents. The functions MarkRemove (deinstall) and MarkKeep (restore
to original state) are also available.
The Mark* functions also compute the side effects of the change
throughout the dependency network. It takes into account ALL possible
effects of this change which includes indirection through a virtual
package, 'or' dependency groups and others.
Recomended Implementation
The best way to make use of the library in a GUI is with an owner draw
tree widget. In most GUI implementations this means you pass an object
handle and a draw function to the tree. To get the best use out of the
library you would pass the package pointer to the tree and a draw
function that gets it's information directly from the cache. This does
two things,
1) Assures minimal memory usage by not duplicating strings
2) Assures the tree is always perfectly in sync with the state of the
package in the fastest manner possible
Other Things
There is a set of classes aimed at accessing information directly from
the index files, I can explain them in a future email
APT has a built in error handling mechanism. Errors of various sorts can
trickle up in something called the Global Error Object (_error) It
maintains a list textual problem descriptions, when many functions
fail they will put their reason into the _error class and return false.
Errors can be printed to the console with _error->DumpErrors(). You will
want to make a function that takes the error text and puts it into a
dialog, see gui/errorshow.cc.
There is also a built in configuration and command-line handling
mechanism represented by the Configuration class. A global instance
for global configuration is called _config. It stored directory things
and others in a heigharchical key/value database. The command line parser
takes command line arguments and sets the proper database entry allowing
a uniform and simple configuration mechanism.
Very soon the new tree will have the completed acquire system which will
allow you to write a pretty front end to the download progress meter,
that's not finished yet though.
The document build/doc/cache.text describes in detail each and every
bit of data that can be directly acessed via the cache. There is a tad
of a discontinuity here though,
pkgCache::PkgIterator I;
I.Name(); // Gives a const char * for the name
I->Name; // Gives an untranslated unsinged long
I.VersionList(); // Gives a Version Iterator
I->VersionList; // Gives an untranslated unsigned long
Some things such as the priority feild must be accessed with -> while
others only provide sensible results if used with the function call form.
Jason
Reply to: