@@ -111,61 +111,117 @@ rec {
111111 touch "$out"
112112 obelisk-asset-manifest-generate "$src" "$haskellManifest" ${packageName} ${moduleName} "$symlinked"
113113 '';
114− # An Obelisk project is a reflex-platform project with a predefined layout and role for each component
115− project = base: projectDefinition: reflex-platform.project (args@{ nixpkgs, ... }:
116− let mkProject = { android ? null #TODO: Better error when missing
117− , ios ? null #TODO: Better error when missing
118− , packages ? {}
119− , overrides ? _: _: {}
120− }:
121− let frontendName = "frontend";
122− backendName = "backend";
123− commonName = "common";
124− staticName = "static";
125− staticPath = base + "/static";
126− assets = processAssets { src = base + "/static"; };
127− # The packages whose names and roles are defined by this package
128− predefinedPackages = filterAttrs (_: x: x != null) {
129− ${frontendName} = nullIfAbsent (base + "/frontend");
130− ${commonName} = nullIfAbsent (base + "/common");
131− ${backendName} = nullIfAbsent (base + "/backend");
132− };
133− combinedPackages = predefinedPackages // packages;
134− projectOverrides = self: super: {
135− ${staticName} = dontHaddock (self.callCabal2nix "static" assets.haskellManifest {});
136− frontend = if self.ghc.isGhcjs then super.frontend.override { obelisk-run-frontend = null; } else super.frontend;
137− };
138− totalOverrides = composeExtensions (composeExtensions defaultHaskellOverrides projectOverrides) overrides;
139− ghcDevPackages = ["obelisk-run-frontend"];
140− in {
141− overrides = totalOverrides;
142− packages = combinedPackages;
143− shells = {
144− ghc = (filter (x: hasAttr x combinedPackages) [
145− backendName
146− commonName
147− frontendName
148− ]);
149− ghcjs = filter (x: hasAttr x combinedPackages) [
150− frontendName
151− commonName
152− ];
153− };
154− withHoogle = false; # Setting this to `true` makes shell reloading far slower
155− android = {
156− ${if android == null then null else frontendName} = {
157− executableName = "frontend";
158− ${if builtins.pathExists staticPath then "assets" else null} = assets.symlinked;
159− } // android;
160− };
161− ios = {
162− ${if ios == null then null else frontendName} = {
163− executableName = "frontend";
164− ${if builtins.pathExists staticPath then "staticSrc" else null} = assets.symlinked;
165− } // ios;
114+ serverExe = backend: frontend: assets: config:
115+ pkgs.runCommand "serverExe" {} ''
116+ mkdir $out
117+ set -eux
118+ ln -s "${backend}"/bin/backend $out/backend
119+ ln -s ${frontend}/bin/frontend.jsexe $out/frontend.jsexe
120+ ln -s "${assets}" $out/static
121+ ln -s "${config}" $out/config
122+ '';
123+ server = exe: hostName:
124+ let system = "x86_64-linux";
125+ nixos = import (pkgs.path + /nixos);
126+ in nixos {
127+ inherit system;
128+ configuration = args: {
129+ imports = [
130+ (pkgs.path + /nixos/modules/virtualisation/amazon-image.nix)
131+ ];
132+ networking = { inherit hostName; };
133+ systemd.services.backend = {
134+ wantedBy = [ "multi-user-target" ];
135+ after = [ "network.target" ];
136+ restartIfChanged = true;
137+ script = ''
138+ ln -sft . "${exe}"/*
139+ mkdir -p log
140+ exec ./backend >>backend.out 2>>backend.err </dev/null
141+ '';
142+ serviceConfig = {
143+ User = "backend";
144+ KillMode = "process";
145+ WorkingDirectory = "~";
146+ Restart = "always";
147+ RestartSec = 5;
166148 };
167149 };
168− in mkProject (projectDefinition args));
150+ users.extraUsers.backend = {
151+ description = "backend service";
152+ home = "/var/lib/backend";
153+ createHome = true;
154+ isSystemUser = true;
155+ group = "backend";
156+ };
157+ ec2.hvm = true;
158+ };
159+ };
160+
161+
162+ # An Obelisk project is a reflex-platform project with a predefined layout and role for each component
163+ project = base: projectDefinition:
164+ let assets = processAssets { src = base + "/static"; };
165+ configPath = base + "/config";
166+ projectOut = reflex-platform.project (args@{ nixpkgs, ... }:
167+ let mkProject = { android ? null #TODO: Better error when missing
168+ , ios ? null #TODO: Better error when missing
169+ , packages ? {}
170+ , overrides ? _: _: {}
171+ }:
172+ let frontendName = "frontend";
173+ backendName = "backend";
174+ commonName = "common";
175+ staticName = "static";
176+ staticPath = base + "/static";
177+ assets = processAssets { src = base + "/static"; };
178+ # The packages whose names and roles are defined by this package
179+ predefinedPackages = filterAttrs (_: x: x != null) {
180+ ${frontendName} = nullIfAbsent (base + "/frontend");
181+ ${commonName} = nullIfAbsent (base + "/common");
182+ ${backendName} = nullIfAbsent (base + "/backend");
183+ };
184+ combinedPackages = predefinedPackages // packages;
185+ projectOverrides = self: super: {
186+ ${staticName} = dontHaddock (self.callCabal2nix "static" assets.haskellManifest {});
187+ frontend = if self.ghc.isGhcjs then super.frontend.override { obelisk-run-frontend = null; } else super.frontend;
188+ };
189+ totalOverrides = composeExtensions (composeExtensions defaultHaskellOverrides projectOverrides) overrides;
190+ ghcDevPackages = ["obelisk-run-frontend"];
191+ in {
192+ overrides = totalOverrides;
193+ packages = combinedPackages;
194+ shells = {
195+ ghc = (filter (x: hasAttr x combinedPackages) [
196+ backendName
197+ commonName
198+ frontendName
199+ ]);
200+ ghcjs = filter (x: hasAttr x combinedPackages) [
201+ frontendName
202+ commonName
203+ ];
204+ };
205+ withHoogle = false; # Setting this to `true` makes shell reloading far slower
206+ android = {
207+ ${if android == null then null else frontendName} = {
208+ executableName = "frontend";
209+ ${if builtins.pathExists staticPath then "assets" else null} = assets.symlinked;
210+ } // android;
211+ };
212+ ios = {
213+ ${if ios == null then null else frontendName} = {
214+ executableName = "frontend";
215+ ${if builtins.pathExists staticPath then "staticSrc" else null} = assets.symlinked;
216+ } // ios;
217+ };
218+ };
219+ in mkProject (projectDefinition args));
220+ in projectOut //
221+ { server = { hostName }:
222+ let exe = serverExe projectOut.ghc.backend projectOut.ghcjs.frontend assets.symlinked configPath;
223+ in server exe hostName;
224+ };
169225 haskellPackageSets = {
170226 ghc = reflex-platform.ghc.override {
171227 overrides = defaultHaskellOverrides;