https://github.com/target/lorri
lorri is a nix-shell
replacement for project development. lorri is
based around fast direnv integration for robust CLI and editor
integration.
👉 Check out our blog post to see how lorri
improves on the nix-shell
experience during everyday development as well as
in common scenarios like channel updates and Nix garbage collection.
The project is about experimenting with and improving the developer's experience with Nix. A particular focus is managing your project's external dependencies, editor integration, and quick feedback.
lorri supports Linux and macOS.
This screencast shows lorri and direnv working together to reload the
development environment as shell.nix
is updated:
If you are using NixOS, home-manager
on Linux, or
nix-darwin
on macOS, and a Nixpkgs channel at least as recent
as nixos-19.09
, you can get started with lorri as follows. Otherwise see the
next section, Setup on other platforms.
-
Enable the daemon service. Set
services.lorri.enable = true;
in your NixOSconfiguration.nix
, your home-managerhome.nix
, or your nix-darwinconfiguration.nix
.This will automatically install the
lorri
command and set up the daemon to run in the background.Note: There's a known issue preventing the lorri daemon from starting automatically upon installation. Until it's resolved, you'll have to reload the user daemon by hand by running
systemctl --user daemon-reload
, or reboot. -
Install direnv. Add
pkgs.direnv
toenvironment.systemPackages
in your NixOSconfiguration.nix
or tohome.packages
in your home-managerhome.nix
. -
Set up the direnv hook for your shell. See this section of the direnv documentation.
-
Activate the lorri integration. Run
lorri init
in your project directory to create ashell.nix
and.envrc
file. This will not overwrite existing files.In your shell, you will now see the following message from direnv:
direnv: error .envrc is blocked. Run `direnv allow` to approve its content.
Activate the integration by running
direnv allow
.
From this point on, lorri monitors your shell.nix
and its dependencies and
triggers builds as required. Whenever a build succeeds, direnv automatically
reloads your environment.
See Usage for more details.
If you are running Nix on a Linux distribution other than NixOS or on macOS, the following instructions will help you get started with lorri.
-
Install lorri. If you are using a Nixpkgs channel at least as recent as
nixos-19.09
, you can install lorri usingnix-env -i lorri
.Otherwise, install lorri from the repository as follows:
$ nix-env -if https://github.com/target/lorri/archive/master.tar.gz
-
Start the daemon. For testing, you can start the daemon in a separate terminal by running
lorri daemon
.See
contrib/daemon.md
for ways to start the daemon automatically in the background. -
Install direnv v2.19.2 or later. If you are using a Nixpkgs channel at least as recent as
nixos-19.03
, you can install a compatible version of direnv usingnix-env -i direnv
.Otherwise, you can install direnv from source as follows:
$ nix-env -if https://github.com/direnv/direnv/archive/master.tar.gz
-
Set up the direnv hook for your shell. See this section of the direnv documentation.
-
Activate the lorri integration. Run
lorri init
in your project directory to create ashell.nix
and.envrc
file. This will not overwrite existing files.In your shell, you will see the following message from direnv:
direnv: error .envrc is blocked. Run `direnv allow` to approve its content.
Activate the integration by running
direnv allow
.
From this point on, lorri monitors your shell.nix
and its dependencies and
triggers builds as required. Whenever a build succeeds, direnv automatically
reloads your environment.
See Usage for more details.
Once the daemon is running and direnv is set up, the daemon process will
continue monitoring and evaluating the Nix expressions in your project's
shell.nix
, and direnv will automatically reload the environment as it
changes.
direnv will continue to load the cached environment when the daemon is not
running. However, the daemon must be running for direnv to reload the
environment based on the current shell.nix
and its dependencies.
With the right setup, you can use lorri and direnv to customize your development environment for each project.
If you use Emacs, our direnv-mode
tutorial is there to
help you get started.
This section needs to be fleshed out more (#244).
lorri embodies a Unix philosophy of doing one thing well. As a result, it works very well with other tools to provide a powerful and streamlined development experience.
direnv is lorri's chief collaborator. From its website:
[direnv] augments existing shells with a new feature that can load and unload environment variables depending on the current directory.
As a foundation, lorri relies on Nix and Nixpkgs to install and manage software packages.
For pinning versions of software during development, niv is very helpful.
Please use the issue tracker
for any problems or bugs you encounter. We are on #lorri
on
freenode
(Webchat), though we might not be responsive at all
times.
Why is lorri not on crates.io?
Command line tools written in Rust are commonly available as Rust crates on crates.io. lorri is not distributed in this way, for good reasons.
lorri can only be built within a Nix environment, and it can only be installed via Nix. This is because lorri specifies its runtime dependencies as a Nix closure, and because Nix is itself a runtime dependency of lorri.
In addition to these technical reasons, there is simply no point in running lorri if you don't have Nix installed. And if you have Nix installed, then you're best off installing lorri via Nix.
All development on lorri happens on the Github repository, in the open. You can propose a change in an issue, then create a pull request after some discussion. Some issues are marked with the “good first issue” label, those are a good place to start. Just remember to leave a comment when you start working on something.
Set these environment variables when debugging:
RUST_LOG=lorri=debug RUST_BACKTRACE=1 lorri watch
lorri sometimes recursively watches a directory that the user did not expect. This can happen for a number of reasons:
- When using a local checkout instead of a channel for
nixpkgs
, lorri watches that directory recursively, and will trigger on any file change. - When specifying
src
via a path, (like the much-usedsrc = ./.;
) lorri watches that path recursively (see target#6 for details). To get around this, use abuiltins.filterSource
-based function to filtersrc
, e.g., usenix-gitignore
:src = pkgs.nix-gitignore.gitignoreSource [] ./.
, or one of the functions innixpkgs/lib/sources.nix
Upgrading lorri is easy with the lorri self-upgrade
command.
By default, the upgrade command will upgrade from the master
branch.
Other upgrade options are available, including upgrading from a
local clone. See lorri self-upgrade --help
for more details.
Yes, you can!
direnv
will ask to run direnv allow
every time the .envrc
changes,
and lorri direnv
will never run anything else than what is required
to set up the nix environment.
If you have a project where you expect everybody to use lorri
(like for example a company project), you can just check in the .envrc
generated by lorri init
.
If you have a project which might be used by people with different
environments, you can still check in your .envrc
, by checking for
lorri
and providing a fallback to direnv
’s builtin use nix
support:
.envrc
:
if type lorri &>/dev/null; then
echo "direnv: using lorri from PATH ($(type -p lorri))"
eval "$(lorri direnv)"
else
# fall back to using direnv's builtin nix support
# to prevent bootstrapping problems.
use nix
fi
# source an additional user-specific .envrc in ./.envrc-local
if [ -e .envrc-local ]; then
source .envrc-local
fi
Then add ./.envrc-local
to your .gitignore
(or similar).
This should make lorri
users happy, while providing a graceful fallback
to users who only have nix
installed.
The evaluator should eagerly reevaluate the Nix expressions as soon as anything material to their output changes. This takes place in a few stages.
builder::run()
instantiates (and builds) the Nix expression with
nix-build -vv
. The evaluator prints each imported Nix file, and
each copied source file. builder::run()
parses the log and notes each
of these paths out as an "input" path.
Each input path is the absolute path which Nix examined.
Each input path is then passed to PathReduction
which examines each
path referenced, and reduces it to a minimum set of paths with the
following rules:
- Discard any store paths which isn't a symlink to outside the store: they are immutable.
- Replace any store path which is a symlink to outside the store to the destination of the symlink.
- Replace a reference to a Nix Channel with the updateable symlink
root of the channel. Concretely, replace the path
/nix/var/nix/profiles/per-user/root/channels/nixos/default.nix
with/nix/var/nix/profiles/per-user/root/
to watch for the channels symlink to change.
Initial testing collapses over 2,000 paths to just five.
Each identified path is watched for changes with inotify (Linux) or fsevent (macOS). If the watched path is a directory, all of its sub-directories are also watched for changes.
Each new batch of change notifications triggers a fresh evaluation. Newly discovered paths are added to the watch list.
lorri creates an indirect garbage collection root for each .drv in
$XDG_CACHE_HOME/lorri
(~/.cache/lorri/
by default) each time it
evaluates your project.
Copyright 2019 Target
License: Apache 2.0 (see LICENSE
file)
################################################################
################################################################
################################################################
################################################################
################################################################
################################################################
#################( )############################################
################################################################
################################################################
################################################################
################################################################
################################################################
################################################################
################################################################
################################################################
################################################################
################################################################
################################################################
################################################################
################################################################
################################################################
################################################################
################################################################