pyratelog

personal blog
git clone git://git.pyratebeard.net/pyratelog.git
Log | Files | Refs | README

20220217-welcome_todo_my_nightmare.md (7087B)


      1 I have always been one to make todo lists.  My process has changed a lot over the years, from when I used actual paper to using only digital lists.  My current setup is a bit hacky but works for me, so I thought I would share it.
      2 
      3 On my PC I started using a [simple script](https://git.z3bra.org/scripts/file/todo.html){target="_blank" rel="noreferrer"} (thanks to z3bra) to add tasks to a file, by default ~/.todo.  There is nothing special about this todo file, it is simple plain text.  I am aware of the [todo.txt method](http://todotxt.org/){target="_blank" rel="noreferrer"} but after trying it for a while I felt like it was not working for me.  I have tried [kanban boards](https://en.wikipedia.org/wiki/Kanban_board){target="_blank" rel="noreferrer"} after using similar methods in work, but I didn't find it worked very well for my own personal tasks.
      4 
      5 My personal note and wiki tool of choice is [vimwiki](http://vimwiki.github.io/){target="_blank" rel="noreferrer"} so I tried keeping my todo list in that.  This worked well for a while but I couldn't find a quick and comfortable workflow with it.
      6 
      7 Other notable attempts include [Taskwarrior](https://taskwarrior.org/){target="_blank" rel="noreferrer"} and [calcurse](https://calcurse.org/){target="_blank" rel="noreferrer"}.
      8 
      9 At the moment I am happy with the simple `todo` script.  I spend a lot of time in [tmux](https://github.com/tmux/tmux/wiki){target="_blank" rel="noreferrer"}, so I have added a couple of keybindings to my config.  I have one keybind to display the todo list in a tmux popup and another to start a command prompt with a prefix so I can write out a task, close the single quotes, and hit enter.  If you're interested the relevant config is
     10 ```
     11 # toggle todo list popup
     12 unbind t
     13 bind t display-popup -w 75 -h 13 ~/bin/todo
     14 
     15 # add task to todo list
     16 unbind T
     17 bind T command-prompt -I "run-shell '~/bin/todo "
     18 ```
     19 
     20 Adjust the width and height of the popup to your preference, and change the path to your script if required.
     21 
     22 This workflow was working quite well when I was at my PC, but what happens when I am not?  On my phone I run [termux](https://termux.com/){target="_blank" rel="noreferrer"} so I can easily log in to my PC from anywhere (with a VPN) and add an entry to my todo list, but sometimes this process is a bit slow, or I may not have a network connection at all.
     23 
     24 I have [Markor](https://gsantner.net/project/markor.html?source=github){target="_blank" rel="noreferrer"} installed for taking notes so I thought I could sync my todo file to my phone to modify in Markor.  I didn't want to install a tool such as [syncthing](https://syncthing.net/){target="_blank" rel="noreferrer"} on both my PC and phone for a single file so I started using `rsync` in a script periodically run by `cron`.  I set my crontab to push the todo file from my PC to my phone at the end of the workday, then pull from my phone before work each workday.
     25 
     26 This worked well as long as I only edited the file on my PC during working hours and on my phone outside of working hours, which is _usually_ the case.  I knew it would bite me in the ass at some point though so I started looking at a way to sync them properly.  I came across `incron`, which is like `cron` but is triggered by filesystem events instead of at specified times.  This looked like a good start, so I installed it on my PC and configured incrontab to push the todo file to my phone whenever it is modified.  I immediately [hit a bug](https://github.com/danfruehauf/incron/issues/12){target="_blank" rel="noreferrer"} which caused `incron` to run once and then not run again.
     27 
     28 Disappointed by this I decided to hack together something similar myself using `inotifywait` from the [inotify-tools](https://github.com/inotify-tools/inotify-tools/wiki){target="_blank" rel="noreferrer"} package.  This tool is really easy to use, and is available in termux.  I set a script on both my PC and my phone to watch the todo file and `rsync` it to the opposite device if it changes.
     29 ```
     30 #!/bin/sh
     31 
     32 LOCAL_TODO="~/.todo"
     33 REMOTE_TODO="/path/to/markor/todo.txt"
     34 REMOTE_HOST="pyratephone"
     35 
     36 exec inotifywait -e close_wait -m $LOCAL_TODO | while read TODOFILE ; do
     37 	rsync $LOCAL_TODO $REMOTE_HOST:$REMOTE_TODO
     38 done
     39 ```
     40 
     41 I daemonised this on my PC and created a service on termux using [termux-services](https://wiki.termux.com/wiki/Termux-services){target="_blank" rel="noreferrer"}.  With the package installed creating a service is straight forward; create a service directory and `run` script
     42 ```
     43 mkdir -p $PREFIX/var/service/todod/log
     44 ln -sf $PREFIX/share/termux-services/svlogger $PREFIX/var/service/todod/log/run
     45 cat >> $PREFIX/var/service/todod/run << EOF
     46 #!/data/data/com.termux/files/usr/bin/sh
     47 
     48 LOCAL_TODO="/path/to/markor/todo.txt"
     49 REMOTE_TODO=".todo"
     50 REMOTE_HOST="pyratepc"
     51 
     52 exec 2>&1
     53 exec inotifywait -e close_write -m $LOCAL_TODO | while read TODOFILE
     54 do
     55 	rsync -e "ssh -i /path/to/sshkey" $LOCAL_TODO $REMOTE_HOST:$REMOTE_TODO
     56 done
     57 EOF
     58 chmod +x $PREFIX/var/service/todod/run
     59 sv start todod
     60 ```
     61 
     62 I immediately hit another issue, the DELETE_SELF file event.  When you pass the `-d` flag to the `todo` script to delete a line it uses the command
     63 ```
     64 sed -i "${1}d" $TODOFILE
     65 ```
     66 
     67 Unfortunately this command causes the file to be replaced with a new file, which generates the DELETE_SELF event.  This means `inotifywait` sees the original file it was monitoring as deleted and can't monitor the file anymore.  It doesn't look at the filename therefore does not recognise that the new todo file is "the same".  To overcome this I switched the use of `sed` with `ed`.  The `delete` function in the `todo` script now looks like this
     68 ```
     69 delete() {
     70 	test -n "$1" || exit 1
     71 	ed $TODO << EOF >/dev/null
     72 ${1}d
     73 w
     74 q
     75 EOF
     76 }
     77 ```
     78 
     79 Using `ed` means the file is opened, the line deleted, and the file closed causing a CLOSE_WAIT event.  You can find my version of the `todo` script on my [git server](https://git.pyratebeard.net/dotfiles/file/bin/bin/todo.html){target="_blank" rel="noreferrer"}.
     80 
     81 The same issue occurs with `rsync`, the file is replaced with a new file causing a DELETE_SELF event.  The quickest way I thought to fix this was to restart the daemon on the opposite device after the `rsync`.  My script now looks like this
     82 ```
     83 #!/bin/sh
     84 
     85 LOCAL_TODO="~/.todo"
     86 REMOTE_TODO="/path/to/markor/todo.txt"
     87 REMOTE_HOST="pyratephone"
     88 DAEMON_RESTART="SVDIR=/data/data/com.termux/files/usr/var/service sv restart todod"
     89 
     90 exec inotifywait -e close_wait -m $LOCAL_TODO | while read TODOFILE ; do
     91 	rsync $LOCAL_TODO $REMOTE_HOST:$REMOTE_TODO
     92 	ssh $REMOTE_HOST "${DAEMON_RESTART}"
     93 done
     94 ```
     95 
     96 The `run` script on my phone has a different $DAEMON_RESTART variable to restart the script on my PC, and specifies the IdentityFile like I did with the `rsync` command.
     97 
     98 So now I have a sync of sorts, and the workflow on my PC works well with the tmux keybindings.  I expect at some point I will need to consider what happens when I make a change to the file and there is no network connection to the other device but that is a task for another day, it's on the todo list.