-
Notifications
You must be signed in to change notification settings - Fork 1
/
export-taskwarrior-dates-to-remind.html
398 lines (203 loc) · 14.4 KB
/
export-taskwarrior-dates-to-remind.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
<!DOCTYPE html>
<html lang="en">
<!-- Beautiful Jekyll | MIT license | Copyright Dean Attali 2016 -->
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<title>Export Taskwarrior Dates To Remind</title>
<meta name="author" content="eshapard" />
<link rel="alternate" type="application/rss+xml" title="My Crappy Code Blog - Watch me code stuff... poorly" href="/feed.xml" />
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.6.0/css/font-awesome.min.css" />
<link rel="stylesheet" href="/css/bootstrap.min.css" />
<link rel="stylesheet" href="/css/bootstrap-social.css" />
<link rel="stylesheet" href="/css/main.css" />
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic" />
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" />
<!-- Facebook OpenGraph tags -->
<meta property="og:title" content="Export Taskwarrior Dates To Remind" />
<meta property="og:description" content="I’ve been playing around with the geeky, efficient, command-line scheduling program remind. It’s very cool once you get used to it. I wanted to automatically export any duedates from taskwarrior, so this is what I came up with. Export Taskwarrior Dates I found a script that did this (written in...">
<meta property="og:type" content="website" />
<meta property="og:url" content="http://eshapard.github.io/export-taskwarrior-dates-to-remind.html" />
<link rel="canonical" href="http://eshapard.github.io/export-taskwarrior-dates-to-remind.html" />
<meta property="og:image" content="http://eshapard.github.io/img/ejs_logo.png" />
<!-- Twitter summary cards -->
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="@" />
<meta name="twitter:creator" content="@" />
<meta name="twitter:title" content="Export Taskwarrior Dates To Remind" />
<meta name="twitter:description" content="I’ve been playing around with the geeky, efficient, command-line scheduling program remind. It’s very cool once you get used to it. I wanted to automatically export any duedates from taskwarrior, so this is what I came up with. Export Taskwarrior Dates I found a script that did this (written in...">
<meta name="twitter:image" content="http://eshapard.github.io/img/ejs_logo.png" />
</head>
<body>
<nav class="navbar navbar-default navbar-fixed-top navbar-custom">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#main-navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="http://eshapard.github.io">My Crappy Code Blog</a>
</div>
<div class="collapse navbar-collapse" id="main-navbar">
<ul class="nav navbar-nav navbar-right">
<li>
<a href="/categories/">Categories</a>
</li>
</ul>
</div>
<div class="avatar-container">
<div class="avatar-img-border">
<a href="http://eshapard.github.io ">
<img class="avatar-img" src="/img/ejs_logo.png" />
</a>
</div>
</div>
</div>
</nav>
<!-- TODO this file has become a mess, refactor it -->
<header class="header-section ">
<div class="intro-header no-img">
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<div class="post-heading">
<h1>Export Taskwarrior Dates To Remind</h1>
<span class="post-meta">Posted on May 31, 2018</span>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<article role="main" class="blog-post">
<p>I’ve been playing around with the geeky, efficient, command-line scheduling program <a href="https://www.roaringpenguin.com/products/remind">remind</a>. It’s very cool once you get used to it.</p>
<p>I wanted to automatically export any duedates from <a href="https://taskwarrior.org/">taskwarrior</a>, so this is what I came up with.</p>
<h2 id="export-taskwarrior-dates">Export Taskwarrior Dates</h2>
<p>I found a script that did this (written in java), but I didn’t like it. It scheduled things that weren’t due and there seemed to be a lot of overhead for a task that amounts to generating a simple text file.</p>
<p>Using taskwarrior’s own export function and a bit of python, I put together the following code. It generates a file for <em>Remind</em> to read from only tasks that have a due date set and are not blocked by another task (such as one it depends on; rare for tasks with due-dates).</p>
<h3 id="remindwarrior">remindWarrior</h3>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/python
</span><span class="kn">import</span> <span class="nn">json</span><span class="p">,</span> <span class="n">subprocess</span>
<span class="kn">from</span> <span class="nn">pprint</span> <span class="kn">import</span> <span class="n">pprint</span>
<span class="n">outfile</span> <span class="o">=</span> <span class="s">'/home/USERNAME/.config/reminders/taskwarrior.rem'</span>
<span class="n">reminders</span> <span class="o">=</span> <span class="s">'# Taskwarrior Tasks with Due Dates</span><span class="se">\n</span><span class="s">'</span>
<span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">subprocess</span><span class="p">.</span><span class="n">check_output</span><span class="p">([</span><span class="s">'task'</span><span class="p">,</span> <span class="s">'+DUE'</span><span class="p">,</span> <span class="s">'+UNBLOCKED'</span><span class="p">,</span> <span class="s">'export'</span><span class="p">])):</span>
<span class="n">reminders</span> <span class="o">+=</span> <span class="p">(</span><span class="s">"REM %s-%s-%s MSG %%</span><span class="se">\"</span><span class="s">%s%%</span><span class="se">\"</span><span class="s"> (taskwarrior)</span><span class="se">\n</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">t</span><span class="p">[</span><span class="s">'due'</span><span class="p">][:</span><span class="mi">4</span><span class="p">],</span><span class="n">t</span><span class="p">[</span><span class="s">'due'</span><span class="p">][</span><span class="mi">4</span><span class="p">:</span><span class="mi">6</span><span class="p">],</span><span class="n">t</span><span class="p">[</span><span class="s">'due'</span><span class="p">][</span><span class="mi">6</span><span class="p">:</span><span class="mi">8</span><span class="p">],</span><span class="n">t</span><span class="p">[</span><span class="s">'description'</span><span class="p">]))</span>
<span class="c1">#print(reminders)
</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">outfile</span><span class="p">,</span> <span class="s">'r'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="c1">#compare file with reminders string
</span> <span class="k">if</span> <span class="n">reminders</span> <span class="o">!=</span> <span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">():</span>
<span class="c1">#write new file only if it differs from existing file
</span> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">outfile</span><span class="p">,</span> <span class="s">'w'</span><span class="p">)</span> <span class="k">as</span> <span class="n">o</span><span class="p">:</span>
<span class="n">o</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">reminders</span><span class="p">)</span>
</code></pre></div></div>
<p>Run <code class="language-plaintext highlighter-rouge">crontab -e</code> and add a line in there to run this sucker every 5 minutes or so:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>*/5 * * * * remindWarrior
</code></pre></div></div>
<p>As you can see, I’ve set up my reminders in a hidden directory. My ~/.reminders file includes a single line.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INCLUDE /home/USER/.config/reminders
</code></pre></div></div>
<p>Note also, that the script checks to see if the new file would be any different from the old file and only writes to the file if it has changed. This becomes significant later.</p>
<h1 id="automatic-re-starting-of-remind">Automatic re-starting of Remind</h1>
<p>I run remind as a daemon so that it will pop up reminders (using <em>gmessage</em>) for me. But when you change the files that remind uses, this daemon doesn’t re-read them. For that reason, and others, I created a script that would kill start the process if it isn’t running, or kill it and restart it again if it is running.</p>
<p>I call it <em>reminderdaemon</em> and it’s how I start the reminder daemon when I log in.</p>
<h3 id="reminderdaemon">reminderdaemon</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/bash
XAUTHORITY=/home/USERNAME/.Xauthority
export XAUTHORITY
pid=$(ps -C rem -o pid=)
if [ -n "$pid" ]
then
#Remind is running so restart it
kill $pid
rem -az -k'gmessage %s -default okay -timeout 30 -center -title Remind -display :0.0' &
else
#Remind is NOT running so start it
rem -az -k'gmessage %s -default okay -timeout 30 -center -title Remind -display :0.0' &
fi
exit
</code></pre></div></div>
<h2 id="incron-or-how-to-automate-the-restart-script-when-files-change">Incron, or how to automate the restart script when files change</h2>
<p>Here’s something really cool that I didn’t know about for a very long time:</p>
<p>You probably know about cron; the service that runs things for you based on time. But there’s also a service called <a href="https://linux.die.net/man/8/incrond">incron</a> that monitors files or folders and triggers actions when those files change. Very cool.</p>
<p>I ran <code class="language-plaintext highlighter-rouge">incrontab -e</code> to edit my incron config file and put the following line in there:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/home/USER/.config/reminders IN_MODIFY /home/USER/bin/reminderdaemon
</code></pre></div></div>
<p>Now whenever one of the files in my <em>.config/reminders</em> directory is updated (including the <em>taskwarrior.rem</em> file), the reminder daemon restarts with the new configuration.</p>
<p>And remember that my <em>remindWarrior</em> script only writes to <em>taskwarrior.rem</em> if it would change the contents. This prevents unnecessarily restarting the daemon every five minutes.</p>
</article>
<div class="blog-tags">
Tags:
<a href="/tag/remind">remind</a>
<a href="/tag/taskwarrior">taskwarrior</a>
<a href="/tag/linux">linux</a>
<a href="/tag/commandline">commandline</a>
</div>
<ul class="pager blog-pager">
<li class="previous">
<a href="/linux/quickly-view-i3wm-hotkeys.html" data-toggle="tooltip" data-placement="top" title="Quickly View I3Wm Hotkeys">← Previous Post</a>
</li>
<li class="next">
<a href="/python/put-not-much-emails-to-sleep.html" data-toggle="tooltip" data-placement="top" title="Put Not-Much Emails To Sleep">Next Post →</a>
</li>
</ul>
</div>
</div>
</div>
<footer>
<div class="container beautiful-jekyll-footer">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<ul class="list-inline text-center footer-links">
<li>
<a href="https://github.com/eshapard" title="GitHub">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-github fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li>
<a href="https://reddit.com/u/BonoboBanana" title="Reddit">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-reddit fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
</ul>
<p class="copyright text-muted">
eshapard
•
2022
•
<a href="http://eshapard.github.io">eshapard.github.io</a>
</p>
<!-- Please don't remove this, keep my open source work credited :) -->
<p class="theme-by text-muted">
Theme by
<a href="http://deanattali.com/beautiful-jekyll/">beautiful-jekyll</a>
</p>
</div>
</div>
</div>
</footer>
<!-- doing something a bit funky here because I want to be careful not to include JQuery twice! -->
<script>
if (typeof jQuery == 'undefined') {
document.write('<script src="/js/jquery-1.11.2.min.js"></scr' + 'ipt>');
}
</script>
<!-- doing something a bit funky here because I want to be careful not to include JQuery twice! -->
<script src="/js/bootstrap.min.js"></script>
<!-- doing something a bit funky here because I want to be careful not to include JQuery twice! -->
<script src="/js/main.js"></script>
</body>
</html>