Design Overview¶
Introduction¶
Distro Tracker is implemented as a Python 3 application using the Django framework.
An important goal of the project is to implement a system which is easily customizable so it could serve Debian derivatives too (vendors).
This document will present an overview of the high-level design choices which were made.
Note that a previous version of the service pre-existed (it was known as the Package Tracking System), but which operated over completely different technology (statically generated documents, etc.). Some features have been kept identical over the rewrite.
Email Interface¶
There are three aspects to the email interface: the control message processing, dispatching received package messages to the correct subscribers and creating news items based on received emails.
This is implemented in the distro_tracker.mail
app. The three mentioned
functionalities are found in the following subpackages and modules of this app:
distro_tracker.mail.control.control
Email Control Messages¶
Distro Tracker expects the system’s MTA to pipe any received control emails to the
distro_tracker.mail.management.commands.tracker_control
Django management
command. For information how to set this up, refer to the
mailbot setup.
The actual processing of the received command email message is implemented in
distro_tracker.mail.control.process.process()
. It does this by retrieving the message’s
payload and feeding it into an instance of
distro_tracker.mail.control.commands.CommandProcessor
.
The CommandProcessor
takes
care of parsing and executing all given commands.
All available commands are implemented in the distro_tracker.mail.control.commands
module. Each command must be a subclass of the
distro_tracker.mail.control.commands.base.Command
class. There are three attributes of the
class that subclasses must override:
META
- most importantly provides the command nameREGEX_LIST
- allows matching a string to the commandhandle()
- implements the command processing
The class distro_tracker.mail.control.commands.CommandFactory
produces instances of
the correct Command
subclasses
based on a given line.
Commands which require confirmation are easily implemented by decorating the
class with the distro_tracker.mail.control.commands.confirmation.needs_confirmation()
class decorator. In addition to that, two more methods can be implemented, but
are not mandatory:
pre_confirm
- for actions which should come before asking forconfirmation for the command. If this method does not return an object which evalutes as a True Boolean, no confirmation is sent. It should also make sure to add appropriate status messages to the response. If the method is not provided, then a default response indicating that a confirmation is required is output.
get_confirmation_message
- Method which should return a stringcontaining an additional message to be included in the confirmation email.
Email Dispatch¶
As is the case for control message processing, Distro Tracker expects the system’s MTA
to pipe any received package emails to a management command -
distro_tracker.mail.management.commands.tracker_dispatch
. For information how to set
this up, refer to the mailbot setup.
The function that performs the processing of a received package message is
distro_tracker.mail.dispatch.process()
. In order to tag the received message
with a package and a keyword, it uses a vendor-provided function
classify_message
.
In case a vendor has not implemented this function, the message is tagged
with the default
keyword.
The same function is also used to transform some of the incoming emails into permanent news items that are displayed on each package page.
Tasks Framework¶
Since Distro Tracker aggregates information based on many different sources,
a way to perform incremental updates is necessary. This means that if an update
from one source causes such changes which could have an effect on some other
information, this information needs to be updated, as well. In order to avoid
recalculating everything after each update, a framework for executing such
tasks is implemented in distro_tracker.core.tasks
.
In order to implement a task, the distro_tracker.core.tasks.BaseTask
class should
be subclassed and mixed together with schedulers to define when the task
should be run. Various mixins exist in
distro_tracker.core.tasks.mixins
to help build task processing some
common entities.
Note
All task classes should be placed in a module called tracker_tasks
found at
the top level of an installed Django app. Tasks in apps which are not
installed will never be run.
Note
Each task’s operation must be idempotent to ensure that if an error does occur before being able to save the state of the job, rerunning the task will not cause any inconsistencies.
For more information see the documentation on the distro_tracker.core.tasks
module.
Vendor-specific Rules¶
Since Distro Tracker aims to be extensible, it allows a simple way for vendors to implement functions which are plugged in by core code when necessary.
Vendor-provided functions can be called using the distro_tracker.vendor.common.call()
function. The function object itself can be retrieved by using the
lower-level distro_tracker.vendor.common.get_callable()
function, but this should
be avoided.
All vendor-provided functions must be found in the module given by the
DISTRO_TRACKER_VENDOR_RULES
settings value.
Package Information¶
Distro Tracker retrieves package information from a set of user-defined repositories.
Admin users can add new distro_tracker.core.models.Repository
instances through
the admin panel. Information from repositories is updated by the task
distro_tracker.core.retrieve_data.UpdateRepositoriesTask
and it emits events
based on changes found in the repositories.
Additional tasks are implemented in distro_tracker.core.retrieve_data
which
use those events to store pre-calculated (extracted) information ready
to be rendered in a variety of contexts (webpage, REST, RDF, etc.).
Distro Tracker also updates the list of existing pseudo packages by using the
vendor-provided function
get_pseudo_package_list
.
All retrieved data can be accessed by using the models found in
distro_tracker.core.models
. Refer to that module’s documentation for convenient
APIs for interacting with the extracted information.
Data model¶
You may wish to check the data model. This can be done for instance with the following command after having installed ‘django_extensions’ in INSTALLED_APPS (see distro_tracker.project.setup.locals.py):
$ ./manage.py graph_models core | dot -Tpng >graph.png
Web Interface¶
Panels Framework¶
Distro Tracker allows an easy way to embed new information on a package Web page.
It consists of implementing a subclass of the distro_tracker.core.panels.BasePanel
class. Panels can provide the HTML directly or, alternatively, the name of the
template which should be included. This template then has to render the panel’s
information to the page.
It is recommended that the panel inherits from the core/panels/panel.html
template and fills in its contents to the blocks defined in the template, so
that the page remains visually consistent. This is not mandatory, however.
Note
All panel classes should be placed in a module called tracker_panels
found at
the top level of an installed Django app. Panels from apps which are not
installed will never appear on a package page.
Distro Tracker implements some general panels which could be used by any vendor.
Refer to the documentation of each panel in distro_tracker.core.panels
to see
any possible ways of augmenting their information by implementing
vendor-specific functions.
Views and Templates¶
The core views are found in distro_tracker.core.views
and are extremely thin.
The package page view only finds the correct package model instance and passes it on to available panels. It renders a template which includes each panel within the skeleton of the page.
Other core views are in charge of a redirect of legacy package URLs, package search and package autocomplete.