diff --git a/.github/workflows/nix-dev-cache.yaml b/.github/workflows/nix-dev-cache.yaml index e4e7aa4987..0104ff2db4 100644 --- a/.github/workflows/nix-dev-cache.yaml +++ b/.github/workflows/nix-dev-cache.yaml @@ -19,7 +19,7 @@ jobs: fail-fast: false matrix: os: - - ubuntu-20.04 + - ubuntu-22.04 - macOS-12 - macOS-14 steps: @@ -37,4 +37,4 @@ jobs: name: unison authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - name: build all packages and development shells - run: nix -L build --accept-flake-config --no-link --keep-going '.#build-tools' + run: nix -L build --accept-flake-config --no-link --keep-going '.#all' diff --git a/development.markdown b/development.markdown index 962a507c63..806a6afbdb 100644 --- a/development.markdown +++ b/development.markdown @@ -96,7 +96,7 @@ This codebase uses symlinks as a workaround for some inconveniences in the `here First you'll need to enable "Developer Mode" in your Windows settings. - See https://consumer.huawei.com/en/support/content/en-us15594140/ + See https://consumer.huawei.com/en/support/content/en-us15594140/ Then you'll need to enable symlink support in your `git` configuration, e.g. @@ -113,8 +113,6 @@ Stack doesn't work deterministically in Windows due to mismatched expectations a ## Building with Nix -## Building package components with nix - ### Build the unison executable ``` nix build @@ -133,28 +131,21 @@ nix build '.#component-unison-cli:exe:transcripts' ### Development environments -#### Get into a development environment for building with stack +#### Get into a development environment for building with stack or cabal This gets you into a development environment with the preferred versions of the compiler and other development tools. These include: +- cabal - ghc - stack - ormolu - haskell-language-server -``` -nix develop -``` - -#### Get into a development environment for building with cabal -This gets you into a development environment with the preferred -versions of the compiler and other development tools. Additionally, -all non-local haskell dependencies (including profiling dependencies) -are provided in the nix shell. +Additionally, all non-local haskell dependencies (including profiling dependencies) are provided in the nix shell. ``` -nix develop '.#cabal-local' +nix develop ``` #### Get into a development environment for building a specific package diff --git a/flake.lock b/flake.lock index d4ece12a51..e0c344904a 100644 --- a/flake.lock +++ b/flake.lock @@ -542,34 +542,34 @@ "type": "github" } }, - "nixpkgs-unstable": { + "nixpkgs-release": { "locked": { - "lastModified": 1695318763, - "narHash": "sha256-FHVPDRP2AfvsxAdc+AsgFJevMz5VBmnZglFUMlxBkcY=", + "lastModified": 1719511581, + "narHash": "sha256-AJrEKLwOT/4oAgiqwRknLXRk9kbokyddHIl/o3sKdB0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e12483116b3b51a185a33a272bf351e357ba9a99", + "rev": "b27c5600975cbca6bae52048b8fd0e5ea2cc51eb", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-unstable", + "ref": "release-23.11", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs-unstable_2": { + "nixpkgs-unstable": { "locked": { - "lastModified": 1699781429, - "narHash": "sha256-UYefjidASiLORAjIvVsUHG6WBtRhM67kTjEY4XfZOFs=", + "lastModified": 1695318763, + "narHash": "sha256-FHVPDRP2AfvsxAdc+AsgFJevMz5VBmnZglFUMlxBkcY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e44462d6021bfe23dfb24b775cc7c390844f773d", + "rev": "e12483116b3b51a185a33a272bf351e357ba9a99", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-unstable", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } @@ -595,11 +595,11 @@ "inputs": { "flake-utils": "flake-utils", "haskellNix": "haskellNix", - "nixpkgs": [ + "nixpkgs-haskellNix": [ "haskellNix", "nixpkgs-unstable" ], - "nixpkgs-unstable": "nixpkgs-unstable_2" + "nixpkgs-release": "nixpkgs-release" } }, "stackage": { diff --git a/flake.nix b/flake.nix index 8c8725da3b..88a67fd58d 100644 --- a/flake.nix +++ b/flake.nix @@ -8,17 +8,17 @@ inputs = { haskellNix.url = "github:input-output-hk/haskell.nix"; - nixpkgs.follows = "haskellNix/nixpkgs-unstable"; - nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable"; + nixpkgs-haskellNix.follows = "haskellNix/nixpkgs-unstable"; + nixpkgs-release.url = "github:NixOS/nixpkgs/release-23.11"; flake-utils.url = "github:numtide/flake-utils"; }; outputs = { self, - nixpkgs, - flake-utils, haskellNix, - nixpkgs-unstable, + nixpkgs-haskellNix, + nixpkgs-release, + flake-utils, }: flake-utils.lib.eachSystem [ "x86_64-linux" @@ -27,99 +27,55 @@ ] (system: let versions = { - ghc = "928"; ormolu = "0.5.2.0"; hls = "2.4.0.0"; stack = "2.13.1"; hpack = "0.35.2"; }; - overlays = [ - haskellNix.overlay - (import ./nix/haskell-nix-overlay.nix) - (import ./nix/unison-overlay.nix) - ]; - pkgs = import nixpkgs { - inherit system overlays; - inherit (haskellNix) config; - }; - haskell-nix-flake = import ./nix/haskell-nix-flake.nix { - inherit pkgs versions; - inherit (nixpkgs-packages) stack hpack; - }; - unstable = import nixpkgs-unstable { + pkgs = import nixpkgs-haskellNix { inherit system; + inherit (haskellNix) config; overlays = [ - (import ./nix/unison-overlay.nix) - (import ./nix/nixpkgs-overlay.nix {inherit versions;}) + haskellNix.overlay + (import ./nix/dependencies.nix {inherit nixpkgs-release;}) ]; }; - nixpkgs-packages = let - hpkgs = unstable.haskell.packages.ghcunison; - exe = unstable.haskell.lib.justStaticExecutables; - in { - ghc = unstable.haskell.compiler."ghc${versions.ghc}"; - ormolu = exe hpkgs.ormolu; - hls = unstable.unison-hls; - stack = unstable.unison-stack; - unwrapped-stack = unstable.stack; - hpack = unstable.hpack; + unison-project = import ./nix/unison-project.nix { + inherit (nixpkgs-haskellNix) lib; + inherit (pkgs) haskell-nix; }; - nixpkgs-devShells = { - only-tools-nixpkgs = unstable.mkShell { - name = "only-tools-nixpkgs"; - buildInputs = let - build-tools = with nixpkgs-packages; [ - ghc - ormolu - hls - stack - hpack - ]; - native-packages = - pkgs.lib.optionals pkgs.stdenv.isDarwin - (with unstable.darwin.apple_sdk.frameworks; [Cocoa]); - c-deps = with unstable; [pkg-config zlib glibcLocales]; - in - build-tools ++ c-deps ++ native-packages; - shellHook = '' - export LD_LIBRARY_PATH=${pkgs.zlib}/lib:$LD_LIBRARY_PATH - ''; - }; + haskell-nix-flake = import ./nix/haskell-nix-flake.nix { + inherit pkgs unison-project versions; + inherit (nixpkgs-haskellNix) lib; }; - renameAttrs = fn: - nixpkgs.lib.mapAttrs' (name: value: { + nixpkgs-haskellNix.lib.mapAttrs' (name: value: { inherit value; name = fn name; }); in - assert nixpkgs-packages.ormolu.version == versions.ormolu; - assert nixpkgs-packages.hls.version == versions.hls; - assert nixpkgs-packages.unwrapped-stack.version == versions.stack; - assert nixpkgs-packages.hpack.version == versions.hpack; { + assert pkgs.stack.version == versions.stack; + assert pkgs.hpack.version == versions.hpack; { packages = - nixpkgs-packages - // renameAttrs (name: "component-${name}") haskell-nix-flake.packages + renameAttrs (name: "component-${name}") haskell-nix-flake.packages // renameAttrs (name: "docker-${name}") (import ./nix/docker.nix { inherit pkgs; haskell-nix = haskell-nix-flake.packages; }) // { default = haskell-nix-flake.defaultPackage; - build-tools = pkgs.symlinkJoin { - name = "build-tools"; - paths = self.devShells."${system}".only-tools-nixpkgs.buildInputs; - }; all = pkgs.symlinkJoin { name = "all"; paths = let - all-other-packages = builtins.attrValues (builtins.removeAttrs self.packages."${system}" ["all" "build-tools"]); + all-other-packages = + builtins.attrValues (builtins.removeAttrs self.packages."${system}" [ + "all" + "docker-ucm" # this package doesn’t produce a directory + ]); devshell-inputs = builtins.concatMap (devShell: devShell.buildInputs ++ devShell.nativeBuildInputs) - [ - self.devShells."${system}".only-tools-nixpkgs - ]; + (builtins.attrValues self.devShells."${system}"); in all-other-packages ++ devshell-inputs; }; @@ -130,9 +86,8 @@ // {default = self.apps."${system}"."component-unison-cli-main:exe:unison";}; devShells = - nixpkgs-devShells - // renameAttrs (name: "cabal-${name}") haskell-nix-flake.devShells - // {default = self.devShells."${system}".only-tools-nixpkgs;}; + renameAttrs (name: "cabal-${name}") haskell-nix-flake.devShells + // {default = self.devShells."${system}".cabal-local;}; checks = renameAttrs (name: "component-${name}") haskell-nix-flake.checks; diff --git a/nix/dependencies.nix b/nix/dependencies.nix new file mode 100644 index 0000000000..7df873660f --- /dev/null +++ b/nix/dependencies.nix @@ -0,0 +1,21 @@ +{nixpkgs-release}: final: prev: let + pinned-pkgs = import nixpkgs-release {inherit (final) system;}; +in { + stack = pinned-pkgs.stack; + + ## See https://docs.haskellstack.org/en/stable/nix_integration/#supporting-both-nix-and-non-nix-developers for an + ## explanation of this package. + stack-wrapped = final.symlinkJoin { + name = "stack"; # will be available as the usual `stack` in terminal + paths = [final.stack]; + buildInputs = [final.makeWrapper]; + postBuild = '' + wrapProgram $out/bin/stack \ + --add-flags "\ + --no-nix \ + --system-ghc \ + --no-install-ghc \ + " + ''; + }; +} diff --git a/nix/haskell-nix-flake.nix b/nix/haskell-nix-flake.nix index c0c992ae01..1f5c6db497 100644 --- a/nix/haskell-nix-flake.nix +++ b/nix/haskell-nix-flake.nix @@ -1,10 +1,10 @@ { - stack, - hpack, + lib, pkgs, + unison-project, versions, }: let - haskell-nix-flake = pkgs.unison-project.flake {}; + haskell-nix-flake = unison-project.flake {}; commonShellArgs = args: args // { @@ -15,10 +15,19 @@ additional = hpkgs: with hpkgs; [Cabal stm exceptions ghc ghc-heap]; buildInputs = let native-packages = - pkgs.lib.optionals pkgs.stdenv.isDarwin + lib.optionals pkgs.stdenv.isDarwin (with pkgs.darwin.apple_sdk.frameworks; [Cocoa]); in - (args.buildInputs or []) ++ [stack hpack pkgs.pkg-config pkgs.zlib pkgs.glibcLocales] ++ native-packages; + (args.buildInputs or []) + ++ [ + pkgs.cachix + pkgs.glibcLocales + pkgs.hpack + pkgs.pkg-config + pkgs.stack-wrapped + pkgs.zlib + ] + ++ native-packages; # workaround for https://gitlab.haskell.org/ghc/ghc/-/issues/11042 shellHook = '' export LD_LIBRARY_PATH=${pkgs.zlib}/lib:$LD_LIBRARY_PATH @@ -49,49 +58,42 @@ }; }; - shellFor = args: pkgs.unison-project.shellFor (commonShellArgs args); + shellFor = args: unison-project.shellFor (commonShellArgs args); - localPackages = with pkgs.lib; filterAttrs (k: v: v.isLocal or false) pkgs.unison-project.hsPkgs; - localPackageNames = builtins.attrNames localPackages; - devShells = let - mkDevShell = pkgName: - shellFor { - packages = hpkgs: [hpkgs."${pkgName}"]; - withHoogle = true; - }; - localPackageDevShells = - pkgs.lib.genAttrs localPackageNames mkDevShell; - in - { - only-tools = shellFor { - packages = _: []; - withHoogle = false; - }; - local = shellFor { - packages = hpkgs: (map (p: hpkgs."${p}") localPackageNames); - withHoogle = false; - }; - } - // localPackageDevShells; - - checks = - haskell-nix-flake.checks - // { - ## This check has a test that tries to write to $HOME, so we give it a fake one. - "unison-cli:test:cli-tests" = haskell-nix-flake.checks."unison-cli:test:cli-tests".overrideAttrs (old: { - ## The builder here doesn’t `runHook preBuild`, so we just prepend onto `buildPhase`. - buildPhase = - '' - export HOME="$TMP/fake-home" - mkdir -p "$HOME" - '' - + old.buildPhase or ""; - }); - }; + localPackages = lib.filterAttrs (k: v: v.isLocal or false) unison-project.hsPkgs; in haskell-nix-flake // { + checks = + haskell-nix-flake.checks + // { + ## This check has a test that tries to write to $HOME, so we give it a fake one. + "unison-cli:test:cli-tests" = haskell-nix-flake.checks."unison-cli:test:cli-tests".overrideAttrs (old: { + ## The builder here doesn’t `runHook preBuild`, so we just prepend onto `buildPhase`. + buildPhase = + '' + export HOME="$TMP/fake-home" + mkdir -p "$HOME" + '' + + old.buildPhase or ""; + }); + }; + defaultPackage = haskell-nix-flake.packages."unison-cli-main:exe:unison"; - inherit (pkgs) unison-project; - inherit checks devShells localPackageNames; + + devShells = let + mkDevShell = pkg: + shellFor { + packages = _hpkgs: [pkg]; + ## Enabling Hoogle causes us to rebuild GHC. + withHoogle = false; + }; + in + { + local = shellFor { + packages = _hpkgs: builtins.attrValues localPackages; + withHoogle = false; + }; + } + // pkgs.lib.mapAttrs (_name: mkDevShell) localPackages; } diff --git a/nix/haskell-nix-overlay.nix b/nix/haskell-nix-overlay.nix deleted file mode 100644 index b98ee874f2..0000000000 --- a/nix/haskell-nix-overlay.nix +++ /dev/null @@ -1,41 +0,0 @@ -final: prev: { - unison-project = with prev.lib.strings; let - cleanSource = pth: let - src' = prev.lib.cleanSourceWith { - filter = filt; - src = pth; - }; - filt = path: type: let - bn = baseNameOf path; - isHiddenFile = hasPrefix "." bn; - isFlakeLock = bn == "flake.lock"; - isNix = hasSuffix ".nix" bn; - in - !isHiddenFile && !isFlakeLock && !isNix; - in - src'; - in - final.haskell-nix.project' { - src = cleanSource ./..; - projectFileName = "stack.yaml"; - modules = [ - # enable profiling - { - enableLibraryProfiling = true; - profilingDetail = "none"; - } - # remove buggy build tool dependencies - ({lib, ...}: { - # this component has the build tool - # `unison-cli:unison` and somehow haskell.nix - # decides to add some file sharing package - # `unison` as a build-tool dependency. - packages.unison-cli.components.exes.cli-integration-tests.build-tools = lib.mkForce []; - }) - ]; - branchMap = { - "https://github.com/unisonweb/configurator.git"."e47e9e9fe1f576f8c835183b9def52d73c01327a" = "unison"; - "https://github.com/unisonweb/shellmet.git"."2fd348592c8f51bb4c0ca6ba4bc8e38668913746" = "topic/avoid-callCommand"; - }; - }; -} diff --git a/nix/nixpkgs-overlay.nix b/nix/nixpkgs-overlay.nix deleted file mode 100644 index 033ee5e881..0000000000 --- a/nix/nixpkgs-overlay.nix +++ /dev/null @@ -1,49 +0,0 @@ -{versions}: final: prev: { - unison-hls = final.haskell-language-server.override { - # build with our overridden haskellPackages that have our pinned - # version of ormolu and hls - haskellPackages = final.haskell.packages."ghc${versions.ghc}"; - dynamic = true; - supportedGhcVersions = [versions.ghc]; - }; - haskell = - prev.haskell - // { - packages = - prev.haskell.packages - // { - ghcunison = prev.haskell.packages."ghc${versions.ghc}".extend (hfinal: hprev: let - inherit (prev.haskell.lib) overrideCabal; - in { - # dependency overrides for ormolu 0.5.2.0 - haskell-language-server = let - p = - hfinal.callHackageDirect - { - pkg = "haskell-language-server"; - ver = versions.hls; - sha256 = "0kp586yc162raljyd5arsxm5ndcx5zfw9v94v27bkjg7x0hp1s8b"; - } - { - hls-fourmolu-plugin = null; - hls-stylish-haskell-plugin = null; - hls-hlint-plugin = null; - hls-floskell-plugin = null; - }; - override = drv: { - doCheck = false; - configureFlags = - (drv.configureFlags or []) - ++ [ - "-f-fourmolu" - "-f-stylishhaskell" - "-f-hlint" - "-f-floskell" - ]; - }; - in - overrideCabal p override; - }); - }; - }; -} diff --git a/nix/unison-overlay.nix b/nix/unison-overlay.nix deleted file mode 100644 index 5f7f1a336d..0000000000 --- a/nix/unison-overlay.nix +++ /dev/null @@ -1,15 +0,0 @@ -final: prev: { - # a wrapped version of stack that passes the necessary flags to use - # the nix provided ghc. - unison-stack = prev.symlinkJoin { - name = "stack"; - paths = [final.stack]; - buildInputs = [final.makeWrapper]; - postBuild = let - flags = ["--no-nix" "--system-ghc" "--no-install-ghc"]; - add-flags = "--add-flags '${prev.lib.concatStringsSep " " flags}'"; - in '' - wrapProgram "$out/bin/stack" ${add-flags} - ''; - }; -} diff --git a/nix/unison-project.nix b/nix/unison-project.nix new file mode 100644 index 0000000000..aa191a5a44 --- /dev/null +++ b/nix/unison-project.nix @@ -0,0 +1,31 @@ +{ + haskell-nix, + lib, +}: let + cleanSource = src: + lib.cleanSourceWith { + inherit src; + filter = path: type: let + bn = baseNameOf path; + isHiddenFile = lib.hasPrefix "." bn; + isFlakeLock = bn == "flake.lock"; + isNix = lib.hasSuffix ".nix" bn; + in + !isHiddenFile && !isFlakeLock && !isNix; + }; +in + haskell-nix.project' { + src = cleanSource ./..; + projectFileName = "stack.yaml"; + modules = [ + # enable profiling + { + enableLibraryProfiling = true; + profilingDetail = "none"; + } + ]; + branchMap = { + "https://github.com/unisonweb/configurator.git"."e47e9e9fe1f576f8c835183b9def52d73c01327a" = "unison"; + "https://github.com/unisonweb/shellmet.git"."2fd348592c8f51bb4c0ca6ba4bc8e38668913746" = "topic/avoid-callCommand"; + }; + }