dburrows/ blog

archive

To reply to a blog post, email me at Daniel_Burrows@alumni.brown.edu. Please let me know whether I should post your reply on the blog page.

aptitude-gtk updates: dpkg progress bar, choosing columns, more

It's been a long time since I wrote about aptitude-gtk. Mostly that's because I haven't been doing any work on it, due to a combination of several holidays, sickness and (last but certainly not least) an unfortunate relapse of WoW-addiction. But we have moved the ball forward since the 0.5.0 release. Some of the changes since then are just polishing, with no major changes in functionality, but there are a few things that are very visible:

Status pipe support

aptitude now supports the dpkg status pipe. This means that it can display a progress bar showing how far through the install process it is. In fact, if you are using the Gnome frontend for Debconf, you don't even need to display the terminal at all, unless a package is so uncouth as to prompt directly on standard input. I'd like to thank the Synaptic developers -- although this is all my own code, their implementation of this functionality was very valuable documentation of how apt frontends use the status pipe in practice. Incidentally, the aptitude implementation is modularized and available in src/generic/apt/parse_dpkg_status.cc and src/generic/apt/parse_dpkg_status.h. If you want to parse dpkg messages in your own GPL project, you might want to take a look at that code. And if I don't forget, I'll ask about including this in apt once the lenny freeze is lifted. [0]

Here's the dpkg progress bar in action, showing that dpkg is configuring libmad0:

aptitude dpkg progress bar

Clicking the "View Details" button on the dpkg progress bar will pop up a terminal in a new tab; you can close the tab and dpkg will go back to running in the background. And yes, I know that the progress bar for the download shouldn't hang around after the download completes. :-)

Searching for partial strings

As noted in the release notes for 0.5.0, incremental searching from the curses frontend was broken by the 0.5.0 release. I've created a new match term named ?term-prefix which matches against any extension of the term; for instance, searching form ?term-prefix(comp) will find any package that matches the term compiler, the term computer, the term compromise, or any other extension of comp. The upshot is that incremental searching should work again.

Editing the list of visible columns

The current package list doesn't show very much information. That's deliberate: I don't want to clutter the default view with a lot of stuff that's only necessary from time to time. But until now, there was no way to change which columns were visible. Now there is:

aptitude 'Edit Columns' dialog

This is a very rough proof-of-concept dialog that I've just checked into the source tree. The checkboxes are fully functional (clicking them shows and hides columns), but the buttons to save the current setup or to apply it to all the active tabs are not working. With this in place, we can think about creating columns for most of the interesting information about a package (archive, maintainer, etc).

[0] By which I mean, I'll say does anyone object if I add this utility code to apt?, and when no-one says no I'll commit it. :-)

Posted Tue Dec 23 23:03:00 2008 Tags: aptitude
On voting to release Lenny

Regarding the ballot currently before the Developers, Christian Perrier writes:

Moreover, the proposal is worded and was pushed in a way that all (but one) options that would allow us to release lenny will need a 3:1 majority, which is obviously very hard to achieve (and as, there are several such proposals, the vote will be spread out among all of them).

So, those folks who make the release of lenny their priority are now facing an interesting tactical choice: how the ..... should we vote for this to happen?

I personnally did choose to vote this way: 5462371.

I agree with Christian's goals, but in my opinion, the ballot he has cast actually makes less likely that the winning option will allow us to release lenny.

In Debian, we run a two-round election using a single ballot. In the first round, any options that need a 3:1 majority must defeat the default option by a 3:1 majority. Options which fail this test are eliminated and dropped from further consideration. In the second round, a winner is chosen from the remaining options using a Condorcet method as usual. The upshot of this is that the votes for the 3:1 majority cannot be spread out, unless people habitually place only one of the 3:1 options over Further Discussion. Furthermore, voting everything below Further Discussion benefits the options that don't require a 3:1 majority over the ones that do.

For a real example, let's say that we have a ballot like this:

[ ] Choice 1: Omelette [3:1]
[ ] Choice 2: Quiche [3:1]
[ ] Choice 3: Toast
[ ] Choice 4: Further Discussion

Suppose that we don't like the ballot at all, but we want an egg-based breakfast. What happens if we vote like this?

[2] Choice 1: Omelette [3:1]
[3] Choice 2: Quiche [3:1]
[4] Choice 3: Toast
[1] Choice 4: Further Discussion

This ballot can be read as: I don't think that omelettes or quiche should pass the 3:1 majority requirement. But if they do, I prefer them to toast. Unless 75% of the remaining voters vote omelette and quiche above toast, those two options will be thrown away, and the vote will be determined by whether half the voters placed toast over further discussion. If you want to make sure that toast doesn't win, you have to vote (insincerely) like this:

[1] Choice 1: Omelette [3:1]
[1] Choice 2: Quiche [3:1]
[3] Choice 3: Toast
[2] Choice 4: Further Discussion

Sadly, there is no way to vote against the vote without effectively also voting for toast!


I wonder if it was a mistake to combine the supermajority vote and the Condorcet vote on a single ballot. Maybe it would be better to write both ballots out explicitly:

Some options on this ballot must be approved by a 3:1
supermajority of the electorate.  Please enter 'Y' next to the
options that you approve of and 'N' next to those you disapprove
of.  Ballot options on which 75% of voters vote 'Y' will proceed
to the next round (below).

[ ] Choice 1: Omelette [3:1]
[ ] Choice 2: Quiche [3:1]

Rank the ballot options below:

[ ] Choice 1: Omelette [3:1]
[ ] Choice 2: Quiche [3:1]
[ ] Choice 3: Toast
[ ] Choice 4: Further Discussion

That would allow people who want to vote against the vote without privileging any of the options over the others to do so: vote Y to all 3:1 options, then vote 2221 on the rest.

On the other hand, I suspect people would be confused in different ways by a voting system that was this complicated, voting Y in places where they should write a number and writing numbers where they should write Y or N. I guess all this mess is why we still use First Past the Post for votes in the real world...

Posted Sun Dec 14 07:30:00 2008 Tags: debian voting
aptitude 0.5.0 released

I've released version 0.5.0 of the aptitude package manager (release notes). Once the mirrors have synced, you should be able to download it from Debian's experimental distribution, or manually from the aptitude package page.


[Edit] This release was uploaded to experimental because it is not a final release. aptitude follows the Linux version numbering scheme in which an odd second digit indicates an unstable development version. DO NOT INSTALL THIS VERSION IF YOU WANT STABLE SOFTWARE; IT IS INCOMPLETE, INADEQUATE, AND PROBABLY INCORRECT.

To reply to some questions that several people have asked me:

  1. The final release of aptitude 0.6.0 will be split into two packages, one containing only the traditional text interface and named aptitude-curses, and one containing the GUI binary named aptitude-gtk, with both of them providing the aptitude binary through Debian's alternatives mechanism. This release wasn't split because the code to drop GTK+ support was buggy and I discovered this fact halfway through assembling the release. It's fixed now.

  2. To run the traditional curses interface, pass the --no-gui command-line parameter or set the option Aptitude::Start-Gui to false in /etc/apt/apt.conf. Unless you want to test that the curses frontend isn't broken, though, there won't be much for you in this release: the only change affecting it is Xapian support, and that currently breaks incremental search. (see the note above about this being an unstable release)

Also, another feature that I suspect might be bothersome is the behavior of updating the package lists and downloading changelogs on startup. There's no switch for changelogs yet, but you can disable the package list update by setting Aptitude::Update-On-Startup to false.


The main change in this release is the new GTK+ frontend, designed and implemented by Obey Arthur Liu with funding from the 2008 edition of Google's Summer of Code.

aptitude 0.5.0 screenshot

The new frontend is is an effort to bring some of the design principles of the curses frontend to a GUI environment, while also exploiting the unique features a GUI gives us and exploring ways to deal with changes in the environment in the nine years since aptitude was first designed. For instance, it is no longer reasonable for the user to actually read the entire package list (when I first installed Debian, you could read through the whole package list in a single sitting). So instead of basing the interface around a list of all the packages, we based it around the ability to search for the packages you're interested in.

This version of aptitude also introduces Xapian searching:

daniel@emurlahn:~$ aptitude search "apt package manager"
i   apt                                  - Advanced front-end for dpkg
p   apt-dater                            - terminal-based remote package update manager
p   apt-dater-dbg                        - terminal-based remote package update manager (d
i   aptitude                             - terminal-based package manager
i   aptitude-dbg                         - Debug symbols for the aptitude package manager
p   createrepo                           - generates the metadata necessary for a RPM pack
p   gnome-apt                            - graphical package manager
p   smartpm                              - An alternative package manager that works with
p   smartpm-core                         - An alternative package manager that works with
i   synaptic                             - Graphical package manager
i A update-manager-core                  - APT update manager core functionality

You might ask why I didn't search for just package manager. The reason is simple: aptitude doesn't yet sort by relevance, and that second search gave me screenfuls of packages whose description contains both package and manager, including addressmanager.app (a PIM for GNUstep), compiz-gtk (a piece of eye candy), and wterm (an X terminal emulator). However, it is worth noting that Xapian searches are fully integrated into the aptitude search language, so they can be combined with non-Xapian search terms in just the way you would expect:

daniel@emurlahn:~$ aptitude search "?installed apt package manager"
i   apt                                  - Advanced front-end for dpkg
i   aptitude                             - terminal-based package manager
i   aptitude-dbg                         - Debug symbols for the aptitude package manager
i   synaptic                             - Graphical package manager
i A update-manager-core                  - APT update manager core functionality

So, all the basic functionality that the GUI version needs is in place; the next step is to start polishing it and filling in the gaps that are left. And, of course, suggestions and bug reports are welcome, so we know where the rough spots and the gaps are. Please send your comments to aptitude-devel@lists.alioth.debian.org so that they are part of the public record and so that people besides me can read them. :-)

Happy package managing!

Posted Tue Nov 11 22:56:00 2008 Tags: aptitude release
Package Management Sudoku 2

I got several emails in reply to my previous post on representing Sudoku problems as package dependencies. Several people asked about the algorithm that aptitude uses to solve these problems. A slightly out-of-date discussion package management and the aptitude algorithm can be found at http://people.debian.org/~dburrows/model.pdf. One question was interesting enough to deserve a follow-up blog post: Wolf T. referred to the page http://norvig.com/sudoku.html and asked how long it would take aptitude aptitude to solve the hard Sudoku problems on that page. He suspected that aptitude would do basic constraint propagation and then be forced to exhaustively search all the possible solutions to the problem.

In brief: the answer is that it doesn't work by default, but not for the reason he suggested, and you can make it work with a few command-line arguments. In order to try this out you'll need a new version of the Sudoku reducer that can parse the problems on that Web page: debsudoku2.py.

If I do a straight conversion of one of those problems and then run it through aptitude, it goes spinning off and never comes back. But aptitude is coded to avoid exhaustive searches; otherwise it couldn't solve dependency problems in reasonable amounts of time. In this particular situation, though, aptitude is clearly performing an exhaustive search; here's one series of status outputs:

open: 5124; closed: 4993; defer: 0; conflict: 374
Resolving dependencies...
open: 10090; closed: 9942; defer: 0; conflict: 398
Resolving dependencies...
open: 14726; closed: 14888; defer: 0; conflict: 440
Resolving dependencies...

Here open is the number of partial solutions that aptitude wants to examine, and closed is the number that it's already examined. aptitude isn't making progress here and it isn't finding solutions; in fact, it's creating, on average, about two new partial solutions for every one it examines.

Why is aptitude doing this? Its resolver isn't a brute-force algorithm; in fact, it looks remarkably like the Sudoku solver discussed at http://norvig.com/sudoku.html. On each step, aptitude takes a partial solution, picks one dependency, and resolves it by installing or removing a package. This is pretty much equivalent to filling in one not-filled-in cell; in fact, in the conflicts Sudoku reduction, it's exactly equivalent.

There is one difference, though, and it stems from a difference in the problem domains of Sudoku and package management:

Not all dependency resolutions are created equal.

In Sudoku, any solution to the puzzle will do. Not so in package management; solving a dependency problem by removing every package on the system will produce a formally correct answer and a very unhappy user. Even results that are not utterly disastrous could be annoying to the user, so the resolver needs to somehow aim for good answers.

The page on Sudoku solvers suggests sticking to whatever value you placed in a cell, unless that doesn't lead to any solutions at all. This is technically known as a depth-first search. The problem with taking this approach when resolving package dependencies is that an apparently safe choice can end up requiring undesirable actions later on (like removing large swathes of the system). For this reason, aptitude tries to strike a balance between sticking to its current line of reasoning, and abandoning it when it seems to be turning out badly (this makes it a form of best-first search).

On typical Debian archives, the package relationships are simple enough that it's OK if aptitude does this from time to time; it makes the search a little more thorough (thus costly), but the ability to back out of questionable branches is very valuable. But it looks like when aptitude is applied to Sudoku puzzles, it has trouble settling on a single series of choices. It keeps thinking that the solutions are getting worse, so it backs up and tries another branch, but they don't look any better over there, so it backs up and tries another branch, and so on.

The option Aptitude::ProblemResolver::StepScore sets how hard aptitude will try to stick to the same line of reasoning. Its default value is 70, which is reasonable for package archives, but turning it up to a large value such as 10000 will cause aptitude to use a straight depth-first search, just like the Sudoku page recommends:

$ aptitude -s -o 'aptitude::problemresolver::stepscore=10000' -o 'aptitude::auto-install=false' install puzzle

Setting auto-install to false is a workaround for another odd corner case/bug that happens to bite this Sudoku problem: for technical reasons, doing this lets aptitude know that it should avoid solutions that cancel the installation of puzzle. Otherwise you have to sit there telling it no for a bunch of solutions you aren't interested in. Future versions of aptitude will probably provide a way to explicitly give hints to the resolver.

With these options, aptitude was able to solve the hard Sudoku puzzles that I gave it in anywhere from fifteen seconds to a minute and 47 seconds. In contrast, the straight Sudoku solver does 30 problems in a second. Why is aptitude so slow? Based on skimming debug traces and looking at the run-time behavior, I conjecture that there are several reasons:

  1. The aptitude search algorithm is very heavyweight. In the case where it takes over a minute, it only actually examines about 5,000 possible solutions. I don't know exactly where all this time is going, but I do know that the resolver does a lot of work on each step, for instance to try and detect dead ends that it hasn't reached yet. This is the conflicts counter that appears while the resolver is running. This pays off tremendously in terms of allowing aptitude to skip huge amounts of work (it may be why aptitude can solve Sudoku puzzles at all!), but it means that the resolver takes a long time for each potential solution it looks at.

  2. The Sudoku page suggests taking the cell with the fewest number of possible entries as the choice. I distinctly remember writing code to do this in aptitude, but it looks like I threw it out at some point or never committed it. I don't see why it should be any worse than the current approach, though (which is to pick an arbitrary dependency); maybe it just got misplaced at some point. Implementing this behavior decreased the time required to solve one puzzle from a minute and 45 seconds to just under a minute; I've committed this change to the post-lenny branch.

  3. The Sudoku resolver has the advantage of being able to very quickly identify illegal moves. aptitude's resolver can learn this information, but it takes time and it can't apply Sudoku-specific optimizations. For instance, the Sudoku solver knows exactly which values can be placed in a given cell at any time. aptitude has to actually consider each of the cells that's available as a possibility and prove to itself that, e.g., 4 and 6 can't be written in the same cell at the same time. And although it can learn this information, it takes time to do so and it takes time to see whether any of the past conflicts that it remembers are present in a given solution.

As I noted above, I've already checked in one change to the resolver's behavior. It might also be worth seeing what happens with a massive increase in StepScore, so I've pegged it at 10000 on my computer to see whether the results I get are noticeably worse.

The third item above -- the fact that aptitude needs to do more work to understand which packages can't be installed -- is interesting. The Sudoku solver is very proactive about this: it keeps track at all times of which cell values are legal, and updates these sets every time it transitions. In contrast, aptitude constantly re-checks all the possible moves it could make to see which ones are currently legal.

I think that the resolver's speed could be boosted a little by doing the following:

  1. Cache the currently legal solutions of each dependency at the time it's inserted into the queue.

  2. When a new search node is generated by resolving a dependency, drop the formerly legal moves that are knocked out (for instance, by installing a different version of the same package).

  3. Come up with a quick way of re-testing new conflicts (the global list of dead-ends) so that search nodes that are already in the queue can be checked against the conflicts that were added since they were queued.

These changes won't make aptitude able to solve problems that it couldn't solve before, or at least not very many of them, but they should make the resolver faster on every problem it encounters. However, I don't think I want to actually implement them. It would be tricky to confirm that the resolver got faster on real dependency problems (since it's normally almost instantaneous), the changes would make the resolver code more complex and fragile (less readable, less maintainable), and there's a real chance of breaking something. Unless there are cases where the resolver is currently too slow on real package archives that don't involve an exponential blowup, I'm going to shelve the idea for now.

Posted Sat Aug 23 11:15:00 2008 Tags: apt cs package management sudoku
Package Management Sudoku

Update: There are more notes on how aptitude performs as a Sudoku solver here.

Russell Coker recently wrote a post entitled Ownership of the Local SE Linux Policy. This post has nothing to do with the substance of his post, which is a discussion of how distributions should configure SELinux by default. I know nothing about SELinux, but something that Russell said in passing caught my attention:

I am not aware of the Debian package dependencies (or those of any other distribution) being about to represent that the postfix package depends on selinux-policy-default-postfix if and only if the selinux-policy-default package is installed. Please note that I am not suggesting that we add support for such things, a package management system that can solve Sudoku based on package dependency rules is not something that I think would be useful or worth having.

(emphasis added)

As it happens, a little-known fact about the Debian packaging system is that you can, in fact, describe Sudoku puzzles in it!

Note for the impatient: If you want to skip all this talk and jump to the code, see debsudoku.py.

For those of you who, like me, are not Sudoku-heads, here's a quick summary of the rules (for the common case of a game with 3 blocks):

  1. The game is played by filling in a 9-by-9 grid with numbers between 1 and 9, inclusive. The board is divided into 9 3-by-3 blocks of grid cells in the obvious way.
  2. All the cells in a column must contain different numbers.
  3. All the cells in a row must contain different numbers.
  4. All the cells in a block must contain different numbers.

There are many ways that you could convert a Sudoku problem into a Debian package archive, but here's a particularly simple one that is close to my summary of the rules. Create 9 * 9 * 9 = 729 packages, named cellR.C-V where R stands for row, C for column, and V for value. Each of these packages represents writing the value V in the cell (R, C). To describe the relationships of each cell to the other cells in the problem, we can create several virtual packages:

Converting these requirements to package dependencies is quite straightforward. For the package cellR.C-V, in block row BR and block column BC, we add these lines to the package's definition:

Provides: cellR.C, blockBR.BC-V, rowR-V, colC-V
Conflicts: cellR.C, blockBR.BC-V, rowR-V, colC-V

For instance, the cell at (5, 8) will get these provides/conflicts for V=2:

Provides: cell5.8, block2.3-2, row5-2, col8-2
Conflicts: cell5.8, block2.3-2, row5-2, col8-2

This relies on the fact that self-conflicts are ignored (see Debian Policy section 7.4).

To actually describe the puzzle we want to solve, we need to add another package that requires two things:

  1. Every cell contains a value.
  2. The cells that the problem fixes have their fixed values.

For instance,

Package: puzzle
Depends: cell1.1, cell1.2, ..., cell5.9-3, cell6.1, ....

if we want to require that the cell at (5, 9) contains the value 3.

Proof-of-concept

As a proof-of-concept, I have written a hacky Python script, named debsudoku.py, that can convert ksudoku saved games into Packages files suitable for use with apt-get or aptitude. In fact, it has two modes: conflicts, which implements the conversion described above, and depends, which implements a different but logically equivalent conversion using only Depends instead of Conflicts. To use the script, save a ksudoku board without doing any work on it, then run

python debsudoku.py /path/to/the/ksudoku/board

I've only done minimal testing on this, so don't use it to fly airplanes (in fact, please don't use any Sudoku player to fly airplanes), but I did use it, in combination with aptitude, to solve a single ksudoku puzzle.

Real-world evaluation

Interestingly, in a test with an easy puzzle generated by ksudoku, aptitude was able to solve the puzzle in just a few seconds when it was expressed with the conflicts reduction, but failed to find a solution at all using depends (I stopped it after several minutes).

I think this is due to how the depends reduction is performed. Take rows: instead of generating conflicts between cells in a row, it requires that each row contain every number between 1 and 9. The problem with this is that aptitude's resolver functions poorly when there are non-obvious conflicts in the dependency structure. It will decide to try a combination of packages that can't be installed together, but it won't realize it. As a result of this, it ends up trying many possible combinations of packages. For instance, it might try to place the number 3 in both (2, 5) and (5, 5). There is no dependency outlawing this in the depends reduction, so aptitude will happily continue trying to resolve dependencies. Since it has used 3 twice in the fifth column, it will not be able to find any way to resolve all the dependencies that state that all the numbers between 1 and 9 appear in the 5th column, but it lacks the higher-level reasoning that would allow it to break out; it will end up trying many or most of the possible ways of filling cells in before it gives up on the offending re-use of 3.

Luckily, real-world package archives (what the aptitude resolver is designed to run on) don't usually look like this.

Posted Tue Aug 19 22:23:00 2008 Tags: apt cs package management sudoku
No hyphenation joy in GTK+.

I've thought on and off that it would be nice for the graphical version of aptitude to have decent hyphenation. Word-wrapping descriptions looks OK, but when the text area is thinner than the entire screen, it can look a little ragged on the right-hand side. For instance, take this rendering of the description of the toy program bb:

Unhyphenated text is ugly

Not too bad, but if I render it in LaTeX, here's how it comes out:

Hyphenated text is pretty

Of course, for very thin text columns (and the above is arguably pushing it), hyphenation and text justification aren't what you want. But it would be nice to be able to at least see what it looked like.

Figuring that GTK+ might have some support for this, I delved into Google. I found this:

Line breaking

Line breaking adds additional layers of complexity. For one, all potential line breaks must be identified, including discretionary hyphens for Latin scripts, and word boundaries in (???). Secondly, inserting hyphens may require reshaping. Third is the line breaking algorithm itself, which may be nontrivial.

-- Pango 0.1 proposal, Raph Levien, 1999

and this:

Future plans for Pango include support for high quality printing, better hyphenation support, full justification, and the ability to handle vertical text such as Chinese and Japanese.

-- Pango: Text handling for the World, LWN (Forrest Cook) 2001

and also this:

I've been working on code to do hyphenation, hopefully to add to Pango. My new code is faster than libhnj and groff and uses less memory.

-- Hyphenation Design (Was Re: Possible Pango 1.4 ideas), Damon Chaplin, post to org.gnome.gtk-i18n-list.

But no sign that any work has been done on hyphenation recently. :-(

The one intriguing thing I noticed, although it's not GTK+ at all, was the libhyphen0 library, which might be useful. Unfortunately, it's a bit more complicated than just flipping a switch in GTK+: the library is documentation-free, so to figure out how to use it I'll need to read through its source code and deduce the expected interface from that. Meh. Probably something to stick way at the bottom of the priority list.

Posted Mon Aug 11 21:16:58 2008 Tags: gtk hyphenation
aptitude 0.4.11.9 released

I've released version 0.4.11.9 of the aptitude package manager (release notes). This release incorporates a few trivial bug-fixes that I hoped to get out before the lenny freeze, but real life intervened. More importantly, it includes the fix for bug #483459, a non-fatal but highly annoying bug that affected Polish users. I hope the release team allows this one into lenny after it's been tested in unstable, but we'll see. I'll put in a formal request for an exemption once the new release has steeped a enough.

Posted Mon Aug 11 20:44:19 2008 Tags: aptitude release
CWidget tutoral 1: 'Hello, world!'

Late last year, I spent some time disentangling aptitude's internal UI library and packaging it as a separate library, which I named cwidget. This article is the first in what will hopefully become a series describing the basic concepts and APIs of cwidget. It applies to the versions of cwidget currently available in Debian sid and lenny, 0.5.11-1 and 0.5.12-1. Autogenerated documentation of cwidget can be found here (but beware that as of this writing it is somewhat incomplete).


In this tutorial, I will walk through a simple program (hello.cc) that initializes cwidget, displays a simple message box, and then terminates the program when the user confirms the message. I assume a basic familiarity with C++.

Screenshot of the 'Hello, World' program

The first thing to do is to include the portions of cwidget that our program will use. Most importantly, we need the top level cwidget routines. These are the global routines that initialize cwidget, shut it down, and control its main loop (among other things).

#include <cwidget/toplevel.h>

cwidget comes with a collection of stock dialog boxes for things like displaying messages to the user. To access the routines that build these dialogs, we write:

#include <cwidget/dialogs.h>

All the symbols provided by the cwidget library are in the cwidget namespace. Using the full library name means that there's a reasonable chance that its names will not conflict with the names provided by other libraries; however, it's a real pain to type cwidget over and over. Since this is the only namespaced library we are using in this program, it's handy to define cw as an alias for cwidget:

namespace cw = cwidget;

Now we're ready to write the main routine. The first interaction of client code with the cwidget library is to initialize it. This will initialize the ncurses library and put the terminal into a mode suitable for a full-screen curses program.

cw::toplevel::init();

Next, we create a dialog box that will be displayed to the user. There are two things to note about this code:

  1. cwidget is Unicode-aware and the ok() routine expects the message string to be a wide-character string. In this case, that means that we need to pass in a wide-character string (indicated by typing L in front of the string).

  2. The second argument tells cwidget what to do when the ok button is pressed. The expression

      sigc::ptr_fun(cw::toplevel::exitmain);
    

    creates a slot using libsigc++. Briefly, a slot is a reference to a function or to a method of a class instance. When invoked, this particular slot will call cwidget::toplevel::exitmain(), which causes the main cwidget loop to exit. The slot is wrapped in cwidget::util::arg, a utility function that handles passing slots as optional arguments.

cw::widgets::widget_ref dialog =
    cw::dialogs::ok(L"Hello, world!",
                    cw::util::arg(sigc::ptr_fun(cw::toplevel::exitmain)));

Now that we have a widget, the next step is to arrange for it to appear on the terminal. In cwidget, control of the terminal is assigned to a single top-level widget: whatever it displays is what gets displayed on the terminal, and all user input is passed directly to it. In a real program this widget will typically manage a collection of sub-widgets and assign each one a screen region, but for now let's just display the dialog box we created:

cw::toplevel::settoplevel(dialog);

With everything initialized, we're ready to start the main loop. mainloop() will keep the display up-to-date and dispatch incoming events (for instance, keystrokes and mouse presses) until exitmain() is invoked.

cw::toplevel::mainloop();

When the user presses Enter or clicks on the Ok button in the dialog, exitmain() will be invoked by the binding that we set up earlier. Once this happens, we need to shut down cwidget in order to restore the terminal to its original state. If you skip this step, the terminal will be garbled and will not work properly when your program exits.

cw::toplevel::shutdown();

And that's it! To compile the program, change to the directory containing hello.cc and run:

$ g++ -o hello hello.cc $(pkg-config --cflags --libs cwidget)

Of course, you'll need to have the g++ and libcwidget-dev packages installed for this to work!

Posted Fri Jul 4 13:03:00 2008 Tags: cwidget tutorial
Welcome to Obey Arthur Liu, GSOC coder

So I've been inexcusably tardy in announcing this, but Obey Arthur Liu is working on aptitude for Google's Summer of Code program. His goal is to write a third interface to the program, using GTK+ to produce the UI; as the abstract for his project states:

I will create a GTK+ GUI for Aptitude that will work alongside improved current ncurses and command-line interfaces. This will offer an alternative to Synaptic with an interface design geared toward usability and advanced functionality.

I'm looking forward to seeing what he comes up with! I think there are a lot of interesting possibilities in the design space of GUI package managers; hopefully he'll have time to explore at least a few of them. At the moment he's focusing on figuring out the care and feeding of the apt library backend and learning some of the quirks you have to deal with when writing a frontend against it.

Arthur's blog can be found at http://www.milliways.fr and on Planet Debian. The Mercurial repository for his work can currently be found at http://dev.graffit.net/aptitude/hg/.

Posted Thu Jun 19 07:22:00 2008 Tags: aptitude debian gsoc
aptitude 0.4.11.4 released

I've released version 0.4.11.4 of the aptitude package manager (release notes). The main motivation for this release is bug #483920, which would cause the resolver to choose solutions badly (e.g., it might prefer downgrading a bunch of packages to keeping them at their current versions). It also includes a simple fix for bug #136874, the fact that the output of aptitude search is badly suited for scripts (it still is, but now there's a command-line option that will make it better).

Posted Sat Jun 7 18:38:00 2008 Tags: aptitude release
Worst Debian day ever.

Regarding the OpenSSL debacle, Julien Blache writes:

Worst Debian day ever since the 2003 compromise. And that was a BAD one.

I disagree. This is far, far worse than the 2003 compromise. The compromise was scary, but the key updates for users were straightforward and as far as we know, user security was never actually compromised. In contrast, every single user who uses Debian or Ubuntu for anything serious is now (Update: and has been for two years) vulnerable to attacks on their supposedly secure cryptography [0] unless they perform a labor-intensive and error-prone series of steps to regenerate all their cryptographic keys -- not to mention finding a secure way to distribute their public keys to everyone who needs them!

[0]: Update: I should perhaps make it clear that I mean anyone who generated a key on such a system. But in a way this makes things worse: unless you're willing to regenerate every key in sight, you need to check each key manually, which means that there's a nontrivial chance that you'll overlook one and leave yourself vulnerable...

Posted Wed May 14 08:10:00 2008 Tags: debian
Breaking radio silence

We've spent the last week and a half moving out of the bizarre twilight zone known as Redmond into the city of Seattle proper. This cuts down on my commute tremendously (although poor Kate has to do the opposite of what I used to do each day), and it's great to be able to walk to the grocery store whenever I want. It may also mean that I'll cut back a bit on my Debian work in favor of actually having a life.

Half my stuff is still in boxes, so I'll be busy with this move for a while longer, but at least I have Internet and email access again now.

Posted Fri May 9 22:30:00 2008
The trifecta of loathing

I talked to my mother last week about the upcoming Pennsylvania primary (scheduled for tomorrow, April 22nd). She lives in the semi-rural Pennsylvania town where I grew up, and so I asked her what her impression was of how the locals felt about the campaign. Well, she said, they think the war is a disaster and they don't want to vote for McCain because they think he'll continue it forever. And of course they don't want to vote for a black man. And they all hate Hillary and think she's evil. So they're having some trouble trying to decide who to vote for; they can't figure out which candidate they despise the least.

Posted Mon Apr 21 20:30:00 2008 Tags: politics
aptitude 0.4.11.2 released

I've released version 0.4.11.2 of the aptitude package manager (release notes). This is basically a bugfix release to clean out some problems that were introduced in the previous release (most notably a nasty problem in safe-upgrade).

Posted Sat Apr 12 20:07:00 2008 Tags: aptitude release
aptitude 0.4.11.1 released

Last weekend, I released version 0.4.11.1 of the aptitude package manager (release notes). This is a minor release focusing mostly on bug-fixes and on a few features that I've been meaning to add but that didn't make it into 0.4.11. I think the most interesting addition is --show-why, which is like --show-deps but traces back to the closest manually installed package.

In some wide-character locales, the fix for bug #472625 in this upload of aptitude triggers bug #473874 and bug #474065 in apt; the symptoms are an error message about line N too long (max 1024) on start-up, and messages saying that method http has died unexpectedly! when you try to update the package lists or install new packages. I've written patches to fix these bugs in apt, and once they're reviewed by the other apt maintainers they should be fixed in the next upload of apt (version 0.7.12). Until then, if you're bitten by this bug, you can work around it by diverting /usr/share/aptitude/aptitude-defaults.$LANG and replacing it with an empty file. For instance, for Russian (ru):

 # dpkg-divert --rename --local --divert /usr/share/aptitude/aptitude-defaults.ru.real --add /usr/share/aptitude/aptitude-defaults.ru
 # echo > /usr/share/aptitude/aptitude-defaults.ru

Once a fixed apt is uploaded, you can remove the diversion like this:

 # rm /usr/share/aptitude/aptitude-defaults.ru
 # dpkg-divert --rename --local --remove /usr/share/aptitude/aptitude-defaults.ru
Posted Sat Apr 5 08:00:00 2008 Tags: aptitude release