Ubiquity
========

This is a graphical installer for Ubuntu, written largely in Python, using
d-i as a backend for many of its functions. The authors are indebted to the
efforts of the Guadalinex project in developing the original
"ubuntu-express" code used as a basis for this project.

Background
----------

Around 2000, the debian-installer (later just "d-i") project started to
replace the old Debian "boot-floppies" installer. The goals of this project
included long-term maintainability, modularity, and code reuse. After a
hiatus during the Debian 3.0 release, this project matured into a usable
installer in 2004 in time for, among others, the releases of Debian 3.1 and
Ubuntu 4.10. From Ubuntu 4.10 to Ubuntu 5.10, d-i was used as the primary
installation program.

d-i continues to provide flexibility and (for a certain significant class of
users) ease of use that a simplified graphical installer will always be
hard-pushed to provide. It is therefore important to continue to support it
in Ubuntu. From a maintainability point of view, it follows that it is
important for any graphical installer supported by Ubuntu to share
substantial amounts of code with d-i, particularly where the backend logic
is intrinsically difficult and has accumulated large quantities of expertise
and bug fixes. Accordingly, Ubiquity is designed to use logic from d-i where
possible, and tries to confine itself to being a high-quality frontend.

(Of course, there remain some areas where d-i does not provide suitable
logic, or where its logic has not proven amenable to direct use within
Ubiquity, so there is still some backend-style logic and code duplication
in Ubiquity. Eventually, as much of this as possible should go away.)

UI Design
---------

The primary focus of Ubiquity's UI is ease of use for new users.
Accordingly, it does not try to provide all possible options, deferring
advanced installation scenarios to d-i so that it does not have to be all
things to all people. See http://wiki.ubuntu.com/UbuntuExpress for the
original details of its user interface design.

Debconf Integration
-------------------

The most challenging part of Ubiquity to understand is undoubtedly its
integration with d-i. Before getting to grips with this, I assume that the
reader has a basic developer-level grasp of the "debconf" configuration
system. Reading the debconf-devel(7) man page is a good idea.

d-i uses debconf for all user interaction. The extant graphical debconf
frontends are functional, but crude from a human interface design
perspective; although this could be improved, the problem is to some extent
intrinsic because they must generate a user interface based on the questions
asked by the confmodule. It is possible to do much better using custom user
interface code. However, at present debconf has no support for doing this
directly (although cdebconf does).

To deal with this, Ubiquity uses the noninteractive debconf frontend, and
instead uses a layer called the "debconffilter". This sits between d-i code
and the debconf frontend, intercepting the debconf protocol, and transforms
relevant debconf protocol messages into events which can be handled in much
the same way as UI events from widget libraries like GTK+ or Qt. While this
requires insider knowledge of the questions which may be asked by each piece
of d-i code, which must often be updated as d-i evolves, it seems to be the
most practical approach at present.

Each piece of d-i code used in Ubiquity is accompanied by a "component",
written in Python, which defines the backend code to be called and any
necessary event handlers. To allow for multiple frontend implementations, it
typically calls methods in the frontend when UI operations are needed.

It is important to remember that each call to component event handlers is
blocking (though non-reentrant). If UI interaction is required in order to
provide an answer to debconf, this must be handled by calling into suitable
frontend functions from the component to wait for the user. The component is
responsible for maintaining its own state machine if necessary.

Partitioning
------------

All partitioning is handled by d-i code (partman), with a presentation layer
on top. The presentation layer navigates partman's menus under the hood to
perform advanced partitioning. See
http://wiki.ubuntu.com/Ubiquity/AdvancedPartitionerRewrite for details.

A graphical disk view has yet to be written for the GTK frontend's advanced
partitioner.

Installation
------------

The actual installation takes place by copying the read-only part of the
live filesystem. The writable part of the live filesystem (i.e. the running
live session) is intentionally not copied, to ensure maximum reproducibility
of the installed system. Thus, any customisations applied by the live boot
process must be re-applied after the read-only filesystem is copied. The
live boot process is responsible for installing hooks in
/usr/lib/ubiquity/target-config/ to take care of this.

After copying the live filesystem, certain unnecessary packages (such as
Ubiquity itself) will be removed. The set of packages to be removed is
computed by taking those packages present in
/cdrom/casper/filesystem.manifest but not present in
/cdrom/casper/filesystem.manifest-desktop, and removing any packages
explicitly requested for installation by installer code. Language packs for
languages which are not to be supported on the installed system will also be
removed.

Logs of the installation will be saved in /var/log/syslog (for messages
emitted by Ubiquity itself and messages emitted by d-i code), and
/var/log/partman (for a trace of the operation of the automatic
partitioner). /var/log/syslog and /var/log/partman are saved in
/var/log/installer/ on the installed system.

Customisation
-------------

Where d-i code is used, it is generally possible to preseed it to change
default behaviour. See the installation guide for details. By default,
preseeding is confined to setting default values for questions, and Ubiquity
will not skip over preseeded steps (this is to allow sensible interpretation
of going backward and forward in the UI); if the --automatic option is used,
preseeded steps will be skipped.

The read-only live filesystem should generally be mounted on /rofs.
Alternatively, an image may be present as /cdrom/casper/filesystem.cloop,
/cdrom/casper/filesystem.squashfs, or (for Guadalinex/Metadistros)
/cdrom/META/META.squashfs. Ubuntu currently uses
/cdrom/casper/filesystem.squashfs. You can preseed
ubiquity/install/filesystem-images with a space-separated list of image
paths to override this; if you provide more than one image, then they will
be overlaid using unionfs.

/cdrom/casper/filesystem.manifest and
/cdrom/casper/filesystem.manifest-desktop should be, respectively, a list of
packages in the full live filesystem and a list of packages that should be
installed in the target system; the format is that produced by running
"dpkg-query -W --showformat='${Package} ${Version}\n'". Ubiquity will remove
any packages present in filesystem.manifest but not present in
filesystem.manifest-desktop after copying the live filesystem. This allows
it to ensure that, for example, Ubiquity itself doesn't end up on the target
system.

Language packs for the selected language are installed by default, using the
Ubuntu naming scheme of language-pack-$LL and language-support-$LL. If you
want to get rid of these (for example because their dependencies are
inconvenient), then you can preseed pkgsel/language-packs to the empty
string.

If /cdrom/.disk/release_notes_url is present, a link to the release notes
will be displayed on the language page. Instances of the string ${LANG} in
that URL will be replaced with the locale, with any encoding removed (e.g.
en, de, pt_BR, zh_CN).

If you're installing from a medium other than a CD or DVD (e.g. over NFS),
then the path of least resistance is to arrange that something that looks
like a CD is available on /cdrom anyway. NFS-mounting an entire CD image is
one approach that has worked with relatively little effort, but you could
also set up the files listed above in some other way.

Frequently Asked Questions
--------------------------

Q. Can I backport the version of Ubiquity from the current Ubuntu
   development release to the previous stable release?

A. Not without quite a bit of work. At present, Ubiquity is still a complex
   piece of software with several bleeding-edge dependencies, and at the
   moment I have no compunctions about making it depend on new packages or
   newer versions of existing packages in order to get the job done
   properly. In future, things may settle down such that there can be more
   compatibility guarantees, particularly if Ubiquity is adopted by other
   Debian-based distributions.

   At the moment, I can think of the following specific issues with
   backporting Ubiquity from Ubuntu 6.10 to Ubuntu 6.06:

     * Ubiquity now uses the new Python policy, which involves a number of
       packaging changes and even a couple of code changes that are
       incompatible with Ubuntu 6.06. These would need to be reverted.

     * Ubiquity now uses console-setup as the backend for the keyboard
       screen rather than kbd-chooser. console-setup will not work on Ubuntu
       6.06, so the kbd-chooser code would need to be resurrected.

     * Ubiquity's GTK frontend now relies on new features in gparted in
       order to fix some user interface bugs.

     * Ubiquity now integrates with the apport crash reporting facility in
       Ubuntu 6.10, which is not available in Ubuntu 6.06. (This would just
       be a matter of removing dependencies; it's optional as far as the
       code is concerned.)

     * Ubiquity's debconf template translations now rely on new features in
       po-debconf 1.0, which was not available in Ubuntu 6.06.

   While I'm aware that there were a number of serious issues with the
   version of Ubiquity that shipped with Ubuntu 6.06 (many of which were
   corrected in Ubuntu 6.06.1), I feel that the right answer to these is to
   backport selected fixes to that branch of Ubiquity rather than trying to
   backport the whole package.

   Similarly, there are at least the following issues with backporting
   Ubiquity from Ubuntu 7.04 to Ubuntu 6.10:

     * Ubiquity depends on a version of console-setup at least as new as the
       one in its own source tree, so the two packages would need to be
       backported together. The new version of console-setup in turn relies
       on a newer version of xkb-data (although probably not inextricably).

     * Ubiquity's GTK frontend now uses gtk.LinkButton, which isn't
       available in the versions of GTK+/PyGTK in Ubuntu 6.10. Similarly,
       you need a more recent version of glade-3 than is available in Ubuntu
       6.10 to edit the user interface definition for the GTK frontend.

     * Regenerating Ubiquity's autotools files (configure et al) requires
       Automake 1.10, not available in Ubuntu 6.10.

     * Ubiquity's apport crash handler now requires a new Python API
       introduced in apport 0.33.


Feel free to ask us (ubuntu-installer@lists.ubuntu.com) if you have any
questions regarding Ubiquity's workings.
