aboutsummaryrefslogtreecommitdiff
path: root/core/update
diff options
context:
space:
mode:
Diffstat (limited to 'core/update')
-rw-r--r--core/update52
1 files changed, 43 insertions, 9 deletions
diff --git a/core/update b/core/update
index 04fd29c..fbe0e86 100644
--- a/core/update
+++ b/core/update
@@ -1,13 +1,12 @@
#!/bin/sh
export now="$(date +%s.%N)"
-update_time=0
-
+# load current state
mkdir -p "$POMODORO_STATE_PATH"
load_or_init() {
property="$1"
default_value="$2"
- property_path="$POMODORO_STATE_PATH/$property"
+ property_path="$POMODORO_STATE_PATH/current/$property"
if [ -f "$property_path" ] ; then
eval $property='"$(cat "$property_path")"'
else
@@ -17,7 +16,13 @@ load_or_init() {
[ -z "$lap" ] && load_or_init lap 0
[ -z "$state" ] && load_or_init state 'reset'
[ -z "$time" ] && load_or_init time 0.0
-[ "$time" = "0.0" ] && update_time=1
+
+# save state (for diff)
+diff_state() { printf '%s:' "$lap" "$state" "$time" ; }
+original_state="$(diff_state)"
+
+# allow overriding this value manually
+[ -z "$update_time" ] && update_time=0
# calculate remaining time on timer
if [ -z "$remaining" ] ; then
@@ -34,6 +39,7 @@ fi
# update remaining time if in reset
[ "$state" = 'reset' ] && update_time=1
+[ "$time" = "0.0" ] && update_time=1
if [ $update_time -eq 1 ] ; then
time="$POMODORO_NORMAL_DURATION"
@@ -42,12 +48,40 @@ if [ $update_time -eq 1 ] ; then
remaining="$time"
fi
-# save state
save_state() {
- mkdir -p "$POMODORO_STATE_PATH"
- echo "$lap" > "$POMODORO_STATE_PATH/lap"
- echo "$state" > "$POMODORO_STATE_PATH/state"
- echo "$time" > "$POMODORO_STATE_PATH/time"
+ # do not save files if state didn't change
+ [ "$original_state" = "$(diff_state)" ] && return
+
+ # The state update needs to be atomic since other instances may access the
+ # state during an update. This is accomplished by replacing a single symlink,
+ # which should be atomic on most POSIX-compatible platforms, and is less
+ # complicated than a lockfile. $POMODORO_STATE_PATH contains three items:
+ #
+ # 1. current -- a symlink to `primary` or `secondary`
+ # 2. primary -- folder containing current state*
+ # 3. secondary -- temporary folder used write new state
+ #
+ # * `primary` will only contain stale state during an update (i.e. while
+ # `current` is pointing to `secondary`)
+
+ mkdir -p "$POMODORO_STATE_PATH/primary" "$POMODORO_STATE_PATH/secondary"
+
+ echo "$lap" > "$POMODORO_STATE_PATH/secondary/lap"
+ echo "$state" > "$POMODORO_STATE_PATH/secondary/state"
+ echo "$time" > "$POMODORO_STATE_PATH/secondary/time"
+
+ ln -sf "secondary" "$POMODORO_STATE_PATH/secondary/current"
+
+ # this is the atomic update that replaces the `current` symlink with the new
+ # state
+ mv "$POMODORO_STATE_PATH/secondary/current" "$POMODORO_STATE_PATH"
+
+ # next, replace the old `primary` state with the new state from `secondary`,
+ # and update the symlink a second time to now point to `primary` again (this
+ # does not change the state)
+ cp -r "$POMODORO_STATE_PATH/secondary/." "$POMODORO_STATE_PATH/primary/"
+ ln -sf "primary" "$POMODORO_STATE_PATH/primary/current"
+ mv "$POMODORO_STATE_PATH/primary/current" "$POMODORO_STATE_PATH"
}
# export state variables