Skip to content

Commit

Permalink
Merge pull request #1653 from pauldub/feat-devenv-support
Browse files Browse the repository at this point in the history
feat: add devenv support
  • Loading branch information
mpscholten committed Apr 29, 2023
2 parents cff023d + 212d1a3 commit 63a0787
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 84 deletions.
15 changes: 14 additions & 1 deletion IHP/IDE/Postgres.hs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
module IHP.IDE.Postgres (startPostgres, stopPostgres) where
module IHP.IDE.Postgres (startPostgres, stopPostgres, waitPostgres) where

import IHP.IDE.Types
import IHP.Prelude
import qualified System.Process as Process
import qualified System.Directory as Directory
import qualified Data.ByteString.Char8 as ByteString
import qualified Data.ByteString.Builder as ByteString
import Control.Concurrent (threadDelay)
import GHC.IO.Handle

import qualified IHP.Log as Log
Expand Down Expand Up @@ -117,3 +118,15 @@ waitUntilReady process callback = do
if "database system is ready to accept connections" `ByteString.isInfixOf` line
then callback
else waitUntilReady process callback

waitPostgres :: (?context :: Context) => IO ()
waitPostgres = do
let isDebugMode = ?context |> get #isDebugMode
threadDelay 1000000
(_, stdout, _) <- Process.readProcessWithExitCode "pg_ctl" ["status"] ""
if "server is running" `isInfixOf` (cs stdout)
then dispatch (UpdatePostgresState PostgresReady)
else do
when isDebugMode (Log.debug ("Waiting for postgres to start" :: Text))
waitPostgres

2 changes: 2 additions & 0 deletions IHP/IDE/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,14 @@ data Action =
data PostgresState
= PostgresNotStarted
| StartingPostgres
| PostgresReady
| PostgresStarted { process :: !ManagedProcess, standardOutput :: !(IORef ByteString.Builder), errorOutput :: !(IORef ByteString.Builder) }

instance Show PostgresState where
show PostgresNotStarted = "NotStarted"
show StartingPostgres = "Starting"
show PostgresStarted { } = "Started"
show PostgresReady { } = "Ready"

data AppGHCIState
= AppGHCINotStarted
Expand Down
9 changes: 5 additions & 4 deletions NixSupport/default.nix
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
{ compiler ? "ghc944"
, additionalNixpkgsOptions ? {}
, pkgs ? import "${toString projectPath}/Config/nix/nixpkgs-config.nix" { ihp = ihp; additionalNixpkgsOptions = additionalNixpkgsOptions; }
, ghc ? pkgs.haskell.packages.${compiler}
, ihp
, haskellDeps ? (p: [])
, otherDeps ? (p: [])
, projectPath ? ./.
, withHoogle ? false
, additionalNixpkgsOptions ? {}
, postgresExtensions ? (p: [])
, optimized ? false
, includeDevTools ? !optimized # Include Haskell Language Server and Postgres?
}:

let
pkgs = import "${toString projectPath}/Config/nix/nixpkgs-config.nix" { ihp = ihp; additionalNixpkgsOptions = additionalNixpkgsOptions; };
ghc = pkgs.haskell.packages.${compiler};
allHaskellPackages =
(if withHoogle
then ghc.ghcWithHoogle
Expand Down Expand Up @@ -79,6 +79,7 @@ in
mkdir -p $out/bin
mv ${appBinary} $out/bin/RunProdServerWithoutOptions
INPUT_HASH="$((basename $out) | cut -d - -f 1)"
makeWrapper $out/bin/RunProdServerWithoutOptions $out/bin/RunProdServer --set-default IHP_ASSET_VERSION $INPUT_HASH --run "cd $out/lib" --prefix PATH : ${pkgs.lib.makeBinPath (otherDeps pkgs)}
Expand All @@ -101,7 +102,7 @@ in
mv static "$out/lib/static"
'';
dontFixup = true;
src = (import <nixpkgs> {}).nix-gitignore.gitignoreSource [] projectPath;
src = pkgs.nix-gitignore.gitignoreSource [] projectPath;
buildInputs = builtins.concatLists [ [allHaskellPackages] allNativePackages ];
nativeBuildInputs = builtins.concatLists [
[ pkgs.makeWrapper ]
Expand Down
86 changes: 86 additions & 0 deletions NixSupport/devenv.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{ pkgs, config, lib, ... }:

let
cfg = config.ihp;
types = lib.types;
in
{
options.ihp = {
enable = lib.mkEnableOption "Enable IHP support";

ghcCompiler = lib.mkOption {
default = pkgs.haskell.packages.ghc944;

description = ''
The GHC compiler to use for IHP.
'';
};

haskellPackages = lib.mkOption {
default = p: with p; [
cabal-install
base
wai
text
hlint
ihp
];
description = ''
List of Haskell packages to be installed in the IHP environment.
'';
};

projectPath = lib.mkOption {
type = types.path;
description = ''
Path to the IHP project.
'';
};
};

config =
let
ghcCompiler = import ./mkGhcCompiler.nix {
inherit pkgs;
inherit (cfg) ghcCompiler;
ihp = ../.;
};
in
lib.mkIf cfg.enable {
packages = [ ghcCompiler.ihp ];

languages.haskell.enable = true;
languages.haskell.package = ghcCompiler.ghc.withPackages cfg.haskellPackages;

scripts.start.exec = ''
${ghcCompiler.ihp}/bin/RunDevServer
'';

processes.devServer.exec = "start";

env.IHP_DEVENV = "1";
env.DATABASE_URL = "postgres:///app?host=${config.env.PGHOST}";

services.postgres.enable = true;
services.postgres.initialDatabases = [
{
name = "app";
schema = pkgs.runCommand "ihp-schema" {} ''
touch $out
echo "-- IHPSchema.sql" >> $out
echo "" >> $out
cat ${../lib/IHP/IHPSchema.sql} | sed -e s'/--.*//' | sed -e s'/$/\\/' >> $out
echo "" >> $out
echo "-- Application/Schema.sql" >> $out
echo "" >> $out
cat ${cfg.projectPath + "/Application/Schema.sql"} | sed -e s'/--.*//' | sed -e s'/$/\\/' >> $out
echo "" >> $out
echo "-- Application/Fixtures.sql" >> $out
echo "" >> $out
cat ${cfg.projectPath + "/Application/Fixtures.sql"} | sed -e s'/--.*//' | sed -e s'/$/\\/' >> $out
'';
}
];
};
}
55 changes: 6 additions & 49 deletions NixSupport/make-nixpkgs-from-options.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,67 +13,24 @@
, additionalNixpkgsOptions ? {}
}:
let
generatedOverrides = haskellPackagesNew: haskellPackagesOld:
let
toPackage = dir: file: _: {
name = builtins.replaceStrings [ ".nix" ] [ "" ] file;

value = haskellPackagesNew.callPackage ("${dir}/${file}") {};
};
makePackageSet = dir: pkgs.lib.mapAttrs' (toPackage dir) (builtins.readDir dir);
in
{ "ihp" = ((haskellPackagesNew.callPackage "${toString ihp}/ihp.nix") { }); } // (makePackageSet haskellPackagesDir) // (makePackageSet "${toString ihp}/NixSupport/haskell-packages/.");

makeOverrides =
function: names: haskellPackagesNew: haskellPackagesOld:
let
toPackage = name: {
inherit name;

value = function haskellPackagesOld.${name};
};
in
builtins.listToAttrs (map toPackage names);

composeExtensionsList = pkgs.lib.fold pkgs.lib.composeExtensions (_: _: {});

ihpDontCheckPackages = ["mmark" "mmark-ext" "mutable-containers" "hiedb" "hls-fourmolu-plugin"];
ihpDoJailbreakPackages = ["haskell-to-elm" "ip" "ghc-syntax-highlighter" "relude" "hs-brotli" "tuples" "singletons-th" "singletons-base" "inflections" "postgresql-simple" "with-utf8" "chell"];
ihpDontHaddockPackages = [];
mkGhcCompiler = import ./mkGhcCompiler.nix;

config = {
allowBroken = true;
packageOverrides = pkgs: rec {
haskell = pkgs.haskell // {
packages = pkgs.haskell.packages // {
"${compiler}" =
pkgs.haskell.packages."${compiler}".override {
overrides = composeExtensionsList [
generatedOverrides

# Overrides provided by IHP
(makeOverrides pkgs.haskell.lib.dontCheck ihpDontCheckPackages )
(makeOverrides pkgs.haskell.lib.doJailbreak ihpDoJailbreakPackages)
(makeOverrides pkgs.haskell.lib.dontHaddock ihpDontHaddockPackages)

# Project specific overrides
(makeOverrides pkgs.haskell.lib.dontCheck dontCheckPackages )
(makeOverrides pkgs.haskell.lib.doJailbreak doJailbreakPackages)
(makeOverrides pkgs.haskell.lib.dontHaddock dontHaddockPackages)
manualOverrides
"${compiler}" = mkGhcCompiler {
inherit pkgs ihp dontCheckPackages doJailbreakPackages dontHaddockPackages manualOverrides;

(self: super: { haskell-language-server = pkgs.haskell.lib.appendConfigureFlag super.haskell-language-server "--enable-executable-dynamic"; })
(self: super: { ormolu = if pkgs.system == "aarch64-darwin" then pkgs.haskell.lib.overrideCabal super.ormolu (_: { enableSeparateBinOutput = false; }) else super.ormolu; })
];
ghcCompiler = pkgs.haskell.packages."${compiler}";
};
}
;
}
;
};
};
};
};


pkgs = (import ((import <nixpkgs> {}).fetchFromGitHub {
owner = "NixOS";
repo = "nixpkgs";
Expand Down
58 changes: 58 additions & 0 deletions NixSupport/mkGhcCompiler.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{ pkgs
, ihp
, ghcCompiler
, dontCheckPackages ? []
, doJailbreakPackages ? []
, dontHaddockPackages ? []
, manualOverrides ? _: _: { }
, haskellPackagesDir ? ./haskell-packages
, ... }:

let
composeExtensionsList = pkgs.lib.fold pkgs.lib.composeExtensions (_: _: { });

generatedOverrides = haskellPackagesNew: haskellPackagesOld:
let
toPackage = dir: file: _: {
name = builtins.replaceStrings [ ".nix" ] [ "" ] file;

value = haskellPackagesNew.callPackage ("${dir}/${file}") { };
};
makePackageSet = dir: pkgs.lib.mapAttrs' (toPackage dir) (builtins.readDir dir);
in {
"ihp" = ((haskellPackagesNew.callPackage "${ihp}/ihp.nix") { });
} // (makePackageSet haskellPackagesDir) // (makePackageSet "${ihp}/NixSupport/haskell-packages/.");

makeOverrides =
function: names: haskellPackagesNew: haskellPackagesOld:
let
toPackage = name: {
inherit name;

value = function haskellPackagesOld.${name};
};
in
builtins.listToAttrs (map toPackage names);

ihpDontCheckPackages = [ "mmark" "mmark-ext" "mutable-containers" "hiedb" "hls-fourmolu-plugin" ];
ihpDoJailbreakPackages = [ "haskell-to-elm" "ip" "ghc-syntax-highlighter" "relude" "hs-brotli" "tuples" "singletons-th" "singletons-base" "inflections" "postgresql-simple" "with-utf8" "chell" ];
ihpDontHaddockPackages = [ ];
in ghcCompiler.override {
overrides = composeExtensionsList [
generatedOverrides

# Overrides provided by IHP
(makeOverrides pkgs.haskell.lib.dontCheck ihpDontCheckPackages)
(makeOverrides pkgs.haskell.lib.doJailbreak ihpDoJailbreakPackages)
(makeOverrides pkgs.haskell.lib.dontHaddock ihpDontHaddockPackages)

# Project specific overrides
(makeOverrides pkgs.haskell.lib.dontCheck dontCheckPackages )
(makeOverrides pkgs.haskell.lib.doJailbreak doJailbreakPackages)
(makeOverrides pkgs.haskell.lib.dontHaddock dontHaddockPackages)
manualOverrides

(self: super: { haskell-language-server = pkgs.haskell.lib.appendConfigureFlag super.haskell-language-server "--enable-executable-dynamic"; })
(self: super: { ormolu = if pkgs.system == "aarch64-darwin" then pkgs.haskell.lib.overrideCabal super.ormolu (_: { enableSeparateBinOutput = false; }) else super.ormolu; })
];
}
Loading

0 comments on commit 63a0787

Please sign in to comment.