|
Writing your own apt-cdrom |
|
========================== |
|
:Author: Julian Andres Klode <[email protected]> |
|
:Release: |release| |
|
:Date: |today| |
|
|
|
This article explains how to utilise python-apt to build your own clone of the |
|
:command:`apt-cdrom` command. To do this, we will take a look at the |
|
:mod:`apt.cdrom` and :mod:`apt.progress.text` modules, and we will learn how |
|
to use apt_pkg.parse_commandline to parse commandline arguments. The code shown |
|
here works on Python 2 and Python 3. |
|
|
|
Basics |
|
------ |
|
The first step in building your own :command:`apt-cdrom` clone is to import the |
|
:mod:`apt` package, which will import :mod:`apt.cdrom` and |
|
:mod:`apt.progress.text`:: |
|
|
|
import apt |
|
|
|
Now we have to create a new :class:`apt.cdrom.Cdrom` object and pass to it an |
|
:class:`apt.progress.text.CdromProgress` object, which is responsible for |
|
displaying the progress and asking questions:: |
|
|
|
cdrom = apt.Cdrom(apt.progress.text.CdromProgress()) |
|
|
|
Now we have to choose the action, depending on the given options on the |
|
command line. For now, we simply use the value of ``sys.argv[1]``:: |
|
|
|
import sys |
|
if sys.argv[1] == 'add': |
|
cdrom.add() |
|
elif sys.argv[1] == 'ident': |
|
cdrom.ident() |
|
|
|
Now we have a basic :command:`apt-cdrom` clone which can add and identify |
|
CD-ROMs:: |
|
|
|
import sys |
|
|
|
import apt |
|
|
|
cdrom = apt.Cdrom(apt.progress.text.CdromProgress()) |
|
if sys.argv[1] == 'add': |
|
cdrom.add() |
|
elif sys.argv[1] == 'ident': |
|
cdrom.ident() |
|
|
|
Advanced example with command-line parsing |
|
------------------------------------------- |
|
Our example clearly misses a way to parse the commandline in a correct |
|
manner. Luckily, :mod:`apt_pkg` provides us with a function to do this: |
|
:func:`apt_pkg.parse_commandline`. To use it, we add ``import apt_pkg`` right |
|
after import apt:: |
|
|
|
import sys |
|
|
|
import apt_pkg |
|
import apt |
|
|
|
|
|
:func:`apt_pkg.parse_commandline` is similar to :mod:`getopt` functions, it |
|
takes a list of recognized options and the arguments and returns all unknown |
|
arguments. If it encounters an unknown argument which starts with a leading |
|
'-', the function raises an error indicating that the option is unknown. The |
|
major difference is that this function manipulates the apt configuration space. |
|
|
|
The function takes 3 arguments. The first argument is an |
|
:class:`apt_pkg.Configuration` object. The second argument is a list of tuples |
|
of the form ``(shortopt, longopt, config, type)``, whereas *shortopt* is a |
|
character indicating the short option name, *longopt* a string indicating the |
|
corresponding long option (e.g. ``"--help"``), *config* the name of the |
|
configuration item which should be set and *type* the type of the argument. |
|
|
|
For apt-cdrom, we can use the following statement:: |
|
|
|
arguments = apt_pkg.parse_commandline(apt_pkg.config, |
|
[('h', "help", "help"), |
|
('v', "version", "version"), |
|
('d', "cdrom", "Acquire::cdrom::mount", "HasArg"), |
|
('r', "rename", "APT::CDROM::Rename"), |
|
('m', "no-mount", "APT::CDROM::NoMount"), |
|
('f', "fast", "APT::CDROM::Fast"), |
|
('n', "just-print", "APT::CDROM::NoAct"), |
|
('n', "recon", "APT::CDROM::NoAct"), |
|
('n', "no-act", "APT::CDROM::NoAct"), |
|
('a', "thorough", "APT::CDROM::Thorough"), |
|
('c', "config-file", "", "ConfigFile"), |
|
('o', "option", "", "ArbItem")], args) |
|
|
|
|
|
This allows us to support all options supported by apt-cdrom. The first option |
|
is --help. As you can see, it omits the fourth field of the tuple; which means |
|
it is a boolean argument. Afterwards you could use |
|
``apt_pkg.config.find_b("help")`` to see whether ``--help`` was specified. In |
|
``('d',"cdrom","Acquire::cdrom::mount","HasArg")`` the fourth field is |
|
``"HasArg"``. This means that the option has an argument, in this case the |
|
location of the mount point. ``('c',"config-file","","ConfigFile")`` shows how |
|
to include configuration files. This option takes a parameter which points to |
|
a configuration file which will be added to the configuration space. |
|
``('o',"option","","ArbItem")`` is yet another type of option, which allows users |
|
to set configuration options on the commandline. |
|
|
|
Now we have to check whether help or version is specified, and print a message |
|
and exit afterwards. To do this, we use :meth:`apt_pkg.Configuration.find_b` |
|
which returns ``True`` if the configuration option exists and evaluates to |
|
``True``:: |
|
|
|
if apt_pkg.config.find_b("help"): |
|
print("This should be a help message") |
|
sys.exit(0) |
|
elif apt_pkg.config.find_b("version"): |
|
print("Version blah.") |
|
sys.exit(0) |
|
|
|
|
|
Now we are ready to create our progress object and our cdrom object. Instead |
|
of using :class:`apt.Cdrom` like in the first example, we will use |
|
:class:`apt_pkg.Cdrom` which provides a very similar interface. We could also |
|
use :class:`apt.Cdrom`, but `apt.Cdrom` provides options like *nomount* which |
|
conflict with our commandline parsing:: |
|
|
|
progress = apt.progress.text.CdromProgress() |
|
cdrom = apt_pkg.Cdrom() |
|
|
|
|
|
Now we have to do the action requested by the user on the commandline. To see |
|
which option was requested, we check the list ``arguments`` which was returned |
|
by ``apt_pkg.parse_commandline`` above, and afterwards call ``cdrom.add`` or |
|
``cdrom.ident``:: |
|
|
|
if apt_pkg.config.find_b("help"): |
|
print("This should be a help message") |
|
sys.exit(0) |
|
elif apt_pkg.config.find_b("version"): |
|
print("Version blah.") |
|
sys.exit(0) |
|
|
|
if not arguments: |
|
sys.stderr.write('E: No operation specified\n') |
|
sys.exit(1) |
|
elif arguments[0] == 'add': |
|
cdrom.add(progress) |
|
elif arguments[0] == 'ident': |
|
cdrom.ident(progress) |
|
else: |
|
sys.stderr.write('E: Invalid operation %s\n' % arguments[0]) |
|
sys.exit(1) |
|
|
|
|
|
After putting all our actions into a main() function, we get a completely |
|
working apt-cdrom clone, which just misses useful ``--help`` and ``--version`` |
|
options. If we add a function show_help(), we get an even more complete |
|
apt-cdrom clone: |
|
|
|
.. literalinclude:: ../examples/apt-cdrom.py |
|
|