this repo has no description
1{
2 description = "A compression multi-tool for the command line.";
3
4 inputs = {
5 nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
6
7 crane = {
8 url = "github:ipetkov/crane";
9 };
10
11 fenix = {
12 # Needed because rust-overlay, normally used by crane, doesn't have llvm-tools for coverage
13 url = "github:nix-community/fenix";
14 inputs.nixpkgs.follows = "nixpkgs";
15 inputs.rust-analyzer-src.follows = "";
16 };
17
18 # Flake helper for better organization with modules.
19 flake-parts = {
20 url = "github:hercules-ci/flake-parts";
21 inputs.nixpkgs-lib.follows = "nixpkgs";
22 };
23
24 # For creating a universal `nix fmt`
25 treefmt-nix = {
26 url = "github:numtide/treefmt-nix";
27 inputs.nixpkgs.follows = "nixpkgs";
28 };
29 };
30
31 outputs = inputs @ {
32 self,
33 flake-parts,
34 ...
35 }:
36 flake-parts.lib.mkFlake {inherit inputs;} {
37 systems = [
38 "aarch64-darwin"
39 "aarch64-linux"
40 "x86_64-darwin"
41 "x86_64-linux"
42 ];
43
44 imports = [
45 flake-parts.flakeModules.easyOverlay
46 inputs.treefmt-nix.flakeModule
47 ];
48
49 perSystem = {
50 config,
51 system,
52 pkgs,
53 ...
54 }: let
55 # Use the stable rust tools from fenix
56 fenixStable = inputs.fenix.packages.${system}.stable;
57 rustSrc = fenixStable.rust-src;
58 toolChain = fenixStable.completeToolchain;
59
60 # Use the toolchain with the crane helper functions
61 craneLib = (inputs.crane.mkLib pkgs).overrideToolchain toolChain;
62
63 # Common arguments for mkCargoDerivation, a helper for the crane functions
64 # Arguments can be included here even if they aren't used, but we only
65 # place them here if they would otherwise show up in multiple places
66 commonArgs = {
67 inherit cargoArtifacts;
68 # Clean the src to only have the Rust-relevant files
69 src = craneLib.cleanCargoSource ./.;
70 strictDeps = true;
71 nativeBuildInputs = [
72 pkgs.pkg-config
73 pkgs.gcc
74 ];
75 };
76
77 # Build only the cargo dependencies so we can cache them all when running in CI
78 cargoArtifacts = craneLib.buildDepsOnly commonArgs;
79
80 # Build the actual crate itself, reusing the cargoArtifacts
81 cmprss = craneLib.buildPackage (commonArgs
82 // {
83 doCheck = false; # Tests are run as a separate build with nextest
84 meta.mainProgram = "cmprss";
85 });
86
87 # Fully static musl build (Linux only)
88 staticMusl = pkgs.lib.optionalAttrs pkgs.stdenv.isLinux (
89 let
90 muslTarget =
91 if system == "x86_64-linux"
92 then "x86_64-unknown-linux-musl"
93 else "aarch64-unknown-linux-musl";
94
95 muslToolchain = inputs.fenix.packages.${system}.combine [
96 fenixStable.cargo
97 fenixStable.rustc
98 inputs.fenix.packages.${system}.targets.${muslTarget}.stable.rust-std
99 ];
100
101 craneLibMusl = (inputs.crane.mkLib pkgs).overrideToolchain muslToolchain;
102
103 musl-cc = pkgs.pkgsStatic.stdenv.cc;
104
105 staticArgs = {
106 src = craneLibMusl.cleanCargoSource ./.;
107 strictDeps = true;
108 CARGO_BUILD_TARGET = muslTarget;
109 CARGO_BUILD_RUSTFLAGS = "-C target-feature=+crt-static";
110 TARGET_CC = "${musl-cc}/bin/${musl-cc.targetPrefix}cc";
111 HOST_CC = "${pkgs.stdenv.cc}/bin/cc";
112 nativeBuildInputs = [
113 musl-cc
114 pkgs.pkg-config
115 ];
116 };
117
118 cargoArtifactsStatic = craneLibMusl.buildDepsOnly staticArgs;
119 in {
120 cmprss-static = craneLibMusl.buildPackage (staticArgs
121 // {
122 cargoArtifacts = cargoArtifactsStatic;
123 doCheck = false;
124 meta.mainProgram = "cmprss";
125 });
126 }
127 );
128 # Source filtered to specific file extensions for lightweight linter checks
129 cleanSrc = pkgs.lib.cleanSource ./.;
130 sourceWithExts = exts:
131 pkgs.lib.cleanSourceWith {
132 src = cleanSrc;
133 filter = path: type:
134 (type == "directory")
135 || (pkgs.lib.any (ext: pkgs.lib.hasSuffix ".${ext}" path) exts);
136 };
137
138 mkSimpleLinter = {
139 name,
140 packages ? [],
141 src ? cleanSrc,
142 command,
143 }:
144 pkgs.runCommand "lint-${name}" {
145 nativeBuildInputs = packages;
146 inherit src;
147 } ''
148 cd $src
149 ${command}
150 mkdir -p $out
151 '';
152
153 linters = {
154 statix = mkSimpleLinter {
155 name = "statix";
156 packages = [pkgs.statix];
157 src = sourceWithExts ["nix"];
158 command = "statix check .";
159 };
160 deadnix = mkSimpleLinter {
161 name = "deadnix";
162 packages = [pkgs.deadnix];
163 src = sourceWithExts ["nix"];
164 command = "deadnix --fail .";
165 };
166 shellcheck = mkSimpleLinter {
167 name = "shellcheck";
168 packages = [pkgs.shellcheck pkgs.findutils];
169 src = sourceWithExts ["sh"];
170 command = ''find . -name "*.sh" -type f -exec shellcheck {} +'';
171 };
172 actionlint = mkSimpleLinter {
173 name = "actionlint";
174 packages = [pkgs.actionlint pkgs.shellcheck pkgs.findutils];
175 src = pkgs.lib.cleanSourceWith {
176 src = cleanSrc;
177 filter = path: type:
178 (type == "directory")
179 || (pkgs.lib.hasSuffix ".yml" path && pkgs.lib.hasInfix ".github" path);
180 };
181 command = ''find .github/workflows -name "*.yml" -exec actionlint {} +'';
182 };
183 };
184 in {
185 packages =
186 {
187 default = cmprss;
188 inherit cmprss;
189
190 # Check code coverage with tarpaulin
191 coverage = craneLib.cargoTarpaulin (commonArgs
192 // {
193 # Use lcov output as thats far more widely supported
194 cargoTarpaulinExtraArgs = "--skip-clean --include-tests --output-dir $out --out lcov";
195 });
196
197 # Run clippy (and deny all warnings) on the crate source
198 clippy = craneLib.cargoClippy (commonArgs
199 // {
200 cargoClippyExtraArgs = "--all-targets -- --deny warnings";
201 });
202
203 # Check docs build successfully
204 doc = craneLib.cargoDoc commonArgs;
205
206 # Check formatting
207 fmt = craneLib.cargoFmt commonArgs;
208
209 # Run tests with cargo-nextest
210 test = craneLib.cargoNextest commonArgs;
211
212 # Audit dependencies, check licenses, and detect duplicate crates
213 deny = craneLib.cargoDeny (commonArgs
214 // {
215 # advisories excluded: needs network access (blocked by nix sandbox)
216 cargoDenyChecks = "bans licenses sources";
217 });
218 }
219 // staticMusl;
220
221 checks =
222 {
223 inherit cmprss;
224 # Build almost every package in checks, with exceptions:
225 # - coverage: It requires a full rebuild, and only needs to be run occasionally
226 inherit (self.packages.${system}) clippy doc fmt test deny;
227 }
228 // linters;
229
230 # This also sets up `nix fmt` to run all formatters
231 treefmt = {
232 projectRootFile = "./flake.nix";
233 programs = {
234 alejandra.enable = true;
235 prettier.enable = true;
236 rustfmt.enable = true;
237 shfmt.enable = true;
238 typos = {
239 enable = true;
240 configFile = "./.config/typos.toml";
241 };
242 };
243 };
244
245 apps = rec {
246 default = cmprss;
247 cmprss.program = self.packages.${system}.cmprss;
248 };
249
250 overlayAttrs = {
251 inherit (config.packages) cmprss;
252 };
253
254 devShells.default = pkgs.mkShell {
255 name = "cmprss";
256 shellHook = ''
257 echo ---------------------
258 just --list
259 echo ---------------------
260 '';
261
262 # Include the packages from the defined checks and packages
263 # Installs the full cargo toolchain and the extra tools, e.g. cargo-tarpaulin.
264 inputsFrom =
265 (builtins.attrValues self.checks.${system})
266 ++ (builtins.attrValues self.packages.${system});
267
268 # Extra inputs can be added here
269 packages = with pkgs; [
270 act # For running Github Actions locally
271 alejandra
272 actionlint
273 deadnix
274 git-cliff
275 gum # Pretty printing in scripts
276 just
277 nodePackages.prettier
278 shellcheck
279 statix
280 typos
281
282 # For running tests
283 diffutils
284
285 # Official tools
286 bzip2
287 gnutar
288 gzip
289 lz4
290 xz
291 zstd
292 ];
293
294 # Many tools read this to find the sources for rust stdlib
295 RUST_SRC_PATH = "${rustSrc}/lib/rustlib/src/rust/library";
296 };
297 };
298 };
299}