1{ config, lib, pkgs, ... }:
2
3# TODO: support non-postgresql
4
5with lib;
6
7let
8 cfg = config.services.redmine;
9
10 ruby = pkgs.ruby;
11
12 databaseYml = ''
13 production:
14 adapter: postgresql
15 database: ${cfg.databaseName}
16 host: ${cfg.databaseHost}
17 password: ${cfg.databasePassword}
18 username: ${cfg.databaseUsername}
19 encoding: utf8
20 '';
21
22 configurationYml = ''
23 default:
24 # Absolute path to the directory where attachments are stored.
25 # The default is the 'files' directory in your Redmine instance.
26 # Your Redmine instance needs to have write permission on this
27 # directory.
28 # Examples:
29 # attachments_storage_path: /var/redmine/files
30 # attachments_storage_path: D:/redmine/files
31 attachments_storage_path: ${cfg.stateDir}/files
32
33 # Absolute path to the SCM commands errors (stderr) log file.
34 # The default is to log in the 'log' directory of your Redmine instance.
35 # Example:
36 # scm_stderr_log_file: /var/log/redmine_scm_stderr.log
37 scm_stderr_log_file: ${cfg.stateDir}/redmine_scm_stderr.log
38
39 ${cfg.extraConfig}
40 '';
41
42 unpackTheme = unpack "theme";
43 unpackPlugin = unpack "plugin";
44 unpack = id: (name: source:
45 pkgs.stdenv.mkDerivation {
46 name = "redmine-${id}-${name}";
47 buildInputs = [ pkgs.unzip ];
48 buildCommand = ''
49 mkdir -p $out
50 cd $out
51 unpackFile ${source}
52 '';
53 });
54
55in {
56
57 options = {
58 services.redmine = {
59 enable = mkOption {
60 type = types.bool;
61 default = false;
62 description = ''
63 Enable the redmine service.
64 '';
65 };
66
67 stateDir = mkOption {
68 type = types.str;
69 default = "/var/redmine";
70 description = "The state directory, logs and plugins are stored here";
71 };
72
73 extraConfig = mkOption {
74 type = types.str;
75 default = "";
76 description = "Extra configuration in configuration.yml";
77 };
78
79 themes = mkOption {
80 type = types.attrsOf types.path;
81 default = {};
82 description = "Set of themes";
83 };
84
85 plugins = mkOption {
86 type = types.attrsOf types.path;
87 default = {};
88 description = "Set of plugins";
89 };
90
91 #databaseType = mkOption {
92 # type = types.str;
93 # default = "postgresql";
94 # description = "Type of database";
95 #};
96
97 databaseHost = mkOption {
98 type = types.str;
99 default = "127.0.0.1";
100 description = "Database hostname";
101 };
102
103 databasePassword = mkOption {
104 type = types.str;
105 default = "";
106 description = "Database user password";
107 };
108
109 databaseName = mkOption {
110 type = types.str;
111 default = "redmine";
112 description = "Database name";
113 };
114
115 databaseUsername = mkOption {
116 type = types.str;
117 default = "redmine";
118 description = "Database user";
119 };
120 };
121 };
122
123 config = mkIf cfg.enable {
124
125 assertions = [
126 { assertion = cfg.databasePassword != "";
127 message = "services.redmine.databasePassword must be set";
128 }
129 ];
130
131 users.extraUsers = [
132 { name = "redmine";
133 group = "redmine";
134 uid = config.ids.uids.redmine;
135 } ];
136
137 users.extraGroups = [
138 { name = "redmine";
139 gid = config.ids.gids.redmine;
140 } ];
141
142 systemd.services.redmine = {
143 after = [ "network.target" "postgresql.service" ];
144 wantedBy = [ "multi-user.target" ];
145 environment.RAILS_ENV = "production";
146 environment.RAILS_ETC = "${cfg.stateDir}/config";
147 environment.RAILS_LOG = "${cfg.stateDir}/log";
148 environment.RAILS_VAR = "${cfg.stateDir}/var";
149 environment.RAILS_CACHE = "${cfg.stateDir}/cache";
150 environment.RAILS_PLUGINS = "${cfg.stateDir}/plugins";
151 environment.RAILS_PUBLIC = "${cfg.stateDir}/public";
152 environment.RAILS_TMP = "${cfg.stateDir}/tmp";
153 environment.SCHEMA = "${cfg.stateDir}/cache/schema.db";
154 environment.HOME = "${pkgs.redmine}/share/redmine";
155 environment.REDMINE_LANG = "en";
156 environment.GEM_HOME = "${pkgs.redmine}/share/redmine/vendor/bundle/ruby/1.9.1";
157 environment.GEM_PATH = "${pkgs.bundler}/${pkgs.bundler.ruby.gemPath}";
158 path = with pkgs; [
159 imagemagickBig
160 subversion
161 mercurial
162 cvs
163 config.services.postgresql.package
164 bazaar
165 gitAndTools.git
166 # once we build binaries for darc enable it
167 #darcs
168 ];
169 preStart = ''
170 # TODO: use env vars
171 for i in plugins public/plugin_assets db files log config cache var/files tmp; do
172 mkdir -p ${cfg.stateDir}/$i
173 done
174
175 chown -R redmine:redmine ${cfg.stateDir}
176 chmod -R 755 ${cfg.stateDir}
177
178 rm -rf ${cfg.stateDir}/public/*
179 cp -R ${pkgs.redmine}/share/redmine/public/* ${cfg.stateDir}/public/
180 for theme in ${concatStringsSep " " (mapAttrsToList unpackTheme cfg.themes)}; do
181 ln -fs $theme/* ${cfg.stateDir}/public/themes/
182 done
183
184 rm -rf ${cfg.stateDir}/plugins/*
185 for plugin in ${concatStringsSep " " (mapAttrsToList unpackPlugin cfg.plugins)}; do
186 ln -fs $plugin/* ${cfg.stateDir}/plugins/''${plugin##*-redmine-plugin-}
187 done
188
189 ln -fs ${pkgs.writeText "database.yml" databaseYml} ${cfg.stateDir}/config/database.yml
190 ln -fs ${pkgs.writeText "configuration.yml" configurationYml} ${cfg.stateDir}/config/configuration.yml
191
192 if [ "${cfg.databaseHost}" = "127.0.0.1" ]; then
193 if ! test -e "${cfg.stateDir}/db-created"; then
194 psql postgres -c "CREATE ROLE redmine WITH LOGIN NOCREATEDB NOCREATEROLE NOCREATEUSER ENCRYPTED PASSWORD '${cfg.databasePassword}'"
195 ${config.services.postgresql.package}/bin/createdb --owner redmine redmine || true
196 touch "${cfg.stateDir}/db-created"
197 fi
198 fi
199
200 cd ${pkgs.redmine}/share/redmine/
201 ${ruby}/bin/rake db:migrate
202 ${ruby}/bin/rake redmine:plugins:migrate
203 ${ruby}/bin/rake redmine:load_default_data
204 ${ruby}/bin/rake generate_secret_token
205 '';
206
207 serviceConfig = {
208 PermissionsStartOnly = true; # preStart must be run as root
209 Type = "simple";
210 User = "redmine";
211 Group = "redmine";
212 TimeoutSec = "300";
213 WorkingDirectory = "${pkgs.redmine}/share/redmine";
214 ExecStart="${ruby}/bin/ruby ${pkgs.redmine}/share/redmine/script/rails server webrick -e production -P ${cfg.stateDir}/redmine.pid";
215 };
216
217 };
218
219 };
220
221}