Skip to content

Commit

Permalink
Merge pull request #22 from cdepillabout/filter
Browse files Browse the repository at this point in the history
Add localPkgFilter argument to stacklock2nix for filtering local Haskell packages
  • Loading branch information
cdepillabout authored May 1, 2023
2 parents 02b9f41 + 95d46d1 commit f0cad47
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 21 deletions.
35 changes: 35 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@

## 2.0.0

* Add a `localPkgFilter` argument to `stacklock2nix`. This can be used to
filter the sources of local Haskell packages.

Here's an example of how you might use it:

```nix
stacklock2nix {
stackYaml = ./stack.yaml;
localPkgFilter = defaultLocalPkgFilter: pkgName: path: type:
if pkgName == "my-example-haskell-lib" && baseNameOf path == "extra-file" then
false
else
defaultLocalPkgFilter path type;
}
```

This is an example of filtering out a file called `extra-file` from the input
source of the Haskell package `my-example-haskell-lib`.

This is a major version bump because if you don't specify the
`localPkgFilter` argument to `stacklock2nix`, it defaults to using a filter
that filters out the `.stack-work/` directory, as well as directories like
`dist-newstyle`. It also passes input files through the
`lib.cleanSourceFilter` function, which filters out `.git/`, as well as a
few other types of files.

While this is technically a major version bump, most users won't be
negatively affected by this change. It is quite likely this won't
affect most people.

Added in [#22](https://github.com/cdepillabout/stacklock2nix/pull/22).

## 1.3.0

* Add `all-cabal-hashes` as an output from `stacklock2nix`. This can be
Expand Down
4 changes: 4 additions & 0 deletions my-example-haskell-lib-easy/my-example-haskell-lib/extra-file
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
This is an extra file.

You may want to use the `localPkgFilter` argument of `stacklock2nix` to ignore
extra files like this.
124 changes: 104 additions & 20 deletions nix/build-support/stacklock2nix/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,52 @@
#
# nixpkgsPath :: Path
nixpkgsPath ? topargs.path
, # A filter function for local packages.
#
# This should be a function you could pass to the `filter` argument of
# `builtins.path` or `lib.cleanSourceWith`. See the documentation for
# either of these functions for how filters work.
#
# localPkgFilter
# :: (Path -> String -> Bool)
# -> String
# -> Path
# -> String
# -> Bool
#
# The first argument is a default filter function that is useful for
# Haskell packages. This is passed to you as a convenience for you
# to use in your own filter functions. This default filter function
# filters out common Haskell development files, like
# `.stack-work`, `dist-newstyle`, etc. It also calls `lib.cleanSourceFilter`.
#
# The second argument is the Haskell package name that is currently being
# filtered. This package name is read from either the `.cabal` or
# `package.yaml` file.
#
# You may want to override this argument if you want to a more specific
# filter for some of your local packages.
#
# Example:
# ```
# defaultLocalPkgFilter: pkgName: path: type:
# if pkgName == "my-example-haskell-lib" && baseNameOf path == "extra-file" then
# false
# else
# defaultLocalPkgFilter path type
# ```
#
# This example filters out the filed called `extra-file` from the input
# source for the `my-example-haskell-lib` package. For all other files,
# `defaultLocalPkgFilter` is called.
#
# Here's an example of a filter that doesn't filter out anything:
#
# ```
# defaultLocalPkgFilter: pkgName: path: type: true
# ```
localPkgFilter ?
defaultLocalPkgFilter: pkgName: path: type: defaultLocalPkgFilter path type
}:

# The stack.yaml path can be computed from the stack.yaml.lock path, or
Expand Down Expand Up @@ -277,27 +323,45 @@ let
#
# data HaskellPkgLock
# = HackageDep { hackage :: String }
# | GitDep { name :: String, git :: String, commit :: String, subdir :: String }
# | GitDep { name :: String, git :: String, commit :: String, version :: String, subdir :: Maybe String }
# | UrlDep { url :: String, name :: String, version :: String, sha256 :: String, subdir :: Maybe String }
#
# In `GitDep`, `subdir` can be left out.
# In `GitDep` and `UrlDep`, `subdir` can be left out (which is what the `Maybe`
# indicates). You cannot pass `null` for `subdir`, you must just leave it
# out if you don't want it to specify it.
#
# Example `HackageDep`:
#
# Example:
# ```
# extraDepCreateNixHaskPkg
# hfinal
# { hackage = "cassava-0.5.3.0@sha256:06e6dbc0f3467f3d9823321171adc08d6edc639491cadb0ad33b2dca1e530d29,6083"; }
# ```
#
# Another Example:
# Example `GitDep`:
#
# ```
# extraDepCreateNixHaskPkg
# hfinal
# { name = "servant-client";
# git = "https://github.com/haskell-servant/servant";
# commit = "1fba9dc6048cea6184964032b861b052cd54878c";
# version = "0.19";
# subdir = "servant-client";
# }
# ```
#
# Example `UrlDep`:
#
# ```
# extraDepCreateNixHaskPkg
# hfinal
# { name = "pretty-simple";
# url = "https://github.com/cdepillabout/pretty-simple/archive/d8ef1b3c2d913a05515b2d1c4fec0b52d2744434.tar.gz";
# version = "4.1.2.0";
# sha256 = "aba1659b4c133b00b7a28837bcb413672823d72835bcee0f1594e0ba4e2ea4af";
# }
# ```
extraDepCreateNixHaskPkg = hfinal: haskPkgLock:
let
extraHackageDep =
Expand Down Expand Up @@ -373,7 +437,10 @@ let
# set.
#
# haskPkgLocksToOverlay
# :: [ { hackage :: String } ] -> HaskellPkgSet -> HaskellPkgSet -> HaskellPkgSet
# :: [ HaskellPkgLock ] -> HaskellPkgSet -> HaskellPkgSet -> HaskellPkgSet
#
# See the documentation for extraDepCreateNixHaskPkg for the definition of
# HaskellPkgLock.
#
# Example:
# ```
Expand Down Expand Up @@ -407,6 +474,7 @@ let
# { name = "servant-client";
# git = "https://github.com/haskell-servant/servant";
# commit = "1fba9dc6048cea6184964032b861b052cd54878c";
# version = "0.19";
# subdir = "servant-client";
# }
# ]
Expand Down Expand Up @@ -438,27 +506,21 @@ let
#
# Note that the basename of the `pkgPath` may be different than the actual
# Haskell package name, which is why this function is needed.
#
# Also note that localPkgPathStr is assumed to be a relative path from
# the directory containing the `stack.yaml` file.
mkLocalPkg = localPkgPathStr:
let
# Path to the Haskell package.
#
# pkgPath :: Path
pkgPath =
lib.cleanSourceWith {
src =
# TODO: I imagine it is not okay to just assume this package path is a
# relative path.
builtins.path { path = dirOf stackYamlReal + ("/" + localPkgPathStr); };
# TODO: Create a better filter, plus make it overrideable for end-users.
filter = path: type: true;
};
# The localPkgPathStr is assumed to be a relative path from the
# directory containing the `stack.yaml` file.
rawPkgPath = builtins.path { path = dirOf stackYamlReal + ("/" + localPkgPathStr); };

# This is `pkgPath`, but with everything removed except `.cabal` files
# and a `package.yaml` file.
#
# justCabalFilePath :: Path
justCabalFilePath = lib.cleanSourceWith {
src = pkgPath;
src = rawPkgPath;
filter = path: type:
lib.hasSuffix ".cabal" path ||
baseNameOf path == "package.yaml";
Expand Down Expand Up @@ -512,7 +574,6 @@ let
# hasSingleCabalFile :: Bool
hasSinglePackageYamlFile = lib.any (file: file == "package.yaml") allPkgFiles;

# pkgName = lib.removeSuffix ".cabal" cabalFileName;
pkgName =
if hasSingleCabalFile then
lib.removeSuffix ".cabal" cabalFileName
Expand All @@ -522,6 +583,29 @@ let
throw
("Could not find any .cabal files or a package.yaml file in package ${localPkgPathStr}. " +
"all files: ${toString allPkgFiles}");

# This is a default filter function for Haskell packages. Filters out
# things like `.stack-work`, `dist-newstyle`, etc. Also calls
# `lib.cleanSourceFilter`.
localPkgDefaultFilter = path: type:
let
haskFilesToIgnore = [
".stack-work"
"stack.yaml"
"stack.yaml.lock"
];
in
(! lib.elem (baseNameOf path) haskFilesToIgnore) &&
(! lib.any (lib.flip lib.hasPrefix (baseNameOf path)) [ "dist" ".ghc" ]) &&
lib.cleanSourceFilter path type;

# Path to the Haskell package.
#
# pkgPath :: Path
pkgPath = lib.cleanSourceWith {
src = rawPkgPath;
filter = path: type: localPkgFilter localPkgDefaultFilter pkgName path type;
};
in
{ inherit pkgPath pkgName; };

Expand Down Expand Up @@ -583,7 +667,7 @@ let

# A selector for picking only local packages defined in a `stack.yaml` from a Haskell package set.
#
# localPkgs :: HaskellPkgSet -> [ HaskellPkgDrv ]
# localPkgsSelector :: HaskellPkgSet -> [ HaskellPkgDrv ]
#
# Example: `my-stacklock-pkg-set.ghcWithPackages my-stacklock.localPkgsSelector`
#
Expand Down
15 changes: 14 additions & 1 deletion test/test-all-cabal-hashes-is-dir.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{ stacklock2nix
{ lib
, stacklock2nix
, haskell
, cabal-install
, fetchFromGitHub
Expand Down Expand Up @@ -37,6 +38,18 @@ let
rev = "80869091dcb9f932c15fe57e30d4d0730c5f87df";
sha256 = "sha256-LAD3/5qeJWbzfqkcWccMOq0pHBnSkNnvBjWnlLzWFvQ=";
};
# This is an example of using the `locakPkgFilter` argument in order to
# filter out extra files that aren't needed.
#
# TODO: This should also actually test that the resulting derivation doesn't
# depend on `extra-file` existing or not existing (since it should be filtered
# out).
localPkgFilter = defaultLocalPkgFilter: pkgName: path: type:
# This filters out the file called `extra-file`
if pkgName == "my-example-haskell-lib" && baseNameOf path == "extra-file" then
false
else
defaultLocalPkgFilter path type;
};
in
stacklock.newPkgSet.my-example-haskell-app

0 comments on commit f0cad47

Please sign in to comment.