52 src = fetchFromGitHub {
56 sha256 = "sha256-FaPcUta5z/8oasw+9zGBRZnUVYD8eCo1t/XwwsFoSM8=";
62 # For backups, themes and assets
71 # Misc required system utils
73 procps # For ps and kill
74 util-linux # For renice
76 nettools # For hostname
91 HOME = "/run/discourse/home";
92 RAILS_ENV = "production";
93 UNICORN_LISTENER = "/run/discourse/sockets/unicorn.sock";
101 , bundlerEnvArgs ? {}
102 , preserveGemsDir ? false
107 rubyEnv = bundlerEnv (bundlerEnvArgs // {
108 inherit name pname version ruby;
111 stdenv.mkDerivation (builtins.removeAttrs args [ "bundlerEnvArgs" ] // {
112 pluginName = if name != null then name else "${pname}-${version}";
113 dontConfigure = true;
119 '' + lib.optionalString (bundlerEnvArgs != {}) (
120 if preserveGemsDir then ''
121 cp -r ${rubyEnv}/lib/ruby/gems/* $out/gems/
124 if [[ -e $out/gems ]]; then
125 echo "Warning: The repo contains a 'gems' directory which will be removed!"
126 echo " If you need to preserve it, set 'preserveGemsDir = true'."
129 ln -sf ${rubyEnv}/lib/ruby/gems $out/gems
135 rake = runCommand "discourse-rake" {
136 nativeBuildInputs = [ makeWrapper ];
139 makeWrapper ${rubyEnv}/bin/rake $out/bin/discourse-rake \
140 ${lib.concatStrings (lib.mapAttrsToList (name: value: "--set ${name} '${value}' ") runtimeEnv)} \
141 --prefix PATH : ${lib.makeBinPath runtimeDeps} \
142 --set RAKEOPT '-f ${discourse}/share/discourse/Rakefile' \
143 --chdir '${discourse}/share/discourse'
146 rubyEnv = bundlerEnv {
147 name = "discourse-ruby-env-${version}";
148 inherit version ruby;
152 gems = import ./rubyEnv/gemset.nix;
155 mini_racer = gems.mini_racer // {
156 buildInputs = [ icu ];
158 NIX_LDFLAGS = "-licui18n";
162 noopScript = writeShellScript "noop" "exit 0";
163 linkFiles = writeShellScript "link-files" ''
166 mkdir -p vendor/v8/${stdenv.hostPlatform.system}/libv8/obj/
167 ln -s "${nodejs_18.libv8}/lib/libv8.a" vendor/v8/${stdenv.hostPlatform.system}/libv8/obj/libv8_monolith.a
169 ln -s ${nodejs_18.libv8}/include vendor/v8/include
171 mkdir -p ext/libv8-node
172 echo '--- !ruby/object:Libv8::Node::Location::Vendor {}' >ext/libv8-node/.location.yml
174 in gems.libv8-node // {
177 cp ${noopScript} libexec/build-libv8
178 cp ${noopScript} libexec/build-monolith
179 cp ${noopScript} libexec/download-node
180 cp ${noopScript} libexec/extract-node
181 cp ${linkFiles} libexec/inject-libv8
184 mini_suffix = gems.mini_suffix // {
185 propagatedBuildInputs = [ libpsl ];
187 # Use our libpsl instead of the vendored one, which isn't
188 # available for aarch64. It has to be called
189 # libpsl.x86_64.so or it isn't found.
191 cp $(readlink -f ${lib.getLib libpsl}/lib/libpsl.so) vendor/libpsl.x86_64.so
197 "default" "assets" "development" "test"
201 assets = stdenv.mkDerivation {
202 pname = "discourse-assets";
205 yarnOfflineCache = fetchYarnDeps {
206 yarnLock = src + "/yarn.lock";
207 hash = "sha256-cSQofaULCmPuWGxS+hK4KlRq9lSkCPiYvhax9X6Dor8=";
210 nativeBuildInputs = runtimeDeps ++ [
221 outputs = [ "out" "javascripts" "node_modules" ];
224 # Use the Ruby API version in the plugin gem path, to match the
225 # one constructed by bundlerEnv
226 ./plugin_gem_api_version.patch
228 # Change the path to the auto generated plugin assets, which
229 # defaults to the plugin's directory and isn't writable at the
230 # time of asset generation
231 ./auto_generated_path.patch
233 # Fix the rake command used to recursively execute itself in the
234 # assets precompilation task.
235 ./assets_rake_command.patch
237 # Little does he know, so he decided there is no need to generate the
238 # theme-transpiler over and over again. Which at the same time allows the removal
239 # of javascript devDependencies from the runtime environment.
240 ./prebuild-theme-transpiler.patch
243 env.RAILS_ENV = "production";
245 # We have to set up an environment that is close enough to
246 # production ready or the assets:precompile task refuses to
247 # run. This means that Redis and PostgreSQL has to be running and
248 # database migrations performed.
250 # Yarn wants a real home directory to write cache, config, etc to
251 export HOME=$NIX_BUILD_TOP/fake_home
254 local offlineCache=$1 yarnLock=$2
256 # Make yarn install packages from our offline cache, not the registry
257 yarn config --offline set yarn-offline-mirror $offlineCache
259 # Fixup "resolved"-entries in yarn.lock to match our offline cache
260 fixup-yarn-lock $yarnLock
262 # Install while ignoring hook scripts
263 yarn --offline --ignore-scripts --cwd $(dirname $yarnLock) install
266 # Install runtime and devDependencies.
267 # The dev deps are necessary for generating the theme-transpiler executed as dependent task
268 # assets:precompile:theme_transpiler before db:migrate and unfortunately also in the runtime
269 yarn_install $yarnOfflineCache yarn.lock
271 # Patch before running postinstall hook script
272 patchShebangs node_modules/
273 patchShebangs --build app/assets/javascripts
274 yarn --offline --cwd app/assets/javascripts run postinstall
275 export SSL_CERT_FILE=${cacert}/etc/ssl/certs/ca-bundle.crt
277 redis-server >/dev/null &
279 initdb -A trust $NIX_BUILD_TOP/postgres >/dev/null
280 postgres -D $NIX_BUILD_TOP/postgres -k $NIX_BUILD_TOP >/dev/null &
281 export PGHOST=$NIX_BUILD_TOP
283 echo "Waiting for Redis and PostgreSQL to be ready.."
284 while ! redis-cli --scan >/dev/null || ! psql -l >/dev/null; do
288 psql -d postgres -tAc 'CREATE USER "discourse"'
289 psql -d postgres -tAc 'CREATE DATABASE "discourse" OWNER "discourse"'
290 psql 'discourse' -tAc "CREATE EXTENSION IF NOT EXISTS pg_trgm"
291 psql 'discourse' -tAc "CREATE EXTENSION IF NOT EXISTS hstore"
293 ${lib.concatMapStringsSep "\n" (p: "ln -sf ${p} plugins/${p.pluginName or ""}") plugins}
295 bundle exec rake db:migrate >/dev/null
302 bundle exec rake assets:precompile
310 mv public/assets $out
312 mv node_modules $node_modules
314 rm -r app/assets/javascripts/plugins
315 mv app/assets/javascripts $javascripts
316 ln -sf /run/discourse/assets/javascripts/plugins $javascripts/plugins
322 discourse = stdenv.mkDerivation {
327 rubyEnv rubyEnv.wrappedRuby rubyEnv.bundler
331 # Load a separate NixOS site settings file
332 ./nixos_defaults.patch
334 # Add a noninteractive admin creation task
337 # Add the path to the CA cert bundle to make TLS work
338 ./action_mailer_ca_cert.patch
340 # Log Unicorn messages to the journal and make request timeout
342 ./unicorn_logging_and_timeout.patch
344 # Use the Ruby API version in the plugin gem path, to match the
345 # one constructed by bundlerEnv
346 ./plugin_gem_api_version.patch
348 # Change the path to the auto generated plugin assets, which
349 # defaults to the plugin's directory and isn't writable at the
350 # time of asset generation
351 ./auto_generated_path.patch
353 # Make sure the notification email setting applies
354 ./notification_email.patch
356 # Little does he know, so he decided there is no need to generate the
357 # theme-transpiler over and over again. Which at the same time allows the removal
358 # of javascript devDependencies from the runtime environment.
359 ./prebuild-theme-transpiler.patch
363 # Always require lib-files and application.rb through their store
364 # path, not their relative state directory path. This gets rid of
365 # warnings and means we don't have to link back to lib from the
367 find config -type f -name "*.rb" -execdir \
368 sed -Ei "s,(\.\./)+(lib|app)/,$out/share/discourse/\2/," {} \;
369 find config -maxdepth 1 -type f -name "*.rb" -execdir \
370 sed -Ei "s,require_relative (\"|')([[:alnum:]].*)(\"|'),require_relative '$out/share/discourse/config/\2'," {} \;
376 mv config config.dist
377 mv public public.dist
386 cp -r . $out/share/discourse
387 rm -r $out/share/discourse/log
388 ln -sf /var/log/discourse $out/share/discourse/log
389 ln -sf /var/lib/discourse/tmp $out/share/discourse/tmp
390 ln -sf /run/discourse/config $out/share/discourse/config
391 ln -sf /run/discourse/public $out/share/discourse/public
392 # This needs to be copied because of symlinks in node_modules
393 # Also this needs to be full node_modules (including dev deps) because without loader.js it just throws 500
394 cp -r ${assets.node_modules} $out/share/discourse/node_modules
395 ln -sf ${assets} $out/share/discourse/public.dist/assets
396 rm -r $out/share/discourse/app/assets/javascripts
397 ln -sf ${assets.javascripts} $out/share/discourse/app/assets/javascripts
398 ${lib.concatMapStringsSep "\n" (p: "ln -sf ${p} $out/share/discourse/plugins/${p.pluginName or ""}") plugins}
404 homepage = "https://www.discourse.org/";
405 platforms = platforms.linux;
406 maintainers = with maintainers; [ talyz ];
407 license = licenses.gpl2Plus;
408 description = "Discourse is an open source discussion platform";
412 inherit rubyEnv runtimeEnv runtimeDeps rake mkDiscoursePlugin assets;
416 enabledPlugins = plugins;
417 plugins = callPackage ./plugins/all-plugins.nix { inherit mkDiscoursePlugin; };
418 ruby = rubyEnv.wrappedRuby;
419 tests = import ../../../../nixos/tests/discourse.nix {
420 inherit (stdenv) system;
422 package = pkgs.discourse.override args;