{ config, lib, pkgs, ... }: # TODO: support non-postgresql with lib; let cfg = config.services.redmine; ruby = pkgs.ruby; databaseYml = '' production: adapter: postgresql database: ${cfg.databaseName} host: ${cfg.databaseHost} password: ${cfg.databasePassword} username: ${cfg.databaseUsername} encoding: utf8 ''; configurationYml = '' default: # Absolute path to the directory where attachments are stored. # The default is the 'files' directory in your Redmine instance. # Your Redmine instance needs to have write permission on this # directory. # Examples: # attachments_storage_path: /var/redmine/files # attachments_storage_path: D:/redmine/files attachments_storage_path: ${cfg.stateDir}/files # Absolute path to the SCM commands errors (stderr) log file. # The default is to log in the 'log' directory of your Redmine instance. # Example: # scm_stderr_log_file: /var/log/redmine_scm_stderr.log scm_stderr_log_file: ${cfg.stateDir}/redmine_scm_stderr.log ${cfg.extraConfig} ''; unpackTheme = unpack "theme"; unpackPlugin = unpack "plugin"; unpack = id: (name: source: pkgs.stdenv.mkDerivation { name = "redmine-${id}-${name}"; buildInputs = [ pkgs.unzip ]; buildCommand = '' mkdir -p $out cd $out unpackFile ${source} ''; }); in { options = { services.redmine = { enable = mkOption { type = types.bool; default = false; description = '' Enable the redmine service. ''; }; stateDir = mkOption { type = types.str; default = "/var/redmine"; description = "The state directory, logs and plugins are stored here"; }; extraConfig = mkOption { type = types.lines; default = ""; description = "Extra configuration in configuration.yml"; }; themes = mkOption { type = types.attrsOf types.path; default = {}; description = "Set of themes"; }; plugins = mkOption { type = types.attrsOf types.path; default = {}; description = "Set of plugins"; }; #databaseType = mkOption { # type = types.str; # default = "postgresql"; # description = "Type of database"; #}; databaseHost = mkOption { type = types.str; default = "127.0.0.1"; description = "Database hostname"; }; databasePassword = mkOption { type = types.str; default = ""; description = "Database user password"; }; databaseName = mkOption { type = types.str; default = "redmine"; description = "Database name"; }; databaseUsername = mkOption { type = types.str; default = "redmine"; description = "Database user"; }; }; }; config = mkIf cfg.enable { assertions = [ { assertion = cfg.databasePassword != ""; message = "services.redmine.databasePassword must be set"; } ]; users.extraUsers = [ { name = "redmine"; group = "redmine"; uid = config.ids.uids.redmine; } ]; users.extraGroups = [ { name = "redmine"; gid = config.ids.gids.redmine; } ]; systemd.services.redmine = { after = [ "network.target" "postgresql.service" ]; wantedBy = [ "multi-user.target" ]; environment.RAILS_ENV = "production"; environment.RAILS_ETC = "${cfg.stateDir}/config"; environment.RAILS_LOG = "${cfg.stateDir}/log"; environment.RAILS_VAR = "${cfg.stateDir}/var"; environment.RAILS_CACHE = "${cfg.stateDir}/cache"; environment.RAILS_PLUGINS = "${cfg.stateDir}/plugins"; environment.RAILS_PUBLIC = "${cfg.stateDir}/public"; environment.RAILS_TMP = "${cfg.stateDir}/tmp"; environment.SCHEMA = "${cfg.stateDir}/cache/schema.db"; environment.HOME = "${pkgs.redmine}/share/redmine"; environment.REDMINE_LANG = "en"; environment.GEM_HOME = "${pkgs.redmine}/share/redmine/vendor/bundle/ruby/1.9.1"; environment.GEM_PATH = "${pkgs.bundler}/${pkgs.bundler.ruby.gemPath}"; path = with pkgs; [ imagemagickBig subversion mercurial cvs config.services.postgresql.package bazaar gitAndTools.git # once we build binaries for darc enable it #darcs ]; preStart = '' # TODO: use env vars for i in plugins public/plugin_assets db files log config cache var/files tmp; do mkdir -p ${cfg.stateDir}/$i done chown -R redmine:redmine ${cfg.stateDir} chmod -R 755 ${cfg.stateDir} rm -rf ${cfg.stateDir}/public/* cp -R ${pkgs.redmine}/share/redmine/public/* ${cfg.stateDir}/public/ for theme in ${concatStringsSep " " (mapAttrsToList unpackTheme cfg.themes)}; do ln -fs $theme/* ${cfg.stateDir}/public/themes/ done rm -rf ${cfg.stateDir}/plugins/* for plugin in ${concatStringsSep " " (mapAttrsToList unpackPlugin cfg.plugins)}; do ln -fs $plugin/* ${cfg.stateDir}/plugins/''${plugin##*-redmine-plugin-} done ln -fs ${pkgs.writeText "database.yml" databaseYml} ${cfg.stateDir}/config/database.yml ln -fs ${pkgs.writeText "configuration.yml" configurationYml} ${cfg.stateDir}/config/configuration.yml if [ "${cfg.databaseHost}" = "127.0.0.1" ]; then if ! test -e "${cfg.stateDir}/db-created"; then psql postgres -c "CREATE ROLE redmine WITH LOGIN NOCREATEDB NOCREATEROLE ENCRYPTED PASSWORD '${cfg.databasePassword}'" ${config.services.postgresql.package}/bin/createdb --owner redmine redmine || true touch "${cfg.stateDir}/db-created" fi fi cd ${pkgs.redmine}/share/redmine/ ${ruby}/bin/rake db:migrate ${ruby}/bin/rake redmine:plugins:migrate ${ruby}/bin/rake redmine:load_default_data ${ruby}/bin/rake generate_secret_token ''; serviceConfig = { PermissionsStartOnly = true; # preStart must be run as root Type = "simple"; User = "redmine"; Group = "redmine"; TimeoutSec = "300"; WorkingDirectory = "${pkgs.redmine}/share/redmine"; ExecStart="${ruby}/bin/ruby ${pkgs.redmine}/share/redmine/script/rails server webrick -e production -P ${cfg.stateDir}/redmine.pid"; }; }; }; }