Do not follow this link

~technomancy/letrec

An isolated content-addressable package loading system for Lua/Fennel
Historical note.
Cache loaded module.
Add a very basic test.

refs

master
browse  log 

clone

read-only
https://git.sr.ht/~technomancy/letrec
read/write
git@git.sr.ht:~technomancy/letrec

You can also use your local clone with git send-email.

#letrec

The name is provisional. To be clear, this is not about the recursive lexical binding form.

An isolated content-addressable package loading system.

Requires Fennel version 0.5.0-dev.

To contribute, please send patches to myself or the Fennel mailing list. Discussion happens largely on the #fennel channel on Freenode or Matrix.

#Historical Note

This repository represents my attempts to build a content-addressable package system for Fennel/Lua. It's not particularly sophisticated, but for pure Fennel/Lua code, it doesn't need to be.

The problem is that extending the system to cover modules implemented in C rather than Fennel/Lua changes it from an easy, fun side project to a sisyphean nightmare, because C code tends to be packaged and built in ways that vary both wildly and pointlessly. Without the ability to cover code that uses C code, this system is of limited value.

#Import

The process starts with the importer. When you want to use a module, it first has to be imported into the store along with all the modules it requires. We analyze the module to identify its dependencies by using containment to replace require with a shim which records the dependency modules. In the future we could do this by parsing the source instead since not all requires happen at the top level; the current approach means that importing only works on well-behaved modules.

Once we determine a module's dependency tree, we walk it down to the leaves and for each leaf module we checksum it. The checksum is based on several factors: the contents of the file, the checksum of letrec itself, and the versions of Fennel and Lua used. The leaf module is copied into the store using a key based on the checksum. Once the leaves are imported, we walk back down the tree, but for non-leaf modules we incorporate the checksums of their dependencies into their checksums. We also store metadata for each module indicating how the module names for each dependency map to checksums.

#Loading

Rather than loading modules by name, you load them based on their key which ensures you're always getting the exact same thing you asked for.

After a module and its dependencies have been imported, it can be loaded. We add a package searcher which knows how to look in the store for modules. It loads it in a context which has require replaced with a letrec-aware equivalent. This version of require looks at the metadata tree that was generated during import, and whenever a module needs to load one of its dependencies, it ensures that it always gets the right one that was locked in at import time.

#Store

Right now we just use a local filesystem directory is the store, but it's easy to imagine replacing it with a networked store such as IPFS, git, DAT, etc.

#TODO

  • test suite
  • automate ingesting an entire library at a time (from luarocks or git)
  • fennel integration in importer
  • project-level config files (mapping human readable names to keys)
  • explore using it in development with changing modules

#Limitations

Right now, the method we use to detect requires is unusual; it runs the file in an isolated environment which records all calls to the require function and aborts if an error is encountered. This means it only works on modules whose dependencies are loaded at the top of the file.

We don't even attempt to handle C modules at this time.

#Glossary

  • Import: to take a normal module and import it into the store
  • Store: the storage location for imported modules
  • Module: a unit of code returning a value referenced by a single name
  • Searcher: a function which searches for a module and provides it to require
  • Resolve: the process of making a module content-addressable
  • Containment: the process of loading a module in an isolated way to analyze it

#License

Copyright © 2020 Phil Hagelberg and contributors

Released under the same license as Fennel.

Do not follow this link