gbaptista / fnx

A package manager for the Fennel language.
https://github.com/gbaptista/fnx
MIT License
27 stars 1 forks source link
fennel fnx package-manager

fnx

A package manager for the Fennel language.

Disclaimer: It's an early-stage project, and you should expect breaking changes.

fspec dep list example

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: