Why Lua was embedded into APT-RPM

Why embedding at all?

APT-RPM is a port of the debian APT tool to RPM systems. Since I’ve started working in the project, I’ve been thinking about integrating a higher level language on it. Actually, it’s pretty easy to explain this intention. How many times have you seen distributions hacking a project to fix some misbehavior specific to their environment, or wanting some very specific functionality, which wouldn’t fit in the general context of the upstream project? Attaching an external language allows you to plug these features, without affecting how the project is conducted. Also, I’m a fan of the productivity and flexibility offered by high level languages.

Why Lua?

One might think I’ve used Lua just because I live in the same country as its core developers (Brazil), but that’s not the case. Indeed, I’ve done a pretty intensive research about embeddable languages before choosing Lua. I was looking for a fast, and small language. When you have a library which has about 500kb, you can’t embed a large interpreter to extend the functionality, otherwise you’d be extending the interpreter, not the library. One might think that the interpreter library would be in the system anyway, so that wouldn’t be a real problem. Unfortunately, that doesn’t apply to APT-RPM, since it is used in small systems, and in installer environments. The current Lua interpreter is still under 100kb, and is very fast if compared to other interpreters. I really think the Lua interpreter has no current competitors in that specific area.

Slot code example

To give you an idea about how comfortable it is to work that way, I’ve recently introduced the possibility of passing generic filenames to the “apt-get install” command. To do that, I’ve introduced a new slot in the APT-RPM core, which is called when the data entered is not found as an available package name. Notice that this slot is generic, and works for other kinds of parameters, besides filenames. In the following slot code, notice that the Lua interface has been wrapped into a more useful API for the APT-RPM environment.

_lua->SetDepCache(Cache); 
_lua->SetDontFix(); 
_lua->SetGlobal("argument", Argument); 
_lua->RunScripts("Scripts::Apt::Install::TranslateArg", false); 
const char *name = _lua->GetGlobal("translated"); 
_lua->ResetGlobals(); 
_lua->ResetCaches(); 

Plugin code example

With the slot code above, developing the filename translation plugin was very straightforward. Of course, some kind of database containing the filename information was needed. I’ve used a compressed textfile, containing thousands of pairs like “filename packagename”, one per line. And here is the final plugin. Can you imagine how much code it’d take if implemented in C , the core language of APT-RPM?

-- Data sample: 
--   argument = "/usr/bin/lua" 
--   contents = "/var/state/apt/Contents.gz" 
--   translated = "newname" 
 
if string.sub(argument, 1, 1) == "/" then 
    contents = confget("Dir::State::contents/f") 
    if string.sub(contents, -3) == ".gz" then 
        file = io.popen("zcat "..contents) 
    elseif string.sub(contents, -4) == ".bz2" then 
        file = io.popen("bzcat "..contents) 
    else 
        file = io.open(contents) 
    end 
    len = string.len(argument) 
    for line in file:lines() do 
        if string.sub(line, 1, len) == argument then 
            _, _, path, name = string.find(line, '(%S )%s (%S )') 
            if path == argument then 
                translated = name 
                break 
            end 
        end 
    end 
    for line in file:lines() do 
        -- nothing, just don't break the pipe 
    end 
    file:close() 
end 

More information

For more information, have a look at https://moin.conectiva.com.br/AptRpm and https://moin.conectiva.com.br/AptRpm/Scripting

This entry was posted in C/C++, Lua, Project. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *