IPython-like RPM Lua interactive console
Recently, I’ve found myself in a position of writing and debugging some Lua based RPM macros and generators:
- speeding up python(abi) dependency generator by rewriting it from Bash to parametric Lua macro
- adding automated provides to replace most of the manual %python_provide calls
- reimplementing %python_provide from scratch as %py_provides
The capabilities of the embedded Lua interpreter in RPM are endless. My Lua skills are not. I need to test the code in small chunks to understand what am I doing.
When I need to do this in Python, I use the IPython console (my second favorite software in the Python ecosystem after pytest).
For Lua, I’ve used the lua
command for a while. It lets me test basic Lua concepts in an interactive console, but it’s not that powerful as the IPython console and it lacks the RPM provided Lua libraries.
I’ve asked Panu (my colleague and an RPM developer I work with when submitting changes to the RPM project) whether there is an interactive console for the Lua interpreter embedded in RPM and the answer was yes. I can use rpm --eval "%{lua:rpm.interactive()}"
. But it has some quirks.
Mostly, there is no command history or even line editing, and the output is hard to get.
ILua
Naturally, I’ve searched for an IPython like Lua console and I’ve found the list of Jupyter Kerneles (IPython console is a frontend to Jupyter). There are 3 Lua kernels there:
- Lua Kernel (discontinued)
- IPyLua (a fork of the above, not much active either)
- ILua
ILua intrigued me mostly because it says right away: “Lua-implementation agnostic, should work with any Lua interpreter out of the box.” That’s exactly what I need. Maybe I can use it with rpm --eval "%{lua:rpm.interactive()}"
.
Turns out I can, but it’s not that simple. The used Lua interpreter needs to respect the $LUA_PATH
environment variable and execute the file given to it as a command-line argument. Naturally, the simplistic rpm --eval "%{lua:rpm.interactive()}"
does neither.
So I’ve created a wrapper:
#!/usr/bin/bash
exec rpm --eval '%{lua:package.path = "'${LUA_PATH}';" .. package.path;'"$(cat "$@")"';rpm.interactive()}'
And it mostly worked. Except for the slight problem with missing print output. (The executed ILua script does the interactivity, so I’ve removed the rpm.interactive()
call at the end.)
I’ve tried to figure out how to launch the RPM Lua interpreter, not in the RPM macro expansion mode (that thing eats all the print output until the end). I’ve done a little RPM symbols lookup and source reading and figured out there is an rpmluaRunScript()
function in librpmio
. So I’ve tried to use it:
#!/usr/bin/python3
from ctypes import cdll, c_char_p
librpmio = cdll.LoadLibrary("librpmio.so.9")
librpmio.rpmluaRunScript(None, c_char_p(b"rpm.interactive()"), None)
It works. A little tweaking to support ILua as well as other use cases:
Note by Panu: rpmluaRunScript()
and rpmluaRunScriptFile()
are not considered public API and are not available in the public headers on C side, although the symbols are accessible in the ABI. So they are subject to change without further notice, although the likelihood of that happening doesn’t seem that great, they’ve been exactly the way are since their inception 16 years ago.
To use this, put the script on your $PATH
and invoke ilua -i <name_of_the_script>
.
And now I have an interactive IPython-like shell for RPM embedded Lua with command history, line editing, completion and more:
Enjoy! PS: ILua is on package review for Fedora, but can be safely pip-installed in the meantime.
Update from 2022
On RPM 4.18, the script above does not work, but you can use this instead:
#!/usr/bin/sh -eu
/usr/bin/rpmlua -e 'package.path = os.getenv("LUA_PATH") .. ";" .. package.path' "$@"
blog comments powered by Disqus