-
Notifications
You must be signed in to change notification settings - Fork 0
/
journal
495 lines (425 loc) · 11.4 KB
/
journal
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
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
#!/bin/bash
# A bash script for your simple journaling.
# Journals are stored either as plain files or
# "locked" files in a `.journal` dir in your
# home dir.
# https://github.com/telos-matter/journal
# 2024_08, HEMMOUDA Aymane
################################################################################
# User settings
# Where the journals are stored
DIR="$HOME/.journal"
# Used editor
EDITOR='vim' # If that's not enough, modify the function called open_editor.
# Whether entries should be locked by default
LOCK_BY_DEFAULT='true' # 'true' or 'false'
# The date-time stamp to use in a first entry
FIRST_ENTRY_FORMAT='+%d/%m/%y %a %l:%M %p:'
# The date-time stamp to use in additional entries
NEW_ENTRY_FORMAT='+%l:%M %p:'
################################################################################
# Constants
# File name format
FILE_FORMAT='+%Y_%m_%d'
# Format that the user provides to read a journal. Without the `+`
READ_JOURNAL_FORMAT="%Y %m %d"
# Temporary dir name. Used inside $DIR
TMP='tmp'
# Locked files extension
LCK_EXT='.zip'
################################################################################
# Used / needed functions
# Opens the editor to edit
# the file given by $1
open_editor () {
"$EDITOR" "$1"
# The used editor has to be such
# that it blocks the process until
# the user finished editing.
# So unfortunately you can't use
# TextEdit on MacOS for example.
}
# Shows a short command synopsis
show_synopsis () {
echo 'Usage: journal [ h | l | u | t | r | y | p ... | YYYY mm dd ]'
}
# Shows usage / help
show_usage () {
echo "
Journal, a bash script for your simple journaling.
Usage:
journal [ h | l | u | t | r | y | p ... | YYYY mm dd ]
Simply run \`journal\` with no arguments to write a journal for today. Some settings can be modified inside the script, like wether or not to lock the journals by default, what editor to use, and some other stuff.
Options:
h, -h, --help show this help message.
l, -l, --locked create a journal that will be locked.
u, -u, --unlocked create a journal that will remain unlocked.
t, -t, --today read todays' journal.
r, -r, --read alias for \`t\`.
y, -y, --yesterday read yesterdays' journal.
p ..., -p ... read the N-th previous journal.
YYYY mm dd read the journal written on the YYYY mm dd.
Examples:
journal write a journal for today or add an entry.
journal l write and lock today's NEW journal.
journal y read yesterdays' journal.
journal p read the journal that was written before today's one.
journal -pp read the 2nd previous journal that was written before today's one.
journal 1970 01 01 read the journal from January, first, 1970.
https://github.com/telos-matter/journal
" | less
}
# Initializes what needs to be initialized
init () {
# Make sure DIR and TMP exist
if [ ! -d "$DIR/$TMP" ]
then
mkdir -p "$DIR/$TMP"
fi
}
# Lets the user add
# the first entry to $1
first_entry () {
# Get the first entry stamp
local STAMP=`date "$FIRST_ENTRY_FORMAT"`
# Write it
echo -n -e "$STAMP\n\t" > "$1"
# Let the user journal
open_editor $1
}
# Lets the user add a new
# entry to $1
new_entry () {
# Get the new entry stamp
local STAMP=`date "$NEW_ENTRY_FORMAT"`
# Append it
echo -n -e "\n$STAMP\n\t" >> "$1"
# Let the user add the entry
open_editor $1
}
# Unlocks $1 into the dir
# $2, using the password $3.
# Returns a success code
unlock () {
unzip -q -P "$3" "$1" -d "$2"
return $?
}
# Same as unlock, but removes
# the locked file ($1) afterwards
# regardless of the success code
unlock_rm () {
unlock $@
local SUCCESS_CODE=$?
rm $1
return $SUCCESS_CODE
}
# Locks $1 into $2
# using the password $3
lock () {
zip -q -e -j "$2" "$1" -P "$3"
}
# Same as lock, but removes
# the unlocked file ($1) afterwards
lock_rm () {
lock $@
rm $1
}
# Checks if $1
# exists in $DIR. Locked or not.
# Returns 0 for true and 1 for false.
journal_exists () {
if [ -f "$DIR/$1" ] || [ -f "$DIR/$1$LCK_EXT" ]
then
return 0
else
return 1
fi
}
# Checks if todays' journal
# exists
today_exists () {
# Get todays journal
local TODAY=`date "$FILE_FORMAT"`
# Check
journal_exists "$TODAY"
# Return
return $?
}
# Copies the existing locked journal $1
# into TMP and tries to unlock it.
# Returns 0 if all went well
# and removes the junk in all cases.
# $1 is the simple name of
# the journal, without LCK_EXT.
# The password is stored
# in the variable PASSWORD, which
# should be unset after
unlock_in_tmp () {
# Make sure it exists
if [ -f "$DIR/$1$LCK_EXT" ]
then
# First copy it
cp "$DIR/$1$LCK_EXT" "$DIR/$TMP/"
# Prompt for password
echo "Password for $1?"
read -s PASSWORD
# Try to unlock
unlock_rm "$DIR/$TMP/$1$LCK_EXT" "$DIR/$TMP/" "$PASSWORD"
# If unlocked successfully
if [ $? -eq 0 ]
then
# Return 0
return 0
# Otherwise if unable to unlock
else
# Show appropriate message
echo 'Incorrect password.'
# And return 1
return 1
fi
# If it does not exist
else
echo 'ASSERTION ERROR: Unreachable' >&2
exit 1
fi
}
# Let the user journal
# for the first time today.
# $1 specifies whether to lock
# the journal or keep it unlocked
new_journal () {
# First get file name. Which is today's date formatted
local FILE=`date "$FILE_FORMAT"`
# Make sure it doesn't already exist
journal_exists $FILE
if [ $? -eq 0 ]
then
# It does exist
echo "ERROR: Today's journal has already been written. Use the command with no arguments to add a new entry." >&2
exit 1
fi
# It doesn't exist, let the user journal
first_entry "$DIR/$FILE"
# Once finished journaling, check if
# it should be locked
if eval "$1"
then
# If so, then prompt for password to use
local PASSWORD
local PASSWORD_CONFIRMATION
while true
do
echo "Password to lock $FILE with?"
read -s PASSWORD
echo "Confirm password:"
read -s PASSWORD_CONFIRMATION
if [ "$PASSWORD" = "$PASSWORD_CONFIRMATION" ]
then
break
fi
echo "The two passwords don't match. Please try again."
done
# Then lock
lock_rm "$DIR/$FILE" "$DIR/$FILE$LCK_EXT" "$PASSWORD"
echo "Journal locked."
else
echo "Journal saved."
fi
}
# Either journal for the first
# time today, or add a new entry
journal_today () {
# First get file name. Which is today's date formatted
local FILE=`date "$FILE_FORMAT"`
# Check if there already is an entry for today that is unlocked
if [ -f "$DIR/$FILE" ]
then
# If so, let the user add a new entry
new_entry "$DIR/$FILE"
echo 'New entry saved.'
# If not, check if it exists but locked
elif [ -f "$DIR/$FILE$LCK_EXT" ]
then
# If so, unlock in TMP
unlock_in_tmp $FILE
# If unlocked successfully
if [ $? -eq 0 ]
then
# Let the user add a new entry
new_entry "$DIR/$TMP/$FILE"
# Lock back again when done
lock_rm "$DIR/$TMP/$FILE" "$DIR/$FILE$LCK_EXT" "$PASSWORD"
# The password is set with unlock_in_tmp. I don't know how "okay" that is
echo 'New entry saved.'
fi
# Otherwise, this is the first entry
else
new_journal "$LOCK_BY_DEFAULT"
fi
}
# Lets the user read the journal
# whose simple name is specified
# in $1. Handles unlocking and all.
# The journal must exist
read_journal () {
# Lets the user read $1
# without editing it
read_without_edit () {
less $1 # Apparently `less` can transfer you to edit a file with `v`
}
# Check if the journal is unlocked
if [ -f "$DIR/$1" ]
then
# If so, let the user read it
read_without_edit "$DIR/$FILE"
# If not, check if it's locked
elif [ -f "$DIR/$1$LCK_EXT" ]
then
# If so, unlock in TMP
unlock_in_tmp $1
# If unlocked successfully
if [ $? -eq 0 ]
then
# Let the user read it
read_without_edit "$DIR/$TMP/$1"
# Remove when done
rm "$DIR/$TMP/$1"
fi
# Otherwise, the journal does not exist
else
echo "ASSERTION ERROR: Expected an existing journal, not: $1"
exit 2
fi
}
# Lets the user read the journal
# written on the $1 $2 $3. (YYYY, MM, DD)
read_journal_date () {
#First format the file name
local FILE=`date -j -f "$READ_JOURNAL_FORMAT" "$1 $2 $3" "$FILE_FORMAT"` # Not sure if this syntax is valid on Linux
# Return if the formatting didn't go well
if [ $? -ne 0 ]
then
return 1
fi
# Check if the journal exists
journal_exists $FILE
if [ $? -eq 0 ]
then
# It does exist
read_journal $FILE
else
# It does not exist
local NICE_DATE=`date -j -f "$READ_JOURNAL_FORMAT" "$1 $2 $3" "+%B the %d, %Y"`
echo "No journal was written on $NICE_DATE. ($FILE)"
fi
}
# Reads the $1-th previous journal
# that is not todays' journal
read_previous () {
# Get journal count
local COUNT=`ls "$DIR" | wc -l`
# Check that there is at least something
if [ $COUNT -le 1 ]
then
echo "ERROR: You haven't written any journals yet"
return 1
fi
# Set N depending on whether today's
# journal exists or not
today_exists
if [ $? -eq 0 ]
then
# TMP + today
N=$(( $1 +2 ))
# Error message suffix
local ERROR_MESSAGE_SUFFIX=" Including today's journal."
else
# Just TMP
N=$(( $1 +1 ))
fi
# Check if we have the N-th previous journal
if [ $COUNT -ge $N ]
then
# If so, retrieve it by:
# Listing, sorting, getting the first N results, then only keeping the last, then remove the LCK_EXT if it's locked
local PREVIOUS=`ls "$DIR" | sort -r | head -n "$N" | tail -n 1 | sed "s/$LCK_EXT//"`
read_journal $PREVIOUS
else
# If it does not exist
# Remove TMP from count
COUNT=$(( $COUNT -1 ))
echo "ERROR: $1 journals back is too far back. You have only written $COUNT journals.$ERROR_MESSAGE_SUFFIX"
fi
}
################################################################################
# "Main"
# Initialize
init
# Call appropriate function depending on the number of args
# No argument -> journaling today for the first
# time or adding a new entry
if [ $# -eq 0 ]
then
journal_today
# One argument -> journaling today for the first
# time, overriding LOCK_BY_DEFAULT.
# Or reading todays, or yesterdays' journal
# Or reading the previous journal
elif [ $# -eq 1 ]
then
# Check if the user wants
# to lock the journal
if [ "$1" = 'l' ] || [ "$1" = '-l' ] || [ "$1" = '--locked' ]
then
new_journal 'true'
# Or if the user wants to
# keep the journal unlocked
elif [ "$1" = 'u' ] || [ "$1" = '-u' ] || [ "$1" = '--unlocked' ]
then
new_journal 'false'
# Or read todays journal
elif [ "$1" = 't' ] || [ "$1" = '-t' ] || [ "$1" = '--today' ] || [ "$1" = 'r' ] || [ "$1" = '-r' ] || [ "$1" = '--read' ]
then
read_journal_date `date "+$READ_JOURNAL_FORMAT"`
# Or read yesterdays journal
elif [ "$1" = 'y' ] || [ "$1" = '-y' ] || [ "$1" = '--yesterday' ]
then
read_journal_date `date -v -1d "+$READ_JOURNAL_FORMAT"` # I also don't think this would work with Linux
# Or read a previous journal
elif [[ "$1" =~ ^p+$ ]] || [[ "$1" =~ ^\-p+$ ]]
then
# Get how many ps are there
P_COUNT=${#1}
if [[ "$1" =~ ^\- ]]
then
P_COUNT=$(( $P_COUNT -1 ))
fi
read_previous $P_COUNT
# Could also be asking for help
elif [ "$1" = 'h' ] || [ "$1" = '-h' ] || [ "$1" = '--help' ]
then
show_usage
# Otherwise usage error
else
echo "ERROR: Unrecognized argument: $1" >&2
show_synopsis
exit 1
fi
# Three arguments -> Wants to read a journal
elif [ $# -eq 3 ]
then
read_journal_date $@
# Anything else -> Error
else
echo "ERROR: Wrong usage" >&2
show_synopsis
exit 1
fi
# Although the variable are automatically removed
# when we exit the process, we override the
# password for extra protection
PASSWORD=`false`
unset PASSWORD
PASSWORD_CONFIRMATION=`false`
unset PASSWORD_CONFIRMATION
exit 0