{
description = "cuenv - A direnv alternative that uses CUE files for environment configuration";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
flake-utils.url = "github:numtide/flake-utils";
treefmt-nix = {
url = "github:numtide/treefmt-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
{ self
, nixpkgs
, rust-overlay
, flake-utils
, treefmt-nix
,
}:
flake-utils.lib.eachDefaultSystem
(
system:
let
overlays = [ (import rust-overlay) ];
pkgs = import nixpkgs {
inherit system overlays;
};
# Platform-specific dependencies
platformDeps =
with pkgs;
if stdenv.isDarwin then
[
darwin.apple_sdk.frameworks.Security
darwin.apple_sdk.frameworks.CoreFoundation
]
else if stdenv.isLinux then
[
glibc
]
else
[ ];
# Build dependencies
buildInputs =
with pkgs;
[
go_1_24
openssl
pkg-config
]
++ platformDeps;
# Native build dependencies
nativeBuildInputs = with pkgs; [
rust-bin.stable."1.88.0".default
pkg-config
gcc
go_1_24
];
# treefmt configuration
treefmt = treefmt-nix.lib.evalModule pkgs {
projectRootFile = "flake.nix";
programs = {
# Nix formatter
nixpkgs-fmt.enable = true;
cue.enable = true;
# Rust formatter
rustfmt = {
enable = true;
# Use same edition as Cargo.toml
edition = "2021";
};
# Go formatter
gofmt.enable = true;
# YAML formatter
yamlfmt.enable = true;
# Prettier formatter - handles markdown with frontmatter support
prettier = {
enable = true;
# Only format markdown files with prettier
includes = [
"*.md"
"*.mdx"
];
};
# TOML formatter
taplo.enable = true;
};
};
# Development tools
devTools = with pkgs; [
cargo-watch
cargo-edit
cargo-outdated
cargo-audit
cue
gopls
gotools
rust-analyzer
treefmt.config.build.wrapper
];
# Read version from Cargo.toml
cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml);
version = cargoToml.package.version;
# Vendor Go dependencies
goVendor = pkgs.stdenv.mkDerivation {
pname = "cuenv-go-vendor";
version = version;
src = ./libcue-bridge;
nativeBuildInputs = [ pkgs.go_1_24 ];
buildPhase = ''
export HOME=$(mktemp -d)
export GOPATH="$HOME/go"
export GOCACHE="$HOME/go-cache"
go mod vendor
'';
installPhase = ''
mkdir -p $out
cp -r vendor $out/
'';
outputHashMode = "recursive";
outputHashAlgo = "sha256";
outputHash = "sha256-l/urNOAK9q5nflBt2ovfbaM3WNCn0ouZlc9RJq/+eKk=";
};
cuenv = pkgs.rustPlatform.buildRustPackage {
pname = "cuenv";
version = version;
src = ./.;
cargoLock = {
lockFile = ./Cargo.lock;
};
# Set up build environment
preBuild = ''
export HOME=$(mktemp -d)
export GOPATH="$HOME/go"
export GOCACHE="$HOME/go-cache"
export CGO_ENABLED=1
# Copy vendored dependencies
cp -r ${goVendor}/vendor libcue-bridge/
chmod -R u+w libcue-bridge
'';
inherit buildInputs nativeBuildInputs;
# Platform-specific linker flags
RUSTFLAGS =
if pkgs.stdenv.isDarwin then
"-C link-arg=-framework -C link-arg=Security -C link-arg=-framework -C link-arg=CoreFoundation"
else
"";
# Ensure Go is available during build
CGO_ENABLED = "1";
GO = "${pkgs.go_1_24}/bin/go";
checkPhase = ''
runHook preCheck
# Skip tests that require network access or special setup
cargo test --offline
runHook postCheck
'';
meta = with pkgs.lib; {
description = "A direnv alternative that uses CUE files for environment configuration";
homepage = "https://github.com/rawkode/cuenv";
license = licenses.mit;
maintainers = [ ];
};
};
in
{
packages = {
default = cuenv;
cuenv = cuenv;
};
# Make treefmt available as a check
checks = {
formatting = treefmt.config.build.check self;
# Run clippy
clippy = cuenv.overrideAttrs (oldAttrs: {
name = "cuenv-clippy";
buildPhase = ''
export HOME=$(mktemp -d)
export GOPATH="$HOME/go"
export GOCACHE="$HOME/go-cache"
export CGO_ENABLED=1
# Copy vendored dependencies
cp -r ${goVendor}/vendor libcue-bridge/
chmod -R u+w libcue-bridge
cargo clippy --offline -- -D warnings
'';
installPhase = ''
mkdir -p $out
touch $out/clippy-passed
'';
});
# Run tests
tests = cuenv.overrideAttrs (oldAttrs: {
name = "cuenv-tests";
doCheck = true;
checkPhase = ''
runHook preCheck
cargo test --offline
runHook postCheck
'';
installPhase = ''
mkdir -p $out
touch $out/tests-passed
'';
});
};
# Make formatter available
formatter = treefmt.config.build.wrapper;
devShells.default = pkgs.mkShell {
buildInputs = buildInputs ++ nativeBuildInputs ++ devTools;
shellHook = ''
echo "cuenv development environment"
echo "Rust version: $(rustc --version)"
echo "Go version: $(go version)"
echo ""
echo "Available commands:"
echo " cargo build - Build the project"
echo " cargo test - Run tests"
echo " cargo run - Run cuenv"
echo " cargo watch - Watch for changes and rebuild"
echo " treefmt - Format all code"
echo " nix flake check - Check code formatting"
echo ""
# Set up environment for building
export CGO_ENABLED=1
export GOPATH="$HOME/go"
export GOCACHE="$HOME/.cache/go-build"
# Platform-specific setup
${
if pkgs.stdenv.isDarwin then
''
export RUSTFLAGS="-C link-arg=-framework -C link-arg=Security -C link-arg=-framework -C link-arg=CoreFoundation"
''
else
""
}
'';
};
}
) // {
# Home Manager module
homeManagerModules.default = { config, lib, pkgs, ... }:
with lib;
let
cfg = config.programs.cuenv;
in
{
options.programs.cuenv = {
enable = mkEnableOption "cuenv, a direnv alternative using CUE files";
package = mkOption {
type = types.package;
default = self.packages.${pkgs.system}.default;
defaultText = literalExpression "cuenv";
description = "The cuenv package to use.";
};
enableBashIntegration = mkOption {
type = types.bool;
default = config.programs.bash.enable;
defaultText = literalExpression "config.programs.bash.enable";
description = ''
Whether to enable Bash integration.
'';
};
enableZshIntegration = mkOption {
type = types.bool;
default = config.programs.zsh.enable;
defaultText = literalExpression "config.programs.zsh.enable";
description = ''
Whether to enable Zsh integration.
'';
};
enableFishIntegration = mkOption {
type = types.bool;
default = config.programs.fish.enable;
defaultText = literalExpression "config.programs.fish.enable";
description = ''
Whether to enable Fish integration.
'';
};
enableNushellIntegration = mkOption {
type = types.bool;
default = config.programs.nushell.enable;
defaultText = literalExpression "config.programs.nushell.enable";
description = ''
Whether to enable Nushell integration.
Note: Nushell support is experimental and may require manual configuration.
'';
};
};
config = mkIf cfg.enable {
home.packages = [ cfg.package ];
programs.bash.initExtra = mkIf cfg.enableBashIntegration ''
# cuenv shell integration
eval "$(${cfg.package}/bin/cuenv init bash)"
'';
programs.zsh.initExtra = mkIf cfg.enableZshIntegration ''
# cuenv shell integration
eval "$(${cfg.package}/bin/cuenv init zsh)"
'';
programs.fish.interactiveShellInit = mkIf cfg.enableFishIntegration ''
# cuenv shell integration
${cfg.package}/bin/cuenv init fish | source
'';
programs.nushell.extraConfig = mkIf cfg.enableNushellIntegration ''
# cuenv shell integration
# Note: This is experimental and may need adjustment based on your Nushell version
let cuenv_init = (${cfg.package}/bin/cuenv init nushell | str trim)
if not ($cuenv_init | is-empty) {
source-env { $cuenv_init | from nuon }
}
'';
};
};
};
}