on mb-kiln-with-custom-static-asset-directory
help
sign in
1{ system ? builtins.currentSystem
3, iosSdkVersion ? "10.2"
7 cleanSource = builtins.filterSource (name: _: let baseName = builtins.baseNameOf name; in !(
8 builtins.match "^\\.ghc\\.environment.*" baseName != null ||
9 baseName == "cabal.project.local"
12 commandRuntimeDeps = pkgs: with pkgs; [
19 getReflexPlatform = sys: import ./dep/reflex-platform {
20 inherit iosSdkVersion config;
22 enableLibraryProfiling = profiling;
26 obeliskExecutableConfig = import ./lib/executable-config { nixpkgs = pkgs; filterGitSource = cleanSource; };
32 # Fix misc upstream packages
34 pkgs = self.callPackage ({ pkgs }: pkgs) {};
36 hnix = pkgs.haskell.lib.dontCheck (self.callCabal2nix "hnix" (pkgs.fetchFromGitHub {
37 owner = "haskell-nix";
39 rev = "42afdc21da5d9e076eab57eaa42bfdde938192b8";
40 sha256 = "0psw384dx9bw2dp93xrzw8rd9amvcwgzn64jzzwby7sfspj6k349";
44 pkgs.obeliskExecutableConfig.haskellOverlay
46 # Add obelisk packages
48 pkgs = self.callPackage ({ pkgs }: pkgs) {};
50 obelisk-executable-config-inject = pkgs.obeliskExecutableConfig.platforms.web.inject self;
52 obelisk-asset-manifest = self.callCabal2nix "obelisk-asset-manifest" (hackGet ./lib/asset + "/manifest") {};
53 obelisk-asset-serve-snap = self.callCabal2nix "obelisk-asset-serve-snap" (hackGet ./lib/asset + "/serve-snap") {};
54 obelisk-backend = self.callCabal2nix "obelisk-backend" (cleanSource ./lib/backend) {};
55 obelisk-cliapp = self.callCabal2nix "obelisk-cliapp" (cleanSource ./lib/cliapp) {};
56 obelisk-command = self.callCabal2nix "obelisk-command" (cleanSource ./lib/command) {};
57 obelisk-frontend = self.callCabal2nix "obelisk-frontend" (cleanSource ./lib/frontend) {};
58 obelisk-run = self.callCabal2nix "obelisk-run" (cleanSource ./lib/run) {};
59 obelisk-route = self.callCabal2nix "obelisk-route" (cleanSource ./lib/route) {};
60 obelisk-selftest = self.callCabal2nix "obelisk-selftest" (cleanSource ./lib/selftest) {};
61 obelisk-snap-extras = self.callCabal2nix "obelisk-snap-extras" (cleanSource ./lib/snap-extras) {};
62 tabulation = self.callCabal2nix "tabulation" (cleanSource ./lib/tabulation) {};
66 pkgs = self.callPackage ({ pkgs }: pkgs) {};
67 haskellLib = pkgs.haskell.lib;
69 # Modify a Haskell package to add completion scripts for the given
70 # executable produced by it. These completion scripts will be picked up
71 # automatically if the resulting derivation is installed, e.g. by
73 addOptparseApplicativeCompletionScripts = exeName: pkg: haskellLib.overrideCabal pkg (drv: {
74 postInstall = (drv.postInstall or "") + ''
75 BASH_COMP_DIR="$out/share/bash-completion/completions"
76 mkdir -p "$BASH_COMP_DIR"
77 "$out/bin/${exeName}" --bash-completion-script "$out/bin/${exeName}" >"$BASH_COMP_DIR/ob"
79 ZSH_COMP_DIR="$out/share/zsh/vendor-completions"
80 mkdir -p "$ZSH_COMP_DIR"
81 "$out/bin/${exeName}" --zsh-completion-script "$out/bin/${exeName}" >"$ZSH_COMP_DIR/_ob"
83 FISH_COMP_DIR="$out/share/fish/vendor_completions.d"
84 mkdir -p "$FISH_COMP_DIR"
85 "$out/bin/${exeName}" --fish-completion-script "$out/bin/${exeName}" >"$FISH_COMP_DIR/ob.fish"
89 # Dynamic linking with split objects dramatically increases startup time (about
90 # 0.5 seconds on a decent machine with SSD), so we do `justStaticExecutables`.
91 obelisk-command = haskellLib.overrideCabal
92 (addOptparseApplicativeCompletionScripts "ob"
93 (haskellLib.justStaticExecutables super.obelisk-command))
95 buildTools = (drv.buildTools or []) ++ [ pkgs.buildPackages.makeWrapper ];
97 ${drv.postFixup or ""}
98 # Make `ob` reference its runtime dependencies.
99 wrapProgram "$out"/bin/ob --prefix PATH : ${pkgs.lib.makeBinPath (commandRuntimeDeps pkgs)}
102 obelisk-selftest = haskellLib.justStaticExecutables super.obelisk-selftest;
108 reflex-platform = getReflexPlatform system;
109 inherit (reflex-platform) hackGet nixpkgs;
112 # The haskell environment used to build Obelisk itself, e.g. the 'ob' command
113 ghcObelisk = reflex-platform.ghc;
115 # Development environments for obelisk packages.
116 ghcObeliskEnvs = pkgs.lib.mapAttrs (n: v: reflex-platform.workOn ghcObelisk v) ghcObelisk;
118 inherit (import ./lib/asset/assets.nix { inherit nixpkgs; }) mkAssets;
120 haskellLib = pkgs.haskell.lib;
123 inherit reflex-platform;
124 inherit (reflex-platform) nixpkgs pinBuildInputs;
125 inherit (nixpkgs) lib;
126 pathGit = ./.; # Used in CI by the migration graph hash algorithm to correctly ignore files.
127 path = reflex-platform.filterGit ./.;
128 obelisk = ghcObelisk;
129 obeliskEnvs = ghcObeliskEnvs;
130 command = ghcObelisk.obelisk-command;
131 shell = pinBuildInputs "obelisk-shell" ([command] ++ commandRuntimeDeps pkgs) [];
133 selftest = pkgs.writeScript "selftest" ''
137 PATH="${command}/bin:$PATH"
138 export OBELISK_IMPL="${hackGet ./.}"
139 "${ghcObelisk.obelisk-selftest}/bin/obelisk-selftest" +RTS -N -RTS "$@"
141 #TODO: Why can't I build ./skeleton directly as a derivation? `nix-build -E ./.` doesn't work
142 skeleton = pkgs.runCommand "skeleton" {
143 dir = builtins.filterSource (path: type: builtins.trace path (baseNameOf path != ".obelisk")) ./skeleton;
147 nullIfAbsent = p: if lib.pathExists p then p else null;
148 #TODO: Avoid copying files within the nix store. Right now, obelisk-asset-manifest-generate copies files into a big blob so that the android/ios static assets can be imported from there; instead, we should get everything lined up right before turning it into an APK, so that copies, if necessary, only exist temporarily.
149 processAssets = { src, packageName ? "obelisk-generated-static", moduleName ? "Obelisk.Generated.Static" }: pkgs.runCommand "asset-manifest" {
151 outputs = [ "out" "haskellManifest" "symlinked" ];
152 nativeBuildInputs = [ ghcObelisk.obelisk-asset-manifest ];
156 mkdir -p "$symlinked"
157 obelisk-asset-manifest-generate "$src" "$haskellManifest" ${packageName} ${moduleName} "$symlinked"
160 compressedJs = frontend: optimizationLevel: pkgs.runCommand "compressedJs" {} ''
163 ln -s "${haskellLib.justStaticExecutables frontend}/bin/frontend.jsexe/all.js" all.unminified.js
164 ${if optimizationLevel == null then ''
165 ln -s all.unminified.js all.js
167 ${pkgs.closurecompiler}/bin/closure-compiler --externs "${reflex-platform.ghcjsExternsJs}" -O ${optimizationLevel} --jscomp_warning=checkVars --create_source_map="all.js.map" --source_map_format=V3 --js_output_file="all.js" all.unminified.js
168 echo "//# sourceMappingURL=all.js.map" >> all.js
173 mkBaseEc2 = { hostName, routeHost, enableHttps, adminEmail, ... }: {...}: {
175 (pkgs.path + /nixos/modules/virtualisation/amazon-image.nix)
179 firewall.allowedTCPPorts = if enableHttps then [ 80 443 ] else [ 80 ];
181 security.acme.certs = if enableHttps then {
182 "${routeHost}".email = adminEmail;
195 , internalPort ? 8000
196 , backendArgs ? "--port=${toString internalPort}"
201 virtualHosts."${routeHost}" = {
202 enableACME = enableHttps;
203 forceSSL = enableHttps;
204 locations.${baseUrl} = {
205 proxyPass = "http://localhost:" + toString internalPort;
206 proxyWebsockets = true;
210 systemd.services.${name} = {
211 wantedBy = [ "multi-user.target" ];
212 after = [ "network.target" ];
213 restartIfChanged = true;
217 exec ./backend ${backendArgs} >>backend.out 2>>backend.err </dev/null
221 KillMode = "process";
222 WorkingDirectory = "~";
229 description = "${user} service";
230 home = "/var/lib/${user}";
235 groups.${group} = {};
240 serverExe = backend: frontend: assets: optimizationLevel: version:
241 pkgs.runCommand "serverExe" {} ''
244 ln -s "${haskellLib.justStaticExecutables backend}"/bin/* $out/
245 ln -s "${mkAssets assets}" $out/static.assets
246 ln -s ${mkAssets (compressedJs frontend optimizationLevel)} $out/frontend.jsexe.assets
247 echo ${version} > $out/version
250 server = { exe, hostName, adminEmail, routeHost, enableHttps, version }@args:
252 nixos = import (pkgs.path + /nixos);
254 system = "x86_64-linux";
257 (serverModules.mkBaseEc2 args)
258 (serverModules.mkObeliskApp args)
264 # An Obelisk project is a reflex-platform project with a predefined layout and role for each component
265 project = base: projectDefinition:
266 let projectOut = sys: (getReflexPlatform sys).project (args@{ nixpkgs, ... }:
267 let mkProject = { android ? null #TODO: Better error when missing
268 , ios ? null #TODO: Better error when missing
270 , overrides ? _: _: {}
271 , staticFiles ? base + /static
273 , shellToolOverrides ? _: _: {}
274 , withHoogle ? false # Setting this to `true` makes shell reloading far slower
275 , __closureCompilerOptimizationLevel ? "ADVANCED" # Set this to `null` to skip the closure-compiler step
277 let frontendName = "frontend";
278 backendName = "backend";
279 commonName = "common";
280 staticName = "obelisk-generated-static";
281 staticFilesImpure = if lib.isDerivation staticFiles then staticFiles else toString staticFiles;
282 processedStatic = processAssets { src = staticFiles; };
283 # The packages whose names and roles are defined by this package
284 predefinedPackages = lib.filterAttrs (_: x: x != null) {
285 ${frontendName} = nullIfAbsent (base + "/frontend");
286 ${commonName} = nullIfAbsent (base + "/common");
287 ${backendName} = nullIfAbsent (base + "/backend");
289 combinedPackages = predefinedPackages // packages;
290 projectOverrides = self: super: {
291 ${staticName} = haskellLib.dontHaddock (self.callCabal2nix staticName processedStatic.haskellManifest {});
292 ${backendName} = haskellLib.addBuildDepend super.${backendName} self.obelisk-run;
294 totalOverrides = lib.composeExtensions projectOverrides overrides;
295 inherit (lib.strings) hasPrefix;
296 privateConfigDirs = ["config/backend"];
297 injectableConfig = builtins.filterSource (path: _:
298 !(lib.lists.any (x: hasPrefix (toString base + "/" + toString x) (toString path)) privateConfigDirs)
300 __androidWithConfig = configPath: {
301 ${if android == null then null else frontendName} = {
302 executableName = "frontend";
303 ${if builtins.pathExists staticFiles then "assets" else null} =
304 nixpkgs.obeliskExecutableConfig.platforms.android.inject
305 (injectableConfig configPath)
306 processedStatic.symlinked;
309 __iosWithConfig = configPath: {
310 ${if ios == null then null else frontendName} = {
311 executableName = "frontend";
312 ${if builtins.pathExists staticFiles then "staticSrc" else null} =
313 nixpkgs.obeliskExecutableConfig.platforms.ios.inject
314 (injectableConfig configPath)
315 processedStatic.symlinked;
319 inherit shellToolOverrides tools withHoogle;
320 overrides = totalOverrides;
321 packages = combinedPackages;
323 ${if android == null && ios == null then null else "ghcSavedSplices"} = (lib.filter (x: lib.hasAttr x combinedPackages) [
327 ghc = (lib.filter (x: lib.hasAttr x combinedPackages) [
332 ghcjs = lib.filter (x: lib.hasAttr x combinedPackages) [
337 android = __androidWithConfig (base + "/config");
338 ios = __iosWithConfig (base + "/config");
339 passthru = { inherit android ios packages overrides tools shellToolOverrides withHoogle staticFiles staticFilesImpure __closureCompilerOptimizationLevel processedStatic __iosWithConfig __androidWithConfig; };
341 in mkProject (projectDefinition args));
342 serverOn = sys: version: serverExe
343 (projectOut sys).ghc.backend
344 (projectOut system).ghcjs.frontend
345 (projectOut sys).passthru.staticFiles
346 (projectOut sys).passthru.__closureCompilerOptimizationLevel
348 linuxExe = serverOn "x86_64-linux";
349 dummyVersion = "Version number is only available for deployments";
350 in projectOut system // {
351 linuxExeConfigurable = linuxExe;
352 linuxExe = linuxExe dummyVersion;
353 exe = serverOn system dummyVersion;
354 server = args@{ hostName, adminEmail, routeHost, enableHttps, version }:
355 server (args // { exe = linuxExe version; });
356 obelisk = import (base + "/.obelisk/impl") {};
358 haskellPackageSets = {
359 inherit (reflex-platform) ghc ghcjs;
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list