Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 14 additions & 49 deletions NixSupport/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
, optimizationLevel ? "2"
, filter
, ihp-env-var-backwards-compat
, static
}:

let
Expand Down Expand Up @@ -119,44 +120,25 @@ let
'';
src = filter { root = pkgs.nix-gitignore.gitignoreSource [] projectPath; include = [filter.isDirectory "Makefile" (filter.matchExt "hs")]; exclude = ["static" "Frontend"]; name = "${appName}-source"; };
buildInputs = [allHaskellPackages];
nativeBuildInputs = [ pkgs.makeWrapper schemaObjectFiles];
nativeBuildInputs = [schemaObjectFiles];
enableParallelBuilding = true;
disallowedReferences = [ ihp ]; # Prevent including the large full IHP source code
};
in
pkgs.stdenv.mkDerivation {
name = appName;
buildPhase = ''
runHook preBuild

# When npm install is executed by the project's makefile it will fail with:
#
# EACCES: permission denied, mkdir '/homeless-shelter'
#
# To avoid this error we use /tmp as our home directory for the build
#
# See https://github.com/svanderburg/node2nix/issues/217#issuecomment-751311272
export HOME=/tmp

export IHP_LIB=${ihp-env-var-backwards-compat}
export IHP=${ihp-env-var-backwards-compat}

make -j static/app.css static/app.js

runHook postBuild
'';
installPhase = ''
runHook preInstall

mkdir -p "$out"
mkdir -p $out/bin $out/lib

INPUT_HASH="$((basename $out) | cut -d - -f 1)"
makeWrapper ${binaries}/bin/RunProdServer $out/bin/RunProdServer --set-default IHP_ASSET_VERSION $INPUT_HASH --set-default IHP_LIB ${ihp-env-var-backwards-compat} --run "cd $out/lib" --prefix PATH : ${pkgs.lib.makeBinPath (otherDeps pkgs)}
pkgs.runCommandNoCC appName { inherit static binaries; nativeBuildInputs = [ pkgs.makeWrapper ]; } ''
# Hash that changes only when `static` changes:
INPUT_HASH="$(basename ${static} | cut -d- -f1)"
makeWrapper ${binaries}/bin/RunProdServer $out/bin/RunProdServer \
--set-default IHP_ASSET_VERSION $INPUT_HASH \
--set-default APP_STATIC ${static} \
--prefix PATH : ${pkgs.lib.makeBinPath (otherDeps pkgs)}

# Copy job runner binary to bin/ if we built it
if [ -f ${binaries}/bin/RunJobs ]; then
makeWrapper ${binaries}/bin/RunJobs $out/bin/RunJobs --set-default IHP_ASSET_VERSION $INPUT_HASH --set-default IHP_LIB ${ihp-env-var-backwards-compat} --run "cd $out/lib" --prefix PATH : ${pkgs.lib.makeBinPath (otherDeps pkgs)}
makeWrapper ${binaries}/bin/RunJobs $out/bin/RunJobs \
--set-default IHP_ASSET_VERSION $INPUT_HASH \
--set-default APP_STATIC ${static} \
--prefix PATH : ${pkgs.lib.makeBinPath (otherDeps pkgs)}
fi;

# Copy other binaries, excluding RunProdServer and RunJobs
Expand All @@ -165,21 +147,4 @@ in
binary_basename=$(basename "$binary")
cp "$binary" "$out/bin/$binary_basename";
done

mv static "$out/lib/static"

runHook postInstall
'';
src = pkgs.nix-gitignore.gitignoreSource [] projectPath;
buildInputs = builtins.concatLists [ allNativePackages ];
nativeBuildInputs = builtins.concatLists [
[ pkgs.makeWrapper
pkgs.cacert # Needed for npm install to work from within the IHP build process
[allHaskellPackages]
]
];
shellHook = "eval $(egrep ^export ${allHaskellPackages}/bin/ghc)";
enableParallelBuilding = true;
impureEnvVars = pkgs.lib.fetchers.proxyImpureEnvVars; # Needed for npm install to work from within the IHP build process
disallowedReferences = [ ihp ]; # Prevent including the large full IHP source code
}
''
75 changes: 74 additions & 1 deletion flake-module.nix
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,27 @@ ihpFlake:
type = lib.types.str;
default = "1";
};

static.extraDirs = lib.mkOption {
type = lib.types.attrsOf (lib.types.oneOf [ lib.types.path lib.types.package ]);
default = {};
description = "Map of subdir name -> derivation/path to be mounted under static/";
example = ''
{
Frontend = self.packages.${system}.frontend; # -> /static/Frontend/...
Bootstrap = "${pkgs.bootstrap5}/dist"; # mount subdir of a package
}
'';
};

static.makeBundling = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Whether to build static files using the Makefile provided by IHP.
If your app doesn't use the Makefile to bundle the CSS, you can disable this for faster builds.
'';
};
};
}
);
Expand Down Expand Up @@ -152,6 +173,7 @@ ihpFlake:
appName = cfg.appName;
filter = ihpFlake.inputs.nix-filter.lib;
ihp-env-var-backwards-compat = ihpFlake.inputs.self.packages.${system}.ihp-env-var-backwards-compat;
static = self'.packages.static;
};

unoptimized-prod-server = import "${ihp}/NixSupport/default.nix" {
Expand All @@ -167,8 +189,25 @@ ihpFlake:
appName = cfg.appName;
filter = ihpFlake.inputs.nix-filter.lib;
ihp-env-var-backwards-compat = ihpFlake.inputs.self.packages.${system}.ihp-env-var-backwards-compat;
static = self'.packages.static;
};

static =
let
# Turn { Frontend = drv; Admin = drv2; } into a farm
extraStaticFarm = pkgs.linkFarm "${cfg.appName}-extra-static" (lib.mapAttrsToList (name: path: { inherit name path; }) cfg.static.extraDirs);
in
pkgs.symlinkJoin {
name = "${cfg.appName}-static";
paths = [
(if cfg.static.makeBundling
then self'.packages.staticFilesCompiledByMake
else (let filter = ihpFlake.inputs.nix-filter.lib; in filter { root = cfg.projectPath; include = ["static"]; name = "static-directory"; }) + "/static"
)
extraStaticFarm
];
};

unoptimized-docker-image = pkgs.dockerTools.buildImage {
name = "ihp-app";
config = { Cmd = [ "${self'.packages.unoptimized-prod-server}/bin/RunProdServer" ]; };
Expand Down Expand Up @@ -206,7 +245,41 @@ ihpFlake:
cp Application/Schema.sql $out/
'';
};
};
} // (if cfg.static.makeBundling then {
staticFilesCompiledByMake = pkgs.stdenv.mkDerivation {
name = "${config.ihp.appName}-staticFilesCompiledByMake";
buildPhase = ''
runHook preBuild
# When npm install is executed by the project's makefile it will fail with:
#
# EACCES: permission denied, mkdir '/homeless-shelter'
#
# To avoid this error we use /tmp as our home directory for the build
#
# See https://github.com/svanderburg/node2nix/issues/217#issuecomment-751311272
export HOME=/tmp

export IHP_LIB=${ihpFlake.inputs.self.packages.${system}.ihp-env-var-backwards-compat}
export IHP=${ihpFlake.inputs.self.packages.${system}.ihp-env-var-backwards-compat}

make -j static/app.css static/app.js
runHook postBuild
'';
installPhase = ''
cp -R static/. $out
'';
src = pkgs.nix-gitignore.gitignoreSource [] cfg.projectPath;
buildInputs = cfg.packages;
nativeBuildInputs = builtins.concatLists [
[ pkgs.makeWrapper
pkgs.cacert # Needed for npm install to work from within the IHP build process
]
];
enableParallelBuilding = true;
impureEnvVars = pkgs.lib.fetchers.proxyImpureEnvVars; # Needed for npm install to work from within the IHP build process
disallowedReferences = [ ihp ]; # Prevent including the large full IHP source code
};
} else {});

devenv.shells.default = lib.mkIf cfg.enable {
packages = [ ghcCompiler.ihp ghcCompiler.ihp-ide pkgs.gnumake ]
Expand Down
3 changes: 2 additions & 1 deletion ihp/IHP/Server.hs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ withBackgroundWorkers pgListener frameworkConfig app = do
initStaticApp :: FrameworkConfig -> IO Application
initStaticApp frameworkConfig = do
frameworkStaticDir <- getDataFileName "static"
appStaticDir <- EnvVar.envOrDefault "APP_STATIC" "static/"
let
maxAge = case frameworkConfig.environment of
Env.Development -> Static.MaxAgeSeconds 0
Expand All @@ -104,7 +105,7 @@ initStaticApp frameworkConfig = do
{ Static.ss404Handler = Just (frameworkConfig.requestLoggerMiddleware handleNotFound)
, Static.ssMaxAge = maxAge
}
appSettings = (Static.defaultWebAppSettings "static/")
appSettings = (Static.defaultWebAppSettings appStaticDir)
{ Static.ss404Handler = Just (Static.staticApp frameworkSettings)
, Static.ssMaxAge = maxAge
}
Expand Down
Loading