aboutsummaryrefslogtreecommitdiff
path: root/nixops/modules/task
diff options
context:
space:
mode:
authorIsmaël Bouya <ismael.bouya@normalesup.org>2019-03-06 16:43:44 +0100
committerIsmaël Bouya <ismael.bouya@normalesup.org>2019-03-06 16:43:44 +0100
commit99b0b74ac87c77b5f39e21c65141d8fcc6753ca2 (patch)
tree476753a86702e468c8dc4f6dca677618ec07518d /nixops/modules/task
parent55fd3780b5c40664233cd3f9b8cf280bd530fdd1 (diff)
downloadNix-99b0b74ac87c77b5f39e21c65141d8fcc6753ca2.tar.gz
Nix-99b0b74ac87c77b5f39e21c65141d8fcc6753ca2.tar.zst
Nix-99b0b74ac87c77b5f39e21c65141d8fcc6753ca2.zip
Add taskwarrior-web
Fixes https://git.immae.eu/mantisbt/view.php?id=67
Diffstat (limited to 'nixops/modules/task')
-rw-r--r--nixops/modules/task/Gemfile.lock139
-rw-r--r--nixops/modules/task/default.nix224
-rw-r--r--nixops/modules/task/fixes.patch56
-rw-r--r--nixops/modules/task/gemset.nix567
-rw-r--r--nixops/modules/task/taskwarrior-web.json15
-rw-r--r--nixops/modules/task/taskwarrior-web.nix24
-rw-r--r--nixops/modules/task/thin.patch23
7 files changed, 1005 insertions, 43 deletions
diff --git a/nixops/modules/task/Gemfile.lock b/nixops/modules/task/Gemfile.lock
new file mode 100644
index 0000000..1b2f5ba
--- /dev/null
+++ b/nixops/modules/task/Gemfile.lock
@@ -0,0 +1,139 @@
1PATH
2 remote: .
3 specs:
4 taskwarrior-web (1.1.12)
5 activesupport (~> 3)
6 json (~> 1.8)
7 parseconfig
8 rack-flash3
9 rinku
10 sinatra
11 sinatra-simple-navigation
12 vegas
13 versionomy
14
15GEM
16 remote: http://rubygems.org/
17 specs:
18 activesupport (3.2.22.5)
19 i18n (~> 0.6, >= 0.6.4)
20 multi_json (~> 1.0)
21 blockenspiel (0.5.0)
22 coderay (1.1.2)
23 concurrent-ruby (1.1.4)
24 daemons (1.3.1)
25 diff-lcs (1.3)
26 docile (1.3.1)
27 eventmachine (1.2.7)
28 ffi (1.10.0)
29 formatador (0.2.5)
30 growl (1.0.3)
31 guard (2.15.0)
32 formatador (>= 0.2.4)
33 listen (>= 2.7, < 4.0)
34 lumberjack (>= 1.0.12, < 2.0)
35 nenv (~> 0.1)
36 notiffany (~> 0.0)
37 pry (>= 0.9.12)
38 shellany (~> 0.0)
39 thor (>= 0.18.1)
40 guard-bundler (2.2.1)
41 bundler (>= 1.3.0, < 3)
42 guard (~> 2.2)
43 guard-compat (~> 1.1)
44 guard-compat (1.2.1)
45 guard-rspec (4.7.3)
46 guard (~> 2.1)
47 guard-compat (~> 1.1)
48 rspec (>= 2.99.0, < 4.0)
49 i18n (0.9.5)
50 concurrent-ruby (~> 1.0)
51 json (1.8.6)
52 listen (3.1.5)
53 rb-fsevent (~> 0.9, >= 0.9.4)
54 rb-inotify (~> 0.9, >= 0.9.7)
55 ruby_dep (~> 1.2)
56 lumberjack (1.0.13)
57 method_source (0.9.2)
58 mini_portile2 (2.4.0)
59 multi_json (1.13.1)
60 mustermann (1.0.3)
61 nenv (0.3.0)
62 nokogiri (1.10.1)
63 mini_portile2 (~> 2.4.0)
64 notiffany (0.1.1)
65 nenv (~> 0.1)
66 shellany (~> 0.0)
67 parseconfig (1.0.8)
68 pry (0.12.2)
69 coderay (~> 1.1.0)
70 method_source (~> 0.9.0)
71 rack (2.0.6)
72 rack-flash3 (1.0.5)
73 rack
74 rack-protection (2.0.5)
75 rack
76 rack-test (1.1.0)
77 rack (>= 1.0, < 3)
78 rake (10.5.0)
79 rb-fsevent (0.10.3)
80 rb-inotify (0.10.0)
81 ffi (~> 1.0)
82 rinku (2.0.5)
83 rspec (2.99.0)
84 rspec-core (~> 2.99.0)
85 rspec-expectations (~> 2.99.0)
86 rspec-mocks (~> 2.99.0)
87 rspec-core (2.99.2)
88 rspec-expectations (2.99.2)
89 diff-lcs (>= 1.1.3, < 2.0)
90 rspec-html-matchers (0.5.0)
91 nokogiri (~> 1)
92 rspec (~> 2, >= 2.11.0)
93 rspec-mocks (2.99.4)
94 ruby_dep (1.5.0)
95 shellany (0.0.1)
96 simple-navigation (4.0.5)
97 activesupport (>= 2.3.2)
98 simplecov (0.16.1)
99 docile (~> 1.1)
100 json (>= 1.8, < 3)
101 simplecov-html (~> 0.10.0)
102 simplecov-html (0.10.2)
103 sinatra (2.0.5)
104 mustermann (~> 1.0)
105 rack (~> 2.0)
106 rack-protection (= 2.0.5)
107 tilt (~> 2.0)
108 sinatra-simple-navigation (4.1.0)
109 simple-navigation (~> 4.0)
110 sinatra (>= 1.0, < 3.0)
111 thin (1.7.2)
112 daemons (~> 1.0, >= 1.0.9)
113 eventmachine (~> 1.0, >= 1.0.4)
114 rack (>= 1, < 3)
115 thor (0.20.3)
116 tilt (2.0.9)
117 vegas (0.1.11)
118 rack (>= 1.0.0)
119 versionomy (0.5.0)
120 blockenspiel (~> 0.5)
121
122PLATFORMS
123 ruby
124
125DEPENDENCIES
126 growl
127 guard-bundler
128 guard-rspec
129 rack-test
130 rake (< 11)
131 rb-fsevent
132 rspec (~> 2)
133 rspec-html-matchers
134 simplecov
135 taskwarrior-web!
136 thin
137
138BUNDLED WITH
139 1.16.2
diff --git a/nixops/modules/task/default.nix b/nixops/modules/task/default.nix
index 3dc3299..2fd61aa 100644
--- a/nixops/modules/task/default.nix
+++ b/nixops/modules/task/default.nix
@@ -6,6 +6,81 @@ let
6 user = config.services.taskserver.user; 6 user = config.services.taskserver.user;
7 env = myconfig.env.tools.task; 7 env = myconfig.env.tools.task;
8 group = config.services.taskserver.group; 8 group = config.services.taskserver.group;
9 taskserver-user-certs = pkgs.runCommand "taskserver-user-certs" {} ''
10 mkdir -p $out/bin
11 cat > $out/bin/taskserver-user-certs <<"EOF"
12 #!/usr/bin/env bash
13
14 user=$1
15
16 silent_certtool() {
17 if ! output="$("${pkgs.gnutls.bin}/bin/certtool" "$@" 2>&1)"; then
18 echo "GNUTLS certtool invocation failed with output:" >&2
19 echo "$output" >&2
20 fi
21 }
22
23 silent_certtool -p \
24 --bits 4096 \
25 --outfile "${vardir}/userkeys/$user.key.pem"
26 ${pkgs.gnused}/bin/sed -i -n -e '/^-----BEGIN RSA PRIVATE KEY-----$/,$p' "${vardir}/userkeys/$user.key.pem"
27
28 silent_certtool -c \
29 --template "${pkgs.writeText "taskserver-ca.template" ''
30 tls_www_client
31 encryption_key
32 signing_key
33 expiration_days = 3650
34 ''}" \
35 --load-ca-certificate "${vardir}/keys/ca.cert" \
36 --load-ca-privkey "${vardir}/keys/ca.key" \
37 --load-privkey "${vardir}/userkeys/$user.key.pem" \
38 --outfile "${vardir}/userkeys/$user.cert.pem"
39 EOF
40 chmod a+x $out/bin/taskserver-user-certs
41 patchShebangs $out/bin/taskserver-user-certs
42 '';
43 taskwarrior-web = pkgs.callPackage ./taskwarrior-web.nix {
44 inherit (mylibs) fetchedGithub;
45 inherit env;
46 };
47 taskwebPages = let
48 uidPages = lib.attrsets.zipAttrs (
49 lib.lists.flatten
50 (lib.attrsets.mapAttrsToList (k: c: map (v: { "${v}" = k; }) c.uid) env.taskwarrior-web)
51 );
52 pages = lib.attrsets.mapAttrs (uid: items:
53 if lib.lists.length items == 1 then
54 ''
55 <html>
56 <head>
57 <meta http-equiv="refresh" content="0; url=/taskweb/${lib.lists.head items}/" />
58 </head>
59 <body></body>
60 </html>
61 ''
62 else
63 ''
64 <html>
65 <head>
66 <title>To-do list disponibles</title>
67 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
68 <meta name="viewport" content="width=device-width, initial-scale=1" />
69 </head>
70 <body>
71 <ul>
72 ${builtins.concatStringsSep "\n" (map (item: "<li><a href='/taskweb/${item}'>${item}</a></li>") items)}
73 </ul>
74 </body>
75 </html>
76 ''
77 ) uidPages;
78 in
79 pkgs.runCommand "taskwerver-pages" {} ''
80 mkdir -p $out/
81 ${builtins.concatStringsSep "\n" (lib.attrsets.mapAttrsToList (k: v: "cp ${pkgs.writeText k v} $out/${k}.html") pages)}
82 echo "Please login" > $out/index.html
83 '';
9in { 84in {
10 options.services.myTasks = { 85 options.services.myTasks = {
11 enable = lib.mkEnableOption "my tasks service"; 86 enable = lib.mkEnableOption "my tasks service";
@@ -13,7 +88,7 @@ in {
13 88
14 config = lib.mkIf cfg.enable { 89 config = lib.mkIf cfg.enable {
15 security.acme.certs."eldiron".extraDomains.${fqdn} = null; 90 security.acme.certs."eldiron".extraDomains.${fqdn} = null;
16 services.myWebsites.tools.modules = [ "proxy_fcgi" ]; 91 services.myWebsites.tools.modules = [ "proxy_fcgi" "sed" ];
17 services.myWebsites.tools.vhostConfs.task = { 92 services.myWebsites.tools.vhostConfs.task = {
18 certName = "eldiron"; 93 certName = "eldiron";
19 hosts = [ "task.immae.eu" ]; 94 hosts = [ "task.immae.eu" ];
@@ -34,7 +109,48 @@ in {
34 SetEnv TASKD_LDAP_BASE "${env.ldap.base}" 109 SetEnv TASKD_LDAP_BASE "${env.ldap.base}"
35 SetEnv TASKD_LDAP_FILTER "${env.ldap.search}" 110 SetEnv TASKD_LDAP_FILTER "${env.ldap.search}"
36 </Directory> 111 </Directory>
37 '' ]; 112 ''
113 ''
114 <Macro Taskwarrior %{folderName}>
115 ProxyPass "unix://${taskwarrior-web.socketsDir}/%{folderName}.sock|http://localhost-%{folderName}/"
116 ProxyPassReverse "unix://${taskwarrior-web.socketsDir}/%{folderName}.sock|http://localhost-%{folderName}/"
117 ProxyPassReverse http://${fqdn}/
118
119 SetOutputFilter Sed
120 OutputSed "s|/ajax|/taskweb/%{folderName}/ajax|g"
121 OutputSed "s|\([^x]\)/tasks|\1/taskweb/%{folderName}/tasks|g"
122 OutputSed "s|\([^x]\)/projects|\1/taskweb/%{folderName}/projects|g"
123 OutputSed "s|http://${fqdn}/|/taskweb/%{folderName}/|g"
124 OutputSed "s|/img/relax.jpg|/taskweb/%{folderName}/img/relax.jpg|g"
125 </Macro>
126 ''
127 ''
128 Alias /taskweb ${taskwebPages}
129 <Directory "${taskwebPages}">
130 DirectoryIndex index.html
131 Require all granted
132 </Directory>
133
134 RewriteEngine on
135 RewriteRule ^/taskweb$ /taskweb/ [R=301,L]
136 RedirectMatch permanent ^/taskweb/([^/]+)$ /taskweb/$1/
137
138 RewriteCond %{LA-U:REMOTE_USER} !=""
139 RewriteCond ${taskwebPages}/%{LA-U:REMOTE_USER}.html -f
140 RewriteRule ^/taskweb/?$ ${taskwebPages}/%{LA-U:REMOTE_USER}.html [L]
141
142 <Location /taskweb/>
143 Use LDAPConnect
144 Require ldap-group cn=users,cn=taskwarrior,ou=services,dc=immae,dc=eu
145 </Location>
146 ''
147 ] ++ (lib.attrsets.mapAttrsToList (k: v: ''
148 <Location /taskweb/${k}/>
149 ${builtins.concatStringsSep "\n" (map (uid: "Require ldap-attribute uid=${uid}") v.uid)}
150
151 Use Taskwarrior ${k}
152 </Location>
153 '') env.taskwarrior-web);
38 }; 154 };
39 services.myPhpfpm.poolConfigs = { 155 services.myPhpfpm.poolConfigs = {
40 tasks = '' 156 tasks = ''
@@ -69,47 +185,7 @@ in {
69 ''; 185 '';
70 }; 186 };
71 187
72 users.users.${user}.packages = [ 188 users.users.${user}.packages = [ taskserver-user-certs ];
73 (pkgs.runCommand "taskserver-user-certs" {} ''
74 mkdir -p $out/bin
75 cat > $out/bin/taskserver-user-certs <<"EOF"
76 #!/usr/bin/env bash
77
78 user=$1
79
80 silent_certtool() {
81 if ! output="$("${pkgs.gnutls.bin}/bin/certtool" "$@" 2>&1)"; then
82 echo "GNUTLS certtool invocation failed with output:" >&2
83 echo "$output" >&2
84 fi
85 }
86
87 silent_certtool -p \
88 --bits 4096 \
89 --outfile "${vardir}/userkeys/$user.key.pem"
90 ${pkgs.gnused}/bin/sed -i -n -e '/^-----BEGIN RSA PRIVATE KEY-----$/,$p' "${vardir}/userkeys/$user.key.pem"
91
92 silent_certtool -c \
93 --template "${pkgs.writeText "taskserver-ca.template" ''
94 tls_www_client
95 encryption_key
96 signing_key
97 expiration_days = 3650
98 ''}" \
99 --load-ca-certificate "${vardir}/keys/ca.cert" \
100 --load-ca-privkey "${vardir}/keys/ca.key" \
101 --load-privkey "${vardir}/userkeys/$user.key.pem" \
102 --outfile "${vardir}/userkeys/$user.cert.pem"
103 EOF
104 chmod a+x $out/bin/taskserver-user-certs
105 patchShebangs $out/bin/taskserver-user-certs
106 '')
107 ];
108
109 systemd.services.taskserver-ca.postStart = ''
110 chown :${group} "${vardir}/keys/ca.key"
111 chmod g+r "${vardir}/keys/ca.key"
112 '';
113 189
114 system.activationScripts.taskserver = { 190 system.activationScripts.taskserver = {
115 deps = [ "users" ]; 191 deps = [ "users" ];
@@ -127,5 +203,67 @@ in {
127 listenHost = "::"; 203 listenHost = "::";
128 requestLimit = 104857600; 204 requestLimit = 104857600;
129 }; 205 };
206
207 system.activationScripts.taskwarrior-web = {
208 deps = [ "users" ];
209 text = ''
210 install -m 0755 -o ${user} -g ${group} -d ${taskwarrior-web.socketsDir}
211 install -m 0750 -o ${user} -g ${group} -d ${taskwarrior-web.varDir}
212 ${builtins.concatStringsSep "\n" (lib.attrsets.mapAttrsToList
213 (k: v: "install -m 0750 -o ${user} -g ${group} -d ${taskwarrior-web.varDir}/${k}")
214 env.taskwarrior-web
215 )}
216 if [ ! -f ${vardir}/userkeys/taskwarrior-web.cert.pem ]; then
217 ${taskserver-user-certs}/bin/taskserver-user-certs taskwarrior-web
218 chown taskd:taskd ${vardir}/userkeys/taskwarrior-web.cert.pem ${vardir}/userkeys/taskwarrior-web.key.pem
219 fi
220 '';
221 };
222
223 systemd.services = (lib.attrsets.mapAttrs' (name: userConfig:
224 let
225 credentials = "${userConfig.org}/${name}/${userConfig.key}";
226 dateFormat = userConfig.date;
227 taskrc = pkgs.writeText "taskrc" ''
228 data.location=${taskwarrior-web.varDir}/${name}
229 taskd.certificate=${vardir}/userkeys/taskwarrior-web.cert.pem
230 taskd.key=${vardir}/userkeys/taskwarrior-web.key.pem
231 taskd.ca=${vardir}/keys/server.cert
232 taskd.server=${fqdn}:${toString config.services.taskserver.listenPort}
233 taskd.credentials=${credentials}
234 dateformat=${dateFormat}
235 '';
236 in lib.attrsets.nameValuePair "taskwarrior-web-${name}" {
237 description = "Taskwarrior webapp for ${name}";
238 wantedBy = [ "multi-user.target" ];
239 after = [ "network.target" ];
240 path = [ pkgs.taskwarrior ];
241
242 environment.TASKRC = taskrc;
243 environment.BUNDLE_PATH = "${taskwarrior-web.gems}/lib/ruby/gems/2.5.0";
244 environment.BUNDLE_GEMFILE = "${taskwarrior-web.gems.confFiles}/Gemfile";
245 environment.LC_ALL = "fr_FR.UTF-8";
246
247 script = ''
248 exec ${taskwarrior-web.gems}/lib/ruby/gems/2.5.0/bin/bundle exec thin start -R config.ru -S ${taskwarrior-web.socketsDir}/${name}.sock
249 '';
250
251 serviceConfig = {
252 User = user;
253 PrivateTmp = true;
254 Restart = "always";
255 TimeoutSec = 60;
256 Type = "simple";
257 WorkingDirectory = taskwarrior-web.rubyRoot;
258 };
259
260 unitConfig.RequiresMountsFor = taskwarrior-web.varDir;
261 }) env.taskwarrior-web) // {
262 taskserver-ca.postStart = ''
263 chown :${group} "${vardir}/keys/ca.key"
264 chmod g+r "${vardir}/keys/ca.key"
265 '';
266 };
267
130 }; 268 };
131} 269}
diff --git a/nixops/modules/task/fixes.patch b/nixops/modules/task/fixes.patch
new file mode 100644
index 0000000..851f9f0
--- /dev/null
+++ b/nixops/modules/task/fixes.patch
@@ -0,0 +1,56 @@
1diff --git a/lib/taskwarrior-web/helpers.rb b/lib/taskwarrior-web/helpers.rb
2index 212aed7..94c57df 100644
3--- a/lib/taskwarrior-web/helpers.rb
4+++ b/lib/taskwarrior-web/helpers.rb
5@@ -1,6 +1,8 @@
6 require 'active_support/core_ext/date/calculations'
7
8 module TaskwarriorWeb::App::Helpers
9+ include ERB::Util
10+
11 def format_date(timestamp)
12 format = TaskwarriorWeb::Config.dateformat || '%-m/%-d/%Y'
13 Time.parse(timestamp).localtime.strftime(format)
14diff --git a/lib/taskwarrior-web/services/builder/base.rb b/lib/taskwarrior-web/services/builder/base.rb
15index 58d246e..8f716ac 100644
16--- a/lib/taskwarrior-web/services/builder/base.rb
17+++ b/lib/taskwarrior-web/services/builder/base.rb
18@@ -10,7 +10,7 @@ module TaskwarriorWeb::CommandBuilder::Base
19 :complete => ':id done',
20 :annotate => ':id annotate',
21 :denotate => ':id denotate',
22- :projects => '_projects',
23+ :projects => '_unique project',
24 :tags => '_tags',
25 :sync => 'sync'
26 }
27diff --git a/lib/taskwarrior-web/views/tasks/_form.erb b/lib/taskwarrior-web/views/tasks/_form.erb
28index 789e7a1..fa08698 100644
29--- a/lib/taskwarrior-web/views/tasks/_form.erb
30+++ b/lib/taskwarrior-web/views/tasks/_form.erb
31@@ -1,14 +1,14 @@
32 <div class="control-group">
33 <label for="task-description" class="control-label">Description</label>
34 <div class="controls">
35- <input type="text" required="required" id="task-description" name="task[description]" value="<%= @task.description unless @task.nil? %>" />
36+ <input type="text" required="required" id="task-description" name="task[description]" value="<%=h @task.description unless @task.nil? %>" />
37 </div>
38 </div>
39
40 <div class="control-group">
41 <label for="task-project" class="control-label">Project</label>
42 <div class="controls">
43- <input type="text" id="task-project" name="task[project]" value="<%= @task.project unless @task.nil? %>" autocomplete="off" />
44+ <input type="text" id="task-project" name="task[project]" value="<%=h @task.project unless @task.nil? %>" autocomplete="off" />
45 </div>
46 </div>
47
48@@ -45,7 +45,7 @@
49 <div class="control-group">
50 <label for="task-tags" class="control-label">Tags</label>
51 <div class="controls">
52- <input type="text" id="task-tags" name="task[tags]" value="<%= @task.tags.join(', ') unless @task.nil? %>" autocomplete="off" />
53+ <input type="text" id="task-tags" name="task[tags]" value="<%=h @task.tags.join(', ') unless @task.nil? %>" autocomplete="off" />
54 <span class="help-block">Enter tags separated by commas or spaces (e.g. <em>each, word will,be a tag</em>)</span>
55 </div>
56 </div>
diff --git a/nixops/modules/task/gemset.nix b/nixops/modules/task/gemset.nix
new file mode 100644
index 0000000..35d13c6
--- /dev/null
+++ b/nixops/modules/task/gemset.nix
@@ -0,0 +1,567 @@
1{
2 activesupport = {
3 dependencies = ["i18n" "multi_json"];
4 groups = ["default"];
5 platforms = [];
6 source = {
7 remotes = ["http://rubygems.org"];
8 sha256 = "0fyxqkkws4px4lzkbcqzp0bwai7nn7jk4p0bgfy0dny9cwm0qc9r";
9 type = "gem";
10 };
11 version = "3.2.22.5";
12 };
13 blockenspiel = {
14 groups = ["default"];
15 platforms = [];
16 source = {
17 remotes = ["http://rubygems.org"];
18 sha256 = "1h701s45n5qprvcpc7fnr45n88p56x07pznkxqnhz1dbdbhb7xx8";
19 type = "gem";
20 };
21 version = "0.5.0";
22 };
23 coderay = {
24 groups = ["default" "local"];
25 platforms = [];
26 source = {
27 remotes = ["http://rubygems.org"];
28 sha256 = "15vav4bhcc2x3jmi3izb11l4d9f3xv8hp2fszb7iqmpsccv1pz4y";
29 type = "gem";
30 };
31 version = "1.1.2";
32 };
33 concurrent-ruby = {
34 groups = ["default"];
35 platforms = [];
36 source = {
37 remotes = ["http://rubygems.org"];
38 sha256 = "1ixcx9pfissxrga53jbdpza85qd5f6b5nq1sfqa9rnfq82qnlbp1";
39 type = "gem";
40 };
41 version = "1.1.4";
42 };
43 daemons = {
44 groups = ["default"];
45 platforms = [];
46 source = {
47 remotes = ["http://rubygems.org"];
48 sha256 = "0l5gai3vd4g7aqff0k1mp41j9zcsvm2rbwmqn115a325k9r7pf4w";
49 type = "gem";
50 };
51 version = "1.3.1";
52 };
53 diff-lcs = {
54 groups = ["default" "development" "local"];
55 platforms = [];
56 source = {
57 remotes = ["http://rubygems.org"];
58 sha256 = "18w22bjz424gzafv6nzv98h0aqkwz3d9xhm7cbr1wfbyas8zayza";
59 type = "gem";
60 };
61 version = "1.3";
62 };
63 docile = {
64 groups = ["default" "local"];
65 platforms = [];
66 source = {
67 remotes = ["http://rubygems.org"];
68 sha256 = "04d2izkna3ahfn6fwq4xrcafa715d3bbqczxm16fq40fqy87xn17";
69 type = "gem";
70 };
71 version = "1.3.1";
72 };
73 eventmachine = {
74 groups = ["default"];
75 platforms = [];
76 source = {
77 remotes = ["http://rubygems.org"];
78 sha256 = "0wh9aqb0skz80fhfn66lbpr4f86ya2z5rx6gm5xlfhd05bj1ch4r";
79 type = "gem";
80 };
81 version = "1.2.7";
82 };
83 ffi = {
84 groups = ["default" "local"];
85 platforms = [];
86 source = {
87 remotes = ["http://rubygems.org"];
88 sha256 = "0j8pzj8raxbir5w5k6s7a042sb5k02pg0f8s4na1r5lan901j00p";
89 type = "gem";
90 };
91 version = "1.10.0";
92 };
93 formatador = {
94 groups = ["default" "local"];
95 platforms = [];
96 source = {
97 remotes = ["http://rubygems.org"];
98 sha256 = "1gc26phrwlmlqrmz4bagq1wd5b7g64avpx0ghxr9xdxcvmlii0l0";
99 type = "gem";
100 };
101 version = "0.2.5";
102 };
103 growl = {
104 groups = ["local"];
105 platforms = [];
106 source = {
107 remotes = ["http://rubygems.org"];
108 sha256 = "0s0y7maljnalpbv2q1j5j5hvb4wcc31y9af0n7x1q2l0fzxgc9n9";
109 type = "gem";
110 };
111 version = "1.0.3";
112 };
113 guard = {
114 dependencies = ["formatador" "listen" "lumberjack" "nenv" "notiffany" "pry" "shellany" "thor"];
115 groups = ["default" "local"];
116 platforms = [];
117 source = {
118 remotes = ["http://rubygems.org"];
119 sha256 = "0h84ja6qvii3hx86w9l4vjpbgl4m8ma8fbawwp7s8l791cgkdcmk";
120 type = "gem";
121 };
122 version = "2.15.0";
123 };
124 guard-bundler = {
125 dependencies = ["guard" "guard-compat"];
126 groups = ["local"];
127 platforms = [];
128 source = {
129 remotes = ["http://rubygems.org"];
130 sha256 = "0lji8f8w7y4prmpr2lqmlljvkqgkgnlsiwqgwvq7b1y3sxlsvy62";
131 type = "gem";
132 };
133 version = "2.2.1";
134 };
135 guard-compat = {
136 groups = ["default" "local"];
137 platforms = [];
138 source = {
139 remotes = ["http://rubygems.org"];
140 sha256 = "1zj6sr1k8w59mmi27rsii0v8xyy2rnsi09nqvwpgj1q10yq1mlis";
141 type = "gem";
142 };
143 version = "1.2.1";
144 };
145 guard-rspec = {
146 dependencies = ["guard" "guard-compat" "rspec"];
147 groups = ["local"];
148 platforms = [];
149 source = {
150 remotes = ["http://rubygems.org"];
151 sha256 = "1jkm5xp90gm4c5s51pmf92i9hc10gslwwic6mvk72g0yplya0yx4";
152 type = "gem";
153 };
154 version = "4.7.3";
155 };
156 i18n = {
157 dependencies = ["concurrent-ruby"];
158 groups = ["default"];
159 platforms = [];
160 source = {
161 remotes = ["http://rubygems.org"];
162 sha256 = "038qvz7kd3cfxk8bvagqhakx68pfbnmghpdkx7573wbf0maqp9a3";
163 type = "gem";
164 };
165 version = "0.9.5";
166 };
167 json = {
168 groups = ["default" "local"];
169 platforms = [];
170 source = {
171 remotes = ["http://rubygems.org"];
172 sha256 = "0qmj7fypgb9vag723w1a49qihxrcf5shzars106ynw2zk352gbv5";
173 type = "gem";
174 };
175 version = "1.8.6";
176 };
177 listen = {
178 dependencies = ["rb-fsevent" "rb-inotify" "ruby_dep"];
179 groups = ["default" "local"];
180 platforms = [];
181 source = {
182 remotes = ["http://rubygems.org"];
183 sha256 = "01v5mrnfqm6sgm8xn2v5swxsn1wlmq7rzh2i48d4jzjsc7qvb6mx";
184 type = "gem";
185 };
186 version = "3.1.5";
187 };
188 lumberjack = {
189 groups = ["default" "local"];
190 platforms = [];
191 source = {
192 remotes = ["http://rubygems.org"];
193 sha256 = "06im7gcg42x77yhz2w5da2ly9xz0n0c36y5ks7xs53v0l9g0vf5n";
194 type = "gem";
195 };
196 version = "1.0.13";
197 };
198 method_source = {
199 groups = ["default" "local"];
200 platforms = [];
201 source = {
202 remotes = ["http://rubygems.org"];
203 sha256 = "1pviwzvdqd90gn6y7illcdd9adapw8fczml933p5vl739dkvl3lq";
204 type = "gem";
205 };
206 version = "0.9.2";
207 };
208 mini_portile2 = {
209 groups = ["default" "development"];
210 platforms = [];
211 source = {
212 remotes = ["http://rubygems.org"];
213 sha256 = "15zplpfw3knqifj9bpf604rb3wc1vhq6363pd6lvhayng8wql5vy";
214 type = "gem";
215 };
216 version = "2.4.0";
217 };
218 multi_json = {
219 groups = ["default"];
220 platforms = [];
221 source = {
222 remotes = ["http://rubygems.org"];
223 sha256 = "1rl0qy4inf1mp8mybfk56dfga0mvx97zwpmq5xmiwl5r770171nv";
224 type = "gem";
225 };
226 version = "1.13.1";
227 };
228 mustermann = {
229 groups = ["default"];
230 platforms = [];
231 source = {
232 remotes = ["http://rubygems.org"];
233 sha256 = "0lycgkmnyy0bf29nnd2zql5a6pcf8sp69g9v4xw0gcfcxgpwp7i1";
234 type = "gem";
235 };
236 version = "1.0.3";
237 };
238 nenv = {
239 groups = ["default" "local"];
240 platforms = [];
241 source = {
242 remotes = ["http://rubygems.org"];
243 sha256 = "0r97jzknll9bhd8yyg2bngnnkj8rjhal667n7d32h8h7ny7nvpnr";
244 type = "gem";
245 };
246 version = "0.3.0";
247 };
248 nokogiri = {
249 dependencies = ["mini_portile2"];
250 groups = ["default" "development"];
251 platforms = [];
252 source = {
253 remotes = ["http://rubygems.org"];
254 sha256 = "09zll7c6j7xr6wyvh5mm5ncj6pkryp70ybcsxdbw1nyphx5dh184";
255 type = "gem";
256 };
257 version = "1.10.1";
258 };
259 notiffany = {
260 dependencies = ["nenv" "shellany"];
261 groups = ["default" "local"];
262 platforms = [];
263 source = {
264 remotes = ["http://rubygems.org"];
265 sha256 = "0x838fa5il0dd9zbm3lxkpbfxcf5fxv9556mayc2mxsdl5ghv8nx";
266 type = "gem";
267 };
268 version = "0.1.1";
269 };
270 parseconfig = {
271 groups = ["default"];
272 platforms = [];
273 source = {
274 remotes = ["http://rubygems.org"];
275 sha256 = "0br2g9k6zc4ygah52aa8cwvpnnkszia29bnvnr8bhpk3rdzi2vmq";
276 type = "gem";
277 };
278 version = "1.0.8";
279 };
280 pry = {
281 dependencies = ["coderay" "method_source"];
282 groups = ["default" "local"];
283 platforms = [];
284 source = {
285 remotes = ["http://rubygems.org"];
286 sha256 = "00rm71x0r1jdycwbs83lf9l6p494m99asakbvqxh8rz7zwnlzg69";
287 type = "gem";
288 };
289 version = "0.12.2";
290 };
291 rack = {
292 groups = ["default" "development"];
293 platforms = [];
294 source = {
295 remotes = ["http://rubygems.org"];
296 sha256 = "1pcgv8dv4vkaczzlix8q3j68capwhk420cddzijwqgi2qb4lm1zm";
297 type = "gem";
298 };
299 version = "2.0.6";
300 };
301 rack-flash3 = {
302 dependencies = ["rack"];
303 groups = ["default"];
304 platforms = [];
305 source = {
306 remotes = ["http://rubygems.org"];
307 sha256 = "0rim9afrns6s8zc4apiymncysyvijpdg18k57kdpz66p55jf4mqz";
308 type = "gem";
309 };
310 version = "1.0.5";
311 };
312 rack-protection = {
313 dependencies = ["rack"];
314 groups = ["default"];
315 platforms = [];
316 source = {
317 remotes = ["http://rubygems.org"];
318 sha256 = "15167q25rmxipqwi6hjqj3i1byi9iwl3xq9b7mdar7qiz39pmjsk";
319 type = "gem";
320 };
321 version = "2.0.5";
322 };
323 rack-test = {
324 dependencies = ["rack"];
325 groups = ["development"];
326 platforms = [];
327 source = {
328 remotes = ["http://rubygems.org"];
329 sha256 = "0rh8h376mx71ci5yklnpqqn118z3bl67nnv5k801qaqn1zs62h8m";
330 type = "gem";
331 };
332 version = "1.1.0";
333 };
334 rake = {
335 groups = ["development"];
336 platforms = [];
337 source = {
338 remotes = ["http://rubygems.org"];
339 sha256 = "0jcabbgnjc788chx31sihc5pgbqnlc1c75wakmqlbjdm8jns2m9b";
340 type = "gem";
341 };
342 version = "10.5.0";
343 };
344 rb-fsevent = {
345 groups = ["local"];
346 platforms = [];
347 source = {
348 remotes = ["http://rubygems.org"];
349 sha256 = "1lm1k7wpz69jx7jrc92w3ggczkjyjbfziq5mg62vjnxmzs383xx8";
350 type = "gem";
351 };
352 version = "0.10.3";
353 };
354 rb-inotify = {
355 dependencies = ["ffi"];
356 groups = ["default" "local"];
357 platforms = [];
358 source = {
359 remotes = ["http://rubygems.org"];
360 sha256 = "1fs7hxm9g6ywv2yih83b879klhc4fs8i0p9166z795qmd77dk0a4";
361 type = "gem";
362 };
363 version = "0.10.0";
364 };
365 rinku = {
366 groups = ["default"];
367 platforms = [];
368 source = {
369 remotes = ["http://rubygems.org"];
370 sha256 = "1smkk299v18brk98gqbdnqrfwm3143kikl30scidqb5j3pzlbz91";
371 type = "gem";
372 };
373 version = "2.0.5";
374 };
375 rspec = {
376 dependencies = ["rspec-core" "rspec-expectations" "rspec-mocks"];
377 groups = ["development" "local"];
378 platforms = [];
379 source = {
380 remotes = ["http://rubygems.org"];
381 sha256 = "14q3hxvngk4ks8h41yw50d5fqbf2dhzwi9rz5ccxvh5a53ak2as3";
382 type = "gem";
383 };
384 version = "2.99.0";
385 };
386 rspec-core = {
387 groups = ["default" "development" "local"];
388 platforms = [];
389 source = {
390 remotes = ["http://rubygems.org"];
391 sha256 = "1wwz21lcz2lwd2jcp2pvq7n1677v23acf7wxsyszp8msb47mw38i";
392 type = "gem";
393 };
394 version = "2.99.2";
395 };
396 rspec-expectations = {
397 dependencies = ["diff-lcs"];
398 groups = ["default" "development" "local"];
399 platforms = [];
400 source = {
401 remotes = ["http://rubygems.org"];
402 sha256 = "11a5pph3anp4xr591dnlcy8xfkdf54qi2lvg4ykpqhxk37si1py3";
403 type = "gem";
404 };
405 version = "2.99.2";
406 };
407 rspec-html-matchers = {
408 dependencies = ["nokogiri" "rspec"];
409 groups = ["development"];
410 platforms = [];
411 source = {
412 remotes = ["http://rubygems.org"];
413 sha256 = "148grzvk0cvh24avhl0shjzz7ldhj138svf48pc5h1fdsb0pnqcv";
414 type = "gem";
415 };
416 version = "0.5.0";
417 };
418 rspec-mocks = {
419 groups = ["default" "development" "local"];
420 platforms = [];
421 source = {
422 remotes = ["http://rubygems.org"];
423 sha256 = "0bzhqahbiswq41nqi6y2dka1k42n0hl14jb6bldb206zp4hikz8r";
424 type = "gem";
425 };
426 version = "2.99.4";
427 };
428 ruby_dep = {
429 groups = ["default" "local"];
430 platforms = [];
431 source = {
432 remotes = ["http://rubygems.org"];
433 sha256 = "1c1bkl97i9mkcvkn1jks346ksnvnnp84cs22gwl0vd7radybrgy5";
434 type = "gem";
435 };
436 version = "1.5.0";
437 };
438 shellany = {
439 groups = ["default" "local"];
440 platforms = [];
441 source = {
442 remotes = ["http://rubygems.org"];
443 sha256 = "1ryyzrj1kxmnpdzhlv4ys3dnl2r5r3d2rs2jwzbnd1v96a8pl4hf";
444 type = "gem";
445 };
446 version = "0.0.1";
447 };
448 simple-navigation = {
449 dependencies = ["activesupport"];
450 groups = ["default"];
451 platforms = [];
452 source = {
453 remotes = ["http://rubygems.org"];
454 sha256 = "08a2s18an3br3xj5j86r33q0hrkai0y157xg67h1khdskb08yylk";
455 type = "gem";
456 };
457 version = "4.0.5";
458 };
459 simplecov = {
460 dependencies = ["docile" "json" "simplecov-html"];
461 groups = ["local"];
462 platforms = [];
463 source = {
464 remotes = ["http://rubygems.org"];
465 sha256 = "1sfyfgf7zrp2n42v7rswkqgk3bbwk1bnsphm24y7laxv3f8z0947";
466 type = "gem";
467 };
468 version = "0.16.1";
469 };
470 simplecov-html = {
471 groups = ["default" "local"];
472 platforms = [];
473 source = {
474 remotes = ["http://rubygems.org"];
475 sha256 = "1lihraa4rgxk8wbfl77fy9sf0ypk31iivly8vl3w04srd7i0clzn";
476 type = "gem";
477 };
478 version = "0.10.2";
479 };
480 sinatra = {
481 dependencies = ["mustermann" "rack" "rack-protection" "tilt"];
482 groups = ["default"];
483 platforms = [];
484 source = {
485 remotes = ["http://rubygems.org"];
486 sha256 = "1gasgn5f15myv08k10i16p326pchxjsy37pgqfw0xm66kcc5d7ry";
487 type = "gem";
488 };
489 version = "2.0.5";
490 };
491 sinatra-simple-navigation = {
492 dependencies = ["simple-navigation" "sinatra"];
493 groups = ["default"];
494 platforms = [];
495 source = {
496 remotes = ["http://rubygems.org"];
497 sha256 = "1gishxd23qw6bwsk7fkagkfc7ihqyvvvb98j9bmwc6wwpsfs4prs";
498 type = "gem";
499 };
500 version = "4.1.0";
501 };
502 taskwarrior-web = {
503 dependencies = ["activesupport" "json" "parseconfig" "rack-flash3" "rinku" "sinatra" "sinatra-simple-navigation" "vegas" "versionomy"];
504 groups = ["default"];
505 platforms = [];
506 bundledByPath = true;
507 path = ./.;
508 source = {
509 path = ./.;
510 type = "path";
511 };
512 version = "1.1.12";
513 };
514 thin = {
515 dependencies = ["daemons" "eventmachine" "rack"];
516 groups = ["default"];
517 platforms = [];
518 source = {
519 remotes = ["http://rubygems.org"];
520 sha256 = "0nagbf9pwy1vg09k6j4xqhbjjzrg5dwzvkn4ffvlj76fsn6vv61f";
521 type = "gem";
522 };
523 version = "1.7.2";
524 };
525 thor = {
526 groups = ["default" "local"];
527 platforms = [];
528 source = {
529 remotes = ["http://rubygems.org"];
530 sha256 = "1yhrnp9x8qcy5vc7g438amd5j9sw83ih7c30dr6g6slgw9zj3g29";
531 type = "gem";
532 };
533 version = "0.20.3";
534 };
535 tilt = {
536 groups = ["default"];
537 platforms = [];
538 source = {
539 remotes = ["http://rubygems.org"];
540 sha256 = "0ca4k0clwf0rkvy7726x4nxpjxkpv67w043i39saxgldxd97zmwz";
541 type = "gem";
542 };
543 version = "2.0.9";
544 };
545 vegas = {
546 dependencies = ["rack"];
547 groups = ["default"];
548 platforms = [];
549 source = {
550 remotes = ["http://rubygems.org"];
551 sha256 = "0kzv0v1zb8vvm188q4pqwahb6468bmiamn6wpsbiq6r5i69s1bs5";
552 type = "gem";
553 };
554 version = "0.1.11";
555 };
556 versionomy = {
557 dependencies = ["blockenspiel"];
558 groups = ["default"];
559 platforms = [];
560 source = {
561 remotes = ["http://rubygems.org"];
562 sha256 = "0i0l4pzrl1vyp4lpg2cxhgkk56spki3lld943d6h7168fj8qyv33";
563 type = "gem";
564 };
565 version = "0.5.0";
566 };
567}
diff --git a/nixops/modules/task/taskwarrior-web.json b/nixops/modules/task/taskwarrior-web.json
new file mode 100644
index 0000000..70f396d
--- /dev/null
+++ b/nixops/modules/task/taskwarrior-web.json
@@ -0,0 +1,15 @@
1{
2 "tag": "a79cfe2-master",
3 "meta": {
4 "name": "taskwarrior-web",
5 "url": "https://github.com/theunraveler/taskwarrior-web",
6 "branch": "master"
7 },
8 "github": {
9 "owner": "theunraveler",
10 "repo": "taskwarrior-web",
11 "rev": "a79cfe2b42791b62364118e58b21b892fff6ded8",
12 "sha256": "028rb4wry2an19707bvy4n305f3s0hipg214224p1m0mb61c3cq4",
13 "fetchSubmodules": true
14 }
15}
diff --git a/nixops/modules/task/taskwarrior-web.nix b/nixops/modules/task/taskwarrior-web.nix
new file mode 100644
index 0000000..49d6946
--- /dev/null
+++ b/nixops/modules/task/taskwarrior-web.nix
@@ -0,0 +1,24 @@
1{ env, ruby_2_5, bundlerEnv, defaultGemConfig, fetchedGithub, stdenv, writeText, pkgs }:
2let
3 varDir = "/var/lib/taskwarrior-web";
4 socketsDir = "/run/taskwarrior-web";
5 rubyRoot = stdenv.mkDerivation (fetchedGithub ./taskwarrior-web.json // rec {
6 phases = [ "unpackPhase" "patchPhase" "installPhase" ];
7 patches = [ ./fixes.patch ./thin.patch ];
8 installPhase = ''
9 cp -a . $out
10 cp ${./Gemfile.lock} $out/Gemfile.lock
11 '';
12 });
13 gems = bundlerEnv {
14 name = "taskwarrior-web-env";
15 ruby = ruby_2_5;
16 pname = "taskwarrior-web";
17 gemset = ./gemset.nix;
18 gemdir = rubyRoot.out;
19 groups = [ "default" "local" "development" ];
20 };
21in
22 {
23 inherit gems varDir socketsDir rubyRoot;
24 }
diff --git a/nixops/modules/task/thin.patch b/nixops/modules/task/thin.patch
new file mode 100644
index 0000000..a7df3e3
--- /dev/null
+++ b/nixops/modules/task/thin.patch
@@ -0,0 +1,23 @@
1diff --git a/Gemfile b/Gemfile
2index 8544e15..9c4279c 100644
3--- a/Gemfile
4+++ b/Gemfile
5@@ -3,6 +3,8 @@ source "http://rubygems.org"
6 # Specify your gem's dependencies in taskwarrior-web.gemspec
7 gemspec
8
9+gem 'thin'
10+
11 group :local do
12 gem 'rb-fsevent', :require => false
13 gem 'growl', :require => false
14diff --git a/config.ru b/config.ru
15index c3050c6..52387d8 100644
16--- a/config.ru
17+++ b/config.ru
18@@ -1,5 +1,4 @@
19 require File.join(File.dirname(__FILE__), 'lib', 'taskwarrior-web')
20
21-disable :run
22 TaskwarriorWeb::App.set({ :environment => :production })
23 run TaskwarriorWeb::App