fnx
A package manager for the Fennel language.
Disclaimer: It's an early-stage project, and you should expect breaking changes.
- 1-liner Installer
- .fnx.fnl File
- Usage
- Embedding
- Installing
- Performance
- sudo
- Debugging
- Development
- Not a Roadmap
1-liner Installer
You need to have all requirements first.
curl -fsSL https://raw.githubusercontent.com/gbaptista/fnx/main/get-fnx.sh -o get-fnx.sh && sh get-fnx.sh
.fnx.fnl
File
The .fnx.fnl
file is a regular Fennel source code in the root directory of your project that should return a table.
Example:
{:name "my-package"
:version "0.0.1"
:dependencies {
:fspec {:fennel/local "../fspec"}
:supernova {:lua/local "../supernova"}
:splah {:fennel/fnx {:path "/home/splah"}}
:radioactive {:fennel/fnx {:git/url "https://git.sr.ht/~me/radioactive"}}
:fireball {:fennel/fnx {:git/url "https://github.com/me/fireball.git"}}
:moonlight {:fennel/fnx {:git/sourcehut "~me/moonlight" :commit "a6c728b"}}
:meteor {:fennel/fnx {:git/sourcehut "~me/meteor" :branch "main"}}
:jellyfish {:fennel/fnx {:git/sourcehut "~me/jellyfish" :tag "v0.0.1"}}
:purple-rain {:fennel/fnx {:git/github "me/purple-rain"}}
:red-sauce {:fennel/fnx {:git/gitlab "me/red-sauce"}}
:lemon {:fennel/fnx {:git/bitbucket "me/lemon"}}
:dkjson {:lua/rock ">= 2.5"}}}
key | description |
---|---|
:name |
Your package name. |
:version |
Your package version. Follows Semantic Versioning 2.0.0 |
:dependencies |
Your package dependencies. The example above should be self explanatory. |
Usage
Try the Hello World example.
Start by creating a .fnx.fnl file for your project.
command | description |
---|---|
fnx |
It’s an alias for the fennel command that wraps it with fnx capabilities. Just use it as a replacement for anything that you would do with fennel . It accept any of the options available for the fennel command. |
fnx help |
List the available fnx commands. |
fnx version |
It returns the fnx version. |
fnx config |
It returns the current fnx configuration. |
fnx debug |
It returns fnx injections for the current directory or file. Use -b if you are embedding. |
fnx env |
Generates environment variables exports to make fnx embeddable. |
fnx dep |
Dependencies Manager CLI. It lists the available fnx dep commands. Its commands accept --global and --local for luarocks . The default is --local . |
fnx dep install |
Install the dependencies described in the .fnx.fnl file. Use -f to force the re-installation of all dependencies. Use --verbose for verbose mode. |
fnx dep uninstall |
Uninstall the dependencies described in the .fnx.fnl file. Use -f to skip confirmation. Use --verbose for verbose mode. |
fnx dep list |
It lists the dependencies described in the .fnx.fnl file. |
Embedding
As is usual for Lua, you may want to embed Fennel into another language, e.g., Sweet Moon. In this scenario, you wouldn't have direct access to the fnx
terminal command.
So, you can run fnx env
to generate the necessary environment variables:
fnx env
export FENNEL_PATH=/home/me/.local/share/.fnx/core/?.fnl
export FNX_DATA_DIRECTORY=/home/me/.local/share/.fnx/
To actual export the variables, you can use:
eval "$(fnx env)"
You can also add the above line to your .bashrc
, .zshrc
, etc.
Then, in your embedded script, you can add:
(local fnx (require :fnx))
(fnx.bootstrap!)
It automatically injects all your dependencies according to your .fnx.fnl
file, similar to using the fnx
command.
You may want to set a specific path to the .fnx.fnl
:
(local fnx (require :fnx))
(fnx.bootstrap! "/home/me/project/.fnx.fnl")
Alternative code, for isolation:
(let [fnx (require :fnx)] (fnx.bootstrap!))
Or, for short:
((. (require :fnx) :bootstrap!))
If you need debugging, check this.
Installing
You need to have all requirements first.
Check the 1-liner Installer as well.
git clone git@github.com:gbaptista/fnx.git
cd fnx
luarocks install supernova --local
fennel run/install.fnl
Installation Options
Options for the fennel run/install.fnl
command:
option | description |
---|---|
-s |
Use auto-detect information and skip questions. |
-f |
Use auto-detect information and overwrite files without confirmation. |
-d |
Install in development mode as a symbolic link for the source code. |
Requirements
Performance
You might not be happy with the performance of the fnx
command compared to fennel
.
Alternatively, to keep using the fennel
command, you can do the same configuration used for embedding:
Export the environment variables:
eval "$(fnx env)"
Add into your entrypoint source code:
(let [fnx (require :fnx)] (fnx.bootstrap!))
Done. Just run fennel source.fnl
as usual instead of fnx source.fnl
.
sudo
If you need to use fnx
with the sudo
command, you may want to install fnx
dependencies in the superuser context for a complete experience.
You can do that with:
sudo fnx sudo
Debugging
You can run fnx debug
to understand what exactly is being injected:
fnx debug
fspec
--add-package-path /.local/share/.fnx/packages/fspec/default/fspec/?.lua
--add-package-path /.local/share/.fnx/packages/fspec/default/?/init.lua
--add-fennel-path /.local/share/.fnx/packages/fspec/default/fspec/?.fnl
--add-fennel-path /.local/share/.fnx/packages/fspec/default/?/init.fnl
--add-macro-path /.local/share/.fnx/packages/fspec/default/fspec/?.fnl
--add-macro-path /.local/share/.fnx/packages/fspec/default/?/init-macros.fnl
--add-macro-path /.local/share/.fnx/packages/fspec/default/?/init.fnl
If you are embedding, you can run:
fnx debug -b
fspec fspec
package.path /.local/share/.fnx/packages/fspec/default/fspec/?.lua
package.path /.local/share/.fnx/packages/fspec/default/?/init.lua
fennel.path /.local/share/.fnx/packages/fspec/default/fspec/?.fnl
fennel.path /.local/share/.fnx/packages/fspec/default/?/init.fnl
fennel.macro-path /.local/share/.fnx/packages/fspec/default/fspec/?.fnl
fennel.macro-path /.local/share/.fnx/packages/fspec/default/?/init-macros.fnl
fennel.macro-path /.local/share/.fnx/packages/fspec/default/?/init.fnl
Inside Fennel
Warning: The
debug
namespace is for debugging only purposes. Its API is unstable and may change anytime. Please don't use it in a way that your project depends on it.
To debug inside Fennel, you need first to ensure that your environment is ready for embedding.
Then, you can use the debug
namespace:
(local fnx (require :fnx))
(local fennel (require :fennel))
(print (fennel.view (fnx.debug.injections)))
; [{:destination "package.path"
; :package "fspec"
; :path "/home/me/.local/share/.fnx/packages/fspec/default/fspec/?.lua"}
; {:destination "package.path"
; :package "fspec"
; :path "/home/me/.local/share/.fnx/packages/fspec/default/?/init.lua"}
; {:destination "fennel.path"
; :package "fspec"
; :path "/home/me/.local/share/.fnx/packages/fspec/default/fspec/?.fnl"}
; ...
(print (fennel.view (fnx.debug.packages)))
; [{:package "fspec" :language "fennel"}
; {:package "supernova" :language "lua"}]
(print (fennel.view (fnx.debug.dot-fnx-path)))
; "/home/me/my-project/.fnx.fnl"
(fnx.bootstrap!)
If you are using a custom .fnx.fnl
file:
(local fnx (require :fnx))
(local custom-dot-fnx "/home/me/some-project/.fnx.fnl")
(fnx.debug.injections custom-dot-fnx)
(fnx.debug.packages custom-dot-fnx)
(fnx.debug.dot-fnx-path custom-dot-fnx)
(fnx.bootstrap! custom-dot-fnx)
Development
fnx dep install
fnx run/test.fnl
Not a Roadmap
A list of things that I don't have time to do or that just aren't itching me enough to do something about it, but I would like to do it someday, eventually:
- binaries;
-
fnx dep add
; -
fnx dep remove
; - Lock file;
- Actually use the version numbers for something;
- Improve performance;
- Get inspired by nix to improve the approach;
- Provide Windows Support.