2021-08-12 12:34:14 +02:00
|
|
|
{ stdenv, pkgs, makeWrapper, runCommand, lib, writeShellScript
|
2021-06-24 19:45:37 +02:00
|
|
|
, fetchFromGitHub, bundlerEnv, callPackage
|
|
|
|
|
|
|
|
, ruby, replace, gzip, gnutar, git, cacert, util-linux, gawk
|
|
|
|
, imagemagick, optipng, pngquant, libjpeg, jpegoptim, gifsicle, libpsl
|
|
|
|
, redis, postgresql, which, brotli, procps, rsync, nodePackages, v8
|
2021-06-23 18:15:14 +02:00
|
|
|
|
|
|
|
, plugins ? []
|
2021-08-12 12:34:14 +02:00
|
|
|
}@args:
|
2021-03-12 12:58:31 +01:00
|
|
|
|
|
|
|
let
|
2021-08-12 12:26:41 +02:00
|
|
|
version = "2.7.7";
|
2021-03-12 12:58:31 +01:00
|
|
|
|
|
|
|
src = fetchFromGitHub {
|
|
|
|
owner = "discourse";
|
|
|
|
repo = "discourse";
|
|
|
|
rev = "v${version}";
|
2021-08-12 12:26:41 +02:00
|
|
|
sha256 = "sha256-rhcTQyirgPX0ITjgotJAYLLSU957GanxAYYhy9j123U=";
|
2021-03-12 12:58:31 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
runtimeDeps = [
|
|
|
|
# For backups, themes and assets
|
|
|
|
rubyEnv.wrappedRuby
|
2021-05-27 06:05:00 +02:00
|
|
|
rsync
|
2021-03-12 12:58:31 +01:00
|
|
|
gzip
|
|
|
|
gnutar
|
|
|
|
git
|
|
|
|
brotli
|
|
|
|
|
|
|
|
# Misc required system utils
|
|
|
|
which
|
|
|
|
procps # For ps and kill
|
|
|
|
util-linux # For renice
|
|
|
|
gawk
|
|
|
|
|
|
|
|
# Image optimization
|
|
|
|
imagemagick
|
|
|
|
optipng
|
|
|
|
pngquant
|
|
|
|
libjpeg
|
|
|
|
jpegoptim
|
|
|
|
gifsicle
|
|
|
|
nodePackages.svgo
|
|
|
|
];
|
|
|
|
|
|
|
|
runtimeEnv = {
|
|
|
|
HOME = "/run/discourse/home";
|
|
|
|
RAILS_ENV = "production";
|
|
|
|
UNICORN_LISTENER = "/run/discourse/sockets/unicorn.sock";
|
|
|
|
};
|
|
|
|
|
2021-06-24 19:45:37 +02:00
|
|
|
mkDiscoursePlugin =
|
|
|
|
{ name ? null
|
|
|
|
, pname ? null
|
|
|
|
, version ? null
|
|
|
|
, meta ? null
|
|
|
|
, bundlerEnvArgs ? {}
|
2021-08-13 18:53:18 +02:00
|
|
|
, preserveGemsDir ? false
|
2021-06-24 19:45:37 +02:00
|
|
|
, 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}";
|
2021-07-22 18:06:55 +02:00
|
|
|
dontConfigure = true;
|
|
|
|
dontBuild = true;
|
2021-06-24 19:45:37 +02:00
|
|
|
installPhase = ''
|
|
|
|
runHook preInstall
|
|
|
|
mkdir -p $out
|
|
|
|
cp -r * $out/
|
2021-08-13 18:53:18 +02:00
|
|
|
'' + 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
|
|
|
|
'' + ''
|
2021-06-24 19:45:37 +02:00
|
|
|
runHook postInstall
|
2021-08-13 18:53:18 +02:00
|
|
|
'');
|
2021-06-24 19:45:37 +02:00
|
|
|
});
|
|
|
|
|
2021-08-15 17:12:23 +02:00
|
|
|
rake = runCommand "discourse-rake" {
|
2021-03-12 12:58:31 +01:00
|
|
|
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 // {
|
2021-05-25 23:16:44 +02:00
|
|
|
libv8-node =
|
|
|
|
let
|
|
|
|
noopScript = writeShellScript "noop" "exit 0";
|
|
|
|
linkFiles = writeShellScript "link-files" ''
|
|
|
|
cd ../..
|
|
|
|
|
|
|
|
mkdir -p vendor/v8/out.gn/libv8/obj/
|
|
|
|
ln -s "${v8}/lib/libv8.a" vendor/v8/out.gn/libv8/obj/libv8_monolith.a
|
|
|
|
|
|
|
|
ln -s ${v8}/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
|
|
|
|
'';
|
|
|
|
};
|
2021-03-12 12:58:31 +01:00
|
|
|
mini_suffix = gems.mini_suffix // {
|
|
|
|
propagatedBuildInputs = [ libpsl ];
|
|
|
|
dontBuild = false;
|
|
|
|
# Use our libpsl instead of the vendored one, which isn't
|
2021-05-25 23:16:44 +02:00
|
|
|
# available for aarch64. It has to be called
|
|
|
|
# libpsl.x86_64.so or it isn't found.
|
2021-03-12 12:58:31 +01:00
|
|
|
postPatch = ''
|
2021-05-25 23:16:44 +02:00
|
|
|
cp $(readlink -f ${libpsl}/lib/libpsl.so) vendor/libpsl.x86_64.so
|
2021-03-12 12:58:31 +01:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
groups = [
|
|
|
|
"default" "assets" "development" "test"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
|
|
|
|
assets = stdenv.mkDerivation {
|
|
|
|
pname = "discourse-assets";
|
|
|
|
inherit version src;
|
|
|
|
|
|
|
|
nativeBuildInputs = [
|
|
|
|
rubyEnv.wrappedRuby
|
|
|
|
postgresql
|
|
|
|
redis
|
|
|
|
which
|
|
|
|
brotli
|
|
|
|
procps
|
|
|
|
nodePackages.uglify-js
|
2021-07-09 16:35:35 +02:00
|
|
|
nodePackages.terser
|
2021-03-12 12:58:31 +01:00
|
|
|
];
|
|
|
|
|
2021-06-24 19:45:37 +02:00
|
|
|
patches = [
|
|
|
|
# Use the Ruby API version in the plugin gem path, to match the
|
|
|
|
# one constructed by bundlerEnv
|
|
|
|
./plugin_gem_api_version.patch
|
2021-08-12 12:37:33 +02:00
|
|
|
|
|
|
|
# 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
|
2021-06-24 19:45:37 +02:00
|
|
|
];
|
|
|
|
|
2021-03-12 12:58:31 +01:00
|
|
|
# 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 = ''
|
2021-05-25 23:16:44 +02:00
|
|
|
export SSL_CERT_FILE=${cacert}/etc/ssl/certs/ca-bundle.crt
|
|
|
|
|
2021-03-12 12:58:31 +01:00
|
|
|
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
|
|
|
|
|
2021-06-24 19:45:37 +02:00
|
|
|
${lib.concatMapStringsSep "\n" (p: "ln -sf ${p} plugins/${p.pluginName or ""}") plugins}
|
2021-06-23 18:15:14 +02:00
|
|
|
|
2021-03-12 12:58:31 +01:00
|
|
|
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
|
|
|
|
|
|
|
|
# Disable jhead, which is currently marked as vulnerable
|
|
|
|
./disable_jhead.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
|
2021-06-24 19:34:38 +02:00
|
|
|
|
2021-06-24 19:45:37 +02:00
|
|
|
# Use the Ruby API version in the plugin gem path, to match the
|
|
|
|
# one constructed by bundlerEnv
|
|
|
|
./plugin_gem_api_version.patch
|
|
|
|
|
2021-06-24 19:34:38 +02:00
|
|
|
# Use mv instead of rename, since rename doesn't work across
|
|
|
|
# device boundaries
|
|
|
|
./use_mv_instead_of_rename.patch
|
2021-08-12 12:37:33 +02:00
|
|
|
|
|
|
|
# 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
|
2021-03-12 12:58:31 +01:00
|
|
|
];
|
|
|
|
|
|
|
|
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
|
2021-09-23 17:22:53 +02:00
|
|
|
ln -sf /var/lib/discourse/tmp $out/share/discourse/tmp
|
2021-03-12 12:58:31 +01:00
|
|
|
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
|
2021-06-24 19:45:37 +02:00
|
|
|
${lib.concatMapStringsSep "\n" (p: "ln -sf ${p} $out/share/discourse/plugins/${p.pluginName or ""}") plugins}
|
2021-03-12 12:58:31 +01:00
|
|
|
|
|
|
|
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 = {
|
2021-06-24 19:45:37 +02:00
|
|
|
inherit rubyEnv runtimeEnv runtimeDeps rake mkDiscoursePlugin;
|
2021-06-23 18:15:14 +02:00
|
|
|
enabledPlugins = plugins;
|
2021-06-24 19:45:37 +02:00
|
|
|
plugins = callPackage ./plugins/all-plugins.nix { inherit mkDiscoursePlugin; };
|
2021-03-12 12:58:31 +01:00
|
|
|
ruby = rubyEnv.wrappedRuby;
|
2021-08-12 12:34:14 +02:00
|
|
|
tests = import ../../../../nixos/tests/discourse.nix { package = pkgs.discourse.override args; };
|
2021-03-12 12:58:31 +01:00
|
|
|
};
|
|
|
|
};
|
|
|
|
in discourse
|