Re: Greetings
On Fri, 19 Mar 1999, Kirk Saranathan wrote:
> Hello, Jason. My name is Kirk Saranathan and I'm one of the engineers
> at Corel working on the Corel Linux distribution. I was given your
> contact info by Wichert Akkerman. I'm hoping to get some info from you
> about the internals of apt so that I may modify (or create) a package
> management front-end to use apt. I'm currently reading the source on
> the apt package and am still learning. I read about a gnome frontend to
> apt but haven't been able to find anything thus far (except for kpackage
> which uses dpkg directly). Could you point me in the right direction?
I belive that Havoc has already told you some info on where to find
compiled gnome-apt binarys, all the apt sources are in CVS, the path for
it is
:pserver:anonymous@cvs.debian.org:/cvs/deity
modules apt and gnome-apt. Some time back I posted a few long summaries on
how to use the library, but formal documentation is scarse :>
The best is often just to ask questions on IRC but you doing this for a
day job in ontario may make that impossible
Hmm, I can't find the summary in the list archives.. here are some
snipits:
-----------
The library source and such forth is in CVS as usual. There is a new
forked development tree called 'apt' which is distinct and very different
from the current release. To get it do something like
export CVSROOT=":pserver:anonymous@cvs.debian.org:/cvs/deity"
cvs login
cvs co apt
cd apt
make startup
make
You'll need g++ and libstdc++2.9. To make use of the library from your
program you'll want to include -L .../apt/build/lib and -I
.../apt/build/include and use -lapt-pkg
Then you can start working on removing your library and replacing it with
this one.. I guess the main areas of questioning would be something like
1) How do I startup the library
2) How do I get a list of packages
- Packages that a package depends on
- With some sort of filter criteria
3) How do I install/remove/keep a package
I guess I'll write another mail outlining the basic elements of each of
these.
----------
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.
- 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.
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.
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.
Reply to:
- References:
- Greetings
- From: Kirk Saranathan <kartiks@corel.ca>