Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi-package projects #7

Closed
srid opened this issue May 30, 2022 · 13 comments · Fixed by #34
Closed

Multi-package projects #7

srid opened this issue May 30, 2022 · 13 comments · Fixed by #34
Labels
api-change help wanted Extra attention is needed

Comments

@srid
Copy link
Owner

srid commented May 30, 2022

How should this flake be changed to support projects with multiple Haskel packages, like https://github.com/hercules-ci/hercules-ci-agent ?

@srid
Copy link
Owner Author

srid commented May 30, 2022

What about packages that use different GHC versions? Do we allow it in a mono-repo?

@roberth
Copy link
Collaborator

roberth commented May 30, 2022

What happens say if hercules-ci-api uses a dependency that is in version conflict with the same in say hercules-ci-cli?

Not sure, but generally you'd avoid this situation. If you do need this, I'd say you're not really in a monorepo situation anyway.

What about packages that use different GHC versions?

This happens with GHCJS SPAs that have regular-GHC backends. I think this is a valid reason for having a unique package set per "project", so project =~ package set =~ ghc version.

@srid
Copy link
Owner Author

srid commented May 30, 2022

(What is =~?)

IIUC then - we have "projects", and each project defines its own package sets and GHC version.

For https://github.com/hercules-ci/hercules-ci-agent - that means there is just one project, which has a package set containing those sub-directories (cabal projects), all using a single GHC version.

For trivial-structured projects (like the ones I maintain), there would be one project which has one package exactly.

For complex projects, you could have a backend project using say GHC-9.2 (and multiple packages inside it) and a frontend project using say GHCJS-8.10.

@roberth
Copy link
Collaborator

roberth commented May 30, 2022

(What is =~?)

The vaguely equals operator ;) "maps 1:1" I guess.

... [ rest of the comment]

Exactly!

@srid
Copy link
Owner Author

srid commented May 30, 2022

Okay, that all sounds good to me. The trivial-structured case won't change much, so 👍🏿

@srid srid pinned this issue Jun 18, 2022
@srid srid added the help wanted Extra attention is needed label Aug 11, 2022
@srid
Copy link
Owner Author

srid commented Sep 14, 2022

In #23, we switched from developPackage to using callCabal2nixWithOptions directly.

@roberth
Copy link
Collaborator

roberth commented Sep 15, 2022

shellFor may be useful.

@HariAmoor-professional
Copy link
Contributor

This task would be a pretty sizable benefit for something for one of my projects, so I'm looking to take it on. I'll update this thread with a PR for review by Srid+contributors when the time comes.

@srid
Copy link
Owner Author

srid commented Oct 6, 2022

Here's a small demo: https://github.com/srid/haskell-multi-nix/blob/master/flake.nix

shellFor and extend are mainly the things we seem to need to implement this.

@srid
Copy link
Owner Author

srid commented Oct 18, 2022

Here's a concrete spec of what this could look like. Consider the three different use cases and what the proposed Nix looks like:

1. Single package project

This would be more or less similar to the current API, except for the extra packages indirection. The "name" attribute can also be determined automatically from packages.${name}.

{
  haskellProjects.default = {
    # overrides = self: super: {}
    hlsCheck.enable = true;
    packages.haskell-template = {
      root = ./.;
    };
  };
}

2. Multi-package single project

Based on https://github.com/srid/haskell-multi-nix/

{
  haskellProjects.default = {
    haskellPackages = pkgs.haskell.packages.ghc924;
    overrides = self: super: {};
    hlsCheck.enable = false;
    hlintCheck.enable = true;
    buildTools = {};
    packages = {
      # foo library
      foo = {
        root = ./foo;
        modifier = drv: pkgs.haskell.lib.dontCheck drv;
      };
      # bar executable (depends on foo)
      bar = {
        root = ./bar;
        flakeAttribute = "bar";  # packages.bar; apps.bar (default: "default-bar")
      };
    };
  };
  packages.default = self'.packages.foo;
  apps.default = self.packages.bar;
}

3. Multi-package multi-project

Typical of GHCJS/reflex/obelisk projects, which have three packages - frontend, backend & common - with 'common' shared between ghc and ghcjs. https://github.com/obsidiansystems/obelisk/tree/master/skeleton

The Ema project is another example, which has both GHC 9.0 and 9.2 outputs: https://github.com/EmaApps/ema/blob/master/flake.nix

{
  haskellProjects = {
    backend = {
      packages = {
        backend.root = ./backend;
        common.root = ./common;
      };
    };
    frontend = {
      haskellPackages = inputs.reflex-platform.ghcjs8107;
      packages = {
        frontend.root = ./backend;
        common.root = ./common;
      };
    };
  };
  devShells.default = self'.devShells.backend-backend;
}

@HariAmoor-professional
Copy link
Contributor

HariAmoor-professional commented Oct 19, 2022

@srid What types should each of root, modifier, and flakeAttribute have? Also, how can I specify that bar should depend on foo in the (2) case (so that Nix will always compile foo first before bar)?

@srid
Copy link
Owner Author

srid commented Oct 20, 2022

@srid What types should each of root, modifier, and flakeAttribute have?

path, functionTo package, str respectively?

Also, how can I specify that bar should depend on foo in the (2) case (so that Nix will always compile foo first before bar)?

You don't need to specify that in Nix. callCabal2Nix will determine that dependency from the cabal file. See https://github.com/srid/haskell-multi-nix/blob/88e758b30a5bdbd6a037aa959b497ec9af6aac7a/bar/bar.cabal#L20

All the packages option does is allow the user to specify a list of local packages.

@srid
Copy link
Owner Author

srid commented Oct 27, 2022

haskellPathsInDir can be used to determine a default value for packages? Then, the minimal Nix would look like

haskellProjects.default = {};

@srid srid closed this as completed in #34 Nov 9, 2022
@srid srid unpinned this issue Nov 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-change help wanted Extra attention is needed
Projects
None yet
3 participants