lgi-devs / lgi

Dynamic Lua binding to GObject libraries using GObject-Introspection
MIT License
436 stars 69 forks source link

Add ability to import lua files from GResources #168

Open TingPing opened 7 years ago

TingPing commented 7 years ago

One of the nice features of gjs is that you can import modules from within a GResource. This leads to the common usage of applications shipping a single resource bundle or single executable and avoids doing extra blocking disk io.

Here is a basic implementation of this:


local lgi = require('lgi')
local Gio = lgi.require('Gio')

package.loaders[#package.loaders + 1] = function (str)
  if str:sub(1, 12) == 'resources://' then
    local data = Gio.resources_lookup_data(str:sub(13), Gio.ResourceLookupFlags.NONE)
    if not data then
      return ' - Failed to find data for that path!'
    end

    local str = data:get_data()
    if not str then
      return ' - Failed to get data for that path!'
    end

    local module = loadstring(str)
    if not module then
      return ' - Failed to load string for that path!'
    end

    return module
  end
end

local window = require('resources:///org/gnome/Foo/window.lua')

Now I am not overly familiar with the codebase or even Lua so I am unsure where this best belongs but any feedback on the idea would be appreciated.

psychon commented 7 years ago

Two comments on your code (I know you write "basic implementation", sorry): It only works in Lua 5.1 (package.loaders was replaced by package.searchers, but I think the semantics are still the same; loadstring was replaced by load) and as far as I can tell, data:get_data() cannot fail (g_bytes_get_data() only returns NULL when size=0), so I'd replace the second part of the code with loadstring(data:get_data() or ""). Oh and perhaps the second argument to loadstring / load should be str so that Lua can use the URI to the 'file' in error messages.

For the idea: I like it. A lot. However, I do not see how to add it nicely to LGI, too.

TingPing commented 7 years ago

Thanks for the comments. Honestly it could be as simple as lgi.require_resource('/foo/bar/window.lua')

TingPing commented 7 years ago

Here is an updated version with better error printing:

function (str)
  if str:sub(1, 12) == 'resources://' then
    local data = Gio.resources_lookup_data(str:sub(13), Gio.ResourceLookupFlags.NONE)
    if not data then
      return ' - Failed to find data for that path!'
    end

    local module, err = loadstring(data:get_data() or '', str)
    if not module then
      return ' - ' .. err
    end

    return module
  end
end