ae77e2fb78
The system attribute is otherwise deduced from the system the evaluation runs on, which could be incorrect if using remote builders.
323 lines
9.5 KiB
Nix
323 lines
9.5 KiB
Nix
{ stdenv, pkgs, makeWrapper, runCommand, lib, writeShellScript
|
|
, fetchFromGitHub, bundlerEnv, callPackage
|
|
|
|
, ruby, replace, gzip, gnutar, git, cacert, util-linux, gawk, nettools
|
|
, imagemagick, optipng, pngquant, libjpeg, jpegoptim, gifsicle, jhead
|
|
, libpsl, redis, postgresql, which, brotli, procps, rsync, icu
|
|
, nodePackages, nodejs-16_x
|
|
|
|
, plugins ? []
|
|
}@args:
|
|
|
|
let
|
|
version = "2.8.0.beta10";
|
|
|
|
src = fetchFromGitHub {
|
|
owner = "discourse";
|
|
repo = "discourse";
|
|
rev = "v${version}";
|
|
sha256 = "sha256-mlTOsHR8p0mTdhZHBESyDAa1XtMJ4uIht0VUcGD6Ses=";
|
|
};
|
|
|
|
runtimeDeps = [
|
|
# For backups, themes and assets
|
|
rubyEnv.wrappedRuby
|
|
rsync
|
|
gzip
|
|
gnutar
|
|
git
|
|
brotli
|
|
|
|
# Misc required system utils
|
|
which
|
|
procps # For ps and kill
|
|
util-linux # For renice
|
|
gawk
|
|
nettools # For hostname
|
|
|
|
# Image optimization
|
|
imagemagick
|
|
optipng
|
|
pngquant
|
|
libjpeg
|
|
jpegoptim
|
|
gifsicle
|
|
nodePackages.svgo
|
|
jhead
|
|
];
|
|
|
|
runtimeEnv = {
|
|
HOME = "/run/discourse/home";
|
|
RAILS_ENV = "production";
|
|
UNICORN_LISTENER = "/run/discourse/sockets/unicorn.sock";
|
|
};
|
|
|
|
mkDiscoursePlugin =
|
|
{ name ? null
|
|
, pname ? null
|
|
, version ? null
|
|
, meta ? null
|
|
, bundlerEnvArgs ? {}
|
|
, preserveGemsDir ? false
|
|
, src
|
|
, ...
|
|
}@args:
|
|
let
|
|
rubyEnv = bundlerEnv (bundlerEnvArgs // {
|
|
inherit name pname version ruby;
|
|
});
|
|
in
|
|
stdenv.mkDerivation (builtins.removeAttrs args [ "bundlerEnvArgs" ] // {
|
|
pluginName = if name != null then name else "${pname}-${version}";
|
|
dontConfigure = true;
|
|
dontBuild = true;
|
|
installPhase = ''
|
|
runHook preInstall
|
|
mkdir -p $out
|
|
cp -r * $out/
|
|
'' + lib.optionalString (bundlerEnvArgs != {}) (
|
|
if preserveGemsDir then ''
|
|
cp -r ${rubyEnv}/lib/ruby/gems/* $out/gems/
|
|
''
|
|
else ''
|
|
if [[ -e $out/gems ]]; then
|
|
echo "Warning: The repo contains a 'gems' directory which will be removed!"
|
|
echo " If you need to preserve it, set 'preserveGemsDir = true'."
|
|
rm -r $out/gems
|
|
fi
|
|
ln -sf ${rubyEnv}/lib/ruby/gems $out/gems
|
|
'' + ''
|
|
runHook postInstall
|
|
'');
|
|
});
|
|
|
|
rake = runCommand "discourse-rake" {
|
|
nativeBuildInputs = [ makeWrapper ];
|
|
} ''
|
|
mkdir -p $out/bin
|
|
makeWrapper ${rubyEnv}/bin/rake $out/bin/discourse-rake \
|
|
${lib.concatStrings (lib.mapAttrsToList (name: value: "--set ${name} '${value}' ") runtimeEnv)} \
|
|
--prefix PATH : ${lib.makeBinPath runtimeDeps} \
|
|
--set RAKEOPT '-f ${discourse}/share/discourse/Rakefile' \
|
|
--run 'cd ${discourse}/share/discourse'
|
|
'';
|
|
|
|
rubyEnv = bundlerEnv {
|
|
name = "discourse-ruby-env-${version}";
|
|
inherit version ruby;
|
|
gemdir = ./rubyEnv;
|
|
gemset =
|
|
let
|
|
gems = import ./rubyEnv/gemset.nix;
|
|
in
|
|
gems // {
|
|
mini_racer = gems.mini_racer // {
|
|
buildInputs = [ icu ];
|
|
dontBuild = false;
|
|
NIX_LDFLAGS = "-licui18n";
|
|
};
|
|
libv8-node =
|
|
let
|
|
noopScript = writeShellScript "noop" "exit 0";
|
|
linkFiles = writeShellScript "link-files" ''
|
|
cd ../..
|
|
|
|
mkdir -p vendor/v8/${stdenv.hostPlatform.system}/libv8/obj/
|
|
ln -s "${nodejs-16_x.libv8}/lib/libv8.a" vendor/v8/${stdenv.hostPlatform.system}/libv8/obj/libv8_monolith.a
|
|
|
|
ln -s ${nodejs-16_x.libv8}/include vendor/v8/include
|
|
|
|
mkdir -p ext/libv8-node
|
|
echo '--- !ruby/object:Libv8::Node::Location::Vendor {}' >ext/libv8-node/.location.yml
|
|
'';
|
|
in gems.libv8-node // {
|
|
dontBuild = false;
|
|
postPatch = ''
|
|
cp ${noopScript} libexec/build-libv8
|
|
cp ${noopScript} libexec/build-monolith
|
|
cp ${noopScript} libexec/download-node
|
|
cp ${noopScript} libexec/extract-node
|
|
cp ${linkFiles} libexec/inject-libv8
|
|
'';
|
|
};
|
|
mini_suffix = gems.mini_suffix // {
|
|
propagatedBuildInputs = [ libpsl ];
|
|
dontBuild = false;
|
|
# Use our libpsl instead of the vendored one, which isn't
|
|
# available for aarch64. It has to be called
|
|
# libpsl.x86_64.so or it isn't found.
|
|
postPatch = ''
|
|
cp $(readlink -f ${libpsl}/lib/libpsl.so) vendor/libpsl.x86_64.so
|
|
'';
|
|
};
|
|
};
|
|
|
|
groups = [
|
|
"default" "assets" "development" "test"
|
|
];
|
|
};
|
|
|
|
assets = stdenv.mkDerivation {
|
|
pname = "discourse-assets";
|
|
inherit version src;
|
|
|
|
nativeBuildInputs = runtimeDeps ++ [
|
|
postgresql
|
|
redis
|
|
nodePackages.uglify-js
|
|
nodePackages.terser
|
|
];
|
|
|
|
patches = [
|
|
# Use the Ruby API version in the plugin gem path, to match the
|
|
# one constructed by bundlerEnv
|
|
./plugin_gem_api_version.patch
|
|
|
|
# Change the path to the auto generated plugin assets, which
|
|
# defaults to the plugin's directory and isn't writable at the
|
|
# time of asset generation
|
|
./auto_generated_path.patch
|
|
];
|
|
|
|
# We have to set up an environment that is close enough to
|
|
# production ready or the assets:precompile task refuses to
|
|
# run. This means that Redis and PostgreSQL has to be running and
|
|
# database migrations performed.
|
|
preBuild = ''
|
|
export SSL_CERT_FILE=${cacert}/etc/ssl/certs/ca-bundle.crt
|
|
|
|
redis-server >/dev/null &
|
|
|
|
initdb -A trust $NIX_BUILD_TOP/postgres >/dev/null
|
|
postgres -D $NIX_BUILD_TOP/postgres -k $NIX_BUILD_TOP >/dev/null &
|
|
export PGHOST=$NIX_BUILD_TOP
|
|
|
|
echo "Waiting for Redis and PostgreSQL to be ready.."
|
|
while ! redis-cli --scan >/dev/null || ! psql -l >/dev/null; do
|
|
sleep 0.1
|
|
done
|
|
|
|
psql -d postgres -tAc 'CREATE USER "discourse"'
|
|
psql -d postgres -tAc 'CREATE DATABASE "discourse" OWNER "discourse"'
|
|
psql 'discourse' -tAc "CREATE EXTENSION IF NOT EXISTS pg_trgm"
|
|
psql 'discourse' -tAc "CREATE EXTENSION IF NOT EXISTS hstore"
|
|
|
|
# Create a temporary home dir to stop bundler from complaining
|
|
mkdir $NIX_BUILD_TOP/tmp_home
|
|
export HOME=$NIX_BUILD_TOP/tmp_home
|
|
|
|
${lib.concatMapStringsSep "\n" (p: "ln -sf ${p} plugins/${p.pluginName or ""}") plugins}
|
|
|
|
export RAILS_ENV=production
|
|
|
|
bundle exec rake db:migrate >/dev/null
|
|
rm -r tmp/*
|
|
'';
|
|
|
|
buildPhase = ''
|
|
runHook preBuild
|
|
|
|
bundle exec rake assets:precompile
|
|
|
|
runHook postBuild
|
|
'';
|
|
|
|
installPhase = ''
|
|
runHook preInstall
|
|
|
|
mv public/assets $out
|
|
|
|
runHook postInstall
|
|
'';
|
|
};
|
|
|
|
discourse = stdenv.mkDerivation {
|
|
pname = "discourse";
|
|
inherit version src;
|
|
|
|
buildInputs = [
|
|
rubyEnv rubyEnv.wrappedRuby rubyEnv.bundler
|
|
];
|
|
|
|
patches = [
|
|
# Load a separate NixOS site settings file
|
|
./nixos_defaults.patch
|
|
|
|
# Add a noninteractive admin creation task
|
|
./admin_create.patch
|
|
|
|
# Add the path to the CA cert bundle to make TLS work
|
|
./action_mailer_ca_cert.patch
|
|
|
|
# Log Unicorn messages to the journal and make request timeout
|
|
# configurable
|
|
./unicorn_logging_and_timeout.patch
|
|
|
|
# Use the Ruby API version in the plugin gem path, to match the
|
|
# one constructed by bundlerEnv
|
|
./plugin_gem_api_version.patch
|
|
|
|
# Change the path to the auto generated plugin assets, which
|
|
# defaults to the plugin's directory and isn't writable at the
|
|
# time of asset generation
|
|
./auto_generated_path.patch
|
|
|
|
# Make sure the notification email setting applies
|
|
./notification_email.patch
|
|
];
|
|
|
|
postPatch = ''
|
|
# Always require lib-files and application.rb through their store
|
|
# path, not their relative state directory path. This gets rid of
|
|
# warnings and means we don't have to link back to lib from the
|
|
# state directory.
|
|
find config -type f -execdir sed -Ei "s,(\.\./)+(lib|app)/,$out/share/discourse/\2/," {} \;
|
|
'';
|
|
|
|
buildPhase = ''
|
|
runHook preBuild
|
|
|
|
mv config config.dist
|
|
mv public public.dist
|
|
|
|
runHook postBuild
|
|
'';
|
|
|
|
installPhase = ''
|
|
runHook preInstall
|
|
|
|
mkdir -p $out/share
|
|
cp -r . $out/share/discourse
|
|
rm -r $out/share/discourse/log
|
|
ln -sf /var/log/discourse $out/share/discourse/log
|
|
ln -sf /var/lib/discourse/tmp $out/share/discourse/tmp
|
|
ln -sf /run/discourse/config $out/share/discourse/config
|
|
ln -sf /run/discourse/assets/javascripts/plugins $out/share/discourse/app/assets/javascripts/plugins
|
|
ln -sf /run/discourse/public $out/share/discourse/public
|
|
ln -sf ${assets} $out/share/discourse/public.dist/assets
|
|
${lib.concatMapStringsSep "\n" (p: "ln -sf ${p} $out/share/discourse/plugins/${p.pluginName or ""}") plugins}
|
|
|
|
runHook postInstall
|
|
'';
|
|
|
|
meta = with lib; {
|
|
homepage = "https://www.discourse.org/";
|
|
platforms = platforms.linux;
|
|
maintainers = with maintainers; [ talyz ];
|
|
license = licenses.gpl2Plus;
|
|
description = "Discourse is an open source discussion platform";
|
|
};
|
|
|
|
passthru = {
|
|
inherit rubyEnv runtimeEnv runtimeDeps rake mkDiscoursePlugin;
|
|
enabledPlugins = plugins;
|
|
plugins = callPackage ./plugins/all-plugins.nix { inherit mkDiscoursePlugin; };
|
|
ruby = rubyEnv.wrappedRuby;
|
|
tests = import ../../../../nixos/tests/discourse.nix {
|
|
inherit (stdenv) system;
|
|
inherit pkgs;
|
|
package = pkgs.discourse.override args;
|
|
};
|
|
};
|
|
};
|
|
in discourse
|