Clean up Nix Flake & make it easier to customize (#12831)

This commit is contained in:
Christopher Smyth 2025-03-04 11:23:28 -05:00 committed by GitHub
parent 671a6036b3
commit 1d453785e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 142 additions and 197 deletions

View file

@ -1,8 +1,78 @@
# Flake's default package for non-flake-enabled nix instances {
let lib,
compat = builtins.fetchTarball { rustPlatform,
url = "https://github.com/edolstra/flake-compat/archive/b4a34015c698c7793d592d66adbab377907a2be8.tar.gz"; callPackage,
sha256 = "sha256:1qc703yg0babixi6wshn5wm2kgl5y1drcswgszh4xxzbrwkk9sv7"; runCommand,
}; installShellFiles,
git,
...
}: let
fs = lib.fileset;
src = fs.difference (fs.gitTracked ./.) (fs.unions [
./.envrc
./rustfmt.toml
./screenshot.png
./book
./docs
./flake.lock
(fs.fileFilter (file: lib.strings.hasInfix ".git" file.name) ./.)
(fs.fileFilter (file: file.hasExt "svg") ./.)
(fs.fileFilter (file: file.hasExt "md") ./.)
(fs.fileFilter (file: file.hasExt "nix") ./.)
]);
# Next we actually need to build the grammars and the runtime directory
# that they reside in. It is built by calling the derivation in the
# grammars.nix file, then taking the runtime directory in the git repo
# and hooking symlinks up to it.
grammars = callPackage ./grammars.nix {};
runtimeDir = runCommand "helix-runtime" {} ''
mkdir -p $out
ln -s ${./runtime}/* $out
rm -r $out/grammars
ln -s ${grammars} $out/grammars
'';
in in
(import compat {src = ./.;}).defaultNix # Currently rustPlatform.buildRustPackage doesn't have the finalAttrs pattern
# hooked up. To get around this while having good customization, mkDerivation is
# used instead.
rustPlatform.buildRustPackage (self: {
cargoLock.lockFile = ./Cargo.lock;
nativeBuildInputs = [
installShellFiles
git
];
buildType = "release";
name = with builtins; (fromTOML (readFile ./helix-term/Cargo.toml)).package.name;
src = fs.toSource {
root = ./.;
fileset = src;
};
# Helix attempts to reach out to the network and get the grammars. Nix doesn't allow this.
HELIX_DISABLE_AUTO_GRAMMAR_BUILD = "1";
# So Helix knows what rev it is.
HELIX_NIX_BUILD_REV = self.rev or self.dirtyRev or null;
doCheck = false;
strictDeps = true;
# Sets the Helix runtimedir to the grammars
env.HELIX_DEFAULT_RUNTIME = "${runtimeDir}";
# Get all the application stuff in the output directory.
postInstall = ''
mkdir -p $out/lib
installShellCompletion ${./contrib/completion}/hx.{bash,fish,zsh}
mkdir -p $out/share/{applications,icons/hicolor/256x256/apps}
cp ${./contrib/Helix.desktop} $out/share/applications
cp ${./contrib/helix.png} $out/share/icons/hicolor/256x256/apps
'';
meta.mainProgram = "hx";
})

28
flake.lock generated
View file

@ -1,20 +1,5 @@
{ {
"nodes": { "nodes": {
"crane": {
"locked": {
"lastModified": 1737563566,
"narHash": "sha256-GLJvkOG29XCynQm8XWPyykMRqIhxKcBARVu7Ydrz02M=",
"owner": "ipetkov",
"repo": "crane",
"rev": "849376434956794ebc7a6b487d31aace395392ba",
"type": "github"
},
"original": {
"owner": "ipetkov",
"repo": "crane",
"type": "github"
}
},
"flake-utils": { "flake-utils": {
"inputs": { "inputs": {
"systems": "systems" "systems": "systems"
@ -35,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1728018373, "lastModified": 1740560979,
"narHash": "sha256-NOiTvBbRLIOe5F6RbHaAh6++BNjsb149fGZd1T4+KBg=", "narHash": "sha256-Vr3Qi346M+8CjedtbyUevIGDZW8LcA1fTG0ugPY/Hic=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "bc947f541ae55e999ffdb4013441347d83b00feb", "rev": "5135c59491985879812717f4c9fea69604e7f26f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -51,7 +36,6 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"crane": "crane",
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay" "rust-overlay": "rust-overlay"
@ -64,11 +48,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1737599167, "lastModified": 1740623427,
"narHash": "sha256-S2rHCrQWCDVp63XxL/AQbGr1g5M8Zx14C7Jooa4oM8o=", "narHash": "sha256-3SdPQrZoa4odlScFDUHd4CUPQ/R1gtH4Mq9u8CBiK8M=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "38374302ae9edf819eac666d1f276d62c712dd06", "rev": "d342e8b5fd88421ff982f383c853f0fc78a847ab",
"type": "github" "type": "github"
}, },
"original": { "original": {

195
flake.nix
View file

@ -8,13 +8,11 @@
url = "github:oxalica/rust-overlay"; url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
crane.url = "github:ipetkov/crane";
}; };
outputs = { outputs = {
self, self,
nixpkgs, nixpkgs,
crane,
flake-utils, flake-utils,
rust-overlay, rust-overlay,
... ...
@ -24,167 +22,56 @@
inherit system; inherit system;
overlays = [(import rust-overlay)]; overlays = [(import rust-overlay)];
}; };
mkRootPath = rel:
builtins.path { # Get Helix's MSRV toolchain to build with by default.
path = "${toString ./.}/${rel}"; msrvToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
name = rel; msrvPlatform = pkgs.makeRustPlatform {
}; cargo = msrvToolchain;
filteredSource = let rustc = msrvToolchain;
pathsToIgnore = [
".envrc"
".ignore"
".github"
".gitignore"
"logo_dark.svg"
"logo_light.svg"
"rust-toolchain.toml"
"rustfmt.toml"
"runtime"
"screenshot.png"
"book"
"docs"
"README.md"
"CHANGELOG.md"
"shell.nix"
"default.nix"
"grammars.nix"
"flake.nix"
"flake.lock"
];
ignorePaths = path: type: let
inherit (nixpkgs) lib;
# split the nix store path into its components
components = lib.splitString "/" path;
# drop off the `/nix/hash-source` section from the path
relPathComponents = lib.drop 4 components;
# reassemble the path components
relPath = lib.concatStringsSep "/" relPathComponents;
in
lib.all (p: ! (lib.hasPrefix p relPath)) pathsToIgnore;
in
builtins.path {
name = "helix-source";
path = toString ./.;
# filter out unnecessary paths
filter = ignorePaths;
};
makeOverridableHelix = old: config: let
grammars = pkgs.callPackage ./grammars.nix config;
runtimeDir = pkgs.runCommand "helix-runtime" {} ''
mkdir -p $out
ln -s ${mkRootPath "runtime"}/* $out
rm -r $out/grammars
ln -s ${grammars} $out/grammars
'';
helix-wrapped =
pkgs.runCommand
old.name
{
inherit (old) pname version;
meta = old.meta or {};
passthru =
(old.passthru or {})
// {
unwrapped = old;
};
nativeBuildInputs = [pkgs.makeWrapper];
makeWrapperArgs = config.makeWrapperArgs or [];
}
''
cp -rs --no-preserve=mode,ownership ${old} $out
wrapProgram "$out/bin/hx" ''${makeWrapperArgs[@]} --set HELIX_RUNTIME "${runtimeDir}"
'';
in
helix-wrapped
// {
override = makeOverridableHelix old;
passthru =
helix-wrapped.passthru
// {
wrapper = old: makeOverridableHelix old config;
};
};
stdenv =
if pkgs.stdenv.isLinux
then pkgs.stdenv
else pkgs.clangStdenv;
rustFlagsEnv = pkgs.lib.optionalString stdenv.isLinux "-C link-arg=-fuse-ld=lld -C target-cpu=native -Clink-arg=-Wl,--no-rosegment --cfg tokio_unstable";
rustToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
craneLibMSRV = (crane.mkLib pkgs).overrideToolchain rustToolchain;
craneLibStable = (crane.mkLib pkgs).overrideToolchain pkgs.pkgsBuildHost.rust-bin.stable.latest.default;
commonArgs = {
inherit stdenv;
inherit (craneLibMSRV.crateNameFromCargoToml {cargoToml = ./helix-term/Cargo.toml;}) pname;
inherit (craneLibMSRV.crateNameFromCargoToml {cargoToml = ./Cargo.toml;}) version;
src = filteredSource;
# disable fetching and building of tree-sitter grammars in the helix-term build.rs
HELIX_DISABLE_AUTO_GRAMMAR_BUILD = "1";
buildInputs = [stdenv.cc.cc.lib];
nativeBuildInputs = [pkgs.installShellFiles];
# disable tests
doCheck = false;
meta.mainProgram = "hx";
}; };
cargoArtifacts = craneLibMSRV.buildDepsOnly commonArgs;
in { in {
packages = { packages = rec {
helix-unwrapped = craneLibStable.buildPackage (commonArgs helix = pkgs.callPackage ./default.nix {};
// {
cargoArtifacts = craneLibStable.buildDepsOnly commonArgs; # The default Helix build. Uses the latest stable Rust toolchain, and unstable
postInstall = '' # nixpkgs.
mkdir -p $out/share/applications $out/share/icons/hicolor/scalable/apps $out/share/icons/hicolor/256x256/apps #
cp contrib/Helix.desktop $out/share/applications # This can be overridden though to add Cargo Features, flags, and different toolchains with
cp logo.svg $out/share/icons/hicolor/scalable/apps/helix.svg # packages.${system}.default.override { ... };
cp contrib/helix.png $out/share/icons/hicolor/256x256/apps default = helix;
installShellCompletion contrib/completion/hx.{bash,fish,zsh}
'';
# set git revision for nix flake builds, see 'git_hash' in helix-loader/build.rs
HELIX_NIX_BUILD_REV = self.rev or self.dirtyRev or null;
});
helix = makeOverridableHelix self.packages.${system}.helix-unwrapped {};
default = self.packages.${system}.helix;
}; };
checks = { checks.helix = self.outputs.packages.${system}.helix.override {
# Build the crate itself buildType = "debug";
inherit (self.packages.${system}) helix; rustPlatform = msrvPlatform;
clippy = craneLibMSRV.cargoClippy (commonArgs
// {
inherit cargoArtifacts;
cargoClippyExtraArgs = "--all-targets -- --deny warnings";
});
fmt = craneLibMSRV.cargoFmt commonArgs;
doc = craneLibMSRV.cargoDoc (commonArgs
// {
inherit cargoArtifacts;
});
test = craneLibMSRV.cargoTest (commonArgs
// {
inherit cargoArtifacts;
});
}; };
devShells.default = pkgs.mkShell { # Devshell behavior is preserved.
inputsFrom = builtins.attrValues self.checks.${system}; devShells.default = let
nativeBuildInputs = with pkgs; rustFlagsEnv = pkgs.lib.optionalString pkgs.stdenv.isLinux "-C link-arg=-fuse-ld=lld -C target-cpu=native -Clink-arg=-Wl,--no-rosegment --cfg tokio_unstable";
[lld_13 cargo-flamegraph rust-analyzer] in
++ (lib.optional (stdenv.isx86_64 && stdenv.isLinux) pkgs.cargo-tarpaulin) pkgs.mkShell
++ (lib.optional stdenv.isLinux pkgs.lldb) {
++ (lib.optional stdenv.isDarwin pkgs.darwin.apple_sdk.frameworks.CoreFoundation); inputsFrom = [self.checks.${system}.helix];
shellHook = '' nativeBuildInputs = with pkgs;
export HELIX_RUNTIME="$PWD/runtime" [
export RUST_BACKTRACE="1" lld_13
export RUSTFLAGS="''${RUSTFLAGS:-""} ${rustFlagsEnv}" cargo-flamegraph
''; rust-bin.nightly.latest.rust-analyzer
}; ]
++ (lib.optional (stdenv.isx86_64 && stdenv.isLinux) cargo-tarpaulin)
++ (lib.optional stdenv.isLinux lldb)
++ (lib.optional stdenv.isDarwin darwin.apple_sdk.frameworks.CoreFoundation);
shellHook = ''
export HELIX_RUNTIME="$PWD/runtime"
export RUST_BACKTRACE="1"
export RUSTFLAGS="''${RUSTFLAGS:-""} ${rustFlagsEnv}"
'';
};
}) })
// { // {
overlays.default = final: prev: { overlays.default = final: prev: {
inherit (self.packages.${final.system}) helix; helix = final.callPackage ./default.nix {};
}; };
}; };

View file

@ -32,10 +32,10 @@
# If `use-grammars.except` is set, use all other grammars. # If `use-grammars.except` is set, use all other grammars.
# Otherwise use all grammars. # Otherwise use all grammars.
useGrammar = grammar: useGrammar = grammar:
if languagesConfig?use-grammars.only then if languagesConfig ? use-grammars.only
builtins.elem grammar.name languagesConfig.use-grammars.only then builtins.elem grammar.name languagesConfig.use-grammars.only
else if languagesConfig?use-grammars.except then else if languagesConfig ? use-grammars.except
!(builtins.elem grammar.name languagesConfig.use-grammars.except) then !(builtins.elem grammar.name languagesConfig.use-grammars.except)
else true; else true;
grammarsToUse = builtins.filter useGrammar languagesConfig.grammar; grammarsToUse = builtins.filter useGrammar languagesConfig.grammar;
gitGrammars = builtins.filter isGitGrammar grammarsToUse; gitGrammars = builtins.filter isGitGrammar grammarsToUse;
@ -66,10 +66,10 @@
version = grammar.source.rev; version = grammar.source.rev;
src = source; src = source;
sourceRoot = if builtins.hasAttr "subpath" grammar.source then sourceRoot =
"source/${grammar.source.subpath}" if builtins.hasAttr "subpath" grammar.source
else then "source/${grammar.source.subpath}"
"source"; else "source";
dontConfigure = true; dontConfigure = true;
@ -116,15 +116,19 @@
''; '';
}; };
grammarsToBuild = builtins.filter includeGrammarIf gitGrammars; grammarsToBuild = builtins.filter includeGrammarIf gitGrammars;
builtGrammars = builtins.map (grammar: { builtGrammars =
inherit (grammar) name; builtins.map (grammar: {
value = buildGrammar grammar; inherit (grammar) name;
}) grammarsToBuild; value = buildGrammar grammar;
})
grammarsToBuild;
extensibleGrammars = extensibleGrammars =
lib.makeExtensible (self: builtins.listToAttrs builtGrammars); lib.makeExtensible (self: builtins.listToAttrs builtGrammars);
overlaidGrammars = lib.pipe extensibleGrammars overlaidGrammars =
lib.pipe extensibleGrammars
(builtins.map (overlay: grammar: grammar.extend overlay) grammarOverlays); (builtins.map (overlay: grammar: grammar.extend overlay) grammarOverlays);
grammarLinks = lib.mapAttrsToList grammarLinks =
lib.mapAttrsToList
(name: artifact: "ln -s ${artifact}/${name}.so $out/${name}.so") (name: artifact: "ln -s ${artifact}/${name}.so $out/${name}.so")
(lib.filterAttrs (n: v: lib.isDerivation v) overlaidGrammars); (lib.filterAttrs (n: v: lib.isDerivation v) overlaidGrammars);
in in